Merge with master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
authorDavid Woodhouse <dwmw2@shinybook.infradead.org>
Tue, 17 May 2005 11:04:46 +0000 (12:04 +0100)
committerDavid Woodhouse <dwmw2@shinybook.infradead.org>
Tue, 17 May 2005 11:04:46 +0000 (12:04 +0100)
34 files changed:
arch/arm/mach-s3c2410/clock.c
arch/arm/mach-s3c2410/s3c2440.c
arch/arm/mm/Kconfig
arch/arm/mm/copypage-v4mc.S [deleted file]
arch/arm/mm/copypage-v4mc.c [new file with mode: 0644]
arch/arm/mm/copypage-v6.c
arch/arm/mm/flush.c
arch/arm/mm/mm-armv.c
drivers/block/ioctl.c
drivers/block/pktcdvd.c
drivers/char/raw.c
drivers/mmc/Kconfig
drivers/mmc/wbsd.c
drivers/mmc/wbsd.h
drivers/net/Makefile
drivers/net/ibm_emac/ibm_emac_core.c
drivers/net/tulip/tulip_core.c
drivers/net/wireless/Kconfig
drivers/serial/21285.c
drivers/serial/8250.c
drivers/serial/amba-pl010.c
drivers/serial/amba-pl011.c
drivers/serial/clps711x.c
drivers/serial/pxa.c
drivers/serial/s3c2410.c
drivers/serial/sa1100.c
drivers/serial/serial_lh7a40x.c
drivers/serial/serial_txx9.c
drivers/serial/vr41xx_siu.c
fs/binfmt_elf.c
include/asm-arm/arch-imx/imx-regs.h
include/asm-arm/arch-s3c2410/regs-nand.h
include/asm-arm/page.h
include/linux/serial_core.h

index e23f534d4e1d1696ff7343ad29f1ecad893f9cc1..8d986b8401c2474f3948bb3a4301c26a9784b7f1 100644 (file)
@@ -478,7 +478,7 @@ static int s3c2440_clk_add(struct sys_device *sysdev)
 {
        unsigned long upllcon = __raw_readl(S3C2410_UPLLCON);
 
-       s3c2440_clk_upll.rate = s3c2410_get_pll(upllcon, clk_xtal.rate) * 2;
+       s3c2440_clk_upll.rate = s3c2410_get_pll(upllcon, clk_xtal.rate);
 
        printk("S3C2440: Clock Support, UPLL %ld.%03ld MHz\n",
               print_mhz(s3c2440_clk_upll.rate));
index 9a8cc5ae225566e5d6d17de94df3fe79dbfe9a2c..d4c8281b55f64a5c3a7a4f2d4fef2c6433215d25 100644 (file)
@@ -192,9 +192,11 @@ void __init s3c2440_map_io(struct map_desc *mach_desc, int size)
 
        iotable_init(s3c2440_iodesc, ARRAY_SIZE(s3c2440_iodesc));
        iotable_init(mach_desc, size);
+
        /* rename any peripherals used differing from the s3c2410 */
 
-       s3c_device_i2c.name = "s3c2440-i2c";
+       s3c_device_i2c.name  = "s3c2440-i2c";
+       s3c_device_nand.name = "s3c2440-nand";
 
        /* change irq for watchdog */
 
@@ -225,7 +227,7 @@ void __init s3c2440_init_clocks(int xtal)
                break;
 
        case S3C2440_CLKDIVN_HDIVN_2:
-               hdiv = 1;
+               hdiv = 2;
                break;
 
        case S3C2440_CLKDIVN_HDIVN_4_8:
index c4fc6be629deeee971c6635b5130d7e329970a63..48bac7da8c70589dba5f06be40b325457398c640 100644 (file)
@@ -412,21 +412,20 @@ config CPU_BPREDICT_DISABLE
 
 config TLS_REG_EMUL
        bool
-       default y if (SMP || CPU_32v6) && (CPU_32v5 || CPU_32v4 || CPU_32v3)
+       default y if SMP && (CPU_32v5 || CPU_32v4 || CPU_32v3)
        help
-         We might be running on an ARMv6+ processor which should have the TLS
-         register but for some reason we can't use it, or maybe an SMP system
-         using a pre-ARMv6 processor (there are apparently a few prototypes
-         like that in existence) and therefore access to that register must
-         be emulated.
+         An SMP system using a pre-ARMv6 processor (there are apparently
+         a few prototypes like that in existence) and therefore access to
+         that required register must be emulated.
 
 config HAS_TLS_REG
        bool
-       depends on CPU_32v6
-       default y if !TLS_REG_EMUL
+       depends on !TLS_REG_EMUL
+       default y if SMP || CPU_32v7
        help
          This selects support for the CP15 thread register.
-         It is defined to be available on ARMv6 or later.  If a particular
-         ARMv6 or later CPU doesn't support it then it must omc;ide "select
-         TLS_REG_EMUL" along with its other caracteristics.
+         It is defined to be available on some ARMv6 processors (including
+         all SMP capable ARMv6's) or later processors.  User space may
+         assume directly accessing that register and always obtain the
+         expected value only on ARMv7 and above.
 
diff --git a/arch/arm/mm/copypage-v4mc.S b/arch/arm/mm/copypage-v4mc.S
deleted file mode 100644 (file)
index 305af3d..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- *  linux/arch/arm/lib/copy_page-armv4mc.S
- *
- *  Copyright (C) 1995-2001 Russell King
- *
- * 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.
- *
- *  ASM optimised string functions
- */
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <asm/constants.h>
-
-       .text
-       .align  5
-/*
- * ARMv4 mini-dcache optimised copy_user_page
- *
- * We flush the destination cache lines just before we write the data into the
- * corresponding address.  Since the Dcache is read-allocate, this removes the
- * Dcache aliasing issue.  The writes will be forwarded to the write buffer,
- * and merged as appropriate.
- *
- * Note: We rely on all ARMv4 processors implementing the "invalidate D line"
- * instruction.  If your processor does not supply this, you have to write your
- * own copy_user_page that does the right thing.
- */
-ENTRY(v4_mc_copy_user_page)
-       stmfd   sp!, {r4, lr}                   @ 2
-       mov     r4, r0
-       mov     r0, r1
-       bl      map_page_minicache
-       mov     r1, #PAGE_SZ/64                 @ 1
-       ldmia   r0!, {r2, r3, ip, lr}           @ 4
-1:     mcr     p15, 0, r4, c7, c6, 1           @ 1   invalidate D line
-       stmia   r4!, {r2, r3, ip, lr}           @ 4
-       ldmia   r0!, {r2, r3, ip, lr}           @ 4+1
-       stmia   r4!, {r2, r3, ip, lr}           @ 4
-       ldmia   r0!, {r2, r3, ip, lr}           @ 4
-       mcr     p15, 0, r4, c7, c6, 1           @ 1   invalidate D line
-       stmia   r4!, {r2, r3, ip, lr}           @ 4
-       ldmia   r0!, {r2, r3, ip, lr}           @ 4
-       subs    r1, r1, #1                      @ 1
-       stmia   r4!, {r2, r3, ip, lr}           @ 4
-       ldmneia r0!, {r2, r3, ip, lr}           @ 4
-       bne     1b                              @ 1
-       ldmfd   sp!, {r4, pc}                   @ 3
-
-       .align  5
-/*
- * ARMv4 optimised clear_user_page
- *
- * Same story as above.
- */
-ENTRY(v4_mc_clear_user_page)
-       str     lr, [sp, #-4]!
-       mov     r1, #PAGE_SZ/64                 @ 1
-       mov     r2, #0                          @ 1
-       mov     r3, #0                          @ 1
-       mov     ip, #0                          @ 1
-       mov     lr, #0                          @ 1
-1:     mcr     p15, 0, r0, c7, c6, 1           @ 1   invalidate D line
-       stmia   r0!, {r2, r3, ip, lr}           @ 4
-       stmia   r0!, {r2, r3, ip, lr}           @ 4
-       mcr     p15, 0, r0, c7, c6, 1           @ 1   invalidate D line
-       stmia   r0!, {r2, r3, ip, lr}           @ 4
-       stmia   r0!, {r2, r3, ip, lr}           @ 4
-       subs    r1, r1, #1                      @ 1
-       bne     1b                              @ 1
-       ldr     pc, [sp], #4
-
-       __INITDATA
-
-       .type   v4_mc_user_fns, #object
-ENTRY(v4_mc_user_fns)
-       .long   v4_mc_clear_user_page
-       .long   v4_mc_copy_user_page
-       .size   v4_mc_user_fns, . - v4_mc_user_fns
diff --git a/arch/arm/mm/copypage-v4mc.c b/arch/arm/mm/copypage-v4mc.c
new file mode 100644 (file)
index 0000000..fc69dcc
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ *  linux/arch/arm/lib/copypage-armv4mc.S
+ *
+ *  Copyright (C) 1995-2005 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This handles the mini data cache, as found on SA11x0 and XScale
+ * processors.  When we copy a user page page, we map it in such a way
+ * that accesses to this page will not touch the main data cache, but
+ * will be cached in the mini data cache.  This prevents us thrashing
+ * the main data cache on page faults.
+ */
+#include <linux/init.h>
+#include <linux/mm.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+
+/*
+ * 0xffff8000 to 0xffffffff is reserved for any ARM architecture
+ * specific hacks for copying pages efficiently.
+ */
+#define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \
+                                 L_PTE_CACHEABLE)
+
+#define TOP_PTE(x)     pte_offset_kernel(top_pmd, x)
+
+static DEFINE_SPINLOCK(minicache_lock);
+
+/*
+ * ARMv4 mini-dcache optimised copy_user_page
+ *
+ * We flush the destination cache lines just before we write the data into the
+ * corresponding address.  Since the Dcache is read-allocate, this removes the
+ * Dcache aliasing issue.  The writes will be forwarded to the write buffer,
+ * and merged as appropriate.
+ *
+ * Note: We rely on all ARMv4 processors implementing the "invalidate D line"
+ * instruction.  If your processor does not supply this, you have to write your
+ * own copy_user_page that does the right thing.
+ */
+static void __attribute__((naked))
+mc_copy_user_page(void *from, void *to)
+{
+       asm volatile(
+       "stmfd  sp!, {r4, lr}                   @ 2\n\
+       mov     r4, %2                          @ 1\n\
+       ldmia   %0!, {r2, r3, ip, lr}           @ 4\n\
+1:     mcr     p15, 0, %1, c7, c6, 1           @ 1   invalidate D line\n\
+       stmia   %1!, {r2, r3, ip, lr}           @ 4\n\
+       ldmia   %0!, {r2, r3, ip, lr}           @ 4+1\n\
+       stmia   %1!, {r2, r3, ip, lr}           @ 4\n\
+       ldmia   %0!, {r2, r3, ip, lr}           @ 4\n\
+       mcr     p15, 0, %1, c7, c6, 1           @ 1   invalidate D line\n\
+       stmia   %1!, {r2, r3, ip, lr}           @ 4\n\
+       ldmia   %0!, {r2, r3, ip, lr}           @ 4\n\
+       subs    r4, r4, #1                      @ 1\n\
+       stmia   %1!, {r2, r3, ip, lr}           @ 4\n\
+       ldmneia %0!, {r2, r3, ip, lr}           @ 4\n\
+       bne     1b                              @ 1\n\
+       ldmfd   sp!, {r4, pc}                   @ 3"
+       :
+       : "r" (from), "r" (to), "I" (PAGE_SIZE / 64));
+}
+
+void v4_mc_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr)
+{
+       spin_lock(&minicache_lock);
+
+       set_pte(TOP_PTE(0xffff8000), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot));
+       flush_tlb_kernel_page(0xffff8000);
+
+       mc_copy_user_page((void *)0xffff8000, kto);
+
+       spin_unlock(&minicache_lock);
+}
+
+/*
+ * ARMv4 optimised clear_user_page
+ */
+void __attribute__((naked))
+v4_mc_clear_user_page(void *kaddr, unsigned long vaddr)
+{
+       asm volatile(
+       "str    lr, [sp, #-4]!\n\
+       mov     r1, %0                          @ 1\n\
+       mov     r2, #0                          @ 1\n\
+       mov     r3, #0                          @ 1\n\
+       mov     ip, #0                          @ 1\n\
+       mov     lr, #0                          @ 1\n\
+1:     mcr     p15, 0, r0, c7, c6, 1           @ 1   invalidate D line\n\
+       stmia   r0!, {r2, r3, ip, lr}           @ 4\n\
+       stmia   r0!, {r2, r3, ip, lr}           @ 4\n\
+       mcr     p15, 0, r0, c7, c6, 1           @ 1   invalidate D line\n\
+       stmia   r0!, {r2, r3, ip, lr}           @ 4\n\
+       stmia   r0!, {r2, r3, ip, lr}           @ 4\n\
+       subs    r1, r1, #1                      @ 1\n\
+       bne     1b                              @ 1\n\
+       ldr     pc, [sp], #4"
+       :
+       : "I" (PAGE_SIZE / 64));
+}
+
+struct cpu_user_fns v4_mc_user_fns __initdata = {
+       .cpu_clear_user_page    = v4_mc_clear_user_page, 
+       .cpu_copy_user_page     = v4_mc_copy_user_page,
+};
index 694ac8208858a9c54475f8f3173b71cca7787d4e..a8c00236bd3d54283da26f1fe36d3a0cc3d6c636 100644 (file)
@@ -26,8 +26,8 @@
 #define to_address     (0xffffc000)
 #define to_pgprot      PAGE_KERNEL
 
