Merge branch 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 26 Feb 2010 18:35:27 +0000 (10:35 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 26 Feb 2010 18:35:27 +0000 (10:35 -0800)
* 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6: (48 commits)
  x86/PCI: Prevent mmconfig memory corruption
  ACPI: Use GPE reference counting to support shared GPEs
  x86/PCI: use host bridge _CRS info by default on 2008 and newer machines
  PCI: augment bus resource table with a list
  PCI: add pci_bus_for_each_resource(), remove direct bus->resource[] refs
  PCI: read bridge windows before filling in subtractive decode resources
  PCI: split up pci_read_bridge_bases()
  PCIe PME: use pci_pcie_cap()
  PCI PM: Run-time callbacks for PCI bus type
  PCIe PME: use pci_is_pcie()
  PCI / ACPI / PM: Platform support for PCI PME wake-up
  ACPI / ACPICA: Multiple system notify handlers per device
  ACPI / PM: Add more run-time wake-up fields
  ACPI: Use GPE reference counting to support shared GPEs
  PCI PM: Make it possible to force using INTx for PCIe PME signaling
  PCI PM: PCIe PME root port service driver
  PCI PM: Add function for checking PME status of devices
  PCI: mark is_pcie obsolete
  PCI: set PCI_PREF_RANGE_TYPE_64 in pci_bridge_check_ranges
  PCI: pciehp: second try to get big range for pcie devices
  ...

176 files changed:
Documentation/dontdiff
Documentation/lguest/lguest.c
Documentation/networking/ip-sysctl.txt
MAINTAINERS
Makefile
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/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/kernel/devices.c
arch/sparc/kernel/of_device_32.c
arch/sparc/kernel/of_device_64.c
arch/sparc/kernel/prom.h
arch/sparc/kernel/prom_common.c
arch/sparc/kernel/smp_64.c
block/blk-core.c
drivers/acpi/processor_idle.c
drivers/acpi/processor_perflib.c
drivers/ata/ahci.c
drivers/block/virtio_blk.c
drivers/char/Kconfig
drivers/char/hvc_beat.c
drivers/char/hvc_console.c
drivers/char/hvc_console.h
drivers/char/hvc_iseries.c
drivers/char/hvc_iucv.c
drivers/char/hvc_rtas.c
drivers/char/hvc_udbg.c
drivers/char/hvc_vio.c
drivers/char/hvc_xen.c
drivers/char/virtio_console.c
drivers/clocksource/cs5535-clockevt.c
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/nv50_instmem.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.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/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/net/e1000/e1000_main.c
drivers/net/mace.c
drivers/net/tc35815.c
drivers/net/usb/cdc_ether.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-tx.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/platform/x86/acer-wmi.c
drivers/sbus/char/openprom.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/usb/storage/usb.c
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
fs/exec.c
fs/proc/proc_devtree.c
include/linux/blkdev.h
include/linux/hid.h
include/linux/input.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/sys.c
lib/idr.c
mm/oom_kill.c
net/bluetooth/hidp/core.c
net/core/dev.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

index 3ad6acead94950a3b83e4f14912e01cc64973b6b..d9bcffd594331d7b52a5608269327a7c6642af31 100644 (file)
@@ -69,7 +69,6 @@ av_permissions.h
 bbootsect
 bin2c
 binkernel.spec
-binoffset
 bootsect
 bounds.h
 bsetup
index 42208511b5c054a20f513c350807e54d67abb724..3119f5db75bd62c7289f5bcee6ee729f51d595ac 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 006b39dec87d66f88edc62f9547482f554a6519e..e87f3cdc8a6afc42c36f9469e7afac9b1ec74b82 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 c95f727236e1ce04d77e0d34484f44f70b8e020c..317ed38826d7e57214cc6b46c96ec3ce599f8ca4 100644 (file)
@@ -2393,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
@@ -3489,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 12b1aa1103eef3604bcd7593a707904760d60e15..1b24895212d8d198587bed5152b56a2cef8134c3 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 ece1bf994499a1d55e33cf64d2c7fd9f13e8dad4..e456f062f2419deb5f2bfd9d0e968d88b1c79ac5 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 cd5837e298b2a6d10db695d5776be3f3b5697459..b008168ae946b6e479c690911c8d2f0e451b1017 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 fc9997b73c09de6183f20ceea4631d590c6d4697..267c7c779e537b1be0c475abaca0719170f54b1f 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 ef3ec1d6ceb382464be02fe743d99fb0b0b3ad1d..03f45a96320412b7a21ac2243f305608b8acae59 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 d9d63831cc2f9d6318257fa358ac41d41553c789..2a56bccce4e02a822a5c3193b6ee72175bd03fd8 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 acf4574d0f188fd7fd99fec2ab911b8a4d0e446e..1c6d684996d7eae768686ba88945e79148180c74 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 b817df172aa95d5e0c18784231e03f2435eeafe7..a15ef6d67ca92e037628f1c9808db4f5cd55e5ad 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 c51405e5792117d868b99dc2fe21c30c8f06061d..29d3cbf9555feae7f96e4faf6b076f797d5b14c4 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 e274fda329f4e5bc9ef0a90484972b650390e2b0..127d732474bf0ceb63dd38c75db8d0cfde1312c0 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 524d9352f17e56a4120008d601d219590fad6a23..f388dc68f60544cf941dfd66267b2a6f7167db1f 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 5179e5e6f8fb94cff2f31f280d3955cc2b5ed33b..38372e7cbb88f1d53372061e5e6e23684bcbc4a9 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 ba3948c700727b212aa2952e729176b7c1501442..50c9af43e0170ac66b283dc2d57bdc28cbc35d96 100644 (file)
@@ -173,6 +173,7 @@ config PPC_OF
 
 config OF
        def_bool y
+       select OF_FLATTREE
 
 config PPC_UDBG_16550
        bool
index 2ab9cbd98826555ffb3e3f8be70f43846b415074..ddd408a93b5a526c1c30d24c7c4d1a119365e338 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 1a4fc0d11a031706ab19018959074ea6fbbfc4f7..666d08db319e313f87c0d1c975a267461df51ca2 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 ccf56ac92de552fd0f5d7867430f6d510977064f..d43fc65749c1161e1b016f884792fcf73948479d 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 4ec3008624662e8a7eb9df4ba1709dd255b8e245..43238b2054b68735a678d0bef885bf193b530fa9 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
@@ -1264,27 +742,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 1b426050a2f91952cb588f2a61388430e387780a..0125604d096e917de7c7c6a923aa61df37c538a8 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 dcddaa5fcb665164bcd0b25370f28bd3fb9d934c..f75a4daa4ca2821439b17177a43a0969e1d2cf82 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 5e0a191764fc0158b5eb7377af019615c3540767..608fd2b584c910548aff61f8a6c4d421a731b572 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 4c506c1463cd28a1bc5c8e3604f0738ea36df688..891f18e337a269a75f07dbcdfb54a1ae11b9c30d 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 be2527a516eabcd5cc6c8db97d22c613abfdcc9a..d35e0520abf007d5278f0f07eaac082a09e170e4 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 08d94e4cedd359909782c71b3b8219409745fc5b..d4f127d18141192bef0d3771e81bc79529d707fc 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 708c751333770b216009d1d4d112a0b0a74c08d1..3ed288e68ec4e613546b12b3ce4f9ec734830488 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 fbc9bbd74dbdc9337ca2880f1d50a590d8f9f3a1..33e815f4466cbe4c58bb80281d29576abc417ca9 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 96d5ce50364eab840571b216c10819e71834408d..ede49e78a8da4f631632d7e553513dab2924f8af 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 b40c22d697f006d06f2e952a5a602dee999bc333..6898e8241cd03826335aae8653e82a1775b5eb24 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 1810e4226e5615543999e7242a8c467991707907..48211ca134c3b3845c80af2a8ab58d9549ffa776 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 9490157da62e06a066073db4b462890ff16f038c..d83135a9830ead5f677b5af278fc183949d6df30 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 5da37c2f22ee28db96e064aae1172e3b61e4a3c1..cf27df6e508bb8ea2d6a0e33c0be595d8d2ad58b 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 b171ae8de90dc5b49aa410c03c166603c37b4d02..b062de9424a484d51e1513e8a0b2ffb86a86faff 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 53a58b34984910630ec44aac5ad5f44036447a75..da527b33ebc708ad2693d9932bbae97f671e2d88 100644 (file)
@@ -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 0a6f2d1798d11b37b5f8570b8bafb0326531d164..b3d4cb5d21b333c54fee00998491644397eb92d1 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 453397fe5e14035fbc980689d844e5673312d4a3..a8591ef2636d4e55a64738e836c4a084a840d71c 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 d80a65d9e893df99c26cb8d0b7c5d7f77528163a..57ac9e28be0caff3b08be55f0228fa8655863739 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 aa36223497b931c9dc96c1ef2d536672aa36248d..eb14844a0021bbccb76d6981c3f9cabb9ac75c35 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 718897e6d37f2293615a858ea880b8e245ad7050..d1a9a0a64f95b5295314bec0ef6c2e96d99775b2 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 e88e8ae04fdbe5a9ecd8fe44c8128e65ab7f96bf..cc978a8c00b797d6c5e9d4300a857a7fa612d6ea 100644 (file)
@@ -880,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;
@@ -965,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 2cabadcc4d8c36806bc886080a6c0cae3d50dd04..a959f6a075083153580902746aabb8f178d425f4 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 b34390347c1685b624f36c13cc864e1c03ccf8ee..a6a736a7dbf2ea1bbe09dd5afae1dd37d44ded55 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 51042f0ba7e163e6b3dbbd7c0c2fbd2a498a33aa..7eff828b21170731fd5c02290136a12665b4e9ea 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 e023682be2c464302ca157cfa65e672485746b8c..3141dd3b6e530f6dc264c04ce089609e1fadd164 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 0afc8b82212e78dd17d7d2b254ec099b5642cfb7..5fe4631e2a6135f1fb2c417246b7e306e980475b 100644 (file)
@@ -84,7 +84,7 @@ static int hvc_beat_put_chars(uint32_t vtermno, const char *buf, int cnt)
        return cnt;
 }
 
