diff options
34 files changed, 852 insertions, 447 deletions
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c index e23f534d4e1d..8d986b8401c2 100644 --- a/arch/arm/mach-s3c2410/clock.c +++ b/arch/arm/mach-s3c2410/clock.c | |||
@@ -478,7 +478,7 @@ static int s3c2440_clk_add(struct sys_device *sysdev) | |||
478 | { | 478 | { |
479 | unsigned long upllcon = __raw_readl(S3C2410_UPLLCON); | 479 | unsigned long upllcon = __raw_readl(S3C2410_UPLLCON); |
480 | 480 | ||
481 | s3c2440_clk_upll.rate = s3c2410_get_pll(upllcon, clk_xtal.rate) * 2; | 481 | s3c2440_clk_upll.rate = s3c2410_get_pll(upllcon, clk_xtal.rate); |
482 | 482 | ||
483 | printk("S3C2440: Clock Support, UPLL %ld.%03ld MHz\n", | 483 | printk("S3C2440: Clock Support, UPLL %ld.%03ld MHz\n", |
484 | print_mhz(s3c2440_clk_upll.rate)); | 484 | print_mhz(s3c2440_clk_upll.rate)); |
diff --git a/arch/arm/mach-s3c2410/s3c2440.c b/arch/arm/mach-s3c2410/s3c2440.c index 9a8cc5ae2255..d4c8281b55f6 100644 --- a/arch/arm/mach-s3c2410/s3c2440.c +++ b/arch/arm/mach-s3c2410/s3c2440.c | |||
@@ -192,9 +192,11 @@ void __init s3c2440_map_io(struct map_desc *mach_desc, int size) | |||
192 | 192 | ||
193 | iotable_init(s3c2440_iodesc, ARRAY_SIZE(s3c2440_iodesc)); | 193 | iotable_init(s3c2440_iodesc, ARRAY_SIZE(s3c2440_iodesc)); |
194 | iotable_init(mach_desc, size); | 194 | iotable_init(mach_desc, size); |
195 | |||
195 | /* rename any peripherals used differing from the s3c2410 */ | 196 | /* rename any peripherals used differing from the s3c2410 */ |
196 | 197 | ||
197 | s3c_device_i2c.name = "s3c2440-i2c"; | 198 | s3c_device_i2c.name = "s3c2440-i2c"; |
199 | s3c_device_nand.name = "s3c2440-nand"; | ||
198 | 200 | ||
199 | /* change irq for watchdog */ | 201 | /* change irq for watchdog */ |
200 | 202 | ||
@@ -225,7 +227,7 @@ void __init s3c2440_init_clocks(int xtal) | |||
225 | break; | 227 | break; |
226 | 228 | ||
227 | case S3C2440_CLKDIVN_HDIVN_2: | 229 | case S3C2440_CLKDIVN_HDIVN_2: |
228 | hdiv = 1; | 230 | hdiv = 2; |
229 | break; | 231 | break; |
230 | 232 | ||
231 | case S3C2440_CLKDIVN_HDIVN_4_8: | 233 | case S3C2440_CLKDIVN_HDIVN_4_8: |
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index c4fc6be629de..48bac7da8c70 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig | |||
@@ -412,21 +412,20 @@ config CPU_BPREDICT_DISABLE | |||
412 | 412 | ||
413 | config TLS_REG_EMUL | 413 | config TLS_REG_EMUL |
414 | bool | 414 | bool |
415 | default y if (SMP || CPU_32v6) && (CPU_32v5 || CPU_32v4 || CPU_32v3) | 415 | default y if SMP && (CPU_32v5 || CPU_32v4 || CPU_32v3) |
416 | help | 416 | help |
417 | We might be running on an ARMv6+ processor which should have the TLS | 417 | An SMP system using a pre-ARMv6 processor (there are apparently |
418 | register but for some reason we can't use it, or maybe an SMP system | 418 | a few prototypes like that in existence) and therefore access to |
419 | using a pre-ARMv6 processor (there are apparently a few prototypes | 419 | that required register must be emulated. |
420 | like that in existence) and therefore access to that register must | ||
421 | be emulated. | ||
422 | 420 | ||
423 | config HAS_TLS_REG | 421 | config HAS_TLS_REG |
424 | bool | 422 | bool |
425 | depends on CPU_32v6 | 423 | depends on !TLS_REG_EMUL |
426 | default y if !TLS_REG_EMUL | 424 | default y if SMP || CPU_32v7 |
427 | help | 425 | help |
428 | This selects support for the CP15 thread register. | 426 | This selects support for the CP15 thread register. |
429 | It is defined to be available on ARMv6 or later. If a particular | 427 | It is defined to be available on some ARMv6 processors (including |
430 | ARMv6 or later CPU doesn't support it then it must omc;ide "select | 428 | all SMP capable ARMv6's) or later processors. User space may |
431 | TLS_REG_EMUL" along with its other caracteristics. | 429 | assume directly accessing that register and always obtain the |
430 | expected value only on ARMv7 and above. | ||
432 | 431 | ||
diff --git a/arch/arm/mm/copypage-v4mc.S b/arch/arm/mm/copypage-v4mc.S deleted file mode 100644 index 305af3dab3d8..000000000000 --- a/arch/arm/mm/copypage-v4mc.S +++ /dev/null | |||
@@ -1,80 +0,0 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/lib/copy_page-armv4mc.S | ||
3 | * | ||
4 | * Copyright (C) 1995-2001 Russell King | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * ASM optimised string functions | ||
11 | */ | ||
12 | #include <linux/linkage.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <asm/constants.h> | ||
15 | |||
16 | .text | ||
17 | .align 5 | ||
18 | /* | ||
19 | * ARMv4 mini-dcache optimised copy_user_page | ||
20 | * | ||
21 | * We flush the destination cache lines just before we write the data into the | ||
22 | * corresponding address. Since the Dcache is read-allocate, this removes the | ||
23 | * Dcache aliasing issue. The writes will be forwarded to the write buffer, | ||
24 | * and merged as appropriate. | ||
25 | * | ||
26 | * Note: We rely on all ARMv4 processors implementing the "invalidate D line" | ||
27 | * instruction. If your processor does not supply this, you have to write your | ||
28 | * own copy_user_page that does the right thing. | ||
29 | */ | ||
30 | ENTRY(v4_mc_copy_user_page) | ||
31 | stmfd sp!, {r4, lr} @ 2 | ||
32 | mov r4, r0 | ||
33 | mov r0, r1 | ||
34 | bl map_page_minicache | ||
35 | mov r1, #PAGE_SZ/64 @ 1 | ||
36 | ldmia r0!, {r2, r3, ip, lr} @ 4 | ||
37 | 1: mcr p15, 0, r4, c7, c6, 1 @ 1 invalidate D line | ||
38 | stmia r4!, {r2, r3, ip, lr} @ 4 | ||
39 | ldmia r0!, {r2, r3, ip, lr} @ 4+1 | ||
40 | stmia r4!, {r2, r3, ip, lr} @ 4 | ||
41 | ldmia r0!, {r2, r3, ip, lr} @ 4 | ||
42 | mcr p15, 0, r4, c7, c6, 1 @ 1 invalidate D line | ||
43 | stmia r4!, {r2, r3, ip, lr} @ 4 | ||
44 | ldmia r0!, {r2, r3, ip, lr} @ 4 | ||
45 | subs r1, r1, #1 @ 1 | ||
46 | stmia r4!, {r2, r3, ip, lr} @ 4 | ||
47 | ldmneia r0!, {r2, r3, ip, lr} @ 4 | ||
48 | bne 1b @ 1 | ||
49 | ldmfd sp!, {r4, pc} @ 3 | ||
50 | |||
51 | .align 5 | ||
52 | /* | ||
53 | * ARMv4 optimised clear_user_page | ||
54 | * | ||
55 | * Same story as above. | ||
56 | */ | ||
57 | ENTRY(v4_mc_clear_user_page) | ||
58 | str lr, [sp, #-4]! | ||
59 | mov r1, #PAGE_SZ/64 @ 1 | ||
60 | mov r2, #0 @ 1 | ||
61 | mov r3, #0 @ 1 | ||
62 | mov ip, #0 @ 1 | ||
63 | mov lr, #0 @ 1 | ||
64 | 1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line | ||
65 | stmia r0!, {r2, r3, ip, lr} @ 4 | ||
66 | stmia r0!, {r2, r3, ip, lr} @ 4 | ||
67 | mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line | ||
68 | stmia r0!, {r2, r3, ip, lr} @ 4 | ||
69 | stmia r0!, {r2, r3, ip, lr} @ 4 | ||
70 | subs r1, r1, #1 @ 1 | ||
71 | bne 1b @ 1 | ||
72 | ldr pc, [sp], #4 | ||
73 | |||
74 | __INITDATA | ||
75 | |||
76 | .type v4_mc_user_fns, #object | ||
77 | ENTRY(v4_mc_user_fns) | ||
78 | .long v4_mc_clear_user_page | ||
79 | .long v4_mc_copy_user_page | ||
80 | .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 index 000000000000..fc69dccdace1 --- /dev/null +++ b/arch/arm/mm/copypage-v4mc.c | |||
@@ -0,0 +1,111 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/lib/copypage-armv4mc.S | ||
3 | * | ||
4 | * Copyright (C) 1995-2005 Russell King | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This handles the mini data cache, as found on SA11x0 and XScale | ||
11 | * processors. When we copy a user page page, we map it in such a way | ||
12 | * that accesses to this page will not touch the main data cache, but | ||
13 | * will be cached in the mini data cache. This prevents us thrashing | ||
14 | * the main data cache on page faults. | ||
15 | */ | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/mm.h> | ||
18 | |||
19 | #include <asm/page.h> | ||
20 | #include <asm/pgtable.h> | ||
21 | #include <asm/tlbflush.h> | ||
22 | |||
23 | /* | ||
24 | * 0xffff8000 to 0xffffffff is reserved for any ARM architecture | ||
25 | * specific hacks for copying pages efficiently. | ||
26 | */ | ||
27 | #define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \ | ||
28 | L_PTE_CACHEABLE) | ||
29 | |||
30 | #define TOP_PTE(x) pte_offset_kernel(top_pmd, x) | ||
31 | |||
32 | static DEFINE_SPINLOCK(minicache_lock); | ||
33 | |||
34 | /* | ||
35 | * ARMv4 mini-dcache optimised copy_user_page | ||
36 | * | ||
37 | * We flush the destination cache lines just before we write the data into the | ||
38 | * corresponding address. Since the Dcache is read-allocate, this removes the | ||
39 | * Dcache aliasing issue. The writes will be forwarded to the write buffer, | ||
40 | * and merged as appropriate. | ||
41 | * | ||
42 | * Note: We rely on all ARMv4 processors implementing the "invalidate D line" | ||
43 | * instruction. If your processor does not supply this, you have to write your | ||
44 | * own copy_user_page that does the right thing. | ||
45 | */ | ||
46 | static void __attribute__((naked)) | ||
47 | mc_copy_user_page(void *from, void *to) | ||
48 | { | ||
49 | asm volatile( | ||
50 | "stmfd sp!, {r4, lr} @ 2\n\ | ||
51 | mov r4, %2 @ 1\n\ | ||
52 | ldmia %0!, {r2, r3, ip, lr} @ 4\n\ | ||
53 | 1: mcr p15, 0, %1, c7, c6, 1 @ 1 invalidate D line\n\ | ||
54 | stmia %1!, {r2, r3, ip, lr} @ 4\n\ | ||
55 | ldmia %0!, {r2, r3, ip, lr} @ 4+1\n\ | ||
56 | stmia %1!, {r2, r3, ip, lr} @ 4\n\ | ||
57 | ldmia %0!, {r2, r3, ip, lr} @ 4\n\ | ||
58 | mcr p15, 0, %1, c7, c6, 1 @ 1 invalidate D line\n\ | ||
59 | stmia %1!, {r2, r3, ip, lr} @ 4\n\ | ||
60 | ldmia %0!, {r2, r3, ip, lr} @ 4\n\ | ||
61 | subs r4, r4, #1 @ 1\n\ | ||
62 | stmia %1!, {r2, r3, ip, lr} @ 4\n\ | ||
63 | ldmneia %0!, {r2, r3, ip, lr} @ 4\n\ | ||
64 | bne 1b @ 1\n\ | ||
65 | ldmfd sp!, {r4, pc} @ 3" | ||
66 | : | ||
67 | : "r" (from), "r" (to), "I" (PAGE_SIZE / 64)); | ||
68 | } | ||
69 | |||
70 | void v4_mc_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr) | ||
71 | { | ||
72 | spin_lock(&minicache_lock); | ||
73 | |||
74 | set_pte(TOP_PTE(0xffff8000), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot)); | ||
75 | flush_tlb_kernel_page(0xffff8000); | ||
76 | |||
77 | mc_copy_user_page((void *)0xffff8000, kto); | ||
78 | |||
79 | spin_unlock(&minicache_lock); | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * ARMv4 optimised clear_user_page | ||
84 | */ | ||
85 | void __attribute__((naked)) | ||
86 | v4_mc_clear_user_page(void *kaddr, unsigned long vaddr) | ||
87 | { | ||
88 | asm volatile( | ||
89 | "str lr, [sp, #-4]!\n\ | ||
90 | mov r1, %0 @ 1\n\ | ||
91 | mov r2, #0 @ 1\n\ | ||
92 | mov r3, #0 @ 1\n\ | ||
93 | mov ip, #0 @ 1\n\ | ||
94 | mov lr, #0 @ 1\n\ | ||
95 | 1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line\n\ | ||
96 | stmia r0!, {r2, r3, ip, lr} @ 4\n\ | ||
97 | stmia r0!, {r2, r3, ip, lr} @ 4\n\ | ||
98 | mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line\n\ | ||
99 | stmia r0!, {r2, r3, ip, lr} @ 4\n\ | ||
100 | stmia r0!, {r2, r3, ip, lr} @ 4\n\ | ||
101 | subs r1, r1, #1 @ 1\n\ | ||
102 | bne 1b @ 1\n\ | ||
103 | ldr pc, [sp], #4" | ||
104 | : | ||
105 | : "I" (PAGE_SIZE / 64)); | ||
106 | } | ||
107 | |||
108 | struct cpu_user_fns v4_mc_user_fns __initdata = { | ||
109 | .cpu_clear_user_page = v4_mc_clear_user_page, | ||
110 | .cpu_copy_user_page = v4_mc_copy_user_page, | ||
111 | }; | ||
diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c index 694ac8208858..a8c00236bd3d 100644 --- a/arch/arm/mm/copypage-v6.c +++ b/arch/arm/mm/copypage-v6.c | |||
@@ -26,8 +26,8 @@ | |||
26 | #define to_address (0xffffc000) | 26 | #define to_address (0xffffc000) |
27 | #define to_pgprot PAGE_KERNEL | 27 | #define to_pgprot PAGE_KERNEL |
28 | 28 | ||
29 | static pte_t *from_pte; | 29 | #define TOP_PTE(x) pte_offset_kernel(top_pmd, x) |
30 | static pte_t *to_pte; | 30 | |
31 | static DEFINE_SPINLOCK(v6_lock); | 31 | static DEFINE_SPINLOCK(v6_lock); |
32 | 32 | ||
33 | #define DCACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT) | 33 | #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 | |||
74 | */ | 74 | */ |
75 | spin_lock(&v6_lock); | 75 | spin_lock(&v6_lock); |
76 | 76 | ||
77 | set_pte(from_pte + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, from_pgprot)); | 77 | set_pte(TOP_PTE(from_address) + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, from_pgprot)); |
78 | set_pte(to_pte + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, to_pgprot)); | 78 | set_pte(TOP_PTE(to_address) + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, to_pgprot)); |
79 | 79 | ||
80 | from = from_address + (offset << PAGE_SHIFT); | 80 | from = from_address + (offset << PAGE_SHIFT); |
81 | to = to_address + (offset << PAGE_SHIFT); | 81 | to = to_address + (offset << PAGE_SHIFT); |
@@ -114,7 +114,7 @@ void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr) | |||
114 | */ | 114 | */ |
115 | spin_lock(&v6_lock); | 115 | spin_lock(&v6_lock); |
116 | 116 | ||
117 | set_pte(to_pte + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, to_pgprot)); | 117 | set_pte(TOP_PTE(to_address) + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, to_pgprot)); |
118 | flush_tlb_kernel_page(to); | 118 | flush_tlb_kernel_page(to); |
119 | clear_page((void *)to); | 119 | clear_page((void *)to); |
120 | 120 | ||
@@ -129,21 +129,6 @@ struct cpu_user_fns v6_user_fns __initdata = { | |||
129 | static int __init v6_userpage_init(void) | 129 | static int __init v6_userpage_init(void) |
130 | { | 130 | { |
131 | if (cache_is_vipt_aliasing()) { | 131 | if (cache_is_vipt_aliasing()) { |
132 | pgd_t *pgd; | ||
133 | pmd_t *pmd; | ||
134 | |||
135 | pgd = pgd_offset_k(from_address); | ||
136 | pmd = pmd_alloc(&init_mm, pgd, from_address); | ||
137 | if (!pmd) | ||
138 | BUG(); | ||
139 | from_pte = pte_alloc_kernel(&init_mm, pmd, from_address); | ||
140 | if (!from_pte) | ||
141 | BUG(); | ||
142 | |||
143 | to_pte = pte_alloc_kernel(&init_mm, pmd, to_address); | ||
144 | if (!to_pte) | ||
145 | BUG(); | ||
146 | |||
147 | cpu_user.cpu_clear_user_page = v6_clear_user_page_aliasing; | 132 | cpu_user.cpu_clear_user_page = v6_clear_user_page_aliasing; |
148 | cpu_user.cpu_copy_user_page = v6_copy_user_page_aliasing; | 133 | cpu_user.cpu_copy_user_page = v6_copy_user_page_aliasing; |
149 | } | 134 | } |
@@ -151,5 +136,4 @@ static int __init v6_userpage_init(void) | |||
151 | return 0; | 136 | return 0; |
152 | } | 137 | } |
153 | 138 | ||
154 | __initcall(v6_userpage_init); | 139 | core_initcall(v6_userpage_init); |
155 | |||
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index c6de48d89503..4085ed983e46 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c | |||
@@ -13,6 +13,29 @@ | |||
13 | 13 | ||
14 | #include <asm/cacheflush.h> | 14 | #include <asm/cacheflush.h> |
15 | #include <asm/system.h> | 15 | #include <asm/system.h> |
16 | #include <asm/tlbflush.h> | ||
17 | |||
18 | #ifdef CONFIG_CPU_CACHE_VIPT | ||
19 | #define ALIAS_FLUSH_START 0xffff4000 | ||
20 | |||
21 | #define TOP_PTE(x) pte_offset_kernel(top_pmd, x) | ||
22 | |||
23 | static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr) | ||
24 | { | ||
25 | unsigned long to = ALIAS_FLUSH_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT); | ||
26 | |||
27 | set_pte(TOP_PTE(to), pfn_pte(pfn, PAGE_KERNEL)); | ||
28 | flush_tlb_kernel_page(to); | ||
29 | |||
30 | asm( "mcrr p15, 0, %1, %0, c14\n" | ||
31 | " mcrr p15, 0, %1, %0, c5\n" | ||
32 | : | ||
33 | : "r" (to), "r" (to + PAGE_SIZE - L1_CACHE_BYTES) | ||
34 | : "cc"); | ||
35 | } | ||
36 | #else | ||
37 | #define flush_pfn_alias(pfn,vaddr) do { } while (0) | ||
38 | #endif | ||
16 | 39 | ||
17 | static void __flush_dcache_page(struct address_space *mapping, struct page *page) | 40 | static void __flush_dcache_page(struct address_space *mapping, struct page *page) |
18 | { | 41 | { |
@@ -37,6 +60,18 @@ static void __flush_dcache_page(struct address_space *mapping, struct page *page | |||
37 | return; | 60 | return; |
38 | 61 | ||
39 | /* | 62 | /* |
63 | * This is a page cache page. If we have a VIPT cache, we | ||
64 | * only need to do one flush - which would be at the relevant | ||
65 | * userspace colour, which is congruent with page->index. | ||
66 | */ | ||
67 | if (cache_is_vipt()) { | ||
68 | if (cache_is_vipt_aliasing()) | ||
69 | flush_pfn_alias(page_to_pfn(page), | ||
70 | page->index << PAGE_CACHE_SHIFT); | ||
71 | return; | ||
72 | } | ||
73 | |||
74 | /* | ||
40 | * There are possible user space mappings of this page: | 75 | * There are possible user space mappings of this page: |
41 | * - VIVT cache: we need to also write back and invalidate all user | 76 | * - VIVT cache: we need to also write back and invalidate all user |
42 | * data in the current VM view associated with this page. | 77 | * data in the current VM view associated with this page. |
@@ -57,8 +92,6 @@ static void __flush_dcache_page(struct address_space *mapping, struct page *page | |||
57 | continue; | 92 | continue; |
58 | offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT; | 93 | offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT; |
59 | flush_cache_page(mpnt, mpnt->vm_start + offset, page_to_pfn(page)); | 94 | flush_cache_page(mpnt, mpnt->vm_start + offset, page_to_pfn(page)); |
60 | if (cache_is_vipt()) | ||
61 | break; | ||
62 | } | 95 | } |
63 | flush_dcache_mmap_unlock(mapping); | 96 | flush_dcache_mmap_unlock(mapping); |
64 | } | 97 | } |
diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c index 585dfb8e20b9..2c2b93d77d43 100644 --- a/arch/arm/mm/mm-armv.c +++ b/arch/arm/mm/mm-armv.c | |||
@@ -37,6 +37,8 @@ pgprot_t pgprot_kernel; | |||
37 | 37 | ||
38 | EXPORT_SYMBOL(pgprot_kernel); | 38 | EXPORT_SYMBOL(pgprot_kernel); |
39 | 39 | ||
40 | pmd_t *top_pmd; | ||
41 | |||
40 | struct cachepolicy { | 42 | struct cachepolicy { |
41 | const char policy[16]; | 43 | const char policy[16]; |
42 | unsigned int cr_mask; | 44 | unsigned int cr_mask; |
@@ -142,6 +144,16 @@ __setup("noalign", noalign_setup); | |||
142 | 144 | ||
143 | #define FIRST_KERNEL_PGD_NR (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD) | 145 | #define FIRST_KERNEL_PGD_NR (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD) |
144 | 146 | ||
147 | static inline pmd_t *pmd_off(pgd_t *pgd, unsigned long virt) | ||
148 | { | ||
149 | return pmd_offset(pgd, virt); | ||
150 | } | ||
151 | |||
152 | static inline pmd_t *pmd_off_k(unsigned long virt) | ||
153 | { | ||
154 | return pmd_off(pgd_offset_k(virt), virt); | ||
155 | } | ||
156 | |||
145 | /* | 157 | /* |
146 | * need to get a 16k page for level 1 | 158 | * need to get a 16k page for level 1 |
147 | */ | 159 | */ |
@@ -220,7 +232,7 @@ void free_pgd_slow(pgd_t *pgd) | |||
220 | return; | 232 | return; |
221 | 233 | ||
222 | /* pgd is always present and good */ | 234 | /* pgd is always present and good */ |
223 | pmd = (pmd_t *)pgd; | 235 | pmd = pmd_off(pgd, 0); |
224 | if (pmd_none(*pmd)) | 236 | if (pmd_none(*pmd)) |
225 | goto free; | 237 | goto free; |
226 | if (pmd_bad(*pmd)) { | 238 | if (pmd_bad(*pmd)) { |
@@ -246,9 +258,8 @@ free: | |||
246 | static inline void | 258 | static inline void |
247 | alloc_init_section(unsigned long virt, unsigned long phys, int prot) | 259 | alloc_init_section(unsigned long virt, unsigned long phys, int prot) |
248 | { | 260 | { |
249 | pmd_t *pmdp; | 261 | pmd_t *pmdp = pmd_off_k(virt); |
250 | 262 | ||
251 | pmdp = pmd_offset(pgd_offset_k(virt), virt); | ||
252 | if (virt & (1 << 20)) | 263 | if (virt & (1 << 20)) |
253 | pmdp++; | 264 | pmdp++; |
254 | 265 | ||
@@ -283,11 +294,9 @@ alloc_init_supersection(unsigned long virt, unsigned long phys, int prot) | |||
283 | static inline void | 294 | static inline void |
284 | alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pgprot_t prot) | 295 | alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pgprot_t prot) |
285 | { | 296 | { |
286 | pmd_t *pmdp; | 297 | pmd_t *pmdp = pmd_off_k(virt); |
287 | pte_t *ptep; | 298 | pte_t *ptep; |
288 | 299 | ||
289 | pmdp = pmd_offset(pgd_offset_k(virt), virt); | ||
290 | |||
291 | if (pmd_none(*pmdp)) { | 300 | if (pmd_none(*pmdp)) { |
292 | unsigned long pmdval; | 301 | unsigned long pmdval; |
293 | ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * | 302 | 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 | |||
310 | */ | 319 | */ |
311 | static inline void clear_mapping(unsigned long virt) | 320 | static inline void clear_mapping(unsigned long virt) |
312 | { | 321 | { |
313 | pmd_clear(pmd_offset(pgd_offset_k(virt), virt)); | 322 | pmd_clear(pmd_off_k(virt)); |
314 | } | 323 | } |
315 | 324 | ||
316 | struct mem_types { | 325 | struct mem_types { |
@@ -578,7 +587,7 @@ void setup_mm_for_reboot(char mode) | |||
578 | PMD_TYPE_SECT; | 587 | PMD_TYPE_SECT; |
579 | if (cpu_arch <= CPU_ARCH_ARMv5) | 588 | if (cpu_arch <= CPU_ARCH_ARMv5) |
580 | pmdval |= PMD_BIT4; | 589 | pmdval |= PMD_BIT4; |
581 | pmd = pmd_offset(pgd + i, i << PGDIR_SHIFT); | 590 | pmd = pmd_off(pgd, i << PGDIR_SHIFT); |
582 | pmd[0] = __pmd(pmdval); | 591 | pmd[0] = __pmd(pmdval); |
583 | pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1))); | 592 | pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1))); |
584 | flush_pmd_entry(pmd); | 593 | flush_pmd_entry(pmd); |
@@ -675,6 +684,8 @@ void __init memtable_init(struct meminfo *mi) | |||
675 | 684 | ||
676 | flush_cache_all(); | 685 | flush_cache_all(); |
677 | flush_tlb_all(); | 686 | flush_tlb_all(); |
687 | |||
688 | top_pmd = pmd_off_k(0xffff0000); | ||
678 | } | 689 | } |
679 | 690 | ||
680 | /* | 691 | /* |
diff --git a/drivers/block/ioctl.c b/drivers/block/ioctl.c index 5e03f5157ef9..6d7bcc9da9e7 100644 --- a/drivers/block/ioctl.c +++ b/drivers/block/ioctl.c | |||
@@ -237,3 +237,5 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg) | |||
237 | } | 237 | } |
238 | return ret; | 238 | return ret; |
239 | } | 239 | } |
240 | |||
241 | EXPORT_SYMBOL_GPL(blkdev_ioctl); | ||
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 1a1fa3ccb913..82ccad0a7f1a 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c | |||
@@ -2406,7 +2406,7 @@ static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u | |||
2406 | case CDROM_LAST_WRITTEN: | 2406 | case CDROM_LAST_WRITTEN: |
2407 | case CDROM_SEND_PACKET: | 2407 | case CDROM_SEND_PACKET: |
2408 | case SCSI_IOCTL_SEND_COMMAND: | 2408 | case SCSI_IOCTL_SEND_COMMAND: |
2409 | return ioctl_by_bdev(pd->bdev, cmd, arg); | 2409 | return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg); |
2410 | 2410 | ||
2411 | case CDROMEJECT: | 2411 | case CDROMEJECT: |
2412 | /* | 2412 | /* |
@@ -2414,7 +2414,7 @@ static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u | |||
2414 | * have to unlock it or else the eject command fails. | 2414 | * have to unlock it or else the eject command fails. |
2415 | */ | 2415 | */ |
2416 | pkt_lock_door(pd, 0); | 2416 | pkt_lock_door(pd, 0); |
2417 | return ioctl_by_bdev(pd->bdev, cmd, arg); | 2417 | return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg); |
2418 | 2418 | ||
2419 | default: | 2419 | default: |
2420 | printk("pktcdvd: Unknown ioctl for %s (%x)\n", pd->name, cmd); | 2420 | printk("pktcdvd: Unknown ioctl for %s (%x)\n", pd->name, cmd); |
diff --git a/drivers/char/raw.c b/drivers/char/raw.c index a2e33ec79615..131465e8de5a 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c | |||
@@ -122,7 +122,7 @@ raw_ioctl(struct inode *inode, struct file *filp, | |||
122 | { | 122 | { |
123 | struct block_device *bdev = filp->private_data; | 123 | struct block_device *bdev = filp->private_data; |
124 | 124 | ||
125 | return ioctl_by_bdev(bdev, command, arg); | 125 | return blkdev_ioctl(bdev->bd_inode, filp, command, arg); |
126 | } | 126 | } |
127 | 127 | ||
128 | static void bind_device(struct raw_config_request *rq) | 128 | static void bind_device(struct raw_config_request *rq) |
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 2e70d74fbdee..4991bbd054f3 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig | |||
@@ -51,7 +51,7 @@ config MMC_PXA | |||
51 | 51 | ||
52 | config MMC_WBSD | 52 | config MMC_WBSD |
53 | tristate "Winbond W83L51xD SD/MMC Card Interface support" | 53 | tristate "Winbond W83L51xD SD/MMC Card Interface support" |
54 | depends on MMC && ISA && ISA_DMA_API | 54 | depends on MMC && ISA_DMA_API |
55 | help | 55 | help |
56 | This selects the Winbond(R) W83L51xD Secure digital and | 56 | This selects the Winbond(R) W83L51xD Secure digital and |
57 | Multimedia card Interface. | 57 | Multimedia card Interface. |
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 39747526c719..b7fbd30b49a0 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c | |||
@@ -28,7 +28,9 @@ | |||
28 | #include <linux/ioport.h> | 28 | #include <linux/ioport.h> |
29 | #include <linux/device.h> | 29 | #include <linux/device.h> |
30 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
31 | #include <linux/dma-mapping.h> | ||
31 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include <linux/pnp.h> | ||
32 | #include <linux/highmem.h> | 34 | #include <linux/highmem.h> |
33 | #include <linux/mmc/host.h> | 35 | #include <linux/mmc/host.h> |
34 | #include <linux/mmc/protocol.h> | 36 | #include <linux/mmc/protocol.h> |
@@ -40,7 +42,7 @@ | |||
40 | #include "wbsd.h" | 42 | #include "wbsd.h" |
41 | 43 | ||
42 | #define DRIVER_NAME "wbsd" | 44 | #define DRIVER_NAME "wbsd" |
43 | #define DRIVER_VERSION "1.1" | 45 | #define DRIVER_VERSION "1.2" |
44 | 46 | ||
45 | #ifdef CONFIG_MMC_DEBUG | 47 | #ifdef CONFIG_MMC_DEBUG |
46 | #define DBG(x...) \ | 48 | #define DBG(x...) \ |
@@ -52,10 +54,6 @@ | |||
52 | #define DBGF(x...) do { } while (0) | 54 | #define DBGF(x...) do { } while (0) |
53 | #endif | 55 | #endif |
54 | 56 | ||
55 | static unsigned int io = 0x248; | ||
56 | static unsigned int irq = 6; | ||
57 | static int dma = 2; | ||
58 | |||
59 | #ifdef CONFIG_MMC_DEBUG | 57 | #ifdef CONFIG_MMC_DEBUG |
60 | void DBG_REG(int reg, u8 value) | 58 | void DBG_REG(int reg, u8 value) |
61 | { | 59 | { |
@@ -79,28 +77,61 @@ void DBG_REG(int reg, u8 value) | |||
79 | #endif | 77 | #endif |
80 | 78 | ||
81 | /* | 79 | /* |
80 | * Device resources | ||
81 | */ | ||
82 | |||
83 | #ifdef CONFIG_PNP | ||
84 | |||
85 | static const struct pnp_device_id pnp_dev_table[] = { | ||
86 | { "WEC0517", 0 }, | ||
87 | { "WEC0518", 0 }, | ||
88 | { "", 0 }, | ||
89 | }; | ||
90 | |||
91 | MODULE_DEVICE_TABLE(pnp, pnp_dev_table); | ||
92 | |||
93 | #endif /* CONFIG_PNP */ | ||
94 | |||
95 | #ifdef CONFIG_PNP | ||
96 | static unsigned int nopnp = 0; | ||
97 | #else | ||
98 | static const unsigned int nopnp = 1; | ||
99 | #endif | ||
100 | static unsigned int io = 0x248; | ||
101 | static unsigned int irq = 6; | ||
102 | static int dma = 2; | ||
103 | |||
104 | /* | ||
82 | * Basic functions | 105 | * Basic functions |
83 | */ | 106 | */ |
84 | 107 | ||
85 | static inline void wbsd_unlock_config(struct wbsd_host* host) | 108 | static inline void wbsd_unlock_config(struct wbsd_host* host) |
86 | { | 109 | { |
110 | BUG_ON(host->config == 0); | ||
111 | |||
87 | outb(host->unlock_code, host->config); | 112 | outb(host->unlock_code, host->config); |
88 | outb(host->unlock_code, host->config); | 113 | outb(host->unlock_code, host->config); |
89 | } | 114 | } |
90 | 115 | ||
91 | static inline void wbsd_lock_config(struct wbsd_host* host) | 116 | static inline void wbsd_lock_config(struct wbsd_host* host) |
92 | { | 117 | { |
118 | BUG_ON(host->config == 0); | ||
119 | |||
93 | outb(LOCK_CODE, host->config); | 120 | outb(LOCK_CODE, host->config); |
94 | } | 121 | } |
95 | 122 | ||
96 | static inline void wbsd_write_config(struct wbsd_host* host, u8 reg, u8 value) | 123 | static inline void wbsd_write_config(struct wbsd_host* host, u8 reg, u8 value) |
97 | { | 124 | { |
125 | BUG_ON(host->config == 0); | ||
126 | |||
98 | outb(reg, host->config); | 127 | outb(reg, host->config); |
99 | outb(value, host->config + 1); | 128 | outb(value, host->config + 1); |
100 | } | 129 | } |
101 | 130 | ||
102 | static inline u8 wbsd_read_config(struct wbsd_host* host, u8 reg) | 131 | static inline u8 wbsd_read_config(struct wbsd_host* host, u8 reg) |
103 | { | 132 | { |
133 | BUG_ON(host->config == 0); | ||
134 | |||
104 | outb(reg, host->config); | 135 | outb(reg, host->config); |
105 | return inb(host->config + 1); | 136 | return inb(host->config + 1); |
106 | } | 137 | } |
@@ -133,6 +164,13 @@ static void wbsd_init_device(struct wbsd_host* host) | |||
133 | wbsd_write_index(host, WBSD_IDX_SETUP, setup); | 164 | wbsd_write_index(host, WBSD_IDX_SETUP, setup); |
134 | 165 | ||
135 | /* | 166 | /* |
167 | * Set DAT3 to input | ||
168 | */ | ||
169 | setup &= ~WBSD_DAT3_H; | ||
170 | wbsd_write_index(host, WBSD_IDX_SETUP, setup); | ||
171 | host->flags &= ~WBSD_FIGNORE_DETECT; | ||
172 | |||
173 | /* | ||
136 | * Read back default clock. | 174 | * Read back default clock. |
137 | */ | 175 | */ |
138 | host->clk = wbsd_read_index(host, WBSD_IDX_CLK); | 176 | host->clk = wbsd_read_index(host, WBSD_IDX_CLK); |
@@ -148,6 +186,14 @@ static void wbsd_init_device(struct wbsd_host* host) | |||
148 | wbsd_write_index(host, WBSD_IDX_TAAC, 0x7F); | 186 | wbsd_write_index(host, WBSD_IDX_TAAC, 0x7F); |
149 | 187 | ||
150 | /* | 188 | /* |
189 | * Test for card presence | ||
190 | */ | ||
191 | if (inb(host->base + WBSD_CSR) & WBSD_CARDPRESENT) | ||
192 | host->flags |= WBSD_FCARD_PRESENT; | ||
193 | else | ||
194 | host->flags &= ~WBSD_FCARD_PRESENT; | ||
195 | |||
196 | /* | ||
151 | * Enable interesting interrupts. | 197 | * Enable interesting interrupts. |
152 | */ | 198 | */ |
153 | ier = 0; | 199 | ier = 0; |
@@ -407,8 +453,6 @@ static inline void wbsd_get_long_reply(struct wbsd_host* host, | |||
407 | } | 453 | } |
408 | } | 454 | } |
409 | 455 | ||
410 | static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs); | ||
411 | |||
412 | static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd) | 456 | static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd) |
413 | { | 457 | { |
414 | int i; | 458 | int i; |
@@ -646,6 +690,13 @@ static void wbsd_fill_fifo(struct wbsd_host* host) | |||
646 | } | 690 | } |
647 | 691 | ||
648 | wbsd_kunmap_sg(host); | 692 | wbsd_kunmap_sg(host); |
693 | |||
694 | /* | ||
695 | * The controller stops sending interrupts for | ||
696 | * 'FIFO empty' under certain conditions. So we | ||
697 | * need to be a bit more pro-active. | ||
698 | */ | ||
699 | tasklet_schedule(&host->fifo_tasklet); | ||
649 | } | 700 | } |
650 | 701 | ||
651 | static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data) | 702 | 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) | |||
850 | wbsd_request_end(host, host->mrq); | 901 | wbsd_request_end(host, host->mrq); |
851 | } | 902 | } |
852 | 903 | ||
853 | /* | 904 | /*****************************************************************************\ |
854 | * MMC Callbacks | 905 | * * |
855 | */ | 906 | * MMC layer callbacks * |
907 | * * | ||
908 | \*****************************************************************************/ | ||
856 | 909 | ||
857 | static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq) | 910 | static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq) |
858 | { | 911 | { |
@@ -874,7 +927,7 @@ static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq) | |||
874 | * If there is no card in the slot then | 927 | * If there is no card in the slot then |
875 | * timeout immediatly. | 928 | * timeout immediatly. |
876 | */ | 929 | */ |
877 | if (!(inb(host->base + WBSD_CSR) & WBSD_CARDPRESENT)) | 930 | if (!(host->flags & WBSD_FCARD_PRESENT)) |
878 | { | 931 | { |
879 | cmd->error = MMC_ERR_TIMEOUT; | 932 | cmd->error = MMC_ERR_TIMEOUT; |
880 | goto done; | 933 | goto done; |
@@ -953,33 +1006,50 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) | |||
953 | host->clk = clk; | 1006 | host->clk = clk; |
954 | } | 1007 | } |
955 | 1008 | ||
1009 | /* | ||
1010 | * Power up card. | ||
1011 | */ | ||
956 | if (ios->power_mode != MMC_POWER_OFF) | 1012 | if (ios->power_mode != MMC_POWER_OFF) |
957 | { | 1013 | { |
958 | /* | ||
959 | * Power up card. | ||
960 | */ | ||
961 | pwr = inb(host->base + WBSD_CSR); | 1014 | pwr = inb(host->base + WBSD_CSR); |
962 | pwr &= ~WBSD_POWER_N; | 1015 | pwr &= ~WBSD_POWER_N; |
963 | outb(pwr, host->base + WBSD_CSR); | 1016 | outb(pwr, host->base + WBSD_CSR); |
964 | |||
965 | /* | ||
966 | * This behaviour is stolen from the | ||
967 | * Windows driver. Don't know why, but | ||
968 | * it is needed. | ||
969 | */ | ||
970 | setup = wbsd_read_index(host, WBSD_IDX_SETUP); | ||
971 | if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) | ||
972 | setup |= WBSD_DAT3_H; | ||
973 | else | ||
974 | setup &= ~WBSD_DAT3_H; | ||
975 | wbsd_write_index(host, WBSD_IDX_SETUP, setup); | ||
976 | |||
977 | mdelay(1); | ||
978 | } | 1017 | } |
979 | 1018 | ||
1019 | /* | ||
1020 | * MMC cards need to have pin 1 high during init. | ||
1021 | * Init time corresponds rather nicely with the bus mode. | ||
1022 | * It wreaks havoc with the card detection though so | ||
1023 | * that needs to be disabed. | ||
1024 | */ | ||
1025 | setup = wbsd_read_index(host, WBSD_IDX_SETUP); | ||
1026 | if ((ios->power_mode == MMC_POWER_ON) && | ||
1027 | (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)) | ||
1028 | { | ||
1029 | setup |= WBSD_DAT3_H; | ||
1030 | host->flags |= WBSD_FIGNORE_DETECT; | ||
1031 | } | ||
1032 | else | ||
1033 | { | ||
1034 | setup &= ~WBSD_DAT3_H; | ||
1035 | host->flags &= ~WBSD_FIGNORE_DETECT; | ||
1036 | } | ||
1037 | wbsd_write_index(host, WBSD_IDX_SETUP, setup); | ||
1038 | |||
980 | spin_unlock_bh(&host->lock); | 1039 | spin_unlock_bh(&host->lock); |
981 | } | 1040 | } |
982 | 1041 | ||
1042 | static struct mmc_host_ops wbsd_ops = { | ||
1043 | .request = wbsd_request, | ||
1044 | .set_ios = wbsd_set_ios, | ||
1045 | }; | ||
1046 | |||
1047 | /*****************************************************************************\ | ||
1048 | * * | ||
1049 | * Interrupt handling * | ||
1050 | * * | ||
1051 | \*****************************************************************************/ | ||
1052 | |||
983 | /* | 1053 | /* |
984 | * Tasklets | 1054 | * Tasklets |
985 | */ | 1055 | */ |
@@ -1005,17 +1075,33 @@ static void wbsd_tasklet_card(unsigned long param) | |||
1005 | { | 1075 | { |
1006 | struct wbsd_host* host = (struct wbsd_host*)param; | 1076 | struct wbsd_host* host = (struct wbsd_host*)param; |
1007 | u8 csr; | 1077 | u8 csr; |
1078 | int change = 0; | ||
1008 | 1079 | ||
1009 | spin_lock(&host->lock); | 1080 | spin_lock(&host->lock); |
1010 | 1081 | ||
1082 | if (host->flags & WBSD_FIGNORE_DETECT) | ||
1083 | { | ||
1084 | spin_unlock(&host->lock); | ||
1085 | return; | ||
1086 | } | ||
1087 | |||
1011 | csr = inb(host->base + WBSD_CSR); | 1088 | csr = inb(host->base + WBSD_CSR); |
1012 | WARN_ON(csr == 0xff); | 1089 | WARN_ON(csr == 0xff); |
1013 | 1090 | ||
1014 | if (csr & WBSD_CARDPRESENT) | 1091 | if (csr & WBSD_CARDPRESENT) |
1015 | DBG("Card inserted\n"); | 1092 | { |
1016 | else | 1093 | if (!(host->flags & WBSD_FCARD_PRESENT)) |
1094 | { | ||
1095 | DBG("Card inserted\n"); | ||
1096 | host->flags |= WBSD_FCARD_PRESENT; | ||
1097 | change = 1; | ||
1098 | } | ||
1099 | } | ||
1100 | else if (host->flags & WBSD_FCARD_PRESENT) | ||
1017 | { | 1101 | { |
1018 | DBG("Card removed\n"); | 1102 | DBG("Card removed\n"); |
1103 | host->flags &= ~WBSD_FCARD_PRESENT; | ||
1104 | change = 1; | ||
1019 | 1105 | ||
1020 | if (host->mrq) | 1106 | if (host->mrq) |
1021 | { | 1107 | { |
@@ -1033,7 +1119,8 @@ static void wbsd_tasklet_card(unsigned long param) | |||
1033 | */ | 1119 | */ |
1034 | spin_unlock(&host->lock); | 1120 | spin_unlock(&host->lock); |
1035 | 1121 | ||
1036 | mmc_detect_change(host->mmc); | 1122 | if (change) |
1123 | mmc_detect_change(host->mmc); | ||
1037 | } | 1124 | } |
1038 | 1125 | ||
1039 | static void wbsd_tasklet_fifo(unsigned long param) | 1126 | 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) | |||
1200 | return IRQ_HANDLED; | 1287 | return IRQ_HANDLED; |
1201 | } | 1288 | } |
1202 | 1289 | ||
1290 | /*****************************************************************************\ | ||
1291 | * * | ||
1292 | * Device initialisation and shutdown * | ||
1293 | * * | ||
1294 | \*****************************************************************************/ | ||
1295 | |||
1203 | /* | 1296 | /* |
1204 | * Support functions for probe | 1297 | * Allocate/free MMC structure. |
1205 | */ | 1298 | */ |
1206 | 1299 | ||
1207 | static int wbsd_scan(struct wbsd_host* host) | 1300 | static int __devinit wbsd_alloc_mmc(struct device* dev) |
1301 | { | ||
1302 | struct mmc_host* mmc; | ||
1303 | struct wbsd_host* host; | ||
1304 | |||
1305 | /* | ||
1306 | * Allocate MMC structure. | ||
1307 | */ | ||
1308 | mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev); | ||
1309 | if (!mmc) | ||
1310 | return -ENOMEM; | ||
1311 | |||
1312 | host = mmc_priv(mmc); | ||
1313 | host->mmc = mmc; | ||
1314 | |||
1315 | host->dma = -1; | ||
1316 | |||
1317 | /* | ||
1318 | * Set host parameters. | ||
1319 | */ | ||
1320 | mmc->ops = &wbsd_ops; | ||
1321 | mmc->f_min = 375000; | ||
1322 | mmc->f_max = 24000000; | ||
1323 | mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; | ||
1324 | |||
1325 | spin_lock_init(&host->lock); | ||
1326 | |||
1327 | /* | ||
1328 | * Maximum number of segments. Worst case is one sector per segment | ||
1329 | * so this will be 64kB/512. | ||
1330 | */ | ||
1331 | mmc->max_hw_segs = 128; | ||
1332 | mmc->max_phys_segs = 128; | ||
1333 | |||
1334 | /* | ||
1335 | * Maximum number of sectors in one transfer. Also limited by 64kB | ||
1336 | * buffer. | ||
1337 | */ | ||
1338 | mmc->max_sectors = 128; | ||
1339 | |||
1340 | /* | ||
1341 | * Maximum segment size. Could be one segment with the maximum number | ||
1342 | * of segments. | ||
1343 | */ | ||
1344 | mmc->max_seg_size = mmc->max_sectors * 512; | ||
1345 | |||
1346 | dev_set_drvdata(dev, mmc); | ||
1347 | |||
1348 | return 0; | ||
1349 | } | ||
1350 | |||
1351 | static void __devexit wbsd_free_mmc(struct device* dev) | ||
1352 | { | ||
1353 | struct mmc_host* mmc; | ||
1354 | |||
1355 | mmc = dev_get_drvdata(dev); | ||
1356 | if (!mmc) | ||
1357 | return; | ||
1358 | |||
1359 | mmc_free_host(mmc); | ||
1360 | |||
1361 | dev_set_drvdata(dev, NULL); | ||
1362 | } | ||
1363 | |||
1364 | /* | ||
1365 | * Scan for known chip id:s | ||
1366 | */ | ||
1367 | |||
1368 | static int __devinit wbsd_scan(struct wbsd_host* host) | ||
1208 | { | 1369 | { |
1209 | int i, j, k; | 1370 | int i, j, k; |
1210 | int id; | 1371 | int id; |
@@ -1258,12 +1419,16 @@ static int wbsd_scan(struct wbsd_host* host) | |||
1258 | return -ENODEV; | 1419 | return -ENODEV; |
1259 | } | 1420 | } |
1260 | 1421 | ||
1261 | static int wbsd_request_regions(struct wbsd_host* host) | 1422 | /* |
1423 | * Allocate/free io port ranges | ||
1424 | */ | ||
1425 | |||
1426 | static int __devinit wbsd_request_region(struct wbsd_host* host, int base) | ||
1262 | { | 1427 | { |
1263 | if (io & 0x7) | 1428 | if (io & 0x7) |
1264 | return -EINVAL; | 1429 | return -EINVAL; |
1265 | 1430 | ||
1266 | if (!request_region(io, 8, DRIVER_NAME)) | 1431 | if (!request_region(base, 8, DRIVER_NAME)) |
1267 | return -EIO; | 1432 | return -EIO; |
1268 | 1433 | ||
1269 | host->base = io; | 1434 | host->base = io; |
@@ -1271,19 +1436,25 @@ static int wbsd_request_regions(struct wbsd_host* host) | |||
1271 | return 0; | 1436 | return 0; |
1272 | } | 1437 | } |
1273 | 1438 | ||
1274 | static void wbsd_release_regions(struct wbsd_host* host) | 1439 | static void __devexit wbsd_release_regions(struct wbsd_host* host) |
1275 | { | 1440 | { |
1276 | if (host->base) | 1441 | if (host->base) |
1277 | release_region(host->base, 8); | 1442 | release_region(host->base, 8); |
1443 | |||
1444 | host->base = 0; | ||
1278 | 1445 | ||
1279 | if (host->config) | 1446 | if (host->config) |
1280 | release_region(host->config, 2); | 1447 | release_region(host->config, 2); |
1448 | |||
1449 | host->config = 0; | ||
1281 | } | 1450 | } |
1282 | 1451 | ||
1283 | static void wbsd_init_dma(struct wbsd_host* host) | 1452 | /* |
1453 | * Allocate/free DMA port and buffer | ||
1454 | */ | ||
1455 | |||
1456 | static void __devinit wbsd_request_dma(struct wbsd_host* host, int dma) | ||
1284 | { | 1457 | { |
1285 | host->dma = -1; | ||
1286 | |||
1287 | if (dma < 0) | 1458 | if (dma < 0) |
1288 | return; | 1459 | return; |
1289 | 1460 | ||
@@ -1294,7 +1465,7 @@ static void wbsd_init_dma(struct wbsd_host* host) | |||
1294 | * We need to allocate a special buffer in | 1465 | * We need to allocate a special buffer in |
1295 | * order for ISA to be able to DMA to it. | 1466 | * order for ISA to be able to DMA to it. |
1296 | */ | 1467 | */ |
1297 | host->dma_buffer = kmalloc(65536, | 1468 | host->dma_buffer = kmalloc(WBSD_DMA_SIZE, |
1298 | GFP_NOIO | GFP_DMA | __GFP_REPEAT | __GFP_NOWARN); | 1469 | GFP_NOIO | GFP_DMA | __GFP_REPEAT | __GFP_NOWARN); |
1299 | if (!host->dma_buffer) | 1470 | if (!host->dma_buffer) |
1300 | goto free; | 1471 | goto free; |
@@ -1302,7 +1473,8 @@ static void wbsd_init_dma(struct wbsd_host* host) | |||
1302 | /* | 1473 | /* |
1303 | * Translate the address to a physical address. | 1474 | * Translate the address to a physical address. |
1304 | */ | 1475 | */ |
1305 | host->dma_addr = isa_virt_to_bus(host->dma_buffer); | 1476 | host->dma_addr = dma_map_single(host->mmc->dev, host->dma_buffer, |
1477 | WBSD_DMA_SIZE, DMA_BIDIRECTIONAL); | ||
1306 | 1478 | ||
1307 | /* | 1479 | /* |
1308 | * ISA DMA must be aligned on a 64k basis. | 1480 | * ISA DMA must be aligned on a 64k basis. |
@@ -1325,6 +1497,10 @@ kfree: | |||
1325 | */ | 1497 | */ |
1326 | BUG_ON(1); | 1498 | BUG_ON(1); |
1327 | 1499 | ||
1500 | dma_unmap_single(host->mmc->dev, host->dma_addr, WBSD_DMA_SIZE, | ||
1501 | DMA_BIDIRECTIONAL); | ||
1502 | host->dma_addr = (dma_addr_t)NULL; | ||
1503 | |||
1328 | kfree(host->dma_buffer); | 1504 | kfree(host->dma_buffer); |
1329 | host->dma_buffer = NULL; | 1505 | host->dma_buffer = NULL; |
1330 | 1506 | ||
@@ -1336,60 +1512,122 @@ err: | |||
1336 | "Falling back on FIFO.\n", dma); | 1512 | "Falling back on FIFO.\n", dma); |
1337 | } | 1513 | } |
1338 | 1514 | ||
1339 | static struct mmc_host_ops wbsd_ops = { | 1515 | static void __devexit wbsd_release_dma(struct wbsd_host* host) |
1340 | .request = wbsd_request, | 1516 | { |
1341 | .set_ios = wbsd_set_ios, | 1517 | if (host->dma_addr) |
1342 | }; | 1518 | dma_unmap_single(host->mmc->dev, host->dma_addr, WBSD_DMA_SIZE, |
1519 | DMA_BIDIRECTIONAL); | ||
1520 | if (host->dma_buffer) | ||
1521 | kfree(host->dma_buffer); | ||
1522 | if (host->dma >= 0) | ||
1523 | free_dma(host->dma); | ||
1524 | |||
1525 | host->dma = -1; | ||
1526 | host->dma_buffer = NULL; | ||
1527 | host->dma_addr = (dma_addr_t)NULL; | ||
1528 | } | ||
1343 | 1529 | ||
1344 | /* | 1530 | /* |
1345 | * Device probe | 1531 | * Allocate/free IRQ. |
1346 | */ | 1532 | */ |
1347 | 1533 | ||
1348 | static int wbsd_probe(struct device* dev) | 1534 | static int __devinit wbsd_request_irq(struct wbsd_host* host, int irq) |
1349 | { | 1535 | { |
1350 | struct wbsd_host* host = NULL; | ||
1351 | struct mmc_host* mmc = NULL; | ||
1352 | int ret; | 1536 | int ret; |
1353 | 1537 | ||
1354 | /* | 1538 | /* |
1355 | * Allocate MMC structure. | 1539 | * Allocate interrupt. |
1356 | */ | 1540 | */ |
1357 | mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev); | 1541 | |
1358 | if (!mmc) | 1542 | ret = request_irq(irq, wbsd_irq, SA_SHIRQ, DRIVER_NAME, host); |
1359 | return -ENOMEM; | 1543 | if (ret) |
1360 | 1544 | return ret; | |
1361 | host = mmc_priv(mmc); | ||
1362 | host->mmc = mmc; | ||
1363 | 1545 | ||
1546 | host->irq = irq; | ||
1547 | |||
1364 | /* | 1548 | /* |
1365 | * Scan for hardware. | 1549 | * Set up tasklets. |
1366 | */ | 1550 | */ |
1367 | ret = wbsd_scan(host); | 1551 | tasklet_init(&host->card_tasklet, wbsd_tasklet_card, (unsigned long)host); |
1368 | if (ret) | 1552 | tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo, (unsigned long)host); |
1369 | goto freemmc; | 1553 | tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc, (unsigned long)host); |
1554 | tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout, (unsigned long)host); | ||
1555 | tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, (unsigned long)host); | ||
1556 | tasklet_init(&host->block_tasklet, wbsd_tasklet_block, (unsigned long)host); | ||
1557 | |||
1558 | return 0; | ||
1559 | } | ||
1370 | 1560 | ||
1371 | /* | 1561 | static void __devexit wbsd_release_irq(struct wbsd_host* host) |
1372 | * Reset the chip. | 1562 | { |
1373 | */ | 1563 | if (!host->irq) |
1374 | wbsd_write_config(host, WBSD_CONF_SWRST, 1); | 1564 | return; |
1375 | wbsd_write_config(host, WBSD_CONF_SWRST, 0); | ||
1376 | 1565 | ||
1566 | free_irq(host->irq, host); | ||
1567 | |||
1568 | host->irq = 0; | ||
1569 | |||
1570 | tasklet_kill(&host->card_tasklet); | ||
1571 | tasklet_kill(&host->fifo_tasklet); | ||
1572 | tasklet_kill(&host->crc_tasklet); | ||
1573 | tasklet_kill(&host->timeout_tasklet); | ||
1574 | tasklet_kill(&host->finish_tasklet); | ||
1575 | tasklet_kill(&host->block_tasklet); | ||
1576 | } | ||
1577 | |||
1578 | /* | ||
1579 | * Allocate all resources for the host. | ||
1580 | */ | ||
1581 | |||
1582 | static int __devinit wbsd_request_resources(struct wbsd_host* host, | ||
1583 | int base, int irq, int dma) | ||
1584 | { | ||
1585 | int ret; | ||
1586 | |||
1377 | /* | 1587 | /* |
1378 | * Allocate I/O ports. | 1588 | * Allocate I/O ports. |
1379 | */ | 1589 | */ |
1380 | ret = wbsd_request_regions(host); | 1590 | ret = wbsd_request_region(host, base); |
1381 | if (ret) | 1591 | if (ret) |
1382 | goto release; | 1592 | return ret; |
1383 | 1593 | ||
1384 | /* | 1594 | /* |
1385 | * Set host parameters. | 1595 | * Allocate interrupt. |
1386 | */ | 1596 | */ |
1387 | mmc->ops = &wbsd_ops; | 1597 | ret = wbsd_request_irq(host, irq); |
1388 | mmc->f_min = 375000; | 1598 | if (ret) |
1389 | mmc->f_max = 24000000; | 1599 | return ret; |
1390 | mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; | 1600 | |
1601 | /* | ||
1602 | * Allocate DMA. | ||
1603 | */ | ||
1604 | wbsd_request_dma(host, dma); | ||
1391 | 1605 | ||
1392 | spin_lock_init(&host->lock); | 1606 | return 0; |
1607 | } | ||
1608 | |||
1609 | /* | ||
1610 | * Release all resources for the host. | ||
1611 | */ | ||
1612 | |||
1613 | static void __devexit wbsd_release_resources(struct wbsd_host* host) | ||
1614 | { | ||
1615 | wbsd_release_dma(host); | ||
1616 | wbsd_release_irq(host); | ||
1617 | wbsd_release_regions(host); | ||
1618 | } | ||
1619 | |||
1620 | /* | ||
1621 | * Configure the resources the chip should use. | ||
1622 | */ | ||
1623 | |||
1624 | static void __devinit wbsd_chip_config(struct wbsd_host* host) | ||
1625 | { | ||
1626 | /* | ||
1627 | * Reset the chip. | ||
1628 | */ | ||
1629 | wbsd_write_config(host, WBSD_CONF_SWRST, 1); | ||
1630 | wbsd_write_config(host, WBSD_CONF_SWRST, 0); | ||
1393 | 1631 | ||
1394 | /* | 1632 | /* |
1395 | * Select SD/MMC function. | 1633 | * Select SD/MMC function. |
@@ -1399,165 +1637,241 @@ static int wbsd_probe(struct device* dev) | |||
1399 | /* | 1637 | /* |
1400 | * Set up card detection. | 1638 | * Set up card detection. |
1401 | */ | 1639 | */ |
1402 | wbsd_write_config(host, WBSD_CONF_PINS, 0x02); | 1640 | wbsd_write_config(host, WBSD_CONF_PINS, WBSD_PINS_DETECT_GP11); |
1403 | 1641 | ||
1404 | /* | 1642 | /* |
1405 | * Configure I/O port. | 1643 | * Configure chip |
1406 | */ | 1644 | */ |
1407 | wbsd_write_config(host, WBSD_CONF_PORT_HI, host->base >> 8); | 1645 | wbsd_write_config(host, WBSD_CONF_PORT_HI, host->base >> 8); |
1408 | wbsd_write_config(host, WBSD_CONF_PORT_LO, host->base & 0xff); | 1646 | wbsd_write_config(host, WBSD_CONF_PORT_LO, host->base & 0xff); |
1409 | |||
1410 | /* | ||
1411 | * Allocate interrupt. | ||
1412 | */ | ||
1413 | ret = request_irq(irq, wbsd_irq, SA_SHIRQ, DRIVER_NAME, host); | ||
1414 | if (ret) | ||
1415 | goto release; | ||
1416 | 1647 | ||
1417 | host->irq = irq; | 1648 | wbsd_write_config(host, WBSD_CONF_IRQ, host->irq); |
1418 | 1649 | ||
1419 | /* | 1650 | if (host->dma >= 0) |
1420 | * Set up tasklets. | 1651 | wbsd_write_config(host, WBSD_CONF_DRQ, host->dma); |
1421 | */ | ||
1422 | tasklet_init(&host->card_tasklet, wbsd_tasklet_card, (unsigned long)host); | ||
1423 | tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo, (unsigned long)host); | ||
1424 | tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc, (unsigned long)host); | ||
1425 | tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout, (unsigned long)host); | ||
1426 | tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, (unsigned long)host); | ||
1427 | tasklet_init(&host->block_tasklet, wbsd_tasklet_block, (unsigned long)host); | ||
1428 | 1652 | ||
1429 | /* | 1653 | /* |
1430 | * Configure interrupt. | 1654 | * Enable and power up chip. |
1431 | */ | 1655 | */ |
1432 | wbsd_write_config(host, WBSD_CONF_IRQ, host->irq); | 1656 | wbsd_write_config(host, WBSD_CONF_ENABLE, 1); |
1657 | wbsd_write_config(host, WBSD_CONF_POWER, 0x20); | ||
1658 | } | ||
1659 | |||
1660 | /* | ||
1661 | * Check that configured resources are correct. | ||
1662 | */ | ||
1663 | |||
1664 | static int __devinit wbsd_chip_validate(struct wbsd_host* host) | ||
1665 | { | ||
1666 | int base, irq, dma; | ||
1433 | 1667 | ||
1434 | /* | 1668 | /* |
1435 | * Allocate DMA. | 1669 | * Select SD/MMC function. |
1436 | */ | 1670 | */ |
1437 | wbsd_init_dma(host); | 1671 | wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD); |
1438 | 1672 | ||
1439 | /* | 1673 | /* |
1440 | * If all went well, then configure DMA. | 1674 | * Read configuration. |
1441 | */ | 1675 | */ |
1442 | if (host->dma >= 0) | 1676 | base = wbsd_read_config(host, WBSD_CONF_PORT_HI) << 8; |
1443 | wbsd_write_config(host, WBSD_CONF_DRQ, host->dma); | 1677 | base |= wbsd_read_config(host, WBSD_CONF_PORT_LO); |
1444 | 1678 | ||
1445 | /* | 1679 | irq = wbsd_read_config(host, WBSD_CONF_IRQ); |
1446 | * Maximum number of segments. Worst case is one sector per segment | 1680 | |
1447 | * so this will be 64kB/512. | 1681 | dma = wbsd_read_config(host, WBSD_CONF_DRQ); |
1448 | */ | ||
1449 | mmc->max_hw_segs = 128; | ||
1450 | mmc->max_phys_segs = 128; | ||
1451 | 1682 | ||
1452 | /* | 1683 | /* |
1453 | * Maximum number of sectors in one transfer. Also limited by 64kB | 1684 | * Validate against given configuration. |
1454 | * buffer. | ||
1455 | */ | 1685 | */ |
1456 | mmc->max_sectors = 128; | 1686 | if (base != host->base) |
1687 | return 0; | ||
1688 | if (irq != host->irq) | ||
1689 | return 0; | ||
1690 | if ((dma != host->dma) && (host->dma != -1)) | ||
1691 | return 0; | ||
1692 | |||
1693 | return 1; | ||
1694 | } | ||
1695 | |||
1696 | /*****************************************************************************\ | ||
1697 | * * | ||
1698 | * Devices setup and shutdown * | ||
1699 | * * | ||
1700 | \*****************************************************************************/ | ||
1701 | |||
1702 | static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma, | ||
1703 | int pnp) | ||
1704 | { | ||
1705 | struct wbsd_host* host = NULL; | ||
1706 | struct mmc_host* mmc = NULL; | ||
1707 | int ret; | ||
1708 | |||
1709 | ret = wbsd_alloc_mmc(dev); | ||
1710 | if (ret) | ||
1711 | return ret; | ||
1712 | |||
1713 | mmc = dev_get_drvdata(dev); | ||
1714 | host = mmc_priv(mmc); | ||
1457 | 1715 | ||
1458 | /* | 1716 | /* |
1459 | * Maximum segment size. Could be one segment with the maximum number | 1717 | * Scan for hardware. |
1460 | * of segments. | ||
1461 | */ | 1718 | */ |
1462 | mmc->max_seg_size = mmc->max_sectors * 512; | 1719 | ret = wbsd_scan(host); |
1720 | if (ret) | ||
1721 | { | ||
1722 | if (pnp && (ret == -ENODEV)) | ||
1723 | { | ||
1724 | printk(KERN_WARNING DRIVER_NAME | ||
1725 | ": Unable to confirm device presence. You may " | ||
1726 | "experience lock-ups.\n"); | ||
1727 | } | ||
1728 | else | ||
1729 | { | ||
1730 | wbsd_free_mmc(dev); | ||
1731 | return ret; | ||
1732 | } | ||
1733 | } | ||
1463 | 1734 | ||
1464 | /* | 1735 | /* |
1465 | * Enable chip. | 1736 | * Request resources. |
1466 | */ | 1737 | */ |
1467 | wbsd_write_config(host, WBSD_CONF_ENABLE, 1); | 1738 | ret = wbsd_request_resources(host, io, irq, dma); |
1739 | if (ret) | ||
1740 | { | ||
1741 | wbsd_release_resources(host); | ||
1742 | wbsd_free_mmc(dev); | ||
1743 | return ret; | ||
1744 | } | ||
1468 | 1745 | ||
1469 | /* | 1746 | /* |
1470 | * Power up chip. | 1747 | * See if chip needs to be configured. |
1471 | */ | 1748 | */ |
1472 | wbsd_write_config(host, WBSD_CONF_POWER, 0x20); | 1749 | if (pnp && (host->config != 0)) |
1750 | { | ||
1751 | if (!wbsd_chip_validate(host)) | ||
1752 | { | ||
1753 | printk(KERN_WARNING DRIVER_NAME | ||
1754 | ": PnP active but chip not configured! " | ||
1755 | "You probably have a buggy BIOS. " | ||
1756 | "Configuring chip manually.\n"); | ||
1757 | wbsd_chip_config(host); | ||
1758 | } | ||
1759 | } | ||
1760 | else | ||
1761 | wbsd_chip_config(host); | ||
1473 | 1762 | ||
1474 | /* | 1763 | /* |
1475 | * Power Management stuff. No idea how this works. | 1764 | * Power Management stuff. No idea how this works. |
1476 | * Not tested. | 1765 | * Not tested. |
1477 | */ | 1766 | */ |
1478 | #ifdef CONFIG_PM | 1767 | #ifdef CONFIG_PM |
1479 | wbsd_write_config(host, WBSD_CONF_PME, 0xA0); | 1768 | if (host->config) |
1769 | wbsd_write_config(host, WBSD_CONF_PME, 0xA0); | ||
1480 | #endif | 1770 | #endif |
1771 | /* | ||
1772 | * Allow device to initialise itself properly. | ||
1773 | */ | ||
1774 | mdelay(5); | ||
1481 | 1775 | ||
1482 | /* | 1776 | /* |
1483 | * Reset the chip into a known state. | 1777 | * Reset the chip into a known state. |
1484 | */ | 1778 | */ |
1485 | wbsd_init_device(host); | 1779 | wbsd_init_device(host); |
1486 | 1780 | ||
1487 | dev_set_drvdata(dev, mmc); | ||
1488 | |||
1489 | /* | ||
1490 | * Add host to MMC layer. | ||
1491 | */ | ||
1492 | mmc_add_host(mmc); | 1781 | mmc_add_host(mmc); |
1493 | 1782 | ||
1494 | printk(KERN_INFO "%s: W83L51xD id %x at 0x%x irq %d dma %d\n", | 1783 | printk(KERN_INFO "%s: W83L51xD", mmc->host_name); |
1495 | mmc->host_name, (int)host->chip_id, (int)host->base, | 1784 | if (host->chip_id != 0) |
1496 | (int)host->irq, (int)host->dma); | 1785 | printk(" id %x", (int)host->chip_id); |
1786 | printk(" at 0x%x irq %d", (int)host->base, (int)host->irq); | ||
1787 | if (host->dma >= 0) | ||
1788 | printk(" dma %d", (int)host->dma); | ||
1789 | else | ||
1790 | printk(" FIFO"); | ||
1791 | if (pnp) | ||
1792 | printk(" PnP"); | ||
1793 | printk("\n"); | ||
1497 | 1794 | ||
1498 | return 0; | 1795 | return 0; |
1499 | |||
1500 | release: | ||
1501 | wbsd_release_regions(host); | ||
1502 | |||
1503 | freemmc: | ||
1504 | mmc_free_host(mmc); | ||
1505 | |||
1506 | return ret; | ||
1507 | } | 1796 | } |
1508 | 1797 | ||
1509 | /* | 1798 | static void __devexit wbsd_shutdown(struct device* dev, int pnp) |
1510 | * Device remove | ||
1511 | */ | ||
1512 | |||
1513 | static int wbsd_remove(struct device* dev) | ||
1514 | { | 1799 | { |
1515 | struct mmc_host* mmc = dev_get_drvdata(dev); | 1800 | struct mmc_host* mmc = dev_get_drvdata(dev); |
1516 | struct wbsd_host* host; | 1801 | struct wbsd_host* host; |
1517 | 1802 | ||
1518 | if (!mmc) | 1803 | if (!mmc) |
1519 | return 0; | 1804 | return; |
1520 | 1805 | ||
1521 | host = mmc_priv(mmc); | 1806 | host = mmc_priv(mmc); |
1522 | 1807 | ||
1523 | /* | ||
1524 | * Unregister host with MMC layer. | ||
1525 | */ | ||
1526 | mmc_remove_host(mmc); | 1808 | mmc_remove_host(mmc); |
1527 | 1809 | ||
1528 | /* | 1810 | if (!pnp) |
1529 | * Power down the SD/MMC function. | 1811 | { |
1530 | */ | 1812 | /* |
1531 | wbsd_unlock_config(host); | 1813 | * Power down the SD/MMC function. |
1532 | wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD); | 1814 | */ |
1533 | wbsd_write_config(host, WBSD_CONF_ENABLE, 0); | 1815 | wbsd_unlock_config(host); |
1534 | wbsd_lock_config(host); | 1816 | wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD); |
1817 | wbsd_write_config(host, WBSD_CONF_ENABLE, 0); | ||
1818 | wbsd_lock_config(host); | ||
1819 | } | ||
1535 | 1820 | ||
1536 | /* | 1821 | wbsd_release_resources(host); |
1537 | * Free resources. | ||
1538 | */ | ||
1539 | if (host->dma_buffer) | ||
1540 | kfree(host->dma_buffer); | ||
1541 | 1822 | ||
1542 | if (host->dma >= 0) | 1823 | wbsd_free_mmc(dev); |
1543 | free_dma(host->dma); | 1824 | } |
1544 | 1825 | ||
1545 | free_irq(host->irq, host); | 1826 | /* |
1827 | * Non-PnP | ||
1828 | */ | ||
1829 | |||
1830 | static int __devinit wbsd_probe(struct device* dev) | ||
1831 | { | ||
1832 | return wbsd_init(dev, io, irq, dma, 0); | ||
1833 | } | ||
1834 | |||
1835 | static int __devexit wbsd_remove(struct device* dev) | ||
1836 | { | ||
1837 | wbsd_shutdown(dev, 0); | ||
1838 | |||
1839 | return 0; | ||
1840 | } | ||
1841 | |||
1842 | /* | ||
1843 | * PnP | ||
1844 | */ | ||
1845 | |||
1846 | #ifdef CONFIG_PNP | ||
1847 | |||
1848 | static int __devinit | ||
1849 | wbsd_pnp_probe(struct pnp_dev * pnpdev, const struct pnp_device_id *dev_id) | ||
1850 | { | ||
1851 | int io, irq, dma; | ||
1546 | 1852 | ||
1547 | tasklet_kill(&host->card_tasklet); | 1853 | /* |
1548 | tasklet_kill(&host->fifo_tasklet); | 1854 | * Get resources from PnP layer. |
1549 | tasklet_kill(&host->crc_tasklet); | 1855 | */ |
1550 | tasklet_kill(&host->timeout_tasklet); | 1856 | io = pnp_port_start(pnpdev, 0); |
1551 | tasklet_kill(&host->finish_tasklet); | 1857 | irq = pnp_irq(pnpdev, 0); |
1552 | tasklet_kill(&host->block_tasklet); | 1858 | if (pnp_dma_valid(pnpdev, 0)) |
1859 | dma = pnp_dma(pnpdev, 0); | ||
1860 | else | ||
1861 | dma = -1; | ||
1553 | 1862 | ||
1554 | wbsd_release_regions(host); | 1863 | DBGF("PnP resources: port %3x irq %d dma %d\n", io, irq, dma); |
1555 | 1864 | ||
1556 | mmc_free_host(mmc); | 1865 | return wbsd_init(&pnpdev->dev, io, irq, dma, 1); |
1866 | } | ||
1557 | 1867 | ||
1558 | return 0; | 1868 | static void __devexit wbsd_pnp_remove(struct pnp_dev * dev) |
1869 | { | ||
1870 | wbsd_shutdown(&dev->dev, 1); | ||
1559 | } | 1871 | } |
1560 | 1872 | ||
1873 | #endif /* CONFIG_PNP */ | ||
1874 | |||
1561 | /* | 1875 | /* |
1562 | * Power management | 1876 | * Power management |
1563 | */ | 1877 | */ |
@@ -1581,17 +1895,7 @@ static int wbsd_resume(struct device *dev, u32 level) | |||
1581 | #define wbsd_resume NULL | 1895 | #define wbsd_resume NULL |
1582 | #endif | 1896 | #endif |
1583 | 1897 | ||
1584 | static void wbsd_release(struct device *dev) | 1898 | static struct platform_device *wbsd_device; |
1585 | { | ||
1586 | } | ||
1587 | |||
1588 | static struct platform_device wbsd_device = { | ||
1589 | .name = DRIVER_NAME, | ||
1590 | .id = -1, | ||
1591 | .dev = { | ||
1592 | .release = wbsd_release, | ||
1593 | }, | ||
1594 | }; | ||
1595 | 1899 | ||
1596 | static struct device_driver wbsd_driver = { | 1900 | static struct device_driver wbsd_driver = { |
1597 | .name = DRIVER_NAME, | 1901 | .name = DRIVER_NAME, |
@@ -1603,6 +1907,17 @@ static struct device_driver wbsd_driver = { | |||
1603 | .resume = wbsd_resume, | 1907 | .resume = wbsd_resume, |
1604 | }; | 1908 | }; |
1605 | 1909 | ||
1910 | #ifdef CONFIG_PNP | ||
1911 | |||
1912 | static struct pnp_driver wbsd_pnp_driver = { | ||
1913 | .name = DRIVER_NAME, | ||
1914 | .id_table = pnp_dev_table, | ||
1915 | .probe = wbsd_pnp_probe, | ||
1916 | .remove = wbsd_pnp_remove, | ||
1917 | }; | ||
1918 | |||
1919 | #endif /* CONFIG_PNP */ | ||
1920 | |||
1606 | /* | 1921 | /* |
1607 | * Module loading/unloading | 1922 | * Module loading/unloading |
1608 | */ | 1923 | */ |
@@ -1615,29 +1930,57 @@ static int __init wbsd_drv_init(void) | |||
1615 | ": Winbond W83L51xD SD/MMC card interface driver, " | 1930 | ": Winbond W83L51xD SD/MMC card interface driver, " |
1616 | DRIVER_VERSION "\n"); | 1931 | DRIVER_VERSION "\n"); |
1617 | printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); | 1932 | printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); |
1618 | |||
1619 | result = driver_register(&wbsd_driver); | ||
1620 | if (result < 0) | ||
1621 | return result; | ||
1622 | 1933 | ||
1623 | result = platform_device_register(&wbsd_device); | 1934 | #ifdef CONFIG_PNP |
1624 | if (result < 0) | 1935 | |
1625 | return result; | 1936 | if (!nopnp) |
1937 | { | ||
1938 | result = pnp_register_driver(&wbsd_pnp_driver); | ||
1939 | if (result < 0) | ||
1940 | return result; | ||
1941 | } | ||
1942 | |||
1943 | #endif /* CONFIG_PNP */ | ||
1944 | |||
1945 | if (nopnp) | ||
1946 | { | ||
1947 | result = driver_register(&wbsd_driver); | ||
1948 | if (result < 0) | ||
1949 | return result; | ||
1950 | |||
1951 | wbsd_device = platform_device_register_simple(DRIVER_NAME, -1, | ||
1952 | NULL, 0); | ||
1953 | if (IS_ERR(wbsd_device)) | ||
1954 | return PTR_ERR(wbsd_device); | ||
1955 | } | ||
1626 | 1956 | ||
1627 | return 0; | 1957 | return 0; |
1628 | } | 1958 | } |
1629 | 1959 | ||
1630 | static void __exit wbsd_drv_exit(void) | 1960 | static void __exit wbsd_drv_exit(void) |
1631 | { | 1961 | { |
1632 | platform_device_unregister(&wbsd_device); | 1962 | #ifdef CONFIG_PNP |
1963 | |||
1964 | if (!nopnp) | ||
1965 | pnp_unregister_driver(&wbsd_pnp_driver); | ||
1633 | 1966 | ||
1634 | driver_unregister(&wbsd_driver); | 1967 | #endif /* CONFIG_PNP */ |
1968 | |||
1969 | if (nopnp) | ||
1970 | { | ||
1971 | platform_device_unregister(wbsd_device); | ||
1972 | |||
1973 | driver_unregister(&wbsd_driver); | ||
1974 | } | ||
1635 | 1975 | ||
1636 | DBG("unloaded\n"); | 1976 | DBG("unloaded\n"); |
1637 | } | 1977 | } |
1638 | 1978 | ||
1639 | module_init(wbsd_drv_init); | 1979 | module_init(wbsd_drv_init); |
1640 | module_exit(wbsd_drv_exit); | 1980 | module_exit(wbsd_drv_exit); |
1981 | #ifdef CONFIG_PNP | ||
1982 | module_param(nopnp, uint, 0444); | ||
1983 | #endif | ||
1641 | module_param(io, uint, 0444); | 1984 | module_param(io, uint, 0444); |
1642 | module_param(irq, uint, 0444); | 1985 | module_param(irq, uint, 0444); |
1643 | module_param(dma, int, 0444); | 1986 | module_param(dma, int, 0444); |
@@ -1646,6 +1989,9 @@ MODULE_LICENSE("GPL"); | |||
1646 | MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver"); | 1989 | MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver"); |
1647 | MODULE_VERSION(DRIVER_VERSION); | 1990 | MODULE_VERSION(DRIVER_VERSION); |
1648 | 1991 | ||
1992 | #ifdef CONFIG_PNP | ||
1993 | MODULE_PARM_DESC(nopnp, "Scan for device instead of relying on PNP. (default 0)"); | ||
1994 | #endif | ||
1649 | MODULE_PARM_DESC(io, "I/O base to allocate. Must be 8 byte aligned. (default 0x248)"); | 1995 | MODULE_PARM_DESC(io, "I/O base to allocate. Must be 8 byte aligned. (default 0x248)"); |
1650 | MODULE_PARM_DESC(irq, "IRQ to allocate. (default 6)"); | 1996 | MODULE_PARM_DESC(irq, "IRQ to allocate. (default 6)"); |
1651 | MODULE_PARM_DESC(dma, "DMA channel to allocate. -1 for no DMA. (default 2)"); | 1997 | MODULE_PARM_DESC(dma, "DMA channel to allocate. -1 for no DMA. (default 2)"); |
diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/wbsd.h index fdc03b56a81f..864f30828d01 100644 --- a/drivers/mmc/wbsd.h +++ b/drivers/mmc/wbsd.h | |||
@@ -35,6 +35,12 @@ const int valid_ids[] = { | |||
35 | 35 | ||
36 | #define DEVICE_SD 0x03 | 36 | #define DEVICE_SD 0x03 |
37 | 37 | ||
38 | #define WBSD_PINS_DAT3_HI 0x20 | ||
39 | #define WBSD_PINS_DAT3_OUT 0x10 | ||
40 | #define WBSD_PINS_GP11_HI 0x04 | ||
41 | #define WBSD_PINS_DETECT_GP11 0x02 | ||
42 | #define WBSD_PINS_DETECT_DAT3 0x01 | ||
43 | |||
38 | #define WBSD_CMDR 0x00 | 44 | #define WBSD_CMDR 0x00 |
39 | #define WBSD_DFR 0x01 | 45 | #define WBSD_DFR 0x01 |
40 | #define WBSD_EIR 0x02 | 46 | #define WBSD_EIR 0x02 |
@@ -133,6 +139,7 @@ const int valid_ids[] = { | |||
133 | #define WBSD_CRC_OK 0x05 /* S010E (00101) */ | 139 | #define WBSD_CRC_OK 0x05 /* S010E (00101) */ |
134 | #define WBSD_CRC_FAIL 0x0B /* S101E (01011) */ | 140 | #define WBSD_CRC_FAIL 0x0B /* S101E (01011) */ |
135 | 141 | ||
142 | #define WBSD_DMA_SIZE 65536 | ||
136 | 143 | ||
137 | struct wbsd_host | 144 | struct wbsd_host |
138 | { | 145 | { |
@@ -140,6 +147,11 @@ struct wbsd_host | |||
140 | 147 | ||
141 | spinlock_t lock; /* Mutex */ | 148 | spinlock_t lock; /* Mutex */ |
142 | 149 | ||
150 | int flags; /* Driver states */ | ||
151 | |||
152 | #define WBSD_FCARD_PRESENT (1<<0) /* Card is present */ | ||
153 | #define WBSD_FIGNORE_DETECT (1<<1) /* Ignore card detection */ | ||
154 | |||
143 | struct mmc_request* mrq; /* Current request */ | 155 | struct mmc_request* mrq; /* Current request */ |
144 | 156 | ||
145 | u8 isr; /* Accumulated ISR */ | 157 | u8 isr; /* Accumulated ISR */ |
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 6202b10dbb4d..e038d55e4f6f 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile | |||
@@ -187,7 +187,7 @@ obj-$(CONFIG_TR) += tokenring/ | |||
187 | obj-$(CONFIG_WAN) += wan/ | 187 | obj-$(CONFIG_WAN) += wan/ |
188 | obj-$(CONFIG_ARCNET) += arcnet/ | 188 | obj-$(CONFIG_ARCNET) += arcnet/ |
189 | obj-$(CONFIG_NET_PCMCIA) += pcmcia/ | 189 | obj-$(CONFIG_NET_PCMCIA) += pcmcia/ |
190 | obj-$(CONFIG_NET_WIRELESS) += wireless/ | 190 | obj-$(CONFIG_NET_RADIO) += wireless/ |
191 | obj-$(CONFIG_NET_TULIP) += tulip/ | 191 | obj-$(CONFIG_NET_TULIP) += tulip/ |
192 | obj-$(CONFIG_HAMRADIO) += hamradio/ | 192 | obj-$(CONFIG_HAMRADIO) += hamradio/ |
193 | obj-$(CONFIG_IRDA) += irda/ | 193 | obj-$(CONFIG_IRDA) += irda/ |
diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index ab44358ddbfc..6482d994d489 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c | |||
@@ -1595,7 +1595,7 @@ static struct ethtool_ops emac_ethtool_ops = { | |||
1595 | static int emac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | 1595 | static int emac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) |
1596 | { | 1596 | { |
1597 | struct ocp_enet_private *fep = dev->priv; | 1597 | struct ocp_enet_private *fep = dev->priv; |
1598 | uint *data = (uint *) & rq->ifr_ifru; | 1598 | uint16_t *data = (uint16_t *) & rq->ifr_ifru; |
1599 | 1599 | ||
1600 | switch (cmd) { | 1600 | switch (cmd) { |
1601 | case SIOCGMIIPHY: | 1601 | case SIOCGMIIPHY: |
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index d098b3ba3538..e0ae3ed6e578 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c | |||
@@ -1104,7 +1104,7 @@ static void set_rx_mode(struct net_device *dev) | |||
1104 | if (entry != 0) { | 1104 | if (entry != 0) { |
1105 | /* Avoid a chip errata by prefixing a dummy entry. Don't do | 1105 | /* Avoid a chip errata by prefixing a dummy entry. Don't do |
1106 | this on the ULI526X as it triggers a different problem */ | 1106 | this on the ULI526X as it triggers a different problem */ |
1107 | if (!(tp->chip_id == ULI526X && (tp->revision = 0x40 || tp->revision == 0x50))) { | 1107 | if (!(tp->chip_id == ULI526X && (tp->revision == 0x40 || tp->revision == 0x50))) { |
1108 | tp->tx_buffers[entry].skb = NULL; | 1108 | tp->tx_buffers[entry].skb = NULL; |
1109 | tp->tx_buffers[entry].mapping = 0; | 1109 | tp->tx_buffers[entry].mapping = 0; |
1110 | tp->tx_ring[entry].length = | 1110 | tp->tx_ring[entry].length = |
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 0aaa12c0c098..1d3231cc471a 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig | |||
@@ -323,7 +323,7 @@ config PRISM54 | |||
323 | For a complete list of supported cards visit <http://prism54.org>. | 323 | For a complete list of supported cards visit <http://prism54.org>. |
324 | Here is the latest confirmed list of supported cards: | 324 | Here is the latest confirmed list of supported cards: |
325 | 325 | ||
326 | 3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72 | 326 | 3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72 (version 1) |
327 | Allnet ALL0271 PCI Card | 327 | Allnet ALL0271 PCI Card |
328 | Compex WL54G Cardbus Card | 328 | Compex WL54G Cardbus Card |
329 | Corega CG-WLCB54GT Cardbus Card | 329 | Corega CG-WLCB54GT Cardbus Card |
diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c index 33fbda79f350..0b10169961eb 100644 --- a/drivers/serial/21285.c +++ b/drivers/serial/21285.c | |||
@@ -126,18 +126,8 @@ static irqreturn_t serial21285_rx_chars(int irq, void *dev_id, struct pt_regs *r | |||
126 | flag = TTY_FRAME; | 126 | flag = TTY_FRAME; |
127 | } | 127 | } |
128 | 128 | ||
129 | if ((rxs & port->ignore_status_mask) == 0) { | 129 | uart_insert_char(port, rxs, RXSTAT_OVERRUN, ch, flag); |
130 | tty_insert_flip_char(tty, ch, flag); | 130 | |
131 | } | ||
132 | if ((rxs & RXSTAT_OVERRUN) && | ||
133 | tty->flip.count < TTY_FLIPBUF_SIZE) { | ||
134 | /* | ||
135 | * Overrun is special, since it's reported | ||
136 | * immediately, and doesn't affect the current | ||
137 | * character. | ||
138 | */ | ||
139 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
140 | } | ||
141 | status = *CSR_UARTFLG; | 131 | status = *CSR_UARTFLG; |
142 | } | 132 | } |
143 | tty_flip_buffer_push(tty); | 133 | tty_flip_buffer_push(tty); |
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 0d9358608fdf..3bbf0cc6e53f 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c | |||
@@ -1122,18 +1122,9 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs) | |||
1122 | } | 1122 | } |
1123 | if (uart_handle_sysrq_char(&up->port, ch, regs)) | 1123 | if (uart_handle_sysrq_char(&up->port, ch, regs)) |
1124 | goto ignore_char; | 1124 | goto ignore_char; |
1125 | if ((lsr & up->port.ignore_status_mask) == 0) { | 1125 | |
1126 | tty_insert_flip_char(tty, ch, flag); | 1126 | uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag); |
1127 | } | 1127 | |
1128 | if ((lsr & UART_LSR_OE) && | ||
1129 | tty->flip.count < TTY_FLIPBUF_SIZE) { | ||
1130 | /* | ||
1131 | * Overrun is special, since it's reported | ||
1132 | * immediately, and doesn't affect the current | ||
1133 | * character. | ||
1134 | */ | ||
1135 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
1136 | } | ||
1137 | ignore_char: | 1128 | ignore_char: |
1138 | lsr = serial_inp(up, UART_LSR); | 1129 | lsr = serial_inp(up, UART_LSR); |
1139 | } while ((lsr & UART_LSR_DR) && (max_count-- > 0)); | 1130 | } while ((lsr & UART_LSR_DR) && (max_count-- > 0)); |
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index f2a5e2933c47..2884b310e54d 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c | |||
@@ -198,18 +198,8 @@ pl010_rx_chars(struct uart_port *port) | |||
198 | if (uart_handle_sysrq_char(port, ch, regs)) | 198 | if (uart_handle_sysrq_char(port, ch, regs)) |
199 | goto ignore_char; | 199 | goto ignore_char; |
200 | 200 | ||
201 | if ((rsr & port->ignore_status_mask) == 0) { | 201 | uart_insert_char(port, rsr, UART01x_RSR_OE, ch, flag); |
202 | tty_insert_flip_char(tty, ch, flag); | 202 | |
203 | } | ||
204 | if ((rsr & UART01x_RSR_OE) && | ||
205 | tty->flip.count < TTY_FLIPBUF_SIZE) { | ||
206 | /* | ||
207 | * Overrun is special, since it's reported | ||
208 | * immediately, and doesn't affect the current | ||
209 | * character | ||
210 | */ | ||
211 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
212 | } | ||
213 | ignore_char: | 203 | ignore_char: |
214 | status = UART_GET_FR(port); | 204 | status = UART_GET_FR(port); |
215 | } | 205 | } |
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index d5cbef3fe8b6..7db88ee18f75 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c | |||
@@ -163,18 +163,8 @@ pl011_rx_chars(struct uart_amba_port *uap) | |||
163 | if (uart_handle_sysrq_char(&uap->port, ch, regs)) | 163 | if (uart_handle_sysrq_char(&uap->port, ch, regs)) |
164 | goto ignore_char; | 164 | goto ignore_char; |
165 | 165 | ||
166 | if ((rsr & uap->port.ignore_status_mask) == 0) { | 166 | uart_insert_char(&uap->port, rsr, UART01x_RSR_OE, ch, flag); |
167 | tty_insert_flip_char(tty, ch, flag); | 167 | |
168 | } | ||
169 | if ((rsr & UART01x_RSR_OE) && | ||
170 | tty->flip.count < TTY_FLIPBUF_SIZE) { | ||
171 | /* | ||
172 | * Overrun is special, since it's reported | ||
173 | * immediately, and doesn't affect the current | ||
174 | * character | ||
175 | */ | ||
176 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
177 | } | ||
178 | ignore_char: | 168 | ignore_char: |
179 | status = readw(uap->port.membase + UART01x_FR); | 169 | status = readw(uap->port.membase + UART01x_FR); |
180 | } | 170 | } |
diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c index 6242f3090a96..e92522b33c48 100644 --- a/drivers/serial/clps711x.c +++ b/drivers/serial/clps711x.c | |||
@@ -143,10 +143,7 @@ static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *re | |||
143 | * CHECK: does overrun affect the current character? | 143 | * CHECK: does overrun affect the current character? |
144 | * ASSUMPTION: it does not. | 144 | * ASSUMPTION: it does not. |
145 | */ | 145 | */ |
146 | if ((ch & port->ignore_status_mask & ~RXSTAT_OVERRUN) == 0) | 146 | uart_insert_char(port, ch, UARTDR_OVERR, ch, flg); |
147 | tty_insert_flip_char(tty, ch, flg); | ||
148 | if ((ch & ~port->ignore_status_mask & RXSTAT_OVERRUN) == 0) | ||
149 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
150 | 147 | ||
151 | ignore_char: | 148 | ignore_char: |
152 | status = clps_readl(SYSFLG(port)); | 149 | status = clps_readl(SYSFLG(port)); |
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index 51d8a49f4477..9dc151d8fa61 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c | |||
@@ -161,20 +161,12 @@ receive_chars(struct uart_pxa_port *up, int *status, struct pt_regs *regs) | |||
161 | else if (*status & UART_LSR_FE) | 161 | else if (*status & UART_LSR_FE) |
162 | flag = TTY_FRAME; | 162 | flag = TTY_FRAME; |
163 | } | 163 | } |
164 | |||
164 | if (uart_handle_sysrq_char(&up->port, ch, regs)) | 165 | if (uart_handle_sysrq_char(&up->port, ch, regs)) |
165 | goto ignore_char; | 166 | goto ignore_char; |
166 | if ((*status & up->port.ignore_status_mask) == 0) { | 167 | |
167 | tty_insert_flip_char(tty, ch, flag); | 168 | uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag); |
168 | } | 169 | |
169 | if ((*status & UART_LSR_OE) && | ||
170 | tty->flip.count < TTY_FLIPBUF_SIZE) { | ||
171 | /* | ||
172 | * Overrun is special, since it's reported | ||
173 | * immediately, and doesn't affect the current | ||
174 | * character. | ||
175 | */ | ||
176 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
177 | } | ||
178 | ignore_char: | 170 | ignore_char: |
179 | *status = serial_in(up, UART_LSR); | 171 | *status = serial_in(up, UART_LSR); |
180 | } while ((*status & UART_LSR_DR) && (max_count-- > 0)); | 172 | } while ((*status & UART_LSR_DR) && (max_count-- > 0)); |
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index 435750d40a47..2a9f7ade2c9d 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c | |||
@@ -394,20 +394,7 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id, struct pt_regs *regs) | |||
394 | if (uart_handle_sysrq_char(port, ch, regs)) | 394 | if (uart_handle_sysrq_char(port, ch, regs)) |
395 | goto ignore_char; | 395 | goto ignore_char; |
396 | 396 | ||
397 | if ((uerstat & port->ignore_status_mask) == 0) { | 397 | uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, ch, flag); |
398 | tty_insert_flip_char(tty, ch, flag); | ||
399 | } | ||
400 | |||
401 | if ((uerstat & S3C2410_UERSTAT_OVERRUN) && | ||
402 | tty->flip.count < TTY_FLIPBUF_SIZE) { | ||
403 | /* | ||
404 | * Overrun is special, since it's reported | ||
405 | * immediately, and doesn't affect the current | ||
406 | * character. | ||
407 | */ | ||
408 | |||
409 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
410 | } | ||
411 | 398 | ||
412 | ignore_char: | 399 | ignore_char: |
413 | continue; | 400 | continue; |
diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c index 157218bc6c6f..22565a67a57c 100644 --- a/drivers/serial/sa1100.c +++ b/drivers/serial/sa1100.c | |||
@@ -237,10 +237,7 @@ sa1100_rx_chars(struct sa1100_port *sport, struct pt_regs *regs) | |||
237 | if (uart_handle_sysrq_char(&sport->port, ch, regs)) | 237 | if (uart_handle_sysrq_char(&sport->port, ch, regs)) |
238 | goto ignore_char; | 238 | goto ignore_char; |
239 | 239 | ||
240 | if ((status & port->ignore_status_mask & ~UTSR1_TO_SM(UTSR1_ROR)) == 0) | 240 | uart_insert_char(&sport->port, status, UTSR1_TO_SM(UTSR1_ROR), ch, flg); |
241 | tty_insert_flip_char(tty, ch, flg); | ||
242 | if (status & ~port->ignore_status_mask & UTSR1_TO_SM(UTSR1_ROR)) | ||
243 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
244 | 241 | ||
245 | ignore_char: | 242 | ignore_char: |
246 | status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) | | 243 | status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) | |
diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c index 85cfa08d3bad..56f269b6bfb1 100644 --- a/drivers/serial/serial_lh7a40x.c +++ b/drivers/serial/serial_lh7a40x.c | |||
@@ -190,18 +190,7 @@ lh7a40xuart_rx_chars (struct uart_port* port) | |||
190 | if (uart_handle_sysrq_char (port, (unsigned char) data, regs)) | 190 | if (uart_handle_sysrq_char (port, (unsigned char) data, regs)) |
191 | continue; | 191 | continue; |
192 | 192 | ||
193 | if ((data & port->ignore_status_mask) == 0) { | 193 | uart_insert_char(port, data, RxOverrunError, data, flag); |
194 | tty_insert_flip_char(tty, data, flag); | ||
195 | } | ||
196 | if ((data & RxOverrunError) | ||
197 | && tty->flip.count < TTY_FLIPBUF_SIZE) { | ||
198 | /* | ||
199 | * Overrun is special, since it's reported | ||
200 | * immediately, and doesn't affect the current | ||
201 | * character | ||
202 | */ | ||
203 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
204 | } | ||
205 | } | 194 | } |
206 | tty_flip_buffer_push (tty); | 195 | tty_flip_buffer_push (tty); |
207 | return; | 196 | return; |
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c index 37b2ef297cbe..3f1051a4a13f 100644 --- a/drivers/serial/serial_txx9.c +++ b/drivers/serial/serial_txx9.c | |||
@@ -350,18 +350,9 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r | |||
350 | } | 350 | } |
351 | if (uart_handle_sysrq_char(&up->port, ch, regs)) | 351 | if (uart_handle_sysrq_char(&up->port, ch, regs)) |
352 | goto ignore_char; | 352 | goto ignore_char; |
353 | if ((disr & up->port.ignore_status_mask) == 0) { | 353 | |
354 | tty_insert_flip_char(tty, ch, flag); | 354 | uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag); |
355 | } | 355 | |
356 | if ((disr & TXX9_SIDISR_UOER) && | ||
357 | tty->flip.count < TTY_FLIPBUF_SIZE) { | ||
358 | /* | ||
359 | * Overrun is special, since it's reported | ||
360 | * immediately, and doesn't affect the current | ||
361 | * character. | ||
362 | */ | ||
363 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
364 | } | ||
365 | ignore_char: | 356 | ignore_char: |
366 | disr = sio_in(up, TXX9_SIDISR); | 357 | disr = sio_in(up, TXX9_SIDISR); |
367 | } while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0)); | 358 | } while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0)); |
diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c index 307886199f2f..5d2ceb623e6f 100644 --- a/drivers/serial/vr41xx_siu.c +++ b/drivers/serial/vr41xx_siu.c | |||
@@ -412,10 +412,8 @@ static inline void receive_chars(struct uart_port *port, uint8_t *status, | |||
412 | 412 | ||
413 | if (uart_handle_sysrq_char(port, ch, regs)) | 413 | if (uart_handle_sysrq_char(port, ch, regs)) |
414 | goto ignore_char; | 414 | goto ignore_char; |
415 | if ((lsr & port->ignore_status_mask) == 0) | 415 | |
416 | tty_insert_flip_char(tty, ch, flag); | 416 | uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); |
417 | if ((lsr & UART_LSR_OE) && (tty->flip.count < TTY_FLIPBUF_SIZE)) | ||
418 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
419 | 417 | ||
420 | ignore_char: | 418 | ignore_char: |
421 | lsr = siu_read(port, UART_LSR); | 419 | lsr = siu_read(port, UART_LSR); |
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index ce9423bb2de3..c374be51b041 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -251,7 +251,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec, | |||
251 | } | 251 | } |
252 | 252 | ||
253 | /* Populate argv and envp */ | 253 | /* Populate argv and envp */ |
254 | p = current->mm->arg_start; | 254 | p = current->mm->arg_end = current->mm->arg_start; |
255 | while (argc-- > 0) { | 255 | while (argc-- > 0) { |
256 | size_t len; | 256 | size_t len; |
257 | __put_user((elf_addr_t)p, argv++); | 257 | __put_user((elf_addr_t)p, argv++); |
@@ -1301,7 +1301,7 @@ static void fill_prstatus(struct elf_prstatus *prstatus, | |||
1301 | static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, | 1301 | static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, |
1302 | struct mm_struct *mm) | 1302 | struct mm_struct *mm) |
1303 | { | 1303 | { |
1304 | int i, len; | 1304 | unsigned int i, len; |
1305 | 1305 | ||
1306 | /* first copy the parameters from user space */ | 1306 | /* first copy the parameters from user space */ |
1307 | memset(psinfo, 0, sizeof(struct elf_prpsinfo)); | 1307 | memset(psinfo, 0, sizeof(struct elf_prpsinfo)); |
diff --git a/include/asm-arm/arch-imx/imx-regs.h b/include/asm-arm/arch-imx/imx-regs.h index f32c203952cf..93b840e8fa60 100644 --- a/include/asm-arm/arch-imx/imx-regs.h +++ b/include/asm-arm/arch-imx/imx-regs.h | |||
@@ -228,6 +228,30 @@ | |||
228 | #define PD31_BIN_SPI2_TXD ( GPIO_PORTD | GPIO_BIN | 31 ) | 228 | #define PD31_BIN_SPI2_TXD ( GPIO_PORTD | GPIO_BIN | 31 ) |
229 | 229 | ||
230 | /* | 230 | /* |
231 | * PWM controller | ||
232 | */ | ||
233 | #define PWMC __REG(IMX_PWM_BASE + 0x00) /* PWM Control Register */ | ||
234 | #define PWMS __REG(IMX_PWM_BASE + 0x04) /* PWM Sample Register */ | ||
235 | #define PWMP __REG(IMX_PWM_BASE + 0x08) /* PWM Period Register */ | ||
236 | #define PWMCNT __REG(IMX_PWM_BASE + 0x0C) /* PWM Counter Register */ | ||
237 | |||
238 | #define PWMC_HCTR (0x01<<18) /* Halfword FIFO Data Swapping */ | ||
239 | #define PWMC_BCTR (0x01<<17) /* Byte FIFO Data Swapping */ | ||
240 | #define PWMC_SWR (0x01<<16) /* Software Reset */ | ||
241 | #define PWMC_CLKSRC (0x01<<15) /* Clock Source */ | ||
242 | #define PWMC_PRESCALER(x) (((x-1) & 0x7F) << 8) /* PRESCALER */ | ||
243 | #define PWMC_IRQ (0x01<< 7) /* Interrupt Request */ | ||
244 | #define PWMC_IRQEN (0x01<< 6) /* Interrupt Request Enable */ | ||
245 | #define PWMC_FIFOAV (0x01<< 5) /* FIFO Available */ | ||
246 | #define PWMC_EN (0x01<< 4) /* Enables/Disables the PWM */ | ||
247 | #define PWMC_REPEAT(x) (((x) & 0x03) << 2) /* Sample Repeats */ | ||
248 | #define PWMC_CLKSEL(x) (((x) & 0x03) << 0) /* Clock Selection */ | ||
249 | |||
250 | #define PWMS_SAMPLE(x) ((x) & 0xFFFF) /* Contains a two-sample word */ | ||
251 | #define PWMP_PERIOD(x) ((x) & 0xFFFF) /* Represents the PWM's period */ | ||
252 | #define PWMC_COUNTER(x) ((x) & 0xFFFF) /* Represents the current count value */ | ||
253 | |||
254 | /* | ||
231 | * DMA Controller | 255 | * DMA Controller |
232 | */ | 256 | */ |
233 | #define DCR __REG(IMX_DMAC_BASE +0x00) /* DMA Control Register */ | 257 | #define DCR __REG(IMX_DMAC_BASE +0x00) /* DMA Control Register */ |
diff --git a/include/asm-arm/arch-s3c2410/regs-nand.h b/include/asm-arm/arch-s3c2410/regs-nand.h index c443ac834698..7cff235e667a 100644 --- a/include/asm-arm/arch-s3c2410/regs-nand.h +++ b/include/asm-arm/arch-s3c2410/regs-nand.h | |||
@@ -1,16 +1,17 @@ | |||
1 | /* linux/include/asm-arm/arch-s3c2410/regs-nand.h | 1 | /* linux/include/asm-arm/arch-s3c2410/regs-nand.h |
2 | * | 2 | * |
3 | * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk> | 3 | * Copyright (c) 2004,2005 Simtec Electronics <linux@simtec.co.uk> |
4 | * http://www.simtec.co.uk/products/SWLINUX/ | 4 | * http://www.simtec.co.uk/products/SWLINUX/ |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | * | 9 | * |
10 | * S3C2410 clock register definitions | 10 | * S3C2410 NAND register definitions |
11 | * | 11 | * |
12 | * Changelog: | 12 | * Changelog: |
13 | * 18-Aug-2004 BJD Copied file from 2.4 and updated | 13 | * 18-Aug-2004 BJD Copied file from 2.4 and updated |
14 | * 01-May-2005 BJD Added definitions for s3c2440 controller | ||
14 | */ | 15 | */ |
15 | 16 | ||
16 | #ifndef __ASM_ARM_REGS_NAND | 17 | #ifndef __ASM_ARM_REGS_NAND |
@@ -26,6 +27,22 @@ | |||
26 | #define S3C2410_NFSTAT S3C2410_NFREG(0x10) | 27 | #define S3C2410_NFSTAT S3C2410_NFREG(0x10) |
27 | #define S3C2410_NFECC S3C2410_NFREG(0x14) | 28 | #define S3C2410_NFECC S3C2410_NFREG(0x14) |
28 | 29 | ||
30 | #define S3C2440_NFCONT S3C2410_NFREG(0x04) | ||
31 | #define S3C2440_NFCMD S3C2410_NFREG(0x08) | ||
32 | #define S3C2440_NFADDR S3C2410_NFREG(0x0C) | ||
33 | #define S3C2440_NFDATA S3C2410_NFREG(0x10) | ||
34 | #define S3C2440_NFECCD0 S3C2410_NFREG(0x14) | ||
35 | #define S3C2440_NFECCD1 S3C2410_NFREG(0x18) | ||
36 | #define S3C2440_NFECCD S3C2410_NFREG(0x1C) | ||
37 | #define S3C2440_NFSTAT S3C2410_NFREG(0x20) | ||
38 | #define S3C2440_NFESTAT0 S3C2410_NFREG(0x24) | ||
39 | #define S3C2440_NFESTAT1 S3C2410_NFREG(0x28) | ||
40 | #define S3C2440_NFMECC0 S3C2410_NFREG(0x2C) | ||
41 | #define S3C2440_NFMECC1 S3C2410_NFREG(0x30) | ||
42 | #define S3C2440_NFSECC S3C2410_NFREG(0x34) | ||
43 | #define S3C2440_NFSBLK S3C2410_NFREG(0x38) | ||
44 | #define S3C2440_NFEBLK S3C2410_NFREG(0x3C) | ||
45 | |||
29 | #define S3C2410_NFCONF_EN (1<<15) | 46 | #define S3C2410_NFCONF_EN (1<<15) |
30 | #define S3C2410_NFCONF_512BYTE (1<<14) | 47 | #define S3C2410_NFCONF_512BYTE (1<<14) |
31 | #define S3C2410_NFCONF_4STEP (1<<13) | 48 | #define S3C2410_NFCONF_4STEP (1<<13) |
@@ -37,7 +54,28 @@ | |||
37 | 54 | ||
38 | #define S3C2410_NFSTAT_BUSY (1<<0) | 55 | #define S3C2410_NFSTAT_BUSY (1<<0) |
39 | 56 | ||
40 | /* think ECC can only be 8bit read? */ | 57 | #define S3C2440_NFCONF_BUSWIDTH_8 (0<<0) |
58 | #define S3C2440_NFCONF_BUSWIDTH_16 (1<<0) | ||
59 | #define S3C2440_NFCONF_ADVFLASH (1<<3) | ||
60 | #define S3C2440_NFCONF_TACLS(x) ((x)<<12) | ||
61 | #define S3C2440_NFCONF_TWRPH0(x) ((x)<<8) | ||
62 | #define S3C2440_NFCONF_TWRPH1(x) ((x)<<4) | ||
63 | |||
64 | #define S3C2440_NFCONT_LOCKTIGHT (1<<13) | ||
65 | #define S3C2440_NFCONT_SOFTLOCK (1<<12) | ||
66 | #define S3C2440_NFCONT_ILLEGALACC_EN (1<<10) | ||
67 | #define S3C2440_NFCONT_RNBINT_EN (1<<9) | ||
68 | #define S3C2440_NFCONT_RN_FALLING (1<<8) | ||
69 | #define S3C2440_NFCONT_SPARE_ECCLOCK (1<<6) | ||
70 | #define S3C2440_NFCONT_MAIN_ECCLOCK (1<<5) | ||
71 | #define S3C2440_NFCONT_INITECC (1<<4) | ||
72 | #define S3C2440_NFCONT_nFCE (1<<1) | ||
73 | #define S3C2440_NFCONT_ENABLE (1<<0) | ||
74 | |||
75 | #define S3C2440_NFSTAT_READY (1<<0) | ||
76 | #define S3C2440_NFSTAT_nCE (1<<1) | ||
77 | #define S3C2440_NFSTAT_RnB_CHANGE (1<<2) | ||
78 | #define S3C2440_NFSTAT_ILLEGAL_ACCESS (1<<3) | ||
41 | 79 | ||
42 | #endif /* __ASM_ARM_REGS_NAND */ | 80 | #endif /* __ASM_ARM_REGS_NAND */ |
43 | 81 | ||
diff --git a/include/asm-arm/page.h b/include/asm-arm/page.h index 4ca3a8e9348f..019c45d75730 100644 --- a/include/asm-arm/page.h +++ b/include/asm-arm/page.h | |||
@@ -114,19 +114,8 @@ extern void __cpu_copy_user_page(void *to, const void *from, | |||
114 | unsigned long user); | 114 | unsigned long user); |
115 | #endif | 115 | #endif |
116 | 116 | ||
117 | #define clear_user_page(addr,vaddr,pg) \ | 117 | #define clear_user_page(addr,vaddr,pg) __cpu_clear_user_page(addr, vaddr) |
118 | do { \ | 118 | #define copy_user_page(to,from,vaddr,pg) __cpu_copy_user_page(to, from, vaddr) |
119 | preempt_disable(); \ | ||
120 | __cpu_clear_user_page(addr, vaddr); \ | ||
121 | preempt_enable(); \ | ||
122 | } while (0) | ||
123 | |||
124 | #define copy_user_page(to,from,vaddr,pg) \ | ||
125 | do { \ | ||
126 | preempt_disable(); \ | ||
127 | __cpu_copy_user_page(to, from, vaddr); \ | ||
128 | preempt_enable(); \ | ||
129 | } while (0) | ||
130 | 119 | ||
131 | #define clear_page(page) memzero((void *)(page), PAGE_SIZE) | 120 | #define clear_page(page) memzero((void *)(page), PAGE_SIZE) |
132 | extern void copy_page(void *to, const void *from); | 121 | extern void copy_page(void *to, const void *from); |
@@ -171,6 +160,9 @@ typedef unsigned long pgprot_t; | |||
171 | 160 | ||
172 | #endif /* STRICT_MM_TYPECHECKS */ | 161 | #endif /* STRICT_MM_TYPECHECKS */ |
173 | 162 | ||
163 | /* the upper-most page table pointer */ | ||
164 | extern pmd_t *top_pmd; | ||
165 | |||
174 | /* Pure 2^n version of get_order */ | 166 | /* Pure 2^n version of get_order */ |
175 | static inline int get_order(unsigned long size) | 167 | static inline int get_order(unsigned long size) |
176 | { | 168 | { |
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index c3fb5984f250..d6025af7efac 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h | |||
@@ -479,6 +479,25 @@ uart_handle_cts_change(struct uart_port *port, unsigned int status) | |||
479 | } | 479 | } |
480 | } | 480 | } |
481 | 481 | ||
482 | #include <linux/tty_flip.h> | ||
483 | |||
484 | static inline void | ||
485 | uart_insert_char(struct uart_port *port, unsigned int status, | ||
486 | unsigned int overrun, unsigned int ch, unsigned int flag) | ||
487 | { | ||
488 | struct tty_struct *tty = port->info->tty; | ||
489 | |||
490 | if ((status & port->ignore_status_mask & ~overrun) == 0) | ||
491 | tty_insert_flip_char(tty, ch, flag); | ||
492 | |||
493 | /* | ||
494 | * Overrun is special. Since it's reported immediately, | ||
495 | * it doesn't affect the current character. | ||
496 | */ | ||
497 | if (status & ~port->ignore_status_mask & overrun) | ||
498 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
499 | } | ||
500 | |||
482 | /* | 501 | /* |
483 | * UART_ENABLE_MS - determine if port should enable modem status irqs | 502 | * UART_ENABLE_MS - determine if port should enable modem status irqs |
484 | */ | 503 | */ |