-static pte_t *from_pte;
-static pte_t *to_pte;
+#define TOP_PTE(x)     pte_offset_kernel(top_pmd, x)
+
 static DEFINE_SPINLOCK(v6_lock);
 
 #define DCACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT)
@@ -74,8 +74,8 @@ void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned long vadd
         */
        spin_lock(&v6_lock);
 
-       set_pte(from_pte + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, from_pgprot));
-       set_pte(to_pte + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, to_pgprot));
+       set_pte(TOP_PTE(from_address) + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, from_pgprot));
+       set_pte(TOP_PTE(to_address) + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, to_pgprot));
 
        from = from_address + (offset << PAGE_SHIFT);
        to   = to_address + (offset << PAGE_SHIFT);
@@ -114,7 +114,7 @@ void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr)
         */
        spin_lock(&v6_lock);
 
-       set_pte(to_pte + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, to_pgprot));
+       set_pte(TOP_PTE(to_address) + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, to_pgprot));
        flush_tlb_kernel_page(to);
        clear_page((void *)to);
 
@@ -129,21 +129,6 @@ struct cpu_user_fns v6_user_fns __initdata = {
 static int __init v6_userpage_init(void)
 {
        if (cache_is_vipt_aliasing()) {
-               pgd_t *pgd;
-               pmd_t *pmd;
-
-               pgd = pgd_offset_k(from_address);
-               pmd = pmd_alloc(&init_mm, pgd, from_address);
-               if (!pmd)
-                       BUG();
-               from_pte = pte_alloc_kernel(&init_mm, pmd, from_address);
-               if (!from_pte)
-                       BUG();
-
-               to_pte = pte_alloc_kernel(&init_mm, pmd, to_address);
-               if (!to_pte)
-                       BUG();
-
                cpu_user.cpu_clear_user_page = v6_clear_user_page_aliasing;
                cpu_user.cpu_copy_user_page = v6_copy_user_page_aliasing;
        }
@@ -151,5 +136,4 @@ static int __init v6_userpage_init(void)
        return 0;
 }
 
-__initcall(v6_userpage_init);
-
+core_initcall(v6_userpage_init);
index c6de48d895032de8d615ee0f1ae8d8b31e13a716..4085ed983e46e07c3ac62ba31f8b0e605ee2594c 100644 (file)
 
 #include <asm/cacheflush.h>
 #include <asm/system.h>
+#include <asm/tlbflush.h>
+
+#ifdef CONFIG_CPU_CACHE_VIPT
+#define ALIAS_FLUSH_START      0xffff4000
+
+#define TOP_PTE(x)     pte_offset_kernel(top_pmd, x)
+
+static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
+{
+       unsigned long to = ALIAS_FLUSH_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT);
+
+       set_pte(TOP_PTE(to), pfn_pte(pfn, PAGE_KERNEL));
+       flush_tlb_kernel_page(to);
+
+       asm(    "mcrr   p15, 0, %1, %0, c14\n"
+       "       mcrr    p15, 0, %1, %0, c5\n"
+           :
+           : "r" (to), "r" (to + PAGE_SIZE - L1_CACHE_BYTES)
+           : "cc");
+}
+#else
+#define flush_pfn_alias(pfn,vaddr)     do { } while (0)
+#endif
 
 static void __flush_dcache_page(struct address_space *mapping, struct page *page)
 {
@@ -36,6 +59,18 @@ static void __flush_dcache_page(struct address_space *mapping, struct page *page
        if (!mapping)
                return;
 
+       /*
+        * This is a page cache page.  If we have a VIPT cache, we
+        * only need to do one flush - which would be at the relevant
+        * userspace colour, which is congruent with page->index.
+        */
+       if (cache_is_vipt()) {
+               if (cache_is_vipt_aliasing())
+                       flush_pfn_alias(page_to_pfn(page),
+                                       page->index << PAGE_CACHE_SHIFT);
+               return;
+       }
+
        /*
         * There are possible user space mappings of this page:
         * - VIVT cache: we need to also write back and invalidate all user
@@ -57,8 +92,6 @@ static void __flush_dcache_page(struct address_space *mapping, struct page *page
                        continue;
                offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT;
                flush_cache_page(mpnt, mpnt->vm_start + offset, page_to_pfn(page));
-               if (cache_is_vipt())
-                       break;
        }
        flush_dcache_mmap_unlock(mapping);
 }
index 585dfb8e20b96a7526b519d85afe8dc67226c562..2c2b93d77d433248dba64b6a1dd525eae51277fc 100644 (file)
@@ -37,6 +37,8 @@ pgprot_t pgprot_kernel;
 
 EXPORT_SYMBOL(pgprot_kernel);
 
+pmd_t *top_pmd;
+
 struct cachepolicy {
        const char      policy[16];
        unsigned int    cr_mask;
@@ -142,6 +144,16 @@ __setup("noalign", noalign_setup);
 
 #define FIRST_KERNEL_PGD_NR    (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD)
 
+static inline pmd_t *pmd_off(pgd_t *pgd, unsigned long virt)
+{
+       return pmd_offset(pgd, virt);
+}
+
+static inline pmd_t *pmd_off_k(unsigned long virt)
+{
+       return pmd_off(pgd_offset_k(virt), virt);
+}
+
 /*
  * need to get a 16k page for level 1
  */
@@ -220,7 +232,7 @@ void free_pgd_slow(pgd_t *pgd)
                return;
 
        /* pgd is always present and good */
-       pmd = (pmd_t *)pgd;
+       pmd = pmd_off(pgd, 0);
        if (pmd_none(*pmd))
                goto free;
        if (pmd_bad(*pmd)) {
@@ -246,9 +258,8 @@ free:
 static inline void
 alloc_init_section(unsigned long virt, unsigned long phys, int prot)
 {
-       pmd_t *pmdp;
+       pmd_t *pmdp = pmd_off_k(virt);
 
-       pmdp = pmd_offset(pgd_offset_k(virt), virt);
        if (virt & (1 << 20))
                pmdp++;
 
@@ -283,11 +294,9 @@ alloc_init_supersection(unsigned long virt, unsigned long phys, int prot)
 static inline void
 alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pgprot_t prot)
 {
-       pmd_t *pmdp;
+       pmd_t *pmdp = pmd_off_k(virt);
        pte_t *ptep;
 
-       pmdp = pmd_offset(pgd_offset_k(virt), virt);
-
        if (pmd_none(*pmdp)) {
                unsigned long pmdval;
                ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE *
@@ -310,7 +319,7 @@ alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pg
  */
 static inline void clear_mapping(unsigned long virt)
 {
-       pmd_clear(pmd_offset(pgd_offset_k(virt), virt));
+       pmd_clear(pmd_off_k(virt));
 }
 
 struct mem_types {
@@ -578,7 +587,7 @@ void setup_mm_for_reboot(char mode)
                         PMD_TYPE_SECT;
                if (cpu_arch <= CPU_ARCH_ARMv5)
                        pmdval |= PMD_BIT4;
-               pmd = pmd_offset(pgd + i, i << PGDIR_SHIFT);
+               pmd = pmd_off(pgd, i << PGDIR_SHIFT);
                pmd[0] = __pmd(pmdval);
                pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
                flush_pmd_entry(pmd);
@@ -675,6 +684,8 @@ void __init memtable_init(struct meminfo *mi)
 
        flush_cache_all();
        flush_tlb_all();
+
+       top_pmd = pmd_off_k(0xffff0000);
 }
 
 /*
index 5e03f5157ef93b2d2b3bc447a36ceba566a2336d..6d7bcc9da9e72f806d0c3fe77aacca8c1ec896e3 100644 (file)
@@ -237,3 +237,5 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
        }
        return ret;
 }
+
+EXPORT_SYMBOL_GPL(blkdev_ioctl);
index 1a1fa3ccb91375031556815e71fa858cdc48ab60..82ccad0a7f1a48e56b4d36a628b56aea5392166e 100644 (file)
@@ -2406,7 +2406,7 @@ static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
        case CDROM_LAST_WRITTEN:
        case CDROM_SEND_PACKET:
        case SCSI_IOCTL_SEND_COMMAND:
-               return ioctl_by_bdev(pd->bdev, cmd, arg);
+               return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg);
 
        case CDROMEJECT:
                /*
@@ -2414,7 +2414,7 @@ static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
                 * have to unlock it or else the eject command fails.
                 */
                pkt_lock_door(pd, 0);
-               return ioctl_by_bdev(pd->bdev, cmd, arg);
+               return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg);
 
        default:
                printk("pktcdvd: Unknown ioctl for %s (%x)\n", pd->name, cmd);
index a2e33ec796151ab4f96f4a869447f87088f0e300..131465e8de5aa72b6e8f5621a6b000c97862f73a 100644 (file)
@@ -122,7 +122,7 @@ raw_ioctl(struct inode *inode, struct file *filp,
 {
        struct block_device *bdev = filp->private_data;
 
-       return ioctl_by_bdev(bdev, command, arg);
+       return blkdev_ioctl(bdev->bd_inode, filp, command, arg);
 }
 
 static void bind_device(struct raw_config_request *rq)
index 2e70d74fbdee2d8bffa3a7a4d01de57061d317a1..4991bbd054f31fcbc86b4b0871dec7777d00154c 100644 (file)
@@ -51,7 +51,7 @@ config MMC_PXA
 
 config MMC_WBSD
        tristate "Winbond W83L51xD SD/MMC Card Interface support"
-       depends on MMC && ISA && ISA_DMA_API
+       depends on MMC && ISA_DMA_API
        help
          This selects the Winbond(R) W83L51xD Secure digital and
           Multimedia card Interface.
index 39747526c719ff1f93241e08206e7fd61884b673..b7fbd30b49a0de18d1b05cf30bcfe62c0f64efac 100644 (file)
@@ -28,7 +28,9 @@
 #include <linux/ioport.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
 #include <linux/delay.h>
+#include <linux/pnp.h>
 #include <linux/highmem.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/protocol.h>
@@ -40,7 +42,7 @@
 #include "wbsd.h"
 
 #define DRIVER_NAME "wbsd"
-#define DRIVER_VERSION "1.1"
+#define DRIVER_VERSION "1.2"
 
 #ifdef CONFIG_MMC_DEBUG
 #define DBG(x...) \
 #define DBGF(x...)     do { } while (0)
 #endif
 
-static unsigned int io = 0x248;
-static unsigned int irq = 6;
-static int dma = 2;
-
 #ifdef CONFIG_MMC_DEBUG
 void DBG_REG(int reg, u8 value)
 {
@@ -78,29 +76,62 @@ void DBG_REG(int reg, u8 value)
 #define DBG_REG(r, v) do {}  while (0)
 #endif
 
+/*
+ * Device resources
+ */
+
+#ifdef CONFIG_PNP
+
+static const struct pnp_device_id pnp_dev_table[] = {
+       { "WEC0517", 0 },
+       { "WEC0518", 0 },
+       { "", 0 },
+};
+
+MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
+
+#endif /* CONFIG_PNP */
+
+#ifdef CONFIG_PNP
+static unsigned int nopnp = 0;
+#else
+static const unsigned int nopnp = 1;
+#endif
+static unsigned int io = 0x248;
+static unsigned int irq = 6;
+static int dma = 2;
+
 /*
  * Basic functions
  */
 
 static inline void wbsd_unlock_config(struct wbsd_host* host)
 {
+       BUG_ON(host->config == 0);
+       
        outb(host->unlock_code, host->config);
        outb(host->unlock_code, host->config);
 }
 
 static inline void wbsd_lock_config(struct wbsd_host* host)
 {
+       BUG_ON(host->config == 0);
+       
        outb(LOCK_CODE, host->config);
 }
 
 static inline void wbsd_write_config(struct wbsd_host* host, u8 reg, u8 value)
 {
+       BUG_ON(host->config == 0);
+       
        outb(reg, host->config);
        outb(value, host->config + 1);
 }
 
 static inline u8 wbsd_read_config(struct wbsd_host* host, u8 reg)
 {
+       BUG_ON(host->config == 0);
+       
        outb(reg, host->config);
        return inb(host->config + 1);
 }
@@ -132,6 +163,13 @@ static void wbsd_init_device(struct wbsd_host* host)
        setup |= WBSD_FIFO_RESET | WBSD_SOFT_RESET;
        wbsd_write_index(host, WBSD_IDX_SETUP, setup);
        
+       /*
+        * Set DAT3 to input
+        */
+       setup &= ~WBSD_DAT3_H;
+       wbsd_write_index(host, WBSD_IDX_SETUP, setup);
+       host->flags &= ~WBSD_FIGNORE_DETECT;
+       
        /*
         * Read back default clock.
         */
@@ -147,6 +185,14 @@ static void wbsd_init_device(struct wbsd_host* host)
         */
        wbsd_write_index(host, WBSD_IDX_TAAC, 0x7F);
        
+       /*
+        * Test for card presence
+        */
+       if (inb(host->base + WBSD_CSR) & WBSD_CARDPRESENT)
+               host->flags |= WBSD_FCARD_PRESENT;
+       else
+               host->flags &= ~WBSD_FCARD_PRESENT;
+       
        /*
         * Enable interesting interrupts.
         */
@@ -407,8 +453,6 @@ static inline void wbsd_get_long_reply(struct wbsd_host* host,
        }
 }
 
-static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs);
-
 static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd)
 {
        int i;
@@ -646,6 +690,13 @@ static void wbsd_fill_fifo(struct wbsd_host* host)
        }
        
        wbsd_kunmap_sg(host);
+       
+       /*
+        * The controller stops sending interrupts for
+        * 'FIFO empty' under certain conditions. So we
+        * need to be a bit more pro-active.
+        */
+       tasklet_schedule(&host->fifo_tasklet);
 }
 
 static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
@@ -850,9 +901,11 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data)
        wbsd_request_end(host, host->mrq);
 }
 