-static struct hv_ops hvc_beat_get_put_ops = {
+static const struct hv_ops hvc_beat_get_put_ops = {
        .get_chars = hvc_beat_get_chars,
        .put_chars = hvc_beat_put_chars,
 };
@@ -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 416d3423150d8d037dce7a459eb8a5fc44a64fc8..d8dac5820f0e601379448716883e437356ea5915 100644 (file)
@@ -125,7 +125,7 @@ static struct hvc_struct *hvc_get_by_index(int index)
  * console interfaces but can still be used as a tty device.  This has to be
  * static because kmalloc will not work during early console init.
  */
-static struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES];
+static const struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES];
 static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] =
        {[0 ... MAX_NR_HVC_CONSOLES - 1] = -1};
 
@@ -247,7 +247,7 @@ static void destroy_hvc_struct(struct kref *kref)
  * vty adapters do NOT get an hvc_instantiate() callback since they
  * appear after early console init.
  */
-int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops)
+int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops)
 {
        struct hvc_struct *hp;
 
@@ -749,7 +749,8 @@ static const struct tty_operations hvc_ops = {
 };
 
 struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int data,
-                                       struct hv_ops *ops, int outbuf_size)
+                                      const struct hv_ops *ops,
+                                      int outbuf_size)
 {
        struct hvc_struct *hp;
        int i;
index 10950ca706d8d9dfe31ca0012b5415aababb5192..52ddf4d3716cac7367aa6a88c6f1271391eaae40 100644 (file)
@@ -55,7 +55,7 @@ struct hvc_struct {
        int outbuf_size;
        int n_outbuf;
        uint32_t vtermno;
-       struct hv_ops *ops;
+       const struct hv_ops *ops;
        int irq_requested;
        int data;
        struct winsize ws;
@@ -76,11 +76,12 @@ struct hv_ops {
 };
 
 /* Register a vterm and a slot index for use as a console (console_init) */
-extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops);
+extern int hvc_instantiate(uint32_t vtermno, int index,
+                          const struct hv_ops *ops);
 
 /* register a vterm for hvc tty operation (module_init or hotplug add) */
 extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int data,
-                               struct hv_ops *ops, int outbuf_size);
+                               const struct hv_ops *ops, int outbuf_size);
 /* remove a vterm from hvc tty operation (module_exit or hotplug remove) */
 extern int hvc_remove(struct hvc_struct *hp);
 
