Merge commit 'origin/master' into next
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Fri, 26 Feb 2010 03:41:00 +0000 (14:41 +1100)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Fri, 26 Feb 2010 03:41:00 +0000 (14:41 +1100)
Manual merge of:
drivers/char/hvc_console.c
drivers/char/hvc_console.h

286 files changed:
Documentation/dontdiff
Documentation/kernel-parameters.txt
Documentation/lguest/lguest.c
Documentation/networking/ip-sysctl.txt
MAINTAINERS
Makefile
arch/arm/include/asm/cacheflush.h
arch/arm/kernel/setup.c
arch/arm/mach-gemini/gpio.c
arch/arm/mach-omap2/mux.c
arch/arm/mm/alignment.c
arch/arm/tools/mach-types
arch/ia64/include/asm/acpi.h
arch/ia64/sn/kernel/setup.c
arch/microblaze/Kconfig
arch/microblaze/include/asm/io.h
arch/microblaze/include/asm/prom.h
arch/microblaze/kernel/cpu/cache.c
arch/microblaze/kernel/of_platform.c
arch/microblaze/kernel/prom.c
arch/mips/bcm47xx/prom.c
arch/mips/mm/highmem.c
arch/parisc/Kconfig
arch/parisc/kernel/pci.c
arch/powerpc/Kconfig
arch/powerpc/include/asm/prom.h
arch/powerpc/kernel/of_platform.c
arch/powerpc/kernel/pci_64.c
arch/powerpc/kernel/prom.c
arch/powerpc/platforms/85xx/mpc85xx_mds.c
arch/powerpc/platforms/85xx/xes_mpc85xx.c
arch/powerpc/platforms/cell/cbe_powerbutton.c
arch/powerpc/platforms/cell/ras.c
arch/powerpc/platforms/cell/spu_manage.c
arch/powerpc/platforms/pasemi/cpufreq.c
arch/powerpc/platforms/powermac/cpufreq_32.c
arch/powerpc/platforms/powermac/cpufreq_64.c
arch/powerpc/platforms/powermac/feature.c
arch/powerpc/platforms/powermac/pfunc_core.c
arch/powerpc/platforms/powermac/smp.c
arch/powerpc/platforms/powermac/time.c
arch/powerpc/platforms/powermac/udbg_scc.c
arch/powerpc/sysdev/grackle.c
arch/sparc/include/asm/stat.h
arch/sparc/kernel/devices.c
arch/sparc/kernel/kstack.h
arch/sparc/kernel/of_device_32.c
arch/sparc/kernel/of_device_64.c
arch/sparc/kernel/pci.c
arch/sparc/kernel/prom.h
arch/sparc/kernel/prom_common.c
arch/sparc/kernel/smp_64.c
arch/sparc/kernel/tsb.S
arch/x86/include/asm/processor.h
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/hw_breakpoint.c
arch/x86/kernel/ptrace.c
block/blk-core.c
drivers/acpi/dock.c
drivers/acpi/processor_idle.c
drivers/acpi/processor_pdc.c
drivers/acpi/processor_perflib.c
drivers/acpi/scan.c
drivers/acpi/tables.c
drivers/ata/ahci.c
drivers/base/class.c
drivers/block/virtio_blk.c
drivers/char/Kconfig
drivers/char/hvc_beat.c
drivers/char/virtio_console.c
drivers/clocksource/cs5535-clockevt.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_bios.h
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_mem.c
drivers/gpu/drm/nouveau/nv04_dac.c
drivers/gpu/drm/nouveau/nv17_tv.c
drivers/gpu/drm/nouveau/nv50_instmem.c
drivers/gpu/drm/radeon/atom.c
drivers/gpu/drm/radeon/r600_blit_kms.c
drivers/gpu/drm/radeon/r600_cp.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_drv.h
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_object.h
drivers/gpu/drm/radeon/radeon_ring.c
drivers/gpu/drm/radeon/rv770.c
drivers/gpu/drm/ttm/ttm_tt.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
drivers/gpu/vga/vgaarb.c
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-3m-pct.c [new file with mode: 0644]
drivers/hid/hid-apple.c
drivers/hid/hid-core.c
drivers/hid/hid-debug.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-lg.c
drivers/hid/hid-lg.h
drivers/hid/hid-lg3ff.c [new file with mode: 0644]
drivers/hid/hid-lgff.c
drivers/hid/hid-magicmouse.c [new file with mode: 0644]
drivers/hid/hid-mosart.c [new file with mode: 0644]
drivers/hid/hid-ntrig.c
drivers/hid/hid-ortek.c [new file with mode: 0644]
drivers/hid/hid-quanta.c [new file with mode: 0644]
drivers/hid/hid-sony.c
drivers/hid/hid-stantum.c [new file with mode: 0644]
drivers/hid/hid-wacom.c
drivers/hid/hidraw.c
drivers/hid/usbhid/hid-core.c
drivers/hid/usbhid/hid-quirks.c
drivers/hid/usbhid/usbhid.h
drivers/input/input-polldev.c
drivers/input/serio/i8042.c
drivers/input/touchscreen/usbtouchscreen.c
drivers/macintosh/adb.c
drivers/macintosh/therm_pm72.c
drivers/macintosh/therm_windtunnel.c
drivers/macintosh/via-pmu-backlight.c
drivers/macintosh/via-pmu.c
drivers/macintosh/windfarm_core.c
drivers/macintosh/windfarm_cpufreq_clamp.c
drivers/macintosh/windfarm_lm75_sensor.c
drivers/macintosh/windfarm_max6690_sensor.c
drivers/macintosh/windfarm_pm112.c
drivers/macintosh/windfarm_pm121.c
drivers/macintosh/windfarm_pm81.c
drivers/macintosh/windfarm_pm91.c
drivers/macintosh/windfarm_smu_sensors.c
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/frontends/l64781.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/bt8xx/bttv-i2c.c
drivers/media/video/bt8xx/bttvp.h
drivers/media/video/mt9t112.c
drivers/media/video/pwc/pwc-ctrl.c
drivers/net/benet/be_cmds.c
drivers/net/e1000/e1000_main.c
drivers/net/ixgbe/ixgbe_82598.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/mace.c
drivers/net/sfc/efx.c
drivers/net/sfc/falcon_boards.c
drivers/net/sfc/mcdi.c
drivers/net/sfc/qt202x_phy.c
drivers/net/tc35815.c
drivers/net/usb/cdc_ether.c
drivers/net/via-velocity.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/main.c
drivers/net/wireless/iwlwifi/iwl-4965.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-rx.c
drivers/net/wireless/iwlwifi/iwl-tx.c
drivers/net/wireless/iwmc3200wifi/rx.c
drivers/net/wireless/rtl818x/rtl8187_dev.c
drivers/of/Kconfig
drivers/of/Makefile
drivers/of/base.c
drivers/of/fdt.c [new file with mode: 0644]
drivers/of/gpio.c
drivers/of/of_i2c.c
drivers/of/of_mdio.c
drivers/of/of_spi.c
drivers/pci/hotplug/acpiphp_glue.c
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/thinkpad_acpi.c
drivers/sbus/char/openprom.c
drivers/scsi/arm/fas216.c
drivers/scsi/fcoe/fcoe.c
drivers/scsi/fcoe/libfcoe.c
drivers/scsi/libfc/fc_exch.c
drivers/scsi/libfc/fc_fcp.c
drivers/scsi/libfc/fc_lport.c
drivers/scsi/libfc/fc_rport.c
drivers/scsi/libiscsi_tcp.c
drivers/scsi/megaraid/megaraid_sas.c
drivers/serial/8250.c
drivers/serial/pmac_zilog.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/coldfire_qspi.c [new file with mode: 0644]
drivers/spi/davinci_spi.c [new file with mode: 0644]
drivers/spi/dw_spi.c
drivers/spi/dw_spi_mmio.c [new file with mode: 0644]
drivers/spi/dw_spi_pci.c
drivers/spi/mpc52xx_psc_spi.c
drivers/spi/mpc52xx_spi.c
drivers/spi/spi_imx.c
drivers/spi/spi_mpc8xxx.c
drivers/spi/spi_ppc4xx.c
drivers/spi/spi_s3c64xx.c
drivers/spi/spi_sh_msiof.c
drivers/spi/spi_stmp.c
drivers/spi/xilinx_spi.c
drivers/spi/xilinx_spi_of.c
drivers/ssb/main.c
drivers/usb/core/devio.c
drivers/usb/gadget/f_eem.c
drivers/usb/gadget/multi.c
drivers/usb/gadget/r8a66597-udc.c
drivers/usb/gadget/s3c-hsotg.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/fhci-tds.c
drivers/usb/misc/sisusbvga/sisusb.c
drivers/usb/otg/Kconfig
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/sierra.c
drivers/usb/storage/unusual_devs.h
drivers/video/aty/aty128fb.c
drivers/video/aty/atyfb_base.c
drivers/video/aty/radeon_backlight.c
drivers/video/efifb.c
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_pci.c
drivers/virtio/virtio_ring.c
drivers/watchdog/bfin_wdt.c
fs/cachefiles/namei.c
fs/exec.c
fs/namei.c
fs/nfsd/vfs.c
fs/proc/base.c
fs/proc/proc_devtree.c
fs/sysfs/inode.c
include/linux/amba/bus.h
include/linux/blkdev.h
include/linux/fs.h
include/linux/hid.h
include/linux/input.h
include/linux/kfifo.h
include/linux/of.h
include/linux/of_fdt.h
include/linux/spi/dw_spi.h
include/linux/virtio.h
include/linux/virtio_balloon.h
include/linux/virtio_blk.h
include/linux/virtio_console.h
kernel/kfifo.c
kernel/perf_event.c
kernel/sys.c
lib/idr.c
mm/migrate.c
mm/oom_kill.c
net/bluetooth/hidp/core.c
net/core/dev.c
net/core/ethtool.c
net/core/net-sysfs.c
net/ipv4/devinet.c
net/ipv4/igmp.c
net/ipv4/ipcomp.c
net/ipv4/tcp_input.c
net/ipv6/addrconf.c
net/ipv6/ipcomp6.c
net/mac80211/ibss.c
net/mac80211/rate.c
net/mac80211/scan.c
net/xfrm/xfrm_state.c
scripts/.gitignore
scripts/binoffset.c [deleted file]
scripts/extract-ikconfig
scripts/kconfig/Makefile
scripts/kconfig/streamline_config.pl
security/integrity/ima/ima_iint.c
security/selinux/ss/ebitmap.c
sound/aoa/fabrics/layout.c
sound/ppc/awacs.c
sound/ppc/burgundy.c
sound/ppc/pmac.c
sound/soc/fsl/efika-audio-fabric.c
sound/soc/fsl/pcm030-audio-fabric.c
tools/perf/util/probe-event.c

index 3ad6ace..d9bcffd 100644 (file)
@@ -69,7 +69,6 @@ av_permissions.h
 bbootsect
 bin2c
 binkernel.spec
-binoffset
 bootsect
 bounds.h
 bsetup
index 736d456..e7848a0 100644 (file)
@@ -199,6 +199,10 @@ and is between 256 and 4096 characters. It is defined in the file
                        acpi_display_output=video
                        See above.
 
+       acpi_early_pdc_eval     [HW,ACPI] Evaluate processor _PDC methods
+                               early. Needed on some platforms to properly
+                               initialize the EC.
+
        acpi_irq_balance [HW,ACPI]
                        ACPI will balance active IRQs
                        default in APIC mode
@@ -311,6 +315,11 @@ and is between 256 and 4096 characters. It is defined in the file
        aic79xx=        [HW,SCSI]
                        See Documentation/scsi/aic79xx.txt.
 
+       alignment=      [KNL,ARM]
+                       Allow the default userspace alignment fault handler
+                       behaviour to be specified.  Bit 0 enables warnings,
+                       bit 1 enables fixups, and bit 2 sends a segfault.
+
        amd_iommu=      [HW,X86-84]
                        Pass parameters to the AMD IOMMU driver in the system.
                        Possible values are:
index 4220851..3119f5d 100644 (file)
@@ -34,7 +34,6 @@
 #include <sys/uio.h>
 #include <termios.h>
 #include <getopt.h>
-#include <zlib.h>
 #include <assert.h>
 #include <sched.h>
 #include <limits.h>
index 006b39d..e87f3cd 100644 (file)
@@ -1074,10 +1074,10 @@ regen_max_retry - INTEGER
        Default: 5
 
 max_addresses - INTEGER
-       Number of maximum addresses per interface.  0 disables limitation.
-       It is recommended not set too large value (or 0) because it would
-       be too easy way to crash kernel to allow to create too much of
-       autoconfigured addresses.
+       Maximum number of autoconfigured addresses per interface.  Setting
+       to zero disables the limitation.  It is not recommended to set this
+       value too large (or to zero) because it would be an easy way to
+       crash the kernel by allowing too many addresses to be created.
        Default: 16
 
 disable_ipv6 - BOOLEAN
index 412eff6..317ed38 100644 (file)
@@ -616,10 +616,10 @@ M:        Richard Purdie <rpurdie@rpsys.net>
 S:     Maintained
 
 ARM/CORTINA SYSTEMS GEMINI ARM ARCHITECTURE
-M:     Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+M:     Paulius Zaleckas <paulius.zaleckas@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 T:     git git://gitorious.org/linux-gemini/mainline.git
-S:     Maintained
+S:     Odd Fixes
 F:     arch/arm/mach-gemini/
 
 ARM/EBSA110 MACHINE SUPPORT
@@ -641,9 +641,9 @@ T:  topgit git://git.openezx.org/openezx.git
 F:     arch/arm/mach-pxa/ezx.c
 
 ARM/FARADAY FA526 PORT
-M:     Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+M:     Paulius Zaleckas <paulius.zaleckas@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Maintained
+S:     Odd Fixes
 F:     arch/arm/mm/*-fa*
 
 ARM/FOOTBRIDGE ARCHITECTURE
@@ -1733,10 +1733,9 @@ F:       include/linux/tfrc.h
 F:     net/dccp/
 
 DECnet NETWORK LAYER
-M:     Christine Caulfield <christine.caulfield@googlemail.com>
 W:     http://linux-decnet.sourceforge.net
 L:     linux-decnet-user@lists.sourceforge.net
-S:     Maintained
+S:     Orphan
 F:     Documentation/networking/decnet.txt
 F:     net/decnet/
 
@@ -2394,6 +2393,12 @@ L:       linuxppc-dev@ozlabs.org
 S:     Odd Fixes
 F:     drivers/char/hvc_*
 
+VIRTIO CONSOLE DRIVER
+M:     Amit Shah <amit.shah@redhat.com>
+L:     virtualization@lists.linux-foundation.org
+S:     Maintained
+F:     drivers/char/virtio_console.c
+
 GSPCA FINEPIX SUBDRIVER
 M:     Frank Zago <frank@zago.net>
 L:     linux-media@vger.kernel.org
@@ -3490,9 +3495,9 @@ S:        Maintained
 F:     drivers/net/wireless/libertas/
 
 MARVELL MV643XX ETHERNET DRIVER
-M:     Lennert Buytenhek <buytenh@marvell.com>
+M:     Lennert Buytenhek <buytenh@wantstofly.org>
 L:     netdev@vger.kernel.org
-S:     Supported
+S:     Maintained
 F:     drivers/net/mv643xx_eth.*
 F:     include/linux/mv643xx.h
 
index 12b1aa1..1b24895 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 33
-EXTRAVERSION = -rc8
+EXTRAVERSION =
 NAME = Man-Eating Seals of Antiquity
 
 # *DOCUMENTATION*
index c77d2fa..8113bb5 100644 (file)
@@ -42,7 +42,8 @@
 #endif
 
 #if defined(CONFIG_CPU_ARM920T) || defined(CONFIG_CPU_ARM922T) || \
-    defined(CONFIG_CPU_ARM925T) || defined(CONFIG_CPU_ARM1020)
+    defined(CONFIG_CPU_ARM925T) || defined(CONFIG_CPU_ARM1020) || \
+    defined(CONFIG_CPU_ARM1026)
 # define MULTI_CACHE 1
 #endif
 
index c6c57b6..621acad 100644 (file)
@@ -102,6 +102,7 @@ struct cpu_cache_fns cpu_cache;
 #endif
 #ifdef CONFIG_OUTER_CACHE
 struct outer_cache_fns outer_cache;
+EXPORT_SYMBOL(outer_cache);
 #endif
 
 struct stack {
index e726385..fe3bd5a 100644 (file)
@@ -86,7 +86,7 @@ static int gpio_set_irq_type(unsigned int irq, unsigned int type)
        unsigned int reg_both, reg_level, reg_type;
 
        reg_type = __raw_readl(base + GPIO_INT_TYPE);
-       reg_level = __raw_readl(base + GPIO_INT_BOTH_EDGE);
+       reg_level = __raw_readl(base + GPIO_INT_LEVEL);
        reg_both = __raw_readl(base + GPIO_INT_BOTH_EDGE);
 
        switch (type) {
@@ -117,7 +117,7 @@ static int gpio_set_irq_type(unsigned int irq, unsigned int type)
        }
 
        __raw_writel(reg_type, base + GPIO_INT_TYPE);
-       __raw_writel(reg_level, base + GPIO_INT_BOTH_EDGE);
+       __raw_writel(reg_level, base + GPIO_INT_LEVEL);
        __raw_writel(reg_both, base + GPIO_INT_BOTH_EDGE);
 
        gpio_ack_irq(irq);
index 5fedc50..5fef73f 100644 (file)
@@ -961,16 +961,14 @@ static void __init omap_mux_init_list(struct omap_mux *superset)
        while (superset->reg_offset !=  OMAP_MUX_TERMINATOR) {
                struct omap_mux *entry;
 
-#ifndef CONFIG_OMAP_MUX
-               /* Skip pins that are not muxed as GPIO by bootloader */
-               if (!OMAP_MODE_GPIO(omap_mux_read(superset->reg_offset))) {
+#ifdef CONFIG_OMAP_MUX
+               if (!superset->muxnames || !superset->muxnames[0]) {
                        superset++;
                        continue;
                }
-#endif
-
-#if defined(CONFIG_OMAP_MUX) && defined(CONFIG_DEBUG_FS)
-               if (!superset->muxnames || !superset->muxnames[0]) {
+#else
+               /* Skip pins that are not muxed as GPIO by bootloader */
+               if (!OMAP_MODE_GPIO(omap_mux_read(superset->reg_offset))) {
                        superset++;
                        continue;
                }
index b270d62..62820ed 100644 (file)
@@ -11,6 +11,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <linux/moduleparam.h>
 #include <linux/compiler.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -77,6 +78,8 @@ static unsigned long ai_dword;
 static unsigned long ai_multi;
 static int ai_usermode;
 
+core_param(alignment, ai_usermode, int, 0600);
+
 #define UM_WARN                (1 << 0)
 #define UM_FIXUP       (1 << 1)
 #define UM_SIGNAL      (1 << 2)
index 5a79fc6..31c2f4c 100644 (file)
@@ -12,7 +12,7 @@
 #
 #   http://www.arm.linux.org.uk/developer/machines/?action=new
 #
-# Last update: Thu Jan 28 22:15:54 2010
+# Last update: Sat Feb 20 14:16:15 2010
 #
 # machine_is_xxx       CONFIG_xxxx             MACH_TYPE_xxx           number
 #
@@ -2257,7 +2257,7 @@ oratisalog                MACH_ORATISALOG         ORATISALOG              2268
 oratismadi             MACH_ORATISMADI         ORATISMADI              2269
 oratisot16             MACH_ORATISOT16         ORATISOT16              2270
 oratisdesk             MACH_ORATISDESK         ORATISDESK              2271
-v2_ca9                 MACH_V2P_CA9            V2P_CA9                 2272
+vexpress               MACH_VEXPRESS           VEXPRESS                2272
 sintexo                        MACH_SINTEXO            SINTEXO                 2273
 cm3389                 MACH_CM3389             CM3389                  2274
 omap3_cio              MACH_OMAP3_CIO          OMAP3_CIO               2275
@@ -2636,3 +2636,45 @@ hw90240                  MACH_HW90240            HW90240                 2648
 dm365_leopard          MACH_DM365_LEOPARD      DM365_LEOPARD           2649
 mityomapl138           MACH_MITYOMAPL138       MITYOMAPL138            2650
 scat110                        MACH_SCAT110            SCAT110                 2651
+acer_a1                        MACH_ACER_A1            ACER_A1                 2652
+cmcontrol              MACH_CMCONTROL          CMCONTROL               2653
+pelco_lamar            MACH_PELCO_LAMAR        PELCO_LAMAR             2654
+rfp43                  MACH_RFP43              RFP43                   2655
+sk86r0301              MACH_SK86R0301          SK86R0301               2656
+ctpxa                  MACH_CTPXA              CTPXA                   2657
+epb_arm9_a             MACH_EPB_ARM9_A         EPB_ARM9_A              2658
+guruplug               MACH_GURUPLUG           GURUPLUG                2659
+spear310               MACH_SPEAR310           SPEAR310                2660
+spear320               MACH_SPEAR320           SPEAR320                2661
+robotx                 MACH_ROBOTX             ROBOTX                  2662
+lsxhl                  MACH_LSXHL              LSXHL                   2663
+smartlite              MACH_SMARTLITE          SMARTLITE               2664
+cws2                   MACH_CWS2               CWS2                    2665
+m619                   MACH_M619               M619                    2666
+smartview              MACH_SMARTVIEW          SMARTVIEW               2667
+lsa_salsa              MACH_LSA_SALSA          LSA_SALSA               2668
+kizbox                 MACH_KIZBOX             KIZBOX                  2669
+htccharmer             MACH_HTCCHARMER         HTCCHARMER              2670
+guf_neso_lt            MACH_GUF_NESO_LT        GUF_NESO_LT             2671
+pm9g45                 MACH_PM9G45             PM9G45                  2672
+htcpanther             MACH_HTCPANTHER         HTCPANTHER              2673
+htcpanther_cdma                MACH_HTCPANTHER_CDMA    HTCPANTHER_CDMA         2674
+reb01                  MACH_REB01              REB01                   2675
+aquila                 MACH_AQUILA             AQUILA                  2676
+spark_sls_hw2          MACH_SPARK_SLS_HW2      SPARK_SLS_HW2           2677
+sheeva_esata           MACH_ESATA_SHEEVAPLUG   ESATA_SHEEVAPLUG        2678
+surf7x30               MACH_SURF7X30           SURF7X30                2679
+micro2440              MACH_MICRO2440          MICRO2440               2680
+am2440                 MACH_AM2440             AM2440                  2681
+tq2440                 MACH_TQ2440             TQ2440                  2682
+lpc2478oem             MACH_LPC2478OEM         LPC2478OEM              2683
+ak880x                 MACH_AK880X             AK880X                  2684
+cobra3530              MACH_COBRA3530          COBRA3530               2685
+pmppb                  MACH_PMPPB              PMPPB                   2686
+u6715                  MACH_U6715              U6715                   2687
+axar1500_sender                MACH_AXAR1500_SENDER    AXAR1500_SENDER         2688
+g30_dvb                        MACH_G30_DVB            G30_DVB                 2689
+vc088x                 MACH_VC088X             VC088X                  2690
+mioa702                        MACH_MIOA702            MIOA702                 2691
+hpmin                  MACH_HPMIN              HPMIN                   2692
+ak880xak               MACH_AK880XAK           AK880XAK                2693
index 7ae5889..e97b255 100644 (file)
@@ -94,6 +94,7 @@ ia64_acpi_release_global_lock (unsigned int *lock)
 #define acpi_noirq 0   /* ACPI always enabled on IA64 */
 #define acpi_pci_disabled 0 /* ACPI PCI always enabled on IA64 */
 #define acpi_strict 1  /* no ACPI spec workarounds on IA64 */
+#define acpi_ht 0      /* no HT-only mode on IA64 */
 #endif
 #define acpi_processor_cstate_check(x) (x) /* no idle limits on IA64 :) */
 static inline void disable_acpi(void) { }
index ece1bf9..e456f06 100644 (file)
@@ -71,7 +71,7 @@ EXPORT_SYMBOL(sn_rtc_cycles_per_second);
 DEFINE_PER_CPU(struct sn_hub_info_s, __sn_hub_info);
 EXPORT_PER_CPU_SYMBOL(__sn_hub_info);
 
-DEFINE_PER_CPU(short [MAX_COMPACT_NODES], __sn_cnodeid_to_nasid);
+DEFINE_PER_CPU(short, __sn_cnodeid_to_nasid[MAX_COMPACT_NODES]);
 EXPORT_PER_CPU_SYMBOL(__sn_cnodeid_to_nasid);
 
 DEFINE_PER_CPU(struct nodepda_s *, __sn_nodepda);
index cd5837e..b008168 100644 (file)
@@ -130,6 +130,7 @@ config CMDLINE_FORCE
 
 config OF
        def_bool y
+       select OF_FLATTREE
 
 config PROC_DEVICETREE
        bool "Support for device tree in /proc"
index fc9997b..267c7c7 100644 (file)
@@ -217,7 +217,7 @@ static inline void __iomem *__ioremap(phys_addr_t address, unsigned long size,
  * Little endian
  */
 
-#define out_le32(a, v) __raw_writel(__cpu_to_le32(v), (a));
+#define out_le32(a, v) __raw_writel(__cpu_to_le32(v), (a))
 #define out_le16(a, v) __raw_writew(__cpu_to_le16(v), (a))
 
 #define in_le32(a) __le32_to_cpu(__raw_readl(a))
index ef3ec1d..03f45a9 100644 (file)
 #include <asm/irq.h>
 #include <asm/atomic.h>
 
-#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT        1
-#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT        1
-
-#define of_compat_cmp(s1, s2, l)       strncasecmp((s1), (s2), (l))
-#define of_prop_cmp(s1, s2)            strcmp((s1), (s2))
-#define of_node_cmp(s1, s2)            strcasecmp((s1), (s2))
-
-extern struct device_node *of_chosen;
-
 #define HAVE_ARCH_DEVTREE_FIXUPS
 
-extern struct device_node *allnodes;   /* temporary while merging */
-extern rwlock_t devtree_lock;  /* temporary while merging */
-
-/* For updating the device tree at runtime */
-extern void of_attach_node(struct device_node *);
-extern void of_detach_node(struct device_node *);
-
 /* Other Prototypes */
 extern int early_uartlite_console(void);
 
-extern struct resource *request_OF_resource(struct device_node *node,
-                               int index, const char *name_postfix);
-extern int release_OF_resource(struct device_node *node, int index);
-
 /*
  * OF address retreival & translation
  */
index d9d6383..2a56bcc 100644 (file)
@@ -172,16 +172,15 @@ do {                                                                      \
 /* It is used only first parameter for OP - for wic, wdc */
 #define CACHE_RANGE_LOOP_1(start, end, line_length, op)                        \
 do {                                                                   \
-       int step = -line_length;                                        \
-       int count = end - start;                                        \
-       BUG_ON(count <= 0);                                             \
+       int volatile temp;                                              \
+       BUG_ON(end - start <= 0);                                       \
                                                                        \
-       __asm__ __volatile__ (" 1:      addk    %0, %0, %1;             \
-                                       " #op " %0, r0;                 \
-                                       bgtid   %1, 1b;                 \
-                                       addk    %1, %1, %2;             \
-                                       " : : "r" (start), "r" (count), \
-                                       "r" (step) : "memory");         \
+       __asm__ __volatile__ (" 1:      " #op " %1, r0;                 \
+                                       cmpu    %0, %1, %2;             \
+                                       bgtid   %0, 1b;                 \
+                                       addk    %1, %1, %3;             \
+                               " : : "r" (temp), "r" (start), "r" (end),\
+                                       "r" (line_length) : "memory");  \
 } while (0);
 
 static void __flush_icache_range_msr_irq(unsigned long start, unsigned long end)
@@ -313,16 +312,6 @@ static void __invalidate_dcache_all_wb(void)
        pr_debug("%s\n", __func__);
        CACHE_ALL_LOOP2(cpuinfo.dcache_size, cpuinfo.dcache_line_length,
                                        wdc.clear)
-
-#if 0
-       unsigned int i;
-
-       pr_debug("%s\n", __func__);
-
-       /* Just loop through cache size and invalidate it */
-       for (i = 0; i < cpuinfo.dcache_size; i += cpuinfo.dcache_line_length)
-                       __invalidate_dcache(0, i);
-#endif
 }
 
 static void __invalidate_dcache_range_wb(unsigned long start,
index acf4574..1c6d684 100644 (file)
@@ -185,7 +185,7 @@ EXPORT_SYMBOL(of_find_device_by_node);
 static int of_dev_phandle_match(struct device *dev, void *data)
 {
        phandle *ph = data;
-       return to_of_device(dev)->node->linux_phandle == *ph;
+       return to_of_device(dev)->node->phandle == *ph;
 }
 
 struct of_device *of_find_device_by_phandle(phandle ph)
index b817df1..a15ef6d 100644 (file)
 #include <asm/sections.h>
 #include <asm/pci-bridge.h>
 
-static int __initdata dt_root_addr_cells;
-static int __initdata dt_root_size_cells;
-
-typedef u32 cell_t;
-
-static struct boot_param_header *initial_boot_params;
-
-/* export that to outside world */
-struct device_node *of_chosen;
-
-static inline char *find_flat_dt_string(u32 offset)
-{
-       return ((char *)initial_boot_params) +
-               initial_boot_params->off_dt_strings + offset;
-}
-
-/**
- * This function is used to scan the flattened device-tree, it is
- * used to extract the memory informations at boot before we can
- * unflatten the tree
- */
-int __init of_scan_flat_dt(int (*it)(unsigned long node,
-                                    const char *uname, int depth,
-                                    void *data),
-                          void *data)
-{
-       unsigned long p = ((unsigned long)initial_boot_params) +
-               initial_boot_params->off_dt_struct;
-       int rc = 0;
-       int depth = -1;
-
-       do {
-               u32 tag = *((u32 *)p);
-               char *pathp;
-
-               p += 4;
-               if (tag == OF_DT_END_NODE) {
-                       depth--;
-                       continue;
-               }
-               if (tag == OF_DT_NOP)
-                       continue;
-               if (tag == OF_DT_END)
-                       break;
-               if (tag == OF_DT_PROP) {
-                       u32 sz = *((u32 *)p);
-                       p += 8;
-                       if (initial_boot_params->version < 0x10)
-                               p = _ALIGN(p, sz >= 8 ? 8 : 4);
-                       p += sz;
-                       p = _ALIGN(p, 4);
-                       continue;
-               }
-               if (tag != OF_DT_BEGIN_NODE) {
-                       printk(KERN_WARNING "Invalid tag %x scanning flattened"
-                               " device tree !\n", tag);
-                       return -EINVAL;
-               }
-               depth++;
-               pathp = (char *)p;
-               p = _ALIGN(p + strlen(pathp) + 1, 4);
-               if ((*pathp) == '/') {
-                       char *lp, *np;
-                       for (lp = NULL, np = pathp; *np; np++)
-                               if ((*np) == '/')
-                                       lp = np+1;
-                       if (lp != NULL)
-                               pathp = lp;
-               }
-               rc = it(p, pathp, depth, data);
-               if (rc != 0)
-                       break;
-       } while (1);
-
-       return rc;
-}
-
-unsigned long __init of_get_flat_dt_root(void)
-{
-       unsigned long p = ((unsigned long)initial_boot_params) +
-               initial_boot_params->off_dt_struct;
-
-       while (*((u32 *)p) == OF_DT_NOP)
-               p += 4;
-       BUG_ON(*((u32 *)p) != OF_DT_BEGIN_NODE);
-       p += 4;
-       return _ALIGN(p + strlen((char *)p) + 1, 4);
-}
-
-/**
- * This function can be used within scan_flattened_dt callback to get
- * access to properties
- */
-void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
-                               unsigned long *size)
-{
-       unsigned long p = node;
-
-       do {
-               u32 tag = *((u32 *)p);
-               u32 sz, noff;
-               const char *nstr;
-
-               p += 4;
-               if (tag == OF_DT_NOP)
-                       continue;
-               if (tag != OF_DT_PROP)
-                       return NULL;
-
-               sz = *((u32 *)p);
-               noff = *((u32 *)(p + 4));
-               p += 8;
-               if (initial_boot_params->version < 0x10)
-                       p = _ALIGN(p, sz >= 8 ? 8 : 4);
-
-               nstr = find_flat_dt_string(noff);
-               if (nstr == NULL) {
-                       printk(KERN_WARNING "Can't find property index"
-                               " name !\n");
-                       return NULL;
-               }
-               if (strcmp(name, nstr) == 0) {
-                       if (size)
-                               *size = sz;
-                       return (void *)p;
-               }
-               p += sz;
-               p = _ALIGN(p, 4);
-       } while (1);
-}
-
-int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
-{
-       const char *cp;
-       unsigned long cplen, l;
-
-       cp = of_get_flat_dt_prop(node, "compatible", &cplen);
-       if (cp == NULL)
-               return 0;
-       while (cplen > 0) {
-               if (strncasecmp(cp, compat, strlen(compat)) == 0)
-                       return 1;
-               l = strlen(cp) + 1;
-               cp += l;
-               cplen -= l;
-       }
-
-       return 0;
-}
-
-static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
-                                       unsigned long align)
-{
-       void *res;
-
-       *mem = _ALIGN(*mem, align);
-       res = (void *)*mem;
-       *mem += size;
-
-       return res;
-}
-
-static unsigned long __init unflatten_dt_node(unsigned long mem,
-                                       unsigned long *p,
-                                       struct device_node *dad,
-                                       struct device_node ***allnextpp,
-                                       unsigned long fpsize)
-{
-       struct device_node *np;
-       struct property *pp, **prev_pp = NULL;
-       char *pathp;
-       u32 tag;
-       unsigned int l, allocl;
-       int has_name = 0;
-       int new_format = 0;
-
-       tag = *((u32 *)(*p));
-       if (tag != OF_DT_BEGIN_NODE) {
-               printk("Weird tag at start of node: %x\n", tag);
-               return mem;
-       }
-       *p += 4;
-       pathp = (char *)*p;
-       l = allocl = strlen(pathp) + 1;
-       *p = _ALIGN(*p + l, 4);
-
-       /* version 0x10 has a more compact unit name here instead of the full
-        * path. we accumulate the full path size using "fpsize", we'll rebuild
-        * it later. We detect this because the first character of the name is
-        * not '/'.
-        */
-       if ((*pathp) != '/') {
-               new_format = 1;
-               if (fpsize == 0) {
-                       /* root node: special case. fpsize accounts for path
-                        * plus terminating zero. root node only has '/', so
-                        * fpsize should be 2, but we want to avoid the first
-                        * level nodes to have two '/' so we use fpsize 1 here
-                        */
-                       fpsize = 1;
-                       allocl = 2;
-               } else {
-                       /* account for '/' and path size minus terminal 0
-                        * already in 'l'
-                        */
-                       fpsize += l;
-                       allocl = fpsize;
-               }
-       }
-
-       np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
-                               __alignof__(struct device_node));
-       if (allnextpp) {
-               memset(np, 0, sizeof(*np));
-               np->full_name = ((char *)np) + sizeof(struct device_node);
-               if (new_format) {
-                       char *p2 = np->full_name;
-                       /* rebuild full path for new format */
-                       if (dad && dad->parent) {
-                               strcpy(p2, dad->full_name);
-#ifdef DEBUG
-                               if ((strlen(p2) + l + 1) != allocl) {
-                                       pr_debug("%s: p: %d, l: %d, a: %d\n",
-                                               pathp, (int)strlen(p2),
-                                               l, allocl);
-                               }
-#endif
-                               p2 += strlen(p2);
-                       }
-                       *(p2++) = '/';
-                       memcpy(p2, pathp, l);
-               } else
-                       memcpy(np->full_name, pathp, l);
-               prev_pp = &np->properties;
-               **allnextpp = np;
-               *allnextpp = &np->allnext;
-               if (dad != NULL) {
-                       np->parent = dad;
-                       /* we temporarily use the next field as `last_child'*/
-                       if (dad->next == NULL)
-                               dad->child = np;
-                       else
-                               dad->next->sibling = np;
-                       dad->next = np;
-               }
-               kref_init(&np->kref);
-       }
-       while (1) {
-               u32 sz, noff;
-               char *pname;
-
-               tag = *((u32 *)(*p));
-               if (tag == OF_DT_NOP) {
-                       *p += 4;
-                       continue;
-               }
-               if (tag != OF_DT_PROP)
-                       break;
-               *p += 4;
-               sz = *((u32 *)(*p));
-               noff = *((u32 *)((*p) + 4));
-               *p += 8;
-               if (initial_boot_params->version < 0x10)
-                       *p = _ALIGN(*p, sz >= 8 ? 8 : 4);
-
-               pname = find_flat_dt_string(noff);
-               if (pname == NULL) {
-                       printk(KERN_INFO
-                               "Can't find property name in list !\n");
-                       break;
-               }
-               if (strcmp(pname, "name") == 0)
-                       has_name = 1;
-               l = strlen(pname) + 1;
-               pp = unflatten_dt_alloc(&mem, sizeof(struct property),
-                                       __alignof__(struct property));
-               if (allnextpp) {
-                       if (strcmp(pname, "linux,phandle") == 0) {
-                               np->node = *((u32 *)*p);
-                               if (np->linux_phandle == 0)
-                                       np->linux_phandle = np->node;
-                       }
-                       if (strcmp(pname, "ibm,phandle") == 0)
-                               np->linux_phandle = *((u32 *)*p);
-                       pp->name = pname;
-                       pp->length = sz;
-                       pp->value = (void *)*p;
-                       *prev_pp = pp;
-                       prev_pp = &pp->next;
-               }
-               *p = _ALIGN((*p) + sz, 4);
-       }
-       /* with version 0x10 we may not have the name property, recreate
-        * it here from the unit name if absent
-        */
-       if (!has_name) {
-               char *p1 = pathp, *ps = pathp, *pa = NULL;
-               int sz;
-
-               while (*p1) {
-                       if ((*p1) == '@')
-                               pa = p1;
-                       if ((*p1) == '/')
-                               ps = p1 + 1;
-                       p1++;
-               }
-               if (pa < ps)
-                       pa = p1;
-               sz = (pa - ps) + 1;
-               pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
-                                       __alignof__(struct property));
-               if (allnextpp) {
-                       pp->name = "name";
-                       pp->length = sz;
-                       pp->value = pp + 1;
-                       *prev_pp = pp;
-                       prev_pp = &pp->next;
-                       memcpy(pp->value, ps, sz - 1);
-                       ((char *)pp->value)[sz - 1] = 0;
-                       pr_debug("fixed up name for %s -> %s\n", pathp,
-                               (char *)pp->value);
-               }
-       }
-       if (allnextpp) {
-               *prev_pp = NULL;
-               np->name = of_get_property(np, "name", NULL);
-               np->type = of_get_property(np, "device_type", NULL);
-
-               if (!np->name)
-                       np->name = "<NULL>";
-               if (!np->type)
-                       np->type = "<NULL>";
-       }
-       while (tag == OF_DT_BEGIN_NODE) {
-               mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize);
-               tag = *((u32 *)(*p));
-       }
-       if (tag != OF_DT_END_NODE) {
-               printk(KERN_INFO "Weird tag at end of node: %x\n", tag);
-               return mem;
-       }
-       *p += 4;
-       return mem;
-}
-
-/**
- * unflattens the device-tree passed by the firmware, creating the
- * tree of struct device_node. It also fills the "name" and "type"
- * pointers of the nodes so the normal device-tree walking functions
- * can be used (this used to be done by finish_device_tree)
- */
-void __init unflatten_device_tree(void)
-{
-       unsigned long start, mem, size;
-       struct device_node **allnextp = &allnodes;
-
-       pr_debug(" -> unflatten_device_tree()\n");
-
-       /* First pass, scan for size */
-       start = ((unsigned long)initial_boot_params) +
-               initial_boot_params->off_dt_struct;
-       size = unflatten_dt_node(0, &start, NULL, NULL, 0);
-       size = (size | 3) + 1;
-
-       pr_debug("  size is %lx, allocating...\n", size);
-
-       /* Allocate memory for the expanded device tree */
-       mem = lmb_alloc(size + 4, __alignof__(struct device_node));
-       mem = (unsigned long) __va(mem);
-
-       ((u32 *)mem)[size / 4] = 0xdeadbeef;
-
-       pr_debug("  unflattening %lx...\n", mem);
-
-       /* Second pass, do actual unflattening */
-       start = ((unsigned long)initial_boot_params) +
-               initial_boot_params->off_dt_struct;
-       unflatten_dt_node(mem, &start, NULL, &allnextp, 0);
-       if (*((u32 *)start) != OF_DT_END)
-               printk(KERN_WARNING "Weird tag at end of tree: %08x\n",
-                       *((u32 *)start));
-       if (((u32 *)mem)[size / 4] != 0xdeadbeef)
-               printk(KERN_WARNING "End of tree marker overwritten: %08x\n",
-                       ((u32 *)mem)[size / 4]);
-       *allnextp = NULL;
-
-       /* Get pointer to OF "/chosen" node for use everywhere */
-       of_chosen = of_find_node_by_path("/chosen");
-       if (of_chosen == NULL)
-               of_chosen = of_find_node_by_path("/chosen@0");
-
-       pr_debug(" <- unflatten_device_tree()\n");
-}
-
-#define early_init_dt_scan_drconf_memory(node) 0
-
-static int __init early_init_dt_scan_cpus(unsigned long node,
-                                         const char *uname, int depth,
-                                         void *data)
-{
-       static int logical_cpuid;
-       char *type = of_get_flat_dt_prop(node, "device_type", NULL);
-       const u32 *intserv;
-       int i, nthreads;
-       int found = 0;
-
-       /* We are scanning "cpu" nodes only */
-       if (type == NULL || strcmp(type, "cpu") != 0)
-               return 0;
-
-       /* Get physical cpuid */
-       intserv = of_get_flat_dt_prop(node, "reg", NULL);
-       nthreads = 1;
-
-       /*
-        * Now see if any of these threads match our boot cpu.
-        * NOTE: This must match the parsing done in smp_setup_cpu_maps.
-        */
-       for (i = 0; i < nthreads; i++) {
-               /*
-                * version 2 of the kexec param format adds the phys cpuid of
-                * booted proc.
-                */
-               if (initial_boot_params && initial_boot_params->version >= 2) {
-                       if (intserv[i] ==
-                                       initial_boot_params->boot_cpuid_phys) {
-                               found = 1;
-                               break;
-                       }
-               } else {
-                       /*
-                        * Check if it's the boot-cpu, set it's hw index now,
-                        * unfortunately this format did not support booting
-                        * off secondary threads.
-                        */
-                       if (of_get_flat_dt_prop(node,
-                                       "linux,boot-cpu", NULL) != NULL) {
-                               found = 1;
-                               break;
-                       }
-               }
-
-#ifdef CONFIG_SMP
-               /* logical cpu id is always 0 on UP kernels */
-               logical_cpuid++;
-#endif
-       }
-
-       if (found) {
-               pr_debug("boot cpu: logical %d physical %d\n", logical_cpuid,
-                       intserv[i]);
-               boot_cpuid = logical_cpuid;
-       }
-
-       return 0;
-}
-
-#ifdef CONFIG_BLK_DEV_INITRD
-static void __init early_init_dt_check_for_initrd(unsigned long node)
-{
-       unsigned long l;
-       u32 *prop;
-
-       pr_debug("Looking for initrd properties... ");
-
-       prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l);
-       if (prop) {
-               initrd_start = (unsigned long)
-                                       __va((u32)of_read_ulong(prop, l/4));
-
-               prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l);
-               if (prop) {
-                       initrd_end = (unsigned long)
-                                       __va((u32)of_read_ulong(prop, 1/4));
-                       initrd_below_start_ok = 1;
-               } else {
-                       initrd_start = 0;
-               }
-       }
-
-       pr_debug("initrd_start=0x%lx  initrd_end=0x%lx\n",
-                                       initrd_start, initrd_end);
-}
-#else
-static inline void early_init_dt_check_for_initrd(unsigned long node)
-{
-}
-#endif /* CONFIG_BLK_DEV_INITRD */
-
-static int __init early_init_dt_scan_chosen(unsigned long node,
-                               const char *uname, int depth, void *data)
-{
-       unsigned long l;
-       char *p;
-
-       pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
-
-       if (depth != 1 ||
-               (strcmp(uname, "chosen") != 0 &&
-                               strcmp(uname, "chosen@0") != 0))
-               return 0;
-
-#ifdef CONFIG_KEXEC
-       lprop = (u64 *)of_get_flat_dt_prop(node,
-                               "linux,crashkernel-base", NULL);
-       if (lprop)
-               crashk_res.start = *lprop;
-
-       lprop = (u64 *)of_get_flat_dt_prop(node,
-                               "linux,crashkernel-size", NULL);
-       if (lprop)
-               crashk_res.end = crashk_res.start + *lprop - 1;
-#endif
-
-       early_init_dt_check_for_initrd(node);
-
-       /* Retreive command line */
-       p = of_get_flat_dt_prop(node, "bootargs", &l);
-       if (p != NULL && l > 0)
-               strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE));
-
-#ifdef CONFIG_CMDLINE
-#ifndef CONFIG_CMDLINE_FORCE
-       if (p == NULL || l == 0 || (l == 1 && (*p) == 0))
-#endif
-               strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
-#endif /* CONFIG_CMDLINE */
-
-       pr_debug("Command line is: %s\n", cmd_line);
-
-       /* break now */
-       return 1;
-}
-
-static int __init early_init_dt_scan_root(unsigned long node,
-                               const char *uname, int depth, void *data)
-{
-       u32 *prop;
-
-       if (depth != 0)
-               return 0;
-
-       prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
-       dt_root_size_cells = (prop == NULL) ? 1 : *prop;
-       pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells);
-
-       prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
-       dt_root_addr_cells = (prop == NULL) ? 2 : *prop;
-       pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells);
-
-       /* break now */
-       return 1;
-}
-
-static u64 __init dt_mem_next_cell(int s, cell_t **cellp)
+void __init early_init_dt_scan_chosen_arch(unsigned long node)
 {
-       cell_t *p = *cellp;
-
-       *cellp = p + s;
-       return of_read_number(p, s);
+       /* No Microblaze specific code here */
 }
 
-static int __init early_init_dt_scan_memory(unsigned long node,
-                               const char *uname, int depth, void *data)
+void __init early_init_dt_add_memory_arch(u64 base, u64 size)
 {
-       char *type = of_get_flat_dt_prop(node, "device_type", NULL);
-       cell_t *reg, *endp;
-       unsigned long l;
-
-       /* Look for the ibm,dynamic-reconfiguration-memory node */
-/*     if (depth == 1 &&
-               strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0)
-               return early_init_dt_scan_drconf_memory(node);
-*/
-       /* We are scanning "memory" nodes only */
-       if (type == NULL) {
-               /*
-                * The longtrail doesn't have a device_type on the
-                * /memory node, so look for the node called /memory@0.
-                */
-               if (depth != 1 || strcmp(uname, "memory@0") != 0)
-                       return 0;
-       } else if (strcmp(type, "memory") != 0)
-               return 0;
-
-       reg = (cell_t *)of_get_flat_dt_prop(node, "linux,usable-memory", &l);
-       if (reg == NULL)
-               reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l);
-       if (reg == NULL)
-               return 0;
-
-       endp = reg + (l / sizeof(cell_t));
-
-       pr_debug("memory scan node %s, reg size %ld, data: %x %x %x %x,\n",
-               uname, l, reg[0], reg[1], reg[2], reg[3]);
-
-       while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
-               u64 base, size;
-
-               base = dt_mem_next_cell(dt_root_addr_cells, &reg);
-               size = dt_mem_next_cell(dt_root_size_cells, &reg);
-
-               if (size == 0)
-                       continue;
-               pr_debug(" - %llx ,  %llx\n", (unsigned long long)base,
-                       (unsigned long long)size);
-
-               lmb_add(base, size);
-       }
-       return 0;
+       lmb_add(base, size);
 }
 
-#ifdef CONFIG_PHYP_DUMP
-/**
- * phyp_dump_calculate_reserve_size() - reserve variable boot area 5% or arg
- *
- * Function to find the largest size we need to reserve
- * during early boot process.
- *
- * It either looks for boot param and returns that OR
- * returns larger of 256 or 5% rounded down to multiples of 256MB.
- *
- */
-static inline unsigned long phyp_dump_calculate_reserve_size(void)
+u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
 {
-       unsigned long tmp;
-
-       if (phyp_dump_info->reserve_bootvar)
-               return phyp_dump_info->reserve_bootvar;
-
-       /* divide by 20 to get 5% of value */
-       tmp = lmb_end_of_DRAM();
-       do_div(tmp, 20);
-
-       /* round it down in multiples of 256 */
-       tmp = tmp & ~0x0FFFFFFFUL;
-
-       return (tmp > PHYP_DUMP_RMR_END ? tmp : PHYP_DUMP_RMR_END);
+       return lmb_alloc(size, align);
 }
 
-/**
- * phyp_dump_reserve_mem() - reserve all not-yet-dumped mmemory
- *
- * This routine may reserve memory regions in the kernel only
- * if the system is supported and a dump was taken in last
- * boot instance or if the hardware is supported and the
- * scratch area needs to be setup. In other instances it returns
- * without reserving anything. The memory in case of dump being
- * active is freed when the dump is collected (by userland tools).
- */
-static void __init phyp_dump_reserve_mem(void)
-{
-       unsigned long base, size;
-       unsigned long variable_reserve_size;
-
-       if (!phyp_dump_info->phyp_dump_configured) {
-               printk(KERN_ERR "Phyp-dump not supported on this hardware\n");
-               return;
-       }
-
-       if (!phyp_dump_info->phyp_dump_at_boot) {
-               printk(KERN_INFO "Phyp-dump disabled at boot time\n");
-               return;
-       }
-
-       variable_reserve_size = phyp_dump_calculate_reserve_size();
-
-       if (phyp_dump_info->phyp_dump_is_active) {
-               /* Reserve *everything* above RMR.Area freed by userland tools*/
-               base = variable_reserve_size;
-               size = lmb_end_of_DRAM() - base;
-
-               /* XXX crashed_ram_end is wrong, since it may be beyond
-                * the memory_limit, it will need to be adjusted. */
-               lmb_reserve(base, size);
-
-               phyp_dump_info->init_reserve_start = base;
-               phyp_dump_info->init_reserve_size = size;
-       } else {
-               size = phyp_dump_info->cpu_state_size +
-                       phyp_dump_info->hpte_region_size +
-                       variable_reserve_size;
-               base = lmb_end_of_DRAM() - size;
-               lmb_reserve(base, size);
-               phyp_dump_info->init_reserve_start = base;
-               phyp_dump_info->init_reserve_size = size;
-       }
-}
-#else
-static inline void __init phyp_dump_reserve_mem(void) {}
-#endif /* CONFIG_PHYP_DUMP  && CONFIG_PPC_RTAS */
-
 #ifdef CONFIG_EARLY_PRINTK
 /* MS this is Microblaze specifig function */
 static int __init early_init_dt_scan_serial(unsigned long node,
@@ -775,11 +98,6 @@ void __init early_init_devtree(void *params)
        /* Setup flat device-tree pointer */
        initial_boot_params = params;
 
-#ifdef CONFIG_PHYP_DUMP
-       /* scan tree to see if dump occured during last boot */
-       of_scan_flat_dt(early_init_dt_scan_phyp_dump, NULL);
-#endif
-
        /* Retrieve various informations from the /chosen node of the
         * device-tree, including the platform type, initrd location and
         * size, TCE reserve, and more ...
@@ -799,33 +117,18 @@ void __init early_init_devtree(void *params)
 
        pr_debug("Phys. mem: %lx\n", (unsigned long) lmb_phys_mem_size());
 
-       pr_debug("Scanning CPUs ...\n");
-
-       /* Retreive CPU related informations from the flat tree
-        * (altivec support, boot CPU ID, ...)
-        */
-       of_scan_flat_dt(early_init_dt_scan_cpus, NULL);
-
        pr_debug(" <- early_init_devtree()\n");
 }
 
-/**
- * Indicates whether the root node has a given value in its
- * compatible property.
- */
-int machine_is_compatible(const char *compat)
+#ifdef CONFIG_BLK_DEV_INITRD
+void __init early_init_dt_setup_initrd_arch(unsigned long start,
+               unsigned long end)
 {
-       struct device_node *root;
-       int rc = 0;
-
-       root = of_find_node_by_path("/");
-       if (root) {
-               rc = of_device_is_compatible(root, compat);
-               of_node_put(root);
-       }
-       return rc;
+       initrd_start = (unsigned long)__va(start);
+       initrd_end = (unsigned long)__va(end);
+       initrd_below_start_ok = 1;
 }
-EXPORT_SYMBOL(machine_is_compatible);
+#endif
 
 /*******
  *
@@ -838,273 +141,6 @@ EXPORT_SYMBOL(machine_is_compatible);
  *
  *******/
 
-/**
- *     of_find_node_by_phandle - Find a node given a phandle
- *     @handle:        phandle of the node to find
- *
- *     Returns a node pointer with refcount incremented, use
- *     of_node_put() on it when done.
- */
-struct device_node *of_find_node_by_phandle(phandle handle)
-{
-       struct device_node *np;
-
-       read_lock(&devtree_lock);
-       for (np = allnodes; np != NULL; np = np->allnext)
-               if (np->linux_phandle == handle)
-                       break;
-       of_node_get(np);
-       read_unlock(&devtree_lock);
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_phandle);
-
-/**
- *     of_node_get - Increment refcount of a node
- *     @node:  Node to inc refcount, NULL is supported to
- *             simplify writing of callers
- *
- *     Returns node.
- */
-struct device_node *of_node_get(struct device_node *node)
-{
-       if (node)
-               kref_get(&node->kref);
-       return node;
-}
-EXPORT_SYMBOL(of_node_get);
-
-static inline struct device_node *kref_to_device_node(struct kref *kref)
-{
-       return container_of(kref, struct device_node, kref);
-}
-
-/**
- *     of_node_release - release a dynamically allocated node
- *     @kref:  kref element of the node to be released
- *
- *     In of_node_put() this function is passed to kref_put()
- *     as the destructor.
- */
-static void of_node_release(struct kref *kref)
-{
-       struct device_node *node = kref_to_device_node(kref);
-       struct property *prop = node->properties;
-
-       /* We should never be releasing nodes that haven't been detached. */
-       if (!of_node_check_flag(node, OF_DETACHED)) {
-               printk(KERN_INFO "WARNING: Bad of_node_put() on %s\n",
-                       node->full_name);
-               dump_stack();
-               kref_init(&node->kref);
-               return;
-       }
-
-       if (!of_node_check_flag(node, OF_DYNAMIC))
-               return;
-
-       while (prop) {
-               struct property *next = prop->next;
-               kfree(prop->name);
-               kfree(prop->value);
-               kfree(prop);
-               prop = next;
-
-               if (!prop) {
-                       prop = node->deadprops;
-                       node->deadprops = NULL;
-               }
-       }
-       kfree(node->full_name);
-       kfree(node->data);
-       kfree(node);
-}
-
-/**
- *     of_node_put - Decrement refcount of a node
- *     @node:  Node to dec refcount, NULL is supported to
- *             simplify writing of callers
- *
- */
-void of_node_put(struct device_node *node)
-{
-       if (node)
-               kref_put(&node->kref, of_node_release);
-}
-EXPORT_SYMBOL(of_node_put);
-
-/*
- * Plug a device node into the tree and global list.
- */
-void of_attach_node(struct device_node *np)
-{
-       unsigned long flags;
-
-       write_lock_irqsave(&devtree_lock, flags);
-       np->sibling = np->parent->child;
-       np->allnext = allnodes;
-       np->parent->child = np;
-       allnodes = np;
-       write_unlock_irqrestore(&devtree_lock, flags);
-}
-
-/*
- * "Unplug" a node from the device tree.  The caller must hold
- * a reference to the node.  The memory associated with the node
- * is not freed until its refcount goes to zero.
- */
-void of_detach_node(struct device_node *np)
-{
-       struct device_node *parent;
-       unsigned long flags;
-
-       write_lock_irqsave(&devtree_lock, flags);
-
-       parent = np->parent;
-       if (!parent)
-               goto out_unlock;
-
-       if (allnodes == np)
-               allnodes = np->allnext;
-       else {
-               struct device_node *prev;
-               for (prev = allnodes;
-                    prev->allnext != np;
-                    prev = prev->allnext)
-                       ;
-               prev->allnext = np->allnext;
-       }
-
-       if (parent->child == np)
-               parent->child = np->sibling;
-       else {
-               struct device_node *prevsib;
-               for (prevsib = np->parent->child;
-                    prevsib->sibling != np;
-                    prevsib = prevsib->sibling)
-                       ;
-               prevsib->sibling = np->sibling;
-       }
-
-       of_node_set_flag(np, OF_DETACHED);
-
-out_unlock:
-       write_unlock_irqrestore(&devtree_lock, flags);
-}
-
-/*
- * Add a property to a node
- */
-int prom_add_property(struct device_node *np, struct property *prop)
-{
-       struct property **next;
-       unsigned long flags;
-
-       prop->next = NULL;
-       write_lock_irqsave(&devtree_lock, flags);
-       next = &np->properties;
-       while (*next) {
-               if (strcmp(prop->name, (*next)->name) == 0) {
-                       /* duplicate ! don't insert it */
-                       write_unlock_irqrestore(&devtree_lock, flags);
-                       return -1;
-               }
-               next = &(*next)->next;
-       }
-       *next = prop;
-       write_unlock_irqrestore(&devtree_lock, flags);
-
-#ifdef CONFIG_PROC_DEVICETREE
-       /* try to add to proc as well if it was initialized */
-       if (np->pde)
-               proc_device_tree_add_prop(np->pde, prop);
-#endif /* CONFIG_PROC_DEVICETREE */
-
-       return 0;
-}
-
-/*
- * Remove a property from a node.  Note that we don't actually
- * remove it, since we have given out who-knows-how-many pointers
- * to the data using get-property.  Instead we just move the property
- * to the "dead properties" list, so it won't be found any more.
- */
-int prom_remove_property(struct device_node *np, struct property *prop)
-{
-       struct property **next;
-       unsigned long flags;
-       int found = 0;
-
-       write_lock_irqsave(&devtree_lock, flags);
-       next = &np->properties;
-       while (*next) {
-               if (*next == prop) {
-                       /* found the node */
-                       *next = prop->next;
-                       prop->next = np->deadprops;
-                       np->deadprops = prop;
-                       found = 1;
-                       break;
-               }
-               next = &(*next)->next;
-       }
-       write_unlock_irqrestore(&devtree_lock, flags);
-
-       if (!found)
-               return -ENODEV;
-
-#ifdef CONFIG_PROC_DEVICETREE
-       /* try to remove the proc node as well */
-       if (np->pde)
-               proc_device_tree_remove_prop(np->pde, prop);
-#endif /* CONFIG_PROC_DEVICETREE */
-
-       return 0;
-}
-
-/*
- * Update a property in a node.  Note that we don't actually
- * remove it, since we have given out who-knows-how-many pointers
- * to the data using get-property.  Instead we just move the property
- * to the "dead properties" list, and add the new property to the
- * property list
- */
-int prom_update_property(struct device_node *np,
-                        struct property *newprop,
-                        struct property *oldprop)
-{
-       struct property **next;
-       unsigned long flags;
-       int found = 0;
-
-       write_lock_irqsave(&devtree_lock, flags);
-       next = &np->properties;
-       while (*next) {
-               if (*next == oldprop) {
-                       /* found the node */
-                       newprop->next = oldprop->next;
-                       *next = newprop;
-                       oldprop->next = np->deadprops;
-                       np->deadprops = oldprop;
-                       found = 1;
-                       break;
-               }
-               next = &(*next)->next;
-       }
-       write_unlock_irqrestore(&devtree_lock, flags);
-
-       if (!found)
-               return -ENODEV;
-
-#ifdef CONFIG_PROC_DEVICETREE
-       /* try to add to proc as well if it was initialized */
-       if (np->pde)
-               proc_device_tree_update_prop(np->pde, newprop, oldprop);
-#endif /* CONFIG_PROC_DEVICETREE */
-
-       return 0;
-}
-
 #if defined(CONFIG_DEBUG_FS) && defined(DEBUG)
 static struct debugfs_blob_wrapper flat_dt_blob;
 
index c51405e..29d3cbf 100644 (file)
@@ -141,6 +141,14 @@ static __init void prom_init_mem(void)
                        break;
        }
 
+       /* Ignoring the last page when ddr size is 128M. Cached
+        * accesses to last page is causing the processor to prefetch
+        * using address above 128M stepping out of the ddr address
+        * space.
+        */
+       if (mem == 0x8000000)
+               mem -= 0x1000;
+
        add_memory_region(0, mem, BOOT_MEM_RAM);
 }
 
index e274fda..127d732 100644 (file)
@@ -1,5 +1,6 @@
 #include <linux/module.h>
 #include <linux/highmem.h>
+#include <linux/sched.h>
 #include <linux/smp.h>
 #include <asm/fixmap.h>
 #include <asm/tlbflush.h>
index 524d935..f388dc6 100644 (file)
@@ -18,7 +18,6 @@ config PARISC
        select BUG
        select HAVE_PERF_EVENTS
        select GENERIC_ATOMIC64 if !64BIT
-       select HAVE_ARCH_TRACEHOOK
        help
          The PA-RISC microprocessor is designed by Hewlett-Packard and used
          in many of their workstations & servers (HP9000 700 and 800 series,
index f7064ab..9e74bfe 100644 (file)
@@ -18,7 +18,6 @@
 
 #include <asm/io.h>
 #include <asm/system.h>
-#include <asm/cache.h>         /* for L1_CACHE_BYTES */
 #include <asm/superio.h>
 
 #define DEBUG_RESOURCES 0
@@ -123,6 +122,10 @@ static int __init pcibios_init(void)
        } else {
                printk(KERN_WARNING "pci_bios != NULL but init() is!\n");
        }
+
+       /* Set the CLS for PCI as early as possible. */
+       pci_cache_line_size = pci_dfl_cache_line_size;
+
        return 0;
 }
 
@@ -171,7 +174,7 @@ void pcibios_set_master(struct pci_dev *dev)
        ** upper byte is PCI_LATENCY_TIMER.
        */
        pci_write_config_word(dev, PCI_CACHE_LINE_SIZE,
-                               (0x80 << 8) | (L1_CACHE_BYTES / sizeof(u32)));
+                             (0x80 << 8) | pci_cache_line_size);
 }
 
 
index 654bba5..155d571 100644 (file)
@@ -173,6 +173,7 @@ config PPC_OF
 
 config OF
        def_bool y
+       select OF_FLATTREE
 
 config PPC_UDBG_16550
        bool
index 2ab9cbd..ddd408a 100644 (file)
 #include <asm/irq.h>
 #include <asm/atomic.h>
 
-#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT        1
-#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT        1
-
-#define of_compat_cmp(s1, s2, l)       strcasecmp((s1), (s2))
-#define of_prop_cmp(s1, s2)            strcmp((s1), (s2))
-#define of_node_cmp(s1, s2)            strcasecmp((s1), (s2))
-
-extern struct device_node *of_chosen;
-
 #define HAVE_ARCH_DEVTREE_FIXUPS
 
-/* For updating the device tree at runtime */
-extern void of_attach_node(struct device_node *);
-extern void of_detach_node(struct device_node *);
-
 #ifdef CONFIG_PPC32
 /*
  * PCI <-> OF matching functions
@@ -52,11 +39,6 @@ extern struct device_node* pci_device_to_OF_node(struct pci_dev *);
 extern void pci_create_OF_bus_map(void);
 #endif
 
-extern struct resource *request_OF_resource(struct device_node* node,
-                               int index, const char* name_postfix);
-extern int release_OF_resource(struct device_node* node, int index);
-
-
 /*
  * OF address retreival & translation
  */
index 1a4fc0d..666d08d 100644 (file)
@@ -214,7 +214,7 @@ EXPORT_SYMBOL(of_find_device_by_node);
 static int of_dev_phandle_match(struct device *dev, void *data)
 {
        phandle *ph = data;
-       return to_of_device(dev)->node->linux_phandle == *ph;
+       return to_of_device(dev)->node->phandle == *ph;
 }
 
 struct of_device *of_find_device_by_phandle(phandle ph)
index ccf56ac..d43fc65 100644 (file)
@@ -224,7 +224,7 @@ long sys_pciconfig_iobase(long which, unsigned long in_bus,
         * G5 machines... So when something asks for bus 0 io base
         * (bus 0 is HT root), we return the AGP one instead.
         */
-       if (in_bus == 0 && machine_is_compatible("MacRISC4")) {
+       if (in_bus == 0 && of_machine_is_compatible("MacRISC4")) {
                struct device_node *agp;
 
                agp = of_find_compatible_node(NULL, NULL, "u3-agp");
index 4ec3008..43238b2 100644 (file)
 #define DBG(fmt...)
 #endif
 
-
-static int __initdata dt_root_addr_cells;
-static int __initdata dt_root_size_cells;
-
 #ifdef CONFIG_PPC64
 int __initdata iommu_is_off;
 int __initdata iommu_force_on;
 unsigned long tce_alloc_start, tce_alloc_end;
 #endif
 
-typedef u32 cell_t;
-
-#if 0
-static struct boot_param_header *initial_boot_params __initdata;
-#else
-struct boot_param_header *initial_boot_params;
-#endif
-
-extern struct device_node *allnodes;   /* temporary while merging */
-
-extern rwlock_t devtree_lock;  /* temporary while merging */
-
-/* export that to outside world */
-struct device_node *of_chosen;
-
-static inline char *find_flat_dt_string(u32 offset)
-{
-       return ((char *)initial_boot_params) +
-               initial_boot_params->off_dt_strings + offset;
-}
-
-/**
- * This function is used to scan the flattened device-tree, it is
- * used to extract the memory informations at boot before we can
- * unflatten the tree
- */
-int __init of_scan_flat_dt(int (*it)(unsigned long node,
-                                    const char *uname, int depth,
-                                    void *data),
-                          void *data)
-{
-       unsigned long p = ((unsigned long)initial_boot_params) +
-               initial_boot_params->off_dt_struct;
-       int rc = 0;
-       int depth = -1;
-
-       do {
-               u32 tag = *((u32 *)p);
-               char *pathp;
-               
-               p += 4;
-               if (tag == OF_DT_END_NODE) {
-                       depth --;
-                       continue;
-               }
-               if (tag == OF_DT_NOP)
-                       continue;
-               if (tag == OF_DT_END)
-                       break;
-               if (tag == OF_DT_PROP) {
-                       u32 sz = *((u32 *)p);
-                       p += 8;
-                       if (initial_boot_params->version < 0x10)
-                               p = _ALIGN(p, sz >= 8 ? 8 : 4);
-                       p += sz;
-                       p = _ALIGN(p, 4);
-                       continue;
-               }
-               if (tag != OF_DT_BEGIN_NODE) {
-                       printk(KERN_WARNING "Invalid tag %x scanning flattened"
-                              " device tree !\n", tag);
-                       return -EINVAL;
-               }
-               depth++;
-               pathp = (char *)p;
-               p = _ALIGN(p + strlen(pathp) + 1, 4);
-               if ((*pathp) == '/') {
-                       char *lp, *np;
-                       for (lp = NULL, np = pathp; *np; np++)
-                               if ((*np) == '/')
-                                       lp = np+1;
-                       if (lp != NULL)
-                               pathp = lp;
-               }
-               rc = it(p, pathp, depth, data);
-               if (rc != 0)
-                       break;          
-       } while(1);
-
-       return rc;
-}
-
-unsigned long __init of_get_flat_dt_root(void)
-{
-       unsigned long p = ((unsigned long)initial_boot_params) +
-               initial_boot_params->off_dt_struct;
-
-       while(*((u32 *)p) == OF_DT_NOP)
-               p += 4;
-       BUG_ON (*((u32 *)p) != OF_DT_BEGIN_NODE);
-       p += 4;
-       return _ALIGN(p + strlen((char *)p) + 1, 4);
-}
-
-/**
- * This  function can be used within scan_flattened_dt callback to get
- * access to properties
- */
-void* __init of_get_flat_dt_prop(unsigned long node, const char *name,
-                                unsigned long *size)
-{
-       unsigned long p = node;
-
-       do {
-               u32 tag = *((u32 *)p);
-               u32 sz, noff;
-               const char *nstr;
-
-               p += 4;
-               if (tag == OF_DT_NOP)
-                       continue;
-               if (tag != OF_DT_PROP)
-                       return NULL;
-
-               sz = *((u32 *)p);
-               noff = *((u32 *)(p + 4));
-               p += 8;
-               if (initial_boot_params->version < 0x10)
-                       p = _ALIGN(p, sz >= 8 ? 8 : 4);
-
-               nstr = find_flat_dt_string(noff);
-               if (nstr == NULL) {
-                       printk(KERN_WARNING "Can't find property index"
-                              " name !\n");
-                       return NULL;
-               }
-               if (strcmp(name, nstr) == 0) {
-                       if (size)
-                               *size = sz;
-                       return (void *)p;
-               }
-               p += sz;
-               p = _ALIGN(p, 4);
-       } while(1);
-}
-
-int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
-{
-       const char* cp;
-       unsigned long cplen, l;
-
-       cp = of_get_flat_dt_prop(node, "compatible", &cplen);
-       if (cp == NULL)
-               return 0;
-       while (cplen > 0) {
-               if (strncasecmp(cp, compat, strlen(compat)) == 0)
-                       return 1;
-               l = strlen(cp) + 1;
-               cp += l;
-               cplen -= l;
-       }
-
-       return 0;
-}
-
-static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
-                                      unsigned long align)
-{
-       void *res;
-
-       *mem = _ALIGN(*mem, align);
-       res = (void *)*mem;
-       *mem += size;
-
-       return res;
-}
-
-static unsigned long __init unflatten_dt_node(unsigned long mem,
-                                             unsigned long *p,
-                                             struct device_node *dad,
-                                             struct device_node ***allnextpp,
-                                             unsigned long fpsize)
-{
-       struct device_node *np;
-       struct property *pp, **prev_pp = NULL;
-       char *pathp;
-       u32 tag;
-       unsigned int l, allocl;
-       int has_name = 0;
-       int new_format = 0;
-
-       tag = *((u32 *)(*p));
-       if (tag != OF_DT_BEGIN_NODE) {
-               printk("Weird tag at start of node: %x\n", tag);
-               return mem;
-       }
-       *p += 4;
-       pathp = (char *)*p;
-       l = allocl = strlen(pathp) + 1;
-       *p = _ALIGN(*p + l, 4);
-
-       /* version 0x10 has a more compact unit name here instead of the full
-        * path. we accumulate the full path size using "fpsize", we'll rebuild
-        * it later. We detect this because the first character of the name is
-        * not '/'.
-        */
-       if ((*pathp) != '/') {
-               new_format = 1;
-               if (fpsize == 0) {
-                       /* root node: special case. fpsize accounts for path
-                        * plus terminating zero. root node only has '/', so
-                        * fpsize should be 2, but we want to avoid the first
-                        * level nodes to have two '/' so we use fpsize 1 here
-                        */
-                       fpsize = 1;
-                       allocl = 2;
-               } else {
-                       /* account for '/' and path size minus terminal 0
-                        * already in 'l'
-                        */
-                       fpsize += l;
-                       allocl = fpsize;
-               }
-       }
-
-
-       np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
-                               __alignof__(struct device_node));
-       if (allnextpp) {
-               memset(np, 0, sizeof(*np));
-               np->full_name = ((char*)np) + sizeof(struct device_node);
-               if (new_format) {
-                       char *p = np->full_name;
-                       /* rebuild full path for new format */
-                       if (dad && dad->parent) {
-                               strcpy(p, dad->full_name);
-#ifdef DEBUG
-                               if ((strlen(p) + l + 1) != allocl) {
-                                       DBG("%s: p: %d, l: %d, a: %d\n",
-                                           pathp, (int)strlen(p), l, allocl);
-                               }
-#endif
-                               p += strlen(p);
-                       }
-                       *(p++) = '/';
-                       memcpy(p, pathp, l);
-               } else
-                       memcpy(np->full_name, pathp, l);
-               prev_pp = &np->properties;
-               **allnextpp = np;
-               *allnextpp = &np->allnext;
-               if (dad != NULL) {
-                       np->parent = dad;
-                       /* we temporarily use the next field as `last_child'*/
-                       if (dad->next == 0)
-                               dad->child = np;
-                       else
-                               dad->next->sibling = np;
-                       dad->next = np;
-               }
-               kref_init(&np->kref);
-       }
-       while(1) {
-               u32 sz, noff;
-               char *pname;
-
-               tag = *((u32 *)(*p));
-               if (tag == OF_DT_NOP) {
-                       *p += 4;
-                       continue;
-               }
-               if (tag != OF_DT_PROP)
-                       break;
-               *p += 4;
-               sz = *((u32 *)(*p));
-               noff = *((u32 *)((*p) + 4));
-               *p += 8;
-               if (initial_boot_params->version < 0x10)
-                       *p = _ALIGN(*p, sz >= 8 ? 8 : 4);
-
-               pname = find_flat_dt_string(noff);
-               if (pname == NULL) {
-                       printk("Can't find property name in list !\n");
-                       break;
-               }
-               if (strcmp(pname, "name") == 0)
-                       has_name = 1;
-               l = strlen(pname) + 1;
-               pp = unflatten_dt_alloc(&mem, sizeof(struct property),
-                                       __alignof__(struct property));
-               if (allnextpp) {
-                       if (strcmp(pname, "linux,phandle") == 0) {
-                               np->node = *((u32 *)*p);
-                               if (np->linux_phandle == 0)
-                                       np->linux_phandle = np->node;
-                       }
-                       if (strcmp(pname, "ibm,phandle") == 0)
-                               np->linux_phandle = *((u32 *)*p);
-                       pp->name = pname;
-                       pp->length = sz;
-                       pp->value = (void *)*p;
-                       *prev_pp = pp;
-                       prev_pp = &pp->next;
-               }
-               *p = _ALIGN((*p) + sz, 4);
-       }
-       /* with version 0x10 we may not have the name property, recreate
-        * it here from the unit name if absent
-        */
-       if (!has_name) {
-               char *p = pathp, *ps = pathp, *pa = NULL;
-               int sz;
-
-               while (*p) {
-                       if ((*p) == '@')
-                               pa = p;
-                       if ((*p) == '/')
-                               ps = p + 1;
-                       p++;
-               }
-               if (pa < ps)
-                       pa = p;
-               sz = (pa - ps) + 1;
-               pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
-                                       __alignof__(struct property));
-               if (allnextpp) {
-                       pp->name = "name";
-                       pp->length = sz;
-                       pp->value = pp + 1;
-                       *prev_pp = pp;
-                       prev_pp = &pp->next;
-                       memcpy(pp->value, ps, sz - 1);
-                       ((char *)pp->value)[sz - 1] = 0;
-                       DBG("fixed up name for %s -> %s\n", pathp,
-                               (char *)pp->value);
-               }
-       }
-       if (allnextpp) {
-               *prev_pp = NULL;
-               np->name = of_get_property(np, "name", NULL);
-               np->type = of_get_property(np, "device_type", NULL);
-
-               if (!np->name)
-                       np->name = "<NULL>";
-               if (!np->type)
-                       np->type = "<NULL>";
-       }
-       while (tag == OF_DT_BEGIN_NODE) {
-               mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize);
-               tag = *((u32 *)(*p));
-       }
-       if (tag != OF_DT_END_NODE) {
-               printk("Weird tag at end of node: %x\n", tag);
-               return mem;
-       }
-       *p += 4;
-       return mem;
-}
-
 static int __init early_parse_mem(char *p)
 {
        if (!p)
@@ -446,7 +93,7 @@ static void __init move_device_tree(void)
        DBG("-> move_device_tree\n");
 
        start = __pa(initial_boot_params);
-       size = initial_boot_params->totalsize;
+       size = be32_to_cpu(initial_boot_params->totalsize);
 
        if ((memory_limit && (start + size) > memory_limit) ||
                        overlaps_crashkernel(start, size)) {
@@ -459,54 +106,6 @@ static void __init move_device_tree(void)
        DBG("<- move_device_tree\n");
 }
 
-/**
- * unflattens the device-tree passed by the firmware, creating the
- * tree of struct device_node. It also fills the "name" and "type"
- * pointers of the nodes so the normal device-tree walking functions
- * can be used (this used to be done by finish_device_tree)
- */
-void __init unflatten_device_tree(void)
-{
-       unsigned long start, mem, size;
-       struct device_node **allnextp = &allnodes;
-
-       DBG(" -> unflatten_device_tree()\n");
-
-       /* First pass, scan for size */
-       start = ((unsigned long)initial_boot_params) +
-               initial_boot_params->off_dt_struct;
-       size = unflatten_dt_node(0, &start, NULL, NULL, 0);
-       size = (size | 3) + 1;
-
-       DBG("  size is %lx, allocating...\n", size);
-
-       /* Allocate memory for the expanded device tree */
-       mem = lmb_alloc(size + 4, __alignof__(struct device_node));
-       mem = (unsigned long) __va(mem);
-
-       ((u32 *)mem)[size / 4] = 0xdeadbeef;
-
-       DBG("  unflattening %lx...\n", mem);
-
-       /* Second pass, do actual unflattening */
-       start = ((unsigned long)initial_boot_params) +
-               initial_boot_params->off_dt_struct;
-       unflatten_dt_node(mem, &start, NULL, &allnextp, 0);
-       if (*((u32 *)start) != OF_DT_END)
-               printk(KERN_WARNING "Weird tag at end of tree: %08x\n", *((u32 *)start));
-       if (((u32 *)mem)[size / 4] != 0xdeadbeef)
-               printk(KERN_WARNING "End of tree marker overwritten: %08x\n",
-                      ((u32 *)mem)[size / 4] );
-       *allnextp = NULL;
-
-       /* Get pointer to OF "/chosen" node for use everywhere */
-       of_chosen = of_find_node_by_path("/chosen");
-       if (of_chosen == NULL)
-               of_chosen = of_find_node_by_path("/chosen@0");
-
-       DBG(" <- unflatten_device_tree()\n");
-}
-
 /*
  * ibm,pa-features is a per-cpu property that contains a string of
  * attribute descriptors, each of which has a 2 byte header plus up
@@ -763,48 +362,9 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
        return 0;
 }
 
-#ifdef CONFIG_BLK_DEV_INITRD
-static void __init early_init_dt_check_for_initrd(unsigned long node)
-{
-       unsigned long l;
-       u32 *prop;
-
-       DBG("Looking for initrd properties... ");
-
-       prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l);
-       if (prop) {
-               initrd_start = (unsigned long)__va(of_read_ulong(prop, l/4));
-
-               prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l);
-               if (prop) {
-                       initrd_end = (unsigned long)
-                                       __va(of_read_ulong(prop, l/4));
-                       initrd_below_start_ok = 1;
-               } else {
-                       initrd_start = 0;
-               }
-       }
-
-       DBG("initrd_start=0x%lx  initrd_end=0x%lx\n", initrd_start, initrd_end);
-}
-#else
-static inline void early_init_dt_check_for_initrd(unsigned long node)
-{
-}
-#endif /* CONFIG_BLK_DEV_INITRD */
-
-static int __init early_init_dt_scan_chosen(unsigned long node,
-                                           const char *uname, int depth, void *data)
+void __init early_init_dt_scan_chosen_arch(unsigned long node)
 {
        unsigned long *lprop;
-       unsigned long l;
-       char *p;
-
-       DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
-
-       if (depth != 1 ||
-           (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
-               return 0;
 
 #ifdef CONFIG_PPC64
        /* check if iommu is forced on or off */
@@ -815,17 +375,17 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
 #endif
 
        /* mem=x on the command line is the preferred mechanism */
-       lprop = of_get_flat_dt_prop(node, "linux,memory-limit", NULL);
-       if (lprop)
-               memory_limit = *lprop;
+       lprop = of_get_flat_dt_prop(node, "linux,memory-limit", NULL);
+       if (lprop)
+               memory_limit = *lprop;
 
 #ifdef CONFIG_PPC64
-       lprop = of_get_flat_dt_prop(node, "linux,tce-alloc-start", NULL);
-       if (lprop)
-               tce_alloc_start = *lprop;
-       lprop = of_get_flat_dt_prop(node, "linux,tce-alloc-end", NULL);
-       if (lprop)
-               tce_alloc_end = *lprop;
+       lprop = of_get_flat_dt_prop(node, "linux,tce-alloc-start", NULL);
+       if (lprop)
+               tce_alloc_start = *lprop;
+       lprop = of_get_flat_dt_prop(node, "linux,tce-alloc-end", NULL);
+       if (lprop)
+               tce_alloc_end = *lprop;
 #endif
 
 #ifdef CONFIG_KEXEC
@@ -837,51 +397,6 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
        if (lprop)
                crashk_res.end = crashk_res.start + *lprop - 1;
 #endif
-
-       early_init_dt_check_for_initrd(node);
-
-       /* Retreive command line */
-       p = of_get_flat_dt_prop(node, "bootargs", &l);
-       if (p != NULL && l > 0)
-               strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE));
-
-#ifdef CONFIG_CMDLINE
-       if (p == NULL || l == 0 || (l == 1 && (*p) == 0))
-               strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
-#endif /* CONFIG_CMDLINE */
-
-       DBG("Command line is: %s\n", cmd_line);
-
-       /* break now */
-       return 1;
-}
-
-static int __init early_init_dt_scan_root(unsigned long node,
-                                         const char *uname, int depth, void *data)
-{
-       u32 *prop;
-
-       if (depth != 0)
-               return 0;
-
-       prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
-       dt_root_size_cells = (prop == NULL) ? 1 : *prop;
-       DBG("dt_root_size_cells = %x\n", dt_root_size_cells);
-
-       prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
-       dt_root_addr_cells = (prop == NULL) ? 2 : *prop;
-       DBG("dt_root_addr_cells = %x\n", dt_root_addr_cells);
-       
-       /* break now */
-       return 1;
-}
-
-static u64 __init dt_mem_next_cell(int s, cell_t **cellp)
-{
-       cell_t *p = *cellp;
-
-       *cellp = p + s;
-       return of_read_number(p, s);
 }
 
 #ifdef CONFIG_PPC_PSERIES
@@ -893,22 +408,22 @@ static u64 __init dt_mem_next_cell(int s, cell_t **cellp)
  */
 static int __init early_init_dt_scan_drconf_memory(unsigned long node)
 {
-       cell_t *dm, *ls, *usm;
+       __be32 *dm, *ls, *usm;
        unsigned long l, n, flags;
        u64 base, size, lmb_size;
        unsigned int is_kexec_kdump = 0, rngs;
 
        ls = of_get_flat_dt_prop(node, "ibm,lmb-size", &l);
-       if (ls == NULL || l < dt_root_size_cells * sizeof(cell_t))
+       if (ls == NULL || l < dt_root_size_cells * sizeof(__be32))
                return 0;
        lmb_size = dt_mem_next_cell(dt_root_size_cells, &ls);
 
        dm = of_get_flat_dt_prop(node, "ibm,dynamic-memory", &l);
-       if (dm == NULL || l < sizeof(cell_t))
+       if (dm == NULL || l < sizeof(__be32))
                return 0;
 
        n = *dm++;      /* number of entries */
-       if (l < (n * (dt_root_addr_cells + 4) + 1) * sizeof(cell_t))
+       if (l < (n * (dt_root_addr_cells + 4) + 1) * sizeof(__be32))
                return 0;
 
        /* check if this is a kexec/kdump kernel. */
@@ -963,65 +478,47 @@ static int __init early_init_dt_scan_drconf_memory(unsigned long node)
 #define early_init_dt_scan_drconf_memory(node) 0
 #endif /* CONFIG_PPC_PSERIES */
 
-static int __init early_init_dt_scan_memory(unsigned long node,
-                                           const char *uname, int depth, void *data)
+static int __init early_init_dt_scan_memory_ppc(unsigned long node,
+                                               const char *uname,
+                                               int depth, void *data)
 {
-       char *type = of_get_flat_dt_prop(node, "device_type", NULL);
-       cell_t *reg, *endp;
-       unsigned long l;
-
-       /* Look for the ibm,dynamic-reconfiguration-memory node */
        if (depth == 1 &&
            strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0)
                return early_init_dt_scan_drconf_memory(node);
+       
+       return early_init_dt_scan_memory(node, uname, depth, data);
+}
 
-       /* We are scanning "memory" nodes only */
-       if (type == NULL) {
-               /*
-                * The longtrail doesn't have a device_type on the
-                * /memory node, so look for the node called /memory@0.
-                */
-               if (depth != 1 || strcmp(uname, "memory@0") != 0)
-                       return 0;
-       } else if (strcmp(type, "memory") != 0)
-               return 0;
-
-       reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
-       if (reg == NULL)
-               reg = of_get_flat_dt_prop(node, "reg", &l);
-       if (reg == NULL)
-               return 0;
-
-       endp = reg + (l / sizeof(cell_t));
-
-       DBG("memory scan node %s, reg size %ld, data: %x %x %x %x,\n",
-           uname, l, reg[0], reg[1], reg[2], reg[3]);
-
-       while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
-               u64 base, size;
+void __init early_init_dt_add_memory_arch(u64 base, u64 size)
+{
+#if defined(CONFIG_PPC64)
+       if (iommu_is_off) {
+               if (base >= 0x80000000ul)
+                       return;
+               if ((base + size) > 0x80000000ul)
+                       size = 0x80000000ul - base;
+       }
+#endif
 
-               base = dt_mem_next_cell(dt_root_addr_cells, &reg);
-               size = dt_mem_next_cell(dt_root_size_cells, &reg);
+       lmb_add(base, size);
 
-               if (size == 0)
-                       continue;
-               DBG(" - %llx ,  %llx\n", (unsigned long long)base,
-                   (unsigned long long)size);
-#ifdef CONFIG_PPC64
-               if (iommu_is_off) {
-                       if (base >= 0x80000000ul)
-                               continue;
-                       if ((base + size) > 0x80000000ul)
-                               size = 0x80000000ul - base;
-               }
-#endif
-               lmb_add(base, size);
+       memstart_addr = min((u64)memstart_addr, base);
+}
 
-               memstart_addr = min((u64)memstart_addr, base);
-       }
+u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
+{
+       return lmb_alloc(size, align);
+}
 
-       return 0;
+#ifdef CONFIG_BLK_DEV_INITRD
+void __init early_init_dt_setup_initrd_arch(unsigned long start,
+               unsigned long end)
+{
+       initrd_start = (unsigned long)__va(start);
+       initrd_end = (unsigned long)__va(end);
+       initrd_below_start_ok = 1;
 }
+#endif
 
 static void __init early_reserve_mem(void)
 {
@@ -1186,7 +683,7 @@ void __init early_init_devtree(void *params)
        /* Scan memory nodes and rebuild LMBs */
        lmb_init();
        of_scan_flat_dt(early_init_dt_scan_root, NULL);
-       of_scan_flat_dt(early_init_dt_scan_memory, NULL);
+       of_scan_flat_dt(early_init_dt_scan_memory_ppc, NULL);
 
        /* Save command line for /proc/cmdline and then parse parameters */
        strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE);
@@ -1234,25 +731,6 @@ void __init early_init_devtree(void *params)
        DBG(" <- early_init_devtree()\n");
 }
 
-
-/**
- * Indicates whether the root node has a given value in its
- * compatible property.
- */
-int machine_is_compatible(const char *compat)
-{
-       struct device_node *root;
-       int rc = 0;
-
-       root = of_find_node_by_path("/");
-       if (root) {
-               rc = of_device_is_compatible(root, compat);
-               of_node_put(root);
-       }
-       return rc;
-}
-EXPORT_SYMBOL(machine_is_compatible);
-
 /*******
  *
  * New implementation of the OF "find" APIs, return a refcounted
@@ -1265,27 +743,6 @@ EXPORT_SYMBOL(machine_is_compatible);
  *******/
 
 /**
- *     of_find_node_by_phandle - Find a node given a phandle
- *     @handle:        phandle of the node to find
- *
- *     Returns a node pointer with refcount incremented, use
- *     of_node_put() on it when done.
- */
-struct device_node *of_find_node_by_phandle(phandle handle)
-{
-       struct device_node *np;
-
-       read_lock(&devtree_lock);
-       for (np = allnodes; np != 0; np = np->allnext)
-               if (np->linux_phandle == handle)
-                       break;
-       of_node_get(np);
-       read_unlock(&devtree_lock);
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_phandle);
-
-/**
  *     of_find_next_cache_node - Find a node's subsidiary cache
  *     @np:    node of type "cpu" or "cache"
  *
@@ -1316,138 +773,6 @@ struct device_node *of_find_next_cache_node(struct device_node *np)
        return NULL;
 }
 
-/**
- *     of_node_get - Increment refcount of a node
- *     @node:  Node to inc refcount, NULL is supported to
- *             simplify writing of callers
- *
- *     Returns node.
- */
-struct device_node *of_node_get(struct device_node *node)
-{
-       if (node)
-               kref_get(&node->kref);
-       return node;
-}
-EXPORT_SYMBOL(of_node_get);
-
-static inline struct device_node * kref_to_device_node(struct kref *kref)
-{
-       return container_of(kref, struct device_node, kref);
-}
-
-/**
- *     of_node_release - release a dynamically allocated node
- *     @kref:  kref element of the node to be released
- *
- *     In of_node_put() this function is passed to kref_put()
- *     as the destructor.
- */
-static void of_node_release(struct kref *kref)
-{
-       struct device_node *node = kref_to_device_node(kref);
-       struct property *prop = node->properties;
-
-       /* We should never be releasing nodes that haven't been detached. */
-       if (!of_node_check_flag(node, OF_DETACHED)) {
-               printk("WARNING: Bad of_node_put() on %s\n", node->full_name);
-               dump_stack();
-               kref_init(&node->kref);
-               return;
-       }
-
-       if (!of_node_check_flag(node, OF_DYNAMIC))
-               return;
-
-       while (prop) {
-               struct property *next = prop->next;
-               kfree(prop->name);
-               kfree(prop->value);
-               kfree(prop);
-               prop = next;
-
-               if (!prop) {
-                       prop = node->deadprops;
-                       node->deadprops = NULL;
-               }
-       }
-       kfree(node->full_name);
-       kfree(node->data);
-       kfree(node);
-}
-
-/**
- *     of_node_put - Decrement refcount of a node
- *     @node:  Node to dec refcount, NULL is supported to
- *             simplify writing of callers
- *
- */
-void of_node_put(struct device_node *node)
-{
-       if (node)
-               kref_put(&node->kref, of_node_release);
-}
-EXPORT_SYMBOL(of_node_put);
-
-/*
- * Plug a device node into the tree and global list.
- */
-void of_attach_node(struct device_node *np)
-{
-       unsigned long flags;
-
-       write_lock_irqsave(&devtree_lock, flags);
-       np->sibling = np->parent->child;
-       np->allnext = allnodes;
-       np->parent->child = np;
-       allnodes = np;
-       write_unlock_irqrestore(&devtree_lock, flags);
-}
-
-/*
- * "Unplug" a node from the device tree.  The caller must hold
- * a reference to the node.  The memory associated with the node
- * is not freed until its refcount goes to zero.
- */
-void of_detach_node(struct device_node *np)
-{
-       struct device_node *parent;
-       unsigned long flags;
-
-       write_lock_irqsave(&devtree_lock, flags);
-
-       parent = np->parent;
-       if (!parent)
-               goto out_unlock;
-
-       if (allnodes == np)
-               allnodes = np->allnext;
-       else {
-               struct device_node *prev;
-               for (prev = allnodes;
-                    prev->allnext != np;
-                    prev = prev->allnext)
-                       ;
-               prev->allnext = np->allnext;
-       }
-
-       if (parent->child == np)
-               parent->child = np->sibling;
-       else {
-               struct device_node *prevsib;
-               for (prevsib = np->parent->child;
-                    prevsib->sibling != np;
-                    prevsib = prevsib->sibling)
-                       ;
-               prevsib->sibling = np->sibling;
-       }
-
-       of_node_set_flag(np, OF_DETACHED);
-
-out_unlock:
-       write_unlock_irqrestore(&devtree_lock, flags);
-}
-
 #ifdef CONFIG_PPC_PSERIES
 /*
  * Fix up the uninitialized fields in a new device node:
@@ -1479,9 +804,9 @@ static int of_finish_dynamic_node(struct device_node *node)
        if (machine_is(powermac))
                return -ENODEV;
 
-       /* fix up new node's linux_phandle field */
+       /* fix up new node's phandle field */
        if ((ibm_phandle = of_get_property(node, "ibm,phandle", NULL)))
-               node->linux_phandle = *ibm_phandle;
+               node->phandle = *ibm_phandle;
 
 out:
        of_node_put(parent);
@@ -1520,120 +845,6 @@ static int __init prom_reconfig_setup(void)
 __initcall(prom_reconfig_setup);
 #endif
 
-/*
- * Add a property to a node
- */
-int prom_add_property(struct device_node* np, struct property* prop)
-{
-       struct property **next;
-       unsigned long flags;
-
-       prop->next = NULL;      
-       write_lock_irqsave(&devtree_lock, flags);
-       next = &np->properties;
-       while (*next) {
-               if (strcmp(prop->name, (*next)->name) == 0) {
-                       /* duplicate ! don't insert it */
-                       write_unlock_irqrestore(&devtree_lock, flags);
-                       return -1;
-               }
-               next = &(*next)->next;
-       }
-       *next = prop;
-       write_unlock_irqrestore(&devtree_lock, flags);
-
-#ifdef CONFIG_PROC_DEVICETREE
-       /* try to add to proc as well if it was initialized */
-       if (np->pde)
-               proc_device_tree_add_prop(np->pde, prop);
-#endif /* CONFIG_PROC_DEVICETREE */
-
-       return 0;
-}
-
-/*
- * Remove a property from a node.  Note that we don't actually
- * remove it, since we have given out who-knows-how-many pointers
- * to the data using get-property.  Instead we just move the property
- * to the "dead properties" list, so it won't be found any more.
- */
-int prom_remove_property(struct device_node *np, struct property *prop)
-{
-       struct property **next;
-       unsigned long flags;
-       int found = 0;
-
-       write_lock_irqsave(&devtree_lock, flags);
-       next = &np->properties;
-       while (*next) {
-               if (*next == prop) {
-                       /* found the node */
-                       *next = prop->next;
-                       prop->next = np->deadprops;
-                       np->deadprops = prop;
-                       found = 1;
-                       break;
-               }
-               next = &(*next)->next;
-       }
-       write_unlock_irqrestore(&devtree_lock, flags);
-
-       if (!found)
-               return -ENODEV;
-
-#ifdef CONFIG_PROC_DEVICETREE
-       /* try to remove the proc node as well */
-       if (np->pde)
-               proc_device_tree_remove_prop(np->pde, prop);
-#endif /* CONFIG_PROC_DEVICETREE */
-
-       return 0;
-}
-
-/*
- * Update a property in a node.  Note that we don't actually
- * remove it, since we have given out who-knows-how-many pointers
- * to the data using get-property.  Instead we just move the property
- * to the "dead properties" list, and add the new property to the
- * property list
- */
-int prom_update_property(struct device_node *np,
-                        struct property *newprop,
-                        struct property *oldprop)
-{
-       struct property **next;
-       unsigned long flags;
-       int found = 0;
-
-       write_lock_irqsave(&devtree_lock, flags);
-       next = &np->properties;
-       while (*next) {
-               if (*next == oldprop) {
-                       /* found the node */
-                       newprop->next = oldprop->next;
-                       *next = newprop;
-                       oldprop->next = np->deadprops;
-                       np->deadprops = oldprop;
-                       found = 1;
-                       break;
-               }
-               next = &(*next)->next;
-       }
-       write_unlock_irqrestore(&devtree_lock, flags);
-
-       if (!found)
-               return -ENODEV;
-
-#ifdef CONFIG_PROC_DEVICETREE
-       /* try to add to proc as well if it was initialized */
-       if (np->pde)
-               proc_device_tree_update_prop(np->pde, newprop, oldprop);
-#endif /* CONFIG_PROC_DEVICETREE */
-
-       return 0;
-}
-
-
 /* Find the device node for a given logical cpu number, also returns the cpu
  * local thread number (index in ibm,interrupt-server#s) if relevant and
  * asked for (non NULL)
index 04af81e..04d105d 100644 (file)
@@ -341,7 +341,8 @@ static void __init mpc85xx_mds_pic_init(void)
        }
 
        mpic = mpic_alloc(np, r.start,
-                       MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+                       MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN |
+                       MPIC_BROKEN_FRR_NIRQS,
                        0, 256, " OpenPIC  ");
        BUG_ON(mpic == NULL);
        of_node_put(np);
index 1b42605..0125604 100644 (file)
@@ -80,8 +80,8 @@ static void xes_mpc85xx_configure_l2(void __iomem *l2_base)
        printk(KERN_INFO "xes_mpc85xx: Enabling L2 as cache\n");
 
        ctl = MPC85xx_L2CTL_L2E | MPC85xx_L2CTL_L2I;
-       if (machine_is_compatible("MPC8540") ||
-           machine_is_compatible("MPC8560"))
+       if (of_machine_is_compatible("MPC8540") ||
+           of_machine_is_compatible("MPC8560"))
                /*
                 * Assume L2 SRAM is used fully for cache, so set
                 * L2BLKSZ (bits 4:5) to match L2SIZ (bits 2:3).
index dcddaa5..f75a4da 100644 (file)
@@ -48,7 +48,7 @@ static int __init cbe_powerbutton_init(void)
        int ret = 0;
        struct input_dev *dev;
 
-       if (!machine_is_compatible("IBM,CBPLUS-1.0")) {
+       if (!of_machine_is_compatible("IBM,CBPLUS-1.0")) {
                printk(KERN_ERR "%s: Not a cell blade.\n", __func__);
                ret = -ENODEV;
                goto out;
index 5e0a191..608fd2b 100644 (file)
@@ -255,7 +255,7 @@ static int __init cbe_sysreset_init(void)
 {
        struct cbe_pmd_regs __iomem *regs;
 
-       sysreset_hack = machine_is_compatible("IBM,CBPLUS-1.0");
+       sysreset_hack = of_machine_is_compatible("IBM,CBPLUS-1.0");
        if (!sysreset_hack)
                return 0;
 
index 4c506c1..891f18e 100644 (file)
@@ -457,7 +457,7 @@ neighbour_spu(int cbe, struct device_node *target, struct device_node *avoid)
                        continue;
                vic_handles = of_get_property(spu_dn, "vicinity", &lenp);
                for (i=0; i < (lenp / sizeof(phandle)); i++) {
-                       if (vic_handles[i] == target->linux_phandle)
+                       if (vic_handles[i] == target->phandle)
                                return spu;
                }
        }
@@ -499,7 +499,7 @@ static void init_affinity_node(int cbe)
 
                        if (strcmp(name, "spe") == 0) {
                                spu = devnode_spu(cbe, vic_dn);
-                               avoid_ph = last_spu_dn->linux_phandle;
+                               avoid_ph = last_spu_dn->phandle;
                        } else {
                                /*
                                 * "mic-tm" and "bif0" nodes do not have
@@ -514,7 +514,7 @@ static void init_affinity_node(int cbe)
                                        last_spu->has_mem_affinity = 1;
                                        spu->has_mem_affinity = 1;
                                }
-                               avoid_ph = vic_dn->linux_phandle;
+                               avoid_ph = vic_dn->phandle;
                        }
 
                        list_add_tail(&spu->aff_list, &last_spu->aff_list);
index be2527a..d35e052 100644 (file)
@@ -304,8 +304,8 @@ static struct cpufreq_driver pas_cpufreq_driver = {
 
 static int __init pas_cpufreq_init(void)
 {
-       if (!machine_is_compatible("PA6T-1682M") &&
-           !machine_is_compatible("pasemi,pwrficient"))
+       if (!of_machine_is_compatible("PA6T-1682M") &&
+           !of_machine_is_compatible("pasemi,pwrficient"))
                return -ENODEV;
 
        return cpufreq_register_driver(&pas_cpufreq_driver);
index 08d94e4..d4f127d 100644 (file)
@@ -657,31 +657,31 @@ static int __init pmac_cpufreq_setup(void)
        cur_freq = (*value) / 1000;
 
        /*  Check for 7447A based MacRISC3 */
-       if (machine_is_compatible("MacRISC3") &&
+       if (of_machine_is_compatible("MacRISC3") &&
            of_get_property(cpunode, "dynamic-power-step", NULL) &&
            PVR_VER(mfspr(SPRN_PVR)) == 0x8003) {
                pmac_cpufreq_init_7447A(cpunode);
        /* Check for other MacRISC3 machines */
-       } else if (machine_is_compatible("PowerBook3,4") ||
-                  machine_is_compatible("PowerBook3,5") ||
-                  machine_is_compatible("MacRISC3")) {
+       } else if (of_machine_is_compatible("PowerBook3,4") ||
+                  of_machine_is_compatible("PowerBook3,5") ||
+                  of_machine_is_compatible("MacRISC3")) {
                pmac_cpufreq_init_MacRISC3(cpunode);
        /* Else check for iBook2 500/600 */
-       } else if (machine_is_compatible("PowerBook4,1")) {
+       } else if (of_machine_is_compatible("PowerBook4,1")) {
                hi_freq = cur_freq;
                low_freq = 400000;
                set_speed_proc = pmu_set_cpu_speed;
                is_pmu_based = 1;
        }
        /* Else check for TiPb 550 */
-       else if (machine_is_compatible("PowerBook3,3") && cur_freq == 550000) {
+       else if (of_machine_is_compatible("PowerBook3,3") && cur_freq == 550000) {
                hi_freq = cur_freq;
                low_freq = 500000;
                set_speed_proc = pmu_set_cpu_speed;
                is_pmu_based = 1;
        }
        /* Else check for TiPb 400 & 500 */
-       else if (machine_is_compatible("PowerBook3,2")) {
+       else if (of_machine_is_compatible("PowerBook3,2")) {
                /* We only know about the 400 MHz and the 500Mhz model
                 * they both have 300 MHz as low frequency
                 */
index 708c751..3ed288e 100644 (file)
@@ -398,11 +398,11 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
        int rc = -ENODEV;
 
        /* Check supported platforms */
-       if (machine_is_compatible("PowerMac8,1") ||
-           machine_is_compatible("PowerMac8,2") ||
-           machine_is_compatible("PowerMac9,1"))
+       if (of_machine_is_compatible("PowerMac8,1") ||
+           of_machine_is_compatible("PowerMac8,2") ||
+           of_machine_is_compatible("PowerMac9,1"))
                use_volts_smu = 1;
-       else if (machine_is_compatible("PowerMac11,2"))
+       else if (of_machine_is_compatible("PowerMac11,2"))
                use_volts_vdnap = 1;
        else
                return -ENODEV;
@@ -729,9 +729,9 @@ static int __init g5_cpufreq_init(void)
                return -ENODEV;
        }
 
-       if (machine_is_compatible("PowerMac7,2") ||
-           machine_is_compatible("PowerMac7,3") ||
-           machine_is_compatible("RackMac3,1"))
+       if (of_machine_is_compatible("PowerMac7,2") ||
+           of_machine_is_compatible("PowerMac7,3") ||
+           of_machine_is_compatible("RackMac3,1"))
                rc = g5_pm72_cpufreq_init(cpus);
 #ifdef CONFIG_PMAC_SMU
        else
index 424b633..9e1b9fd 100644 (file)
@@ -2426,7 +2426,7 @@ static int __init probe_motherboard(void)
            }
        }
        for(i=0; i<ARRAY_SIZE(pmac_mb_defs); i++) {
-           if (machine_is_compatible(pmac_mb_defs[i].model_string)) {
+           if (of_machine_is_compatible(pmac_mb_defs[i].model_string)) {
                pmac_mb = pmac_mb_defs[i];
                goto found;
            }
index 96d5ce5..ede49e7 100644 (file)
@@ -842,7 +842,7 @@ struct pmf_function *__pmf_find_function(struct device_node *target,
        list_for_each_entry(func, &dev->functions, link) {
                if (name && strcmp(name, func->name))
                        continue;
-               if (func->phandle && target->node != func->phandle)
+               if (func->phandle && target->phandle != func->phandle)
                        continue;
                if ((func->flags & flags) == 0)
                        continue;
index b40c22d..6898e82 100644 (file)
@@ -693,9 +693,9 @@ static void __init smp_core99_setup(int ncpus)
 #ifdef CONFIG_PPC64
 
        /* i2c based HW sync on some G5s */
-       if (machine_is_compatible("PowerMac7,2") ||
-           machine_is_compatible("PowerMac7,3") ||
-           machine_is_compatible("RackMac3,1"))
+       if (of_machine_is_compatible("PowerMac7,2") ||
+           of_machine_is_compatible("PowerMac7,3") ||
+           of_machine_is_compatible("RackMac3,1"))
                smp_core99_setup_i2c_hwsync(ncpus);
 
        /* pfunc based HW sync on recent G5s */
@@ -713,7 +713,7 @@ static void __init smp_core99_setup(int ncpus)
 #else /* CONFIG_PPC64 */
 
        /* GPIO based HW sync on ppc32 Core99 */
-       if (pmac_tb_freeze == NULL && !machine_is_compatible("MacRISC4")) {
+       if (pmac_tb_freeze == NULL && !of_machine_is_compatible("MacRISC4")) {
                struct device_node *cpu;
                const u32 *tbprop = NULL;
 
@@ -750,7 +750,7 @@ static void __init smp_core99_setup(int ncpus)
 #endif
 
        /* 32 bits SMP can't NAP */
-       if (!machine_is_compatible("MacRISC4"))
+       if (!of_machine_is_compatible("MacRISC4"))
                powersave_nap = 0;
 }
 
@@ -852,7 +852,7 @@ static void __devinit smp_core99_setup_cpu(int cpu_nr)
                /* If we didn't start the second CPU, we must take
                 * it off the bus
                 */
-               if (machine_is_compatible("MacRISC4") &&
+               if (of_machine_is_compatible("MacRISC4") &&
                    num_online_cpus() < 2)              
                        g5_phy_disable_cpu1();
 #endif /* CONFIG_PPC64 */
index 1810e42..48211ca 100644 (file)
@@ -317,9 +317,9 @@ void __init pmac_calibrate_decr(void)
         * calibration. That's better since the VIA itself seems
         * to be slightly off. --BenH
         */
-       if (!machine_is_compatible("MacRISC2") &&
-           !machine_is_compatible("MacRISC3") &&
-           !machine_is_compatible("MacRISC4"))
+       if (!of_machine_is_compatible("MacRISC2") &&
+           !of_machine_is_compatible("MacRISC3") &&
+           !of_machine_is_compatible("MacRISC4"))
                if (via_calibrate_decr())
                        return;
 
@@ -328,7 +328,7 @@ void __init pmac_calibrate_decr(void)
         * probably implement calibration based on the KL timer on these
         * machines anyway... -BenH
         */
-       if (machine_is_compatible("PowerMac3,5"))
+       if (of_machine_is_compatible("PowerMac3,5"))
                if (via_calibrate_decr())
                        return;
 #endif
index 9490157..d83135a 100644 (file)
@@ -132,9 +132,9 @@ void udbg_scc_init(int force_scc)
                scc_inittab[1] = in_8(sccc);
                out_8(sccc, 12);
                scc_inittab[3] = in_8(sccc);
-       } else if (machine_is_compatible("RackMac1,1")
-                  || machine_is_compatible("RackMac1,2")
-                  || machine_is_compatible("MacRISC4")) {
+       } else if (of_machine_is_compatible("RackMac1,1")
+                  || of_machine_is_compatible("RackMac1,2")
+                  || of_machine_is_compatible("MacRISC4")) {
                /* Xserves and G5s default to 57600 */
                scc_inittab[1] = 0;
                scc_inittab[3] = 0;
index 5da37c2..cf27df6 100644 (file)
@@ -56,9 +56,9 @@ static inline void grackle_set_loop_snoop(struct pci_controller *bp, int enable)
 void __init setup_grackle(struct pci_controller *hose)
 {
        setup_indirect_pci(hose, 0xfec00000, 0xfee00000, 0);
-       if (machine_is_compatible("PowerMac1,1"))
+       if (of_machine_is_compatible("PowerMac1,1"))
                ppc_pci_add_flags(PPC_PCI_REASSIGN_ALL_BUS);
-       if (machine_is_compatible("AAPL,PowerBook1998"))
+       if (of_machine_is_compatible("AAPL,PowerBook1998"))
                grackle_set_loop_snoop(hose, 1);
 #if 0  /* Disabled for now, HW problems ??? */
        grackle_set_stg(hose, 1);
index 55db5ec..39327d6 100644 (file)
@@ -53,8 +53,8 @@ struct stat {
        ino_t           st_ino;
        mode_t          st_mode;
        short           st_nlink;
-       uid_t           st_uid;
-       gid_t           st_gid;
+       uid16_t         st_uid;
+       gid16_t         st_gid;
        unsigned short  st_rdev;
        off_t           st_size;
        time_t          st_atime;
index b171ae8..b062de9 100644 (file)
@@ -59,7 +59,7 @@ static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg,
 
        cur_inst = 0;
        for_each_node_by_type(dp, "cpu") {
-               int err = check_cpu_node(dp->node, &cur_inst,
+               int err = check_cpu_node(dp->phandle, &cur_inst,
                                         compare, compare_arg,
                                         prom_node, mid);
                if (!err) {
index 4248d96..5247283 100644 (file)
@@ -11,6 +11,10 @@ static inline bool kstack_valid(struct thread_info *tp, unsigned long sp)
 {
        unsigned long base = (unsigned long) tp;
 
+       /* Stack pointer must be 16-byte aligned.  */
+       if (sp & (16UL - 1))
+               return false;
+
        if (sp >= (base + sizeof(struct thread_info)) &&
            sp <= (base + THREAD_SIZE - sizeof(struct sparc_stackf)))
                return true;
index 4c26eb5..da527b3 100644 (file)
@@ -105,7 +105,7 @@ static unsigned long of_bus_sbus_get_flags(const u32 *addr, unsigned long flags)
 
 static int of_bus_ambapp_match(struct device_node *np)
 {
-       return !strcmp(np->name, "ambapp");
+       return !strcmp(np->type, "ambapp");
 }
 
 static void of_bus_ambapp_count_cells(struct device_node *child,
@@ -433,7 +433,7 @@ build_resources:
        if (!parent)
                dev_set_name(&op->dev, "root");
        else
-               dev_set_name(&op->dev, "%08x", dp->node);
+               dev_set_name(&op->dev, "%08x", dp->phandle);
 
        if (of_device_register(op)) {
                printk("%s: Could not register of device.\n",
index 0a6f2d1..b3d4cb5 100644 (file)
@@ -676,7 +676,7 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
        if (!parent)
                dev_set_name(&op->dev, "root");
        else
-               dev_set_name(&op->dev, "%08x", dp->node);
+               dev_set_name(&op->dev, "%08x", dp->phandle);
 
        if (of_device_register(op)) {
                printk("%s: Could not register of device.\n",
index 539e83f..592b03d 100644 (file)
@@ -247,6 +247,7 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
                                         struct pci_bus *bus, int devfn)
 {
        struct dev_archdata *sd;
+       struct pci_slot *slot;
        struct of_device *op;
        struct pci_dev *dev;
        const char *type;
@@ -286,6 +287,11 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
        dev->dev.bus = &pci_bus_type;
        dev->devfn = devfn;
        dev->multifunction = 0;         /* maybe a lie? */
+       set_pcie_port_type(dev);
+
+       list_for_each_entry(slot, &dev->bus->slots, list)
+               if (PCI_SLOT(dev->devfn) == slot->number)
+                       dev->slot = slot;
 
        dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff);
        dev->device = of_getintprop_default(node, "device-id", 0xffff);
@@ -322,6 +328,7 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
 
        dev->current_state = 4;         /* unknown power state */
        dev->error_state = pci_channel_io_normal;
+       dev->dma_mask = 0xffffffff;
 
        if (!strcmp(node->name, "pci")) {
                /* a PCI-PCI bridge */
index 453397f..a8591ef 100644 (file)
@@ -4,9 +4,6 @@
 #include <linux/spinlock.h>
 #include <asm/prom.h>
 
-extern struct device_node *allnodes;   /* temporary while merging */
-extern rwlock_t devtree_lock;  /* temporary while merging */
-
 extern void * prom_early_alloc(unsigned long size);
 extern void irq_trans_init(struct device_node *dp);
 
index d80a65d..57ac9e2 100644 (file)
@@ -37,18 +37,6 @@ EXPORT_SYMBOL(of_console_path);
 char *of_console_options;
 EXPORT_SYMBOL(of_console_options);
 
-struct device_node *of_find_node_by_phandle(phandle handle)
-{
-       struct device_node *np;
-
-       for (np = allnodes; np; np = np->allnext)
-               if (np->node == handle)
-                       break;
-
-       return np;
-}
-EXPORT_SYMBOL(of_find_node_by_phandle);
-
 int of_getintprop_default(struct device_node *np, const char *name, int def)
 {
        struct property *prop;
@@ -89,7 +77,7 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len
                        void *old_val = prop->value;
                        int ret;
 
-                       ret = prom_setprop(dp->node, name, val, len);
+                       ret = prom_setprop(dp->phandle, name, val, len);
 
                        err = -EINVAL;
                        if (ret >= 0) {
@@ -236,7 +224,7 @@ static struct device_node * __init prom_create_node(phandle node,
 
        dp->name = get_one_property(node, "name");
        dp->type = get_one_property(node, "device_type");
-       dp->node = node;
+       dp->phandle = node;
 
        dp->properties = build_prop_list(node);
 
@@ -313,7 +301,7 @@ void __init prom_build_devicetree(void)
 
        nextp = &allnodes->allnext;
        allnodes->child = prom_build_tree(allnodes,
-                                         prom_getchild(allnodes->node),
+                                         prom_getchild(allnodes->phandle),
                                          &nextp);
        of_console_init();
 
index aa36223..eb14844 100644 (file)
@@ -370,7 +370,7 @@ static int __cpuinit smp_boot_one_cpu(unsigned int cpu)
        } else {
                struct device_node *dp = of_find_node_by_cpuid(cpu);
 
-               prom_startcpu(dp->node, entry, cookie);
+               prom_startcpu(dp->phandle, entry, cookie);
        }
 
        for (timeout = 0; timeout < 50000; timeout++) {
index 8c91d9b..db15d12 100644 (file)
@@ -191,10 +191,12 @@ tsb_dtlb_load:
 
 tsb_itlb_load:
        /* Executable bit must be set.  */
-661:   andcc           %g5, _PAGE_EXEC_4U, %g0
-       .section        .sun4v_1insn_patch, "ax"
+661:   sethi           %hi(_PAGE_EXEC_4U), %g4
+       andcc           %g5, %g4, %g0
+       .section        .sun4v_2insn_patch, "ax"
        .word           661b
        andcc           %g5, _PAGE_EXEC_4V, %g0
+       nop
        .previous
 
        be,pn           %xcc, tsb_do_fault
index fc801ba..b753ea5 100644 (file)
@@ -450,6 +450,8 @@ struct thread_struct {
        struct perf_event       *ptrace_bps[HBP_NUM];
        /* Debug status used for traps, single steps, etc... */
        unsigned long           debugreg6;
+       /* Keep track of the exact dr7 value set by the user */
+       unsigned long           ptrace_dr7;
        /* Fault info: */
        unsigned long           cr2;
        unsigned long           trap_no;
index 0acbcdf..af1c583 100644 (file)
@@ -1344,14 +1344,6 @@ static struct dmi_system_id __initdata acpi_dmi_table[] = {
         },
        {
         .callback = force_acpi_ht,
-        .ident = "ASUS P2B-DS",
-        .matches = {
-                    DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
-                    DMI_MATCH(DMI_BOARD_NAME, "P2B-DS"),
-                    },
-        },
-       {
-        .callback = force_acpi_ht,
         .ident = "ASUS CUR-DLS",
         .matches = {
                     DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
index 05d5fec..bb6006e 100644 (file)
@@ -212,25 +212,6 @@ static int arch_check_va_in_kernelspace(unsigned long va, u8 hbp_len)
        return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
 }
 
-/*
- * Store a breakpoint's encoded address, length, and type.
- */
-static int arch_store_info(struct perf_event *bp)
-{
-       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
-       /*
-        * For kernel-addresses, either the address or symbol name can be
-        * specified.
-        */
-       if (info->name)
-               info->address = (unsigned long)
-                               kallsyms_lookup_name(info->name);
-       if (info->address)
-               return 0;
-
-       return -EINVAL;
-}
-
 int arch_bp_generic_fields(int x86_len, int x86_type,
                           int *gen_len, int *gen_type)
 {
@@ -362,10 +343,13 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp,
                return ret;
        }
 
-       ret = arch_store_info(bp);
-
-       if (ret < 0)
-               return ret;
+       /*
+        * For kernel-addresses, either the address or symbol name can be
+        * specified.
+        */
+       if (info->name)
+               info->address = (unsigned long)
+                               kallsyms_lookup_name(info->name);
        /*
         * Check that the low-order bits of the address are appropriate
         * for the alignment implied by len.
index 017d937..0c1033d 100644 (file)
@@ -702,7 +702,7 @@ static unsigned long ptrace_get_debugreg(struct task_struct *tsk, int n)
        } else if (n == 6) {
                val = thread->debugreg6;
         } else if (n == 7) {
-               val = ptrace_get_dr7(thread->ptrace_bps);
+               val = thread->ptrace_dr7;
        }
        return val;
 }
@@ -778,8 +778,11 @@ int ptrace_set_debugreg(struct task_struct *tsk, int n, unsigned long val)
                        return rc;
        }
        /* All that's left is DR7 */
-       if (n == 7)
+       if (n == 7) {
                rc = ptrace_write_dr7(tsk, val);
+               if (!rc)
+                       thread->ptrace_dr7 = val;
+       }
 
 ret_path:
        return rc;
index 718897e..d1a9a0a 100644 (file)
@@ -1147,7 +1147,7 @@ void init_request_from_bio(struct request *req, struct bio *bio)
  */
 static inline bool queue_should_plug(struct request_queue *q)
 {
-       return !(blk_queue_nonrot(q) && blk_queue_queuing(q));
+       return !(blk_queue_nonrot(q) && blk_queue_tagged(q));
 }
 
 static int __make_request(struct request_queue *q, struct bio *bio)
@@ -1859,15 +1859,8 @@ void blk_dequeue_request(struct request *rq)
         * and to it is freed is accounted as io that is in progress at
         * the driver side.
         */
-       if (blk_account_rq(rq)) {
+       if (blk_account_rq(rq))
                q->in_flight[rq_is_sync(rq)]++;
-               /*
-                * Mark this device as supporting hardware queuing, if
-                * we have more IOs in flight than 4.
-                */
-               if (!blk_queue_queuing(q) && queue_in_flight(q) > 4)
-                       set_bit(QUEUE_FLAG_CQ, &q->queue_flags);
-       }
 }
 
 /**
index bbc2c13..b2586f5 100644 (file)
@@ -935,6 +935,7 @@ static int dock_add(acpi_handle handle)
        struct platform_device *dd;
 
        id = dock_station_count;
+       memset(&ds, 0, sizeof(ds));
        dd = platform_device_register_data(NULL, "dock", id, &ds, sizeof(ds));
        if (IS_ERR(dd))
                return PTR_ERR(dd);
index 7c0441f..cc978a8 100644 (file)
@@ -110,6 +110,14 @@ static struct dmi_system_id __cpuinitdata processor_power_dmi_table[] = {
          DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"),
          DMI_MATCH(DMI_BIOS_VERSION,"SHE845M0.86C.0013.D.0302131307")},
         (void *)2},
+       { set_max_cstate, "Pavilion zv5000", {
+         DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+         DMI_MATCH(DMI_PRODUCT_NAME,"Pavilion zv5000 (DS502A#ABA)")},
+        (void *)1},
+       { set_max_cstate, "Asus L8400B", {
+         DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+         DMI_MATCH(DMI_PRODUCT_NAME,"L8400B series Notebook PC")},
+        (void *)1},
        {},
 };
 
@@ -872,12 +880,14 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
                return(acpi_idle_enter_c1(dev, state));
 
        local_irq_disable();
-       current_thread_info()->status &= ~TS_POLLING;
-       /*
-        * TS_POLLING-cleared state must be visible before we test
-        * NEED_RESCHED:
-        */
-       smp_mb();
+       if (cx->entry_method != ACPI_CSTATE_FFH) {
+               current_thread_info()->status &= ~TS_POLLING;
+               /*
+                * TS_POLLING-cleared state must be visible before we test
+                * NEED_RESCHED:
+                */
+               smp_mb();
+       }
 
        if (unlikely(need_resched())) {
                current_thread_info()->status |= TS_POLLING;
@@ -957,12 +967,14 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
        }
 
        local_irq_disable();
-       current_thread_info()->status &= ~TS_POLLING;
-       /*
-        * TS_POLLING-cleared state must be visible before we test
-        * NEED_RESCHED:
-        */
-       smp_mb();
+       if (cx->entry_method != ACPI_CSTATE_FFH) {
+               current_thread_info()->status &= ~TS_POLLING;
+               /*
+                * TS_POLLING-cleared state must be visible before we test
+                * NEED_RESCHED:
+                */
+               smp_mb();
+       }
 
        if (unlikely(need_resched())) {
                current_thread_info()->status |= TS_POLLING;
index 7247819..e306ba9 100644 (file)
@@ -125,6 +125,8 @@ acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in)
        return status;
 }
 
+static int early_pdc_done;
+
 void acpi_processor_set_pdc(acpi_handle handle)
 {
        struct acpi_object_list *obj_list;
@@ -132,6 +134,9 @@ void acpi_processor_set_pdc(acpi_handle handle)
        if (arch_has_acpi_pdc() == false)
                return;
 
+       if (early_pdc_done)
+               return;
+
        obj_list = acpi_processor_alloc_pdc();
        if (!obj_list)
                return;
@@ -151,6 +156,13 @@ static int set_early_pdc_optin(const struct dmi_system_id *id)
        return 0;
 }
 
+static int param_early_pdc_optin(char *s)
+{
+       early_pdc_optin = 1;
+       return 1;
+}
+__setup("acpi_early_pdc_eval", param_early_pdc_optin);
+
 static struct dmi_system_id __cpuinitdata early_pdc_optin_table[] = {
        {
        set_early_pdc_optin, "HP Envy", {
@@ -192,4 +204,6 @@ void __init acpi_early_processor_set_pdc(void)
        acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
                            ACPI_UINT32_MAX,
                            early_init_pdc, NULL, NULL, NULL);
+
+       early_pdc_done = 1;
 }
index 2cabadc..a959f6a 100644 (file)
@@ -413,7 +413,11 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr)
        if (result)
                goto update_bios;
 
-       return 0;
+       /* We need to call _PPC once when cpufreq starts */
+       if (ignore_ppc != 1)
+               result = acpi_processor_get_platform_limit(pr);
+
+       return result;
 
        /*
         * Having _PPC but missing frequencies (_PSS, _PCT) is a very good hint that
index ff9f622..3e00967 100644 (file)
@@ -1336,9 +1336,25 @@ static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops,
 
        if (child)
                *child = device;
-       return 0;
+
+       if (device)
+               return 0;
+       else
+               return -ENODEV;
 }
 
+/*
+ * acpi_bus_add and acpi_bus_start
+ *
+ * scan a given ACPI tree and (probably recently hot-plugged)
+ * create and add or starts found devices.
+ *
+ * If no devices were found -ENODEV is returned which does not
+ * mean that this is a real error, there just have been no suitable
+ * ACPI objects in the table trunk from which the kernel could create
+ * a device and add/start an appropriate driver.
+ */
+
 int
 acpi_bus_add(struct acpi_device **child,
             struct acpi_device *parent, acpi_handle handle, int type)
@@ -1348,8 +1364,7 @@ acpi_bus_add(struct acpi_device **child,
        memset(&ops, 0, sizeof(ops));
        ops.acpi_op_add = 1;
 
-       acpi_bus_scan(handle, &ops, child);
-       return 0;
+       return acpi_bus_scan(handle, &ops, child);
 }
 EXPORT_SYMBOL(acpi_bus_add);
 
@@ -1357,11 +1372,13 @@ int acpi_bus_start(struct acpi_device *device)
 {
        struct acpi_bus_ops ops;
 
+       if (!device)
+               return -EINVAL;
+
        memset(&ops, 0, sizeof(ops));
        ops.acpi_op_start = 1;
 
-       acpi_bus_scan(device->handle, &ops, NULL);
-       return 0;
+       return acpi_bus_scan(device->handle, &ops, NULL);
 }
 EXPORT_SYMBOL(acpi_bus_start);
 
index f336bca..8a0ed28 100644 (file)
@@ -213,7 +213,7 @@ acpi_table_parse_entries(char *id,
        unsigned long table_end;
        acpi_size tbl_size;
 
-       if (acpi_disabled)
+       if (acpi_disabled && !acpi_ht)
                return -ENODEV;
 
        if (!handler)
@@ -280,7 +280,7 @@ int __init acpi_table_parse(char *id, acpi_table_handler handler)
        struct acpi_table_header *table = NULL;
        acpi_size tbl_size;
 
-       if (acpi_disabled)
+       if (acpi_disabled && !acpi_ht)
                return -ENODEV;
 
        if (!handler)
index b343903..a6a736a 100644 (file)
@@ -3082,8 +3082,16 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        ahci_save_initial_config(pdev, hpriv);
 
        /* prepare host */
-       if (hpriv->cap & HOST_CAP_NCQ)
-               pi.flags |= ATA_FLAG_NCQ | ATA_FLAG_FPDMA_AA;
+       if (hpriv->cap & HOST_CAP_NCQ) {
+               pi.flags |= ATA_FLAG_NCQ;
+               /* Auto-activate optimization is supposed to be supported on
+                  all AHCI controllers indicating NCQ support, but it seems
+                  to be broken at least on some NVIDIA MCP79 chipsets.
+                  Until we get info on which NVIDIA chipsets don't have this
+                  issue, if any, disable AA on all NVIDIA AHCIs. */
+               if (pdev->vendor != PCI_VENDOR_ID_NVIDIA)
+                       pi.flags |= ATA_FLAG_FPDMA_AA;
+       }
 
        if (hpriv->cap & HOST_CAP_PMP)
                pi.flags |= ATA_FLAG_PMP;
index 161746d..6e2c3b0 100644 (file)
@@ -59,6 +59,8 @@ static void class_release(struct kobject *kobj)
        else
                pr_debug("class '%s' does not have a release() function, "
                         "be careful\n", class->name);
+
+       kfree(cp);
 }
 
 static struct sysfs_ops class_sysfs_ops = {
index 51042f0..7eff828 100644 (file)
@@ -243,10 +243,12 @@ static int index_to_minor(int index)
 static int __devinit virtblk_probe(struct virtio_device *vdev)
 {
        struct virtio_blk *vblk;
+       struct request_queue *q;
        int err;
        u64 cap;
-       u32 v;
-       u32 blk_size, sg_elems;
+       u32 v, blk_size, sg_elems, opt_io_size;
+       u16 min_io_size;
+       u8 physical_block_exp, alignment_offset;
 
        if (index_to_minor(index) >= 1 << MINORBITS)
                return -ENOSPC;
@@ -293,13 +295,13 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
                goto out_mempool;
        }
 
-       vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock);
-       if (!vblk->disk->queue) {
+       q = vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock);
+       if (!q) {
                err = -ENOMEM;
                goto out_put_disk;
        }
 
-       vblk->disk->queue->queuedata = vblk;
+       q->queuedata = vblk;
 
        if (index < 26) {
                sprintf(vblk->disk->disk_name, "vd%c", 'a' + index % 26);
@@ -323,10 +325,10 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
 
        /* If barriers are supported, tell block layer that queue is ordered */
        if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH))
-               blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_DRAIN_FLUSH,
+               blk_queue_ordered(q, QUEUE_ORDERED_DRAIN_FLUSH,
                                  virtblk_prepare_flush);
        else if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER))
-               blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);
+               blk_queue_ordered(q, QUEUE_ORDERED_TAG, NULL);
 
        /* If disk is read-only in the host, the guest should obey */
        if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO))
@@ -345,14 +347,14 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
        set_capacity(vblk->disk, cap);
 
        /* We can handle whatever the host told us to handle. */
-       blk_queue_max_phys_segments(vblk->disk->queue, vblk->sg_elems-2);
-       blk_queue_max_hw_segments(vblk->disk->queue, vblk->sg_elems-2);
+       blk_queue_max_phys_segments(q, vblk->sg_elems-2);
+       blk_queue_max_hw_segments(q, vblk->sg_elems-2);
 
        /* No need to bounce any requests */
-       blk_queue_bounce_limit(vblk->disk->queue, BLK_BOUNCE_ANY);
+       blk_queue_bounce_limit(q, BLK_BOUNCE_ANY);
 
        /* No real sector limit. */
-       blk_queue_max_sectors(vblk->disk->queue, -1U);
+       blk_queue_max_sectors(q, -1U);
 
        /* Host can optionally specify maximum segment size and number of
         * segments. */
@@ -360,16 +362,45 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
                                offsetof(struct virtio_blk_config, size_max),
                                &v);
        if (!err)
-               blk_queue_max_segment_size(vblk->disk->queue, v);
+               blk_queue_max_segment_size(q, v);
        else
-               blk_queue_max_segment_size(vblk->disk->queue, -1U);
+               blk_queue_max_segment_size(q, -1U);
 
        /* Host can optionally specify the block size of the device */
        err = virtio_config_val(vdev, VIRTIO_BLK_F_BLK_SIZE,
                                offsetof(struct virtio_blk_config, blk_size),
                                &blk_size);
        if (!err)
-               blk_queue_logical_block_size(vblk->disk->queue, blk_size);
+               blk_queue_logical_block_size(q, blk_size);
+       else
+               blk_size = queue_logical_block_size(q);
+
+       /* Use topology information if available */
+       err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
+                       offsetof(struct virtio_blk_config, physical_block_exp),
+                       &physical_block_exp);
+       if (!err && physical_block_exp)
+               blk_queue_physical_block_size(q,
+                               blk_size * (1 << physical_block_exp));
+
+       err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
+                       offsetof(struct virtio_blk_config, alignment_offset),
+                       &alignment_offset);
+       if (!err && alignment_offset)
+               blk_queue_alignment_offset(q, blk_size * alignment_offset);
+
+       err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
+                       offsetof(struct virtio_blk_config, min_io_size),
+                       &min_io_size);
+       if (!err && min_io_size)
+               blk_queue_io_min(q, blk_size * min_io_size);
+
+       err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
+                       offsetof(struct virtio_blk_config, opt_io_size),
+                       &opt_io_size);
+       if (!err && opt_io_size)
+               blk_queue_io_opt(q, blk_size * opt_io_size);
+
 
        add_disk(vblk->disk);
        return 0;
@@ -412,7 +443,7 @@ static struct virtio_device_id id_table[] = {
 static unsigned int features[] = {
        VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
        VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
-       VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_FLUSH
+       VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY
 };
 
 /*
index e023682..3141dd3 100644 (file)
@@ -666,6 +666,14 @@ config VIRTIO_CONSOLE
        help
          Virtio console for use with lguest and other hypervisors.
 
+         Also serves as a general-purpose serial device for data
+         transfer between the guest and host.  Character devices at
+         /dev/vportNpn will be created when corresponding ports are
+         found, where N is the device number and n is the port number
+         within that device.  If specified by the host, a sysfs
+         attribute called 'name' will be populated with a name for
+         the port which can be used by udev scripts to create a
+         symlink to the device.
 
 config HVCS
        tristate "IBM Hypervisor Virtual Console Server support"
index 6913fc3..5fe4631 100644 (file)
@@ -99,7 +99,7 @@ static int hvc_beat_config(char *p)
 
 static int __init hvc_beat_console_init(void)
 {
-       if (hvc_beat_useit && machine_is_compatible("Beat")) {
+       if (hvc_beat_useit && of_machine_is_compatible("Beat")) {
                hvc_instantiate(0, 0, &hvc_beat_get_put_ops);
        }
        return 0;
index a035ae3..213373b 100644 (file)
@@ -1,18 +1,6 @@
-/*D:300
- * The Guest console driver
- *
- * Writing console drivers is one of the few remaining Dark Arts in Linux.
- * Fortunately for us, the path of virtual consoles has been well-trodden by
- * the PowerPC folks, who wrote "hvc_console.c" to generically support any
- * virtual console.  We use that infrastructure which only requires us to write
- * the basic put_chars and get_chars functions and call the right register
- * functions.
- :*/
-
-/*M:002 The console can be flooded: while the Guest is processing input the
- * Host can send more.  Buffering in the Host could alleviate this, but it is a
- * difficult problem in general. :*/
-/* Copyright (C) 2006, 2007 Rusty Russell, IBM Corporation
+/*
+ * Copyright (C) 2006, 2007, 2009 Rusty Russell, IBM Corporation
+ * Copyright (C) 2009, 2010 Red Hat, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * 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/cdev.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
 #include <linux/err.h>
+#include <linux/fs.h>
 #include <linux/init.h>
+#include <linux/list.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
 #include <linux/virtio.h>
 #include <linux/virtio_console.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
 #include "hvc_console.h"
 
-/*D:340 These represent our input and output console queues, and the virtio
- * operations for them. */
-static struct virtqueue *in_vq, *out_vq;
-static struct virtio_device *vdev;
+/*
+ * This is a global struct for storing common data for all the devices
+ * this driver handles.
+ *
+ * Mainly, it has a linked list for all the consoles in one place so
+ * that callbacks from hvc for get_chars(), put_chars() work properly
+ * across multiple devices and multiple ports per device.
+ */
+struct ports_driver_data {
+       /* Used for registering chardevs */
+       struct class *class;
+
+       /* Used for exporting per-port information to debugfs */
+       struct dentry *debugfs_dir;
+
+       /* Number of devices this driver is handling */
+       unsigned int index;
+
+       /*
+        * This is used to keep track of the number of hvc consoles
+        * spawned by this driver.  This number is given as the first
+        * argument to hvc_alloc().  To correctly map an initial
+        * console spawned via hvc_instantiate to the console being
+        * hooked up via hvc_alloc, we need to pass the same vtermno.
+        *
+        * We also just assume the first console being initialised was
+        * the first one that got used as the initial console.
+        */
+       unsigned int next_vtermno;
+
+       /* All the console devices handled by this driver */
+       struct list_head consoles;
+};
+static struct ports_driver_data pdrvdata;
+
+DEFINE_SPINLOCK(pdrvdata_lock);
+
+/* This struct holds information that's relevant only for console ports */
+struct console {
+       /* We'll place all consoles in a list in the pdrvdata struct */
+       struct list_head list;
+
+       /* The hvc device associated with this console port */
+       struct hvc_struct *hvc;
+
+       /*
+        * This number identifies the number that we used to register
+        * with hvc in hvc_instantiate() and hvc_alloc(); this is the
+        * number passed on by the hvc callbacks to us to
+        * differentiate between the other console ports handled by
+        * this driver
+        */
+       u32 vtermno;
+};
+
+struct port_buffer {
+       char *buf;
+
+       /* size of the buffer in *buf above */
+       size_t size;
+
+       /* used length of the buffer */
+       size_t len;
+       /* offset in the buf from which to consume data */
+       size_t offset;
+};
+
+/*
+ * This is a per-device struct that stores data common to all the
+ * ports for that device (vdev->priv).
+ */
+struct ports_device {
+       /*
+        * Workqueue handlers where we process deferred work after
+        * notification
+        */
+       struct work_struct control_work;
+       struct work_struct config_work;
+
+       struct list_head ports;
+
+       /* To protect the list of ports */
+       spinlock_t ports_lock;
+
+       /* To protect the vq operations for the control channel */
+       spinlock_t cvq_lock;
+
+       /* The current config space is stored here */
+       struct virtio_console_config config;
+
+       /* The virtio device we're associated with */
+       struct virtio_device *vdev;
+
+       /*
+        * A couple of virtqueues for the control channel: one for
+        * guest->host transfers, one for host->guest transfers
+        */
+       struct virtqueue *c_ivq, *c_ovq;
+
+       /* Array of per-port IO virtqueues */
+       struct virtqueue **in_vqs, **out_vqs;
+
+       /* Used for numbering devices for sysfs and debugfs */
+       unsigned int drv_index;
+
+       /* Major number for this device.  Ports will be created as minors. */
+       int chr_major;
+};
+
+/* This struct holds the per-port data */
+struct port {
+       /* Next port in the list, head is in the ports_device */
+       struct list_head list;
+
+       /* Pointer to the parent virtio_console device */
+       struct ports_device *portdev;
+
+       /* The current buffer from which data has to be fed to readers */
+       struct port_buffer *inbuf;
+
+       /*
+        * To protect the operations on the in_vq associated with this
+        * port.  Has to be a spinlock because it can be called from
+        * interrupt context (get_char()).
+        */
+       spinlock_t inbuf_lock;
+
+       /* The IO vqs for this port */
+       struct virtqueue *in_vq, *out_vq;
+
+       /* File in the debugfs directory that exposes this port's information */
+       struct dentry *debugfs_file;
+
+       /*
+        * The entries in this struct will be valid if this port is
+        * hooked up to an hvc console
+        */
+       struct console cons;
+
+       /* Each port associates with a separate char device */
+       struct cdev cdev;
+       struct device *dev;
+
+       /* A waitqueue for poll() or blocking read operations */
+       wait_queue_head_t waitqueue;
+
+       /* The 'name' of the port that we expose via sysfs properties */
+       char *name;
+
+       /* The 'id' to identify the port with the Host */
+       u32 id;
+
+       /* Is the host device open */
+       bool host_connected;
+
+       /* We should allow only one process to open a port */
+       bool guest_connected;
+};
+
+/* This is the very early arch-specified put chars function. */
+static int (*early_put_chars)(u32, const char *, int);
+
+static struct port *find_port_by_vtermno(u32 vtermno)
+{
+       struct port *port;
+       struct console *cons;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pdrvdata_lock, flags);
+       list_for_each_entry(cons, &pdrvdata.consoles, list) {
+               if (cons->vtermno == vtermno) {
+                       port = container_of(cons, struct port, cons);
+                       goto out;
+               }
+       }
+       port = NULL;
+out:
+       spin_unlock_irqrestore(&pdrvdata_lock, flags);
+       return port;
+}
+
+static struct port *find_port_by_id(struct ports_device *portdev, u32 id)
+{
+       struct port *port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&portdev->ports_lock, flags);
+       list_for_each_entry(port, &portdev->ports, list)
+               if (port->id == id)
+                       goto out;
+       port = NULL;
+out:
+       spin_unlock_irqrestore(&portdev->ports_lock, flags);
+
+       return port;
+}
+
+static struct port *find_port_by_vq(struct ports_device *portdev,
+                                   struct virtqueue *vq)
+{
+       struct port *port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&portdev->ports_lock, flags);
+       list_for_each_entry(port, &portdev->ports, list)
+               if (port->in_vq == vq || port->out_vq == vq)
+                       goto out;
+       port = NULL;
+out:
+       spin_unlock_irqrestore(&portdev->ports_lock, flags);
+       return port;
+}
+
+static bool is_console_port(struct port *port)
+{
+       if (port->cons.hvc)
+               return true;
+       return false;
+}
+
+static inline bool use_multiport(struct ports_device *portdev)
+{
+       /*
+        * This condition can be true when put_chars is called from
+        * early_init
+        */
+       if (!portdev->vdev)
+               return 0;
+       return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
+}
 
-/* This is our input buffer, and how much data is left in it. */
-static unsigned int in_len;
-static char *in, *inbuf;
+static void free_buf(struct port_buffer *buf)
+{
+       kfree(buf->buf);
+       kfree(buf);
+}
+
+static struct port_buffer *alloc_buf(size_t buf_size)
+{
+       struct port_buffer *buf;
 
-/* The operations for our console. */
-static struct hv_ops virtio_cons;
+       buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+       if (!buf)
+               goto fail;
+       buf->buf = kzalloc(buf_size, GFP_KERNEL);
+       if (!buf->buf)
+               goto free_buf;
+       buf->len = 0;
+       buf->offset = 0;
+       buf->size = buf_size;
+       return buf;
+
+free_buf:
+       kfree(buf);
+fail:
+       return NULL;
+}
+
+/* Callers should take appropriate locks */
+static void *get_inbuf(struct port *port)
+{
+       struct port_buffer *buf;
+       struct virtqueue *vq;
+       unsigned int len;
 
-/* The hvc device */
-static struct hvc_struct *hvc;
+       vq = port->in_vq;
+       buf = vq->vq_ops->get_buf(vq, &len);
+       if (buf) {
+               buf->len = len;
+               buf->offset = 0;
+       }
+       return buf;
+}
 
-/*D:310 The put_chars() callback is pretty straightforward.
+/*
+ * Create a scatter-gather list representing our input buffer and put
+ * it in the queue.
  *
- * We turn the characters into a scatter-gather list, add it to the output
- * queue and then kick the Host.  Then we sit here waiting for it to finish:
- * inefficient in theory, but in practice implementations will do it
- * immediately (lguest's Launcher does). */
-static int put_chars(u32 vtermno, const char *buf, int count)
+ * Callers should take appropriate locks.
+ */
+static int add_inbuf(struct virtqueue *vq, struct port_buffer *buf)
 {
        struct scatterlist sg[1];
+       int ret;
+
+       sg_init_one(sg, buf->buf, buf->size);
+
+       ret = vq->vq_ops->add_buf(vq, sg, 0, 1, buf);
+       vq->vq_ops->kick(vq);
+       return ret;
+}
+
+/* Discard any unread data this port has. Callers lockers. */
+static void discard_port_data(struct port *port)
+{
+       struct port_buffer *buf;
+       struct virtqueue *vq;
        unsigned int len;
+       int ret;
 
-       /* This is a convenient routine to initialize a single-elem sg list */
-       sg_init_one(sg, buf, count);
+       vq = port->in_vq;
+       if (port->inbuf)
+               buf = port->inbuf;
+       else
+               buf = vq->vq_ops->get_buf(vq, &len);
 
-       /* add_buf wants a token to identify this buffer: we hand it any
-        * non-NULL pointer, since there's only ever one buffer. */
-       if (out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, (void *)1) >= 0) {
-               /* Tell Host to go! */
-               out_vq->vq_ops->kick(out_vq);
-               /* Chill out until it's done with the buffer. */
-               while (!out_vq->vq_ops->get_buf(out_vq, &len))
-                       cpu_relax();
+       ret = 0;
+       while (buf) {
+               if (add_inbuf(vq, buf) < 0) {
+                       ret++;
+                       free_buf(buf);
+               }
+               buf = vq->vq_ops->get_buf(vq, &len);
        }
+       port->inbuf = NULL;
+       if (ret)
+               dev_warn(port->dev, "Errors adding %d buffers back to vq\n",
+                        ret);
+}
 
-       /* We're expected to return the amount of data we wrote: all of it. */
-       return count;
+static bool port_has_data(struct port *port)
+{
+       unsigned long flags;
+       bool ret;
+
+       spin_lock_irqsave(&port->inbuf_lock, flags);
+       if (port->inbuf) {
+               ret = true;
+               goto out;
+       }
+       port->inbuf = get_inbuf(port);
+       if (port->inbuf) {
+               ret = true;
+               goto out;
+       }
+       ret = false;
+out:
+       spin_unlock_irqrestore(&port->inbuf_lock, flags);
+       return ret;
 }
 
-/* Create a scatter-gather list representing our input buffer and put it in the
- * queue. */
-static void add_inbuf(void)
+static ssize_t send_control_msg(struct port *port, unsigned int event,
+                               unsigned int value)
 {
        struct scatterlist sg[1];
-       sg_init_one(sg, inbuf, PAGE_SIZE);
+       struct virtio_console_control cpkt;
+       struct virtqueue *vq;
+       int len;
+
+       if (!use_multiport(port->portdev))
+               return 0;
+
+       cpkt.id = port->id;
+       cpkt.event = event;
+       cpkt.value = value;
+
+       vq = port->portdev->c_ovq;
 
-       /* We should always be able to add one buffer to an empty queue. */
-       if (in_vq->vq_ops->add_buf(in_vq, sg, 0, 1, inbuf) < 0)
-               BUG();
-       in_vq->vq_ops->kick(in_vq);
+       sg_init_one(sg, &cpkt, sizeof(cpkt));
+       if (vq->vq_ops->add_buf(vq, sg, 1, 0, &cpkt) >= 0) {
+               vq->vq_ops->kick(vq);
+               while (!vq->vq_ops->get_buf(vq, &len))
+                       cpu_relax();
+       }
+       return 0;
 }
 
-/*D:350 get_chars() is the callback from the hvc_console infrastructure when
- * an interrupt is received.
- *
- * Most of the code deals with the fact that the hvc_console() infrastructure
- * only asks us for 16 bytes at a time.  We keep in_offset and in_used fields
- * for partially-filled buffers. */
-static int get_chars(u32 vtermno, char *buf, int count)
+static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count)
 {
-       /* If we don't have an input queue yet, we can't get input. */
-       BUG_ON(!in_vq);
+       struct scatterlist sg[1];
+       struct virtqueue *out_vq;
+       ssize_t ret;
+       unsigned int len;
+
+       out_vq = port->out_vq;
+
+       sg_init_one(sg, in_buf, in_count);
+       ret = out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, in_buf);
+
+       /* Tell Host to go! */
+       out_vq->vq_ops->kick(out_vq);
+
+       if (ret < 0) {
+               len = 0;
+               goto fail;
+       }
+
+       /*
+        * Wait till the host acknowledges it pushed out the data we
+        * sent. Also ensure we return to userspace the number of
+        * bytes that were successfully consumed by the host.
+        */
+       while (!out_vq->vq_ops->get_buf(out_vq, &len))
+               cpu_relax();
+fail:
+       /* We're expected to return the amount of data we wrote */
+       return len;
+}
+
+/*
+ * Give out the data that's requested from the buffer that we have
+ * queued up.
+ */
+static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count,
+                           bool to_user)
+{
+       struct port_buffer *buf;
+       unsigned long flags;
+
+       if (!out_count || !port_has_data(port))
+               return 0;
+
+       buf = port->inbuf;
+       out_count = min(out_count, buf->len - buf->offset);
+
+       if (to_user) {
+               ssize_t ret;
+
+               ret = copy_to_user(out_buf, buf->buf + buf->offset, out_count);
+               if (ret)
+                       return -EFAULT;
+       } else {
+               memcpy(out_buf, buf->buf + buf->offset, out_count);
+       }
+
+       buf->offset += out_count;
+
+       if (buf->offset == buf->len) {
+               /*
+                * We're done using all the data in this buffer.
+                * Re-queue so that the Host can send us more data.
+                */
+               spin_lock_irqsave(&port->inbuf_lock, flags);
+               port->inbuf = NULL;
+
+               if (add_inbuf(port->in_vq, buf) < 0)
+                       dev_warn(port->dev, "failed add_buf\n");
+
+               spin_unlock_irqrestore(&port->inbuf_lock, flags);
+       }
+       /* Return the number of bytes actually copied */
+       return out_count;
+}
 
-       /* No buffer?  Try to get one. */
-       if (!in_len) {
-               in = in_vq->vq_ops->get_buf(in_vq, &in_len);
-               if (!in)
+/* The condition that must be true for polling to end */
+static bool wait_is_over(struct port *port)
+{
+       return port_has_data(port) || !port->host_connected;
+}
+
+static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
+                             size_t count, loff_t *offp)
+{
+       struct port *port;
+       ssize_t ret;
+
+       port = filp->private_data;
+
+       if (!port_has_data(port)) {
+               /*
+                * If nothing's connected on the host just return 0 in
+                * case of list_empty; this tells the userspace app
+                * that there's no connection
+                */
+               if (!port->host_connected)
                        return 0;
+               if (filp->f_flags & O_NONBLOCK)
+                       return -EAGAIN;
+
+               ret = wait_event_interruptible(port->waitqueue,
+                                              wait_is_over(port));
+               if (ret < 0)
+                       return ret;
+       }
+       /*
+        * We could've received a disconnection message while we were
+        * waiting for more data.
+        *
+        * This check is not clubbed in the if() statement above as we
+        * might receive some data as well as the host could get
+        * disconnected after we got woken up from our wait.  So we
+        * really want to give off whatever data we have and only then
+        * check for host_connected.
+        */
+       if (!port_has_data(port) && !port->host_connected)
+               return 0;
+
+       return fill_readbuf(port, ubuf, count, true);
+}
+
+static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
+                              size_t count, loff_t *offp)
+{
+       struct port *port;
+       char *buf;
+       ssize_t ret;
+
+       port = filp->private_data;
+
+       count = min((size_t)(32 * 1024), count);
+
+       buf = kmalloc(count, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       ret = copy_from_user(buf, ubuf, count);
+       if (ret) {
+               ret = -EFAULT;
+               goto free_buf;
        }
 
-       /* You want more than we have to give?  Well, try wanting less! */
-       if (in_len < count)
-               count = in_len;
+       ret = send_buf(port, buf, count);
+free_buf:
+       kfree(buf);
+       return ret;
+}
+
+static unsigned int port_fops_poll(struct file *filp, poll_table *wait)
+{
+       struct port *port;
+       unsigned int ret;
+
+       port = filp->private_data;
+       poll_wait(filp, &port->waitqueue, wait);
+
+       ret = 0;
+       if (port->inbuf)
+               ret |= POLLIN | POLLRDNORM;
+       if (port->host_connected)
+               ret |= POLLOUT;
+       if (!port->host_connected)
+               ret |= POLLHUP;
+
+       return ret;
+}
+
+static int port_fops_release(struct inode *inode, struct file *filp)
+{
+       struct port *port;
+
+       port = filp->private_data;
+
+       /* Notify host of port being closed */
+       send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
+
+       spin_lock_irq(&port->inbuf_lock);
+       port->guest_connected = false;
+
+       discard_port_data(port);
+
+       spin_unlock_irq(&port->inbuf_lock);
+
+       return 0;
+}
+
+static int port_fops_open(struct inode *inode, struct file *filp)
+{
+       struct cdev *cdev = inode->i_cdev;
+       struct port *port;
+
+       port = container_of(cdev, struct port, cdev);
+       filp->private_data = port;
+
+       /*
+        * Don't allow opening of console port devices -- that's done
+        * via /dev/hvc
+        */
+       if (is_console_port(port))
+               return -ENXIO;
+
+       /* Allow only one process to open a particular port at a time */
+       spin_lock_irq(&port->inbuf_lock);
+       if (port->guest_connected) {
+               spin_unlock_irq(&port->inbuf_lock);
+               return -EMFILE;
+       }
 
-       /* Copy across to their buffer and increment offset. */
-       memcpy(buf, in, count);
-       in += count;
-       in_len -= count;
+       port->guest_connected = true;
+       spin_unlock_irq(&port->inbuf_lock);
 
-       /* Finished?  Re-register buffer so Host will use it again. */
-       if (in_len == 0)
-               add_inbuf();
+       /* Notify host of port being opened */
+       send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1);
 
-       return count;
+       return 0;
 }
-/*:*/
 
-/*D:320 Console drivers are initialized very early so boot messages can go out,
- * so we do things slightly differently from the generic virtio initialization
- * of the net and block drivers.
+/*
+ * The file operations that we support: programs in the guest can open
+ * a console device, read from it, write to it, poll for data and
+ * close it.  The devices are at
+ *   /dev/vport<device number>p<port number>
+ */
+static const struct file_operations port_fops = {
+       .owner = THIS_MODULE,
+       .open  = port_fops_open,
+       .read  = port_fops_read,
+       .write = port_fops_write,
+       .poll  = port_fops_poll,
+       .release = port_fops_release,
+};
+
+/*
+ * The put_chars() callback is pretty straightforward.
  *
- * At this stage, the console is output-only.  It's too early to set up a
- * virtqueue, so we let the drivers do some boutique early-output thing. */
-int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int))
+ * We turn the characters into a scatter-gather list, add it to the
+ * output queue and then kick the Host.  Then we sit here waiting for
+ * it to finish: inefficient in theory, but in practice
+ * implementations will do it immediately (lguest's Launcher does).
+ */
+static int put_chars(u32 vtermno, const char *buf, int count)
 {
-       virtio_cons.put_chars = put_chars;
-       return hvc_instantiate(0, 0, &virtio_cons);
+       struct port *port;
+
+       port = find_port_by_vtermno(vtermno);
+       if (!port)
+               return 0;
+
+       if (unlikely(early_put_chars))
+               return early_put_chars(vtermno, buf, count);
+
+       return send_buf(port, (void *)buf, count);
 }
 
 /*
- * virtio console configuration. This supports:
- * - console resize
+ * get_chars() is the callback from the hvc_console infrastructure
+ * when an interrupt is received.
+ *
+ * We call out to fill_readbuf that gets us the required data from the
+ * buffers that are queued up.
  */
-static void virtcons_apply_config(struct virtio_device *dev)
+static int get_chars(u32 vtermno, char *buf, int count)
 {
+       struct port *port;
+
+       port = find_port_by_vtermno(vtermno);
+       if (!port)
+               return 0;
+
+       /* If we don't have an input queue yet, we can't get input. */
+       BUG_ON(!port->in_vq);
+
+       return fill_readbuf(port, buf, count, false);
+}
+
+static void resize_console(struct port *port)
+{
+       struct virtio_device *vdev;
        struct winsize ws;
 
-       if (virtio_has_feature(dev, VIRTIO_CONSOLE_F_SIZE)) {
-               dev->config->get(dev,
-                                offsetof(struct virtio_console_config, cols),
-                                &ws.ws_col, sizeof(u16));
-               dev->config->get(dev,
-                                offsetof(struct virtio_console_config, rows),
-                                &ws.ws_row, sizeof(u16));
-               hvc_resize(hvc, ws);
+       vdev = port->portdev->vdev;
+       if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE)) {
+               vdev->config->get(vdev,
+                                 offsetof(struct virtio_console_config, cols),
+                                 &ws.ws_col, sizeof(u16));
+               vdev->config->get(vdev,
+                                 offsetof(struct virtio_console_config, rows),
+                                 &ws.ws_row, sizeof(u16));
+               hvc_resize(port->cons.hvc, ws);
        }
 }
 
-/*
- * we support only one console, the hvc struct is a global var
- * We set the configuration at this point, since we now have a tty
- */
+/* We set the configuration at this point, since we now have a tty */
 static int notifier_add_vio(struct hvc_struct *hp, int data)
 {
+       struct port *port;
+
+       port = find_port_by_vtermno(hp->vtermno);
+       if (!port)
+               return -EINVAL;
+
        hp->irq_requested = 1;
-       virtcons_apply_config(vdev);
+       resize_console(port);
 
        return 0;
 }
@@ -173,79 +713,797 @@ static void notifier_del_vio(struct hvc_struct *hp, int data)
        hp->irq_requested = 0;
 }
 
-static void hvc_handle_input(struct virtqueue *vq)
+/* The operations for console ports. */
+static const struct hv_ops hv_ops = {
+       .get_chars = get_chars,
+       .put_chars = put_chars,
+       .notifier_add = notifier_add_vio,
+       .notifier_del = notifier_del_vio,
+       .notifier_hangup = notifier_del_vio,
+};
+
+/*
+ * Console drivers are initialized very early so boot messages can go
+ * out, so we do things slightly differently from the generic virtio
+ * initialization of the net and block drivers.
+ *
+ * At this stage, the console is output-only.  It's too early to set
+ * up a virtqueue, so we let the drivers do some boutique early-output
+ * thing.
+ */
+int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int))
 {
-       if (hvc_poll(hvc))
+       early_put_chars = put_chars;
+       return hvc_instantiate(0, 0, &hv_ops);
+}
+
+int init_port_console(struct port *port)
+{
+       int ret;
+
+       /*
+        * The Host's telling us this port is a console port.  Hook it
+        * up with an hvc console.
+        *
+        * To set up and manage our virtual console, we call
+        * hvc_alloc().
+        *
+        * The first argument of hvc_alloc() is the virtual console
+        * number.  The second argument is the parameter for the
+        * notification mechanism (like irq number).  We currently
+        * leave this as zero, virtqueues have implicit notifications.
+        *
+        * The third argument is a "struct hv_ops" containing the
+        * put_chars() get_chars(), notifier_add() and notifier_del()
+        * pointers.  The final argument is the output buffer size: we
+        * can do any size, so we put PAGE_SIZE here.
+        */
+       port->cons.vtermno = pdrvdata.next_vtermno;
+
+       port->cons.hvc = hvc_alloc(port->cons.vtermno, 0, &hv_ops, PAGE_SIZE);
+       if (IS_ERR(port->cons.hvc)) {
+               ret = PTR_ERR(port->cons.hvc);
+               dev_err(port->dev,
+                       "error %d allocating hvc for port\n", ret);
+               port->cons.hvc = NULL;
+               return ret;
+       }
+       spin_lock_irq(&pdrvdata_lock);
+       pdrvdata.next_vtermno++;
+       list_add_tail(&port->cons.list, &pdrvdata.consoles);
+       spin_unlock_irq(&pdrvdata_lock);
+       port->guest_connected = true;
+
+       /* Notify host of port being opened */
+       send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
+
+       return 0;
+}
+
+static ssize_t show_port_name(struct device *dev,
+                             struct device_attribute *attr, char *buffer)
+{
+       struct port *port;
+
+       port = dev_get_drvdata(dev);
+
+       return sprintf(buffer, "%s\n", port->name);
+}
+
+static DEVICE_ATTR(name, S_IRUGO, show_port_name, NULL);
+
+static struct attribute *port_sysfs_entries[] = {
+       &dev_attr_name.attr,
+       NULL
+};
+
+static struct attribute_group port_attribute_group = {
+       .name = NULL,           /* put in device directory */
+       .attrs = port_sysfs_entries,
+};
+
+static int debugfs_open(struct inode *inode, struct file *filp)
+{
+       filp->private_data = inode->i_private;
+       return 0;
+}
+
+static ssize_t debugfs_read(struct file *filp, char __user *ubuf,
+                           size_t count, loff_t *offp)
+{
+       struct port *port;
+       char *buf;
+       ssize_t ret, out_offset, out_count;
+
+       out_count = 1024;
+       buf = kmalloc(out_count, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       port = filp->private_data;
+       out_offset = 0;
+       out_offset += snprintf(buf + out_offset, out_count,
+                              "name: %s\n", port->name ? port->name : "");
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "guest_connected: %d\n", port->guest_connected);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "host_connected: %d\n", port->host_connected);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "is_console: %s\n",
+                              is_console_port(port) ? "yes" : "no");
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "console_vtermno: %u\n", port->cons.vtermno);
+
+       ret = simple_read_from_buffer(ubuf, count, offp, buf, out_offset);
+       kfree(buf);
+       return ret;
+}
+
+static const struct file_operations port_debugfs_ops = {
+       .owner = THIS_MODULE,
+       .open  = debugfs_open,
+       .read  = debugfs_read,
+};
+
+/* Remove all port-specific data. */
+static int remove_port(struct port *port)
+{
+       struct port_buffer *buf;
+
+       spin_lock_irq(&port->portdev->ports_lock);
+       list_del(&port->list);
+       spin_unlock_irq(&port->portdev->ports_lock);
+
+       if (is_console_port(port)) {
+               spin_lock_irq(&pdrvdata_lock);
+               list_del(&port->cons.list);
+               spin_unlock_irq(&pdrvdata_lock);
+               hvc_remove(port->cons.hvc);
+       }
+       if (port->guest_connected)
+               send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
+
+       sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
+       device_destroy(pdrvdata.class, port->dev->devt);
+       cdev_del(&port->cdev);
+
+       /* Remove unused data this port might have received. */
+       discard_port_data(port);
+
+       /* Remove buffers we queued up for the Host to send us data in. */
+       while ((buf = port->in_vq->vq_ops->detach_unused_buf(port->in_vq)))
+               free_buf(buf);
+
+       kfree(port->name);
+
+       debugfs_remove(port->debugfs_file);
+
+       kfree(port);
+       return 0;
+}
+
+/* Any private messages that the Host and Guest want to share */
+static void handle_control_message(struct ports_device *portdev,
+                                  struct port_buffer *buf)
+{
+       struct virtio_console_control *cpkt;
+       struct port *port;
+       size_t name_size;
+       int err;
+
+       cpkt = (struct virtio_console_control *)(buf->buf + buf->offset);
+
+       port = find_port_by_id(portdev, cpkt->id);
+       if (!port) {
+               /* No valid header at start of buffer.  Drop it. */
+               dev_dbg(&portdev->vdev->dev,
+                       "Invalid index %u in control packet\n", cpkt->id);
+               return;
+       }
+
+       switch (cpkt->event) {
+       case VIRTIO_CONSOLE_CONSOLE_PORT:
+               if (!cpkt->value)
+                       break;
+               if (is_console_port(port))
+                       break;
+
+               init_port_console(port);
+               /*
+                * Could remove the port here in case init fails - but
+                * have to notify the host first.
+                */
+               break;
+       case VIRTIO_CONSOLE_RESIZE:
+               if (!is_console_port(port))
+                       break;
+               port->cons.hvc->irq_requested = 1;
+               resize_console(port);
+               break;
+       case VIRTIO_CONSOLE_PORT_OPEN:
+               port->host_connected = cpkt->value;
+               wake_up_interruptible(&port->waitqueue);
+               break;
+       case VIRTIO_CONSOLE_PORT_NAME:
+               /*
+                * Skip the size of the header and the cpkt to get the size
+                * of the name that was sent
+                */
+               name_size = buf->len - buf->offset - sizeof(*cpkt) + 1;
+
+               port->name = kmalloc(name_size, GFP_KERNEL);
+               if (!port->name) {
+                       dev_err(port->dev,
+                               "Not enough space to store port name\n");
+                       break;
+               }
+               strncpy(port->name, buf->buf + buf->offset + sizeof(*cpkt),
+                       name_size - 1);
+               port->name[name_size - 1] = 0;
+
+               /*
+                * Since we only have one sysfs attribute, 'name',
+                * create it only if we have a name for the port.
+                */
+               err = sysfs_create_group(&port->dev->kobj,
+                                        &port_attribute_group);
+               if (err)
+                       dev_err(port->dev,
+                               "Error %d creating sysfs device attributes\n",
+                               err);
+
+               break;
+       case VIRTIO_CONSOLE_PORT_REMOVE:
+               /*
+                * Hot unplug the port.  We don't decrement nr_ports
+                * since we don't want to deal with extra complexities
+                * of using the lowest-available port id: We can just
+                * pick up the nr_ports number as the id and not have
+                * userspace send it to us.  This helps us in two
+                * ways:
+                *
+                * - We don't need to have a 'port_id' field in the
+                *   config space when a port is hot-added.  This is a
+                *   good thing as we might queue up multiple hotplug
+                *   requests issued in our workqueue.
+                *
+                * - Another way to deal with this would have been to
+                *   use a bitmap of the active ports and select the
+                *   lowest non-active port from that map.  That
+                *   bloats the already tight config space and we
+                *   would end up artificially limiting the
+                *   max. number of ports to sizeof(bitmap).  Right
+                *   now we can support 2^32 ports (as the port id is
+                *   stored in a u32 type).
+                *
+                */
+               remove_port(port);
+               break;
+       }
+}
+
+static void control_work_handler(struct work_struct *work)
+{
+       struct ports_device *portdev;
+       struct virtqueue *vq;
+       struct port_buffer *buf;
+       unsigned int len;
+
+       portdev = container_of(work, struct ports_device, control_work);
+       vq = portdev->c_ivq;
+
+       spin_lock(&portdev->cvq_lock);
+       while ((buf = vq->vq_ops->get_buf(vq, &len))) {
+               spin_unlock(&portdev->cvq_lock);
+
+               buf->len = len;
+               buf->offset = 0;
+
+               handle_control_message(portdev, buf);
+
+               spin_lock(&portdev->cvq_lock);
+               if (add_inbuf(portdev->c_ivq, buf) < 0) {
+                       dev_warn(&portdev->vdev->dev,
+                                "Error adding buffer to queue\n");
+                       free_buf(buf);
+               }
+       }
+       spin_unlock(&portdev->cvq_lock);
+}
+
+static void in_intr(struct virtqueue *vq)
+{
+       struct port *port;
+       unsigned long flags;
+
+       port = find_port_by_vq(vq->vdev->priv, vq);
+       if (!port)
+               return;
+
+       spin_lock_irqsave(&port->inbuf_lock, flags);
+       if (!port->inbuf)
+               port->inbuf = get_inbuf(port);
+
+       /*
+        * Don't queue up data when port is closed.  This condition
+        * can be reached when a console port is not yet connected (no
+        * tty is spawned) and the host sends out data to console
+        * ports.  For generic serial ports, the host won't
+        * (shouldn't) send data till the guest is connected.
+        */
+       if (!port->guest_connected)
+               discard_port_data(port);
+
+       spin_unlock_irqrestore(&port->inbuf_lock, flags);
+
+       wake_up_interruptible(&port->waitqueue);
+
+       if (is_console_port(port) && hvc_poll(port->cons.hvc))
                hvc_kick();
 }
 
-/*D:370 Once we're further in boot, we get probed like any other virtio device.
- * At this stage we set up the output virtqueue.
- *
- * To set up and manage our virtual console, we call hvc_alloc().  Since we
- * never remove the console device we never need this pointer again.
+static void control_intr(struct virtqueue *vq)
+{
+       struct ports_device *portdev;
+
+       portdev = vq->vdev->priv;
+       schedule_work(&portdev->control_work);
+}
+
+static void config_intr(struct virtio_device *vdev)
+{
+       struct ports_device *portdev;
+
+       portdev = vdev->priv;
+       if (use_multiport(portdev)) {
+               /* Handle port hot-add */
+               schedule_work(&portdev->config_work);
+       }
+       /*
+        * We'll use this way of resizing only for legacy support.
+        * For newer userspace (VIRTIO_CONSOLE_F_MULTPORT+), use
+        * control messages to indicate console size changes so that
+        * it can be done per-port
+        */
+       resize_console(find_port_by_id(portdev, 0));
+}
+
+static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock)
+{
+       struct port_buffer *buf;
+       unsigned int ret;
+       int err;
+
+       ret = 0;
+       do {
+               buf = alloc_buf(PAGE_SIZE);
+               if (!buf)
+                       break;
+
+               spin_lock_irq(lock);
+               err = add_inbuf(vq, buf);
+               if (err < 0) {
+                       spin_unlock_irq(lock);
+                       free_buf(buf);
+                       break;
+               }
+               ret++;
+               spin_unlock_irq(lock);
+       } while (err > 0);
+
+       return ret;
+}
+
+static int add_port(struct ports_device *portdev, u32 id)
+{
+       char debugfs_name[16];
+       struct port *port;
+       struct port_buffer *buf;
+       dev_t devt;
+       int err;
+
+       port = kmalloc(sizeof(*port), GFP_KERNEL);
+       if (!port) {
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       port->portdev = portdev;
+       port->id = id;
+
+       port->name = NULL;
+       port->inbuf = NULL;
+       port->cons.hvc = NULL;
+
+       port->host_connected = port->guest_connected = false;
+
+       port->in_vq = portdev->in_vqs[port->id];
+       port->out_vq = portdev->out_vqs[port->id];
+
+       cdev_init(&port->cdev, &port_fops);
+
+       devt = MKDEV(portdev->chr_major, id);
+       err = cdev_add(&port->cdev, devt, 1);
+       if (err < 0) {
+               dev_err(&port->portdev->vdev->dev,
+                       "Error %d adding cdev for port %u\n", err, id);
+               goto free_port;
+       }
+       port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev,
+                                 devt, port, "vport%up%u",
+                                 port->portdev->drv_index, id);
+       if (IS_ERR(port->dev)) {
+               err = PTR_ERR(port->dev);
+               dev_err(&port->portdev->vdev->dev,
+                       "Error %d creating device for port %u\n",
+                       err, id);
+               goto free_cdev;
+       }
+
+       spin_lock_init(&port->inbuf_lock);
+       init_waitqueue_head(&port->waitqueue);
+
+       /* Fill the in_vq with buffers so the host can send us data. */
+       err = fill_queue(port->in_vq, &port->inbuf_lock);
+       if (!err) {
+               dev_err(port->dev, "Error allocating inbufs\n");
+               err = -ENOMEM;
+               goto free_device;
+       }
+
+       /*
+        * If we're not using multiport support, this has to be a console port
+        */
+       if (!use_multiport(port->portdev)) {
+               err = init_port_console(port);
+               if (err)
+                       goto free_inbufs;
+       }
+
+       spin_lock_irq(&portdev->ports_lock);
+       list_add_tail(&port->list, &port->portdev->ports);
+       spin_unlock_irq(&portdev->ports_lock);
+
+       /*
+        * Tell the Host we're set so that it can send us various
+        * configuration parameters for this port (eg, port name,
+        * caching, whether this is a console port, etc.)
+        */
+       send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
+
+       if (pdrvdata.debugfs_dir) {
+               /*
+                * Finally, create the debugfs file that we can use to
+                * inspect a port's state at any time
+                */
+               sprintf(debugfs_name, "vport%up%u",
+                       port->portdev->drv_index, id);
+               port->debugfs_file = debugfs_create_file(debugfs_name, 0444,
+                                                        pdrvdata.debugfs_dir,
+                                                        port,
+                                                        &port_debugfs_ops);
+       }
+       return 0;
+
+free_inbufs:
+       while ((buf = port->in_vq->vq_ops->detach_unused_buf(port->in_vq)))
+               free_buf(buf);
+free_device:
+       device_destroy(pdrvdata.class, port->dev->devt);
+free_cdev:
+       cdev_del(&port->cdev);
+free_port:
+       kfree(port);
+fail:
+       return err;
+}
+
+/*
+ * The workhandler for config-space updates.
  *
- * Finally we put our input buffer in the input queue, ready to receive. */
-static int __devinit virtcons_probe(struct virtio_device *dev)
+ * This is called when ports are hot-added.
+ */
+static void config_work_handler(struct work_struct *work)
+{
+       struct virtio_console_config virtconconf;
+       struct ports_device *portdev;
+       struct virtio_device *vdev;
+       int err;
+
+       portdev = container_of(work, struct ports_device, config_work);
+
+       vdev = portdev->vdev;
+       vdev->config->get(vdev,
+                         offsetof(struct virtio_console_config, nr_ports),
+                         &virtconconf.nr_ports,
+                         sizeof(virtconconf.nr_ports));
+
+       if (portdev->config.nr_ports == virtconconf.nr_ports) {
+               /*
+                * Port 0 got hot-added.  Since we already did all the
+                * other initialisation for it, just tell the Host
+                * that the port is ready if we find the port.  In
+                * case the port was hot-removed earlier, we call
+                * add_port to add the port.
+                */
+               struct port *port;
+
+               port = find_port_by_id(portdev, 0);
+               if (!port)
+                       add_port(portdev, 0);
+               else
+                       send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
+               return;
+       }
+       if (virtconconf.nr_ports > portdev->config.max_nr_ports) {
+               dev_warn(&vdev->dev,
+                        "More ports specified (%u) than allowed (%u)",
+                        portdev->config.nr_ports + 1,
+                        portdev->config.max_nr_ports);
+               return;
+       }
+       if (virtconconf.nr_ports < portdev->config.nr_ports)
+               return;
+
+       /* Hot-add ports */
+       while (virtconconf.nr_ports - portdev->config.nr_ports) {
+               err = add_port(portdev, portdev->config.nr_ports);
+               if (err)
+                       break;
+               portdev->config.nr_ports++;
+       }
+}
+
+static int init_vqs(struct ports_device *portdev)
 {
-       vq_callback_t *callbacks[] = { hvc_handle_input, NULL};
-       const char *names[] = { "input", "output" };
-       struct virtqueue *vqs[2];
+       vq_callback_t **io_callbacks;
+       char **io_names;
+       struct virtqueue **vqs;
+       u32 i, j, nr_ports, nr_queues;
        int err;
 
-       vdev = dev;
+       nr_ports = portdev->config.max_nr_ports;
+       nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2;
 
-       /* This is the scratch page we use to receive console input */
-       inbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
-       if (!inbuf) {
+       vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL);
+       if (!vqs) {
                err = -ENOMEM;
                goto fail;
        }
+       io_callbacks = kmalloc(nr_queues * sizeof(vq_callback_t *), GFP_KERNEL);
+       if (!io_callbacks) {
+               err = -ENOMEM;
+               goto free_vqs;
+       }
+       io_names = kmalloc(nr_queues * sizeof(char *), GFP_KERNEL);
+       if (!io_names) {
+               err = -ENOMEM;
+               goto free_callbacks;
+       }
+       portdev->in_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
+                                 GFP_KERNEL);
+       if (!portdev->in_vqs) {
+               err = -ENOMEM;
+               goto free_names;
+       }
+       portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
+                                  GFP_KERNEL);
+       if (!portdev->out_vqs) {
+               err = -ENOMEM;
+               goto free_invqs;
+       }
+
+       /*
+        * For backward compat (newer host but older guest), the host
+        * spawns a console port first and also inits the vqs for port
+        * 0 before others.
+        */
+       j = 0;
+       io_callbacks[j] = in_intr;
+       io_callbacks[j + 1] = NULL;
+       io_names[j] = "input";
+       io_names[j + 1] = "output";
+       j += 2;
 
+       if (use_multiport(portdev)) {
+               io_callbacks[j] = control_intr;
+               io_callbacks[j + 1] = NULL;
+               io_names[j] = "control-i";
+               io_names[j + 1] = "control-o";
+
+               for (i = 1; i < nr_ports; i++) {
+                       j += 2;
+                       io_callbacks[j] = in_intr;
+                       io_callbacks[j + 1] = NULL;
+                       io_names[j] = "input";
+                       io_names[j + 1] = "output";
+               }
+       }
        /* Find the queues. */
-       /* FIXME: This is why we want to wean off hvc: we do nothing
-        * when input comes in. */
-       err = vdev->config->find_vqs(vdev, 2, vqs, callbacks, names);
+       err = portdev->vdev->config->find_vqs(portdev->vdev, nr_queues, vqs,
+                                             io_callbacks,
+                                             (const char **)io_names);
        if (err)
+               goto free_outvqs;
+
+       j = 0;
+       portdev->in_vqs[0] = vqs[0];
+       portdev->out_vqs[0] = vqs[1];
+       j += 2;
+       if (use_multiport(portdev)) {
+               portdev->c_ivq = vqs[j];
+               portdev->c_ovq = vqs[j + 1];
+
+               for (i = 1; i < nr_ports; i++) {
+                       j += 2;
+                       portdev->in_vqs[i] = vqs[j];
+                       portdev->out_vqs[i] = vqs[j + 1];
+               }
+       }
+       kfree(io_callbacks);
+       kfree(io_names);
+       kfree(vqs);
+
+       return 0;
+
+free_names:
+       kfree(io_names);
+free_callbacks:
+       kfree(io_callbacks);
+free_outvqs:
+       kfree(portdev->out_vqs);
+free_invqs:
+       kfree(portdev->in_vqs);
+free_vqs:
+       kfree(vqs);
+fail:
+       return err;
+}
+
+static const struct file_operations portdev_fops = {
+       .owner = THIS_MODULE,
+};
+
+/*
+ * Once we're further in boot, we get probed like any other virtio
+ * device.
+ *
+ * If the host also supports multiple console ports, we check the
+ * config space to see how many ports the host has spawned.  We
+ * initialize each port found.
+ */
+static int __devinit virtcons_probe(struct virtio_device *vdev)
+{
+       struct ports_device *portdev;
+       u32 i;
+       int err;
+       bool multiport;
+
+       portdev = kmalloc(sizeof(*portdev), GFP_KERNEL);
+       if (!portdev) {
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       /* Attach this portdev to this virtio_device, and vice-versa. */
+       portdev->vdev = vdev;
+       vdev->priv = portdev;
+
+       spin_lock_irq(&pdrvdata_lock);
+       portdev->drv_index = pdrvdata.index++;
+       spin_unlock_irq(&pdrvdata_lock);
+
+       portdev->chr_major = register_chrdev(0, "virtio-portsdev",
+                                            &portdev_fops);
+       if (portdev->chr_major < 0) {
+               dev_err(&vdev->dev,
+                       "Error %d registering chrdev for device %u\n",
+                       portdev->chr_major, portdev->drv_index);
+               err = portdev->chr_major;
                goto free;
+       }
 
-       in_vq = vqs[0];
-       out_vq = vqs[1];
+       multiport = false;
+       portdev->config.nr_ports = 1;
+       portdev->config.max_nr_ports = 1;
+       if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT)) {
+               multiport = true;
+               vdev->features[0] |= 1 << VIRTIO_CONSOLE_F_MULTIPORT;
 
-       /* Start using the new console output. */
-       virtio_cons.get_chars = get_chars;
-       virtio_cons.put_chars = put_chars;
-       virtio_cons.notifier_add = notifier_add_vio;
-       virtio_cons.notifier_del = notifier_del_vio;
-       virtio_cons.notifier_hangup = notifier_del_vio;
-
-       /* The first argument of hvc_alloc() is the virtual console number, so
-        * we use zero.  The second argument is the parameter for the
-        * notification mechanism (like irq number). We currently leave this
-        * as zero, virtqueues have implicit notifications.
-        *
-        * The third argument is a "struct hv_ops" containing the put_chars()
-        * get_chars(), notifier_add() and notifier_del() pointers.
-        * The final argument is the output buffer size: we can do any size,
-        * so we put PAGE_SIZE here. */
-       hvc = hvc_alloc(0, 0, &virtio_cons, PAGE_SIZE);
-       if (IS_ERR(hvc)) {
-               err = PTR_ERR(hvc);
-               goto free_vqs;
+               vdev->config->get(vdev, offsetof(struct virtio_console_config,
+                                                nr_ports),
+                                 &portdev->config.nr_ports,
+                                 sizeof(portdev->config.nr_ports));
+               vdev->config->get(vdev, offsetof(struct virtio_console_config,
+                                                max_nr_ports),
+                                 &portdev->config.max_nr_ports,
+                                 sizeof(portdev->config.max_nr_ports));
+               if (portdev->config.nr_ports > portdev->config.max_nr_ports) {
+                       dev_warn(&vdev->dev,
+                                "More ports (%u) specified than allowed (%u). Will init %u ports.",
+                                portdev->config.nr_ports,
+                                portdev->config.max_nr_ports,
+                                portdev->config.max_nr_ports);
+
+                       portdev->config.nr_ports = portdev->config.max_nr_ports;
+               }
+       }
+
+       /* Let the Host know we support multiple ports.*/
+       vdev->config->finalize_features(vdev);
+
+       err = init_vqs(portdev);
+       if (err < 0) {
+               dev_err(&vdev->dev, "Error %d initializing vqs\n", err);
+               goto free_chrdev;
+       }
+
+       spin_lock_init(&portdev->ports_lock);
+       INIT_LIST_HEAD(&portdev->ports);
+
+       if (multiport) {
+               spin_lock_init(&portdev->cvq_lock);
+               INIT_WORK(&portdev->control_work, &control_work_handler);
+               INIT_WORK(&portdev->config_work, &config_work_handler);
+
+               err = fill_queue(portdev->c_ivq, &portdev->cvq_lock);
+               if (!err) {
+                       dev_err(&vdev->dev,
+                               "Error allocating buffers for control queue\n");
+                       err = -ENOMEM;
+                       goto free_vqs;
+               }
        }
 
-       /* Register the input buffer the first time. */
-       add_inbuf();
+       for (i = 0; i < portdev->config.nr_ports; i++)
+               add_port(portdev, i);
+
+       /* Start using the new console output. */
+       early_put_chars = NULL;
        return 0;
 
 free_vqs:
        vdev->config->del_vqs(vdev);
+       kfree(portdev->in_vqs);
+       kfree(portdev->out_vqs);
+free_chrdev:
+       unregister_chrdev(portdev->chr_major, "virtio-portsdev");
 free:
-       kfree(inbuf);
+       kfree(portdev);
 fail:
        return err;
 }
 
+static void virtcons_remove(struct virtio_device *vdev)
+{
+       struct ports_device *portdev;
+       struct port *port, *port2;
+       struct port_buffer *buf;
+       unsigned int len;
+
+       portdev = vdev->priv;
+
+       cancel_work_sync(&portdev->control_work);
+       cancel_work_sync(&portdev->config_work);
+
+       list_for_each_entry_safe(port, port2, &portdev->ports, list)
+               remove_port(port);
+
+       unregister_chrdev(portdev->chr_major, "virtio-portsdev");
+
+       while ((buf = portdev->c_ivq->vq_ops->get_buf(portdev->c_ivq, &len)))
+               free_buf(buf);
+
+       while ((buf = portdev->c_ivq->vq_ops->detach_unused_buf(portdev->c_ivq)))
+               free_buf(buf);
+
+       vdev->config->del_vqs(vdev);
+       kfree(portdev->in_vqs);
+       kfree(portdev->out_vqs);
+
+       kfree(portdev);
+}
+
 static struct virtio_device_id id_table[] = {
        { VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID },
        { 0 },
@@ -253,6 +1511,7 @@ static struct virtio_device_id id_table[] = {
 
 static unsigned int features[] = {
        VIRTIO_CONSOLE_F_SIZE,
+       VIRTIO_CONSOLE_F_MULTIPORT,
 };
 
 static struct virtio_driver virtio_console = {
@@ -262,14 +1521,41 @@ static struct virtio_driver virtio_console = {
        .driver.owner = THIS_MODULE,
        .id_table =     id_table,
        .probe =        virtcons_probe,
-       .config_changed = virtcons_apply_config,
+       .remove =       virtcons_remove,
+       .config_changed = config_intr,
 };
 
 static int __init init(void)
 {
+       int err;
+
+       pdrvdata.class = class_create(THIS_MODULE, "virtio-ports");
+       if (IS_ERR(pdrvdata.class)) {
+               err = PTR_ERR(pdrvdata.class);
+               pr_err("Error %d creating virtio-ports class\n", err);
+               return err;
+       }
+
+       pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL);
+       if (!pdrvdata.debugfs_dir) {
+               pr_warning("Error %ld creating debugfs dir for virtio-ports\n",
+                          PTR_ERR(pdrvdata.debugfs_dir));
+       }
+       INIT_LIST_HEAD(&pdrvdata.consoles);
+
        return register_virtio_driver(&virtio_console);
 }
+
+static void __exit fini(void)
+{
+       unregister_virtio_driver(&virtio_console);
+
+       class_destroy(pdrvdata.class);
+       if (pdrvdata.debugfs_dir)
+               debugfs_remove_recursive(pdrvdata.debugfs_dir);
+}
 module_init(init);
+module_exit(fini);
 
 MODULE_DEVICE_TABLE(virtio, id_table);
 MODULE_DESCRIPTION("Virtio console driver");
index 27d20fa..b314a99 100644 (file)
@@ -21,7 +21,7 @@
 
 #define DRV_NAME "cs5535-clockevt"
 
-static int timer_irq = CONFIG_CS5535_MFGPT_DEFAULT_IRQ;
+static int timer_irq;
 module_param_named(irq, timer_irq, int, 0644);
 MODULE_PARM_DESC(irq, "Which IRQ to use for the clock source MFGPT ticks.");
 
index f665b05..ab6c973 100644 (file)
@@ -598,6 +598,50 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev,
        return mode;
 }
 
+/*
+ * EDID is delightfully ambiguous about how interlaced modes are to be
+ * encoded.  Our internal representation is of frame height, but some
+ * HDTV detailed timings are encoded as field height.
+ *
+ * The format list here is from CEA, in frame size.  Technically we
+ * should be checking refresh rate too.  Whatever.
+ */
+static void
+drm_mode_do_interlace_quirk(struct drm_display_mode *mode,
+                           struct detailed_pixel_timing *pt)
+{
+       int i;
+       static const struct {
+               int w, h;
+       } cea_interlaced[] = {
+               { 1920, 1080 },
+               {  720,  480 },
+               { 1440,  480 },
+               { 2880,  480 },
+               {  720,  576 },
+               { 1440,  576 },
+               { 2880,  576 },
+       };
+       static const int n_sizes =
+               sizeof(cea_interlaced)/sizeof(cea_interlaced[0]);
+
+       if (!(pt->misc & DRM_EDID_PT_INTERLACED))
+               return;
+
+       for (i = 0; i < n_sizes; i++) {
+               if ((mode->hdisplay == cea_interlaced[i].w) &&
+                   (mode->vdisplay == cea_interlaced[i].h / 2)) {
+                       mode->vdisplay *= 2;
+                       mode->vsync_start *= 2;
+                       mode->vsync_end *= 2;
+                       mode->vtotal *= 2;
+                       mode->vtotal |= 1;
+               }
+       }
+
+       mode->flags |= DRM_MODE_FLAG_INTERLACE;
+}
+
 /**
  * drm_mode_detailed - create a new mode from an EDID detailed timing section
  * @dev: DRM device (needed to create new mode)
@@ -680,8 +724,7 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
 
        drm_mode_set_name(mode);
 
-       if (pt->misc & DRM_EDID_PT_INTERLACED)
-               mode->flags |= DRM_MODE_FLAG_INTERLACE;
+       drm_mode_do_interlace_quirk(mode, pt);
 
        if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) {
                pt->misc |= DRM_EDID_PT_HSYNC_POSITIVE | DRM_EDID_PT_VSYNC_POSITIVE;
index 79beffc..cf4cb3e 100644 (file)
@@ -176,6 +176,8 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
 
 static int i915_drm_freeze(struct drm_device *dev)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
        pci_save_state(dev->pdev);
 
        /* If KMS is active, we do the leavevt stuff here */
@@ -191,17 +193,12 @@ static int i915_drm_freeze(struct drm_device *dev)
 
        i915_save_state(dev);
 
-       return 0;
-}
-
-static void i915_drm_suspend(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
        intel_opregion_free(dev, 1);
 
        /* Modeset on resume, not lid events */
        dev_priv->modeset_on_lid = 0;
+
+       return 0;
 }
 
 static int i915_suspend(struct drm_device *dev, pm_message_t state)
@@ -221,8 +218,6 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
        if (error)
                return error;
 
-       i915_drm_suspend(dev);
-
        if (state.event == PM_EVENT_SUSPEND) {
                /* Shut down the device */
                pci_disable_device(dev->pdev);
@@ -237,6 +232,10 @@ static int i915_drm_thaw(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int error = 0;
 
+       i915_restore_state(dev);
+
+       intel_opregion_init(dev, 1);
+
        /* KMS EnterVT equivalent */
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                mutex_lock(&dev->struct_mutex);
@@ -263,10 +262,6 @@ static int i915_resume(struct drm_device *dev)
 
        pci_set_master(dev->pdev);
 
-       i915_restore_state(dev);
-
-       intel_opregion_init(dev, 1);
-
        return i915_drm_thaw(dev);
 }
 
@@ -423,8 +418,6 @@ static int i915_pm_suspend(struct device *dev)
        if (error)
                return error;
 
-       i915_drm_suspend(drm_dev);
-
        pci_disable_device(pdev);
        pci_set_power_state(pdev, PCI_D3hot);
 
@@ -464,13 +457,8 @@ static int i915_pm_poweroff(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct drm_device *drm_dev = pci_get_drvdata(pdev);
-       int error;
-
-       error = i915_drm_freeze(drm_dev);
-       if (!error)
-               i915_drm_suspend(drm_dev);
 
-       return error;
+       return i915_drm_freeze(drm_dev);
 }
 
 const struct dev_pm_ops i915_pm_ops = {
index b1d0acb..c2e8a45 100644 (file)
@@ -636,6 +636,13 @@ static const struct dmi_system_id bad_lid_status[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "PC-81005"),
                },
        },
+       {
+               .ident = "Clevo M5x0N",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "CLEVO Co."),
+                       DMI_MATCH(DMI_BOARD_NAME, "M5x0N"),
+               },
+       },
        { }
 };
 
index 2cd0fad..0e9cd1d 100644 (file)
@@ -5861,13 +5861,12 @@ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table,
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nvbios *bios = &dev_priv->VBIOS;
        struct init_exec iexec = { true, false };
-       unsigned long flags;
 
-       spin_lock_irqsave(&bios->lock, flags);
+       mutex_lock(&bios->lock);
        bios->display.output = dcbent;
        parse_init_table(bios, table, &iexec);
        bios->display.output = NULL;
-       spin_unlock_irqrestore(&bios->lock, flags);
+       mutex_unlock(&bios->lock);
 }
 
 static bool NVInitVBIOS(struct drm_device *dev)
@@ -5876,7 +5875,7 @@ static bool NVInitVBIOS(struct drm_device *dev)
        struct nvbios *bios = &dev_priv->VBIOS;
 
        memset(bios, 0, sizeof(struct nvbios));
-       spin_lock_init(&bios->lock);
+       mutex_init(&bios->lock);
        bios->dev = dev;
 
        if (!NVShadowVBIOS(dev, bios->data))
index 68446fd..fd94bd6 100644 (file)
@@ -205,7 +205,7 @@ struct nvbios {
        struct drm_device *dev;
        struct nouveau_bios_info pub;
 
-       spinlock_t lock;
+       struct mutex lock;
 
        uint8_t data[NV_PROM_SIZE];
        unsigned int length;
index 5445cef..1c15ef3 100644 (file)
@@ -583,6 +583,7 @@ struct drm_nouveau_private {
        uint64_t vm_end;
        struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR];
        int vm_vram_pt_nr;
+       uint64_t vram_sys_base;
 
        /* the mtrr covering the FB */
        int fb_mtrr;
index 8f3a12f..2dc09db 100644 (file)
@@ -285,53 +285,50 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
                        uint32_t flags, uint64_t phys)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_gpuobj **pgt;
-       unsigned psz, pfl, pages;
-
-       if (virt >= dev_priv->vm_gart_base &&
-           (virt + size) < (dev_priv->vm_gart_base + dev_priv->vm_gart_size)) {
-               psz = 12;
-               pgt = &dev_priv->gart_info.sg_ctxdma;
-               pfl = 0x21;
-               virt -= dev_priv->vm_gart_base;
-       } else
-       if (virt >= dev_priv->vm_vram_base &&
-           (virt + size) < (dev_priv->vm_vram_base + dev_priv->vm_vram_size)) {
-               psz = 16;
-               pgt = dev_priv->vm_vram_pt;
-               pfl = 0x01;
-               virt -= dev_priv->vm_vram_base;
-       } else {
-               NV_ERROR(dev, "Invalid address: 0x%16llx-0x%16llx\n",
-                        virt, virt + size - 1);
-               return -EINVAL;
-       }
+       struct nouveau_gpuobj *pgt;
+       unsigned block;
+       int i;
 
-       pages = size >> psz;
+       virt = ((virt - dev_priv->vm_vram_base) >> 16) << 1;
+       size = (size >> 16) << 1;
+
+       phys |= ((uint64_t)flags << 32);
+       phys |= 1;
+       if (dev_priv->vram_sys_base) {
+               phys += dev_priv->vram_sys_base;
+               phys |= 0x30;
+       }
 
        dev_priv->engine.instmem.prepare_access(dev, true);
-       if (flags & 0x80000000) {
-               while (pages--) {
-                       struct nouveau_gpuobj *pt = pgt[virt >> 29];
-                       unsigned pte = ((virt & 0x1fffffffULL) >> psz) << 1;
+       while (size) {
+               unsigned offset_h = upper_32_bits(phys);
+               unsigned offset_l = lower_32_bits(phys);
+               unsigned pte, end;
+
+               for (i = 7; i >= 0; i--) {
+                       block = 1 << (i + 1);
+                       if (size >= block && !(virt & (block - 1)))
+                               break;
+               }
+               offset_l |= (i << 7);
 
-                       nv_wo32(dev, pt, pte++, 0x00000000);
-                       nv_wo32(dev, pt, pte++, 0x00000000);
+               phys += block << 15;
+               size -= block;
 
-                       virt += (1 << psz);
-               }
-       } else {
-               while (pages--) {
-                       struct nouveau_gpuobj *pt = pgt[virt >> 29];
-                       unsigned pte = ((virt & 0x1fffffffULL) >> psz) << 1;
-                       unsigned offset_h = upper_32_bits(phys) & 0xff;
-                       unsigned offset_l = lower_32_bits(phys);
+               while (block) {
+                       pgt = dev_priv->vm_vram_pt[virt >> 14];
+                       pte = virt & 0x3ffe;
 
-                       nv_wo32(dev, pt, pte++, offset_l | pfl);
-                       nv_wo32(dev, pt, pte++, offset_h | flags);
+                       end = pte + block;
+                       if (end > 16384)
+                               end = 16384;
+                       block -= (end - pte);
+                       virt  += (end - pte);
 
-                       phys += (1 << psz);
-                       virt += (1 << psz);
+                       while (pte < end) {
+                               nv_wo32(dev, pgt, pte++, offset_l);
+                               nv_wo32(dev, pgt, pte++, offset_h);
+                       }
                }
        }
        dev_priv->engine.instmem.finish_access(dev);
@@ -356,7 +353,41 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
 void
 nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
 {
-       nv50_mem_vm_bind_linear(dev, virt, size, 0x80000000, 0);
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *pgt;
+       unsigned pages, pte, end;
+
+       virt -= dev_priv->vm_vram_base;
+       pages = (size >> 16) << 1;
+
+       dev_priv->engine.instmem.prepare_access(dev, true);
+       while (pages) {
+               pgt = dev_priv->vm_vram_pt[virt >> 29];
+               pte = (virt & 0x1ffe0000ULL) >> 15;
+
+               end = pte + pages;
+               if (end > 16384)
+                       end = 16384;
+               pages -= (end - pte);
+               virt  += (end - pte) << 15;
+
+               while (pte < end)
+                       nv_wo32(dev, pgt, pte++, 0);
+       }
+       dev_priv->engine.instmem.finish_access(dev);
+
+       nv_wr32(dev, 0x100c80, 0x00050001);
+       if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
+               NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
+               NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
+               return;
+       }
+
+       nv_wr32(dev, 0x100c80, 0x00000001);
+       if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
+               NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
+               NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
+       }
 }
 
 /*
index d0e038d..1d73b15 100644 (file)
@@ -119,7 +119,7 @@ static enum drm_connector_status nv04_dac_detect(struct drm_encoder *encoder,
                                                 struct drm_connector *connector)
 {
        struct drm_device *dev = encoder->dev;
-       uint8_t saved_seq1, saved_pi, saved_rpc1;
+       uint8_t saved_seq1, saved_pi, saved_rpc1, saved_cr_mode;
        uint8_t saved_palette0[3], saved_palette_mask;
        uint32_t saved_rtest_ctrl, saved_rgen_ctrl;
        int i;
@@ -135,6 +135,9 @@ static enum drm_connector_status nv04_dac_detect(struct drm_encoder *encoder,
                /* only implemented for head A for now */
                NVSetOwner(dev, 0);
 
+       saved_cr_mode = NVReadVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX);
+       NVWriteVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX, saved_cr_mode | 0x80);
+
        saved_seq1 = NVReadVgaSeq(dev, 0, NV_VIO_SR_CLOCK_INDEX);
        NVWriteVgaSeq(dev, 0, NV_VIO_SR_CLOCK_INDEX, saved_seq1 & ~0x20);
 
@@ -203,6 +206,7 @@ out:
        NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_PIXEL_INDEX, saved_pi);
        NVWriteVgaCrtc(dev, 0, NV_CIO_CRE_RPC1_INDEX, saved_rpc1);
        NVWriteVgaSeq(dev, 0, NV_VIO_SR_CLOCK_INDEX, saved_seq1);
+       NVWriteVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX, saved_cr_mode);
 
        if (blue == 0x18) {
                NV_INFO(dev, "Load detected on head A\n");
index 58b917c..21ac6e4 100644 (file)
@@ -579,6 +579,8 @@ static void nv17_tv_restore(struct drm_encoder *encoder)
                                nouveau_encoder(encoder)->restore.output);
 
        nv17_tv_state_load(dev, &to_tv_enc(encoder)->saved_state);
+
+       nouveau_encoder(encoder)->last_dpms = NV_DPMS_CLEARED;
 }
 
 static int nv17_tv_create_resources(struct drm_encoder *encoder,
index 94400f7..f0dc4e3 100644 (file)
@@ -76,6 +76,11 @@ nv50_instmem_init(struct drm_device *dev)
        for (i = 0x1700; i <= 0x1710; i += 4)
                priv->save1700[(i-0x1700)/4] = nv_rd32(dev, i);
 
+       if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac)
+               dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10) << 12;
+       else
+               dev_priv->vram_sys_base = 0;
+
        /* Reserve the last MiB of VRAM, we should probably try to avoid
         * setting up the below tables over the top of the VBIOS image at
         * some point.
@@ -172,16 +177,28 @@ nv50_instmem_init(struct drm_device *dev)
         * We map the entire fake channel into the start of the PRAMIN BAR
         */
        ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pt_size, 0x1000,
-                                                       0, &priv->pramin_pt);
+                                    0, &priv->pramin_pt);
        if (ret)
                return ret;
 
-       for (i = 0, v = c_offset; i < pt_size; i += 8, v += 0x1000) {
-               if (v < (c_offset + c_size))
-                       BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, v | 1);
-               else
-                       BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, 0x00000009);
+       v = c_offset | 1;
+       if (dev_priv->vram_sys_base) {
+               v += dev_priv->vram_sys_base;
+               v |= 0x30;
+       }
+
+       i = 0;
+       while (v < dev_priv->vram_sys_base + c_offset + c_size) {
+               BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, v);
+               BAR0_WI32(priv->pramin_pt->gpuobj, i + 4, 0x00000000);
+               v += 0x1000;
+               i += 8;
+       }
+
+       while (i < pt_size) {
+               BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, 0x00000000);
                BAR0_WI32(priv->pramin_pt->gpuobj, i + 4, 0x00000000);
+               i += 8;
        }
 
        BAR0_WI32(chan->vm_pd, 0x00, priv->pramin_pt->instance | 0x63);
@@ -416,7 +433,9 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv;
-       uint32_t pte, pte_end, vram;
+       struct nouveau_gpuobj *pramin_pt = priv->pramin_pt->gpuobj;
+       uint32_t pte, pte_end;
+       uint64_t vram;
 
        if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound)
                return -EINVAL;
@@ -424,20 +443,24 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
        NV_DEBUG(dev, "st=0x%0llx sz=0x%0llx\n",
                 gpuobj->im_pramin->start, gpuobj->im_pramin->size);
 
-       pte     = (gpuobj->im_pramin->start >> 12) << 3;
-       pte_end = ((gpuobj->im_pramin->size >> 12) << 3) + pte;
+       pte     = (gpuobj->im_pramin->start >> 12) << 1;
+       pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte;
        vram    = gpuobj->im_backing_start;
 
        NV_DEBUG(dev, "pramin=0x%llx, pte=%d, pte_end=%d\n",
                 gpuobj->im_pramin->start, pte, pte_end);
        NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start);
 
+       vram |= 1;
+       if (dev_priv->vram_sys_base) {
+               vram += dev_priv->vram_sys_base;
+               vram |= 0x30;
+       }
+
        dev_priv->engine.instmem.prepare_access(dev, true);
        while (pte < pte_end) {
-               nv_wo32(dev, priv->pramin_pt->gpuobj, (pte + 0)/4, vram | 1);
-               nv_wo32(dev, priv->pramin_pt->gpuobj, (pte + 4)/4, 0x00000000);
-
-               pte += 8;
+               nv_wo32(dev, pramin_pt, pte++, lower_32_bits(vram));
+               nv_wo32(dev, pramin_pt, pte++, upper_32_bits(vram));
                vram += NV50_INSTMEM_PAGE_SIZE;
        }
        dev_priv->engine.instmem.finish_access(dev);
@@ -470,14 +493,13 @@ nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
        if (gpuobj->im_bound == 0)
                return -EINVAL;
 
-       pte     = (gpuobj->im_pramin->start >> 12) << 3;
-       pte_end = ((gpuobj->im_pramin->size >> 12) << 3) + pte;
+       pte     = (gpuobj->im_pramin->start >> 12) << 1;
+       pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte;
 
        dev_priv->engine.instmem.prepare_access(dev, true);
        while (pte < pte_end) {
-               nv_wo32(dev, priv->pramin_pt->gpuobj, (pte + 0)/4, 0x00000009);
-               nv_wo32(dev, priv->pramin_pt->gpuobj, (pte + 4)/4, 0x00000000);
-               pte += 8;
+               nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000);
+               nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000);
        }
        dev_priv->engine.instmem.finish_access(dev);
 
index 2a3df55..7f152f6 100644 (file)
@@ -643,7 +643,7 @@ static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg)
        uint8_t count = U8((*ptr)++);
        SDEBUG("   count: %d\n", count);
        if (arg == ATOM_UNIT_MICROSEC)
-               schedule_timeout_uninterruptible(usecs_to_jiffies(count));
+               udelay(count);
        else
                schedule_timeout_uninterruptible(msecs_to_jiffies(count));
 }
index af1c3ca..446b765 100644 (file)
@@ -543,9 +543,6 @@ int r600_vb_ib_get(struct radeon_device *rdev)
 void r600_vb_ib_put(struct radeon_device *rdev)
 {
        radeon_fence_emit(rdev, rdev->r600_blit.vb_ib->fence);
-       mutex_lock(&rdev->ib_pool.mutex);
-       list_add_tail(&rdev->r600_blit.vb_ib->list, &rdev->ib_pool.scheduled_ibs);
-       mutex_unlock(&rdev->ib_pool.mutex);
        radeon_ib_free(rdev, &rdev->r600_blit.vb_ib);
 }
 
index 6d5a711..75bcf35 100644 (file)
@@ -1428,9 +1428,12 @@ static void r700_gfx_init(struct drm_device *dev,
 
        gb_tiling_config |= R600_BANK_SWAPS(1);
 
-       backend_map = r700_get_tile_pipe_to_backend_map(dev_priv->r600_max_tile_pipes,
-                                                       dev_priv->r600_max_backends,
-                                                       (0xff << dev_priv->r600_max_backends) & 0xff);
+       if ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_RV740)
+               backend_map = 0x28;
+       else
+               backend_map = r700_get_tile_pipe_to_backend_map(dev_priv->r600_max_tile_pipes,
+                                                               dev_priv->r600_max_backends,
+                                                               (0xff << dev_priv->r600_max_backends) & 0xff);
        gb_tiling_config |= R600_BACKEND_MAP(backend_map);
 
        cc_gc_shader_pipe_config =
index f57480b..c0356bb 100644 (file)
@@ -96,6 +96,7 @@ extern int radeon_audio;
  * symbol;
  */
 #define RADEON_MAX_USEC_TIMEOUT                100000  /* 100 ms */
+/* RADEON_IB_POOL_SIZE must be a power of 2 */
 #define RADEON_IB_POOL_SIZE            16
 #define RADEON_DEBUGFS_MAX_NUM_FILES   32
 #define RADEONFB_CONN_LIMIT            4
@@ -363,11 +364,12 @@ void radeon_irq_kms_sw_irq_put(struct radeon_device *rdev);
  */
 struct radeon_ib {
        struct list_head        list;
-       unsigned long           idx;
+       unsigned                idx;
        uint64_t                gpu_addr;
        struct radeon_fence     *fence;
-       uint32_t        *ptr;
+       uint32_t                *ptr;
        uint32_t                length_dw;
+       bool                    free;
 };
 
 /*
@@ -377,10 +379,9 @@ struct radeon_ib {
 struct radeon_ib_pool {
        struct mutex            mutex;
        struct radeon_bo        *robj;
-       struct list_head        scheduled_ibs;
        struct radeon_ib        ibs[RADEON_IB_POOL_SIZE];
        bool                    ready;
-       DECLARE_BITMAP(alloc_bm, RADEON_IB_POOL_SIZE);
+       unsigned                head_id;
 };
 
 struct radeon_cp {
index 2dcda61..4d88315 100644 (file)
@@ -206,6 +206,15 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,
                        *connector_type = DRM_MODE_CONNECTOR_DVID;
        }
 
+       /* Asrock RS600 board lists the DVI port as HDMI */
+       if ((dev->pdev->device == 0x7941) &&
+           (dev->pdev->subsystem_vendor == 0x1849) &&
+           (dev->pdev->subsystem_device == 0x7941)) {
+               if ((*connector_type == DRM_MODE_CONNECTOR_HDMIA) &&
+                   (supported_device == ATOM_DEVICE_DFP3_SUPPORT))
+                       *connector_type = DRM_MODE_CONNECTOR_DVID;
+       }
+
        /* a-bit f-i90hd - ciaranm on #radeonhd - this board has no DVI */
        if ((dev->pdev->device == 0x7941) &&
            (dev->pdev->subsystem_vendor == 0x147b) &&
index e7b1944..22d4761 100644 (file)
@@ -1279,47 +1279,47 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
        rdev->mode_info.connector_table = radeon_connector_table;
        if (rdev->mode_info.connector_table == CT_NONE) {
 #ifdef CONFIG_PPC_PMAC
-               if (machine_is_compatible("PowerBook3,3")) {
+               if (of_machine_is_compatible("PowerBook3,3")) {
                        /* powerbook with VGA */
                        rdev->mode_info.connector_table = CT_POWERBOOK_VGA;
-               } else if (machine_is_compatible("PowerBook3,4") ||
-                          machine_is_compatible("PowerBook3,5")) {
+               } else if (of_machine_is_compatible("PowerBook3,4") ||
+                          of_machine_is_compatible("PowerBook3,5")) {
                        /* powerbook with internal tmds */
                        rdev->mode_info.connector_table = CT_POWERBOOK_INTERNAL;
-               } else if (machine_is_compatible("PowerBook5,1") ||
-                          machine_is_compatible("PowerBook5,2") ||
-                          machine_is_compatible("PowerBook5,3") ||
-                          machine_is_compatible("PowerBook5,4") ||
-                          machine_is_compatible("PowerBook5,5")) {
+               } else if (of_machine_is_compatible("PowerBook5,1") ||
+                          of_machine_is_compatible("PowerBook5,2") ||
+                          of_machine_is_compatible("PowerBook5,3") ||
+                          of_machine_is_compatible("PowerBook5,4") ||
+                          of_machine_is_compatible("PowerBook5,5")) {
                        /* powerbook with external single link tmds (sil164) */
                        rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL;
-               } else if (machine_is_compatible("PowerBook5,6")) {
+               } else if (of_machine_is_compatible("PowerBook5,6")) {
                        /* powerbook with external dual or single link tmds */
                        rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL;
-               } else if (machine_is_compatible("PowerBook5,7") ||
-                          machine_is_compatible("PowerBook5,8") ||
-                          machine_is_compatible("PowerBook5,9")) {
+               } else if (of_machine_is_compatible("PowerBook5,7") ||
+                          of_machine_is_compatible("PowerBook5,8") ||
+                          of_machine_is_compatible("PowerBook5,9")) {
                        /* PowerBook6,2 ? */
                        /* powerbook with external dual link tmds (sil1178?) */
                        rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL;
-               } else if (machine_is_compatible("PowerBook4,1") ||
-                          machine_is_compatible("PowerBook4,2") ||
-                          machine_is_compatible("PowerBook4,3") ||
-                          machine_is_compatible("PowerBook6,3") ||
-                          machine_is_compatible("PowerBook6,5") ||
-                          machine_is_compatible("PowerBook6,7")) {
+               } else if (of_machine_is_compatible("PowerBook4,1") ||
+                          of_machine_is_compatible("PowerBook4,2") ||
+                          of_machine_is_compatible("PowerBook4,3") ||
+                          of_machine_is_compatible("PowerBook6,3") ||
+                          of_machine_is_compatible("PowerBook6,5") ||
+                          of_machine_is_compatible("PowerBook6,7")) {
                        /* ibook */
                        rdev->mode_info.connector_table = CT_IBOOK;
-               } else if (machine_is_compatible("PowerMac4,4")) {
+               } else if (of_machine_is_compatible("PowerMac4,4")) {
                        /* emac */
                        rdev->mode_info.connector_table = CT_EMAC;
-               } else if (machine_is_compatible("PowerMac10,1")) {
+               } else if (of_machine_is_compatible("PowerMac10,1")) {
                        /* mini with internal tmds */
                        rdev->mode_info.connector_table = CT_MINI_INTERNAL;
-               } else if (machine_is_compatible("PowerMac10,2")) {
+               } else if (of_machine_is_compatible("PowerMac10,2")) {
                        /* mini with external tmds */
                        rdev->mode_info.connector_table = CT_MINI_EXTERNAL;
-               } else if (machine_is_compatible("PowerMac12,1")) {
+               } else if (of_machine_is_compatible("PowerMac12,1")) {
                        /* PowerMac8,1 ? */
                        /* imac g5 isight */
                        rdev->mode_info.connector_table = CT_IMAC_G5_ISIGHT;
index 2381885..65f8194 100644 (file)
@@ -780,7 +780,7 @@ static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connect
                         * connected and the DVI port disconnected.  If the edid doesn't
                         * say HDMI, vice versa.
                         */
-                       if (radeon_connector->shared_ddc && connector_status_connected) {
+                       if (radeon_connector->shared_ddc && (ret == connector_status_connected)) {
                                struct drm_device *dev = connector->dev;
                                struct drm_connector *list_connector;
                                struct radeon_connector *list_radeon_connector;
@@ -1060,8 +1060,7 @@ radeon_add_atom_connector(struct drm_device *dev,
                        return;
                }
                if (radeon_connector->ddc_bus && i2c_bus->valid) {
-                       if (memcmp(&radeon_connector->ddc_bus->rec, i2c_bus,
-                                   sizeof(struct radeon_i2c_bus_rec)) == 0) {
+                       if (radeon_connector->ddc_bus->rec.i2c_id == i2c_bus->i2c_id) {
                                radeon_connector->shared_ddc = true;
                                shared_ddc = true;
                        }
index 1190148..e9d0850 100644 (file)
@@ -86,7 +86,7 @@ int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
                                                &p->validated);
                }
        }
-       return radeon_bo_list_validate(&p->validated, p->ib->fence);
+       return radeon_bo_list_validate(&p->validated);
 }
 
 int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
@@ -189,12 +189,10 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error)
 {
        unsigned i;
 
-       if (error && parser->ib) {
-               radeon_bo_list_unvalidate(&parser->validated,
-                                               parser->ib->fence);
-       } else {
-               radeon_bo_list_unreserve(&parser->validated);
+       if (!error && parser->ib) {
+               radeon_bo_list_fence(&parser->validated, parser->ib->fence);
        }
+       radeon_bo_list_unreserve(&parser->validated);
        for (i = 0; i < parser->nrelocs; i++) {
                if (parser->relocs[i].gobj) {
                        mutex_lock(&parser->rdev->ddev->struct_mutex);
index e137852..c57ad60 100644 (file)
  * 1.29- R500 3D cmd buffer support
  * 1.30- Add support for occlusion queries
  * 1.31- Add support for num Z pipes from GET_PARAM
+ * 1.32- fixes for rv740 setup
  */
 #define DRIVER_MAJOR           1
-#define DRIVER_MINOR           31
+#define DRIVER_MINOR           32
 #define DRIVER_PATCHLEVEL      0
 
 enum radeon_cp_microcode_version {
index d72a71b..f1da370 100644 (file)
@@ -306,11 +306,10 @@ void radeon_bo_list_unreserve(struct list_head *head)
        }
 }
 
-int radeon_bo_list_validate(struct list_head *head, void *fence)
+int radeon_bo_list_validate(struct list_head *head)
 {
        struct radeon_bo_list *lobj;
        struct radeon_bo *bo;
-       struct radeon_fence *old_fence = NULL;
        int r;
 
        r = radeon_bo_list_reserve(head);
@@ -334,32 +333,27 @@ int radeon_bo_list_validate(struct list_head *head, void *fence)
                }
                lobj->gpu_offset = radeon_bo_gpu_offset(bo);
                lobj->tiling_flags = bo->tiling_flags;
-               if (fence) {
-                       old_fence = (struct radeon_fence *)bo->tbo.sync_obj;
-                       bo->tbo.sync_obj = radeon_fence_ref(fence);
-                       bo->tbo.sync_obj_arg = NULL;
-               }
-               if (old_fence) {
-                       radeon_fence_unref(&old_fence);
-               }
        }
        return 0;
 }
 
-void radeon_bo_list_unvalidate(struct list_head *head, void *fence)
+void radeon_bo_list_fence(struct list_head *head, void *fence)
 {
        struct radeon_bo_list *lobj;
-       struct radeon_fence *old_fence;
-
-       if (fence)
-               list_for_each_entry(lobj, head, list) {
-                       old_fence = to_radeon_fence(lobj->bo->tbo.sync_obj);
-                       if (old_fence == fence) {
-                               lobj->bo->tbo.sync_obj = NULL;
-                               radeon_fence_unref(&old_fence);
-                       }
+       struct radeon_bo *bo;
+       struct radeon_fence *old_fence = NULL;
+
+       list_for_each_entry(lobj, head, list) {
+               bo = lobj->bo;
+               spin_lock(&bo->tbo.lock);
+               old_fence = (struct radeon_fence *)bo->tbo.sync_obj;
+               bo->tbo.sync_obj = radeon_fence_ref(fence);
+               bo->tbo.sync_obj_arg = NULL;
+               spin_unlock(&bo->tbo.lock);
+               if (old_fence) {
+                       radeon_fence_unref(&old_fence);
                }
-       radeon_bo_list_unreserve(head);
+       }
 }
 
 int radeon_bo_fbdev_mmap(struct radeon_bo *bo,
index a02f180..7ab43de 100644 (file)
@@ -156,8 +156,8 @@ extern void radeon_bo_list_add_object(struct radeon_bo_list *lobj,
                                struct list_head *head);
 extern int radeon_bo_list_reserve(struct list_head *head);
 extern void radeon_bo_list_unreserve(struct list_head *head);
-extern int radeon_bo_list_validate(struct list_head *head, void *fence);
-extern void radeon_bo_list_unvalidate(struct list_head *head, void *fence);
+extern int radeon_bo_list_validate(struct list_head *head);
+extern void radeon_bo_list_fence(struct list_head *head, void *fence);
 extern int radeon_bo_fbdev_mmap(struct radeon_bo *bo,
                                struct vm_area_struct *vma);
 extern int radeon_bo_set_tiling_flags(struct radeon_bo *bo,
index 4d12b2d..6579eb4 100644 (file)
@@ -41,68 +41,55 @@ int radeon_ib_get(struct radeon_device *rdev, struct radeon_ib **ib)
 {
        struct radeon_fence *fence;
        struct radeon_ib *nib;
-       unsigned long i;
-       int r = 0;
+       int r = 0, i, c;
 
        *ib = NULL;
        r = radeon_fence_create(rdev, &fence);
        if (r) {
-               DRM_ERROR("failed to create fence for new IB\n");
+               dev_err(rdev->dev, "failed to create fence for new IB\n");
                return r;
        }
        mutex_lock(&rdev->ib_pool.mutex);
-       i = find_first_zero_bit(rdev->ib_pool.alloc_bm, RADEON_IB_POOL_SIZE);
-       if (i < RADEON_IB_POOL_SIZE) {
-               set_bit(i, rdev->ib_pool.alloc_bm);
-               rdev->ib_pool.ibs[i].length_dw = 0;
-               *ib = &rdev->ib_pool.ibs[i];
-               mutex_unlock(&rdev->ib_pool.mutex);
-               goto out;
+       for (i = rdev->ib_pool.head_id, c = 0, nib = NULL; c < RADEON_IB_POOL_SIZE; c++, i++) {
+               i &= (RADEON_IB_POOL_SIZE - 1);
+               if (rdev->ib_pool.ibs[i].free) {
+                       nib = &rdev->ib_pool.ibs[i];
+                       break;
+               }
        }
-       if (list_empty(&rdev->ib_pool.scheduled_ibs)) {
-               /* we go do nothings here */
+       if (nib == NULL) {
+               /* This should never happen, it means we allocated all
+                * IB and haven't scheduled one yet, return EBUSY to
+                * userspace hoping that on ioctl recall we get better
+                * luck
+                */
+               dev_err(rdev->dev, "no free indirect buffer !\n");
                mutex_unlock(&rdev->ib_pool.mutex);
-               DRM_ERROR("all IB allocated none scheduled.\n");
-               r = -EINVAL;
-               goto out;
+               radeon_fence_unref(&fence);
+               return -EBUSY;
        }
-       /* get the first ib on the scheduled list */
-       nib = list_entry(rdev->ib_pool.scheduled_ibs.next,
-                        struct radeon_ib, list);
-       if (nib->fence == NULL) {
-               /* we go do nothings here */
+       rdev->ib_pool.head_id = (nib->idx + 1) & (RADEON_IB_POOL_SIZE - 1);
+       nib->free = false;
+       if (nib->fence) {
                mutex_unlock(&rdev->ib_pool.mutex);
-               DRM_ERROR("IB %lu scheduled without a fence.\n", nib->idx);
-               r = -EINVAL;
-               goto out;
-       }
-       mutex_unlock(&rdev->ib_pool.mutex);
-
-       r = radeon_fence_wait(nib->fence, false);
-       if (r) {
-               DRM_ERROR("radeon: IB(%lu:0x%016lX:%u)\n", nib->idx,
-                         (unsigned long)nib->gpu_addr, nib->length_dw);
-               DRM_ERROR("radeon: GPU lockup detected, fail to get a IB\n");
-               goto out;
+               r = radeon_fence_wait(nib->fence, false);
+               if (r) {
+                       dev_err(rdev->dev, "error waiting fence of IB(%u:0x%016lX:%u)\n",
+                               nib->idx, (unsigned long)nib->gpu_addr, nib->length_dw);
+                       mutex_lock(&rdev->ib_pool.mutex);
+                       nib->free = true;
+                       mutex_unlock(&rdev->ib_pool.mutex);
+                       radeon_fence_unref(&fence);
+                       return r;
+               }
+               mutex_lock(&rdev->ib_pool.mutex);
        }
        radeon_fence_unref(&nib->fence);
-
+       nib->fence = fence;
        nib->length_dw = 0;
-
-       /* scheduled list is accessed here */
-       mutex_lock(&rdev->ib_pool.mutex);
-       list_del(&nib->list);
-       INIT_LIST_HEAD(&nib->list);
        mutex_unlock(&rdev->ib_pool.mutex);
-
        *ib = nib;
-out:
-       if (r) {
-               radeon_fence_unref(&fence);
-       } else {
-               (*ib)->fence = fence;
-       }
-       return r;
+       return 0;
 }
 
 void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib)
@@ -113,19 +100,10 @@ void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib)
        if (tmp == NULL) {
                return;
        }
-       mutex_lock(&rdev->ib_pool.mutex);
-       if (!list_empty(&tmp->list) && !radeon_fence_signaled(tmp->fence)) {
-               /* IB is scheduled & not signaled don't do anythings */
-               mutex_unlock(&rdev->ib_pool.mutex);
-               return;
-       }
-       list_del(&tmp->list);
-       INIT_LIST_HEAD(&tmp->list);
-       if (tmp->fence)
+       if (!tmp->fence->emited)
                radeon_fence_unref(&tmp->fence);
-
-       tmp->length_dw = 0;
-       clear_bit(tmp->idx, rdev->ib_pool.alloc_bm);
+       mutex_lock(&rdev->ib_pool.mutex);
+       tmp->free = true;
        mutex_unlock(&rdev->ib_pool.mutex);
 }
 
@@ -135,7 +113,7 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib)
 
        if (!ib->length_dw || !rdev->cp.ready) {
                /* TODO: Nothings in the ib we should report. */
-               DRM_ERROR("radeon: couldn't schedule IB(%lu).\n", ib->idx);
+               DRM_ERROR("radeon: couldn't schedule IB(%u).\n", ib->idx);
                return -EINVAL;
        }
 
@@ -148,7 +126,8 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib)
        radeon_ring_ib_execute(rdev, ib);
        radeon_fence_emit(rdev, ib->fence);
        mutex_lock(&rdev->ib_pool.mutex);
-       list_add_tail(&ib->list, &rdev->ib_pool.scheduled_ibs);
+       /* once scheduled IB is considered free and protected by the fence */
+       ib->free = true;
        mutex_unlock(&rdev->ib_pool.mutex);
        radeon_ring_unlock_commit(rdev);
        return 0;
@@ -164,7 +143,6 @@ int radeon_ib_pool_init(struct radeon_device *rdev)
        if (rdev->ib_pool.robj)
                return 0;
        /* Allocate 1M object buffer */
-       INIT_LIST_HEAD(&rdev->ib_pool.scheduled_ibs);
        r = radeon_bo_create(rdev, NULL,  RADEON_IB_POOL_SIZE*64*1024,
                                true, RADEON_GEM_DOMAIN_GTT,
                                &rdev->ib_pool.robj);
@@ -195,9 +173,9 @@ int radeon_ib_pool_init(struct radeon_device *rdev)
                rdev->ib_pool.ibs[i].ptr = ptr + offset;
                rdev->ib_pool.ibs[i].idx = i;
                rdev->ib_pool.ibs[i].length_dw = 0;
-               INIT_LIST_HEAD(&rdev->ib_pool.ibs[i].list);
+               rdev->ib_pool.ibs[i].free = true;
        }
-       bitmap_zero(rdev->ib_pool.alloc_bm, RADEON_IB_POOL_SIZE);
+       rdev->ib_pool.head_id = 0;
        rdev->ib_pool.ready = true;
        DRM_INFO("radeon: ib pool ready.\n");
        if (radeon_debugfs_ib_init(rdev)) {
@@ -214,7 +192,6 @@ void radeon_ib_pool_fini(struct radeon_device *rdev)
                return;
        }
        mutex_lock(&rdev->ib_pool.mutex);
-       bitmap_zero(rdev->ib_pool.alloc_bm, RADEON_IB_POOL_SIZE);
        if (rdev->ib_pool.robj) {
                r = radeon_bo_reserve(rdev->ib_pool.robj, false);
                if (likely(r == 0)) {
@@ -363,7 +340,7 @@ static int radeon_debugfs_ib_info(struct seq_file *m, void *data)
        if (ib == NULL) {
                return 0;
        }
-       seq_printf(m, "IB %04lu\n", ib->idx);
+       seq_printf(m, "IB %04u\n", ib->idx);
        seq_printf(m, "IB fence %p\n", ib->fence);
        seq_printf(m, "IB size %05u dwords\n", ib->length_dw);
        for (i = 0; i < ib->length_dw; i++) {
index 5943d56..0302167 100644 (file)
@@ -549,9 +549,12 @@ static void rv770_gpu_init(struct radeon_device *rdev)
 
        gb_tiling_config |= BANK_SWAPS(1);
 
-       backend_map = r700_get_tile_pipe_to_backend_map(rdev->config.rv770.max_tile_pipes,
-                                                       rdev->config.rv770.max_backends,
-                                                       (0xff << rdev->config.rv770.max_backends) & 0xff);
+       if (rdev->family == CHIP_RV740)
+               backend_map = 0x28;
+       else
+               backend_map = r700_get_tile_pipe_to_backend_map(rdev->config.rv770.max_tile_pipes,
+                                                               rdev->config.rv770.max_backends,
+                                                               (0xff << rdev->config.rv770.max_backends) & 0xff);
        gb_tiling_config |= BACKEND_MAP(backend_map);
 
        cc_gc_shader_pipe_config =
index e2123af..3d47a2c 100644 (file)
@@ -196,14 +196,15 @@ EXPORT_SYMBOL(ttm_tt_populate);
 
 #ifdef CONFIG_X86
 static inline int ttm_tt_set_page_caching(struct page *p,
-                                         enum ttm_caching_state c_state)
+                                         enum ttm_caching_state c_old,
+                                         enum ttm_caching_state c_new)
 {
        int ret = 0;
 
        if (PageHighMem(p))
                return 0;
 
-       if (get_page_memtype(p) != -1) {
+       if (c_old != tt_cached) {
                /* p isn't in the default caching state, set it to
                 * writeback first to free its current memtype. */
 
@@ -212,16 +213,17 @@ static inline int ttm_tt_set_page_caching(struct page *p,
                        return ret;
        }
 
-       if (c_state == tt_wc)
+       if (c_new == tt_wc)
                ret = set_memory_wc((unsigned long) page_address(p), 1);
-       else if (c_state == tt_uncached)
+       else if (c_new == tt_uncached)
                ret = set_pages_uc(p, 1);
 
        return ret;
 }
 #else /* CONFIG_X86 */
 static inline int ttm_tt_set_page_caching(struct page *p,
-                                         enum ttm_caching_state c_state)
+                                         enum ttm_caching_state c_old,
+                                         enum ttm_caching_state c_new)
 {
        return 0;
 }
@@ -254,7 +256,9 @@ static int ttm_tt_set_caching(struct ttm_tt *ttm,
        for (i = 0; i < ttm->num_pages; ++i) {
                cur_page = ttm->pages[i];
                if (likely(cur_page != NULL)) {
-                       ret = ttm_tt_set_page_caching(cur_page, c_state);
+                       ret = ttm_tt_set_page_caching(cur_page,
+                                                     ttm->caching_state,
+                                                     c_state);
                        if (unlikely(ret != 0))
                                goto out_err;
                }
@@ -268,7 +272,7 @@ out_err:
        for (j = 0; j < i; ++j) {
                cur_page = ttm->pages[j];
                if (likely(cur_page != NULL)) {
-                       (void)ttm_tt_set_page_caching(cur_page,
+                       (void)ttm_tt_set_page_caching(cur_page, c_state,
                                                      ttm->caching_state);
                }
        }
index a6e8f68..0c9c081 100644 (file)
@@ -348,22 +348,19 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
                 */
 
                DRM_INFO("It appears like vesafb is loaded. "
-                        "Ignore above error if any. Entering stealth mode.\n");
+                        "Ignore above error if any.\n");
                ret = pci_request_region(dev->pdev, 2, "vmwgfx stealth probe");
                if (unlikely(ret != 0)) {
                        DRM_ERROR("Failed reserving the SVGA MMIO resource.\n");
                        goto out_no_device;
                }
-               vmw_kms_init(dev_priv);
-               vmw_overlay_init(dev_priv);
-       } else {
-               ret = vmw_request_device(dev_priv);
-               if (unlikely(ret != 0))
-                       goto out_no_device;
-               vmw_kms_init(dev_priv);
-               vmw_overlay_init(dev_priv);
-               vmw_fb_init(dev_priv);
        }
+       ret = vmw_request_device(dev_priv);
+       if (unlikely(ret != 0))
+               goto out_no_device;
+       vmw_kms_init(dev_priv);
+       vmw_overlay_init(dev_priv);
+       vmw_fb_init(dev_priv);
 
        dev_priv->pm_nb.notifier_call = vmwgfx_pm_notifier;
        register_pm_notifier(&dev_priv->pm_nb);
@@ -406,17 +403,15 @@ static int vmw_driver_unload(struct drm_device *dev)
 
        unregister_pm_notifier(&dev_priv->pm_nb);
 
-       if (!dev_priv->stealth) {
-               vmw_fb_close(dev_priv);
-               vmw_kms_close(dev_priv);
-               vmw_overlay_close(dev_priv);
-               vmw_release_device(dev_priv);
-               pci_release_regions(dev->pdev);
-       } else {
-               vmw_kms_close(dev_priv);
-               vmw_overlay_close(dev_priv);
+       vmw_fb_close(dev_priv);
+       vmw_kms_close(dev_priv);
+       vmw_overlay_close(dev_priv);
+       vmw_release_device(dev_priv);
+       if (dev_priv->stealth)
                pci_release_region(dev->pdev, 2);
-       }
+       else
+               pci_release_regions(dev->pdev);
+
        if (dev_priv->capabilities & SVGA_CAP_IRQMASK)
                drm_irq_uninstall(dev_priv->dev);
        if (dev->devname == vmw_devname)
@@ -585,11 +580,6 @@ static int vmw_master_set(struct drm_device *dev,
        int ret = 0;
 
        DRM_INFO("Master set.\n");
-       if (dev_priv->stealth) {
-               ret = vmw_request_device(dev_priv);
-               if (unlikely(ret != 0))
-                       return ret;
-       }
 
        if (active) {
                BUG_ON(active != &dev_priv->fbdev_master);
@@ -649,18 +639,11 @@ static void vmw_master_drop(struct drm_device *dev,
 
        ttm_lock_set_kill(&vmaster->lock, true, SIGTERM);
 
-       if (dev_priv->stealth) {
-               ret = ttm_bo_evict_mm(&dev_priv->bdev, TTM_PL_VRAM);
-               if (unlikely(ret != 0))
-                       DRM_ERROR("Unable to clean VRAM on master drop.\n");
-               vmw_release_device(dev_priv);
-       }
        dev_priv->active_master = &dev_priv->fbdev_master;
        ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM);
        ttm_vt_unlock(&dev_priv->fbdev_master.lock);
 
-       if (!dev_priv->stealth)
-               vmw_fb_on(dev_priv);
+       vmw_fb_on(dev_priv);
 }
 
 
index d69caf9..0897359 100644 (file)
@@ -182,25 +182,19 @@ static int vmw_cmd_present_check(struct vmw_private *dev_priv,
        return vmw_cmd_sid_check(dev_priv, sw_context, &cmd->body.sid);
 }
 
-static int vmw_cmd_dma(struct vmw_private *dev_priv,
-                      struct vmw_sw_context *sw_context,
-                      SVGA3dCmdHeader *header)
+static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
+                                  struct vmw_sw_context *sw_context,
+                                  SVGAGuestPtr *ptr,
+                                  struct vmw_dma_buffer **vmw_bo_p)
 {
-       uint32_t handle;
        struct vmw_dma_buffer *vmw_bo = NULL;
        struct ttm_buffer_object *bo;
-       struct vmw_surface *srf = NULL;
-       struct vmw_dma_cmd {
-               SVGA3dCmdHeader header;
-               SVGA3dCmdSurfaceDMA dma;
-       } *cmd;
+       uint32_t handle = ptr->gmrId;
        struct vmw_relocation *reloc;
-       int ret;
        uint32_t cur_validate_node;
        struct ttm_validate_buffer *val_buf;
+       int ret;
 
-       cmd = container_of(header, struct vmw_dma_cmd, header);
-       handle = cmd->dma.guest.ptr.gmrId;
        ret = vmw_user_dmabuf_lookup(sw_context->tfile, handle, &vmw_bo);
        if (unlikely(ret != 0)) {
                DRM_ERROR("Could not find or use GMR region.\n");
@@ -209,14 +203,14 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv,
        bo = &vmw_bo->base;
 
        if (unlikely(sw_context->cur_reloc >= VMWGFX_MAX_RELOCATIONS)) {
-               DRM_ERROR("Max number of DMA commands per submission"
+               DRM_ERROR("Max number relocations per submission"
                          " exceeded\n");
                ret = -EINVAL;
                goto out_no_reloc;
        }
 
        reloc = &sw_context->relocs[sw_context->cur_reloc++];
-       reloc->location = &cmd->dma.guest.ptr;
+       reloc->location = ptr;
 
        cur_validate_node = vmw_dmabuf_validate_node(bo, sw_context->cur_val_buf);
        if (unlikely(cur_validate_node >= VMWGFX_MAX_GMRS)) {
@@ -234,7 +228,89 @@ static int vmw_cmd_dma(struct vmw_private *dev_priv,
                list_add_tail(&val_buf->head, &sw_context->validate_nodes);
                ++sw_context->cur_val_buf;
        }
+       *vmw_bo_p = vmw_bo;
+       return 0;
+
+out_no_reloc:
+       vmw_dmabuf_unreference(&vmw_bo);
+       vmw_bo_p = NULL;
+       return ret;
+}
+
+static int vmw_cmd_end_query(struct vmw_private *dev_priv,
+                            struct vmw_sw_context *sw_context,
+                            SVGA3dCmdHeader *header)
+{
+       struct vmw_dma_buffer *vmw_bo;
+       struct vmw_query_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdEndQuery q;
+       } *cmd;
+       int ret;
+
+       cmd = container_of(header, struct vmw_query_cmd, header);
+       ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
+       if (unlikely(ret != 0))
+               return ret;
+
+       ret = vmw_translate_guest_ptr(dev_priv, sw_context,
+                                     &cmd->q.guestResult,
+                                     &vmw_bo);
+       if (unlikely(ret != 0))
+               return ret;
+
+       vmw_dmabuf_unreference(&vmw_bo);
+       return 0;
+}
 
+static int vmw_cmd_wait_query(struct vmw_private *dev_priv,
+                             struct vmw_sw_context *sw_context,
+                             SVGA3dCmdHeader *header)
+{
+       struct vmw_dma_buffer *vmw_bo;
+       struct vmw_query_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdWaitForQuery q;
+       } *cmd;
+       int ret;
+
+       cmd = container_of(header, struct vmw_query_cmd, header);
+       ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
+       if (unlikely(ret != 0))
+               return ret;
+
+       ret = vmw_translate_guest_ptr(dev_priv, sw_context,
+                                     &cmd->q.guestResult,
+                                     &vmw_bo);
+       if (unlikely(ret != 0))
+               return ret;
+
+       vmw_dmabuf_unreference(&vmw_bo);
+       return 0;
+}
+
+
+static int vmw_cmd_dma(struct vmw_private *dev_priv,
+                      struct vmw_sw_context *sw_context,
+                      SVGA3dCmdHeader *header)
+{
+       struct vmw_dma_buffer *vmw_bo = NULL;
+       struct ttm_buffer_object *bo;
+       struct vmw_surface *srf = NULL;
+       struct vmw_dma_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdSurfaceDMA dma;
+       } *cmd;
+       int ret;
+
+       cmd = container_of(header, struct vmw_dma_cmd, header);
+       ret = vmw_translate_guest_ptr(dev_priv, sw_context,
+                                     &cmd->dma.guest.ptr,
+                                     &vmw_bo);
+       if (unlikely(ret != 0))
+               return ret;
+
+       bo = &vmw_bo->base;
        ret = vmw_user_surface_lookup_handle(dev_priv, sw_context->tfile,
                                             cmd->dma.host.sid, &srf);
        if (ret) {
@@ -379,8 +455,8 @@ static vmw_cmd_func vmw_cmd_funcs[SVGA_3D_CMD_MAX] = {
        VMW_CMD_DEF(SVGA_3D_CMD_DRAW_PRIMITIVES, &vmw_cmd_draw),
        VMW_CMD_DEF(SVGA_3D_CMD_SETSCISSORRECT, &vmw_cmd_cid_check),
        VMW_CMD_DEF(SVGA_3D_CMD_BEGIN_QUERY, &vmw_cmd_cid_check),
-       VMW_CMD_DEF(SVGA_3D_CMD_END_QUERY, &vmw_cmd_cid_check),
-       VMW_CMD_DEF(SVGA_3D_CMD_WAIT_FOR_QUERY, &vmw_cmd_cid_check),
+       VMW_CMD_DEF(SVGA_3D_CMD_END_QUERY, &vmw_cmd_end_query),
+       VMW_CMD_DEF(SVGA_3D_CMD_WAIT_FOR_QUERY, &vmw_cmd_wait_query),
        VMW_CMD_DEF(SVGA_3D_CMD_PRESENT_READBACK, &vmw_cmd_ok),
        VMW_CMD_DEF(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN,
                    &vmw_cmd_blt_surf_screen_check)
index 4f4f643..a933670 100644 (file)
@@ -559,6 +559,9 @@ int vmw_fb_init(struct vmw_private *vmw_priv)
        info->pixmap.scan_align = 1;
 #endif
 
+       info->aperture_base = vmw_priv->vram_start;
+       info->aperture_size = vmw_priv->vram_size;
+
        /*
         * Dirty & Deferred IO
         */
index 24b56dc..2f6cf69 100644 (file)
@@ -961,7 +961,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
                remaining -= 7;
                pr_devel("client 0x%p called 'target'\n", priv);
                /* if target is default */
-               if (!strncmp(kbuf, "default", 7))
+               if (!strncmp(curr_pos, "default", 7))
                        pdev = pci_dev_get(vga_default_device());
                else {
                        if (!vga_pci_str_to_vars(curr_pos, remaining,
index 24d90ea..71d4c07 100644 (file)
@@ -55,6 +55,12 @@ source "drivers/hid/usbhid/Kconfig"
 menu "Special HID drivers"
        depends on HID
 
+config HID_3M_PCT
+       tristate "3M PCT"
+       depends on USB_HID
+       ---help---
+       Support for 3M PCT touch screens.
+
 config HID_A4TECH
        tristate "A4 tech" if EMBEDDED
        depends on USB_HID
@@ -183,6 +189,23 @@ config LOGIRUMBLEPAD2_FF
          Say Y here if you want to enable force feedback support for Logitech
          Rumblepad 2 devices.
 
+config LOGIG940_FF
+       bool "Logitech Flight System G940 force feedback support"
+       depends on HID_LOGITECH
+       select INPUT_FF_MEMLESS
+       help
+         Say Y here if you want to enable force feedback support for Logitech
+         Flight System G940 devices.
+
+config HID_MAGICMOUSE
+       tristate "Apple MagicMouse multi-touch support"
+       depends on BT_HIDP
+       ---help---
+       Support for the Apple Magic Mouse multi-touch.
+
+       Say Y here if you want support for the multi-touch features of the
+       Apple Wireless "Magic" Mouse.
+
 config HID_MICROSOFT
        tristate "Microsoft" if EMBEDDED
        depends on USB_HID
@@ -190,6 +213,12 @@ config HID_MICROSOFT
        ---help---
        Support for Microsoft devices that are not fully compliant with HID standard.
 
+config HID_MOSART
+       tristate "MosArt"
+       depends on USB_HID
+       ---help---
+       Support for MosArt dual-touch panels.
+
 config HID_MONTEREY
        tristate "Monterey" if EMBEDDED
        depends on USB_HID
@@ -198,12 +227,18 @@ config HID_MONTEREY
        Support for Monterey Genius KB29E.
 
 config HID_NTRIG
-       tristate "NTrig" if EMBEDDED
+       tristate "NTrig"
        depends on USB_HID
-       default !EMBEDDED
        ---help---
        Support for N-Trig touch screen.
 
+config HID_ORTEK
+       tristate "Ortek" if EMBEDDED
+       depends on USB_HID
+       default !EMBEDDED
+       ---help---
+       Support for Ortek WKB-2000 wireless keyboard + mouse trackpad.
+
 config HID_PANTHERLORD
        tristate "Pantherlord support" if EMBEDDED
        depends on USB_HID
@@ -227,6 +262,12 @@ config HID_PETALYNX
        ---help---
        Support for Petalynx Maxter remote control.
 
+config HID_QUANTA
+       tristate "Quanta Optical Touch"
+       depends on USB_HID
+       ---help---
+       Support for Quanta Optical Touch dual-touch panels.
+
 config HID_SAMSUNG
        tristate "Samsung" if EMBEDDED
        depends on USB_HID
@@ -241,6 +282,12 @@ config HID_SONY
        ---help---
        Support for Sony PS3 controller.
 
+config HID_STANTUM
+       tristate "Stantum"
+       depends on USB_HID
+       ---help---
+       Support for Stantum multitouch panel.
+
 config HID_SUNPLUS
        tristate "Sunplus" if EMBEDDED
        depends on USB_HID
@@ -305,9 +352,8 @@ config THRUSTMASTER_FF
          Rumble Force or Force Feedback Wheel.
 
 config HID_WACOM
-       tristate "Wacom Bluetooth devices support" if EMBEDDED
+       tristate "Wacom Bluetooth devices support"
        depends on BT_HIDP
-       default !EMBEDDED
        ---help---
        Support for Wacom Graphire Bluetooth tablet.
 
index 0de2dff..0b2618f 100644 (file)
@@ -18,7 +18,11 @@ endif
 ifdef CONFIG_LOGIRUMBLEPAD2_FF
        hid-logitech-objs       += hid-lg2ff.o
 endif
+ifdef CONFIG_LOGIG940_FF
+       hid-logitech-objs       += hid-lg3ff.o
+endif
 
+obj-$(CONFIG_HID_3M_PCT)       += hid-3m-pct.o
 obj-$(CONFIG_HID_A4TECH)       += hid-a4tech.o
 obj-$(CONFIG_HID_APPLE)                += hid-apple.o
 obj-$(CONFIG_HID_BELKIN)       += hid-belkin.o
@@ -31,14 +35,19 @@ obj-$(CONFIG_HID_GYRATION)  += hid-gyration.o
 obj-$(CONFIG_HID_KENSINGTON)   += hid-kensington.o
 obj-$(CONFIG_HID_KYE)          += hid-kye.o
 obj-$(CONFIG_HID_LOGITECH)     += hid-logitech.o
+obj-$(CONFIG_HID_MAGICMOUSE)    += hid-magicmouse.o
 obj-$(CONFIG_HID_MICROSOFT)    += hid-microsoft.o
 obj-$(CONFIG_HID_MONTEREY)     += hid-monterey.o
+obj-$(CONFIG_HID_MOSART)       += hid-mosart.o
 obj-$(CONFIG_HID_NTRIG)                += hid-ntrig.o
+obj-$(CONFIG_HID_ORTEK)                += hid-ortek.o
+obj-$(CONFIG_HID_QUANTA)       += hid-quanta.o
 obj-$(CONFIG_HID_PANTHERLORD)  += hid-pl.o
 obj-$(CONFIG_HID_PETALYNX)     += hid-petalynx.o
 obj-$(CONFIG_HID_SAMSUNG)      += hid-samsung.o
 obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
 obj-$(CONFIG_HID_SONY)         += hid-sony.o
+obj-$(CONFIG_HID_STANTUM)      += hid-stantum.o
 obj-$(CONFIG_HID_SUNPLUS)      += hid-sunplus.o
 obj-$(CONFIG_HID_GREENASIA)    += hid-gaff.o
 obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o
diff --git a/drivers/hid/hid-3m-pct.c b/drivers/hid/hid-3m-pct.c
new file mode 100644 (file)
index 0000000..2370aef
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ *  HID driver for 3M PCT multitouch panels
+ *
+ *  Copyright (c) 2009 Stephane Chatty <chatty@enac.fr>
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
+MODULE_DESCRIPTION("3M PCT multitouch panels");
+MODULE_LICENSE("GPL");
+
+#include "hid-ids.h"
+
+struct mmm_finger {
+       __s32 x, y;
+       __u8 rank;
+       bool touch, valid;
+};
+
+struct mmm_data {
+       struct mmm_finger f[10];
+       __u8 curid, num;
+       bool touch, valid;
+};
+
+static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       switch (usage->hid & HID_USAGE_PAGE) {
+
+       case HID_UP_BUTTON:
+               return -1;
+
+       case HID_UP_GENDESK:
+               switch (usage->hid) {
+               case HID_GD_X:
+                       hid_map_usage(hi, usage, bit, max,
+                                       EV_ABS, ABS_MT_POSITION_X);
+                       /* touchscreen emulation */
+                       input_set_abs_params(hi->input, ABS_X,
+                                               field->logical_minimum,
+                                               field->logical_maximum, 0, 0);
+                       return 1;
+               case HID_GD_Y:
+                       hid_map_usage(hi, usage, bit, max,
+                                       EV_ABS, ABS_MT_POSITION_Y);
+                       /* touchscreen emulation */
+                       input_set_abs_params(hi->input, ABS_Y,
+                                               field->logical_minimum,
+                                               field->logical_maximum, 0, 0);
+                       return 1;
+               }
+               return 0;
+
+       case HID_UP_DIGITIZER:
+               switch (usage->hid) {
+               /* we do not want to map these: no input-oriented meaning */
+               case 0x14:
+               case 0x23:
+               case HID_DG_INPUTMODE:
+               case HID_DG_DEVICEINDEX:
+               case HID_DG_CONTACTCOUNT:
+               case HID_DG_CONTACTMAX:
+               case HID_DG_INRANGE:
+               case HID_DG_CONFIDENCE:
+                       return -1;
+               case HID_DG_TIPSWITCH:
+                       /* touchscreen emulation */
+                       hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
+                       return 1;
+               case HID_DG_CONTACTID:
+                       hid_map_usage(hi, usage, bit, max,
+                                       EV_ABS, ABS_MT_TRACKING_ID);
+                       return 1;
+               }
+               /* let hid-input decide for the others */
+               return 0;
+
+       case 0xff000000:
+               /* we do not want to map these: no input-oriented meaning */
+               return -1;
+       }
+
+       return 0;
+}
+
+static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       if (usage->type == EV_KEY || usage->type == EV_ABS)
+               clear_bit(usage->code, *bit);
+
+       return 0;
+}
+
+/*
+ * this function is called when a whole packet has been received and processed,
+ * so that it can decide what to send to the input layer.
+ */
+static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
+{
+       struct mmm_finger *oldest = 0;
+       bool pressed = false, released = false;
+       int i;
+
+       /*
+        * we need to iterate on all fingers to decide if we have a press
+        * or a release event in our touchscreen emulation.
+        */
+       for (i = 0; i < 10; ++i) {
+               struct mmm_finger *f = &md->f[i];
+               if (!f->valid) {
+                       /* this finger is just placeholder data, ignore */
+               } else if (f->touch) {
+                       /* this finger is on the screen */
+                       input_event(input, EV_ABS, ABS_MT_TRACKING_ID, i);
+                       input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x);
+                       input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y);
+                       input_mt_sync(input);
+                       /*
+                        * touchscreen emulation: maintain the age rank
+                        * of this finger, decide if we have a press
+                        */
+                       if (f->rank == 0) {
+                               f->rank = ++(md->num);
+                               if (f->rank == 1)
+                                       pressed = true;
+                       }
+                       if (f->rank == 1)
+                               oldest = f;
+               } else {
+                       /* this finger took off the screen */
+                       /* touchscreen emulation: maintain age rank of others */
+                       int j;
+
+                       for (j = 0; j < 10; ++j) {
+                               struct mmm_finger *g = &md->f[j];
+                               if (g->rank > f->rank) {
+                                       g->rank--;
+                                       if (g->rank == 1)
+                                               oldest = g;
+                               }
+                       }
+                       f->rank = 0;
+                       --(md->num);
+                       if (md->num == 0)
+                               released = true;
+               }
+               f->valid = 0;
+       }
+
+       /* touchscreen emulation */
+       if (oldest) {
+               if (pressed)
+                       input_event(input, EV_KEY, BTN_TOUCH, 1);
+               input_event(input, EV_ABS, ABS_X, oldest->x);
+               input_event(input, EV_ABS, ABS_Y, oldest->y);
+       } else if (released) {
+               input_event(input, EV_KEY, BTN_TOUCH, 0);
+       }
+}
+
+/*
+ * this function is called upon all reports
+ * so that we can accumulate contact point information,
+ * and call input_mt_sync after each point.
+ */
+static int mmm_event(struct hid_device *hid, struct hid_field *field,
+                               struct hid_usage *usage, __s32 value)
+{
+       struct mmm_data *md = hid_get_drvdata(hid);
+       /*
+        * strangely, this function can be called before
+        * field->hidinput is initialized!
+        */
+       if (hid->claimed & HID_CLAIMED_INPUT) {
+               struct input_dev *input = field->hidinput->input;
+               switch (usage->hid) {
+               case HID_DG_TIPSWITCH:
+                       md->touch = value;
+                       break;
+               case HID_DG_CONFIDENCE:
+                       md->valid = value;
+                       break;
+               case HID_DG_CONTACTID:
+                       if (md->valid) {
+                               md->curid = value;
+                               md->f[value].touch = md->touch;
+                               md->f[value].valid = 1;
+                       }
+                       break;
+               case HID_GD_X:
+                       if (md->valid)
+                               md->f[md->curid].x = value;
+                       break;
+               case HID_GD_Y:
+                       if (md->valid)
+                               md->f[md->curid].y = value;
+                       break;
+               case HID_DG_CONTACTCOUNT:
+                       mmm_filter_event(md, input);
+                       break;
+               }
+       }
+
+       /* we have handled the hidinput part, now remains hiddev */
+       if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
+               hid->hiddev_hid_event(hid, field, usage, value);
+
+       return 1;
+}
+
+static int mmm_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       int ret;
+       struct mmm_data *md;
+
+       md = kzalloc(sizeof(struct mmm_data), GFP_KERNEL);
+       if (!md) {
+               dev_err(&hdev->dev, "cannot allocate 3M data\n");
+               return -ENOMEM;
+       }
+       hid_set_drvdata(hdev, md);
+
+       ret = hid_parse(hdev);
+       if (!ret)
+               ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+
+       if (ret)
+               kfree(md);
+       return ret;
+}
+
+static void mmm_remove(struct hid_device *hdev)
+{
+       hid_hw_stop(hdev);
+       kfree(hid_get_drvdata(hdev));
+       hid_set_drvdata(hdev, NULL);
+}
+
+static const struct hid_device_id mmm_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, mmm_devices);
+
+static const struct hid_usage_id mmm_grabbed_usages[] = {
+       { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
+       { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
+};
+
+static struct hid_driver mmm_driver = {
+       .name = "3m-pct",
+       .id_table = mmm_devices,
+       .probe = mmm_probe,
+       .remove = mmm_remove,
+       .input_mapping = mmm_input_mapping,
+       .input_mapped = mmm_input_mapped,
+       .usage_table = mmm_grabbed_usages,
+       .event = mmm_event,
+};
+
+static int __init mmm_init(void)
+{
+       return hid_register_driver(&mmm_driver);
+}
+
+static void __exit mmm_exit(void)
+{
+       hid_unregister_driver(&mmm_driver);
+}
+
+module_init(mmm_init);
+module_exit(mmm_exit);
+MODULE_LICENSE("GPL");
+
index 5b4d66d..78286b1 100644 (file)
@@ -40,6 +40,11 @@ module_param(fnmode, uint, 0644);
 MODULE_PARM_DESC(fnmode, "Mode of fn key on Apple keyboards (0 = disabled, "
                "[1] = fkeyslast, 2 = fkeysfirst)");
 
+static unsigned int iso_layout = 1;
+module_param(iso_layout, uint, 0644);
+MODULE_PARM_DESC(iso_layout, "Enable/Disable hardcoded ISO-layout of the keyboard. "
+               "(0 = disabled, [1] = enabled)");
+
 struct apple_sc {
        unsigned long quirks;
        unsigned int fn_on;
@@ -199,11 +204,13 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
                }
        }
 
-       if (asc->quirks & APPLE_ISO_KEYBOARD) {
-               trans = apple_find_translation(apple_iso_keyboard, usage->code);
-               if (trans) {
-                       input_event(input, usage->type, trans->to, value);
-                       return 1;
+        if (iso_layout) {
+               if (asc->quirks & APPLE_ISO_KEYBOARD) {
+                       trans = apple_find_translation(apple_iso_keyboard, usage->code);
+                       if (trans) {
+                               input_event(input, usage->type, trans->to, value);
+                               return 1;
+                       }
                }
        }
 
index eabe5f8..368fbb0 100644 (file)
@@ -4,7 +4,7 @@
  *  Copyright (c) 1999 Andreas Gal
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
- *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2006-2010 Jiri Kosina
  */
 
 /*
@@ -51,7 +51,7 @@ EXPORT_SYMBOL_GPL(hid_debug);
  * Register a new report for a device.
  */
 
-static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id)
+struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id)
 {
        struct hid_report_enum *report_enum = device->report_enum + type;
        struct hid_report *report;
@@ -75,6 +75,7 @@ static struct hid_report *hid_register_report(struct hid_device *device, unsigne
 
        return report;
 }
+EXPORT_SYMBOL_GPL(hid_register_report);
 
 /*
  * Register a new field for this report.
@@ -387,7 +388,8 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
        __u32 data;
        unsigned n;
 
-       if (item->size == 0) {
+       /* Local delimiter could have value 0, which allows size to be 0 */
+       if (item->size == 0 && item->tag != HID_LOCAL_ITEM_TAG_DELIMITER) {
                dbg_hid("item data expected for local item\n");
                return -1;
        }
@@ -1248,11 +1250,13 @@ EXPORT_SYMBOL_GPL(hid_disconnect);
 
 /* a list of devices for which there is a specialized driver on HID bus */
 static const struct hid_device_id hid_blacklist[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
        { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
        { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI) },
@@ -1324,6 +1328,7 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) },
@@ -1337,10 +1342,15 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
        { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
        { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
        { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
@@ -1543,8 +1553,9 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) },
        { HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM)},
-       { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM2)},
+       { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT)},
+       { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)},
+       { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)},
        { HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) },
        { HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) },
@@ -1661,8 +1672,6 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) },
        { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY1) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) },
        { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
index 6abd036..cd4ece6 100644 (file)
@@ -864,13 +864,13 @@ static const char **names[EV_MAX + 1] = {
        [EV_SND] = sounds,                      [EV_REP] = repeats,
 };
 
-void hid_resolv_event(__u8 type, __u16 code, struct seq_file *f) {
-
+static void hid_resolv_event(__u8 type, __u16 code, struct seq_file *f)
+{
        seq_printf(f, "%s.%s", events[type] ? events[type] : "?",
                names[type] ? (names[type][code] ? names[type][code] : "?") : "?");
 }
 
-void hid_dump_input_mapping(struct hid_device *hid, struct seq_file *f)
+static void hid_dump_input_mapping(struct hid_device *hid, struct seq_file *f)
 {
        int i, j, k;
        struct hid_report *report;
index 010368e..72c05f9 100644 (file)
@@ -18,6 +18,9 @@
 #ifndef HID_IDS_H_FILE
 #define HID_IDS_H_FILE
 
+#define USB_VENDOR_ID_3M               0x0596
+#define USB_DEVICE_ID_3M1968           0x0500
+
 #define USB_VENDOR_ID_A4TECH           0x09da
 #define USB_DEVICE_ID_A4TECH_WCP32PU   0x0006
 #define USB_DEVICE_ID_A4TECH_X5_005D   0x000a
@@ -56,6 +59,7 @@
 
 #define USB_VENDOR_ID_APPLE            0x05ac
 #define USB_DEVICE_ID_APPLE_MIGHTYMOUSE        0x0304
+#define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI      0x020e
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO       0x020f
 #define USB_DEVICE_ID_APPLE_GEYSER_ANSI        0x0214
 #define USB_DEVICE_ID_APPLE_ATV_IRCONTROL      0x8241
 #define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
 
-#define USB_VENDOR_ID_ASUS             0x0b05
-#define USB_DEVICE_ID_ASUS_LCM         0x1726
-#define USB_DEVICE_ID_ASUS_LCM2                0x175b
+#define USB_VENDOR_ID_ASUS             0x0486
+#define USB_DEVICE_ID_ASUS_T91MT       0x0185
+
+#define USB_VENDOR_ID_ASUSTEK          0x0b05
+#define USB_DEVICE_ID_ASUSTEK_LCM      0x1726
+#define USB_DEVICE_ID_ASUSTEK_LCM2     0x175b
 
 #define USB_VENDOR_ID_ATEN             0x0557
 #define USB_DEVICE_ID_ATEN_UC100KM     0x2004
 #define USB_VENDOR_ID_ESSENTIAL_REALITY        0x0d7f
 #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
 
+#define USB_VENDOR_ID_ETURBOTOUCH      0x22b9
+#define USB_DEVICE_ID_ETURBOTOUCH      0x0006
+
 #define USB_VENDOR_ID_ETT              0x0664
 #define USB_DEVICE_ID_TC5UH            0x0309
 
 #define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2    0xc219
 #define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D     0xc283
 #define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO     0xc286
+#define USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940      0xc287
 #define USB_DEVICE_ID_LOGITECH_WHEEL   0xc294
 #define USB_DEVICE_ID_LOGITECH_WINGMAN_FFG     0xc293
 #define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL      0xc295
 #define USB_VENDOR_ID_ONTRAK           0x0a07
 #define USB_DEVICE_ID_ONTRAK_ADU100    0x0064
 
+#define USB_VENDOR_ID_ORTEK            0x05a4
+#define USB_DEVICE_ID_ORTEK_WKB2000    0x2000
+
 #define USB_VENDOR_ID_PANJIT           0x134c
 
 #define USB_VENDOR_ID_PANTHERLORD      0x0810
 #define USB_VENDOR_ID_POWERCOM         0x0d9f
 #define USB_DEVICE_ID_POWERCOM_UPS     0x0002
 
+#define USB_VENDOR_ID_PRODIGE          0x05af
+#define USB_DEVICE_ID_PRODIGE_CORDLESS 0x3062
+
 #define USB_VENDOR_ID_SAITEK           0x06a3
 #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
 
+#define USB_VENDOR_ID_QUANTA           0x0408
+#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH     0x3000
+#define USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN  0x3001
+
 #define USB_VENDOR_ID_SAMSUNG          0x0419
 #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE        0x0001
 
 #define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST    0x0034
 #define USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST     0x0046
 
+#define USB_VENDOR_ID_STANTUM          0x1f87
+#define USB_DEVICE_ID_MTP              0x0002
+
 #define USB_VENDOR_ID_SUN              0x0430
 #define USB_DEVICE_ID_RARITAN_KVM_DONGLE       0xcdab
 
 #define USB_VENDOR_ID_SUNPLUS          0x04fc
 #define USB_DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8
 
-#define USB_VENDOR_ID_TENX             0x1130
-#define USB_DEVICE_ID_TENX_IBUDDY1     0x0001
-#define USB_DEVICE_ID_TENX_IBUDDY2     0x0002
-
 #define USB_VENDOR_ID_THRUSTMASTER     0x044f
 
+#define USB_VENDOR_ID_TOUCHPACK                0x1bfd
+#define USB_DEVICE_ID_TOUCHPACK_RTS    0x1688
+
 #define USB_VENDOR_ID_TOPMAX           0x0663
 #define USB_DEVICE_ID_TOPMAX_COBRAPAD  0x0103
 
index 5862b0f..79d9edd 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Copyright (c) 2000-2001 Vojtech Pavlik
- *  Copyright (c) 2006-2007 Jiri Kosina
+ *  Copyright (c) 2006-2010 Jiri Kosina
  *
  *  HID to Linux Input mapping
  */
@@ -193,12 +193,17 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                break;
 
        case HID_UP_BUTTON:
-               code = ((usage->hid - 1) & 0xf);
+               code = ((usage->hid - 1) & HID_USAGE);
 
                switch (field->application) {
                case HID_GD_MOUSE:
                case HID_GD_POINTER:  code += 0x110; break;
-               case HID_GD_JOYSTICK: code += 0x120; break;
+               case HID_GD_JOYSTICK:
+                                     if (code <= 0xf)
+                                             code += BTN_JOYSTICK;
+                                     else
+                                             code += BTN_TRIGGER_HAPPY;
+                                     break;
                case HID_GD_GAMEPAD:  code += 0x130; break;
                default:
                        switch (field->physical) {
@@ -400,6 +405,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                case 0x192: map_key_clear(KEY_CALC);            break;
                case 0x194: map_key_clear(KEY_FILE);            break;
                case 0x196: map_key_clear(KEY_WWW);             break;
+               case 0x199: map_key_clear(KEY_CHAT);            break;
                case 0x19c: map_key_clear(KEY_LOGOFF);          break;
                case 0x19e: map_key_clear(KEY_COFFEE);          break;
                case 0x1a6: map_key_clear(KEY_HELP);            break;
index 9fcd3d0..3677c90 100644 (file)
@@ -34,6 +34,7 @@
 #define LG_FF                  0x200
 #define LG_FF2                 0x400
 #define LG_RDESC_REL_ABS       0x800
+#define LG_FF3                 0x1000
 
 /*
  * Certain Logitech keyboards send in report #3 keys which are far
@@ -266,7 +267,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
                goto err_free;
        }
 
-       if (quirks & (LG_FF | LG_FF2))
+       if (quirks & (LG_FF | LG_FF2 | LG_FF3))
                connect_mask &= ~HID_CONNECT_FF;
 
        ret = hid_hw_start(hdev, connect_mask);
@@ -279,6 +280,8 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
                lgff_init(hdev);
        if (quirks & LG_FF2)
                lg2ff_init(hdev);
+       if (quirks & LG_FF3)
+               lg3ff_init(hdev);
 
        return 0;
 err_free:
@@ -331,6 +334,8 @@ static const struct hid_device_id lg_devices[] = {
                .driver_data = LG_FF },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
                .driver_data = LG_FF2 },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
+               .driver_data = LG_FF3 },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
                .driver_data = LG_RDESC_REL_ABS },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER),
index bf31592..ce2ac86 100644 (file)
@@ -13,4 +13,10 @@ int lg2ff_init(struct hid_device *hdev);
 static inline int lg2ff_init(struct hid_device *hdev) { return -1; }
 #endif
 
+#ifdef CONFIG_LOGIG940_FF
+int lg3ff_init(struct hid_device *hdev);
+#else
+static inline int lg3ff_init(struct hid_device *hdev) { return -1; }
+#endif
+
 #endif
diff --git a/drivers/hid/hid-lg3ff.c b/drivers/hid/hid-lg3ff.c
new file mode 100644 (file)
index 0000000..4002832
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ *  Force feedback support for Logitech Flight System G940
+ *
+ *  Copyright (c) 2009 Gary Stein <LordCnidarian@gmail.com>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+
+#include "usbhid/usbhid.h"
+#include "hid-lg.h"
+
+/*
+ * G940 Theory of Operation (from experimentation)
+ *
+ * There are 63 fields (only 3 of them currently used)
+ * 0 - seems to be command field
+ * 1 - 30 deal with the x axis
+ * 31 -60 deal with the y axis
+ *
+ * Field 1 is x axis constant force
+ * Field 31 is y axis constant force
+ *
+ * other interesting fields 1,2,3,4 on x axis
+ * (same for 31,32,33,34 on y axis)
+ *
+ * 0 0 127 127 makes the joystick autocenter hard
+ *
+ * 127 0 127 127 makes the joystick loose on the right,
+ * but stops all movemnt left
+ *
+ * -127 0 -127 -127 makes the joystick loose on the left,
+ * but stops all movement right
+ *
+ * 0 0 -127 -127 makes the joystick rattle very hard
+ *
+ * I'm sure these are effects that I don't know enough about them
+ */
+
+struct lg3ff_device {
+       struct hid_report *report;
+};
+
+static int hid_lg3ff_play(struct input_dev *dev, void *data,
+                        struct ff_effect *effect)
+{
+       struct hid_device *hid = input_get_drvdata(dev);
+       struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+       struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+       int x, y;
+
+/*
+ * Maxusage should always be 63 (maximum fields)
+ * likely a better way to ensure this data is clean
+ */
+       memset(report->field[0]->value, 0, sizeof(__s32)*report->field[0]->maxusage);
+
+       switch (effect->type) {
+       case FF_CONSTANT:
+/*
+ * Already clamped in ff_memless
+ * 0 is center (different then other logitech)
+ */
+               x = effect->u.ramp.start_level;
+               y = effect->u.ramp.end_level;
+
+               /* send command byte */
+               report->field[0]->value[0] = 0x51;
+
+/*
+ * Sign backwards from other Force3d pro
+ * which get recast here in two's complement 8 bits
+ */
+               report->field[0]->value[1] = (unsigned char)(-x);
+               report->field[0]->value[31] = (unsigned char)(-y);
+
+               usbhid_submit_report(hid, report, USB_DIR_OUT);
+               break;
+       }
+       return 0;
+}
+static void hid_lg3ff_set_autocenter(struct input_dev *dev, u16 magnitude)
+{
+       struct hid_device *hid = input_get_drvdata(dev);
+       struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+       struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+
+/*
+ * Auto Centering probed from device
+ * NOTE: deadman's switch on G940 must be covered
+ * for effects to work
+ */
+       report->field[0]->value[0] = 0x51;
+       report->field[0]->value[1] = 0x00;
+       report->field[0]->value[2] = 0x00;
+       report->field[0]->value[3] = 0x7F;
+       report->field[0]->value[4] = 0x7F;
+       report->field[0]->value[31] = 0x00;
+       report->field[0]->value[32] = 0x00;
+       report->field[0]->value[33] = 0x7F;
+       report->field[0]->value[34] = 0x7F;
+
+       usbhid_submit_report(hid, report, USB_DIR_OUT);
+}
+
+
+static const signed short ff3_joystick_ac[] = {
+       FF_CONSTANT,
+       FF_AUTOCENTER,
+       -1
+};
+
+int lg3ff_init(struct hid_device *hid)
+{
+       struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+       struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+       struct input_dev *dev = hidinput->input;
+       struct hid_report *report;
+       struct hid_field *field;
+       const signed short *ff_bits = ff3_joystick_ac;
+       int error;
+       int i;
+
+       /* Find the report to use */
+       if (list_empty(report_list)) {
+               err_hid("No output report found");
+               return -1;
+       }
+
+       /* Check that the report looks ok */
+       report = list_entry(report_list->next, struct hid_report, list);
+       if (!report) {
+               err_hid("NULL output report");
+               return -1;
+       }
+
+       field = report->field[0];
+       if (!field) {
+               err_hid("NULL field");
+               return -1;
+       }
+
+       /* Assume single fixed device G940 */
+       for (i = 0; ff_bits[i] >= 0; i++)
+               set_bit(ff_bits[i], dev->ffbit);
+
+       error = input_ff_create_memless(dev, NULL, hid_lg3ff_play);
+       if (error)
+               return error;
+
+       if (test_bit(FF_AUTOCENTER, dev->ffbit))
+               dev->ff->set_autocenter = hid_lg3ff_set_autocenter;
+
+       dev_info(&hid->dev, "Force feedback for Logitech Flight System G940 by "
+                       "Gary Stein <LordCnidarian@gmail.com>\n");
+       return 0;
+}
+
index 987abeb..61142b7 100644 (file)
@@ -67,6 +67,7 @@ static const struct dev_type devices[] = {
        { 0x046d, 0xc219, ff_rumble },
        { 0x046d, 0xc283, ff_joystick },
        { 0x046d, 0xc286, ff_joystick_ac },
+       { 0x046d, 0xc287, ff_joystick_ac },
        { 0x046d, 0xc293, ff_joystick },
        { 0x046d, 0xc294, ff_wheel },
        { 0x046d, 0xc295, ff_joystick },
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
new file mode 100644 (file)
index 0000000..4a3a94f
--- /dev/null
@@ -0,0 +1,449 @@
+/*
+ *   Apple "Magic" Wireless Mouse driver
+ *
+ *   Copyright (c) 2010 Michael Poole <mdpoole@troilus.org>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "hid-ids.h"
+
+static bool emulate_3button = true;
+module_param(emulate_3button, bool, 0644);
+MODULE_PARM_DESC(emulate_3button, "Emulate a middle button");
+
+static int middle_button_start = -350;
+static int middle_button_stop = +350;
+
+static bool emulate_scroll_wheel = true;
+module_param(emulate_scroll_wheel, bool, 0644);
+MODULE_PARM_DESC(emulate_scroll_wheel, "Emulate a scroll wheel");
+
+static bool report_touches = true;
+module_param(report_touches, bool, 0644);
+MODULE_PARM_DESC(report_touches, "Emit touch records (otherwise, only use them for emulation)");
+
+static bool report_undeciphered;
+module_param(report_undeciphered, bool, 0644);
+MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state field using a MSC_RAW event");
+
+#define TOUCH_REPORT_ID   0x29
+/* These definitions are not precise, but they're close enough.  (Bits
+ * 0x03 seem to indicate the aspect ratio of the touch, bits 0x70 seem
+ * to be some kind of bit mask -- 0x20 may be a near-field reading,
+ * and 0x40 is actual contact, and 0x10 may be a start/stop or change
+ * indication.)
+ */
+#define TOUCH_STATE_MASK  0xf0
+#define TOUCH_STATE_NONE  0x00
+#define TOUCH_STATE_START 0x30
+#define TOUCH_STATE_DRAG  0x40
+
+/**
+ * struct magicmouse_sc - Tracks Magic Mouse-specific data.
+ * @input: Input device through which we report events.
+ * @quirks: Currently unused.
+ * @last_timestamp: Timestamp from most recent (18-bit) touch report
+ *     (units of milliseconds over short windows, but seems to
+ *     increase faster when there are no touches).
+ * @delta_time: 18-bit difference between the two most recent touch
+ *     reports from the mouse.
+ * @ntouches: Number of touches in most recent touch report.
+ * @scroll_accel: Number of consecutive scroll motions.
+ * @scroll_jiffies: Time of last scroll motion.
+ * @touches: Most recent data for a touch, indexed by tracking ID.
+ * @tracking_ids: Mapping of current touch input data to @touches.
+ */
+struct magicmouse_sc {
+       struct input_dev *input;
+       unsigned long quirks;
+
+       int last_timestamp;
+       int delta_time;
+       int ntouches;
+       int scroll_accel;
+       unsigned long scroll_jiffies;
+
+       struct {
+               short x;
+               short y;
+               short scroll_y;
+               u8 size;
+       } touches[16];
+       int tracking_ids[16];
+};
+
+static int magicmouse_firm_touch(struct magicmouse_sc *msc)
+{
+       int touch = -1;
+       int ii;
+
+       /* If there is only one "firm" touch, set touch to its
+        * tracking ID.
+        */
+       for (ii = 0; ii < msc->ntouches; ii++) {
+               int idx = msc->tracking_ids[ii];
+               if (msc->touches[idx].size < 8) {
+                       /* Ignore this touch. */
+               } else if (touch >= 0) {
+                       touch = -1;
+                       break;
+               } else {
+                       touch = idx;
+               }
+       }
+
+       return touch;
+}
+
+static void magicmouse_emit_buttons(struct magicmouse_sc *msc, int state)
+{
+       int last_state = test_bit(BTN_LEFT, msc->input->key) << 0 |
+               test_bit(BTN_RIGHT, msc->input->key) << 1 |
+               test_bit(BTN_MIDDLE, msc->input->key) << 2;
+
+       if (emulate_3button) {
+               int id;
+
+               /* If some button was pressed before, keep it held
+                * down.  Otherwise, if there's exactly one firm
+                * touch, use that to override the mouse's guess.
+                */
+               if (state == 0) {
+                       /* The button was released. */
+               } else if (last_state != 0) {
+                       state = last_state;
+               } else if ((id = magicmouse_firm_touch(msc)) >= 0) {
+                       int x = msc->touches[id].x;
+                       if (x < middle_button_start)
+                               state = 1;
+                       else if (x > middle_button_stop)
+                               state = 2;
+                       else
+                               state = 4;
+               } /* else: we keep the mouse's guess */
+
+               input_report_key(msc->input, BTN_MIDDLE, state & 4);
+       }
+
+       input_report_key(msc->input, BTN_LEFT, state & 1);
+       input_report_key(msc->input, BTN_RIGHT, state & 2);
+
+       if (state != last_state)
+               msc->scroll_accel = 0;
+}
+
+static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tdata)
+{
+       struct input_dev *input = msc->input;
+       __s32 x_y = tdata[0] << 8 | tdata[1] << 16 | tdata[2] << 24;
+       int misc = tdata[5] | tdata[6] << 8;
+       int id = (misc >> 6) & 15;
+       int x = x_y << 12 >> 20;
+       int y = -(x_y >> 20);
+
+       /* Store tracking ID and other fields. */
+       msc->tracking_ids[raw_id] = id;
+       msc->touches[id].x = x;
+       msc->touches[id].y = y;
+       msc->touches[id].size = misc & 63;
+
+       /* If requested, emulate a scroll wheel by detecting small
+        * vertical touch motions along the middle of the mouse.
+        */
+       if (emulate_scroll_wheel &&
+           middle_button_start < x && x < middle_button_stop) {
+               static const int accel_profile[] = {
+                       256, 228, 192, 160, 128, 96, 64, 32,
+               };
+               unsigned long now = jiffies;
+               int step = msc->touches[id].scroll_y - y;
+
+               /* Reset acceleration after half a second. */
+               if (time_after(now, msc->scroll_jiffies + HZ / 2))
+                       msc->scroll_accel = 0;
+
+               /* Calculate and apply the scroll motion. */
+               switch (tdata[7] & TOUCH_STATE_MASK) {
+               case TOUCH_STATE_START:
+                       msc->touches[id].scroll_y = y;
+                       msc->scroll_accel = min_t(int, msc->scroll_accel + 1,
+                                               ARRAY_SIZE(accel_profile) - 1);
+                       break;
+               case TOUCH_STATE_DRAG:
+                       step = step / accel_profile[msc->scroll_accel];
+                       if (step != 0) {
+                               msc->touches[id].scroll_y = y;
+                               msc->scroll_jiffies = now;
+                               input_report_rel(input, REL_WHEEL, step);
+                       }
+                       break;
+               }
+       }
+
+       /* Generate the input events for this touch. */
+       if (report_touches) {
+               int orientation = (misc >> 10) - 32;
+
+               input_report_abs(input, ABS_MT_TRACKING_ID, id);
+               input_report_abs(input, ABS_MT_TOUCH_MAJOR, tdata[3]);
+               input_report_abs(input, ABS_MT_TOUCH_MINOR, tdata[4]);
+               input_report_abs(input, ABS_MT_ORIENTATION, orientation);
+               input_report_abs(input, ABS_MT_POSITION_X, x);
+               input_report_abs(input, ABS_MT_POSITION_Y, y);
+
+               if (report_undeciphered)
+                       input_event(input, EV_MSC, MSC_RAW, tdata[7]);
+
+               input_mt_sync(input);
+       }
+}
+
+static int magicmouse_raw_event(struct hid_device *hdev,
+               struct hid_report *report, u8 *data, int size)
+{
+       struct magicmouse_sc *msc = hid_get_drvdata(hdev);
+       struct input_dev *input = msc->input;
+       int x, y, ts, ii, clicks;
+
+       switch (data[0]) {
+       case 0x10:
+               if (size != 6)
+                       return 0;
+               x = (__s16)(data[2] | data[3] << 8);
+               y = (__s16)(data[4] | data[5] << 8);
+               clicks = data[1];
+               break;
+       case TOUCH_REPORT_ID:
+               /* Expect six bytes of prefix, and N*8 bytes of touch data. */
+               if (size < 6 || ((size - 6) % 8) != 0)
+                       return 0;
+               ts = data[3] >> 6 | data[4] << 2 | data[5] << 10;
+               msc->delta_time = (ts - msc->last_timestamp) & 0x3ffff;
+               msc->last_timestamp = ts;
+               msc->ntouches = (size - 6) / 8;
+               for (ii = 0; ii < msc->ntouches; ii++)
+                       magicmouse_emit_touch(msc, ii, data + ii * 8 + 6);
+               /* When emulating three-button mode, it is important
+                * to have the current touch information before
+                * generating a click event.
+                */
+               x = (signed char)data[1];
+               y = (signed char)data[2];
+               clicks = data[3];
+               break;
+       case 0x20: /* Theoretically battery status (0-100), but I have
+                   * never seen it -- maybe it is only upon request.
+                   */
+       case 0x60: /* Unknown, maybe laser on/off. */
+       case 0x61: /* Laser reflection status change.
+                   * data[1]: 0 = spotted, 1 = lost
+                   */
+       default:
+               return 0;
+       }
+
+       magicmouse_emit_buttons(msc, clicks & 3);
+       input_report_rel(input, REL_X, x);
+       input_report_rel(input, REL_Y, y);
+       input_sync(input);
+       return 1;
+}
+
+static int magicmouse_input_open(struct input_dev *dev)
+{
+       struct hid_device *hid = input_get_drvdata(dev);
+
+       return hid->ll_driver->open(hid);
+}
+
+static void magicmouse_input_close(struct input_dev *dev)
+{
+       struct hid_device *hid = input_get_drvdata(dev);
+
+       hid->ll_driver->close(hid);
+}
+
+static void magicmouse_setup_input(struct input_dev *input, struct hid_device *hdev)
+{
+       input_set_drvdata(input, hdev);
+       input->event = hdev->ll_driver->hidinput_input_event;
+       input->open = magicmouse_input_open;
+       input->close = magicmouse_input_close;
+
+       input->name = hdev->name;
+       input->phys = hdev->phys;
+       input->uniq = hdev->uniq;
+       input->id.bustype = hdev->bus;
+       input->id.vendor = hdev->vendor;
+       input->id.product = hdev->product;
+       input->id.version = hdev->version;
+       input->dev.parent = hdev->dev.parent;
+
+       __set_bit(EV_KEY, input->evbit);
+       __set_bit(BTN_LEFT, input->keybit);
+       __set_bit(BTN_RIGHT, input->keybit);
+       if (emulate_3button)
+               __set_bit(BTN_MIDDLE, input->keybit);
+       __set_bit(BTN_TOOL_FINGER, input->keybit);
+
+       __set_bit(EV_REL, input->evbit);
+       __set_bit(REL_X, input->relbit);
+       __set_bit(REL_Y, input->relbit);
+       if (emulate_scroll_wheel)
+               __set_bit(REL_WHEEL, input->relbit);
+
+       if (report_touches) {
+               __set_bit(EV_ABS, input->evbit);
+
+               input_set_abs_params(input, ABS_MT_TRACKING_ID, 0, 15, 0, 0);
+               input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 4, 0);
+               input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255, 4, 0);
+               input_set_abs_params(input, ABS_MT_ORIENTATION, -32, 31, 1, 0);
+               input_set_abs_params(input, ABS_MT_POSITION_X, -1100, 1358,
+                               4, 0);
+               /* Note: Touch Y position from the device is inverted relative
+                * to how pointer motion is reported (and relative to how USB
+                * HID recommends the coordinates work).  This driver keeps
+                * the origin at the same position, and just uses the additive
+                * inverse of the reported Y.
+                */
+               input_set_abs_params(input, ABS_MT_POSITION_Y, -1589, 2047,
+                               4, 0);
+       }
+
+       if (report_undeciphered) {
+               __set_bit(EV_MSC, input->evbit);
+               __set_bit(MSC_RAW, input->mscbit);
+       }
+}
+
+static int magicmouse_probe(struct hid_device *hdev,
+       const struct hid_device_id *id)
+{
+       __u8 feature_1[] = { 0xd7, 0x01 };
+       __u8 feature_2[] = { 0xf8, 0x01, 0x32 };
+       struct input_dev *input;
+       struct magicmouse_sc *msc;
+       struct hid_report *report;
+       int ret;
+
+       msc = kzalloc(sizeof(*msc), GFP_KERNEL);
+       if (msc == NULL) {
+               dev_err(&hdev->dev, "can't alloc magicmouse descriptor\n");
+               return -ENOMEM;
+       }
+
+       msc->quirks = id->driver_data;
+       hid_set_drvdata(hdev, msc);
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               dev_err(&hdev->dev, "magicmouse hid parse failed\n");
+               goto err_free;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+       if (ret) {
+               dev_err(&hdev->dev, "magicmouse hw start failed\n");
+               goto err_free;
+       }
+
+       report = hid_register_report(hdev, HID_INPUT_REPORT, TOUCH_REPORT_ID);
+       if (!report) {
+               dev_err(&hdev->dev, "unable to register touch report\n");
+               ret = -ENOMEM;
+               goto err_stop_hw;
+       }
+       report->size = 6;
+
+       ret = hdev->hid_output_raw_report(hdev, feature_1, sizeof(feature_1),
+                       HID_FEATURE_REPORT);
+       if (ret != sizeof(feature_1)) {
+               dev_err(&hdev->dev, "unable to request touch data (1:%d)\n",
+                               ret);
+               goto err_stop_hw;
+       }
+       ret = hdev->hid_output_raw_report(hdev, feature_2,
+                       sizeof(feature_2), HID_FEATURE_REPORT);
+       if (ret != sizeof(feature_2)) {
+               dev_err(&hdev->dev, "unable to request touch data (2:%d)\n",
+                               ret);
+               goto err_stop_hw;
+       }
+
+       input = input_allocate_device();
+       if (!input) {
+               dev_err(&hdev->dev, "can't alloc input device\n");
+               ret = -ENOMEM;
+               goto err_stop_hw;
+       }
+       magicmouse_setup_input(input, hdev);
+
+       ret = input_register_device(input);
+       if (ret) {
+               dev_err(&hdev->dev, "input device registration failed\n");
+               goto err_input;
+       }
+       msc->input = input;
+
+       return 0;
+err_input:
+       input_free_device(input);
+err_stop_hw:
+       hid_hw_stop(hdev);
+err_free:
+       kfree(msc);
+       return ret;
+}
+
+static void magicmouse_remove(struct hid_device *hdev)
+{
+       hid_hw_stop(hdev);
+       kfree(hid_get_drvdata(hdev));
+}
+
+static const struct hid_device_id magic_mice[] = {
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE),
+               .driver_data = 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, magic_mice);
+
+static struct hid_driver magicmouse_driver = {
+       .name = "magicmouse",
+       .id_table = magic_mice,
+       .probe = magicmouse_probe,
+       .remove = magicmouse_remove,
+       .raw_event = magicmouse_raw_event,
+};
+
+static int __init magicmouse_init(void)
+{
+       int ret;
+
+       ret = hid_register_driver(&magicmouse_driver);
+       if (ret)
+               printk(KERN_ERR "can't register magicmouse driver\n");
+
+       return ret;
+}
+
+static void __exit magicmouse_exit(void)
+{
+       hid_unregister_driver(&magicmouse_driver);
+}
+
+module_init(magicmouse_init);
+module_exit(magicmouse_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-mosart.c b/drivers/hid/hid-mosart.c
new file mode 100644 (file)
index 0000000..c871816
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ *  HID driver for the multitouch panel on the ASUS EeePC T91MT
+ *
+ *  Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
+ *  Copyright (c) 2010 Teemu Tuominen <teemu.tuominen@cybercom.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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
+
+MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
+MODULE_DESCRIPTION("MosArt dual-touch panel");
+MODULE_LICENSE("GPL");
+
+#include "hid-ids.h"
+
+struct mosart_data {
+       __u16 x, y;
+       __u8 id;
+       bool valid;             /* valid finger data, or just placeholder? */
+       bool first;             /* is this the first finger in this frame? */
+       bool activity_now;      /* at least one active finger in this frame? */
+       bool activity;          /* at least one active finger previously? */
+};
+
+static int mosart_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       switch (usage->hid & HID_USAGE_PAGE) {
+
+       case HID_UP_GENDESK:
+               switch (usage->hid) {
+               case HID_GD_X:
+                       hid_map_usage(hi, usage, bit, max,
+                                       EV_ABS, ABS_MT_POSITION_X);
+                       /* touchscreen emulation */
+                       input_set_abs_params(hi->input, ABS_X,
+                                               field->logical_minimum,
+                                               field->logical_maximum, 0, 0);
+                       return 1;
+               case HID_GD_Y:
+                       hid_map_usage(hi, usage, bit, max,
+                                       EV_ABS, ABS_MT_POSITION_Y);
+                       /* touchscreen emulation */
+                       input_set_abs_params(hi->input, ABS_Y,
+                                               field->logical_minimum,
+                                               field->logical_maximum, 0, 0);
+                       return 1;
+               }
+               return 0;
+
+       case HID_UP_DIGITIZER:
+               switch (usage->hid) {
+               case HID_DG_CONFIDENCE:
+               case HID_DG_TIPSWITCH:
+               case HID_DG_INPUTMODE:
+               case HID_DG_DEVICEINDEX:
+               case HID_DG_CONTACTCOUNT:
+               case HID_DG_CONTACTMAX:
+               case HID_DG_TIPPRESSURE:
+               case HID_DG_WIDTH:
+               case HID_DG_HEIGHT:
+                       return -1;
+               case HID_DG_INRANGE:
+                       /* touchscreen emulation */
+                       hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
+                       return 1;
+
+               case HID_DG_CONTACTID:
+                       hid_map_usage(hi, usage, bit, max,
+                                       EV_ABS, ABS_MT_TRACKING_ID);
+                       return 1;
+
+               }
+               return 0;
+
+       case 0xff000000:
+               /* ignore HID features */
+               return -1;
+       }
+
+       return 0;
+}
+
+static int mosart_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       if (usage->type == EV_KEY || usage->type == EV_ABS)
+               clear_bit(usage->code, *bit);
+
+       return 0;
+}
+
+/*
+ * this function is called when a whole finger has been parsed,
+ * so that it can decide what to send to the input layer.
+ */
+static void mosart_filter_event(struct mosart_data *td, struct input_dev *input)
+{
+       td->first = !td->first; /* touchscreen emulation */
+
+       if (!td->valid) {
+               /*
+                * touchscreen emulation: if no finger in this frame is valid
+                * and there previously was finger activity, this is a release
+                */ 
+               if (!td->first && !td->activity_now && td->activity) {
+                       input_event(input, EV_KEY, BTN_TOUCH, 0);
+                       td->activity = false;
+               }
+               return;
+       }
+
+       input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
+       input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
+       input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
+
+       input_mt_sync(input);
+       td->valid = false;
+
+       /* touchscreen emulation: if first active finger in this frame... */
+       if (!td->activity_now) {
+               /* if there was no previous activity, emit touch event */
+               if (!td->activity) {
+                       input_event(input, EV_KEY, BTN_TOUCH, 1);
+                       td->activity = true;
+               }
+               td->activity_now = true;
+               /* and in any case this is our preferred finger */
+               input_event(input, EV_ABS, ABS_X, td->x);
+               input_event(input, EV_ABS, ABS_Y, td->y);
+       }
+}
+
+
+static int mosart_event(struct hid_device *hid, struct hid_field *field,
+                               struct hid_usage *usage, __s32 value)
+{
+       struct mosart_data *td = hid_get_drvdata(hid);
+
+       if (hid->claimed & HID_CLAIMED_INPUT) {
+               struct input_dev *input = field->hidinput->input;
+               switch (usage->hid) {
+               case HID_DG_INRANGE:
+                       td->valid = !!value;
+                       break;
+               case HID_GD_X:
+                       td->x = value;
+                       break;
+               case HID_GD_Y:
+                       td->y = value;
+                       mosart_filter_event(td, input);
+                       break;
+               case HID_DG_CONTACTID:
+                       td->id = value;
+                       break;
+               case HID_DG_CONTACTCOUNT:
+                       /* touch emulation: this is the last field in a frame */
+                       td->first = false;
+                       td->activity_now = false;
+                       break;
+               case HID_DG_CONFIDENCE:
+               case HID_DG_TIPSWITCH:
+                       /* avoid interference from generic hidinput handling */
+                       break;
+
+               default:
+                       /* fallback to the generic hidinput handling */
+                       return 0;
+               }
+       }
+
+       /* we have handled the hidinput part, now remains hiddev */
+       if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
+               hid->hiddev_hid_event(hid, field, usage, value);
+
+       return 1;
+}
+
+static int mosart_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       int ret;
+       struct mosart_data *td;
+
+
+       td = kmalloc(sizeof(struct mosart_data), GFP_KERNEL);
+       if (!td) {
+               dev_err(&hdev->dev, "cannot allocate MosArt data\n");
+               return -ENOMEM;
+       }
+       td->valid = false;
+       td->activity = false;
+       td->activity_now = false;
+       td->first = false;
+       hid_set_drvdata(hdev, td);
+
+       /* currently, it's better to have one evdev device only */
+#if 0
+       hdev->quirks |= HID_QUIRK_MULTI_INPUT;
+#endif
+
+       ret = hid_parse(hdev);
+       if (ret == 0)
+               ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+
+       if (ret == 0) {
+               struct hid_report_enum *re = hdev->report_enum
+                                               + HID_FEATURE_REPORT;
+               struct hid_report *r = re->report_id_hash[7];
+
+               r->field[0]->value[0] = 0x02;
+               usbhid_submit_report(hdev, r, USB_DIR_OUT);
+       } else 
+               kfree(td);
+
+       return ret;
+}
+
+static void mosart_remove(struct hid_device *hdev)
+{
+       hid_hw_stop(hdev);
+       kfree(hid_get_drvdata(hdev));
+       hid_set_drvdata(hdev, NULL);
+}
+
+static const struct hid_device_id mosart_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, mosart_devices);
+
+static const struct hid_usage_id mosart_grabbed_usages[] = {
+       { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
+       { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
+};
+
+static struct hid_driver mosart_driver = {
+       .name = "mosart",
+       .id_table = mosart_devices,
+       .probe = mosart_probe,
+       .remove = mosart_remove,
+       .input_mapping = mosart_input_mapping,
+       .input_mapped = mosart_input_mapped,
+       .usage_table = mosart_grabbed_usages,
+       .event = mosart_event,
+};
+
+static int __init mosart_init(void)
+{
+       return hid_register_driver(&mosart_driver);
+}
+
+static void __exit mosart_exit(void)
+{
+       hid_unregister_driver(&mosart_driver);
+}
+
+module_init(mosart_init);
+module_exit(mosart_exit);
+
index 49ce69d..3234c72 100644 (file)
                                        EV_KEY, (c))
 
 struct ntrig_data {
-       __s32 x, y, id, w, h;
-       char reading_a_point, found_contact_id;
-       char pen_active;
-       char finger_active;
-       char inverted;
+       /* Incoming raw values for a single contact */
+       __u16 x, y, w, h;
+       __u16 id;
+       __u8 confidence;
+
+       bool reading_mt;
+       __u8 first_contact_confidence;
+
+       __u8 mt_footer[4];
+       __u8 mt_foot_count;
 };
 
 /*
@@ -42,8 +47,11 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                struct hid_field *field, struct hid_usage *usage,
                unsigned long **bit, int *max)
 {
-       switch (usage->hid & HID_USAGE_PAGE) {
+       /* No special mappings needed for the pen and single touch */
+       if (field->physical)
+               return 0;
 
+       switch (usage->hid & HID_USAGE_PAGE) {
        case HID_UP_GENDESK:
                switch (usage->hid) {
                case HID_GD_X:
@@ -66,18 +74,12 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
        case HID_UP_DIGITIZER:
                switch (usage->hid) {
                /* we do not want to map these for now */
-               case HID_DG_CONTACTID: /* value is useless */
+               case HID_DG_CONTACTID: /* Not trustworthy, squelch for now */
                case HID_DG_INPUTMODE:
                case HID_DG_DEVICEINDEX:
-               case HID_DG_CONTACTCOUNT:
                case HID_DG_CONTACTMAX:
                        return -1;
 
-               /* original mapping by Rafi Rubin */
-               case HID_DG_CONFIDENCE:
-                       nt_map_key_clear(BTN_TOOL_DOUBLETAP);
-                       return 1;
-
                /* width/height mapped on TouchMajor/TouchMinor/Orientation */
                case HID_DG_WIDTH:
                        hid_map_usage(hi, usage, bit, max,
@@ -104,6 +106,10 @@ static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi,
                struct hid_field *field, struct hid_usage *usage,
                unsigned long **bit, int *max)
 {
+       /* No special mappings needed for the pen and single touch */
+       if (field->physical)
+               return 0;
+
        if (usage->type == EV_KEY || usage->type == EV_REL
                        || usage->type == EV_ABS)
                clear_bit(usage->code, *bit);
@@ -123,31 +129,30 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
        struct input_dev *input = field->hidinput->input;
        struct ntrig_data *nd = hid_get_drvdata(hid);
 
+       /* No special handling needed for the pen */
+       if (field->application == HID_DG_PEN)
+               return 0;
+
         if (hid->claimed & HID_CLAIMED_INPUT) {
                switch (usage->hid) {
-
-               case HID_DG_INRANGE:
-                       if (field->application & 0x3)
-                               nd->pen_active = (value != 0);
-                       else
-                               nd->finger_active = (value != 0);
-                       return 0;
-
-               case HID_DG_INVERT:
-                       nd->inverted = value;
-                       return 0;
-
+               case 0xff000001:
+                       /* Tag indicating the start of a multitouch group */
+                       nd->reading_mt = 1;
+                       nd->first_contact_confidence = 0;
+                       break;
+               case HID_DG_CONFIDENCE:
+                       nd->confidence = value;
+                       break;
                case HID_GD_X:
                        nd->x = value;
-                       nd->reading_a_point = 1;
+                       /* Clear the contact footer */
+                       nd->mt_foot_count = 0;
                        break;
                case HID_GD_Y:
                        nd->y = value;
                        break;
                case HID_DG_CONTACTID:
                        nd->id = value;
-                       /* we receive this only when in multitouch mode */
-                       nd->found_contact_id = 1;
                        break;
                case HID_DG_WIDTH:
                        nd->w = value;
@@ -159,35 +164,13 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
                         * report received in a finger event. We want
                         * to emit a normal (X, Y) position
                         */
-                       if (!nd->found_contact_id) {
-                               if (nd->pen_active && nd->finger_active) {
-                                       input_report_key(input, BTN_TOOL_DOUBLETAP, 0);
-                                       input_report_key(input, BTN_TOOL_DOUBLETAP, 1);
-                               }
+                       if (!nd->reading_mt) {
+                               input_report_key(input, BTN_TOOL_DOUBLETAP,
+                                                (nd->confidence != 0));
                                input_event(input, EV_ABS, ABS_X, nd->x);
                                input_event(input, EV_ABS, ABS_Y, nd->y);
                        }
                        break;
-               case HID_DG_TIPPRESSURE:
-                       /*
-                        * when in single touch mode, this is the last
-                        * report received in a pen event. We want
-                        * to emit a normal (X, Y) position
-                        */
-                       if (! nd->found_contact_id) {
-                               if (nd->pen_active && nd->finger_active) {
-                                       input_report_key(input,
-                                                       nd->inverted ? BTN_TOOL_RUBBER : BTN_TOOL_PEN
-                                                       , 0);
-                                       input_report_key(input,
-                                                       nd->inverted ? BTN_TOOL_RUBBER : BTN_TOOL_PEN
-                                                       , 1);
-                               }
-                               input_event(input, EV_ABS, ABS_X, nd->x);
-                               input_event(input, EV_ABS, ABS_Y, nd->y);
-                               input_event(input, EV_ABS, ABS_PRESSURE, value);
-                       }
-                       break;
                case 0xff000002:
                        /*
                         * we receive this when the device is in multitouch
@@ -195,10 +178,34 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
                         * this usage tells if the contact point is real
                         * or a placeholder
                         */
-                       if (!nd->reading_a_point || value != 1)
+
+                       /* Shouldn't get more than 4 footer packets, so skip */
+                       if (nd->mt_foot_count >= 4)
                                break;
+
+                       nd->mt_footer[nd->mt_foot_count++] = value;
+
+                       /* if the footer isn't complete break */
+                       if (nd->mt_foot_count != 4)
+                               break;
+
+                       /* Pen activity signal, trigger end of touch. */
+                       if (nd->mt_footer[2]) {
+                               nd->confidence = 0;
+                               break;
+                       }
+
+                       /* If the contact was invalid */
+                       if (!(nd->confidence && nd->mt_footer[0])
+                                       || nd->w <= 250
+                                       || nd->h <= 190) {
+                               nd->confidence = 0;
+                               break;
+                       }
+
                        /* emit a normal (X, Y) for the first point only */
                        if (nd->id == 0) {
+                               nd->first_contact_confidence = nd->confidence;
                                input_event(input, EV_ABS, ABS_X, nd->x);
                                input_event(input, EV_ABS, ABS_Y, nd->y);
                        }
@@ -220,8 +227,39 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
                                                ABS_MT_TOUCH_MINOR, nd->w);
                        }
                        input_mt_sync(field->hidinput->input);
-                       nd->reading_a_point = 0;
-                       nd->found_contact_id = 0;
+                       break;
+
+               case HID_DG_CONTACTCOUNT: /* End of a multitouch group */
+                       if (!nd->reading_mt)
+                               break;
+
+                       nd->reading_mt = 0;
+
+                       if (nd->first_contact_confidence) {
+                               switch (value) {
+                               case 0: /* for single touch devices */
+                               case 1:
+                                       input_report_key(input,
+                                                       BTN_TOOL_DOUBLETAP, 1);
+                                       break;
+                               case 2:
+                                       input_report_key(input,
+                                                       BTN_TOOL_TRIPLETAP, 1);
+                                       break;
+                               case 3:
+                               default:
+                                       input_report_key(input,
+                                                       BTN_TOOL_QUADTAP, 1);
+                               }
+                               input_report_key(input, BTN_TOUCH, 1);
+                       } else {
+                               input_report_key(input,
+                                               BTN_TOOL_DOUBLETAP, 0);
+                               input_report_key(input,
+                                               BTN_TOOL_TRIPLETAP, 0);
+                               input_report_key(input,
+                                               BTN_TOOL_QUADTAP, 0);
+                       }
                        break;
 
                default:
@@ -231,8 +269,8 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field,
        }
 
        /* we have handled the hidinput part, now remains hiddev */
-        if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
-                hid->hiddev_hid_event(hid, field, usage, value);
+       if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_hid_event)
+               hid->hiddev_hid_event(hid, field, usage, value);
 
        return 1;
 }
@@ -241,23 +279,67 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
        int ret;
        struct ntrig_data *nd;
+       struct hid_input *hidinput;
+       struct input_dev *input;
+
+       if (id->driver_data)
+               hdev->quirks |= HID_QUIRK_MULTI_INPUT;
 
        nd = kmalloc(sizeof(struct ntrig_data), GFP_KERNEL);
        if (!nd) {
                dev_err(&hdev->dev, "cannot allocate N-Trig data\n");
                return -ENOMEM;
        }
-       nd->reading_a_point = 0;
-       nd->found_contact_id = 0;
+
+       nd->reading_mt = 0;
        hid_set_drvdata(hdev, nd);
 
        ret = hid_parse(hdev);
-       if (!ret)
-               ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+       if (ret) {
+               dev_err(&hdev->dev, "parse failed\n");
+               goto err_free;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+       if (ret) {
+               dev_err(&hdev->dev, "hw start failed\n");
+               goto err_free;
+       }
 
-       if (ret)
-               kfree (nd);
 
+       list_for_each_entry(hidinput, &hdev->inputs, list) {
+               input = hidinput->input;
+               switch (hidinput->report->field[0]->application) {
+               case HID_DG_PEN:
+                       input->name = "N-Trig Pen";
+                       break;
+               case HID_DG_TOUCHSCREEN:
+                       __clear_bit(BTN_TOOL_PEN, input->keybit);
+                       /*
+                        * A little something special to enable
+                        * two and three finger taps.
+                        */
+                       __set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
+                       __set_bit(BTN_TOOL_TRIPLETAP, input->keybit);
+                       __set_bit(BTN_TOOL_QUADTAP, input->keybit);
+                       /*
+                        * The physical touchscreen (single touch)
+                        * input has a value for physical, whereas
+                        * the multitouch only has logical input
+                        * fields.
+                        */
+                       input->name =
+                               (hidinput->report->field[0]
+                                ->physical) ?
+                               "N-Trig Touchscreen" :
+                               "N-Trig MultiTouch";
+                       break;
+               }
+       }
+
+       return 0;
+err_free:
+       kfree(nd);
        return ret;
 }
 
@@ -276,7 +358,7 @@ MODULE_DEVICE_TABLE(hid, ntrig_devices);
 
 static const struct hid_usage_id ntrig_grabbed_usages[] = {
        { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
-       { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
+       { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1 }
 };
 
 static struct hid_driver ntrig_driver = {
diff --git a/drivers/hid/hid-ortek.c b/drivers/hid/hid-ortek.c
new file mode 100644 (file)
index 0000000..aa9a960
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *  HID driver for Ortek WKB-2000 (wireless keyboard + mouse trackpad).
+ *  Fixes LogicalMaximum error in USB report description, see
+ *  http://bugzilla.kernel.org/show_bug.cgi?id=14787
+ *
+ *  Copyright (c) 2010 Johnathon Harris <jmharris@gmail.com>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static void ortek_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+               unsigned int rsize)
+{
+       if (rsize >= 56 && rdesc[54] == 0x25 && rdesc[55] == 0x01) {
+               dev_info(&hdev->dev, "Fixing up Ortek WKB-2000 "
+                               "report descriptor.\n");
+               rdesc[55] = 0x92;
+       }
+}
+
+static const struct hid_device_id ortek_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, ortek_devices);
+
+static struct hid_driver ortek_driver = {
+       .name = "ortek",
+       .id_table = ortek_devices,
+       .report_fixup = ortek_report_fixup
+};
+
+static int __init ortek_init(void)
+{
+       return hid_register_driver(&ortek_driver);
+}
+
+static void __exit ortek_exit(void)
+{
+       hid_unregister_driver(&ortek_driver);
+}
+
+module_init(ortek_init);
+module_exit(ortek_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-quanta.c b/drivers/hid/hid-quanta.c
new file mode 100644 (file)
index 0000000..01dd51c
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ *  HID driver for Quanta Optical Touch dual-touch panels
+ *
+ *  Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
+MODULE_DESCRIPTION("Quanta dual-touch panel");
+MODULE_LICENSE("GPL");
+
+#include "hid-ids.h"
+
+struct quanta_data {
+       __u16 x, y;
+       __u8 id;
+       bool valid;             /* valid finger data, or just placeholder? */
+       bool first;             /* is this the first finger in this frame? */
+       bool activity_now;      /* at least one active finger in this frame? */
+       bool activity;          /* at least one active finger previously? */
+};
+
+static int quanta_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       switch (usage->hid & HID_USAGE_PAGE) {
+
+       case HID_UP_GENDESK:
+               switch (usage->hid) {
+               case HID_GD_X:
+                       hid_map_usage(hi, usage, bit, max,
+                                       EV_ABS, ABS_MT_POSITION_X);
+                       /* touchscreen emulation */
+                       input_set_abs_params(hi->input, ABS_X,
+                                               field->logical_minimum,
+                                               field->logical_maximum, 0, 0);
+                       return 1;
+               case HID_GD_Y:
+                       hid_map_usage(hi, usage, bit, max,
+                                       EV_ABS, ABS_MT_POSITION_Y);
+                       /* touchscreen emulation */
+                       input_set_abs_params(hi->input, ABS_Y,
+                                               field->logical_minimum,
+                                               field->logical_maximum, 0, 0);
+                       return 1;
+               }
+               return 0;
+
+       case HID_UP_DIGITIZER:
+               switch (usage->hid) {
+               case HID_DG_CONFIDENCE:
+               case HID_DG_TIPSWITCH:
+               case HID_DG_INPUTMODE:
+               case HID_DG_DEVICEINDEX:
+               case HID_DG_CONTACTCOUNT:
+               case HID_DG_CONTACTMAX:
+               case HID_DG_TIPPRESSURE:
+               case HID_DG_WIDTH:
+               case HID_DG_HEIGHT:
+                       return -1;
+               case HID_DG_INRANGE:
+                       /* touchscreen emulation */
+                       hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
+                       return 1;
+               case HID_DG_CONTACTID:
+                       hid_map_usage(hi, usage, bit, max,
+                                       EV_ABS, ABS_MT_TRACKING_ID);
+                       return 1;
+               }
+               return 0;
+
+       case 0xff000000:
+               /* ignore vendor-specific features */
+               return -1;
+       }
+
+       return 0;
+}
+
+static int quanta_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       if (usage->type == EV_KEY || usage->type == EV_ABS)
+               clear_bit(usage->code, *bit);
+
+       return 0;
+}
+
+/*
+ * this function is called when a whole finger has been parsed,
+ * so that it can decide what to send to the input layer.
+ */
+static void quanta_filter_event(struct quanta_data *td, struct input_dev *input)
+{
+       
+       td->first = !td->first; /* touchscreen emulation */
+
+       if (!td->valid) {
+               /*
+                * touchscreen emulation: if no finger in this frame is valid
+                * and there previously was finger activity, this is a release
+                */ 
+               if (!td->first && !td->activity_now && td->activity) {
+                       input_event(input, EV_KEY, BTN_TOUCH, 0);
+                       td->activity = false;
+               }
+               return;
+       }
+
+       input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
+       input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
+       input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
+
+       input_mt_sync(input);
+       td->valid = false;
+
+       /* touchscreen emulation: if first active finger in this frame... */
+       if (!td->activity_now) {
+               /* if there was no previous activity, emit touch event */
+               if (!td->activity) {
+                       input_event(input, EV_KEY, BTN_TOUCH, 1);
+                       td->activity = true;
+               }
+               td->activity_now = true;
+               /* and in any case this is our preferred finger */
+               input_event(input, EV_ABS, ABS_X, td->x);
+               input_event(input, EV_ABS, ABS_Y, td->y);
+       }
+}
+
+
+static int quanta_event(struct hid_device *hid, struct hid_field *field,
+                               struct hid_usage *usage, __s32 value)
+{
+       struct quanta_data *td = hid_get_drvdata(hid);
+
+       if (hid->claimed & HID_CLAIMED_INPUT) {
+               struct input_dev *input = field->hidinput->input;
+
+               switch (usage->hid) {
+               case HID_DG_INRANGE:
+                       td->valid = !!value;
+                       break;
+               case HID_GD_X:
+                       td->x = value;
+                       break;
+               case HID_GD_Y:
+                       td->y = value;
+                       quanta_filter_event(td, input);
+                       break;
+               case HID_DG_CONTACTID:
+                       td->id = value;
+                       break;
+               case HID_DG_CONTACTCOUNT:
+                       /* touch emulation: this is the last field in a frame */
+                       td->first = false;
+                       td->activity_now = false;
+                       break;
+               case HID_DG_CONFIDENCE:
+               case HID_DG_TIPSWITCH:
+                       /* avoid interference from generic hidinput handling */
+                       break;
+
+               default:
+                       /* fallback to the generic hidinput handling */
+                       return 0;
+               }
+       }
+
+       /* we have handled the hidinput part, now remains hiddev */
+       if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
+               hid->hiddev_hid_event(hid, field, usage, value);
+
+       return 1;
+}
+
+static int quanta_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       int ret;
+       struct quanta_data *td;
+
+       td = kmalloc(sizeof(struct quanta_data), GFP_KERNEL);
+       if (!td) {
+               dev_err(&hdev->dev, "cannot allocate Quanta Touch data\n");
+               return -ENOMEM;
+       }
+       td->valid = false;
+       td->activity = false;
+       td->activity_now = false;
+       td->first = false;
+       hid_set_drvdata(hdev, td);
+
+       ret = hid_parse(hdev);
+       if (!ret)
+               ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+
+       if (ret)
+               kfree(td);
+
+       return ret;
+}
+
+static void quanta_remove(struct hid_device *hdev)
+{
+       hid_hw_stop(hdev);
+       kfree(hid_get_drvdata(hdev));
+       hid_set_drvdata(hdev, NULL);
+}
+
+static const struct hid_device_id quanta_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
+                       USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
+                       USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, quanta_devices);
+
+static const struct hid_usage_id quanta_grabbed_usages[] = {
+       { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
+       { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
+};
+
+static struct hid_driver quanta_driver = {
+       .name = "quanta-touch",
+       .id_table = quanta_devices,
+       .probe = quanta_probe,
+       .remove = quanta_remove,
+       .input_mapping = quanta_input_mapping,
+       .input_mapped = quanta_input_mapped,
+       .usage_table = quanta_grabbed_usages,
+       .event = quanta_event,
+};
+
+static int __init quanta_init(void)
+{
+       return hid_register_driver(&quanta_driver);
+}
+
+static void __exit quanta_exit(void)
+{
+       hid_unregister_driver(&quanta_driver);
+}
+
+module_init(quanta_init);
+module_exit(quanta_exit);
+
index 4e84502..9bf00d7 100644 (file)
@@ -48,7 +48,7 @@ static void sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
  * to "operational".  Without this, the ps3 controller will not report any
  * events.
  */
-static int sony_set_operational(struct hid_device *hdev)
+static int sony_set_operational_usb(struct hid_device *hdev)
 {
        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
        struct usb_device *dev = interface_to_usbdev(intf);
@@ -73,6 +73,12 @@ static int sony_set_operational(struct hid_device *hdev)
        return ret;
 }
 
+static int sony_set_operational_bt(struct hid_device *hdev)
+{
+       unsigned char buf[] = { 0x53, 0xf4,  0x42, 0x03, 0x00, 0x00 };
+       return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
+}
+
 static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
        int ret;
@@ -81,7 +87,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        sc = kzalloc(sizeof(*sc), GFP_KERNEL);
        if (sc == NULL) {
-               dev_err(&hdev->dev, "can't alloc apple descriptor\n");
+               dev_err(&hdev->dev, "can't alloc sony descriptor\n");
                return -ENOMEM;
        }
 
@@ -101,7 +107,17 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
                goto err_free;
        }
 
-       ret = sony_set_operational(hdev);
+       switch (hdev->bus) {
+       case BUS_USB:
+               ret = sony_set_operational_usb(hdev);
+               break;
+       case BUS_BLUETOOTH:
+               ret = sony_set_operational_bt(hdev);
+               break;
+       default:
+               ret = 0;
+       }
+
        if (ret < 0)
                goto err_stop;
 
@@ -121,6 +137,7 @@ static void sony_remove(struct hid_device *hdev)
 
 static const struct hid_device_id sony_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE),
                .driver_data = VAIO_RDESC_CONSTANT },
        { }
diff --git a/drivers/hid/hid-stantum.c b/drivers/hid/hid-stantum.c
new file mode 100644 (file)
index 0000000..2e592a0
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ *  HID driver for Stantum multitouch panels
+ *
+ *  Copyright (c) 2009 Stephane Chatty <chatty@enac.fr>
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
+MODULE_DESCRIPTION("Stantum HID multitouch panels");
+MODULE_LICENSE("GPL");
+
+#include "hid-ids.h"
+
+struct stantum_data {
+       __s32 x, y, z, w, h;    /* x, y, pressure, width, height */
+       __u16 id;               /* touch id */
+       bool valid;             /* valid finger data, or just placeholder? */
+       bool first;             /* first finger in the HID packet? */
+       bool activity;          /* at least one active finger so far? */
+};
+
+static int stantum_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       switch (usage->hid & HID_USAGE_PAGE) {
+
+       case HID_UP_GENDESK:
+               switch (usage->hid) {
+               case HID_GD_X:
+                       hid_map_usage(hi, usage, bit, max,
+                                       EV_ABS, ABS_MT_POSITION_X);
+                       /* touchscreen emulation */
+                       input_set_abs_params(hi->input, ABS_X,
+                                               field->logical_minimum,
+                                               field->logical_maximum, 0, 0);
+                       return 1;
+               case HID_GD_Y:
+                       hid_map_usage(hi, usage, bit, max,
+                                       EV_ABS, ABS_MT_POSITION_Y);
+                       /* touchscreen emulation */
+                       input_set_abs_params(hi->input, ABS_Y,
+                                               field->logical_minimum,
+                                               field->logical_maximum, 0, 0);
+                       return 1;
+               }
+               return 0;
+
+       case HID_UP_DIGITIZER:
+               switch (usage->hid) {
+               case HID_DG_INRANGE:
+               case HID_DG_CONFIDENCE:
+               case HID_DG_INPUTMODE:
+               case HID_DG_DEVICEINDEX:
+               case HID_DG_CONTACTCOUNT:
+               case HID_DG_CONTACTMAX:
+                       return -1;
+
+               case HID_DG_TIPSWITCH:
+                       /* touchscreen emulation */
+                       hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
+                       return 1;
+
+               case HID_DG_WIDTH:
+                       hid_map_usage(hi, usage, bit, max,
+                                       EV_ABS, ABS_MT_TOUCH_MAJOR);
+                       return 1;
+               case HID_DG_HEIGHT:
+                       hid_map_usage(hi, usage, bit, max,
+                                       EV_ABS, ABS_MT_TOUCH_MINOR);
+                       input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
+                                       1, 1, 0, 0);
+                       return 1;
+               case HID_DG_TIPPRESSURE:
+                       hid_map_usage(hi, usage, bit, max,
+                                       EV_ABS, ABS_MT_PRESSURE);
+                       return 1;
+
+               case HID_DG_CONTACTID:
+                       hid_map_usage(hi, usage, bit, max,
+                                       EV_ABS, ABS_MT_TRACKING_ID);
+                       return 1;
+
+               }
+               return 0;
+
+       case 0xff000000:
+               /* no input-oriented meaning */
+               return -1;
+       }
+
+       return 0;
+}
+
+static int stantum_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+               struct hid_field *field, struct hid_usage *usage,
+               unsigned long **bit, int *max)
+{
+       if (usage->type == EV_KEY || usage->type == EV_ABS)
+               clear_bit(usage->code, *bit);
+
+       return 0;
+}
+
+/*
+ * this function is called when a whole finger has been parsed,
+ * so that it can decide what to send to the input layer.
+ */
+static void stantum_filter_event(struct stantum_data *sd,
+                                       struct input_dev *input)
+{
+       bool wide;
+
+       if (!sd->valid) {
+               /*
+                * touchscreen emulation: if the first finger is not valid and
+                * there previously was finger activity, this is a release
+                */
+               if (sd->first && sd->activity) {
+                       input_event(input, EV_KEY, BTN_TOUCH, 0);
+                       sd->activity = false;
+               }
+               return;
+       }
+
+       input_event(input, EV_ABS, ABS_MT_TRACKING_ID, sd->id);
+       input_event(input, EV_ABS, ABS_MT_POSITION_X, sd->x);
+       input_event(input, EV_ABS, ABS_MT_POSITION_Y, sd->y);
+
+       wide = (sd->w > sd->h);
+       input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
+       input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, wide ? sd->w : sd->h);
+       input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, wide ? sd->h : sd->w);
+
+       input_event(input, EV_ABS, ABS_MT_PRESSURE, sd->z);
+
+       input_mt_sync(input);
+       sd->valid = false;
+
+       /* touchscreen emulation */
+       if (sd->first) {
+               if (!sd->activity) {
+                       input_event(input, EV_KEY, BTN_TOUCH, 1);
+                       sd->activity = true;
+               }
+               input_event(input, EV_ABS, ABS_X, sd->x);
+               input_event(input, EV_ABS, ABS_Y, sd->y);
+       }
+       sd->first = false;
+}
+
+
+static int stantum_event(struct hid_device *hid, struct hid_field *field,
+                               struct hid_usage *usage, __s32 value)
+{
+       struct stantum_data *sd = hid_get_drvdata(hid);
+
+       if (hid->claimed & HID_CLAIMED_INPUT) {
+               struct input_dev *input = field->hidinput->input;
+
+               switch (usage->hid) {
+               case HID_DG_INRANGE:
+                       /* this is the last field in a finger */
+                       stantum_filter_event(sd, input);
+                       break;
+               case HID_DG_WIDTH:
+                       sd->w = value;
+                       break;
+               case HID_DG_HEIGHT:
+                       sd->h = value;
+                       break;
+               case HID_GD_X:
+                       sd->x = value;
+                       break;
+               case HID_GD_Y:
+                       sd->y = value;
+                       break;
+               case HID_DG_TIPPRESSURE:
+                       sd->z = value;
+                       break;
+               case HID_DG_CONTACTID:
+                       sd->id = value;
+                       break;
+               case HID_DG_CONFIDENCE:
+                       sd->valid = !!value;
+                       break;
+               case 0xff000002:
+                       /* this comes only before the first finger */
+                       sd->first = true;
+                       break;
+
+               default:
+                       /* ignore the others */
+                       return 1;
+               }
+       }
+
+       /* we have handled the hidinput part, now remains hiddev */
+       if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
+               hid->hiddev_hid_event(hid, field, usage, value);
+
+       return 1;
+}
+
+static int stantum_probe(struct hid_device *hdev,
+                               const struct hid_device_id *id)
+{
+       int ret;
+       struct stantum_data *sd;
+
+       sd = kmalloc(sizeof(struct stantum_data), GFP_KERNEL);
+       if (!sd) {
+               dev_err(&hdev->dev, "cannot allocate Stantum data\n");
+               return -ENOMEM;
+       }
+       sd->valid = false;
+       sd->first = false;
+       sd->activity = false;
+       hid_set_drvdata(hdev, sd);
+
+       ret = hid_parse(hdev);
+       if (!ret)
+               ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+
+       if (ret)
+               kfree(sd);
+
+       return ret;
+}
+
+static void stantum_remove(struct hid_device *hdev)
+{
+       hid_hw_stop(hdev);
+       kfree(hid_get_drvdata(hdev));
+       hid_set_drvdata(hdev, NULL);
+}
+
+static const struct hid_device_id stantum_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, stantum_devices);
+
+static const struct hid_usage_id stantum_grabbed_usages[] = {
+       { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
+       { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
+};
+
+static struct hid_driver stantum_driver = {
+       .name = "stantum",
+       .id_table = stantum_devices,
+       .probe = stantum_probe,
+       .remove = stantum_remove,
+       .input_mapping = stantum_input_mapping,
+       .input_mapped = stantum_input_mapped,
+       .usage_table = stantum_grabbed_usages,
+       .event = stantum_event,
+};
+
+static int __init stantum_init(void)
+{
+       return hid_register_driver(&stantum_driver);
+}
+
+static void __exit stantum_exit(void)
+{
+       hid_unregister_driver(&stantum_driver);
+}
+
+module_init(stantum_init);
+module_exit(stantum_exit);
+
index 12dcda5..8d3b46f 100644 (file)
@@ -156,7 +156,9 @@ static int wacom_probe(struct hid_device *hdev,
        struct hid_input *hidinput;
        struct input_dev *input;
        struct wacom_data *wdata;
+       char rep_data[2];
        int ret;
+       int limit;
 
        wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
        if (wdata == NULL) {
@@ -166,6 +168,7 @@ static int wacom_probe(struct hid_device *hdev,
 
        hid_set_drvdata(hdev, wdata);
 
+       /* Parse the HID report now */
        ret = hid_parse(hdev);
        if (ret) {
                dev_err(&hdev->dev, "parse failed\n");
@@ -178,6 +181,31 @@ static int wacom_probe(struct hid_device *hdev,
                goto err_free;
        }
 
+       /*
+        * Note that if the raw queries fail, it's not a hard failure and it
+        * is safe to continue
+        */
+
+       /* Set Wacom mode2 */
+       rep_data[0] = 0x03; rep_data[1] = 0x00;
+       limit = 3;
+       do {
+               ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
+                               HID_FEATURE_REPORT);
+       } while (ret < 0 && limit-- > 0);
+       if (ret < 0)
+               dev_warn(&hdev->dev, "failed to poke device #1, %d\n", ret);
+
+       /* 0x06 - high reporting speed, 0x05 - low speed */
+       rep_data[0] = 0x06; rep_data[1] = 0x00;
+       limit = 3;
+       do {
+               ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
+                               HID_FEATURE_REPORT);
+       } while (ret < 0 && limit-- > 0);
+       if (ret < 0)
+               dev_warn(&hdev->dev, "failed to poke device #2, %d\n", ret);
+
        hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
        input = hidinput->input;
 
index cdd1369..d044767 100644 (file)
@@ -134,7 +134,7 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t
                goto out;
        }
 
-       ret = dev->hid_output_raw_report(dev, buf, count);
+       ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT);
 out:
        kfree(buf);
        return ret;
index e2997a8..56d06cd 100644 (file)
@@ -5,7 +5,7 @@
  *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
  *  Copyright (c) 2007-2008 Oliver Neukum
- *  Copyright (c) 2006-2009 Jiri Kosina
+ *  Copyright (c) 2006-2010 Jiri Kosina
  */
 
 /*
@@ -316,6 +316,7 @@ static int hid_submit_out(struct hid_device *hid)
                        err_hid("usb_submit_urb(out) failed");
                        return -1;
                }
+               usbhid->last_out = jiffies;
        } else {
                /*
                 * queue work to wake up the device.
@@ -377,6 +378,7 @@ static int hid_submit_ctrl(struct hid_device *hid)
                        err_hid("usb_submit_urb(ctrl) failed");
                        return -1;
                }
+               usbhid->last_ctrl = jiffies;
        } else {
                /*
                 * queue work to wake up the device.
@@ -512,9 +514,20 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
                usbhid->out[usbhid->outhead].report = report;
                usbhid->outhead = head;
 
-               if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl))
+               if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) {
                        if (hid_submit_out(hid))
                                clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
+               } else {
+                       /*
+                        * the queue is known to run
+                        * but an earlier request may be stuck
+                        * we may need to time out
+                        * no race because this is called under
+                        * spinlock
+                        */
+                       if (time_after(jiffies, usbhid->last_out + HZ * 5))
+                               usb_unlink_urb(usbhid->urbout);
+               }
                return;
        }
 
@@ -535,9 +548,20 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
        usbhid->ctrl[usbhid->ctrlhead].dir = dir;
        usbhid->ctrlhead = head;
 
-       if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl))
+       if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl)) {
                if (hid_submit_ctrl(hid))
                        clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+       } else {
+               /*
+                * the queue is known to run
+                * but an earlier request may be stuck
+                * we may need to time out
+                * no race because this is called under
+                * spinlock
+                */
+               if (time_after(jiffies, usbhid->last_ctrl + HZ * 5))
+                       usb_unlink_urb(usbhid->urbctrl);
+       }
 }
 
 void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
@@ -774,7 +798,8 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
        return 0;
 }
 
-static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count)
+static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count,
+               unsigned char report_type)
 {
        struct usbhid_device *usbhid = hid->driver_data;
        struct usb_device *dev = hid_to_usb_dev(hid);
@@ -785,7 +810,7 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co
        ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
                HID_REQ_SET_REPORT,
                USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-               ((HID_OUTPUT_REPORT + 1) << 8) | *buf,
+               ((report_type + 1) << 8) | *buf,
                interface->desc.bInterfaceNumber, buf + 1, count - 1,
                USB_CTRL_SET_TIMEOUT);
 
@@ -981,9 +1006,6 @@ static int usbhid_start(struct hid_device *hid)
 
        spin_lock_init(&usbhid->lock);
 
-       usbhid->intf = intf;
-       usbhid->ifnum = interface->desc.bInterfaceNumber;
-
        usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL);
        if (!usbhid->urbctrl) {
                ret = -ENOMEM;
@@ -1154,6 +1176,8 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
 
        hid->driver_data = usbhid;
        usbhid->hid = hid;
+       usbhid->intf = intf;
+       usbhid->ifnum = interface->desc.bInterfaceNumber;
 
        ret = hid_add_device(hid);
        if (ret) {
@@ -1342,7 +1366,7 @@ static int hid_reset_resume(struct usb_interface *intf)
 
 #endif /* CONFIG_PM */
 
-static struct usb_device_id hid_usb_ids [] = {
+static const struct usb_device_id hid_usb_ids[] = {
        { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
                .bInterfaceClass = USB_INTERFACE_CLASS_HID },
        { }                                             /* Terminating entry */
index 38773dc..7844280 100644 (file)
@@ -43,8 +43,10 @@ static const struct hid_blacklist {
 
        { USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL },
 
+       { USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
        { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT },
+       { USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS, HID_QUIRK_MULTI_INPUT },
 
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
@@ -57,6 +59,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT },
index 08f505c..ec20400 100644 (file)
@@ -80,12 +80,14 @@ struct usbhid_device {
        unsigned char ctrlhead, ctrltail;                               /* Control fifo head & tail */
        char *ctrlbuf;                                                  /* Control buffer */
        dma_addr_t ctrlbuf_dma;                                         /* Control buffer dma */
+       unsigned long last_ctrl;                                                /* record of last output for timeouts */
 
        struct urb *urbout;                                             /* Output URB */
        struct hid_output_fifo out[HID_CONTROL_FIFO_SIZE];              /* Output pipe fifo */
        unsigned char outhead, outtail;                                 /* Output pipe fifo head & tail */
        char *outbuf;                                                   /* Output buffer */
        dma_addr_t outbuf_dma;                                          /* Output buffer dma */
+       unsigned long last_out;                                                 /* record of last output for timeouts */
 
        spinlock_t lock;                                                /* fifo spinlock */
        unsigned long iofl;                                             /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
index aa6713b..291d939 100644 (file)
@@ -100,6 +100,12 @@ static void input_close_polled_device(struct input_dev *input)
        struct input_polled_dev *dev = input_get_drvdata(input);
 
        cancel_delayed_work_sync(&dev->work);
+       /*
+        * Clean up work struct to remove references to the workqueue.
+        * It may be destroyed by the next call. This causes problems
+        * at next device open-close in case of poll_interval == 0.
+        */
+       INIT_DELAYED_WORK(&dev->work, dev->work.work.func);
        input_polldev_stop_workqueue();
 
        if (dev->close)
index d84a36e..b54aee7 100644 (file)
@@ -1161,9 +1161,17 @@ static int i8042_pm_restore(struct device *dev)
        return 0;
 }
 
+static int i8042_pm_thaw(struct device *dev)
+{
+       i8042_interrupt(0, NULL);
+
+       return 0;
+}
+
 static const struct dev_pm_ops i8042_pm_ops = {
        .suspend        = i8042_pm_reset,
        .resume         = i8042_pm_restore,
+       .thaw           = i8042_pm_thaw,
        .poweroff       = i8042_pm_reset,
        .restore        = i8042_pm_restore,
 };
index 09a5e73..5256123 100644 (file)
@@ -618,8 +618,8 @@ static int idealtek_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 #ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
 static int general_touch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 {
-       dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1] ;
-       dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3] ;
+       dev->x = (pkt[2] << 8) | pkt[1];
+       dev->y = (pkt[4] << 8) | pkt[3];
        dev->press = pkt[5] & 0xff;
        dev->touch = pkt[0] & 0x01;
 
@@ -809,9 +809,9 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
 #ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
        [DEVTYPE_GENERAL_TOUCH] = {
                .min_xc         = 0x0,
-               .max_xc         = 0x0500,
+               .max_xc         = 0x7fff,
                .min_yc         = 0x0,
-               .max_yc         = 0x0500,
+               .max_yc         = 0x7fff,
                .rept_size      = 7,
                .read_data      = general_touch_read_data,
        },
index 23741ce..d840a10 100644 (file)
@@ -322,8 +322,8 @@ static int __init adb_init(void)
                adb_controller = NULL;
        } else {
 #ifdef CONFIG_PPC
-               if (machine_is_compatible("AAPL,PowerBook1998") ||
-                       machine_is_compatible("PowerBook1,1"))
+               if (of_machine_is_compatible("AAPL,PowerBook1998") ||
+                       of_machine_is_compatible("PowerBook1,1"))
                        sleepy_trackpad = 1;
 #endif /* CONFIG_PPC */
 
index 454bc50..5738d8b 100644 (file)
@@ -1899,7 +1899,7 @@ static int create_control_loops(void)
         */
        if (rackmac)
                cpu_pid_type = CPU_PID_TYPE_RACKMAC;
-       else if (machine_is_compatible("PowerMac7,3")
+       else if (of_machine_is_compatible("PowerMac7,3")
            && (cpu_count > 1)
            && fcu_fans[CPUA_PUMP_RPM_INDEX].id != FCU_FAN_ABSENT_ID
            && fcu_fans[CPUB_PUMP_RPM_INDEX].id != FCU_FAN_ABSENT_ID) {
@@ -2234,10 +2234,10 @@ static int __init therm_pm72_init(void)
 {
        struct device_node *np;
 
-       rackmac = machine_is_compatible("RackMac3,1");
+       rackmac = of_machine_is_compatible("RackMac3,1");
 
-       if (!machine_is_compatible("PowerMac7,2") &&
-           !machine_is_compatible("PowerMac7,3") &&
+       if (!of_machine_is_compatible("PowerMac7,2") &&
+           !of_machine_is_compatible("PowerMac7,3") &&
            !rackmac)
                return -ENODEV;
 
index ba48fd7..7fb8b4d 100644 (file)
@@ -490,7 +490,7 @@ g4fan_init( void )
        info = of_get_property(np, "thermal-info", NULL);
        of_node_put(np);
 
-       if( !info || !machine_is_compatible("PowerMac3,6") )
+       if( !info || !of_machine_is_compatible("PowerMac3,6") )
                return -ENODEV;
 
        if( info->id != 3 ) {
index a348bb0..4f3c447 100644 (file)
@@ -150,13 +150,13 @@ void __init pmu_backlight_init()
 
        /* Special case for the old PowerBook since I can't test on it */
        autosave =
-               machine_is_compatible("AAPL,3400/2400") ||
-               machine_is_compatible("AAPL,3500");
+               of_machine_is_compatible("AAPL,3400/2400") ||
+               of_machine_is_compatible("AAPL,3500");
 
        if (!autosave &&
            !pmac_has_backlight_type("pmu") &&
-           !machine_is_compatible("AAPL,PowerBook1998") &&
-           !machine_is_compatible("PowerBook1,1"))
+           !of_machine_is_compatible("AAPL,PowerBook1998") &&
+           !of_machine_is_compatible("PowerBook1,1"))
                return;
 
        snprintf(name, sizeof(name), "pmubl");
index db379c3..4276484 100644 (file)
@@ -463,8 +463,8 @@ static int __init via_pmu_dev_init(void)
 #endif
 
 #ifdef CONFIG_PPC32
-       if (machine_is_compatible("AAPL,3400/2400") ||
-               machine_is_compatible("AAPL,3500")) {
+       if (of_machine_is_compatible("AAPL,3400/2400") ||
+               of_machine_is_compatible("AAPL,3500")) {
                int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
                        NULL, PMAC_MB_INFO_MODEL, 0);
                pmu_battery_count = 1;
@@ -472,8 +472,8 @@ static int __init via_pmu_dev_init(void)
                        pmu_batteries[0].flags |= PMU_BATT_TYPE_COMET;
                else
                        pmu_batteries[0].flags |= PMU_BATT_TYPE_HOOPER;
-       } else if (machine_is_compatible("AAPL,PowerBook1998") ||
-               machine_is_compatible("PowerBook1,1")) {
+       } else if (of_machine_is_compatible("AAPL,PowerBook1998") ||
+               of_machine_is_compatible("PowerBook1,1")) {
                pmu_battery_count = 2;
                pmu_batteries[0].flags |= PMU_BATT_TYPE_SMART;
                pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART;
index 075b4d9..437f55c 100644 (file)
@@ -468,9 +468,9 @@ static int __init windfarm_core_init(void)
        DBG("wf: core loaded\n");
 
        /* Don't register on old machines that use therm_pm72 for now */
-       if (machine_is_compatible("PowerMac7,2") ||
-           machine_is_compatible("PowerMac7,3") ||
-           machine_is_compatible("RackMac3,1"))
+       if (of_machine_is_compatible("PowerMac7,2") ||
+           of_machine_is_compatible("PowerMac7,3") ||
+           of_machine_is_compatible("RackMac3,1"))
                return -ENODEV;
        platform_device_register(&wf_platform_device);
        return 0;
index 900aade..1a77a7c 100644 (file)
@@ -76,9 +76,9 @@ static int __init wf_cpufreq_clamp_init(void)
        struct wf_control *clamp;
 
        /* Don't register on old machines that use therm_pm72 for now */
-       if (machine_is_compatible("PowerMac7,2") ||
-           machine_is_compatible("PowerMac7,3") ||
-           machine_is_compatible("RackMac3,1"))
+       if (of_machine_is_compatible("PowerMac7,2") ||
+           of_machine_is_compatible("PowerMac7,3") ||
+           of_machine_is_compatible("RackMac3,1"))
                return -ENODEV;
 
        clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL);
index ed6426a..d8257d3 100644 (file)
@@ -239,9 +239,9 @@ static struct i2c_driver wf_lm75_driver = {
 static int __init wf_lm75_sensor_init(void)
 {
        /* Don't register on old machines that use therm_pm72 for now */
-       if (machine_is_compatible("PowerMac7,2") ||
-           machine_is_compatible("PowerMac7,3") ||
-           machine_is_compatible("RackMac3,1"))
+       if (of_machine_is_compatible("PowerMac7,2") ||
+           of_machine_is_compatible("PowerMac7,3") ||
+           of_machine_is_compatible("RackMac3,1"))
                return -ENODEV;
        return i2c_add_driver(&wf_lm75_driver);
 }
index a67b349..b486eb9 100644 (file)
@@ -188,9 +188,9 @@ static struct i2c_driver wf_max6690_driver = {
 static int __init wf_max6690_sensor_init(void)
 {
        /* Don't register on old machines that use therm_pm72 for now */
-       if (machine_is_compatible("PowerMac7,2") ||
-           machine_is_compatible("PowerMac7,3") ||
-           machine_is_compatible("RackMac3,1"))
+       if (of_machine_is_compatible("PowerMac7,2") ||
+           of_machine_is_compatible("PowerMac7,3") ||
+           of_machine_is_compatible("RackMac3,1"))
                return -ENODEV;
        return i2c_add_driver(&wf_max6690_driver);
 }
index 73d695d..e0ee807 100644 (file)
@@ -676,7 +676,7 @@ static int __init wf_pm112_init(void)
 {
        struct device_node *cpu;
 
-       if (!machine_is_compatible("PowerMac11,2"))
+       if (!of_machine_is_compatible("PowerMac11,2"))
                return -ENODEV;
 
        /* Count the number of CPU cores */
index 66ec4fb..947d4af 100644 (file)
@@ -1008,7 +1008,7 @@ static int __init pm121_init(void)
 {
        int rc = -ENODEV;
 
-       if (machine_is_compatible("PowerMac12,1"))
+       if (of_machine_is_compatible("PowerMac12,1"))
                rc = pm121_init_pm();
 
        if (rc == 0) {
index abbe206..565d5b2 100644 (file)
@@ -779,8 +779,8 @@ static int __init wf_smu_init(void)
 {
        int rc = -ENODEV;
 
-       if (machine_is_compatible("PowerMac8,1") ||
-           machine_is_compatible("PowerMac8,2"))
+       if (of_machine_is_compatible("PowerMac8,1") ||
+           of_machine_is_compatible("PowerMac8,2"))
                rc = wf_init_pm();
 
        if (rc == 0) {
index 764c525..bea9916 100644 (file)
@@ -711,7 +711,7 @@ static int __init wf_smu_init(void)
 {
        int rc = -ENODEV;
 
-       if (machine_is_compatible("PowerMac9,1"))
+       if (of_machine_is_compatible("PowerMac9,1"))
                rc = wf_init_pm();
 
        if (rc == 0) {
index 9c567b9..3c19350 100644 (file)
@@ -363,9 +363,9 @@ smu_cpu_power_create(struct wf_sensor *volts, struct wf_sensor *amps)
         * I yet have to figure out what's up with 8,2 and will have to
         * adjust for later, unless we can 100% trust the SDB partition...
         */
-       if ((machine_is_compatible("PowerMac8,1") ||
-            machine_is_compatible("PowerMac8,2") ||
-            machine_is_compatible("PowerMac9,1")) &&
+       if ((of_machine_is_compatible("PowerMac8,1") ||
+            of_machine_is_compatible("PowerMac8,2") ||
+            of_machine_is_compatible("PowerMac9,1")) &&
            cpuvcp_version >= 2) {
                pow->quadratic = 1;
                DBG("windfarm: CPU Power using quadratic transform\n");
index 1b24989..465295b 100644 (file)
@@ -112,11 +112,13 @@ config DVB_USB_CXUSB
        select DVB_MT352 if !DVB_FE_CUSTOMISE
        select DVB_ZL10353 if !DVB_FE_CUSTOMISE
        select DVB_DIB7000P if !DVB_FE_CUSTOMISE
-       select DVB_LGS8GL5 if !DVB_FE_CUSTOMISE
        select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE
+       select DVB_ATBM8830 if !DVB_FE_CUSTOMISE
+       select DVB_LGS8GXX if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_MAX2165 if !MEDIA_TUNER_CUSTOMISE
        help
          Say Y here to support the Conexant USB2.0 hybrid reference design.
          Currently, only DVB and ATSC modes are supported, analog mode
index 3051b64..445fa10 100644 (file)
@@ -192,8 +192,8 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa
        spi_bias *= qam_tab[p->constellation];
        spi_bias /= p->code_rate_HP + 1;
        spi_bias /= (guard_tab[p->guard_interval] + 32);
-       spi_bias *= 1000ULL;
-       spi_bias /= 1000ULL + ppm/1000;
+       spi_bias *= 1000;
+       spi_bias /= 1000 + ppm/1000;
        spi_bias *= p->code_rate_HP;
 
        val0x04 = (p->transmission_mode << 2) | p->guard_interval;
index 3182a40..ae08b07 100644 (file)
@@ -4461,6 +4461,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
                request_modules(btv);
        }
 
+       init_bttv_i2c_ir(btv);
        bttv_input_init(btv);
 
        /* everything is fine */
index 63aa31a..407fa61 100644 (file)
@@ -388,7 +388,12 @@ int __devinit init_bttv_i2c(struct bttv *btv)
        if (0 == btv->i2c_rc && i2c_scan)
                do_i2c_scan(btv->c.v4l2_dev.name, &btv->i2c_client);
 
-       /* Instantiate the IR receiver device, if present */
+       return btv->i2c_rc;
+}
+
+/* Instantiate the I2C IR receiver device, if present */
+void __devinit init_bttv_i2c_ir(struct bttv *btv)
+{
        if (0 == btv->i2c_rc) {
                struct i2c_board_info info;
                /* The external IR receiver is at i2c address 0x34 (0x35 for
@@ -408,7 +413,6 @@ int __devinit init_bttv_i2c(struct bttv *btv)
                strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
                i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list);
        }
-       return btv->i2c_rc;
 }
 
 int __devexit fini_bttv_i2c(struct bttv *btv)
index a1d0e9c..6cccc2a 100644 (file)
@@ -279,6 +279,7 @@ extern unsigned int bttv_debug;
 extern unsigned int bttv_gpio;
 extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
 extern int init_bttv_i2c(struct bttv *btv);
+extern void init_bttv_i2c_ir(struct bttv *btv);
 extern int fini_bttv_i2c(struct bttv *btv);
 
 #define bttv_printk if (bttv_verbose) printk
index fc4dd60..7438f8d 100644 (file)
@@ -514,7 +514,7 @@ static int mt9t112_init_pll(const struct i2c_client *client)
        /* poll to verify out of standby. Must Poll this bit */
        for (i = 0; i < 100; i++) {
                mt9t112_reg_read(data, client, 0x0018);
-               if (0x4000 & data)
+               if (!(0x4000 & data))
                        break;
 
                mdelay(10);
index 50b415e..f7f7e04 100644 (file)
@@ -753,7 +753,7 @@ int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
                buf[0] = 0xff; /* fixed */
 
        ret = send_control_msg(pdev,
-               SET_LUM_CTL, SHUTTER_MODE_FORMATTER, &buf, sizeof(buf));
+               SET_LUM_CTL, SHUTTER_MODE_FORMATTER, &buf, 1);
 
        if (!mode && ret >= 0) {
                if (value < 0)
index fee6eee..006cb2e 100644 (file)
@@ -296,6 +296,7 @@ static void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr,
        req_hdr->opcode = opcode;
        req_hdr->subsystem = subsystem;
        req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr));
+       req_hdr->version = 0;
 }
 
 static void be_cmd_page_addrs_prepare(struct phys_addr *pages, u32 max_pages,
index d29bb53..7655436 100644 (file)
@@ -4006,11 +4006,21 @@ check_page:
                        }
                }
 
-               if (!buffer_info->dma)
+               if (!buffer_info->dma) {
                        buffer_info->dma = pci_map_page(pdev,
                                                        buffer_info->page, 0,
                                                        buffer_info->length,
                                                        PCI_DMA_FROMDEVICE);
+                       if (pci_dma_mapping_error(pdev, buffer_info->dma)) {
+                               put_page(buffer_info->page);
+                               dev_kfree_skb(skb);
+                               buffer_info->page = NULL;
+                               buffer_info->skb = NULL;
+                               buffer_info->dma = 0;
+                               adapter->alloc_rx_buff_failed++;
+                               break; /* while !buffer_info->skb */
+                       }
+               }
 
                rx_desc = E1000_RX_DESC(*rx_ring, i);
                rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
@@ -4101,6 +4111,13 @@ map_skb:
                                                  skb->data,
                                                  buffer_info->length,
                                                  PCI_DMA_FROMDEVICE);
+               if (pci_dma_mapping_error(pdev, buffer_info->dma)) {
+                       dev_kfree_skb(skb);
+                       buffer_info->skb = NULL;
+                       buffer_info->dma = 0;
+                       adapter->alloc_rx_buff_failed++;
+                       break; /* while !buffer_info->skb */
+               }
 
                /*
                 * XXX if it was allocated cleanly it will never map to a
index 3103f41..35a06b4 100644 (file)
@@ -357,12 +357,34 @@ static s32 ixgbe_fc_enable_82598(struct ixgbe_hw *hw, s32 packetbuf_num)
        u32 fctrl_reg;
        u32 rmcs_reg;
        u32 reg;
+       u32 link_speed = 0;
+       bool link_up;
 
 #ifdef CONFIG_DCB
        if (hw->fc.requested_mode == ixgbe_fc_pfc)
                goto out;
 
 #endif /* CONFIG_DCB */
+       /*
+        * On 82598 having Rx FC on causes resets while doing 1G
+        * so if it's on turn it off once we know link_speed. For
+        * more details see 82598 Specification update.
+        */
+       hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
+       if (link_up && link_speed == IXGBE_LINK_SPEED_1GB_FULL) {
+               switch (hw->fc.requested_mode) {
+               case ixgbe_fc_full:
+                       hw->fc.requested_mode = ixgbe_fc_tx_pause;
+                       break;
+               case ixgbe_fc_rx_pause:
+                       hw->fc.requested_mode = ixgbe_fc_none;
+                       break;
+               default:
+                       /* no change */
+                       break;
+               }
+       }
+
        /* Negotiate the fc mode to use */
        ret_val = ixgbe_fc_autoneg(hw);
        if (ret_val)
index 7b7c848..951b73c 100644 (file)
@@ -5763,6 +5763,10 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
        if (err)
                goto err_sw_init;
 
+       /* Make it possible the adapter to be woken up via WOL */
+       if (adapter->hw.mac.type == ixgbe_mac_82599EB)
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_WUS, ~0);
+
        /*
         * If there is a fan on this device and it has failed log the
         * failure.
index d9fbad3..43aea91 100644 (file)
@@ -206,7 +206,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
                mp->port_aaui = port_aaui;
        else {
                /* Apple Network Server uses the AAUI port */
-               if (machine_is_compatible("AAPL,ShinerESB"))
+               if (of_machine_is_compatible("AAPL,ShinerESB"))
                        mp->port_aaui = 1;
                else {
 #ifdef CONFIG_MACE_AAUI_PORT
index 103e8b0..46997e1 100644 (file)
@@ -2284,6 +2284,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
  fail2:
        efx_fini_struct(efx);
  fail1:
+       WARN_ON(rc > 0);
        EFX_LOG(efx, "initialisation failed. rc=%d\n", rc);
        free_netdev(net_dev);
        return rc;
index bf0b96a..5712fdd 100644 (file)
 #define FALCON_BOARD_SFN4111T 0x51
 #define FALCON_BOARD_SFN4112F 0x52
 
+/* Board temperature is about 15°C above ambient when air flow is
+ * limited. */
+#define FALCON_BOARD_TEMP_BIAS 15
+
+/* SFC4000 datasheet says: 'The maximum permitted junction temperature
+ * is 125°C; the thermal design of the environment for the SFC4000
+ * should aim to keep this well below 100°C.' */
+#define FALCON_JUNC_TEMP_MAX   90
+
 /*****************************************************************************
  * Support for LM87 sensor chip used on several boards
  */
@@ -548,16 +557,16 @@ fail_hwmon:
 static u8 sfe4002_lm87_channel = 0x03; /* use AIN not FAN inputs */
 
 static const u8 sfe4002_lm87_regs[] = {
-       LM87_IN_LIMITS(0, 0x83, 0x91),          /* 2.5V:  1.8V +/- 5% */
-       LM87_IN_LIMITS(1, 0x51, 0x5a),          /* Vccp1: 1.2V +/- 5% */
-       LM87_IN_LIMITS(2, 0xb6, 0xca),          /* 3.3V:  3.3V +/- 5% */
-       LM87_IN_LIMITS(3, 0xb0, 0xc9),          /* 5V:    4.6-5.2V */
-       LM87_IN_LIMITS(4, 0xb0, 0xe0),          /* 12V:   11-14V */
-       LM87_IN_LIMITS(5, 0x44, 0x4b),          /* Vccp2: 1.0V +/- 5% */
-       LM87_AIN_LIMITS(0, 0xa0, 0xb2),         /* AIN1:  1.66V +/- 5% */
-       LM87_AIN_LIMITS(1, 0x91, 0xa1),         /* AIN2:  1.5V +/- 5% */
-       LM87_TEMP_INT_LIMITS(10, 60),           /* board */
-       LM87_TEMP_EXT1_LIMITS(10, 70),          /* Falcon */
+       LM87_IN_LIMITS(0, 0x7c, 0x99),          /* 2.5V:  1.8V +/- 10% */
+       LM87_IN_LIMITS(1, 0x4c, 0x5e),          /* Vccp1: 1.2V +/- 10% */
+       LM87_IN_LIMITS(2, 0xac, 0xd4),          /* 3.3V:  3.3V +/- 10% */
+       LM87_IN_LIMITS(3, 0xac, 0xd4),          /* 5V:    5.0V +/- 10% */
+       LM87_IN_LIMITS(4, 0xac, 0xe0),          /* 12V:   10.8-14V */
+       LM87_IN_LIMITS(5, 0x3f, 0x4f),          /* Vccp2: 1.0V +/- 10% */
+       LM87_AIN_LIMITS(0, 0x98, 0xbb),         /* AIN1:  1.66V +/- 10% */
+       LM87_AIN_LIMITS(1, 0x8a, 0xa9),         /* AIN2:  1.5V +/- 10% */
+       LM87_TEMP_INT_LIMITS(0, 80 + FALCON_BOARD_TEMP_BIAS),
+       LM87_TEMP_EXT1_LIMITS(0, FALCON_JUNC_TEMP_MAX),
        0
 };
 
@@ -619,14 +628,14 @@ static int sfe4002_init(struct efx_nic *efx)
 static u8 sfn4112f_lm87_channel = 0x03; /* use AIN not FAN inputs */
 
 static const u8 sfn4112f_lm87_regs[] = {
-       LM87_IN_LIMITS(0, 0x83, 0x91),          /* 2.5V:  1.8V +/- 5% */
-       LM87_IN_LIMITS(1, 0x51, 0x5a),          /* Vccp1: 1.2V +/- 5% */
-       LM87_IN_LIMITS(2, 0xb6, 0xca),          /* 3.3V:  3.3V +/- 5% */
-       LM87_IN_LIMITS(4, 0xb0, 0xe0),          /* 12V:   11-14V */
-       LM87_IN_LIMITS(5, 0x44, 0x4b),          /* Vccp2: 1.0V +/- 5% */
-       LM87_AIN_LIMITS(1, 0x91, 0xa1),         /* AIN2:  1.5V +/- 5% */
-       LM87_TEMP_INT_LIMITS(10, 60),           /* board */
-       LM87_TEMP_EXT1_LIMITS(10, 70),          /* Falcon */
+       LM87_IN_LIMITS(0, 0x7c, 0x99),          /* 2.5V:  1.8V +/- 10% */
+       LM87_IN_LIMITS(1, 0x4c, 0x5e),          /* Vccp1: 1.2V +/- 10% */
+       LM87_IN_LIMITS(2, 0xac, 0xd4),          /* 3.3V:  3.3V +/- 10% */
+       LM87_IN_LIMITS(4, 0xac, 0xe0),          /* 12V:   10.8-14V */
+       LM87_IN_LIMITS(5, 0x3f, 0x4f),          /* Vccp2: 1.0V +/- 10% */
+       LM87_AIN_LIMITS(1, 0x8a, 0xa9),         /* AIN2:  1.5V +/- 10% */
+       LM87_TEMP_INT_LIMITS(0, 60 + FALCON_BOARD_TEMP_BIAS),
+       LM87_TEMP_EXT1_LIMITS(0, FALCON_JUNC_TEMP_MAX),
        0
 };
 
index 9f035b9..f66b3da 100644 (file)
@@ -127,7 +127,7 @@ static int efx_mcdi_poll(struct efx_nic *efx)
        efx_dword_t reg;
 
        /* Check for a reboot atomically with respect to efx_mcdi_copyout() */
-       rc = efx_mcdi_poll_reboot(efx);
+       rc = -efx_mcdi_poll_reboot(efx);
        if (rc)
                goto out;
 
index e0d13a4..67eec7a 100644 (file)
@@ -320,7 +320,7 @@ static int qt202x_reset_phy(struct efx_nic *efx)
 
        falcon_board(efx)->type->init_phy(efx);
 
-       return rc;
+       return 0;
 
  fail:
        EFX_ERR(efx, "PHY reset timed out\n");
index 75a669d..d71c197 100644 (file)
@@ -1437,7 +1437,6 @@ static int tc35815_do_interrupt(struct net_device *dev, u32 status, int limit)
                /* Transmit complete. */
                lp->lstats.tx_ints++;
                tc35815_txdone(dev);
-               netif_wake_queue(dev);
                if (ret < 0)
                        ret = 0;
        }
index 4f27f02..5f3b9ea 100644 (file)
@@ -584,6 +584,11 @@ static const struct usb_device_id  products [] = {
                        USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
        .driver_info = (unsigned long) &mbm_info,
 }, {
+       /* Ericsson C3607w ver 2 */
+       USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x190b, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
+       .driver_info = (unsigned long) &mbm_info,
+}, {
        /* Toshiba F3507g */
        USB_DEVICE_AND_INTERFACE_INFO(0x0930, 0x130b, USB_CLASS_COMM,
                        USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
index c93f58f..317aa34 100644 (file)
@@ -1877,13 +1877,12 @@ static void velocity_error(struct velocity_info *vptr, int status)
 /**
  *     tx_srv          -       transmit interrupt service
  *     @vptr; Velocity
- *     @status:
  *
  *     Scan the queues looking for transmitted packets that
  *     we can complete and clean up. Update any statistics as
  *     necessary/
  */
-static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
+static int velocity_tx_srv(struct velocity_info *vptr)
 {
        struct tx_desc *td;
        int qnum;
@@ -2090,14 +2089,12 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
 /**
  *     velocity_rx_srv         -       service RX interrupt
  *     @vptr: velocity
- *     @status: adapter status (unused)
  *
  *     Walk the receive ring of the velocity adapter and remove
  *     any received packets from the receive queue. Hand the ring
  *     slots back to the adapter for reuse.
  */
-static int velocity_rx_srv(struct velocity_info *vptr, int status,
-               int budget_left)
+static int velocity_rx_srv(struct velocity_info *vptr, int budget_left)
 {
        struct net_device_stats *stats = &vptr->dev->stats;
        int rd_curr = vptr->rx.curr;
@@ -2151,32 +2148,24 @@ static int velocity_poll(struct napi_struct *napi, int budget)
        struct velocity_info *vptr = container_of(napi,
                        struct velocity_info, napi);
        unsigned int rx_done;
-       u32 isr_status;
-
-       spin_lock(&vptr->lock);
-       isr_status = mac_read_isr(vptr->mac_regs);
-
-       /* Ack the interrupt */
-       mac_write_isr(vptr->mac_regs, isr_status);
-       if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI)))
-               velocity_error(vptr, isr_status);
+       unsigned long flags;
 
+       spin_lock_irqsave(&vptr->lock, flags);
        /*
         * Do rx and tx twice for performance (taken from the VIA
         * out-of-tree driver).
         */
-       rx_done = velocity_rx_srv(vptr, isr_status, budget / 2);
-       velocity_tx_srv(vptr, isr_status);
-       rx_done += velocity_rx_srv(vptr, isr_status, budget - rx_done);
-       velocity_tx_srv(vptr, isr_status);
-
-       spin_unlock(&vptr->lock);
+       rx_done = velocity_rx_srv(vptr, budget / 2);
+       velocity_tx_srv(vptr);
+       rx_done += velocity_rx_srv(vptr, budget - rx_done);
+       velocity_tx_srv(vptr);
 
        /* If budget not fully consumed, exit the polling mode */
        if (rx_done < budget) {
                napi_complete(napi);
                mac_enable_int(vptr->mac_regs);
        }
+       spin_unlock_irqrestore(&vptr->lock, flags);
 
        return rx_done;
 }
@@ -2206,10 +2195,17 @@ static irqreturn_t velocity_intr(int irq, void *dev_instance)
                return IRQ_NONE;
        }
 
+       /* Ack the interrupt */
+       mac_write_isr(vptr->mac_regs, isr_status);
+
        if (likely(napi_schedule_prep(&vptr->napi))) {
                mac_disable_int(vptr->mac_regs);
                __napi_schedule(&vptr->napi);
        }
+
+       if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI)))
+               velocity_error(vptr, isr_status);
+
        spin_unlock(&vptr->lock);
 
        return IRQ_HANDLED;
@@ -3100,7 +3096,7 @@ static int velocity_resume(struct pci_dev *pdev)
        velocity_init_registers(vptr, VELOCITY_INIT_WOL);
        mac_disable_int(vptr->mac_regs);
 
-       velocity_tx_srv(vptr, 0);
+       velocity_tx_srv(vptr);
 
        for (i = 0; i < vptr->tx.numq; i++) {
                if (vptr->tx.used[i])
@@ -3344,6 +3340,7 @@ static int velocity_set_coalesce(struct net_device *dev,
 {
        struct velocity_info *vptr = netdev_priv(dev);
        int max_us = 0x3f * 64;
+       unsigned long flags;
 
        /* 6 bits of  */
        if (ecmd->tx_coalesce_usecs > max_us)
@@ -3365,6 +3362,7 @@ static int velocity_set_coalesce(struct net_device *dev,
                        ecmd->tx_coalesce_usecs);
 
        /* Setup the interrupt suppression and queue timers */
+       spin_lock_irqsave(&vptr->lock, flags);
        mac_disable_int(vptr->mac_regs);
        setup_adaptive_interrupts(vptr);
        setup_queue_timers(vptr);
@@ -3372,6 +3370,7 @@ static int velocity_set_coalesce(struct net_device *dev,
        mac_write_int_mask(vptr->int_mask, vptr->mac_regs);
        mac_clear_isr(vptr->mac_regs);
        mac_enable_int(vptr->mac_regs);
+       spin_unlock_irqrestore(&vptr->lock, flags);
 
        return 0;
 }
index fa12b90..29bf336 100644 (file)
@@ -1615,7 +1615,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
                bf->bf_frmlen -= padsize;
        }
 
-       if (conf_is_ht(&hw->conf) && !is_pae(skb))
+       if (conf_is_ht(&hw->conf))
                bf->bf_state.bf_type |= BUF_HT;
 
        bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq);
@@ -1701,7 +1701,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
                        goto tx_done;
                }
 
-               if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+               if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && !is_pae(skb)) {
                        /*
                         * Try aggregation if it's a unicast data frame
                         * and the destination is HT capable.
index fe3bf94..c484cc2 100644 (file)
 #define B43_MMIO_TSF_2                 0x636   /* core rev < 3 only */
 #define B43_MMIO_TSF_3                 0x638   /* core rev < 3 only */
 #define B43_MMIO_RNG                   0x65A
+#define B43_MMIO_IFSSLOT               0x684   /* Interframe slot time */
 #define B43_MMIO_IFSCTL                        0x688 /* Interframe space control */
 #define  B43_MMIO_IFSCTL_USE_EDCF      0x0004
 #define B43_MMIO_POWERUP_DELAY         0x6A8
index 4c41cfe..490fb45 100644 (file)
@@ -628,10 +628,17 @@ static void b43_upload_card_macaddress(struct b43_wldev *dev)
 static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time)
 {
        /* slot_time is in usec. */
-       if (dev->phy.type != B43_PHYTYPE_G)
+       /* This test used to exit for all but a G PHY. */
+       if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
                return;
-       b43_write16(dev, 0x684, 510 + slot_time);
-       b43_shm_write16(dev, B43_SHM_SHARED, 0x0010, slot_time);
+       b43_write16(dev, B43_MMIO_IFSSLOT, 510 + slot_time);
+       /* Shared memory location 0x0010 is the slot time and should be
+        * set to slot_time; however, this register is initially 0 and changing
+        * the value adversely affects the transmit rate for BCM4311
+        * devices. Until this behavior is unterstood, delete this step
+        *
+        * b43_shm_write16(dev, B43_SHM_SHARED, 0x0010, slot_time);
+        */
 }
 
 static void b43_short_slot_timing_enable(struct b43_wldev *dev)
index 9b4b8b5..3146281 100644 (file)
@@ -2008,7 +2008,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
                        IWL_DEBUG_TX_REPLY(priv, "Retry scheduler reclaim scd_ssn "
                                           "%d index %d\n", scd_ssn , index);
                        freed = iwl_tx_queue_reclaim(priv, txq_id, index);
-                       priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+                       iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
 
                        if (priv->mac80211_registered &&
                            (iwl_queue_space(&txq->q) > txq->q.low_mark) &&
index de45f30..cffaae7 100644 (file)
@@ -1125,7 +1125,7 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
                                        scd_ssn , index, txq_id, txq->swq_id);
 
                        freed = iwl_tx_queue_reclaim(priv, txq_id, index);
-                       priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+                       iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
 
                        if (priv->mac80211_registered &&
                            (iwl_queue_space(&txq->q) > txq->q.low_mark) &&
@@ -1153,16 +1153,14 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv,
                                   tx_resp->failure_frame);
 
                freed = iwl_tx_queue_reclaim(priv, txq_id, index);
-               if (ieee80211_is_data_qos(tx_resp->frame_ctrl))
-                       priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+               iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
 
                if (priv->mac80211_registered &&
                    (iwl_queue_space(&txq->q) > txq->q.low_mark))
                        iwl_wake_queue(priv, txq_id);
        }
 
-       if (ieee80211_is_data_qos(tx_resp->frame_ctrl))
-               iwl_txq_check_empty(priv, sta_id, tid, txq_id);
+       iwl_txq_check_empty(priv, sta_id, tid, txq_id);
 
        if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
                IWL_ERR(priv, "TODO:  Implement Tx ABORT REQUIRED!!!\n");
index 5461f10..f36f804 100644 (file)
@@ -2745,6 +2745,7 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
                        priv->staging_rxon.flags = 0;
 
                iwl_set_rxon_channel(priv, conf->channel);
+               iwl_set_rxon_ht(priv, ht_conf);
 
                iwl_set_flags_for_band(priv, conf->channel->band);
                spin_unlock_irqrestore(&priv->lock, flags);
index 27ca859..b69e972 100644 (file)
@@ -446,6 +446,8 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv);
 int iwl_hw_tx_queue_init(struct iwl_priv *priv,
                         struct iwl_tx_queue *txq);
 int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
+void iwl_free_tfds_in_queue(struct iwl_priv *priv,
+                           int sta_id, int tid, int freed);
 int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
                      int slots_num, u32 txq_id);
 void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id);
index 6f36b6e..2dbce85 100644 (file)
@@ -928,7 +928,10 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
        if (ieee80211_is_mgmt(fc) ||
            ieee80211_has_protected(fc) ||
            ieee80211_has_morefrags(fc) ||
-           le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)
+           le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG ||
+           (ieee80211_is_data_qos(fc) &&
+            *ieee80211_get_qos_ctl(hdr) &
+            IEEE80211_QOS_CONTROL_A_MSDU_PRESENT))
                ret = skb_linearize(skb);
        else
                ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ?
index 87ce2bd..8f40715 100644 (file)
@@ -120,6 +120,20 @@ int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
 EXPORT_SYMBOL(iwl_txq_update_write_ptr);
 
 
+void iwl_free_tfds_in_queue(struct iwl_priv *priv,
+                           int sta_id, int tid, int freed)
+{
+       if (priv->stations[sta_id].tid[tid].tfds_in_queue >= freed)
+               priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+       else {
+               IWL_ERR(priv, "free more than tfds_in_queue (%u:%d)\n",
+                       priv->stations[sta_id].tid[tid].tfds_in_queue,
+                       freed);
+               priv->stations[sta_id].tid[tid].tfds_in_queue = 0;
+       }
+}
+EXPORT_SYMBOL(iwl_free_tfds_in_queue);
+
 /**
  * iwl_tx_queue_free - Deallocate DMA queue.
  * @txq: Transmit queue to deallocate.
@@ -1131,6 +1145,7 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
        struct iwl_queue *q = &txq->q;
        struct iwl_tx_info *tx_info;
        int nfreed = 0;
+       struct ieee80211_hdr *hdr;
 
        if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) {
                IWL_ERR(priv, "Read index for DMA queue txq id (%d), index %d, "
@@ -1145,13 +1160,16 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
 
                tx_info = &txq->txb[txq->q.read_ptr];
                iwl_tx_status(priv, tx_info->skb[0]);
+
+               hdr = (struct ieee80211_hdr *)tx_info->skb[0]->data;
+               if (hdr && ieee80211_is_data_qos(hdr->frame_control))
+                       nfreed++;
                tx_info->skb[0] = NULL;
 
                if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
                        priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq);
 
                priv->cfg->ops->lib->txq_free_tfd(priv, txq);
-               nfreed++;
        }
        return nfreed;
 }
@@ -1559,7 +1577,7 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
        if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) {
                /* calculate mac80211 ampdu sw queue to wake */
                int freed = iwl_tx_queue_reclaim(priv, scd_flow, index);
-               priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+               iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
 
                if ((iwl_queue_space(&txq->q) > txq->q.low_mark) &&
                    priv->mac80211_registered &&
index 6d6ed74..f727b4a 100644 (file)
@@ -794,7 +794,7 @@ static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf,
        }
 
        bss->bss = kzalloc(bss_len, GFP_KERNEL);
-       if (!bss) {
+       if (!bss->bss) {
                kfree(bss);
                IWM_ERR(iwm, "Couldn't allocate bss\n");
                return -ENOMEM;
index bc5726d..7ba3052 100644 (file)
@@ -65,6 +65,7 @@ static struct usb_device_id rtl8187_table[] __devinitdata = {
        /* Sitecom */
        {USB_DEVICE(0x0df6, 0x000d), .driver_info = DEVICE_RTL8187},
        {USB_DEVICE(0x0df6, 0x0028), .driver_info = DEVICE_RTL8187B},
+       {USB_DEVICE(0x0df6, 0x0029), .driver_info = DEVICE_RTL8187B},
        /* Sphairon Access Systems GmbH */
        {USB_DEVICE(0x114B, 0x0150), .driver_info = DEVICE_RTL8187},
        /* Dick Smith Electronics */
index d2fa27c..7cecc8f 100644 (file)
@@ -1,3 +1,11 @@
+config OF_FLATTREE
+       bool
+       depends on OF
+
+config OF_DYNAMIC
+       def_bool y
+       depends on OF && PPC_OF
+
 config OF_DEVICE
        def_bool y
        depends on OF && (SPARC || PPC_OF || MICROBLAZE)
index bdfb5f5..f232cc9 100644 (file)
@@ -1,4 +1,5 @@
 obj-y = base.o
+obj-$(CONFIG_OF_FLATTREE) += fdt.o
 obj-$(CONFIG_OF_DEVICE) += device.o platform.o
 obj-$(CONFIG_OF_GPIO)   += gpio.o
 obj-$(CONFIG_OF_I2C)   += of_i2c.o
index e6627b2..cb96888 100644 (file)
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/spinlock.h>
+#include <linux/proc_fs.h>
 
 struct device_node *allnodes;
+struct device_node *of_chosen;
 
 /* use when traversing tree through the allnext, child, sibling,
  * or parent members of struct device_node.
@@ -37,7 +39,7 @@ int of_n_addr_cells(struct device_node *np)
                        np = np->parent;
                ip = of_get_property(np, "#address-cells", NULL);
                if (ip)
-                       return *ip;
+                       return be32_to_cpup(ip);
        } while (np->parent);
        /* No #address-cells property for the root node */
        return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
@@ -53,13 +55,88 @@ int of_n_size_cells(struct device_node *np)
                        np = np->parent;
                ip = of_get_property(np, "#size-cells", NULL);
                if (ip)
-                       return *ip;
+                       return be32_to_cpup(ip);
        } while (np->parent);
        /* No #size-cells property for the root node */
        return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
 }
 EXPORT_SYMBOL(of_n_size_cells);
 
+#if !defined(CONFIG_SPARC)   /* SPARC doesn't do ref counting (yet) */
+/**
+ *     of_node_get - Increment refcount of a node
+ *     @node:  Node to inc refcount, NULL is supported to
+ *             simplify writing of callers
+ *
+ *     Returns node.
+ */
+struct device_node *of_node_get(struct device_node *node)
+{
+       if (node)
+               kref_get(&node->kref);
+       return node;
+}
+EXPORT_SYMBOL(of_node_get);
+
+static inline struct device_node *kref_to_device_node(struct kref *kref)
+{
+       return container_of(kref, struct device_node, kref);
+}
+
+/**
+ *     of_node_release - release a dynamically allocated node
+ *     @kref:  kref element of the node to be released
+ *
+ *     In of_node_put() this function is passed to kref_put()
+ *     as the destructor.
+ */
+static void of_node_release(struct kref *kref)
+{
+       struct device_node *node = kref_to_device_node(kref);
+       struct property *prop = node->properties;
+
+       /* We should never be releasing nodes that haven't been detached. */
+       if (!of_node_check_flag(node, OF_DETACHED)) {
+               pr_err("ERROR: Bad of_node_put() on %s\n", node->full_name);
+               dump_stack();
+               kref_init(&node->kref);
+               return;
+       }
+
+       if (!of_node_check_flag(node, OF_DYNAMIC))
+               return;
+
+       while (prop) {
+               struct property *next = prop->next;
+               kfree(prop->name);
+               kfree(prop->value);
+               kfree(prop);
+               prop = next;
+
+               if (!prop) {
+                       prop = node->deadprops;
+                       node->deadprops = NULL;
+               }
+       }
+       kfree(node->full_name);
+       kfree(node->data);
+       kfree(node);
+}
+
+/**
+ *     of_node_put - Decrement refcount of a node
+ *     @node:  Node to dec refcount, NULL is supported to
+ *             simplify writing of callers
+ *
+ */
+void of_node_put(struct device_node *node)
+{
+       if (node)
+               kref_put(&node->kref, of_node_release);
+}
+EXPORT_SYMBOL(of_node_put);
+#endif /* !CONFIG_SPARC */
+
 struct property *of_find_property(const struct device_node *np,
                                  const char *name,
                                  int *lenp)
@@ -144,6 +221,27 @@ int of_device_is_compatible(const struct device_node *device,
 EXPORT_SYMBOL(of_device_is_compatible);
 
 /**
+ * of_machine_is_compatible - Test root of device tree for a given compatible value
+ * @compat: compatible string to look for in root node's compatible property.
+ *
+ * Returns true if the root node has the given value in its
+ * compatible property.
+ */
+int of_machine_is_compatible(const char *compat)
+{
+       struct device_node *root;
+       int rc = 0;
+
+       root = of_find_node_by_path("/");
+       if (root) {
+               rc = of_device_is_compatible(root, compat);
+               of_node_put(root);
+       }
+       return rc;
+}
+EXPORT_SYMBOL(of_machine_is_compatible);
+
+/**
  *  of_device_is_available - check if a device is available for use
  *
  *  @device: Node to check for availability
@@ -519,6 +617,27 @@ int of_modalias_node(struct device_node *node, char *modalias, int len)
 EXPORT_SYMBOL_GPL(of_modalias_node);
 
 /**
+ * of_find_node_by_phandle - Find a node given a phandle
+ * @handle:    phandle of the node to find
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_phandle(phandle handle)
+{
+       struct device_node *np;
+
+       read_lock(&devtree_lock);
+       for (np = allnodes; np; np = np->allnext)
+               if (np->phandle == handle)
+                       break;
+       of_node_get(np);
+       read_unlock(&devtree_lock);
+       return np;
+}
+EXPORT_SYMBOL(of_find_node_by_phandle);
+
+/**
  * of_parse_phandle - Resolve a phandle property to a device_node pointer
  * @np: Pointer to device node holding phandle property
  * @phandle_name: Name of property holding a phandle value
@@ -578,8 +697,8 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
                                const void **out_args)
 {
        int ret = -EINVAL;
-       const u32 *list;
-       const u32 *list_end;
+       const __be32 *list;
+       const __be32 *list_end;
        int size;
        int cur_index = 0;
        struct device_node *node = NULL;
@@ -593,7 +712,7 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
        list_end = list + size / sizeof(*list);
 
        while (list < list_end) {
-               const u32 *cells;
+               const __be32 *cells;
                const phandle *phandle;
 
                phandle = list++;
@@ -617,7 +736,7 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
                        goto err1;
                }
 
-               list += *cells;
+               list += be32_to_cpup(cells);
                if (list > list_end) {
                        pr_debug("%s: insufficient arguments length\n",
                                 np->full_name);
@@ -658,3 +777,190 @@ err0:
        return ret;
 }
 EXPORT_SYMBOL(of_parse_phandles_with_args);
+
+/**
+ * prom_add_property - Add a property to a node
+ */
+int prom_add_property(struct device_node *np, struct property *prop)
+{
+       struct property **next;
+       unsigned long flags;
+
+       prop->next = NULL;
+       write_lock_irqsave(&devtree_lock, flags);
+       next = &np->properties;
+       while (*next) {
+               if (strcmp(prop->name, (*next)->name) == 0) {
+                       /* duplicate ! don't insert it */
+                       write_unlock_irqrestore(&devtree_lock, flags);
+                       return -1;
+               }
+               next = &(*next)->next;
+       }
+       *next = prop;
+       write_unlock_irqrestore(&devtree_lock, flags);
+
+#ifdef CONFIG_PROC_DEVICETREE
+       /* try to add to proc as well if it was initialized */
+       if (np->pde)
+               proc_device_tree_add_prop(np->pde, prop);
+#endif /* CONFIG_PROC_DEVICETREE */
+
+       return 0;
+}
+
+/**
+ * prom_remove_property - Remove a property from a node.
+ *
+ * Note that we don't actually remove it, since we have given out
+ * who-knows-how-many pointers to the data using get-property.
+ * Instead we just move the property to the "dead properties"
+ * list, so it won't be found any more.
+ */
+int prom_remove_property(struct device_node *np, struct property *prop)
+{
+       struct property **next;
+       unsigned long flags;
+       int found = 0;
+
+       write_lock_irqsave(&devtree_lock, flags);
+       next = &np->properties;
+       while (*next) {
+               if (*next == prop) {
+                       /* found the node */
+                       *next = prop->next;
+                       prop->next = np->deadprops;
+                       np->deadprops = prop;
+                       found = 1;
+                       break;
+               }
+               next = &(*next)->next;
+       }
+       write_unlock_irqrestore(&devtree_lock, flags);
+
+       if (!found)
+               return -ENODEV;
+
+#ifdef CONFIG_PROC_DEVICETREE
+       /* try to remove the proc node as well */
+       if (np->pde)
+               proc_device_tree_remove_prop(np->pde, prop);
+#endif /* CONFIG_PROC_DEVICETREE */
+
+       return 0;
+}
+
+/*
+ * prom_update_property - Update a property in a node.
+ *
+ * Note that we don't actually remove it, since we have given out
+ * who-knows-how-many pointers to the data using get-property.
+ * Instead we just move the property to the "dead properties" list,
+ * and add the new property to the property list
+ */
+int prom_update_property(struct device_node *np,
+                        struct property *newprop,
+                        struct property *oldprop)
+{
+       struct property **next;
+       unsigned long flags;
+       int found = 0;
+
+       write_lock_irqsave(&devtree_lock, flags);
+       next = &np->properties;
+       while (*next) {
+               if (*next == oldprop) {
+                       /* found the node */
+                       newprop->next = oldprop->next;
+                       *next = newprop;
+                       oldprop->next = np->deadprops;
+                       np->deadprops = oldprop;
+                       found = 1;
+                       break;
+               }
+               next = &(*next)->next;
+       }
+       write_unlock_irqrestore(&devtree_lock, flags);
+
+       if (!found)
+               return -ENODEV;
+
+#ifdef CONFIG_PROC_DEVICETREE
+       /* try to add to proc as well if it was initialized */
+       if (np->pde)
+               proc_device_tree_update_prop(np->pde, newprop, oldprop);
+#endif /* CONFIG_PROC_DEVICETREE */
+
+       return 0;
+}
+
+#if defined(CONFIG_OF_DYNAMIC)
+/*
+ * Support for dynamic device trees.
+ *
+ * On some platforms, the device tree can be manipulated at runtime.
+ * The routines in this section support adding, removing and changing
+ * device tree nodes.
+ */
+
+/**
+ * of_attach_node - Plug a device node into the tree and global list.
+ */
+void of_attach_node(struct device_node *np)
+{
+       unsigned long flags;
+
+       write_lock_irqsave(&devtree_lock, flags);
+       np->sibling = np->parent->child;
+       np->allnext = allnodes;
+       np->parent->child = np;
+       allnodes = np;
+       write_unlock_irqrestore(&devtree_lock, flags);
+}
+
+/**
+ * of_detach_node - "Unplug" a node from the device tree.
+ *
+ * The caller must hold a reference to the node.  The memory associated with
+ * the node is not freed until its refcount goes to zero.
+ */
+void of_detach_node(struct device_node *np)
+{
+       struct device_node *parent;
+       unsigned long flags;
+
+       write_lock_irqsave(&devtree_lock, flags);
+
+       parent = np->parent;
+       if (!parent)
+               goto out_unlock;
+
+       if (allnodes == np)
+               allnodes = np->allnext;
+       else {
+               struct device_node *prev;
+               for (prev = allnodes;
+                    prev->allnext != np;
+                    prev = prev->allnext)
+                       ;
+               prev->allnext = np->allnext;
+       }
+
+       if (parent->child == np)
+               parent->child = np->sibling;
+       else {
+               struct device_node *prevsib;
+               for (prevsib = np->parent->child;
+                    prevsib->sibling != np;
+                    prevsib = prevsib->sibling)
+                       ;
+               prevsib->sibling = np->sibling;
+       }
+
+       of_node_set_flag(np, OF_DETACHED);
+
+out_unlock:
+       write_unlock_irqrestore(&devtree_lock, flags);
+}
+#endif /* defined(CONFIG_OF_DYNAMIC) */
+
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
new file mode 100644 (file)
index 0000000..406757a
--- /dev/null
@@ -0,0 +1,590 @@
+/*
+ * Functions for working with the Flattened Device Tree data format
+ *
+ * Copyright 2009 Benjamin Herrenschmidt, IBM Corp
+ * benh@kernel.crashing.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/initrd.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+
+#ifdef CONFIG_PPC
+#include <asm/machdep.h>
+#endif /* CONFIG_PPC */
+
+#include <asm/page.h>
+
+int __initdata dt_root_addr_cells;
+int __initdata dt_root_size_cells;
+
+struct boot_param_header *initial_boot_params;
+
+char *find_flat_dt_string(u32 offset)
+{
+       return ((char *)initial_boot_params) +
+               be32_to_cpu(initial_boot_params->off_dt_strings) + offset;
+}
+
+/**
+ * of_scan_flat_dt - scan flattened tree blob and call callback on each.
+ * @it: callback function
+ * @data: context data pointer
+ *
+ * This function is used to scan the flattened device-tree, it is
+ * used to extract the memory information at boot before we can
+ * unflatten the tree
+ */
+int __init of_scan_flat_dt(int (*it)(unsigned long node,
+                                    const char *uname, int depth,
+                                    void *data),
+                          void *data)
+{
+       unsigned long p = ((unsigned long)initial_boot_params) +
+               be32_to_cpu(initial_boot_params->off_dt_struct);
+       int rc = 0;
+       int depth = -1;
+
+       do {
+               u32 tag = be32_to_cpup((__be32 *)p);
+               char *pathp;
+
+               p += 4;
+               if (tag == OF_DT_END_NODE) {
+                       depth--;
+                       continue;
+               }
+               if (tag == OF_DT_NOP)
+                       continue;
+               if (tag == OF_DT_END)
+                       break;
+               if (tag == OF_DT_PROP) {
+                       u32 sz = be32_to_cpup((__be32 *)p);
+                       p += 8;
+                       if (be32_to_cpu(initial_boot_params->version) < 0x10)
+                               p = _ALIGN(p, sz >= 8 ? 8 : 4);
+                       p += sz;
+                       p = _ALIGN(p, 4);
+                       continue;
+               }
+               if (tag != OF_DT_BEGIN_NODE) {
+                       pr_err("Invalid tag %x in flat device tree!\n", tag);
+                       return -EINVAL;
+               }
+               depth++;
+               pathp = (char *)p;
+               p = _ALIGN(p + strlen(pathp) + 1, 4);
+               if ((*pathp) == '/') {
+                       char *lp, *np;
+                       for (lp = NULL, np = pathp; *np; np++)
+                               if ((*np) == '/')
+                                       lp = np+1;
+                       if (lp != NULL)
+                               pathp = lp;
+               }
+               rc = it(p, pathp, depth, data);
+               if (rc != 0)
+                       break;
+       } while (1);
+
+       return rc;
+}
+
+/**
+ * of_get_flat_dt_root - find the root node in the flat blob
+ */
+unsigned long __init of_get_flat_dt_root(void)
+{
+       unsigned long p = ((unsigned long)initial_boot_params) +
+               be32_to_cpu(initial_boot_params->off_dt_struct);
+
+       while (be32_to_cpup((__be32 *)p) == OF_DT_NOP)
+               p += 4;
+       BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE);
+       p += 4;
+       return _ALIGN(p + strlen((char *)p) + 1, 4);
+}
+
+/**
+ * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr
+ *
+ * This function can be used within scan_flattened_dt callback to get
+ * access to properties
+ */
+void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
+                                unsigned long *size)
+{
+       unsigned long p = node;
+
+       do {
+               u32 tag = be32_to_cpup((__be32 *)p);
+               u32 sz, noff;
+               const char *nstr;
+
+               p += 4;
+               if (tag == OF_DT_NOP)
+                       continue;
+               if (tag != OF_DT_PROP)
+                       return NULL;
+
+               sz = be32_to_cpup((__be32 *)p);
+               noff = be32_to_cpup((__be32 *)(p + 4));
+               p += 8;
+               if (be32_to_cpu(initial_boot_params->version) < 0x10)
+                       p = _ALIGN(p, sz >= 8 ? 8 : 4);
+
+               nstr = find_flat_dt_string(noff);
+               if (nstr == NULL) {
+                       pr_warning("Can't find property index name !\n");
+                       return NULL;
+               }
+               if (strcmp(name, nstr) == 0) {
+                       if (size)
+                               *size = sz;
+                       return (void *)p;
+               }
+               p += sz;
+               p = _ALIGN(p, 4);
+       } while (1);
+}
+
+/**
+ * of_flat_dt_is_compatible - Return true if given node has compat in compatible list
+ * @node: node to test
+ * @compat: compatible string to compare with compatible list.
+ */
+int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
+{
+       const char *cp;
+       unsigned long cplen, l;
+
+       cp = of_get_flat_dt_prop(node, "compatible", &cplen);
+       if (cp == NULL)
+               return 0;
+       while (cplen > 0) {
+               if (strncasecmp(cp, compat, strlen(compat)) == 0)
+                       return 1;
+               l = strlen(cp) + 1;
+               cp += l;
+               cplen -= l;
+       }
+
+       return 0;
+}
+
+static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
+                                      unsigned long align)
+{
+       void *res;
+
+       *mem = _ALIGN(*mem, align);
+       res = (void *)*mem;
+       *mem += size;
+
+       return res;
+}
+
+/**
+ * unflatten_dt_node - Alloc and populate a device_node from the flat tree
+ * @p: pointer to node in flat tree
+ * @dad: Parent struct device_node
+ * @allnextpp: pointer to ->allnext from last allocated device_node
+ * @fpsize: Size of the node path up at the current depth.
+ */
+unsigned long __init unflatten_dt_node(unsigned long mem,
+                                       unsigned long *p,
+                                       struct device_node *dad,
+                                       struct device_node ***allnextpp,
+                                       unsigned long fpsize)
+{
+       struct device_node *np;
+       struct property *pp, **prev_pp = NULL;
+       char *pathp;
+       u32 tag;
+       unsigned int l, allocl;
+       int has_name = 0;
+       int new_format = 0;
+
+       tag = be32_to_cpup((__be32 *)(*p));
+       if (tag != OF_DT_BEGIN_NODE) {
+               pr_err("Weird tag at start of node: %x\n", tag);
+               return mem;
+       }
+       *p += 4;
+       pathp = (char *)*p;
+       l = allocl = strlen(pathp) + 1;
+       *p = _ALIGN(*p + l, 4);
+
+       /* version 0x10 has a more compact unit name here instead of the full
+        * path. we accumulate the full path size using "fpsize", we'll rebuild
+        * it later. We detect this because the first character of the name is
+        * not '/'.
+        */
+       if ((*pathp) != '/') {
+               new_format = 1;
+               if (fpsize == 0) {
+                       /* root node: special case. fpsize accounts for path
+                        * plus terminating zero. root node only has '/', so
+                        * fpsize should be 2, but we want to avoid the first
+                        * level nodes to have two '/' so we use fpsize 1 here
+                        */
+                       fpsize = 1;
+                       allocl = 2;
+               } else {
+                       /* account for '/' and path size minus terminal 0
+                        * already in 'l'
+                        */
+                       fpsize += l;
+                       allocl = fpsize;
+               }
+       }
+
+       np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
+                               __alignof__(struct device_node));
+       if (allnextpp) {
+               memset(np, 0, sizeof(*np));
+               np->full_name = ((char *)np) + sizeof(struct device_node);
+               if (new_format) {
+                       char *fn = np->full_name;
+                       /* rebuild full path for new format */
+                       if (dad && dad->parent) {
+                               strcpy(fn, dad->full_name);
+#ifdef DEBUG
+                               if ((strlen(fn) + l + 1) != allocl) {
+                                       pr_debug("%s: p: %d, l: %d, a: %d\n",
+                                               pathp, (int)strlen(fn),
+                                               l, allocl);
+                               }
+#endif
+                               fn += strlen(fn);
+                       }
+                       *(fn++) = '/';
+                       memcpy(fn, pathp, l);
+               } else
+                       memcpy(np->full_name, pathp, l);
+               prev_pp = &np->properties;
+               **allnextpp = np;
+               *allnextpp = &np->allnext;
+               if (dad != NULL) {
+                       np->parent = dad;
+                       /* we temporarily use the next field as `last_child'*/
+                       if (dad->next == NULL)
+                               dad->child = np;
+                       else
+                               dad->next->sibling = np;
+                       dad->next = np;
+               }
+               kref_init(&np->kref);
+       }
+       while (1) {
+               u32 sz, noff;
+               char *pname;
+
+               tag = be32_to_cpup((__be32 *)(*p));
+               if (tag == OF_DT_NOP) {
+                       *p += 4;
+                       continue;
+               }
+               if (tag != OF_DT_PROP)
+                       break;
+               *p += 4;
+               sz = be32_to_cpup((__be32 *)(*p));
+               noff = be32_to_cpup((__be32 *)((*p) + 4));
+               *p += 8;
+               if (be32_to_cpu(initial_boot_params->version) < 0x10)
+                       *p = _ALIGN(*p, sz >= 8 ? 8 : 4);
+
+               pname = find_flat_dt_string(noff);
+               if (pname == NULL) {
+                       pr_info("Can't find property name in list !\n");
+                       break;
+               }
+               if (strcmp(pname, "name") == 0)
+                       has_name = 1;
+               l = strlen(pname) + 1;
+               pp = unflatten_dt_alloc(&mem, sizeof(struct property),
+                                       __alignof__(struct property));
+               if (allnextpp) {
+                       /* We accept flattened tree phandles either in
+                        * ePAPR-style "phandle" properties, or the
+                        * legacy "linux,phandle" properties.  If both
+                        * appear and have different values, things
+                        * will get weird.  Don't do that. */
+                       if ((strcmp(pname, "phandle") == 0) ||
+                           (strcmp(pname, "linux,phandle") == 0)) {
+                               if (np->phandle == 0)
+                                       np->phandle = *((u32 *)*p);
+                       }
+                       /* And we process the "ibm,phandle" property
+                        * used in pSeries dynamic device tree
+                        * stuff */
+                       if (strcmp(pname, "ibm,phandle") == 0)
+                               np->phandle = *((u32 *)*p);
+                       pp->name = pname;
+                       pp->length = sz;
+                       pp->value = (void *)*p;
+                       *prev_pp = pp;
+                       prev_pp = &pp->next;
+               }
+               *p = _ALIGN((*p) + sz, 4);
+       }
+       /* with version 0x10 we may not have the name property, recreate
+        * it here from the unit name if absent
+        */
+       if (!has_name) {
+               char *p1 = pathp, *ps = pathp, *pa = NULL;
+               int sz;
+
+               while (*p1) {
+                       if ((*p1) == '@')
+                               pa = p1;
+                       if ((*p1) == '/')
+                               ps = p1 + 1;
+                       p1++;
+               }
+               if (pa < ps)
+                       pa = p1;
+               sz = (pa - ps) + 1;
+               pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
+                                       __alignof__(struct property));
+               if (allnextpp) {
+                       pp->name = "name";
+                       pp->length = sz;
+                       pp->value = pp + 1;
+                       *prev_pp = pp;
+                       prev_pp = &pp->next;
+                       memcpy(pp->value, ps, sz - 1);
+                       ((char *)pp->value)[sz - 1] = 0;
+                       pr_debug("fixed up name for %s -> %s\n", pathp,
+                               (char *)pp->value);
+               }
+       }
+       if (allnextpp) {
+               *prev_pp = NULL;
+               np->name = of_get_property(np, "name", NULL);
+               np->type = of_get_property(np, "device_type", NULL);
+
+               if (!np->name)
+                       np->name = "<NULL>";
+               if (!np->type)
+                       np->type = "<NULL>";
+       }
+       while (tag == OF_DT_BEGIN_NODE) {
+               mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize);
+               tag = be32_to_cpup((__be32 *)(*p));
+       }
+       if (tag != OF_DT_END_NODE) {
+               pr_err("Weird tag at end of node: %x\n", tag);
+               return mem;
+       }
+       *p += 4;
+       return mem;
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+/**
+ * early_init_dt_check_for_initrd - Decode initrd location from flat tree
+ * @node: reference to node containing initrd location ('chosen')
+ */
+void __init early_init_dt_check_for_initrd(unsigned long node)
+{
+       unsigned long start, end, len;
+       __be32 *prop;
+
+       pr_debug("Looking for initrd properties... ");
+
+       prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len);
+       if (!prop)
+               return;
+       start = of_read_ulong(prop, len/4);
+
+       prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len);
+       if (!prop)
+               return;
+       end = of_read_ulong(prop, len/4);
+
+       early_init_dt_setup_initrd_arch(start, end);
+       pr_debug("initrd_start=0x%lx  initrd_end=0x%lx\n", start, end);
+}
+#else
+inline void early_init_dt_check_for_initrd(unsigned long node)
+{
+}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+/**
+ * early_init_dt_scan_root - fetch the top level address and size cells
+ */
+int __init early_init_dt_scan_root(unsigned long node, const char *uname,
+                                  int depth, void *data)
+{
+       __be32 *prop;
+
+       if (depth != 0)
+               return 0;
+
+       dt_root_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
+       dt_root_addr_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
+
+       prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
+       if (prop)
+               dt_root_size_cells = be32_to_cpup(prop);
+       pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells);
+
+       prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
+       if (prop)
+               dt_root_addr_cells = be32_to_cpup(prop);
+       pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells);
+
+       /* break now */
+       return 1;
+}
+
+u64 __init dt_mem_next_cell(int s, __be32 **cellp)
+{
+       __be32 *p = *cellp;
+
+       *cellp = p + s;
+       return of_read_number(p, s);
+}
+
+/**
+ * early_init_dt_scan_memory - Look for an parse memory nodes
+ */
+int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
+                                    int depth, void *data)
+{
+       char *type = of_get_flat_dt_prop(node, "device_type", NULL);
+       __be32 *reg, *endp;
+       unsigned long l;
+
+       /* We are scanning "memory" nodes only */
+       if (type == NULL) {
+               /*
+                * The longtrail doesn't have a device_type on the
+                * /memory node, so look for the node called /memory@0.
+                */
+               if (depth != 1 || strcmp(uname, "memory@0") != 0)
+                       return 0;
+       } else if (strcmp(type, "memory") != 0)
+               return 0;
+
+       reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
+       if (reg == NULL)
+               reg = of_get_flat_dt_prop(node, "reg", &l);
+       if (reg == NULL)
+               return 0;
+
+       endp = reg + (l / sizeof(__be32));
+
+       pr_debug("memory scan node %s, reg size %ld, data: %x %x %x %x,\n",
+           uname, l, reg[0], reg[1], reg[2], reg[3]);
+
+       while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
+               u64 base, size;
+
+               base = dt_mem_next_cell(dt_root_addr_cells, &reg);
+               size = dt_mem_next_cell(dt_root_size_cells, &reg);
+
+               if (size == 0)
+                       continue;
+               pr_debug(" - %llx ,  %llx\n", (unsigned long long)base,
+                   (unsigned long long)size);
+
+               early_init_dt_add_memory_arch(base, size);
+       }
+
+       return 0;
+}
+
+int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
+                                    int depth, void *data)
+{
+       unsigned long l;
+       char *p;
+
+       pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
+
+       if (depth != 1 ||
+           (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
+               return 0;
+
+       early_init_dt_check_for_initrd(node);
+
+       /* Retreive command line */
+       p = of_get_flat_dt_prop(node, "bootargs", &l);
+       if (p != NULL && l > 0)
+               strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE));
+
+#ifdef CONFIG_CMDLINE
+#ifndef CONFIG_CMDLINE_FORCE
+       if (p == NULL || l == 0 || (l == 1 && (*p) == 0))
+#endif
+               strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
+#endif /* CONFIG_CMDLINE */
+
+       early_init_dt_scan_chosen_arch(node);
+
+       pr_debug("Command line is: %s\n", cmd_line);
+
+       /* break now */
+       return 1;
+}
+
+/**
+ * unflatten_device_tree - create tree of device_nodes from flat blob
+ *
+ * unflattens the device-tree passed by the firmware, creating the
+ * tree of struct device_node. It also fills the "name" and "type"
+ * pointers of the nodes so the normal device-tree walking functions
+ * can be used.
+ */
+void __init unflatten_device_tree(void)
+{
+       unsigned long start, mem, size;
+       struct device_node **allnextp = &allnodes;
+
+       pr_debug(" -> unflatten_device_tree()\n");
+
+       /* First pass, scan for size */
+       start = ((unsigned long)initial_boot_params) +
+               be32_to_cpu(initial_boot_params->off_dt_struct);
+       size = unflatten_dt_node(0, &start, NULL, NULL, 0);
+       size = (size | 3) + 1;
+
+       pr_debug("  size is %lx, allocating...\n", size);
+
+       /* Allocate memory for the expanded device tree */
+       mem = early_init_dt_alloc_memory_arch(size + 4,
+                       __alignof__(struct device_node));
+       mem = (unsigned long) __va(mem);
+
+       ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef);
+
+       pr_debug("  unflattening %lx...\n", mem);
+
+       /* Second pass, do actual unflattening */
+       start = ((unsigned long)initial_boot_params) +
+               be32_to_cpu(initial_boot_params->off_dt_struct);
+       unflatten_dt_node(mem, &start, NULL, &allnextp, 0);
+       if (be32_to_cpup((__be32 *)start) != OF_DT_END)
+               pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start));
+       if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef)
+               pr_warning("End of tree marker overwritten: %08x\n",
+                          be32_to_cpu(((__be32 *)mem)[size / 4]));
+       *allnextp = NULL;
+
+       /* Get pointer to OF "/chosen" node for use everywhere */
+       of_chosen = of_find_node_by_path("/chosen");
+       if (of_chosen == NULL)
+               of_chosen = of_find_node_by_path("/chosen@0");
+
+       pr_debug(" <- unflatten_device_tree()\n");
+}
index 6eea601..24c3606 100644 (file)
@@ -36,7 +36,7 @@ int of_get_gpio_flags(struct device_node *np, int index,
        struct of_gpio_chip *of_gc = NULL;
        int size;
        const void *gpio_spec;
-       const u32 *gpio_cells;
+       const __be32 *gpio_cells;
 
        ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index,
                                          &gc, &gpio_spec);
@@ -55,7 +55,7 @@ int of_get_gpio_flags(struct device_node *np, int index,
 
        gpio_cells = of_get_property(gc, "#gpio-cells", &size);
        if (!gpio_cells || size != sizeof(*gpio_cells) ||
-                       *gpio_cells != of_gc->gpio_cells) {
+                       be32_to_cpup(gpio_cells) != of_gc->gpio_cells) {
                pr_debug("%s: wrong #gpio-cells for %s\n",
                         np->full_name, gc->full_name);
                ret = -EINVAL;
@@ -127,7 +127,8 @@ EXPORT_SYMBOL(of_gpio_count);
 int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, struct device_node *np,
                         const void *gpio_spec, enum of_gpio_flags *flags)
 {
-       const u32 *gpio = gpio_spec;
+       const __be32 *gpio = gpio_spec;
+       const u32 n = be32_to_cpup(gpio);
 
        /*
         * We're discouraging gpio_cells < 2, since that way you'll have to
@@ -140,13 +141,13 @@ int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, struct device_node *np,
                return -EINVAL;
        }
 
-       if (*gpio > of_gc->gc.ngpio)
+       if (n > of_gc->gc.ngpio)
                return -EINVAL;
 
        if (flags)
-               *flags = gpio[1];
+               *flags = be32_to_cpu(gpio[1]);
 
-       return *gpio;
+       return n;
 }
 EXPORT_SYMBOL(of_gpio_simple_xlate);
 
index fa65a2b..a3a708e 100644 (file)
@@ -25,7 +25,7 @@ void of_register_i2c_devices(struct i2c_adapter *adap,
        for_each_child_of_node(adap_node, node) {
                struct i2c_board_info info = {};
                struct dev_archdata dev_ad = {};
-               const u32 *addr;
+               const __be32 *addr;
                int len;
 
                if (of_modalias_node(node, info.type, sizeof(info.type)) < 0)
@@ -40,7 +40,7 @@ void of_register_i2c_devices(struct i2c_adapter *adap,
 
                info.irq = irq_of_parse_and_map(node, 0);
 
-               info.addr = *addr;
+               info.addr = be32_to_cpup(addr);
 
                dev_archdata_set_node(&dev_ad, node);
                info.archdata = &dev_ad;
index 4b22ba5..18ecae4 100644 (file)
@@ -51,7 +51,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
 
        /* Loop over the child nodes and register a phy_device for each one */
        for_each_child_of_node(np, child) {
-               const u32 *addr;
+               const __be32 *addr;
                int len;
 
                /* A PHY must have a reg property in the range [0-31] */
@@ -68,7 +68,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
                                mdio->irq[*addr] = PHY_POLL;
                }
 
-               phy = get_phy_device(mdio, *addr);
+               phy = get_phy_device(mdio, be32_to_cpup(addr));
                if (!phy) {
                        dev_err(&mdio->dev, "error probing PHY at address %i\n",
                                *addr);
@@ -160,7 +160,7 @@ struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
        struct device_node *net_np;
        char bus_id[MII_BUS_ID_SIZE + 3];
        struct phy_device *phy;
-       const u32 *phy_id;
+       const __be32 *phy_id;
        int sz;
 
        if (!dev->dev.parent)
@@ -174,7 +174,7 @@ struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
        if (!phy_id || sz < sizeof(*phy_id))
                return NULL;
 
-       sprintf(bus_id, PHY_ID_FMT, "0", phy_id[0]);
+       sprintf(bus_id, PHY_ID_FMT, "0", be32_to_cpu(phy_id[0]));
 
        phy = phy_connect(dev, bus_id, hndlr, 0, iface);
        return IS_ERR(phy) ? NULL : phy;
index bed0ed6..f65f48b 100644 (file)
@@ -23,7 +23,7 @@ void of_register_spi_devices(struct spi_master *master, struct device_node *np)
 {
        struct spi_device *spi;
        struct device_node *nc;
-       const u32 *prop;
+       const __be32 *prop;
        int rc;
        int len;
 
@@ -54,7 +54,7 @@ void of_register_spi_devices(struct spi_master *master, struct device_node *np)
                        spi_dev_put(spi);
                        continue;
                }
-               spi->chip_select = *prop;
+               spi->chip_select = be32_to_cpup(prop);
 
                /* Mode (clock phase/polarity/etc.) */
                if (of_find_property(nc, "spi-cpha", NULL))
@@ -72,7 +72,7 @@ void of_register_spi_devices(struct spi_master *master, struct device_node *np)
                        spi_dev_put(spi);
                        continue;
                }
-               spi->max_speed_hz = *prop;
+               spi->max_speed_hz = be32_to_cpup(prop);
 
                /* IRQ */
                spi->irq = irq_of_parse_and_map(nc, 0);
index 8e952fd..cb2fd01 100644 (file)
@@ -720,12 +720,6 @@ static int acpiphp_bus_add(struct acpiphp_func *func)
                        -ret_val);
                goto acpiphp_bus_add_out;
        }
-       /*
-        * try to start anyway.  We could have failed to add
-        * simply because this bus had previously been added
-        * on another add.  Don't bother with the return value
-        * we just keep going.
-        */
        ret_val = acpi_bus_start(device);
 
 acpiphp_bus_add_out:
index 07d14df..226b3e9 100644 (file)
@@ -934,7 +934,7 @@ static int __devinit acer_backlight_init(struct device *dev)
        acer_backlight_device = bd;
 
        bd->props.power = FB_BLANK_UNBLANK;
-       bd->props.brightness = max_brightness;
+       bd->props.brightness = read_brightness(bd);
        bd->props.max_brightness = max_brightness;
        backlight_update_status(bd);
        return 0;
index e67e4fe..eb603f1 100644 (file)
@@ -5771,7 +5771,7 @@ static void thermal_exit(void)
        case TPACPI_THERMAL_ACPI_TMP07:
        case TPACPI_THERMAL_ACPI_UPDT:
                sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj,
-                                  &thermal_temp_input16_group);
+                                  &thermal_temp_input8_group);
                break;
        case TPACPI_THERMAL_NONE:
        default:
index 75ac19b..fc2f676 100644 (file)
@@ -233,7 +233,7 @@ static int opromnext(void __user *argp, unsigned int cmd, struct device_node *dp
 
        ph = 0;
        if (dp)
-               ph = dp->node;
+               ph = dp->phandle;
 
        data->current_node = dp;
        *((int *) op->oprom_array) = ph;
@@ -256,7 +256,7 @@ static int oprompci2node(void __user *argp, struct device_node *dp, struct openp
 
                dp = pci_device_to_OF_node(pdev);
                data->current_node = dp;
-               *((int *)op->oprom_array) = dp->node;
+               *((int *)op->oprom_array) = dp->phandle;
                op->oprom_size = sizeof(int);
                err = copyout(argp, op, bufsize + sizeof(int));
 
@@ -273,7 +273,7 @@ static int oprompath2node(void __user *argp, struct device_node *dp, struct open
 
        dp = of_find_node_by_path(op->oprom_array);
        if (dp)
-               ph = dp->node;
+               ph = dp->phandle;
        data->current_node = dp;
        *((int *)op->oprom_array) = ph;
        op->oprom_size = sizeof(int);
@@ -540,7 +540,7 @@ static int opiocgetnext(unsigned int cmd, void __user *argp)
                }
        }
        if (dp)
-               nd = dp->node;
+               nd = dp->phandle;
        if (copy_to_user(argp, &nd, sizeof(phandle)))
                return -EFAULT;
 
@@ -570,7 +570,7 @@ static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
        case OPIOCGETOPTNODE:
                BUILD_BUG_ON(sizeof(phandle) != sizeof(int));
 
-               if (copy_to_user(argp, &options_node->node, sizeof(phandle)))
+               if (copy_to_user(argp, &options_node->phandle, sizeof(phandle)))
                        return -EFAULT;
 
                return 0;
index 4775426..9e71ac6 100644 (file)
@@ -2516,7 +2516,7 @@ int fas216_eh_device_reset(struct scsi_cmnd *SCpnt)
                if (info->scsi.phase == PHASE_IDLE)
                        fas216_kick(info);
 
-               mod_timer(&info->eh_timer, 30 * HZ);
+               mod_timer(&info->eh_timer, jiffies + 30 * HZ);
                spin_unlock_irqrestore(&info->host_lock, flags);
 
                /*
index 10be9f3..2f47ae7 100644 (file)
@@ -2009,6 +2009,8 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp)
        fcoe_interface_cleanup(fcoe);
        rtnl_unlock();
        fcoe_if_destroy(fcoe->ctlr.lp);
+       module_put(THIS_MODULE);
+
 out_putdev:
        dev_put(netdev);
 out_nodev:
@@ -2059,6 +2061,11 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)
        }
 #endif
 
+       if (!try_module_get(THIS_MODULE)) {
+               rc = -EINVAL;
+               goto out_nomod;
+       }
+
        rtnl_lock();
        netdev = fcoe_if_to_netdev(buffer);
        if (!netdev) {
@@ -2099,17 +2106,24 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)
        if (!fcoe_link_ok(lport))
                fcoe_ctlr_link_up(&fcoe->ctlr);
 
-       rc = 0;
-out_free:
        /*
         * Release from init in fcoe_interface_create(), on success lport
         * should be holding a reference taken in fcoe_if_create().
         */
        fcoe_interface_put(fcoe);
+       dev_put(netdev);
+       rtnl_unlock();
+       mutex_unlock(&fcoe_config_mutex);
+
+       return 0;
+out_free:
+       fcoe_interface_put(fcoe);
 out_putdev:
        dev_put(netdev);
 out_nodev:
        rtnl_unlock();
+       module_put(THIS_MODULE);
+out_nomod:
        mutex_unlock(&fcoe_config_mutex);
        return rc;
 }
index 9823291..511cb6b 100644 (file)
@@ -1187,7 +1187,7 @@ static void fcoe_ctlr_timeout(unsigned long arg)
                        next_timer = fip->ctlr_ka_time;
 
                if (time_after_eq(jiffies, fip->port_ka_time)) {
-                       fip->port_ka_time += jiffies +
+                       fip->port_ka_time = jiffies +
                                msecs_to_jiffies(FIP_VN_KA_PERIOD);
                        fip->send_port_ka = 1;
                }
index 19d711c..7f43647 100644 (file)
@@ -1890,7 +1890,7 @@ static struct fc_seq *fc_exch_seq_send(struct fc_lport *lport,
        fc_exch_setup_hdr(ep, fp, ep->f_ctl);
        sp->cnt++;
 
-       if (ep->xid <= lport->lro_xid)
+       if (ep->xid <= lport->lro_xid && fh->fh_r_ctl == FC_RCTL_DD_UNSOL_CMD)
                fc_fcp_ddp_setup(fr_fsp(fp), ep->xid);
 
        if (unlikely(lport->tt.frame_send(lport, fp)))
index 881d5df..6fde2fa 100644 (file)
@@ -298,9 +298,6 @@ void fc_fcp_ddp_setup(struct fc_fcp_pkt *fsp, u16 xid)
 {
        struct fc_lport *lport;
 
-       if (!fsp)
-               return;
-
        lport = fsp->lp;
        if ((fsp->req_flags & FC_SRB_READ) &&
            (lport->lro_enabled) && (lport->tt.ddp_setup)) {
index 0b16502..7ec8ce7 100644 (file)
@@ -1800,7 +1800,8 @@ int fc_lport_bsg_request(struct fc_bsg_job *job)
        u32 did;
 
        job->reply->reply_payload_rcv_len = 0;
-       rsp->resid_len = job->reply_payload.payload_len;
+       if (rsp)
+               rsp->resid_len = job->reply_payload.payload_len;
 
        mutex_lock(&lport->lp_mutex);
 
index 0230052..97923bb 100644 (file)
@@ -623,7 +623,7 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,
 
                tov = ntohl(plp->fl_csp.sp_e_d_tov);
                if (ntohs(plp->fl_csp.sp_features) & FC_SP_FT_EDTR)
-                       tov /= 1000;
+                       tov /= 1000000;
                if (tov > rdata->e_d_tov)
                        rdata->e_d_tov = tov;
                csp_seq = ntohs(plp->fl_csp.sp_tot_seq);
index db6856c..4ad87fd 100644 (file)
@@ -992,12 +992,10 @@ static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task)
                if (r2t == NULL) {
                        if (kfifo_out(&tcp_task->r2tqueue,
                            (void *)&tcp_task->r2t, sizeof(void *)) !=
-                           sizeof(void *)) {
-                               WARN_ONCE(1, "unexpected fifo state");
+                           sizeof(void *))
                                r2t = NULL;
-                       }
-
-                       r2t = tcp_task->r2t;
+                       else
+                               r2t = tcp_task->r2t;
                }
                spin_unlock_bh(&session->lock);
        }
index 708ea31..d9b8ca5 100644 (file)
@@ -3781,6 +3781,7 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
            compat_alloc_user_space(sizeof(struct megasas_iocpacket));
        int i;
        int error = 0;
+       compat_uptr_t ptr;
 
        if (clear_user(ioc, sizeof(*ioc)))
                return -EFAULT;
@@ -3793,9 +3794,22 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
            copy_in_user(&ioc->sge_count, &cioc->sge_count, sizeof(u32)))
                return -EFAULT;
 
-       for (i = 0; i < MAX_IOCTL_SGE; i++) {
-               compat_uptr_t ptr;
+       /*
+        * The sense_ptr is used in megasas_mgmt_fw_ioctl only when
+        * sense_len is not null, so prepare the 64bit value under
+        * the same condition.
+        */
+       if (ioc->sense_len) {
+               void __user **sense_ioc_ptr =
+                       (void __user **)(ioc->frame.raw + ioc->sense_off);
+               compat_uptr_t *sense_cioc_ptr =
+                       (compat_uptr_t *)(cioc->frame.raw + cioc->sense_off);
+               if (get_user(ptr, sense_cioc_ptr) ||
+                   put_user(compat_ptr(ptr), sense_ioc_ptr))
+                       return -EFAULT;
+       }
 
+       for (i = 0; i < MAX_IOCTL_SGE; i++) {
                if (get_user(ptr, &cioc->sgl[i].iov_base) ||
                    put_user(compat_ptr(ptr), &ioc->sgl[i].iov_base) ||
                    copy_in_user(&ioc->sgl[i].iov_len,
index c3e37c8..e9b15c3 100644 (file)
@@ -83,6 +83,9 @@ static unsigned int skip_txen_test; /* force skip of txen test at init time */
 
 #define PASS_LIMIT     256
 
+#define BOTH_EMPTY     (UART_LSR_TEMT | UART_LSR_THRE)
+
+
 /*
  * We default to IRQ0 for the "no irq" hack.   Some
  * machine types want others as well - they're free
@@ -1792,7 +1795,7 @@ static unsigned int serial8250_tx_empty(struct uart_port *port)
        up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
        spin_unlock_irqrestore(&up->port.lock, flags);
 
-       return lsr & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+       return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0;
 }
 
 static unsigned int serial8250_get_mctrl(struct uart_port *port)
@@ -1850,8 +1853,6 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state)
        spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
-#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
-
 /*
  *     Wait for transmitter & holding register to empty
  */
index 683e66f..3e2ae48 100644 (file)
@@ -2031,9 +2031,9 @@ static int __init pmz_console_setup(struct console *co, char *options)
        /*
         * XServe's default to 57600 bps
         */
-       if (machine_is_compatible("RackMac1,1")
-           || machine_is_compatible("RackMac1,2")
-           || machine_is_compatible("MacRISC4"))
+       if (of_machine_is_compatible("RackMac1,1")
+           || of_machine_is_compatible("RackMac1,2")
+           || of_machine_is_compatible("MacRISC4"))
                baud = 57600;
 
        /*
index f55eb01..0fee95c 100644 (file)
@@ -100,6 +100,23 @@ config SPI_BUTTERFLY
          inexpensive battery powered microcontroller evaluation board.
          This same cable can be used to flash new firmware.
 
+config SPI_COLDFIRE_QSPI
+       tristate "Freescale Coldfire QSPI controller"
+       depends on (M520x || M523x || M5249 || M527x || M528x || M532x)
+       help
+         This enables support for the Coldfire QSPI controller in master
+         mode.
+
+         This driver can also be built as a module.  If so, the module
+         will be called coldfire_qspi.
+
+config SPI_DAVINCI
+       tristate "SPI controller driver for DaVinci/DA8xx SoC's"
+       depends on SPI_MASTER && ARCH_DAVINCI
+       select SPI_BITBANG
+       help
+         SPI master controller for DaVinci and DA8xx SPI modules.
+
 config SPI_GPIO
        tristate "GPIO-based bitbanging SPI Master"
        depends on GENERIC_GPIO
@@ -308,7 +325,7 @@ config SPI_NUC900
 #
 
 config SPI_DESIGNWARE
-       bool "DesignWare SPI controller core support"
+       tristate "DesignWare SPI controller core support"
        depends on SPI_MASTER
        help
          general driver for SPI controller core from DesignWare
@@ -317,6 +334,10 @@ config SPI_DW_PCI
        tristate "PCI interface driver for DW SPI core"
        depends on SPI_DESIGNWARE && PCI
 
+config SPI_DW_MMIO
+       tristate "Memory-mapped io interface driver for DW SPI core"
+       depends on SPI_DESIGNWARE && HAVE_CLK
+
 #
 # There are lots of SPI device types, with sensors and memory
 # being probably the most widely used ones.
index f3d2810..d7d0f89 100644 (file)
@@ -16,8 +16,11 @@ obj-$(CONFIG_SPI_BFIN)                       += spi_bfin5xx.o
 obj-$(CONFIG_SPI_BITBANG)              += spi_bitbang.o
 obj-$(CONFIG_SPI_AU1550)               += au1550_spi.o
 obj-$(CONFIG_SPI_BUTTERFLY)            += spi_butterfly.o
+obj-$(CONFIG_SPI_COLDFIRE_QSPI)                += coldfire_qspi.o
+obj-$(CONFIG_SPI_DAVINCI)              += davinci_spi.o
 obj-$(CONFIG_SPI_DESIGNWARE)           += dw_spi.o
 obj-$(CONFIG_SPI_DW_PCI)               += dw_spi_pci.o
+obj-$(CONFIG_SPI_DW_MMIO)              += dw_spi_mmio.o
 obj-$(CONFIG_SPI_GPIO)                 += spi_gpio.o
 obj-$(CONFIG_SPI_IMX)                  += spi_imx.o
 obj-$(CONFIG_SPI_LM70_LLP)             += spi_lm70llp.o
diff --git a/drivers/spi/coldfire_qspi.c b/drivers/spi/coldfire_qspi.c
new file mode 100644 (file)
index 0000000..59be3ef
--- /dev/null
@@ -0,0 +1,640 @@
+/*
+ * Freescale/Motorola Coldfire Queued SPI driver
+ *
+ * Copyright 2010 Steven King <sfking@fdwdc.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., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
+ *
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/spi/spi.h>
+
+#include <asm/coldfire.h>
+#include <asm/mcfqspi.h>
+
+#define        DRIVER_NAME "mcfqspi"
+
+#define        MCFQSPI_BUSCLK                  (MCF_BUSCLK / 2)
+
+#define        MCFQSPI_QMR                     0x00
+#define                MCFQSPI_QMR_MSTR        0x8000
+#define                MCFQSPI_QMR_CPOL        0x0200
+#define                MCFQSPI_QMR_CPHA        0x0100
+#define        MCFQSPI_QDLYR                   0x04
+#define                MCFQSPI_QDLYR_SPE       0x8000
+#define        MCFQSPI_QWR                     0x08
+#define                MCFQSPI_QWR_HALT        0x8000
+#define                MCFQSPI_QWR_WREN        0x4000
+#define                MCFQSPI_QWR_CSIV        0x1000
+#define        MCFQSPI_QIR                     0x0C
+#define                MCFQSPI_QIR_WCEFB       0x8000
+#define                MCFQSPI_QIR_ABRTB       0x4000
+#define                MCFQSPI_QIR_ABRTL       0x1000
+#define                MCFQSPI_QIR_WCEFE       0x0800
+#define                MCFQSPI_QIR_ABRTE       0x0400
+#define                MCFQSPI_QIR_SPIFE       0x0100
+#define                MCFQSPI_QIR_WCEF        0x0008
+#define                MCFQSPI_QIR_ABRT        0x0004
+#define                MCFQSPI_QIR_SPIF        0x0001
+#define        MCFQSPI_QAR                     0x010
+#define                MCFQSPI_QAR_TXBUF       0x00
+#define                MCFQSPI_QAR_RXBUF       0x10
+#define                MCFQSPI_QAR_CMDBUF      0x20
+#define        MCFQSPI_QDR                     0x014
+#define        MCFQSPI_QCR                     0x014
+#define                MCFQSPI_QCR_CONT        0x8000
+#define                MCFQSPI_QCR_BITSE       0x4000
+#define                MCFQSPI_QCR_DT          0x2000
+
+struct mcfqspi {
+       void __iomem *iobase;
+       int irq;
+       struct clk *clk;
+       struct mcfqspi_cs_control *cs_control;
+
+       wait_queue_head_t waitq;
+
+       struct work_struct work;
+       struct workqueue_struct *workq;
+       spinlock_t lock;
+       struct list_head msgq;
+};
+
+static void mcfqspi_wr_qmr(struct mcfqspi *mcfqspi, u16 val)
+{
+       writew(val, mcfqspi->iobase + MCFQSPI_QMR);
+}
+
+static void mcfqspi_wr_qdlyr(struct mcfqspi *mcfqspi, u16 val)
+{
+       writew(val, mcfqspi->iobase + MCFQSPI_QDLYR);
+}
+
+static u16 mcfqspi_rd_qdlyr(struct mcfqspi *mcfqspi)
+{
+       return readw(mcfqspi->iobase + MCFQSPI_QDLYR);
+}
+
+static void mcfqspi_wr_qwr(struct mcfqspi *mcfqspi, u16 val)
+{
+       writew(val, mcfqspi->iobase + MCFQSPI_QWR);
+}
+
+static void mcfqspi_wr_qir(struct mcfqspi *mcfqspi, u16 val)
+{
+       writew(val, mcfqspi->iobase + MCFQSPI_QIR);
+}
+
+static void mcfqspi_wr_qar(struct mcfqspi *mcfqspi, u16 val)
+{
+       writew(val, mcfqspi->iobase + MCFQSPI_QAR);
+}
+
+static void mcfqspi_wr_qdr(struct mcfqspi *mcfqspi, u16 val)
+{
+       writew(val, mcfqspi->iobase + MCFQSPI_QDR);
+}
+
+static u16 mcfqspi_rd_qdr(struct mcfqspi *mcfqspi)
+{
+       return readw(mcfqspi->iobase + MCFQSPI_QDR);
+}
+
+static void mcfqspi_cs_select(struct mcfqspi *mcfqspi, u8 chip_select,
+                           bool cs_high)
+{
+       mcfqspi->cs_control->select(mcfqspi->cs_control, chip_select, cs_high);
+}
+
+static void mcfqspi_cs_deselect(struct mcfqspi *mcfqspi, u8 chip_select,
+                               bool cs_high)
+{
+       mcfqspi->cs_control->deselect(mcfqspi->cs_control, chip_select, cs_high);
+}
+
+static int mcfqspi_cs_setup(struct mcfqspi *mcfqspi)
+{
+       return (mcfqspi->cs_control && mcfqspi->cs_control->setup) ?
+               mcfqspi->cs_control->setup(mcfqspi->cs_control) : 0;
+}
+
+static void mcfqspi_cs_teardown(struct mcfqspi *mcfqspi)
+{
+       if (mcfqspi->cs_control && mcfqspi->cs_control->teardown)
+               mcfqspi->cs_control->teardown(mcfqspi->cs_control);
+}
+
+static u8 mcfqspi_qmr_baud(u32 speed_hz)
+{
+       return clamp((MCFQSPI_BUSCLK + speed_hz - 1) / speed_hz, 2u, 255u);
+}
+
+static bool mcfqspi_qdlyr_spe(struct mcfqspi *mcfqspi)
+{
+       return mcfqspi_rd_qdlyr(mcfqspi) & MCFQSPI_QDLYR_SPE;
+}
+
+static irqreturn_t mcfqspi_irq_handler(int this_irq, void *dev_id)
+{
+       struct mcfqspi *mcfqspi = dev_id;
+
+       /* clear interrupt */
+       mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE | MCFQSPI_QIR_SPIF);
+       wake_up(&mcfqspi->waitq);
+
+       return IRQ_HANDLED;
+}
+
+static void mcfqspi_transfer_msg8(struct mcfqspi *mcfqspi, unsigned count,
+                                 const u8 *txbuf, u8 *rxbuf)
+{
+       unsigned i, n, offset = 0;
+
+       n = min(count, 16u);
+
+       mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_CMDBUF);
+       for (i = 0; i < n; ++i)
+               mcfqspi_wr_qdr(mcfqspi, MCFQSPI_QCR_BITSE);
+
+       mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_TXBUF);
+       if (txbuf)
+               for (i = 0; i < n; ++i)
+                       mcfqspi_wr_qdr(mcfqspi, *txbuf++);
+       else
+               for (i = 0; i < count; ++i)
+                       mcfqspi_wr_qdr(mcfqspi, 0);
+
+       count -= n;
+       if (count) {
+               u16 qwr = 0xf08;
+               mcfqspi_wr_qwr(mcfqspi, 0x700);
+               mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
+
+               do {
+                       wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));
+                       mcfqspi_wr_qwr(mcfqspi, qwr);
+                       mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
+                       if (rxbuf) {
+                               mcfqspi_wr_qar(mcfqspi,
+                                              MCFQSPI_QAR_RXBUF + offset);
+                               for (i = 0; i < 8; ++i)
+                                       *rxbuf++ = mcfqspi_rd_qdr(mcfqspi);
+                       }
+                       n = min(count, 8u);
+                       if (txbuf) {
+                               mcfqspi_wr_qar(mcfqspi,
+                                              MCFQSPI_QAR_TXBUF + offset);
+                               for (i = 0; i < n; ++i)
+                                       mcfqspi_wr_qdr(mcfqspi, *txbuf++);
+                       }
+                       qwr = (offset ? 0x808 : 0) + ((n - 1) << 8);
+                       offset ^= 8;
+                       count -= n;
+               } while (count);
+               wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));
+               mcfqspi_wr_qwr(mcfqspi, qwr);
+               mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
+               if (rxbuf) {
+                       mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset);
+                       for (i = 0; i < 8; ++i)
+                               *rxbuf++ = mcfqspi_rd_qdr(mcfqspi);
+                       offset ^= 8;
+               }
+       } else {
+               mcfqspi_wr_qwr(mcfqspi, (n - 1) << 8);
+               mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
+       }
+       wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));
+       if (rxbuf) {
+               mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset);
+               for (i = 0; i < n; ++i)
+                       *rxbuf++ = mcfqspi_rd_qdr(mcfqspi);
+       }
+}
+
+static void mcfqspi_transfer_msg16(struct mcfqspi *mcfqspi, unsigned count,
+                                  const u16 *txbuf, u16 *rxbuf)
+{
+       unsigned i, n, offset = 0;
+
+       n = min(count, 16u);
+
+       mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_CMDBUF);
+       for (i = 0; i < n; ++i)
+               mcfqspi_wr_qdr(mcfqspi, MCFQSPI_QCR_BITSE);
+
+       mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_TXBUF);
+       if (txbuf)
+               for (i = 0; i < n; ++i)
+                       mcfqspi_wr_qdr(mcfqspi, *txbuf++);
+       else
+               for (i = 0; i < count; ++i)
+                       mcfqspi_wr_qdr(mcfqspi, 0);
+
+       count -= n;
+       if (count) {
+               u16 qwr = 0xf08;
+               mcfqspi_wr_qwr(mcfqspi, 0x700);
+               mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
+
+               do {
+                       wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));
+                       mcfqspi_wr_qwr(mcfqspi, qwr);
+                       mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
+                       if (rxbuf) {
+                               mcfqspi_wr_qar(mcfqspi,
+                                              MCFQSPI_QAR_RXBUF + offset);
+                               for (i = 0; i < 8; ++i)
+                                       *rxbuf++ = mcfqspi_rd_qdr(mcfqspi);
+                       }
+                       n = min(count, 8u);
+                       if (txbuf) {
+                               mcfqspi_wr_qar(mcfqspi,
+                                              MCFQSPI_QAR_TXBUF + offset);
+                               for (i = 0; i < n; ++i)
+                                       mcfqspi_wr_qdr(mcfqspi, *txbuf++);
+                       }
+                       qwr = (offset ? 0x808 : 0x000) + ((n - 1) << 8);
+                       offset ^= 8;
+                       count -= n;
+               } while (count);
+               wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));
+               mcfqspi_wr_qwr(mcfqspi, qwr);
+               mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
+               if (rxbuf) {
+                       mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset);
+                       for (i = 0; i < 8; ++i)
+                               *rxbuf++ = mcfqspi_rd_qdr(mcfqspi);
+                       offset ^= 8;
+               }
+       } else {
+               mcfqspi_wr_qwr(mcfqspi, (n - 1) << 8);
+               mcfqspi_wr_qdlyr(mcfqspi, MCFQSPI_QDLYR_SPE);
+       }
+       wait_event(mcfqspi->waitq, !mcfqspi_qdlyr_spe(mcfqspi));
+       if (rxbuf) {
+               mcfqspi_wr_qar(mcfqspi, MCFQSPI_QAR_RXBUF + offset);
+               for (i = 0; i < n; ++i)
+                       *rxbuf++ = mcfqspi_rd_qdr(mcfqspi);
+       }
+}
+
+static void mcfqspi_work(struct work_struct *work)
+{
+       struct mcfqspi *mcfqspi = container_of(work, struct mcfqspi, work);
+       unsigned long flags;
+
+       spin_lock_irqsave(&mcfqspi->lock, flags);
+       while (!list_empty(&mcfqspi->msgq)) {
+               struct spi_message *msg;
+               struct spi_device *spi;
+               struct spi_transfer *xfer;
+               int status = 0;
+
+               msg = container_of(mcfqspi->msgq.next, struct spi_message,
+                                  queue);
+
+               list_del_init(&mcfqspi->msgq);
+               spin_unlock_irqrestore(&mcfqspi->lock, flags);
+
+               spi = msg->spi;
+
+               list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+                       bool cs_high = spi->mode & SPI_CS_HIGH;
+                       u16 qmr = MCFQSPI_QMR_MSTR;
+
+                       if (xfer->bits_per_word)
+                               qmr |= xfer->bits_per_word << 10;
+                       else
+                               qmr |= spi->bits_per_word << 10;
+                       if (spi->mode & SPI_CPHA)
+                               qmr |= MCFQSPI_QMR_CPHA;
+                       if (spi->mode & SPI_CPOL)
+                               qmr |= MCFQSPI_QMR_CPOL;
+                       if (xfer->speed_hz)
+                               qmr |= mcfqspi_qmr_baud(xfer->speed_hz);
+                       else
+                               qmr |= mcfqspi_qmr_baud(spi->max_speed_hz);
+                       mcfqspi_wr_qmr(mcfqspi, qmr);
+
+                       mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high);
+
+                       mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);
+                       if ((xfer->bits_per_word ? xfer->bits_per_word :
+                                               spi->bits_per_word) == 8)
+                               mcfqspi_transfer_msg8(mcfqspi, xfer->len,
+                                                     xfer->tx_buf,
+                                                     xfer->rx_buf);
+                       else
+                               mcfqspi_transfer_msg16(mcfqspi, xfer->len / 2,
+                                                      xfer->tx_buf,
+                                                      xfer->rx_buf);
+                       mcfqspi_wr_qir(mcfqspi, 0);
+
+                       if (xfer->delay_usecs)
+                               udelay(xfer->delay_usecs);
+                       if (xfer->cs_change) {
+                               if (!list_is_last(&xfer->transfer_list,
+                                                 &msg->transfers))
+                                       mcfqspi_cs_deselect(mcfqspi,
+                                                           spi->chip_select,
+                                                           cs_high);
+                       } else {
+                               if (list_is_last(&xfer->transfer_list,
+                                                &msg->transfers))
+                                       mcfqspi_cs_deselect(mcfqspi,
+                                                           spi->chip_select,
+                                                           cs_high);
+                       }
+                       msg->actual_length += xfer->len;
+               }
+               msg->status = status;
+               msg->complete(msg->context);
+
+               spin_lock_irqsave(&mcfqspi->lock, flags);
+       }
+       spin_unlock_irqrestore(&mcfqspi->lock, flags);
+}
+
+static int mcfqspi_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+       struct mcfqspi *mcfqspi;
+       struct spi_transfer *xfer;
+       unsigned long flags;
+
+       mcfqspi = spi_master_get_devdata(spi->master);
+
+       list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+               if (xfer->bits_per_word && ((xfer->bits_per_word < 8)
+                                       || (xfer->bits_per_word > 16))) {
+                       dev_dbg(&spi->dev,
+                               "%d bits per word is not supported\n",
+                               xfer->bits_per_word);
+                       goto fail;
+               }
+               if (xfer->speed_hz) {
+                       u32 real_speed = MCFQSPI_BUSCLK /
+                               mcfqspi_qmr_baud(xfer->speed_hz);
+                       if (real_speed != xfer->speed_hz)
+                               dev_dbg(&spi->dev,
+                                       "using speed %d instead of %d\n",
+                                       real_speed, xfer->speed_hz);
+               }
+       }
+       msg->status = -EINPROGRESS;
+       msg->actual_length = 0;
+
+       spin_lock_irqsave(&mcfqspi->lock, flags);
+       list_add_tail(&msg->queue, &mcfqspi->msgq);
+       queue_work(mcfqspi->workq, &mcfqspi->work);
+       spin_unlock_irqrestore(&mcfqspi->lock, flags);
+
+       return 0;
+fail:
+       msg->status = -EINVAL;
+       return -EINVAL;
+}
+
+static int mcfqspi_setup(struct spi_device *spi)
+{
+       if ((spi->bits_per_word < 8) || (spi->bits_per_word > 16)) {
+               dev_dbg(&spi->dev, "%d bits per word is not supported\n",
+                       spi->bits_per_word);
+               return -EINVAL;
+       }
+       if (spi->chip_select >= spi->master->num_chipselect) {
+               dev_dbg(&spi->dev, "%d chip select is out of range\n",
+                       spi->chip_select);
+               return -EINVAL;
+       }
+
+       mcfqspi_cs_deselect(spi_master_get_devdata(spi->master),
+                           spi->chip_select, spi->mode & SPI_CS_HIGH);
+
+       dev_dbg(&spi->dev,
+                       "bits per word %d, chip select %d, speed %d KHz\n",
+                       spi->bits_per_word, spi->chip_select,
+                       (MCFQSPI_BUSCLK / mcfqspi_qmr_baud(spi->max_speed_hz))
+                       / 1000);
+
+       return 0;
+}
+
+static int __devinit mcfqspi_probe(struct platform_device *pdev)
+{
+       struct spi_master *master;
+       struct mcfqspi *mcfqspi;
+       struct resource *res;
+       struct mcfqspi_platform_data *pdata;
+       int status;
+
+       master = spi_alloc_master(&pdev->dev, sizeof(*mcfqspi));
+       if (master == NULL) {
+               dev_dbg(&pdev->dev, "spi_alloc_master failed\n");
+               return -ENOMEM;
+       }
+
+       mcfqspi = spi_master_get_devdata(master);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_dbg(&pdev->dev, "platform_get_resource failed\n");
+               status = -ENXIO;
+               goto fail0;
+       }
+
+       if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+               dev_dbg(&pdev->dev, "request_mem_region failed\n");
+               status = -EBUSY;
+               goto fail0;
+       }
+
+       mcfqspi->iobase = ioremap(res->start, resource_size(res));
+       if (!mcfqspi->iobase) {
+               dev_dbg(&pdev->dev, "ioremap failed\n");
+               status = -ENOMEM;
+               goto fail1;
+       }
+
+       mcfqspi->irq = platform_get_irq(pdev, 0);
+       if (mcfqspi->irq < 0) {
+               dev_dbg(&pdev->dev, "platform_get_irq failed\n");
+               status = -ENXIO;
+               goto fail2;
+       }
+
+       status = request_irq(mcfqspi->irq, mcfqspi_irq_handler, IRQF_DISABLED,
+                            pdev->name, mcfqspi);
+       if (status) {
+               dev_dbg(&pdev->dev, "request_irq failed\n");
+               goto fail2;
+       }
+
+       mcfqspi->clk = clk_get(&pdev->dev, "qspi_clk");
+       if (IS_ERR(mcfqspi->clk)) {
+               dev_dbg(&pdev->dev, "clk_get failed\n");
+               status = PTR_ERR(mcfqspi->clk);
+               goto fail3;
+       }
+       clk_enable(mcfqspi->clk);
+
+       mcfqspi->workq = create_singlethread_workqueue(dev_name(master->dev.parent));
+       if (!mcfqspi->workq) {
+               dev_dbg(&pdev->dev, "create_workqueue failed\n");
+               status = -ENOMEM;
+               goto fail4;
+       }
+       INIT_WORK(&mcfqspi->work, mcfqspi_work);
+       spin_lock_init(&mcfqspi->lock);
+       INIT_LIST_HEAD(&mcfqspi->msgq);
+       init_waitqueue_head(&mcfqspi->waitq);
+
+       pdata = pdev->dev.platform_data;
+       if (!pdata) {
+               dev_dbg(&pdev->dev, "platform data is missing\n");
+               goto fail5;
+       }
+       master->bus_num = pdata->bus_num;
+       master->num_chipselect = pdata->num_chipselect;
+
+       mcfqspi->cs_control = pdata->cs_control;
+       status = mcfqspi_cs_setup(mcfqspi);
+       if (status) {
+               dev_dbg(&pdev->dev, "error initializing cs_control\n");
+               goto fail5;
+       }
+
+       master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
+       master->setup = mcfqspi_setup;
+       master->transfer = mcfqspi_transfer;
+
+       platform_set_drvdata(pdev, master);
+
+       status = spi_register_master(master);
+       if (status) {
+               dev_dbg(&pdev->dev, "spi_register_master failed\n");
+               goto fail6;
+       }
+       dev_info(&pdev->dev, "Coldfire QSPI bus driver\n");
+
+       return 0;
+
+fail6:
+       mcfqspi_cs_teardown(mcfqspi);
+fail5:
+       destroy_workqueue(mcfqspi->workq);
+fail4:
+       clk_disable(mcfqspi->clk);
+       clk_put(mcfqspi->clk);
+fail3:
+       free_irq(mcfqspi->irq, mcfqspi);
+fail2:
+       iounmap(mcfqspi->iobase);
+fail1:
+       release_mem_region(res->start, resource_size(res));
+fail0:
+       spi_master_put(master);
+
+       dev_dbg(&pdev->dev, "Coldfire QSPI probe failed\n");
+
+       return status;
+}
+
+static int __devexit mcfqspi_remove(struct platform_device *pdev)
+{
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       /* disable the hardware (set the baud rate to 0) */
+       mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR);
+
+       platform_set_drvdata(pdev, NULL);
+       mcfqspi_cs_teardown(mcfqspi);
+       destroy_workqueue(mcfqspi->workq);
+       clk_disable(mcfqspi->clk);
+       clk_put(mcfqspi->clk);
+       free_irq(mcfqspi->irq, mcfqspi);
+       iounmap(mcfqspi->iobase);
+       release_mem_region(res->start, resource_size(res));
+       spi_unregister_master(master);
+       spi_master_put(master);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int mcfqspi_suspend(struct device *dev)
+{
+       struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev));
+
+       clk_disable(mcfqspi->clk);
+
+       return 0;
+}
+
+static int mcfqspi_resume(struct device *dev)
+{
+       struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev));
+
+       clk_enable(mcfqspi->clk);
+
+       return 0;
+}
+
+static struct dev_pm_ops mcfqspi_dev_pm_ops = {
+       .suspend        = mcfqspi_suspend,
+       .resume         = mcfqspi_resume,
+};
+
+#define        MCFQSPI_DEV_PM_OPS      (&mcfqspi_dev_pm_ops)
+#else
+#define        MCFQSPI_DEV_PM_OPS      NULL
+#endif
+
+static struct platform_driver mcfqspi_driver = {
+       .driver.name    = DRIVER_NAME,
+       .driver.owner   = THIS_MODULE,
+       .driver.pm      = MCFQSPI_DEV_PM_OPS,
+       .remove         = __devexit_p(mcfqspi_remove),
+};
+
+static int __init mcfqspi_init(void)
+{
+       return platform_driver_probe(&mcfqspi_driver, mcfqspi_probe);
+}
+module_init(mcfqspi_init);
+
+static void __exit mcfqspi_exit(void)
+{
+       platform_driver_unregister(&mcfqspi_driver);
+}
+module_exit(mcfqspi_exit);
+
+MODULE_AUTHOR("Steven King <sfking@fdwdc.com>");
+MODULE_DESCRIPTION("Coldfire QSPI Controller Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c
new file mode 100644 (file)
index 0000000..225ab60
--- /dev/null
@@ -0,0 +1,1255 @@
+/*
+ * Copyright (C) 2009 Texas Instruments.
+ *
+ * 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/interrupt.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include <mach/spi.h>
+#include <mach/edma.h>
+
+#define SPI_NO_RESOURCE                ((resource_size_t)-1)
+
+#define SPI_MAX_CHIPSELECT     2
+
+#define CS_DEFAULT     0xFF
+
+#define SPI_BUFSIZ     (SMP_CACHE_BYTES + 1)
+#define DAVINCI_DMA_DATA_TYPE_S8       0x01
+#define DAVINCI_DMA_DATA_TYPE_S16      0x02
+#define DAVINCI_DMA_DATA_TYPE_S32      0x04
+
+#define SPIFMT_PHASE_MASK      BIT(16)
+#define SPIFMT_POLARITY_MASK   BIT(17)
+#define SPIFMT_DISTIMER_MASK   BIT(18)
+#define SPIFMT_SHIFTDIR_MASK   BIT(20)
+#define SPIFMT_WAITENA_MASK    BIT(21)
+#define SPIFMT_PARITYENA_MASK  BIT(22)
+#define SPIFMT_ODD_PARITY_MASK BIT(23)
+#define SPIFMT_WDELAY_MASK     0x3f000000u
+#define SPIFMT_WDELAY_SHIFT    24
+#define SPIFMT_CHARLEN_MASK    0x0000001Fu
+
+/* SPIGCR1 */
+#define SPIGCR1_SPIENA_MASK    0x01000000u
+
+/* SPIPC0 */
+#define SPIPC0_DIFUN_MASK      BIT(11)         /* MISO */
+#define SPIPC0_DOFUN_MASK      BIT(10)         /* MOSI */
+#define SPIPC0_CLKFUN_MASK     BIT(9)          /* CLK */
+#define SPIPC0_SPIENA_MASK     BIT(8)          /* nREADY */
+#define SPIPC0_EN1FUN_MASK     BIT(1)
+#define SPIPC0_EN0FUN_MASK     BIT(0)
+
+#define SPIINT_MASKALL         0x0101035F
+#define SPI_INTLVL_1           0x000001FFu
+#define SPI_INTLVL_0           0x00000000u
+
+/* SPIDAT1 */
+#define SPIDAT1_CSHOLD_SHIFT   28
+#define SPIDAT1_CSNR_SHIFT     16
+#define SPIGCR1_CLKMOD_MASK    BIT(1)
+#define SPIGCR1_MASTER_MASK     BIT(0)
+#define SPIGCR1_LOOPBACK_MASK  BIT(16)
+
+/* SPIBUF */
+#define SPIBUF_TXFULL_MASK     BIT(29)
+#define SPIBUF_RXEMPTY_MASK    BIT(31)
+
+/* Error Masks */
+#define SPIFLG_DLEN_ERR_MASK           BIT(0)
+#define SPIFLG_TIMEOUT_MASK            BIT(1)
+#define SPIFLG_PARERR_MASK             BIT(2)
+#define SPIFLG_DESYNC_MASK             BIT(3)
+#define SPIFLG_BITERR_MASK             BIT(4)
+#define SPIFLG_OVRRUN_MASK             BIT(6)
+#define SPIFLG_RX_INTR_MASK            BIT(8)
+#define SPIFLG_TX_INTR_MASK            BIT(9)
+#define SPIFLG_BUF_INIT_ACTIVE_MASK    BIT(24)
+#define SPIFLG_MASK                    (SPIFLG_DLEN_ERR_MASK \
+                               | SPIFLG_TIMEOUT_MASK | SPIFLG_PARERR_MASK \
+                               | SPIFLG_DESYNC_MASK | SPIFLG_BITERR_MASK \
+                               | SPIFLG_OVRRUN_MASK | SPIFLG_RX_INTR_MASK \
+                               | SPIFLG_TX_INTR_MASK \
+                               | SPIFLG_BUF_INIT_ACTIVE_MASK)
+
+#define SPIINT_DLEN_ERR_INTR   BIT(0)
+#define SPIINT_TIMEOUT_INTR    BIT(1)
+#define SPIINT_PARERR_INTR     BIT(2)
+#define SPIINT_DESYNC_INTR     BIT(3)
+#define SPIINT_BITERR_INTR     BIT(4)
+#define SPIINT_OVRRUN_INTR     BIT(6)
+#define SPIINT_RX_INTR         BIT(8)
+#define SPIINT_TX_INTR         BIT(9)
+#define SPIINT_DMA_REQ_EN      BIT(16)
+#define SPIINT_ENABLE_HIGHZ    BIT(24)
+
+#define SPI_T2CDELAY_SHIFT     16
+#define SPI_C2TDELAY_SHIFT     24
+
+/* SPI Controller registers */
+#define SPIGCR0                0x00
+#define SPIGCR1                0x04
+#define SPIINT         0x08
+#define SPILVL         0x0c
+#define SPIFLG         0x10
+#define SPIPC0         0x14
+#define SPIPC1         0x18
+#define SPIPC2         0x1c
+#define SPIPC3         0x20
+#define SPIPC4         0x24
+#define SPIPC5         0x28
+#define SPIPC6         0x2c
+#define SPIPC7         0x30
+#define SPIPC8         0x34
+#define SPIDAT0                0x38
+#define SPIDAT1                0x3c
+#define SPIBUF         0x40
+#define SPIEMU         0x44
+#define SPIDELAY       0x48
+#define SPIDEF         0x4c
+#define SPIFMT0                0x50
+#define SPIFMT1                0x54
+#define SPIFMT2                0x58
+#define SPIFMT3                0x5c
+#define TGINTVEC0      0x60
+#define TGINTVEC1      0x64
+
+struct davinci_spi_slave {
+       u32     cmd_to_write;
+       u32     clk_ctrl_to_write;
+       u32     bytes_per_word;
+       u8      active_cs;
+};
+
+/* We have 2 DMA channels per CS, one for RX and one for TX */
+struct davinci_spi_dma {
+       int                     dma_tx_channel;
+       int                     dma_rx_channel;
+       int                     dma_tx_sync_dev;
+       int                     dma_rx_sync_dev;
+       enum dma_event_q        eventq;
+
+       struct completion       dma_tx_completion;
+       struct completion       dma_rx_completion;
+};
+
+/* SPI Controller driver's private data. */
+struct davinci_spi {
+       struct spi_bitbang      bitbang;
+       struct clk              *clk;
+
+       u8                      version;
+       resource_size_t         pbase;
+       void __iomem            *base;
+       size_t                  region_size;
+       u32                     irq;
+       struct completion       done;
+
+       const void              *tx;
+       void                    *rx;
+       u8                      *tmp_buf;
+       int                     count;
+       struct davinci_spi_dma  *dma_channels;
+       struct                  davinci_spi_platform_data *pdata;
+
+       void                    (*get_rx)(u32 rx_data, struct davinci_spi *);
+       u32                     (*get_tx)(struct davinci_spi *);
+
+       struct davinci_spi_slave slave[SPI_MAX_CHIPSELECT];
+};
+
+static unsigned use_dma;
+
+static void davinci_spi_rx_buf_u8(u32 data, struct davinci_spi *davinci_spi)
+{
+       u8 *rx = davinci_spi->rx;
+
+       *rx++ = (u8)data;
+       davinci_spi->rx = rx;
+}
+
+static void davinci_spi_rx_buf_u16(u32 data, struct davinci_spi *davinci_spi)
+{
+       u16 *rx = davinci_spi->rx;
+
+       *rx++ = (u16)data;
+       davinci_spi->rx = rx;
+}
+
+static u32 davinci_spi_tx_buf_u8(struct davinci_spi *davinci_spi)
+{
+       u32 data;
+       const u8 *tx = davinci_spi->tx;
+
+       data = *tx++;
+       davinci_spi->tx = tx;
+       return data;
+}
+
+static u32 davinci_spi_tx_buf_u16(struct davinci_spi *davinci_spi)
+{
+       u32 data;
+       const u16 *tx = davinci_spi->tx;
+
+       data = *tx++;
+       davinci_spi->tx = tx;
+       return data;
+}
+
+static inline void set_io_bits(void __iomem *addr, u32 bits)
+{
+       u32 v = ioread32(addr);
+
+       v |= bits;
+       iowrite32(v, addr);
+}
+
+static inline void clear_io_bits(void __iomem *addr, u32 bits)
+{
+       u32 v = ioread32(addr);
+
+       v &= ~bits;
+       iowrite32(v, addr);
+}
+
+static inline void set_fmt_bits(void __iomem *addr, u32 bits, int cs_num)
+{
+       set_io_bits(addr + SPIFMT0 + (0x4 * cs_num), bits);
+}
+
+static inline void clear_fmt_bits(void __iomem *addr, u32 bits, int cs_num)
+{
+       clear_io_bits(addr + SPIFMT0 + (0x4 * cs_num), bits);
+}
+
+static void davinci_spi_set_dma_req(const struct spi_device *spi, int enable)
+{
+       struct davinci_spi *davinci_spi = spi_master_get_devdata(spi->master);
+
+       if (enable)
+               set_io_bits(davinci_spi->base + SPIINT, SPIINT_DMA_REQ_EN);
+       else
+               clear_io_bits(davinci_spi->base + SPIINT, SPIINT_DMA_REQ_EN);
+}
+
+/*
+ * Interface to control the chip select signal
+ */
+static void davinci_spi_chipselect(struct spi_device *spi, int value)
+{
+       struct davinci_spi *davinci_spi;
+       struct davinci_spi_platform_data *pdata;
+       u32 data1_reg_val = 0;
+
+       davinci_spi = spi_master_get_devdata(spi->master);
+       pdata = davinci_spi->pdata;
+
+       /*
+        * Board specific chip select logic decides the polarity and cs
+        * line for the controller
+        */
+       if (value == BITBANG_CS_INACTIVE) {
+               set_io_bits(davinci_spi->base + SPIDEF, CS_DEFAULT);
+
+               data1_reg_val |= CS_DEFAULT << SPIDAT1_CSNR_SHIFT;
+               iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1);
+
+               while ((ioread32(davinci_spi->base + SPIBUF)
+                                       & SPIBUF_RXEMPTY_MASK) == 0)
+                       cpu_relax();
+       }
+}
+
+/**
+ * davinci_spi_setup_transfer - This functions will determine transfer method
+ * @spi: spi device on which data transfer to be done
+ * @t: spi transfer in which transfer info is filled
+ *
+ * This function determines data transfer method (8/16/32 bit transfer).
+ * It will also set the SPI Clock Control register according to
+ * SPI slave device freq.
+ */
+static int davinci_spi_setup_transfer(struct spi_device *spi,
+               struct spi_transfer *t)
+{
+
+       struct davinci_spi *davinci_spi;
+       struct davinci_spi_platform_data *pdata;
+       u8 bits_per_word = 0;
+       u32 hz = 0, prescale;
+
+       davinci_spi = spi_master_get_devdata(spi->master);
+       pdata = davinci_spi->pdata;
+
+       if (t) {
+               bits_per_word = t->bits_per_word;
+               hz = t->speed_hz;
+       }
+
+       /* if bits_per_word is not set then set it default */
+       if (!bits_per_word)
+               bits_per_word = spi->bits_per_word;
+
+       /*
+        * Assign function pointer to appropriate transfer method
+        * 8bit, 16bit or 32bit transfer
+        */
+       if (bits_per_word <= 8 && bits_per_word >= 2) {
+               davinci_spi->get_rx = davinci_spi_rx_buf_u8;
+               davinci_spi->get_tx = davinci_spi_tx_buf_u8;
+               davinci_spi->slave[spi->chip_select].bytes_per_word = 1;
+       } else if (bits_per_word <= 16 && bits_per_word >= 2) {
+               davinci_spi->get_rx = davinci_spi_rx_buf_u16;
+               davinci_spi->get_tx = davinci_spi_tx_buf_u16;
+               davinci_spi->slave[spi->chip_select].bytes_per_word = 2;
+       } else
+               return -EINVAL;
+
+       if (!hz)
+               hz = spi->max_speed_hz;
+
+       clear_fmt_bits(davinci_spi->base, SPIFMT_CHARLEN_MASK,
+                       spi->chip_select);
+       set_fmt_bits(davinci_spi->base, bits_per_word & 0x1f,
+                       spi->chip_select);
+
+       prescale = ((clk_get_rate(davinci_spi->clk) / hz) - 1) & 0xff;
+
+       clear_fmt_bits(davinci_spi->base, 0x0000ff00, spi->chip_select);
+       set_fmt_bits(davinci_spi->base, prescale << 8, spi->chip_select);
+
+       return 0;
+}
+
+static void davinci_spi_dma_rx_callback(unsigned lch, u16 ch_status, void *data)
+{
+       struct spi_device *spi = (struct spi_device *)data;
+       struct davinci_spi *davinci_spi;
+       struct davinci_spi_dma *davinci_spi_dma;
+       struct davinci_spi_platform_data *pdata;
+
+       davinci_spi = spi_master_get_devdata(spi->master);
+       davinci_spi_dma = &(davinci_spi->dma_channels[spi->chip_select]);
+       pdata = davinci_spi->pdata;
+
+       if (ch_status == DMA_COMPLETE)
+               edma_stop(davinci_spi_dma->dma_rx_channel);
+       else
+               edma_clean_channel(davinci_spi_dma->dma_rx_channel);
+
+       complete(&davinci_spi_dma->dma_rx_completion);
+       /* We must disable the DMA RX request */
+       davinci_spi_set_dma_req(spi, 0);
+}
+
+static void davinci_spi_dma_tx_callback(unsigned lch, u16 ch_status, void *data)
+{
+       struct spi_device *spi = (struct spi_device *)data;
+       struct davinci_spi *davinci_spi;
+       struct davinci_spi_dma *davinci_spi_dma;
+       struct davinci_spi_platform_data *pdata;
+
+       davinci_spi = spi_master_get_devdata(spi->master);
+       davinci_spi_dma = &(davinci_spi->dma_channels[spi->chip_select]);
+       pdata = davinci_spi->pdata;
+
+       if (ch_status == DMA_COMPLETE)
+               edma_stop(davinci_spi_dma->dma_tx_channel);
+       else
+               edma_clean_channel(davinci_spi_dma->dma_tx_channel);
+
+       complete(&davinci_spi_dma->dma_tx_completion);
+       /* We must disable the DMA TX request */
+       davinci_spi_set_dma_req(spi, 0);
+}
+
+static int davinci_spi_request_dma(struct spi_device *spi)
+{
+       struct davinci_spi *davinci_spi;
+       struct davinci_spi_dma *davinci_spi_dma;
+       struct davinci_spi_platform_data *pdata;
+       struct device *sdev;
+       int r;
+
+       davinci_spi = spi_master_get_devdata(spi->master);
+       davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
+       pdata = davinci_spi->pdata;
+       sdev = davinci_spi->bitbang.master->dev.parent;
+
+       r = edma_alloc_channel(davinci_spi_dma->dma_rx_sync_dev,
+                               davinci_spi_dma_rx_callback, spi,
+                               davinci_spi_dma->eventq);
+       if (r < 0) {
+               dev_dbg(sdev, "Unable to request DMA channel for SPI RX\n");
+               return -EAGAIN;
+       }
+       davinci_spi_dma->dma_rx_channel = r;
+       r = edma_alloc_channel(davinci_spi_dma->dma_tx_sync_dev,
+                               davinci_spi_dma_tx_callback, spi,
+                               davinci_spi_dma->eventq);
+       if (r < 0) {
+               edma_free_channel(davinci_spi_dma->dma_rx_channel);
+               davinci_spi_dma->dma_rx_channel = -1;
+               dev_dbg(sdev, "Unable to request DMA channel for SPI TX\n");
+               return -EAGAIN;
+       }
+       davinci_spi_dma->dma_tx_channel = r;
+
+       return 0;
+}
+
+/**
+ * davinci_spi_setup - This functions will set default transfer method
+ * @spi: spi device on which data transfer to be done
+ *
+ * This functions sets the default transfer method.
+ */
+
+static int davinci_spi_setup(struct spi_device *spi)
+{
+       int retval;
+       struct davinci_spi *davinci_spi;
+       struct davinci_spi_dma *davinci_spi_dma;
+       struct device *sdev;
+
+       davinci_spi = spi_master_get_devdata(spi->master);
+       sdev = davinci_spi->bitbang.master->dev.parent;
+
+       /* if bits per word length is zero then set it default 8 */
+       if (!spi->bits_per_word)
+               spi->bits_per_word = 8;
+
+       davinci_spi->slave[spi->chip_select].cmd_to_write = 0;
+
+       if (use_dma && davinci_spi->dma_channels) {
+               davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
+
+               if ((davinci_spi_dma->dma_rx_channel == -1)
+                               || (davinci_spi_dma->dma_tx_channel == -1)) {
+                       retval = davinci_spi_request_dma(spi);
+                       if (retval < 0)
+                               return retval;
+               }
+       }
+
+       /*
+        * SPI in DaVinci and DA8xx operate between
+        * 600 KHz and 50 MHz
+        */
+       if (spi->max_speed_hz < 600000 || spi->max_speed_hz > 50000000) {
+               dev_dbg(sdev, "Operating frequency is not in acceptable "
+                               "range\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Set up SPIFMTn register, unique to this chipselect.
+        *
+        * NOTE: we could do all of these with one write.  Also, some
+        * of the "version 2" features are found in chips that don't
+        * support all of them...
+        */
+       if (spi->mode & SPI_LSB_FIRST)
+               set_fmt_bits(davinci_spi->base, SPIFMT_SHIFTDIR_MASK,
+                               spi->chip_select);
+       else
+               clear_fmt_bits(davinci_spi->base, SPIFMT_SHIFTDIR_MASK,
+                               spi->chip_select);
+
+       if (spi->mode & SPI_CPOL)
+               set_fmt_bits(davinci_spi->base, SPIFMT_POLARITY_MASK,
+                               spi->chip_select);
+       else
+               clear_fmt_bits(davinci_spi->base, SPIFMT_POLARITY_MASK,
+                               spi->chip_select);
+
+       if (!(spi->mode & SPI_CPHA))
+               set_fmt_bits(davinci_spi->base, SPIFMT_PHASE_MASK,
+                               spi->chip_select);
+       else
+               clear_fmt_bits(davinci_spi->base, SPIFMT_PHASE_MASK,
+                               spi->chip_select);
+
+       /*
+        * Version 1 hardware supports two basic SPI modes:
+        *  - Standard SPI mode uses 4 pins, with chipselect
+        *  - 3 pin SPI is a 4 pin variant without CS (SPI_NO_CS)
+        *      (distinct from SPI_3WIRE, with just one data wire;
+        *      or similar variants without MOSI or without MISO)
+        *
+        * Version 2 hardware supports an optional handshaking signal,
+        * so it can support two more modes:
+        *  - 5 pin SPI variant is standard SPI plus SPI_READY
+        *  - 4 pin with enable is (SPI_READY | SPI_NO_CS)
+        */
+
+       if (davinci_spi->version == SPI_VERSION_2) {
+               clear_fmt_bits(davinci_spi->base, SPIFMT_WDELAY_MASK,
+                               spi->chip_select);
+               set_fmt_bits(davinci_spi->base,
+                               (davinci_spi->pdata->wdelay
+                                               << SPIFMT_WDELAY_SHIFT)
+                                       & SPIFMT_WDELAY_MASK,
+                               spi->chip_select);
+
+               if (davinci_spi->pdata->odd_parity)
+                       set_fmt_bits(davinci_spi->base,
+                                       SPIFMT_ODD_PARITY_MASK,
+                                       spi->chip_select);
+               else
+                       clear_fmt_bits(davinci_spi->base,
+                                       SPIFMT_ODD_PARITY_MASK,
+                                       spi->chip_select);
+
+               if (davinci_spi->pdata->parity_enable)
+                       set_fmt_bits(davinci_spi->base,
+                                       SPIFMT_PARITYENA_MASK,
+                                       spi->chip_select);
+               else
+                       clear_fmt_bits(davinci_spi->base,
+                                       SPIFMT_PARITYENA_MASK,
+                                       spi->chip_select);
+
+               if (davinci_spi->pdata->wait_enable)
+                       set_fmt_bits(davinci_spi->base,
+                                       SPIFMT_WAITENA_MASK,
+                                       spi->chip_select);
+               else
+                       clear_fmt_bits(davinci_spi->base,
+                                       SPIFMT_WAITENA_MASK,
+                                       spi->chip_select);
+
+               if (davinci_spi->pdata->timer_disable)
+                       set_fmt_bits(davinci_spi->base,
+                                       SPIFMT_DISTIMER_MASK,
+                                       spi->chip_select);
+               else
+                       clear_fmt_bits(davinci_spi->base,
+                                       SPIFMT_DISTIMER_MASK,
+                                       spi->chip_select);
+       }
+
+       retval = davinci_spi_setup_transfer(spi, NULL);
+
+       return retval;
+}
+
+static void davinci_spi_cleanup(struct spi_device *spi)
+{
+       struct davinci_spi *davinci_spi = spi_master_get_devdata(spi->master);
+       struct davinci_spi_dma *davinci_spi_dma;
+
+       davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
+
+       if (use_dma && davinci_spi->dma_channels) {
+               davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
+
+               if ((davinci_spi_dma->dma_rx_channel != -1)
+                               && (davinci_spi_dma->dma_tx_channel != -1)) {
+                       edma_free_channel(davinci_spi_dma->dma_tx_channel);
+                       edma_free_channel(davinci_spi_dma->dma_rx_channel);
+               }
+       }
+}
+
+static int davinci_spi_bufs_prep(struct spi_device *spi,
+                                struct davinci_spi *davinci_spi)
+{
+       int op_mode = 0;
+
+       /*
+        * REVISIT  unless devices disagree about SPI_LOOP or
+        * SPI_READY (SPI_NO_CS only allows one device!), this
+        * should not need to be done before each message...
+        * optimize for both flags staying cleared.
+        */
+
+       op_mode = SPIPC0_DIFUN_MASK
+               | SPIPC0_DOFUN_MASK
+               | SPIPC0_CLKFUN_MASK;
+       if (!(spi->mode & SPI_NO_CS))
+               op_mode |= 1 << spi->chip_select;
+       if (spi->mode & SPI_READY)
+               op_mode |= SPIPC0_SPIENA_MASK;
+
+       iowrite32(op_mode, davinci_spi->base + SPIPC0);
+
+       if (spi->mode & SPI_LOOP)
+               set_io_bits(davinci_spi->base + SPIGCR1,
+                               SPIGCR1_LOOPBACK_MASK);
+       else
+               clear_io_bits(davinci_spi->base + SPIGCR1,
+                               SPIGCR1_LOOPBACK_MASK);
+
+       return 0;
+}
+
+static int davinci_spi_check_error(struct davinci_spi *davinci_spi,
+                                  int int_status)
+{
+       struct device *sdev = davinci_spi->bitbang.master->dev.parent;
+
+       if (int_status & SPIFLG_TIMEOUT_MASK) {
+               dev_dbg(sdev, "SPI Time-out Error\n");
+               return -ETIMEDOUT;
+       }
+       if (int_status & SPIFLG_DESYNC_MASK) {
+               dev_dbg(sdev, "SPI Desynchronization Error\n");
+               return -EIO;
+       }
+       if (int_status & SPIFLG_BITERR_MASK) {
+               dev_dbg(sdev, "SPI Bit error\n");
+               return -EIO;
+       }
+
+       if (davinci_spi->version == SPI_VERSION_2) {
+               if (int_status & SPIFLG_DLEN_ERR_MASK) {
+                       dev_dbg(sdev, "SPI Data Length Error\n");
+                       return -EIO;
+               }
+               if (int_status & SPIFLG_PARERR_MASK) {
+                       dev_dbg(sdev, "SPI Parity Error\n");
+                       return -EIO;
+               }
+               if (int_status & SPIFLG_OVRRUN_MASK) {
+                       dev_dbg(sdev, "SPI Data Overrun error\n");
+                       return -EIO;
+               }
+               if (int_status & SPIFLG_TX_INTR_MASK) {
+                       dev_dbg(sdev, "SPI TX intr bit set\n");
+                       return -EIO;
+               }
+               if (int_status & SPIFLG_BUF_INIT_ACTIVE_MASK) {
+                       dev_dbg(sdev, "SPI Buffer Init Active\n");
+                       return -EBUSY;
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * davinci_spi_bufs - functions which will handle transfer data
+ * @spi: spi device on which data transfer to be done
+ * @t: spi transfer in which transfer info is filled
+ *
+ * This function will put data to be transferred into data register
+ * of SPI controller and then wait until the completion will be marked
+ * by the IRQ Handler.
+ */
+static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t)
+{
+       struct davinci_spi *davinci_spi;
+       int int_status, count, ret;
+       u8 conv, tmp;
+       u32 tx_data, data1_reg_val;
+       u32 buf_val, flg_val;
+       struct davinci_spi_platform_data *pdata;
+
+       davinci_spi = spi_master_get_devdata(spi->master);
+       pdata = davinci_spi->pdata;
+
+       davinci_spi->tx = t->tx_buf;
+       davinci_spi->rx = t->rx_buf;
+
+       /* convert len to words based on bits_per_word */
+       conv = davinci_spi->slave[spi->chip_select].bytes_per_word;
+       davinci_spi->count = t->len / conv;
+
+       INIT_COMPLETION(davinci_spi->done);
+
+       ret = davinci_spi_bufs_prep(spi, davinci_spi);
+       if (ret)
+               return ret;
+
+       /* Enable SPI */
+       set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
+
+       iowrite32(0 | (pdata->c2tdelay << SPI_C2TDELAY_SHIFT) |
+                       (pdata->t2cdelay << SPI_T2CDELAY_SHIFT),
+                       davinci_spi->base + SPIDELAY);
+
+       count = davinci_spi->count;
+       data1_reg_val = pdata->cs_hold << SPIDAT1_CSHOLD_SHIFT;
+       tmp = ~(0x1 << spi->chip_select);
+
+       clear_io_bits(davinci_spi->base + SPIDEF, ~tmp);
+
+       data1_reg_val |= tmp << SPIDAT1_CSNR_SHIFT;
+
+       while ((ioread32(davinci_spi->base + SPIBUF)
+                               & SPIBUF_RXEMPTY_MASK) == 0)
+               cpu_relax();
+
+       /* Determine the command to execute READ or WRITE */
+       if (t->tx_buf) {
+               clear_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKALL);
+
+               while (1) {
+                       tx_data = davinci_spi->get_tx(davinci_spi);
+
+                       data1_reg_val &= ~(0xFFFF);
+                       data1_reg_val |= (0xFFFF & tx_data);
+
+                       buf_val = ioread32(davinci_spi->base + SPIBUF);
+                       if ((buf_val & SPIBUF_TXFULL_MASK) == 0) {
+                               iowrite32(data1_reg_val,
+                                               davinci_spi->base + SPIDAT1);
+
+                               count--;
+                       }
+                       while (ioread32(davinci_spi->base + SPIBUF)
+                                       & SPIBUF_RXEMPTY_MASK)
+                               cpu_relax();
+
+                       /* getting the returned byte */
+                       if (t->rx_buf) {
+                               buf_val = ioread32(davinci_spi->base + SPIBUF);
+                               davinci_spi->get_rx(buf_val, davinci_spi);
+                       }
+                       if (count <= 0)
+                               break;
+               }
+       } else {
+               if (pdata->poll_mode) {
+                       while (1) {
+                               /* keeps the serial clock going */
+                               if ((ioread32(davinci_spi->base + SPIBUF)
+                                               & SPIBUF_TXFULL_MASK) == 0)
+                                       iowrite32(data1_reg_val,
+                                               davinci_spi->base + SPIDAT1);
+
+                               while (ioread32(davinci_spi->base + SPIBUF) &
+                                               SPIBUF_RXEMPTY_MASK)
+                                       cpu_relax();
+
+                               flg_val = ioread32(davinci_spi->base + SPIFLG);
+                               buf_val = ioread32(davinci_spi->base + SPIBUF);
+
+                               davinci_spi->get_rx(buf_val, davinci_spi);
+
+                               count--;
+                               if (count <= 0)
+                                       break;
+                       }
+               } else {        /* Receive in Interrupt mode */
+                       int i;
+
+                       for (i = 0; i < davinci_spi->count; i++) {
+                               set_io_bits(davinci_spi->base + SPIINT,
+                                               SPIINT_BITERR_INTR
+                                               | SPIINT_OVRRUN_INTR
+                                               | SPIINT_RX_INTR);
+
+                               iowrite32(data1_reg_val,
+                                               davinci_spi->base + SPIDAT1);
+
+                               while (ioread32(davinci_spi->base + SPIINT) &
+                                               SPIINT_RX_INTR)
+                                       cpu_relax();
+                       }
+                       iowrite32((data1_reg_val & 0x0ffcffff),
+                                       davinci_spi->base + SPIDAT1);
+               }
+       }
+
+       /*
+        * Check for bit error, desync error,parity error,timeout error and
+        * receive overflow errors
+        */
+       int_status = ioread32(davinci_spi->base + SPIFLG);
+
+       ret = davinci_spi_check_error(davinci_spi, int_status);
+       if (ret != 0)
+               return ret;
+
+       /* SPI Framework maintains the count only in bytes so convert back */
+       davinci_spi->count *= conv;
+
+       return t->len;
+}
+
+#define DAVINCI_DMA_DATA_TYPE_S8       0x01
+#define DAVINCI_DMA_DATA_TYPE_S16      0x02
+#define DAVINCI_DMA_DATA_TYPE_S32      0x04
+
+static int davinci_spi_bufs_dma(struct spi_device *spi, struct spi_transfer *t)
+{
+       struct davinci_spi *davinci_spi;
+       int int_status = 0;
+       int count, temp_count;
+       u8 conv = 1;
+       u8 tmp;
+       u32 data1_reg_val;
+       struct davinci_spi_dma *davinci_spi_dma;
+       int word_len, data_type, ret;
+       unsigned long tx_reg, rx_reg;
+       struct davinci_spi_platform_data *pdata;
+       struct device *sdev;
+
+       davinci_spi = spi_master_get_devdata(spi->master);
+       pdata = davinci_spi->pdata;
+       sdev = davinci_spi->bitbang.master->dev.parent;
+
+       davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
+
+       tx_reg = (unsigned long)davinci_spi->pbase + SPIDAT1;
+       rx_reg = (unsigned long)davinci_spi->pbase + SPIBUF;
+
+       davinci_spi->tx = t->tx_buf;
+       davinci_spi->rx = t->rx_buf;
+
+       /* convert len to words based on bits_per_word */
+       conv = davinci_spi->slave[spi->chip_select].bytes_per_word;
+       davinci_spi->count = t->len / conv;
+
+       INIT_COMPLETION(davinci_spi->done);
+
+       init_completion(&davinci_spi_dma->dma_rx_completion);
+       init_completion(&davinci_spi_dma->dma_tx_completion);
+
+       word_len = conv * 8;
+
+       if (word_len <= 8)
+               data_type = DAVINCI_DMA_DATA_TYPE_S8;
+       else if (word_len <= 16)
+               data_type = DAVINCI_DMA_DATA_TYPE_S16;
+       else if (word_len <= 32)
+               data_type = DAVINCI_DMA_DATA_TYPE_S32;
+       else
+               return -EINVAL;
+
+       ret = davinci_spi_bufs_prep(spi, davinci_spi);
+       if (ret)
+               return ret;
+
+       /* Put delay val if required */
+       iowrite32(0 | (pdata->c2tdelay << SPI_C2TDELAY_SHIFT) |
+                       (pdata->t2cdelay << SPI_T2CDELAY_SHIFT),
+                       davinci_spi->base + SPIDELAY);
+
+       count = davinci_spi->count;     /* the number of elements */
+       data1_reg_val = pdata->cs_hold << SPIDAT1_CSHOLD_SHIFT;
+
+       /* CS default = 0xFF */
+       tmp = ~(0x1 << spi->chip_select);
+
+       clear_io_bits(davinci_spi->base + SPIDEF, ~tmp);
+
+       data1_reg_val |= tmp << SPIDAT1_CSNR_SHIFT;
+
+       /* disable all interrupts for dma transfers */
+       clear_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKALL);
+       /* Disable SPI to write configuration bits in SPIDAT */
+       clear_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
+       iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1);
+       /* Enable SPI */
+       set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
+
+       while ((ioread32(davinci_spi->base + SPIBUF)
+                               & SPIBUF_RXEMPTY_MASK) == 0)
+               cpu_relax();
+
+
+       if (t->tx_buf) {
+               t->tx_dma = dma_map_single(&spi->dev, (void *)t->tx_buf, count,
+                               DMA_TO_DEVICE);
+               if (dma_mapping_error(&spi->dev, t->tx_dma)) {
+                       dev_dbg(sdev, "Unable to DMA map a %d bytes"
+                               " TX buffer\n", count);
+                       return -ENOMEM;
+               }
+               temp_count = count;
+       } else {
+               /* We need TX clocking for RX transaction */
+               t->tx_dma = dma_map_single(&spi->dev,
+                               (void *)davinci_spi->tmp_buf, count + 1,
+                               DMA_TO_DEVICE);
+               if (dma_mapping_error(&spi->dev, t->tx_dma)) {
+                       dev_dbg(sdev, "Unable to DMA map a %d bytes"
+                               " TX tmp buffer\n", count);
+                       return -ENOMEM;
+               }
+               temp_count = count + 1;
+       }
+
+       edma_set_transfer_params(davinci_spi_dma->dma_tx_channel,
+                                       data_type, temp_count, 1, 0, ASYNC);
+       edma_set_dest(davinci_spi_dma->dma_tx_channel, tx_reg, INCR, W8BIT);
+       edma_set_src(davinci_spi_dma->dma_tx_channel, t->tx_dma, INCR, W8BIT);
+       edma_set_src_index(davinci_spi_dma->dma_tx_channel, data_type, 0);
+       edma_set_dest_index(davinci_spi_dma->dma_tx_channel, 0, 0);
+
+       if (t->rx_buf) {
+               /* initiate transaction */
+               iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1);
+
+               t->rx_dma = dma_map_single(&spi->dev, (void *)t->rx_buf, count,
+                               DMA_FROM_DEVICE);
+               if (dma_mapping_error(&spi->dev, t->rx_dma)) {
+                       dev_dbg(sdev, "Couldn't DMA map a %d bytes RX buffer\n",
+                                       count);
+                       if (t->tx_buf != NULL)
+                               dma_unmap_single(NULL, t->tx_dma,
+                                                count, DMA_TO_DEVICE);
+                       return -ENOMEM;
+               }
+               edma_set_transfer_params(davinci_spi_dma->dma_rx_channel,
+                               data_type, count, 1, 0, ASYNC);
+               edma_set_src(davinci_spi_dma->dma_rx_channel,
+                               rx_reg, INCR, W8BIT);
+               edma_set_dest(davinci_spi_dma->dma_rx_channel,
+                               t->rx_dma, INCR, W8BIT);
+               edma_set_src_index(davinci_spi_dma->dma_rx_channel, 0, 0);
+               edma_set_dest_index(davinci_spi_dma->dma_rx_channel,
+                               data_type, 0);
+       }
+
+       if ((t->tx_buf) || (t->rx_buf))
+               edma_start(davinci_spi_dma->dma_tx_channel);
+
+       if (t->rx_buf)
+               edma_start(davinci_spi_dma->dma_rx_channel);
+
+       if ((t->rx_buf) || (t->tx_buf))
+               davinci_spi_set_dma_req(spi, 1);
+
+       if (t->tx_buf)
+               wait_for_completion_interruptible(
+                               &davinci_spi_dma->dma_tx_completion);
+
+       if (t->rx_buf)
+               wait_for_completion_interruptible(
+                               &davinci_spi_dma->dma_rx_completion);
+
+       dma_unmap_single(NULL, t->tx_dma, temp_count, DMA_TO_DEVICE);
+
+       if (t->rx_buf)
+               dma_unmap_single(NULL, t->rx_dma, count, DMA_FROM_DEVICE);
+
+       /*
+        * Check for bit error, desync error,parity error,timeout error and
+        * receive overflow errors
+        */
+       int_status = ioread32(davinci_spi->base + SPIFLG);
+
+       ret = davinci_spi_check_error(davinci_spi, int_status);
+       if (ret != 0)
+               return ret;
+
+       /* SPI Framework maintains the count only in bytes so convert back */
+       davinci_spi->count *= conv;
+
+       return t->len;
+}
+
+/**
+ * davinci_spi_irq - IRQ handler for DaVinci SPI
+ * @irq: IRQ number for this SPI Master
+ * @context_data: structure for SPI Master controller davinci_spi
+ */
+static irqreturn_t davinci_spi_irq(s32 irq, void *context_data)
+{
+       struct davinci_spi *davinci_spi = context_data;
+       u32 int_status, rx_data = 0;
+       irqreturn_t ret = IRQ_NONE;
+
+       int_status = ioread32(davinci_spi->base + SPIFLG);
+
+       while ((int_status & SPIFLG_RX_INTR_MASK)) {
+               if (likely(int_status & SPIFLG_RX_INTR_MASK)) {
+                       ret = IRQ_HANDLED;
+
+                       rx_data = ioread32(davinci_spi->base + SPIBUF);
+                       davinci_spi->get_rx(rx_data, davinci_spi);
+
+                       /* Disable Receive Interrupt */
+                       iowrite32(~(SPIINT_RX_INTR | SPIINT_TX_INTR),
+                                       davinci_spi->base + SPIINT);
+               } else
+                       (void)davinci_spi_check_error(davinci_spi, int_status);
+
+               int_status = ioread32(davinci_spi->base + SPIFLG);
+       }
+
+       return ret;
+}
+
+/**
+ * davinci_spi_probe - probe function for SPI Master Controller
+ * @pdev: platform_device structure which contains plateform specific data
+ */
+static int davinci_spi_probe(struct platform_device *pdev)
+{
+       struct spi_master *master;
+       struct davinci_spi *davinci_spi;
+       struct davinci_spi_platform_data *pdata;
+       struct resource *r, *mem;
+       resource_size_t dma_rx_chan = SPI_NO_RESOURCE;
+       resource_size_t dma_tx_chan = SPI_NO_RESOURCE;
+       resource_size_t dma_eventq = SPI_NO_RESOURCE;
+       int i = 0, ret = 0;
+
+       pdata = pdev->dev.platform_data;
+       if (pdata == NULL) {
+               ret = -ENODEV;
+               goto err;
+       }
+
+       master = spi_alloc_master(&pdev->dev, sizeof(struct davinci_spi));
+       if (master == NULL) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       dev_set_drvdata(&pdev->dev, master);
+
+       davinci_spi = spi_master_get_devdata(master);
+       if (davinci_spi == NULL) {
+               ret = -ENOENT;
+               goto free_master;
+       }
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (r == NULL) {
+               ret = -ENOENT;
+               goto free_master;
+       }
+
+       davinci_spi->pbase = r->start;
+       davinci_spi->region_size = resource_size(r);
+       davinci_spi->pdata = pdata;
+
+       mem = request_mem_region(r->start, davinci_spi->region_size,
+                                       pdev->name);
+       if (mem == NULL) {
+               ret = -EBUSY;
+               goto free_master;
+       }
+
+       davinci_spi->base = (struct davinci_spi_reg __iomem *)
+                       ioremap(r->start, davinci_spi->region_size);
+       if (davinci_spi->base == NULL) {
+               ret = -ENOMEM;
+               goto release_region;
+       }
+
+       davinci_spi->irq = platform_get_irq(pdev, 0);
+       if (davinci_spi->irq <= 0) {
+               ret = -EINVAL;
+               goto unmap_io;
+       }
+
+       ret = request_irq(davinci_spi->irq, davinci_spi_irq, IRQF_DISABLED,
+                         dev_name(&pdev->dev), davinci_spi);
+       if (ret)
+               goto unmap_io;
+
+       /* Allocate tmp_buf for tx_buf */
+       davinci_spi->tmp_buf = kzalloc(SPI_BUFSIZ, GFP_KERNEL);
+       if (davinci_spi->tmp_buf == NULL) {
+               ret = -ENOMEM;
+               goto irq_free;
+       }
+
+       davinci_spi->bitbang.master = spi_master_get(master);
+       if (davinci_spi->bitbang.master == NULL) {
+               ret = -ENODEV;
+               goto free_tmp_buf;
+       }
+
+       davinci_spi->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(davinci_spi->clk)) {
+               ret = -ENODEV;
+               goto put_master;
+       }
+       clk_enable(davinci_spi->clk);
+
+
+       master->bus_num = pdev->id;
+       master->num_chipselect = pdata->num_chipselect;
+       master->setup = davinci_spi_setup;
+       master->cleanup = davinci_spi_cleanup;
+
+       davinci_spi->bitbang.chipselect = davinci_spi_chipselect;
+       davinci_spi->bitbang.setup_transfer = davinci_spi_setup_transfer;
+
+       davinci_spi->version = pdata->version;
+       use_dma = pdata->use_dma;
+
+       davinci_spi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP;
+       if (davinci_spi->version == SPI_VERSION_2)
+               davinci_spi->bitbang.flags |= SPI_READY;
+
+       if (use_dma) {
+                       r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+                       if (r)
+                               dma_rx_chan = r->start;
+                       r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+                       if (r)
+                               dma_tx_chan = r->start;
+                       r = platform_get_resource(pdev, IORESOURCE_DMA, 2);
+                       if (r)
+                               dma_eventq = r->start;
+       }
+
+       if (!use_dma ||
+           dma_rx_chan == SPI_NO_RESOURCE ||
+           dma_tx_chan == SPI_NO_RESOURCE ||
+           dma_eventq  == SPI_NO_RESOURCE) {
+               davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_pio;
+               use_dma = 0;
+       } else {
+               davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_dma;
+               davinci_spi->dma_channels = kzalloc(master->num_chipselect
+                               * sizeof(struct davinci_spi_dma), GFP_KERNEL);
+               if (davinci_spi->dma_channels == NULL) {
+                       ret = -ENOMEM;
+                       goto free_clk;
+               }
+
+               for (i = 0; i < master->num_chipselect; i++) {
+                       davinci_spi->dma_channels[i].dma_rx_channel = -1;
+                       davinci_spi->dma_channels[i].dma_rx_sync_dev =
+                               dma_rx_chan;
+                       davinci_spi->dma_channels[i].dma_tx_channel = -1;
+                       davinci_spi->dma_channels[i].dma_tx_sync_dev =
+                               dma_tx_chan;
+                       davinci_spi->dma_channels[i].eventq = dma_eventq;
+               }
+               dev_info(&pdev->dev, "DaVinci SPI driver in EDMA mode\n"
+                               "Using RX channel = %d , TX channel = %d and "
+                               "event queue = %d", dma_rx_chan, dma_tx_chan,
+                               dma_eventq);
+       }
+
+       davinci_spi->get_rx = davinci_spi_rx_buf_u8;
+       davinci_spi->get_tx = davinci_spi_tx_buf_u8;
+
+       init_completion(&davinci_spi->done);
+
+       /* Reset In/OUT SPI module */
+       iowrite32(0, davinci_spi->base + SPIGCR0);
+       udelay(100);
+       iowrite32(1, davinci_spi->base + SPIGCR0);
+
+       /* Clock internal */
+       if (davinci_spi->pdata->clk_internal)
+               set_io_bits(davinci_spi->base + SPIGCR1,
+                               SPIGCR1_CLKMOD_MASK);
+       else
+               clear_io_bits(davinci_spi->base + SPIGCR1,
+                               SPIGCR1_CLKMOD_MASK);
+
+       /* master mode default */
+       set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_MASTER_MASK);
+
+       if (davinci_spi->pdata->intr_level)
+               iowrite32(SPI_INTLVL_1, davinci_spi->base + SPILVL);
+       else
+               iowrite32(SPI_INTLVL_0, davinci_spi->base + SPILVL);
+
+       ret = spi_bitbang_start(&davinci_spi->bitbang);
+       if (ret)
+               goto free_clk;
+
+       dev_info(&pdev->dev, "Controller at 0x%p \n", davinci_spi->base);
+
+       if (!pdata->poll_mode)
+               dev_info(&pdev->dev, "Operating in interrupt mode"
+                       " using IRQ %d\n", davinci_spi->irq);
+
+       return ret;
+
+free_clk:
+       clk_disable(davinci_spi->clk);
+       clk_put(davinci_spi->clk);
+put_master:
+       spi_master_put(master);
+free_tmp_buf:
+       kfree(davinci_spi->tmp_buf);
+irq_free:
+       free_irq(davinci_spi->irq, davinci_spi);
+unmap_io:
+       iounmap(davinci_spi->base);
+release_region:
+       release_mem_region(davinci_spi->pbase, davinci_spi->region_size);
+free_master:
+       kfree(master);
+err:
+       return ret;
+}
+
+/**
+ * davinci_spi_remove - remove function for SPI Master Controller
+ * @pdev: platform_device structure which contains plateform specific data
+ *
+ * This function will do the reverse action of davinci_spi_probe function
+ * It will free the IRQ and SPI controller's memory region.
+ * It will also call spi_bitbang_stop to destroy the work queue which was
+ * created by spi_bitbang_start.
+ */
+static int __exit davinci_spi_remove(struct platform_device *pdev)
+{
+       struct davinci_spi *davinci_spi;
+       struct spi_master *master;
+
+       master = dev_get_drvdata(&pdev->dev);
+       davinci_spi = spi_master_get_devdata(master);
+
+       spi_bitbang_stop(&davinci_spi->bitbang);
+
+       clk_disable(davinci_spi->clk);
+       clk_put(davinci_spi->clk);
+       spi_master_put(master);
+       kfree(davinci_spi->tmp_buf);
+       free_irq(davinci_spi->irq, davinci_spi);
+       iounmap(davinci_spi->base);
+       release_mem_region(davinci_spi->pbase, davinci_spi->region_size);
+
+       return 0;
+}
+
+static struct platform_driver davinci_spi_driver = {
+       .driver.name = "spi_davinci",
+       .remove = __exit_p(davinci_spi_remove),
+};
+
+static int __init davinci_spi_init(void)
+{
+       return platform_driver_probe(&davinci_spi_driver, davinci_spi_probe);
+}
+module_init(davinci_spi_init);
+
+static void __exit davinci_spi_exit(void)
+{
+       platform_driver_unregister(&davinci_spi_driver);
+}
+module_exit(davinci_spi_exit);
+
+MODULE_DESCRIPTION("TI DaVinci SPI Master Controller Driver");
+MODULE_LICENSE("GPL");
index 31620fa..8ed38f1 100644 (file)
@@ -152,6 +152,7 @@ static void mrst_spi_debugfs_remove(struct dw_spi *dws)
 #else
 static inline int mrst_spi_debugfs_init(struct dw_spi *dws)
 {
+       return 0;
 }
 
 static inline void mrst_spi_debugfs_remove(struct dw_spi *dws)
@@ -161,14 +162,14 @@ static inline void mrst_spi_debugfs_remove(struct dw_spi *dws)
 
 static void wait_till_not_busy(struct dw_spi *dws)
 {
-       unsigned long end = jiffies + usecs_to_jiffies(1000);
+       unsigned long end = jiffies + 1 + usecs_to_jiffies(1000);
 
        while (time_before(jiffies, end)) {
                if (!(dw_readw(dws, sr) & SR_BUSY))
                        return;
        }
        dev_err(&dws->master->dev,
-               "DW SPI: Stutus keeps busy for 1000us after a read/write!\n");
+               "DW SPI: Status keeps busy for 1000us after a read/write!\n");
 }
 
 static void flush(struct dw_spi *dws)
@@ -358,6 +359,8 @@ static void transfer_complete(struct dw_spi *dws)
 static irqreturn_t interrupt_transfer(struct dw_spi *dws)
 {
        u16 irq_status, irq_mask = 0x3f;
+       u32 int_level = dws->fifo_len / 2;
+       u32 left;
 
        irq_status = dw_readw(dws, isr) & irq_mask;
        /* Error handling */
@@ -369,22 +372,23 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws)
                return IRQ_HANDLED;
        }
 
-       /* INT comes from tx */
-       if (dws->tx && (irq_status & SPI_INT_TXEI)) {
-               while (dws->tx < dws->tx_end)
+       if (irq_status & SPI_INT_TXEI) {
+               spi_mask_intr(dws, SPI_INT_TXEI);
+
+               left = (dws->tx_end - dws->tx) / dws->n_bytes;
+               left = (left > int_level) ? int_level : left;
+
+               while (left--)
                        dws->write(dws);
+               dws->read(dws);
 
-               if (dws->tx == dws->tx_end) {
-                       spi_mask_intr(dws, SPI_INT_TXEI);
+               /* Re-enable the IRQ if there is still data left to tx */
+               if (dws->tx_end > dws->tx)
+                       spi_umask_intr(dws, SPI_INT_TXEI);
+               else
                        transfer_complete(dws);
-               }
        }
 
-       /* INT comes from rx */
-       if (dws->rx && (irq_status & SPI_INT_RXFI)) {
-               if (dws->read(dws))
-                       transfer_complete(dws);
-       }
        return IRQ_HANDLED;
 }
 
@@ -404,12 +408,9 @@ static irqreturn_t dw_spi_irq(int irq, void *dev_id)
 /* Must be called inside pump_transfers() */
 static void poll_transfer(struct dw_spi *dws)
 {
-       if (dws->tx) {
-               while (dws->write(dws))
-                       dws->read(dws);
-       }
+       while (dws->write(dws))
+               dws->read(dws);
 
-       dws->read(dws);
        transfer_complete(dws);
 }
 
@@ -428,6 +429,7 @@ static void pump_transfers(unsigned long data)
        u8 bits = 0;
        u8 imask = 0;
        u8 cs_change = 0;
+       u16 txint_level = 0;
        u16 clk_div = 0;
        u32 speed = 0;
        u32 cr0 = 0;
@@ -438,6 +440,9 @@ static void pump_transfers(unsigned long data)
        chip = dws->cur_chip;
        spi = message->spi;
 
+       if (unlikely(!chip->clk_div))
+               chip->clk_div = dws->max_freq / chip->speed_hz;
+
        if (message->state == ERROR_STATE) {
                message->status = -EIO;
                goto early_exit;
@@ -492,7 +497,7 @@ static void pump_transfers(unsigned long data)
 
                        /* clk_div doesn't support odd number */
                        clk_div = dws->max_freq / speed;
-                       clk_div = (clk_div >> 1) << 1;
+                       clk_div = (clk_div + 1) & 0xfffe;
 
                        chip->speed_hz = speed;
                        chip->clk_div = clk_div;
@@ -532,14 +537,35 @@ static void pump_transfers(unsigned long data)
        }
        message->state = RUNNING_STATE;
 
+       /*
+        * Adjust transfer mode if necessary. Requires platform dependent
+        * chipselect mechanism.
+        */
+       if (dws->cs_control) {
+               if (dws->rx && dws->tx)
+                       chip->tmode = 0x00;
+               else if (dws->rx)
+                       chip->tmode = 0x02;
+               else
+                       chip->tmode = 0x01;
+
+               cr0 &= ~(0x3 << SPI_MODE_OFFSET);
+               cr0 |= (chip->tmode << SPI_TMOD_OFFSET);
+       }
+
        /* Check if current transfer is a DMA transaction */
        dws->dma_mapped = map_dma_buffers(dws);
 
+       /*
+        * Interrupt mode
+        * we only need set the TXEI IRQ, as TX/RX always happen syncronizely
+        */
        if (!dws->dma_mapped && !chip->poll_mode) {
-               if (dws->rx)
-                       imask |= SPI_INT_RXFI;
-               if (dws->tx)
-                       imask |= SPI_INT_TXEI;
+               int templen = dws->len / dws->n_bytes;
+               txint_level = dws->fifo_len / 2;
+               txint_level = (templen > txint_level) ? txint_level : templen;
+
+               imask |= SPI_INT_TXEI;
                dws->transfer_handler = interrupt_transfer;
        }
 
@@ -549,21 +575,23 @@ static void pump_transfers(unsigned long data)
         *      2. clk_div is changed
         *      3. control value changes
         */
-       if (dw_readw(dws, ctrl0) != cr0 || cs_change || clk_div) {
+       if (dw_readw(dws, ctrl0) != cr0 || cs_change || clk_div || imask) {
                spi_enable_chip(dws, 0);
 
                if (dw_readw(dws, ctrl0) != cr0)
                        dw_writew(dws, ctrl0, cr0);
 
+               spi_set_clk(dws, clk_div ? clk_div : chip->clk_div);
+               spi_chip_sel(dws, spi->chip_select);
+
                /* Set the interrupt mask, for poll mode just diable all int */
                spi_mask_intr(dws, 0xff);
-               if (!chip->poll_mode)
+               if (imask)
                        spi_umask_intr(dws, imask);
+               if (txint_level)
+                       dw_writew(dws, txfltr, txint_level);
 
-               spi_set_clk(dws, clk_div ? clk_div : chip->clk_div);
-               spi_chip_sel(dws, spi->chip_select);
                spi_enable_chip(dws, 1);
-
                if (cs_change)
                        dws->prev_chip = chip;
        }
@@ -712,11 +740,11 @@ static int dw_spi_setup(struct spi_device *spi)
        }
        chip->bits_per_word = spi->bits_per_word;
 
+       if (!spi->max_speed_hz) {
+               dev_err(&spi->dev, "No max speed HZ parameter\n");
+               return -EINVAL;
+       }
        chip->speed_hz = spi->max_speed_hz;
-       if (chip->speed_hz)
-               chip->clk_div = 25000000 / chip->speed_hz;
-       else
-               chip->clk_div = 8;      /* default value */
 
        chip->tmode = 0; /* Tx & Rx */
        /* Default SPI mode is SCPOL = 0, SCPH = 0 */
@@ -735,7 +763,7 @@ static void dw_spi_cleanup(struct spi_device *spi)
        kfree(chip);
 }
 
-static int __init init_queue(struct dw_spi *dws)
+static int __devinit init_queue(struct dw_spi *dws)
 {
        INIT_LIST_HEAD(&dws->queue);
        spin_lock_init(&dws->lock);
@@ -817,6 +845,22 @@ static void spi_hw_init(struct dw_spi *dws)
        spi_mask_intr(dws, 0xff);
        spi_enable_chip(dws, 1);
        flush(dws);
+
+       /*
+        * Try to detect the FIFO depth if not set by interface driver,
+        * the depth could be from 2 to 256 from HW spec
+        */
+       if (!dws->fifo_len) {
+               u32 fifo;
+               for (fifo = 2; fifo <= 257; fifo++) {
+                       dw_writew(dws, txfltr, fifo);
+                       if (fifo != dw_readw(dws, txfltr))
+                               break;
+               }
+
+               dws->fifo_len = (fifo == 257) ? 0 : fifo;
+               dw_writew(dws, txfltr, 0);
+       }
 }
 
 int __devinit dw_spi_add_host(struct dw_spi *dws)
@@ -913,6 +957,7 @@ void __devexit dw_spi_remove_host(struct dw_spi *dws)
        /* Disconnect from the SPI framework */
        spi_unregister_master(dws->master);
 }
+EXPORT_SYMBOL(dw_spi_remove_host);
 
 int dw_spi_suspend_host(struct dw_spi *dws)
 {
diff --git a/drivers/spi/dw_spi_mmio.c b/drivers/spi/dw_spi_mmio.c
new file mode 100644 (file)
index 0000000..e35b45a
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * dw_spi_mmio.c - Memory-mapped interface driver for DW SPI Core
+ *
+ * Copyright (c) 2010, Octasic semiconductor.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/spi/dw_spi.h>
+#include <linux/spi/spi.h>
+
+#define DRIVER_NAME "dw_spi_mmio"
+
+struct dw_spi_mmio {
+       struct dw_spi  dws;
+       struct clk     *clk;
+};
+
+static int __devinit dw_spi_mmio_probe(struct platform_device *pdev)
+{
+       struct dw_spi_mmio *dwsmmio;
+       struct dw_spi *dws;
+       struct resource *mem, *ioarea;
+       int ret;
+
+       dwsmmio = kzalloc(sizeof(struct dw_spi_mmio), GFP_KERNEL);
+       if (!dwsmmio) {
+               ret = -ENOMEM;
+               goto err_end;
+       }
+
+       dws = &dwsmmio->dws;
+
+       /* Get basic io resource and map it */
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem) {
+               dev_err(&pdev->dev, "no mem resource?\n");
+               ret = -EINVAL;
+               goto err_kfree;
+       }
+
+       ioarea = request_mem_region(mem->start, resource_size(mem),
+                       pdev->name);
+       if (!ioarea) {
+               dev_err(&pdev->dev, "SPI region already claimed\n");
+               ret = -EBUSY;
+               goto err_kfree;
+       }
+
+       dws->regs = ioremap_nocache(mem->start, resource_size(mem));
+       if (!dws->regs) {
+               dev_err(&pdev->dev, "SPI region already mapped\n");
+               ret = -ENOMEM;
+               goto err_release_reg;
+       }
+
+       dws->irq = platform_get_irq(pdev, 0);
+       if (dws->irq < 0) {
+               dev_err(&pdev->dev, "no irq resource?\n");
+               ret = dws->irq; /* -ENXIO */
+               goto err_unmap;
+       }
+
+       dwsmmio->clk = clk_get(&pdev->dev, NULL);
+       if (!dwsmmio->clk) {
+               ret = -ENODEV;
+               goto err_irq;
+       }
+       clk_enable(dwsmmio->clk);
+
+       dws->parent_dev = &pdev->dev;
+       dws->bus_num = 0;
+       dws->num_cs = 4;
+       dws->max_freq = clk_get_rate(dwsmmio->clk);
+
+       ret = dw_spi_add_host(dws);
+       if (ret)
+               goto err_clk;
+
+       platform_set_drvdata(pdev, dwsmmio);
+       return 0;
+
+err_clk:
+       clk_disable(dwsmmio->clk);
+       clk_put(dwsmmio->clk);
+       dwsmmio->clk = NULL;
+err_irq:
+       free_irq(dws->irq, dws);
+err_unmap:
+       iounmap(dws->regs);
+err_release_reg:
+       release_mem_region(mem->start, resource_size(mem));
+err_kfree:
+       kfree(dwsmmio);
+err_end:
+       return ret;
+}
+
+static int __devexit dw_spi_mmio_remove(struct platform_device *pdev)
+{
+       struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev);
+       struct resource *mem;
+
+       platform_set_drvdata(pdev, NULL);
+
+       clk_disable(dwsmmio->clk);
+       clk_put(dwsmmio->clk);
+       dwsmmio->clk = NULL;
+
+       free_irq(dwsmmio->dws.irq, &dwsmmio->dws);
+       dw_spi_remove_host(&dwsmmio->dws);
+       iounmap(dwsmmio->dws.regs);
+       kfree(dwsmmio);
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(mem->start, resource_size(mem));
+       return 0;
+}
+
+static struct platform_driver dw_spi_mmio_driver = {
+       .remove         = __devexit_p(dw_spi_mmio_remove),
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init dw_spi_mmio_init(void)
+{
+       return platform_driver_probe(&dw_spi_mmio_driver, dw_spi_mmio_probe);
+}
+module_init(dw_spi_mmio_init);
+
+static void __exit dw_spi_mmio_exit(void)
+{
+       platform_driver_unregister(&dw_spi_mmio_driver);
+}
+module_exit(dw_spi_mmio_exit);
+
+MODULE_AUTHOR("Jean-Hugues Deschenes <jean-hugues.deschenes@octasic.com>");
+MODULE_DESCRIPTION("Memory-mapped I/O interface driver for DW SPI Core");
+MODULE_LICENSE("GPL v2");
index 34ba691..1f0735f 100644 (file)
@@ -73,6 +73,7 @@ static int __devinit spi_pci_probe(struct pci_dev *pdev,
        dws->num_cs = 4;
        dws->max_freq = 25000000;       /* for Moorestwon */
        dws->irq = pdev->irq;
+       dws->fifo_len = 40;             /* FIFO has 40 words buffer */
 
        ret = dw_spi_add_host(dws);
        if (ret)
@@ -98,6 +99,7 @@ static void __devexit spi_pci_remove(struct pci_dev *pdev)
        struct dw_spi_pci *dwpci = pci_get_drvdata(pdev);
 
        pci_set_drvdata(pdev, NULL);
+       dw_spi_remove_host(&dwpci->dws);
        iounmap(dwpci->dws.regs);
        pci_release_region(pdev, 0);
        kfree(dwpci);
index f50c81d..0474786 100644 (file)
@@ -503,7 +503,7 @@ static int __exit mpc52xx_psc_spi_of_remove(struct of_device *op)
        return mpc52xx_psc_spi_do_remove(&op->dev);
 }
 
-static struct of_device_id mpc52xx_psc_spi_of_match[] = {
+static const struct of_device_id mpc52xx_psc_spi_of_match[] = {
        { .compatible = "fsl,mpc5200-psc-spi", },
        { .compatible = "mpc5200-psc-spi", }, /* old */
        {}
index 45bfe64..6eab465 100644 (file)
@@ -550,7 +550,7 @@ static int __devexit mpc52xx_spi_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id mpc52xx_spi_match[] __devinitdata = {
+static const struct of_device_id mpc52xx_spi_match[] __devinitconst = {
        { .compatible = "fsl,mpc5200-spi", },
        {}
 };
index 1893f1e..0ddbbe4 100644 (file)
@@ -469,7 +469,7 @@ static int spi_imx_setup(struct spi_device *spi)
        struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
        int gpio = spi_imx->chipselect[spi->chip_select];
 
-       pr_debug("%s: mode %d, %u bpw, %d hz\n", __func__,
+       dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n", __func__,
                 spi->mode, spi->bits_per_word, spi->max_speed_hz);
 
        if (gpio >= 0)
index 1fb2a6e..4f0cc9d 100644 (file)
@@ -365,7 +365,7 @@ int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
 
        if ((mpc8xxx_spi->spibrg / hz) > 64) {
                cs->hw_mode |= SPMODE_DIV16;
-               pm = mpc8xxx_spi->spibrg / (hz * 64);
+               pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1;
 
                WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. "
                          "Will use %d Hz instead.\n", dev_name(&spi->dev),
@@ -373,7 +373,7 @@ int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
                if (pm > 16)
                        pm = 16;
        } else
-               pm = mpc8xxx_spi->spibrg / (hz * 4);
+               pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1;
        if (pm)
                pm--;
 
@@ -1328,7 +1328,7 @@ static struct of_platform_driver of_mpc8xxx_spi_driver = {
 static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev)
 {
        struct resource *mem;
-       unsigned int irq;
+       int irq;
        struct spi_master *master;
 
        if (!pdev->dev.platform_data)
@@ -1339,7 +1339,7 @@ static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev)
                return -EINVAL;
 
        irq = platform_get_irq(pdev, 0);
-       if (!irq)
+       if (irq <= 0)
                return -EINVAL;
 
        master = mpc8xxx_spi_probe(&pdev->dev, mem, irq);
index 140a18d..6d8d402 100644 (file)
@@ -578,7 +578,7 @@ static int __exit spi_ppc4xx_of_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id spi_ppc4xx_of_match[] = {
+static const struct of_device_id spi_ppc4xx_of_match[] = {
        { .compatible = "ibm,ppc4xx-spi", },
        {},
 };
index 88a456d..9736581 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/spi/spi.h>
 
 #include <mach/dma.h>
-#include <plat/spi.h>
+#include <plat/s3c64xx-spi.h>
 
 /* Registers and bit-fields */
 
 /**
  * struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver.
  * @clk: Pointer to the spi clock.
+ * @src_clk: Pointer to the clock used to generate SPI signals.
  * @master: Pointer to the SPI Protocol master.
  * @workqueue: Work queue for the SPI xfer requests.
  * @cntrlr_info: Platform specific data for the controller this driver manages.
 struct s3c64xx_spi_driver_data {
        void __iomem                    *regs;
        struct clk                      *clk;
+       struct clk                      *src_clk;
        struct platform_device          *pdev;
        struct spi_master               *master;
        struct workqueue_struct         *workqueue;
-       struct s3c64xx_spi_cntrlr_info  *cntrlr_info;
+       struct s3c64xx_spi_info  *cntrlr_info;
        struct spi_device               *tgl_spi;
        struct work_struct              work;
        struct list_head                queue;
@@ -180,7 +182,7 @@ static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
 
 static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
 {
-       struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+       struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
        void __iomem *regs = sdd->regs;
        unsigned long loops;
        u32 val;
@@ -225,7 +227,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
                                struct spi_device *spi,
                                struct spi_transfer *xfer, int dma_mode)
 {
-       struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+       struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
        void __iomem *regs = sdd->regs;
        u32 modecfg, chcfg;
 
@@ -298,19 +300,20 @@ static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd,
                if (sdd->tgl_spi != spi) { /* if last mssg on diff device */
                        /* Deselect the last toggled device */
                        cs = sdd->tgl_spi->controller_data;
-                       cs->set_level(spi->mode & SPI_CS_HIGH ? 0 : 1);
+                       cs->set_level(cs->line,
+                                       spi->mode & SPI_CS_HIGH ? 0 : 1);
                }
                sdd->tgl_spi = NULL;
        }
 
        cs = spi->controller_data;
-       cs->set_level(spi->mode & SPI_CS_HIGH ? 1 : 0);
+       cs->set_level(cs->line, spi->mode & SPI_CS_HIGH ? 1 : 0);
 }
 
 static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
                                struct spi_transfer *xfer, int dma_mode)
 {
-       struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+       struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
        void __iomem *regs = sdd->regs;
        unsigned long val;
        int ms;
@@ -384,12 +387,11 @@ static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd,
        if (sdd->tgl_spi == spi)
                sdd->tgl_spi = NULL;
 
-       cs->set_level(spi->mode & SPI_CS_HIGH ? 0 : 1);
+       cs->set_level(cs->line, spi->mode & SPI_CS_HIGH ? 0 : 1);
 }
 
 static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
 {
-       struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
        void __iomem *regs = sdd->regs;
        u32 val;
 
@@ -435,7 +437,7 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
        /* Configure Clock */
        val = readl(regs + S3C64XX_SPI_CLK_CFG);
        val &= ~S3C64XX_SPI_PSR_MASK;
-       val |= ((clk_get_rate(sci->src_clk) / sdd->cur_speed / 2 - 1)
+       val |= ((clk_get_rate(sdd->src_clk) / sdd->cur_speed / 2 - 1)
                        & S3C64XX_SPI_PSR_MASK);
        writel(val, regs + S3C64XX_SPI_CLK_CFG);
 
@@ -558,7 +560,7 @@ static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd,
 static void handle_msg(struct s3c64xx_spi_driver_data *sdd,
                                        struct spi_message *msg)
 {
-       struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+       struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
        struct spi_device *spi = msg->spi;
        struct s3c64xx_spi_csinfo *cs = spi->controller_data;
        struct spi_transfer *xfer;
@@ -632,8 +634,8 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd,
                S3C64XX_SPI_DEACT(sdd);
 
                if (status) {
-                       dev_err(&spi->dev, "I/O Error: \
-                               rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
+                       dev_err(&spi->dev, "I/O Error: "
+                               "rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
                                xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0,
                                (sdd->state & RXBUSY) ? 'f' : 'p',
                                (sdd->state & TXBUSY) ? 'f' : 'p',
@@ -786,7 +788,7 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
 {
        struct s3c64xx_spi_csinfo *cs = spi->controller_data;
        struct s3c64xx_spi_driver_data *sdd;
-       struct s3c64xx_spi_cntrlr_info *sci;
+       struct s3c64xx_spi_info *sci;
        struct spi_message *msg;
        u32 psr, speed;
        unsigned long flags;
@@ -831,17 +833,17 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
        }
 
        /* Check if we can provide the requested rate */
-       speed = clk_get_rate(sci->src_clk) / 2 / (0 + 1); /* Max possible */
+       speed = clk_get_rate(sdd->src_clk) / 2 / (0 + 1); /* Max possible */
 
        if (spi->max_speed_hz > speed)
                spi->max_speed_hz = speed;
 
-       psr = clk_get_rate(sci->src_clk) / 2 / spi->max_speed_hz - 1;
+       psr = clk_get_rate(sdd->src_clk) / 2 / spi->max_speed_hz - 1;
        psr &= S3C64XX_SPI_PSR_MASK;
        if (psr == S3C64XX_SPI_PSR_MASK)
                psr--;
 
-       speed = clk_get_rate(sci->src_clk) / 2 / (psr + 1);
+       speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
        if (spi->max_speed_hz < speed) {
                if (psr+1 < S3C64XX_SPI_PSR_MASK) {
                        psr++;
@@ -851,7 +853,7 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
                }
        }
 
-       speed = clk_get_rate(sci->src_clk) / 2 / (psr + 1);
+       speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
        if (spi->max_speed_hz >= speed)
                spi->max_speed_hz = speed;
        else
@@ -867,7 +869,7 @@ setup_exit:
 
 static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
 {
-       struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+       struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
        void __iomem *regs = sdd->regs;
        unsigned int val;
 
@@ -902,7 +904,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
 {
        struct resource *mem_res, *dmatx_res, *dmarx_res;
        struct s3c64xx_spi_driver_data *sdd;
-       struct s3c64xx_spi_cntrlr_info *sci;
+       struct s3c64xx_spi_info *sci;
        struct spi_master *master;
        int ret;
 
@@ -1000,18 +1002,15 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
                goto err4;
        }
 
-       if (sci->src_clk_nr == S3C64XX_SPI_SRCCLK_PCLK)
-               sci->src_clk = sdd->clk;
-       else
-               sci->src_clk = clk_get(&pdev->dev, sci->src_clk_name);
-       if (IS_ERR(sci->src_clk)) {
+       sdd->src_clk = clk_get(&pdev->dev, sci->src_clk_name);
+       if (IS_ERR(sdd->src_clk)) {
                dev_err(&pdev->dev,
                        "Unable to acquire clock '%s'\n", sci->src_clk_name);
-               ret = PTR_ERR(sci->src_clk);
+               ret = PTR_ERR(sdd->src_clk);
                goto err5;
        }
 
-       if (sci->src_clk != sdd->clk && clk_enable(sci->src_clk)) {
+       if (clk_enable(sdd->src_clk)) {
                dev_err(&pdev->dev, "Couldn't enable clock '%s'\n",
                                                        sci->src_clk_name);
                ret = -EBUSY;
@@ -1040,11 +1039,10 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
                goto err8;
        }
 
-       dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d \
-                                       with %d Slaves attached\n",
+       dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d "
+                                       "with %d Slaves attached\n",
                                        pdev->id, master->num_chipselect);
-       dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\
-                                       \tDMA=[Rx-%d, Tx-%d]\n",
+       dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n",
                                        mem_res->end, mem_res->start,
                                        sdd->rx_dmach, sdd->tx_dmach);
 
@@ -1053,11 +1051,9 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
 err8:
        destroy_workqueue(sdd->workqueue);
 err7:
-       if (sci->src_clk != sdd->clk)
-               clk_disable(sci->src_clk);
+       clk_disable(sdd->src_clk);
 err6:
-       if (sci->src_clk != sdd->clk)
-               clk_put(sci->src_clk);
+       clk_put(sdd->src_clk);
 err5:
        clk_disable(sdd->clk);
 err4:
@@ -1078,7 +1074,6 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
 {
        struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
        struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
-       struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
        struct resource *mem_res;
        unsigned long flags;
 
@@ -1093,11 +1088,8 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
 
        destroy_workqueue(sdd->workqueue);
 
-       if (sci->src_clk != sdd->clk)
-               clk_disable(sci->src_clk);
-
-       if (sci->src_clk != sdd->clk)
-               clk_put(sci->src_clk);
+       clk_disable(sdd->src_clk);
+       clk_put(sdd->src_clk);
 
        clk_disable(sdd->clk);
        clk_put(sdd->clk);
@@ -1105,7 +1097,8 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
        iounmap((void *) sdd->regs);
 
        mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(mem_res->start, resource_size(mem_res));
+       if (mem_res != NULL)
+               release_mem_region(mem_res->start, resource_size(mem_res));
 
        platform_set_drvdata(pdev, NULL);
        spi_master_put(master);
@@ -1118,8 +1111,6 @@ static int s3c64xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
        struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
-       struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
-       struct s3c64xx_spi_csinfo *cs;
        unsigned long flags;
 
        spin_lock_irqsave(&sdd->lock, flags);
@@ -1130,9 +1121,7 @@ static int s3c64xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
                msleep(10);
 
        /* Disable the clock */
-       if (sci->src_clk != sdd->clk)
-               clk_disable(sci->src_clk);
-
+       clk_disable(sdd->src_clk);
        clk_disable(sdd->clk);
 
        sdd->cur_speed = 0; /* Output Clock is stopped */
@@ -1144,15 +1133,13 @@ static int s3c64xx_spi_resume(struct platform_device *pdev)
 {
        struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
        struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
-       struct s3c64xx_spi_cntrlr_info *sci = sdd->cntrlr_info;
+       struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
        unsigned long flags;
 
        sci->cfg_gpio(pdev);
 
        /* Enable the clock */
-       if (sci->src_clk != sdd->clk)
-               clk_enable(sci->src_clk);
-
+       clk_enable(sdd->src_clk);
        clk_enable(sdd->clk);
 
        s3c64xx_spi_hwinit(sdd, pdev->id);
index 30973ec..d93b667 100644 (file)
 #include <linux/bitmap.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/err.h>
 
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
 #include <linux/spi/sh_msiof.h>
 
-#include <asm/spi.h>
 #include <asm/unaligned.h>
 
 struct sh_msiof_spi_priv {
index 2552bb3..fadff76 100644 (file)
@@ -76,7 +76,7 @@ struct stmp_spi {
                        break;                                          \
                }                                                       \
                cpu_relax();                                            \
-       } while (time_before(end_jiffies, jiffies));                    \
+       } while (time_before(jiffies, end_jiffies));                    \
        succeeded;                                                      \
        })
 
index 9f38637..1b47363 100644 (file)
@@ -93,6 +93,26 @@ struct xilinx_spi {
        void (*rx_fn) (struct xilinx_spi *);
 };
 
+static void xspi_write32(u32 val, void __iomem *addr)
+{
+       iowrite32(val, addr);
+}
+
+static unsigned int xspi_read32(void __iomem *addr)
+{
+       return ioread32(addr);
+}
+
+static void xspi_write32_be(u32 val, void __iomem *addr)
+{
+       iowrite32be(val, addr);
+}
+
+static unsigned int xspi_read32_be(void __iomem *addr)
+{
+       return ioread32be(addr);
+}
+
 static void xspi_tx8(struct xilinx_spi *xspi)
 {
        xspi->write_fn(*xspi->tx_ptr, xspi->regs + XSPI_TXD_OFFSET);
@@ -374,11 +394,11 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
        xspi->mem = *mem;
        xspi->irq = irq;
        if (pdata->little_endian) {
-               xspi->read_fn = ioread32;
-               xspi->write_fn = iowrite32;
+               xspi->read_fn = xspi_read32;
+               xspi->write_fn = xspi_write32;
        } else {
-               xspi->read_fn = ioread32be;
-               xspi->write_fn = iowrite32be;
+               xspi->read_fn = xspi_read32_be;
+               xspi->write_fn = xspi_write32_be;
        }
        xspi->bits_per_word = pdata->bits_per_word;
        if (xspi->bits_per_word == 8) {
index 71dc3ad..ed34a8d 100644 (file)
@@ -99,7 +99,7 @@ static int __exit xilinx_spi_of_remove(struct of_device *op)
        return xilinx_spi_remove(op);
 }
 
-static struct of_device_id xilinx_spi_of_match[] = {
+static const struct of_device_id xilinx_spi_of_match[] = {
        { .compatible = "xlnx,xps-spi-2.00.a", },
        { .compatible = "xlnx,xps-spi-2.00.b", },
        {}
index 5681ebe..03dfd27 100644 (file)
@@ -494,8 +494,7 @@ static int ssb_devices_register(struct ssb_bus *bus)
 #endif
                        break;
                case SSB_BUSTYPE_SDIO:
-#ifdef CONFIG_SSB_SDIO
-                       sdev->irq = bus->host_sdio->dev.irq;
+#ifdef CONFIG_SSB_SDIOHOST
                        dev->parent = &bus->host_sdio->dev;
 #endif
                        break;
index 6e8bcdf..a678186 100644 (file)
@@ -1312,9 +1312,9 @@ static int processcompl(struct async *as, void __user * __user *arg)
        void __user *addr = as->userurb;
        unsigned int i;
 
-       if (as->userbuffer)
+       if (as->userbuffer && urb->actual_length)
                if (copy_to_user(as->userbuffer, urb->transfer_buffer,
-                                urb->transfer_buffer_length))
+                                urb->actual_length))
                        goto err_out;
        if (put_user(as->status, &userurb->status))
                goto err_out;
@@ -1334,14 +1334,11 @@ static int processcompl(struct async *as, void __user * __user *arg)
                }
        }
 
-       free_async(as);
-
        if (put_user(addr, (void __user * __user *)arg))
                return -EFAULT;
        return 0;
 
 err_out:
-       free_async(as);
        return -EFAULT;
 }
 
@@ -1371,8 +1368,11 @@ static struct async *reap_as(struct dev_state *ps)
 static int proc_reapurb(struct dev_state *ps, void __user *arg)
 {
        struct async *as = reap_as(ps);
-       if (as)
-               return processcompl(as, (void __user * __user *)arg);
+       if (as) {
+               int retval = processcompl(as, (void __user * __user *)arg);
+               free_async(as);
+               return retval;
+       }
        if (signal_pending(current))
                return -EINTR;
        return -EIO;
@@ -1380,11 +1380,16 @@ static int proc_reapurb(struct dev_state *ps, void __user *arg)
 
 static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg)
 {
+       int retval;
        struct async *as;
 
-       if (!(as = async_getcompleted(ps)))
-               return -EAGAIN;
-       return processcompl(as, (void __user * __user *)arg);
+       as = async_getcompleted(ps);
+       retval = -EAGAIN;
+       if (as) {
+               retval = processcompl(as, (void __user * __user *)arg);
+               free_async(as);
+       }
+       return retval;
 }
 
 #ifdef CONFIG_COMPAT
@@ -1475,9 +1480,9 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
        void __user *addr = as->userurb;
        unsigned int i;
 
-       if (as->userbuffer)
+       if (as->userbuffer && urb->actual_length)
                if (copy_to_user(as->userbuffer, urb->transfer_buffer,
-                                urb->transfer_buffer_length))
+                                urb->actual_length))
                        return -EFAULT;
        if (put_user(as->status, &userurb->status))
                return -EFAULT;
@@ -1497,7 +1502,6 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
                }
        }
 
-       free_async(as);
        if (put_user(ptr_to_compat(addr), (u32 __user *)arg))
                return -EFAULT;
        return 0;
@@ -1506,8 +1510,11 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
 static int proc_reapurb_compat(struct dev_state *ps, void __user *arg)
 {
        struct async *as = reap_as(ps);
-       if (as)
-               return processcompl_compat(as, (void __user * __user *)arg);
+       if (as) {
+               int retval = processcompl_compat(as, (void __user * __user *)arg);
+               free_async(as);
+               return retval;
+       }
        if (signal_pending(current))
                return -EINTR;
        return -EIO;
@@ -1515,11 +1522,16 @@ static int proc_reapurb_compat(struct dev_state *ps, void __user *arg)
 
 static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg)
 {
+       int retval;
        struct async *as;
 
-       if (!(as = async_getcompleted(ps)))
-               return -EAGAIN;
-       return processcompl_compat(as, (void __user * __user *)arg);
+       retval = -EAGAIN;
+       as = async_getcompleted(ps);
+       if (as) {
+               retval = processcompl_compat(as, (void __user * __user *)arg);
+               free_async(as);
+       }
+       return retval;
 }
 
 
index 0a577d5..d4f0db5 100644 (file)
@@ -358,7 +358,7 @@ done:
         * b15:         bmType (0 == data)
         */
        len = skb->len;
-       put_unaligned_le16((len & 0x3FFF) | BIT(14), skb_push(skb, 2));
+       put_unaligned_le16(len & 0x3FFF, skb_push(skb, 2));
 
        /* add a zero-length EEM packet, if needed */
        if (padlen)
@@ -464,7 +464,6 @@ static int eem_unwrap(struct gether *port,
                        }
 
                        /* validate CRC */
-                       crc = get_unaligned_le32(skb->data + len - ETH_FCS_LEN);
                        if (header & BIT(14)) {
                                crc = get_unaligned_le32(skb->data + len
                                                        - ETH_FCS_LEN);
index 4295601..76496f5 100644 (file)
@@ -29,7 +29,7 @@
 #if defined USB_ETH_RNDIS
 #  undef USB_ETH_RNDIS
 #endif
-#ifdef CONFIG_USB_ETH_RNDIS
+#ifdef CONFIG_USB_G_MULTI_RNDIS
 #  define USB_ETH_RNDIS y
 #endif
 
index e220fb8..8b45145 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/err.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
index 4b5dbd0..5fc80a1 100644 (file)
@@ -2582,6 +2582,7 @@ err:
        hsotg->gadget.dev.driver = NULL;
        return ret;
 }
+EXPORT_SYMBOL(usb_gadget_register_driver);
 
 int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 {
index c75d927..1937267 100644 (file)
@@ -196,7 +196,9 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
                        if (hostpc_reg) {
                                u32     t3;
 
+                               spin_unlock_irq(&ehci->lock);
                                msleep(5);/* 5ms for HCD enter low pwr mode */
+                               spin_lock_irq(&ehci->lock);
                                t3 = ehci_readl(ehci, hostpc_reg);
                                ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg);
                                t3 = ehci_readl(ehci, hostpc_reg);
@@ -904,17 +906,18 @@ static int ehci_hub_control (
                        if ((temp & PORT_PE) == 0
                                        || (temp & PORT_RESET) != 0)
                                goto error;
-                       ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
+
                        /* After above check the port must be connected.
                         * Set appropriate bit thus could put phy into low power
                         * mode if we have hostpc feature
                         */
+                       temp &= ~PORT_WKCONN_E;
+                       temp |= PORT_WKDISC_E | PORT_WKOC_E;
+                       ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
                        if (hostpc_reg) {
-                               temp &= ~PORT_WKCONN_E;
-                               temp |= (PORT_WKDISC_E | PORT_WKOC_E);
-                               ehci_writel(ehci, temp | PORT_SUSPEND,
-                                                       status_reg);
+                               spin_unlock_irqrestore(&ehci->lock, flags);
                                msleep(5);/* 5ms for HCD enter low pwr mode */
+                               spin_lock_irqsave(&ehci->lock, flags);
                                temp1 = ehci_readl(ehci, hostpc_reg);
                                ehci_writel(ehci, temp1 | HOSTPC_PHCD,
                                        hostpc_reg);
index d224ab4..e123289 100644 (file)
@@ -105,7 +105,7 @@ void fhci_ep0_free(struct fhci_usb *usb)
                if (ep->td_base)
                        cpm_muram_free(cpm_muram_offset(ep->td_base));
 
-               if (ep->conf_frame_Q) {
+               if (kfifo_initialized(&ep->conf_frame_Q)) {
                        size = cq_howmany(&ep->conf_frame_Q);
                        for (; size; size--) {
                                struct packet *pkt = cq_get(&ep->conf_frame_Q);
@@ -115,7 +115,7 @@ void fhci_ep0_free(struct fhci_usb *usb)
                        cq_delete(&ep->conf_frame_Q);
                }
 
-               if (ep->empty_frame_Q) {
+               if (kfifo_initialized(&ep->empty_frame_Q)) {
                        size = cq_howmany(&ep->empty_frame_Q);
                        for (; size; size--) {
                                struct packet *pkt = cq_get(&ep->empty_frame_Q);
@@ -125,7 +125,7 @@ void fhci_ep0_free(struct fhci_usb *usb)
                        cq_delete(&ep->empty_frame_Q);
                }
 
-               if (ep->dummy_packets_Q) {
+               if (kfifo_initialized(&ep->dummy_packets_Q)) {
                        size = cq_howmany(&ep->dummy_packets_Q);
                        for (; size; size--) {
                                u8 *buff = cq_get(&ep->dummy_packets_Q);
index 0025847..8b37a4b 100644 (file)
@@ -3245,6 +3245,7 @@ static struct usb_device_id sisusb_table [] = {
        { USB_DEVICE(0x0711, 0x0902) },
        { USB_DEVICE(0x0711, 0x0903) },
        { USB_DEVICE(0x0711, 0x0918) },
+       { USB_DEVICE(0x0711, 0x0920) },
        { USB_DEVICE(0x182d, 0x021c) },
        { USB_DEVICE(0x182d, 0x0269) },
        { }
index de56b3d..3d2d3e5 100644 (file)
@@ -44,6 +44,7 @@ config ISP1301_OMAP
 config USB_ULPI
        bool "Generic ULPI Transceiver Driver"
        depends on ARM
+       select USB_OTG_UTILS
        help
          Enable this to support ULPI connected USB OTG transceivers which
          are likely found on embedded boards.
index 216f187..7638828 100644 (file)
@@ -50,7 +50,7 @@
  * Version Information
  */
 #define DRIVER_VERSION "v1.5.0"
-#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>"
+#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>, Andreas Mohr"
 #define DRIVER_DESC "USB FTDI Serial Converters Driver"
 
 static int debug;
@@ -145,10 +145,15 @@ static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = {
 
 
 
+/*
+ * Device ID not listed? Test via module params product/vendor or
+ * /sys/bus/usb/ftdi_sio/new_id, then send patch/report!
+ */
 static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_NXTCAM_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) },
@@ -552,9 +557,16 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) },
        /*
-        * Due to many user requests for multiple ELV devices we enable
-        * them by default.
+        * ELV devices:
         */
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_USR_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_MSM1_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_KL100_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_WS550_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_EC3000_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_WS888_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_TWS550_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_FEM_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) },
@@ -571,11 +583,17 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_UTP8_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_WS444PC_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1010PC_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_ELV_HS485_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_UMS100_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_TFD128_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_FM3RX_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_ELV_WS777_PID) },
        { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
        { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
        { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
@@ -697,6 +715,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
        { USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) },
        { USB_DEVICE(PAPOUCH_VID, PAPOUCH_QUIDO4x4_PID) },
+       { USB_DEVICE(PAPOUCH_VID, PAPOUCH_AD4USB_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DGQG_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_DOMINTELL_DUSB_PID) },
        { USB_DEVICE(ALTI2_VID, ALTI2_N3_PID) },
index da92b49..c8951ae 100644 (file)
@@ -38,6 +38,8 @@
 /* www.candapter.com Ewert Energy Systems CANdapter device */
 #define FTDI_CANDAPTER_PID 0x9F80 /* Product Id */
 
+#define FTDI_NXTCAM_PID                0xABB8 /* NXTCam for Mindstorms NXT */
+
 /* OOCDlink by Joern Kaipf <joernk@web.de>
  * (http://www.joernonline.de/dw/doku.php?id=start&idx=projects:oocdlink) */
 #define FTDI_OOCDLINK_PID      0xbaf8  /* Amontec JTAGkey */
 /*
  * ELV USB devices submitted by Christian Abt of ELV (www.elv.de).
  * All of these devices use FTDI's vendor ID (0x0403).
+ * Further IDs taken from ELV Windows .inf file.
  *
  * The previously included PID for the UO 100 module was incorrect.
  * In fact, that PID was for ELV's UR 100 USB-RS232 converter (0xFB58).
  *
  * Armin Laeuger originally sent the PID for the UM 100 module.
  */
+#define FTDI_ELV_USR_PID       0xE000  /* ELV Universal-Sound-Recorder */
+#define FTDI_ELV_MSM1_PID      0xE001  /* ELV Mini-Sound-Modul */
+#define FTDI_ELV_KL100_PID     0xE002  /* ELV Kfz-Leistungsmesser KL 100 */
+#define FTDI_ELV_WS550_PID     0xE004  /* WS 550 */
+#define FTDI_ELV_EC3000_PID    0xE006  /* ENERGY CONTROL 3000 USB */
+#define FTDI_ELV_WS888_PID     0xE008  /* WS 888 */
+#define FTDI_ELV_TWS550_PID    0xE009  /* Technoline WS 550 */
+#define FTDI_ELV_FEM_PID       0xE00A  /* Funk Energie Monitor */
 #define FTDI_ELV_FHZ1300PC_PID 0xE0E8  /* FHZ 1300 PC */
 #define FTDI_ELV_WS500_PID     0xE0E9  /* PC-Wetterstation (WS 500) */
 #define FTDI_ELV_HS485_PID     0xE0EA  /* USB to RS-485 adapter */
+#define FTDI_ELV_UMS100_PID    0xE0EB  /* ELV USB Master-Slave Schaltsteckdose UMS 100 */
+#define FTDI_ELV_TFD128_PID    0xE0EC  /* ELV Temperatur-Feuchte-Datenlogger TFD 128 */
+#define FTDI_ELV_FM3RX_PID     0xE0ED  /* ELV Messwertuebertragung FM3 RX */
+#define FTDI_ELV_WS777_PID     0xE0EE  /* Conrad WS 777 */
 #define FTDI_ELV_EM1010PC_PID  0xE0EF  /* Engery monitor EM 1010 PC */
 #define FTDI_ELV_CSI8_PID      0xE0F0  /* Computer-Schalt-Interface (CSI 8) */
 #define FTDI_ELV_EM1000DL_PID  0xE0F1  /* PC-Datenlogger fuer Energiemonitor (EM 1000 DL) */
 #define FTDI_ELV_PCK100_PID    0xE0F2  /* PC-Kabeltester (PCK 100) */
 #define FTDI_ELV_RFP500_PID    0xE0F3  /* HF-Leistungsmesser (RFP 500) */
 #define FTDI_ELV_FS20SIG_PID   0xE0F4  /* Signalgeber (FS 20 SIG) */
+#define FTDI_ELV_UTP8_PID      0xE0F5  /* ELV UTP 8 */
 #define FTDI_ELV_WS300PC_PID   0xE0F6  /* PC-Wetterstation (WS 300 PC) */
+#define FTDI_ELV_WS444PC_PID   0xE0F7  /* Conrad WS 444 PC */
 #define FTDI_PHI_FISCO_PID      0xE40B  /* PHI Fisco USB to Serial cable */
 #define FTDI_ELV_UAD8_PID      0xF068  /* USB-AD-Wandler (UAD 8) */
 #define FTDI_ELV_UDA7_PID      0xF069  /* USB-DA-Wandler (UDA 7) */
 #define PAPOUCH_VID                    0x5050  /* Vendor ID */
 #define PAPOUCH_TMU_PID                        0x0400  /* TMU USB Thermometer */
 #define PAPOUCH_QUIDO4x4_PID           0x0900  /* Quido 4/4 Module */
+#define PAPOUCH_AD4USB_PID             0x8003  /* AD4USB Measurement Module */
 
 /*
  * Marvell SheevaPlug
index ac1b644..3eb6143 100644 (file)
@@ -298,6 +298,7 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x1199, 0x68A3),   /* Sierra Wireless Direct IP modems */
          .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
        },
+       { USB_DEVICE(0x413C, 0x08133) }, /* Dell Computer Corp. Wireless 5720 VZW Mobile Broadband (EVDO Rev-A) Minicard GPS Port */
 
        { }
 };
index c932f90..49575fb 100644 (file)
@@ -941,7 +941,7 @@ UNUSUAL_DEV(  0x07ab, 0xfccd, 0x0000, 0x9999,
 UNUSUAL_DEV(  0x07af, 0x0004, 0x0100, 0x0133,
                "Microtech",
                "USB-SCSI-DB25",
-               US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
+               US_SC_DEVICE, US_PR_DEVICE, usb_stor_euscsi_init,
                US_FL_SCM_MULT_TARG ), 
 
 UNUSUAL_DEV(  0x07af, 0x0005, 0x0100, 0x0100,
index e4e4d43..9ee67d6 100644 (file)
@@ -1931,22 +1931,22 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i
                         * PowerMac2,2 summer 2000 iMacs
                         * PowerMac4,1 january 2001 iMacs "flower power"
                         */
-                       if (machine_is_compatible("PowerMac2,1") ||
-                           machine_is_compatible("PowerMac2,2") ||
-                           machine_is_compatible("PowerMac4,1"))
+                       if (of_machine_is_compatible("PowerMac2,1") ||
+                           of_machine_is_compatible("PowerMac2,2") ||
+                           of_machine_is_compatible("PowerMac4,1"))
                                default_vmode = VMODE_1024_768_75;
 
                        /* iBook SE */
-                       if (machine_is_compatible("PowerBook2,2"))
+                       if (of_machine_is_compatible("PowerBook2,2"))
                                default_vmode = VMODE_800_600_60;
 
                        /* PowerBook Firewire (Pismo), iBook Dual USB */
-                       if (machine_is_compatible("PowerBook3,1") ||
-                           machine_is_compatible("PowerBook4,1"))
+                       if (of_machine_is_compatible("PowerBook3,1") ||
+                           of_machine_is_compatible("PowerBook4,1"))
                                default_vmode = VMODE_1024_768_60;
 
                        /* PowerBook Titanium */
-                       if (machine_is_compatible("PowerBook3,2"))
+                       if (of_machine_is_compatible("PowerBook3,2"))
                                default_vmode = VMODE_1152_768_60;
        
                        if (default_cmode > 16) 
index 1ddeb4c..e45ab8d 100644 (file)
@@ -2439,7 +2439,7 @@ static int __devinit aty_init(struct fb_info *info)
         * The Apple iBook1 uses non-standard memory frequencies.
         * We detect it and set the frequency manually.
         */
-       if (machine_is_compatible("PowerBook2,1")) {
+       if (of_machine_is_compatible("PowerBook2,1")) {
                par->pll_limits.mclk = 70;
                par->pll_limits.xclk = 53;
        }
@@ -2659,7 +2659,7 @@ static int __devinit aty_init(struct fb_info *info)
                      FBINFO_HWACCEL_YPAN;
 
 #ifdef CONFIG_PMAC_BACKLIGHT
-       if (M64_HAS(G3_PB_1_1) && machine_is_compatible("PowerBook1,1")) {
+       if (M64_HAS(G3_PB_1_1) && of_machine_is_compatible("PowerBook1,1")) {
                /*
                 * these bits let the 101 powerbook
                 * wake up from sleep -- paulus
@@ -2690,9 +2690,9 @@ static int __devinit aty_init(struct fb_info *info)
                                if (M64_HAS(G3_PB_1024x768))
                                        /* G3 PowerBook with 1024x768 LCD */
                                        default_vmode = VMODE_1024_768_60;
-                               else if (machine_is_compatible("iMac"))
+                               else if (of_machine_is_compatible("iMac"))
                                        default_vmode = VMODE_1024_768_75;
-                               else if (machine_is_compatible("PowerBook2,1"))
+                               else if (of_machine_is_compatible("PowerBook2,1"))
                                        /* iBook with 800x600 LCD */
                                        default_vmode = VMODE_800_600_60;
                                else
@@ -3104,7 +3104,7 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
        }
 
        dp = pci_device_to_OF_node(pdev);
-       if (node == dp->node) {
+       if (node == dp->phandle) {
                struct fb_var_screeninfo *var = &default_var;
                unsigned int N, P, Q, M, T, R;
                u32 v_total, h_total;
index 1a056ad..fa1198c 100644 (file)
@@ -175,9 +175,9 @@ void radeonfb_bl_init(struct radeonfb_info *rinfo)
 
 #ifdef CONFIG_PMAC_BACKLIGHT
        pdata->negative = pdata->negative ||
-               machine_is_compatible("PowerBook4,3") ||
-               machine_is_compatible("PowerBook6,3") ||
-               machine_is_compatible("PowerBook6,5");
+               of_machine_is_compatible("PowerBook4,3") ||
+               of_machine_is_compatible("PowerBook6,3") ||
+               of_machine_is_compatible("PowerBook6,5");
 #endif
 
        rinfo->info->bl_dev = bd;
index eb12182..d25df51 100644 (file)
@@ -161,8 +161,17 @@ static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
        return 0;
 }
 
+static void efifb_destroy(struct fb_info *info)
+{
+       if (info->screen_base)
+               iounmap(info->screen_base);
+       release_mem_region(info->aperture_base, info->aperture_size);
+       framebuffer_release(info);
+}
+
 static struct fb_ops efifb_ops = {
        .owner          = THIS_MODULE,
+       .fb_destroy     = efifb_destroy,
        .fb_setcolreg   = efifb_setcolreg,
        .fb_fillrect    = cfb_fillrect,
        .fb_copyarea    = cfb_copyarea,
@@ -281,7 +290,7 @@ static int __init efifb_probe(struct platform_device *dev)
        info->par = NULL;
 
        info->aperture_base = efifb_fix.smem_start;
-       info->aperture_size = size_total;
+       info->aperture_size = size_remap;
 
        info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len);
        if (!info->screen_base) {
index 505be88..369f2ee 100644 (file)
@@ -28,7 +28,7 @@
 struct virtio_balloon
 {
        struct virtio_device *vdev;
-       struct virtqueue *inflate_vq, *deflate_vq;
+       struct virtqueue *inflate_vq, *deflate_vq, *stats_vq;
 
        /* Where the ballooning thread waits for config to change. */
        wait_queue_head_t config_change;
@@ -49,6 +49,10 @@ struct virtio_balloon
        /* The array of pfns we tell the Host about. */
        unsigned int num_pfns;
        u32 pfns[256];
+
+       /* Memory statistics */
+       int need_stats_update;
+       struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
 };
 
 static struct virtio_device_id id_table[] = {
@@ -154,6 +158,72 @@ static void leak_balloon(struct virtio_balloon *vb, size_t num)
        }
 }
 
+static inline void update_stat(struct virtio_balloon *vb, int idx,
+                              u16 tag, u64 val)
+{
+       BUG_ON(idx >= VIRTIO_BALLOON_S_NR);
+       vb->stats[idx].tag = tag;
+       vb->stats[idx].val = val;
+}
+
+#define pages_to_bytes(x) ((u64)(x) << PAGE_SHIFT)
+
+static void update_balloon_stats(struct virtio_balloon *vb)
+{
+       unsigned long events[NR_VM_EVENT_ITEMS];
+       struct sysinfo i;
+       int idx = 0;
+
+       all_vm_events(events);
+       si_meminfo(&i);
+
+       update_stat(vb, idx++, VIRTIO_BALLOON_S_SWAP_IN,
+                               pages_to_bytes(events[PSWPIN]));
+       update_stat(vb, idx++, VIRTIO_BALLOON_S_SWAP_OUT,
+                               pages_to_bytes(events[PSWPOUT]));
+       update_stat(vb, idx++, VIRTIO_BALLOON_S_MAJFLT, events[PGMAJFAULT]);
+       update_stat(vb, idx++, VIRTIO_BALLOON_S_MINFLT, events[PGFAULT]);
+       update_stat(vb, idx++, VIRTIO_BALLOON_S_MEMFREE,
+                               pages_to_bytes(i.freeram));
+       update_stat(vb, idx++, VIRTIO_BALLOON_S_MEMTOT,
+                               pages_to_bytes(i.totalram));
+}
+
+/*
+ * While most virtqueues communicate guest-initiated requests to the hypervisor,
+ * the stats queue operates in reverse.  The driver initializes the virtqueue
+ * with a single buffer.  From that point forward, all conversations consist of
+ * a hypervisor request (a call to this function) which directs us to refill
+ * the virtqueue with a fresh stats buffer.  Since stats collection can sleep,
+ * we notify our kthread which does the actual work via stats_handle_request().
+ */
+static void stats_request(struct virtqueue *vq)
+{
+       struct virtio_balloon *vb;
+       unsigned int len;
+
+       vb = vq->vq_ops->get_buf(vq, &len);
+       if (!vb)
+               return;
+       vb->need_stats_update = 1;
+       wake_up(&vb->config_change);
+}
+
+static void stats_handle_request(struct virtio_balloon *vb)
+{
+       struct virtqueue *vq;
+       struct scatterlist sg;
+
+       vb->need_stats_update = 0;
+       update_balloon_stats(vb);
+
+       vq = vb->stats_vq;
+       sg_init_one(&sg, vb->stats, sizeof(vb->stats));
+       if (vq->vq_ops->add_buf(vq, &sg, 1, 0, vb) < 0)
+               BUG();
+       vq->vq_ops->kick(vq);
+}
+
 static void virtballoon_changed(struct virtio_device *vdev)
 {
        struct virtio_balloon *vb = vdev->priv;
@@ -190,8 +260,11 @@ static int balloon(void *_vballoon)
                try_to_freeze();
                wait_event_interruptible(vb->config_change,
                                         (diff = towards_target(vb)) != 0
+                                        || vb->need_stats_update
                                         || kthread_should_stop()
                                         || freezing(current));
+               if (vb->need_stats_update)
+                       stats_handle_request(vb);
                if (diff > 0)
                        fill_balloon(vb, diff);
                else if (diff < 0)
@@ -204,10 +277,10 @@ static int balloon(void *_vballoon)
 static int virtballoon_probe(struct virtio_device *vdev)
 {
        struct virtio_balloon *vb;
-       struct virtqueue *vqs[2];
-       vq_callback_t *callbacks[] = { balloon_ack, balloon_ack };
-       const char *names[] = { "inflate", "deflate" };
-       int err;
+       struct virtqueue *vqs[3];
+       vq_callback_t *callbacks[] = { balloon_ack, balloon_ack, stats_request };
+       const char *names[] = { "inflate", "deflate", "stats" };
+       int err, nvqs;
 
        vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL);
        if (!vb) {
@@ -219,14 +292,31 @@ static int virtballoon_probe(struct virtio_device *vdev)
        vb->num_pages = 0;
        init_waitqueue_head(&vb->config_change);
        vb->vdev = vdev;
+       vb->need_stats_update = 0;
 
-       /* We expect two virtqueues. */
-       err = vdev->config->find_vqs(vdev, 2, vqs, callbacks, names);
+       /* We expect two virtqueues: inflate and deflate,
+        * and optionally stat. */
+       nvqs = virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ) ? 3 : 2;
+       err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names);
        if (err)
                goto out_free_vb;
 
        vb->inflate_vq = vqs[0];
        vb->deflate_vq = vqs[1];
+       if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ)) {
+               struct scatterlist sg;
+               vb->stats_vq = vqs[2];
+
+               /*
+                * Prime this virtqueue with one buffer so the hypervisor can
+                * use it to signal us later.
+                */
+               sg_init_one(&sg, vb->stats, sizeof vb->stats);
+               if (vb->stats_vq->vq_ops->add_buf(vb->stats_vq,
+                                                 &sg, 1, 0, vb) < 0)
+                       BUG();
+               vb->stats_vq->vq_ops->kick(vb->stats_vq);
+       }
 
        vb->thread = kthread_run(balloon, vb, "vballoon");
        if (IS_ERR(vb->thread)) {
@@ -264,7 +354,10 @@ static void __devexit virtballoon_remove(struct virtio_device *vdev)
        kfree(vb);
 }
 
-static unsigned int features[] = { VIRTIO_BALLOON_F_MUST_TELL_HOST };
+static unsigned int features[] = {
+       VIRTIO_BALLOON_F_MUST_TELL_HOST,
+       VIRTIO_BALLOON_F_STATS_VQ,
+};
 
 static struct virtio_driver virtio_balloon_driver = {
        .feature_table = features,
index 28d9cf7..1d5191f 100644 (file)
@@ -702,7 +702,7 @@ static struct pci_driver virtio_pci_driver = {
        .name           = "virtio-pci",
        .id_table       = virtio_pci_id_table,
        .probe          = virtio_pci_probe,
-       .remove         = virtio_pci_remove,
+       .remove         = __devexit_p(virtio_pci_remove),
 #ifdef CONFIG_PM
        .suspend        = virtio_pci_suspend,
        .resume         = virtio_pci_resume,
index fbd2ecd..0db906b 100644 (file)
 #include <linux/virtio_config.h>
 #include <linux/device.h>
 
+/* virtio guest is communicating with a virtual "device" that actually runs on
+ * a host processor.  Memory barriers are used to control SMP effects. */
+#ifdef CONFIG_SMP
+/* Where possible, use SMP barriers which are more lightweight than mandatory
+ * barriers, because mandatory barriers control MMIO effects on accesses
+ * through relaxed memory I/O windows (which virtio does not use). */
+#define virtio_mb() smp_mb()
+#define virtio_rmb() smp_rmb()
+#define virtio_wmb() smp_wmb()
+#else
+/* We must force memory ordering even if guest is UP since host could be
+ * running on another CPU, but SMP barriers are defined to barrier() in that
+ * configuration. So fall back to mandatory barriers instead. */
+#define virtio_mb() mb()
+#define virtio_rmb() rmb()
+#define virtio_wmb() wmb()
+#endif
+
 #ifdef DEBUG
 /* For development, we want to crash whenever the ring is screwed. */
 #define BAD_RING(_vq, fmt, args...)                            \
                        panic("%s:in_use = %i\n",               \
                              (_vq)->vq.name, (_vq)->in_use);   \
                (_vq)->in_use = __LINE__;                       \
-               mb();                                           \
        } while (0)
 #define END_USE(_vq) \
-       do { BUG_ON(!(_vq)->in_use); (_vq)->in_use = 0; mb(); } while(0)
+       do { BUG_ON(!(_vq)->in_use); (_vq)->in_use = 0; } while(0)
 #else
 #define BAD_RING(_vq, fmt, args...)                            \
        do {                                                    \
@@ -221,13 +238,13 @@ static void vring_kick(struct virtqueue *_vq)
        START_USE(vq);
        /* Descriptors and available array need to be set before we expose the
         * new available array entries. */
-       wmb();
+       virtio_wmb();
 
        vq->vring.avail->idx += vq->num_added;
        vq->num_added = 0;
 
        /* Need to update avail index before checking if we should notify */
-       mb();
+       virtio_mb();
 
        if (!(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY))
                /* Prod other side to tell it about changes. */
@@ -286,7 +303,7 @@ static void *vring_get_buf(struct virtqueue *_vq, unsigned int *len)
        }
 
        /* Only get used array entries after they have been exposed by host. */
-       rmb();
+       virtio_rmb();
 
        i = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].id;
        *len = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].len;
@@ -324,7 +341,7 @@ static bool vring_enable_cb(struct virtqueue *_vq)
        /* We optimistically turn back on interrupts, then check if there was
         * more to do. */
        vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
-       mb();
+       virtio_mb();
        if (unlikely(more_used(vq))) {
                END_USE(vq);
                return false;
@@ -334,6 +351,30 @@ static bool vring_enable_cb(struct virtqueue *_vq)
        return true;
 }
 
+static void *vring_detach_unused_buf(struct virtqueue *_vq)
+{
+       struct vring_virtqueue *vq = to_vvq(_vq);
+       unsigned int i;
+       void *buf;
+
+       START_USE(vq);
+
+       for (i = 0; i < vq->vring.num; i++) {
+               if (!vq->data[i])
+                       continue;
+               /* detach_buf clears data, so grab it now. */
+               buf = vq->data[i];
+               detach_buf(vq, i);
+               END_USE(vq);
+               return buf;
+       }
+       /* That should have freed everything. */
+       BUG_ON(vq->num_free != vq->vring.num);
+
+       END_USE(vq);
+       return NULL;
+}
+
 irqreturn_t vring_interrupt(int irq, void *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
@@ -360,6 +401,7 @@ static struct virtqueue_ops vring_vq_ops = {
        .kick = vring_kick,
        .disable_cb = vring_disable_cb,
        .enable_cb = vring_enable_cb,
+       .detach_unused_buf = vring_detach_unused_buf,
 };
 
 struct virtqueue *vring_new_virtqueue(unsigned int num,
@@ -406,8 +448,11 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
        /* Put everything in free lists. */
        vq->num_free = num;
        vq->free_head = 0;
-       for (i = 0; i < num-1; i++)
+       for (i = 0; i < num-1; i++) {
                vq->vring.desc[i].next = i+1;
+               vq->data[i] = NULL;
+       }
+       vq->data[i] = NULL;
 
        return &vq->vq;
 }
index c7b3f9d..2159e66 100644 (file)
@@ -1,9 +1,8 @@
 /*
  * Blackfin On-Chip Watchdog Driver
- *  Supports BF53[123]/BF53[467]/BF54[2489]/BF561
  *
  * Originally based on softdog.c
- * Copyright 2006-2007 Analog Devices Inc.
+ * Copyright 2006-2010 Analog Devices Inc.
  * Copyright 2006-2007 Michele d'Amico
  * Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
@@ -137,13 +136,15 @@ static int bfin_wdt_running(void)
  */
 static int bfin_wdt_set_timeout(unsigned long t)
 {
-       u32 cnt;
+       u32 cnt, max_t, sclk;
        unsigned long flags;
 
-       stampit();
+       sclk = get_sclk();
+       max_t = -1 / sclk;
+       cnt = t * sclk;
+       stamp("maxtimeout=%us newtimeout=%lus (cnt=%#x)", max_t, t, cnt);
 
-       cnt = t * get_sclk();
-       if (cnt < get_sclk()) {
+       if (t > max_t) {
                printk(KERN_WARNING PFX "timeout value is too large\n");
                return -EINVAL;
        }
index 14ac480..eeb4986 100644 (file)
@@ -348,7 +348,17 @@ int cachefiles_delete_object(struct cachefiles_cache *cache,
        dir = dget_parent(object->dentry);
 
        mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
-       ret = cachefiles_bury_object(cache, dir, object->dentry);
+
+       /* we need to check that our parent is _still_ our parent - it may have
+        * been renamed */
+       if (dir == object->dentry->d_parent) {
+               ret = cachefiles_bury_object(cache, dir, object->dentry);
+       } else {
+               /* it got moved, presumably by cachefilesd culling it, so it's
+                * no longer in the key path and we can ignore it */
+               mutex_unlock(&dir->d_inode->i_mutex);
+               ret = 0;
+       }
 
        dput(dir);
        _leave(" = %d", ret);
index e95c692..cce6bbd 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -637,7 +637,6 @@ int setup_arg_pages(struct linux_binprm *bprm,
         * will align it up.
         */
        rlim_stack = rlimit(RLIMIT_STACK) & PAGE_MASK;
-       rlim_stack = min(rlim_stack, stack_size);
 #ifdef CONFIG_STACK_GROWSUP
        if (stack_size + stack_expand > rlim_stack)
                stack_base = vma->vm_start + rlim_stack;
index d62fdc8..a4855af 100644 (file)
@@ -823,6 +823,17 @@ fail:
 }
 
 /*
+ * This is a temporary kludge to deal with "automount" symlinks; proper
+ * solution is to trigger them on follow_mount(), so that do_lookup()
+ * would DTRT.  To be killed before 2.6.34-final.
+ */
+static inline int follow_on_final(struct inode *inode, unsigned lookup_flags)
+{
+       return inode && unlikely(inode->i_op->follow_link) &&
+               ((lookup_flags & LOOKUP_FOLLOW) || S_ISDIR(inode->i_mode));
+}
+
+/*
  * Name resolution.
  * This is the basic name resolution function, turning a pathname into
  * the final dentry. We expect 'base' to be positive and a directory.
@@ -942,8 +953,7 @@ last_component:
                if (err)
                        break;
                inode = next.dentry->d_inode;
-               if ((lookup_flags & LOOKUP_FOLLOW)
-                   && inode && inode->i_op->follow_link) {
+               if (follow_on_final(inode, lookup_flags)) {
                        err = do_follow_link(&next, nd);
                        if (err)
                                goto return_err;
index 97d79ef..8715d19 100644 (file)
@@ -752,7 +752,8 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
                            flags, current_cred());
        if (IS_ERR(*filp))
                host_err = PTR_ERR(*filp);
-       host_err = ima_file_check(*filp, access);
+       else
+               host_err = ima_file_check(*filp, access);
 out_nfserr:
        err = nfserrno(host_err);
 out:
index e42bbd8..58324c2 100644 (file)
@@ -2369,16 +2369,30 @@ static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
        struct pid_namespace *ns = dentry->d_sb->s_fs_info;
        pid_t tgid = task_tgid_nr_ns(current, ns);
-       char tmp[PROC_NUMBUF];
-       if (!tgid)
-               return ERR_PTR(-ENOENT);
-       sprintf(tmp, "%d", task_tgid_nr_ns(current, ns));
-       return ERR_PTR(vfs_follow_link(nd,tmp));
+       char *name = ERR_PTR(-ENOENT);
+       if (tgid) {
+               name = __getname();
+               if (!name)
+                       name = ERR_PTR(-ENOMEM);
+               else
+                       sprintf(name, "%d", tgid);
+       }
+       nd_set_link(nd, name);
+       return NULL;
+}
+
+static void proc_self_put_link(struct dentry *dentry, struct nameidata *nd,
+                               void *cookie)
+{
+       char *s = nd_get_link(nd);
+       if (!IS_ERR(s))
+               __putname(s);
 }
 
 static const struct inode_operations proc_self_inode_operations = {
        .readlink       = proc_self_readlink,
        .follow_link    = proc_self_follow_link,
+       .put_link       = proc_self_put_link,
 };
 
 /*
index 123257b..f8650dc 100644 (file)
 #include <linux/seq_file.h>
 #include <linux/stat.h>
 #include <linux/string.h>
+#include <linux/of.h>
+#include <linux/module.h>
 #include <asm/prom.h>
 #include <asm/uaccess.h>
 #include "internal.h"
 
-#ifndef HAVE_ARCH_DEVTREE_FIXUPS
 static inline void set_node_proc_entry(struct device_node *np,
                                       struct proc_dir_entry *de)
 {
-}
+#ifdef HAVE_ARCH_DEVTREE_FIXUPS
+       np->pde = de;
 #endif
+}
 
 static struct proc_dir_entry *proc_device_tree;
 
index 220b758..6a06a1d 100644 (file)
@@ -81,24 +81,23 @@ int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr * iattr)
                if (!sd_attrs)
                        return -ENOMEM;
                sd->s_iattr = sd_attrs;
-       } else {
-               /* attributes were changed at least once in past */
-               iattrs = &sd_attrs->ia_iattr;
-
-               if (ia_valid & ATTR_UID)
-                       iattrs->ia_uid = iattr->ia_uid;
-               if (ia_valid & ATTR_GID)
-                       iattrs->ia_gid = iattr->ia_gid;
-               if (ia_valid & ATTR_ATIME)
-                       iattrs->ia_atime = iattr->ia_atime;
-               if (ia_valid & ATTR_MTIME)
-                       iattrs->ia_mtime = iattr->ia_mtime;
-               if (ia_valid & ATTR_CTIME)
-                       iattrs->ia_ctime = iattr->ia_ctime;
-               if (ia_valid & ATTR_MODE) {
-                       umode_t mode = iattr->ia_mode;
-                       iattrs->ia_mode = sd->s_mode = mode;
-               }
+       }
+       /* attributes were changed at least once in past */
+       iattrs = &sd_attrs->ia_iattr;
+
+       if (ia_valid & ATTR_UID)
+               iattrs->ia_uid = iattr->ia_uid;
+       if (ia_valid & ATTR_GID)
+               iattrs->ia_gid = iattr->ia_gid;
+       if (ia_valid & ATTR_ATIME)
+               iattrs->ia_atime = iattr->ia_atime;
+       if (ia_valid & ATTR_MTIME)
+               iattrs->ia_mtime = iattr->ia_mtime;
+       if (ia_valid & ATTR_CTIME)
+               iattrs->ia_ctime = iattr->ia_ctime;
+       if (ia_valid & ATTR_MODE) {
+               umode_t mode = iattr->ia_mode;
+               iattrs->ia_mode = sd->s_mode = mode;
        }
        return 0;
 }
index ab94335..6816be6 100644 (file)
@@ -1,5 +1,9 @@
 /*
- *  linux/include/asm-arm/hardware/amba.h
+ *  linux/include/amba/bus.h
+ *
+ *  This device type deals with ARM PrimeCells and anything else that
+ *  presents a proper CID (0xB105F00D) at the end of the I/O register
+ *  region or that is derived from a PrimeCell.
  *
  *  Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved.
  *
index 5c80189..1896e86 100644 (file)
@@ -461,8 +461,7 @@ struct request_queue
 #define QUEUE_FLAG_NONROT      14      /* non-rotational device (SSD) */
 #define QUEUE_FLAG_VIRT        QUEUE_FLAG_NONROT /* paravirt device */
 #define QUEUE_FLAG_IO_STAT     15      /* do IO stats */
-#define QUEUE_FLAG_CQ         16       /* hardware does queuing */
-#define QUEUE_FLAG_DISCARD     17      /* supports DISCARD */
+#define QUEUE_FLAG_DISCARD     16      /* supports DISCARD */
 
 #define QUEUE_FLAG_DEFAULT     ((1 << QUEUE_FLAG_IO_STAT) |            \
                                 (1 << QUEUE_FLAG_CLUSTER) |            \
@@ -586,7 +585,6 @@ enum {
 
 #define blk_queue_plugged(q)   test_bit(QUEUE_FLAG_PLUGGED, &(q)->queue_flags)
 #define blk_queue_tagged(q)    test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags)
-#define blk_queue_queuing(q)   test_bit(QUEUE_FLAG_CQ, &(q)->queue_flags)
 #define blk_queue_stopped(q)   test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags)
 #define blk_queue_nomerges(q)  test_bit(QUEUE_FLAG_NOMERGES, &(q)->queue_flags)
 #define blk_queue_nonrot(q)    test_bit(QUEUE_FLAG_NONROT, &(q)->queue_flags)
index b1bcb27..ebb1cd5 100644 (file)
@@ -729,6 +729,7 @@ struct inode {
        uid_t                   i_uid;
        gid_t                   i_gid;
        dev_t                   i_rdev;
+       unsigned int            i_blkbits;
        u64                     i_version;
        loff_t                  i_size;
 #ifdef __NEED_I_SIZE_ORDERED
@@ -738,7 +739,6 @@ struct inode {
        struct timespec         i_mtime;
        struct timespec         i_ctime;
        blkcnt_t                i_blocks;
-       unsigned int            i_blkbits;
        unsigned short          i_bytes;
        umode_t                 i_mode;
        spinlock_t              i_lock; /* i_blocks, i_bytes, maybe i_size */
index 8709365..b1344ec 100644 (file)
@@ -501,7 +501,7 @@ struct hid_device {                                                 /* device report descriptor */
        void (*hiddev_report_event) (struct hid_device *, struct hid_report *);
 
        /* handler for raw output data, used by hidraw */
-       int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t);
+       int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t, unsigned char);
 
        /* debugging support via debugfs */
        unsigned short debug;
@@ -663,7 +663,7 @@ struct hid_ll_driver {
 
 /* Applications from HID Usage Tables 4/8/99 Version 1.1 */
 /* We ignore a few input applications that are not widely used */
-#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001) || (a == 0x000d0002))
+#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001) || ((a >= 0x000d0002) && (a <= 0x000d0006)))
 
 /* HID core API */
 
@@ -690,6 +690,7 @@ int hid_input_report(struct hid_device *, int type, u8 *, int, int);
 int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field);
 void hid_output_report(struct hid_report *report, __u8 *data);
 struct hid_device *hid_allocate_device(void);
+struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id);
 int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
 int hid_check_keys_pressed(struct hid_device *hid);
 int hid_connect(struct hid_device *hid, unsigned int connect_mask);
index 735ceaf..f44ee91 100644 (file)
@@ -376,6 +376,7 @@ struct input_absinfo {
 #define KEY_DISPLAY_OFF                245     /* display device to off state */
 
 #define KEY_WIMAX              246
+#define KEY_RFKILL             247     /* Key that controls all radios */
 
 /* Range 248 - 255 is reserved for special needs of AT keyboard driver */
 
@@ -597,6 +598,48 @@ struct input_absinfo {
 
 #define KEY_CAMERA_FOCUS       0x210
 
+#define BTN_TRIGGER_HAPPY              0x2c0
+#define BTN_TRIGGER_HAPPY1             0x2c0
+#define BTN_TRIGGER_HAPPY2             0x2c1
+#define BTN_TRIGGER_HAPPY3             0x2c2
+#define BTN_TRIGGER_HAPPY4             0x2c3
+#define BTN_TRIGGER_HAPPY5             0x2c4
+#define BTN_TRIGGER_HAPPY6             0x2c5
+#define BTN_TRIGGER_HAPPY7             0x2c6
+#define BTN_TRIGGER_HAPPY8             0x2c7
+#define BTN_TRIGGER_HAPPY9             0x2c8
+#define BTN_TRIGGER_HAPPY10            0x2c9
+#define BTN_TRIGGER_HAPPY11            0x2ca
+#define BTN_TRIGGER_HAPPY12            0x2cb
+#define BTN_TRIGGER_HAPPY13            0x2cc
+#define BTN_TRIGGER_HAPPY14            0x2cd
+#define BTN_TRIGGER_HAPPY15            0x2ce
+#define BTN_TRIGGER_HAPPY16            0x2cf
+#define BTN_TRIGGER_HAPPY17            0x2d0
+#define BTN_TRIGGER_HAPPY18            0x2d1
+#define BTN_TRIGGER_HAPPY19            0x2d2
+#define BTN_TRIGGER_HAPPY20            0x2d3
+#define BTN_TRIGGER_HAPPY21            0x2d4
+#define BTN_TRIGGER_HAPPY22            0x2d5
+#define BTN_TRIGGER_HAPPY23            0x2d6
+#define BTN_TRIGGER_HAPPY24            0x2d7
+#define BTN_TRIGGER_HAPPY25            0x2d8
+#define BTN_TRIGGER_HAPPY26            0x2d9
+#define BTN_TRIGGER_HAPPY27            0x2da
+#define BTN_TRIGGER_HAPPY28            0x2db
+#define BTN_TRIGGER_HAPPY29            0x2dc
+#define BTN_TRIGGER_HAPPY30            0x2dd
+#define BTN_TRIGGER_HAPPY31            0x2de
+#define BTN_TRIGGER_HAPPY32            0x2df
+#define BTN_TRIGGER_HAPPY33            0x2e0
+#define BTN_TRIGGER_HAPPY34            0x2e1
+#define BTN_TRIGGER_HAPPY35            0x2e2
+#define BTN_TRIGGER_HAPPY36            0x2e3
+#define BTN_TRIGGER_HAPPY37            0x2e4
+#define BTN_TRIGGER_HAPPY38            0x2e5
+#define BTN_TRIGGER_HAPPY39            0x2e6
+#define BTN_TRIGGER_HAPPY40            0x2e7
+
 /* We avoid low common keys in module aliases so they don't get huge. */
 #define KEY_MIN_INTERESTING    KEY_MUTE
 #define KEY_MAX                        0x2ff
index 6f6c5f3..bc0fc79 100644 (file)
@@ -124,7 +124,7 @@ extern __must_check unsigned int kfifo_out_peek(struct kfifo *fifo,
  */
 static inline bool kfifo_initialized(struct kfifo *fifo)
 {
-       return fifo->buffer != 0;
+       return fifo->buffer != NULL;
 }
 
 /**
index e7facd8..f6d9cbc 100644 (file)
 #include <linux/bitops.h>
 #include <linux/kref.h>
 #include <linux/mod_devicetable.h>
+#include <linux/spinlock.h>
+
+#include <asm/byteorder.h>
+
+#ifdef CONFIG_OF
 
 typedef u32 phandle;
 typedef u32 ihandle;
@@ -39,10 +44,7 @@ struct of_irq_controller;
 struct device_node {
        const char *name;
        const char *type;
-       phandle node;
-#if !defined(CONFIG_SPARC)
-       phandle linux_phandle;
-#endif
+       phandle phandle;
        char    *full_name;
 
        struct  property *properties;
@@ -63,6 +65,11 @@ struct device_node {
 #endif
 };
 
+/* Pointer for first entry in chain of all nodes. */
+extern struct device_node *allnodes;
+extern struct device_node *of_chosen;
+extern rwlock_t devtree_lock;
+
 static inline int of_node_check_flag(struct device_node *n, unsigned long flag)
 {
        return test_bit(flag, &n->_flags);
@@ -73,12 +80,6 @@ static inline void of_node_set_flag(struct device_node *n, unsigned long flag)
        set_bit(flag, &n->_flags);
 }
 
-static inline void
-set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
-{
-       dn->pde = de;
-}
-
 extern struct device_node *of_find_all_nodes(struct device_node *prev);
 
 #if defined(CONFIG_SPARC)
@@ -101,26 +102,36 @@ extern void of_node_put(struct device_node *node);
  */
 
 /* Helper to read a big number; size is in cells (not bytes) */
-static inline u64 of_read_number(const u32 *cell, int size)
+static inline u64 of_read_number(const __be32 *cell, int size)
 {
        u64 r = 0;
        while (size--)
-               r = (r << 32) | *(cell++);
+               r = (r << 32) | be32_to_cpu(*(cell++));
        return r;
 }
 
 /* Like of_read_number, but we want an unsigned long result */
-#ifdef CONFIG_PPC32
-static inline unsigned long of_read_ulong(const u32 *cell, int size)
+static inline unsigned long of_read_ulong(const __be32 *cell, int size)
 {
-       return cell[size-1];
+       /* toss away upper bits if unsigned long is smaller than u64 */
+       return of_read_number(cell, size);
 }
-#else
-#define of_read_ulong(cell, size)      of_read_number(cell, size)
-#endif
 
 #include <asm/prom.h>
 
+/* Default #address and #size cells.  Allow arch asm/prom.h to override */
+#if !defined(OF_ROOT_NODE_ADDR_CELLS_DEFAULT)
+#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 1
+#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1
+#endif
+
+/* Default string compare functions, Allow arch asm/prom.h to override */
+#if !defined(of_compat_cmp)
+#define of_compat_cmp(s1, s2, l)       strncasecmp((s1), (s2), (l))
+#define of_prop_cmp(s1, s2)            strcmp((s1), (s2))
+#define of_node_cmp(s1, s2)            strcasecmp((s1), (s2))
+#endif
+
 /* flag descriptions */
 #define OF_DYNAMIC     1 /* node and properties were allocated via kmalloc */
 #define OF_DETACHED    2 /* node has been detached from the device tree */
@@ -187,4 +198,19 @@ extern int of_parse_phandles_with_args(struct device_node *np,
        const char *list_name, const char *cells_name, int index,
        struct device_node **out_node, const void **out_args);
 
+extern int of_machine_is_compatible(const char *compat);
+
+extern int prom_add_property(struct device_node* np, struct property* prop);
+extern int prom_remove_property(struct device_node *np, struct property *prop);
+extern int prom_update_property(struct device_node *np,
+                               struct property *newprop,
+                               struct property *oldprop);
+
+#if defined(CONFIG_OF_DYNAMIC)
+/* For updating the device tree at runtime */
+extern void of_attach_node(struct device_node *);
+extern void of_detach_node(struct device_node *);
+#endif
+
+#endif /* CONFIG_OF */
 #endif /* _LINUX_OF_H */
index 41d432b..a1ca92c 100644 (file)
  * ends when size is 0
  */
 struct boot_param_header {
-       u32     magic;                  /* magic word OF_DT_HEADER */
-       u32     totalsize;              /* total size of DT block */
-       u32     off_dt_struct;          /* offset to structure */
-       u32     off_dt_strings;         /* offset to strings */
-       u32     off_mem_rsvmap;         /* offset to memory reserve map */
-       u32     version;                /* format version */
-       u32     last_comp_version;      /* last compatible version */
+       __be32  magic;                  /* magic word OF_DT_HEADER */
+       __be32  totalsize;              /* total size of DT block */
+       __be32  off_dt_struct;          /* offset to structure */
+       __be32  off_dt_strings;         /* offset to strings */
+       __be32  off_mem_rsvmap;         /* offset to memory reserve map */
+       __be32  version;                /* format version */
+       __be32  last_comp_version;      /* last compatible version */
        /* version 2 fields below */
-       u32     boot_cpuid_phys;        /* Physical CPU id we're booting on */
+       __be32  boot_cpuid_phys;        /* Physical CPU id we're booting on */
        /* version 3 fields below */
-       u32     dt_strings_size;        /* size of the DT strings block */
+       __be32  dt_strings_size;        /* size of the DT strings block */
        /* version 17 fields below */
-       u32     dt_struct_size;         /* size of the DT structure block */
+       __be32  dt_struct_size;         /* size of the DT structure block */
 };
 
+/* TBD: Temporary export of fdt globals - remove when code fully merged */
+extern int __initdata dt_root_addr_cells;
+extern int __initdata dt_root_size_cells;
+extern struct boot_param_header *initial_boot_params;
+
 /* For scanning the flat device-tree at boot time */
-extern int __init of_scan_flat_dt(int (*it)(unsigned long node,
-                                           const char *uname, int depth,
-                                           void *data),
-                                 void *data);
-extern void __init *of_get_flat_dt_prop(unsigned long node, const char *name,
-                                       unsigned long *size);
-extern int __init of_flat_dt_is_compatible(unsigned long node,
-                                          const char *name);
-extern unsigned long __init of_get_flat_dt_root(void);
+extern char *find_flat_dt_string(u32 offset);
+extern int of_scan_flat_dt(int (*it)(unsigned long node, const char *uname,
+                                    int depth, void *data),
+                          void *data);
+extern void *of_get_flat_dt_prop(unsigned long node, const char *name,
+                                unsigned long *size);
+extern int of_flat_dt_is_compatible(unsigned long node, const char *name);
+extern unsigned long of_get_flat_dt_root(void);
+extern void early_init_dt_scan_chosen_arch(unsigned long node);
+extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
+                                    int depth, void *data);
+extern void early_init_dt_check_for_initrd(unsigned long node);
+extern int early_init_dt_scan_memory(unsigned long node, const char *uname,
+                                    int depth, void *data);
+extern void early_init_dt_add_memory_arch(u64 base, u64 size);
+extern u64 early_init_dt_alloc_memory_arch(u64 size, u64 align);
+extern u64 dt_mem_next_cell(int s, __be32 **cellp);
+
+/*
+ * If BLK_DEV_INITRD, the fdt early init code will call this function,
+ * to be provided by the arch code. start and end are specified as
+ * physical addresses.
+ */
+#ifdef CONFIG_BLK_DEV_INITRD
+extern void early_init_dt_setup_initrd_arch(unsigned long start,
+                                           unsigned long end);
+#endif
+
+/* Early flat tree scan hooks */
+extern int early_init_dt_scan_root(unsigned long node, const char *uname,
+                                  int depth, void *data);
 
 /* Other Prototypes */
-extern void finish_device_tree(void);
 extern void unflatten_device_tree(void);
 extern void early_init_devtree(void *);
-extern int machine_is_compatible(const char *compat);
-extern void print_properties(struct device_node *node);
-extern int prom_n_intr_cells(struct device_node* np);
-extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
-extern int prom_add_property(struct device_node* np, struct property* prop);
-extern int prom_remove_property(struct device_node *np, struct property *prop);
-extern int prom_update_property(struct device_node *np,
-                               struct property *newprop,
-                               struct property *oldprop);
 
 #endif /* __ASSEMBLY__ */
 #endif /* _LINUX_OF_FDT_H */
index 51b3e77..cc813f9 100644 (file)
@@ -90,6 +90,7 @@ struct dw_spi {
        unsigned long           paddr;
        u32                     iolen;
        int                     irq;
+       u32                     fifo_len;       /* depth of the FIFO buffer */
        u32                     max_freq;       /* max bus freq supported */
 
        u16                     bus_num;
@@ -171,6 +172,10 @@ static inline void spi_chip_sel(struct dw_spi *dws, u16 cs)
 {
        if (cs > dws->num_cs)
                return;
+
+       if (dws->cs_control)
+               dws->cs_control(1);
+
        dw_writel(dws, ser, 1 << cs);
 }
 
index 057a2e0..f508c65 100644 (file)
@@ -51,6 +51,9 @@ struct virtqueue {
  *     This re-enables callbacks; it returns "false" if there are pending
  *     buffers in the queue, to detect a possible race between the driver
  *     checking for more work, and enabling callbacks.
+ * @detach_unused_buf: detach first unused buffer
+ *     vq: the struct virtqueue we're talking about.
+ *     Returns NULL or the "data" token handed to add_buf
  *
  * Locking rules are straightforward: the driver is responsible for
  * locking.  No two operations may be invoked simultaneously, with the exception
@@ -71,6 +74,7 @@ struct virtqueue_ops {
 
        void (*disable_cb)(struct virtqueue *vq);
        bool (*enable_cb)(struct virtqueue *vq);
+       void *(*detach_unused_buf)(struct virtqueue *vq);
 };
 
 /**
index 1418f04..a50ecd1 100644 (file)
@@ -7,6 +7,7 @@
 
 /* The feature bitmap for virtio balloon */
 #define VIRTIO_BALLOON_F_MUST_TELL_HOST        0 /* Tell before reclaiming pages */
+#define VIRTIO_BALLOON_F_STATS_VQ      1 /* Memory Stats virtqueue */
 
 /* Size of a PFN in the balloon interface. */
 #define VIRTIO_BALLOON_PFN_SHIFT 12
@@ -18,4 +19,18 @@ struct virtio_balloon_config
        /* Number of pages we've actually got in balloon. */
        __le32 actual;
 };
+
+#define VIRTIO_BALLOON_S_SWAP_IN  0   /* Amount of memory swapped in */
+#define VIRTIO_BALLOON_S_SWAP_OUT 1   /* Amount of memory swapped out */
+#define VIRTIO_BALLOON_S_MAJFLT   2   /* Number of major faults */
+#define VIRTIO_BALLOON_S_MINFLT   3   /* Number of minor faults */
+#define VIRTIO_BALLOON_S_MEMFREE  4   /* Total amount of free memory */
+#define VIRTIO_BALLOON_S_MEMTOT   5   /* Total amount of memory */
+#define VIRTIO_BALLOON_S_NR       6
+
+struct virtio_balloon_stat {
+       u16 tag;
+       u64 val;
+} __attribute__((packed));
+
 #endif /* _LINUX_VIRTIO_BALLOON_H */
index fd294c5..e52029e 100644 (file)
@@ -15,6 +15,7 @@
 #define VIRTIO_BLK_F_BLK_SIZE  6       /* Block size of disk is available*/
 #define VIRTIO_BLK_F_SCSI      7       /* Supports scsi command passthru */
 #define VIRTIO_BLK_F_FLUSH     9       /* Cache flush command support */
+#define VIRTIO_BLK_F_TOPOLOGY  10      /* Topology information is available */
 
 struct virtio_blk_config {
        /* The capacity (in 512-byte sectors). */
@@ -29,8 +30,20 @@ struct virtio_blk_config {
                __u8 heads;
                __u8 sectors;
        } geometry;
+
        /* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */
        __u32 blk_size;
+
+       /* the next 4 entries are guarded by VIRTIO_BLK_F_TOPOLOGY  */
+       /* exponent for physical block per logical block. */
+       __u8 physical_block_exp;
+       /* alignment offset in logical blocks. */
+       __u8 alignment_offset;
+       /* minimum I/O size without performance penalty in logical blocks. */
+       __u16 min_io_size;
+       /* optimal sustained I/O size in logical blocks. */
+       __u32 opt_io_size;
+
 } __attribute__((packed));
 
 /*
index fe88517..ae4f039 100644 (file)
@@ -3,19 +3,45 @@
 #include <linux/types.h>
 #include <linux/virtio_ids.h>
 #include <linux/virtio_config.h>
-/* This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
- * anyone can use the definitions to implement compatible drivers/servers. */
+/*
+ * This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
+ * anyone can use the definitions to implement compatible drivers/servers.
+ *
+ * Copyright (C) Red Hat, Inc., 2009, 2010
+ */
 
 /* Feature bits */
 #define VIRTIO_CONSOLE_F_SIZE  0       /* Does host provide console size? */
+#define VIRTIO_CONSOLE_F_MULTIPORT 1   /* Does host provide multiple ports? */
 
 struct virtio_console_config {
        /* colums of the screens */
        __u16 cols;
        /* rows of the screens */
        __u16 rows;
+       /* max. number of ports this device can hold */
+       __u32 max_nr_ports;
+       /* number of ports added so far */
+       __u32 nr_ports;
 } __attribute__((packed));
 
+/*
+ * A message that's passed between the Host and the Guest for a
+ * particular port.
+ */
+struct virtio_console_control {
+       __u32 id;               /* Port number */
+       __u16 event;            /* The kind of control event (see below) */
+       __u16 value;            /* Extra information for the key */
+};
+
+/* Some events for control messages */
+#define VIRTIO_CONSOLE_PORT_READY      0
+#define VIRTIO_CONSOLE_CONSOLE_PORT    1
+#define VIRTIO_CONSOLE_RESIZE          2
+#define VIRTIO_CONSOLE_PORT_OPEN       3
+#define VIRTIO_CONSOLE_PORT_NAME       4
+#define VIRTIO_CONSOLE_PORT_REMOVE     5
 
 #ifdef __KERNEL__
 int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int));
index 498cabb..35edbe2 100644 (file)
@@ -80,7 +80,7 @@ int kfifo_alloc(struct kfifo *fifo, unsigned int size, gfp_t gfp_mask)
 
        buffer = kmalloc(size, gfp_mask);
        if (!buffer) {
-               _kfifo_init(fifo, 0, 0);
+               _kfifo_init(fifo, NULL, 0);
                return -ENOMEM;
        }
 
@@ -97,6 +97,7 @@ EXPORT_SYMBOL(kfifo_alloc);
 void kfifo_free(struct kfifo *fifo)
 {
        kfree(fifo->buffer);
+       _kfifo_init(fifo, NULL, 0);
 }
 EXPORT_SYMBOL(kfifo_free);
 
index 2b19297..2ae7409 100644 (file)
@@ -3259,8 +3259,6 @@ static void perf_event_task_output(struct perf_event *event,
        task_event->event_id.tid = perf_event_tid(event, task);
        task_event->event_id.ptid = perf_event_tid(event, current);
 
-       task_event->event_id.time = perf_clock();
-
        perf_output_put(&handle, task_event->event_id);
 
        perf_output_end(&handle);
@@ -3268,7 +3266,7 @@ static void perf_event_task_output(struct perf_event *event,
 
 static int perf_event_task_match(struct perf_event *event)
 {
-       if (event->state != PERF_EVENT_STATE_ACTIVE)
+       if (event->state < PERF_EVENT_STATE_INACTIVE)
                return 0;
 
        if (event->cpu != -1 && event->cpu != smp_processor_id())
@@ -3300,7 +3298,7 @@ static void perf_event_task_event(struct perf_task_event *task_event)
        cpuctx = &get_cpu_var(perf_cpu_context);
        perf_event_task_ctx(&cpuctx->ctx, task_event);
        if (!ctx)
-               ctx = rcu_dereference(task_event->task->perf_event_ctxp);
+               ctx = rcu_dereference(current->perf_event_ctxp);
        if (ctx)
                perf_event_task_ctx(ctx, task_event);
        put_cpu_var(perf_cpu_context);
@@ -3331,6 +3329,7 @@ static void perf_event_task(struct task_struct *task,
                        /* .ppid */
                        /* .tid  */
                        /* .ptid */
+                       .time = perf_clock(),
                },
        };
 
@@ -3380,7 +3379,7 @@ static void perf_event_comm_output(struct perf_event *event,
 
 static int perf_event_comm_match(struct perf_event *event)
 {
-       if (event->state != PERF_EVENT_STATE_ACTIVE)
+       if (event->state < PERF_EVENT_STATE_INACTIVE)
                return 0;
 
        if (event->cpu != -1 && event->cpu != smp_processor_id())
@@ -3500,7 +3499,7 @@ static void perf_event_mmap_output(struct perf_event *event,
 static int perf_event_mmap_match(struct perf_event *event,
                                   struct perf_mmap_event *mmap_event)
 {
-       if (event->state != PERF_EVENT_STATE_ACTIVE)
+       if (event->state < PERF_EVENT_STATE_INACTIVE)
                return 0;
 
        if (event->cpu != -1 && event->cpu != smp_processor_id())
index 26a6b73..18bde97 100644 (file)
@@ -222,6 +222,7 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who)
        if (which > PRIO_USER || which < PRIO_PROCESS)
                return -EINVAL;
 
+       rcu_read_lock();
        read_lock(&tasklist_lock);
        switch (which) {
                case PRIO_PROCESS:
@@ -267,6 +268,7 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who)
        }
 out_unlock:
        read_unlock(&tasklist_lock);
+       rcu_read_unlock();
 
        return retval;
 }
index 1cac726..0dc7822 100644 (file)
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -156,10 +156,12 @@ static int sub_alloc(struct idr *idp, int *starting_id, struct idr_layer **pa)
                        id = (id | ((1 << (IDR_BITS * l)) - 1)) + 1;
 
                        /* if already at the top layer, we need to grow */
-                       if (!(p = pa[l])) {
+                       if (id >= 1 << (idp->layers * IDR_BITS)) {
                                *starting_id = id;
                                return IDR_NEED_TO_GROW;
                        }
+                       p = pa[l];
+                       BUG_ON(!p);
 
                        /* If we need to go up one layer, continue the
                         * loop; otherwise, restart from the top.
index 9a0db5b..880bd59 100644 (file)
@@ -1002,33 +1002,27 @@ static int do_pages_stat(struct mm_struct *mm, unsigned long nr_pages,
 #define DO_PAGES_STAT_CHUNK_NR 16
        const void __user *chunk_pages[DO_PAGES_STAT_CHUNK_NR];
        int chunk_status[DO_PAGES_STAT_CHUNK_NR];
-       unsigned long i, chunk_nr = DO_PAGES_STAT_CHUNK_NR;
-       int err;
 
-       for (i = 0; i < nr_pages; i += chunk_nr) {
-               if (chunk_nr > nr_pages - i)
-                       chunk_nr = nr_pages - i;
+       while (nr_pages) {
+               unsigned long chunk_nr;
 
-               err = copy_from_user(chunk_pages, &pages[i],
-                                    chunk_nr * sizeof(*chunk_pages));
-               if (err) {
-                       err = -EFAULT;
-                       goto out;
-               }
+               chunk_nr = nr_pages;
+               if (chunk_nr > DO_PAGES_STAT_CHUNK_NR)
+                       chunk_nr = DO_PAGES_STAT_CHUNK_NR;
+
+               if (copy_from_user(chunk_pages, pages, chunk_nr * sizeof(*chunk_pages)))
+                       break;
 
                do_pages_stat_array(mm, chunk_nr, chunk_pages, chunk_status);
 
-               err = copy_to_user(&status[i], chunk_status,
-                                  chunk_nr * sizeof(*chunk_status));
-               if (err) {
-                       err = -EFAULT;
-                       goto out;
-               }
-       }
-       err = 0;
+               if (copy_to_user(status, chunk_status, chunk_nr * sizeof(*status)))
+                       break;
 
-out:
-       return err;
+               pages += chunk_nr;
+               status += chunk_nr;
+               nr_pages -= chunk_nr;
+       }
+       return nr_pages ? -EFAULT : 0;
 }
 
 /*
index f52481b..2370504 100644 (file)
@@ -459,6 +459,8 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
        list_for_each_entry(c, &p->children, sibling) {
                if (c->mm == p->mm)
                        continue;
+               if (mem && !task_in_mem_cgroup(c, mem))
+                       continue;
                if (!oom_kill_task(c))
                        return 0;
        }
index fc6ec1e..280529a 100644 (file)
@@ -313,10 +313,21 @@ static int hidp_send_report(struct hidp_session *session, struct hid_report *rep
        return hidp_queue_report(session, buf, rsize);
 }
 
-static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count)
+static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count,
+               unsigned char report_type)
 {
-       if (hidp_send_ctrl_message(hid->driver_data,
-                       HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE,
+       switch (report_type) {
+       case HID_FEATURE_REPORT:
+               report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE;
+               break;
+       case HID_OUTPUT_REPORT:
+               report_type = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (hidp_send_ctrl_message(hid->driver_data, report_type,
                        data, count))
                return -ENOMEM;
        return count;
index be9924f..ec87421 100644 (file)
@@ -2761,7 +2761,7 @@ gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb,
        switch (ret) {
        case GRO_NORMAL:
        case GRO_HELD:
-               skb->protocol = eth_type_trans(skb, napi->dev);
+               skb->protocol = eth_type_trans(skb, skb->dev);
 
                if (ret == GRO_HELD)
                        skb_gro_pull(skb, -ETH_HLEN);
index d8aee58..236a998 100644 (file)
@@ -927,6 +927,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
        case ETHTOOL_GPERMADDR:
        case ETHTOOL_GUFO:
        case ETHTOOL_GGSO:
+       case ETHTOOL_GGRO:
        case ETHTOOL_GFLAGS:
        case ETHTOOL_GPFLAGS:
        case ETHTOOL_GRXFH:
index fbc1c74..099c753 100644 (file)
@@ -410,7 +410,8 @@ static ssize_t wireless_show(struct device *d, char *buf,
        const struct iw_statistics *iw;
        ssize_t ret = -EINVAL;
 
-       rtnl_lock();
+       if (!rtnl_trylock())
+               return restart_syscall();
        if (dev_isalive(dev)) {
                iw = get_wireless_stats(dev);
                if (iw)
index 040c4f0..26dec2b 100644 (file)
@@ -1317,14 +1317,19 @@ static int devinet_sysctl_forward(ctl_table *ctl, int write,
 {
        int *valp = ctl->data;
        int val = *valp;
+       loff_t pos = *ppos;
        int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
 
        if (write && *valp != val) {
                struct net *net = ctl->extra2;
 
                if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
-                       if (!rtnl_trylock())
+                       if (!rtnl_trylock()) {
+                               /* Restore the original values before restarting */
+                               *valp = val;
+                               *ppos = pos;
                                return restart_syscall();
+                       }
                        if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
                                inet_forward_change(net);
                        } else if (*valp) {
index 76c0840..a42f658 100644 (file)
@@ -946,7 +946,6 @@ int igmp_rcv(struct sk_buff *skb)
                break;
        case IGMP_HOST_MEMBERSHIP_REPORT:
        case IGMPV2_HOST_MEMBERSHIP_REPORT:
-       case IGMPV3_HOST_MEMBERSHIP_REPORT:
                /* Is it our report looped back? */
                if (skb_rtable(skb)->fl.iif == 0)
                        break;
@@ -960,6 +959,7 @@ int igmp_rcv(struct sk_buff *skb)
                in_dev_put(in_dev);
                return pim_rcv_v1(skb);
 #endif
+       case IGMPV3_HOST_MEMBERSHIP_REPORT:
        case IGMP_DVMRP:
        case IGMP_TRACE:
        case IGMP_HOST_LEAVE_MESSAGE:
index 38fbf04..544ce08 100644 (file)
@@ -124,16 +124,12 @@ static int ipcomp4_init_state(struct xfrm_state *x)
        if (x->props.mode == XFRM_MODE_TUNNEL) {
                err = ipcomp_tunnel_attach(x);
                if (err)
-                       goto error_tunnel;
+                       goto out;
        }
 
        err = 0;
 out:
        return err;
-
-error_tunnel:
-       ipcomp_destroy(x);
-       goto out;
 }
 
 static const struct xfrm_type ipcomp_type = {
index 28e0296..3fddc69 100644 (file)
@@ -5783,11 +5783,9 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 
                                /* tcp_ack considers this ACK as duplicate
                                 * and does not calculate rtt.
-                                * Fix it at least with timestamps.
+                                * Force it here.
                                 */
-                               if (tp->rx_opt.saw_tstamp &&
-                                   tp->rx_opt.rcv_tsecr && !tp->srtt)
-                                       tcp_ack_saw_tstamp(sk, 0);
+                               tcp_ack_update_rtt(sk, 0, 0);
 
                                if (tp->rx_opt.tstamp_ok)
                                        tp->advmss -= TCPOLEN_TSTAMP_ALIGNED;
index de7a194..143791d 100644 (file)
@@ -502,8 +502,11 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old)
        if (p == &net->ipv6.devconf_dflt->forwarding)
                return 0;
 
-       if (!rtnl_trylock())
+       if (!rtnl_trylock()) {
+               /* Restore the original values before restarting */
+               *p = old;
                return restart_syscall();
+       }
 
        if (p == &net->ipv6.devconf_all->forwarding) {
                __s32 newf = net->ipv6.devconf_all->forwarding;
@@ -4028,12 +4031,15 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write,
 {
        int *valp = ctl->data;
        int val = *valp;
+       loff_t pos = *ppos;
        int ret;
 
        ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
 
        if (write)
                ret = addrconf_fixup_forwarding(ctl, valp, val);
+       if (ret)
+               *ppos = pos;
        return ret;
 }
 
@@ -4075,8 +4081,11 @@ static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int old)
        if (p == &net->ipv6.devconf_dflt->disable_ipv6)
                return 0;
 
-       if (!rtnl_trylock())
+       if (!rtnl_trylock()) {
+               /* Restore the original values before restarting */
+               *p = old;
                return restart_syscall();
+       }
 
        if (p == &net->ipv6.devconf_all->disable_ipv6) {
                __s32 newf = net->ipv6.devconf_all->disable_ipv6;
@@ -4095,12 +4104,15 @@ int addrconf_sysctl_disable(ctl_table *ctl, int write,
 {
        int *valp = ctl->data;
        int val = *valp;
+       loff_t pos = *ppos;
        int ret;
 
        ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
 
        if (write)
                ret = addrconf_disable_ipv6(ctl, valp, val);
+       if (ret)
+               *ppos = pos;
        return ret;
 }
 
index 2f2a5ca..002e6ee 100644 (file)
@@ -154,16 +154,12 @@ static int ipcomp6_init_state(struct xfrm_state *x)
        if (x->props.mode == XFRM_MODE_TUNNEL) {
                err = ipcomp6_tunnel_attach(x);
                if (err)
-                       goto error_tunnel;
+                       goto out;
        }
 
        err = 0;
 out:
        return err;
-error_tunnel:
-       ipcomp_destroy(x);
-
-       goto out;
 }
 
 static const struct xfrm_type ipcomp6_type =
index 1f2db64..22f0c2a 100644 (file)
@@ -647,7 +647,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
        }
        if (pos[1] != 0 &&
            (pos[1] != ifibss->ssid_len ||
-            !memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len))) {
+            memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len))) {
                /* Ignore ProbeReq for foreign SSID */
                return;
        }
index b9007f8..12a2bff 100644 (file)
@@ -245,6 +245,9 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
                info->control.rates[i].count = 1;
        }
 
+       if (sdata->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
+               return;
+
        if (sta && sdata->force_unicast_rateidx > -1) {
                info->control.rates[0].idx = sdata->force_unicast_rateidx;
        } else {
index f934c96..bc17cf7 100644 (file)
@@ -439,6 +439,16 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
        if (local->scan_req)
                return -EBUSY;
 
+       if (req != local->int_scan_req &&
+           sdata->vif.type == NL80211_IFTYPE_STATION &&
+           !list_empty(&ifmgd->work_list)) {
+               /* actually wait for the work it's doing to finish/time out */
+               set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request);
+               local->scan_req = req;
+               local->scan_sdata = sdata;
+               return 0;
+       }
+
        if (local->ops->hw_scan) {
                u8 *ies;
 
@@ -463,14 +473,6 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
        local->scan_req = req;
        local->scan_sdata = sdata;
 
-       if (req != local->int_scan_req &&
-           sdata->vif.type == NL80211_IFTYPE_STATION &&
-           !list_empty(&ifmgd->work_list)) {
-               /* actually wait for the work it's doing to finish/time out */
-               set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request);
-               return 0;
-       }
-
        if (local->ops->hw_scan)
                __set_bit(SCAN_HW_SCANNING, &local->scanning);
        else
index b36cc34..f445ea1 100644 (file)
@@ -1102,7 +1102,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
        int err = -ENOMEM;
        struct xfrm_state *x = xfrm_state_alloc(net);
        if (!x)
-               goto error;
+               goto out;
 
        memcpy(&x->id, &orig->id, sizeof(x->id));
        memcpy(&x->sel, &orig->sel, sizeof(x->sel));
@@ -1160,16 +1160,10 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
        return x;
 
  error:
+       xfrm_state_put(x);
+out:
        if (errp)
                *errp = err;
-       if (x) {
-               kfree(x->aalg);
-               kfree(x->ealg);
-               kfree(x->calg);
-               kfree(x->encap);
-               kfree(x->coaddr);
-       }
-       kfree(x);
        return NULL;
 }
 
index 52cab46..c5d5db5 100644 (file)
@@ -6,5 +6,4 @@ kallsyms
 pnmtologo
 bin2c
 unifdef
-binoffset
 ihex2fw
diff --git a/scripts/binoffset.c b/scripts/binoffset.c
deleted file mode 100644 (file)
index 1a2e39b..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-/***************************************************************************
- * binoffset.c
- * (C) 2002 Randy Dunlap <rdunlap@xenotime.net>
-
-#   This program is free software; you can redistribute it and/or modify
-#   it under the terms of the GNU General Public License as published by
-#   the Free Software Foundation; either version 2 of the License, or
-#   (at your option) any later version.
-#
-#   This program is distributed in the hope that it will be useful,
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#   GNU General Public License for more details.
-#
-#   You should have received a copy of the GNU General Public License
-#   along with this program; if not, write to the Free Software
-#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-# binoffset.c:
-# - searches a (binary) file for a specified (binary) pattern
-# - returns the offset of the located pattern or ~0 if not found
-# - exits with exit status 0 normally or non-0 if pattern is not found
-#   or any other error occurs.
-
-****************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-
-#define VERSION                "0.1"
-#define BUF_SIZE       (16 * 1024)
-#define PAT_SIZE       100
-
-char           *progname;
-char           *inputname;
-int            inputfd;
-unsigned int   bix;                    /* buf index */
-unsigned char  patterns [PAT_SIZE] = {0}; /* byte-sized pattern array */
-int            pat_len;                /* actual number of pattern bytes */
-unsigned char  *madr;                  /* mmap address */
-size_t         filesize;
-int            num_matches = 0;
-off_t          firstloc = 0;
-
-void usage (void)
-{
-       fprintf (stderr, "%s ver. %s\n", progname, VERSION);
-       fprintf (stderr, "usage:  %s filename pattern_bytes\n",
-                       progname);
-       fprintf (stderr, "        [prints location of pattern_bytes in file]\n");
-       exit (1);
-}
-
-void get_pattern (int pat_count, char *pats [])
-{
-       int ix, err, tmp;
-
-#ifdef DEBUG
-       fprintf (stderr,"get_pattern: count = %d\n", pat_count);
-       for (ix = 0; ix < pat_count; ix++)
-               fprintf (stderr, "  pat # %d:  [%s]\n", ix, pats[ix]);
-#endif
-
-       for (ix = 0; ix < pat_count; ix++) {
-               tmp = 0;
-               err = sscanf (pats[ix], "%5i", &tmp);
-               if (err != 1 || tmp > 0xff) {
-                       fprintf (stderr, "pattern or value error in pattern # %d [%s]\n",
-                                       ix, pats[ix]);
-                       usage ();
-               }
-               patterns [ix] = tmp;
-       }
-       pat_len = pat_count;
-}
-
-void search_pattern (void)
-{
-       for (bix = 0; bix < filesize; bix++) {
-               if (madr[bix] == patterns[0]) {
-                       if (memcmp (&madr[bix], patterns, pat_len) == 0) {
-                               if (num_matches == 0)
-                                       firstloc = bix;
-                               num_matches++;
-                       }
-               }
-       }
-}
-
-#ifdef NOTDEF
-size_t get_filesize (int fd)
-{
-       off_t end_off = lseek (fd, 0, SEEK_END);
-       lseek (fd, 0, SEEK_SET);
-       return (size_t) end_off;
-}
-#endif
-
-size_t get_filesize (int fd)
-{
-       int err;
-       struct stat stat;
-
-       err = fstat (fd, &stat);
-       fprintf (stderr, "filesize: %ld\n", err < 0 ? (long)err : stat.st_size);
-       if (err < 0)
-               return err;
-       return (size_t) stat.st_size;
-}
-
-int main (int argc, char *argv [])
-{
-       progname = argv[0];
-
-       if (argc < 3)
-               usage ();
-
-       get_pattern (argc - 2, argv + 2);
-
-       inputname = argv[1];
-
-       inputfd = open (inputname, O_RDONLY);
-       if (inputfd == -1) {
-               fprintf (stderr, "%s: cannot open '%s'\n",
-                               progname, inputname);
-               exit (3);
-       }
-
-       filesize = get_filesize (inputfd);
-
-       madr = mmap (0, filesize, PROT_READ, MAP_PRIVATE, inputfd, 0);
-       if (madr == MAP_FAILED) {
-               fprintf (stderr, "mmap error = %d\n", errno);
-               close (inputfd);
-               exit (4);
-       }
-
-       search_pattern ();
-
-       if (munmap (madr, filesize))
-               fprintf (stderr, "munmap error = %d\n", errno);
-
-       if (close (inputfd))
-               fprintf (stderr, "%s: error %d closing '%s'\n",
-                               progname, errno, inputname);
-
-       fprintf (stderr, "number of pattern matches = %d\n", num_matches);
-       if (num_matches == 0)
-               firstloc = ~0;
-       printf ("%ld\n", firstloc);
-       fprintf (stderr, "%ld\n", firstloc);
-
-       exit (num_matches ? 0 : 2);
-}
-
-/* end binoffset.c */
index de233ff..37f30d3 100755 (executable)
@@ -1,92 +1,53 @@
 #!/bin/sh
-# extracts .config info from a [b]zImage file
-# uses: binoffset (new), dd, zcat, strings, grep
-# $arg1 is [b]zImage filename
-
-binoffset="./scripts/binoffset"
-test -e $binoffset || cc -o $binoffset ./scripts/binoffset.c || exit 1
-
-IKCFG_ST="0x49 0x4b 0x43 0x46 0x47 0x5f 0x53 0x54"
-IKCFG_ED="0x49 0x4b 0x43 0x46 0x47 0x5f 0x45 0x44"
-dump_config() {
-    file="$1"
-
-    start=`$binoffset $file $IKCFG_ST 2>/dev/null`
-    [ "$?" != "0" ] && start="-1"
-    if [ "$start" -eq "-1" ]; then
-       return
-    fi
-    end=`$binoffset $file $IKCFG_ED 2>/dev/null`
-    [ "$?" != "0" ] && end="-1"
-    if [ "$end" -eq "-1" ]; then
-       return
-    fi
-
-    start=`expr $start + 8`
-    size=`expr $end - $start`
-
-    dd if="$file" ibs=1 skip="$start" count="$size" 2>/dev/null | zcat
-
-    clean_up
-    exit 0
-}
-
-
-usage()
-{
-       echo "  usage: extract-ikconfig [b]zImage_filename"
-}
-
-clean_up()
+# ----------------------------------------------------------------------
+# extract-ikconfig - Extract the .config file from a kernel image
+#
+# This will only work when the kernel was compiled with CONFIG_IKCONFIG.
+#
+# The obscure use of the "tr" filter is to work around older versions of
+# "grep" that report the byte offset of the line instead of the pattern.
+#
+# (c) 2009, Dick Streefland <dick@streefland.net>
+# Licensed under the terms of the GNU General Public License.
+# ----------------------------------------------------------------------
+
+gz1='\037\213\010'
+gz2='01'
+cf1='IKCFG_ST\037\213\010'
+cf2='0123456789'
+
+dump_config()
 {
-       if [ "$TMPFILE" != "" ]; then
-               rm -f $TMPFILE
+       if      pos=`tr "$cf1\n$cf2" "\n$cf2=" < "$1" | grep -abo "^$cf2"`
+       then
+               pos=${pos%%:*}
+               tail -c+$(($pos+8)) "$1" | zcat -q
+               exit 0
        fi
 }
 
-if [ $# -lt 1 ]
+# Check invocation:
+me=${0##*/}
+img=$1
+if     [ $# -ne 1 -o ! -s "$img" ]
 then
-       usage
-       exit 1
+       echo "Usage: $me <kernel-image>" >&2
+       exit 2
 fi
 
-TMPFILE=`mktemp -t ikconfig-XXXXXX` || exit 1
-image="$1"
-
-# vmlinux: Attempt to dump the configuration from the file directly
-dump_config "$image"
-
-GZHDR1="0x1f 0x8b 0x08 0x00"
-GZHDR2="0x1f 0x8b 0x08 0x08"
-
-ELFHDR="0x7f 0x45 0x4c 0x46"
-
-# vmlinux.gz: Check for a compressed images
-off=`$binoffset "$image" $GZHDR1 2>/dev/null`
-[ "$?" != "0" ] && off="-1"
-if [ "$off" -eq "-1" ]; then
-       off=`$binoffset "$image" $GZHDR2 2>/dev/null`
-       [ "$?" != "0" ] && off="-1"
-fi
-if [ "$off" -eq "0" ]; then
-       zcat <"$image" >"$TMPFILE"
-       dump_config "$TMPFILE"
-elif [ "$off" -ne "-1" ]; then
-       (dd ibs="$off" skip=1 count=0 && dd bs=512k) <"$image" 2>/dev/null | \
-               zcat >"$TMPFILE"
-       dump_config "$TMPFILE"
-
-# check if this is simply an ELF file
-else
-       off=`$binoffset "$image" $ELFHDR 2>/dev/null`
-       [ "$?" != "0" ] && off="-1"
-       if [ "$off" -eq "0" ]; then
-               dump_config "$image"
-       fi
-fi
-
-echo "ERROR: Unable to extract kernel configuration information."
-echo "       This kernel image may not have the config info."
-
-clean_up
+# Initial attempt for uncompressed images or objects:
+dump_config "$img"
+
+# That didn't work, so decompress and try again:
+tmp=/tmp/ikconfig$$
+trap "rm -f $tmp" 0
+for    pos in `tr "$gz1\n$gz2" "\n$gz2=" < "$img" | grep -abo "^$gz2"`
+do
+       pos=${pos%%:*}
+       tail -c+$pos "$img" | zcat 2> /dev/null > $tmp
+       dump_config $tmp
+done
+
+# Bail out:
+echo "$me: Cannot find kernel config." >&2
 exit 1
index 999e8a7..186c466 100644 (file)
@@ -30,8 +30,17 @@ silentoldconfig: $(obj)/conf
        $(Q)mkdir -p include/generated
        $< -s $(Kconfig)
 
+# if no path is given, then use src directory to find file
+ifdef LSMOD
+LSMOD_F := $(LSMOD)
+ifeq ($(findstring /,$(LSMOD)),)
+  LSMOD_F := $(objtree)/$(LSMOD)
+endif
+endif
+
 localmodconfig: $(obj)/streamline_config.pl $(obj)/conf
-       $(Q)perl $< $(srctree) $(Kconfig) > .tmp.config
+       $(Q)mkdir -p include/generated
+       $(Q)perl $< $(srctree) $(Kconfig) $(LSMOD_F) > .tmp.config
        $(Q)if [ -f .config ]; then                             \
                        cmp -s .tmp.config .config ||           \
                        (mv -f .config .config.old.1;           \
@@ -45,7 +54,8 @@ localmodconfig: $(obj)/streamline_config.pl $(obj)/conf
        $(Q)rm -f .tmp.config
 
 localyesconfig: $(obj)/streamline_config.pl $(obj)/conf
-       $(Q)perl $< $(srctree) $(Kconfig) > .tmp.config
+       $(Q)mkdir -p include/generated
+       $(Q)perl $< $(srctree) $(Kconfig) $(LSMOD_F) > .tmp.config
        $(Q)sed -i s/=m/=y/ .tmp.config
        $(Q)if [ -f .config ]; then                             \
                        cmp -s .tmp.config .config ||           \
index 0d80082..afbd54a 100644 (file)
@@ -113,6 +113,7 @@ find_config;
 # Get the build source and top level Kconfig file (passed in)
 my $ksource = $ARGV[0];
 my $kconfig = $ARGV[1];
+my $lsmod_file = $ARGV[2];
 
 my @makefiles = `find $ksource -name Makefile`;
 my %depends;
@@ -121,6 +122,8 @@ my %prompts;
 my %objects;
 my $var;
 my $cont = 0;
+my $iflevel = 0;
+my @ifdeps;
 
 # prevent recursion
 my %read_kconfigs;
@@ -146,6 +149,15 @@ sub read_kconfig {
            $state = "NEW";
            $config = $1;
 
+           for (my $i = 0; $i < $iflevel; $i++) {
+               if ($i) {
+                   $depends{$config} .= " " . $ifdeps[$i];
+               } else {
+                   $depends{$config} = $ifdeps[$i];
+               }
+               $state = "DEP";
+           }
+
        # collect the depends for the config
        } elsif ($state eq "NEW" && /^\s*depends\s+on\s+(.*)$/) {
            $state = "DEP";
@@ -166,6 +178,21 @@ sub read_kconfig {
            # note if the config has a prompt
            $prompt{$config} = 1;
 
+       # Check for if statements
+       } elsif (/^if\s+(.*\S)\s*$/) {
+           my $deps = $1;
+           # remove beginning and ending non text
+           $deps =~ s/^[^a-zA-Z0-9_]*//;
+           $deps =~ s/[^a-zA-Z0-9_]*$//;
+
+           my @deps = split /[^a-zA-Z0-9_]+/, $deps;
+
+           $ifdeps[$iflevel++] = join ':', @deps;
+
+       } elsif (/^endif/) {
+
+           $iflevel-- if ($iflevel);
+
        # stop on "help"
        } elsif (/^\s*help\s*$/) {
            $state = "NONE";
@@ -237,8 +264,36 @@ foreach my $makefile (@makefiles) {
 
 my %modules;
 
-# see what modules are loaded on this system
-open(LIN,"/sbin/lsmod|") || die "Cant lsmod";
+if (defined($lsmod_file)) {
+    if ( ! -f $lsmod_file) {
+       die "$lsmod_file not found";
+    }
+    if ( -x $lsmod_file) {
+       # the file is executable, run it
+       open(LIN, "$lsmod_file|");
+    } else {
+       # Just read the contents
+       open(LIN, "$lsmod_file");
+    }
+} else {
+
+    # see what modules are loaded on this system
+    my $lsmod;
+
+    foreach $dir ( ("/sbin", "/bin", "/usr/sbin", "/usr/bin") ) {
+       if ( -x "$dir/lsmod" ) {
+           $lsmod = "$dir/lsmod";
+           last;
+       }
+}
+    if (!defined($lsmod)) {
+       # try just the path
+       $lsmod = "lsmod";
+    }
+
+    open(LIN,"$lsmod|") || die "Can not call lsmod with $lsmod";
+}
+
 while (<LIN>) {
        next if (/^Module/);  # Skip the first line.
        if (/^(\S+)/) {
index 0d83edc..2d4d05d 100644 (file)
@@ -63,12 +63,11 @@ int ima_inode_alloc(struct inode *inode)
        spin_lock(&ima_iint_lock);
        rc = radix_tree_insert(&ima_iint_store, (unsigned long)inode, iint);
        spin_unlock(&ima_iint_lock);
+       radix_tree_preload_end();
 out:
        if (rc < 0)
                kmem_cache_free(iint_cache, iint);
 
-       radix_tree_preload_end();
-
        return rc;
 }
 
index 68c7348..04b6145 100644 (file)
@@ -128,7 +128,7 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap,
                        cmap_idx = delta / NETLBL_CATMAP_MAPSIZE;
                        cmap_sft = delta % NETLBL_CATMAP_MAPSIZE;
                        c_iter->bitmap[cmap_idx]
-                               |= e_iter->maps[cmap_idx] << cmap_sft;
+                               |= e_iter->maps[i] << cmap_sft;
                }
                e_iter = e_iter->next;
        }
index 586965f..7a437da 100644 (file)
@@ -768,7 +768,7 @@ static int check_codec(struct aoa_codec *codec,
                                "required property %s not present\n", propname);
                        return -ENODEV;
                }
-               if (*ref != codec->node->linux_phandle) {
+               if (*ref != codec->node->phandle) {
                        printk(KERN_INFO "snd-aoa-fabric-layout: "
                                "%s doesn't match!\n", propname);
                        return -ENODEV;
index 2e15646..b366793 100644 (file)
@@ -751,8 +751,8 @@ static void snd_pmac_awacs_suspend(struct snd_pmac *chip)
 
 static void snd_pmac_awacs_resume(struct snd_pmac *chip)
 {
-       if (machine_is_compatible("PowerBook3,1")
-           || machine_is_compatible("PowerBook3,2")) {
+       if (of_machine_is_compatible("PowerBook3,1")
+           || of_machine_is_compatible("PowerBook3,2")) {
                msleep(100);
                snd_pmac_awacs_write_reg(chip, 1,
                        chip->awacs_reg[1] & ~MASK_PAROUT);
@@ -780,16 +780,16 @@ static void snd_pmac_awacs_resume(struct snd_pmac *chip)
 }
 #endif /* CONFIG_PM */
 
-#define IS_PM7500 (machine_is_compatible("AAPL,7500") \
-               || machine_is_compatible("AAPL,8500") \
-               || machine_is_compatible("AAPL,9500"))
-#define IS_PM5500 (machine_is_compatible("AAPL,e411"))
-#define IS_BEIGE (machine_is_compatible("AAPL,Gossamer"))
-#define IS_IMAC1 (machine_is_compatible("PowerMac2,1"))
-#define IS_IMAC2 (machine_is_compatible("PowerMac2,2") \
-               || machine_is_compatible("PowerMac4,1"))
-#define IS_G4AGP (machine_is_compatible("PowerMac3,1"))
-#define IS_LOMBARD (machine_is_compatible("PowerBook1,1"))
+#define IS_PM7500 (of_machine_is_compatible("AAPL,7500") \
+               || of_machine_is_compatible("AAPL,8500") \
+               || of_machine_is_compatible("AAPL,9500"))
+#define IS_PM5500 (of_machine_is_compatible("AAPL,e411"))
+#define IS_BEIGE (of_machine_is_compatible("AAPL,Gossamer"))
+#define IS_IMAC1 (of_machine_is_compatible("PowerMac2,1"))
+#define IS_IMAC2 (of_machine_is_compatible("PowerMac2,2") \
+               || of_machine_is_compatible("PowerMac4,1"))
+#define IS_G4AGP (of_machine_is_compatible("PowerMac3,1"))
+#define IS_LOMBARD (of_machine_is_compatible("PowerBook1,1"))
 
 static int imac1, imac2;
 
index 0accfe4..1f72e1c 100644 (file)
@@ -582,7 +582,7 @@ static int snd_pmac_burgundy_detect_headphone(struct snd_pmac *chip)
 static void snd_pmac_burgundy_update_automute(struct snd_pmac *chip, int do_notify)
 {
        if (chip->auto_mute) {
-               int imac = machine_is_compatible("iMac");
+               int imac = of_machine_is_compatible("iMac");
                int reg, oreg;
                reg = oreg = snd_pmac_burgundy_rcb(chip,
                                MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES);
@@ -620,7 +620,7 @@ static void snd_pmac_burgundy_update_automute(struct snd_pmac *chip, int do_noti
  */
 int __devinit snd_pmac_burgundy_init(struct snd_pmac *chip)
 {
-       int imac = machine_is_compatible("iMac");
+       int imac = of_machine_is_compatible("iMac");
        int i, err;
 
        /* Checks to see the chip is alive and kicking */
index 7bc492e..8508117 100644 (file)
@@ -922,11 +922,11 @@ static void __devinit detect_byte_swap(struct snd_pmac *chip)
        }
 
        /* it seems the Pismo & iBook can't byte-swap in hardware. */
-       if (machine_is_compatible("PowerBook3,1") ||
-           machine_is_compatible("PowerBook2,1"))
+       if (of_machine_is_compatible("PowerBook3,1") ||
+           of_machine_is_compatible("PowerBook2,1"))
                chip->can_byte_swap = 0 ;
 
-       if (machine_is_compatible("PowerBook2,1"))
+       if (of_machine_is_compatible("PowerBook2,1"))
                chip->can_duplex = 0;
 }
 
@@ -959,11 +959,11 @@ static int __devinit snd_pmac_detect(struct snd_pmac *chip)
        chip->control_mask = MASK_IEPC | MASK_IEE | 0x11; /* default */
 
        /* check machine type */
-       if (machine_is_compatible("AAPL,3400/2400")
-           || machine_is_compatible("AAPL,3500"))
+       if (of_machine_is_compatible("AAPL,3400/2400")
+           || of_machine_is_compatible("AAPL,3500"))
                chip->is_pbook_3400 = 1;
-       else if (machine_is_compatible("PowerBook1,1")
-                || machine_is_compatible("AAPL,PowerBook1998"))
+       else if (of_machine_is_compatible("PowerBook1,1")
+                || of_machine_is_compatible("AAPL,PowerBook1998"))
                chip->is_pbook_G3 = 1;
        chip->node = of_find_node_by_name(NULL, "awacs");
        sound = of_node_get(chip->node);
@@ -1033,8 +1033,8 @@ static int __devinit snd_pmac_detect(struct snd_pmac *chip)
        }
        if (of_device_is_compatible(sound, "tumbler")) {
                chip->model = PMAC_TUMBLER;
-               chip->can_capture = machine_is_compatible("PowerMac4,2")
-                               || machine_is_compatible("PowerBook4,1");
+               chip->can_capture = of_machine_is_compatible("PowerMac4,2")
+                               || of_machine_is_compatible("PowerBook4,1");
                chip->can_duplex = 0;
                // chip->can_byte_swap = 0; /* FIXME: check this */
                chip->num_freqs = ARRAY_SIZE(tumbler_freqs);
index 3326e2a..1a5b8e0 100644 (file)
@@ -55,7 +55,7 @@ static __init int efika_fabric_init(void)
        struct platform_device *pdev;
        int rc;
 
-       if (!machine_is_compatible("bplan,efika"))
+       if (!of_machine_is_compatible("bplan,efika"))
                return -ENODEV;
 
        card.platform = &mpc5200_audio_dma_platform;
index b928ef7..6644cba 100644 (file)
@@ -55,7 +55,7 @@ static __init int pcm030_fabric_init(void)
        struct platform_device *pdev;
        int rc;
 
-       if (!machine_is_compatible("phytec,pcm030"))
+       if (!of_machine_is_compatible("phytec,pcm030"))
                return -ENODEV;
 
        card.platform = &mpc5200_audio_dma_platform;
index 29465d4..fde17b0 100644 (file)
@@ -272,6 +272,7 @@ int synthesize_perf_probe_point(struct probe_point *pp)
        int ret;
 
        pp->probes[0] = buf = zalloc(MAX_CMDLEN);
+       pp->found = 1;
        if (!buf)
                die("Failed to allocate memory by zalloc.");
        if (pp->offset) {
@@ -294,6 +295,7 @@ int synthesize_perf_probe_point(struct probe_point *pp)
 error:
                free(pp->probes[0]);
                pp->probes[0] = NULL;
+               pp->found = 0;
        }
        return ret;
 }
@@ -455,6 +457,7 @@ void show_perf_probe_events(void)
        struct strlist *rawlist;
        struct str_node *ent;
 
+       memset(&pp, 0, sizeof(pp));
        fd = open_kprobe_events(O_RDONLY, 0);
        rawlist = get_trace_kprobe_event_rawlist(fd);
        close(fd);