-/*
- * MMC Callbacks
- */
+/*****************************************************************************\
+ *                                                                           *
+ * MMC layer callbacks                                                       *
+ *                                                                           *
+\*****************************************************************************/
 
 static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq)
 {
@@ -874,7 +927,7 @@ static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq)
         * If there is no card in the slot then
         * timeout immediatly.
         */
-       if (!(inb(host->base + WBSD_CSR) & WBSD_CARDPRESENT))
+       if (!(host->flags & WBSD_FCARD_PRESENT))
        {
                cmd->error = MMC_ERR_TIMEOUT;
                goto done;
@@ -953,33 +1006,50 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
                host->clk = clk;
        }
 
+       /*
+        * Power up card.
+        */
        if (ios->power_mode != MMC_POWER_OFF)
        {
-               /*
-                * Power up card.
-                */
                pwr = inb(host->base + WBSD_CSR);
                pwr &= ~WBSD_POWER_N;
                outb(pwr, host->base + WBSD_CSR);
-
-               /*
-                * This behaviour is stolen from the
-                * Windows driver. Don't know why, but
-                * it is needed.
-                */
-               setup = wbsd_read_index(host, WBSD_IDX_SETUP);
-               if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
-                       setup |= WBSD_DAT3_H;
-               else
-                       setup &= ~WBSD_DAT3_H;
-               wbsd_write_index(host, WBSD_IDX_SETUP, setup);
-
-               mdelay(1);
        }
 