index 936d05bf37fa3264ae48ec539f0787d6a1a7c3cc..fd0242676a2a4530a24470f78e8609369ee0873b 100644 (file)
@@ -197,7 +197,7 @@ done:
        return sent;
 }
 
-static struct hv_ops hvc_get_put_ops = {
+static const struct hv_ops hvc_get_put_ops = {
        .get_chars = get_chars,
        .put_chars = put_chars,
        .notifier_add = notifier_add_irq,
index fe62bd0e17b751f55e359addc54ee4569a4f7488..21681a81cc35d6ee5cc5a09ac5d37e8be7ce5e15 100644 (file)
@@ -922,7 +922,7 @@ static int hvc_iucv_pm_restore_thaw(struct device *dev)
 
 
 /* HVC operations */
-static struct hv_ops hvc_iucv_ops = {
+static const struct hv_ops hvc_iucv_ops = {
        .get_chars = hvc_iucv_get_chars,
        .put_chars = hvc_iucv_put_chars,
        .notifier_add = hvc_iucv_notifier_add,
index 88590d040046decb71f76629c3aa52fd0383817b..61c4a61558d972abebb2ba6fd11d906066169ac6 100644 (file)
@@ -71,7 +71,7 @@ static int hvc_rtas_read_console(uint32_t vtermno, char *buf, int count)
        return i;
 }
 
-static struct hv_ops hvc_rtas_get_put_ops = {
+static const struct hv_ops hvc_rtas_get_put_ops = {
        .get_chars = hvc_rtas_read_console,
        .put_chars = hvc_rtas_write_console,
 };
index bd63ba878a560eecf3513dd58989331337c1a7f4..b0957e61a7befc015fb05adf587e32d48626edea 100644 (file)
@@ -58,7 +58,7 @@ static int hvc_udbg_get(uint32_t vtermno, char *buf, int count)
        return i;
 }
 
-static struct hv_ops hvc_udbg_ops = {
+static const struct hv_ops hvc_udbg_ops = {
        .get_chars = hvc_udbg_get,
        .put_chars = hvc_udbg_put,
 };
index 10be343d6ae75127c1aa980c1667fe518bbbb0ab..27370e99c66fa0a371ffec67a6e6d87b35af4477 100644 (file)
@@ -77,7 +77,7 @@ static int filtered_get_chars(uint32_t vtermno, char *buf, int count)
        return got;
 }
 
-static struct hv_ops hvc_get_put_ops = {
+static const struct hv_ops hvc_get_put_ops = {
        .get_chars = filtered_get_chars,
        .put_chars = hvc_put_chars,
        .notifier_add = notifier_add_irq,
index b1a71638c772b8ed5be135408c612130d7b2ec8b..60446f82a3fc2653c905adb3a6f944c1686f0863 100644 (file)
@@ -122,7 +122,7 @@ static int read_console(uint32_t vtermno, char *buf, int len)
        return recv;
 }
 
-static struct hv_ops hvc_ops = {
+static const struct hv_ops hvc_ops = {
        .get_chars = read_console,
        .put_chars = write_console,
        .notifier_add = notifier_add_irq,
index a035ae39a3594bad321536817c5943695c3be433..213373b5f17fc61e2112001a23811e82e44bcc63 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 27d20fac19d153a9fca968fb169dbed9c1490e3f..b314a999aabea67ad637b6ebfde64beef6cb3aaa 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 5445cefdd03ec4e765f45ab4e62fc2deddd74810..1c15ef37b71cffc9c234f08b0337e50e1af4ff6e 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 8f3a12f614ed27e4bcade0cd1f76863af59c8d48..2dc09dbd817d06d178343bf7280f7187115dd555 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 d0e038d289484d4b0bb01bfaefb081e74abb1e33..1d73b15d70daf52c52e83dcac5a9200f304c288a 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 94400f777e7f9bd1d83eb73890bf23450fb7bfa6..f0dc4e36ef055c7d711eaf1a54a501d41bbce2d2 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 e7b19440102efc61f5ca99701840c7b0c0e15573..22d476160d5293ec74e38a44e14630eea5922c9b 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 d69caf92ffe78bfc4060f7daf99c10d60af5e6b7..0897359b3e4e27550dbe2d767e2ca3a50be49c14 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 24d90ea246ce95096dd0d74ba3f50b1dcae4b8fc..71d4c0703629a55331aed27e12aa17cd63ffa66c 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 0de2dff5542c9c59255f546fa8b2b512d9312c9e..0b2618f092ca525b272bf10242ff4843b68cfce2 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 5b4d66dc1a05600ded73ece82be8fae8d61dc43c..78286b184ace5ebe58850623b5ab670d1c995a64 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 eabe5f87c6c1a7dfd35f66445edda66f9558669d..368fbb0c4ca6b161d2acea66d7a10bdf4c6a36f5 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 6abd0369aedba0125f935dc357f292d5e6850017..cd4ece6fdfb967b8fe89227742dd49e13b09df67 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 010368e649ed2fc54ca3832add6e91c1ea791ea2..72c05f90553c7ec84351a34acf2ff6fc3ca10dbc 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 5862b0f3b55d1de24413744cde877ca33031212a..79d9edd0bdfa489cd075164d36464a15e6267b92 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 9fcd3d017ab3ac012906b296e81e9c78ccb070c5..3677c9037a11036da88292adf0693b6ea1531242 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 bf31592eaf79dc32757296f47191e6e66f1d2477..ce2ac86726245e984829680ba64a77d5bd38a5f2 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 987abebe08296a4f37770e2164e623012d4cac95..61142b76a9b19fe90826dfda870d7717d7f36f4b 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 49ce69d7bba754ee37e62ec386ab48385879b52a..3234c729a895f1cf733e59149c07eb5e83fac1b6 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 4e8450228a24f8e097dd7c7f073815f5873b7c1c..9bf00d77d92b8f7201b910fe39ab374ba1015ae0 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 12dcda529201b4795e268d1826cf3cf10b58ec01..8d3b46f5d14956ea4bf60bde0f067cf8bed22105 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 cdd136942bcaa9e1435b1d2efc5444bf6f3317fc..d04476700b7b4eb792e41d381a61b535e0666f8f 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 e2997a8d5e1b4b726ac9b62f0d60e2647ae37ce4..56d06cd8075b32f9cc6faec1f1909925f3f79c43 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 38773dc2821b3360119afad656aab279046bdaba..7844280897d1940c1a02ac37b95305ad7ad49d39 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 08f505ca2e3db47426a2940fb2876a2e89ba9e14..ec20400c7f2904bf793ac82b37cac65df03ac161 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 23741cec45e3e43210fdbac7e11c6ecc9c4eb1d5..d840a109f8336968b42aa3f96d8751318fdf763b 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 454bc501df3cfbb3629f0388692a8931bb6fcc94..5738d8bf2d97e8918330147c8827e551fd2ec317 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 ba48fd76396eb9746d72e0db077b55dbf0f23ffa..7fb8b4da35a7a740c81dbd005e2d05d1f656926d 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 a348bb0791d37b764a2e61ffe55bacd57a12e182..4f3c4479c16aa16da18efd22bbc37e12dc39d2c7 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 db379c3814326db904a17a76b7182ec4266a3a4a..42764849eb787c42fe38315333e0d6bbcd544287 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 075b4d99e35497c9a8f505af04d1fdf617489680..437f55c5d18d32f02fbd89c6fd220108cfe6e857 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 900aade0619871c683b2a29cf45a3638c925a957..1a77a7c97d0e58d3141b667b6ff2b55be0aa3f52 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 ed6426a107738b4dff5a1d639140a7f22b7c9b27..d8257d35afde91c225b49bad6f0cc9885cf3fc69 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 a67b349319e9c9be57f19faf3f309ff487e06448..b486eb929fde725fb9e0271d4af46cdc241c2113 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 73d695dc9e5059c950c99f8c08a0cd30a2141c39..e0ee80700cde4713430452bffbeb0625a51479db 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 66ec4fb115bb203a3c566cead227e650386b8d4d..947d4afa25ca9abfe199ffea35f2233e944c9498 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 abbe206474f58ce2ff1de53e274d6df7158b92f4..565d5b2adc95918e2d89a2076bc6b6441d70a3da 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 764c525b2117f0ac2420992063ac1efdcb512a21..bea99168ff35c9366d43d0ad460b0989c2f2f225 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 9c567b93f417b05d7ad15cd054c30627d851fb16..3c193504bb8002d9aa8d497976c119967a63700c 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 d29bb532eccf15349f8792fbb0f5b803beda29db..765543663a4f29ada5fef9fe31032a476d306dda 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 d9fbad386389718a393437437336d6763644cc7c..43aea91e33699ace0a407bcd018f64a728b492ab 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 75a669d48e5ebc4be3d79b84ee09ff7a50d85845..d71c1976072e7bcbda5739748a9d92bf67b44d17 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 4f27f022fbf7b93bb65aace8189e3b3039192b61..5f3b9eaeb04fbc76ea1a721931d331ebe6e4ccd1 100644 (file)
@@ -583,6 +583,11 @@ static const struct usb_device_id  products [] = {
        USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x1049, USB_CLASS_COMM,
                        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,
index 9b4b8b5c757464f0f48e9455ed1ea23f0a418a4f..31462813bac0c798bf0749fe35d3265edbdf85f1 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 de45f308b7440a56024ea5b54491633c4628398f..cffaae772d513169a356c3aa28e76a692c2b656d 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 d10bea64fce3004335557f07cbc084ae5921a2d0..f36f804804fc2d0a54f3a3e260324738e776bbef 100644 (file)
@@ -2744,8 +2744,8 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
                if ((le16_to_cpu(priv->staging_rxon.channel) != ch))
                        priv->staging_rxon.flags = 0;
 
-               iwl_set_rxon_ht(priv, ht_conf);
                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 27ca859e7453c250ca70aea6d64ce9820ae6f98d..b69e972671b2c156b208d3615b7370a55e79c252 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 87ce2bd292c7810630cd382239a15283f82add76..8f407156285768cc992d1f28d1a92d467a97c4a2 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 d2fa27c5c1b28e444748214e363bb3c462a43f0e..7cecc8fea9bd799ffd37e7361c7636cbe3bd69f1 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 bdfb5f5d4b06d46d6e05ff2e219cf712328945ef..f232cc98ce00904e9b655c0fd51b6dd5fa3028d4 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 e6627b2320f16a89a56d30e9a7e00b6c2c80130a..cb96888d142785c4f9ea82f19e1de26ffcd448c7 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)
@@ -143,6 +220,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
  *
@@ -518,6 +616,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
@@ -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 6eea601a92043b69f3c95c86aa06ae077327c03a..24c3606217f86a5db00bbf36547ba90d0489e2b2 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 fa65a2b2ae2e44737edb5d4e19daf767e331bd9c..a3a708e590d00eabbd2ce62105d2bd4c06bbd922 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 4b22ba568b19919a1cb81c0164ba248bd90bd17d..18ecae4a4375d461957b04ee8171f1e5e1434b8c 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 bed0ed6dcdc1329259c58a72e2b697bfbd72e091..f65f48b9844885c9708596c73aa4f7eeefba1904 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 07d14dfdf0b42f01caab15df68123f023219517c..226b3e93498c45d8f63fc2f67544950a512b20cd 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 75ac19b1192ff40d144fec752b7937b158abe86e..fc2f676e984da2aaf9937f4662cff2e83a73dcb7 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 683e66f18e8cd37b45e5d91e18061470286cbb5b..3e2ae4807ae2f0a697945dcd0a18ba1b6091c2e3 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 f55eb0107336b0a66ca8f68dd41b9a3752d3bb3a..0fee95cd9a49dde3ae57af9911204cbc71b8baa2 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 f3d2810ba11c9f3fd11cbdaddf9b50431e70b70b..d7d0f89b797bbcf180475215cc64bc44d5c97400 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 31620fae77be607a469bbdc7baf3b314921a1ba9..8ed38f1d6c18d36daab177affb9fb1e015cd2c07 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 34ba69161734e19f5b1685a295ceab783cb4113e..1f0735f9cc76ab0232aa282f19f071b89be827ce 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 f50c81df336a7831a76cdc85f92a1f3c2a7b7527..04747868d6c4d4605ec679f21306b650b4475657 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 45bfe645817332f7a3754237815c263e909582ea..6eab46537a0ae3a6bb1d52d9a9662fc24c60da18 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 1893f1e96dc4906da0a92d1d4de38492781faa53..0ddbbe45e83442f77f2334e7e84a87d5d77ac810 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 1fb2a6ea328cfcff9ce8ec3a03700f3bec729947..4f0cc9d457e04b6c115d08a72014e83ff4e5bd58 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 140a18d6cf3eba059fabbf122e65767ec04bb046..6d8d4026a07a6569e0ba2812a0ce705dc94c5b67 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 88a456dba967c91091dbb7eb0a4321f5c5bbcd3d..97365815a729a2d3c17d47d3815ffa38ff6c6526 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 30973ec16a93d6bd3d0968b04bd3d8b81f534c33..d93b66743ba759fc70a55531699f23f00a81333a 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 2552bb36400564f58a66285647a7faa951090be8..fadff76eb7e06807e5171dc074b5416db02d032b 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 9f386379c16974285c48c48932075d4025471b90..1b47363cb73f6d8c624b0af5bc44d2047e6ae8a7 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 71dc3adc049577f0a5159fdca7864786218e1930..ed34a8d419c7545b1a3912d9737e48c100852fb2 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 e9f995486ec1b1fa46021ed0bd3202044d0a425a..bbeeb92a213101d7eeab4314c91532da707247f7 100644 (file)
@@ -78,7 +78,7 @@ MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
 MODULE_DESCRIPTION("USB Mass Storage driver for Linux");
 MODULE_LICENSE("GPL");
 
-static unsigned int delay_use = 5;
+static unsigned int delay_use = 1;
 module_param(delay_use, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
 
index e4e4d433b00701a16bac2255bd54a1a10b928188..9ee67d6da7101f1d3b0f714553792f60015b4c02 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 1ddeb4c34763a3db66b6f2e3c863ff56747c300e..e45ab8db2ddc6f7f46d98ff09504dcc8c45ff2e6 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 1a056adb61c836784fce99d1c0314e710f4948e8..fa1198c4ccc5d0041072b5ca95913134e3531ee3 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 eb12182b20598861937b46496b8716efcae1e366..d25df51bb0d2b3160efe478fb4e64f968014ea04 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 505be88c82aefd7361c7f85f95a8394ffc8ca922..369f2eebbad14d5a2999712549894260f4e407e4 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 28d9cf7cf72f9fd1ee8aeea96085da394d48702e..1d5191fab62e440928376f33666a92a15d7be5df 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 fbd2ecde93e409ea9287d068d3f2322297c910cc..0db906b3c95d71bd985fa97b2fc62c52a7244104 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 e95c692ef0e4acb3434e6d9386a56954907226c8..cce6bbdbdbb11705afbe6c729007ede3b8714e92 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 123257bb356b38bc8fe614b101a2354a24c82e47..f8650dce74fb069c6a66a497c4933cc50e630539 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 5c8018977efa8551a6df91c62c2272ce64b8ddb4..1896e868854f949ed12c1ef38eb145b7c3633801 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 87093652dda8d00ee341132f40eb17d5b46171be..b1344ec4b7fc9fe93305eaf2d96cfed494bb3de7 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 663208afb64ce37ed16334debe6f40a4a858418f..f44ee9114401777eb5f0628a03fa074084a23ca9 100644 (file)
@@ -598,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 e7facd8fbce87a35aa25ccd1d2af5121dbba71a0..f6d9cbc39c9ca684907940822ead7425c9f2c5da 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 41d432b13553ad32799962e69235f324ca5c56a0..a1ca92ccb0ff65dc06241ab2ac7bb04bf44c7f92 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 51b3e771a9a3f832b062fe4cde257c07bf204606..cc813f95a2f2b6a4ddf19d04ed1b60fc321c9712 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 057a2e0107589763411cfeea1bd6e7e4b189a24c..f508c651e53dec96f7d27a840979fd80a42e0d10 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 1418f048cb34741919b788160a4657eba462b2fe..a50ecd1b81a2acce1da35758767d3abcf0b06a99 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 fd294c56d5717d56bc0df1412d621cc059673e1e..e52029e98919bb38401dd1848de418277ba271a9 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 fe885174cc1f061ef8d0b706a362d27574ca616f..ae4f039515b441f3407d88da1e2172a78bab2e5b 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 26a6b73a6b85bbc2a4ee1e1392d3aa86d1e9a850..18bde979f346c46a8af621b62171912a1db98f5a 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 1cac726c44bc17cc6fa1a7b5ab6358279a0c9a5d..0dc782216d4b94dc423c2d62d1ac70a2b6d30ddc 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 f52481b1c1e5442c9a5b16b06b22221b75b9bb7c..237050478f28f46fc59c5c9984337f1c3d60de08 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 fc6ec1e726527ac7b64ed084d2a766175c9401ff..280529ad9274afe107dc4b566f25768c4c044d73 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 be9924f60ec34bafa135916455595e794a7fe86c..ec874218b20638887a54140ee3612f50659743b1 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 52cab46ae35a3be5a6a1869ce2b01aa9c4e06190..c5d5db54c009994c5945200b055e56b4869e7fff 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 de233ff43c1c3e73b0b93cf04bcbb9105db16570..37f30d36c944645988c722d81e854744a5a18f39 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 999e8a7d5bf7e1be6aa473bc865c4a4d2df36d75..186c46604d0669f8f1d4cfbcaf7ad0cdc6d658fa 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 0d800820c3cd72d6408079b6dbdec96eac954515..afbd54ac1d832ed758bf959f6bbc6ae5fc59f6aa 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 0d83edcfc4028620d9f9dee37fe826c8c50b5712..2d4d05d92fdacf01048ac9857541e8d17a3f0855 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 68c7348d1acc6628f4c6121207edc34f6a7f707a..04b6145d767f96093423d5f733e6fe1b6a4e5687 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 586965f9605fd55d4a6cf9c8f804f01d373647bb..7a437da056465dc189619231d63dc1d0b6fb79dc 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 2e156467b814bf48c94ee902f363995a49cde6f6..b36679384b27b6ab1486481d15a6e779c9c6a126 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 0accfe49735bad21718be559ae110c657f15ceb0..1f72e1c786bf2f389e18788bd3b304287312617a 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 7bc492ee77ecf1978f659e5180e62e55fb990cd9..85081172403f25ec056a99eb58a341fbd5d57370 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 3326e2a1e8633a9ee357541c687536ec701f6f62..1a5b8e0d6a34d986fcfb62c5ac0c7cdc6ad9f2b7 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 b928ef7d28eb82461e7ac3513bef6534d2addf75..6644cba7cbf20e5a16e75ad459df1c2663afcc93 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;