+       /*
+        * MMC cards need to have pin 1 high during init.
+        * Init time corresponds rather nicely with the bus mode.
+        * It wreaks havoc with the card detection though so
+        * that needs to be disabed.
+        */
+       setup = wbsd_read_index(host, WBSD_IDX_SETUP);
+       if ((ios->power_mode == MMC_POWER_ON) &&
+               (ios->bus_mode == MMC_BUSMODE_OPENDRAIN))
+       {
+               setup |= WBSD_DAT3_H;
+               host->flags |= WBSD_FIGNORE_DETECT;
+       }
+       else
+       {
+               setup &= ~WBSD_DAT3_H;
+               host->flags &= ~WBSD_FIGNORE_DETECT;
+       }
+       wbsd_write_index(host, WBSD_IDX_SETUP, setup);
+       
        spin_unlock_bh(&host->lock);
 }
 
+static struct mmc_host_ops wbsd_ops = {
+       .request        = wbsd_request,
+       .set_ios        = wbsd_set_ios,
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Interrupt handling                                                        *
+ *                                                                           *
+\*****************************************************************************/
+
 /*
  * Tasklets
  */
@@ -1005,17 +1075,33 @@ static void wbsd_tasklet_card(unsigned long param)
 {
        struct wbsd_host* host = (struct wbsd_host*)param;
        u8 csr;
+       int change = 0;
        
        spin_lock(&host->lock);
        
+       if (host->flags & WBSD_FIGNORE_DETECT)
+       {
+               spin_unlock(&host->lock);
+               return;
+       }
+       
        csr = inb(host->base + WBSD_CSR);
        WARN_ON(csr == 0xff);
        
        if (csr & WBSD_CARDPRESENT)
-               DBG("Card inserted\n");
-       else
+       {
+               if (!(host->flags & WBSD_FCARD_PRESENT))
+               {
+                       DBG("Card inserted\n");
+                       host->flags |= WBSD_FCARD_PRESENT;
+                       change = 1;
+               }
+       }
+       else if (host->flags & WBSD_FCARD_PRESENT)
        {
                DBG("Card removed\n");
+               host->flags &= ~WBSD_FCARD_PRESENT;
+               change = 1;
                
                if (host->mrq)
                {
@@ -1033,7 +1119,8 @@ static void wbsd_tasklet_card(unsigned long param)
         */
        spin_unlock(&host->lock);
 
-       mmc_detect_change(host->mmc);
+       if (change)
+               mmc_detect_change(host->mmc);
 }
 
 static void wbsd_tasklet_fifo(unsigned long param)
@@ -1200,11 +1287,85 @@ static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
+/*****************************************************************************\
+ *                                                                           *
+ * Device initialisation and shutdown                                        *
+ *                                                                           *
+\*****************************************************************************/
+
 /*
- * Support functions for probe
+ * Allocate/free MMC structure.
  */
 
-static int wbsd_scan(struct wbsd_host* host)
+static int __devinit wbsd_alloc_mmc(struct device* dev)
+{
+       struct mmc_host* mmc;
+       struct wbsd_host* host;
+       
+       /*
+        * Allocate MMC structure.
+        */
+       mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev);
+       if (!mmc)
+               return -ENOMEM;
+       
+       host = mmc_priv(mmc);
+       host->mmc = mmc;
+
+       host->dma = -1;
+
+       /*
+        * Set host parameters.
+        */
+       mmc->ops = &wbsd_ops;
+       mmc->f_min = 375000;
+       mmc->f_max = 24000000;
+       mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
+       
+       spin_lock_init(&host->lock);
+       
+       /*
+        * Maximum number of segments. Worst case is one sector per segment
+        * so this will be 64kB/512.
+        */
+       mmc->max_hw_segs = 128;
+       mmc->max_phys_segs = 128;
+       
+       /*
+        * Maximum number of sectors in one transfer. Also limited by 64kB
+        * buffer.
+        */
+       mmc->max_sectors = 128;
+       
+       /*
+        * Maximum segment size. Could be one segment with the maximum number
+        * of segments.
+        */
+       mmc->max_seg_size = mmc->max_sectors * 512;
+       
+       dev_set_drvdata(dev, mmc);
+       
+       return 0;
+}
+
+static void __devexit wbsd_free_mmc(struct device* dev)
+{
+       struct mmc_host* mmc;
+       
+       mmc = dev_get_drvdata(dev);
+       if (!mmc)
+               return;
+       
+       mmc_free_host(mmc);
+       
+       dev_set_drvdata(dev, NULL);
+}
+
+/*
+ * Scan for known chip id:s
+ */
+
+static int __devinit wbsd_scan(struct wbsd_host* host)
 {
        int i, j, k;
        int id;
@@ -1258,12 +1419,16 @@ static int wbsd_scan(struct wbsd_host* host)
        return -ENODEV;
 }
 
-static int wbsd_request_regions(struct wbsd_host* host)
+/*
+ * Allocate/free io port ranges
+ */
+
+static int __devinit wbsd_request_region(struct wbsd_host* host, int base)
 {
        if (io & 0x7)
                return -EINVAL;
        
-       if (!request_region(io, 8, DRIVER_NAME))
+       if (!request_region(base, 8, DRIVER_NAME))
                return -EIO;
        
        host->base = io;
@@ -1271,19 +1436,25 @@ static int wbsd_request_regions(struct wbsd_host* host)
        return 0;
 }
 
-static void wbsd_release_regions(struct wbsd_host* host)
+static void __devexit wbsd_release_regions(struct wbsd_host* host)
 {
        if (host->base)
                release_region(host->base, 8);
+       
+       host->base = 0;
 
        if (host->config)
                release_region(host->config, 2);
+       
+       host->config = 0;
 }
 
-static void wbsd_init_dma(struct wbsd_host* host)
+/*
+ * Allocate/free DMA port and buffer
+ */
+
+static void __devinit wbsd_request_dma(struct wbsd_host* host, int dma)
 {
-       host->dma = -1;
-       
        if (dma < 0)
                return;
        
@@ -1294,7 +1465,7 @@ static void wbsd_init_dma(struct wbsd_host* host)
         * We need to allocate a special buffer in
         * order for ISA to be able to DMA to it.
         */
-       host->dma_buffer = kmalloc(65536,
+       host->dma_buffer = kmalloc(WBSD_DMA_SIZE,
                GFP_NOIO | GFP_DMA | __GFP_REPEAT | __GFP_NOWARN);
        if (!host->dma_buffer)
                goto free;
@@ -1302,7 +1473,8 @@ static void wbsd_init_dma(struct wbsd_host* host)
        /*
         * Translate the address to a physical address.
         */
-       host->dma_addr = isa_virt_to_bus(host->dma_buffer);
+       host->dma_addr = dma_map_single(host->mmc->dev, host->dma_buffer,
+               WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
                        
        /*
         * ISA DMA must be aligned on a 64k basis.
@@ -1325,6 +1497,10 @@ kfree:
         */
        BUG_ON(1);
        
+       dma_unmap_single(host->mmc->dev, host->dma_addr, WBSD_DMA_SIZE,
+               DMA_BIDIRECTIONAL);
+       host->dma_addr = (dma_addr_t)NULL;
+       
        kfree(host->dma_buffer);
        host->dma_buffer = NULL;
 
@@ -1336,60 +1512,122 @@ err:
                "Falling back on FIFO.\n", dma);
 }
 
-static struct mmc_host_ops wbsd_ops = {
-       .request        = wbsd_request,
-       .set_ios        = wbsd_set_ios,
-};
+static void __devexit wbsd_release_dma(struct wbsd_host* host)
+{
+       if (host->dma_addr)
+               dma_unmap_single(host->mmc->dev, host->dma_addr, WBSD_DMA_SIZE,
+                       DMA_BIDIRECTIONAL);
+       if (host->dma_buffer)
+               kfree(host->dma_buffer);
+       if (host->dma >= 0)
+               free_dma(host->dma);
+       
+       host->dma = -1;
+       host->dma_buffer = NULL;
+       host->dma_addr = (dma_addr_t)NULL;
+}
 
 /*
- * Device probe
+ * Allocate/free IRQ.
  */
 
-static int wbsd_probe(struct device* dev)
+static int __devinit wbsd_request_irq(struct wbsd_host* host, int irq)
 {
-       struct wbsd_host* host = NULL;
-       struct mmc_host* mmc = NULL;
        int ret;
        
        /*
-        * Allocate MMC structure.
+        * Allocate interrupt.
         */
-       mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev);
-       if (!mmc)
-               return -ENOMEM;
-       
-       host = mmc_priv(mmc);
-       host->mmc = mmc;
+
+       ret = request_irq(irq, wbsd_irq, SA_SHIRQ, DRIVER_NAME, host);
+       if (ret)
+               return ret;
        
+       host->irq = irq;
+
        /*
-        * Scan for hardware.
+        * Set up tasklets.
         */
-       ret = wbsd_scan(host);
-       if (ret)
-               goto freemmc;
+       tasklet_init(&host->card_tasklet, wbsd_tasklet_card, (unsigned long)host);
+       tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo, (unsigned long)host);
+       tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc, (unsigned long)host);
+       tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout, (unsigned long)host);
+       tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, (unsigned long)host);
+       tasklet_init(&host->block_tasklet, wbsd_tasklet_block, (unsigned long)host);
+       
+       return 0;
+}
 
-       /*
-        * Reset the chip.
-        */     
-       wbsd_write_config(host, WBSD_CONF_SWRST, 1);
-       wbsd_write_config(host, WBSD_CONF_SWRST, 0);
+static void __devexit wbsd_release_irq(struct wbsd_host* host)
+{
+       if (!host->irq)
+               return;
 
+       free_irq(host->irq, host);
+       
+       host->irq = 0;
+               
+       tasklet_kill(&host->card_tasklet);
+       tasklet_kill(&host->fifo_tasklet);
+       tasklet_kill(&host->crc_tasklet);
+       tasklet_kill(&host->timeout_tasklet);
+       tasklet_kill(&host->finish_tasklet);
+       tasklet_kill(&host->block_tasklet);
+}
+
+/*
+ * Allocate all resources for the host.
+ */
+
+static int __devinit wbsd_request_resources(struct wbsd_host* host,
+       int base, int irq, int dma)
+{
+       int ret;
+       
        /*
         * Allocate I/O ports.
         */
-       ret = wbsd_request_regions(host);
+       ret = wbsd_request_region(host, base);
        if (ret)
-               goto release;
+               return ret;
 
        /*
-        * Set host parameters.
+        * Allocate interrupt.
         */
-       mmc->ops = &wbsd_ops;
-       mmc->f_min = 375000;
-       mmc->f_max = 24000000;
-       mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
+       ret = wbsd_request_irq(host, irq);
+       if (ret)
+               return ret;
+
+       /*
+        * Allocate DMA.
+        */
+       wbsd_request_dma(host, dma);
        
-       spin_lock_init(&host->lock);
+       return 0;
+}
+
+/*
+ * Release all resources for the host.
+ */
+
+static void __devexit wbsd_release_resources(struct wbsd_host* host)
+{
+       wbsd_release_dma(host);
+       wbsd_release_irq(host);
+       wbsd_release_regions(host);
+}
+
+/*
+ * Configure the resources the chip should use.
+ */
+
+static void __devinit wbsd_chip_config(struct wbsd_host* host)
+{
+       /*
+        * Reset the chip.
+        */     
+       wbsd_write_config(host, WBSD_CONF_SWRST, 1);
+       wbsd_write_config(host, WBSD_CONF_SWRST, 0);
 
        /*
         * Select SD/MMC function.
@@ -1399,165 +1637,241 @@ static int wbsd_probe(struct device* dev)
        /*
         * Set up card detection.
         */
-       wbsd_write_config(host, WBSD_CONF_PINS, 0x02);
+       wbsd_write_config(host, WBSD_CONF_PINS, WBSD_PINS_DETECT_GP11);
        
        /*
-        * Configure I/O port.
+        * Configure chip
         */
        wbsd_write_config(host, WBSD_CONF_PORT_HI, host->base >> 8);
        wbsd_write_config(host, WBSD_CONF_PORT_LO, host->base & 0xff);
-
-       /*
-        * Allocate interrupt.
-        */
-       ret = request_irq(irq, wbsd_irq, SA_SHIRQ, DRIVER_NAME, host);
-       if (ret)
-               goto release;
        
-       host->irq = irq;
+       wbsd_write_config(host, WBSD_CONF_IRQ, host->irq);
        
-       /*
-        * Set up tasklets.
-        */
-       tasklet_init(&host->card_tasklet, wbsd_tasklet_card, (unsigned long)host);
-       tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo, (unsigned long)host);
-       tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc, (unsigned long)host);
-       tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout, (unsigned long)host);
-       tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, (unsigned long)host);
-       tasklet_init(&host->block_tasklet, wbsd_tasklet_block, (unsigned long)host);
+       if (host->dma >= 0)
+               wbsd_write_config(host, WBSD_CONF_DRQ, host->dma);
        
        /*
-        * Configure interrupt.
+        * Enable and power up chip.
         */
-       wbsd_write_config(host, WBSD_CONF_IRQ, host->irq);
+       wbsd_write_config(host, WBSD_CONF_ENABLE, 1);
+       wbsd_write_config(host, WBSD_CONF_POWER, 0x20);
+}
+
+/*
+ * Check that configured resources are correct.
+ */
+static int __devinit wbsd_chip_validate(struct wbsd_host* host)
+{
+       int base, irq, dma;
        
        /*
-        * Allocate DMA.
+        * Select SD/MMC function.
         */
-       wbsd_init_dma(host);
+       wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
        
        /*
-        * If all went well, then configure DMA.
+        * Read configuration.
         */
-       if (host->dma >= 0)
-               wbsd_write_config(host, WBSD_CONF_DRQ, host->dma);
+       base = wbsd_read_config(host, WBSD_CONF_PORT_HI) << 8;
+       base |= wbsd_read_config(host, WBSD_CONF_PORT_LO);
        
-       /*
-        * Maximum number of segments. Worst case is one sector per segment
-        * so this will be 64kB/512.
-        */
-       mmc->max_hw_segs = 128;
-       mmc->max_phys_segs = 128;
+       irq = wbsd_read_config(host, WBSD_CONF_IRQ);
+       
+       dma = wbsd_read_config(host, WBSD_CONF_DRQ);
        
        /*
-        * Maximum number of sectors in one transfer. Also limited by 64kB
-        * buffer.
+        * Validate against given configuration.
         */
-       mmc->max_sectors = 128;
+       if (base != host->base)
+               return 0;
+       if (irq != host->irq)
+               return 0;
+       if ((dma != host->dma) && (host->dma != -1))
+               return 0;
+       
+       return 1;
+}
+
+/*****************************************************************************\
+ *                                                                           *
+ * Devices setup and shutdown                                                *
+ *                                                                           *
+\*****************************************************************************/
+
+static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma,
+       int pnp)
+{
+       struct wbsd_host* host = NULL;
+       struct mmc_host* mmc = NULL;
+       int ret;
+       
+       ret = wbsd_alloc_mmc(dev);
+       if (ret)
+               return ret;
+       
+       mmc = dev_get_drvdata(dev);
+       host = mmc_priv(mmc);
        
        /*
-        * Maximum segment size. Could be one segment with the maximum number
-        * of segments.
+        * Scan for hardware.
         */
-       mmc->max_seg_size = mmc->max_sectors * 512;
+       ret = wbsd_scan(host);
+       if (ret)
+       {
+               if (pnp && (ret == -ENODEV))
+               {
+                       printk(KERN_WARNING DRIVER_NAME
+                               ": Unable to confirm device presence. You may "
+                               "experience lock-ups.\n");
+               }
+               else
+               {
+                       wbsd_free_mmc(dev);
+                       return ret;
+               }
+       }
        
        /*
-        * Enable chip.
+        * Request resources.
         */
-       wbsd_write_config(host, WBSD_CONF_ENABLE, 1);
+       ret = wbsd_request_resources(host, io, irq, dma);
+       if (ret)
+       {
+               wbsd_release_resources(host);
+               wbsd_free_mmc(dev);
+               return ret;
+       }
        
        /*
-        * Power up chip.
+        * See if chip needs to be configured.
         */
-       wbsd_write_config(host, WBSD_CONF_POWER, 0x20);
+       if (pnp && (host->config != 0))
+       {
+               if (!wbsd_chip_validate(host))
+               {
+                       printk(KERN_WARNING DRIVER_NAME
+                               ": PnP active but chip not configured! "
+                               "You probably have a buggy BIOS. "
+                               "Configuring chip manually.\n");
+                       wbsd_chip_config(host);
+               }
+       }
+       else
+               wbsd_chip_config(host);
        
        /*
         * Power Management stuff. No idea how this works.
         * Not tested.
         */
 #ifdef CONFIG_PM
-       wbsd_write_config(host, WBSD_CONF_PME, 0xA0);
+       if (host->config)
+               wbsd_write_config(host, WBSD_CONF_PME, 0xA0);
 #endif
+       /*
+        * Allow device to initialise itself properly.
+        */
+       mdelay(5);
 
        /*
         * Reset the chip into a known state.
         */
        wbsd_init_device(host);
        
-       dev_set_drvdata(dev, mmc);
-       
-       /*
-        * Add host to MMC layer.
-        */
        mmc_add_host(mmc);
 
-       printk(KERN_INFO "%s: W83L51xD id %x at 0x%x irq %d dma %d\n",
-               mmc->host_name, (int)host->chip_id, (int)host->base,
-               (int)host->irq, (int)host->dma);
+       printk(KERN_INFO "%s: W83L51xD", mmc->host_name);
+       if (host->chip_id != 0)
+               printk(" id %x", (int)host->chip_id);
+       printk(" at 0x%x irq %d", (int)host->base, (int)host->irq);
+       if (host->dma >= 0)
+               printk(" dma %d", (int)host->dma);
+       else
+               printk(" FIFO");
+       if (pnp)
+               printk(" PnP");
+       printk("\n");
 
        return 0;
-
-release:
-       wbsd_release_regions(host);
-
-freemmc:
-       mmc_free_host(mmc);
-
-       return ret;
 }
 
-/*
- * Device remove
- */
-
-static int wbsd_remove(struct device* dev)
+static void __devexit wbsd_shutdown(struct device* dev, int pnp)
 {
        struct mmc_host* mmc = dev_get_drvdata(dev);
        struct wbsd_host* host;
        
        if (!mmc)
-               return 0;
+               return;
 
        host = mmc_priv(mmc);
        
-       /*
-        * Unregister host with MMC layer.
-        */
        mmc_remove_host(mmc);
 
-       /*
-        * Power down the SD/MMC function.
-        */
-       wbsd_unlock_config(host);
-       wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
-       wbsd_write_config(host, WBSD_CONF_ENABLE, 0);
-       wbsd_lock_config(host);
+       if (!pnp)
+       {
+               /*
+                * Power down the SD/MMC function.
+                */
+               wbsd_unlock_config(host);
+               wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
+               wbsd_write_config(host, WBSD_CONF_ENABLE, 0);
+               wbsd_lock_config(host);
+       }
        
-       /*
-        * Free resources.
-        */
-       if (host->dma_buffer)
-               kfree(host->dma_buffer);
+       wbsd_release_resources(host);
        
-       if (host->dma >= 0)
-               free_dma(host->dma);
+       wbsd_free_mmc(dev);
+}
 
-       free_irq(host->irq, host);
+/*
+ * Non-PnP
+ */
+
+static int __devinit wbsd_probe(struct device* dev)
+{
+       return wbsd_init(dev, io, irq, dma, 0);
+}
+
+static int __devexit wbsd_remove(struct device* dev)
+{
+       wbsd_shutdown(dev, 0);
+
+       return 0;
+}
+
+/*
+ * PnP
+ */
+
+#ifdef CONFIG_PNP
+
+static int __devinit
+wbsd_pnp_probe(struct pnp_dev * pnpdev, const struct pnp_device_id *dev_id)
+{
+       int io, irq, dma;
        
-       tasklet_kill(&host->card_tasklet);
-       tasklet_kill(&host->fifo_tasklet);
-       tasklet_kill(&host->crc_tasklet);
-       tasklet_kill(&host->timeout_tasklet);
-       tasklet_kill(&host->finish_tasklet);
-       tasklet_kill(&host->block_tasklet);
+       /*
+        * Get resources from PnP layer.
+        */
+       io = pnp_port_start(pnpdev, 0);
+       irq = pnp_irq(pnpdev, 0);
+       if (pnp_dma_valid(pnpdev, 0))
+               dma = pnp_dma(pnpdev, 0);
+       else
+               dma = -1;
        
-       wbsd_release_regions(host);
+       DBGF("PnP resources: port %3x irq %d dma %d\n", io, irq, dma);
        
-       mmc_free_host(mmc);
+       return wbsd_init(&pnpdev->dev, io, irq, dma, 1);
+}
 
-       return 0;
+static void __devexit wbsd_pnp_remove(struct pnp_dev * dev)
+{
+       wbsd_shutdown(&dev->dev, 1);
 }
 
+#endif /* CONFIG_PNP */
+
 /*
  * Power management
  */
@@ -1581,17 +1895,7 @@ static int wbsd_resume(struct device *dev, u32 level)
 #define wbsd_resume NULL
 #endif
 
-static void wbsd_release(struct device *dev)
-{
-}
-
-static struct platform_device wbsd_device = {
-       .name           = DRIVER_NAME,
-       .id                     = -1,
-       .dev            = {
-               .release = wbsd_release,
-       },
-};
+static struct platform_device *wbsd_device;
 
 static struct device_driver wbsd_driver = {
        .name           = DRIVER_NAME,
@@ -1603,6 +1907,17 @@ static struct device_driver wbsd_driver = {
        .resume         = wbsd_resume,
 };
 
+#ifdef CONFIG_PNP
+
+static struct pnp_driver wbsd_pnp_driver = {
+       .name           = DRIVER_NAME,
+       .id_table       = pnp_dev_table,
+       .probe          = wbsd_pnp_probe,
+       .remove         = wbsd_pnp_remove,
+};
+
+#endif /* CONFIG_PNP */
+
 /*
  * Module loading/unloading
  */
@@ -1615,29 +1930,57 @@ static int __init wbsd_drv_init(void)
                ": Winbond W83L51xD SD/MMC card interface driver, "
                DRIVER_VERSION "\n");
        printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
-       
-       result = driver_register(&wbsd_driver);
-       if (result < 0)
-               return result;
 
-       result = platform_device_register(&wbsd_device);
-       if (result < 0)
-               return result;
+#ifdef CONFIG_PNP
+
+       if (!nopnp)
+       {
+               result = pnp_register_driver(&wbsd_pnp_driver);
+               if (result < 0)
+                       return result;
+       }
+
+#endif /* CONFIG_PNP */        
+       
+       if (nopnp)
+       {
+               result = driver_register(&wbsd_driver);
+               if (result < 0)
+                       return result;
+
+               wbsd_device = platform_device_register_simple(DRIVER_NAME, -1,
+                       NULL, 0);
+               if (IS_ERR(wbsd_device))
+                       return PTR_ERR(wbsd_device);
+       }
 
        return 0;
 }
 
 static void __exit wbsd_drv_exit(void)
 {
-       platform_device_unregister(&wbsd_device);
+#ifdef CONFIG_PNP
+
+       if (!nopnp)
+               pnp_unregister_driver(&wbsd_pnp_driver);
        
-       driver_unregister(&wbsd_driver);
+#endif /* CONFIG_PNP */        
+
+       if (nopnp)
+       {
+               platform_device_unregister(wbsd_device);
+       
+               driver_unregister(&wbsd_driver);
+       }
 
        DBG("unloaded\n");
 }
 
 module_init(wbsd_drv_init);
 module_exit(wbsd_drv_exit);
+#ifdef CONFIG_PNP
+module_param(nopnp, uint, 0444);
+#endif
 module_param(io, uint, 0444);
 module_param(irq, uint, 0444);
 module_param(dma, int, 0444);
@@ -1646,6 +1989,9 @@ MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver");
 MODULE_VERSION(DRIVER_VERSION);
 
+#ifdef CONFIG_PNP
+MODULE_PARM_DESC(nopnp, "Scan for device instead of relying on PNP. (default 0)");
+#endif
 MODULE_PARM_DESC(io, "I/O base to allocate. Must be 8 byte aligned. (default 0x248)");
 MODULE_PARM_DESC(irq, "IRQ to allocate. (default 6)");
 MODULE_PARM_DESC(dma, "DMA channel to allocate. -1 for no DMA. (default 2)");
index fdc03b56a81fbdecb38b0a394927efcc750ba442..864f30828d01fe4f52da21502c91f3cec18e6ed4 100644 (file)
@@ -35,6 +35,12 @@ const int valid_ids[] = {
 
 #define DEVICE_SD              0x03
 
+#define WBSD_PINS_DAT3_HI      0x20
+#define WBSD_PINS_DAT3_OUT     0x10
+#define WBSD_PINS_GP11_HI      0x04
+#define WBSD_PINS_DETECT_GP11  0x02
+#define WBSD_PINS_DETECT_DAT3  0x01
+
 #define WBSD_CMDR              0x00
 #define WBSD_DFR               0x01
 #define WBSD_EIR               0x02
@@ -133,6 +139,7 @@ const int valid_ids[] = {
 #define WBSD_CRC_OK            0x05 /* S010E (00101) */
 #define WBSD_CRC_FAIL          0x0B /* S101E (01011) */
 
+#define WBSD_DMA_SIZE          65536
 
 struct wbsd_host
 {
@@ -140,6 +147,11 @@ struct wbsd_host
        
        spinlock_t              lock;           /* Mutex */
 
+       int                     flags;          /* Driver states */
+
+#define WBSD_FCARD_PRESENT     (1<<0)          /* Card is present */
+#define WBSD_FIGNORE_DETECT    (1<<1)          /* Ignore card detection */
+       
        struct mmc_request*     mrq;            /* Current request */
        
        u8                      isr;            /* Accumulated ISR */
index 6202b10dbb4df11c92119b253fc7281fe5bbf41d..e038d55e4f6f96257fa2e31b5cb97c62fd3ea2d7 100644 (file)
@@ -187,7 +187,7 @@ obj-$(CONFIG_TR) += tokenring/
 obj-$(CONFIG_WAN) += wan/
 obj-$(CONFIG_ARCNET) += arcnet/
 obj-$(CONFIG_NET_PCMCIA) += pcmcia/
-obj-$(CONFIG_NET_WIRELESS) += wireless/
+obj-$(CONFIG_NET_RADIO) += wireless/
 obj-$(CONFIG_NET_TULIP) += tulip/
 obj-$(CONFIG_HAMRADIO) += hamradio/
 obj-$(CONFIG_IRDA) += irda/
index ab44358ddbfc9a7c2a618a24fe820e8239bdcf32..6482d994d4899aef539f2639bd70703c306d3c90 100644 (file)
@@ -1595,7 +1595,7 @@ static struct ethtool_ops emac_ethtool_ops = {
 static int emac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
        struct ocp_enet_private *fep = dev->priv;
-       uint *data = (uint *) & rq->ifr_ifru;
+       uint16_t *data = (uint16_t *) & rq->ifr_ifru;
 
        switch (cmd) {
        case SIOCGMIIPHY:
index d098b3ba35384fb912989348fd6da59820711ca4..e0ae3ed6e5785832794a8cb32dec13d1d592f5cc 100644 (file)
@@ -1104,7 +1104,7 @@ static void set_rx_mode(struct net_device *dev)
                        if (entry != 0) {
                                /* Avoid a chip errata by prefixing a dummy entry. Don't do
                                   this on the ULI526X as it triggers a different problem */
-                               if (!(tp->chip_id == ULI526X && (tp->revision = 0x40 || tp->revision == 0x50))) {
+                               if (!(tp->chip_id == ULI526X && (tp->revision == 0x40 || tp->revision == 0x50))) {
                                        tp->tx_buffers[entry].skb = NULL;
                                        tp->tx_buffers[entry].mapping = 0;
                                        tp->tx_ring[entry].length =
index 0aaa12c0c098ae48d48cac1535abf92e7c0880f9..1d3231cc471acff346ef9dd6425d66c1b96c4276 100644 (file)
@@ -323,7 +323,7 @@ config PRISM54
          For a complete list of supported cards visit <http://prism54.org>.
          Here is the latest confirmed list of supported cards:
 
-         3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72
+         3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72 (version 1)
          Allnet ALL0271 PCI Card
          Compex WL54G Cardbus Card
          Corega CG-WLCB54GT Cardbus Card
index 33fbda79f3507f83f00ca3b9c8f9167f6500c136..0b10169961ebfe2898efecb192a00c5a47c4b1df 100644 (file)
@@ -126,18 +126,8 @@ static irqreturn_t serial21285_rx_chars(int irq, void *dev_id, struct pt_regs *r
                                flag = TTY_FRAME;
                }
 
-               if ((rxs & port->ignore_status_mask) == 0) {
-                       tty_insert_flip_char(tty, ch, flag);
-               }
-               if ((rxs & RXSTAT_OVERRUN) &&
-                   tty->flip.count < TTY_FLIPBUF_SIZE) {
-                       /*
-                        * Overrun is special, since it's reported
-                        * immediately, and doesn't affect the current
-                        * character.
-                        */
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               }
+               uart_insert_char(port, rxs, RXSTAT_OVERRUN, ch, flag);
+
                status = *CSR_UARTFLG;
        }
        tty_flip_buffer_push(tty);
index 0d9358608fdfdc8c6d53824dfc9f11a4d1fe38f9..3bbf0cc6e53f9989fd52630432570cd2152e8cf8 100644 (file)
@@ -1122,18 +1122,9 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
                }
                if (uart_handle_sysrq_char(&up->port, ch, regs))
                        goto ignore_char;
-               if ((lsr & up->port.ignore_status_mask) == 0) {
-                       tty_insert_flip_char(tty, ch, flag);
-               }
-               if ((lsr & UART_LSR_OE) &&
-                   tty->flip.count < TTY_FLIPBUF_SIZE) {
-                       /*
-                        * Overrun is special, since it's reported
-                        * immediately, and doesn't affect the current
-                        * character.
-                        */
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               }
+
+               uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
+
        ignore_char:
                lsr = serial_inp(up, UART_LSR);
        } while ((lsr & UART_LSR_DR) && (max_count-- > 0));
index f2a5e2933c4709b2b56fc4167e041b0e366e5782..2884b310e54d2d01f50d012d4394343b08b5717a 100644 (file)
@@ -198,18 +198,8 @@ pl010_rx_chars(struct uart_port *port)
                if (uart_handle_sysrq_char(port, ch, regs))
                        goto ignore_char;
 
-               if ((rsr & port->ignore_status_mask) == 0) {
-                       tty_insert_flip_char(tty, ch, flag);
-               }
-               if ((rsr & UART01x_RSR_OE) &&
-                   tty->flip.count < TTY_FLIPBUF_SIZE) {
-                       /*
-                        * Overrun is special, since it's reported
-                        * immediately, and doesn't affect the current
-                        * character
-                        */
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               }
+               uart_insert_char(port, rsr, UART01x_RSR_OE, ch, flag);
+
        ignore_char:
                status = UART_GET_FR(port);
        }
index d5cbef3fe8b6adb42cf900aaffbec87494c8fdf8..7db88ee18f75fb1f138f71921c05d833aa935a51 100644 (file)
@@ -163,18 +163,8 @@ pl011_rx_chars(struct uart_amba_port *uap)
                if (uart_handle_sysrq_char(&uap->port, ch, regs))
                        goto ignore_char;
 
-               if ((rsr & uap->port.ignore_status_mask) == 0) {
-                       tty_insert_flip_char(tty, ch, flag);
-               }
-               if ((rsr & UART01x_RSR_OE) &&
-                   tty->flip.count < TTY_FLIPBUF_SIZE) {
-                       /*
-                        * Overrun is special, since it's reported
-                        * immediately, and doesn't affect the current
-                        * character
-                        */
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               }
+               uart_insert_char(&uap->port, rsr, UART01x_RSR_OE, ch, flag);
+
        ignore_char:
                status = readw(uap->port.membase + UART01x_FR);
        }
index 6242f3090a96f76372ad8e35367bbbc790e68cf0..e92522b33c48e9e4e283b8fbd498d4e8b7e45c12 100644 (file)
@@ -143,10 +143,7 @@ static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *re
                 * CHECK: does overrun affect the current character?
                 * ASSUMPTION: it does not.
                 */
-               if ((ch & port->ignore_status_mask & ~RXSTAT_OVERRUN) == 0)
-                       tty_insert_flip_char(tty, ch, flg);
-               if ((ch & ~port->ignore_status_mask & RXSTAT_OVERRUN) == 0)
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+               uart_insert_char(port, ch, UARTDR_OVERR, ch, flg);
 
        ignore_char:
                status = clps_readl(SYSFLG(port));
index 51d8a49f4477bb6f23048b361e4ad367ecdb9758..9dc151d8fa612bb16554f6d4d15382a5d4eaf7ab 100644 (file)
@@ -161,20 +161,12 @@ receive_chars(struct uart_pxa_port *up, int *status, struct pt_regs *regs)
                        else if (*status & UART_LSR_FE)
                                flag = TTY_FRAME;
                }
+
                if (uart_handle_sysrq_char(&up->port, ch, regs))
                        goto ignore_char;
-               if ((*status & up->port.ignore_status_mask) == 0) {
-                       tty_insert_flip_char(tty, ch, flag);
-               }
-               if ((*status & UART_LSR_OE) &&
-                   tty->flip.count < TTY_FLIPBUF_SIZE) {
-                       /*
-                        * Overrun is special, since it's reported
-                        * immediately, and doesn't affect the current
-                        * character.
-                        */
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               }
+
+               uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
+
        ignore_char:
                *status = serial_in(up, UART_LSR);
        } while ((*status & UART_LSR_DR) && (max_count-- > 0));
index 435750d40a471001c860ba0b21b0443901534eab..2a9f7ade2c9d58faa134e84d698d9025af5365b1 100644 (file)
@@ -394,20 +394,7 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id, struct pt_regs *regs)
                if (uart_handle_sysrq_char(port, ch, regs))
                        goto ignore_char;
 
-               if ((uerstat & port->ignore_status_mask) == 0) {
-                       tty_insert_flip_char(tty, ch, flag);
-               }
-
-               if ((uerstat & S3C2410_UERSTAT_OVERRUN) &&
-                   tty->flip.count < TTY_FLIPBUF_SIZE) {
-                       /*
-                        * Overrun is special, since it's reported
-                        * immediately, and doesn't affect the current
-                        * character.
-                        */
-
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               }
+               uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, ch, flag);
 
        ignore_char:
                continue;
index 157218bc6c6fba4ddbce2e2294d381903a620eb5..22565a67a57cd0e6e63a85540addbcbbe2ec5321 100644 (file)
@@ -237,10 +237,7 @@ sa1100_rx_chars(struct sa1100_port *sport, struct pt_regs *regs)
                if (uart_handle_sysrq_char(&sport->port, ch, regs))
                        goto ignore_char;
 
-               if ((status & port->ignore_status_mask & ~UTSR1_TO_SM(UTSR1_ROR)) == 0)
-                       tty_insert_flip_char(tty, ch, flg);
-               if (status & ~port->ignore_status_mask & UTSR1_TO_SM(UTSR1_ROR))
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+               uart_insert_char(&sport->port, status, UTSR1_TO_SM(UTSR1_ROR), ch, flg);
 
        ignore_char:
                status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
index 85cfa08d3bad7955bb79279f73be920e332fb03f..56f269b6bfb12c53fb323c66dcab126010888bee 100644 (file)
@@ -190,18 +190,7 @@ lh7a40xuart_rx_chars (struct uart_port* port)
                if (uart_handle_sysrq_char (port, (unsigned char) data, regs))
                        continue;
 
-               if ((data & port->ignore_status_mask) == 0) {
-                       tty_insert_flip_char(tty, data, flag);
-               }
-               if ((data & RxOverrunError)
-                   && tty->flip.count < TTY_FLIPBUF_SIZE) {
-                       /*
-                        * Overrun is special, since it's reported
-                        * immediately, and doesn't affect the current
-                        * character
-                        */
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               }
+               uart_insert_char(port, data, RxOverrunError, data, flag);
        }
        tty_flip_buffer_push (tty);
        return;
index 37b2ef297cbec3816b06d2a30ad588a80abbfdd1..3f1051a4a13f8f51cab2efa2783f287e734c8ecb 100644 (file)
@@ -350,18 +350,9 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r
                }
                if (uart_handle_sysrq_char(&up->port, ch, regs))
                        goto ignore_char;
-               if ((disr & up->port.ignore_status_mask) == 0) {
-                       tty_insert_flip_char(tty, ch, flag);
-               }
-               if ((disr & TXX9_SIDISR_UOER) &&
-                   tty->flip.count < TTY_FLIPBUF_SIZE) {
-                       /*
-                        * Overrun is special, since it's reported
-                        * immediately, and doesn't affect the current
-                        * character.
-                        */
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               }
+
+               uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag);
+
        ignore_char:
                disr = sio_in(up, TXX9_SIDISR);
        } while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0));
index 307886199f2f6f1301d6aa240b1f3263e9ec8a90..5d2ceb623e6fcebe34319cac6c4bcd72d2c78739 100644 (file)
@@ -412,10 +412,8 @@ static inline void receive_chars(struct uart_port *port, uint8_t *status,
 
                if (uart_handle_sysrq_char(port, ch, regs))
                        goto ignore_char;
-               if ((lsr & port->ignore_status_mask) == 0)
-                       tty_insert_flip_char(tty, ch, flag);
-               if ((lsr & UART_LSR_OE) && (tty->flip.count < TTY_FLIPBUF_SIZE))
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+
+               uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
 
        ignore_char:
                lsr = siu_read(port, UART_LSR);
index ce9423bb2de319d095a3ac5d8e762dcd6d8b3913..c374be51b041a698341ddbda6b9fc5fe1329df46 100644 (file)
@@ -251,7 +251,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec,
        }
 
        /* Populate argv and envp */
-       p = current->mm->arg_start;
+       p = current->mm->arg_end = current->mm->arg_start;
        while (argc-- > 0) {
                size_t len;
                __put_user((elf_addr_t)p, argv++);
@@ -1301,7 +1301,7 @@ static void fill_prstatus(struct elf_prstatus *prstatus,
 static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
                       struct mm_struct *mm)
 {
-       int i, len;
+       unsigned int i, len;
        
        /* first copy the parameters from user space */
        memset(psinfo, 0, sizeof(struct elf_prpsinfo));
index f32c203952cf766617f2b1464513661db48c629d..93b840e8fa603d32d5b9e6fcfbbb33e7fa0e0b37 100644 (file)
 #define PD31_PF_TMR2OUT      ( GPIO_PORTD | GPIO_PF | 31 )
 #define PD31_BIN_SPI2_TXD    ( GPIO_PORTD | GPIO_BIN | 31 )
 
+/*
+ * PWM controller
+ */
+#define PWMC   __REG(IMX_PWM_BASE + 0x00)      /* PWM Control Register         */
+#define PWMS   __REG(IMX_PWM_BASE + 0x04)      /* PWM Sample Register          */
+#define PWMP   __REG(IMX_PWM_BASE + 0x08)      /* PWM Period Register          */
+#define PWMCNT __REG(IMX_PWM_BASE + 0x0C)      /* PWM Counter Register         */
+
+#define PWMC_HCTR              (0x01<<18)              /* Halfword FIFO Data Swapping  */
+#define PWMC_BCTR              (0x01<<17)              /* Byte FIFO Data Swapping      */
+#define PWMC_SWR               (0x01<<16)              /* Software Reset               */
+#define PWMC_CLKSRC            (0x01<<15)              /* Clock Source                 */
+#define PWMC_PRESCALER(x)      (((x-1) & 0x7F) << 8)   /* PRESCALER                    */
+#define PWMC_IRQ               (0x01<< 7)              /* Interrupt Request            */
+#define PWMC_IRQEN             (0x01<< 6)              /* Interrupt Request Enable     */
+#define PWMC_FIFOAV            (0x01<< 5)              /* FIFO Available               */
+#define PWMC_EN                        (0x01<< 4)              /* Enables/Disables the PWM     */
+#define PWMC_REPEAT(x)         (((x) & 0x03) << 2)     /* Sample Repeats               */
+#define PWMC_CLKSEL(x)         (((x) & 0x03) << 0)     /* Clock Selection              */
+
+#define PWMS_SAMPLE(x)         ((x) & 0xFFFF)          /* Contains a two-sample word   */
+#define PWMP_PERIOD(x)         ((x) & 0xFFFF)          /* Represents the PWM's period  */
+#define PWMC_COUNTER(x)                ((x) & 0xFFFF)          /* Represents the current count value   */
+
 /*
  *  DMA Controller
  */
index c443ac83469862d688ceb66df0f620429431fbec..7cff235e667aeea2ef79c9d002bebc85b2d95abb 100644 (file)
@@ -1,16 +1,17 @@
 /* linux/include/asm-arm/arch-s3c2410/regs-nand.h
  *
- * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
+ * Copyright (c) 2004,2005 Simtec Electronics <linux@simtec.co.uk>
  *                   http://www.simtec.co.uk/products/SWLINUX/
  *
  * 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.
  *
- * S3C2410 clock register definitions
+ * S3C2410 NAND register definitions
  *
  *  Changelog:
  *    18-Aug-2004    BJD     Copied file from 2.4 and updated
+ *    01-May-2005    BJD     Added definitions for s3c2440 controller
 */
 
 #ifndef __ASM_ARM_REGS_NAND
 #define S3C2410_NFSTAT  S3C2410_NFREG(0x10)
 #define S3C2410_NFECC   S3C2410_NFREG(0x14)
 
+#define S3C2440_NFCONT   S3C2410_NFREG(0x04)
+#define S3C2440_NFCMD    S3C2410_NFREG(0x08)
+#define S3C2440_NFADDR   S3C2410_NFREG(0x0C)
+#define S3C2440_NFDATA   S3C2410_NFREG(0x10)
+#define S3C2440_NFECCD0  S3C2410_NFREG(0x14)
+#define S3C2440_NFECCD1  S3C2410_NFREG(0x18)
+#define S3C2440_NFECCD   S3C2410_NFREG(0x1C)
+#define S3C2440_NFSTAT   S3C2410_NFREG(0x20)
+#define S3C2440_NFESTAT0 S3C2410_NFREG(0x24)
+#define S3C2440_NFESTAT1 S3C2410_NFREG(0x28)
+#define S3C2440_NFMECC0  S3C2410_NFREG(0x2C)
+#define S3C2440_NFMECC1  S3C2410_NFREG(0x30)
+#define S3C2440_NFSECC   S3C2410_NFREG(0x34)
+#define S3C2440_NFSBLK   S3C2410_NFREG(0x38)
+#define S3C2440_NFEBLK   S3C2410_NFREG(0x3C)
+
 #define S3C2410_NFCONF_EN          (1<<15)
 #define S3C2410_NFCONF_512BYTE     (1<<14)
 #define S3C2410_NFCONF_4STEP       (1<<13)
 
 #define S3C2410_NFSTAT_BUSY        (1<<0)
 
-/* think ECC can only be 8bit read? */
+#define S3C2440_NFCONF_BUSWIDTH_8      (0<<0)
+#define S3C2440_NFCONF_BUSWIDTH_16     (1<<0)
+#define S3C2440_NFCONF_ADVFLASH                (1<<3)
+#define S3C2440_NFCONF_TACLS(x)                ((x)<<12)
+#define S3C2440_NFCONF_TWRPH0(x)       ((x)<<8)
+#define S3C2440_NFCONF_TWRPH1(x)       ((x)<<4)
+
+#define S3C2440_NFCONT_LOCKTIGHT       (1<<13)
+#define S3C2440_NFCONT_SOFTLOCK                (1<<12)
+#define S3C2440_NFCONT_ILLEGALACC_EN   (1<<10)
+#define S3C2440_NFCONT_RNBINT_EN       (1<<9)
+#define S3C2440_NFCONT_RN_FALLING      (1<<8)
+#define S3C2440_NFCONT_SPARE_ECCLOCK   (1<<6)
+#define S3C2440_NFCONT_MAIN_ECCLOCK    (1<<5)
+#define S3C2440_NFCONT_INITECC         (1<<4)
+#define S3C2440_NFCONT_nFCE            (1<<1)
+#define S3C2440_NFCONT_ENABLE          (1<<0)
+
+#define S3C2440_NFSTAT_READY           (1<<0)
+#define S3C2440_NFSTAT_nCE             (1<<1)
+#define S3C2440_NFSTAT_RnB_CHANGE      (1<<2)
+#define S3C2440_NFSTAT_ILLEGAL_ACCESS  (1<<3)
 
 #endif /* __ASM_ARM_REGS_NAND */
 
index 4ca3a8e9348f53becec9d7969d8c73d0f64a3d3a..019c45d7573053a9af19088f2df4af8cb4c5e95a 100644 (file)
@@ -114,19 +114,8 @@ extern void __cpu_copy_user_page(void *to, const void *from,
                                 unsigned long user);
 #endif
 
-#define clear_user_page(addr,vaddr,pg)                 \
-       do {                                            \
-               preempt_disable();                      \
-               __cpu_clear_user_page(addr, vaddr);     \
-               preempt_enable();                       \
-       } while (0)
-
-#define copy_user_page(to,from,vaddr,pg)               \
-       do {                                            \
-               preempt_disable();                      \
-               __cpu_copy_user_page(to, from, vaddr);  \
-               preempt_enable();                       \
-       } while (0)
+#define clear_user_page(addr,vaddr,pg)  __cpu_clear_user_page(addr, vaddr)
+#define copy_user_page(to,from,vaddr,pg) __cpu_copy_user_page(to, from, vaddr)
 
 #define clear_page(page)       memzero((void *)(page), PAGE_SIZE)
 extern void copy_page(void *to, const void *from);
@@ -171,6 +160,9 @@ typedef unsigned long pgprot_t;
 
 #endif /* STRICT_MM_TYPECHECKS */
 
+/* the upper-most page table pointer */
+extern pmd_t *top_pmd;
+
 /* Pure 2^n version of get_order */
 static inline int get_order(unsigned long size)
 {
index c3fb5984f250a19e5f45ff23551fc7d148e9790e..d6025af7efac39154d65c90f447b54f79a43ac37 100644 (file)
@@ -479,6 +479,25 @@ uart_handle_cts_change(struct uart_port *port, unsigned int status)
        }
 }
 
+#include <linux/tty_flip.h>
+
+static inline void
+uart_insert_char(struct uart_port *port, unsigned int status,
+                unsigned int overrun, unsigned int ch, unsigned int flag)
+{
+       struct tty_struct *tty = port->info->tty;
+
+       if ((status & port->ignore_status_mask & ~overrun) == 0)
+               tty_insert_flip_char(tty, ch, flag);
+
+       /*
+        * Overrun is special.  Since it's reported immediately,
+        * it doesn't affect the current character.
+        */
+       if (status & ~port->ignore_status_mask & overrun)
+               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+}
+
 /*
  *     UART_ENABLE_MS - determine if port should enable modem status irqs
  */