diff options
210 files changed, 7256 insertions, 5927 deletions
diff --git a/Documentation/SubmitChecklist b/Documentation/SubmitChecklist index 6491b2c45dd4..3af3e65cf43b 100644 --- a/Documentation/SubmitChecklist +++ b/Documentation/SubmitChecklist | |||
@@ -73,9 +73,9 @@ kernel patches. | |||
73 | If the new code is substantial, addition of subsystem-specific fault | 73 | If the new code is substantial, addition of subsystem-specific fault |
74 | injection might be appropriate. | 74 | injection might be appropriate. |
75 | 75 | ||
76 | 22: Newly-added code has been compiled with `gcc -W'. This will generate | 76 | 22: Newly-added code has been compiled with `gcc -W' (use "make |
77 | lots of noise, but is good for finding bugs like "warning: comparison | 77 | EXTRA_CFLAGS=-W"). This will generate lots of noise, but is good for |
78 | between signed and unsigned". | 78 | finding bugs like "warning: comparison between signed and unsigned". |
79 | 79 | ||
80 | 23: Tested after it has been merged into the -mm patchset to make sure | 80 | 23: Tested after it has been merged into the -mm patchset to make sure |
81 | that it still works with all of the other queued patches and various | 81 | that it still works with all of the other queued patches and various |
diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt index f8528db967fa..e8be0abb346c 100644 --- a/Documentation/gpio.txt +++ b/Documentation/gpio.txt | |||
@@ -66,7 +66,9 @@ registers; another might implement it by delegating through abstractions | |||
66 | used for several very different kinds of GPIO controller. | 66 | used for several very different kinds of GPIO controller. |
67 | 67 | ||
68 | That said, if the convention is supported on their platform, drivers should | 68 | That said, if the convention is supported on their platform, drivers should |
69 | use it when possible: | 69 | use it when possible. Platforms should declare GENERIC_GPIO support in |
70 | Kconfig (boolean true), which multi-platform drivers can depend on when | ||
71 | using the include file: | ||
70 | 72 | ||
71 | #include <asm/gpio.h> | 73 | #include <asm/gpio.h> |
72 | 74 | ||
diff --git a/arch/frv/kernel/gdb-stub.c b/arch/frv/kernel/gdb-stub.c index 9550f37fb62c..1e7a101cbf4c 100644 --- a/arch/frv/kernel/gdb-stub.c +++ b/arch/frv/kernel/gdb-stub.c | |||
@@ -1195,7 +1195,7 @@ static void gdbstub_check_breakpoint(void) | |||
1195 | /* | 1195 | /* |
1196 | * | 1196 | * |
1197 | */ | 1197 | */ |
1198 | static void __attribute__((unused)) gdbstub_show_regs(void) | 1198 | static void __maybe_unused gdbstub_show_regs(void) |
1199 | { | 1199 | { |
1200 | unsigned long *reg; | 1200 | unsigned long *reg; |
1201 | int loop; | 1201 | int loop; |
@@ -1223,7 +1223,7 @@ static void __attribute__((unused)) gdbstub_show_regs(void) | |||
1223 | /* | 1223 | /* |
1224 | * dump debugging regs | 1224 | * dump debugging regs |
1225 | */ | 1225 | */ |
1226 | static void __attribute__((unused)) gdbstub_dump_debugregs(void) | 1226 | static void __maybe_unused gdbstub_dump_debugregs(void) |
1227 | { | 1227 | { |
1228 | gdbstub_printk("DCR %08lx ", __debug_status.dcr); | 1228 | gdbstub_printk("DCR %08lx ", __debug_status.dcr); |
1229 | gdbstub_printk("BRR %08lx\n", __debug_status.brr); | 1229 | gdbstub_printk("BRR %08lx\n", __debug_status.brr); |
@@ -2079,25 +2079,25 @@ void gdbstub_exit(int status) | |||
2079 | * GDB wants to call malloc() and free() to allocate memory for calling kernel | 2079 | * GDB wants to call malloc() and free() to allocate memory for calling kernel |
2080 | * functions directly from its command line | 2080 | * functions directly from its command line |
2081 | */ | 2081 | */ |
2082 | static void *malloc(size_t size) __attribute__((unused)); | 2082 | static void *malloc(size_t size) __maybe_unused; |
2083 | static void *malloc(size_t size) | 2083 | static void *malloc(size_t size) |
2084 | { | 2084 | { |
2085 | return kmalloc(size, GFP_ATOMIC); | 2085 | return kmalloc(size, GFP_ATOMIC); |
2086 | } | 2086 | } |
2087 | 2087 | ||
2088 | static void free(void *p) __attribute__((unused)); | 2088 | static void free(void *p) __maybe_unused; |
2089 | static void free(void *p) | 2089 | static void free(void *p) |
2090 | { | 2090 | { |
2091 | kfree(p); | 2091 | kfree(p); |
2092 | } | 2092 | } |
2093 | 2093 | ||
2094 | static uint32_t ___get_HSR0(void) __attribute__((unused)); | 2094 | static uint32_t ___get_HSR0(void) __maybe_unused; |
2095 | static uint32_t ___get_HSR0(void) | 2095 | static uint32_t ___get_HSR0(void) |
2096 | { | 2096 | { |
2097 | return __get_HSR(0); | 2097 | return __get_HSR(0); |
2098 | } | 2098 | } |
2099 | 2099 | ||
2100 | static uint32_t ___set_HSR0(uint32_t x) __attribute__((unused)); | 2100 | static uint32_t ___set_HSR0(uint32_t x) __maybe_unused; |
2101 | static uint32_t ___set_HSR0(uint32_t x) | 2101 | static uint32_t ___set_HSR0(uint32_t x) |
2102 | { | 2102 | { |
2103 | __set_HSR(0, x); | 2103 | __set_HSR(0, x); |
diff --git a/arch/h8300/kernel/syscalls.S b/arch/h8300/kernel/syscalls.S index dab98fd99e63..54e21c3f2057 100644 --- a/arch/h8300/kernel/syscalls.S +++ b/arch/h8300/kernel/syscalls.S | |||
@@ -31,7 +31,7 @@ SYMBOL_NAME_LABEL(sys_call_table) | |||
31 | .long SYMBOL_NAME(sys_mknod) | 31 | .long SYMBOL_NAME(sys_mknod) |
32 | .long SYMBOL_NAME(sys_chmod) /* 15 */ | 32 | .long SYMBOL_NAME(sys_chmod) /* 15 */ |
33 | .long SYMBOL_NAME(sys_chown16) | 33 | .long SYMBOL_NAME(sys_chown16) |
34 | .long SYMBOL_NAME(sys_ni_syscall) /* old break syscall holder */ | 34 | .long SYMBOL_NAME(sys_ni_syscall) /* old break syscall holder */ |
35 | .long SYMBOL_NAME(sys_stat) | 35 | .long SYMBOL_NAME(sys_stat) |
36 | .long SYMBOL_NAME(sys_lseek) | 36 | .long SYMBOL_NAME(sys_lseek) |
37 | .long SYMBOL_NAME(sys_getpid) /* 20 */ | 37 | .long SYMBOL_NAME(sys_getpid) /* 20 */ |
@@ -45,11 +45,11 @@ SYMBOL_NAME_LABEL(sys_call_table) | |||
45 | .long SYMBOL_NAME(sys_fstat) | 45 | .long SYMBOL_NAME(sys_fstat) |
46 | .long SYMBOL_NAME(sys_pause) | 46 | .long SYMBOL_NAME(sys_pause) |
47 | .long SYMBOL_NAME(sys_utime) /* 30 */ | 47 | .long SYMBOL_NAME(sys_utime) /* 30 */ |
48 | .long SYMBOL_NAME(sys_ni_syscall) /* old stty syscall holder */ | 48 | .long SYMBOL_NAME(sys_ni_syscall) /* old stty syscall holder */ |
49 | .long SYMBOL_NAME(sys_ni_syscall) /* old gtty syscall holder */ | 49 | .long SYMBOL_NAME(sys_ni_syscall) /* old gtty syscall holder */ |
50 | .long SYMBOL_NAME(sys_access) | 50 | .long SYMBOL_NAME(sys_access) |
51 | .long SYMBOL_NAME(sys_nice) | 51 | .long SYMBOL_NAME(sys_nice) |
52 | .long SYMBOL_NAME(sys_ni_syscall) /* 35 */ /* old ftime syscall holder */ | 52 | .long SYMBOL_NAME(sys_ni_syscall) /* 35 old ftime syscall holder */ |
53 | .long SYMBOL_NAME(sys_sync) | 53 | .long SYMBOL_NAME(sys_sync) |
54 | .long SYMBOL_NAME(sys_kill) | 54 | .long SYMBOL_NAME(sys_kill) |
55 | .long SYMBOL_NAME(sys_rename) | 55 | .long SYMBOL_NAME(sys_rename) |
@@ -58,7 +58,7 @@ SYMBOL_NAME_LABEL(sys_call_table) | |||
58 | .long SYMBOL_NAME(sys_dup) | 58 | .long SYMBOL_NAME(sys_dup) |
59 | .long SYMBOL_NAME(sys_pipe) | 59 | .long SYMBOL_NAME(sys_pipe) |
60 | .long SYMBOL_NAME(sys_times) | 60 | .long SYMBOL_NAME(sys_times) |
61 | .long SYMBOL_NAME(sys_ni_syscall) /* old prof syscall holder */ | 61 | .long SYMBOL_NAME(sys_ni_syscall) /* old prof syscall holder */ |
62 | .long SYMBOL_NAME(sys_brk) /* 45 */ | 62 | .long SYMBOL_NAME(sys_brk) /* 45 */ |
63 | .long SYMBOL_NAME(sys_setgid16) | 63 | .long SYMBOL_NAME(sys_setgid16) |
64 | .long SYMBOL_NAME(sys_getgid16) | 64 | .long SYMBOL_NAME(sys_getgid16) |
@@ -66,13 +66,13 @@ SYMBOL_NAME_LABEL(sys_call_table) | |||
66 | .long SYMBOL_NAME(sys_geteuid16) | 66 | .long SYMBOL_NAME(sys_geteuid16) |
67 | .long SYMBOL_NAME(sys_getegid16) /* 50 */ | 67 | .long SYMBOL_NAME(sys_getegid16) /* 50 */ |
68 | .long SYMBOL_NAME(sys_acct) | 68 | .long SYMBOL_NAME(sys_acct) |
69 | .long SYMBOL_NAME(sys_umount) /* recycled never used phys() */ | 69 | .long SYMBOL_NAME(sys_umount) /* recycled never used phys() */ |
70 | .long SYMBOL_NAME(sys_ni_syscall) /* old lock syscall holder */ | 70 | .long SYMBOL_NAME(sys_ni_syscall) /* old lock syscall holder */ |
71 | .long SYMBOL_NAME(sys_ioctl) | 71 | .long SYMBOL_NAME(sys_ioctl) |
72 | .long SYMBOL_NAME(sys_fcntl) /* 55 */ | 72 | .long SYMBOL_NAME(sys_fcntl) /* 55 */ |
73 | .long SYMBOL_NAME(sys_ni_syscall) /* old mpx syscall holder */ | 73 | .long SYMBOL_NAME(sys_ni_syscall) /* old mpx syscall holder */ |
74 | .long SYMBOL_NAME(sys_setpgid) | 74 | .long SYMBOL_NAME(sys_setpgid) |
75 | .long SYMBOL_NAME(sys_ni_syscall) /* old ulimit syscall holder */ | 75 | .long SYMBOL_NAME(sys_ni_syscall) /* old ulimit syscall holder */ |
76 | .long SYMBOL_NAME(sys_ni_syscall) | 76 | .long SYMBOL_NAME(sys_ni_syscall) |
77 | .long SYMBOL_NAME(sys_umask) /* 60 */ | 77 | .long SYMBOL_NAME(sys_umask) /* 60 */ |
78 | .long SYMBOL_NAME(sys_chroot) | 78 | .long SYMBOL_NAME(sys_chroot) |
@@ -112,7 +112,7 @@ SYMBOL_NAME_LABEL(sys_call_table) | |||
112 | .long SYMBOL_NAME(sys_fchown16) /* 95 */ | 112 | .long SYMBOL_NAME(sys_fchown16) /* 95 */ |
113 | .long SYMBOL_NAME(sys_getpriority) | 113 | .long SYMBOL_NAME(sys_getpriority) |
114 | .long SYMBOL_NAME(sys_setpriority) | 114 | .long SYMBOL_NAME(sys_setpriority) |
115 | .long SYMBOL_NAME(sys_ni_syscall) /* old profil syscall holder */ | 115 | .long SYMBOL_NAME(sys_ni_syscall) /* old profil syscall holder */ |
116 | .long SYMBOL_NAME(sys_statfs) | 116 | .long SYMBOL_NAME(sys_statfs) |
117 | .long SYMBOL_NAME(sys_fstatfs) /* 100 */ | 117 | .long SYMBOL_NAME(sys_fstatfs) /* 100 */ |
118 | .long SYMBOL_NAME(sys_ni_syscall) /* ioperm for i386 */ | 118 | .long SYMBOL_NAME(sys_ni_syscall) /* ioperm for i386 */ |
@@ -202,8 +202,8 @@ SYMBOL_NAME_LABEL(sys_call_table) | |||
202 | .long SYMBOL_NAME(sys_capset) /* 185 */ | 202 | .long SYMBOL_NAME(sys_capset) /* 185 */ |
203 | .long SYMBOL_NAME(sys_sigaltstack) | 203 | .long SYMBOL_NAME(sys_sigaltstack) |
204 | .long SYMBOL_NAME(sys_sendfile) | 204 | .long SYMBOL_NAME(sys_sendfile) |
205 | .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */ | 205 | .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */ |
206 | .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */ | 206 | .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */ |
207 | .long SYMBOL_NAME(sys_vfork) /* 190 */ | 207 | .long SYMBOL_NAME(sys_vfork) /* 190 */ |
208 | .long SYMBOL_NAME(sys_getrlimit) | 208 | .long SYMBOL_NAME(sys_getrlimit) |
209 | .long SYMBOL_NAME(sys_mmap2) | 209 | .long SYMBOL_NAME(sys_mmap2) |
@@ -236,10 +236,10 @@ SYMBOL_NAME_LABEL(sys_call_table) | |||
236 | .long SYMBOL_NAME(sys_ni_syscall) | 236 | .long SYMBOL_NAME(sys_ni_syscall) |
237 | .long SYMBOL_NAME(sys_getdents64) /* 220 */ | 237 | .long SYMBOL_NAME(sys_getdents64) /* 220 */ |
238 | .long SYMBOL_NAME(sys_fcntl64) | 238 | .long SYMBOL_NAME(sys_fcntl64) |
239 | .long SYMBOL_NAME(sys_ni_syscall) /* reserved for TUX */ | 239 | .long SYMBOL_NAME(sys_ni_syscall) /* reserved TUX */ |
240 | .long SYMBOL_NAME(sys_ni_syscall) | 240 | .long SYMBOL_NAME(sys_ni_syscall) /* reserved Security */ |
241 | .long SYMBOL_NAME(sys_gettid) | 241 | .long SYMBOL_NAME(sys_gettid) |
242 | .long SYMBOL_NAME(sys_ni_syscall) /* 225 */ /* sys_readahead */ | 242 | .long SYMBOL_NAME(sys_readahead) /* 225 */ |
243 | .long SYMBOL_NAME(sys_setxattr) | 243 | .long SYMBOL_NAME(sys_setxattr) |
244 | .long SYMBOL_NAME(sys_lsetxattr) | 244 | .long SYMBOL_NAME(sys_lsetxattr) |
245 | .long SYMBOL_NAME(sys_fsetxattr) | 245 | .long SYMBOL_NAME(sys_fsetxattr) |
@@ -257,8 +257,8 @@ SYMBOL_NAME_LABEL(sys_call_table) | |||
257 | .long SYMBOL_NAME(sys_futex) /* 240 */ | 257 | .long SYMBOL_NAME(sys_futex) /* 240 */ |
258 | .long SYMBOL_NAME(sys_sched_setaffinity) | 258 | .long SYMBOL_NAME(sys_sched_setaffinity) |
259 | .long SYMBOL_NAME(sys_sched_getaffinity) | 259 | .long SYMBOL_NAME(sys_sched_getaffinity) |
260 | .long SYMBOL_NAME(sys_ni_syscall) /* sys_set_thread_area */ | 260 | .long SYMBOL_NAME(sys_ni_syscall) |
261 | .long SYMBOL_NAME(sys_ni_syscall) /* sys_get_thread_area */ | 261 | .long SYMBOL_NAME(sys_ni_syscall) |
262 | .long SYMBOL_NAME(sys_io_setup) /* 245 */ | 262 | .long SYMBOL_NAME(sys_io_setup) /* 245 */ |
263 | .long SYMBOL_NAME(sys_io_destroy) | 263 | .long SYMBOL_NAME(sys_io_destroy) |
264 | .long SYMBOL_NAME(sys_io_getevents) | 264 | .long SYMBOL_NAME(sys_io_getevents) |
@@ -288,8 +288,8 @@ SYMBOL_NAME_LABEL(sys_call_table) | |||
288 | .long SYMBOL_NAME(sys_utimes) | 288 | .long SYMBOL_NAME(sys_utimes) |
289 | .long SYMBOL_NAME(sys_fadvise64_64) | 289 | .long SYMBOL_NAME(sys_fadvise64_64) |
290 | .long SYMBOL_NAME(sys_ni_syscall) /* sys_vserver */ | 290 | .long SYMBOL_NAME(sys_ni_syscall) /* sys_vserver */ |
291 | .long SYMBOL_NAME(sys_mbind) | 291 | .long SYMBOL_NAME(sys_ni_syscall) |
292 | .long SYMBOL_NAME(sys_get_mempolicy) | 292 | .long SYMBOL_NAME(sys_get_mempolicy) /* 275 */ |
293 | .long SYMBOL_NAME(sys_set_mempolicy) | 293 | .long SYMBOL_NAME(sys_set_mempolicy) |
294 | .long SYMBOL_NAME(sys_mq_open) | 294 | .long SYMBOL_NAME(sys_mq_open) |
295 | .long SYMBOL_NAME(sys_mq_unlink) | 295 | .long SYMBOL_NAME(sys_mq_unlink) |
@@ -297,16 +297,42 @@ SYMBOL_NAME_LABEL(sys_call_table) | |||
297 | .long SYMBOL_NAME(sys_mq_timedreceive) /* 280 */ | 297 | .long SYMBOL_NAME(sys_mq_timedreceive) /* 280 */ |
298 | .long SYMBOL_NAME(sys_mq_notify) | 298 | .long SYMBOL_NAME(sys_mq_notify) |
299 | .long SYMBOL_NAME(sys_mq_getsetattr) | 299 | .long SYMBOL_NAME(sys_mq_getsetattr) |
300 | .long SYMBOL_NAME(sys_ni_syscall) /* reserved for kexec */ | ||
301 | .long SYMBOL_NAME(sys_waitid) | 300 | .long SYMBOL_NAME(sys_waitid) |
302 | .long SYMBOL_NAME(sys_ni_syscall) /* 285 */ /* available */ | 301 | .long SYMBOL_NAME(sys_ni_syscall) /* sys_kexec_load */ |
303 | .long SYMBOL_NAME(sys_add_key) | 302 | .long SYMBOL_NAME(sys_add_key) /* 285 */ |
304 | .long SYMBOL_NAME(sys_request_key) | 303 | .long SYMBOL_NAME(sys_request_key) |
305 | .long SYMBOL_NAME(sys_keyctl) | 304 | .long SYMBOL_NAME(sys_keyctl) |
306 | 305 | .long SYMBOL_NAME(sys_ioprio_set) | |
307 | .rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4 | 306 | .long SYMBOL_NAME(sys_ioprio_get) /* 290 */ |
308 | .long SYMBOL_NAME(sys_ni_syscall) | 307 | .long SYMBOL_NAME(sys_inotify_init) |
309 | .endr | 308 | .long SYMBOL_NAME(sys_inotify_add_watch) |
309 | .long SYMBOL_NAME(sys_inotify_rm_watch) | ||
310 | .long SYMBOL_NAME(sys_migrate_pages) | ||
311 | .long SYMBOL_NAME(sys_openat) /* 295 */ | ||
312 | .long SYMBOL_NAME(sys_mkdirat) | ||
313 | .long SYMBOL_NAME(sys_mknodat) | ||
314 | .long SYMBOL_NAME(sys_fchownat) | ||
315 | .long SYMBOL_NAME(sys_futimesat) | ||
316 | .long SYMBOL_NAME(sys_fstatat64) /* 300 */ | ||
317 | .long SYMBOL_NAME(sys_unlinkat) | ||
318 | .long SYMBOL_NAME(sys_renameat) | ||
319 | .long SYMBOL_NAME(sys_linkat) | ||
320 | .long SYMBOL_NAME(sys_symlinkat) | ||
321 | .long SYMBOL_NAME(sys_readlinkat) /* 305 */ | ||
322 | .long SYMBOL_NAME(sys_fchmodat) | ||
323 | .long SYMBOL_NAME(sys_faccessat) | ||
324 | .long SYMBOL_NAME(sys_ni_syscall) /* sys_pselect6 */ | ||
325 | .long SYMBOL_NAME(sys_ni_syscall) /* sys_ppoll */ | ||
326 | .long SYMBOL_NAME(sys_unshare) /* 310 */ | ||
327 | .long SYMBOL_NAME(sys_set_robust_list) | ||
328 | .long SYMBOL_NAME(sys_get_robust_list) | ||
329 | .long SYMBOL_NAME(sys_splice) | ||
330 | .long SYMBOL_NAME(sys_sync_file_range) | ||
331 | .long SYMBOL_NAME(sys_tee) /* 315 */ | ||
332 | .long SYMBOL_NAME(sys_vmsplice) | ||
333 | .long SYMBOL_NAME(sys_ni_syscall) /* sys_move_pages */ | ||
334 | .long SYMBOL_NAME(sys_getcpu) | ||
335 | .long SYMBOL_NAME(sys_ni_syscall) /* sys_epoll_pwait */ | ||
310 | 336 | ||
311 | .macro call_sp addr | 337 | .macro call_sp addr |
312 | mov.l #SYMBOL_NAME(\addr),er6 | 338 | mov.l #SYMBOL_NAME(\addr),er6 |
diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S index 0772678ceecf..bf6adce52267 100644 --- a/arch/i386/kernel/syscall_table.S +++ b/arch/i386/kernel/syscall_table.S | |||
@@ -320,3 +320,6 @@ ENTRY(sys_call_table) | |||
320 | .long sys_getcpu | 320 | .long sys_getcpu |
321 | .long sys_epoll_pwait | 321 | .long sys_epoll_pwait |
322 | .long sys_utimensat /* 320 */ | 322 | .long sys_utimensat /* 320 */ |
323 | .long sys_signalfd | ||
324 | .long sys_timerfd | ||
325 | .long sys_eventfd | ||
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig index 9740d6b8ae11..c3bb8a755b00 100644 --- a/arch/m32r/Kconfig +++ b/arch/m32r/Kconfig | |||
@@ -241,6 +241,10 @@ config GENERIC_CALIBRATE_DELAY | |||
241 | bool | 241 | bool |
242 | default y | 242 | default y |
243 | 243 | ||
244 | config SCHED_NO_NO_OMIT_FRAME_POINTER | ||
245 | bool | ||
246 | default y | ||
247 | |||
244 | config PREEMPT | 248 | config PREEMPT |
245 | bool "Preemptible Kernel" | 249 | bool "Preemptible Kernel" |
246 | help | 250 | help |
diff --git a/arch/m32r/mm/mmu.S b/arch/m32r/mm/mmu.S index 8bb74b10dca7..49a6d16a3d58 100644 --- a/arch/m32r/mm/mmu.S +++ b/arch/m32r/mm/mmu.S | |||
@@ -163,7 +163,8 @@ ENTRY(tme_handler) | |||
163 | 163 | ||
164 | ; pte_data = (unsigned long)pte_val(*pte); | 164 | ; pte_data = (unsigned long)pte_val(*pte); |
165 | ld r2, @r3 ; r2: pte data | 165 | ld r2, @r3 ; r2: pte data |
166 | or3 r2, r2, #2 ; _PAGE_PRESENT(=2) | 166 | and3 r3, r2, #2 ; _PAGE_PRESENT(=2) check |
167 | beqz r3, 3f | ||
167 | 168 | ||
168 | .fillinsn | 169 | .fillinsn |
169 | 5: | 170 | 5: |
@@ -264,11 +265,8 @@ ENTRY(tme_handler) | |||
264 | ; | 265 | ; |
265 | and3 r1, r1, #0xeff | 266 | and3 r1, r1, #0xeff |
266 | ldi r4, #611 ; _KERNPG_TABLE(=611) | 267 | ldi r4, #611 ; _KERNPG_TABLE(=611) |
267 | beq r1, r4, 4f ; !pmd_bad(*pmd) ? | 268 | bne r1, r4, 3f ; !pmd_bad(*pmd) ? |
268 | .fillinsn | 269 | |
269 | 3: | ||
270 | ldi r1, #0 ; r1: pte_data = 0 | ||
271 | bra 5f | ||
272 | .fillinsn | 270 | .fillinsn |
273 | 4: | 271 | 4: |
274 | ; pte = pte_offset(pmd, address); | 272 | ; pte = pte_offset(pmd, address); |
@@ -282,8 +280,10 @@ ENTRY(tme_handler) | |||
282 | add r4, r3 ; r4: pte | 280 | add r4, r3 ; r4: pte |
283 | ; pte_data = (unsigned long)pte_val(*pte); | 281 | ; pte_data = (unsigned long)pte_val(*pte); |
284 | ld r1, @r4 ; r1: pte_data | 282 | ld r1, @r4 ; r1: pte_data |
285 | .fillinsn | 283 | and3 r3, r1, #2 ; _PAGE_PRESENT(=2) check |
284 | beqz r3, 3f | ||
286 | 285 | ||
286 | .fillinsn | ||
287 | ;; set tlb | 287 | ;; set tlb |
288 | ; r0: address, r1: pte_data, r2: entry | 288 | ; r0: address, r1: pte_data, r2: entry |
289 | ; r3,r4: (free) | 289 | ; r3,r4: (free) |
@@ -295,8 +295,7 @@ ENTRY(tme_handler) | |||
295 | and3 r4, r4, #(MMU_CONTEXT_ASID_MASK) | 295 | and3 r4, r4, #(MMU_CONTEXT_ASID_MASK) |
296 | or r3, r4 | 296 | or r3, r4 |
297 | st r3, @r2 | 297 | st r3, @r2 |
298 | or3 r4, r1, #2 ; _PAGE_PRESENT(=2) | 298 | st r1, @(4,r2) ; set_tlb_data(entry, pte_data); |
299 | st r4, @(4,r2) ; set_tlb_data(entry, pte_data); | ||
300 | 299 | ||
301 | ld r4, @sp+ | 300 | ld r4, @sp+ |
302 | ld r3, @sp+ | 301 | ld r3, @sp+ |
@@ -306,6 +305,11 @@ ENTRY(tme_handler) | |||
306 | ld sp, @sp+ | 305 | ld sp, @sp+ |
307 | rte | 306 | rte |
308 | 307 | ||
308 | .fillinsn | ||
309 | 3: | ||
310 | ldi r1, #2 ; r1: pte_data = 0 | _PAGE_PRESENT(=2) | ||
311 | bra 5b | ||
312 | |||
309 | #else | 313 | #else |
310 | #error unknown isa configuration | 314 | #error unknown isa configuration |
311 | #endif | 315 | #endif |
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 9ed4931af164..068377a2a8dc 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c | |||
@@ -173,7 +173,7 @@ void local_irq_restore(unsigned long en) | |||
173 | lv1_get_version_info(&tmp); | 173 | lv1_get_version_info(&tmp); |
174 | } | 174 | } |
175 | 175 | ||
176 | hard_irq_enable(); | 176 | __hard_irq_enable(); |
177 | } | 177 | } |
178 | #endif /* CONFIG_PPC64 */ | 178 | #endif /* CONFIG_PPC64 */ |
179 | 179 | ||
diff --git a/arch/powerpc/kernel/swsusp.c b/arch/powerpc/kernel/swsusp.c index 064a7ba4f02c..77b7b34b5955 100644 --- a/arch/powerpc/kernel/swsusp.c +++ b/arch/powerpc/kernel/swsusp.c | |||
@@ -36,8 +36,4 @@ void restore_processor_state(void) | |||
36 | #ifdef CONFIG_PPC32 | 36 | #ifdef CONFIG_PPC32 |
37 | set_context(current->active_mm->context.id, current->active_mm->pgd); | 37 | set_context(current->active_mm->context.id, current->active_mm->pgd); |
38 | #endif | 38 | #endif |
39 | |||
40 | #ifdef CONFIG_PPC64 | ||
41 | hard_irq_enable(); | ||
42 | #endif | ||
43 | } | 39 | } |
diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c index 8c20f0fb8651..812bf563ed65 100644 --- a/arch/powerpc/platforms/cell/pervasive.c +++ b/arch/powerpc/platforms/cell/pervasive.c | |||
@@ -43,12 +43,10 @@ static void cbe_power_save(void) | |||
43 | unsigned long ctrl, thread_switch_control; | 43 | unsigned long ctrl, thread_switch_control; |
44 | 44 | ||
45 | /* | 45 | /* |
46 | * We need to hard disable interrupts, but we also need to mark them | 46 | * We need to hard disable interrupts, the local_irq_enable() done by |
47 | * hard disabled in the PACA so that the local_irq_enable() done by | 47 | * our caller upon return will hard re-enable. |
48 | * our caller upon return propertly hard enables. | ||
49 | */ | 48 | */ |
50 | hard_irq_disable(); | 49 | hard_irq_disable(); |
51 | get_paca()->hard_enabled = 0; | ||
52 | 50 | ||
53 | ctrl = mfspr(SPRN_CTRLF); | 51 | ctrl = mfspr(SPRN_CTRLF); |
54 | 52 | ||
diff --git a/arch/um/Kconfig b/arch/um/Kconfig index b9c0f307a8fa..c504312219b4 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig | |||
@@ -277,7 +277,8 @@ config HIGHMEM | |||
277 | 277 | ||
278 | config KERNEL_STACK_ORDER | 278 | config KERNEL_STACK_ORDER |
279 | int "Kernel stack size order" | 279 | int "Kernel stack size order" |
280 | default 2 | 280 | default 1 if 64BIT |
281 | default 0 if !64BIT | ||
281 | help | 282 | help |
282 | This option determines the size of UML kernel stacks. They will | 283 | This option determines the size of UML kernel stacks. They will |
283 | be 1 << order pages. The default is OK unless you're running Valgrind | 284 | be 1 << order pages. The default is OK unless you're running Valgrind |
diff --git a/arch/um/defconfig b/arch/um/defconfig index f938fa822146..a54d0efecae1 100644 --- a/arch/um/defconfig +++ b/arch/um/defconfig | |||
@@ -86,7 +86,7 @@ CONFIG_MCONSOLE=y | |||
86 | # CONFIG_MAGIC_SYSRQ is not set | 86 | # CONFIG_MAGIC_SYSRQ is not set |
87 | CONFIG_NEST_LEVEL=0 | 87 | CONFIG_NEST_LEVEL=0 |
88 | # CONFIG_HIGHMEM is not set | 88 | # CONFIG_HIGHMEM is not set |
89 | CONFIG_KERNEL_STACK_ORDER=2 | 89 | CONFIG_KERNEL_STACK_ORDER=0 |
90 | CONFIG_UML_REAL_TIME_CLOCK=y | 90 | CONFIG_UML_REAL_TIME_CLOCK=y |
91 | 91 | ||
92 | # | 92 | # |
diff --git a/arch/um/include/common-offsets.h b/arch/um/include/common-offsets.h index 5593a8027083..541f4a8ca512 100644 --- a/arch/um/include/common-offsets.h +++ b/arch/um/include/common-offsets.h | |||
@@ -28,3 +28,5 @@ DEFINE(UM_NR_CPUS, NR_CPUS); | |||
28 | 28 | ||
29 | /* For crypto assembler code. */ | 29 | /* For crypto assembler code. */ |
30 | DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx)); | 30 | DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx)); |
31 | |||
32 | DEFINE(UM_THREAD_SIZE, THREAD_SIZE); | ||
diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h index 50a49691e0e6..8d7f7c1cb9c6 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/kern_util.h | |||
@@ -117,4 +117,7 @@ extern void sigio_handler(int sig, union uml_pt_regs *regs); | |||
117 | 117 | ||
118 | extern void copy_sc(union uml_pt_regs *regs, void *from); | 118 | extern void copy_sc(union uml_pt_regs *regs, void *from); |
119 | 119 | ||
120 | unsigned long to_irq_stack(int sig, unsigned long *mask_out); | ||
121 | unsigned long from_irq_stack(int nested); | ||
122 | |||
120 | #endif | 123 | #endif |
diff --git a/arch/um/include/os.h b/arch/um/include/os.h index 688d181b5f8a..4d9fb26387d5 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h | |||
@@ -272,7 +272,6 @@ extern void do_longjmp(void *p, int val); | |||
272 | 272 | ||
273 | /* util.c */ | 273 | /* util.c */ |
274 | extern void stack_protections(unsigned long address); | 274 | extern void stack_protections(unsigned long address); |
275 | extern void task_protections(unsigned long address); | ||
276 | extern int raw(int fd); | 275 | extern int raw(int fd); |
277 | extern void setup_machinename(char *machine_out); | 276 | extern void setup_machinename(char *machine_out); |
278 | extern void setup_hostinfo(char *buf, int len); | 277 | extern void setup_hostinfo(char *buf, int len); |
diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S index e36f92b463ce..87a4e4427d8d 100644 --- a/arch/um/kernel/dyn.lds.S +++ b/arch/um/kernel/dyn.lds.S | |||
@@ -97,6 +97,8 @@ SECTIONS | |||
97 | .data : { | 97 | .data : { |
98 | . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ | 98 | . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ |
99 | *(.data.init_task) | 99 | *(.data.init_task) |
100 | . = ALIGN(KERNEL_STACK_SIZE); | ||
101 | *(.data.init_irqstack) | ||
100 | *(.data .data.* .gnu.linkonce.d.*) | 102 | *(.data .data.* .gnu.linkonce.d.*) |
101 | SORT(CONSTRUCTORS) | 103 | SORT(CONSTRUCTORS) |
102 | } | 104 | } |
diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c index cda91aa8e703..d4f1d1ab252b 100644 --- a/arch/um/kernel/init_task.c +++ b/arch/um/kernel/init_task.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,intel.linux}.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
5 | 5 | ||
@@ -33,28 +33,20 @@ EXPORT_SYMBOL(init_task); | |||
33 | /* | 33 | /* |
34 | * Initial thread structure. | 34 | * Initial thread structure. |
35 | * | 35 | * |
36 | * We need to make sure that this is 16384-byte aligned due to the | 36 | * We need to make sure that this is aligned due to the |
37 | * way process stacks are handled. This is done by having a special | 37 | * way process stacks are handled. This is done by having a special |
38 | * "init_task" linker map entry.. | 38 | * "init_task" linker map entry.. |
39 | */ | 39 | */ |
40 | 40 | ||
41 | union thread_union init_thread_union | 41 | union thread_union init_thread_union |
42 | __attribute__((__section__(".data.init_task"))) = | 42 | __attribute__((__section__(".data.init_task"))) = |
43 | { INIT_THREAD_INFO(init_task) }; | 43 | { INIT_THREAD_INFO(init_task) }; |
44 | |||
45 | union thread_union cpu0_irqstack | ||
46 | __attribute__((__section__(".data.init_irqstack"))) = | ||
47 | { INIT_THREAD_INFO(init_task) }; | ||
44 | 48 | ||
45 | void unprotect_stack(unsigned long stack) | 49 | void unprotect_stack(unsigned long stack) |
46 | { | 50 | { |
47 | os_protect_memory((void *) stack, (1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE, | 51 | os_protect_memory((void *) stack, THREAD_SIZE, 1, 1, 0); |
48 | 1, 1, 0); | ||
49 | } | 52 | } |
50 | |||
51 | /* | ||
52 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
53 | * Emacs will notice this stuff at the end of the file and automatically | ||
54 | * adjust the settings for this buffer only. This must remain at the end | ||
55 | * of the file. | ||
56 | * --------------------------------------------------------------------------- | ||
57 | * Local variables: | ||
58 | * c-file-style: "linux" | ||
59 | * End: | ||
60 | */ | ||
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index 8f2ed3690315..dba04d88b432 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) | 2 | * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | * Derived (i.e. mostly copied) from arch/i386/kernel/irq.c: | 4 | * Derived (i.e. mostly copied) from arch/i386/kernel/irq.c: |
@@ -32,6 +32,7 @@ | |||
32 | #include "sigio.h" | 32 | #include "sigio.h" |
33 | #include "um_malloc.h" | 33 | #include "um_malloc.h" |
34 | #include "misc_constants.h" | 34 | #include "misc_constants.h" |
35 | #include "as-layout.h" | ||
35 | 36 | ||
36 | /* | 37 | /* |
37 | * Generic, controller-independent functions: | 38 | * Generic, controller-independent functions: |
@@ -53,7 +54,7 @@ int show_interrupts(struct seq_file *p, void *v) | |||
53 | if (i < NR_IRQS) { | 54 | if (i < NR_IRQS) { |
54 | spin_lock_irqsave(&irq_desc[i].lock, flags); | 55 | spin_lock_irqsave(&irq_desc[i].lock, flags); |
55 | action = irq_desc[i].action; | 56 | action = irq_desc[i].action; |
56 | if (!action) | 57 | if (!action) |
57 | goto skip; | 58 | goto skip; |
58 | seq_printf(p, "%3d: ",i); | 59 | seq_printf(p, "%3d: ",i); |
59 | #ifndef CONFIG_SMP | 60 | #ifndef CONFIG_SMP |
@@ -468,3 +469,113 @@ int init_aio_irq(int irq, char *name, irq_handler_t handler) | |||
468 | out: | 469 | out: |
469 | return err; | 470 | return err; |
470 | } | 471 | } |
472 | |||
473 | /* | ||
474 | * IRQ stack entry and exit: | ||
475 | * | ||
476 | * Unlike i386, UML doesn't receive IRQs on the normal kernel stack | ||
477 | * and switch over to the IRQ stack after some preparation. We use | ||
478 | * sigaltstack to receive signals on a separate stack from the start. | ||
479 | * These two functions make sure the rest of the kernel won't be too | ||
480 | * upset by being on a different stack. The IRQ stack has a | ||
481 | * thread_info structure at the bottom so that current et al continue | ||
482 | * to work. | ||
483 | * | ||
484 | * to_irq_stack copies the current task's thread_info to the IRQ stack | ||
485 | * thread_info and sets the tasks's stack to point to the IRQ stack. | ||
486 | * | ||
487 | * from_irq_stack copies the thread_info struct back (flags may have | ||
488 | * been modified) and resets the task's stack pointer. | ||
489 | * | ||
490 | * Tricky bits - | ||
491 | * | ||
492 | * What happens when two signals race each other? UML doesn't block | ||
493 | * signals with sigprocmask, SA_DEFER, or sa_mask, so a second signal | ||
494 | * could arrive while a previous one is still setting up the | ||
495 | * thread_info. | ||
496 | * | ||
497 | * There are three cases - | ||
498 | * The first interrupt on the stack - sets up the thread_info and | ||
499 | * handles the interrupt | ||
500 | * A nested interrupt interrupting the copying of the thread_info - | ||
501 | * can't handle the interrupt, as the stack is in an unknown state | ||
502 | * A nested interrupt not interrupting the copying of the | ||
503 | * thread_info - doesn't do any setup, just handles the interrupt | ||
504 | * | ||
505 | * The first job is to figure out whether we interrupted stack setup. | ||
506 | * This is done by xchging the signal mask with thread_info->pending. | ||
507 | * If the value that comes back is zero, then there is no setup in | ||
508 | * progress, and the interrupt can be handled. If the value is | ||
509 | * non-zero, then there is stack setup in progress. In order to have | ||
510 | * the interrupt handled, we leave our signal in the mask, and it will | ||
511 | * be handled by the upper handler after it has set up the stack. | ||
512 | * | ||
513 | * Next is to figure out whether we are the outer handler or a nested | ||
514 | * one. As part of setting up the stack, thread_info->real_thread is | ||
515 | * set to non-NULL (and is reset to NULL on exit). This is the | ||
516 | * nesting indicator. If it is non-NULL, then the stack is already | ||
517 | * set up and the handler can run. | ||
518 | */ | ||
519 | |||
520 | static unsigned long pending_mask; | ||
521 | |||
522 | unsigned long to_irq_stack(int sig, unsigned long *mask_out) | ||
523 | { | ||
524 | struct thread_info *ti; | ||
525 | unsigned long mask, old; | ||
526 | int nested; | ||
527 | |||
528 | mask = xchg(&pending_mask, 1 << sig); | ||
529 | if(mask != 0){ | ||
530 | /* If any interrupts come in at this point, we want to | ||
531 | * make sure that their bits aren't lost by our | ||
532 | * putting our bit in. So, this loop accumulates bits | ||
533 | * until xchg returns the same value that we put in. | ||
534 | * When that happens, there were no new interrupts, | ||
535 | * and pending_mask contains a bit for each interrupt | ||
536 | * that came in. | ||
537 | */ | ||
538 | old = 1 << sig; | ||
539 | do { | ||
540 | old |= mask; | ||
541 | mask = xchg(&pending_mask, old); | ||
542 | } while(mask != old); | ||
543 | return 1; | ||
544 | } | ||
545 | |||
546 | ti = current_thread_info(); | ||
547 | nested = (ti->real_thread != NULL); | ||
548 | if(!nested){ | ||
549 | struct task_struct *task; | ||
550 | struct thread_info *tti; | ||
551 | |||
552 | task = cpu_tasks[ti->cpu].task; | ||
553 | tti = task_thread_info(task); | ||
554 | *ti = *tti; | ||
555 | ti->real_thread = tti; | ||
556 | task->stack = ti; | ||
557 | } | ||
558 | |||
559 | mask = xchg(&pending_mask, 0); | ||
560 | *mask_out |= mask | nested; | ||
561 | return 0; | ||
562 | } | ||
563 | |||
564 | unsigned long from_irq_stack(int nested) | ||
565 | { | ||
566 | struct thread_info *ti, *to; | ||
567 | unsigned long mask; | ||
568 | |||
569 | ti = current_thread_info(); | ||
570 | |||
571 | pending_mask = 1; | ||
572 | |||
573 | to = ti->real_thread; | ||
574 | current->stack = to; | ||
575 | ti->real_thread = NULL; | ||
576 | *to = *ti; | ||
577 | |||
578 | mask = xchg(&pending_mask, 0); | ||
579 | return mask & ~1; | ||
580 | } | ||
581 | |||
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index a96ae1a0610e..2a69a7ce5792 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c | |||
@@ -163,8 +163,12 @@ static int start_kernel_proc(void *unused) | |||
163 | 163 | ||
164 | extern int userspace_pid[]; | 164 | extern int userspace_pid[]; |
165 | 165 | ||
166 | extern char cpu0_irqstack[]; | ||
167 | |||
166 | int start_uml_skas(void) | 168 | int start_uml_skas(void) |
167 | { | 169 | { |
170 | stack_protections((unsigned long) &cpu0_irqstack); | ||
171 | set_sigstack(cpu0_irqstack, THREAD_SIZE); | ||
168 | if(proc_mm) | 172 | if(proc_mm) |
169 | userspace_pid[0] = start_userspace(0); | 173 | userspace_pid[0] = start_userspace(0); |
170 | 174 | ||
diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c index 98e21743e604..40126cb51801 100644 --- a/arch/um/kernel/tt/exec_kern.c +++ b/arch/um/kernel/tt/exec_kern.c | |||
@@ -57,7 +57,7 @@ void flush_thread_tt(void) | |||
57 | enable_timer(); | 57 | enable_timer(); |
58 | free_page(stack); | 58 | free_page(stack); |
59 | protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); | 59 | protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); |
60 | task_protections((unsigned long) current_thread); | 60 | stack_protections((unsigned long) current_thread); |
61 | force_flush_all(); | 61 | force_flush_all(); |
62 | unblock_signals(); | 62 | unblock_signals(); |
63 | } | 63 | } |
diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c index c631303cb800..74347adf81bf 100644 --- a/arch/um/kernel/tt/process_kern.c +++ b/arch/um/kernel/tt/process_kern.c | |||
@@ -209,7 +209,7 @@ void finish_fork_handler(int sig) | |||
209 | if(current->mm != current->parent->mm) | 209 | if(current->mm != current->parent->mm) |
210 | protect_memory(uml_reserved, high_physmem - uml_reserved, 1, | 210 | protect_memory(uml_reserved, high_physmem - uml_reserved, 1, |
211 | 1, 0, 1); | 211 | 1, 0, 1); |
212 | task_protections((unsigned long) current_thread); | 212 | stack_protections((unsigned long) current_thread); |
213 | 213 | ||
214 | free_page(current->thread.temp_stack); | 214 | free_page(current->thread.temp_stack); |
215 | local_irq_disable(); | 215 | local_irq_disable(); |
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 1cf954a47fd7..ecc458fe51b9 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c | |||
@@ -459,7 +459,7 @@ int __init linux_main(int argc, char **argv) | |||
459 | 459 | ||
460 | uml_postsetup(); | 460 | uml_postsetup(); |
461 | 461 | ||
462 | task_protections((unsigned long) &init_thread_info); | 462 | stack_protections((unsigned long) &init_thread_info); |
463 | os_flush_stdout(); | 463 | os_flush_stdout(); |
464 | 464 | ||
465 | return CHOOSE_MODE(start_uml_tt(), start_uml_skas()); | 465 | return CHOOSE_MODE(start_uml_tt(), start_uml_skas()); |
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S index f6301274cf3c..bc59f97e34d0 100644 --- a/arch/um/kernel/uml.lds.S +++ b/arch/um/kernel/uml.lds.S | |||
@@ -59,6 +59,8 @@ SECTIONS | |||
59 | { | 59 | { |
60 | . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ | 60 | . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ |
61 | *(.data.init_task) | 61 | *(.data.init_task) |
62 | . = ALIGN(KERNEL_STACK_SIZE); | ||
63 | *(.data.init_irqstack) | ||
62 | *(.data) | 64 | *(.data) |
63 | *(.gnu.linkonce.d*) | 65 | *(.gnu.linkonce.d*) |
64 | CONSTRUCTORS | 66 | CONSTRUCTORS |
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 48d493415301..18e5c8b67eb8 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c | |||
@@ -61,15 +61,19 @@ void sig_handler(int sig, struct sigcontext *sc) | |||
61 | 61 | ||
62 | static void real_alarm_handler(int sig, struct sigcontext *sc) | 62 | static void real_alarm_handler(int sig, struct sigcontext *sc) |
63 | { | 63 | { |
64 | union uml_pt_regs regs; | ||
65 | |||
64 | if(sig == SIGALRM) | 66 | if(sig == SIGALRM) |
65 | switch_timers(0); | 67 | switch_timers(0); |
66 | 68 | ||
67 | CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas, | 69 | if(sc != NULL) |
68 | sig, sc); | 70 | copy_sc(®s, sc); |
71 | regs.skas.is_user = 0; | ||
72 | unblock_signals(); | ||
73 | timer_handler(sig, ®s); | ||
69 | 74 | ||
70 | if(sig == SIGALRM) | 75 | if(sig == SIGALRM) |
71 | switch_timers(1); | 76 | switch_timers(1); |
72 | |||
73 | } | 77 | } |
74 | 78 | ||
75 | void alarm_handler(int sig, struct sigcontext *sc) | 79 | void alarm_handler(int sig, struct sigcontext *sc) |
@@ -113,6 +117,46 @@ void remove_sigstack(void) | |||
113 | 117 | ||
114 | void (*handlers[_NSIG])(int sig, struct sigcontext *sc); | 118 | void (*handlers[_NSIG])(int sig, struct sigcontext *sc); |
115 | 119 | ||
120 | void handle_signal(int sig, struct sigcontext *sc) | ||
121 | { | ||
122 | unsigned long pending = 0; | ||
123 | |||
124 | do { | ||
125 | int nested, bail; | ||
126 | |||
127 | /* | ||
128 | * pending comes back with one bit set for each | ||
129 | * interrupt that arrived while setting up the stack, | ||
130 | * plus a bit for this interrupt, plus the zero bit is | ||
131 | * set if this is a nested interrupt. | ||
132 | * If bail is true, then we interrupted another | ||
133 | * handler setting up the stack. In this case, we | ||
134 | * have to return, and the upper handler will deal | ||
135 | * with this interrupt. | ||
136 | */ | ||
137 | bail = to_irq_stack(sig, &pending); | ||
138 | if(bail) | ||
139 | return; | ||
140 | |||
141 | nested = pending & 1; | ||
142 | pending &= ~1; | ||
143 | |||
144 | while((sig = ffs(pending)) != 0){ | ||
145 | sig--; | ||
146 | pending &= ~(1 << sig); | ||
147 | (*handlers[sig])(sig, sc); | ||
148 | } | ||
149 | |||
150 | /* Again, pending comes back with a mask of signals | ||
151 | * that arrived while tearing down the stack. If this | ||
152 | * is non-zero, we just go back, set up the stack | ||
153 | * again, and handle the new interrupts. | ||
154 | */ | ||
155 | if(!nested) | ||
156 | pending = from_irq_stack(nested); | ||
157 | } while(pending); | ||
158 | } | ||
159 | |||
116 | extern void hard_handler(int sig); | 160 | extern void hard_handler(int sig); |
117 | 161 | ||
118 | void set_handler(int sig, void (*handler)(int), int flags, ...) | 162 | void set_handler(int sig, void (*handler)(int), int flags, ...) |
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index 6a0e466d01e3..f9d2f8545afe 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c | |||
@@ -288,7 +288,8 @@ int start_userspace(unsigned long stub_stack) | |||
288 | void userspace(union uml_pt_regs *regs) | 288 | void userspace(union uml_pt_regs *regs) |
289 | { | 289 | { |
290 | int err, status, op, pid = userspace_pid[0]; | 290 | int err, status, op, pid = userspace_pid[0]; |
291 | int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/ | 291 | /* To prevent races if using_sysemu changes under us.*/ |
292 | int local_using_sysemu; | ||
292 | 293 | ||
293 | while(1){ | 294 | while(1){ |
294 | restore_registers(pid, regs); | 295 | restore_registers(pid, regs); |
@@ -296,7 +297,8 @@ void userspace(union uml_pt_regs *regs) | |||
296 | /* Now we set local_using_sysemu to be used for one loop */ | 297 | /* Now we set local_using_sysemu to be used for one loop */ |
297 | local_using_sysemu = get_using_sysemu(); | 298 | local_using_sysemu = get_using_sysemu(); |
298 | 299 | ||
299 | op = SELECT_PTRACE_OPERATION(local_using_sysemu, singlestepping(NULL)); | 300 | op = SELECT_PTRACE_OPERATION(local_using_sysemu, |
301 | singlestepping(NULL)); | ||
300 | 302 | ||
301 | err = ptrace(op, pid, 0, 0); | 303 | err = ptrace(op, pid, 0, 0); |
302 | if(err) | 304 | if(err) |
@@ -490,8 +492,8 @@ void map_stub_pages(int fd, unsigned long code, | |||
490 | void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)) | 492 | void new_thread(void *stack, jmp_buf *buf, void (*handler)(void)) |
491 | { | 493 | { |
492 | (*buf)[0].JB_IP = (unsigned long) handler; | 494 | (*buf)[0].JB_IP = (unsigned long) handler; |
493 | (*buf)[0].JB_SP = (unsigned long) stack + | 495 | (*buf)[0].JB_SP = (unsigned long) stack + UM_THREAD_SIZE - |
494 | (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) - sizeof(void *); | 496 | sizeof(void *); |
495 | } | 497 | } |
496 | 498 | ||
497 | #define INIT_JMP_NEW_THREAD 0 | 499 | #define INIT_JMP_NEW_THREAD 0 |
@@ -533,8 +535,7 @@ int start_idle_thread(void *stack, jmp_buf *switch_buf) | |||
533 | case INIT_JMP_NEW_THREAD: | 535 | case INIT_JMP_NEW_THREAD: |
534 | (*switch_buf)[0].JB_IP = (unsigned long) new_thread_handler; | 536 | (*switch_buf)[0].JB_IP = (unsigned long) new_thread_handler; |
535 | (*switch_buf)[0].JB_SP = (unsigned long) stack + | 537 | (*switch_buf)[0].JB_SP = (unsigned long) stack + |
536 | (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) - | 538 | UM_THREAD_SIZE - sizeof(void *); |
537 | sizeof(void *); | ||
538 | break; | 539 | break; |
539 | case INIT_JMP_CALLBACK: | 540 | case INIT_JMP_CALLBACK: |
540 | (*cb_proc)(cb_arg); | 541 | (*cb_proc)(cb_arg); |
diff --git a/arch/um/os-Linux/sys-i386/signal.c b/arch/um/os-Linux/sys-i386/signal.c index 0d3eae518352..f311609f93da 100644 --- a/arch/um/os-Linux/sys-i386/signal.c +++ b/arch/um/os-Linux/sys-i386/signal.c | |||
@@ -1,15 +1,13 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com) | 2 | * Copyright (C) 2006 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <signal.h> | 6 | #include <signal.h> |
7 | 7 | ||
8 | extern void (*handlers[])(int sig, struct sigcontext *sc); | 8 | extern void handle_signal(int sig, struct sigcontext *sc); |
9 | 9 | ||
10 | void hard_handler(int sig) | 10 | void hard_handler(int sig) |
11 | { | 11 | { |
12 | struct sigcontext *sc = (struct sigcontext *) (&sig + 1); | 12 | handle_signal(sig, (struct sigcontext *) (&sig + 1)); |
13 | |||
14 | (*handlers[sig])(sig, sc); | ||
15 | } | 13 | } |
diff --git a/arch/um/os-Linux/sys-x86_64/signal.c b/arch/um/os-Linux/sys-x86_64/signal.c index 3f369e5f976b..82a388822cd3 100644 --- a/arch/um/os-Linux/sys-x86_64/signal.c +++ b/arch/um/os-Linux/sys-x86_64/signal.c | |||
@@ -1,16 +1,16 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com) | 2 | * Copyright (C) 2006 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
3 | * Licensed under the GPL | 3 | * Licensed under the GPL |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <signal.h> | 6 | #include <signal.h> |
7 | 7 | ||
8 | extern void (*handlers[])(int sig, struct sigcontext *sc); | 8 | extern void handle_signal(int sig, struct sigcontext *sc); |
9 | 9 | ||
10 | void hard_handler(int sig) | 10 | void hard_handler(int sig) |
11 | { | 11 | { |
12 | struct ucontext *uc; | 12 | struct ucontext *uc; |
13 | asm("movq %%rdx, %0" : "=r" (uc)); | 13 | asm("movq %%rdx, %0" : "=r" (uc)); |
14 | 14 | ||
15 | (*handlers[sig])(sig, (struct sigcontext *) &uc->uc_mcontext); | 15 | handle_signal(sig, (struct sigcontext *) &uc->uc_mcontext); |
16 | } | 16 | } |
diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c index c307a89ed259..7cbcf484e13d 100644 --- a/arch/um/os-Linux/util.c +++ b/arch/um/os-Linux/util.c | |||
@@ -33,25 +33,8 @@ | |||
33 | 33 | ||
34 | void stack_protections(unsigned long address) | 34 | void stack_protections(unsigned long address) |
35 | { | 35 | { |
36 | int prot = PROT_READ | PROT_WRITE | PROT_EXEC; | 36 | if(mprotect((void *) address, UM_THREAD_SIZE, |
37 | 37 | PROT_READ | PROT_WRITE | PROT_EXEC) < 0) | |
38 | if(mprotect((void *) address, UM_KERN_PAGE_SIZE, prot) < 0) | ||
39 | panic("protecting stack failed, errno = %d", errno); | ||
40 | } | ||
41 | |||
42 | void task_protections(unsigned long address) | ||
43 | { | ||
44 | unsigned long guard = address + UM_KERN_PAGE_SIZE; | ||
45 | unsigned long stack = guard + UM_KERN_PAGE_SIZE; | ||
46 | int prot = 0, pages; | ||
47 | |||
48 | #ifdef notdef | ||
49 | if(mprotect((void *) stack, UM_KERN_PAGE_SIZE, prot) < 0) | ||
50 | panic("protecting guard page failed, errno = %d", errno); | ||
51 | #endif | ||
52 | pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER) - 2; | ||
53 | prot = PROT_READ | PROT_WRITE | PROT_EXEC; | ||
54 | if(mprotect((void *) stack, pages * UM_KERN_PAGE_SIZE, prot) < 0) | ||
55 | panic("protecting stack failed, errno = %d", errno); | 38 | panic("protecting stack failed, errno = %d", errno); |
56 | } | 39 | } |
57 | 40 | ||
@@ -72,7 +55,7 @@ int raw(int fd) | |||
72 | 55 | ||
73 | /* XXX tcsetattr could have applied only some changes | 56 | /* XXX tcsetattr could have applied only some changes |
74 | * (and cfmakeraw() is a set of changes) */ | 57 | * (and cfmakeraw() is a set of changes) */ |
75 | return(0); | 58 | return 0; |
76 | } | 59 | } |
77 | 60 | ||
78 | void setup_machinename(char *machine_out) | 61 | void setup_machinename(char *machine_out) |
diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S index f21068378272..52be79beb306 100644 --- a/arch/x86_64/ia32/ia32entry.S +++ b/arch/x86_64/ia32/ia32entry.S | |||
@@ -716,4 +716,7 @@ ia32_sys_call_table: | |||
716 | .quad sys_getcpu | 716 | .quad sys_getcpu |
717 | .quad sys_epoll_pwait | 717 | .quad sys_epoll_pwait |
718 | .quad compat_sys_utimensat /* 320 */ | 718 | .quad compat_sys_utimensat /* 320 */ |
719 | .quad sys_signalfd | ||
720 | .quad sys_timerfd | ||
721 | .quad sys_eventfd | ||
719 | ia32_syscall_end: | 722 | ia32_syscall_end: |
diff --git a/arch/x86_64/kernel/head64.c b/arch/x86_64/kernel/head64.c index 213d90e04755..6c34bdd22e26 100644 --- a/arch/x86_64/kernel/head64.c +++ b/arch/x86_64/kernel/head64.c | |||
@@ -62,13 +62,6 @@ void __init x86_64_start_kernel(char * real_mode_data) | |||
62 | { | 62 | { |
63 | int i; | 63 | int i; |
64 | 64 | ||
65 | /* | ||
66 | * Make sure kernel is aligned to 2MB address. Catching it at compile | ||
67 | * time is better. Change your config file and compile the kernel | ||
68 | * for a 2MB aligned address (CONFIG_PHYSICAL_START) | ||
69 | */ | ||
70 | BUILD_BUG_ON(CONFIG_PHYSICAL_START & (__KERNEL_ALIGN - 1)); | ||
71 | |||
72 | /* clear bss before set_intr_gate with early_idt_handler */ | 65 | /* clear bss before set_intr_gate with early_idt_handler */ |
73 | clear_bss(); | 66 | clear_bss(); |
74 | 67 | ||
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 0f4203b499af..6055b9c0ac0f 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c | |||
@@ -307,7 +307,9 @@ static void hci_uart_tty_close(struct tty_struct *tty) | |||
307 | 307 | ||
308 | if (hu) { | 308 | if (hu) { |
309 | struct hci_dev *hdev = hu->hdev; | 309 | struct hci_dev *hdev = hu->hdev; |
310 | hci_uart_close(hdev); | 310 | |
311 | if (hdev) | ||
312 | hci_uart_close(hdev); | ||
311 | 313 | ||
312 | if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { | 314 | if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { |
313 | hu->proto->close(hu); | 315 | hu->proto->close(hu); |
@@ -473,12 +475,18 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, | |||
473 | tty->low_latency = 1; | 475 | tty->low_latency = 1; |
474 | } else | 476 | } else |
475 | return -EBUSY; | 477 | return -EBUSY; |
478 | break; | ||
476 | 479 | ||
477 | case HCIUARTGETPROTO: | 480 | case HCIUARTGETPROTO: |
478 | if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) | 481 | if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) |
479 | return hu->proto->id; | 482 | return hu->proto->id; |
480 | return -EUNATCH; | 483 | return -EUNATCH; |
481 | 484 | ||
485 | case HCIUARTGETDEVICE: | ||
486 | if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) | ||
487 | return hu->hdev->id; | ||
488 | return -EUNATCH; | ||
489 | |||
482 | default: | 490 | default: |
483 | err = n_tty_ioctl(tty, file, cmd, arg); | 491 | err = n_tty_ioctl(tty, file, cmd, arg); |
484 | break; | 492 | break; |
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index b250e6789dee..1097ce72393f 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h | |||
@@ -28,8 +28,9 @@ | |||
28 | #endif | 28 | #endif |
29 | 29 | ||
30 | /* Ioctls */ | 30 | /* Ioctls */ |
31 | #define HCIUARTSETPROTO _IOW('U', 200, int) | 31 | #define HCIUARTSETPROTO _IOW('U', 200, int) |
32 | #define HCIUARTGETPROTO _IOR('U', 201, int) | 32 | #define HCIUARTGETPROTO _IOR('U', 201, int) |
33 | #define HCIUARTGETDEVICE _IOR('U', 202, int) | ||
33 | 34 | ||
34 | /* UART protocols */ | 35 | /* UART protocols */ |
35 | #define HCI_UART_MAX_PROTO 4 | 36 | #define HCI_UART_MAX_PROTO 4 |
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 6ac3ca4c723c..b3d4ccc33a47 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c | |||
@@ -1544,21 +1544,18 @@ static unsigned int normal_poll(struct tty_struct * tty, struct file * file, pol | |||
1544 | } | 1544 | } |
1545 | 1545 | ||
1546 | struct tty_ldisc tty_ldisc_N_TTY = { | 1546 | struct tty_ldisc tty_ldisc_N_TTY = { |
1547 | TTY_LDISC_MAGIC, /* magic */ | 1547 | .magic = TTY_LDISC_MAGIC, |
1548 | "n_tty", /* name */ | 1548 | .name = "n_tty", |
1549 | 0, /* num */ | 1549 | .open = n_tty_open, |
1550 | 0, /* flags */ | 1550 | .close = n_tty_close, |
1551 | n_tty_open, /* open */ | 1551 | .flush_buffer = n_tty_flush_buffer, |
1552 | n_tty_close, /* close */ | 1552 | .chars_in_buffer = n_tty_chars_in_buffer, |
1553 | n_tty_flush_buffer, /* flush_buffer */ | 1553 | .read = read_chan, |
1554 | n_tty_chars_in_buffer, /* chars_in_buffer */ | 1554 | .write = write_chan, |
1555 | read_chan, /* read */ | 1555 | .ioctl = n_tty_ioctl, |
1556 | write_chan, /* write */ | 1556 | .set_termios = n_tty_set_termios, |
1557 | n_tty_ioctl, /* ioctl */ | 1557 | .poll = normal_poll, |
1558 | n_tty_set_termios, /* set_termios */ | 1558 | .receive_buf = n_tty_receive_buf, |
1559 | normal_poll, /* poll */ | 1559 | .write_wakeup = n_tty_write_wakeup |
1560 | NULL, /* hangup */ | ||
1561 | n_tty_receive_buf, /* receive_buf */ | ||
1562 | n_tty_write_wakeup /* write_wakeup */ | ||
1563 | }; | 1560 | }; |
1564 | 1561 | ||
diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c index 245f03195b7c..8cc60b693460 100644 --- a/drivers/char/rio/riocmd.c +++ b/drivers/char/rio/riocmd.c | |||
@@ -402,7 +402,7 @@ static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struc | |||
402 | rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: Host number %Zd, name ``%s''\n", HostP - p->RIOHosts, HostP->Name); | 402 | rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: Host number %Zd, name ``%s''\n", HostP - p->RIOHosts, HostP->Name); |
403 | rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: Rup number 0x%x\n", rup); | 403 | rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: Rup number 0x%x\n", rup); |
404 | 404 | ||
405 | if (Rup >= (unsigned short) MAX_RUP) { | 405 | if (Rup < (unsigned short) MAX_RUP) { |
406 | rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: This is the RUP for RTA ``%s''\n", HostP->Mapping[Rup].Name); | 406 | rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: This is the RUP for RTA ``%s''\n", HostP->Mapping[Rup].Name); |
407 | } else | 407 | } else |
408 | rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: This is the RUP for link ``%c'' of host ``%s''\n", ('A' + Rup - MAX_RUP), HostP->Name); | 408 | rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: This is the RUP for link ``%c'' of host ``%s''\n", ('A' + Rup - MAX_RUP), HostP->Name); |
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 61a63da420c2..a3fd7e7ba5a9 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c | |||
@@ -1014,9 +1014,6 @@ static int rp_open(struct tty_struct *tty, struct file *filp) | |||
1014 | /* | 1014 | /* |
1015 | * Info->count is now 1; so it's safe to sleep now. | 1015 | * Info->count is now 1; so it's safe to sleep now. |
1016 | */ | 1016 | */ |
1017 | info->session = process_session(current); | ||
1018 | info->pgrp = process_group(current); | ||
1019 | |||
1020 | if ((info->flags & ROCKET_INITIALIZED) == 0) { | 1017 | if ((info->flags & ROCKET_INITIALIZED) == 0) { |
1021 | cp = &info->channel; | 1018 | cp = &info->channel; |
1022 | sSetRxTrigger(cp, TRIG_1); | 1019 | sSetRxTrigger(cp, TRIG_1); |
diff --git a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h index 89b4d7b10d12..b4c53dfa7951 100644 --- a/drivers/char/rocket_int.h +++ b/drivers/char/rocket_int.h | |||
@@ -1158,8 +1158,6 @@ struct r_port { | |||
1158 | int xmit_head; | 1158 | int xmit_head; |
1159 | int xmit_tail; | 1159 | int xmit_tail; |
1160 | int xmit_cnt; | 1160 | int xmit_cnt; |
1161 | int session; | ||
1162 | int pgrp; | ||
1163 | int cd_status; | 1161 | int cd_status; |
1164 | int ignore_status_mask; | 1162 | int ignore_status_mask; |
1165 | int read_status_mask; | 1163 | int read_status_mask; |
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 2a7736b5f2f7..02b49bc00028 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c | |||
@@ -1171,6 +1171,112 @@ static int ioctl(struct tty_struct *tty, struct file *file, | |||
1171 | } | 1171 | } |
1172 | 1172 | ||
1173 | /* | 1173 | /* |
1174 | * support for 32 bit ioctl calls on 64 bit systems | ||
1175 | */ | ||
1176 | #ifdef CONFIG_COMPAT | ||
1177 | static long get_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *user_params) | ||
1178 | { | ||
1179 | struct MGSL_PARAMS32 tmp_params; | ||
1180 | |||
1181 | DBGINFO(("%s get_params32\n", info->device_name)); | ||
1182 | tmp_params.mode = (compat_ulong_t)info->params.mode; | ||
1183 | tmp_params.loopback = info->params.loopback; | ||
1184 | tmp_params.flags = info->params.flags; | ||
1185 | tmp_params.encoding = info->params.encoding; | ||
1186 | tmp_params.clock_speed = (compat_ulong_t)info->params.clock_speed; | ||
1187 | tmp_params.addr_filter = info->params.addr_filter; | ||
1188 | tmp_params.crc_type = info->params.crc_type; | ||
1189 | tmp_params.preamble_length = info->params.preamble_length; | ||
1190 | tmp_params.preamble = info->params.preamble; | ||
1191 | tmp_params.data_rate = (compat_ulong_t)info->params.data_rate; | ||
1192 | tmp_params.data_bits = info->params.data_bits; | ||
1193 | tmp_params.stop_bits = info->params.stop_bits; | ||
1194 | tmp_params.parity = info->params.parity; | ||
1195 | if (copy_to_user(user_params, &tmp_params, sizeof(struct MGSL_PARAMS32))) | ||
1196 | return -EFAULT; | ||
1197 | return 0; | ||
1198 | } | ||
1199 | |||
1200 | static long set_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *new_params) | ||
1201 | { | ||
1202 | struct MGSL_PARAMS32 tmp_params; | ||
1203 | |||
1204 | DBGINFO(("%s set_params32\n", info->device_name)); | ||
1205 | if (copy_from_user(&tmp_params, new_params, sizeof(struct MGSL_PARAMS32))) | ||
1206 | return -EFAULT; | ||
1207 | |||
1208 | spin_lock(&info->lock); | ||
1209 | info->params.mode = tmp_params.mode; | ||
1210 | info->params.loopback = tmp_params.loopback; | ||
1211 | info->params.flags = tmp_params.flags; | ||
1212 | info->params.encoding = tmp_params.encoding; | ||
1213 | info->params.clock_speed = tmp_params.clock_speed; | ||
1214 | info->params.addr_filter = tmp_params.addr_filter; | ||
1215 | info->params.crc_type = tmp_params.crc_type; | ||
1216 | info->params.preamble_length = tmp_params.preamble_length; | ||
1217 | info->params.preamble = tmp_params.preamble; | ||
1218 | info->params.data_rate = tmp_params.data_rate; | ||
1219 | info->params.data_bits = tmp_params.data_bits; | ||
1220 | info->params.stop_bits = tmp_params.stop_bits; | ||
1221 | info->params.parity = tmp_params.parity; | ||
1222 | spin_unlock(&info->lock); | ||
1223 | |||
1224 | change_params(info); | ||
1225 | |||
1226 | return 0; | ||
1227 | } | ||
1228 | |||
1229 | static long slgt_compat_ioctl(struct tty_struct *tty, struct file *file, | ||
1230 | unsigned int cmd, unsigned long arg) | ||
1231 | { | ||
1232 | struct slgt_info *info = tty->driver_data; | ||
1233 | int rc = -ENOIOCTLCMD; | ||
1234 | |||
1235 | if (sanity_check(info, tty->name, "compat_ioctl")) | ||
1236 | return -ENODEV; | ||
1237 | DBGINFO(("%s compat_ioctl() cmd=%08X\n", info->device_name, cmd)); | ||
1238 | |||
1239 | switch (cmd) { | ||
1240 | |||
1241 | case MGSL_IOCSPARAMS32: | ||
1242 | rc = set_params32(info, compat_ptr(arg)); | ||
1243 | break; | ||
1244 | |||
1245 | case MGSL_IOCGPARAMS32: | ||
1246 | rc = get_params32(info, compat_ptr(arg)); | ||
1247 | break; | ||
1248 | |||
1249 | case MGSL_IOCGPARAMS: | ||
1250 | case MGSL_IOCSPARAMS: | ||
1251 | case MGSL_IOCGTXIDLE: | ||
1252 | case MGSL_IOCGSTATS: | ||
1253 | case MGSL_IOCWAITEVENT: | ||
1254 | case MGSL_IOCGIF: | ||
1255 | case MGSL_IOCSGPIO: | ||
1256 | case MGSL_IOCGGPIO: | ||
1257 | case MGSL_IOCWAITGPIO: | ||
1258 | case TIOCGICOUNT: | ||
1259 | rc = ioctl(tty, file, cmd, (unsigned long)(compat_ptr(arg))); | ||
1260 | break; | ||
1261 | |||
1262 | case MGSL_IOCSTXIDLE: | ||
1263 | case MGSL_IOCTXENABLE: | ||
1264 | case MGSL_IOCRXENABLE: | ||
1265 | case MGSL_IOCTXABORT: | ||
1266 | case TIOCMIWAIT: | ||
1267 | case MGSL_IOCSIF: | ||
1268 | rc = ioctl(tty, file, cmd, arg); | ||
1269 | break; | ||
1270 | } | ||
1271 | |||
1272 | DBGINFO(("%s compat_ioctl() cmd=%08X rc=%d\n", info->device_name, cmd, rc)); | ||
1273 | return rc; | ||
1274 | } | ||
1275 | #else | ||
1276 | #define slgt_compat_ioctl NULL | ||
1277 | #endif /* ifdef CONFIG_COMPAT */ | ||
1278 | |||
1279 | /* | ||
1174 | * proc fs support | 1280 | * proc fs support |
1175 | */ | 1281 | */ |
1176 | static inline int line_info(char *buf, struct slgt_info *info) | 1282 | static inline int line_info(char *buf, struct slgt_info *info) |
@@ -3446,6 +3552,7 @@ static const struct tty_operations ops = { | |||
3446 | .chars_in_buffer = chars_in_buffer, | 3552 | .chars_in_buffer = chars_in_buffer, |
3447 | .flush_buffer = flush_buffer, | 3553 | .flush_buffer = flush_buffer, |
3448 | .ioctl = ioctl, | 3554 | .ioctl = ioctl, |
3555 | .compat_ioctl = slgt_compat_ioctl, | ||
3449 | .throttle = throttle, | 3556 | .throttle = throttle, |
3450 | .unthrottle = unthrottle, | 3557 | .unthrottle = unthrottle, |
3451 | .send_xchar = send_xchar, | 3558 | .send_xchar = send_xchar, |
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index fc662e4ce58a..fe62c2170d01 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
@@ -151,6 +151,12 @@ static int tty_open(struct inode *, struct file *); | |||
151 | static int tty_release(struct inode *, struct file *); | 151 | static int tty_release(struct inode *, struct file *); |
152 | int tty_ioctl(struct inode * inode, struct file * file, | 152 | int tty_ioctl(struct inode * inode, struct file * file, |
153 | unsigned int cmd, unsigned long arg); | 153 | unsigned int cmd, unsigned long arg); |
154 | #ifdef CONFIG_COMPAT | ||
155 | static long tty_compat_ioctl(struct file * file, unsigned int cmd, | ||
156 | unsigned long arg); | ||
157 | #else | ||
158 | #define tty_compat_ioctl NULL | ||
159 | #endif | ||
154 | static int tty_fasync(int fd, struct file * filp, int on); | 160 | static int tty_fasync(int fd, struct file * filp, int on); |
155 | static void release_tty(struct tty_struct *tty, int idx); | 161 | static void release_tty(struct tty_struct *tty, int idx); |
156 | static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); | 162 | static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); |
@@ -1143,8 +1149,8 @@ static unsigned int hung_up_tty_poll(struct file * filp, poll_table * wait) | |||
1143 | return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM; | 1149 | return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM; |
1144 | } | 1150 | } |
1145 | 1151 | ||
1146 | static int hung_up_tty_ioctl(struct inode * inode, struct file * file, | 1152 | static long hung_up_tty_ioctl(struct file * file, |
1147 | unsigned int cmd, unsigned long arg) | 1153 | unsigned int cmd, unsigned long arg) |
1148 | { | 1154 | { |
1149 | return cmd == TIOCSPGRP ? -ENOTTY : -EIO; | 1155 | return cmd == TIOCSPGRP ? -ENOTTY : -EIO; |
1150 | } | 1156 | } |
@@ -1155,6 +1161,7 @@ static const struct file_operations tty_fops = { | |||
1155 | .write = tty_write, | 1161 | .write = tty_write, |
1156 | .poll = tty_poll, | 1162 | .poll = tty_poll, |
1157 | .ioctl = tty_ioctl, | 1163 | .ioctl = tty_ioctl, |
1164 | .compat_ioctl = tty_compat_ioctl, | ||
1158 | .open = tty_open, | 1165 | .open = tty_open, |
1159 | .release = tty_release, | 1166 | .release = tty_release, |
1160 | .fasync = tty_fasync, | 1167 | .fasync = tty_fasync, |
@@ -1167,6 +1174,7 @@ static const struct file_operations ptmx_fops = { | |||
1167 | .write = tty_write, | 1174 | .write = tty_write, |
1168 | .poll = tty_poll, | 1175 | .poll = tty_poll, |
1169 | .ioctl = tty_ioctl, | 1176 | .ioctl = tty_ioctl, |
1177 | .compat_ioctl = tty_compat_ioctl, | ||
1170 | .open = ptmx_open, | 1178 | .open = ptmx_open, |
1171 | .release = tty_release, | 1179 | .release = tty_release, |
1172 | .fasync = tty_fasync, | 1180 | .fasync = tty_fasync, |
@@ -1179,6 +1187,7 @@ static const struct file_operations console_fops = { | |||
1179 | .write = redirected_tty_write, | 1187 | .write = redirected_tty_write, |
1180 | .poll = tty_poll, | 1188 | .poll = tty_poll, |
1181 | .ioctl = tty_ioctl, | 1189 | .ioctl = tty_ioctl, |
1190 | .compat_ioctl = tty_compat_ioctl, | ||
1182 | .open = tty_open, | 1191 | .open = tty_open, |
1183 | .release = tty_release, | 1192 | .release = tty_release, |
1184 | .fasync = tty_fasync, | 1193 | .fasync = tty_fasync, |
@@ -1189,7 +1198,8 @@ static const struct file_operations hung_up_tty_fops = { | |||
1189 | .read = hung_up_tty_read, | 1198 | .read = hung_up_tty_read, |
1190 | .write = hung_up_tty_write, | 1199 | .write = hung_up_tty_write, |
1191 | .poll = hung_up_tty_poll, | 1200 | .poll = hung_up_tty_poll, |
1192 | .ioctl = hung_up_tty_ioctl, | 1201 | .unlocked_ioctl = hung_up_tty_ioctl, |
1202 | .compat_ioctl = hung_up_tty_ioctl, | ||
1193 | .release = tty_release, | 1203 | .release = tty_release, |
1194 | }; | 1204 | }; |
1195 | 1205 | ||
@@ -3357,6 +3367,32 @@ int tty_ioctl(struct inode * inode, struct file * file, | |||
3357 | return retval; | 3367 | return retval; |
3358 | } | 3368 | } |
3359 | 3369 | ||
3370 | #ifdef CONFIG_COMPAT | ||
3371 | static long tty_compat_ioctl(struct file * file, unsigned int cmd, | ||
3372 | unsigned long arg) | ||
3373 | { | ||
3374 | struct inode *inode = file->f_dentry->d_inode; | ||
3375 | struct tty_struct *tty = file->private_data; | ||
3376 | struct tty_ldisc *ld; | ||
3377 | int retval = -ENOIOCTLCMD; | ||
3378 | |||
3379 | if (tty_paranoia_check(tty, inode, "tty_ioctl")) | ||
3380 | return -EINVAL; | ||
3381 | |||
3382 | if (tty->driver->compat_ioctl) { | ||
3383 | retval = (tty->driver->compat_ioctl)(tty, file, cmd, arg); | ||
3384 | if (retval != -ENOIOCTLCMD) | ||
3385 | return retval; | ||
3386 | } | ||
3387 | |||
3388 | ld = tty_ldisc_ref_wait(tty); | ||
3389 | if (ld->compat_ioctl) | ||
3390 | retval = ld->compat_ioctl(tty, file, cmd, arg); | ||
3391 | tty_ldisc_deref(ld); | ||
3392 | |||
3393 | return retval; | ||
3394 | } | ||
3395 | #endif | ||
3360 | 3396 | ||
3361 | /* | 3397 | /* |
3362 | * This implements the "Secure Attention Key" --- the idea is to | 3398 | * This implements the "Secure Attention Key" --- the idea is to |
@@ -3689,6 +3725,7 @@ void tty_set_operations(struct tty_driver *driver, | |||
3689 | driver->write_room = op->write_room; | 3725 | driver->write_room = op->write_room; |
3690 | driver->chars_in_buffer = op->chars_in_buffer; | 3726 | driver->chars_in_buffer = op->chars_in_buffer; |
3691 | driver->ioctl = op->ioctl; | 3727 | driver->ioctl = op->ioctl; |
3728 | driver->compat_ioctl = op->compat_ioctl; | ||
3692 | driver->set_termios = op->set_termios; | 3729 | driver->set_termios = op->set_termios; |
3693 | driver->throttle = op->throttle; | 3730 | driver->throttle = op->throttle; |
3694 | driver->unthrottle = op->unthrottle; | 3731 | driver->unthrottle = op->unthrottle; |
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index a19b65ed3119..7f817897b178 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c | |||
@@ -240,11 +240,94 @@ static inline void hidinput_pb_setup(struct input_dev *input) | |||
240 | } | 240 | } |
241 | #endif | 241 | #endif |
242 | 242 | ||
243 | static inline int match_scancode(int code, int scancode) | ||
244 | { | ||
245 | if (scancode == 0) | ||
246 | return 1; | ||
247 | return ((code & (HID_USAGE_PAGE | HID_USAGE)) == scancode); | ||
248 | } | ||
249 | |||
250 | static inline int match_keycode(int code, int keycode) | ||
251 | { | ||
252 | if (keycode == 0) | ||
253 | return 1; | ||
254 | return (code == keycode); | ||
255 | } | ||
256 | |||
257 | static struct hid_usage *hidinput_find_key(struct hid_device *hid, | ||
258 | int scancode, int keycode) | ||
259 | { | ||
260 | int i, j, k; | ||
261 | struct hid_report *report; | ||
262 | struct hid_usage *usage; | ||
263 | |||
264 | for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) { | ||
265 | list_for_each_entry(report, &hid->report_enum[k].report_list, list) { | ||
266 | for (i = 0; i < report->maxfield; i++) { | ||
267 | for ( j = 0; j < report->field[i]->maxusage; j++) { | ||
268 | usage = report->field[i]->usage + j; | ||
269 | if (usage->type == EV_KEY && | ||
270 | match_scancode(usage->hid, scancode) && | ||
271 | match_keycode(usage->code, keycode)) | ||
272 | return usage; | ||
273 | } | ||
274 | } | ||
275 | } | ||
276 | } | ||
277 | return NULL; | ||
278 | } | ||
279 | |||
280 | static int hidinput_getkeycode(struct input_dev *dev, int scancode, | ||
281 | int *keycode) | ||
282 | { | ||
283 | struct hid_device *hid = dev->private; | ||
284 | struct hid_usage *usage; | ||
285 | |||
286 | usage = hidinput_find_key(hid, scancode, 0); | ||
287 | if (usage) { | ||
288 | *keycode = usage->code; | ||
289 | return 0; | ||
290 | } | ||
291 | return -EINVAL; | ||
292 | } | ||
293 | |||
294 | static int hidinput_setkeycode(struct input_dev *dev, int scancode, | ||
295 | int keycode) | ||
296 | { | ||
297 | struct hid_device *hid = dev->private; | ||
298 | struct hid_usage *usage; | ||
299 | int old_keycode; | ||
300 | |||
301 | if (keycode < 0 || keycode > KEY_MAX) | ||
302 | return -EINVAL; | ||
303 | |||
304 | usage = hidinput_find_key(hid, scancode, 0); | ||
305 | if (usage) { | ||
306 | old_keycode = usage->code; | ||
307 | usage->code = keycode; | ||
308 | |||
309 | clear_bit(old_keycode, dev->keybit); | ||
310 | set_bit(usage->code, dev->keybit); | ||
311 | #ifdef CONFIG_HID_DEBUG | ||
312 | printk (KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode); | ||
313 | #endif | ||
314 | /* Set the keybit for the old keycode if the old keycode is used | ||
315 | * by another key */ | ||
316 | if (hidinput_find_key (hid, 0, old_keycode)) | ||
317 | set_bit(old_keycode, dev->keybit); | ||
318 | |||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | return -EINVAL; | ||
323 | } | ||
324 | |||
325 | |||
243 | static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, | 326 | static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, |
244 | struct hid_usage *usage) | 327 | struct hid_usage *usage) |
245 | { | 328 | { |
246 | struct input_dev *input = hidinput->input; | 329 | struct input_dev *input = hidinput->input; |
247 | struct hid_device *device = input->private; | 330 | struct hid_device *device = input_get_drvdata(input); |
248 | int max = 0, code; | 331 | int max = 0, code; |
249 | unsigned long *bit = NULL; | 332 | unsigned long *bit = NULL; |
250 | 333 | ||
@@ -553,6 +636,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
553 | case 0x1015: map_key_clear(KEY_RECORD); break; | 636 | case 0x1015: map_key_clear(KEY_RECORD); break; |
554 | case 0x1016: map_key_clear(KEY_PLAYER); break; | 637 | case 0x1016: map_key_clear(KEY_PLAYER); break; |
555 | case 0x1017: map_key_clear(KEY_EJECTCD); break; | 638 | case 0x1017: map_key_clear(KEY_EJECTCD); break; |
639 | case 0x1018: map_key_clear(KEY_MEDIA); break; | ||
556 | case 0x1019: map_key_clear(KEY_PROG1); break; | 640 | case 0x1019: map_key_clear(KEY_PROG1); break; |
557 | case 0x101a: map_key_clear(KEY_PROG2); break; | 641 | case 0x101a: map_key_clear(KEY_PROG2); break; |
558 | case 0x101b: map_key_clear(KEY_PROG3); break; | 642 | case 0x101b: map_key_clear(KEY_PROG3); break; |
@@ -560,9 +644,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
560 | case 0x1020: map_key_clear(KEY_ZOOMOUT); break; | 644 | case 0x1020: map_key_clear(KEY_ZOOMOUT); break; |
561 | case 0x1021: map_key_clear(KEY_ZOOMRESET); break; | 645 | case 0x1021: map_key_clear(KEY_ZOOMRESET); break; |
562 | case 0x1023: map_key_clear(KEY_CLOSE); break; | 646 | case 0x1023: map_key_clear(KEY_CLOSE); break; |
647 | case 0x1027: map_key_clear(KEY_MENU); break; | ||
563 | /* this one is marked as 'Rotate' */ | 648 | /* this one is marked as 'Rotate' */ |
564 | case 0x1028: map_key_clear(KEY_ANGLE); break; | 649 | case 0x1028: map_key_clear(KEY_ANGLE); break; |
565 | case 0x1029: map_key_clear(KEY_SHUFFLE); break; | 650 | case 0x1029: map_key_clear(KEY_SHUFFLE); break; |
651 | case 0x102a: map_key_clear(KEY_BACK); break; | ||
652 | case 0x102b: map_key_clear(KEY_CYCLEWINDOWS); break; | ||
566 | case 0x1041: map_key_clear(KEY_BATTERY); break; | 653 | case 0x1041: map_key_clear(KEY_BATTERY); break; |
567 | case 0x1042: map_key_clear(KEY_WORDPROCESSOR); break; | 654 | case 0x1042: map_key_clear(KEY_WORDPROCESSOR); break; |
568 | case 0x1043: map_key_clear(KEY_SPREADSHEET); break; | 655 | case 0x1043: map_key_clear(KEY_SPREADSHEET); break; |
@@ -855,13 +942,15 @@ EXPORT_SYMBOL_GPL(hidinput_find_field); | |||
855 | 942 | ||
856 | static int hidinput_open(struct input_dev *dev) | 943 | static int hidinput_open(struct input_dev *dev) |
857 | { | 944 | { |
858 | struct hid_device *hid = dev->private; | 945 | struct hid_device *hid = input_get_drvdata(dev); |
946 | |||
859 | return hid->hid_open(hid); | 947 | return hid->hid_open(hid); |
860 | } | 948 | } |
861 | 949 | ||
862 | static void hidinput_close(struct input_dev *dev) | 950 | static void hidinput_close(struct input_dev *dev) |
863 | { | 951 | { |
864 | struct hid_device *hid = dev->private; | 952 | struct hid_device *hid = input_get_drvdata(dev); |
953 | |||
865 | hid->hid_close(hid); | 954 | hid->hid_close(hid); |
866 | } | 955 | } |
867 | 956 | ||
@@ -909,10 +998,12 @@ int hidinput_connect(struct hid_device *hid) | |||
909 | return -1; | 998 | return -1; |
910 | } | 999 | } |
911 | 1000 | ||
912 | input_dev->private = hid; | 1001 | input_set_drvdata(input_dev, hid); |
913 | input_dev->event = hid->hidinput_input_event; | 1002 | input_dev->event = hid->hidinput_input_event; |
914 | input_dev->open = hidinput_open; | 1003 | input_dev->open = hidinput_open; |
915 | input_dev->close = hidinput_close; | 1004 | input_dev->close = hidinput_close; |
1005 | input_dev->setkeycode = hidinput_setkeycode; | ||
1006 | input_dev->getkeycode = hidinput_getkeycode; | ||
916 | 1007 | ||
917 | input_dev->name = hid->name; | 1008 | input_dev->name = hid->name; |
918 | input_dev->phys = hid->phys; | 1009 | input_dev->phys = hid->phys; |
@@ -921,7 +1012,7 @@ int hidinput_connect(struct hid_device *hid) | |||
921 | input_dev->id.vendor = hid->vendor; | 1012 | input_dev->id.vendor = hid->vendor; |
922 | input_dev->id.product = hid->product; | 1013 | input_dev->id.product = hid->product; |
923 | input_dev->id.version = hid->version; | 1014 | input_dev->id.version = hid->version; |
924 | input_dev->cdev.dev = hid->dev; | 1015 | input_dev->dev.parent = hid->dev; |
925 | hidinput->input = input_dev; | 1016 | hidinput->input = input_dev; |
926 | list_add_tail(&hidinput->list, &hid->inputs); | 1017 | list_add_tail(&hidinput->list, &hid->inputs); |
927 | } | 1018 | } |
diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig index 7c87bdc538bc..1b4b572f899b 100644 --- a/drivers/hid/usbhid/Kconfig +++ b/drivers/hid/usbhid/Kconfig | |||
@@ -25,12 +25,12 @@ comment "Input core support is needed for USB HID input layer or HIDBP support" | |||
25 | depends on USB_HID && INPUT=n | 25 | depends on USB_HID && INPUT=n |
26 | 26 | ||
27 | config USB_HIDINPUT_POWERBOOK | 27 | config USB_HIDINPUT_POWERBOOK |
28 | bool "Enable support for iBook/PowerBook special keys" | 28 | bool "Enable support for iBook/PowerBook/MacBook/MacBookPro special keys" |
29 | default n | 29 | default n |
30 | depends on USB_HID | 30 | depends on USB_HID |
31 | help | 31 | help |
32 | Say Y here if you want support for the special keys (Fn, Numlock) on | 32 | Say Y here if you want support for the special keys (Fn, Numlock) on |
33 | Apple iBooks and PowerBooks. | 33 | Apple iBooks, PowerBooks, MacBooks and MacBook Pros. |
34 | 34 | ||
35 | If unsure, say N. | 35 | If unsure, say N. |
36 | 36 | ||
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 91d610358d57..d91b9dac6dff 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c | |||
@@ -446,7 +446,7 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns | |||
446 | 446 | ||
447 | static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | 447 | static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) |
448 | { | 448 | { |
449 | struct hid_device *hid = dev->private; | 449 | struct hid_device *hid = input_get_drvdata(dev); |
450 | struct hid_field *field; | 450 | struct hid_field *field; |
451 | int offset; | 451 | int offset; |
452 | 452 | ||
@@ -626,14 +626,10 @@ static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) | |||
626 | { | 626 | { |
627 | struct usbhid_device *usbhid = hid->driver_data; | 627 | struct usbhid_device *usbhid = hid->driver_data; |
628 | 628 | ||
629 | if (usbhid->inbuf) | 629 | usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma); |
630 | usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma); | 630 | usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma); |
631 | if (usbhid->outbuf) | 631 | usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma); |
632 | usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma); | 632 | usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma); |
633 | if (usbhid->cr) | ||
634 | usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma); | ||
635 | if (usbhid->ctrlbuf) | ||
636 | usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma); | ||
637 | } | 633 | } |
638 | 634 | ||
639 | /* | 635 | /* |
@@ -692,6 +688,30 @@ static void hid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize) | |||
692 | } | 688 | } |
693 | } | 689 | } |
694 | 690 | ||
691 | /* | ||
692 | * Some USB barcode readers from cypress have usage min and usage max in | ||
693 | * the wrong order | ||
694 | */ | ||
695 | static void hid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize) | ||
696 | { | ||
697 | short fixed = 0; | ||
698 | int i; | ||
699 | |||
700 | for (i = 0; i < rsize - 4; i++) { | ||
701 | if (rdesc[i] == 0x29 && rdesc [i+2] == 0x19) { | ||
702 | unsigned char tmp; | ||
703 | |||
704 | rdesc[i] = 0x19; rdesc[i+2] = 0x29; | ||
705 | tmp = rdesc[i+3]; | ||
706 | rdesc[i+3] = rdesc[i+1]; | ||
707 | rdesc[i+1] = tmp; | ||
708 | } | ||
709 | } | ||
710 | |||
711 | if (fixed) | ||
712 | info("Fixing up Cypress report descriptor"); | ||
713 | } | ||
714 | |||
695 | static struct hid_device *usb_hid_configure(struct usb_interface *intf) | 715 | static struct hid_device *usb_hid_configure(struct usb_interface *intf) |
696 | { | 716 | { |
697 | struct usb_host_interface *interface = intf->cur_altsetting; | 717 | struct usb_host_interface *interface = intf->cur_altsetting; |
@@ -758,6 +778,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) | |||
758 | if (quirks & HID_QUIRK_LOGITECH_DESCRIPTOR) | 778 | if (quirks & HID_QUIRK_LOGITECH_DESCRIPTOR) |
759 | hid_fixup_logitech_descriptor(rdesc, rsize); | 779 | hid_fixup_logitech_descriptor(rdesc, rsize); |
760 | 780 | ||
781 | if (quirks & HID_QUIRK_SWAPPED_MIN_MAX) | ||
782 | hid_fixup_cypress_descriptor(rdesc, rsize); | ||
783 | |||
761 | #ifdef CONFIG_HID_DEBUG | 784 | #ifdef CONFIG_HID_DEBUG |
762 | printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n); | 785 | printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n); |
763 | for (n = 0; n < rsize; n++) | 786 | for (n = 0; n < rsize; n++) |
diff --git a/drivers/hid/usbhid/hid-lgff.c b/drivers/hid/usbhid/hid-lgff.c index 92d2553f17b6..c5cd4107d6af 100644 --- a/drivers/hid/usbhid/hid-lgff.c +++ b/drivers/hid/usbhid/hid-lgff.c | |||
@@ -60,7 +60,7 @@ static const struct dev_type devices[] = { | |||
60 | 60 | ||
61 | static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect) | 61 | static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect) |
62 | { | 62 | { |
63 | struct hid_device *hid = dev->private; | 63 | struct hid_device *hid = input_get_drvdata(dev); |
64 | struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; | 64 | struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; |
65 | struct hid_report *report = list_entry(report_list->next, struct hid_report, list); | 65 | struct hid_report *report = list_entry(report_list->next, struct hid_report, list); |
66 | int x, y; | 66 | int x, y; |
diff --git a/drivers/hid/usbhid/hid-plff.c b/drivers/hid/usbhid/hid-plff.c index 76d2e6e14db4..d6a8f2b49bd2 100644 --- a/drivers/hid/usbhid/hid-plff.c +++ b/drivers/hid/usbhid/hid-plff.c | |||
@@ -37,7 +37,7 @@ struct plff_device { | |||
37 | static int hid_plff_play(struct input_dev *dev, void *data, | 37 | static int hid_plff_play(struct input_dev *dev, void *data, |
38 | struct ff_effect *effect) | 38 | struct ff_effect *effect) |
39 | { | 39 | { |
40 | struct hid_device *hid = dev->private; | 40 | struct hid_device *hid = input_get_drvdata(dev); |
41 | struct plff_device *plff = data; | 41 | struct plff_device *plff = data; |
42 | int left, right; | 42 | int left, right; |
43 | 43 | ||
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 17a87555e32f..f6c4145dc202 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c | |||
@@ -92,6 +92,8 @@ | |||
92 | #define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001 | 92 | #define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001 |
93 | #define USB_DEVICE_ID_CYPRESS_HIDCOM 0x5500 | 93 | #define USB_DEVICE_ID_CYPRESS_HIDCOM 0x5500 |
94 | #define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE 0x7417 | 94 | #define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE 0x7417 |
95 | #define USB_DEVICE_ID_CYPRESS_BARCODE_1 0xde61 | ||
96 | #define USB_DEVICE_ID_CYPRESS_BARCODE_2 0xde64 | ||
95 | 97 | ||
96 | #define USB_VENDOR_ID_DELL 0x413c | 98 | #define USB_VENDOR_ID_DELL 0x413c |
97 | #define USB_DEVICE_ID_DELL_W7658 0x2005 | 99 | #define USB_DEVICE_ID_DELL_W7658 0x2005 |
@@ -193,6 +195,7 @@ | |||
193 | 195 | ||
194 | #define USB_VENDOR_ID_LOGITECH 0x046d | 196 | #define USB_VENDOR_ID_LOGITECH 0x046d |
195 | #define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 | 197 | #define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 |
198 | #define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294 | ||
196 | #define USB_DEVICE_ID_S510_RECEIVER 0xc50c | 199 | #define USB_DEVICE_ID_S510_RECEIVER 0xc50c |
197 | #define USB_DEVICE_ID_S510_RECEIVER_2 0xc517 | 200 | #define USB_DEVICE_ID_S510_RECEIVER_2 0xc517 |
198 | #define USB_DEVICE_ID_MX3000_RECEIVER 0xc513 | 201 | #define USB_DEVICE_ID_MX3000_RECEIVER 0xc513 |
@@ -422,6 +425,7 @@ static const struct hid_blacklist { | |||
422 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, | 425 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, |
423 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, | 426 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, |
424 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, | 427 | { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, |
428 | { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET }, | ||
425 | { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, | 429 | { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, |
426 | { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, | 430 | { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, |
427 | { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, | 431 | { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, |
@@ -445,6 +449,9 @@ static const struct hid_blacklist { | |||
445 | 449 | ||
446 | { USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS }, | 450 | { USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS }, |
447 | 451 | ||
452 | { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_SWAPPED_MIN_MAX }, | ||
453 | { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_SWAPPED_MIN_MAX }, | ||
454 | |||
448 | { 0, 0 } | 455 | { 0, 0 } |
449 | }; | 456 | }; |
450 | 457 | ||
diff --git a/drivers/hid/usbhid/hid-tmff.c b/drivers/hid/usbhid/hid-tmff.c index ab67331620d0..ab5ba6ef891c 100644 --- a/drivers/hid/usbhid/hid-tmff.c +++ b/drivers/hid/usbhid/hid-tmff.c | |||
@@ -59,7 +59,7 @@ static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum) | |||
59 | 59 | ||
60 | static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect) | 60 | static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect) |
61 | { | 61 | { |
62 | struct hid_device *hid = dev->private; | 62 | struct hid_device *hid = input_get_drvdata(dev); |
63 | struct tmff_device *tmff = data; | 63 | struct tmff_device *tmff = data; |
64 | int left, right; /* Rumbling */ | 64 | int left, right; /* Rumbling */ |
65 | 65 | ||
diff --git a/drivers/hid/usbhid/hid-zpff.c b/drivers/hid/usbhid/hid-zpff.c index 7bd8238ca212..a7fbffcdaf36 100644 --- a/drivers/hid/usbhid/hid-zpff.c +++ b/drivers/hid/usbhid/hid-zpff.c | |||
@@ -37,7 +37,7 @@ struct zpff_device { | |||
37 | static int hid_zpff_play(struct input_dev *dev, void *data, | 37 | static int hid_zpff_play(struct input_dev *dev, void *data, |
38 | struct ff_effect *effect) | 38 | struct ff_effect *effect) |
39 | { | 39 | { |
40 | struct hid_device *hid = dev->private; | 40 | struct hid_device *hid = input_get_drvdata(dev); |
41 | struct zpff_device *zpff = data; | 41 | struct zpff_device *zpff = data; |
42 | int left, right; | 42 | int left, right; |
43 | 43 | ||
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index a8b3d66cd498..488d61bdbf2c 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c | |||
@@ -51,6 +51,7 @@ struct hiddev { | |||
51 | wait_queue_head_t wait; | 51 | wait_queue_head_t wait; |
52 | struct hid_device *hid; | 52 | struct hid_device *hid; |
53 | struct list_head list; | 53 | struct list_head list; |
54 | spinlock_t list_lock; | ||
54 | }; | 55 | }; |
55 | 56 | ||
56 | struct hiddev_list { | 57 | struct hiddev_list { |
@@ -161,7 +162,9 @@ static void hiddev_send_event(struct hid_device *hid, | |||
161 | { | 162 | { |
162 | struct hiddev *hiddev = hid->hiddev; | 163 | struct hiddev *hiddev = hid->hiddev; |
163 | struct hiddev_list *list; | 164 | struct hiddev_list *list; |
165 | unsigned long flags; | ||
164 | 166 | ||
167 | spin_lock_irqsave(&hiddev->list_lock, flags); | ||
165 | list_for_each_entry(list, &hiddev->list, node) { | 168 | list_for_each_entry(list, &hiddev->list, node) { |
166 | if (uref->field_index != HID_FIELD_INDEX_NONE || | 169 | if (uref->field_index != HID_FIELD_INDEX_NONE || |
167 | (list->flags & HIDDEV_FLAG_REPORT) != 0) { | 170 | (list->flags & HIDDEV_FLAG_REPORT) != 0) { |
@@ -171,6 +174,7 @@ static void hiddev_send_event(struct hid_device *hid, | |||
171 | kill_fasync(&list->fasync, SIGIO, POLL_IN); | 174 | kill_fasync(&list->fasync, SIGIO, POLL_IN); |
172 | } | 175 | } |
173 | } | 176 | } |
177 | spin_unlock_irqrestore(&hiddev->list_lock, flags); | ||
174 | 178 | ||
175 | wake_up_interruptible(&hiddev->wait); | 179 | wake_up_interruptible(&hiddev->wait); |
176 | } | 180 | } |
@@ -235,9 +239,13 @@ static int hiddev_fasync(int fd, struct file *file, int on) | |||
235 | static int hiddev_release(struct inode * inode, struct file * file) | 239 | static int hiddev_release(struct inode * inode, struct file * file) |
236 | { | 240 | { |
237 | struct hiddev_list *list = file->private_data; | 241 | struct hiddev_list *list = file->private_data; |
242 | unsigned long flags; | ||
238 | 243 | ||
239 | hiddev_fasync(-1, file, 0); | 244 | hiddev_fasync(-1, file, 0); |
245 | |||
246 | spin_lock_irqsave(&list->hiddev->list_lock, flags); | ||
240 | list_del(&list->node); | 247 | list_del(&list->node); |
248 | spin_unlock_irqrestore(&list->hiddev->list_lock, flags); | ||
241 | 249 | ||
242 | if (!--list->hiddev->open) { | 250 | if (!--list->hiddev->open) { |
243 | if (list->hiddev->exist) | 251 | if (list->hiddev->exist) |
@@ -257,6 +265,7 @@ static int hiddev_release(struct inode * inode, struct file * file) | |||
257 | static int hiddev_open(struct inode *inode, struct file *file) | 265 | static int hiddev_open(struct inode *inode, struct file *file) |
258 | { | 266 | { |
259 | struct hiddev_list *list; | 267 | struct hiddev_list *list; |
268 | unsigned long flags; | ||
260 | 269 | ||
261 | int i = iminor(inode) - HIDDEV_MINOR_BASE; | 270 | int i = iminor(inode) - HIDDEV_MINOR_BASE; |
262 | 271 | ||
@@ -267,7 +276,11 @@ static int hiddev_open(struct inode *inode, struct file *file) | |||
267 | return -ENOMEM; | 276 | return -ENOMEM; |
268 | 277 | ||
269 | list->hiddev = hiddev_table[i]; | 278 | list->hiddev = hiddev_table[i]; |
279 | |||
280 | spin_lock_irqsave(&list->hiddev->list_lock, flags); | ||
270 | list_add_tail(&list->node, &hiddev_table[i]->list); | 281 | list_add_tail(&list->node, &hiddev_table[i]->list); |
282 | spin_unlock_irqrestore(&list->hiddev->list_lock, flags); | ||
283 | |||
271 | file->private_data = list; | 284 | file->private_data = list; |
272 | 285 | ||
273 | if (!list->hiddev->open++) | 286 | if (!list->hiddev->open++) |
@@ -773,6 +786,7 @@ int hiddev_connect(struct hid_device *hid) | |||
773 | 786 | ||
774 | init_waitqueue_head(&hiddev->wait); | 787 | init_waitqueue_head(&hiddev->wait); |
775 | INIT_LIST_HEAD(&hiddev->list); | 788 | INIT_LIST_HEAD(&hiddev->list); |
789 | spin_lock_init(&hiddev->list_lock); | ||
776 | hiddev->hid = hid; | 790 | hiddev->hid = hid; |
777 | hiddev->exist = 1; | 791 | hiddev->exist = 1; |
778 | 792 | ||
diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c index 65aa12e8d7b3..130978780713 100644 --- a/drivers/hid/usbhid/usbkbd.c +++ b/drivers/hid/usbhid/usbkbd.c | |||
@@ -133,12 +133,11 @@ resubmit: | |||
133 | static int usb_kbd_event(struct input_dev *dev, unsigned int type, | 133 | static int usb_kbd_event(struct input_dev *dev, unsigned int type, |
134 | unsigned int code, int value) | 134 | unsigned int code, int value) |
135 | { | 135 | { |
136 | struct usb_kbd *kbd = dev->private; | 136 | struct usb_kbd *kbd = input_get_drvdata(dev); |
137 | 137 | ||
138 | if (type != EV_LED) | 138 | if (type != EV_LED) |
139 | return -1; | 139 | return -1; |
140 | 140 | ||
141 | |||
142 | kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) | | 141 | kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) | |
143 | (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) | | 142 | (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) | |
144 | (!!test_bit(LED_NUML, dev->led)); | 143 | (!!test_bit(LED_NUML, dev->led)); |
@@ -175,7 +174,7 @@ static void usb_kbd_led(struct urb *urb) | |||
175 | 174 | ||
176 | static int usb_kbd_open(struct input_dev *dev) | 175 | static int usb_kbd_open(struct input_dev *dev) |
177 | { | 176 | { |
178 | struct usb_kbd *kbd = dev->private; | 177 | struct usb_kbd *kbd = input_get_drvdata(dev); |
179 | 178 | ||
180 | kbd->irq->dev = kbd->usbdev; | 179 | kbd->irq->dev = kbd->usbdev; |
181 | if (usb_submit_urb(kbd->irq, GFP_KERNEL)) | 180 | if (usb_submit_urb(kbd->irq, GFP_KERNEL)) |
@@ -186,7 +185,7 @@ static int usb_kbd_open(struct input_dev *dev) | |||
186 | 185 | ||
187 | static void usb_kbd_close(struct input_dev *dev) | 186 | static void usb_kbd_close(struct input_dev *dev) |
188 | { | 187 | { |
189 | struct usb_kbd *kbd = dev->private; | 188 | struct usb_kbd *kbd = input_get_drvdata(dev); |
190 | 189 | ||
191 | usb_kill_urb(kbd->irq); | 190 | usb_kill_urb(kbd->irq); |
192 | } | 191 | } |
@@ -211,12 +210,9 @@ static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd) | |||
211 | { | 210 | { |
212 | usb_free_urb(kbd->irq); | 211 | usb_free_urb(kbd->irq); |
213 | usb_free_urb(kbd->led); | 212 | usb_free_urb(kbd->led); |
214 | if (kbd->new) | 213 | usb_buffer_free(dev, 8, kbd->new, kbd->new_dma); |
215 | usb_buffer_free(dev, 8, kbd->new, kbd->new_dma); | 214 | usb_buffer_free(dev, sizeof(struct usb_ctrlrequest), kbd->cr, kbd->cr_dma); |
216 | if (kbd->cr) | 215 | usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma); |
217 | usb_buffer_free(dev, sizeof(struct usb_ctrlrequest), kbd->cr, kbd->cr_dma); | ||
218 | if (kbd->leds) | ||
219 | usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma); | ||
220 | } | 216 | } |
221 | 217 | ||
222 | static int usb_kbd_probe(struct usb_interface *iface, | 218 | static int usb_kbd_probe(struct usb_interface *iface, |
@@ -274,8 +270,9 @@ static int usb_kbd_probe(struct usb_interface *iface, | |||
274 | input_dev->name = kbd->name; | 270 | input_dev->name = kbd->name; |
275 | input_dev->phys = kbd->phys; | 271 | input_dev->phys = kbd->phys; |
276 | usb_to_input_id(dev, &input_dev->id); | 272 | usb_to_input_id(dev, &input_dev->id); |
277 | input_dev->cdev.dev = &iface->dev; | 273 | input_dev->dev.parent = &iface->dev; |
278 | input_dev->private = kbd; | 274 | |
275 | input_set_drvdata(input_dev, kbd); | ||
279 | 276 | ||
280 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); | 277 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); |
281 | input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA); | 278 | input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA); |
diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c index 573776d865e1..5345c73bcf62 100644 --- a/drivers/hid/usbhid/usbmouse.c +++ b/drivers/hid/usbhid/usbmouse.c | |||
@@ -96,7 +96,7 @@ resubmit: | |||
96 | 96 | ||
97 | static int usb_mouse_open(struct input_dev *dev) | 97 | static int usb_mouse_open(struct input_dev *dev) |
98 | { | 98 | { |
99 | struct usb_mouse *mouse = dev->private; | 99 | struct usb_mouse *mouse = input_get_drvdata(dev); |
100 | 100 | ||
101 | mouse->irq->dev = mouse->usbdev; | 101 | mouse->irq->dev = mouse->usbdev; |
102 | if (usb_submit_urb(mouse->irq, GFP_KERNEL)) | 102 | if (usb_submit_urb(mouse->irq, GFP_KERNEL)) |
@@ -107,7 +107,7 @@ static int usb_mouse_open(struct input_dev *dev) | |||
107 | 107 | ||
108 | static void usb_mouse_close(struct input_dev *dev) | 108 | static void usb_mouse_close(struct input_dev *dev) |
109 | { | 109 | { |
110 | struct usb_mouse *mouse = dev->private; | 110 | struct usb_mouse *mouse = input_get_drvdata(dev); |
111 | 111 | ||
112 | usb_kill_urb(mouse->irq); | 112 | usb_kill_urb(mouse->irq); |
113 | } | 113 | } |
@@ -171,7 +171,7 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i | |||
171 | input_dev->name = mouse->name; | 171 | input_dev->name = mouse->name; |
172 | input_dev->phys = mouse->phys; | 172 | input_dev->phys = mouse->phys; |
173 | usb_to_input_id(dev, &input_dev->id); | 173 | usb_to_input_id(dev, &input_dev->id); |
174 | input_dev->cdev.dev = &intf->dev; | 174 | input_dev->dev.parent = &intf->dev; |
175 | 175 | ||
176 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); | 176 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); |
177 | input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); | 177 | input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); |
@@ -179,7 +179,8 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i | |||
179 | input_dev->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA); | 179 | input_dev->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA); |
180 | input_dev->relbit[0] |= BIT(REL_WHEEL); | 180 | input_dev->relbit[0] |= BIT(REL_WHEEL); |
181 | 181 | ||
182 | input_dev->private = mouse; | 182 | input_set_drvdata(input_dev, mouse); |
183 | |||
183 | input_dev->open = usb_mouse_open; | 184 | input_dev->open = usb_mouse_open; |
184 | input_dev->close = usb_mouse_close; | 185 | input_dev->close = usb_mouse_close; |
185 | 186 | ||
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 55a72592704c..b234729706be 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
@@ -336,7 +336,7 @@ static int bits_to_user(unsigned long *bits, unsigned int maxbit, | |||
336 | 336 | ||
337 | if (compat) { | 337 | if (compat) { |
338 | len = NBITS_COMPAT(maxbit) * sizeof(compat_long_t); | 338 | len = NBITS_COMPAT(maxbit) * sizeof(compat_long_t); |
339 | if (len < maxlen) | 339 | if (len > maxlen) |
340 | len = maxlen; | 340 | len = maxlen; |
341 | 341 | ||
342 | for (i = 0; i < len / sizeof(compat_long_t); i++) | 342 | for (i = 0; i < len / sizeof(compat_long_t); i++) |
diff --git a/drivers/md/md.c b/drivers/md/md.c index 65814b0340cb..c10ce91b64e9 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
@@ -5103,7 +5103,7 @@ static int is_mddev_idle(mddev_t *mddev) | |||
5103 | * | 5103 | * |
5104 | * Note: the following is an unsigned comparison. | 5104 | * Note: the following is an unsigned comparison. |
5105 | */ | 5105 | */ |
5106 | if ((curr_events - rdev->last_events + 4096) > 8192) { | 5106 | if ((long)curr_events - (long)rdev->last_events > 4096) { |
5107 | rdev->last_events = curr_events; | 5107 | rdev->last_events = curr_events; |
5108 | idle = 0; | 5108 | idle = 0; |
5109 | } | 5109 | } |
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index 7c8ccc09b601..829da9a1d113 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig | |||
@@ -141,6 +141,20 @@ config ACT200L_DONGLE | |||
141 | To activate support for ACTiSYS IR-200L dongle you will have to | 141 | To activate support for ACTiSYS IR-200L dongle you will have to |
142 | start irattach like this: "irattach -d act200l". | 142 | start irattach like this: "irattach -d act200l". |
143 | 143 | ||
144 | config KINGSUN_DONGLE | ||
145 | tristate "KingSun/DonShine DS-620 IrDA-USB dongle" | ||
146 | depends on IRDA && USB && EXPERIMENTAL | ||
147 | help | ||
148 | Say Y or M here if you want to build support for the KingSun/DonShine | ||
149 | DS-620 IrDA-USB bridge device driver. | ||
150 | |||
151 | This USB bridge does not conform to the IrDA-USB device class | ||
152 | specification, and therefore needs its own specific driver. This | ||
153 | dongle supports SIR speed only (9600 bps). | ||
154 | |||
155 | To compile it as a module, choose M here: the module will be called | ||
156 | kingsun-sir. | ||
157 | |||
144 | comment "Old SIR device drivers" | 158 | comment "Old SIR device drivers" |
145 | 159 | ||
146 | config IRPORT_SIR | 160 | config IRPORT_SIR |
diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index 5be09f1b9ee2..233a2f923730 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile | |||
@@ -45,6 +45,7 @@ obj-$(CONFIG_MCP2120_DONGLE) += mcp2120-sir.o | |||
45 | obj-$(CONFIG_ACT200L_DONGLE) += act200l-sir.o | 45 | obj-$(CONFIG_ACT200L_DONGLE) += act200l-sir.o |
46 | obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o | 46 | obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o |
47 | obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o | 47 | obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o |
48 | obj-$(CONFIG_KINGSUN_DONGLE) += kingsun-sir.o | ||
48 | 49 | ||
49 | # The SIR helper module | 50 | # The SIR helper module |
50 | sir-dev-objs := sir_dev.o sir_dongle.o | 51 | sir-dev-objs := sir_dev.o sir_dongle.o |
diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c new file mode 100644 index 000000000000..217429122e79 --- /dev/null +++ b/drivers/net/irda/kingsun-sir.c | |||
@@ -0,0 +1,657 @@ | |||
1 | /***************************************************************************** | ||
2 | * | ||
3 | * Filename: kingsun-sir.c | ||
4 | * Version: 0.1.1 | ||
5 | * Description: Irda KingSun/DonShine USB Dongle | ||
6 | * Status: Experimental | ||
7 | * Author: Alex Villac�s Lasso <a_villacis@palosanto.com> | ||
8 | * | ||
9 | * Based on stir4200 and mcs7780 drivers, with (strange?) differences | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | * | ||
24 | *****************************************************************************/ | ||
25 | |||
26 | /* | ||
27 | * This is my current (2007-04-25) understanding of how this dongle is supposed | ||
28 | * to work. This is based on reverse-engineering and examination of the packet | ||
29 | * data sent and received by the WinXP driver using USBSnoopy. Feel free to | ||
30 | * update here as more of this dongle is known: | ||
31 | * | ||
32 | * General: Unlike the other USB IrDA dongles, this particular dongle exposes, | ||
33 | * not two bulk (in and out) endpoints, but two *interrupt* ones. This dongle, | ||
34 | * like the bulk based ones (stir4200.c and mcs7780.c), requires polling in | ||
35 | * order to receive data. | ||
36 | * Transmission: Just like stir4200, this dongle uses a raw stream of data, | ||
37 | * which needs to be wrapped and escaped in a similar way as in stir4200.c. | ||
38 | * Reception: Poll-based, as in stir4200. Each read returns the contents of a | ||
39 | * 8-byte buffer, of which the first byte (LSB) indicates the number of bytes | ||
40 | * (1-7) of valid data contained within the remaining 7 bytes. For example, if | ||
41 | * the buffer had the following contents: | ||
42 | * 06 ff ff ff c0 01 04 aa | ||
43 | * This means that (06) there are 6 bytes of valid data. The byte 0xaa at the | ||
44 | * end is garbage (left over from a previous reception) and is discarded. | ||
45 | * If a read returns an "impossible" value as the length of valid data (such as | ||
46 | * 0x36) in the first byte, then the buffer is uninitialized (as is the case of | ||
47 | * first plug-in) and its contents should be discarded. There is currently no | ||
48 | * evidence that the top 5 bits of the 1st byte of the buffer can have values | ||
49 | * other than 0 once reception begins. | ||
50 | * Once valid bytes are collected, the assembled stream is a sequence of | ||
51 | * wrapped IrDA frames that is unwrapped and unescaped as in stir4200.c. | ||
52 | * BIG FAT WARNING: the dongle does *not* reset the RX buffer in any way after | ||
53 | * a successful read from the host, which means that in absence of further | ||
54 | * reception, repeated reads from the dongle will return the exact same | ||
55 | * contents repeatedly. Attempts to be smart and cache a previous read seem | ||
56 | * to result in corrupted packets, so this driver depends on the unwrap logic | ||
57 | * to sort out any repeated reads. | ||
58 | * Speed change: no commands observed so far to change speed, assumed fixed | ||
59 | * 9600bps (SIR). | ||
60 | */ | ||
61 | |||
62 | #include <linux/module.h> | ||
63 | #include <linux/moduleparam.h> | ||
64 | #include <linux/kernel.h> | ||
65 | #include <linux/types.h> | ||
66 | #include <linux/errno.h> | ||
67 | #include <linux/init.h> | ||
68 | #include <linux/slab.h> | ||
69 | #include <linux/module.h> | ||
70 | #include <linux/kref.h> | ||
71 | #include <linux/usb.h> | ||
72 | #include <linux/device.h> | ||
73 | #include <linux/crc32.h> | ||
74 | |||
75 | #include <asm/unaligned.h> | ||
76 | #include <asm/byteorder.h> | ||
77 | #include <asm/uaccess.h> | ||
78 | |||
79 | #include <net/irda/irda.h> | ||
80 | #include <net/irda/wrapper.h> | ||
81 | #include <net/irda/crc.h> | ||
82 | |||
83 | /* | ||
84 | * According to lsusb, 0x07c0 is assigned to | ||
85 | * "Code Mercenaries Hard- und Software GmbH" | ||
86 | */ | ||
87 | #define KING_VENDOR_ID 0x07c0 | ||
88 | #define KING_PRODUCT_ID 0x4200 | ||
89 | |||
90 | /* These are the currently known USB ids */ | ||
91 | static struct usb_device_id dongles[] = { | ||
92 | /* KingSun Co,Ltd IrDA/USB Bridge */ | ||
93 | { USB_DEVICE(KING_VENDOR_ID, KING_PRODUCT_ID) }, | ||
94 | { } | ||
95 | }; | ||
96 | |||
97 | MODULE_DEVICE_TABLE(usb, dongles); | ||
98 | |||
99 | #define KINGSUN_MTT 0x07 | ||
100 | |||
101 | #define KINGSUN_FIFO_SIZE 4096 | ||
102 | #define KINGSUN_EP_IN 0 | ||
103 | #define KINGSUN_EP_OUT 1 | ||
104 | |||
105 | struct kingsun_cb { | ||
106 | struct usb_device *usbdev; /* init: probe_irda */ | ||
107 | struct net_device *netdev; /* network layer */ | ||
108 | struct irlap_cb *irlap; /* The link layer we are binded to */ | ||
109 | struct net_device_stats stats; /* network statistics */ | ||
110 | struct qos_info qos; | ||
111 | |||
112 | __u8 *in_buf; /* receive buffer */ | ||
113 | __u8 *out_buf; /* transmit buffer */ | ||
114 | __u8 max_rx; /* max. atomic read from dongle | ||
115 | (usually 8), also size of in_buf */ | ||
116 | __u8 max_tx; /* max. atomic write to dongle | ||
117 | (usually 8) */ | ||
118 | |||
119 | iobuff_t rx_buff; /* receive unwrap state machine */ | ||
120 | struct timeval rx_time; | ||
121 | spinlock_t lock; | ||
122 | int receiving; | ||
123 | |||
124 | __u8 ep_in; | ||
125 | __u8 ep_out; | ||
126 | |||
127 | struct urb *tx_urb; | ||
128 | struct urb *rx_urb; | ||
129 | }; | ||
130 | |||
131 | /* Callback transmission routine */ | ||
132 | static void kingsun_send_irq(struct urb *urb) | ||
133 | { | ||
134 | struct kingsun_cb *kingsun = urb->context; | ||
135 | struct net_device *netdev = kingsun->netdev; | ||
136 | |||
137 | /* in process of stopping, just drop data */ | ||
138 | if (!netif_running(kingsun->netdev)) { | ||
139 | err("kingsun_send_irq: Network not running!"); | ||
140 | return; | ||
141 | } | ||
142 | |||
143 | /* unlink, shutdown, unplug, other nasties */ | ||
144 | if (urb->status != 0) { | ||
145 | err("kingsun_send_irq: urb asynchronously failed - %d", | ||
146 | urb->status); | ||
147 | } | ||
148 | netif_wake_queue(netdev); | ||
149 | } | ||
150 | |||
151 | /* | ||
152 | * Called from net/core when new frame is available. | ||
153 | */ | ||
154 | static int kingsun_hard_xmit(struct sk_buff *skb, struct net_device *netdev) | ||
155 | { | ||
156 | struct kingsun_cb *kingsun; | ||
157 | int wraplen; | ||
158 | int ret = 0; | ||
159 | |||
160 | if (skb == NULL || netdev == NULL) | ||
161 | return -EINVAL; | ||
162 | |||
163 | netif_stop_queue(netdev); | ||
164 | |||
165 | /* the IRDA wrapping routines don't deal with non linear skb */ | ||
166 | SKB_LINEAR_ASSERT(skb); | ||
167 | |||
168 | kingsun = netdev_priv(netdev); | ||
169 | |||
170 | spin_lock(&kingsun->lock); | ||
171 | |||
172 | /* Append data to the end of whatever data remains to be transmitted */ | ||
173 | wraplen = async_wrap_skb(skb, | ||
174 | kingsun->out_buf, | ||
175 | KINGSUN_FIFO_SIZE); | ||
176 | |||
177 | /* Calculate how much data can be transmitted in this urb */ | ||
178 | usb_fill_int_urb(kingsun->tx_urb, kingsun->usbdev, | ||
179 | usb_sndintpipe(kingsun->usbdev, kingsun->ep_out), | ||
180 | kingsun->out_buf, wraplen, kingsun_send_irq, | ||
181 | kingsun, 1); | ||
182 | |||
183 | if ((ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC))) { | ||
184 | err("kingsun_hard_xmit: failed tx_urb submit: %d", ret); | ||
185 | switch (ret) { | ||
186 | case -ENODEV: | ||
187 | case -EPIPE: | ||
188 | break; | ||
189 | default: | ||
190 | kingsun->stats.tx_errors++; | ||
191 | netif_start_queue(netdev); | ||
192 | } | ||
193 | } else { | ||
194 | kingsun->stats.tx_packets++; | ||
195 | kingsun->stats.tx_bytes += skb->len; | ||
196 | } | ||
197 | |||
198 | dev_kfree_skb(skb); | ||
199 | spin_unlock(&kingsun->lock); | ||
200 | |||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | /* Receive callback function */ | ||
205 | static void kingsun_rcv_irq(struct urb *urb) | ||
206 | { | ||
207 | struct kingsun_cb *kingsun = urb->context; | ||
208 | int ret; | ||
209 | |||
210 | /* in process of stopping, just drop data */ | ||
211 | if (!netif_running(kingsun->netdev)) { | ||
212 | kingsun->receiving = 0; | ||
213 | return; | ||
214 | } | ||
215 | |||
216 | /* unlink, shutdown, unplug, other nasties */ | ||
217 | if (urb->status != 0) { | ||
218 | err("kingsun_rcv_irq: urb asynchronously failed - %d", | ||
219 | urb->status); | ||
220 | kingsun->receiving = 0; | ||
221 | return; | ||
222 | } | ||
223 | |||
224 | if (urb->actual_length == kingsun->max_rx) { | ||
225 | __u8 *bytes = urb->transfer_buffer; | ||
226 | int i; | ||
227 | |||
228 | /* The very first byte in the buffer indicates the length of | ||
229 | valid data in the read. This byte must be in the range | ||
230 | 1..kingsun->max_rx -1 . Values outside this range indicate | ||
231 | an uninitialized Rx buffer when the dongle has just been | ||
232 | plugged in. */ | ||
233 | if (bytes[0] >= 1 && bytes[0] < kingsun->max_rx) { | ||
234 | for (i = 1; i <= bytes[0]; i++) { | ||
235 | async_unwrap_char(kingsun->netdev, | ||
236 | &kingsun->stats, | ||
237 | &kingsun->rx_buff, bytes[i]); | ||
238 | } | ||
239 | kingsun->netdev->last_rx = jiffies; | ||
240 | do_gettimeofday(&kingsun->rx_time); | ||
241 | kingsun->receiving = | ||
242 | (kingsun->rx_buff.state != OUTSIDE_FRAME) | ||
243 | ? 1 : 0; | ||
244 | } | ||
245 | } else if (urb->actual_length > 0) { | ||
246 | err("%s(): Unexpected response length, expected %d got %d", | ||
247 | __FUNCTION__, kingsun->max_rx, urb->actual_length); | ||
248 | } | ||
249 | /* This urb has already been filled in kingsun_net_open */ | ||
250 | ret = usb_submit_urb(urb, GFP_ATOMIC); | ||
251 | } | ||
252 | |||
253 | /* | ||
254 | * Function kingsun_net_open (dev) | ||
255 | * | ||
256 | * Network device is taken up. Usually this is done by "ifconfig irda0 up" | ||
257 | */ | ||
258 | static int kingsun_net_open(struct net_device *netdev) | ||
259 | { | ||
260 | struct kingsun_cb *kingsun = netdev_priv(netdev); | ||
261 | int err = -ENOMEM; | ||
262 | char hwname[16]; | ||
263 | |||
264 | /* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */ | ||
265 | kingsun->receiving = 0; | ||
266 | |||
267 | /* Initialize for SIR to copy data directly into skb. */ | ||
268 | kingsun->rx_buff.in_frame = FALSE; | ||
269 | kingsun->rx_buff.state = OUTSIDE_FRAME; | ||
270 | kingsun->rx_buff.truesize = IRDA_SKB_MAX_MTU; | ||
271 | kingsun->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU); | ||
272 | if (!kingsun->rx_buff.skb) | ||
273 | goto free_mem; | ||
274 | |||
275 | skb_reserve(kingsun->rx_buff.skb, 1); | ||
276 | kingsun->rx_buff.head = kingsun->rx_buff.skb->data; | ||
277 | do_gettimeofday(&kingsun->rx_time); | ||
278 | |||
279 | kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
280 | if (!kingsun->rx_urb) | ||
281 | goto free_mem; | ||
282 | |||
283 | kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
284 | if (!kingsun->tx_urb) | ||
285 | goto free_mem; | ||
286 | |||
287 | /* | ||
288 | * Now that everything should be initialized properly, | ||
289 | * Open new IrLAP layer instance to take care of us... | ||
290 | */ | ||
291 | sprintf(hwname, "usb#%d", kingsun->usbdev->devnum); | ||
292 | kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname); | ||
293 | if (!kingsun->irlap) { | ||
294 | err("kingsun-sir: irlap_open failed"); | ||
295 | goto free_mem; | ||
296 | } | ||
297 | |||
298 | /* Start first reception */ | ||
299 | usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev, | ||
300 | usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in), | ||
301 | kingsun->in_buf, kingsun->max_rx, | ||
302 | kingsun_rcv_irq, kingsun, 1); | ||
303 | kingsun->rx_urb->status = 0; | ||
304 | err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); | ||
305 | if (err) { | ||
306 | err("kingsun-sir: first urb-submit failed: %d", err); | ||
307 | goto close_irlap; | ||
308 | } | ||
309 | |||
310 | netif_start_queue(netdev); | ||
311 | |||
312 | /* Situation at this point: | ||
313 | - all work buffers allocated | ||
314 | - urbs allocated and ready to fill | ||
315 | - max rx packet known (in max_rx) | ||
316 | - unwrap state machine initialized, in state outside of any frame | ||
317 | - receive request in progress | ||
318 | - IrLAP layer started, about to hand over packets to send | ||
319 | */ | ||
320 | |||
321 | return 0; | ||
322 | |||
323 | close_irlap: | ||
324 | irlap_close(kingsun->irlap); | ||
325 | free_mem: | ||
326 | if (kingsun->tx_urb) { | ||
327 | usb_free_urb(kingsun->tx_urb); | ||
328 | kingsun->tx_urb = NULL; | ||
329 | } | ||
330 | if (kingsun->rx_urb) { | ||
331 | usb_free_urb(kingsun->rx_urb); | ||
332 | kingsun->rx_urb = NULL; | ||
333 | } | ||
334 | if (kingsun->rx_buff.skb) { | ||
335 | kfree_skb(kingsun->rx_buff.skb); | ||
336 | kingsun->rx_buff.skb = NULL; | ||
337 | kingsun->rx_buff.head = NULL; | ||
338 | } | ||
339 | return err; | ||
340 | } | ||
341 | |||
342 | /* | ||
343 | * Function kingsun_net_close (kingsun) | ||
344 | * | ||
345 | * Network device is taken down. Usually this is done by | ||
346 | * "ifconfig irda0 down" | ||
347 | */ | ||
348 | static int kingsun_net_close(struct net_device *netdev) | ||
349 | { | ||
350 | struct kingsun_cb *kingsun = netdev_priv(netdev); | ||
351 | |||
352 | /* Stop transmit processing */ | ||
353 | netif_stop_queue(netdev); | ||
354 | |||
355 | /* Mop up receive && transmit urb's */ | ||
356 | usb_kill_urb(kingsun->tx_urb); | ||
357 | usb_kill_urb(kingsun->rx_urb); | ||
358 | |||
359 | usb_free_urb(kingsun->tx_urb); | ||
360 | usb_free_urb(kingsun->rx_urb); | ||
361 | |||
362 | kingsun->tx_urb = NULL; | ||
363 | kingsun->rx_urb = NULL; | ||
364 | |||
365 | kfree_skb(kingsun->rx_buff.skb); | ||
366 | kingsun->rx_buff.skb = NULL; | ||
367 | kingsun->rx_buff.head = NULL; | ||
368 | kingsun->rx_buff.in_frame = FALSE; | ||
369 | kingsun->rx_buff.state = OUTSIDE_FRAME; | ||
370 | kingsun->receiving = 0; | ||
371 | |||
372 | /* Stop and remove instance of IrLAP */ | ||
373 | if (kingsun->irlap) | ||
374 | irlap_close(kingsun->irlap); | ||
375 | |||
376 | kingsun->irlap = NULL; | ||
377 | |||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | /* | ||
382 | * IOCTLs : Extra out-of-band network commands... | ||
383 | */ | ||
384 | static int kingsun_net_ioctl(struct net_device *netdev, struct ifreq *rq, | ||
385 | int cmd) | ||
386 | { | ||
387 | struct if_irda_req *irq = (struct if_irda_req *) rq; | ||
388 | struct kingsun_cb *kingsun = netdev_priv(netdev); | ||
389 | int ret = 0; | ||
390 | |||
391 | switch (cmd) { | ||
392 | case SIOCSBANDWIDTH: /* Set bandwidth */ | ||
393 | if (!capable(CAP_NET_ADMIN)) | ||
394 | return -EPERM; | ||
395 | |||
396 | /* Check if the device is still there */ | ||
397 | if (netif_device_present(kingsun->netdev)) | ||
398 | /* No observed commands for speed change */ | ||
399 | ret = -EOPNOTSUPP; | ||
400 | break; | ||
401 | |||
402 | case SIOCSMEDIABUSY: /* Set media busy */ | ||
403 | if (!capable(CAP_NET_ADMIN)) | ||
404 | return -EPERM; | ||
405 | |||
406 | /* Check if the IrDA stack is still there */ | ||
407 | if (netif_running(kingsun->netdev)) | ||
408 | irda_device_set_media_busy(kingsun->netdev, TRUE); | ||
409 | break; | ||
410 | |||
411 | case SIOCGRECEIVING: | ||
412 | /* Only approximately true */ | ||
413 | irq->ifr_receiving = kingsun->receiving; | ||
414 | break; | ||
415 | |||
416 | default: | ||
417 | ret = -EOPNOTSUPP; | ||
418 | } | ||
419 | |||
420 | return ret; | ||
421 | } | ||
422 | |||
423 | /* | ||
424 | * Get device stats (for /proc/net/dev and ifconfig) | ||
425 | */ | ||
426 | static struct net_device_stats * | ||
427 | kingsun_net_get_stats(struct net_device *netdev) | ||
428 | { | ||
429 | struct kingsun_cb *kingsun = netdev_priv(netdev); | ||
430 | return &kingsun->stats; | ||
431 | } | ||
432 | |||
433 | /* | ||
434 | * This routine is called by the USB subsystem for each new device | ||
435 | * in the system. We need to check if the device is ours, and in | ||
436 | * this case start handling it. | ||
437 | */ | ||
438 | static int kingsun_probe(struct usb_interface *intf, | ||
439 | const struct usb_device_id *id) | ||
440 | { | ||
441 | struct usb_host_interface *interface; | ||
442 | struct usb_endpoint_descriptor *endpoint; | ||
443 | |||
444 | struct usb_device *dev = interface_to_usbdev(intf); | ||
445 | struct kingsun_cb *kingsun = NULL; | ||
446 | struct net_device *net = NULL; | ||
447 | int ret = -ENOMEM; | ||
448 | int pipe, maxp_in, maxp_out; | ||
449 | __u8 ep_in; | ||
450 | __u8 ep_out; | ||
451 | |||
452 | /* Check that there really are two interrupt endpoints. | ||
453 | Check based on the one in drivers/usb/input/usbmouse.c | ||
454 | */ | ||
455 | interface = intf->cur_altsetting; | ||
456 | if (interface->desc.bNumEndpoints != 2) { | ||
457 | err("kingsun-sir: expected 2 endpoints, found %d", | ||
458 | interface->desc.bNumEndpoints); | ||
459 | return -ENODEV; | ||
460 | } | ||
461 | endpoint = &interface->endpoint[KINGSUN_EP_IN].desc; | ||
462 | if (!usb_endpoint_is_int_in(endpoint)) { | ||
463 | err("kingsun-sir: endpoint 0 is not interrupt IN"); | ||
464 | return -ENODEV; | ||
465 | } | ||
466 | |||
467 | ep_in = endpoint->bEndpointAddress; | ||
468 | pipe = usb_rcvintpipe(dev, ep_in); | ||
469 | maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); | ||
470 | if (maxp_in > 255 || maxp_in <= 1) { | ||
471 | err("%s: endpoint 0 has max packet size %d not in range", | ||
472 | __FILE__, maxp_in); | ||
473 | return -ENODEV; | ||
474 | } | ||
475 | |||
476 | endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc; | ||
477 | if (!usb_endpoint_is_int_out(endpoint)) { | ||
478 | err("kingsun-sir: endpoint 1 is not interrupt OUT"); | ||
479 | return -ENODEV; | ||
480 | } | ||
481 | |||
482 | ep_out = endpoint->bEndpointAddress; | ||
483 | pipe = usb_sndintpipe(dev, ep_out); | ||
484 | maxp_out = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); | ||
485 | |||
486 | /* Allocate network device container. */ | ||
487 | net = alloc_irdadev(sizeof(*kingsun)); | ||
488 | if(!net) | ||
489 | goto err_out1; | ||
490 | |||
491 | SET_MODULE_OWNER(net); | ||
492 | SET_NETDEV_DEV(net, &intf->dev); | ||
493 | kingsun = netdev_priv(net); | ||
494 | kingsun->irlap = NULL; | ||
495 | kingsun->tx_urb = NULL; | ||
496 | kingsun->rx_urb = NULL; | ||
497 | kingsun->ep_in = ep_in; | ||
498 | kingsun->ep_out = ep_out; | ||
499 | kingsun->in_buf = NULL; | ||
500 | kingsun->out_buf = NULL; | ||
501 | kingsun->max_rx = (__u8)maxp_in; | ||
502 | kingsun->max_tx = (__u8)maxp_out; | ||
503 | kingsun->netdev = net; | ||
504 | kingsun->usbdev = dev; | ||
505 | kingsun->rx_buff.in_frame = FALSE; | ||
506 | kingsun->rx_buff.state = OUTSIDE_FRAME; | ||
507 | kingsun->rx_buff.skb = NULL; | ||
508 | kingsun->receiving = 0; | ||
509 | spin_lock_init(&kingsun->lock); | ||
510 | |||
511 | /* Allocate input buffer */ | ||
512 | kingsun->in_buf = (__u8 *)kmalloc(kingsun->max_rx, GFP_KERNEL); | ||
513 | if (!kingsun->in_buf) | ||
514 | goto free_mem; | ||
515 | |||
516 | /* Allocate output buffer */ | ||
517 | kingsun->out_buf = (__u8 *)kmalloc(KINGSUN_FIFO_SIZE, GFP_KERNEL); | ||
518 | if (!kingsun->out_buf) | ||
519 | goto free_mem; | ||
520 | |||
521 | printk(KERN_INFO "KingSun/DonShine IRDA/USB found at address %d, " | ||
522 | "Vendor: %x, Product: %x\n", | ||
523 | dev->devnum, le16_to_cpu(dev->descriptor.idVendor), | ||
524 | le16_to_cpu(dev->descriptor.idProduct)); | ||
525 | |||
526 | /* Initialize QoS for this device */ | ||
527 | irda_init_max_qos_capabilies(&kingsun->qos); | ||
528 | |||
529 | /* That's the Rx capability. */ | ||
530 | kingsun->qos.baud_rate.bits &= IR_9600; | ||
531 | kingsun->qos.min_turn_time.bits &= KINGSUN_MTT; | ||
532 | irda_qos_bits_to_value(&kingsun->qos); | ||
533 | |||
534 | /* Override the network functions we need to use */ | ||
535 | net->hard_start_xmit = kingsun_hard_xmit; | ||
536 | net->open = kingsun_net_open; | ||
537 | net->stop = kingsun_net_close; | ||
538 | net->get_stats = kingsun_net_get_stats; | ||
539 | net->do_ioctl = kingsun_net_ioctl; | ||
540 | |||
541 | ret = register_netdev(net); | ||
542 | if (ret != 0) | ||
543 | goto free_mem; | ||
544 | |||
545 | info("IrDA: Registered KingSun/DonShine device %s", net->name); | ||
546 | |||
547 | usb_set_intfdata(intf, kingsun); | ||
548 | |||
549 | /* Situation at this point: | ||
550 | - all work buffers allocated | ||
551 | - urbs not allocated, set to NULL | ||
552 | - max rx packet known (in max_rx) | ||
553 | - unwrap state machine (partially) initialized, but skb == NULL | ||
554 | */ | ||
555 | |||
556 | return 0; | ||
557 | |||
558 | free_mem: | ||
559 | if (kingsun->out_buf) kfree(kingsun->out_buf); | ||
560 | if (kingsun->in_buf) kfree(kingsun->in_buf); | ||
561 | free_netdev(net); | ||
562 | err_out1: | ||
563 | return ret; | ||
564 | } | ||
565 | |||
566 | /* | ||
567 | * The current device is removed, the USB layer tell us to shut it down... | ||
568 | */ | ||
569 | static void kingsun_disconnect(struct usb_interface *intf) | ||
570 | { | ||
571 | struct kingsun_cb *kingsun = usb_get_intfdata(intf); | ||
572 | |||
573 | if (!kingsun) | ||
574 | return; | ||
575 | |||
576 | unregister_netdev(kingsun->netdev); | ||
577 | |||
578 | /* Mop up receive && transmit urb's */ | ||
579 | if (kingsun->tx_urb != NULL) { | ||
580 | usb_kill_urb(kingsun->tx_urb); | ||
581 | usb_free_urb(kingsun->tx_urb); | ||
582 | kingsun->tx_urb = NULL; | ||
583 | } | ||
584 | if (kingsun->rx_urb != NULL) { | ||
585 | usb_kill_urb(kingsun->rx_urb); | ||
586 | usb_free_urb(kingsun->rx_urb); | ||
587 | kingsun->rx_urb = NULL; | ||
588 | } | ||
589 | |||
590 | kfree(kingsun->out_buf); | ||
591 | kfree(kingsun->in_buf); | ||
592 | free_netdev(kingsun->netdev); | ||
593 | |||
594 | usb_set_intfdata(intf, NULL); | ||
595 | } | ||
596 | |||
597 | #ifdef CONFIG_PM | ||
598 | /* USB suspend, so power off the transmitter/receiver */ | ||
599 | static int kingsun_suspend(struct usb_interface *intf, pm_message_t message) | ||
600 | { | ||
601 | struct kingsun_cb *kingsun = usb_get_intfdata(intf); | ||
602 | |||
603 | netif_device_detach(kingsun->netdev); | ||
604 | if (kingsun->tx_urb != NULL) usb_kill_urb(kingsun->tx_urb); | ||
605 | if (kingsun->rx_urb != NULL) usb_kill_urb(kingsun->rx_urb); | ||
606 | return 0; | ||
607 | } | ||
608 | |||
609 | /* Coming out of suspend, so reset hardware */ | ||
610 | static int kingsun_resume(struct usb_interface *intf) | ||
611 | { | ||
612 | struct kingsun_cb *kingsun = usb_get_intfdata(intf); | ||
613 | |||
614 | if (kingsun->rx_urb != NULL) | ||
615 | usb_submit_urb(kingsun->rx_urb, GFP_KERNEL); | ||
616 | netif_device_attach(kingsun->netdev); | ||
617 | |||
618 | return 0; | ||
619 | } | ||
620 | #endif | ||
621 | |||
622 | /* | ||
623 | * USB device callbacks | ||
624 | */ | ||
625 | static struct usb_driver irda_driver = { | ||
626 | .name = "kingsun-sir", | ||
627 | .probe = kingsun_probe, | ||
628 | .disconnect = kingsun_disconnect, | ||
629 | .id_table = dongles, | ||
630 | #ifdef CONFIG_PM | ||
631 | .suspend = kingsun_suspend, | ||
632 | .resume = kingsun_resume, | ||
633 | #endif | ||
634 | }; | ||
635 | |||
636 | /* | ||
637 | * Module insertion | ||
638 | */ | ||
639 | static int __init kingsun_init(void) | ||
640 | { | ||
641 | return usb_register(&irda_driver); | ||
642 | } | ||
643 | module_init(kingsun_init); | ||
644 | |||
645 | /* | ||
646 | * Module removal | ||
647 | */ | ||
648 | static void __exit kingsun_cleanup(void) | ||
649 | { | ||
650 | /* Deregister the driver and remove all pending instances */ | ||
651 | usb_deregister(&irda_driver); | ||
652 | } | ||
653 | module_exit(kingsun_cleanup); | ||
654 | |||
655 | MODULE_AUTHOR("Alex Villac�s Lasso <a_villacis@palosanto.com>"); | ||
656 | MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun/DonShine"); | ||
657 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 1759baad439c..ad445d5e58c7 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -397,7 +397,7 @@ config RTC_DRV_BFIN | |||
397 | 397 | ||
398 | config RTC_DRV_RS5C313 | 398 | config RTC_DRV_RS5C313 |
399 | tristate "Ricoh RS5C313" | 399 | tristate "Ricoh RS5C313" |
400 | depends on RTC_CLASS && BROKEN | 400 | depends on RTC_CLASS && SH_LANDISK |
401 | help | 401 | help |
402 | If you say yes here you get support for the Ricoh RS5C313 RTC chips. | 402 | If you say yes here you get support for the Ricoh RS5C313 RTC chips. |
403 | 403 | ||
diff --git a/drivers/rtc/rtc-rs5c313.c b/drivers/rtc/rtc-rs5c313.c index 9d6de371495b..66eb133bf5fd 100644 --- a/drivers/rtc/rtc-rs5c313.c +++ b/drivers/rtc/rtc-rs5c313.c | |||
@@ -126,7 +126,7 @@ static void rs5c313_write_data(unsigned char data) | |||
126 | static unsigned char rs5c313_read_data(void) | 126 | static unsigned char rs5c313_read_data(void) |
127 | { | 127 | { |
128 | int i; | 128 | int i; |
129 | unsigned char data; | 129 | unsigned char data = 0; |
130 | 130 | ||
131 | for (i = 0; i < 8; i++) { | 131 | for (i = 0; i < 8; i++) { |
132 | ndelay(700); | 132 | ndelay(700); |
@@ -194,7 +194,7 @@ static void rs5c313_write_reg(unsigned char addr, unsigned char data) | |||
194 | return; | 194 | return; |
195 | } | 195 | } |
196 | 196 | ||
197 | static inline unsigned char rs5c313_read_cntreg(unsigned char addr) | 197 | static inline unsigned char rs5c313_read_cntreg(void) |
198 | { | 198 | { |
199 | return rs5c313_read_reg(RS5C313_ADDR_CNTREG); | 199 | return rs5c313_read_reg(RS5C313_ADDR_CNTREG); |
200 | } | 200 | } |
@@ -212,7 +212,9 @@ static inline void rs5c313_write_intintvreg(unsigned char data) | |||
212 | static int rs5c313_rtc_read_time(struct device *dev, struct rtc_time *tm) | 212 | static int rs5c313_rtc_read_time(struct device *dev, struct rtc_time *tm) |
213 | { | 213 | { |
214 | int data; | 214 | int data; |
215 | int cnt; | ||
215 | 216 | ||
217 | cnt = 0; | ||
216 | while (1) { | 218 | while (1) { |
217 | RS5C313_CEENABLE; /* CE:H */ | 219 | RS5C313_CEENABLE; /* CE:H */ |
218 | 220 | ||
@@ -225,6 +227,10 @@ static int rs5c313_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
225 | RS5C313_CEDISABLE; | 227 | RS5C313_CEDISABLE; |
226 | ndelay(700); /* CE:L */ | 228 | ndelay(700); /* CE:L */ |
227 | 229 | ||
230 | if (cnt++ > 100) { | ||
231 | dev_err(dev, "%s: timeout error\n", __FUNCTION__); | ||
232 | return -EIO; | ||
233 | } | ||
228 | } | 234 | } |
229 | 235 | ||
230 | data = rs5c313_read_reg(RS5C313_ADDR_SEC); | 236 | data = rs5c313_read_reg(RS5C313_ADDR_SEC); |
@@ -266,7 +272,9 @@ static int rs5c313_rtc_read_time(struct device *dev, struct rtc_time *tm) | |||
266 | static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm) | 272 | static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm) |
267 | { | 273 | { |
268 | int data; | 274 | int data; |
275 | int cnt; | ||
269 | 276 | ||
277 | cnt = 0; | ||
270 | /* busy check. */ | 278 | /* busy check. */ |
271 | while (1) { | 279 | while (1) { |
272 | RS5C313_CEENABLE; /* CE:H */ | 280 | RS5C313_CEENABLE; /* CE:H */ |
@@ -279,6 +287,11 @@ static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
279 | RS5C313_MISCOP; | 287 | RS5C313_MISCOP; |
280 | RS5C313_CEDISABLE; | 288 | RS5C313_CEDISABLE; |
281 | ndelay(700); /* CE:L */ | 289 | ndelay(700); /* CE:L */ |
290 | |||
291 | if (cnt++ > 100) { | ||
292 | dev_err(dev, "%s: timeout error\n", __FUNCTION__); | ||
293 | return -EIO; | ||
294 | } | ||
282 | } | 295 | } |
283 | 296 | ||
284 | data = BIN2BCD(tm->tm_sec); | 297 | data = BIN2BCD(tm->tm_sec); |
@@ -317,6 +330,7 @@ static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm) | |||
317 | static void rs5c313_check_xstp_bit(void) | 330 | static void rs5c313_check_xstp_bit(void) |
318 | { | 331 | { |
319 | struct rtc_time tm; | 332 | struct rtc_time tm; |
333 | int cnt; | ||
320 | 334 | ||
321 | RS5C313_CEENABLE; /* CE:H */ | 335 | RS5C313_CEENABLE; /* CE:H */ |
322 | if (rs5c313_read_cntreg() & RS5C313_CNTREG_WTEN_XSTP) { | 336 | if (rs5c313_read_cntreg() & RS5C313_CNTREG_WTEN_XSTP) { |
@@ -326,12 +340,16 @@ static void rs5c313_check_xstp_bit(void) | |||
326 | rs5c313_write_cntreg(0x07); | 340 | rs5c313_write_cntreg(0x07); |
327 | 341 | ||
328 | /* busy check. */ | 342 | /* busy check. */ |
329 | while (rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY) | 343 | for (cnt = 0; cnt < 100; cnt++) { |
344 | if (!(rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY)) | ||
345 | break; | ||
330 | RS5C313_MISCOP; | 346 | RS5C313_MISCOP; |
347 | } | ||
331 | 348 | ||
332 | memset(&tm, 0, sizeof(struct rtc_time)); | 349 | memset(&tm, 0, sizeof(struct rtc_time)); |
333 | tm.tm_mday = 1; | 350 | tm.tm_mday = 1; |
334 | tm.tm_mon = 1; | 351 | tm.tm_mon = 1 - 1; |
352 | tm.tm_year = 2000 - 1900; | ||
335 | 353 | ||
336 | rs5c313_rtc_set_time(NULL, &tm); | 354 | rs5c313_rtc_set_time(NULL, &tm); |
337 | printk(KERN_ERR "RICHO RS5C313: invalid value, resetting to " | 355 | printk(KERN_ERR "RICHO RS5C313: invalid value, resetting to " |
@@ -356,7 +374,7 @@ static int rs5c313_rtc_probe(struct platform_device *pdev) | |||
356 | 374 | ||
357 | platform_set_drvdata(pdev, rtc); | 375 | platform_set_drvdata(pdev, rtc); |
358 | 376 | ||
359 | return err; | 377 | return 0; |
360 | } | 378 | } |
361 | 379 | ||
362 | static int __devexit rs5c313_rtc_remove(struct platform_device *pdev) | 380 | static int __devexit rs5c313_rtc_remove(struct platform_device *pdev) |
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 7c9d37f651e3..5e3f748f2693 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig | |||
@@ -107,6 +107,13 @@ config SPI_IMX | |||
107 | This enables using the Freescale iMX SPI controller in master | 107 | This enables using the Freescale iMX SPI controller in master |
108 | mode. | 108 | mode. |
109 | 109 | ||
110 | config SPI_MPC52xx_PSC | ||
111 | tristate "Freescale MPC52xx PSC SPI controller" | ||
112 | depends on SPI_MASTER && PPC_MPC52xx && EXPERIMENTAL | ||
113 | help | ||
114 | This enables using the Freescale MPC52xx Programmable Serial | ||
115 | Controller in master SPI mode. | ||
116 | |||
110 | config SPI_MPC83xx | 117 | config SPI_MPC83xx |
111 | tristate "Freescale MPC83xx SPI controller" | 118 | tristate "Freescale MPC83xx SPI controller" |
112 | depends on SPI_MASTER && PPC_83xx && EXPERIMENTAL | 119 | depends on SPI_MASTER && PPC_83xx && EXPERIMENTAL |
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 624b6363f490..5788d867de84 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile | |||
@@ -19,6 +19,7 @@ obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o | |||
19 | obj-$(CONFIG_SPI_IMX) += spi_imx.o | 19 | obj-$(CONFIG_SPI_IMX) += spi_imx.o |
20 | obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o | 20 | obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o |
21 | obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o | 21 | obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o |
22 | obj-$(CONFIG_SPI_MPC52xx_PSC) += mpc52xx_psc_spi.o | ||
22 | obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o | 23 | obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o |
23 | obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o | 24 | obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o |
24 | obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o | 25 | obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o |
diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c new file mode 100644 index 000000000000..052359fc41ee --- /dev/null +++ b/drivers/spi/mpc52xx_psc_spi.c | |||
@@ -0,0 +1,654 @@ | |||
1 | /* | ||
2 | * MPC52xx SPC in SPI mode driver. | ||
3 | * | ||
4 | * Maintainer: Dragos Carp | ||
5 | * | ||
6 | * Copyright (C) 2006 TOPTICA Photonics AG. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | |||
19 | #if defined(CONFIG_PPC_MERGE) | ||
20 | #include <asm/of_platform.h> | ||
21 | #else | ||
22 | #include <linux/platform_device.h> | ||
23 | #endif | ||
24 | |||
25 | #include <linux/workqueue.h> | ||
26 | #include <linux/completion.h> | ||
27 | #include <linux/io.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/spi/spi.h> | ||
30 | #include <linux/fsl_devices.h> | ||
31 | |||
32 | #include <asm/mpc52xx.h> | ||
33 | #include <asm/mpc52xx_psc.h> | ||
34 | |||
35 | #define MCLK 20000000 /* PSC port MClk in hz */ | ||
36 | |||
37 | struct mpc52xx_psc_spi { | ||
38 | /* fsl_spi_platform data */ | ||
39 | void (*activate_cs)(u8, u8); | ||
40 | void (*deactivate_cs)(u8, u8); | ||
41 | u32 sysclk; | ||
42 | |||
43 | /* driver internal data */ | ||
44 | struct mpc52xx_psc __iomem *psc; | ||
45 | unsigned int irq; | ||
46 | u8 bits_per_word; | ||
47 | u8 busy; | ||
48 | |||
49 | struct workqueue_struct *workqueue; | ||
50 | struct work_struct work; | ||
51 | |||
52 | struct list_head queue; | ||
53 | spinlock_t lock; | ||
54 | |||
55 | struct completion done; | ||
56 | }; | ||
57 | |||
58 | /* controller state */ | ||
59 | struct mpc52xx_psc_spi_cs { | ||
60 | int bits_per_word; | ||
61 | int speed_hz; | ||
62 | }; | ||
63 | |||
64 | /* set clock freq, clock ramp, bits per work | ||
65 | * if t is NULL then reset the values to the default values | ||
66 | */ | ||
67 | static int mpc52xx_psc_spi_transfer_setup(struct spi_device *spi, | ||
68 | struct spi_transfer *t) | ||
69 | { | ||
70 | struct mpc52xx_psc_spi_cs *cs = spi->controller_state; | ||
71 | |||
72 | cs->speed_hz = (t && t->speed_hz) | ||
73 | ? t->speed_hz : spi->max_speed_hz; | ||
74 | cs->bits_per_word = (t && t->bits_per_word) | ||
75 | ? t->bits_per_word : spi->bits_per_word; | ||
76 | cs->bits_per_word = ((cs->bits_per_word + 7) / 8) * 8; | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static void mpc52xx_psc_spi_activate_cs(struct spi_device *spi) | ||
81 | { | ||
82 | struct mpc52xx_psc_spi_cs *cs = spi->controller_state; | ||
83 | struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); | ||
84 | struct mpc52xx_psc __iomem *psc = mps->psc; | ||
85 | u32 sicr; | ||
86 | u16 ccr; | ||
87 | |||
88 | sicr = in_be32(&psc->sicr); | ||
89 | |||
90 | /* Set clock phase and polarity */ | ||
91 | if (spi->mode & SPI_CPHA) | ||
92 | sicr |= 0x00001000; | ||
93 | else | ||
94 | sicr &= ~0x00001000; | ||
95 | if (spi->mode & SPI_CPOL) | ||
96 | sicr |= 0x00002000; | ||
97 | else | ||
98 | sicr &= ~0x00002000; | ||
99 | |||
100 | if (spi->mode & SPI_LSB_FIRST) | ||
101 | sicr |= 0x10000000; | ||
102 | else | ||
103 | sicr &= ~0x10000000; | ||
104 | out_be32(&psc->sicr, sicr); | ||
105 | |||
106 | /* Set clock frequency and bits per word | ||
107 | * Because psc->ccr is defined as 16bit register instead of 32bit | ||
108 | * just set the lower byte of BitClkDiv | ||
109 | */ | ||
110 | ccr = in_be16(&psc->ccr); | ||
111 | ccr &= 0xFF00; | ||
112 | if (cs->speed_hz) | ||
113 | ccr |= (MCLK / cs->speed_hz - 1) & 0xFF; | ||
114 | else /* by default SPI Clk 1MHz */ | ||
115 | ccr |= (MCLK / 1000000 - 1) & 0xFF; | ||
116 | out_be16(&psc->ccr, ccr); | ||
117 | mps->bits_per_word = cs->bits_per_word; | ||
118 | |||
119 | if (mps->activate_cs) | ||
120 | mps->activate_cs(spi->chip_select, | ||
121 | (spi->mode & SPI_CS_HIGH) ? 1 : 0); | ||
122 | } | ||
123 | |||
124 | static void mpc52xx_psc_spi_deactivate_cs(struct spi_device *spi) | ||
125 | { | ||
126 | struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); | ||
127 | |||
128 | if (mps->deactivate_cs) | ||
129 | mps->deactivate_cs(spi->chip_select, | ||
130 | (spi->mode & SPI_CS_HIGH) ? 1 : 0); | ||
131 | } | ||
132 | |||
133 | #define MPC52xx_PSC_BUFSIZE (MPC52xx_PSC_RFNUM_MASK + 1) | ||
134 | /* wake up when 80% fifo full */ | ||
135 | #define MPC52xx_PSC_RFALARM (MPC52xx_PSC_BUFSIZE * 20 / 100) | ||
136 | |||
137 | static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi, | ||
138 | struct spi_transfer *t) | ||
139 | { | ||
140 | struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); | ||
141 | struct mpc52xx_psc __iomem *psc = mps->psc; | ||
142 | unsigned rb = 0; /* number of bytes receieved */ | ||
143 | unsigned sb = 0; /* number of bytes sent */ | ||
144 | unsigned char *rx_buf = (unsigned char *)t->rx_buf; | ||
145 | unsigned char *tx_buf = (unsigned char *)t->tx_buf; | ||
146 | unsigned rfalarm; | ||
147 | unsigned send_at_once = MPC52xx_PSC_BUFSIZE; | ||
148 | unsigned recv_at_once; | ||
149 | unsigned bpw = mps->bits_per_word / 8; | ||
150 | |||
151 | if (!t->tx_buf && !t->rx_buf && t->len) | ||
152 | return -EINVAL; | ||
153 | |||
154 | /* enable transmiter/receiver */ | ||
155 | out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE); | ||
156 | while (rb < t->len) { | ||
157 | if (t->len - rb > MPC52xx_PSC_BUFSIZE) { | ||
158 | rfalarm = MPC52xx_PSC_RFALARM; | ||
159 | } else { | ||
160 | send_at_once = t->len - sb; | ||
161 | rfalarm = MPC52xx_PSC_BUFSIZE - (t->len - rb); | ||
162 | } | ||
163 | |||
164 | dev_dbg(&spi->dev, "send %d bytes...\n", send_at_once); | ||
165 | if (tx_buf) { | ||
166 | for (; send_at_once; sb++, send_at_once--) { | ||
167 | /* set EOF flag */ | ||
168 | if (mps->bits_per_word | ||
169 | && (sb + 1) % bpw == 0) | ||
170 | out_8(&psc->ircr2, 0x01); | ||
171 | out_8(&psc->mpc52xx_psc_buffer_8, tx_buf[sb]); | ||
172 | } | ||
173 | } else { | ||
174 | for (; send_at_once; sb++, send_at_once--) { | ||
175 | /* set EOF flag */ | ||
176 | if (mps->bits_per_word | ||
177 | && ((sb + 1) % bpw) == 0) | ||
178 | out_8(&psc->ircr2, 0x01); | ||
179 | out_8(&psc->mpc52xx_psc_buffer_8, 0); | ||
180 | } | ||
181 | } | ||
182 | |||
183 | |||
184 | /* enable interupts and wait for wake up | ||
185 | * if just one byte is expected the Rx FIFO genererates no | ||
186 | * FFULL interrupt, so activate the RxRDY interrupt | ||
187 | */ | ||
188 | out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1); | ||
189 | if (t->len - rb == 1) { | ||
190 | out_8(&psc->mode, 0); | ||
191 | } else { | ||
192 | out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL); | ||
193 | out_be16(&psc->rfalarm, rfalarm); | ||
194 | } | ||
195 | out_be16(&psc->mpc52xx_psc_imr, MPC52xx_PSC_IMR_RXRDY); | ||
196 | wait_for_completion(&mps->done); | ||
197 | recv_at_once = in_be16(&psc->rfnum); | ||
198 | dev_dbg(&spi->dev, "%d bytes received\n", recv_at_once); | ||
199 | |||
200 | send_at_once = recv_at_once; | ||
201 | if (rx_buf) { | ||
202 | for (; recv_at_once; rb++, recv_at_once--) | ||
203 | rx_buf[rb] = in_8(&psc->mpc52xx_psc_buffer_8); | ||
204 | } else { | ||
205 | for (; recv_at_once; rb++, recv_at_once--) | ||
206 | in_8(&psc->mpc52xx_psc_buffer_8); | ||
207 | } | ||
208 | } | ||
209 | /* disable transmiter/receiver */ | ||
210 | out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | static void mpc52xx_psc_spi_work(struct work_struct *work) | ||
216 | { | ||
217 | struct mpc52xx_psc_spi *mps = | ||
218 | container_of(work, struct mpc52xx_psc_spi, work); | ||
219 | |||
220 | spin_lock_irq(&mps->lock); | ||
221 | mps->busy = 1; | ||
222 | while (!list_empty(&mps->queue)) { | ||
223 | struct spi_message *m; | ||
224 | struct spi_device *spi; | ||
225 | struct spi_transfer *t = NULL; | ||
226 | unsigned cs_change; | ||
227 | int status; | ||
228 | |||
229 | m = container_of(mps->queue.next, struct spi_message, queue); | ||
230 | list_del_init(&m->queue); | ||
231 | spin_unlock_irq(&mps->lock); | ||
232 | |||
233 | spi = m->spi; | ||
234 | cs_change = 1; | ||
235 | status = 0; | ||
236 | list_for_each_entry (t, &m->transfers, transfer_list) { | ||
237 | if (t->bits_per_word || t->speed_hz) { | ||
238 | status = mpc52xx_psc_spi_transfer_setup(spi, t); | ||
239 | if (status < 0) | ||
240 | break; | ||
241 | } | ||
242 | |||
243 | if (cs_change) | ||
244 | mpc52xx_psc_spi_activate_cs(spi); | ||
245 | cs_change = t->cs_change; | ||
246 | |||
247 | status = mpc52xx_psc_spi_transfer_rxtx(spi, t); | ||
248 | if (status) | ||
249 | break; | ||
250 | m->actual_length += t->len; | ||
251 | |||
252 | if (t->delay_usecs) | ||
253 | udelay(t->delay_usecs); | ||
254 | |||
255 | if (cs_change) | ||
256 | mpc52xx_psc_spi_deactivate_cs(spi); | ||
257 | } | ||
258 | |||
259 | m->status = status; | ||
260 | m->complete(m->context); | ||
261 | |||
262 | if (status || !cs_change) | ||
263 | mpc52xx_psc_spi_deactivate_cs(spi); | ||
264 | |||
265 | mpc52xx_psc_spi_transfer_setup(spi, NULL); | ||
266 | |||
267 | spin_lock_irq(&mps->lock); | ||
268 | } | ||
269 | mps->busy = 0; | ||
270 | spin_unlock_irq(&mps->lock); | ||
271 | } | ||
272 | |||
273 | static int mpc52xx_psc_spi_setup(struct spi_device *spi) | ||
274 | { | ||
275 | struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); | ||
276 | struct mpc52xx_psc_spi_cs *cs = spi->controller_state; | ||
277 | unsigned long flags; | ||
278 | |||
279 | if (spi->bits_per_word%8) | ||
280 | return -EINVAL; | ||
281 | |||
282 | if (!cs) { | ||
283 | cs = kzalloc(sizeof *cs, GFP_KERNEL); | ||
284 | if (!cs) | ||
285 | return -ENOMEM; | ||
286 | spi->controller_state = cs; | ||
287 | } | ||
288 | |||
289 | cs->bits_per_word = spi->bits_per_word; | ||
290 | cs->speed_hz = spi->max_speed_hz; | ||
291 | |||
292 | spin_lock_irqsave(&mps->lock, flags); | ||
293 | if (!mps->busy) | ||
294 | mpc52xx_psc_spi_deactivate_cs(spi); | ||
295 | spin_unlock_irqrestore(&mps->lock, flags); | ||
296 | |||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | static int mpc52xx_psc_spi_transfer(struct spi_device *spi, | ||
301 | struct spi_message *m) | ||
302 | { | ||
303 | struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master); | ||
304 | unsigned long flags; | ||
305 | |||
306 | m->actual_length = 0; | ||
307 | m->status = -EINPROGRESS; | ||
308 | |||
309 | spin_lock_irqsave(&mps->lock, flags); | ||
310 | list_add_tail(&m->queue, &mps->queue); | ||
311 | queue_work(mps->workqueue, &mps->work); | ||
312 | spin_unlock_irqrestore(&mps->lock, flags); | ||
313 | |||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | static void mpc52xx_psc_spi_cleanup(struct spi_device *spi) | ||
318 | { | ||
319 | kfree(spi->controller_state); | ||
320 | } | ||
321 | |||
322 | static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps) | ||
323 | { | ||
324 | struct mpc52xx_cdm __iomem *cdm; | ||
325 | struct mpc52xx_gpio __iomem *gpio; | ||
326 | struct mpc52xx_psc __iomem *psc = mps->psc; | ||
327 | u32 ul; | ||
328 | u32 mclken_div; | ||
329 | int ret = 0; | ||
330 | |||
331 | #if defined(CONFIG_PPC_MERGE) | ||
332 | cdm = mpc52xx_find_and_map("mpc52xx-cdm"); | ||
333 | gpio = mpc52xx_find_and_map("mpc52xx-gpio"); | ||
334 | #else | ||
335 | cdm = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE); | ||
336 | gpio = ioremap(MPC52xx_PA(MPC52xx_GPIO_OFFSET), MPC52xx_GPIO_SIZE); | ||
337 | #endif | ||
338 | if (!cdm || !gpio) { | ||
339 | printk(KERN_ERR "Error mapping CDM/GPIO\n"); | ||
340 | ret = -EFAULT; | ||
341 | goto unmap_regs; | ||
342 | } | ||
343 | |||
344 | /* default sysclk is 512MHz */ | ||
345 | mclken_div = 0x8000 | | ||
346 | (((mps->sysclk ? mps->sysclk : 512000000) / MCLK) & 0x1FF); | ||
347 | |||
348 | switch (psc_id) { | ||
349 | case 1: | ||
350 | ul = in_be32(&gpio->port_config); | ||
351 | ul &= 0xFFFFFFF8; | ||
352 | ul |= 0x00000006; | ||
353 | out_be32(&gpio->port_config, ul); | ||
354 | out_be16(&cdm->mclken_div_psc1, mclken_div); | ||
355 | ul = in_be32(&cdm->clk_enables); | ||
356 | ul |= 0x00000020; | ||
357 | out_be32(&cdm->clk_enables, ul); | ||
358 | break; | ||
359 | case 2: | ||
360 | ul = in_be32(&gpio->port_config); | ||
361 | ul &= 0xFFFFFF8F; | ||
362 | ul |= 0x00000060; | ||
363 | out_be32(&gpio->port_config, ul); | ||
364 | out_be16(&cdm->mclken_div_psc2, mclken_div); | ||
365 | ul = in_be32(&cdm->clk_enables); | ||
366 | ul |= 0x00000040; | ||
367 | out_be32(&cdm->clk_enables, ul); | ||
368 | break; | ||
369 | case 3: | ||
370 | ul = in_be32(&gpio->port_config); | ||
371 | ul &= 0xFFFFF0FF; | ||
372 | ul |= 0x00000600; | ||
373 | out_be32(&gpio->port_config, ul); | ||
374 | out_be16(&cdm->mclken_div_psc3, mclken_div); | ||
375 | ul = in_be32(&cdm->clk_enables); | ||
376 | ul |= 0x00000080; | ||
377 | out_be32(&cdm->clk_enables, ul); | ||
378 | break; | ||
379 | case 6: | ||
380 | ul = in_be32(&gpio->port_config); | ||
381 | ul &= 0xFF8FFFFF; | ||
382 | ul |= 0x00700000; | ||
383 | out_be32(&gpio->port_config, ul); | ||
384 | out_be16(&cdm->mclken_div_psc6, mclken_div); | ||
385 | ul = in_be32(&cdm->clk_enables); | ||
386 | ul |= 0x00000010; | ||
387 | out_be32(&cdm->clk_enables, ul); | ||
388 | break; | ||
389 | default: | ||
390 | ret = -EINVAL; | ||
391 | goto unmap_regs; | ||
392 | } | ||
393 | |||
394 | /* Reset the PSC into a known state */ | ||
395 | out_8(&psc->command, MPC52xx_PSC_RST_RX); | ||
396 | out_8(&psc->command, MPC52xx_PSC_RST_TX); | ||
397 | out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE); | ||
398 | |||
399 | /* Disable interrupts, interrupts are based on alarm level */ | ||
400 | out_be16(&psc->mpc52xx_psc_imr, 0); | ||
401 | out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1); | ||
402 | out_8(&psc->rfcntl, 0); | ||
403 | out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL); | ||
404 | |||
405 | /* Configure 8bit codec mode as a SPI master and use EOF flags */ | ||
406 | /* SICR_SIM_CODEC8|SICR_GENCLK|SICR_SPI|SICR_MSTR|SICR_USEEOF */ | ||
407 | out_be32(&psc->sicr, 0x0180C800); | ||
408 | out_be16(&psc->ccr, 0x070F); /* by default SPI Clk 1MHz */ | ||
409 | |||
410 | /* Set 2ms DTL delay */ | ||
411 | out_8(&psc->ctur, 0x00); | ||
412 | out_8(&psc->ctlr, 0x84); | ||
413 | |||
414 | mps->bits_per_word = 8; | ||
415 | |||
416 | unmap_regs: | ||
417 | if (cdm) | ||
418 | iounmap(cdm); | ||
419 | if (gpio) | ||
420 | iounmap(gpio); | ||
421 | |||
422 | return ret; | ||
423 | } | ||
424 | |||
425 | static irqreturn_t mpc52xx_psc_spi_isr(int irq, void *dev_id) | ||
426 | { | ||
427 | struct mpc52xx_psc_spi *mps = (struct mpc52xx_psc_spi *)dev_id; | ||
428 | struct mpc52xx_psc __iomem *psc = mps->psc; | ||
429 | |||
430 | /* disable interrupt and wake up the work queue */ | ||
431 | if (in_be16(&psc->mpc52xx_psc_isr) & MPC52xx_PSC_IMR_RXRDY) { | ||
432 | out_be16(&psc->mpc52xx_psc_imr, 0); | ||
433 | complete(&mps->done); | ||
434 | return IRQ_HANDLED; | ||
435 | } | ||
436 | return IRQ_NONE; | ||
437 | } | ||
438 | |||
439 | /* bus_num is used only for the case dev->platform_data == NULL */ | ||
440 | static int __init mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr, | ||
441 | u32 size, unsigned int irq, s16 bus_num) | ||
442 | { | ||
443 | struct fsl_spi_platform_data *pdata = dev->platform_data; | ||
444 | struct mpc52xx_psc_spi *mps; | ||
445 | struct spi_master *master; | ||
446 | int ret; | ||
447 | |||
448 | if (pdata == NULL) | ||
449 | return -ENODEV; | ||
450 | |||
451 | master = spi_alloc_master(dev, sizeof *mps); | ||
452 | if (master == NULL) | ||
453 | return -ENOMEM; | ||
454 | |||
455 | dev_set_drvdata(dev, master); | ||
456 | mps = spi_master_get_devdata(master); | ||
457 | |||
458 | mps->irq = irq; | ||
459 | if (pdata == NULL) { | ||
460 | dev_warn(dev, "probe called without platform data, no " | ||
461 | "(de)activate_cs function will be called\n"); | ||
462 | mps->activate_cs = NULL; | ||
463 | mps->deactivate_cs = NULL; | ||
464 | mps->sysclk = 0; | ||
465 | master->bus_num = bus_num; | ||
466 | master->num_chipselect = 255; | ||
467 | } else { | ||
468 | mps->activate_cs = pdata->activate_cs; | ||
469 | mps->deactivate_cs = pdata->deactivate_cs; | ||
470 | mps->sysclk = pdata->sysclk; | ||
471 | master->bus_num = pdata->bus_num; | ||
472 | master->num_chipselect = pdata->max_chipselect; | ||
473 | } | ||
474 | master->setup = mpc52xx_psc_spi_setup; | ||
475 | master->transfer = mpc52xx_psc_spi_transfer; | ||
476 | master->cleanup = mpc52xx_psc_spi_cleanup; | ||
477 | |||
478 | mps->psc = ioremap(regaddr, size); | ||
479 | if (!mps->psc) { | ||
480 | dev_err(dev, "could not ioremap I/O port range\n"); | ||
481 | ret = -EFAULT; | ||
482 | goto free_master; | ||
483 | } | ||
484 | |||
485 | ret = request_irq(mps->irq, mpc52xx_psc_spi_isr, 0, "mpc52xx-psc-spi", | ||
486 | mps); | ||
487 | if (ret) | ||
488 | goto free_master; | ||
489 | |||
490 | ret = mpc52xx_psc_spi_port_config(master->bus_num, mps); | ||
491 | if (ret < 0) | ||
492 | goto free_irq; | ||
493 | |||
494 | spin_lock_init(&mps->lock); | ||
495 | init_completion(&mps->done); | ||
496 | INIT_WORK(&mps->work, mpc52xx_psc_spi_work); | ||
497 | INIT_LIST_HEAD(&mps->queue); | ||
498 | |||
499 | mps->workqueue = create_singlethread_workqueue( | ||
500 | master->cdev.dev->bus_id); | ||
501 | if (mps->workqueue == NULL) { | ||
502 | ret = -EBUSY; | ||
503 | goto free_irq; | ||
504 | } | ||
505 | |||
506 | ret = spi_register_master(master); | ||
507 | if (ret < 0) | ||
508 | goto unreg_master; | ||
509 | |||
510 | return ret; | ||
511 | |||
512 | unreg_master: | ||
513 | destroy_workqueue(mps->workqueue); | ||
514 | free_irq: | ||
515 | free_irq(mps->irq, mps); | ||
516 | free_master: | ||
517 | if (mps->psc) | ||
518 | iounmap(mps->psc); | ||
519 | spi_master_put(master); | ||
520 | |||
521 | return ret; | ||
522 | } | ||
523 | |||
524 | static int __exit mpc52xx_psc_spi_do_remove(struct device *dev) | ||
525 | { | ||
526 | struct spi_master *master = dev_get_drvdata(dev); | ||
527 | struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master); | ||
528 | |||
529 | flush_workqueue(mps->workqueue); | ||
530 | destroy_workqueue(mps->workqueue); | ||
531 | spi_unregister_master(master); | ||
532 | free_irq(mps->irq, mps); | ||
533 | if (mps->psc) | ||
534 | iounmap(mps->psc); | ||
535 | |||
536 | return 0; | ||
537 | } | ||
538 | |||
539 | #if !defined(CONFIG_PPC_MERGE) | ||
540 | static int __init mpc52xx_psc_spi_probe(struct platform_device *dev) | ||
541 | { | ||
542 | switch(dev->id) { | ||
543 | case 1: | ||
544 | case 2: | ||
545 | case 3: | ||
546 | case 6: | ||
547 | return mpc52xx_psc_spi_do_probe(&dev->dev, | ||
548 | MPC52xx_PA(MPC52xx_PSCx_OFFSET(dev->id)), | ||
549 | MPC52xx_PSC_SIZE, platform_get_irq(dev, 0), dev->id); | ||
550 | default: | ||
551 | return -EINVAL; | ||
552 | } | ||
553 | } | ||
554 | |||
555 | static int __exit mpc52xx_psc_spi_remove(struct platform_device *dev) | ||
556 | { | ||
557 | return mpc52xx_psc_spi_do_remove(&dev->dev); | ||
558 | } | ||
559 | |||
560 | static struct platform_driver mpc52xx_psc_spi_platform_driver = { | ||
561 | .remove = __exit_p(mpc52xx_psc_spi_remove), | ||
562 | .driver = { | ||
563 | .name = "mpc52xx-psc-spi", | ||
564 | .owner = THIS_MODULE, | ||
565 | }, | ||
566 | }; | ||
567 | |||
568 | static int __init mpc52xx_psc_spi_init(void) | ||
569 | { | ||
570 | return platform_driver_probe(&mpc52xx_psc_spi_platform_driver, | ||
571 | mpc52xx_psc_spi_probe); | ||
572 | } | ||
573 | module_init(mpc52xx_psc_spi_init); | ||
574 | |||
575 | static void __exit mpc52xx_psc_spi_exit(void) | ||
576 | { | ||
577 | platform_driver_unregister(&mpc52xx_psc_spi_platform_driver); | ||
578 | } | ||
579 | module_exit(mpc52xx_psc_spi_exit); | ||
580 | |||
581 | #else /* defined(CONFIG_PPC_MERGE) */ | ||
582 | |||
583 | static int __init mpc52xx_psc_spi_of_probe(struct of_device *op, | ||
584 | const struct of_device_id *match) | ||
585 | { | ||
586 | const u32 *regaddr_p; | ||
587 | u64 regaddr64, size64; | ||
588 | s16 id = -1; | ||
589 | |||
590 | regaddr_p = of_get_address(op->node, 0, &size64, NULL); | ||
591 | if (!regaddr_p) { | ||
592 | printk(KERN_ERR "Invalid PSC address\n"); | ||
593 | return -EINVAL; | ||
594 | } | ||
595 | regaddr64 = of_translate_address(op->node, regaddr_p); | ||
596 | |||
597 | if (op->dev.platform_data == NULL) { | ||
598 | struct device_node *np; | ||
599 | int i = 0; | ||
600 | |||
601 | for_each_node_by_type(np, "spi") { | ||
602 | if (of_find_device_by_node(np) == op) { | ||
603 | id = i; | ||
604 | break; | ||
605 | } | ||
606 | i++; | ||
607 | } | ||
608 | } | ||
609 | |||
610 | return mpc52xx_psc_spi_do_probe(&op->dev, (u32)regaddr64, (u32)size64, | ||
611 | irq_of_parse_and_map(op->node, 0), id); | ||
612 | } | ||
613 | |||
614 | static int __exit mpc52xx_psc_spi_of_remove(struct of_device *op) | ||
615 | { | ||
616 | return mpc52xx_psc_spi_do_remove(&op->dev); | ||
617 | } | ||
618 | |||
619 | static struct of_device_id mpc52xx_psc_spi_of_match[] = { | ||
620 | { .type = "spi", .compatible = "mpc52xx-psc-spi", }, | ||
621 | {}, | ||
622 | }; | ||
623 | |||
624 | MODULE_DEVICE_TABLE(of, mpc52xx_psc_spi_of_match); | ||
625 | |||
626 | static struct of_platform_driver mpc52xx_psc_spi_of_driver = { | ||
627 | .owner = THIS_MODULE, | ||
628 | .name = "mpc52xx-psc-spi", | ||
629 | .match_table = mpc52xx_psc_spi_of_match, | ||
630 | .probe = mpc52xx_psc_spi_of_probe, | ||
631 | .remove = __exit_p(mpc52xx_psc_spi_of_remove), | ||
632 | .driver = { | ||
633 | .name = "mpc52xx-psc-spi", | ||
634 | .owner = THIS_MODULE, | ||
635 | }, | ||
636 | }; | ||
637 | |||
638 | static int __init mpc52xx_psc_spi_init(void) | ||
639 | { | ||
640 | return of_register_platform_driver(&mpc52xx_psc_spi_of_driver); | ||
641 | } | ||
642 | module_init(mpc52xx_psc_spi_init); | ||
643 | |||
644 | static void __exit mpc52xx_psc_spi_exit(void) | ||
645 | { | ||
646 | of_unregister_platform_driver(&mpc52xx_psc_spi_of_driver); | ||
647 | } | ||
648 | module_exit(mpc52xx_psc_spi_exit); | ||
649 | |||
650 | #endif /* defined(CONFIG_PPC_MERGE) */ | ||
651 | |||
652 | MODULE_AUTHOR("Dragos Carp"); | ||
653 | MODULE_DESCRIPTION("MPC52xx PSC SPI Driver"); | ||
654 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index f54438828cb9..eebcb708cff1 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -748,6 +748,22 @@ config FB_S1D13XXX | |||
748 | working with S1D13806). Product specs at | 748 | working with S1D13806). Product specs at |
749 | <http://www.erd.epson.com/vdc/html/legacy_13xxx.htm> | 749 | <http://www.erd.epson.com/vdc/html/legacy_13xxx.htm> |
750 | 750 | ||
751 | config FB_ATMEL | ||
752 | tristate "AT91/AT32 LCD Controller support" | ||
753 | depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || AVR32) | ||
754 | select FB_CFB_FILLRECT | ||
755 | select FB_CFB_COPYAREA | ||
756 | select FB_CFB_IMAGEBLIT | ||
757 | help | ||
758 | This enables support for the AT91/AT32 LCD Controller. | ||
759 | |||
760 | config FB_INTSRAM | ||
761 | bool "Frame Buffer in internal SRAM" | ||
762 | depends on FB_ATMEL && ARCH_AT91SAM9261 | ||
763 | help | ||
764 | Say Y if you want to map Frame Buffer in internal SRAM. Say N if you want | ||
765 | to let frame buffer in external SDRAM. | ||
766 | |||
751 | config FB_NVIDIA | 767 | config FB_NVIDIA |
752 | tristate "nVidia Framebuffer Support" | 768 | tristate "nVidia Framebuffer Support" |
753 | depends on FB && PCI | 769 | depends on FB && PCI |
@@ -780,6 +796,15 @@ config FB_NVIDIA_I2C | |||
780 | independently validate video mode parameters, you should say Y | 796 | independently validate video mode parameters, you should say Y |
781 | here. | 797 | here. |
782 | 798 | ||
799 | config FB_NVIDIA_DEBUG | ||
800 | bool "Lots of debug output" | ||
801 | depends on FB_NVIDIA | ||
802 | default n | ||
803 | help | ||
804 | Say Y here if you want the nVidia driver to output all sorts | ||
805 | of debugging information to provide to the maintainer when | ||
806 | something goes wrong. | ||
807 | |||
783 | config FB_NVIDIA_BACKLIGHT | 808 | config FB_NVIDIA_BACKLIGHT |
784 | bool "Support for backlight control" | 809 | bool "Support for backlight control" |
785 | depends on FB_NVIDIA | 810 | depends on FB_NVIDIA |
@@ -819,7 +844,7 @@ config FB_RIVA_I2C | |||
819 | here. | 844 | here. |
820 | 845 | ||
821 | config FB_RIVA_DEBUG | 846 | config FB_RIVA_DEBUG |
822 | bool "Lots of debug output from Riva(nVidia) driver" | 847 | bool "Lots of debug output" |
823 | depends on FB_RIVA | 848 | depends on FB_RIVA |
824 | default n | 849 | default n |
825 | help | 850 | help |
@@ -1431,8 +1456,11 @@ config FB_ARK | |||
1431 | and ICS 5342 RAMDAC. | 1456 | and ICS 5342 RAMDAC. |
1432 | 1457 | ||
1433 | config FB_PM3 | 1458 | config FB_PM3 |
1434 | tristate "Permedia3 support" | 1459 | tristate "Permedia3 support (EXPERIMENTAL)" |
1435 | depends on FB && PCI && BROKEN | 1460 | depends on FB && PCI && EXPERIMENTAL |
1461 | select FB_CFB_FILLRECT | ||
1462 | select FB_CFB_COPYAREA | ||
1463 | select FB_CFB_IMAGEBLIT | ||
1436 | help | 1464 | help |
1437 | This is the frame buffer device driver for the 3DLabs Permedia3 | 1465 | This is the frame buffer device driver for the 3DLabs Permedia3 |
1438 | chipset, used in Formac ProFormance III, 3DLabs Oxygen VX1 & | 1466 | chipset, used in Formac ProFormance III, 3DLabs Oxygen VX1 & |
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 0b70567458fb..bd8b05229500 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
@@ -87,6 +87,7 @@ obj-$(CONFIG_FB_G364) += g364fb.o | |||
87 | obj-$(CONFIG_FB_SA1100) += sa1100fb.o | 87 | obj-$(CONFIG_FB_SA1100) += sa1100fb.o |
88 | obj-$(CONFIG_FB_HIT) += hitfb.o | 88 | obj-$(CONFIG_FB_HIT) += hitfb.o |
89 | obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o | 89 | obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o |
90 | obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o | ||
90 | obj-$(CONFIG_FB_PVR2) += pvr2fb.o | 91 | obj-$(CONFIG_FB_PVR2) += pvr2fb.o |
91 | obj-$(CONFIG_FB_VOODOO1) += sstfb.o | 92 | obj-$(CONFIG_FB_VOODOO1) += sstfb.o |
92 | obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o | 93 | obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o |
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c new file mode 100644 index 000000000000..e1d5bd0c98c4 --- /dev/null +++ b/drivers/video/atmel_lcdfb.c | |||
@@ -0,0 +1,752 @@ | |||
1 | /* | ||
2 | * Driver for AT91/AT32 LCD Controller | ||
3 | * | ||
4 | * Copyright (C) 2007 Atmel Corporation | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file COPYING in the main directory of this archive for | ||
8 | * more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | #include <linux/dma-mapping.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/clk.h> | ||
16 | #include <linux/fb.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/delay.h> | ||
19 | |||
20 | #include <asm/arch/board.h> | ||
21 | #include <asm/arch/cpu.h> | ||
22 | #include <asm/arch/gpio.h> | ||
23 | |||
24 | #include <video/atmel_lcdc.h> | ||
25 | |||
26 | #define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg)) | ||
27 | #define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg)) | ||
28 | |||
29 | /* configurable parameters */ | ||
30 | #define ATMEL_LCDC_CVAL_DEFAULT 0xc8 | ||
31 | #define ATMEL_LCDC_DMA_BURST_LEN 8 | ||
32 | |||
33 | #if defined(CONFIG_ARCH_AT91SAM9263) | ||
34 | #define ATMEL_LCDC_FIFO_SIZE 2048 | ||
35 | #else | ||
36 | #define ATMEL_LCDC_FIFO_SIZE 512 | ||
37 | #endif | ||
38 | |||
39 | #if defined(CONFIG_ARCH_AT91) | ||
40 | #define ATMEL_LCDFB_FBINFO_DEFAULT FBINFO_DEFAULT | ||
41 | |||
42 | static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, | ||
43 | struct fb_var_screeninfo *var) | ||
44 | { | ||
45 | |||
46 | } | ||
47 | #elif defined(CONFIG_AVR32) | ||
48 | #define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \ | ||
49 | | FBINFO_PARTIAL_PAN_OK \ | ||
50 | | FBINFO_HWACCEL_XPAN \ | ||
51 | | FBINFO_HWACCEL_YPAN) | ||
52 | |||
53 | static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, | ||
54 | struct fb_var_screeninfo *var) | ||
55 | { | ||
56 | u32 dma2dcfg; | ||
57 | u32 pixeloff; | ||
58 | |||
59 | pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f; | ||
60 | |||
61 | dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8; | ||
62 | dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET; | ||
63 | lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg); | ||
64 | |||
65 | /* Update configuration */ | ||
66 | lcdc_writel(sinfo, ATMEL_LCDC_DMACON, | ||
67 | lcdc_readl(sinfo, ATMEL_LCDC_DMACON) | ||
68 | | ATMEL_LCDC_DMAUPDT); | ||
69 | } | ||
70 | #endif | ||
71 | |||
72 | |||
73 | static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = { | ||
74 | .type = FB_TYPE_PACKED_PIXELS, | ||
75 | .visual = FB_VISUAL_TRUECOLOR, | ||
76 | .xpanstep = 0, | ||
77 | .ypanstep = 0, | ||
78 | .ywrapstep = 0, | ||
79 | .accel = FB_ACCEL_NONE, | ||
80 | }; | ||
81 | |||
82 | |||
83 | static void atmel_lcdfb_update_dma(struct fb_info *info, | ||
84 | struct fb_var_screeninfo *var) | ||
85 | { | ||
86 | struct atmel_lcdfb_info *sinfo = info->par; | ||
87 | struct fb_fix_screeninfo *fix = &info->fix; | ||
88 | unsigned long dma_addr; | ||
89 | |||
90 | dma_addr = (fix->smem_start + var->yoffset * fix->line_length | ||
91 | + var->xoffset * var->bits_per_pixel / 8); | ||
92 | |||
93 | dma_addr &= ~3UL; | ||
94 | |||
95 | /* Set framebuffer DMA base address and pixel offset */ | ||
96 | lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr); | ||
97 | |||
98 | atmel_lcdfb_update_dma2d(sinfo, var); | ||
99 | } | ||
100 | |||
101 | static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo) | ||
102 | { | ||
103 | struct fb_info *info = sinfo->info; | ||
104 | |||
105 | dma_free_writecombine(info->device, info->fix.smem_len, | ||
106 | info->screen_base, info->fix.smem_start); | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory | ||
111 | * @sinfo: the frame buffer to allocate memory for | ||
112 | */ | ||
113 | static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo) | ||
114 | { | ||
115 | struct fb_info *info = sinfo->info; | ||
116 | struct fb_var_screeninfo *var = &info->var; | ||
117 | |||
118 | info->fix.smem_len = (var->xres_virtual * var->yres_virtual | ||
119 | * ((var->bits_per_pixel + 7) / 8)); | ||
120 | |||
121 | info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len, | ||
122 | (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL); | ||
123 | |||
124 | if (!info->screen_base) { | ||
125 | return -ENOMEM; | ||
126 | } | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | /** | ||
132 | * atmel_lcdfb_check_var - Validates a var passed in. | ||
133 | * @var: frame buffer variable screen structure | ||
134 | * @info: frame buffer structure that represents a single frame buffer | ||
135 | * | ||
136 | * Checks to see if the hardware supports the state requested by | ||
137 | * var passed in. This function does not alter the hardware | ||
138 | * state!!! This means the data stored in struct fb_info and | ||
139 | * struct atmel_lcdfb_info do not change. This includes the var | ||
140 | * inside of struct fb_info. Do NOT change these. This function | ||
141 | * can be called on its own if we intent to only test a mode and | ||
142 | * not actually set it. The stuff in modedb.c is a example of | ||
143 | * this. If the var passed in is slightly off by what the | ||
144 | * hardware can support then we alter the var PASSED in to what | ||
145 | * we can do. If the hardware doesn't support mode change a | ||
146 | * -EINVAL will be returned by the upper layers. You don't need | ||
147 | * to implement this function then. If you hardware doesn't | ||
148 | * support changing the resolution then this function is not | ||
149 | * needed. In this case the driver would just provide a var that | ||
150 | * represents the static state the screen is in. | ||
151 | * | ||
152 | * Returns negative errno on error, or zero on success. | ||
153 | */ | ||
154 | static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, | ||
155 | struct fb_info *info) | ||
156 | { | ||
157 | struct device *dev = info->device; | ||
158 | struct atmel_lcdfb_info *sinfo = info->par; | ||
159 | unsigned long clk_value_khz; | ||
160 | |||
161 | clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; | ||
162 | |||
163 | dev_dbg(dev, "%s:\n", __func__); | ||
164 | dev_dbg(dev, " resolution: %ux%u\n", var->xres, var->yres); | ||
165 | dev_dbg(dev, " pixclk: %lu KHz\n", PICOS2KHZ(var->pixclock)); | ||
166 | dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel); | ||
167 | dev_dbg(dev, " clk: %lu KHz\n", clk_value_khz); | ||
168 | |||
169 | if ((PICOS2KHZ(var->pixclock) * var->bits_per_pixel / 8) > clk_value_khz) { | ||
170 | dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock)); | ||
171 | return -EINVAL; | ||
172 | } | ||
173 | |||
174 | /* Force same alignment for each line */ | ||
175 | var->xres = (var->xres + 3) & ~3UL; | ||
176 | var->xres_virtual = (var->xres_virtual + 3) & ~3UL; | ||
177 | |||
178 | var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0; | ||
179 | var->transp.msb_right = 0; | ||
180 | var->transp.offset = var->transp.length = 0; | ||
181 | var->xoffset = var->yoffset = 0; | ||
182 | |||
183 | switch (var->bits_per_pixel) { | ||
184 | case 2: | ||
185 | case 4: | ||
186 | case 8: | ||
187 | var->red.offset = var->green.offset = var->blue.offset = 0; | ||
188 | var->red.length = var->green.length = var->blue.length | ||
189 | = var->bits_per_pixel; | ||
190 | break; | ||
191 | case 15: | ||
192 | case 16: | ||
193 | var->red.offset = 0; | ||
194 | var->green.offset = 5; | ||
195 | var->blue.offset = 10; | ||
196 | var->red.length = var->green.length = var->blue.length = 5; | ||
197 | break; | ||
198 | case 24: | ||
199 | case 32: | ||
200 | var->red.offset = 0; | ||
201 | var->green.offset = 8; | ||
202 | var->blue.offset = 16; | ||
203 | var->red.length = var->green.length = var->blue.length = 8; | ||
204 | break; | ||
205 | default: | ||
206 | dev_err(dev, "color depth %d not supported\n", | ||
207 | var->bits_per_pixel); | ||
208 | return -EINVAL; | ||
209 | } | ||
210 | |||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | /** | ||
215 | * atmel_lcdfb_set_par - Alters the hardware state. | ||
216 | * @info: frame buffer structure that represents a single frame buffer | ||
217 | * | ||
218 | * Using the fb_var_screeninfo in fb_info we set the resolution | ||
219 | * of the this particular framebuffer. This function alters the | ||
220 | * par AND the fb_fix_screeninfo stored in fb_info. It doesn't | ||
221 | * not alter var in fb_info since we are using that data. This | ||
222 | * means we depend on the data in var inside fb_info to be | ||
223 | * supported by the hardware. atmel_lcdfb_check_var is always called | ||
224 | * before atmel_lcdfb_set_par to ensure this. Again if you can't | ||
225 | * change the resolution you don't need this function. | ||
226 | * | ||
227 | */ | ||
228 | static int atmel_lcdfb_set_par(struct fb_info *info) | ||
229 | { | ||
230 | struct atmel_lcdfb_info *sinfo = info->par; | ||
231 | unsigned long value; | ||
232 | unsigned long clk_value_khz; | ||
233 | |||
234 | dev_dbg(info->device, "%s:\n", __func__); | ||
235 | dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n", | ||
236 | info->var.xres, info->var.yres, | ||
237 | info->var.xres_virtual, info->var.yres_virtual); | ||
238 | |||
239 | /* Turn off the LCD controller and the DMA controller */ | ||
240 | lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET); | ||
241 | |||
242 | lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0); | ||
243 | |||
244 | if (info->var.bits_per_pixel <= 8) | ||
245 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; | ||
246 | else | ||
247 | info->fix.visual = FB_VISUAL_TRUECOLOR; | ||
248 | |||
249 | info->fix.line_length = info->var.xres_virtual * (info->var.bits_per_pixel / 8); | ||
250 | |||
251 | /* Re-initialize the DMA engine... */ | ||
252 | dev_dbg(info->device, " * update DMA engine\n"); | ||
253 | atmel_lcdfb_update_dma(info, &info->var); | ||
254 | |||
255 | /* ...set frame size and burst length = 8 words (?) */ | ||
256 | value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32; | ||
257 | value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET); | ||
258 | lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value); | ||
259 | |||
260 | /* Now, the LCDC core... */ | ||
261 | |||
262 | /* Set pixel clock */ | ||
263 | clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; | ||
264 | |||
265 | value = clk_value_khz / PICOS2KHZ(info->var.pixclock); | ||
266 | |||
267 | if (clk_value_khz % PICOS2KHZ(info->var.pixclock)) | ||
268 | value++; | ||
269 | |||
270 | value = (value / 2) - 1; | ||
271 | |||
272 | if (value <= 0) { | ||
273 | dev_notice(info->device, "Bypassing pixel clock divider\n"); | ||
274 | lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS); | ||
275 | } else | ||
276 | lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, value << ATMEL_LCDC_CLKVAL_OFFSET); | ||
277 | |||
278 | /* Initialize control register 2 */ | ||
279 | value = sinfo->default_lcdcon2; | ||
280 | |||
281 | if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) | ||
282 | value |= ATMEL_LCDC_INVLINE_INVERTED; | ||
283 | if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) | ||
284 | value |= ATMEL_LCDC_INVFRAME_INVERTED; | ||
285 | |||
286 | switch (info->var.bits_per_pixel) { | ||
287 | case 1: value |= ATMEL_LCDC_PIXELSIZE_1; break; | ||
288 | case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break; | ||
289 | case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break; | ||
290 | case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break; | ||
291 | case 15: /* fall through */ | ||
292 | case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break; | ||
293 | case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break; | ||
294 | case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break; | ||
295 | default: BUG(); break; | ||
296 | } | ||
297 | dev_dbg(info->device, " * LCDCON2 = %08lx\n", value); | ||
298 | lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value); | ||
299 | |||
300 | /* Vertical timing */ | ||
301 | value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET; | ||
302 | value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET; | ||
303 | value |= info->var.lower_margin; | ||
304 | dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value); | ||
305 | lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value); | ||
306 | |||
307 | /* Horizontal timing */ | ||
308 | value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET; | ||
309 | value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET; | ||
310 | value |= (info->var.left_margin - 1); | ||
311 | dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value); | ||
312 | lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value); | ||
313 | |||
314 | /* Display size */ | ||
315 | value = (info->var.xres - 1) << ATMEL_LCDC_HOZVAL_OFFSET; | ||
316 | value |= info->var.yres - 1; | ||
317 | lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value); | ||
318 | |||
319 | /* FIFO Threshold: Use formula from data sheet */ | ||
320 | value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3); | ||
321 | lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value); | ||
322 | |||
323 | /* Toggle LCD_MODE every frame */ | ||
324 | lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0); | ||
325 | |||
326 | /* Disable all interrupts */ | ||
327 | lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); | ||
328 | |||
329 | /* Set contrast */ | ||
330 | value = ATMEL_LCDC_PS_DIV8 | ATMEL_LCDC_POL_POSITIVE | ATMEL_LCDC_ENA_PWMENABLE; | ||
331 | lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value); | ||
332 | lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); | ||
333 | /* ...wait for DMA engine to become idle... */ | ||
334 | while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) | ||
335 | msleep(10); | ||
336 | |||
337 | dev_dbg(info->device, " * re-enable DMA engine\n"); | ||
338 | /* ...and enable it with updated configuration */ | ||
339 | lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon); | ||
340 | |||
341 | dev_dbg(info->device, " * re-enable LCDC core\n"); | ||
342 | lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, | ||
343 | (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR); | ||
344 | |||
345 | dev_dbg(info->device, " * DONE\n"); | ||
346 | |||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | static inline unsigned int chan_to_field(unsigned int chan, const struct fb_bitfield *bf) | ||
351 | { | ||
352 | chan &= 0xffff; | ||
353 | chan >>= 16 - bf->length; | ||
354 | return chan << bf->offset; | ||
355 | } | ||
356 | |||
357 | /** | ||
358 | * atmel_lcdfb_setcolreg - Optional function. Sets a color register. | ||
359 | * @regno: Which register in the CLUT we are programming | ||
360 | * @red: The red value which can be up to 16 bits wide | ||
361 | * @green: The green value which can be up to 16 bits wide | ||
362 | * @blue: The blue value which can be up to 16 bits wide. | ||
363 | * @transp: If supported the alpha value which can be up to 16 bits wide. | ||
364 | * @info: frame buffer info structure | ||
365 | * | ||
366 | * Set a single color register. The values supplied have a 16 bit | ||
367 | * magnitude which needs to be scaled in this function for the hardware. | ||
368 | * Things to take into consideration are how many color registers, if | ||
369 | * any, are supported with the current color visual. With truecolor mode | ||
370 | * no color palettes are supported. Here a psuedo palette is created | ||
371 | * which we store the value in pseudo_palette in struct fb_info. For | ||
372 | * pseudocolor mode we have a limited color palette. To deal with this | ||
373 | * we can program what color is displayed for a particular pixel value. | ||
374 | * DirectColor is similar in that we can program each color field. If | ||
375 | * we have a static colormap we don't need to implement this function. | ||
376 | * | ||
377 | * Returns negative errno on error, or zero on success. In an | ||
378 | * ideal world, this would have been the case, but as it turns | ||
379 | * out, the other drivers return 1 on failure, so that's what | ||
380 | * we're going to do. | ||
381 | */ | ||
382 | static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red, | ||
383 | unsigned int green, unsigned int blue, | ||
384 | unsigned int transp, struct fb_info *info) | ||
385 | { | ||
386 | struct atmel_lcdfb_info *sinfo = info->par; | ||
387 | unsigned int val; | ||
388 | u32 *pal; | ||
389 | int ret = 1; | ||
390 | |||
391 | if (info->var.grayscale) | ||
392 | red = green = blue = (19595 * red + 38470 * green | ||
393 | + 7471 * blue) >> 16; | ||
394 | |||
395 | switch (info->fix.visual) { | ||
396 | case FB_VISUAL_TRUECOLOR: | ||
397 | if (regno < 16) { | ||
398 | pal = info->pseudo_palette; | ||
399 | |||
400 | val = chan_to_field(red, &info->var.red); | ||
401 | val |= chan_to_field(green, &info->var.green); | ||
402 | val |= chan_to_field(blue, &info->var.blue); | ||
403 | |||
404 | pal[regno] = val; | ||
405 | ret = 0; | ||
406 | } | ||
407 | break; | ||
408 | |||
409 | case FB_VISUAL_PSEUDOCOLOR: | ||
410 | if (regno < 256) { | ||
411 | val = ((red >> 11) & 0x001f); | ||
412 | val |= ((green >> 6) & 0x03e0); | ||
413 | val |= ((blue >> 1) & 0x7c00); | ||
414 | |||
415 | /* | ||
416 | * TODO: intensity bit. Maybe something like | ||
417 | * ~(red[10] ^ green[10] ^ blue[10]) & 1 | ||
418 | */ | ||
419 | |||
420 | lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val); | ||
421 | ret = 0; | ||
422 | } | ||
423 | break; | ||
424 | } | ||
425 | |||
426 | return ret; | ||
427 | } | ||
428 | |||
429 | static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var, | ||
430 | struct fb_info *info) | ||
431 | { | ||
432 | dev_dbg(info->device, "%s\n", __func__); | ||
433 | |||
434 | atmel_lcdfb_update_dma(info, var); | ||
435 | |||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | static struct fb_ops atmel_lcdfb_ops = { | ||
440 | .owner = THIS_MODULE, | ||
441 | .fb_check_var = atmel_lcdfb_check_var, | ||
442 | .fb_set_par = atmel_lcdfb_set_par, | ||
443 | .fb_setcolreg = atmel_lcdfb_setcolreg, | ||
444 | .fb_pan_display = atmel_lcdfb_pan_display, | ||
445 | .fb_fillrect = cfb_fillrect, | ||
446 | .fb_copyarea = cfb_copyarea, | ||
447 | .fb_imageblit = cfb_imageblit, | ||
448 | }; | ||
449 | |||
450 | static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id) | ||
451 | { | ||
452 | struct fb_info *info = dev_id; | ||
453 | struct atmel_lcdfb_info *sinfo = info->par; | ||
454 | u32 status; | ||
455 | |||
456 | status = lcdc_readl(sinfo, ATMEL_LCDC_ISR); | ||
457 | lcdc_writel(sinfo, ATMEL_LCDC_IDR, status); | ||
458 | return IRQ_HANDLED; | ||
459 | } | ||
460 | |||
461 | static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo) | ||
462 | { | ||
463 | struct fb_info *info = sinfo->info; | ||
464 | int ret = 0; | ||
465 | |||
466 | memset_io(info->screen_base, 0, info->fix.smem_len); | ||
467 | info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW; | ||
468 | |||
469 | dev_info(info->device, | ||
470 | "%luKiB frame buffer at %08lx (mapped at %p)\n", | ||
471 | (unsigned long)info->fix.smem_len / 1024, | ||
472 | (unsigned long)info->fix.smem_start, | ||
473 | info->screen_base); | ||
474 | |||
475 | /* Allocate colormap */ | ||
476 | ret = fb_alloc_cmap(&info->cmap, 256, 0); | ||
477 | if (ret < 0) | ||
478 | dev_err(info->device, "Alloc color map failed\n"); | ||
479 | |||
480 | return ret; | ||
481 | } | ||
482 | |||
483 | static void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo) | ||
484 | { | ||
485 | if (sinfo->bus_clk) | ||
486 | clk_enable(sinfo->bus_clk); | ||
487 | clk_enable(sinfo->lcdc_clk); | ||
488 | } | ||
489 | |||
490 | static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo) | ||
491 | { | ||
492 | if (sinfo->bus_clk) | ||
493 | clk_disable(sinfo->bus_clk); | ||
494 | clk_disable(sinfo->lcdc_clk); | ||
495 | } | ||
496 | |||
497 | |||
498 | static int __init atmel_lcdfb_probe(struct platform_device *pdev) | ||
499 | { | ||
500 | struct device *dev = &pdev->dev; | ||
501 | struct fb_info *info; | ||
502 | struct atmel_lcdfb_info *sinfo; | ||
503 | struct atmel_lcdfb_info *pdata_sinfo; | ||
504 | struct resource *regs = NULL; | ||
505 | struct resource *map = NULL; | ||
506 | int ret; | ||
507 | |||
508 | dev_dbg(dev, "%s BEGIN\n", __func__); | ||
509 | |||
510 | ret = -ENOMEM; | ||
511 | info = framebuffer_alloc(sizeof(struct atmel_lcdfb_info), dev); | ||
512 | if (!info) { | ||
513 | dev_err(dev, "cannot allocate memory\n"); | ||
514 | goto out; | ||
515 | } | ||
516 | |||
517 | sinfo = info->par; | ||
518 | |||
519 | if (dev->platform_data) { | ||
520 | pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data; | ||
521 | sinfo->default_bpp = pdata_sinfo->default_bpp; | ||
522 | sinfo->default_dmacon = pdata_sinfo->default_dmacon; | ||
523 | sinfo->default_lcdcon2 = pdata_sinfo->default_lcdcon2; | ||
524 | sinfo->default_monspecs = pdata_sinfo->default_monspecs; | ||
525 | sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control; | ||
526 | sinfo->guard_time = pdata_sinfo->guard_time; | ||
527 | } else { | ||
528 | dev_err(dev, "cannot get default configuration\n"); | ||
529 | goto free_info; | ||
530 | } | ||
531 | sinfo->info = info; | ||
532 | sinfo->pdev = pdev; | ||
533 | |||
534 | strcpy(info->fix.id, sinfo->pdev->name); | ||
535 | info->flags = ATMEL_LCDFB_FBINFO_DEFAULT; | ||
536 | info->pseudo_palette = sinfo->pseudo_palette; | ||
537 | info->fbops = &atmel_lcdfb_ops; | ||
538 | |||
539 | memcpy(&info->monspecs, sinfo->default_monspecs, sizeof(info->monspecs)); | ||
540 | info->fix = atmel_lcdfb_fix; | ||
541 | |||
542 | /* Enable LCDC Clocks */ | ||
543 | if (cpu_is_at91sam9261() || cpu_is_at32ap7000()) { | ||
544 | sinfo->bus_clk = clk_get(dev, "hck1"); | ||
545 | if (IS_ERR(sinfo->bus_clk)) { | ||
546 | ret = PTR_ERR(sinfo->bus_clk); | ||
547 | goto free_info; | ||
548 | } | ||
549 | } | ||
550 | sinfo->lcdc_clk = clk_get(dev, "lcdc_clk"); | ||
551 | if (IS_ERR(sinfo->lcdc_clk)) { | ||
552 | ret = PTR_ERR(sinfo->lcdc_clk); | ||
553 | goto put_bus_clk; | ||
554 | } | ||
555 | atmel_lcdfb_start_clock(sinfo); | ||
556 | |||
557 | ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb, | ||
558 | info->monspecs.modedb_len, info->monspecs.modedb, | ||
559 | sinfo->default_bpp); | ||
560 | if (!ret) { | ||
561 | dev_err(dev, "no suitable video mode found\n"); | ||
562 | goto stop_clk; | ||
563 | } | ||
564 | |||
565 | |||
566 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
567 | if (!regs) { | ||
568 | dev_err(dev, "resources unusable\n"); | ||
569 | ret = -ENXIO; | ||
570 | goto stop_clk; | ||
571 | } | ||
572 | |||
573 | sinfo->irq_base = platform_get_irq(pdev, 0); | ||
574 | if (sinfo->irq_base < 0) { | ||
575 | dev_err(dev, "unable to get irq\n"); | ||
576 | ret = sinfo->irq_base; | ||
577 | goto stop_clk; | ||
578 | } | ||
579 | |||
580 | /* Initialize video memory */ | ||
581 | map = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
582 | if (map) { | ||
583 | /* use a pre-allocated memory buffer */ | ||
584 | info->fix.smem_start = map->start; | ||
585 | info->fix.smem_len = map->end - map->start + 1; | ||
586 | if (!request_mem_region(info->fix.smem_start, | ||
587 | info->fix.smem_len, pdev->name)) { | ||
588 | ret = -EBUSY; | ||
589 | goto stop_clk; | ||
590 | } | ||
591 | |||
592 | info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); | ||
593 | if (!info->screen_base) | ||
594 | goto release_intmem; | ||
595 | } else { | ||
596 | /* alocate memory buffer */ | ||
597 | ret = atmel_lcdfb_alloc_video_memory(sinfo); | ||
598 | if (ret < 0) { | ||
599 | dev_err(dev, "cannot allocate framebuffer: %d\n", ret); | ||
600 | goto stop_clk; | ||
601 | } | ||
602 | } | ||
603 | |||
604 | /* LCDC registers */ | ||
605 | info->fix.mmio_start = regs->start; | ||
606 | info->fix.mmio_len = regs->end - regs->start + 1; | ||
607 | |||
608 | if (!request_mem_region(info->fix.mmio_start, | ||
609 | info->fix.mmio_len, pdev->name)) { | ||
610 | ret = -EBUSY; | ||
611 | goto free_fb; | ||
612 | } | ||
613 | |||
614 | sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len); | ||
615 | if (!sinfo->mmio) { | ||
616 | dev_err(dev, "cannot map LCDC registers\n"); | ||
617 | goto release_mem; | ||
618 | } | ||
619 | |||
620 | /* interrupt */ | ||
621 | ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info); | ||
622 | if (ret) { | ||
623 | dev_err(dev, "request_irq failed: %d\n", ret); | ||
624 | goto unmap_mmio; | ||
625 | } | ||
626 | |||
627 | ret = atmel_lcdfb_init_fbinfo(sinfo); | ||
628 | if (ret < 0) { | ||
629 | dev_err(dev, "init fbinfo failed: %d\n", ret); | ||
630 | goto unregister_irqs; | ||
631 | } | ||
632 | |||
633 | /* | ||
634 | * This makes sure that our colour bitfield | ||
635 | * descriptors are correctly initialised. | ||
636 | */ | ||
637 | atmel_lcdfb_check_var(&info->var, info); | ||
638 | |||
639 | ret = fb_set_var(info, &info->var); | ||
640 | if (ret) { | ||
641 | dev_warn(dev, "unable to set display parameters\n"); | ||
642 | goto free_cmap; | ||
643 | } | ||
644 | |||
645 | dev_set_drvdata(dev, info); | ||
646 | |||
647 | /* | ||
648 | * Tell the world that we're ready to go | ||
649 | */ | ||
650 | ret = register_framebuffer(info); | ||
651 | if (ret < 0) { | ||
652 | dev_err(dev, "failed to register framebuffer device: %d\n", ret); | ||
653 | goto free_cmap; | ||
654 | } | ||
655 | |||
656 | /* Power up the LCDC screen */ | ||
657 | if (sinfo->atmel_lcdfb_power_control) | ||
658 | sinfo->atmel_lcdfb_power_control(1); | ||
659 | |||
660 | dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %lu\n", | ||
661 | info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base); | ||
662 | |||
663 | return 0; | ||
664 | |||
665 | |||
666 | free_cmap: | ||
667 | fb_dealloc_cmap(&info->cmap); | ||
668 | unregister_irqs: | ||
669 | free_irq(sinfo->irq_base, info); | ||
670 | unmap_mmio: | ||
671 | iounmap(sinfo->mmio); | ||
672 | release_mem: | ||
673 | release_mem_region(info->fix.mmio_start, info->fix.mmio_len); | ||
674 | free_fb: | ||
675 | if (map) | ||
676 | iounmap(info->screen_base); | ||
677 | else | ||
678 | atmel_lcdfb_free_video_memory(sinfo); | ||
679 | |||
680 | release_intmem: | ||
681 | if (map) | ||
682 | release_mem_region(info->fix.smem_start, info->fix.smem_len); | ||
683 | stop_clk: | ||
684 | atmel_lcdfb_stop_clock(sinfo); | ||
685 | clk_put(sinfo->lcdc_clk); | ||
686 | put_bus_clk: | ||
687 | if (sinfo->bus_clk) | ||
688 | clk_put(sinfo->bus_clk); | ||
689 | free_info: | ||
690 | framebuffer_release(info); | ||
691 | out: | ||
692 | dev_dbg(dev, "%s FAILED\n", __func__); | ||
693 | return ret; | ||
694 | } | ||
695 | |||
696 | static int __exit atmel_lcdfb_remove(struct platform_device *pdev) | ||
697 | { | ||
698 | struct device *dev = &pdev->dev; | ||
699 | struct fb_info *info = dev_get_drvdata(dev); | ||
700 | struct atmel_lcdfb_info *sinfo = info->par; | ||
701 | |||
702 | if (!sinfo) | ||
703 | return 0; | ||
704 | |||
705 | if (sinfo->atmel_lcdfb_power_control) | ||
706 | sinfo->atmel_lcdfb_power_control(0); | ||
707 | unregister_framebuffer(info); | ||
708 | atmel_lcdfb_stop_clock(sinfo); | ||
709 | clk_put(sinfo->lcdc_clk); | ||
710 | if (sinfo->bus_clk) | ||
711 | clk_put(sinfo->bus_clk); | ||
712 | fb_dealloc_cmap(&info->cmap); | ||
713 | free_irq(sinfo->irq_base, info); | ||
714 | iounmap(sinfo->mmio); | ||
715 | release_mem_region(info->fix.mmio_start, info->fix.mmio_len); | ||
716 | if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) { | ||
717 | iounmap(info->screen_base); | ||
718 | release_mem_region(info->fix.smem_start, info->fix.smem_len); | ||
719 | } else { | ||
720 | atmel_lcdfb_free_video_memory(sinfo); | ||
721 | } | ||
722 | |||
723 | dev_set_drvdata(dev, NULL); | ||
724 | framebuffer_release(info); | ||
725 | |||
726 | return 0; | ||
727 | } | ||
728 | |||
729 | static struct platform_driver atmel_lcdfb_driver = { | ||
730 | .remove = __exit_p(atmel_lcdfb_remove), | ||
731 | .driver = { | ||
732 | .name = "atmel_lcdfb", | ||
733 | .owner = THIS_MODULE, | ||
734 | }, | ||
735 | }; | ||
736 | |||
737 | static int __init atmel_lcdfb_init(void) | ||
738 | { | ||
739 | return platform_driver_probe(&atmel_lcdfb_driver, atmel_lcdfb_probe); | ||
740 | } | ||
741 | |||
742 | static void __exit atmel_lcdfb_exit(void) | ||
743 | { | ||
744 | platform_driver_unregister(&atmel_lcdfb_driver); | ||
745 | } | ||
746 | |||
747 | module_init(atmel_lcdfb_init); | ||
748 | module_exit(atmel_lcdfb_exit); | ||
749 | |||
750 | MODULE_DESCRIPTION("AT91/AT32 LCD Controller framebuffer driver"); | ||
751 | MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@rfo.atmel.com>"); | ||
752 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index aa3935df852a..63b85bf81a65 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig | |||
@@ -19,13 +19,6 @@ config VGA_CONSOLE | |||
19 | 19 | ||
20 | Say Y. | 20 | Say Y. |
21 | 21 | ||
22 | # if [ "$CONFIG_PCI" = "y" -a "$CONFIG_VGA_CONSOLE" = "y" ]; then | ||
23 | # bool ' Allow VGA on any bus?' CONFIG_VGA_HOSE | ||
24 | # if [ "$CONFIG_VGA_HOSE" = "y" ]; then | ||
25 | # define_bool CONFIG_DUMMY_CONSOLE y | ||
26 | # fi | ||
27 | # fi | ||
28 | |||
29 | config VGACON_SOFT_SCROLLBACK | 22 | config VGACON_SOFT_SCROLLBACK |
30 | bool "Enable Scrollback Buffer in System RAM" | 23 | bool "Enable Scrollback Buffer in System RAM" |
31 | depends on VGA_CONSOLE | 24 | depends on VGA_CONSOLE |
diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c index c627955aa124..aff11bbf59a7 100644 --- a/drivers/video/nvidia/nv_hw.c +++ b/drivers/video/nvidia/nv_hw.c | |||
@@ -149,7 +149,9 @@ static void nvGetClocks(struct nvidia_par *par, unsigned int *MClk, | |||
149 | pll = NV_RD32(par->PMC, 0x4024); | 149 | pll = NV_RD32(par->PMC, 0x4024); |
150 | M = pll & 0xFF; | 150 | M = pll & 0xFF; |
151 | N = (pll >> 8) & 0xFF; | 151 | N = (pll >> 8) & 0xFF; |
152 | if (((par->Chipset & 0xfff0) == 0x0290) || ((par->Chipset & 0xfff0) == 0x0390) || ((par->Chipset & 0xfff0) == 0x02E0)) { | 152 | if (((par->Chipset & 0xfff0) == 0x0290) || |
153 | ((par->Chipset & 0xfff0) == 0x0390) || | ||
154 | ((par->Chipset & 0xfff0) == 0x02E0)) { | ||
153 | MB = 1; | 155 | MB = 1; |
154 | NB = 1; | 156 | NB = 1; |
155 | } else { | 157 | } else { |
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index f85edf084da3..41f63658572f 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c | |||
@@ -37,7 +37,6 @@ | |||
37 | #include "nv_proto.h" | 37 | #include "nv_proto.h" |
38 | #include "nv_dma.h" | 38 | #include "nv_dma.h" |
39 | 39 | ||
40 | #undef CONFIG_FB_NVIDIA_DEBUG | ||
41 | #ifdef CONFIG_FB_NVIDIA_DEBUG | 40 | #ifdef CONFIG_FB_NVIDIA_DEBUG |
42 | #define NVTRACE printk | 41 | #define NVTRACE printk |
43 | #else | 42 | #else |
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index 1ac5264bb2c1..ab5e66890e4e 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c | |||
@@ -204,17 +204,6 @@ static inline void WAIT_FIFO(struct pm2fb_par* p, u32 a) | |||
204 | } | 204 | } |
205 | #endif | 205 | #endif |
206 | 206 | ||
207 | static void wait_pm2(struct pm2fb_par* par) { | ||
208 | |||
209 | WAIT_FIFO(par, 1); | ||
210 | pm2_WR(par, PM2R_SYNC, 0); | ||
211 | mb(); | ||
212 | do { | ||
213 | while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0); | ||
214 | rmb(); | ||
215 | } while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC)); | ||
216 | } | ||
217 | |||
218 | /* | 207 | /* |
219 | * partial products for the supported horizontal resolutions. | 208 | * partial products for the supported horizontal resolutions. |
220 | */ | 209 | */ |
@@ -1050,13 +1039,30 @@ static int pm2fb_blank(int blank_mode, struct fb_info *info) | |||
1050 | return 0; | 1039 | return 0; |
1051 | } | 1040 | } |
1052 | 1041 | ||
1042 | static int pm2fb_sync(struct fb_info *info) | ||
1043 | { | ||
1044 | struct pm2fb_par *par = info->par; | ||
1045 | |||
1046 | WAIT_FIFO(par, 1); | ||
1047 | pm2_WR(par, PM2R_SYNC, 0); | ||
1048 | mb(); | ||
1049 | do { | ||
1050 | while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0) | ||
1051 | udelay(10); | ||
1052 | rmb(); | ||
1053 | } while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC)); | ||
1054 | |||
1055 | return 0; | ||
1056 | } | ||
1057 | |||
1053 | /* | 1058 | /* |
1054 | * block operation. copy=0: rectangle fill, copy=1: rectangle copy. | 1059 | * block operation. copy=0: rectangle fill, copy=1: rectangle copy. |
1055 | */ | 1060 | */ |
1056 | static void pm2fb_block_op(struct pm2fb_par* par, int copy, | 1061 | static void pm2fb_block_op(struct fb_info* info, int copy, |
1057 | s32 xsrc, s32 ysrc, | 1062 | s32 xsrc, s32 ysrc, |
1058 | s32 x, s32 y, s32 w, s32 h, | 1063 | s32 x, s32 y, s32 w, s32 h, |
1059 | u32 color) { | 1064 | u32 color) { |
1065 | struct pm2fb_par *par = info->par; | ||
1060 | 1066 | ||
1061 | if (!w || !h) | 1067 | if (!w || !h) |
1062 | return; | 1068 | return; |
@@ -1076,13 +1082,11 @@ static void pm2fb_block_op(struct pm2fb_par* par, int copy, | |||
1076 | (x<xsrc ? PM2F_INCREASE_X : 0) | | 1082 | (x<xsrc ? PM2F_INCREASE_X : 0) | |
1077 | (y<ysrc ? PM2F_INCREASE_Y : 0) | | 1083 | (y<ysrc ? PM2F_INCREASE_Y : 0) | |
1078 | (copy ? 0 : PM2F_RENDER_FASTFILL)); | 1084 | (copy ? 0 : PM2F_RENDER_FASTFILL)); |
1079 | wait_pm2(par); | ||
1080 | } | 1085 | } |
1081 | 1086 | ||
1082 | static void pm2fb_fillrect (struct fb_info *info, | 1087 | static void pm2fb_fillrect (struct fb_info *info, |
1083 | const struct fb_fillrect *region) | 1088 | const struct fb_fillrect *region) |
1084 | { | 1089 | { |
1085 | struct pm2fb_par *par = info->par; | ||
1086 | struct fb_fillrect modded; | 1090 | struct fb_fillrect modded; |
1087 | int vxres, vyres; | 1091 | int vxres, vyres; |
1088 | u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ? | 1092 | u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ? |
@@ -1116,7 +1120,7 @@ static void pm2fb_fillrect (struct fb_info *info, | |||
1116 | color |= color << 16; | 1120 | color |= color << 16; |
1117 | 1121 | ||
1118 | if(info->var.bits_per_pixel != 24) | 1122 | if(info->var.bits_per_pixel != 24) |
1119 | pm2fb_block_op(par, 0, 0, 0, | 1123 | pm2fb_block_op(info, 0, 0, 0, |
1120 | modded.dx, modded.dy, | 1124 | modded.dx, modded.dy, |
1121 | modded.width, modded.height, color); | 1125 | modded.width, modded.height, color); |
1122 | else | 1126 | else |
@@ -1126,7 +1130,6 @@ static void pm2fb_fillrect (struct fb_info *info, | |||
1126 | static void pm2fb_copyarea(struct fb_info *info, | 1130 | static void pm2fb_copyarea(struct fb_info *info, |
1127 | const struct fb_copyarea *area) | 1131 | const struct fb_copyarea *area) |
1128 | { | 1132 | { |
1129 | struct pm2fb_par *par = info->par; | ||
1130 | struct fb_copyarea modded; | 1133 | struct fb_copyarea modded; |
1131 | u32 vxres, vyres; | 1134 | u32 vxres, vyres; |
1132 | 1135 | ||
@@ -1156,7 +1159,7 @@ static void pm2fb_copyarea(struct fb_info *info, | |||
1156 | if(modded.dy + modded.height > vyres) | 1159 | if(modded.dy + modded.height > vyres) |
1157 | modded.height = vyres - modded.dy; | 1160 | modded.height = vyres - modded.dy; |
1158 | 1161 | ||
1159 | pm2fb_block_op(par, 1, modded.sx, modded.sy, | 1162 | pm2fb_block_op(info, 1, modded.sx, modded.sy, |
1160 | modded.dx, modded.dy, | 1163 | modded.dx, modded.dy, |
1161 | modded.width, modded.height, 0); | 1164 | modded.width, modded.height, 0); |
1162 | } | 1165 | } |
@@ -1177,6 +1180,7 @@ static struct fb_ops pm2fb_ops = { | |||
1177 | .fb_fillrect = pm2fb_fillrect, | 1180 | .fb_fillrect = pm2fb_fillrect, |
1178 | .fb_copyarea = pm2fb_copyarea, | 1181 | .fb_copyarea = pm2fb_copyarea, |
1179 | .fb_imageblit = cfb_imageblit, | 1182 | .fb_imageblit = cfb_imageblit, |
1183 | .fb_sync = pm2fb_sync, | ||
1180 | }; | 1184 | }; |
1181 | 1185 | ||
1182 | /* | 1186 | /* |
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c index bd787e80177d..6c4dfcb0feb9 100644 --- a/drivers/video/pm3fb.c +++ b/drivers/video/pm3fb.c | |||
@@ -1,55 +1,25 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device | 2 | * linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device |
3 | * | 3 | * |
4 | * Copyright (C) 2001 Romain Dolbeau <dolbeau@irisa.fr> | 4 | * Copyright (C) 2001 Romain Dolbeau <romain@dolbeau.org>. |
5 | * | ||
6 | * Ported to 2.6 kernel on 1 May 2007 by Krzysztof Helt <krzysztof.h1@wp.pl> | ||
7 | * based on pm2fb.c | ||
8 | * | ||
5 | * Based on code written by: | 9 | * Based on code written by: |
6 | * Sven Luther, <luther@dpt-info.u-strasbg.fr> | 10 | * Sven Luther, <luther@dpt-info.u-strasbg.fr> |
7 | * Alan Hourihane, <alanh@fairlite.demon.co.uk> | 11 | * Alan Hourihane, <alanh@fairlite.demon.co.uk> |
8 | * Russell King, <rmk@arm.linux.org.uk> | 12 | * Russell King, <rmk@arm.linux.org.uk> |
9 | * Based on linux/drivers/video/skeletonfb.c: | 13 | * Based on linux/drivers/video/skeletonfb.c: |
10 | * Copyright (C) 1997 Geert Uytterhoeven | 14 | * Copyright (C) 1997 Geert Uytterhoeven |
11 | * Based on linux/driver/video/pm2fb.c: | 15 | * Based on linux/driver/video/pm2fb.c: |
12 | * Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) | 16 | * Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) |
13 | * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) | 17 | * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) |
14 | * | 18 | * |
15 | * This file is subject to the terms and conditions of the GNU General Public | 19 | * This file is subject to the terms and conditions of the GNU General Public |
16 | * License. See the file COPYING in the main directory of this archive for | 20 | * License. See the file COPYING in the main directory of this archive for |
17 | * more details. | 21 | * more details. |
18 | * | 22 | * |
19 | * $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $ | ||
20 | * | ||
21 | * CHANGELOG: | ||
22 | * Mon Feb 11 10:35:48 MET 2002, v 1.4.11B: Cosmetic update. | ||
23 | * Wed Jan 23 14:16:59 MET 2002, v 1.4.11: Preliminary 2.5.x support, patch for 2.5.2. | ||
24 | * Wed Nov 28 11:08:29 MET 2001, v 1.4.10: potential bug fix for SDRAM-based board, patch for 2.4.16. | ||
25 | * Thu Sep 20 10:24:42 MET DST 2001, v 1.4.9: sync bug fix, preliminary flatpanel support, better timings. | ||
26 | * Tue Aug 28 10:13:01 MET DST 2001, v 1.4.8: memory timings check, minor bug fixes. | ||
27 | * Wed Jul 18 19:06:14 CEST 2001, v 1.4.7: Mode fix (800x600-100, 1024x768-100 changed), using HW panning + accel bug fix. | ||
28 | * Mon Jun 25 10:33:56 MET DST 2001, v 1.4.6: Depth 12 fix, chip reset ioctl, moved memory erase ioctl to DEBUG. | ||
29 | * Wed Jun 20 11:13:08 MET DST 2001, v 1.4.5: Fixed missing blinking cursor in 8bpp, code cleaning, memory erase IOCTL. | ||
30 | * Mon Jun 18 16:00:27 CEST 2001, v 1.4.4: Depth 12 (RGBA 4444) support, code cleaning. | ||
31 | * Fri Jun 15 13:53:01 CEST 2001, v 1.4.3: Removed warnings, depth 15 support, add 'depth' option. | ||
32 | * Thu Jun 14 10:13:52 MET DST 2001, v 1.4.2: Fixed depth switching bug, preliminary 15bpp (RGB5551) support. | ||
33 | * Thu Apr 12 11:16:45 MET DST 2001, v 1.4.1B: Doc updates. | ||
34 | * Fri Apr 6 11:12:53 MET DST 2001, v 1.4.1: Configure.help, minor cleanup | ||
35 | * Thu Mar 29 10:56:50 MET DST 2001, v 1.4.0: Module & module options support (note: linux patch changed, 2.2.19 added). | ||
36 | * Thu Mar 15 15:30:31 MET 2001, v 1.3.2: Fixed mirroring bug on little-endian. | ||
37 | * Wed Mar 14 21:25:54 CET 2001, v 1.3.1: Fixed bug in BlockMove (_bmov). | ||
38 | * Tue Mar 13 10:53:19 MET 2001, v 1.3.0: Character drawing hardware support (in all width between 1 and 16), fixes. | ||
39 | * Thu Mar 8 10:20:16 MET 2001, v 1.2.2: Better J2000 support, "font:" option. | ||
40 | * Tue Mar 6 21:25:04 CET 2001, v 1.2.1: Better acceleration support. | ||
41 | * Mon Mar 5 21:54:17 CET 2001, v 1.2.0: Partial acceleration support (clear & bmove) | ||
42 | * Mon Mar 5 12:52:15 CET 2001, v 1.1.3: Big pan_display fix. | ||
43 | * Sun Mar 4 22:21:50 CET 2001, v 1.1.2: (numerous) bug fixes. | ||
44 | * Fri Mar 2 15:54:07 CET 2001, v 1.1.1: Might have Appian J2000 support, resource mangement in 2.4 | ||
45 | * Wed Feb 28 18:21:35 CET 2001, v 1.1.0: Might have multiple boards support (added, but not yest tested) | ||
46 | * Tue Feb 27 17:31:12 CET 2001, v 1.0.6: fixes boot-time mode select, add more default mode | ||
47 | * Tue Feb 27 14:01:36 CET 2001, v 1.0.5: fixes (1.0.4 was broken for 2.2), cleaning up | ||
48 | * Mon Feb 26 23:17:36 CET 2001, v 1.0.4: preliminary 2.4.x support, dropped (useless on pm3) partial product, more OF fix | ||
49 | * Mon Feb 26 20:59:05 CET 2001, v 1.0.3: No more shadow register (and wasted memory), endianess fix, use OF-preset resolution by default | ||
50 | * Wed Feb 21 22:09:30 CET 2001, v 1.0.2: Code cleaning for future multiboard support, better OF support, bugs fix | ||
51 | * Wed Feb 21 19:58:56 CET 2001, v 1.0.1: OpenFirmware support, fixed memory detection, better debug support, code cleaning | ||
52 | * Wed Feb 21 14:47:06 CET 2001, v 1.0.0: First working version | ||
53 | */ | 23 | */ |
54 | 24 | ||
55 | #include <linux/module.h> | 25 | #include <linux/module.h> |
@@ -58,856 +28,155 @@ | |||
58 | #include <linux/string.h> | 28 | #include <linux/string.h> |
59 | #include <linux/mm.h> | 29 | #include <linux/mm.h> |
60 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
61 | #include <linux/vmalloc.h> | ||
62 | #include <linux/delay.h> | 31 | #include <linux/delay.h> |
63 | #include <linux/interrupt.h> | ||
64 | #include <linux/fb.h> | 32 | #include <linux/fb.h> |
65 | #include <linux/init.h> | 33 | #include <linux/init.h> |
66 | #include <linux/pci.h> | 34 | #include <linux/pci.h> |
67 | #include <linux/ioport.h> | ||
68 | #include <linux/ctype.h> | ||
69 | |||
70 | #include <video/fbcon.h> | ||
71 | #include <video/fbcon-mfb.h> | ||
72 | #include <video/fbcon-cfb2.h> | ||
73 | #include <video/fbcon-cfb4.h> | ||
74 | #include <video/fbcon-cfb8.h> | ||
75 | #include <video/fbcon-cfb16.h> | ||
76 | #include <video/fbcon-cfb24.h> | ||
77 | #include <video/fbcon-cfb32.h> | ||
78 | #include <video/pm3fb.h> | ||
79 | 35 | ||
80 | #include <asm/io.h> | 36 | #include <video/pm3fb.h> |
81 | #include <asm/uaccess.h> | ||
82 | 37 | ||
83 | #ifdef CONFIG_FB_OF | 38 | #if !defined(CONFIG_PCI) |
84 | #include <asm/prom.h> | 39 | #error "Only generic PCI cards supported." |
85 | #endif | 40 | #endif |
86 | 41 | ||
87 | /* ************************************* */ | 42 | #undef PM3FB_MASTER_DEBUG |
88 | /* ***** The various "global" data ***** */ | 43 | #ifdef PM3FB_MASTER_DEBUG |
89 | /* ************************************* */ | 44 | #define DPRINTK(a,b...) printk(KERN_DEBUG "pm3fb: %s: " a, __FUNCTION__ , ## b) |
90 | 45 | #else | |
91 | /* those will need a rework for multiple board support */ | 46 | #define DPRINTK(a,b...) |
92 | /* Driver name */ | ||
93 | static const char permedia3_name[16] = "Permedia3"; | ||
94 | |||
95 | /* the fb_par struct, mandatory */ | ||
96 | struct pm3fb_par { | ||
97 | u32 pixclock; /* pixclock in KHz */ | ||
98 | |||
99 | u32 width; /* width of virtual screen */ | ||
100 | u32 height; /* height of virtual screen */ | ||
101 | |||
102 | u32 hsstart; /* horiz. sync start */ | ||
103 | u32 hsend; /* horiz. sync end */ | ||
104 | u32 hbend; /* horiz. blank end (also gate end) */ | ||
105 | u32 htotal; /* total width (w/ sync & blank) */ | ||
106 | |||
107 | u32 vsstart; /* vert. sync start */ | ||
108 | u32 vsend; /* vert. sync end */ | ||
109 | u32 vbend; /* vert. blank end */ | ||
110 | u32 vtotal; /* total height (w/ sync & blank) */ | ||
111 | |||
112 | u32 stride; /* screen stride */ | ||
113 | u32 base; /* screen base (xoffset+yoffset) in 128 bits unit */ | ||
114 | /* NOTE : unlike other pm3 stuff above, stored *after* shiftbpp. don't ask */ | ||
115 | u32 depth; /* screen depth (8, 12, 15, 16 or 32) */ | ||
116 | u32 video; /* video control (hsync,vsync) */ | ||
117 | }; | ||
118 | |||
119 | /* memory timings */ | ||
120 | struct pm3fb_timings | ||
121 | { | ||
122 | unsigned long caps; | ||
123 | unsigned long timings; | ||
124 | unsigned long control; | ||
125 | unsigned long refresh; | ||
126 | unsigned long powerdown; | ||
127 | }; | ||
128 | typedef enum pm3fb_timing_result { pm3fb_timing_ok, pm3fb_timing_problem, pm3fb_timing_retry } pm3fb_timing_result; | ||
129 | #define PM3FB_UNKNOWN_TIMING_VALUE ((unsigned long)-1) | ||
130 | #define PM3FB_UNKNOWN_TIMINGS { PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE } | ||
131 | |||
132 | /* the fb_info struct, mandatory */ | ||
133 | struct pm3fb_info { | ||
134 | struct fb_info_gen gen; | ||
135 | unsigned long board_num; /* internal board number */ | ||
136 | unsigned long use_current; | ||
137 | struct pm3fb_par *current_par; | ||
138 | struct pci_dev *dev; /* PCI device */ | ||
139 | unsigned long board_type; /* index in the cardbase */ | ||
140 | unsigned char *fb_base; /* framebuffer memory base */ | ||
141 | u32 fb_size; /* framebuffer memory size */ | ||
142 | unsigned char *p_fb; /* physical address of frame buffer */ | ||
143 | unsigned char *v_fb; /* virtual address of frame buffer */ | ||
144 | unsigned char *pIOBase; /* physical address of registers region, must be rg_base or rg_base+PM2_REGS_SIZE depending on the host endianness */ | ||
145 | unsigned char *vIOBase; /* address of registers after ioremap() */ | ||
146 | struct { | ||
147 | u8 transp; | ||
148 | u8 red; | ||
149 | u8 green; | ||
150 | u8 blue; | ||
151 | } palette[256]; | ||
152 | union { | ||
153 | #ifdef FBCON_HAS_CFB16 | ||
154 | u16 cmap12[16]; /* RGBA 4444 */ | ||
155 | u16 cmap15[16]; /* RGBA 5551 */ | ||
156 | u16 cmap16[16]; /* RGBA 5650 */ | ||
157 | #endif | ||
158 | #ifdef FBCON_HAS_CFB32 | ||
159 | u32 cmap32[16]; | ||
160 | #endif | 47 | #endif |
161 | } cmap; | ||
162 | struct pm3fb_timings memt; | ||
163 | }; | ||
164 | |||
165 | /* regular resolution database*/ | ||
166 | static struct { | ||
167 | char name[16]; | ||
168 | struct pm3fb_par user_mode; | ||
169 | } mode_base[] __initdata = { | ||
170 | { | ||
171 | "default-800x600", { | ||
172 | 49500, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625, | ||
173 | 800, 0, 8, | ||
174 | PM3VideoControl_ENABLE | | ||
175 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
176 | | | ||
177 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
178 | | PM3VideoControl_PIXELSIZE_8BIT}}, { | ||
179 | "1024x768-74", { | ||
180 | 78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38, | ||
181 | 806, 1024, 0, 8, | ||
182 | PM3VideoControl_ENABLE | | ||
183 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
184 | | | ||
185 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
186 | | PM3VideoControl_PIXELSIZE_8BIT}}, { | ||
187 | "1024x768-74-32", { | ||
188 | 78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38, | ||
189 | 806, 1024, 0, 32, | ||
190 | PM3VideoControl_ENABLE | | ||
191 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
192 | | | ||
193 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
194 | | PM3VideoControl_PIXELSIZE_32BIT}}, | ||
195 | /* Generated mode : "1600x1024", for the SGI 1600SW flat panel*/ | ||
196 | { | ||
197 | "SGI1600SW", { | ||
198 | 108000, 1600, 1024, 16, 56, 104, 1704, 3, 6, 32, | ||
199 | 1056, 1600, 0, 8, | ||
200 | PM3VideoControl_ENABLE| | ||
201 | PM3VideoControl_HSYNC_ACTIVE_LOW|PM3VideoControl_VSYNC_ACTIVE_LOW| | ||
202 | PM3VideoControl_PIXELSIZE_32BIT}}, | ||
203 | /* ##### auto-generated mode, by fbtimings2pm3 */ | ||
204 | /* Generated mode : "640x480-60" */ | ||
205 | { | ||
206 | "640x480-60", { | ||
207 | 25174, 640, 480, 16, 112, 160, 800, 10, 12, 45, | ||
208 | 525, 640, 0, 8, | ||
209 | PM3VideoControl_ENABLE | | ||
210 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
211 | | | ||
212 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
213 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
214 | /* Generated mode : "640x480-72" */ | ||
215 | { | ||
216 | "640x480-72", { | ||
217 | 31199, 640, 480, 24, 64, 192, 832, 9, 12, 40, 520, | ||
218 | 640, 0, 8, | ||
219 | PM3VideoControl_ENABLE | | ||
220 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
221 | | | ||
222 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
223 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
224 | /* Generated mode : "640x480-75" */ | ||
225 | { | ||
226 | "640x480-75", { | ||
227 | 31499, 640, 480, 16, 80, 200, 840, 1, 4, 20, 500, | ||
228 | 640, 0, 8, | ||
229 | PM3VideoControl_ENABLE | | ||
230 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
231 | | | ||
232 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
233 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
234 | /* Generated mode : "640x480-90" */ | ||
235 | { | ||
236 | "640x480-90", { | ||
237 | 39909, 640, 480, 32, 72, 192, 832, 25, 39, 53, 533, | ||
238 | 640, 0, 8, | ||
239 | PM3VideoControl_ENABLE | | ||
240 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
241 | | | ||
242 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
243 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
244 | /* Generated mode : "640x480-100" */ | ||
245 | { | ||
246 | "640x480-100", { | ||
247 | 44899, 640, 480, 32, 160, 208, 848, 22, 34, 51, | ||
248 | 531, 640, 0, 8, | ||
249 | PM3VideoControl_ENABLE | | ||
250 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
251 | | | ||
252 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
253 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
254 | /* Generated mode : "800x600-48-lace" */ | ||
255 | /* INTERLACED NOT SUPPORTED | ||
256 | {"800x600-48-lace", {35999, 800, 600, 80, 208, 264, 1064, 11, 23, 102, 702, 800, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, | ||
257 | INTERLACED NOT SUPPORTED */ | ||
258 | /* Generated mode : "800x600-56" */ | ||
259 | { | ||
260 | "800x600-56", { | ||
261 | 35999, 800, 600, 24, 96, 224, 1024, 1, 3, 25, 625, | ||
262 | 800, 0, 8, | ||
263 | PM3VideoControl_ENABLE | | ||
264 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
265 | | | ||
266 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
267 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
268 | /* Generated mode : "800x600-60" */ | ||
269 | { | ||
270 | "800x600-60", { | ||
271 | 40000, 800, 600, 40, 168, 256, 1056, 1, 5, 28, 628, | ||
272 | 800, 0, 8, | ||
273 | PM3VideoControl_ENABLE | | ||
274 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
275 | | | ||
276 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
277 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
278 | /* Generated mode : "800x600-70" */ | ||
279 | { | ||
280 | "800x600-70", { | ||
281 | 44899, 800, 600, 24, 168, 208, 1008, 9, 21, 36, | ||
282 | 636, 800, 0, 8, | ||
283 | PM3VideoControl_ENABLE | | ||
284 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
285 | | | ||
286 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
287 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
288 | /* Generated mode : "800x600-72" */ | ||
289 | { | ||
290 | "800x600-72", { | ||
291 | 50000, 800, 600, 56, 176, 240, 1040, 37, 43, 66, | ||
292 | 666, 800, 0, 8, | ||
293 | PM3VideoControl_ENABLE | | ||
294 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
295 | | | ||
296 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
297 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
298 | /* Generated mode : "800x600-75" */ | ||
299 | { | ||
300 | "800x600-75", { | ||
301 | 49497, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625, | ||
302 | 800, 0, 8, | ||
303 | PM3VideoControl_ENABLE | | ||
304 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
305 | | | ||
306 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
307 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
308 | /* Generated mode : "800x600-90" */ | ||
309 | { | ||
310 | "800x600-90", { | ||
311 | 56637, 800, 600, 8, 72, 192, 992, 8, 19, 35, 635, | ||
312 | 800, 0, 8, | ||
313 | PM3VideoControl_ENABLE | | ||
314 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
315 | | | ||
316 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
317 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
318 | /* Generated mode : "800x600-100", from /etc/fb.modes */ | ||
319 | /* DISABLED, hsstart == 0 | ||
320 | { | ||
321 | "800x600-100", { | ||
322 | 67499, 800, 600, 0, 64, 280, 1080, 7, 11, 25, 625, | ||
323 | 800, 0, 8, | ||
324 | PM3VideoControl_ENABLE | | ||
325 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
326 | | | ||
327 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
328 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
329 | */ | ||
330 | /* Generated mode : "800x600-100", from ??? */ | ||
331 | { | ||
332 | "800x600-100", { | ||
333 | 69650, 800, 600, 64, 128, 288, 1088, 4, 10, 40, 640, 800, 0, 8, | ||
334 | PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW| | ||
335 | PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}}, | ||
336 | /* Generated mode : "1024x768-43-lace" */ | ||
337 | /* INTERLACED NOT SUPPORTED | ||
338 | {"1024x768-43-lace", {44899, 1024, 768, 8, 184, 240, 1264, 1, 9, 49, 817, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, | ||
339 | INTERLACED NOT SUPPORTED */ | ||
340 | /* Generated mode : "1024x768-60" */ | ||
341 | { | ||
342 | "1024x768-60", { | ||
343 | 64998, 1024, 768, 24, 160, 320, 1344, 3, 9, 38, | ||
344 | 806, 1024, 0, 8, | ||
345 | PM3VideoControl_ENABLE | | ||
346 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
347 | | | ||
348 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
349 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
350 | /* Generated mode : "1024x768-70" */ | ||
351 | { | ||
352 | "1024x768-70", { | ||
353 | 74996, 1024, 768, 24, 160, 304, 1328, 3, 9, 38, | ||
354 | 806, 1024, 0, 8, | ||
355 | PM3VideoControl_ENABLE | | ||
356 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
357 | | | ||
358 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
359 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
360 | /* Generated mode : "1024x768-72" */ | ||
361 | { | ||
362 | "1024x768-72", { | ||
363 | 74996, 10224, 768, 24, 160, 264, 10488, 3, 9, 38, | ||
364 | 806, 10224, 0, 8, | ||
365 | PM3VideoControl_ENABLE | | ||
366 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
367 | | | ||
368 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
369 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
370 | /* Generated mode : "1024x768-75" */ | ||
371 | { | ||
372 | "1024x768-75", { | ||
373 | 78746, 1024, 768, 16, 112, 288, 1312, 1, 4, 32, | ||
374 | 800, 1024, 0, 8, | ||
375 | PM3VideoControl_ENABLE | | ||
376 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
377 | | | ||
378 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
379 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
380 | /* Generated mode : "1024x768-90" */ | ||
381 | { | ||
382 | "1024x768-90", { | ||
383 | 100000, 1024, 768, 0, 96, 288, 1312, 21, 36, 77, | ||
384 | 845, 1024, 0, 8, | ||
385 | PM3VideoControl_ENABLE | | ||
386 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
387 | | | ||
388 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
389 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
390 | /* Generated mode : "1024x768-100", from /etc/fb.modes */ | ||
391 | /* DISABLED, vsstart == 0 | ||
392 | { | ||
393 | "1024x768-100", { | ||
394 | 109998, 1024, 768, 0, 88, 368, 1392, 0, 8, 24, 792, | ||
395 | 1024, 0, 8, | ||
396 | PM3VideoControl_ENABLE | | ||
397 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
398 | | | ||
399 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
400 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
401 | */ | ||
402 | /* Generated mode : "1024x768-100", from ??? */ | ||
403 | { | ||
404 | "1024x768-100", { | ||
405 | 115500, 1024, 768, 32, 224, 416, 1440, 3, 13, 34, 802, 1024, 0, 8, | ||
406 | PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW| | ||
407 | PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}}, | ||
408 | /* Generated mode : "1152x864-43-lace" */ | ||
409 | /* INTERLACED NOT SUPPORTED | ||
410 | {"1152x864-43-lace", {64998, 1152, 864, 72, 200, 264, 1416, 78, 87, 191, 1055, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, | ||
411 | INTERLACED NOT SUPPORTED */ | ||
412 | /* Generated mode : "1152x864-47-lace" */ | ||
413 | /* INTERLACED NOT SUPPORTED | ||
414 | {"1152x864-47-lace", {64998, 1152, 864, 88, 216, 296, 1448, 30, 39, 83, 947, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, | ||
415 | INTERLACED NOT SUPPORTED */ | ||
416 | /* Generated mode : "1152x864-60" */ | ||
417 | { | ||
418 | "1152x864-60", { | ||
419 | 80000, 1152, 864, 64, 176, 304, 1456, 6, 11, 52, | ||
420 | 916, 1152, 0, 8, | ||
421 | PM3VideoControl_ENABLE | | ||
422 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
423 | | | ||
424 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
425 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
426 | /* Generated mode : "1152x864-70" */ | ||
427 | { | ||
428 | "1152x864-70", { | ||
429 | 100000, 1152, 864, 40, 192, 360, 1512, 13, 24, 81, | ||
430 | 945, 1152, 0, 8, | ||
431 | PM3VideoControl_ENABLE | | ||
432 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
433 | | | ||
434 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
435 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
436 | /* Generated mode : "1152x864-75" */ | ||
437 | { | ||
438 | "1152x864-75", { | ||
439 | 109998, 1152, 864, 24, 168, 312, 1464, 45, 53, 138, | ||
440 | 1002, 1152, 0, 8, | ||
441 | PM3VideoControl_ENABLE | | ||
442 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
443 | | | ||
444 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
445 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
446 | /* Generated mode : "1152x864-80" */ | ||
447 | { | ||
448 | "1152x864-80", { | ||
449 | 109998, 1152, 864, 16, 128, 288, 1440, 30, 37, 94, | ||
450 | 958, 1152, 0, 8, | ||
451 | PM3VideoControl_ENABLE | | ||
452 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
453 | | | ||
454 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
455 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
456 | /* Generated mode : "1280x1024-43-lace" */ | ||
457 | /* INTERLACED NOT SUPPORTED | ||
458 | {"1280x1024-43-lace", {80000, 1024, 1024, 80, 160, 320, 1344, 50, 60, 125, 1149, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, | ||
459 | INTERLACED NOT SUPPORTED */ | ||
460 | /* Generated mode : "1280x1024-47-lace" */ | ||
461 | /* INTERLACED NOT SUPPORTED | ||
462 | {"1280x1024-47-lace", {80000, 1280, 1024, 80, 160, 320, 1600, 1, 11, 29, 1053, 1280, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}}, | ||
463 | INTERLACED NOT SUPPORTED */ | ||
464 | /* Generated mode : "1280x1024-60" */ | ||
465 | { | ||
466 | "1280x1024-60", { | ||
467 | 107991, 1280, 1024, 48, 160, 408, 1688, 1, 4, 42, | ||
468 | 1066, 1280, 0, 8, | ||
469 | PM3VideoControl_ENABLE | | ||
470 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
471 | | | ||
472 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
473 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
474 | /* Generated mode : "1280x1024-70" */ | ||
475 | { | ||
476 | "1280x1024-70", { | ||
477 | 125992, 1280, 1024, 80, 192, 408, 1688, 1, 6, 42, | ||
478 | 1066, 1280, 0, 8, | ||
479 | PM3VideoControl_ENABLE | | ||
480 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
481 | | | ||
482 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
483 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
484 | /* Generated mode : "1280x1024-74" */ | ||
485 | { | ||
486 | "1280x1024-74", { | ||
487 | 134989, 1280, 1024, 32, 176, 432, 1712, 0, 30, 40, | ||
488 | 1064, 1280, 0, 8, | ||
489 | PM3VideoControl_ENABLE | | ||
490 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
491 | | | ||
492 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
493 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
494 | /* Generated mode : "1280x1024-75" */ | ||
495 | { | ||
496 | "1280x1024-75", { | ||
497 | 134989, 1280, 1024, 16, 160, 408, 1688, 1, 4, 42, | ||
498 | 1066, 1280, 0, 8, | ||
499 | PM3VideoControl_ENABLE | | ||
500 | PM3VideoControl_HSYNC_ACTIVE_HIGH | ||
501 | | | ||
502 | PM3VideoControl_VSYNC_ACTIVE_HIGH | ||
503 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
504 | /* Generated mode : "1600x1200-60" */ | ||
505 | { | ||
506 | "1600x1200-60", { | ||
507 | 155981, 1600, 1200, 32, 192, 448, 2048, 10, 18, 70, | ||
508 | 1270, 1600, 0, 8, | ||
509 | PM3VideoControl_ENABLE | | ||
510 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
511 | | | ||
512 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
513 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
514 | /* Generated mode : "1600x1200-66" */ | ||
515 | { | ||
516 | "1600x1200-66", { | ||
517 | 171998, 1600, 1200, 40, 176, 480, 2080, 3, 6, 53, | ||
518 | 1253, 1600, 0, 8, | ||
519 | PM3VideoControl_ENABLE | | ||
520 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
521 | | | ||
522 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
523 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
524 | /* Generated mode : "1600x1200-76" */ | ||
525 | { | ||
526 | "1600x1200-76", { | ||
527 | 197980, 1600, 1200, 40, 176, 480, 2080, 3, 8, 50, | ||
528 | 1250, 1600, 0, 8, | ||
529 | PM3VideoControl_ENABLE | | ||
530 | PM3VideoControl_HSYNC_ACTIVE_LOW | ||
531 | | | ||
532 | PM3VideoControl_VSYNC_ACTIVE_LOW | ||
533 | | PM3VideoControl_PIXELSIZE_8BIT}}, | ||
534 | /* ##### end of auto-generated mode */ | ||
535 | { | ||
536 | "\0",} | ||
537 | }; | ||
538 | 48 | ||
539 | /* more mandatory stuff (see skeletonfb.c + framebuffer driver HOWTO */ | 49 | /* |
540 | static struct pm3fb_info fb_info[PM3_MAX_BOARD]; | 50 | * Driver data |
541 | static struct pm3fb_par current_par[PM3_MAX_BOARD]; | 51 | */ |
542 | static int current_par_valid[PM3_MAX_BOARD]; | 52 | static char *mode_option __devinitdata; |
543 | /* to allow explicit filtering of board */ | ||
544 | short bus[PM3_MAX_BOARD]; | ||
545 | short slot[PM3_MAX_BOARD]; | ||
546 | short func[PM3_MAX_BOARD]; | ||
547 | short disable[PM3_MAX_BOARD]; | ||
548 | short noaccel[PM3_MAX_BOARD]; | ||
549 | char fontn[PM3_MAX_BOARD][PM3_FONTNAME_SIZE]; | ||
550 | short depth[PM3_MAX_BOARD]; | ||
551 | short flatpanel[PM3_MAX_BOARD]; | ||
552 | static struct display disp[PM3_MAX_BOARD]; | ||
553 | static char g_options[PM3_OPTIONS_SIZE] __initdata = "pm3fb,dummy"; | ||
554 | short printtimings = 0; | ||
555 | short forcesize[PM3_MAX_BOARD]; | ||
556 | |||
557 | /* ********************* */ | ||
558 | /* ***** prototype ***** */ | ||
559 | /* ********************* */ | ||
560 | /* card-specific */ | ||
561 | static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info); | ||
562 | /* permedia3-specific */ | ||
563 | static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info); | ||
564 | static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info); | ||
565 | static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info); | ||
566 | static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info, | ||
567 | unsigned long r); | ||
568 | static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock, /* In kHz units */ | ||
569 | unsigned long refclock, /* In kHz units */ | ||
570 | unsigned char *prescale, /* ClkPreScale */ | ||
571 | unsigned char *feedback, /* ClkFeedBackScale */ | ||
572 | unsigned char *postscale | ||
573 | /* ClkPostScale */ ); | ||
574 | static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc); | ||
575 | static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b); | ||
576 | static void pm3fb_common_init(struct pm3fb_info *l_fb_info); | ||
577 | static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info, | ||
578 | unsigned long depth, int v); | ||
579 | static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info, | ||
580 | unsigned long depth, int v); | ||
581 | static void pm3fb_mapIO(struct pm3fb_info *l_fb_info); | ||
582 | static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info); | ||
583 | #if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) | ||
584 | static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info); | ||
585 | #endif | ||
586 | static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info); | ||
587 | static void pm3fb_write_mode(struct pm3fb_info *l_fb_info); | ||
588 | static void pm3fb_read_mode(struct pm3fb_info *l_fb_info, | ||
589 | struct pm3fb_par *curpar); | ||
590 | static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info); | ||
591 | /* accelerated permedia3-specific */ | ||
592 | #ifdef PM3FB_USE_ACCEL | ||
593 | static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info); | ||
594 | static void pm3fb_init_engine(struct pm3fb_info *l_fb_info); | ||
595 | #ifdef FBCON_HAS_CFB32 | ||
596 | static void pm3fb_cfb32_clear(struct vc_data *conp, | ||
597 | struct display *p, | ||
598 | int sy, int sx, int height, int width); | ||
599 | static void pm3fb_cfb32_clear_margins(struct vc_data *conp, | ||
600 | struct display *p, int bottom_only); | ||
601 | #endif /* FBCON_HAS_CFB32 */ | ||
602 | #ifdef FBCON_HAS_CFB16 | ||
603 | static void pm3fb_cfb16_clear(struct vc_data *conp, | ||
604 | struct display *p, | ||
605 | int sy, int sx, int height, int width); | ||
606 | static void pm3fb_cfb16_clear_margins(struct vc_data *conp, | ||
607 | struct display *p, int bottom_only); | ||
608 | #endif /* FBCON_HAS_CFB16 */ | ||
609 | #ifdef FBCON_HAS_CFB8 | ||
610 | static void pm3fb_cfb8_clear(struct vc_data *conp, | ||
611 | struct display *p, | ||
612 | int sy, int sx, int height, int width); | ||
613 | static void pm3fb_cfb8_clear_margins(struct vc_data *conp, | ||
614 | struct display *p, int bottom_only); | ||
615 | #endif /* FBCON_HAS_CFB8 */ | ||
616 | #if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32) | ||
617 | static void pm3fb_cfbX_bmove(struct display *p, | ||
618 | int sy, int sx, | ||
619 | int dy, int dx, int height, int width); | ||
620 | static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p, | ||
621 | int c, int yy, int xx); | ||
622 | static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p, | ||
623 | const unsigned short *s, int count, int yy, | ||
624 | int xx); | ||
625 | static void pm3fb_cfbX_revc(struct display *p, int xx, int yy); | ||
626 | #endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */ | ||
627 | #endif /* PM3FB_USE_ACCEL */ | ||
628 | /* pre-init */ | ||
629 | static void pm3fb_mode_setup(char *mode, unsigned long board_num); | ||
630 | static void pm3fb_pciid_setup(char *pciid, unsigned long board_num); | ||
631 | static char *pm3fb_boardnum_setup(char *options, unsigned long *bn); | ||
632 | static void pm3fb_real_setup(char *options); | ||
633 | /* fbdev */ | ||
634 | static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix, | ||
635 | const void *par, struct fb_info_gen *info); | ||
636 | static int pm3fb_decode_var(const struct fb_var_screeninfo *var, | ||
637 | void *par, struct fb_info_gen *info); | ||
638 | static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d); | ||
639 | static int pm3fb_encode_var(struct fb_var_screeninfo *var, | ||
640 | const void *par, struct fb_info_gen *info); | ||
641 | static void pm3fb_get_par(void *par, struct fb_info_gen *info); | ||
642 | static void pm3fb_set_par(const void *par, struct fb_info_gen *info); | ||
643 | static void pm3fb_set_color(struct pm3fb_info *l_fb_info, | ||
644 | unsigned char regno, unsigned char r, | ||
645 | unsigned char g, unsigned char b); | ||
646 | static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green, | ||
647 | unsigned *blue, unsigned *transp, | ||
648 | struct fb_info *info); | ||
649 | static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, | ||
650 | unsigned blue, unsigned transp, | ||
651 | struct fb_info *info); | ||
652 | static int pm3fb_blank(int blank_mode, struct fb_info_gen *info); | ||
653 | static void pm3fb_set_disp(const void *par, struct display *disp, | ||
654 | struct fb_info_gen *info); | ||
655 | static void pm3fb_detect(void); | ||
656 | static int pm3fb_pan_display(const struct fb_var_screeninfo *var, | ||
657 | struct fb_info_gen *info); | ||
658 | static int pm3fb_ioctl(struct fb_info *info, u_int cmd, u_long arg); | ||
659 | |||
660 | |||
661 | /* the struct that hold them together */ | ||
662 | struct fbgen_hwswitch pm3fb_switch = { | ||
663 | pm3fb_detect, pm3fb_encode_fix, pm3fb_decode_var, pm3fb_encode_var, | ||
664 | pm3fb_get_par, pm3fb_set_par, pm3fb_getcolreg, | ||
665 | pm3fb_pan_display, pm3fb_blank, pm3fb_set_disp | ||
666 | }; | ||
667 | 53 | ||
668 | static struct fb_ops pm3fb_ops = { | 54 | /* |
669 | .owner = THIS_MODULE, | 55 | * If your driver supports multiple boards, you should make the |
670 | .fb_get_fix = fbgen_get_fix, | 56 | * below data types arrays, or allocate them dynamically (using kmalloc()). |
671 | .fb_get_var = fbgen_get_var, | 57 | */ |
672 | .fb_set_var = fbgen_set_var, | ||
673 | .fb_get_cmap = fbgen_get_cmap, | ||
674 | .fb_set_cmap = fbgen_set_cmap, | ||
675 | .fb_setcolreg = pm3fb_setcolreg, | ||
676 | .fb_pan_display =fbgen_pan_display, | ||
677 | .fb_blank = fbgen_blank, | ||
678 | .fb_ioctl = pm3fb_ioctl, | ||
679 | }; | ||
680 | 58 | ||
681 | #ifdef PM3FB_USE_ACCEL | 59 | /* |
682 | #ifdef FBCON_HAS_CFB32 | 60 | * This structure defines the hardware state of the graphics card. Normally |
683 | static struct display_switch pm3fb_cfb32 = { | 61 | * you place this in a header file in linux/include/video. This file usually |
684 | fbcon_cfb32_setup, pm3fb_cfbX_bmove, pm3fb_cfb32_clear, | 62 | * also includes register information. That allows other driver subsystems |
685 | pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc, | 63 | * and userland applications the ability to use the same header file to |
686 | NULL /* cursor() */ , NULL /* set_font() */ , | 64 | * avoid duplicate work and easy porting of software. |
687 | pm3fb_cfb32_clear_margins, | 65 | */ |
688 | FONTWIDTHRANGE(1, 16) /* true only if accelerated... */ | 66 | struct pm3_par { |
689 | }; | 67 | unsigned char __iomem *v_regs;/* virtual address of p_regs */ |
690 | #endif /* FBCON_HAS_CFB32 */ | 68 | u32 video; /* video flags before blanking */ |
691 | #ifdef FBCON_HAS_CFB16 | 69 | u32 base; /* screen base (xoffset+yoffset) in 128 bits unit */ |
692 | static struct display_switch pm3fb_cfb16 = { | 70 | u32 palette[16]; |
693 | fbcon_cfb16_setup, pm3fb_cfbX_bmove, pm3fb_cfb16_clear, | ||
694 | pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc, | ||
695 | NULL /* cursor() */ , NULL /* set_font() */ , | ||
696 | pm3fb_cfb16_clear_margins, | ||
697 | FONTWIDTHRANGE(1, 16) /* true only if accelerated... */ | ||
698 | }; | ||
699 | #endif /* FBCON_HAS_CFB16 */ | ||
700 | #ifdef FBCON_HAS_CFB8 | ||
701 | static struct display_switch pm3fb_cfb8 = { | ||
702 | fbcon_cfb8_setup, pm3fb_cfbX_bmove, pm3fb_cfb8_clear, | ||
703 | pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc, | ||
704 | NULL /* cursor() */ , NULL /* set_font() */ , | ||
705 | pm3fb_cfb8_clear_margins, | ||
706 | FONTWIDTHRANGE(1, 16) /* true only if accelerated... */ | ||
707 | }; | ||
708 | #endif /* FBCON_HAS_CFB8 */ | ||
709 | #endif /* PM3FB_USE_ACCEL */ | ||
710 | |||
711 | /* ****************************** */ | ||
712 | /* ***** card-specific data ***** */ | ||
713 | /* ****************************** */ | ||
714 | struct pm3fb_card_timings { | ||
715 | unsigned long memsize; /* 0 for last value (i.e. default) */ | ||
716 | struct pm3fb_timings memt; | ||
717 | }; | 71 | }; |
718 | 72 | ||
719 | static struct pm3fb_card_timings t_FormacProFormance3[] = { | 73 | /* |
720 | { 16, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} }, | 74 | * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo |
721 | { 0, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} } /* from 16 MB PF3 */ | 75 | * if we don't use modedb. If we do use modedb see pm3fb_init how to use it |
76 | * to get a fb_var_screeninfo. Otherwise define a default var as well. | ||
77 | */ | ||
78 | static struct fb_fix_screeninfo pm3fb_fix __devinitdata = { | ||
79 | .id = "Permedia3", | ||
80 | .type = FB_TYPE_PACKED_PIXELS, | ||
81 | .visual = FB_VISUAL_PSEUDOCOLOR, | ||
82 | .xpanstep = 1, | ||
83 | .ypanstep = 1, | ||
84 | .ywrapstep = 0, | ||
85 | .accel = FB_ACCEL_NONE, | ||
722 | }; | 86 | }; |
723 | 87 | ||
724 | static struct pm3fb_card_timings t_AppianJeronimo2000[] = { | 88 | /* |
725 | { 32, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} }, | 89 | * Utility functions |
726 | { 0, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} } /* from 32MB J2000 */ | 90 | */ |
727 | }; | ||
728 | 91 | ||
729 | static struct pm3fb_card_timings t_3DLabsOxygenVX1[] = { | 92 | static inline u32 PM3_READ_REG(struct pm3_par *par, s32 off) |
730 | { 32, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} }, | 93 | { |
731 | { 0, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} } /* from 32MB VX1 */ | 94 | return fb_readl(par->v_regs + off); |
732 | }; | 95 | } |
733 | 96 | ||
734 | static struct { | 97 | static inline void PM3_WRITE_REG(struct pm3_par *par, s32 off, u32 v) |
735 | char cardname[32]; /* recognized card name */ | 98 | { |
736 | u16 subvendor; /* subvendor of the card */ | 99 | fb_writel(v, par->v_regs + off); |
737 | u16 subdevice; /* subdevice of the card */ | 100 | } |
738 | u8 func; /* function of the card to which the extra init apply */ | ||
739 | void (*specific_setup)(struct pm3fb_info *l_fb_info); /* card/func specific setup, done before _any_ FB access */ | ||
740 | struct pm3fb_card_timings *c_memt; /* defauls timings for the boards */ | ||
741 | } cardbase[] = { | ||
742 | { "Unknown Permedia3 board", 0xFFFF, 0xFFFF, 0xFF, NULL, NULL }, | ||
743 | { "Appian Jeronimo 2000 head 1", 0x1097, 0x3d32, 1, NULL, | ||
744 | t_AppianJeronimo2000 | ||
745 | }, | ||
746 | { "Appian Jeronimo 2000 head 2", 0x1097, 0x3d32, 2, pm3fb_j2000_setup, | ||
747 | t_AppianJeronimo2000 | ||
748 | }, | ||
749 | { "Formac ProFormance 3", PCI_VENDOR_ID_3DLABS, 0x000a, 0, NULL, /* Formac use 3DLabs ID ?!? */ | ||
750 | t_FormacProFormance3 | ||
751 | }, | ||
752 | { "3DLabs Permedia3 Create!", PCI_VENDOR_ID_3DLABS, 0x0127, 0, NULL, NULL }, | ||
753 | { "3DLabs Oxygen VX1 PCI", PCI_VENDOR_ID_3DLABS, 0x0121, 0, NULL, | ||
754 | t_3DLabsOxygenVX1 | ||
755 | }, | ||
756 | { "3DLabs Oxygen VX1 AGP", PCI_VENDOR_ID_3DLABS, 0x0125, 0, NULL, NULL }, | ||
757 | { "3DLabs Oxygen VX1-16 AGP", PCI_VENDOR_ID_3DLABS, 0x0140, 0, NULL, NULL }, | ||
758 | { "3DLabs Oxygen VX1-1600SW PCI", PCI_VENDOR_ID_3DLABS, 0x0800, 0, NULL, NULL }, | ||
759 | { "\0", 0x0, 0x0, 0, NULL, NULL } | ||
760 | }; | ||
761 | 101 | ||
762 | /* ********************************** */ | 102 | static inline void PM3_WAIT(struct pm3_par *par, u32 n) |
763 | /* ***** card-specific function ***** */ | 103 | { |
764 | /* ********************************** */ | 104 | while (PM3_READ_REG(par, PM3InFIFOSpace) < n); |
765 | static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info) | ||
766 | { /* the appian j2000 require more initialization of the second head */ | ||
767 | /* l_fb_info must point to the _second_ head of the J2000 */ | ||
768 | |||
769 | DTRACE; | ||
770 | |||
771 | l_fb_info->memt = t_AppianJeronimo2000[0].memt; /* 32 MB, first and only j2000 ? */ | ||
772 | |||
773 | pm3fb_write_memory_timings(l_fb_info); | ||
774 | } | 105 | } |
775 | 106 | ||
776 | /* *************************************** */ | 107 | static inline void PM3_SLOW_WRITE_REG(struct pm3_par *par, s32 off, u32 v) |
777 | /* ***** permedia3-specific function ***** */ | ||
778 | /* *************************************** */ | ||
779 | static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info) | ||
780 | { | 108 | { |
781 | l_fb_info->memt.caps = PM3_READ_REG(PM3LocalMemCaps); | 109 | if (par->v_regs) { |
782 | l_fb_info->memt.timings = PM3_READ_REG(PM3LocalMemTimings); | 110 | mb(); |
783 | l_fb_info->memt.control = PM3_READ_REG(PM3LocalMemControl); | 111 | PM3_WAIT(par, 1); |
784 | l_fb_info->memt.refresh = PM3_READ_REG(PM3LocalMemRefresh); | 112 | wmb(); |
785 | l_fb_info->memt.powerdown = PM3_READ_REG(PM3LocalMemPowerDown); | 113 | PM3_WRITE_REG(par, off, v); |
786 | |||
787 | if ((l_fb_info->memt.caps == PM3FB_UNKNOWN_TIMING_VALUE) || | ||
788 | (l_fb_info->memt.timings == PM3FB_UNKNOWN_TIMING_VALUE) || | ||
789 | (l_fb_info->memt.control == PM3FB_UNKNOWN_TIMING_VALUE) || | ||
790 | (l_fb_info->memt.refresh == PM3FB_UNKNOWN_TIMING_VALUE) || | ||
791 | (l_fb_info->memt.powerdown == PM3FB_UNKNOWN_TIMING_VALUE)) | ||
792 | { | ||
793 | printk(KERN_ERR "pm3fb: invalid memory timings in permedia3 board #%ld\n", l_fb_info->board_num); | ||
794 | return(pm3fb_try_memory_timings(l_fb_info)); | ||
795 | } | 114 | } |
796 | return(pm3fb_timing_ok); | ||
797 | } | 115 | } |
798 | 116 | ||
799 | static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info) | 117 | static inline void PM3_SET_INDEX(struct pm3_par *par, unsigned index) |
800 | { | 118 | { |
801 | if (cardbase[l_fb_info->board_type].c_memt) | 119 | PM3_SLOW_WRITE_REG(par, PM3RD_IndexHigh, (index >> 8) & 0xff); |
802 | { | 120 | PM3_SLOW_WRITE_REG(par, PM3RD_IndexLow, index & 0xff); |
803 | int i = 0, done = 0; | ||
804 | while (!done) | ||
805 | { | ||
806 | if ((cardbase[l_fb_info->board_type].c_memt[i].memsize == l_fb_info->fb_size) | ||
807 | || !(cardbase[l_fb_info->board_type].c_memt[i].memsize)) | ||
808 | { /* will use the 0-sized timings by default */ | ||
809 | done = 1; | ||
810 | l_fb_info->memt = cardbase[l_fb_info->board_type].c_memt[i].memt; | ||
811 | printk(KERN_WARNING "pm3fb: trying to use predefined memory timings for permedia3 board #%ld (%s, %ld MB)\n", | ||
812 | l_fb_info->board_num, | ||
813 | cardbase[l_fb_info->board_type].cardname, | ||
814 | cardbase[l_fb_info->board_type].c_memt[i].memsize); | ||
815 | pm3fb_write_memory_timings(l_fb_info); | ||
816 | return(pm3fb_timing_retry); | ||
817 | } | ||
818 | i++; | ||
819 | } | ||
820 | } else | ||
821 | return(pm3fb_timing_problem); | ||
822 | return(pm3fb_timing_ok); | ||
823 | } | 121 | } |
824 | 122 | ||
825 | static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info) | 123 | static inline void PM3_WRITE_DAC_REG(struct pm3_par *par, unsigned r, u8 v) |
826 | { | 124 | { |
827 | unsigned char m, n, p; | 125 | PM3_SET_INDEX(par, r); |
828 | unsigned long clockused; | 126 | wmb(); |
829 | 127 | PM3_WRITE_REG(par, PM3RD_IndexedData, v); | |
830 | PM3_SLOW_WRITE_REG(PM3LocalMemCaps, l_fb_info->memt.caps); | ||
831 | PM3_SLOW_WRITE_REG(PM3LocalMemTimings, l_fb_info->memt.timings); | ||
832 | PM3_SLOW_WRITE_REG(PM3LocalMemControl, l_fb_info->memt.control); | ||
833 | PM3_SLOW_WRITE_REG(PM3LocalMemRefresh, l_fb_info->memt.refresh); | ||
834 | PM3_SLOW_WRITE_REG(PM3LocalMemPowerDown, l_fb_info->memt.powerdown); | ||
835 | |||
836 | clockused = | ||
837 | pm3fb_CalculateClock(l_fb_info, 2 * 105000, PM3_REF_CLOCK, &m, | ||
838 | &n, &p); | ||
839 | |||
840 | PM3_WRITE_DAC_REG(PM3RD_KClkPreScale, m); | ||
841 | PM3_WRITE_DAC_REG(PM3RD_KClkFeedbackScale, n); | ||
842 | PM3_WRITE_DAC_REG(PM3RD_KClkPostScale, p); | ||
843 | PM3_WRITE_DAC_REG(PM3RD_KClkControl, | ||
844 | PM3RD_KClkControl_STATE_RUN | | ||
845 | PM3RD_KClkControl_SOURCE_PLL | | ||
846 | PM3RD_KClkControl_ENABLE); | ||
847 | PM3_WRITE_DAC_REG(PM3RD_MClkControl, | ||
848 | PM3RD_MClkControl_STATE_RUN | | ||
849 | PM3RD_MClkControl_SOURCE_KCLK | | ||
850 | PM3RD_MClkControl_ENABLE); | ||
851 | PM3_WRITE_DAC_REG(PM3RD_SClkControl, | ||
852 | PM3RD_SClkControl_STATE_RUN | | ||
853 | PM3RD_SClkControl_SOURCE_PCLK | | ||
854 | PM3RD_SClkControl_ENABLE); | ||
855 | } | 128 | } |
856 | 129 | ||
857 | static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info, | 130 | static inline void pm3fb_set_color(struct pm3_par *par, unsigned char regno, |
858 | unsigned long r) | 131 | unsigned char r, unsigned char g, unsigned char b) |
859 | { | 132 | { |
860 | DASSERT((l_fb_info->vIOBase != (unsigned char *) (-1)), | 133 | PM3_SLOW_WRITE_REG(par, PM3RD_PaletteWriteAddress, regno); |
861 | "l_fb_info->vIOBase mapped in read dac reg\n"); | 134 | PM3_SLOW_WRITE_REG(par, PM3RD_PaletteData, r); |
862 | PM3_SET_INDEX(r); | 135 | PM3_SLOW_WRITE_REG(par, PM3RD_PaletteData, g); |
863 | mb(); | 136 | PM3_SLOW_WRITE_REG(par, PM3RD_PaletteData, b); |
864 | return (PM3_READ_REG(PM3RD_IndexedData)); | 137 | } |
138 | |||
139 | static void pm3fb_clear_colormap(struct pm3_par *par, | ||
140 | unsigned char r, unsigned char g, unsigned char b) | ||
141 | { | ||
142 | int i; | ||
143 | |||
144 | for (i = 0; i < 256 ; i++) /* fill color map with white */ | ||
145 | pm3fb_set_color(par, i, r, g, b); | ||
146 | |||
865 | } | 147 | } |
866 | 148 | ||
867 | /* Calculating various clock parameter */ | 149 | /* Calculating various clock parameter */ |
868 | static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock, /* In kHz units */ | 150 | static void pm3fb_calculate_clock(unsigned long reqclock, |
869 | unsigned long refclock, /* In kHz units */ | 151 | unsigned char *prescale, |
870 | unsigned char *prescale, /* ClkPreScale */ | 152 | unsigned char *feedback, |
871 | unsigned char *feedback, /* ClkFeedBackScale */ | 153 | unsigned char *postscale) |
872 | unsigned char *postscale | ||
873 | /* ClkPostScale */ ) | ||
874 | { | 154 | { |
875 | int f, pre, post; | 155 | int f, pre, post; |
876 | unsigned long freq; | 156 | unsigned long freq; |
877 | long freqerr = 1000; | 157 | long freqerr = 1000; |
878 | unsigned long actualclock = 0; | 158 | long currerr; |
879 | |||
880 | DTRACE; | ||
881 | 159 | ||
882 | for (f = 1; f < 256; f++) { | 160 | for (f = 1; f < 256; f++) { |
883 | for (pre = 1; pre < 256; pre++) { | 161 | for (pre = 1; pre < 256; pre++) { |
884 | for (post = 0; post < 5; post++) { | 162 | for (post = 0; post < 5; post++) { |
885 | freq = | 163 | freq = ((2*PM3_REF_CLOCK * f) >> post) / pre; |
886 | ((2 * refclock * f) / | 164 | currerr = (reqclock > freq) |
887 | (pre * (1 << post))); | 165 | ? reqclock - freq |
888 | if ((reqclock > freq - freqerr) | 166 | : freq - reqclock; |
889 | && (reqclock < freq + freqerr)) { | 167 | if (currerr < freqerr) { |
890 | freqerr = | 168 | freqerr = currerr; |
891 | (reqclock > | ||
892 | freq) ? reqclock - | ||
893 | freq : freq - reqclock; | ||
894 | *feedback = f; | 169 | *feedback = f; |
895 | *prescale = pre; | 170 | *prescale = pre; |
896 | *postscale = post; | 171 | *postscale = post; |
897 | actualclock = freq; | ||
898 | } | 172 | } |
899 | } | 173 | } |
900 | } | 174 | } |
901 | } | 175 | } |
902 | |||
903 | return (actualclock); | ||
904 | } | 176 | } |
905 | 177 | ||
906 | static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info, | 178 | static inline int pm3fb_shift_bpp(unsigned long depth, int v) |
907 | unsigned long depth, int v) | ||
908 | { | 179 | { |
909 | DTRACE; | ||
910 | |||
911 | switch (depth) { | 180 | switch (depth) { |
912 | case 8: | 181 | case 8: |
913 | return (v >> 4); | 182 | return (v >> 4); |
@@ -918,181 +187,59 @@ static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info, | |||
918 | case 32: | 187 | case 32: |
919 | return (v >> 2); | 188 | return (v >> 2); |
920 | } | 189 | } |
921 | DPRINTK(1, "Unsupported depth %ld\n", depth); | 190 | DPRINTK("Unsupported depth %ld\n", depth); |
922 | return (0); | 191 | return 0; |
923 | } | ||
924 | |||
925 | static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info, | ||
926 | unsigned long depth, int v) | ||
927 | { | ||
928 | DTRACE; | ||
929 | |||
930 | switch (depth) { | ||
931 | case 8: | ||
932 | return (v << 4); | ||
933 | case 12: | ||
934 | case 15: | ||
935 | case 16: | ||
936 | return (v << 3); | ||
937 | case 32: | ||
938 | return (v << 2); | ||
939 | } | ||
940 | DPRINTK(1, "Unsupported depth %ld\n", depth); | ||
941 | return (0); | ||
942 | } | ||
943 | |||
944 | static void pm3fb_mapIO(struct pm3fb_info *l_fb_info) | ||
945 | { | ||
946 | DTRACE; | ||
947 | |||
948 | l_fb_info->vIOBase = | ||
949 | ioremap((unsigned long) l_fb_info->pIOBase, PM3_REGS_SIZE); | ||
950 | l_fb_info->v_fb = | ||
951 | ioremap((unsigned long) l_fb_info->p_fb, l_fb_info->fb_size); | ||
952 | DPRINTK(2, "IO mapping : IOBase %lx / %lx, fb %lx / %lx\n", | ||
953 | (unsigned long) l_fb_info->pIOBase, | ||
954 | (unsigned long) l_fb_info->vIOBase, | ||
955 | (unsigned long) l_fb_info->p_fb, | ||
956 | (unsigned long) l_fb_info->v_fb); | ||
957 | } | ||
958 | |||
959 | static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info) | ||
960 | { | ||
961 | DTRACE; | ||
962 | |||
963 | iounmap(l_fb_info->vIOBase); | ||
964 | iounmap(l_fb_info->v_fb); | ||
965 | l_fb_info->vIOBase = (unsigned char *) -1; | ||
966 | l_fb_info->v_fb = (unsigned char *) -1; | ||
967 | } | ||
968 | |||
969 | #if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) | ||
970 | static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info) | ||
971 | { | ||
972 | DPRINTK(2, "PM3Aperture0: 0x%08x\n", PM3_READ_REG(PM3Aperture0)); | ||
973 | DPRINTK(2, "PM3Aperture1: 0x%08x\n", PM3_READ_REG(PM3Aperture1)); | ||
974 | DPRINTK(2, "PM3ByAperture1Mode: 0x%08x\n", | ||
975 | PM3_READ_REG(PM3ByAperture1Mode)); | ||
976 | DPRINTK(2, "PM3ByAperture2Mode: 0x%08x\n", | ||
977 | PM3_READ_REG(PM3ByAperture2Mode)); | ||
978 | DPRINTK(2, "PM3ChipConfig: 0x%08x\n", PM3_READ_REG(PM3ChipConfig)); | ||
979 | DPRINTK(2, "PM3FIFODis: 0x%08x\n", PM3_READ_REG(PM3FIFODis)); | ||
980 | DPRINTK(2, "PM3HTotal: 0x%08x\n", PM3_READ_REG(PM3HTotal)); | ||
981 | DPRINTK(2, "PM3HbEnd: 0x%08x\n", PM3_READ_REG(PM3HbEnd)); | ||
982 | DPRINTK(2, "PM3HgEnd: 0x%08x\n", PM3_READ_REG(PM3HgEnd)); | ||
983 | DPRINTK(2, "PM3HsEnd: 0x%08x\n", PM3_READ_REG(PM3HsEnd)); | ||
984 | DPRINTK(2, "PM3HsStart: 0x%08x\n", PM3_READ_REG(PM3HsStart)); | ||
985 | DPRINTK(2, "PM3MemBypassWriteMask: 0x%08x\n", | ||
986 | PM3_READ_REG(PM3MemBypassWriteMask)); | ||
987 | DPRINTK(2, "PM3RD_IndexControl: 0x%08x\n", | ||
988 | PM3_READ_REG(PM3RD_IndexControl)); | ||
989 | DPRINTK(2, "PM3ScreenBase: 0x%08x\n", PM3_READ_REG(PM3ScreenBase)); | ||
990 | DPRINTK(2, "PM3ScreenStride: 0x%08x\n", | ||
991 | PM3_READ_REG(PM3ScreenStride)); | ||
992 | DPRINTK(2, "PM3VClkCtl: 0x%08x\n", PM3_READ_REG(PM3VClkCtl)); | ||
993 | DPRINTK(2, "PM3VTotal: 0x%08x\n", PM3_READ_REG(PM3VTotal)); | ||
994 | DPRINTK(2, "PM3VbEnd: 0x%08x\n", PM3_READ_REG(PM3VbEnd)); | ||
995 | DPRINTK(2, "PM3VideoControl: 0x%08x\n", | ||
996 | PM3_READ_REG(PM3VideoControl)); | ||
997 | DPRINTK(2, "PM3VsEnd: 0x%08x\n", PM3_READ_REG(PM3VsEnd)); | ||
998 | DPRINTK(2, "PM3VsStart: 0x%08x\n", PM3_READ_REG(PM3VsStart)); | ||
999 | |||
1000 | DPRINTK(2, "PM3RD_ColorFormat: %ld\n", | ||
1001 | PM3_READ_DAC_REG(PM3RD_ColorFormat)); | ||
1002 | DPRINTK(2, "PM3RD_DACControl: %ld\n", | ||
1003 | PM3_READ_DAC_REG(PM3RD_DACControl)); | ||
1004 | DPRINTK(2, "PM3RD_DClk0FeedbackScale: %ld\n", | ||
1005 | PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale)); | ||
1006 | DPRINTK(2, "PM3RD_DClk0PostScale: %ld\n", | ||
1007 | PM3_READ_DAC_REG(PM3RD_DClk0PostScale)); | ||
1008 | DPRINTK(2, "PM3RD_DClk0PreScale: %ld\n", | ||
1009 | PM3_READ_DAC_REG(PM3RD_DClk0PreScale)); | ||
1010 | DPRINTK(2, "[not set] PM3RD_IndexControl: %ld\n", | ||
1011 | PM3_READ_DAC_REG(PM3RD_IndexControl)); | ||
1012 | DPRINTK(2, "PM3RD_MiscControl: %ld\n", | ||
1013 | PM3_READ_DAC_REG(PM3RD_MiscControl)); | ||
1014 | DPRINTK(2, "PM3RD_PixelSize: %ld\n", | ||
1015 | PM3_READ_DAC_REG(PM3RD_PixelSize)); | ||
1016 | DPRINTK(2, "PM3RD_SyncControl: %ld\n", | ||
1017 | PM3_READ_DAC_REG(PM3RD_SyncControl)); | ||
1018 | } | ||
1019 | |||
1020 | #endif /* defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) */ | ||
1021 | static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info) | ||
1022 | { | ||
1023 | u16 subvendor, subdevice; | ||
1024 | |||
1025 | if ((!pci_read_config_word | ||
1026 | (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor)) | ||
1027 | && | ||
1028 | (!pci_read_config_word | ||
1029 | (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) { | ||
1030 | /* well, nothing... */ | ||
1031 | } else { | ||
1032 | subvendor = subdevice = (u16)-1; | ||
1033 | } | ||
1034 | |||
1035 | printk(KERN_INFO "pm3fb: memory timings for board #%ld (subvendor: 0x%hx, subdevice: 0x%hx)\n", l_fb_info->board_num, subvendor, subdevice); | ||
1036 | printk(KERN_INFO " PM3LocalMemCaps: 0x%08x\n", | ||
1037 | PM3_READ_REG(PM3LocalMemCaps)); | ||
1038 | printk(KERN_INFO " PM3LocalMemTimings: 0x%08x\n", | ||
1039 | PM3_READ_REG(PM3LocalMemTimings)); | ||
1040 | printk(KERN_INFO " PM3LocalMemControl: 0x%08x\n", | ||
1041 | PM3_READ_REG(PM3LocalMemControl)); | ||
1042 | printk(KERN_INFO " PM3LocalMemRefresh: 0x%08x\n", | ||
1043 | PM3_READ_REG(PM3LocalMemRefresh)); | ||
1044 | printk(KERN_INFO " PM3LocalMemPowerDown: 0x%08x\n", | ||
1045 | PM3_READ_REG(PM3LocalMemPowerDown)); | ||
1046 | } | 192 | } |
1047 | 193 | ||
1048 | /* write the mode to registers */ | 194 | /* write the mode to registers */ |
1049 | static void pm3fb_write_mode(struct pm3fb_info *l_fb_info) | 195 | static void pm3fb_write_mode(struct fb_info *info) |
1050 | { | 196 | { |
197 | struct pm3_par *par = info->par; | ||
1051 | char tempsync = 0x00, tempmisc = 0x00; | 198 | char tempsync = 0x00, tempmisc = 0x00; |
1052 | DTRACE; | 199 | const u32 hsstart = info->var.right_margin; |
1053 | 200 | const u32 hsend = hsstart + info->var.hsync_len; | |
1054 | PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xffffffff); | 201 | const u32 hbend = hsend + info->var.left_margin; |
1055 | PM3_SLOW_WRITE_REG(PM3Aperture0, 0x00000000); | 202 | const u32 xres = (info->var.xres + 31) & ~31; |
1056 | PM3_SLOW_WRITE_REG(PM3Aperture1, 0x00000000); | 203 | const u32 htotal = xres + hbend; |
1057 | PM3_SLOW_WRITE_REG(PM3FIFODis, 0x00000007); | 204 | const u32 vsstart = info->var.lower_margin; |
1058 | 205 | const u32 vsend = vsstart + info->var.vsync_len; | |
1059 | PM3_SLOW_WRITE_REG(PM3HTotal, | 206 | const u32 vbend = vsend + info->var.upper_margin; |
1060 | pm3fb_Shiftbpp(l_fb_info, | 207 | const u32 vtotal = info->var.yres + vbend; |
1061 | l_fb_info->current_par->depth, | 208 | const u32 width = (info->var.xres_virtual + 7) & ~7; |
1062 | l_fb_info->current_par->htotal - | 209 | |
1063 | 1)); | 210 | PM3_SLOW_WRITE_REG(par, PM3MemBypassWriteMask, 0xffffffff); |
1064 | PM3_SLOW_WRITE_REG(PM3HsEnd, | 211 | PM3_SLOW_WRITE_REG(par, PM3Aperture0, 0x00000000); |
1065 | pm3fb_Shiftbpp(l_fb_info, | 212 | PM3_SLOW_WRITE_REG(par, PM3Aperture1, 0x00000000); |
1066 | l_fb_info->current_par->depth, | 213 | PM3_SLOW_WRITE_REG(par, PM3FIFODis, 0x00000007); |
1067 | l_fb_info->current_par->hsend)); | 214 | |
1068 | PM3_SLOW_WRITE_REG(PM3HsStart, | 215 | PM3_SLOW_WRITE_REG(par, PM3HTotal, |
1069 | pm3fb_Shiftbpp(l_fb_info, | 216 | pm3fb_shift_bpp(info->var.bits_per_pixel, |
1070 | l_fb_info->current_par->depth, | 217 | htotal - 1)); |
1071 | l_fb_info->current_par-> | 218 | PM3_SLOW_WRITE_REG(par, PM3HsEnd, |
219 | pm3fb_shift_bpp(info->var.bits_per_pixel, | ||
220 | hsend)); | ||
221 | PM3_SLOW_WRITE_REG(par, PM3HsStart, | ||
222 | pm3fb_shift_bpp(info->var.bits_per_pixel, | ||
1072 | hsstart)); | 223 | hsstart)); |
1073 | PM3_SLOW_WRITE_REG(PM3HbEnd, | 224 | PM3_SLOW_WRITE_REG(par, PM3HbEnd, |
1074 | pm3fb_Shiftbpp(l_fb_info, | 225 | pm3fb_shift_bpp(info->var.bits_per_pixel, |
1075 | l_fb_info->current_par->depth, | 226 | hbend)); |
1076 | l_fb_info->current_par->hbend)); | 227 | PM3_SLOW_WRITE_REG(par, PM3HgEnd, |
1077 | PM3_SLOW_WRITE_REG(PM3HgEnd, | 228 | pm3fb_shift_bpp(info->var.bits_per_pixel, |
1078 | pm3fb_Shiftbpp(l_fb_info, | 229 | hbend)); |
1079 | l_fb_info->current_par->depth, | 230 | PM3_SLOW_WRITE_REG(par, PM3ScreenStride, |
1080 | l_fb_info->current_par->hbend)); | 231 | pm3fb_shift_bpp(info->var.bits_per_pixel, |
1081 | PM3_SLOW_WRITE_REG(PM3ScreenStride, | 232 | width)); |
1082 | pm3fb_Shiftbpp(l_fb_info, | 233 | PM3_SLOW_WRITE_REG(par, PM3VTotal, vtotal - 1); |
1083 | l_fb_info->current_par->depth, | 234 | PM3_SLOW_WRITE_REG(par, PM3VsEnd, vsend - 1); |
1084 | l_fb_info->current_par->stride)); | 235 | PM3_SLOW_WRITE_REG(par, PM3VsStart, vsstart - 1); |
1085 | PM3_SLOW_WRITE_REG(PM3VTotal, l_fb_info->current_par->vtotal - 1); | 236 | PM3_SLOW_WRITE_REG(par, PM3VbEnd, vbend); |
1086 | PM3_SLOW_WRITE_REG(PM3VsEnd, l_fb_info->current_par->vsend - 1); | 237 | |
1087 | PM3_SLOW_WRITE_REG(PM3VsStart, | 238 | switch (info->var.bits_per_pixel) { |
1088 | l_fb_info->current_par->vsstart - 1); | ||
1089 | PM3_SLOW_WRITE_REG(PM3VbEnd, l_fb_info->current_par->vbend); | ||
1090 | |||
1091 | switch (l_fb_info->current_par->depth) { | ||
1092 | case 8: | 239 | case 8: |
1093 | PM3_SLOW_WRITE_REG(PM3ByAperture1Mode, | 240 | PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode, |
1094 | PM3ByApertureMode_PIXELSIZE_8BIT); | 241 | PM3ByApertureMode_PIXELSIZE_8BIT); |
1095 | PM3_SLOW_WRITE_REG(PM3ByAperture2Mode, | 242 | PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode, |
1096 | PM3ByApertureMode_PIXELSIZE_8BIT); | 243 | PM3ByApertureMode_PIXELSIZE_8BIT); |
1097 | break; | 244 | break; |
1098 | 245 | ||
@@ -1100,15 +247,15 @@ static void pm3fb_write_mode(struct pm3fb_info *l_fb_info) | |||
1100 | case 15: | 247 | case 15: |
1101 | case 16: | 248 | case 16: |
1102 | #ifndef __BIG_ENDIAN | 249 | #ifndef __BIG_ENDIAN |
1103 | PM3_SLOW_WRITE_REG(PM3ByAperture1Mode, | 250 | PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode, |
1104 | PM3ByApertureMode_PIXELSIZE_16BIT); | 251 | PM3ByApertureMode_PIXELSIZE_16BIT); |
1105 | PM3_SLOW_WRITE_REG(PM3ByAperture2Mode, | 252 | PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode, |
1106 | PM3ByApertureMode_PIXELSIZE_16BIT); | 253 | PM3ByApertureMode_PIXELSIZE_16BIT); |
1107 | #else | 254 | #else |
1108 | PM3_SLOW_WRITE_REG(PM3ByAperture1Mode, | 255 | PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode, |
1109 | PM3ByApertureMode_PIXELSIZE_16BIT | | 256 | PM3ByApertureMode_PIXELSIZE_16BIT | |
1110 | PM3ByApertureMode_BYTESWAP_BADC); | 257 | PM3ByApertureMode_BYTESWAP_BADC); |
1111 | PM3_SLOW_WRITE_REG(PM3ByAperture2Mode, | 258 | PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode, |
1112 | PM3ByApertureMode_PIXELSIZE_16BIT | | 259 | PM3ByApertureMode_PIXELSIZE_16BIT | |
1113 | PM3ByApertureMode_BYTESWAP_BADC); | 260 | PM3ByApertureMode_BYTESWAP_BADC); |
1114 | #endif /* ! __BIG_ENDIAN */ | 261 | #endif /* ! __BIG_ENDIAN */ |
@@ -1116,23 +263,23 @@ static void pm3fb_write_mode(struct pm3fb_info *l_fb_info) | |||
1116 | 263 | ||
1117 | case 32: | 264 | case 32: |
1118 | #ifndef __BIG_ENDIAN | 265 | #ifndef __BIG_ENDIAN |
1119 | PM3_SLOW_WRITE_REG(PM3ByAperture1Mode, | 266 | PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode, |
1120 | PM3ByApertureMode_PIXELSIZE_32BIT); | 267 | PM3ByApertureMode_PIXELSIZE_32BIT); |
1121 | PM3_SLOW_WRITE_REG(PM3ByAperture2Mode, | 268 | PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode, |
1122 | PM3ByApertureMode_PIXELSIZE_32BIT); | 269 | PM3ByApertureMode_PIXELSIZE_32BIT); |
1123 | #else | 270 | #else |
1124 | PM3_SLOW_WRITE_REG(PM3ByAperture1Mode, | 271 | PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode, |
1125 | PM3ByApertureMode_PIXELSIZE_32BIT | | 272 | PM3ByApertureMode_PIXELSIZE_32BIT | |
1126 | PM3ByApertureMode_BYTESWAP_DCBA); | 273 | PM3ByApertureMode_BYTESWAP_DCBA); |
1127 | PM3_SLOW_WRITE_REG(PM3ByAperture2Mode, | 274 | PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode, |
1128 | PM3ByApertureMode_PIXELSIZE_32BIT | | 275 | PM3ByApertureMode_PIXELSIZE_32BIT | |
1129 | PM3ByApertureMode_BYTESWAP_DCBA); | 276 | PM3ByApertureMode_BYTESWAP_DCBA); |
1130 | #endif /* ! __BIG_ENDIAN */ | 277 | #endif /* ! __BIG_ENDIAN */ |
1131 | break; | 278 | break; |
1132 | 279 | ||
1133 | default: | 280 | default: |
1134 | DPRINTK(1, "Unsupported depth %d\n", | 281 | DPRINTK("Unsupported depth %d\n", |
1135 | l_fb_info->current_par->depth); | 282 | info->var.bits_per_pixel); |
1136 | break; | 283 | break; |
1137 | } | 284 | } |
1138 | 285 | ||
@@ -1143,95 +290,86 @@ static void pm3fb_write_mode(struct pm3fb_info *l_fb_info) | |||
1143 | * sync options in PM3RD_SyncControl. --rmk | 290 | * sync options in PM3RD_SyncControl. --rmk |
1144 | */ | 291 | */ |
1145 | { | 292 | { |
1146 | unsigned int video = l_fb_info->current_par->video; | 293 | unsigned int video = par->video; |
1147 | 294 | ||
1148 | video &= ~(PM3VideoControl_HSYNC_MASK | | 295 | video &= ~(PM3VideoControl_HSYNC_MASK | |
1149 | PM3VideoControl_VSYNC_MASK); | 296 | PM3VideoControl_VSYNC_MASK); |
1150 | video |= PM3VideoControl_HSYNC_ACTIVE_HIGH | | 297 | video |= PM3VideoControl_HSYNC_ACTIVE_HIGH | |
1151 | PM3VideoControl_VSYNC_ACTIVE_HIGH; | 298 | PM3VideoControl_VSYNC_ACTIVE_HIGH; |
1152 | PM3_SLOW_WRITE_REG(PM3VideoControl, video); | 299 | PM3_SLOW_WRITE_REG(par, PM3VideoControl, video); |
1153 | } | 300 | } |
1154 | PM3_SLOW_WRITE_REG(PM3VClkCtl, | 301 | PM3_SLOW_WRITE_REG(par, PM3VClkCtl, |
1155 | (PM3_READ_REG(PM3VClkCtl) & 0xFFFFFFFC)); | 302 | (PM3_READ_REG(par, PM3VClkCtl) & 0xFFFFFFFC)); |
1156 | PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base); | 303 | PM3_SLOW_WRITE_REG(par, PM3ScreenBase, par->base); |
1157 | PM3_SLOW_WRITE_REG(PM3ChipConfig, | 304 | PM3_SLOW_WRITE_REG(par, PM3ChipConfig, |
1158 | (PM3_READ_REG(PM3ChipConfig) & 0xFFFFFFFD)); | 305 | (PM3_READ_REG(par, PM3ChipConfig) & 0xFFFFFFFD)); |
1159 | 306 | ||
1160 | { | 307 | { |
1161 | unsigned char m; /* ClkPreScale */ | 308 | unsigned char uninitialized_var(m); /* ClkPreScale */ |
1162 | unsigned char n; /* ClkFeedBackScale */ | 309 | unsigned char uninitialized_var(n); /* ClkFeedBackScale */ |
1163 | unsigned char p; /* ClkPostScale */ | 310 | unsigned char uninitialized_var(p); /* ClkPostScale */ |
1164 | (void)pm3fb_CalculateClock(l_fb_info, l_fb_info->current_par->pixclock, PM3_REF_CLOCK, &m, &n, &p); | 311 | unsigned long pixclock = PICOS2KHZ(info->var.pixclock); |
1165 | 312 | ||
1166 | DPRINTK(2, | 313 | (void)pm3fb_calculate_clock(pixclock, &m, &n, &p); |
1167 | "Pixclock: %d, Pre: %d, Feedback: %d, Post: %d\n", | 314 | |
1168 | l_fb_info->current_par->pixclock, (int) m, (int) n, | 315 | DPRINTK("Pixclock: %ld, Pre: %d, Feedback: %d, Post: %d\n", |
1169 | (int) p); | 316 | pixclock, (int) m, (int) n, (int) p); |
1170 | 317 | ||
1171 | PM3_WRITE_DAC_REG(PM3RD_DClk0PreScale, m); | 318 | PM3_WRITE_DAC_REG(par, PM3RD_DClk0PreScale, m); |
1172 | PM3_WRITE_DAC_REG(PM3RD_DClk0FeedbackScale, n); | 319 | PM3_WRITE_DAC_REG(par, PM3RD_DClk0FeedbackScale, n); |
1173 | PM3_WRITE_DAC_REG(PM3RD_DClk0PostScale, p); | 320 | PM3_WRITE_DAC_REG(par, PM3RD_DClk0PostScale, p); |
1174 | } | 321 | } |
1175 | /* | 322 | /* |
1176 | PM3_WRITE_DAC_REG(PM3RD_IndexControl, 0x00); | 323 | PM3_WRITE_DAC_REG(par, PM3RD_IndexControl, 0x00); |
1177 | */ | 324 | */ |
1178 | /* | 325 | /* |
1179 | PM3_SLOW_WRITE_REG(PM3RD_IndexControl, 0x00); | 326 | PM3_SLOW_WRITE_REG(par, PM3RD_IndexControl, 0x00); |
1180 | */ | 327 | */ |
1181 | if ((l_fb_info->current_par->video & PM3VideoControl_HSYNC_MASK) == | 328 | if ((par->video & PM3VideoControl_HSYNC_MASK) == |
1182 | PM3VideoControl_HSYNC_ACTIVE_HIGH) | 329 | PM3VideoControl_HSYNC_ACTIVE_HIGH) |
1183 | tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH; | 330 | tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH; |
1184 | if ((l_fb_info->current_par->video & PM3VideoControl_VSYNC_MASK) == | 331 | if ((par->video & PM3VideoControl_VSYNC_MASK) == |
1185 | PM3VideoControl_VSYNC_ACTIVE_HIGH) | 332 | PM3VideoControl_VSYNC_ACTIVE_HIGH) |
1186 | tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH; | 333 | tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH; |
1187 | |||
1188 | PM3_WRITE_DAC_REG(PM3RD_SyncControl, tempsync); | ||
1189 | DPRINTK(2, "PM3RD_SyncControl: %d\n", tempsync); | ||
1190 | |||
1191 | if (flatpanel[l_fb_info->board_num]) | ||
1192 | { | ||
1193 | PM3_WRITE_DAC_REG(PM3RD_DACControl, PM3RD_DACControl_BLANK_PEDESTAL_ENABLE); | ||
1194 | PM3_WAIT(2); | ||
1195 | PM3_WRITE_REG(PM3VSConfiguration, 0x06); | ||
1196 | PM3_WRITE_REG(0x5a00, 1 << 14); /* black magic... */ | ||
1197 | tempmisc = PM3RD_MiscControl_VSB_OUTPUT_ENABLE; | ||
1198 | } | ||
1199 | else | ||
1200 | PM3_WRITE_DAC_REG(PM3RD_DACControl, 0x00); | ||
1201 | 334 | ||
1202 | switch (l_fb_info->current_par->depth) { | 335 | PM3_WRITE_DAC_REG(par, PM3RD_SyncControl, tempsync); |
336 | DPRINTK("PM3RD_SyncControl: %d\n", tempsync); | ||
337 | |||
338 | PM3_WRITE_DAC_REG(par, PM3RD_DACControl, 0x00); | ||
339 | |||
340 | switch (info->var.bits_per_pixel) { | ||
1203 | case 8: | 341 | case 8: |
1204 | PM3_WRITE_DAC_REG(PM3RD_PixelSize, | 342 | PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, |
1205 | PM3RD_PixelSize_8_BIT_PIXELS); | 343 | PM3RD_PixelSize_8_BIT_PIXELS); |
1206 | PM3_WRITE_DAC_REG(PM3RD_ColorFormat, | 344 | PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, |
1207 | PM3RD_ColorFormat_CI8_COLOR | | 345 | PM3RD_ColorFormat_CI8_COLOR | |
1208 | PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); | 346 | PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); |
1209 | tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; | 347 | tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; |
1210 | break; | 348 | break; |
1211 | case 12: | 349 | case 12: |
1212 | PM3_WRITE_DAC_REG(PM3RD_PixelSize, | 350 | PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, |
1213 | PM3RD_PixelSize_16_BIT_PIXELS); | 351 | PM3RD_PixelSize_16_BIT_PIXELS); |
1214 | PM3_WRITE_DAC_REG(PM3RD_ColorFormat, | 352 | PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, |
1215 | PM3RD_ColorFormat_4444_COLOR | | 353 | PM3RD_ColorFormat_4444_COLOR | |
1216 | PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | | 354 | PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | |
1217 | PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); | 355 | PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); |
1218 | tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | | 356 | tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | |
1219 | PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; | 357 | PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; |
1220 | break; | 358 | break; |
1221 | case 15: | 359 | case 15: |
1222 | PM3_WRITE_DAC_REG(PM3RD_PixelSize, | 360 | PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, |
1223 | PM3RD_PixelSize_16_BIT_PIXELS); | 361 | PM3RD_PixelSize_16_BIT_PIXELS); |
1224 | PM3_WRITE_DAC_REG(PM3RD_ColorFormat, | 362 | PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, |
1225 | PM3RD_ColorFormat_5551_FRONT_COLOR | | 363 | PM3RD_ColorFormat_5551_FRONT_COLOR | |
1226 | PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | | 364 | PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | |
1227 | PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); | 365 | PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); |
1228 | tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | | 366 | tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | |
1229 | PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; | 367 | PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; |
1230 | break; | 368 | break; |
1231 | case 16: | 369 | case 16: |
1232 | PM3_WRITE_DAC_REG(PM3RD_PixelSize, | 370 | PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, |
1233 | PM3RD_PixelSize_16_BIT_PIXELS); | 371 | PM3RD_PixelSize_16_BIT_PIXELS); |
1234 | PM3_WRITE_DAC_REG(PM3RD_ColorFormat, | 372 | PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, |
1235 | PM3RD_ColorFormat_565_FRONT_COLOR | | 373 | PM3RD_ColorFormat_565_FRONT_COLOR | |
1236 | PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | | 374 | PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW | |
1237 | PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); | 375 | PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE); |
@@ -1239,1936 +377,280 @@ static void pm3fb_write_mode(struct pm3fb_info *l_fb_info) | |||
1239 | PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; | 377 | PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; |
1240 | break; | 378 | break; |
1241 | case 32: | 379 | case 32: |
1242 | PM3_WRITE_DAC_REG(PM3RD_PixelSize, | 380 | PM3_WRITE_DAC_REG(par, PM3RD_PixelSize, |
1243 | PM3RD_PixelSize_32_BIT_PIXELS); | 381 | PM3RD_PixelSize_32_BIT_PIXELS); |
1244 | PM3_WRITE_DAC_REG(PM3RD_ColorFormat, | 382 | PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat, |
1245 | PM3RD_ColorFormat_8888_COLOR | | 383 | PM3RD_ColorFormat_8888_COLOR | |
1246 | PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); | 384 | PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW); |
1247 | tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | | 385 | tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE | |
1248 | PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; | 386 | PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE; |
1249 | break; | 387 | break; |
1250 | } | 388 | } |
1251 | PM3_WRITE_DAC_REG(PM3RD_MiscControl, tempmisc); | 389 | PM3_WRITE_DAC_REG(par, PM3RD_MiscControl, tempmisc); |
1252 | |||
1253 | PM3_SHOW_CUR_MODE; | ||
1254 | } | 390 | } |
1255 | 391 | ||
1256 | static void pm3fb_read_mode(struct pm3fb_info *l_fb_info, | 392 | /* |
1257 | struct pm3fb_par *curpar) | 393 | * hardware independent functions |
1258 | { | 394 | */ |
1259 | unsigned long pixsize1, pixsize2, clockused; | 395 | int pm3fb_init(void); |
1260 | unsigned long pre, feedback, post; | 396 | int pm3fb_setup(char*); |
1261 | |||
1262 | DTRACE; | ||
1263 | |||
1264 | clockused = PM3_READ_REG(PM3VClkCtl); | ||
1265 | 397 | ||
1266 | switch (clockused) { | 398 | static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) |
1267 | case 3: | 399 | { |
1268 | pre = PM3_READ_DAC_REG(PM3RD_DClk3PreScale); | 400 | u32 lpitch; |
1269 | feedback = PM3_READ_DAC_REG(PM3RD_DClk3FeedbackScale); | ||
1270 | post = PM3_READ_DAC_REG(PM3RD_DClk3PostScale); | ||
1271 | 401 | ||
1272 | DPRINTK(2, | 402 | var->transp.offset = 0; |
1273 | "DClk3 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n", | 403 | var->transp.length = 0; |
1274 | pre, feedback, post, PM3_SCALE_TO_CLOCK(pre, | 404 | switch(var->bits_per_pixel) { |
1275 | feedback, | 405 | case 8: |
1276 | post)); | 406 | var->red.length = var->green.length = var->blue.length = 8; |
407 | var->red.offset = var->green.offset = var->blue.offset = 0; | ||
1277 | break; | 408 | break; |
1278 | case 2: | 409 | case 12: |
1279 | pre = PM3_READ_DAC_REG(PM3RD_DClk2PreScale); | 410 | var->red.offset = 8; |
1280 | feedback = PM3_READ_DAC_REG(PM3RD_DClk2FeedbackScale); | 411 | var->red.length = 4; |
1281 | post = PM3_READ_DAC_REG(PM3RD_DClk2PostScale); | 412 | var->green.offset = 4; |
1282 | 413 | var->green.length = 4; | |
1283 | DPRINTK(2, | 414 | var->blue.offset = 0; |
1284 | "DClk2 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n", | 415 | var->blue.length = 4; |
1285 | pre, feedback, post, PM3_SCALE_TO_CLOCK(pre, | 416 | var->transp.offset = 12; |
1286 | feedback, | 417 | var->transp.length = 4; |
1287 | post)); | 418 | case 15: |
419 | var->red.offset = 10; | ||
420 | var->red.length = 5; | ||
421 | var->green.offset = 5; | ||
422 | var->green.length = 5; | ||
423 | var->blue.offset = 0; | ||
424 | var->blue.length = 5; | ||
425 | var->transp.offset = 15; | ||
426 | var->transp.length = 1; | ||
1288 | break; | 427 | break; |
1289 | case 1: | 428 | case 16: |
1290 | pre = PM3_READ_DAC_REG(PM3RD_DClk1PreScale); | 429 | var->red.offset = 11; |
1291 | feedback = PM3_READ_DAC_REG(PM3RD_DClk1FeedbackScale); | 430 | var->red.length = 5; |
1292 | post = PM3_READ_DAC_REG(PM3RD_DClk1PostScale); | 431 | var->green.offset = 5; |
1293 | 432 | var->green.length = 6; | |
1294 | DPRINTK(2, | 433 | var->blue.offset = 0; |
1295 | "DClk1 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n", | 434 | var->blue.length = 5; |
1296 | pre, feedback, post, PM3_SCALE_TO_CLOCK(pre, | ||
1297 | feedback, | ||
1298 | post)); | ||
1299 | break; | 435 | break; |
1300 | case 0: | 436 | case 32: |
1301 | pre = PM3_READ_DAC_REG(PM3RD_DClk0PreScale); | 437 | var->transp.offset = 24; |
1302 | feedback = PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale); | 438 | var->transp.length = 8; |
1303 | post = PM3_READ_DAC_REG(PM3RD_DClk0PostScale); | 439 | var->red.offset = 16; |
1304 | 440 | var->green.offset = 8; | |
1305 | DPRINTK(2, | 441 | var->blue.offset = 0; |
1306 | "DClk0 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n", | 442 | var->red.length = var->green.length = var->blue.length = 8; |
1307 | pre, feedback, post, PM3_SCALE_TO_CLOCK(pre, | ||
1308 | feedback, | ||
1309 | post)); | ||
1310 | break; | 443 | break; |
1311 | default: | 444 | default: |
1312 | pre = feedback = post = 0; | 445 | DPRINTK("depth not supported: %u\n", var->bits_per_pixel); |
1313 | DPRINTK(1, "Unknowk D clock used : %ld\n", clockused); | 446 | return -EINVAL; |
1314 | break; | ||
1315 | } | ||
1316 | |||
1317 | curpar->pixclock = PM3_SCALE_TO_CLOCK(pre, feedback, post); | ||
1318 | |||
1319 | pixsize1 = | ||
1320 | PM3ByApertureMode_PIXELSIZE_MASK & | ||
1321 | (PM3_READ_REG(PM3ByAperture1Mode)); | ||
1322 | pixsize2 = | ||
1323 | PM3ByApertureMode_PIXELSIZE_MASK & | ||
1324 | (PM3_READ_REG(PM3ByAperture2Mode)); | ||
1325 | |||
1326 | DASSERT((pixsize1 == pixsize2), | ||
1327 | "pixsize the same in both aperture\n"); | ||
1328 | |||
1329 | if (pixsize1 & PM3ByApertureMode_PIXELSIZE_32BIT) | ||
1330 | curpar->depth = 32; | ||
1331 | else if (pixsize1 & PM3ByApertureMode_PIXELSIZE_16BIT) | ||
1332 | { | ||
1333 | curpar->depth = 16; | ||
1334 | } | ||
1335 | else | ||
1336 | curpar->depth = 8; | ||
1337 | |||
1338 | /* not sure if I need to add one on the next ; it give better result with */ | ||
1339 | curpar->htotal = | ||
1340 | pm3fb_Unshiftbpp(l_fb_info, curpar->depth, | ||
1341 | 1 + PM3_READ_REG(PM3HTotal)); | ||
1342 | curpar->hsend = | ||
1343 | pm3fb_Unshiftbpp(l_fb_info, curpar->depth, | ||
1344 | PM3_READ_REG(PM3HsEnd)); | ||
1345 | curpar->hsstart = | ||
1346 | pm3fb_Unshiftbpp(l_fb_info, curpar->depth, | ||
1347 | PM3_READ_REG(PM3HsStart)); | ||
1348 | curpar->hbend = | ||
1349 | pm3fb_Unshiftbpp(l_fb_info, curpar->depth, | ||
1350 | PM3_READ_REG(PM3HbEnd)); | ||
1351 | |||
1352 | curpar->stride = | ||
1353 | pm3fb_Unshiftbpp(l_fb_info, curpar->depth, | ||
1354 | PM3_READ_REG(PM3ScreenStride)); | ||
1355 | |||
1356 | curpar->vtotal = 1 + PM3_READ_REG(PM3VTotal); | ||
1357 | curpar->vsend = 1 + PM3_READ_REG(PM3VsEnd); | ||
1358 | curpar->vsstart = 1 + PM3_READ_REG(PM3VsStart); | ||
1359 | curpar->vbend = PM3_READ_REG(PM3VbEnd); | ||
1360 | |||
1361 | curpar->video = PM3_READ_REG(PM3VideoControl); | ||
1362 | |||
1363 | curpar->base = PM3_READ_REG(PM3ScreenBase); | ||
1364 | curpar->width = curpar->htotal - curpar->hbend; /* make virtual == displayed resolution */ | ||
1365 | curpar->height = curpar->vtotal - curpar->vbend; | ||
1366 | |||
1367 | DPRINTK(2, "Found : %d * %d, %d Khz, stride is %08x\n", | ||
1368 | curpar->width, curpar->height, curpar->pixclock, | ||
1369 | curpar->stride); | ||
1370 | } | ||
1371 | |||
1372 | static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info) | ||
1373 | { | ||
1374 | unsigned long memsize = 0, tempBypass, i, temp1, temp2; | ||
1375 | u16 subvendor, subdevice; | ||
1376 | pm3fb_timing_result ptr; | ||
1377 | |||
1378 | DTRACE; | ||
1379 | |||
1380 | l_fb_info->fb_size = 64 * 1024 * 1024; /* pm3 aperture always 64 MB */ | ||
1381 | pm3fb_mapIO(l_fb_info); /* temporary map IO */ | ||
1382 | |||
1383 | DASSERT((l_fb_info->vIOBase != NULL), | ||
1384 | "IO successfully mapped before mem detect\n"); | ||
1385 | DASSERT((l_fb_info->v_fb != NULL), | ||
1386 | "FB successfully mapped before mem detect\n"); | ||
1387 | |||
1388 | /* card-specific stuff, *before* accessing *any* FB memory */ | ||
1389 | if ((!pci_read_config_word | ||
1390 | (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor)) | ||
1391 | && | ||
1392 | (!pci_read_config_word | ||
1393 | (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) { | ||
1394 | i = 0; l_fb_info->board_type = 0; | ||
1395 | while ((cardbase[i].cardname[0]) && !(l_fb_info->board_type)) { | ||
1396 | if ((cardbase[i].subvendor == subvendor) && | ||
1397 | (cardbase[i].subdevice == subdevice) && | ||
1398 | (cardbase[i].func == PCI_FUNC(l_fb_info->dev->devfn))) { | ||
1399 | DPRINTK(2, "Card #%ld is an %s\n", | ||
1400 | l_fb_info->board_num, | ||
1401 | cardbase[i].cardname); | ||
1402 | if (cardbase[i].specific_setup) | ||
1403 | cardbase[i].specific_setup(l_fb_info); | ||
1404 | l_fb_info->board_type = i; | ||
1405 | } | ||
1406 | i++; | ||
1407 | } | ||
1408 | if (!l_fb_info->board_type) { | ||
1409 | DPRINTK(1, "Card #%ld is an unknown 0x%04x / 0x%04x\n", | ||
1410 | l_fb_info->board_num, subvendor, subdevice); | ||
1411 | } | ||
1412 | } else { | ||
1413 | printk(KERN_ERR "pm3fb: Error: pci_read_config_word failed, board #%ld\n", | ||
1414 | l_fb_info->board_num); | ||
1415 | } | ||
1416 | |||
1417 | if (printtimings) | ||
1418 | pm3fb_show_cur_timing(l_fb_info); | ||
1419 | |||
1420 | /* card-specific setup is done, we preserve the final | ||
1421 | memory timing for future reference */ | ||
1422 | if ((ptr = pm3fb_preserve_memory_timings(l_fb_info)) == pm3fb_timing_problem) { /* memory timings were wrong ! oops.... */ | ||
1423 | return(0); | ||
1424 | } | ||
1425 | |||
1426 | tempBypass = PM3_READ_REG(PM3MemBypassWriteMask); | ||
1427 | |||
1428 | DPRINTK(2, "PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass); | ||
1429 | |||
1430 | PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xFFFFFFFF); | ||
1431 | |||
1432 | /* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */ | ||
1433 | for (i = 0; i < 32; i++) { | ||
1434 | fb_writel(i * 0x00345678, | ||
1435 | (l_fb_info->v_fb + (i * 1048576))); | ||
1436 | mb(); | ||
1437 | temp1 = fb_readl((l_fb_info->v_fb + (i * 1048576))); | ||
1438 | |||
1439 | /* Let's check for wrapover, write will fail at 16MB boundary */ | ||
1440 | if (temp1 == (i * 0x00345678)) | ||
1441 | memsize = i; | ||
1442 | else | ||
1443 | break; | ||
1444 | } | ||
1445 | |||
1446 | DPRINTK(2, "First detect pass already got %ld MB\n", memsize + 1); | ||
1447 | |||
1448 | if (memsize == i) { | ||
1449 | for (i = 0; i < 32; i++) { | ||
1450 | /* Clear first 32MB ; 0 is 0, no need to byteswap */ | ||
1451 | writel(0x0000000, | ||
1452 | (l_fb_info->v_fb + (i * 1048576))); | ||
1453 | mb(); | ||
1454 | } | ||
1455 | |||
1456 | for (i = 32; i < 64; i++) { | ||
1457 | fb_writel(i * 0x00345678, | ||
1458 | (l_fb_info->v_fb + (i * 1048576))); | ||
1459 | mb(); | ||
1460 | temp1 = | ||
1461 | fb_readl((l_fb_info->v_fb + (i * 1048576))); | ||
1462 | temp2 = | ||
1463 | fb_readl((l_fb_info->v_fb + | ||
1464 | ((i - 32) * 1048576))); | ||
1465 | if ((temp1 == (i * 0x00345678)) && (temp2 == 0)) /* different value, different RAM... */ | ||
1466 | memsize = i; | ||
1467 | else | ||
1468 | break; | ||
1469 | } | ||
1470 | } | ||
1471 | |||
1472 | DPRINTK(2, "Second detect pass got %ld MB\n", memsize + 1); | ||
1473 | |||
1474 | PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, tempBypass); | ||
1475 | |||
1476 | pm3fb_unmapIO(l_fb_info); | ||
1477 | memsize = 1048576 * (memsize + 1); | ||
1478 | |||
1479 | DPRINTK(2, "Returning 0x%08lx bytes\n", memsize); | ||
1480 | |||
1481 | if (forcesize[l_fb_info->board_num] && ((forcesize[l_fb_info->board_num] * 1048576) != memsize)) | ||
1482 | { | ||
1483 | printk(KERN_WARNING "pm3fb: mismatch between probed (%ld MB) and specified (%hd MB) memory size, using SPECIFIED !\n", memsize, forcesize[l_fb_info->board_num]); | ||
1484 | memsize = 1048576 * forcesize[l_fb_info->board_num]; | ||
1485 | } | ||
1486 | |||
1487 | l_fb_info->fb_size = memsize; | ||
1488 | |||
1489 | if (ptr == pm3fb_timing_retry) | ||
1490 | { | ||
1491 | printk(KERN_WARNING "pm3fb: retrying memory timings check"); | ||
1492 | if (pm3fb_try_memory_timings(l_fb_info) == pm3fb_timing_problem) | ||
1493 | return(0); | ||
1494 | } | ||
1495 | |||
1496 | return (memsize); | ||
1497 | } | ||
1498 | |||
1499 | static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc) | ||
1500 | { | ||
1501 | int i; | ||
1502 | |||
1503 | DTRACE; | ||
1504 | |||
1505 | for (i = 0; i < (l_fb_info->fb_size / sizeof(u32)) ; i++) /* clear entire FB memory to black */ | ||
1506 | { | ||
1507 | fb_writel(cc, (l_fb_info->v_fb + (i * sizeof(u32)))); | ||
1508 | } | 447 | } |
1509 | } | 448 | var->height = var->width = -1; |
1510 | |||
1511 | static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b) | ||
1512 | { | ||
1513 | int i; | ||
1514 | |||
1515 | DTRACE; | ||
1516 | |||
1517 | for (i = 0; i < 256 ; i++) /* fill color map with white */ | ||
1518 | pm3fb_set_color(l_fb_info, i, r, g, b); | ||
1519 | |||
1520 | } | ||
1521 | |||
1522 | /* common initialisation */ | ||
1523 | static void pm3fb_common_init(struct pm3fb_info *l_fb_info) | ||
1524 | { | ||
1525 | DTRACE; | ||
1526 | |||
1527 | DPRINTK(2, "Initializing board #%ld @ %lx\n", l_fb_info->board_num, | ||
1528 | (unsigned long) l_fb_info); | ||
1529 | |||
1530 | strcpy(l_fb_info->gen.info.modename, permedia3_name); | ||
1531 | disp[l_fb_info->board_num].scrollmode = 0; /* SCROLL_YNOMOVE; *//* 0 means "let fbcon choose" */ | ||
1532 | l_fb_info->gen.parsize = sizeof(struct pm3fb_par); | ||
1533 | l_fb_info->gen.info.changevar = NULL; | ||
1534 | l_fb_info->gen.info.fbops = &pm3fb_ops; | ||
1535 | l_fb_info->gen.info.disp = &(disp[l_fb_info->board_num]); | ||
1536 | if (fontn[l_fb_info->board_num][0]) | ||
1537 | strcpy(l_fb_info->gen.info.fontname, | ||
1538 | fontn[l_fb_info->board_num]); | ||
1539 | l_fb_info->gen.info.switch_con = &fbgen_switch; | ||
1540 | l_fb_info->gen.info.updatevar = &fbgen_update_var; /* */ | ||
1541 | l_fb_info->gen.info.flags = FBINFO_FLAG_DEFAULT; | ||
1542 | |||
1543 | pm3fb_mapIO(l_fb_info); | ||
1544 | |||
1545 | pm3fb_clear_memory(l_fb_info, 0); | ||
1546 | pm3fb_clear_colormap(l_fb_info, 0, 0, 0); | ||
1547 | |||
1548 | (void) fbgen_get_var(&(disp[l_fb_info->board_num]).var, -1, | ||
1549 | &l_fb_info->gen.info); | ||
1550 | 449 | ||
1551 | if (depth[l_fb_info->board_num]) /* override mode-defined depth */ | 450 | if (var->xres != var->xres_virtual) { |
1552 | { | 451 | DPRINTK("virtual x resolution != physical x resolution not supported\n"); |
1553 | pm3fb_encode_depth(&(disp[l_fb_info->board_num]).var, depth[l_fb_info->board_num]); | 452 | return -EINVAL; |
1554 | (disp[l_fb_info->board_num]).var.bits_per_pixel = depth2bpp(depth[l_fb_info->board_num]); | ||
1555 | } | 453 | } |
1556 | 454 | ||
1557 | (void) fbgen_do_set_var(&(disp[l_fb_info->board_num]).var, 1, | 455 | if (var->yres > var->yres_virtual) { |
1558 | &l_fb_info->gen); | 456 | DPRINTK("virtual y resolution < physical y resolution not possible\n"); |
1559 | 457 | return -EINVAL; | |
1560 | fbgen_set_disp(-1, &l_fb_info->gen); | ||
1561 | |||
1562 | do_install_cmap(0, &l_fb_info->gen.info); | ||
1563 | |||
1564 | if (register_framebuffer(&l_fb_info->gen.info) < 0) { | ||
1565 | DPRINTK(1, "Couldn't register framebuffer\n"); | ||
1566 | return; | ||
1567 | } | 458 | } |
1568 | 459 | ||
1569 | PM3_WRITE_DAC_REG(PM3RD_CursorMode, | 460 | if (var->xoffset) { |
1570 | PM3RD_CursorMode_CURSOR_DISABLE); | 461 | DPRINTK("xoffset not supported\n"); |
1571 | 462 | return -EINVAL; | |
1572 | PM3_SHOW_CUR_MODE; | ||
1573 | |||
1574 | pm3fb_write_mode(l_fb_info); | ||
1575 | |||
1576 | printk("fb%d: %s, using %uK of video memory (%s)\n", | ||
1577 | l_fb_info->gen.info.node, | ||
1578 | permedia3_name, (u32) (l_fb_info->fb_size >> 10), | ||
1579 | cardbase[l_fb_info->board_type].cardname); | ||
1580 | } | ||
1581 | |||
1582 | /* **************************************************** */ | ||
1583 | /* ***** accelerated permedia3-specific functions ***** */ | ||
1584 | /* **************************************************** */ | ||
1585 | #ifdef PM3FB_USE_ACCEL | ||
1586 | static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info) | ||
1587 | { | ||
1588 | DTRACE; | ||
1589 | |||
1590 | PM3_SLOW_WRITE_REG(PM3FilterMode, PM3FilterModeSync); | ||
1591 | PM3_SLOW_WRITE_REG(PM3Sync, 0); | ||
1592 | mb(); | ||
1593 | do { | ||
1594 | while ((PM3_READ_REG(PM3OutFIFOWords)) == 0); | ||
1595 | rmb(); | ||
1596 | } while ((PM3_READ_REG(PM3OutputFifo)) != PM3Sync_Tag); | ||
1597 | } | ||
1598 | |||
1599 | static void pm3fb_init_engine(struct pm3fb_info *l_fb_info) | ||
1600 | { | ||
1601 | PM3_SLOW_WRITE_REG(PM3FilterMode, PM3FilterModeSync); | ||
1602 | PM3_SLOW_WRITE_REG(PM3StatisticMode, 0x0); | ||
1603 | PM3_SLOW_WRITE_REG(PM3DeltaMode, 0x0); | ||
1604 | PM3_SLOW_WRITE_REG(PM3RasterizerMode, 0x0); | ||
1605 | PM3_SLOW_WRITE_REG(PM3ScissorMode, 0x0); | ||
1606 | PM3_SLOW_WRITE_REG(PM3LineStippleMode, 0x0); | ||
1607 | PM3_SLOW_WRITE_REG(PM3AreaStippleMode, 0x0); | ||
1608 | PM3_SLOW_WRITE_REG(PM3GIDMode, 0x0); | ||
1609 | PM3_SLOW_WRITE_REG(PM3DepthMode, 0x0); | ||
1610 | PM3_SLOW_WRITE_REG(PM3StencilMode, 0x0); | ||
1611 | PM3_SLOW_WRITE_REG(PM3StencilData, 0x0); | ||
1612 | PM3_SLOW_WRITE_REG(PM3ColorDDAMode, 0x0); | ||
1613 | PM3_SLOW_WRITE_REG(PM3TextureCoordMode, 0x0); | ||
1614 | PM3_SLOW_WRITE_REG(PM3TextureIndexMode0, 0x0); | ||
1615 | PM3_SLOW_WRITE_REG(PM3TextureIndexMode1, 0x0); | ||
1616 | PM3_SLOW_WRITE_REG(PM3TextureReadMode, 0x0); | ||
1617 | PM3_SLOW_WRITE_REG(PM3LUTMode, 0x0); | ||
1618 | PM3_SLOW_WRITE_REG(PM3TextureFilterMode, 0x0); | ||
1619 | PM3_SLOW_WRITE_REG(PM3TextureCompositeMode, 0x0); | ||
1620 | PM3_SLOW_WRITE_REG(PM3TextureApplicationMode, 0x0); | ||
1621 | PM3_SLOW_WRITE_REG(PM3TextureCompositeColorMode1, 0x0); | ||
1622 | PM3_SLOW_WRITE_REG(PM3TextureCompositeAlphaMode1, 0x0); | ||
1623 | PM3_SLOW_WRITE_REG(PM3TextureCompositeColorMode0, 0x0); | ||
1624 | PM3_SLOW_WRITE_REG(PM3TextureCompositeAlphaMode0, 0x0); | ||
1625 | PM3_SLOW_WRITE_REG(PM3FogMode, 0x0); | ||
1626 | PM3_SLOW_WRITE_REG(PM3ChromaTestMode, 0x0); | ||
1627 | PM3_SLOW_WRITE_REG(PM3AlphaTestMode, 0x0); | ||
1628 | PM3_SLOW_WRITE_REG(PM3AntialiasMode, 0x0); | ||
1629 | PM3_SLOW_WRITE_REG(PM3YUVMode, 0x0); | ||
1630 | PM3_SLOW_WRITE_REG(PM3AlphaBlendColorMode, 0x0); | ||
1631 | PM3_SLOW_WRITE_REG(PM3AlphaBlendAlphaMode, 0x0); | ||
1632 | PM3_SLOW_WRITE_REG(PM3DitherMode, 0x0); | ||
1633 | PM3_SLOW_WRITE_REG(PM3LogicalOpMode, 0x0); | ||
1634 | PM3_SLOW_WRITE_REG(PM3RouterMode, 0x0); | ||
1635 | PM3_SLOW_WRITE_REG(PM3Window, 0x0); | ||
1636 | |||
1637 | PM3_SLOW_WRITE_REG(PM3Config2D, 0x0); | ||
1638 | |||
1639 | PM3_SLOW_WRITE_REG(PM3SpanColorMask, 0xffffffff); | ||
1640 | |||
1641 | PM3_SLOW_WRITE_REG(PM3XBias, 0x0); | ||
1642 | PM3_SLOW_WRITE_REG(PM3YBias, 0x0); | ||
1643 | PM3_SLOW_WRITE_REG(PM3DeltaControl, 0x0); | ||
1644 | |||
1645 | PM3_SLOW_WRITE_REG(PM3BitMaskPattern, 0xffffffff); | ||
1646 | |||
1647 | PM3_SLOW_WRITE_REG(PM3FBDestReadEnables, | ||
1648 | PM3FBDestReadEnables_E(0xff) | | ||
1649 | PM3FBDestReadEnables_R(0xff) | | ||
1650 | PM3FBDestReadEnables_ReferenceAlpha(0xff)); | ||
1651 | PM3_SLOW_WRITE_REG(PM3FBDestReadBufferAddr0, 0x0); | ||
1652 | PM3_SLOW_WRITE_REG(PM3FBDestReadBufferOffset0, 0x0); | ||
1653 | PM3_SLOW_WRITE_REG(PM3FBDestReadBufferWidth0, | ||
1654 | PM3FBDestReadBufferWidth_Width(l_fb_info-> | ||
1655 | current_par-> | ||
1656 | width)); | ||
1657 | |||
1658 | PM3_SLOW_WRITE_REG(PM3FBDestReadMode, | ||
1659 | PM3FBDestReadMode_ReadEnable | | ||
1660 | PM3FBDestReadMode_Enable0); | ||
1661 | PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferAddr, 0x0); | ||
1662 | PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferOffset, 0x0); | ||
1663 | PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferWidth, | ||
1664 | PM3FBSourceReadBufferWidth_Width(l_fb_info-> | ||
1665 | current_par-> | ||
1666 | width)); | ||
1667 | PM3_SLOW_WRITE_REG(PM3FBSourceReadMode, | ||
1668 | PM3FBSourceReadMode_Blocking | | ||
1669 | PM3FBSourceReadMode_ReadEnable); | ||
1670 | |||
1671 | { | ||
1672 | unsigned long rm = 1; | ||
1673 | switch (l_fb_info->current_par->depth) { | ||
1674 | case 8: | ||
1675 | PM3_SLOW_WRITE_REG(PM3PixelSize, | ||
1676 | PM3PixelSize_GLOBAL_8BIT); | ||
1677 | break; | ||
1678 | case 12: | ||
1679 | case 15: | ||
1680 | case 16: | ||
1681 | PM3_SLOW_WRITE_REG(PM3PixelSize, | ||
1682 | PM3PixelSize_GLOBAL_16BIT); | ||
1683 | break; | ||
1684 | case 32: | ||
1685 | PM3_SLOW_WRITE_REG(PM3PixelSize, | ||
1686 | PM3PixelSize_GLOBAL_32BIT); | ||
1687 | break; | ||
1688 | default: | ||
1689 | DPRINTK(1, "Unsupported depth %d\n", | ||
1690 | l_fb_info->current_par->depth); | ||
1691 | break; | ||
1692 | } | ||
1693 | PM3_SLOW_WRITE_REG(PM3RasterizerMode, rm); | ||
1694 | } | 463 | } |
1695 | 464 | ||
1696 | PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xffffffff); | 465 | if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { |
1697 | PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xffffffff); | 466 | DPRINTK("interlace not supported\n"); |
1698 | PM3_SLOW_WRITE_REG(PM3FBWriteMode, | 467 | return -EINVAL; |
1699 | PM3FBWriteMode_WriteEnable | | ||
1700 | PM3FBWriteMode_OpaqueSpan | | ||
1701 | PM3FBWriteMode_Enable0); | ||
1702 | PM3_SLOW_WRITE_REG(PM3FBWriteBufferAddr0, 0x0); | ||
1703 | PM3_SLOW_WRITE_REG(PM3FBWriteBufferOffset0, 0x0); | ||
1704 | PM3_SLOW_WRITE_REG(PM3FBWriteBufferWidth0, | ||
1705 | PM3FBWriteBufferWidth_Width(l_fb_info-> | ||
1706 | current_par-> | ||
1707 | width)); | ||
1708 | |||
1709 | PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 0x0); | ||
1710 | { | ||
1711 | unsigned long sofb = (8UL * l_fb_info->fb_size) / | ||
1712 | ((depth2bpp(l_fb_info->current_par->depth)) | ||
1713 | * l_fb_info->current_par->width); /* size in lines of FB */ | ||
1714 | if (sofb > 4095) | ||
1715 | PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 4095); | ||
1716 | else | ||
1717 | PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, sofb); | ||
1718 | |||
1719 | switch (l_fb_info->current_par->depth) { | ||
1720 | case 8: | ||
1721 | PM3_SLOW_WRITE_REG(PM3DitherMode, | ||
1722 | (1 << 10) | (2 << 3)); | ||
1723 | break; | ||
1724 | case 12: | ||
1725 | case 15: | ||
1726 | case 16: | ||
1727 | PM3_SLOW_WRITE_REG(PM3DitherMode, | ||
1728 | (1 << 10) | (1 << 3)); | ||
1729 | break; | ||
1730 | case 32: | ||
1731 | PM3_SLOW_WRITE_REG(PM3DitherMode, | ||
1732 | (1 << 10) | (0 << 3)); | ||
1733 | break; | ||
1734 | default: | ||
1735 | DPRINTK(1, "Unsupported depth %d\n", | ||
1736 | l_fb_info->current_par->depth); | ||
1737 | break; | ||
1738 | } | ||
1739 | } | 468 | } |
1740 | 469 | ||
1741 | PM3_SLOW_WRITE_REG(PM3dXDom, 0x0); | 470 | var->xres = (var->xres + 31) & ~31; /* could sometimes be 8 */ |
1742 | PM3_SLOW_WRITE_REG(PM3dXSub, 0x0); | 471 | lpitch = var->xres * ((var->bits_per_pixel + 7)>>3); |
1743 | PM3_SLOW_WRITE_REG(PM3dY, (1 << 16)); | ||
1744 | PM3_SLOW_WRITE_REG(PM3StartXDom, 0x0); | ||
1745 | PM3_SLOW_WRITE_REG(PM3StartXSub, 0x0); | ||
1746 | PM3_SLOW_WRITE_REG(PM3StartY, 0x0); | ||
1747 | PM3_SLOW_WRITE_REG(PM3Count, 0x0); | ||
1748 | |||
1749 | /* Disable LocalBuffer. better safe than sorry */ | ||
1750 | PM3_SLOW_WRITE_REG(PM3LBDestReadMode, 0x0); | ||
1751 | PM3_SLOW_WRITE_REG(PM3LBDestReadEnables, 0x0); | ||
1752 | PM3_SLOW_WRITE_REG(PM3LBSourceReadMode, 0x0); | ||
1753 | PM3_SLOW_WRITE_REG(PM3LBWriteMode, 0x0); | ||
1754 | |||
1755 | pm3fb_wait_pm3(l_fb_info); | ||
1756 | } | ||
1757 | 472 | ||
1758 | #ifdef FBCON_HAS_CFB32 | 473 | if (var->xres < 200 || var->xres > 2048) { |
1759 | static void pm3fb_cfb32_clear(struct vc_data *conp, | 474 | DPRINTK("width not supported: %u\n", var->xres); |
1760 | struct display *p, | 475 | return -EINVAL; |
1761 | int sy, int sx, int height, int width) | ||
1762 | { | ||
1763 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; | ||
1764 | u32 c; | ||
1765 | |||
1766 | DTRACE; | ||
1767 | |||
1768 | sx = sx * fontwidth(p); | ||
1769 | width = width * fontwidth(p); | ||
1770 | sy = sy * fontheight(p); | ||
1771 | height = height * fontheight(p); | ||
1772 | c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)]; | ||
1773 | |||
1774 | /* block fills in 32bpp are hard, but in low res (width <= 1600 :-) | ||
1775 | we can use 16bpp operations, but not if NoWriteMask is on (SDRAM) */ | ||
1776 | if ((l_fb_info->current_par->width > 1600) || | ||
1777 | (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)) { | ||
1778 | PM3_WAIT(4); | ||
1779 | |||
1780 | PM3_WRITE_REG(PM3Config2D, | ||
1781 | PM3Config2D_UseConstantSource | | ||
1782 | PM3Config2D_ForegroundROPEnable | | ||
1783 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
1784 | PM3Config2D_FBWriteEnable); | ||
1785 | |||
1786 | PM3_WRITE_REG(PM3ForegroundColor, c); | ||
1787 | |||
1788 | PM3_WRITE_REG(PM3RectanglePosition, | ||
1789 | (PM3RectanglePosition_XOffset(sx)) | | ||
1790 | (PM3RectanglePosition_YOffset(sy))); | ||
1791 | |||
1792 | PM3_WRITE_REG(PM3Render2D, | ||
1793 | PM3Render2D_XPositive | | ||
1794 | PM3Render2D_YPositive | | ||
1795 | PM3Render2D_Operation_Normal | | ||
1796 | PM3Render2D_SpanOperation | | ||
1797 | (PM3Render2D_Width(width)) | | ||
1798 | (PM3Render2D_Height(height))); | ||
1799 | } else { | ||
1800 | PM3_WAIT(8); | ||
1801 | |||
1802 | PM3_WRITE_REG(PM3FBBlockColor, c); | ||
1803 | |||
1804 | PM3_WRITE_REG(PM3PixelSize, PM3PixelSize_GLOBAL_16BIT); | ||
1805 | |||
1806 | PM3_WRITE_REG(PM3FBWriteBufferWidth0, | ||
1807 | PM3FBWriteBufferWidth_Width(l_fb_info-> | ||
1808 | current_par-> | ||
1809 | width << 1)); | ||
1810 | |||
1811 | PM3_WRITE_REG(PM3Config2D, | ||
1812 | PM3Config2D_UseConstantSource | | ||
1813 | PM3Config2D_ForegroundROPEnable | | ||
1814 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
1815 | PM3Config2D_FBWriteEnable); | ||
1816 | |||
1817 | PM3_WRITE_REG(PM3RectanglePosition, | ||
1818 | (PM3RectanglePosition_XOffset(sx << 1)) | | ||
1819 | (PM3RectanglePosition_YOffset(sy))); | ||
1820 | |||
1821 | PM3_WRITE_REG(PM3Render2D, | ||
1822 | PM3Render2D_XPositive | | ||
1823 | PM3Render2D_YPositive | | ||
1824 | PM3Render2D_Operation_Normal | | ||
1825 | (PM3Render2D_Width(width << 1)) | | ||
1826 | (PM3Render2D_Height(height))); | ||
1827 | |||
1828 | PM3_WRITE_REG(PM3FBWriteBufferWidth0, | ||
1829 | PM3FBWriteBufferWidth_Width(l_fb_info-> | ||
1830 | current_par-> | ||
1831 | width)); | ||
1832 | |||
1833 | PM3_WRITE_REG(PM3PixelSize, PM3PixelSize_GLOBAL_32BIT); | ||
1834 | } | 476 | } |
1835 | 477 | ||
1836 | pm3fb_wait_pm3(l_fb_info); | 478 | if (var->yres < 200 || var->yres > 4095) { |
1837 | } | 479 | DPRINTK("height not supported: %u\n", var->yres); |
1838 | 480 | return -EINVAL; | |
1839 | static void pm3fb_cfb32_clear_margins(struct vc_data *conp, | ||
1840 | struct display *p, int bottom_only) | ||
1841 | { | ||
1842 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; | ||
1843 | int sx, sy; | ||
1844 | u32 c; | ||
1845 | |||
1846 | DTRACE; | ||
1847 | |||
1848 | sx = conp->vc_cols * fontwidth(p); /* right margin */ | ||
1849 | sy = conp->vc_rows * fontheight(p); /* bottom margin */ | ||
1850 | c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)]; | ||
1851 | |||
1852 | if (!bottom_only) { /* right margin top->bottom */ | ||
1853 | PM3_WAIT(4); | ||
1854 | |||
1855 | PM3_WRITE_REG(PM3Config2D, | ||
1856 | PM3Config2D_UseConstantSource | | ||
1857 | PM3Config2D_ForegroundROPEnable | | ||
1858 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
1859 | PM3Config2D_FBWriteEnable); | ||
1860 | |||
1861 | PM3_WRITE_REG(PM3ForegroundColor, c); | ||
1862 | |||
1863 | PM3_WRITE_REG(PM3RectanglePosition, | ||
1864 | (PM3RectanglePosition_XOffset | ||
1865 | (p->var.xoffset + | ||
1866 | sx)) | (PM3RectanglePosition_YOffset(p-> | ||
1867 | var. | ||
1868 | yoffset))); | ||
1869 | |||
1870 | PM3_WRITE_REG(PM3Render2D, | ||
1871 | PM3Render2D_XPositive | | ||
1872 | PM3Render2D_YPositive | | ||
1873 | PM3Render2D_Operation_Normal | | ||
1874 | PM3Render2D_SpanOperation | | ||
1875 | (PM3Render2D_Width(p->var.xres - sx)) | | ||
1876 | (PM3Render2D_Height(p->var.yres))); | ||
1877 | } | 481 | } |
1878 | 482 | ||
1879 | /* bottom margin left -> right */ | 483 | if (lpitch * var->yres_virtual > info->fix.smem_len) { |
1880 | PM3_WAIT(4); | 484 | DPRINTK("no memory for screen (%ux%ux%u)\n", |
1881 | 485 | var->xres, var->yres_virtual, var->bits_per_pixel); | |
1882 | PM3_WRITE_REG(PM3Config2D, | 486 | return -EINVAL; |
1883 | PM3Config2D_UseConstantSource | | ||
1884 | PM3Config2D_ForegroundROPEnable | | ||
1885 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
1886 | PM3Config2D_FBWriteEnable); | ||
1887 | |||
1888 | PM3_WRITE_REG(PM3ForegroundColor, c); | ||
1889 | |||
1890 | PM3_WRITE_REG(PM3RectanglePosition, | ||
1891 | (PM3RectanglePosition_XOffset(p->var.xoffset)) | | ||
1892 | (PM3RectanglePosition_YOffset(p->var.yoffset + sy))); | ||
1893 | |||
1894 | PM3_WRITE_REG(PM3Render2D, | ||
1895 | PM3Render2D_XPositive | | ||
1896 | PM3Render2D_YPositive | | ||
1897 | PM3Render2D_Operation_Normal | | ||
1898 | PM3Render2D_SpanOperation | | ||
1899 | (PM3Render2D_Width(p->var.xres)) | | ||
1900 | (PM3Render2D_Height(p->var.yres - sy))); | ||
1901 | |||
1902 | pm3fb_wait_pm3(l_fb_info); | ||
1903 | } | ||
1904 | #endif /* FBCON_HAS_CFB32 */ | ||
1905 | #ifdef FBCON_HAS_CFB16 | ||
1906 | static void pm3fb_cfb16_clear(struct vc_data *conp, | ||
1907 | struct display *p, | ||
1908 | int sy, int sx, int height, int width) | ||
1909 | { | ||
1910 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; | ||
1911 | u32 c; | ||
1912 | |||
1913 | DTRACE; | ||
1914 | |||
1915 | sx = sx * fontwidth(p); | ||
1916 | width = width * fontwidth(p); | ||
1917 | sy = sy * fontheight(p); | ||
1918 | height = height * fontheight(p); | ||
1919 | c = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)]; | ||
1920 | c = c | (c << 16); | ||
1921 | |||
1922 | PM3_WAIT(4); | ||
1923 | |||
1924 | if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) | ||
1925 | PM3_WRITE_REG(PM3ForegroundColor, c); | ||
1926 | else | ||
1927 | PM3_WRITE_REG(PM3FBBlockColor, c); | ||
1928 | |||
1929 | PM3_WRITE_REG(PM3Config2D, | ||
1930 | PM3Config2D_UseConstantSource | | ||
1931 | PM3Config2D_ForegroundROPEnable | | ||
1932 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
1933 | PM3Config2D_FBWriteEnable); | ||
1934 | |||
1935 | PM3_WRITE_REG(PM3RectanglePosition, | ||
1936 | (PM3RectanglePosition_XOffset(sx)) | | ||
1937 | (PM3RectanglePosition_YOffset(sy))); | ||
1938 | |||
1939 | if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) | ||
1940 | PM3_WRITE_REG(PM3Render2D, | ||
1941 | PM3Render2D_XPositive | | ||
1942 | PM3Render2D_YPositive | | ||
1943 | PM3Render2D_Operation_Normal | | ||
1944 | PM3Render2D_SpanOperation | | ||
1945 | (PM3Render2D_Width(width)) | | ||
1946 | (PM3Render2D_Height(height))); | ||
1947 | else | ||
1948 | PM3_WRITE_REG(PM3Render2D, | ||
1949 | PM3Render2D_XPositive | | ||
1950 | PM3Render2D_YPositive | | ||
1951 | PM3Render2D_Operation_Normal | | ||
1952 | (PM3Render2D_Width(width)) | | ||
1953 | (PM3Render2D_Height(height))); | ||
1954 | |||
1955 | pm3fb_wait_pm3(l_fb_info); | ||
1956 | } | ||
1957 | |||
1958 | static void pm3fb_cfb16_clear_margins(struct vc_data *conp, | ||
1959 | struct display *p, int bottom_only) | ||
1960 | { | ||
1961 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; | ||
1962 | int sx, sy; | ||
1963 | u32 c; | ||
1964 | |||
1965 | DTRACE; | ||
1966 | |||
1967 | sx = conp->vc_cols * fontwidth(p); /* right margin */ | ||
1968 | sy = conp->vc_rows * fontheight(p); /* bottom margin */ | ||
1969 | c = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)]; | ||
1970 | c = c | (c << 16); | ||
1971 | |||
1972 | if (!bottom_only) { /* right margin top->bottom */ | ||
1973 | PM3_WAIT(4); | ||
1974 | |||
1975 | PM3_WRITE_REG(PM3Config2D, | ||
1976 | PM3Config2D_UseConstantSource | | ||
1977 | PM3Config2D_ForegroundROPEnable | | ||
1978 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
1979 | PM3Config2D_FBWriteEnable); | ||
1980 | |||
1981 | if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) | ||
1982 | PM3_WRITE_REG(PM3ForegroundColor, c); | ||
1983 | else | ||
1984 | PM3_WRITE_REG(PM3FBBlockColor, c); | ||
1985 | |||
1986 | PM3_WRITE_REG(PM3RectanglePosition, | ||
1987 | (PM3RectanglePosition_XOffset | ||
1988 | (p->var.xoffset + | ||
1989 | sx)) | (PM3RectanglePosition_YOffset(p-> | ||
1990 | var. | ||
1991 | yoffset))); | ||
1992 | if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) | ||
1993 | PM3_WRITE_REG(PM3Render2D, | ||
1994 | PM3Render2D_XPositive | | ||
1995 | PM3Render2D_YPositive | | ||
1996 | PM3Render2D_Operation_Normal | | ||
1997 | PM3Render2D_SpanOperation | | ||
1998 | (PM3Render2D_Width(p->var.xres - sx)) | | ||
1999 | (PM3Render2D_Height(p->var.yres))); | ||
2000 | else | ||
2001 | PM3_WRITE_REG(PM3Render2D, | ||
2002 | PM3Render2D_XPositive | | ||
2003 | PM3Render2D_YPositive | | ||
2004 | PM3Render2D_Operation_Normal | | ||
2005 | (PM3Render2D_Width(p->var.xres - sx)) | | ||
2006 | (PM3Render2D_Height(p->var.yres))); | ||
2007 | } | 487 | } |
2008 | |||
2009 | /* bottom margin left -> right */ | ||
2010 | PM3_WAIT(4); | ||
2011 | |||
2012 | PM3_WRITE_REG(PM3Config2D, | ||
2013 | PM3Config2D_UseConstantSource | | ||
2014 | PM3Config2D_ForegroundROPEnable | | ||
2015 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
2016 | PM3Config2D_FBWriteEnable); | ||
2017 | |||
2018 | if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) | ||
2019 | PM3_WRITE_REG(PM3ForegroundColor, c); | ||
2020 | else | ||
2021 | PM3_WRITE_REG(PM3FBBlockColor, c); | ||
2022 | |||
2023 | |||
2024 | PM3_WRITE_REG(PM3RectanglePosition, | ||
2025 | (PM3RectanglePosition_XOffset(p->var.xoffset)) | | ||
2026 | (PM3RectanglePosition_YOffset(p->var.yoffset + sy))); | ||
2027 | |||
2028 | if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) | ||
2029 | PM3_WRITE_REG(PM3Render2D, | ||
2030 | PM3Render2D_XPositive | | ||
2031 | PM3Render2D_YPositive | | ||
2032 | PM3Render2D_Operation_Normal | | ||
2033 | PM3Render2D_SpanOperation | | ||
2034 | (PM3Render2D_Width(p->var.xres)) | | ||
2035 | (PM3Render2D_Height(p->var.yres - sy))); | ||
2036 | else | ||
2037 | PM3_WRITE_REG(PM3Render2D, | ||
2038 | PM3Render2D_XPositive | | ||
2039 | PM3Render2D_YPositive | | ||
2040 | PM3Render2D_Operation_Normal | | ||
2041 | (PM3Render2D_Width(p->var.xres)) | | ||
2042 | (PM3Render2D_Height(p->var.yres - sy))); | ||
2043 | |||
2044 | pm3fb_wait_pm3(l_fb_info); | ||
2045 | } | ||
2046 | #endif /* FBCON_HAS_CFB16 */ | ||
2047 | #ifdef FBCON_HAS_CFB8 | ||
2048 | static void pm3fb_cfb8_clear(struct vc_data *conp, | ||
2049 | struct display *p, | ||
2050 | int sy, int sx, int height, int width) | ||
2051 | { | ||
2052 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; | ||
2053 | u32 c; | ||
2054 | |||
2055 | DTRACE; | ||
2056 | |||
2057 | sx = sx * fontwidth(p); | ||
2058 | width = width * fontwidth(p); | ||
2059 | sy = sy * fontheight(p); | ||
2060 | height = height * fontheight(p); | ||
2061 | |||
2062 | c = attr_bgcol_ec(p, conp); | ||
2063 | c |= c << 8; | ||
2064 | c |= c << 16; | ||
2065 | |||
2066 | PM3_WAIT(4); | ||
2067 | |||
2068 | PM3_WRITE_REG(PM3Config2D, | ||
2069 | PM3Config2D_UseConstantSource | | ||
2070 | PM3Config2D_ForegroundROPEnable | | ||
2071 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
2072 | PM3Config2D_FBWriteEnable); | ||
2073 | 488 | ||
2074 | PM3_WRITE_REG(PM3ForegroundColor, c); | 489 | if (PICOS2KHZ(var->pixclock) > PM3_MAX_PIXCLOCK) { |
2075 | 490 | DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock)); | |
2076 | PM3_WRITE_REG(PM3RectanglePosition, | 491 | return -EINVAL; |
2077 | (PM3RectanglePosition_XOffset(sx)) | | ||
2078 | (PM3RectanglePosition_YOffset(sy))); | ||
2079 | |||
2080 | PM3_WRITE_REG(PM3Render2D, | ||
2081 | PM3Render2D_XPositive | | ||
2082 | PM3Render2D_YPositive | | ||
2083 | PM3Render2D_Operation_Normal | | ||
2084 | PM3Render2D_SpanOperation | | ||
2085 | (PM3Render2D_Width(width)) | | ||
2086 | (PM3Render2D_Height(height))); | ||
2087 | |||
2088 | pm3fb_wait_pm3(l_fb_info); | ||
2089 | } | ||
2090 | |||
2091 | static void pm3fb_cfb8_clear_margins(struct vc_data *conp, | ||
2092 | struct display *p, int bottom_only) | ||
2093 | { | ||
2094 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; | ||
2095 | int sx, sy; | ||
2096 | u32 c; | ||
2097 | |||
2098 | DTRACE; | ||
2099 | |||
2100 | sx = conp->vc_cols * fontwidth(p); /* right margin */ | ||
2101 | sy = conp->vc_rows * fontheight(p); /* bottom margin */ | ||
2102 | c = attr_bgcol_ec(p, conp); | ||
2103 | c |= c << 8; | ||
2104 | c |= c << 16; | ||
2105 | |||
2106 | if (!bottom_only) { /* right margin top->bottom */ | ||
2107 | PM3_WAIT(4); | ||
2108 | |||
2109 | PM3_WRITE_REG(PM3Config2D, | ||
2110 | PM3Config2D_UseConstantSource | | ||
2111 | PM3Config2D_ForegroundROPEnable | | ||
2112 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
2113 | PM3Config2D_FBWriteEnable); | ||
2114 | |||
2115 | PM3_WRITE_REG(PM3ForegroundColor, c); | ||
2116 | |||
2117 | PM3_WRITE_REG(PM3RectanglePosition, | ||
2118 | (PM3RectanglePosition_XOffset | ||
2119 | (p->var.xoffset + | ||
2120 | sx)) | (PM3RectanglePosition_YOffset(p-> | ||
2121 | var. | ||
2122 | yoffset))); | ||
2123 | |||
2124 | PM3_WRITE_REG(PM3Render2D, | ||
2125 | PM3Render2D_XPositive | | ||
2126 | PM3Render2D_YPositive | | ||
2127 | PM3Render2D_Operation_Normal | | ||
2128 | PM3Render2D_SpanOperation | | ||
2129 | (PM3Render2D_Width(p->var.xres - sx)) | | ||
2130 | (PM3Render2D_Height(p->var.yres))); | ||
2131 | } | 492 | } |
2132 | 493 | ||
2133 | /* bottom margin left -> right */ | 494 | var->accel_flags = 0; /* Can't mmap if this is on */ |
2134 | PM3_WAIT(4); | ||
2135 | |||
2136 | PM3_WRITE_REG(PM3Config2D, | ||
2137 | PM3Config2D_UseConstantSource | | ||
2138 | PM3Config2D_ForegroundROPEnable | | ||
2139 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
2140 | PM3Config2D_FBWriteEnable); | ||
2141 | |||
2142 | PM3_WRITE_REG(PM3ForegroundColor, c); | ||
2143 | |||
2144 | PM3_WRITE_REG(PM3RectanglePosition, | ||
2145 | (PM3RectanglePosition_XOffset(p->var.xoffset)) | | ||
2146 | (PM3RectanglePosition_YOffset(p->var.yoffset + sy))); | ||
2147 | |||
2148 | PM3_WRITE_REG(PM3Render2D, | ||
2149 | PM3Render2D_XPositive | | ||
2150 | PM3Render2D_YPositive | | ||
2151 | PM3Render2D_Operation_Normal | | ||
2152 | PM3Render2D_SpanOperation | | ||
2153 | (PM3Render2D_Width(p->var.xres)) | | ||
2154 | (PM3Render2D_Height(p->var.yres - sy))); | ||
2155 | 495 | ||
2156 | pm3fb_wait_pm3(l_fb_info); | 496 | DPRINTK("Checking graphics mode at %dx%d depth %d\n", |
2157 | } | 497 | var->xres, var->yres, var->bits_per_pixel); |
2158 | #endif /* FBCON_HAS_CFB8 */ | 498 | return 0; |
2159 | #if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32) | ||
2160 | static void pm3fb_cfbX_bmove(struct display *p, | ||
2161 | int sy, int sx, | ||
2162 | int dy, int dx, int height, int width) | ||
2163 | { | ||
2164 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; | ||
2165 | int x_align, o_x, o_y; | ||
2166 | |||
2167 | DTRACE; | ||
2168 | |||
2169 | sx = sx * fontwidth(p); | ||
2170 | dx = dx * fontwidth(p); | ||
2171 | width = width * fontwidth(p); | ||
2172 | sy = sy * fontheight(p); | ||
2173 | dy = dy * fontheight(p); | ||
2174 | height = height * fontheight(p); | ||
2175 | |||
2176 | o_x = sx - dx; /*(sx > dx ) ? (sx - dx) : (dx - sx); */ | ||
2177 | o_y = sy - dy; /*(sy > dy ) ? (sy - dy) : (dy - sy); */ | ||
2178 | |||
2179 | x_align = (sx & 0x1f); | ||
2180 | |||
2181 | PM3_WAIT(6); | ||
2182 | |||
2183 | PM3_WRITE_REG(PM3Config2D, | ||
2184 | PM3Config2D_UserScissorEnable | | ||
2185 | PM3Config2D_ForegroundROPEnable | | ||
2186 | PM3Config2D_Blocking | | ||
2187 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
2188 | PM3Config2D_FBWriteEnable); | ||
2189 | |||
2190 | PM3_WRITE_REG(PM3ScissorMinXY, | ||
2191 | ((dy & 0x0fff) << 16) | (dx & 0x0fff)); | ||
2192 | PM3_WRITE_REG(PM3ScissorMaxXY, | ||
2193 | (((dy + height) & 0x0fff) << 16) | | ||
2194 | ((dx + width) & 0x0fff)); | ||
2195 | |||
2196 | PM3_WRITE_REG(PM3FBSourceReadBufferOffset, | ||
2197 | PM3FBSourceReadBufferOffset_XOffset(o_x) | | ||
2198 | PM3FBSourceReadBufferOffset_YOffset(o_y)); | ||
2199 | |||
2200 | PM3_WRITE_REG(PM3RectanglePosition, | ||
2201 | (PM3RectanglePosition_XOffset(dx - x_align)) | | ||
2202 | (PM3RectanglePosition_YOffset(dy))); | ||
2203 | |||
2204 | PM3_WRITE_REG(PM3Render2D, | ||
2205 | ((sx > dx) ? PM3Render2D_XPositive : 0) | | ||
2206 | ((sy > dy) ? PM3Render2D_YPositive : 0) | | ||
2207 | PM3Render2D_Operation_Normal | | ||
2208 | PM3Render2D_SpanOperation | | ||
2209 | PM3Render2D_FBSourceReadEnable | | ||
2210 | (PM3Render2D_Width(width + x_align)) | | ||
2211 | (PM3Render2D_Height(height))); | ||
2212 | |||
2213 | pm3fb_wait_pm3(l_fb_info); | ||
2214 | } | 499 | } |
2215 | 500 | ||
2216 | static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p, | 501 | static int pm3fb_set_par(struct fb_info *info) |
2217 | int c, int yy, int xx) | ||
2218 | { | 502 | { |
2219 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; | 503 | struct pm3_par *par = info->par; |
2220 | u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0; | 504 | const u32 xres = (info->var.xres + 31) & ~31; |
2221 | u32 fgx, bgx, ldat; | 505 | const int depth = (info->var.bits_per_pixel + 7) & ~7; |
2222 | int sx, sy, i; | ||
2223 | 506 | ||
2224 | DTRACE; | 507 | par->base = pm3fb_shift_bpp(info->var.bits_per_pixel, |
508 | (info->var.yoffset * xres) | ||
509 | + info->var.xoffset); | ||
510 | par->video = 0; | ||
2225 | 511 | ||
2226 | if (l_fb_info->current_par->depth == 8) | 512 | if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) |
2227 | fgx = attr_fgcol(p, c); | 513 | par->video |= PM3VideoControl_HSYNC_ACTIVE_HIGH; |
2228 | else if (depth2bpp(l_fb_info->current_par->depth) == 16) | ||
2229 | fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, c)]; | ||
2230 | else | 514 | else |
2231 | fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, c)]; | 515 | par->video |= PM3VideoControl_HSYNC_ACTIVE_LOW; |
2232 | 516 | ||
2233 | PM3_COLOR(fgx); | 517 | if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) |
2234 | 518 | par->video |= PM3VideoControl_VSYNC_ACTIVE_HIGH; | |
2235 | if (l_fb_info->current_par->depth == 8) | ||
2236 | bgx = attr_bgcol(p, c); | ||
2237 | else if (depth2bpp(l_fb_info->current_par->depth) == 16) | ||
2238 | bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, c)]; | ||
2239 | else | 519 | else |
2240 | bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, c)]; | 520 | par->video |= PM3VideoControl_VSYNC_ACTIVE_LOW; |
2241 | |||
2242 | PM3_COLOR(bgx); | ||
2243 | |||
2244 | PM3_WAIT(4); | ||
2245 | |||
2246 | PM3_WRITE_REG(PM3Config2D, | ||
2247 | PM3Config2D_UseConstantSource | | ||
2248 | PM3Config2D_ForegroundROPEnable | | ||
2249 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
2250 | PM3Config2D_FBWriteEnable | PM3Config2D_OpaqueSpan); | ||
2251 | |||
2252 | PM3_WRITE_REG(PM3ForegroundColor, fgx); | ||
2253 | PM3_WRITE_REG(PM3FillBackgroundColor, bgx); | ||
2254 | |||
2255 | /* WARNING : address select X need to specify 8 bits for fontwidth <= 8 */ | ||
2256 | /* and 16 bits for fontwidth <= 16 */ | ||
2257 | /* same in _putcs, same for Y and fontheight */ | ||
2258 | if (fontwidth(p) <= 8) | ||
2259 | asx = 2; | ||
2260 | else if (fontwidth(p) <= 16) | ||
2261 | asx = 3; /* look OK */ | ||
2262 | if (fontheight(p) <= 8) | ||
2263 | asy = 2; | ||
2264 | else if (fontheight(p) <= 16) | ||
2265 | asy = 3; /* look OK */ | ||
2266 | else if (fontheight(p) <= 32) | ||
2267 | asy = 4; /* look OK */ | ||
2268 | |||
2269 | sx = xx * fontwidth(p); | ||
2270 | sy = yy * fontheight(p); | ||
2271 | |||
2272 | if (fontwidth(p) <= 8) | ||
2273 | o_x = (8 - (sx & 0x7)) & 0x7; | ||
2274 | else if (fontwidth(p) <= 16) | ||
2275 | o_x = (16 - (sx & 0xF)) & 0xF; | ||
2276 | if (fontheight(p) <= 8) | ||
2277 | o_y = (8 - (sy & 0x7)) & 0x7; | ||
2278 | else if (fontheight(p) <= 16) | ||
2279 | o_y = (16 - (sy & 0xF)) & 0xF; | ||
2280 | else if (fontheight(p) <= 32) | ||
2281 | o_y = (32 - (sy & 0x1F)) & 0x1F; | ||
2282 | |||
2283 | PM3_WRITE_REG(PM3AreaStippleMode, (o_x << 7) | (o_y << 12) | /* x_offset, y_offset in pattern */ | ||
2284 | (1 << 18) | /* BE */ | ||
2285 | 1 | (asx << 1) | (asy << 4) | /* address select x/y */ | ||
2286 | (1 << 20)); /* OpaqueSpan */ | ||
2287 | |||
2288 | if (fontwidth(p) <= 8) { | ||
2289 | cdat = p->fontdata + (c & p->charmask) * fontheight(p); | ||
2290 | } else { | ||
2291 | cdat = | ||
2292 | p->fontdata + | ||
2293 | ((c & p->charmask) * (fontheight(p) << 1)); | ||
2294 | } | ||
2295 | |||
2296 | PM3_WAIT(2 + fontheight(p)); | ||
2297 | |||
2298 | for (i = 0; i < fontheight(p); i++) { /* assume fontheight <= 32 */ | ||
2299 | if (fontwidth(p) <= 8) { | ||
2300 | ldat = *cdat++; | ||
2301 | } else { /* assume fontwidth <= 16 ATM */ | ||
2302 | |||
2303 | ldat = ((*cdat++) << 8); | ||
2304 | ldat |= *cdat++; | ||
2305 | } | ||
2306 | PM3_WRITE_REG(AreaStipplePattern_indexed(i), ldat); | ||
2307 | } | ||
2308 | |||
2309 | PM3_WRITE_REG(PM3RectanglePosition, | ||
2310 | (PM3RectanglePosition_XOffset(sx)) | | ||
2311 | (PM3RectanglePosition_YOffset(sy))); | ||
2312 | 521 | ||
2313 | PM3_WRITE_REG(PM3Render2D, | 522 | if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) |
2314 | PM3Render2D_AreaStippleEnable | | 523 | par->video |= PM3VideoControl_LINE_DOUBLE_ON; |
2315 | PM3Render2D_XPositive | | ||
2316 | PM3Render2D_YPositive | | ||
2317 | PM3Render2D_Operation_Normal | | ||
2318 | PM3Render2D_SpanOperation | | ||
2319 | (PM3Render2D_Width(fontwidth(p))) | | ||
2320 | (PM3Render2D_Height(fontheight(p)))); | ||
2321 | |||
2322 | pm3fb_wait_pm3(l_fb_info); | ||
2323 | } | ||
2324 | |||
2325 | static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p, | ||
2326 | const unsigned short *s, int count, int yy, | ||
2327 | int xx) | ||
2328 | { | ||
2329 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; | ||
2330 | u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0; | ||
2331 | u32 fgx, bgx, ldat; | ||
2332 | int sx, sy, i, j; | ||
2333 | u16 sc; | ||
2334 | |||
2335 | DTRACE; | ||
2336 | |||
2337 | sc = scr_readw(s); | ||
2338 | if (l_fb_info->current_par->depth == 8) | ||
2339 | fgx = attr_fgcol(p, sc); | ||
2340 | else if (depth2bpp(l_fb_info->current_par->depth) == 16) | ||
2341 | fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, sc)]; | ||
2342 | else | ||
2343 | fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, sc)]; | ||
2344 | |||
2345 | PM3_COLOR(fgx); | ||
2346 | |||
2347 | if (l_fb_info->current_par->depth == 8) | ||
2348 | bgx = attr_bgcol(p, sc); | ||
2349 | else if (depth2bpp(l_fb_info->current_par->depth) == 16) | ||
2350 | bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, sc)]; | ||
2351 | else | 524 | else |
2352 | bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, sc)]; | 525 | par->video |= PM3VideoControl_LINE_DOUBLE_OFF; |
2353 | |||
2354 | PM3_COLOR(bgx); | ||
2355 | |||
2356 | PM3_WAIT(4); | ||
2357 | |||
2358 | PM3_WRITE_REG(PM3Config2D, | ||
2359 | PM3Config2D_UseConstantSource | | ||
2360 | PM3Config2D_ForegroundROPEnable | | ||
2361 | (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */ | ||
2362 | PM3Config2D_FBWriteEnable | | ||
2363 | PM3Config2D_OpaqueSpan); | ||
2364 | |||
2365 | PM3_WRITE_REG(PM3ForegroundColor, fgx); | ||
2366 | PM3_WRITE_REG(PM3FillBackgroundColor, bgx); | ||
2367 | |||
2368 | /* WARNING : address select X need to specify 8 bits for fontwidth <= 8 */ | ||
2369 | /* and 16 bits for fontwidth <= 16 */ | ||
2370 | /* same in _putc, same for Y and fontheight */ | ||
2371 | if (fontwidth(p) <= 8) | ||
2372 | asx = 2; | ||
2373 | else if (fontwidth(p) <= 16) | ||
2374 | asx = 3; /* look OK */ | ||
2375 | if (fontheight(p) <= 8) | ||
2376 | asy = 2; | ||
2377 | else if (fontheight(p) <= 16) | ||
2378 | asy = 3; /* look OK */ | ||
2379 | else if (fontheight(p) <= 32) | ||
2380 | asy = 4; /* look OK */ | ||
2381 | |||
2382 | sy = yy * fontheight(p); | ||
2383 | |||
2384 | if (fontheight(p) <= 8) | ||
2385 | o_y = (8 - (sy & 0x7)) & 0x7; | ||
2386 | else if (fontheight(p) <= 16) | ||
2387 | o_y = (16 - (sy & 0xF)) & 0xF; | ||
2388 | else if (fontheight(p) <= 32) | ||
2389 | o_y = (32 - (sy & 0x1F)) & 0x1F; | ||
2390 | |||
2391 | for (j = 0; j < count; j++) { | ||
2392 | sc = scr_readw(s + j); | ||
2393 | if (fontwidth(p) <= 8) | ||
2394 | cdat = p->fontdata + | ||
2395 | (sc & p->charmask) * fontheight(p); | ||
2396 | else | ||
2397 | cdat = p->fontdata + | ||
2398 | ((sc & p->charmask) * fontheight(p) << 1); | ||
2399 | |||
2400 | sx = (xx + j) * fontwidth(p); | ||
2401 | |||
2402 | if (fontwidth(p) <= 8) | ||
2403 | o_x = (8 - (sx & 0x7)) & 0x7; | ||
2404 | else if (fontwidth(p) <= 16) | ||
2405 | o_x = (16 - (sx & 0xF)) & 0xF; | ||
2406 | |||
2407 | PM3_WAIT(3 + fontheight(p)); | ||
2408 | |||
2409 | PM3_WRITE_REG(PM3AreaStippleMode, (o_x << 7) | (o_y << 12) | /* x_offset, y_offset in pattern */ | ||
2410 | (1 << 18) | /* BE */ | ||
2411 | 1 | (asx << 1) | (asy << 4) | /* address select x/y */ | ||
2412 | (1 << 20)); /* OpaqueSpan */ | ||
2413 | |||
2414 | for (i = 0; i < fontheight(p); i++) { /* assume fontheight <= 32 */ | ||
2415 | if (fontwidth(p) <= 8) { | ||
2416 | ldat = *cdat++; | ||
2417 | } else { /* assume fontwidth <= 16 ATM */ | ||
2418 | ldat = ((*cdat++) << 8); | ||
2419 | ldat |= *cdat++; | ||
2420 | } | ||
2421 | PM3_WRITE_REG(AreaStipplePattern_indexed(i), ldat); | ||
2422 | } | ||
2423 | |||
2424 | PM3_WRITE_REG(PM3RectanglePosition, | ||
2425 | (PM3RectanglePosition_XOffset(sx)) | | ||
2426 | (PM3RectanglePosition_YOffset(sy))); | ||
2427 | |||
2428 | PM3_WRITE_REG(PM3Render2D, | ||
2429 | PM3Render2D_AreaStippleEnable | | ||
2430 | PM3Render2D_XPositive | | ||
2431 | PM3Render2D_YPositive | | ||
2432 | PM3Render2D_Operation_Normal | | ||
2433 | PM3Render2D_SpanOperation | | ||
2434 | (PM3Render2D_Width(fontwidth(p))) | | ||
2435 | (PM3Render2D_Height(fontheight(p)))); | ||
2436 | } | ||
2437 | pm3fb_wait_pm3(l_fb_info); | ||
2438 | } | ||
2439 | 526 | ||
2440 | static void pm3fb_cfbX_revc(struct display *p, int xx, int yy) | 527 | if (info->var.activate == FB_ACTIVATE_NOW) |
2441 | { | 528 | par->video |= PM3VideoControl_ENABLE; |
2442 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info; | 529 | else { |
2443 | 530 | par->video |= PM3VideoControl_DISABLE; | |
2444 | xx = xx * fontwidth(p); | 531 | DPRINTK("PM3Video disabled\n"); |
2445 | yy = yy * fontheight(p); | ||
2446 | |||
2447 | if (l_fb_info->current_par->depth == 8) | ||
2448 | { | ||
2449 | if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) | ||
2450 | PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0x0F0F0F0F); | ||
2451 | else | ||
2452 | PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0x0F0F0F0F); | ||
2453 | } | 532 | } |
2454 | 533 | switch (depth) { | |
2455 | PM3_WAIT(3); | ||
2456 | |||
2457 | PM3_WRITE_REG(PM3Config2D, | ||
2458 | PM3Config2D_UseConstantSource | | ||
2459 | PM3Config2D_ForegroundROPEnable | | ||
2460 | (PM3Config2D_ForegroundROP(0xa)) | /* Oxa is GXinvert */ | ||
2461 | PM3Config2D_FBDestReadEnable | | ||
2462 | PM3Config2D_FBWriteEnable); | ||
2463 | |||
2464 | PM3_WRITE_REG(PM3RectanglePosition, | ||
2465 | (PM3RectanglePosition_XOffset(xx)) | | ||
2466 | (PM3RectanglePosition_YOffset(yy))); | ||
2467 | |||
2468 | PM3_WRITE_REG(PM3Render2D, | ||
2469 | PM3Render2D_XPositive | | ||
2470 | PM3Render2D_YPositive | | ||
2471 | PM3Render2D_Operation_Normal | | ||
2472 | PM3Render2D_SpanOperation | | ||
2473 | (PM3Render2D_Width(fontwidth(p))) | | ||
2474 | (PM3Render2D_Height(fontheight(p)))); | ||
2475 | |||
2476 | pm3fb_wait_pm3(l_fb_info); | ||
2477 | |||
2478 | if (l_fb_info->current_par->depth == 8) | ||
2479 | { | ||
2480 | if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask) | ||
2481 | PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xFFFFFFFF); | ||
2482 | else | ||
2483 | PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xFFFFFFFF); | ||
2484 | } | ||
2485 | } | ||
2486 | |||
2487 | #endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */ | ||
2488 | #endif /* PM3FB_USE_ACCEL */ | ||
2489 | /* *********************************** */ | ||
2490 | /* ***** pre-init board(s) setup ***** */ | ||
2491 | /* *********************************** */ | ||
2492 | |||
2493 | static void pm3fb_mode_setup(char *mode, unsigned long board_num) | ||
2494 | { | ||
2495 | struct pm3fb_info *l_fb_info = &(fb_info[board_num]); | ||
2496 | struct pm3fb_par *l_fb_par = &(current_par[board_num]); | ||
2497 | unsigned long i = 0; | ||
2498 | |||
2499 | current_par_valid[board_num] = 0; | ||
2500 | |||
2501 | if (!strncmp(mode, "current", 7)) { | ||
2502 | l_fb_info->use_current = 1; /* default w/ OpenFirmware */ | ||
2503 | } else { | ||
2504 | while ((mode_base[i].name[0]) | ||
2505 | && (!current_par_valid[board_num])) { | ||
2506 | if (! | ||
2507 | (strncmp | ||
2508 | (mode, mode_base[i].name, | ||
2509 | strlen(mode_base[i].name)))) { | ||
2510 | memcpy(l_fb_par, &(mode_base[i].user_mode), | ||
2511 | sizeof(struct pm3fb_par)); | ||
2512 | current_par_valid[board_num] = 1; | ||
2513 | DPRINTK(2, "Mode set to %s\n", | ||
2514 | mode_base[i].name); | ||
2515 | } | ||
2516 | i++; | ||
2517 | } | ||
2518 | DASSERT(current_par_valid[board_num], | ||
2519 | "Valid mode on command line\n"); | ||
2520 | } | ||
2521 | } | ||
2522 | |||
2523 | static void pm3fb_pciid_setup(char *pciid, unsigned long board_num) | ||
2524 | { | ||
2525 | short l_bus = -1, l_slot = -1, l_func = -1; | ||
2526 | char *next; | ||
2527 | |||
2528 | if (pciid) { | ||
2529 | l_bus = simple_strtoul(pciid, &next, 10); | ||
2530 | if (next && (next[0] == ':')) { | ||
2531 | pciid = next + 1; | ||
2532 | l_slot = simple_strtoul(pciid, &next, 10); | ||
2533 | if (next && (next[0] == ':')) { | ||
2534 | pciid = next + 1; | ||
2535 | l_func = | ||
2536 | simple_strtoul(pciid, (char **) NULL, | ||
2537 | 10); | ||
2538 | } | ||
2539 | } | ||
2540 | } else | ||
2541 | return; | ||
2542 | |||
2543 | if ((l_bus >= 0) && (l_slot >= 0) && (l_func >= 0)) { | ||
2544 | bus[board_num] = l_bus; | ||
2545 | slot[board_num] = l_slot; | ||
2546 | func[board_num] = l_func; | ||
2547 | DPRINTK(2, "Board #%ld will be PciId: %hd:%hd:%hd\n", | ||
2548 | board_num, l_bus, l_slot, l_func); | ||
2549 | } else { | ||
2550 | DPRINTK(1, "Invalid PciId: %hd:%hd:%hd for board #%ld\n", | ||
2551 | l_bus, l_slot, l_func, board_num); | ||
2552 | } | ||
2553 | } | ||
2554 | |||
2555 | static void pm3fb_font_setup(char *lf, unsigned long board_num) | ||
2556 | { | ||
2557 | unsigned long lfs = strlen(lf); | ||
2558 | |||
2559 | if (lfs > (PM3_FONTNAME_SIZE - 1)) { | ||
2560 | DPRINTK(1, "Fontname %s too long\n", lf); | ||
2561 | return; | ||
2562 | } | ||
2563 | strlcpy(fontn[board_num], lf, lfs + 1); | ||
2564 | } | ||
2565 | |||
2566 | static void pm3fb_bootdepth_setup(char *bds, unsigned long board_num) | ||
2567 | { | ||
2568 | unsigned long bd = simple_strtoul(bds, (char **) NULL, 10); | ||
2569 | |||
2570 | if (!(depth_supported(bd))) { | ||
2571 | printk(KERN_WARNING "pm3fb: ignoring invalid depth %s for board #%ld\n", | ||
2572 | bds, board_num); | ||
2573 | return; | ||
2574 | } | ||
2575 | depth[board_num] = bd; | ||
2576 | } | ||
2577 | |||
2578 | static void pm3fb_forcesize_setup(char *bds, unsigned long board_num) | ||
2579 | { | ||
2580 | unsigned long bd = simple_strtoul(bds, (char **) NULL, 10); | ||
2581 | |||
2582 | if (bd > 64) { | ||
2583 | printk(KERN_WARNING "pm3fb: ignoring invalid memory size %s for board #%ld\n", | ||
2584 | bds, board_num); | ||
2585 | return; | ||
2586 | } | ||
2587 | forcesize[board_num] = bd; | ||
2588 | } | ||
2589 | |||
2590 | static char *pm3fb_boardnum_setup(char *options, unsigned long *bn) | ||
2591 | { | ||
2592 | char *next; | ||
2593 | |||
2594 | if (!(isdigit(options[0]))) { | ||
2595 | (*bn) = 0; | ||
2596 | return (options); | ||
2597 | } | ||
2598 | |||
2599 | (*bn) = simple_strtoul(options, &next, 10); | ||
2600 | |||
2601 | if (next && (next[0] == ':') && ((*bn) >= 0) | ||
2602 | && ((*bn) <= PM3_MAX_BOARD)) { | ||
2603 | DPRINTK(2, "Board_num seen as %ld\n", (*bn)); | ||
2604 | return (next + 1); | ||
2605 | } else { | ||
2606 | (*bn) = 0; | ||
2607 | DPRINTK(2, "Board_num default to %ld\n", (*bn)); | ||
2608 | return (options); | ||
2609 | } | ||
2610 | } | ||
2611 | |||
2612 | static void pm3fb_real_setup(char *options) | ||
2613 | { | ||
2614 | char *next; | ||
2615 | unsigned long i, bn; | ||
2616 | struct pm3fb_info *l_fb_info; | ||
2617 | |||
2618 | DTRACE; | ||
2619 | |||
2620 | DPRINTK(2, "Options : %s\n", options); | ||
2621 | |||
2622 | for (i = 0; i < PM3_MAX_BOARD; i++) { | ||
2623 | l_fb_info = &(fb_info[i]); | ||
2624 | memset(l_fb_info, 0, sizeof(struct pm3fb_info)); | ||
2625 | l_fb_info->gen.fbhw = &pm3fb_switch; | ||
2626 | l_fb_info->board_num = i; | ||
2627 | current_par_valid[i] = 0; | ||
2628 | slot[i] = -1; | ||
2629 | func[i] = -1; | ||
2630 | bus[i] = -1; | ||
2631 | disable[i] = 0; | ||
2632 | noaccel[i] = 0; | ||
2633 | fontn[i][0] = '\0'; | ||
2634 | depth[i] = 0; | ||
2635 | l_fb_info->current_par = &(current_par[i]); | ||
2636 | } | ||
2637 | |||
2638 | /* eat up prefix pm3fb and whatever is used as separator i.e. :,= */ | ||
2639 | if (!strncmp(options, "pm3fb", 5)) { | ||
2640 | options += 5; | ||
2641 | while (((*options) == ',') || ((*options) == ':') | ||
2642 | || ((*options) == '=')) | ||
2643 | options++; | ||
2644 | } | ||
2645 | |||
2646 | while (options) { | ||
2647 | bn = 0; | ||
2648 | if ((next = strchr(options, ','))) { | ||
2649 | (*next) = '\0'; | ||
2650 | next++; | ||
2651 | } | ||
2652 | |||
2653 | if (!strncmp(options, "mode:", 5)) { | ||
2654 | options = pm3fb_boardnum_setup(options + 5, &bn); | ||
2655 | DPRINTK(2, "Setting mode for board #%ld\n", bn); | ||
2656 | pm3fb_mode_setup(options, bn); | ||
2657 | } else if (!strncmp(options, "off:", 4)) { | ||
2658 | options = pm3fb_boardnum_setup(options + 4, &bn); | ||
2659 | DPRINTK(2, "Disabling board #%ld\n", bn); | ||
2660 | disable[bn] = 1; | ||
2661 | } else if (!strncmp(options, "off", 3)) { /* disable everything */ | ||
2662 | for (i = 0; i < PM3_MAX_BOARD; i++) | ||
2663 | disable[i] = 1; | ||
2664 | } else if (!strncmp(options, "disable:", 8)) { | ||
2665 | options = pm3fb_boardnum_setup(options + 8, &bn); | ||
2666 | DPRINTK(2, "Disabling board #%ld\n", bn); | ||
2667 | disable[bn] = 1; | ||
2668 | } else if (!strncmp(options, "pciid:", 6)) { | ||
2669 | options = pm3fb_boardnum_setup(options + 6, &bn); | ||
2670 | DPRINTK(2, "Setting PciID for board #%ld\n", bn); | ||
2671 | pm3fb_pciid_setup(options, bn); | ||
2672 | } else if (!strncmp(options, "noaccel:", 8)) { | ||
2673 | options = pm3fb_boardnum_setup(options + 8, &bn); | ||
2674 | noaccel[bn] = 1; | ||
2675 | } else if (!strncmp(options, "font:", 5)) { | ||
2676 | options = pm3fb_boardnum_setup(options + 5, &bn); | ||
2677 | pm3fb_font_setup(options, bn); | ||
2678 | } else if (!strncmp(options, "depth:", 6)) { | ||
2679 | options = pm3fb_boardnum_setup(options + 6, &bn); | ||
2680 | pm3fb_bootdepth_setup(options, bn); | ||
2681 | } else if (!strncmp(options, "printtimings", 12)) { | ||
2682 | printtimings = 1; | ||
2683 | } else if (!strncmp(options, "flatpanel:", 10)) { | ||
2684 | options = pm3fb_boardnum_setup(options + 10, &bn); | ||
2685 | flatpanel[bn] = 1; | ||
2686 | } else if (!strncmp(options, "forcesize:", 10)) { | ||
2687 | options = pm3fb_boardnum_setup(options + 10, &bn); | ||
2688 | pm3fb_forcesize_setup(options, bn); | ||
2689 | } | ||
2690 | options = next; | ||
2691 | } | ||
2692 | } | ||
2693 | |||
2694 | /* ********************************************** */ | ||
2695 | /* ***** framebuffer API standard functions ***** */ | ||
2696 | /* ********************************************** */ | ||
2697 | |||
2698 | static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix, | ||
2699 | const void *par, struct fb_info_gen *info) | ||
2700 | { | ||
2701 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; | ||
2702 | struct pm3fb_par *p = (struct pm3fb_par *) par; | ||
2703 | |||
2704 | DTRACE; | ||
2705 | |||
2706 | strcpy(fix->id, permedia3_name); | ||
2707 | fix->smem_start = (unsigned long)l_fb_info->p_fb; | ||
2708 | fix->smem_len = l_fb_info->fb_size; | ||
2709 | fix->mmio_start = (unsigned long)l_fb_info->pIOBase; | ||
2710 | fix->mmio_len = PM3_REGS_SIZE; | ||
2711 | #ifdef PM3FB_USE_ACCEL | ||
2712 | if (!(noaccel[l_fb_info->board_num])) | ||
2713 | fix->accel = FB_ACCEL_3DLABS_PERMEDIA3; | ||
2714 | else | ||
2715 | #endif /* PM3FB_USE_ACCEL */ | ||
2716 | fix->accel = FB_ACCEL_NONE; | ||
2717 | fix->type = FB_TYPE_PACKED_PIXELS; | ||
2718 | fix->visual = | ||
2719 | (p->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; | ||
2720 | if (current_par_valid[l_fb_info->board_num]) | ||
2721 | fix->line_length = | ||
2722 | l_fb_info->current_par->width * | ||
2723 | depth2ByPP(l_fb_info->current_par->depth); | ||
2724 | else | ||
2725 | fix->line_length = 0; | ||
2726 | fix->xpanstep = 64 / depth2bpp(p->depth); | ||
2727 | fix->ypanstep = 1; | ||
2728 | fix->ywrapstep = 0; | ||
2729 | return (0); | ||
2730 | } | ||
2731 | |||
2732 | static int pm3fb_decode_var(const struct fb_var_screeninfo *var, | ||
2733 | void *par, struct fb_info_gen *info) | ||
2734 | { | ||
2735 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; | ||
2736 | struct pm3fb_par *p = (struct pm3fb_par *) par; | ||
2737 | struct pm3fb_par temp_p; | ||
2738 | u32 xres; | ||
2739 | |||
2740 | DTRACE; | ||
2741 | |||
2742 | DASSERT((var != NULL), "fb_var_screeninfo* not NULL"); | ||
2743 | DASSERT((p != NULL), "pm3fb_par* not NULL"); | ||
2744 | DASSERT((l_fb_info != NULL), "pm3fb_info* not NULL"); | ||
2745 | |||
2746 | memset(&temp_p, 0, sizeof(struct pm3fb_par)); | ||
2747 | temp_p.width = (var->xres_virtual + 7) & ~7; | ||
2748 | temp_p.height = var->yres_virtual; | ||
2749 | |||
2750 | if (!(depth_supported(var->bits_per_pixel))) /* round unsupported up to a multiple of 8 */ | ||
2751 | temp_p.depth = depth2bpp(var->bits_per_pixel); | ||
2752 | else | ||
2753 | temp_p.depth = var->bits_per_pixel; | ||
2754 | |||
2755 | temp_p.depth = (temp_p.depth > 32) ? 32 : temp_p.depth; /* max 32 */ | ||
2756 | temp_p.depth = (temp_p.depth == 24) ? 32 : temp_p.depth; /* 24 unsupported, round-up to 32 */ | ||
2757 | |||
2758 | if ((temp_p.depth == 16) && (var->red.length == 5) && (var->green.length == 5) && (var->blue.length == 5)) | ||
2759 | temp_p.depth = 15; /* RGBA 5551 is stored as depth 15 */ | ||
2760 | |||
2761 | if ((temp_p.depth == 16) && (var->red.length == 4) && (var->green.length == 4) && (var->blue.length == 4)) | ||
2762 | temp_p.depth = 12; /* RGBA 4444 is stored as depth 12 */ | ||
2763 | |||
2764 | |||
2765 | DPRINTK(2, | ||
2766 | "xres: %d, yres: %d, vxres: %d, vyres: %d ; xoffset:%d, yoffset: %d\n", | ||
2767 | var->xres, var->yres, var->xres_virtual, var->yres_virtual, | ||
2768 | var->xoffset, var->yoffset); | ||
2769 | |||
2770 | xres = (var->xres + 31) & ~31; | ||
2771 | if (temp_p.width < xres + var->xoffset) | ||
2772 | temp_p.width = xres + var->xoffset; | ||
2773 | if (temp_p.height < var->yres + var->yoffset) | ||
2774 | temp_p.height = var->yres + var->yoffset; | ||
2775 | |||
2776 | if (temp_p.width > 2048) { | ||
2777 | DPRINTK(1, "virtual width not supported: %u\n", | ||
2778 | temp_p.width); | ||
2779 | return (-EINVAL); | ||
2780 | } | ||
2781 | if (var->yres < 200) { | ||
2782 | DPRINTK(1, "height not supported: %u\n", (u32) var->yres); | ||
2783 | return (-EINVAL); | ||
2784 | } | ||
2785 | if (temp_p.height < 200 || temp_p.height > 4095) { | ||
2786 | DPRINTK(1, "virtual height not supported: %u\n", | ||
2787 | temp_p.height); | ||
2788 | return (-EINVAL); | ||
2789 | } | ||
2790 | if (!(depth_supported(temp_p.depth))) { | ||
2791 | DPRINTK(1, "depth not supported: %u\n", temp_p.depth); | ||
2792 | return (-EINVAL); | ||
2793 | } | ||
2794 | if ((temp_p.width * temp_p.height * depth2ByPP(temp_p.depth)) > | ||
2795 | l_fb_info->fb_size) { | ||
2796 | DPRINTK(1, "no memory for screen (%ux%ux%u)\n", | ||
2797 | temp_p.width, temp_p.height, temp_p.depth); | ||
2798 | return (-EINVAL); | ||
2799 | } | ||
2800 | |||
2801 | if ((!var->pixclock) || | ||
2802 | (!var->right_margin) || | ||
2803 | (!var->hsync_len) || | ||
2804 | (!var->left_margin) || | ||
2805 | (!var->lower_margin) || | ||
2806 | (!var->vsync_len) || (!var->upper_margin) | ||
2807 | ) { | ||
2808 | unsigned long i = 0, done = 0; | ||
2809 | printk(KERN_WARNING "pm3fb: refusing to use a likely wrong timing\n"); | ||
2810 | |||
2811 | while ((mode_base[i].user_mode.width) && !done) { | ||
2812 | if ((mode_base[i].user_mode.width == temp_p.width) | ||
2813 | && (mode_base[i].user_mode.height == | ||
2814 | temp_p.height)) { | ||
2815 | printk(KERN_NOTICE "pm3fb: using close match %s\n", | ||
2816 | mode_base[i].name); | ||
2817 | temp_p = mode_base[i].user_mode; | ||
2818 | done = 1; | ||
2819 | } | ||
2820 | i++; | ||
2821 | } | ||
2822 | if (!done) | ||
2823 | return (-EINVAL); | ||
2824 | } else { | ||
2825 | temp_p.pixclock = PICOS2KHZ(var->pixclock); | ||
2826 | if (temp_p.pixclock > PM3_MAX_PIXCLOCK) { | ||
2827 | DPRINTK(1, "pixclock too high (%uKHz)\n", | ||
2828 | temp_p.pixclock); | ||
2829 | return (-EINVAL); | ||
2830 | } | ||
2831 | |||
2832 | temp_p.hsstart = var->right_margin; | ||
2833 | temp_p.hsend = var->right_margin + var->hsync_len; | ||
2834 | temp_p.hbend = | ||
2835 | var->right_margin + var->hsync_len + var->left_margin; | ||
2836 | temp_p.htotal = xres + temp_p.hbend; | ||
2837 | |||
2838 | temp_p.vsstart = var->lower_margin; | ||
2839 | temp_p.vsend = var->lower_margin + var->vsync_len; | ||
2840 | temp_p.vbend = | ||
2841 | var->lower_margin + var->vsync_len + var->upper_margin; | ||
2842 | temp_p.vtotal = var->yres + temp_p.vbend; | ||
2843 | |||
2844 | temp_p.stride = temp_p.width; | ||
2845 | |||
2846 | DPRINTK(2, "Using %d * %d, %d Khz, stride is %08x\n", | ||
2847 | temp_p.width, temp_p.height, temp_p.pixclock, | ||
2848 | temp_p.stride); | ||
2849 | |||
2850 | temp_p.base = | ||
2851 | pm3fb_Shiftbpp(l_fb_info, temp_p.depth, | ||
2852 | (var->yoffset * xres) + var->xoffset); | ||
2853 | |||
2854 | temp_p.video = 0; | ||
2855 | |||
2856 | if (var->sync & FB_SYNC_HOR_HIGH_ACT) | ||
2857 | temp_p.video |= PM3VideoControl_HSYNC_ACTIVE_HIGH; | ||
2858 | else | ||
2859 | temp_p.video |= PM3VideoControl_HSYNC_ACTIVE_LOW; | ||
2860 | |||
2861 | if (var->sync & FB_SYNC_VERT_HIGH_ACT) | ||
2862 | temp_p.video |= PM3VideoControl_VSYNC_ACTIVE_HIGH; | ||
2863 | else | ||
2864 | temp_p.video |= PM3VideoControl_VSYNC_ACTIVE_LOW; | ||
2865 | |||
2866 | if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { | ||
2867 | DPRINTK(1, "Interlaced mode not supported\n\n"); | ||
2868 | return (-EINVAL); | ||
2869 | } | ||
2870 | |||
2871 | if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) | ||
2872 | temp_p.video |= PM3VideoControl_LINE_DOUBLE_ON; | ||
2873 | else | ||
2874 | temp_p.video |= PM3VideoControl_LINE_DOUBLE_OFF; | ||
2875 | |||
2876 | if (var->activate == FB_ACTIVATE_NOW) | ||
2877 | temp_p.video |= PM3VideoControl_ENABLE; | ||
2878 | else { | ||
2879 | temp_p.video |= PM3VideoControl_DISABLE; | ||
2880 | DPRINTK(2, "PM3Video disabled\n"); | ||
2881 | } | ||
2882 | |||
2883 | switch (temp_p.depth) { | ||
2884 | case 8: | ||
2885 | temp_p.video |= PM3VideoControl_PIXELSIZE_8BIT; | ||
2886 | break; | ||
2887 | case 12: | ||
2888 | case 15: | ||
2889 | case 16: | ||
2890 | temp_p.video |= PM3VideoControl_PIXELSIZE_16BIT; | ||
2891 | break; | ||
2892 | case 32: | ||
2893 | temp_p.video |= PM3VideoControl_PIXELSIZE_32BIT; | ||
2894 | break; | ||
2895 | default: | ||
2896 | DPRINTK(1, "Unsupported depth\n"); | ||
2897 | break; | ||
2898 | } | ||
2899 | } | ||
2900 | (*p) = temp_p; | ||
2901 | |||
2902 | #ifdef PM3FB_USE_ACCEL | ||
2903 | if (var->accel_flags & FB_ACCELF_TEXT) | ||
2904 | noaccel[l_fb_info->board_num] = 0; | ||
2905 | else | ||
2906 | noaccel[l_fb_info->board_num] = 1; | ||
2907 | #endif /* PM3FB_USE_ACCEL */ | ||
2908 | |||
2909 | return (0); | ||
2910 | } | ||
2911 | |||
2912 | static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d) | ||
2913 | { | ||
2914 | switch (d) { | ||
2915 | case 8: | 534 | case 8: |
2916 | var->red.length = var->green.length = var->blue.length = 8; | 535 | par->video |= PM3VideoControl_PIXELSIZE_8BIT; |
2917 | var->red.offset = var->green.offset = var->blue.offset = 0; | ||
2918 | var->transp.offset = var->transp.length = 0; | ||
2919 | break; | 536 | break; |
2920 | |||
2921 | case 12: | 537 | case 12: |
2922 | var->red.offset = 8; | ||
2923 | var->red.length = 4; | ||
2924 | var->green.offset = 4; | ||
2925 | var->green.length = 4; | ||
2926 | var->blue.offset = 0; | ||
2927 | var->blue.length = 4; | ||
2928 | var->transp.offset = 12; | ||
2929 | var->transp.length = 4; | ||
2930 | break; | ||
2931 | |||
2932 | case 15: | 538 | case 15: |
2933 | var->red.offset = 10; | ||
2934 | var->red.length = 5; | ||
2935 | var->green.offset = 5; | ||
2936 | var->green.length = 5; | ||
2937 | var->blue.offset = 0; | ||
2938 | var->blue.length = 5; | ||
2939 | var->transp.offset = 15; | ||
2940 | var->transp.length = 1; | ||
2941 | break; | ||
2942 | |||
2943 | case 16: | 539 | case 16: |
2944 | var->red.offset = 11; | 540 | par->video |= PM3VideoControl_PIXELSIZE_16BIT; |
2945 | var->red.length = 5; | ||
2946 | var->green.offset = 5; | ||
2947 | var->green.length = 6; | ||
2948 | var->blue.offset = 0; | ||
2949 | var->blue.length = 5; | ||
2950 | var->transp.offset = var->transp.length = 0; | ||
2951 | break; | 541 | break; |
2952 | |||
2953 | case 32: | 542 | case 32: |
2954 | var->transp.offset = 24; | 543 | par->video |= PM3VideoControl_PIXELSIZE_32BIT; |
2955 | var->red.offset = 16; | ||
2956 | var->green.offset = 8; | ||
2957 | var->blue.offset = 0; | ||
2958 | var->red.length = var->green.length = | ||
2959 | var->blue.length = var->transp.length = 8; | ||
2960 | break; | 544 | break; |
2961 | |||
2962 | default: | 545 | default: |
2963 | DPRINTK(1, "Unsupported depth %ld\n", d); | 546 | DPRINTK("Unsupported depth\n"); |
2964 | break; | 547 | break; |
2965 | } | 548 | } |
2966 | } | ||
2967 | 549 | ||
2968 | static int pm3fb_encode_var(struct fb_var_screeninfo *var, | 550 | info->fix.visual = |
2969 | const void *par, struct fb_info_gen *info) | 551 | (depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; |
2970 | { | 552 | info->fix.line_length = ((info->var.xres_virtual + 7) & ~7) |
2971 | struct pm3fb_par *p = (struct pm3fb_par *) par; | 553 | * depth / 8; |
2972 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; | ||
2973 | |||
2974 | u32 base; | ||
2975 | |||
2976 | DTRACE; | ||
2977 | |||
2978 | DASSERT((var != NULL), "fb_var_screeninfo* not NULL"); | ||
2979 | DASSERT((p != NULL), "pm3fb_par* not NULL"); | ||
2980 | DASSERT((info != NULL), "fb_info_gen* not NULL"); | ||
2981 | |||
2982 | memset(var, 0, sizeof(struct fb_var_screeninfo)); | ||
2983 | |||
2984 | #ifdef PM3FB_USE_ACCEL | ||
2985 | if (!(noaccel[l_fb_info->board_num])) | ||
2986 | var->accel_flags |= FB_ACCELF_TEXT; | ||
2987 | #endif /* PM3FB_USE_ACCEL */ | ||
2988 | |||
2989 | var->xres_virtual = p->width; | ||
2990 | var->yres_virtual = p->height; | ||
2991 | var->xres = p->htotal - p->hbend; | ||
2992 | var->yres = p->vtotal - p->vbend; | ||
2993 | |||
2994 | DPRINTK(2, "xres = %d, yres : %d\n", var->xres, var->yres); | ||
2995 | |||
2996 | var->right_margin = p->hsstart; | ||
2997 | var->hsync_len = p->hsend - p->hsstart; | ||
2998 | var->left_margin = p->hbend - p->hsend; | ||
2999 | var->lower_margin = p->vsstart; | ||
3000 | var->vsync_len = p->vsend - p->vsstart; | ||
3001 | var->upper_margin = p->vbend - p->vsend; | ||
3002 | var->bits_per_pixel = depth2bpp(p->depth); | ||
3003 | |||
3004 | pm3fb_encode_depth(var, p->depth); | ||
3005 | |||
3006 | base = pm3fb_Unshiftbpp(l_fb_info, p->depth, p->base); | ||
3007 | |||
3008 | var->xoffset = base % var->xres; | ||
3009 | var->yoffset = base / var->xres; | ||
3010 | |||
3011 | var->height = var->width = -1; | ||
3012 | |||
3013 | var->pixclock = KHZ2PICOS(p->pixclock); | ||
3014 | |||
3015 | if ((p->video & PM3VideoControl_HSYNC_MASK) == | ||
3016 | PM3VideoControl_HSYNC_ACTIVE_HIGH) | ||
3017 | var->sync |= FB_SYNC_HOR_HIGH_ACT; | ||
3018 | if ((p->video & PM3VideoControl_VSYNC_MASK) == | ||
3019 | PM3VideoControl_VSYNC_ACTIVE_HIGH) | ||
3020 | var->sync |= FB_SYNC_VERT_HIGH_ACT; | ||
3021 | if (p->video & PM3VideoControl_LINE_DOUBLE_ON) | ||
3022 | var->vmode = FB_VMODE_DOUBLE; | ||
3023 | |||
3024 | return (0); | ||
3025 | } | ||
3026 | |||
3027 | static void pm3fb_get_par(void *par, struct fb_info_gen *info) | ||
3028 | { | ||
3029 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; | ||
3030 | |||
3031 | DTRACE; | ||
3032 | 554 | ||
3033 | if (!current_par_valid[l_fb_info->board_num]) { | 555 | /* pm3fb_clear_memory(info, 0);*/ |
3034 | if (l_fb_info->use_current) | 556 | pm3fb_clear_colormap(par, 0, 0, 0); |
3035 | pm3fb_read_mode(l_fb_info, l_fb_info->current_par); | 557 | PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, |
3036 | else | 558 | PM3RD_CursorMode_CURSOR_DISABLE); |
3037 | memcpy(l_fb_info->current_par, | 559 | pm3fb_write_mode(info); |
3038 | &(mode_base[0].user_mode), | 560 | return 0; |
3039 | sizeof(struct pm3fb_par)); | ||
3040 | current_par_valid[l_fb_info->board_num] = 1; | ||
3041 | } | ||
3042 | *((struct pm3fb_par *) par) = *(l_fb_info->current_par); | ||
3043 | } | ||
3044 | |||
3045 | static void pm3fb_set_par(const void *par, struct fb_info_gen *info) | ||
3046 | { | ||
3047 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; | ||
3048 | |||
3049 | DTRACE; | ||
3050 | |||
3051 | *(l_fb_info->current_par) = *((struct pm3fb_par *) par); | ||
3052 | current_par_valid[l_fb_info->board_num] = 1; | ||
3053 | |||
3054 | pm3fb_write_mode(l_fb_info); | ||
3055 | |||
3056 | #ifdef PM3FB_USE_ACCEL | ||
3057 | pm3fb_init_engine(l_fb_info); | ||
3058 | #endif /* PM3FB_USE_ACCEL */ | ||
3059 | } | ||
3060 | |||
3061 | static void pm3fb_set_color(struct pm3fb_info *l_fb_info, | ||
3062 | unsigned char regno, unsigned char r, | ||
3063 | unsigned char g, unsigned char b) | ||
3064 | { | ||
3065 | DTRACE; | ||
3066 | |||
3067 | PM3_SLOW_WRITE_REG(PM3RD_PaletteWriteAddress, regno); | ||
3068 | PM3_SLOW_WRITE_REG(PM3RD_PaletteData, r); | ||
3069 | PM3_SLOW_WRITE_REG(PM3RD_PaletteData, g); | ||
3070 | PM3_SLOW_WRITE_REG(PM3RD_PaletteData, b); | ||
3071 | } | ||
3072 | |||
3073 | static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green, | ||
3074 | unsigned *blue, unsigned *transp, | ||
3075 | struct fb_info *info) | ||
3076 | { | ||
3077 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; | ||
3078 | |||
3079 | DTRACE; | ||
3080 | |||
3081 | if (regno < 256) { | ||
3082 | *red = | ||
3083 | l_fb_info->palette[regno].red << 8 | l_fb_info-> | ||
3084 | palette[regno].red; | ||
3085 | *green = | ||
3086 | l_fb_info->palette[regno].green << 8 | l_fb_info-> | ||
3087 | palette[regno].green; | ||
3088 | *blue = | ||
3089 | l_fb_info->palette[regno].blue << 8 | l_fb_info-> | ||
3090 | palette[regno].blue; | ||
3091 | *transp = | ||
3092 | l_fb_info->palette[regno].transp << 8 | l_fb_info-> | ||
3093 | palette[regno].transp; | ||
3094 | } | ||
3095 | return (regno > 255); | ||
3096 | } | 561 | } |
3097 | 562 | ||
3098 | static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, | 563 | static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green, |
3099 | unsigned blue, unsigned transp, | 564 | unsigned blue, unsigned transp, |
3100 | struct fb_info *info) | 565 | struct fb_info *info) |
3101 | { | 566 | { |
3102 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; | 567 | struct pm3_par *par = info->par; |
3103 | 568 | ||
3104 | DTRACE; | 569 | if (regno >= 256) /* no. of hw registers */ |
570 | return -EINVAL; | ||
571 | |||
572 | /* grayscale works only partially under directcolor */ | ||
573 | if (info->var.grayscale) { | ||
574 | /* grayscale = 0.30*R + 0.59*G + 0.11*B */ | ||
575 | red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; | ||
576 | } | ||
577 | |||
578 | /* Directcolor: | ||
579 | * var->{color}.offset contains start of bitfield | ||
580 | * var->{color}.length contains length of bitfield | ||
581 | * {hardwarespecific} contains width of DAC | ||
582 | * pseudo_palette[X] is programmed to (X << red.offset) | | ||
583 | * (X << green.offset) | | ||
584 | * (X << blue.offset) | ||
585 | * RAMDAC[X] is programmed to (red, green, blue) | ||
586 | * color depth = SUM(var->{color}.length) | ||
587 | * | ||
588 | * Pseudocolor: | ||
589 | * var->{color}.offset is 0 | ||
590 | * var->{color}.length contains width of DAC or the number of unique | ||
591 | * colors available (color depth) | ||
592 | * pseudo_palette is not used | ||
593 | * RAMDAC[X] is programmed to (red, green, blue) | ||
594 | * color depth = var->{color}.length | ||
595 | */ | ||
3105 | 596 | ||
3106 | if (regno < 16) { | 597 | /* |
3107 | switch (l_fb_info->current_par->depth) { | 598 | * This is the point where the color is converted to something that |
3108 | #ifdef FBCON_HAS_CFB8 | 599 | * is acceptable by the hardware. |
600 | */ | ||
601 | #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) | ||
602 | red = CNVT_TOHW(red, info->var.red.length); | ||
603 | green = CNVT_TOHW(green, info->var.green.length); | ||
604 | blue = CNVT_TOHW(blue, info->var.blue.length); | ||
605 | transp = CNVT_TOHW(transp, info->var.transp.length); | ||
606 | #undef CNVT_TOHW | ||
607 | |||
608 | if (info->fix.visual == FB_VISUAL_TRUECOLOR || | ||
609 | info->fix.visual == FB_VISUAL_DIRECTCOLOR) { | ||
610 | u32 v; | ||
611 | |||
612 | if (regno >= 16) | ||
613 | return -EINVAL; | ||
614 | |||
615 | v = (red << info->var.red.offset) | | ||
616 | (green << info->var.green.offset) | | ||
617 | (blue << info->var.blue.offset) | | ||
618 | (transp << info->var.transp.offset); | ||
619 | |||
620 | switch (info->var.bits_per_pixel) { | ||
3109 | case 8: | 621 | case 8: |
3110 | break; | 622 | break; |
3111 | #endif | ||
3112 | #ifdef FBCON_HAS_CFB16 | ||
3113 | case 12: | ||
3114 | l_fb_info->cmap.cmap12[regno] = | ||
3115 | (((u32) red & 0xf000) >> 4) | | ||
3116 | (((u32) green & 0xf000) >> 8) | | ||
3117 | (((u32) blue & 0xf000) >> 12); | ||
3118 | break; | ||
3119 | |||
3120 | case 15: | ||
3121 | l_fb_info->cmap.cmap15[regno] = | ||
3122 | (((u32) red & 0xf800) >> 1) | | ||
3123 | (((u32) green & 0xf800) >> 6) | | ||
3124 | (((u32) blue & 0xf800) >> 11); | ||
3125 | break; | ||
3126 | |||
3127 | case 16: | 623 | case 16: |
3128 | l_fb_info->cmap.cmap16[regno] = | 624 | case 24: |
3129 | ((u32) red & 0xf800) | | ||
3130 | (((u32) green & 0xfc00) >> 5) | | ||
3131 | (((u32) blue & 0xf800) >> 11); | ||
3132 | break; | ||
3133 | #endif | ||
3134 | #ifdef FBCON_HAS_CFB32 | ||
3135 | case 32: | 625 | case 32: |
3136 | l_fb_info->cmap.cmap32[regno] = | 626 | ((u32*)(info->pseudo_palette))[regno] = v; |
3137 | (((u32) transp & 0xff00) << 16) | | ||
3138 | (((u32) red & 0xff00) << 8) | | ||
3139 | (((u32) green & 0xff00)) | | ||
3140 | (((u32) blue & 0xff00) >> 8); | ||
3141 | break; | ||
3142 | #endif | ||
3143 | default: | ||
3144 | DPRINTK(1, "bad depth %u\n", | ||
3145 | l_fb_info->current_par->depth); | ||
3146 | break; | 627 | break; |
3147 | } | 628 | } |
629 | return 0; | ||
3148 | } | 630 | } |
3149 | if (regno < 256) { | 631 | else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) |
3150 | l_fb_info->palette[regno].red = red >> 8; | 632 | pm3fb_set_color(par, regno, red, green, blue); |
3151 | l_fb_info->palette[regno].green = green >> 8; | 633 | |
3152 | l_fb_info->palette[regno].blue = blue >> 8; | 634 | return 0; |
3153 | l_fb_info->palette[regno].transp = transp >> 8; | ||
3154 | if (l_fb_info->current_par->depth == 8) | ||
3155 | pm3fb_set_color(l_fb_info, regno, red >> 8, | ||
3156 | green >> 8, blue >> 8); | ||
3157 | } | ||
3158 | return (regno > 255); | ||
3159 | } | 635 | } |
3160 | 636 | ||
3161 | static int pm3fb_blank(int blank_mode, struct fb_info_gen *info) | 637 | static int pm3fb_pan_display(struct fb_var_screeninfo *var, |
638 | struct fb_info *info) | ||
3162 | { | 639 | { |
3163 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; | 640 | struct pm3_par *par = info->par; |
3164 | u32 video; | 641 | const u32 xres = (var->xres + 31) & ~31; |
3165 | |||
3166 | DTRACE; | ||
3167 | 642 | ||
3168 | if (!current_par_valid[l_fb_info->board_num]) | 643 | par->base = pm3fb_shift_bpp(var->bits_per_pixel, |
3169 | return (1); | 644 | (var->yoffset * xres) |
645 | + var->xoffset); | ||
646 | PM3_SLOW_WRITE_REG(par, PM3ScreenBase, par->base); | ||
647 | return 0; | ||
648 | } | ||
3170 | 649 | ||
3171 | video = l_fb_info->current_par->video; | 650 | static int pm3fb_blank(int blank_mode, struct fb_info *info) |
651 | { | ||
652 | struct pm3_par *par = info->par; | ||
653 | u32 video = par->video; | ||
3172 | 654 | ||
3173 | /* | 655 | /* |
3174 | * Oxygen VX1 - it appears that setting PM3VideoControl and | 656 | * Oxygen VX1 - it appears that setting PM3VideoControl and |
@@ -3181,454 +663,345 @@ static int pm3fb_blank(int blank_mode, struct fb_info_gen *info) | |||
3181 | video |= PM3VideoControl_HSYNC_ACTIVE_HIGH | | 663 | video |= PM3VideoControl_HSYNC_ACTIVE_HIGH | |
3182 | PM3VideoControl_VSYNC_ACTIVE_HIGH; | 664 | PM3VideoControl_VSYNC_ACTIVE_HIGH; |
3183 | 665 | ||
3184 | if (blank_mode > 0) { | 666 | switch (blank_mode) { |
3185 | switch (blank_mode - 1) { | 667 | case FB_BLANK_UNBLANK: |
3186 | 668 | video = video | PM3VideoControl_ENABLE; | |
3187 | case VESA_NO_BLANKING: /* FIXME */ | ||
3188 | video = video & ~(PM3VideoControl_ENABLE); | ||
3189 | break; | ||
3190 | |||
3191 | case VESA_HSYNC_SUSPEND: | ||
3192 | video = video & ~(PM3VideoControl_HSYNC_MASK | | ||
3193 | PM3VideoControl_BLANK_ACTIVE_LOW); | ||
3194 | break; | ||
3195 | case VESA_VSYNC_SUSPEND: | ||
3196 | video = video & ~(PM3VideoControl_VSYNC_MASK | | ||
3197 | PM3VideoControl_BLANK_ACTIVE_LOW); | ||
3198 | break; | ||
3199 | case VESA_POWERDOWN: | ||
3200 | video = video & ~(PM3VideoControl_HSYNC_MASK | | ||
3201 | PM3VideoControl_VSYNC_MASK | | ||
3202 | PM3VideoControl_BLANK_ACTIVE_LOW); | ||
3203 | break; | ||
3204 | default: | ||
3205 | DPRINTK(1, "Unsupported blanking %d\n", | ||
3206 | blank_mode); | ||
3207 | return (1); | ||
3208 | break; | ||
3209 | } | ||
3210 | } | ||
3211 | |||
3212 | PM3_SLOW_WRITE_REG(PM3VideoControl, video); | ||
3213 | |||
3214 | return (0); | ||
3215 | } | ||
3216 | |||
3217 | static void pm3fb_set_disp(const void *par, struct display *disp, | ||
3218 | struct fb_info_gen *info) | ||
3219 | { | ||
3220 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; | ||
3221 | struct pm3fb_par *p = (struct pm3fb_par *) par; | ||
3222 | u32 flags; | ||
3223 | |||
3224 | DTRACE; | ||
3225 | |||
3226 | local_irq_save(flags); | ||
3227 | info->info.screen_base = l_fb_info->v_fb; | ||
3228 | switch (p->depth) { | ||
3229 | #ifdef FBCON_HAS_CFB8 | ||
3230 | case 8: | ||
3231 | #ifdef PM3FB_USE_ACCEL | ||
3232 | if (!(noaccel[l_fb_info->board_num])) | ||
3233 | disp->dispsw = &pm3fb_cfb8; | ||
3234 | else | ||
3235 | #endif /* PM3FB_USE_ACCEL */ | ||
3236 | disp->dispsw = &fbcon_cfb8; | ||
3237 | break; | 669 | break; |
3238 | #endif | 670 | case FB_BLANK_NORMAL: /* FIXME */ |
3239 | #ifdef FBCON_HAS_CFB16 | 671 | video = video & ~(PM3VideoControl_ENABLE); |
3240 | case 12: | ||
3241 | #ifdef PM3FB_USE_ACCEL | ||
3242 | if (!(noaccel[l_fb_info->board_num])) | ||
3243 | disp->dispsw = &pm3fb_cfb16; | ||
3244 | else | ||
3245 | #endif /* PM3FB_USE_ACCEL */ | ||
3246 | disp->dispsw = &fbcon_cfb16; | ||
3247 | disp->dispsw_data = l_fb_info->cmap.cmap12; | ||
3248 | break; | 672 | break; |
3249 | case 15: | 673 | case FB_BLANK_HSYNC_SUSPEND: |
3250 | #ifdef PM3FB_USE_ACCEL | 674 | video = video & ~(PM3VideoControl_HSYNC_MASK | |
3251 | if (!(noaccel[l_fb_info->board_num])) | 675 | PM3VideoControl_BLANK_ACTIVE_LOW); |
3252 | disp->dispsw = &pm3fb_cfb16; | ||
3253 | else | ||
3254 | #endif /* PM3FB_USE_ACCEL */ | ||
3255 | disp->dispsw = &fbcon_cfb16; | ||
3256 | disp->dispsw_data = l_fb_info->cmap.cmap15; | ||
3257 | break; | 676 | break; |
3258 | case 16: | 677 | case FB_BLANK_VSYNC_SUSPEND: |
3259 | #ifdef PM3FB_USE_ACCEL | 678 | video = video & ~(PM3VideoControl_VSYNC_MASK | |
3260 | if (!(noaccel[l_fb_info->board_num])) | 679 | PM3VideoControl_BLANK_ACTIVE_LOW); |
3261 | disp->dispsw = &pm3fb_cfb16; | ||
3262 | else | ||
3263 | #endif /* PM3FB_USE_ACCEL */ | ||
3264 | disp->dispsw = &fbcon_cfb16; | ||
3265 | disp->dispsw_data = l_fb_info->cmap.cmap16; | ||
3266 | break; | 680 | break; |
3267 | #endif | 681 | case FB_BLANK_POWERDOWN: |
3268 | #ifdef FBCON_HAS_CFB32 | 682 | video = video & ~(PM3VideoControl_HSYNC_MASK | |
3269 | case 32: | 683 | PM3VideoControl_VSYNC_MASK | |
3270 | #ifdef PM3FB_USE_ACCEL | 684 | PM3VideoControl_BLANK_ACTIVE_LOW); |
3271 | if (!(noaccel[l_fb_info->board_num])) | ||
3272 | disp->dispsw = &pm3fb_cfb32; | ||
3273 | else | ||
3274 | #endif /* PM3FB_USE_ACCEL */ | ||
3275 | disp->dispsw = &fbcon_cfb32; | ||
3276 | disp->dispsw_data = l_fb_info->cmap.cmap32; | ||
3277 | break; | 685 | break; |
3278 | #endif /* FBCON_HAS_CFB32 */ | ||
3279 | default: | 686 | default: |
3280 | disp->dispsw = &fbcon_dummy; | 687 | DPRINTK("Unsupported blanking %d\n", blank_mode); |
3281 | DPRINTK(1, "Invalid depth, using fbcon_dummy\n"); | 688 | return 1; |
3282 | break; | ||
3283 | } | 689 | } |
3284 | local_irq_restore(flags); | 690 | |
691 | PM3_SLOW_WRITE_REG(par,PM3VideoControl, video); | ||
692 | |||
693 | return 0; | ||
3285 | } | 694 | } |
3286 | 695 | ||
3287 | /* */ | 696 | /* |
3288 | static void pm3fb_detect(void) | 697 | * Frame buffer operations |
3289 | { | 698 | */ |
3290 | struct pci_dev *dev_array[PM3_MAX_BOARD]; | ||
3291 | struct pci_dev *dev = NULL; | ||
3292 | struct pm3fb_info *l_fb_info = &(fb_info[0]); | ||
3293 | unsigned long i, j, done; | ||
3294 | 699 | ||
3295 | DTRACE; | 700 | static struct fb_ops pm3fb_ops = { |
701 | .owner = THIS_MODULE, | ||
702 | .fb_check_var = pm3fb_check_var, | ||
703 | .fb_set_par = pm3fb_set_par, | ||
704 | .fb_setcolreg = pm3fb_setcolreg, | ||
705 | .fb_pan_display = pm3fb_pan_display, | ||
706 | .fb_fillrect = cfb_fillrect, /* Needed !!! */ | ||
707 | .fb_copyarea = cfb_copyarea, /* Needed !!! */ | ||
708 | .fb_imageblit = cfb_imageblit, /* Needed !!! */ | ||
709 | .fb_blank = pm3fb_blank, | ||
710 | }; | ||
3296 | 711 | ||
3297 | for (i = 0; i < PM3_MAX_BOARD; i++) { | 712 | /* ------------------------------------------------------------------------- */ |
3298 | dev_array[i] = NULL; | ||
3299 | fb_info[i].dev = NULL; | ||
3300 | } | ||
3301 | 713 | ||
3302 | dev = pci_get_device(PCI_VENDOR_ID_3DLABS, | 714 | /* |
3303 | PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev); | 715 | * Initialization |
716 | */ | ||
3304 | 717 | ||
3305 | for (i = 0; ((i < PM3_MAX_BOARD) && dev); i++) { | 718 | /* mmio register are already mapped when this function is called */ |
3306 | dev_array[i] = dev; | 719 | /* the pm3fb_fix.smem_start is also set */ |
3307 | dev = pci_get_device(PCI_VENDOR_ID_3DLABS, | 720 | static unsigned long pm3fb_size_memory(struct pm3_par *par) |
3308 | PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev); | 721 | { |
3309 | } | 722 | unsigned long memsize = 0, tempBypass, i, temp1, temp2; |
723 | unsigned char __iomem *screen_mem; | ||
3310 | 724 | ||
3311 | if (dev) { /* more than PM3_MAX_BOARD */ | 725 | pm3fb_fix.smem_len = 64 * 1024 * 1024; /* request full aperture size */ |
3312 | printk(KERN_WARNING "pm3fb: Warning: more than %d boards found\n", | 726 | /* Linear frame buffer - request region and map it. */ |
3313 | PM3_MAX_BOARD); | 727 | if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len, |
728 | "pm3fb smem")) { | ||
729 | printk(KERN_WARNING "pm3fb: Can't reserve smem.\n"); | ||
730 | return 0; | ||
3314 | } | 731 | } |
3315 | 732 | screen_mem = | |
3316 | if (!dev_array[0]) { /* not a single board, abort */ | 733 | ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len); |
3317 | return; | 734 | if (!screen_mem) { |
735 | printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n"); | ||
736 | release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); | ||
737 | return 0; | ||
3318 | } | 738 | } |
3319 | 739 | ||
3320 | /* allocate user-defined boards */ | 740 | /* TODO: card-specific stuff, *before* accessing *any* FB memory */ |
3321 | for (i = 0; i < PM3_MAX_BOARD; i++) { | 741 | /* For Appian Jeronimo 2000 board second head */ |
3322 | if ((bus[i] >= 0) && (slot[i] >= 0) && (func[i] >= 0)) { | 742 | |
3323 | for (j = 0; j < PM3_MAX_BOARD; j++) { | 743 | tempBypass = PM3_READ_REG(par, PM3MemBypassWriteMask); |
3324 | if ((dev_array[j] != NULL) && | 744 | |
3325 | (dev_array[j]->bus->number == bus[i]) | 745 | DPRINTK("PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass); |
3326 | && (PCI_SLOT(dev_array[j]->devfn) == | 746 | |
3327 | slot[i]) | 747 | PM3_SLOW_WRITE_REG(par, PM3MemBypassWriteMask, 0xFFFFFFFF); |
3328 | && (PCI_FUNC(dev_array[j]->devfn) == | 748 | |
3329 | func[i])) { | 749 | /* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */ |
3330 | fb_info[i].dev = dev_array[j]; | 750 | for (i = 0; i < 32; i++) { |
3331 | dev_array[j] = NULL; | 751 | fb_writel(i * 0x00345678, |
3332 | } | 752 | (screen_mem + (i * 1048576))); |
3333 | } | 753 | mb(); |
3334 | } | 754 | temp1 = fb_readl((screen_mem + (i * 1048576))); |
755 | |||
756 | /* Let's check for wrapover, write will fail at 16MB boundary */ | ||
757 | if (temp1 == (i * 0x00345678)) | ||
758 | memsize = i; | ||
759 | else | ||
760 | break; | ||
3335 | } | 761 | } |
3336 | /* allocate remaining boards */ | 762 | |
3337 | for (i = 0; i < PM3_MAX_BOARD; i++) { | 763 | DPRINTK("First detect pass already got %ld MB\n", memsize + 1); |
3338 | if (fb_info[i].dev == NULL) { | 764 | |
3339 | done = 0; | 765 | if (memsize + 1 == i) { |
3340 | for (j = 0; ((j < PM3_MAX_BOARD) && (!done)); j++) { | 766 | for (i = 0; i < 32; i++) { |
3341 | if (dev_array[j] != NULL) { | 767 | /* Clear first 32MB ; 0 is 0, no need to byteswap */ |
3342 | fb_info[i].dev = dev_array[j]; | 768 | writel(0x0000000, |
3343 | dev_array[j] = NULL; | 769 | (screen_mem + (i * 1048576))); |
3344 | done = 1; | 770 | mb(); |
3345 | } | ||
3346 | } | ||
3347 | } | 771 | } |
3348 | } | ||
3349 | 772 | ||
3350 | /* at that point, all PCI Permedia3 are detected and allocated */ | 773 | for (i = 32; i < 64; i++) { |
3351 | /* now, initialize... or not */ | 774 | fb_writel(i * 0x00345678, |
3352 | for (i = 0; i < PM3_MAX_BOARD; i++) { | 775 | (screen_mem + (i * 1048576))); |
3353 | l_fb_info = &(fb_info[i]); | 776 | mb(); |
3354 | if (l_fb_info->dev && !disable[i]) { /* PCI device was found and not disabled by user */ | 777 | temp1 = |
3355 | DPRINTK(2, | 778 | fb_readl((screen_mem + (i * 1048576))); |
3356 | "found @%lx Vendor %lx Device %lx ; base @ : %lx - %lx - %lx - %lx - %lx - %lx, irq %ld\n", | 779 | temp2 = |
3357 | (unsigned long) l_fb_info->dev, | 780 | fb_readl((screen_mem + ((i - 32) * 1048576))); |
3358 | (unsigned long) l_fb_info->dev->vendor, | 781 | /* different value, different RAM... */ |
3359 | (unsigned long) l_fb_info->dev->device, | 782 | if ((temp1 == (i * 0x00345678)) && (temp2 == 0)) |
3360 | (unsigned long) | 783 | memsize = i; |
3361 | pci_resource_start(l_fb_info->dev, 0), | 784 | else |
3362 | (unsigned long) | 785 | break; |
3363 | pci_resource_start(l_fb_info->dev, 1), | ||
3364 | (unsigned long) | ||
3365 | pci_resource_start(l_fb_info->dev, 2), | ||
3366 | (unsigned long) | ||
3367 | pci_resource_start(l_fb_info->dev, 3), | ||
3368 | (unsigned long) | ||
3369 | pci_resource_start(l_fb_info->dev, 4), | ||
3370 | (unsigned long) | ||
3371 | pci_resource_start(l_fb_info->dev, 5), | ||
3372 | (unsigned long) l_fb_info->dev->irq); | ||
3373 | |||
3374 | l_fb_info->pIOBase = | ||
3375 | (unsigned char *) | ||
3376 | pci_resource_start(l_fb_info->dev, 0); | ||
3377 | #ifdef __BIG_ENDIAN | ||
3378 | l_fb_info->pIOBase += PM3_REGS_SIZE; | ||
3379 | #endif | ||
3380 | l_fb_info->vIOBase = (unsigned char *) -1; | ||
3381 | l_fb_info->p_fb = | ||
3382 | (unsigned char *) | ||
3383 | pci_resource_start(l_fb_info->dev, 1); | ||
3384 | l_fb_info->v_fb = (unsigned char *) -1; | ||
3385 | |||
3386 | if (!request_mem_region | ||
3387 | ((unsigned long)l_fb_info->p_fb, 64 * 1024 * 1024, /* request full aperture size */ | ||
3388 | "pm3fb")) { | ||
3389 | printk | ||
3390 | (KERN_ERR "pm3fb: Error: couldn't request framebuffer memory, board #%ld\n", | ||
3391 | l_fb_info->board_num); | ||
3392 | continue; | ||
3393 | } | ||
3394 | if (!request_mem_region | ||
3395 | ((unsigned long)l_fb_info->pIOBase, PM3_REGS_SIZE, | ||
3396 | "pm3fb I/O regs")) { | ||
3397 | printk | ||
3398 | (KERN_ERR "pm3fb: Error: couldn't request IObase memory, board #%ld\n", | ||
3399 | l_fb_info->board_num); | ||
3400 | continue; | ||
3401 | } | ||
3402 | if (forcesize[l_fb_info->board_num]) | ||
3403 | l_fb_info->fb_size = forcesize[l_fb_info->board_num]; | ||
3404 | |||
3405 | l_fb_info->fb_size = | ||
3406 | pm3fb_size_memory(l_fb_info); | ||
3407 | if (l_fb_info->fb_size) { | ||
3408 | (void) pci_enable_device(l_fb_info->dev); | ||
3409 | pm3fb_common_init(l_fb_info); | ||
3410 | } else | ||
3411 | printk(KERN_ERR "pm3fb: memory problem, not enabling board #%ld\n", l_fb_info->board_num); | ||
3412 | } | 786 | } |
3413 | } | 787 | } |
3414 | } | 788 | DPRINTK("Second detect pass got %ld MB\n", memsize + 1); |
3415 | 789 | ||
3416 | static int pm3fb_pan_display(const struct fb_var_screeninfo *var, | 790 | PM3_SLOW_WRITE_REG(par, PM3MemBypassWriteMask, tempBypass); |
3417 | struct fb_info_gen *info) | ||
3418 | { | ||
3419 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; | ||
3420 | 791 | ||
3421 | DTRACE; | 792 | iounmap(screen_mem); |
793 | release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); | ||
794 | memsize = 1048576 * (memsize + 1); | ||
3422 | 795 | ||
3423 | if (!current_par_valid[l_fb_info->board_num]) | 796 | DPRINTK("Returning 0x%08lx bytes\n", memsize); |
3424 | return -EINVAL; | ||
3425 | 797 | ||
3426 | l_fb_info->current_par->base = /* in 128 bits chunk - i.e. AFTER Shiftbpp */ | 798 | return memsize; |
3427 | pm3fb_Shiftbpp(l_fb_info, | ||
3428 | l_fb_info->current_par->depth, | ||
3429 | (var->yoffset * l_fb_info->current_par->width) + | ||
3430 | var->xoffset); | ||
3431 | PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base); | ||
3432 | return 0; | ||
3433 | } | 799 | } |
3434 | 800 | ||
3435 | static int pm3fb_ioctl(struct fb_info *info, u_int cmd, u_long arg) | 801 | static int __devinit pm3fb_probe(struct pci_dev *dev, |
802 | const struct pci_device_id *ent) | ||
3436 | { | 803 | { |
3437 | struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info; | 804 | struct fb_info *info; |
3438 | u32 cm, i; | 805 | struct pm3_par *par; |
3439 | #ifdef PM3FB_MASTER_DEBUG | 806 | struct device* device = &dev->dev; /* for pci drivers */ |
3440 | char cc[3]; | 807 | int err, retval = -ENXIO; |
3441 | #endif /* PM3FB_MASTER_DEBUG */ | ||
3442 | 808 | ||
3443 | switch(cmd) | 809 | err = pci_enable_device(dev); |
3444 | { | 810 | if (err) { |
3445 | #ifdef PM3FB_MASTER_DEBUG | 811 | printk(KERN_WARNING "pm3fb: Can't enable PCI dev: %d\n", err); |
3446 | case PM3FBIO_CLEARMEMORY: | 812 | return err; |
3447 | if (copy_from_user(&cm, (void *)arg, sizeof(u32))) | 813 | } |
3448 | return(-EFAULT); | 814 | /* |
3449 | pm3fb_clear_memory(l_fb_info, cm); | 815 | * Dynamically allocate info and par |
3450 | return(0); | 816 | */ |
3451 | break; | 817 | info = framebuffer_alloc(sizeof(struct pm3_par), device); |
3452 | 818 | ||
3453 | case PM3FBIO_CLEARCMAP: | 819 | if (!info) |
3454 | if (copy_from_user(cc, (void*)arg, 3 * sizeof(char))) | 820 | return -ENOMEM; |
3455 | return(-EFAULT); | 821 | par = info->par; |
3456 | pm3fb_clear_colormap(l_fb_info, cc[0], cc[1], cc[2]); | ||
3457 | return(0); | ||
3458 | break; | ||
3459 | #endif /* PM3FB_MASTER_DEBUG */ | ||
3460 | |||
3461 | case PM3FBIO_RESETCHIP: | ||
3462 | cm = 1; | ||
3463 | PM3_SLOW_WRITE_REG(PM3ResetStatus, 1); | ||
3464 | for (i = 0 ; (i < 10000) && cm ; i++) | ||
3465 | { | ||
3466 | PM3_DELAY(10); | ||
3467 | cm = PM3_READ_REG(PM3ResetStatus); | ||
3468 | } | ||
3469 | if (cm) | ||
3470 | { | ||
3471 | printk(KERN_ERR "pm3fb: chip reset failed with status 0x%x\n", cm); | ||
3472 | return(-EIO); | ||
3473 | } | ||
3474 | /* first thing first, reload memory timings */ | ||
3475 | pm3fb_write_memory_timings(l_fb_info); | ||
3476 | #ifdef PM3FB_USE_ACCEL | ||
3477 | pm3fb_init_engine(l_fb_info); | ||
3478 | #endif /* PM3FB_USE_ACCEL */ | ||
3479 | pm3fb_write_mode(l_fb_info); | ||
3480 | return(0); | ||
3481 | break; | ||
3482 | 822 | ||
3483 | default: | 823 | /* |
3484 | DPRINTK(2, "unknown ioctl: %d (%x)\n", cmd, cmd); | 824 | * Here we set the screen_base to the virtual memory address |
3485 | return(-EINVAL); | 825 | * for the framebuffer. |
826 | */ | ||
827 | pm3fb_fix.mmio_start = pci_resource_start(dev, 0); | ||
828 | pm3fb_fix.mmio_len = PM3_REGS_SIZE; | ||
829 | |||
830 | /* Registers - request region and map it. */ | ||
831 | if (!request_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len, | ||
832 | "pm3fb regbase")) { | ||
833 | printk(KERN_WARNING "pm3fb: Can't reserve regbase.\n"); | ||
834 | goto err_exit_neither; | ||
835 | } | ||
836 | par->v_regs = | ||
837 | ioremap_nocache(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); | ||
838 | if (!par->v_regs) { | ||
839 | printk(KERN_WARNING "pm3fb: Can't remap %s register area.\n", | ||
840 | pm3fb_fix.id); | ||
841 | release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); | ||
842 | goto err_exit_neither; | ||
843 | } | ||
844 | |||
845 | #if defined(__BIG_ENDIAN) | ||
846 | pm3fb_fix.mmio_start += PM3_REGS_SIZE; | ||
847 | DPRINTK("Adjusting register base for big-endian.\n"); | ||
848 | #endif | ||
849 | /* Linear frame buffer - request region and map it. */ | ||
850 | pm3fb_fix.smem_start = pci_resource_start(dev, 1); | ||
851 | pm3fb_fix.smem_len = pm3fb_size_memory(par); | ||
852 | if (!pm3fb_fix.smem_len) | ||
853 | { | ||
854 | printk(KERN_WARNING "pm3fb: Can't find memory on board.\n"); | ||
855 | goto err_exit_mmio; | ||
3486 | } | 856 | } |
3487 | } | 857 | if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len, |
3488 | 858 | "pm3fb smem")) { | |
3489 | /* ****************************************** */ | 859 | printk(KERN_WARNING "pm3fb: Can't reserve smem.\n"); |
3490 | /* ***** standard FB API init functions ***** */ | 860 | goto err_exit_mmio; |
3491 | /* ****************************************** */ | 861 | } |
862 | info->screen_base = | ||
863 | ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len); | ||
864 | if (!info->screen_base) { | ||
865 | printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n"); | ||
866 | release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); | ||
867 | goto err_exit_mmio; | ||
868 | } | ||
869 | info->screen_size = pm3fb_fix.smem_len; | ||
3492 | 870 | ||
3493 | int __init pm3fb_setup(char *options) | 871 | info->fbops = &pm3fb_ops; |
3494 | { | ||
3495 | long opsi = strlen(options); | ||
3496 | 872 | ||
3497 | DTRACE; | 873 | par->video = PM3_READ_REG(par, PM3VideoControl); |
3498 | 874 | ||
3499 | memcpy(g_options, options, | 875 | info->fix = pm3fb_fix; |
3500 | ((opsi + 1) > | 876 | info->pseudo_palette = par->palette; |
3501 | PM3_OPTIONS_SIZE) ? PM3_OPTIONS_SIZE : (opsi + 1)); | 877 | info->flags = FBINFO_DEFAULT;/* | FBINFO_HWACCEL_YPAN;*/ |
3502 | g_options[PM3_OPTIONS_SIZE - 1] = 0; | ||
3503 | 878 | ||
3504 | return (0); | 879 | /* |
3505 | } | 880 | * This should give a reasonable default video mode. The following is |
881 | * done when we can set a video mode. | ||
882 | */ | ||
883 | if (!mode_option) | ||
884 | mode_option = "640x480@60"; | ||
3506 | 885 | ||
3507 | int __init pm3fb_init(void) | 886 | retval = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); |
3508 | { | ||
3509 | DTRACE; | ||
3510 | 887 | ||
3511 | DPRINTK(2, "This is pm3fb.c, CVS version: $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $"); | 888 | if (!retval || retval == 4) { |
889 | retval = -EINVAL; | ||
890 | goto err_exit_both; | ||
891 | } | ||
3512 | 892 | ||
3513 | pm3fb_real_setup(g_options); | 893 | /* This has to been done !!! */ |
894 | if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { | ||
895 | retval = -ENOMEM; | ||
896 | goto err_exit_both; | ||
897 | } | ||
3514 | 898 | ||
3515 | pm3fb_detect(); | 899 | /* |
900 | * For drivers that can... | ||
901 | */ | ||
902 | pm3fb_check_var(&info->var, info); | ||
3516 | 903 | ||
3517 | if (!fb_info[0].dev) { /* not even one board ??? */ | 904 | if (register_framebuffer(info) < 0) { |
3518 | DPRINTK(1, "No PCI Permedia3 board detected\n"); | 905 | retval = -EINVAL; |
906 | goto err_exit_all; | ||
3519 | } | 907 | } |
3520 | return (0); | 908 | printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, |
909 | info->fix.id); | ||
910 | pci_set_drvdata(dev, info); /* or dev_set_drvdata(device, info) */ | ||
911 | return 0; | ||
912 | |||
913 | err_exit_all: | ||
914 | fb_dealloc_cmap(&info->cmap); | ||
915 | err_exit_both: | ||
916 | iounmap(info->screen_base); | ||
917 | release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len); | ||
918 | err_exit_mmio: | ||
919 | iounmap(par->v_regs); | ||
920 | release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len); | ||
921 | err_exit_neither: | ||
922 | framebuffer_release(info); | ||
923 | return retval; | ||
3521 | } | 924 | } |
3522 | 925 | ||
3523 | /* ************************* */ | 926 | /* |
3524 | /* **** Module support ***** */ | 927 | * Cleanup |
3525 | /* ************************* */ | 928 | */ |
929 | static void __devexit pm3fb_remove(struct pci_dev *dev) | ||
930 | { | ||
931 | struct fb_info *info = pci_get_drvdata(dev); | ||
3526 | 932 | ||
3527 | #ifdef MODULE | 933 | if (info) { |
3528 | MODULE_AUTHOR("Romain Dolbeau"); | 934 | struct fb_fix_screeninfo *fix = &info->fix; |
3529 | MODULE_DESCRIPTION("Permedia3 framebuffer device driver"); | 935 | struct pm3_par *par = info->par; |
3530 | static char *mode[PM3_MAX_BOARD]; | ||
3531 | module_param_array(mode, charp, NULL, 0); | ||
3532 | MODULE_PARM_DESC(mode,"video mode"); | ||
3533 | module_param_array(disable, short, NULL, 0); | ||
3534 | MODULE_PARM_DESC(disable,"disable board"); | ||
3535 | static short off[PM3_MAX_BOARD]; | ||
3536 | module_param_array(off, short, NULL, 0); | ||
3537 | MODULE_PARM_DESC(off,"disable board"); | ||
3538 | static char *pciid[PM3_MAX_BOARD]; | ||
3539 | module_param_array(pciid, charp, NULL, 0); | ||
3540 | MODULE_PARM_DESC(pciid,"board PCI Id"); | ||
3541 | module_param_array(noaccel, short, NULL, 0); | ||
3542 | MODULE_PARM_DESC(noaccel,"disable accel"); | ||
3543 | static char *font[PM3_MAX_BOARD]; | ||
3544 | module_param_array(font, charp, NULL, 0); | ||
3545 | MODULE_PARM_DESC(font,"choose font"); | ||
3546 | module_param(depth, short, NULL, 0); | ||
3547 | MODULE_PARM_DESC(depth,"boot-time depth"); | ||
3548 | module_param(printtimings, short, NULL, 0); | ||
3549 | MODULE_PARM_DESC(printtimings, "print the memory timings of the card(s)"); | ||
3550 | module_param(forcesize, short, NULL, 0); | ||
3551 | MODULE_PARM_DESC(forcesize, "force specified memory size"); | ||
3552 | /* | ||
3553 | MODULE_SUPPORTED_DEVICE("Permedia3 PCI boards") | ||
3554 | MODULE_GENERIC_TABLE(gtype,name) | ||
3555 | MODULE_DEVICE_TABLE(type,name) | ||
3556 | */ | ||
3557 | 936 | ||
3558 | void pm3fb_build_options(void) | 937 | unregister_framebuffer(info); |
3559 | { | 938 | fb_dealloc_cmap(&info->cmap); |
3560 | int i; | ||
3561 | char ts[128]; | ||
3562 | 939 | ||
3563 | strcpy(g_options, "pm3fb"); | 940 | iounmap(info->screen_base); |
3564 | for (i = 0; i < PM3_MAX_BOARD ; i++) | 941 | release_mem_region(fix->smem_start, fix->smem_len); |
3565 | { | 942 | iounmap(par->v_regs); |
3566 | if (mode[i]) | 943 | release_mem_region(fix->mmio_start, fix->mmio_len); |
3567 | { | 944 | |
3568 | sprintf(ts, ",mode:%d:%s", i, mode[i]); | 945 | pci_set_drvdata(dev, NULL); |
3569 | strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); | 946 | framebuffer_release(info); |
3570 | } | ||
3571 | if (disable[i] || off[i]) | ||
3572 | { | ||
3573 | sprintf(ts, ",disable:%d:", i); | ||
3574 | strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); | ||
3575 | } | ||
3576 | if (pciid[i]) | ||
3577 | { | ||
3578 | sprintf(ts, ",pciid:%d:%s", i, pciid[i]); | ||
3579 | strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); | ||
3580 | } | ||
3581 | if (noaccel[i]) | ||
3582 | { | ||
3583 | sprintf(ts, ",noaccel:%d:", i); | ||
3584 | strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); | ||
3585 | } | ||
3586 | if (font[i]) | ||
3587 | { | ||
3588 | sprintf(ts, ",font:%d:%s", i, font[i]); | ||
3589 | strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); | ||
3590 | } | ||
3591 | if (depth[i]) | ||
3592 | { | ||
3593 | sprintf(ts, ",depth:%d:%d", i, depth[i]); | ||
3594 | strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options)); | ||
3595 | } | ||
3596 | } | 947 | } |
3597 | g_options[PM3_OPTIONS_SIZE - 1] = '\0'; | ||
3598 | DPRINTK(1, "pm3fb use options: %s\n", g_options); | ||
3599 | } | 948 | } |
3600 | 949 | ||
3601 | int init_module(void) | 950 | static struct pci_device_id pm3fb_id_table[] = { |
951 | { PCI_VENDOR_ID_3DLABS, 0x0a, | ||
952 | PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, | ||
953 | 0xff0000, 0 }, | ||
954 | { 0, } | ||
955 | }; | ||
956 | |||
957 | /* For PCI drivers */ | ||
958 | static struct pci_driver pm3fb_driver = { | ||
959 | .name = "pm3fb", | ||
960 | .id_table = pm3fb_id_table, | ||
961 | .probe = pm3fb_probe, | ||
962 | .remove = __devexit_p(pm3fb_remove), | ||
963 | }; | ||
964 | |||
965 | MODULE_DEVICE_TABLE(pci, pm3fb_id_table); | ||
966 | |||
967 | int __init pm3fb_init(void) | ||
3602 | { | 968 | { |
3603 | DTRACE; | 969 | /* |
970 | * For kernel boot options (in 'video=pm3fb:<options>' format) | ||
971 | */ | ||
972 | #ifndef MODULE | ||
973 | char *option = NULL; | ||
3604 | 974 | ||
3605 | pm3fb_build_options(); | 975 | if (fb_get_options("pm3fb", &option)) |
976 | return -ENODEV; | ||
977 | pm3fb_setup(option); | ||
978 | #endif | ||
3606 | 979 | ||
3607 | pm3fb_init(); | 980 | return pci_register_driver(&pm3fb_driver); |
981 | } | ||
3608 | 982 | ||
3609 | return 0; | 983 | static void __exit pm3fb_exit(void) |
984 | { | ||
985 | pci_unregister_driver(&pm3fb_driver); | ||
3610 | } | 986 | } |
3611 | 987 | ||
3612 | void cleanup_module(void) | 988 | #ifdef MODULE |
989 | /* | ||
990 | * Setup | ||
991 | */ | ||
992 | |||
993 | /* | ||
994 | * Only necessary if your driver takes special options, | ||
995 | * otherwise we fall back on the generic fb_setup(). | ||
996 | */ | ||
997 | int __init pm3fb_setup(char *options) | ||
3613 | { | 998 | { |
3614 | DTRACE; | 999 | /* Parse user speficied options (`video=pm3fb:') */ |
3615 | { | 1000 | return 0; |
3616 | unsigned long i; | ||
3617 | struct pm3fb_info *l_fb_info; | ||
3618 | for (i = 0; i < PM3_MAX_BOARD; i++) { | ||
3619 | l_fb_info = &(fb_info[i]); | ||
3620 | pci_dev_put(l_fb_info->dev); | ||
3621 | if (l_fb_info->dev != NULL && !(disable[l_fb_info->board_num])) { | ||
3622 | if (l_fb_info->vIOBase != (unsigned char *) -1) { | ||
3623 | pm3fb_unmapIO(l_fb_info); | ||
3624 | release_mem_region(l_fb_info->p_fb, | ||
3625 | l_fb_info->fb_size); | ||
3626 | release_mem_region(l_fb_info->pIOBase, | ||
3627 | PM3_REGS_SIZE); | ||
3628 | } | ||
3629 | unregister_framebuffer(&l_fb_info->gen.info); | ||
3630 | } | ||
3631 | } | ||
3632 | } | ||
3633 | } | 1001 | } |
3634 | #endif /* MODULE */ | 1002 | #endif /* MODULE */ |
1003 | |||
1004 | module_init(pm3fb_init); | ||
1005 | module_exit(pm3fb_exit); | ||
1006 | |||
1007 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/riva/rivafb-i2c.c b/drivers/video/riva/rivafb-i2c.c index 76e6ce353c8e..a0e22ac483a3 100644 --- a/drivers/video/riva/rivafb-i2c.c +++ b/drivers/video/riva/rivafb-i2c.c | |||
@@ -70,8 +70,6 @@ static int riva_gpio_getscl(void* data) | |||
70 | if (VGA_RD08(par->riva.PCIO, 0x3d5) & 0x04) | 70 | if (VGA_RD08(par->riva.PCIO, 0x3d5) & 0x04) |
71 | val = 1; | 71 | val = 1; |
72 | 72 | ||
73 | val = VGA_RD08(par->riva.PCIO, 0x3d5); | ||
74 | |||
75 | return val; | 73 | return val; |
76 | } | 74 | } |
77 | 75 | ||
diff --git a/fs/Makefile b/fs/Makefile index 9edf4112bee0..720c29d57a62 100644 --- a/fs/Makefile +++ b/fs/Makefile | |||
@@ -22,6 +22,10 @@ endif | |||
22 | obj-$(CONFIG_INOTIFY) += inotify.o | 22 | obj-$(CONFIG_INOTIFY) += inotify.o |
23 | obj-$(CONFIG_INOTIFY_USER) += inotify_user.o | 23 | obj-$(CONFIG_INOTIFY_USER) += inotify_user.o |
24 | obj-$(CONFIG_EPOLL) += eventpoll.o | 24 | obj-$(CONFIG_EPOLL) += eventpoll.o |
25 | obj-$(CONFIG_ANON_INODES) += anon_inodes.o | ||
26 | obj-$(CONFIG_SIGNALFD) += signalfd.o | ||
27 | obj-$(CONFIG_TIMERFD) += timerfd.o | ||
28 | obj-$(CONFIG_EVENTFD) += eventfd.o | ||
25 | obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o | 29 | obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o |
26 | 30 | ||
27 | nfsd-$(CONFIG_NFSD) := nfsctl.o | 31 | nfsd-$(CONFIG_NFSD) := nfsctl.o |
diff --git a/fs/afs/afs.h b/fs/afs/afs.h index 52d0752265b8..245257948140 100644 --- a/fs/afs/afs.h +++ b/fs/afs/afs.h | |||
@@ -16,6 +16,9 @@ | |||
16 | 16 | ||
17 | #define AFS_MAXCELLNAME 64 /* maximum length of a cell name */ | 17 | #define AFS_MAXCELLNAME 64 /* maximum length of a cell name */ |
18 | #define AFS_MAXVOLNAME 64 /* maximum length of a volume name */ | 18 | #define AFS_MAXVOLNAME 64 /* maximum length of a volume name */ |
19 | #define AFSNAMEMAX 256 /* maximum length of a filename plus NUL */ | ||
20 | #define AFSPATHMAX 1024 /* maximum length of a pathname plus NUL */ | ||
21 | #define AFSOPAQUEMAX 1024 /* maximum length of an opaque field */ | ||
19 | 22 | ||
20 | typedef unsigned afs_volid_t; | 23 | typedef unsigned afs_volid_t; |
21 | typedef unsigned afs_vnodeid_t; | 24 | typedef unsigned afs_vnodeid_t; |
@@ -143,4 +146,24 @@ struct afs_volsync { | |||
143 | time_t creation; /* volume creation time */ | 146 | time_t creation; /* volume creation time */ |
144 | }; | 147 | }; |
145 | 148 | ||
149 | /* | ||
150 | * AFS volume status record | ||
151 | */ | ||
152 | struct afs_volume_status { | ||
153 | u32 vid; /* volume ID */ | ||
154 | u32 parent_id; /* parent volume ID */ | ||
155 | u8 online; /* true if volume currently online and available */ | ||
156 | u8 in_service; /* true if volume currently in service */ | ||
157 | u8 blessed; /* same as in_service */ | ||
158 | u8 needs_salvage; /* true if consistency checking required */ | ||
159 | u32 type; /* volume type (afs_voltype_t) */ | ||
160 | u32 min_quota; /* minimum space set aside (blocks) */ | ||
161 | u32 max_quota; /* maximum space this volume may occupy (blocks) */ | ||
162 | u32 blocks_in_use; /* space this volume currently occupies (blocks) */ | ||
163 | u32 part_blocks_avail; /* space available in volume's partition */ | ||
164 | u32 part_max_blocks; /* size of volume's partition */ | ||
165 | }; | ||
166 | |||
167 | #define AFS_BLOCK_SIZE 1024 | ||
168 | |||
146 | #endif /* AFS_H */ | 169 | #endif /* AFS_H */ |
diff --git a/fs/afs/afs_fs.h b/fs/afs/afs_fs.h index d963ef4daee8..a18c374ebe08 100644 --- a/fs/afs/afs_fs.h +++ b/fs/afs/afs_fs.h | |||
@@ -28,7 +28,8 @@ enum AFS_FS_Operations { | |||
28 | FSMAKEDIR = 141, /* AFS Create a directory */ | 28 | FSMAKEDIR = 141, /* AFS Create a directory */ |
29 | FSREMOVEDIR = 142, /* AFS Remove a directory */ | 29 | FSREMOVEDIR = 142, /* AFS Remove a directory */ |
30 | FSGIVEUPCALLBACKS = 147, /* AFS Discard callback promises */ | 30 | FSGIVEUPCALLBACKS = 147, /* AFS Discard callback promises */ |
31 | FSGETVOLUMEINFO = 148, /* AFS Get root volume information */ | 31 | FSGETVOLUMEINFO = 148, /* AFS Get information about a volume */ |
32 | FSGETVOLUMESTATUS = 149, /* AFS Get volume status information */ | ||
32 | FSGETROOTVOLUME = 151, /* AFS Get root volume name */ | 33 | FSGETROOTVOLUME = 151, /* AFS Get root volume name */ |
33 | FSLOOKUP = 161, /* AFS lookup file in directory */ | 34 | FSLOOKUP = 161, /* AFS lookup file in directory */ |
34 | FSFETCHDATA64 = 65537, /* AFS Fetch file data */ | 35 | FSFETCHDATA64 = 65537, /* AFS Fetch file data */ |
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 2fb31276196b..719af4fb15dc 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
@@ -497,7 +497,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, | |||
497 | 497 | ||
498 | ASSERTCMP(dentry->d_inode, ==, NULL); | 498 | ASSERTCMP(dentry->d_inode, ==, NULL); |
499 | 499 | ||
500 | if (dentry->d_name.len > 255) { | 500 | if (dentry->d_name.len >= AFSNAMEMAX) { |
501 | _leave(" = -ENAMETOOLONG"); | 501 | _leave(" = -ENAMETOOLONG"); |
502 | return ERR_PTR(-ENAMETOOLONG); | 502 | return ERR_PTR(-ENAMETOOLONG); |
503 | } | 503 | } |
@@ -736,7 +736,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
736 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode); | 736 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode); |
737 | 737 | ||
738 | ret = -ENAMETOOLONG; | 738 | ret = -ENAMETOOLONG; |
739 | if (dentry->d_name.len > 255) | 739 | if (dentry->d_name.len >= AFSNAMEMAX) |
740 | goto error; | 740 | goto error; |
741 | 741 | ||
742 | key = afs_request_key(dvnode->volume->cell); | 742 | key = afs_request_key(dvnode->volume->cell); |
@@ -801,7 +801,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry) | |||
801 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name); | 801 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name); |
802 | 802 | ||
803 | ret = -ENAMETOOLONG; | 803 | ret = -ENAMETOOLONG; |
804 | if (dentry->d_name.len > 255) | 804 | if (dentry->d_name.len >= AFSNAMEMAX) |
805 | goto error; | 805 | goto error; |
806 | 806 | ||
807 | key = afs_request_key(dvnode->volume->cell); | 807 | key = afs_request_key(dvnode->volume->cell); |
@@ -847,7 +847,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) | |||
847 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name); | 847 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name); |
848 | 848 | ||
849 | ret = -ENAMETOOLONG; | 849 | ret = -ENAMETOOLONG; |
850 | if (dentry->d_name.len > 255) | 850 | if (dentry->d_name.len >= AFSNAMEMAX) |
851 | goto error; | 851 | goto error; |
852 | 852 | ||
853 | key = afs_request_key(dvnode->volume->cell); | 853 | key = afs_request_key(dvnode->volume->cell); |
@@ -921,7 +921,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
921 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode); | 921 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode); |
922 | 922 | ||
923 | ret = -ENAMETOOLONG; | 923 | ret = -ENAMETOOLONG; |
924 | if (dentry->d_name.len > 255) | 924 | if (dentry->d_name.len >= AFSNAMEMAX) |
925 | goto error; | 925 | goto error; |
926 | 926 | ||
927 | key = afs_request_key(dvnode->volume->cell); | 927 | key = afs_request_key(dvnode->volume->cell); |
@@ -990,7 +990,7 @@ static int afs_link(struct dentry *from, struct inode *dir, | |||
990 | dentry->d_name.name); | 990 | dentry->d_name.name); |
991 | 991 | ||
992 | ret = -ENAMETOOLONG; | 992 | ret = -ENAMETOOLONG; |
993 | if (dentry->d_name.len > 255) | 993 | if (dentry->d_name.len >= AFSNAMEMAX) |
994 | goto error; | 994 | goto error; |
995 | 995 | ||
996 | key = afs_request_key(dvnode->volume->cell); | 996 | key = afs_request_key(dvnode->volume->cell); |
@@ -1038,11 +1038,11 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, | |||
1038 | content); | 1038 | content); |
1039 | 1039 | ||
1040 | ret = -ENAMETOOLONG; | 1040 | ret = -ENAMETOOLONG; |
1041 | if (dentry->d_name.len > 255) | 1041 | if (dentry->d_name.len >= AFSNAMEMAX) |
1042 | goto error; | 1042 | goto error; |
1043 | 1043 | ||
1044 | ret = -EINVAL; | 1044 | ret = -EINVAL; |
1045 | if (strlen(content) > 1023) | 1045 | if (strlen(content) >= AFSPATHMAX) |
1046 | goto error; | 1046 | goto error; |
1047 | 1047 | ||
1048 | key = afs_request_key(dvnode->volume->cell); | 1048 | key = afs_request_key(dvnode->volume->cell); |
@@ -1112,7 +1112,7 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1112 | new_dentry->d_name.name); | 1112 | new_dentry->d_name.name); |
1113 | 1113 | ||
1114 | ret = -ENAMETOOLONG; | 1114 | ret = -ENAMETOOLONG; |
1115 | if (new_dentry->d_name.len > 255) | 1115 | if (new_dentry->d_name.len >= AFSNAMEMAX) |
1116 | goto error; | 1116 | goto error; |
1117 | 1117 | ||
1118 | key = afs_request_key(orig_dvnode->volume->cell); | 1118 | key = afs_request_key(orig_dvnode->volume->cell); |
diff --git a/fs/afs/file.c b/fs/afs/file.c index 3e25795e5a42..9c0e721d9fc2 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c | |||
@@ -236,7 +236,7 @@ static void afs_invalidatepage(struct page *page, unsigned long offset) | |||
236 | { | 236 | { |
237 | int ret = 1; | 237 | int ret = 1; |
238 | 238 | ||
239 | kenter("{%lu},%lu", page->index, offset); | 239 | _enter("{%lu},%lu", page->index, offset); |
240 | 240 | ||
241 | BUG_ON(!PageLocked(page)); | 241 | BUG_ON(!PageLocked(page)); |
242 | 242 | ||
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 56cc0efa2a0c..5dff1308b6f0 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c | |||
@@ -202,6 +202,29 @@ static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr) | |||
202 | } | 202 | } |
203 | 203 | ||
204 | /* | 204 | /* |
205 | * decode an AFSFetchVolumeStatus block | ||
206 | */ | ||
207 | static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp, | ||
208 | struct afs_volume_status *vs) | ||
209 | { | ||
210 | const __be32 *bp = *_bp; | ||
211 | |||
212 | vs->vid = ntohl(*bp++); | ||
213 | vs->parent_id = ntohl(*bp++); | ||
214 | vs->online = ntohl(*bp++); | ||
215 | vs->in_service = ntohl(*bp++); | ||
216 | vs->blessed = ntohl(*bp++); | ||
217 | vs->needs_salvage = ntohl(*bp++); | ||
218 | vs->type = ntohl(*bp++); | ||
219 | vs->min_quota = ntohl(*bp++); | ||
220 | vs->max_quota = ntohl(*bp++); | ||
221 | vs->blocks_in_use = ntohl(*bp++); | ||
222 | vs->part_blocks_avail = ntohl(*bp++); | ||
223 | vs->part_max_blocks = ntohl(*bp++); | ||
224 | *_bp = bp; | ||
225 | } | ||
226 | |||
227 | /* | ||
205 | * deliver reply data to an FS.FetchStatus | 228 | * deliver reply data to an FS.FetchStatus |
206 | */ | 229 | */ |
207 | static int afs_deliver_fs_fetch_status(struct afs_call *call, | 230 | static int afs_deliver_fs_fetch_status(struct afs_call *call, |
@@ -1450,3 +1473,278 @@ int afs_fs_setattr(struct afs_server *server, struct key *key, | |||
1450 | 1473 | ||
1451 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | 1474 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); |
1452 | } | 1475 | } |
1476 | |||
1477 | /* | ||
1478 | * deliver reply data to an FS.GetVolumeStatus | ||
1479 | */ | ||
1480 | static int afs_deliver_fs_get_volume_status(struct afs_call *call, | ||
1481 | struct sk_buff *skb, bool last) | ||
1482 | { | ||
1483 | const __be32 *bp; | ||
1484 | char *p; | ||
1485 | int ret; | ||
1486 | |||
1487 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); | ||
1488 | |||
1489 | switch (call->unmarshall) { | ||
1490 | case 0: | ||
1491 | call->offset = 0; | ||
1492 | call->unmarshall++; | ||
1493 | |||
1494 | /* extract the returned status record */ | ||
1495 | case 1: | ||
1496 | _debug("extract status"); | ||
1497 | ret = afs_extract_data(call, skb, last, call->buffer, | ||
1498 | 12 * 4); | ||
1499 | switch (ret) { | ||
1500 | case 0: break; | ||
1501 | case -EAGAIN: return 0; | ||
1502 | default: return ret; | ||
1503 | } | ||
1504 | |||
1505 | bp = call->buffer; | ||
1506 | xdr_decode_AFSFetchVolumeStatus(&bp, call->reply2); | ||
1507 | call->offset = 0; | ||
1508 | call->unmarshall++; | ||
1509 | |||
1510 | /* extract the volume name length */ | ||
1511 | case 2: | ||
1512 | ret = afs_extract_data(call, skb, last, &call->tmp, 4); | ||
1513 | switch (ret) { | ||
1514 | case 0: break; | ||
1515 | case -EAGAIN: return 0; | ||
1516 | default: return ret; | ||
1517 | } | ||
1518 | |||
1519 | call->count = ntohl(call->tmp); | ||
1520 | _debug("volname length: %u", call->count); | ||
1521 | if (call->count >= AFSNAMEMAX) | ||
1522 | return -EBADMSG; | ||
1523 | call->offset = 0; | ||
1524 | call->unmarshall++; | ||
1525 | |||
1526 | /* extract the volume name */ | ||
1527 | case 3: | ||
1528 | _debug("extract volname"); | ||
1529 | if (call->count > 0) { | ||
1530 | ret = afs_extract_data(call, skb, last, call->reply3, | ||
1531 | call->count); | ||
1532 | switch (ret) { | ||
1533 | case 0: break; | ||
1534 | case -EAGAIN: return 0; | ||
1535 | default: return ret; | ||
1536 | } | ||
1537 | } | ||
1538 | |||
1539 | p = call->reply3; | ||
1540 | p[call->count] = 0; | ||
1541 | _debug("volname '%s'", p); | ||
1542 | |||
1543 | call->offset = 0; | ||
1544 | call->unmarshall++; | ||
1545 | |||
1546 | /* extract the volume name padding */ | ||
1547 | if ((call->count & 3) == 0) { | ||
1548 | call->unmarshall++; | ||
1549 | goto no_volname_padding; | ||
1550 | } | ||
1551 | call->count = 4 - (call->count & 3); | ||
1552 | |||
1553 | case 4: | ||
1554 | ret = afs_extract_data(call, skb, last, call->buffer, | ||
1555 | call->count); | ||
1556 | switch (ret) { | ||
1557 | case 0: break; | ||
1558 | case -EAGAIN: return 0; | ||
1559 | default: return ret; | ||
1560 | } | ||
1561 | |||
1562 | call->offset = 0; | ||
1563 | call->unmarshall++; | ||
1564 | no_volname_padding: | ||
1565 | |||
1566 | /* extract the offline message length */ | ||
1567 | case 5: | ||
1568 | ret = afs_extract_data(call, skb, last, &call->tmp, 4); | ||
1569 | switch (ret) { | ||
1570 | case 0: break; | ||
1571 | case -EAGAIN: return 0; | ||
1572 | default: return ret; | ||
1573 | } | ||
1574 | |||
1575 | call->count = ntohl(call->tmp); | ||
1576 | _debug("offline msg length: %u", call->count); | ||
1577 | if (call->count >= AFSNAMEMAX) | ||
1578 | return -EBADMSG; | ||
1579 | call->offset = 0; | ||
1580 | call->unmarshall++; | ||
1581 | |||
1582 | /* extract the offline message */ | ||
1583 | case 6: | ||
1584 | _debug("extract offline"); | ||
1585 | if (call->count > 0) { | ||
1586 | ret = afs_extract_data(call, skb, last, call->reply3, | ||
1587 | call->count); | ||
1588 | switch (ret) { | ||
1589 | case 0: break; | ||
1590 | case -EAGAIN: return 0; | ||
1591 | default: return ret; | ||
1592 | } | ||
1593 | } | ||
1594 | |||
1595 | p = call->reply3; | ||
1596 | p[call->count] = 0; | ||
1597 | _debug("offline '%s'", p); | ||
1598 | |||
1599 | call->offset = 0; | ||
1600 | call->unmarshall++; | ||
1601 | |||
1602 | /* extract the offline message padding */ | ||
1603 | if ((call->count & 3) == 0) { | ||
1604 | call->unmarshall++; | ||
1605 | goto no_offline_padding; | ||
1606 | } | ||
1607 | call->count = 4 - (call->count & 3); | ||
1608 | |||
1609 | case 7: | ||
1610 | ret = afs_extract_data(call, skb, last, call->buffer, | ||
1611 | call->count); | ||
1612 | switch (ret) { | ||
1613 | case 0: break; | ||
1614 | case -EAGAIN: return 0; | ||
1615 | default: return ret; | ||
1616 | } | ||
1617 | |||
1618 | call->offset = 0; | ||
1619 | call->unmarshall++; | ||
1620 | no_offline_padding: | ||
1621 | |||
1622 | /* extract the message of the day length */ | ||
1623 | case 8: | ||
1624 | ret = afs_extract_data(call, skb, last, &call->tmp, 4); | ||
1625 | switch (ret) { | ||
1626 | case 0: break; | ||
1627 | case -EAGAIN: return 0; | ||
1628 | default: return ret; | ||
1629 | } | ||
1630 | |||
1631 | call->count = ntohl(call->tmp); | ||
1632 | _debug("motd length: %u", call->count); | ||
1633 | if (call->count >= AFSNAMEMAX) | ||
1634 | return -EBADMSG; | ||
1635 | call->offset = 0; | ||
1636 | call->unmarshall++; | ||
1637 | |||
1638 | /* extract the message of the day */ | ||
1639 | case 9: | ||
1640 | _debug("extract motd"); | ||
1641 | if (call->count > 0) { | ||
1642 | ret = afs_extract_data(call, skb, last, call->reply3, | ||
1643 | call->count); | ||
1644 | switch (ret) { | ||
1645 | case 0: break; | ||
1646 | case -EAGAIN: return 0; | ||
1647 | default: return ret; | ||
1648 | } | ||
1649 | } | ||
1650 | |||
1651 | p = call->reply3; | ||
1652 | p[call->count] = 0; | ||
1653 | _debug("motd '%s'", p); | ||
1654 | |||
1655 | call->offset = 0; | ||
1656 | call->unmarshall++; | ||
1657 | |||
1658 | /* extract the message of the day padding */ | ||
1659 | if ((call->count & 3) == 0) { | ||
1660 | call->unmarshall++; | ||
1661 | goto no_motd_padding; | ||
1662 | } | ||
1663 | call->count = 4 - (call->count & 3); | ||
1664 | |||
1665 | case 10: | ||
1666 | ret = afs_extract_data(call, skb, last, call->buffer, | ||
1667 | call->count); | ||
1668 | switch (ret) { | ||
1669 | case 0: break; | ||
1670 | case -EAGAIN: return 0; | ||
1671 | default: return ret; | ||
1672 | } | ||
1673 | |||
1674 | call->offset = 0; | ||
1675 | call->unmarshall++; | ||
1676 | no_motd_padding: | ||
1677 | |||
1678 | case 11: | ||
1679 | _debug("trailer %d", skb->len); | ||
1680 | if (skb->len != 0) | ||
1681 | return -EBADMSG; | ||
1682 | break; | ||
1683 | } | ||
1684 | |||
1685 | if (!last) | ||
1686 | return 0; | ||
1687 | |||
1688 | _leave(" = 0 [done]"); | ||
1689 | return 0; | ||
1690 | } | ||
1691 | |||
1692 | /* | ||
1693 | * destroy an FS.GetVolumeStatus call | ||
1694 | */ | ||
1695 | static void afs_get_volume_status_call_destructor(struct afs_call *call) | ||
1696 | { | ||
1697 | kfree(call->reply3); | ||
1698 | call->reply3 = NULL; | ||
1699 | afs_flat_call_destructor(call); | ||
1700 | } | ||
1701 | |||
1702 | /* | ||
1703 | * FS.GetVolumeStatus operation type | ||
1704 | */ | ||
1705 | static const struct afs_call_type afs_RXFSGetVolumeStatus = { | ||
1706 | .name = "FS.GetVolumeStatus", | ||
1707 | .deliver = afs_deliver_fs_get_volume_status, | ||
1708 | .abort_to_error = afs_abort_to_error, | ||
1709 | .destructor = afs_get_volume_status_call_destructor, | ||
1710 | }; | ||
1711 | |||
1712 | /* | ||
1713 | * fetch the status of a volume | ||
1714 | */ | ||
1715 | int afs_fs_get_volume_status(struct afs_server *server, | ||
1716 | struct key *key, | ||
1717 | struct afs_vnode *vnode, | ||
1718 | struct afs_volume_status *vs, | ||
1719 | const struct afs_wait_mode *wait_mode) | ||
1720 | { | ||
1721 | struct afs_call *call; | ||
1722 | __be32 *bp; | ||
1723 | void *tmpbuf; | ||
1724 | |||
1725 | _enter(""); | ||
1726 | |||
1727 | tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL); | ||
1728 | if (!tmpbuf) | ||
1729 | return -ENOMEM; | ||
1730 | |||
1731 | call = afs_alloc_flat_call(&afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4); | ||
1732 | if (!call) { | ||
1733 | kfree(tmpbuf); | ||
1734 | return -ENOMEM; | ||
1735 | } | ||
1736 | |||
1737 | call->key = key; | ||
1738 | call->reply = vnode; | ||
1739 | call->reply2 = vs; | ||
1740 | call->reply3 = tmpbuf; | ||
1741 | call->service_id = FS_SERVICE; | ||
1742 | call->port = htons(AFS_FS_PORT); | ||
1743 | |||
1744 | /* marshall the parameters */ | ||
1745 | bp = call->request; | ||
1746 | bp[0] = htonl(FSGETVOLUMESTATUS); | ||
1747 | bp[1] = htonl(vnode->fid.vid); | ||
1748 | |||
1749 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | ||
1750 | } | ||
diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 515a5d12d8fb..47f5fed7195d 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c | |||
@@ -209,11 +209,15 @@ bad_inode: | |||
209 | */ | 209 | */ |
210 | void afs_zap_data(struct afs_vnode *vnode) | 210 | void afs_zap_data(struct afs_vnode *vnode) |
211 | { | 211 | { |
212 | _enter("zap data {%x:%u}", vnode->fid.vid, vnode->fid.vnode); | 212 | _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode); |
213 | 213 | ||
214 | /* nuke all the non-dirty pages that aren't locked, mapped or being | 214 | /* nuke all the non-dirty pages that aren't locked, mapped or being |
215 | * written back */ | 215 | * written back in a regular file and completely discard the pages in a |
216 | invalidate_remote_inode(&vnode->vfs_inode); | 216 | * directory or symlink */ |
217 | if (S_ISREG(vnode->vfs_inode.i_mode)) | ||
218 | invalidate_remote_inode(&vnode->vfs_inode); | ||
219 | else | ||
220 | invalidate_inode_pages2(vnode->vfs_inode.i_mapping); | ||
217 | } | 221 | } |
218 | 222 | ||
219 | /* | 223 | /* |
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index a30d4fa768e3..4953ba5a6f44 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
@@ -506,6 +506,10 @@ extern int afs_fs_store_data(struct afs_server *, struct afs_writeback *, | |||
506 | extern int afs_fs_setattr(struct afs_server *, struct key *, | 506 | extern int afs_fs_setattr(struct afs_server *, struct key *, |
507 | struct afs_vnode *, struct iattr *, | 507 | struct afs_vnode *, struct iattr *, |
508 | const struct afs_wait_mode *); | 508 | const struct afs_wait_mode *); |
509 | extern int afs_fs_get_volume_status(struct afs_server *, struct key *, | ||
510 | struct afs_vnode *, | ||
511 | struct afs_volume_status *, | ||
512 | const struct afs_wait_mode *); | ||
509 | 513 | ||
510 | /* | 514 | /* |
511 | * inode.c | 515 | * inode.c |
@@ -672,6 +676,8 @@ extern int afs_vnode_rename(struct afs_vnode *, struct afs_vnode *, | |||
672 | extern int afs_vnode_store_data(struct afs_writeback *, pgoff_t, pgoff_t, | 676 | extern int afs_vnode_store_data(struct afs_writeback *, pgoff_t, pgoff_t, |
673 | unsigned, unsigned); | 677 | unsigned, unsigned); |
674 | extern int afs_vnode_setattr(struct afs_vnode *, struct key *, struct iattr *); | 678 | extern int afs_vnode_setattr(struct afs_vnode *, struct key *, struct iattr *); |
679 | extern int afs_vnode_get_volume_status(struct afs_vnode *, struct key *, | ||
680 | struct afs_volume_status *); | ||
675 | 681 | ||
676 | /* | 682 | /* |
677 | * volume.c | 683 | * volume.c |
diff --git a/fs/afs/super.c b/fs/afs/super.c index d24be334b608..579af632c8e8 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c | |||
@@ -21,22 +21,20 @@ | |||
21 | #include <linux/fs.h> | 21 | #include <linux/fs.h> |
22 | #include <linux/pagemap.h> | 22 | #include <linux/pagemap.h> |
23 | #include <linux/parser.h> | 23 | #include <linux/parser.h> |
24 | #include <linux/statfs.h> | ||
24 | #include "internal.h" | 25 | #include "internal.h" |
25 | 26 | ||
26 | #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */ | 27 | #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */ |
27 | 28 | ||
28 | static void afs_i_init_once(void *foo, struct kmem_cache *cachep, | 29 | static void afs_i_init_once(void *foo, struct kmem_cache *cachep, |
29 | unsigned long flags); | 30 | unsigned long flags); |
30 | |||
31 | static int afs_get_sb(struct file_system_type *fs_type, | 31 | static int afs_get_sb(struct file_system_type *fs_type, |
32 | int flags, const char *dev_name, | 32 | int flags, const char *dev_name, |
33 | void *data, struct vfsmount *mnt); | 33 | void *data, struct vfsmount *mnt); |
34 | |||
35 | static struct inode *afs_alloc_inode(struct super_block *sb); | 34 | static struct inode *afs_alloc_inode(struct super_block *sb); |
36 | |||
37 | static void afs_put_super(struct super_block *sb); | 35 | static void afs_put_super(struct super_block *sb); |
38 | |||
39 | static void afs_destroy_inode(struct inode *inode); | 36 | static void afs_destroy_inode(struct inode *inode); |
37 | static int afs_statfs(struct dentry *dentry, struct kstatfs *buf); | ||
40 | 38 | ||
41 | struct file_system_type afs_fs_type = { | 39 | struct file_system_type afs_fs_type = { |
42 | .owner = THIS_MODULE, | 40 | .owner = THIS_MODULE, |
@@ -47,7 +45,7 @@ struct file_system_type afs_fs_type = { | |||
47 | }; | 45 | }; |
48 | 46 | ||
49 | static const struct super_operations afs_super_ops = { | 47 | static const struct super_operations afs_super_ops = { |
50 | .statfs = simple_statfs, | 48 | .statfs = afs_statfs, |
51 | .alloc_inode = afs_alloc_inode, | 49 | .alloc_inode = afs_alloc_inode, |
52 | .drop_inode = generic_delete_inode, | 50 | .drop_inode = generic_delete_inode, |
53 | .write_inode = afs_write_inode, | 51 | .write_inode = afs_write_inode, |
@@ -488,6 +486,7 @@ static struct inode *afs_alloc_inode(struct super_block *sb) | |||
488 | vnode->flags = 1 << AFS_VNODE_UNSET; | 486 | vnode->flags = 1 << AFS_VNODE_UNSET; |
489 | vnode->cb_promised = false; | 487 | vnode->cb_promised = false; |
490 | 488 | ||
489 | _leave(" = %p", &vnode->vfs_inode); | ||
491 | return &vnode->vfs_inode; | 490 | return &vnode->vfs_inode; |
492 | } | 491 | } |
493 | 492 | ||
@@ -498,7 +497,7 @@ static void afs_destroy_inode(struct inode *inode) | |||
498 | { | 497 | { |
499 | struct afs_vnode *vnode = AFS_FS_I(inode); | 498 | struct afs_vnode *vnode = AFS_FS_I(inode); |
500 | 499 | ||
501 | _enter("{%lu}", inode->i_ino); | 500 | _enter("%p{%x:%u}", inode, vnode->fid.vid, vnode->fid.vnode); |
502 | 501 | ||
503 | _debug("DESTROY INODE %p", inode); | 502 | _debug("DESTROY INODE %p", inode); |
504 | 503 | ||
@@ -507,3 +506,36 @@ static void afs_destroy_inode(struct inode *inode) | |||
507 | kmem_cache_free(afs_inode_cachep, vnode); | 506 | kmem_cache_free(afs_inode_cachep, vnode); |
508 | atomic_dec(&afs_count_active_inodes); | 507 | atomic_dec(&afs_count_active_inodes); |
509 | } | 508 | } |
509 | |||
510 | /* | ||
511 | * return information about an AFS volume | ||
512 | */ | ||
513 | static int afs_statfs(struct dentry *dentry, struct kstatfs *buf) | ||
514 | { | ||
515 | struct afs_volume_status vs; | ||
516 | struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode); | ||
517 | struct key *key; | ||
518 | int ret; | ||
519 | |||
520 | key = afs_request_key(vnode->volume->cell); | ||
521 | if (IS_ERR(key)) | ||
522 | return PTR_ERR(key); | ||
523 | |||
524 | ret = afs_vnode_get_volume_status(vnode, key, &vs); | ||
525 | key_put(key); | ||
526 | if (ret < 0) { | ||
527 | _leave(" = %d", ret); | ||
528 | return ret; | ||
529 | } | ||
530 | |||
531 | buf->f_type = dentry->d_sb->s_magic; | ||
532 | buf->f_bsize = AFS_BLOCK_SIZE; | ||
533 | buf->f_namelen = AFSNAMEMAX - 1; | ||
534 | |||
535 | if (vs.max_quota == 0) | ||
536 | buf->f_blocks = vs.part_max_blocks; | ||
537 | else | ||
538 | buf->f_blocks = vs.max_quota; | ||
539 | buf->f_bavail = buf->f_bfree = buf->f_blocks - vs.blocks_in_use; | ||
540 | return 0; | ||
541 | } | ||
diff --git a/fs/afs/vnode.c b/fs/afs/vnode.c index ec814660209f..c36c98ce2c3c 100644 --- a/fs/afs/vnode.c +++ b/fs/afs/vnode.c | |||
@@ -175,24 +175,33 @@ static void afs_vnode_deleted_remotely(struct afs_vnode *vnode) | |||
175 | { | 175 | { |
176 | struct afs_server *server; | 176 | struct afs_server *server; |
177 | 177 | ||
178 | _enter("{%p}", vnode->server); | ||
179 | |||
178 | set_bit(AFS_VNODE_DELETED, &vnode->flags); | 180 | set_bit(AFS_VNODE_DELETED, &vnode->flags); |
179 | 181 | ||
180 | server = vnode->server; | 182 | server = vnode->server; |
181 | if (vnode->cb_promised) { | 183 | if (server) { |
182 | spin_lock(&server->cb_lock); | ||
183 | if (vnode->cb_promised) { | 184 | if (vnode->cb_promised) { |
184 | rb_erase(&vnode->cb_promise, &server->cb_promises); | 185 | spin_lock(&server->cb_lock); |
185 | vnode->cb_promised = false; | 186 | if (vnode->cb_promised) { |
187 | rb_erase(&vnode->cb_promise, | ||
188 | &server->cb_promises); | ||
189 | vnode->cb_promised = false; | ||
190 | } | ||
191 | spin_unlock(&server->cb_lock); | ||
186 | } | 192 | } |
187 | spin_unlock(&server->cb_lock); | ||
188 | } | ||
189 | 193 | ||
190 | spin_lock(&vnode->server->fs_lock); | 194 | spin_lock(&server->fs_lock); |
191 | rb_erase(&vnode->server_rb, &vnode->server->fs_vnodes); | 195 | rb_erase(&vnode->server_rb, &server->fs_vnodes); |
192 | spin_unlock(&vnode->server->fs_lock); | 196 | spin_unlock(&server->fs_lock); |
193 | 197 | ||
194 | vnode->server = NULL; | 198 | vnode->server = NULL; |
195 | afs_put_server(server); | 199 | afs_put_server(server); |
200 | } else { | ||
201 | ASSERT(!vnode->cb_promised); | ||
202 | } | ||
203 | |||
204 | _leave(""); | ||
196 | } | 205 | } |
197 | 206 | ||
198 | /* | 207 | /* |
@@ -225,7 +234,7 @@ void afs_vnode_finalise_status_update(struct afs_vnode *vnode, | |||
225 | */ | 234 | */ |
226 | static void afs_vnode_status_update_failed(struct afs_vnode *vnode, int ret) | 235 | static void afs_vnode_status_update_failed(struct afs_vnode *vnode, int ret) |
227 | { | 236 | { |
228 | _enter("%p,%d", vnode, ret); | 237 | _enter("{%x:%u},%d", vnode->fid.vid, vnode->fid.vnode, ret); |
229 | 238 | ||
230 | spin_lock(&vnode->lock); | 239 | spin_lock(&vnode->lock); |
231 | 240 | ||
@@ -860,3 +869,55 @@ no_server: | |||
860 | spin_unlock(&vnode->lock); | 869 | spin_unlock(&vnode->lock); |
861 | return PTR_ERR(server); | 870 | return PTR_ERR(server); |
862 | } | 871 | } |
872 | |||
873 | /* | ||
874 | * get the status of a volume | ||
875 | */ | ||
876 | int afs_vnode_get_volume_status(struct afs_vnode *vnode, struct key *key, | ||
877 | struct afs_volume_status *vs) | ||
878 | { | ||
879 | struct afs_server *server; | ||
880 | int ret; | ||
881 | |||
882 | _enter("%s{%x:%u.%u},%x,", | ||
883 | vnode->volume->vlocation->vldb.name, | ||
884 | vnode->fid.vid, | ||
885 | vnode->fid.vnode, | ||
886 | vnode->fid.unique, | ||
887 | key_serial(key)); | ||
888 | |||
889 | /* this op will fetch the status */ | ||
890 | spin_lock(&vnode->lock); | ||
891 | vnode->update_cnt++; | ||
892 | spin_unlock(&vnode->lock); | ||
893 | |||
894 | do { | ||
895 | /* pick a server to query */ | ||
896 | server = afs_volume_pick_fileserver(vnode); | ||
897 | if (IS_ERR(server)) | ||
898 | goto no_server; | ||
899 | |||
900 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); | ||
901 | |||
902 | ret = afs_fs_get_volume_status(server, key, vnode, vs, &afs_sync_call); | ||
903 | |||
904 | } while (!afs_volume_release_fileserver(vnode, server, ret)); | ||
905 | |||
906 | /* adjust the flags */ | ||
907 | if (ret == 0) { | ||
908 | afs_vnode_finalise_status_update(vnode, server); | ||
909 | afs_put_server(server); | ||
910 | } else { | ||
911 | afs_vnode_status_update_failed(vnode, ret); | ||
912 | } | ||
913 | |||
914 | _leave(" = %d", ret); | ||
915 | return ret; | ||
916 | |||
917 | no_server: | ||
918 | spin_lock(&vnode->lock); | ||
919 | vnode->update_cnt--; | ||
920 | ASSERTCMP(vnode->update_cnt, >=, 0); | ||
921 | spin_unlock(&vnode->lock); | ||
922 | return PTR_ERR(server); | ||
923 | } | ||
diff --git a/fs/afs/write.c b/fs/afs/write.c index 67ae4dbf66b3..28f37516c126 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c | |||
@@ -395,8 +395,9 @@ static int afs_write_back_from_locked_page(struct afs_writeback *wb, | |||
395 | if (n == 0) | 395 | if (n == 0) |
396 | goto no_more; | 396 | goto no_more; |
397 | if (pages[0]->index != start) { | 397 | if (pages[0]->index != start) { |
398 | for (n--; n >= 0; n--) | 398 | do { |
399 | put_page(pages[n]); | 399 | put_page(pages[--n]); |
400 | } while (n > 0); | ||
400 | goto no_more; | 401 | goto no_more; |
401 | } | 402 | } |
402 | 403 | ||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/highmem.h> | 30 | #include <linux/highmem.h> |
31 | #include <linux/workqueue.h> | 31 | #include <linux/workqueue.h> |
32 | #include <linux/security.h> | 32 | #include <linux/security.h> |
33 | #include <linux/eventfd.h> | ||
33 | 34 | ||
34 | #include <asm/kmap_types.h> | 35 | #include <asm/kmap_types.h> |
35 | #include <asm/uaccess.h> | 36 | #include <asm/uaccess.h> |
@@ -417,6 +418,7 @@ static struct kiocb fastcall *__aio_get_req(struct kioctx *ctx) | |||
417 | req->private = NULL; | 418 | req->private = NULL; |
418 | req->ki_iovec = NULL; | 419 | req->ki_iovec = NULL; |
419 | INIT_LIST_HEAD(&req->ki_run_list); | 420 | INIT_LIST_HEAD(&req->ki_run_list); |
421 | req->ki_eventfd = ERR_PTR(-EINVAL); | ||
420 | 422 | ||
421 | /* Check if the completion queue has enough free space to | 423 | /* Check if the completion queue has enough free space to |
422 | * accept an event from this io. | 424 | * accept an event from this io. |
@@ -458,6 +460,8 @@ static inline void really_put_req(struct kioctx *ctx, struct kiocb *req) | |||
458 | { | 460 | { |
459 | assert_spin_locked(&ctx->ctx_lock); | 461 | assert_spin_locked(&ctx->ctx_lock); |
460 | 462 | ||
463 | if (!IS_ERR(req->ki_eventfd)) | ||
464 | fput(req->ki_eventfd); | ||
461 | if (req->ki_dtor) | 465 | if (req->ki_dtor) |
462 | req->ki_dtor(req); | 466 | req->ki_dtor(req); |
463 | if (req->ki_iovec != &req->ki_inline_vec) | 467 | if (req->ki_iovec != &req->ki_inline_vec) |
@@ -942,6 +946,14 @@ int fastcall aio_complete(struct kiocb *iocb, long res, long res2) | |||
942 | return 1; | 946 | return 1; |
943 | } | 947 | } |
944 | 948 | ||
949 | /* | ||
950 | * Check if the user asked us to deliver the result through an | ||
951 | * eventfd. The eventfd_signal() function is safe to be called | ||
952 | * from IRQ context. | ||
953 | */ | ||
954 | if (!IS_ERR(iocb->ki_eventfd)) | ||
955 | eventfd_signal(iocb->ki_eventfd, 1); | ||
956 | |||
945 | info = &ctx->ring_info; | 957 | info = &ctx->ring_info; |
946 | 958 | ||
947 | /* add a completion event to the ring buffer. | 959 | /* add a completion event to the ring buffer. |
@@ -1526,8 +1538,7 @@ int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, | |||
1526 | ssize_t ret; | 1538 | ssize_t ret; |
1527 | 1539 | ||
1528 | /* enforce forwards compatibility on users */ | 1540 | /* enforce forwards compatibility on users */ |
1529 | if (unlikely(iocb->aio_reserved1 || iocb->aio_reserved2 || | 1541 | if (unlikely(iocb->aio_reserved1 || iocb->aio_reserved2)) { |
1530 | iocb->aio_reserved3)) { | ||
1531 | pr_debug("EINVAL: io_submit: reserve field set\n"); | 1542 | pr_debug("EINVAL: io_submit: reserve field set\n"); |
1532 | return -EINVAL; | 1543 | return -EINVAL; |
1533 | } | 1544 | } |
@@ -1551,6 +1562,19 @@ int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, | |||
1551 | fput(file); | 1562 | fput(file); |
1552 | return -EAGAIN; | 1563 | return -EAGAIN; |
1553 | } | 1564 | } |
1565 | if (iocb->aio_flags & IOCB_FLAG_RESFD) { | ||
1566 | /* | ||
1567 | * If the IOCB_FLAG_RESFD flag of aio_flags is set, get an | ||
1568 | * instance of the file* now. The file descriptor must be | ||
1569 | * an eventfd() fd, and will be signaled for each completed | ||
1570 | * event using the eventfd_signal() function. | ||
1571 | */ | ||
1572 | req->ki_eventfd = eventfd_fget((int) iocb->aio_resfd); | ||
1573 | if (unlikely(IS_ERR(req->ki_eventfd))) { | ||
1574 | ret = PTR_ERR(req->ki_eventfd); | ||
1575 | goto out_put_req; | ||
1576 | } | ||
1577 | } | ||
1554 | 1578 | ||
1555 | req->ki_filp = file; | 1579 | req->ki_filp = file; |
1556 | ret = put_user(req->ki_key, &user_iocb->aio_key); | 1580 | ret = put_user(req->ki_key, &user_iocb->aio_key); |
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c new file mode 100644 index 000000000000..40fe3a3222e4 --- /dev/null +++ b/fs/anon_inodes.c | |||
@@ -0,0 +1,200 @@ | |||
1 | /* | ||
2 | * fs/anon_inodes.c | ||
3 | * | ||
4 | * Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org> | ||
5 | * | ||
6 | * Thanks to Arnd Bergmann for code review and suggestions. | ||
7 | * More changes for Thomas Gleixner suggestions. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/file.h> | ||
12 | #include <linux/poll.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/fs.h> | ||
16 | #include <linux/mount.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/magic.h> | ||
20 | #include <linux/anon_inodes.h> | ||
21 | |||
22 | #include <asm/uaccess.h> | ||
23 | |||
24 | static struct vfsmount *anon_inode_mnt __read_mostly; | ||
25 | static struct inode *anon_inode_inode; | ||
26 | static const struct file_operations anon_inode_fops; | ||
27 | |||
28 | static int anon_inodefs_get_sb(struct file_system_type *fs_type, int flags, | ||
29 | const char *dev_name, void *data, | ||
30 | struct vfsmount *mnt) | ||
31 | { | ||
32 | return get_sb_pseudo(fs_type, "anon_inode:", NULL, ANON_INODE_FS_MAGIC, | ||
33 | mnt); | ||
34 | } | ||
35 | |||
36 | static int anon_inodefs_delete_dentry(struct dentry *dentry) | ||
37 | { | ||
38 | /* | ||
39 | * We faked vfs to believe the dentry was hashed when we created it. | ||
40 | * Now we restore the flag so that dput() will work correctly. | ||
41 | */ | ||
42 | dentry->d_flags |= DCACHE_UNHASHED; | ||
43 | return 1; | ||
44 | } | ||
45 | |||
46 | static struct file_system_type anon_inode_fs_type = { | ||
47 | .name = "anon_inodefs", | ||
48 | .get_sb = anon_inodefs_get_sb, | ||
49 | .kill_sb = kill_anon_super, | ||
50 | }; | ||
51 | static struct dentry_operations anon_inodefs_dentry_operations = { | ||
52 | .d_delete = anon_inodefs_delete_dentry, | ||
53 | }; | ||
54 | |||
55 | /** | ||
56 | * anon_inode_getfd - creates a new file instance by hooking it up to and | ||
57 | * anonymous inode, and a dentry that describe the "class" | ||
58 | * of the file | ||
59 | * | ||
60 | * @pfd: [out] pointer to the file descriptor | ||
61 | * @dpinode: [out] pointer to the inode | ||
62 | * @pfile: [out] pointer to the file struct | ||
63 | * @name: [in] name of the "class" of the new file | ||
64 | * @fops [in] file operations for the new file | ||
65 | * @priv [in] private data for the new file (will be file's private_data) | ||
66 | * | ||
67 | * Creates a new file by hooking it on a single inode. This is useful for files | ||
68 | * that do not need to have a full-fledged inode in order to operate correctly. | ||
69 | * All the files created with anon_inode_getfd() will share a single inode, by | ||
70 | * hence saving memory and avoiding code duplication for the file/inode/dentry | ||
71 | * setup. | ||
72 | */ | ||
73 | int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile, | ||
74 | const char *name, const struct file_operations *fops, | ||
75 | void *priv) | ||
76 | { | ||
77 | struct qstr this; | ||
78 | struct dentry *dentry; | ||
79 | struct inode *inode; | ||
80 | struct file *file; | ||
81 | int error, fd; | ||
82 | |||
83 | if (IS_ERR(anon_inode_inode)) | ||
84 | return -ENODEV; | ||
85 | file = get_empty_filp(); | ||
86 | if (!file) | ||
87 | return -ENFILE; | ||
88 | |||
89 | inode = igrab(anon_inode_inode); | ||
90 | if (IS_ERR(inode)) { | ||
91 | error = PTR_ERR(inode); | ||
92 | goto err_put_filp; | ||
93 | } | ||
94 | |||
95 | error = get_unused_fd(); | ||
96 | if (error < 0) | ||
97 | goto err_iput; | ||
98 | fd = error; | ||
99 | |||
100 | /* | ||
101 | * Link the inode to a directory entry by creating a unique name | ||
102 | * using the inode sequence number. | ||
103 | */ | ||
104 | error = -ENOMEM; | ||
105 | this.name = name; | ||
106 | this.len = strlen(name); | ||
107 | this.hash = 0; | ||
108 | dentry = d_alloc(anon_inode_mnt->mnt_sb->s_root, &this); | ||
109 | if (!dentry) | ||
110 | goto err_put_unused_fd; | ||
111 | dentry->d_op = &anon_inodefs_dentry_operations; | ||
112 | /* Do not publish this dentry inside the global dentry hash table */ | ||
113 | dentry->d_flags &= ~DCACHE_UNHASHED; | ||
114 | d_instantiate(dentry, inode); | ||
115 | |||
116 | file->f_path.mnt = mntget(anon_inode_mnt); | ||
117 | file->f_path.dentry = dentry; | ||
118 | file->f_mapping = inode->i_mapping; | ||
119 | |||
120 | file->f_pos = 0; | ||
121 | file->f_flags = O_RDWR; | ||
122 | file->f_op = fops; | ||
123 | file->f_mode = FMODE_READ | FMODE_WRITE; | ||
124 | file->f_version = 0; | ||
125 | file->private_data = priv; | ||
126 | |||
127 | fd_install(fd, file); | ||
128 | |||
129 | *pfd = fd; | ||
130 | *pinode = inode; | ||
131 | *pfile = file; | ||
132 | return 0; | ||
133 | |||
134 | err_put_unused_fd: | ||
135 | put_unused_fd(fd); | ||
136 | err_iput: | ||
137 | iput(inode); | ||
138 | err_put_filp: | ||
139 | put_filp(file); | ||
140 | return error; | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * A single inode exist for all anon_inode files. Contrary to pipes, | ||
145 | * anon_inode inodes has no per-instance data associated, so we can avoid | ||
146 | * the allocation of multiple of them. | ||
147 | */ | ||
148 | static struct inode *anon_inode_mkinode(void) | ||
149 | { | ||
150 | struct inode *inode = new_inode(anon_inode_mnt->mnt_sb); | ||
151 | |||
152 | if (!inode) | ||
153 | return ERR_PTR(-ENOMEM); | ||
154 | |||
155 | inode->i_fop = &anon_inode_fops; | ||
156 | |||
157 | /* | ||
158 | * Mark the inode dirty from the very beginning, | ||
159 | * that way it will never be moved to the dirty | ||
160 | * list because mark_inode_dirty() will think | ||
161 | * that it already _is_ on the dirty list. | ||
162 | */ | ||
163 | inode->i_state = I_DIRTY; | ||
164 | inode->i_mode = S_IRUSR | S_IWUSR; | ||
165 | inode->i_uid = current->fsuid; | ||
166 | inode->i_gid = current->fsgid; | ||
167 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
168 | return inode; | ||
169 | } | ||
170 | |||
171 | static int __init anon_inode_init(void) | ||
172 | { | ||
173 | int error; | ||
174 | |||
175 | error = register_filesystem(&anon_inode_fs_type); | ||
176 | if (error) | ||
177 | goto err_exit; | ||
178 | anon_inode_mnt = kern_mount(&anon_inode_fs_type); | ||
179 | if (IS_ERR(anon_inode_mnt)) { | ||
180 | error = PTR_ERR(anon_inode_mnt); | ||
181 | goto err_unregister_filesystem; | ||
182 | } | ||
183 | anon_inode_inode = anon_inode_mkinode(); | ||
184 | if (IS_ERR(anon_inode_inode)) { | ||
185 | error = PTR_ERR(anon_inode_inode); | ||
186 | goto err_mntput; | ||
187 | } | ||
188 | |||
189 | return 0; | ||
190 | |||
191 | err_mntput: | ||
192 | mntput(anon_inode_mnt); | ||
193 | err_unregister_filesystem: | ||
194 | unregister_filesystem(&anon_inode_fs_type); | ||
195 | err_exit: | ||
196 | panic(KERN_ERR "anon_inode_init() failed (%d)\n", error); | ||
197 | } | ||
198 | |||
199 | fs_initcall(anon_inode_init); | ||
200 | |||
diff --git a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h index 4ef544434b51..8b4cca3c4705 100644 --- a/fs/autofs/autofs_i.h +++ b/fs/autofs/autofs_i.h | |||
@@ -101,7 +101,7 @@ struct autofs_symlink { | |||
101 | struct autofs_sb_info { | 101 | struct autofs_sb_info { |
102 | u32 magic; | 102 | u32 magic; |
103 | struct file *pipe; | 103 | struct file *pipe; |
104 | pid_t oz_pgrp; | 104 | struct pid *oz_pgrp; |
105 | int catatonic; | 105 | int catatonic; |
106 | struct super_block *sb; | 106 | struct super_block *sb; |
107 | unsigned long exp_timeout; | 107 | unsigned long exp_timeout; |
@@ -122,7 +122,7 @@ static inline struct autofs_sb_info *autofs_sbi(struct super_block *sb) | |||
122 | filesystem without "magic".) */ | 122 | filesystem without "magic".) */ |
123 | 123 | ||
124 | static inline int autofs_oz_mode(struct autofs_sb_info *sbi) { | 124 | static inline int autofs_oz_mode(struct autofs_sb_info *sbi) { |
125 | return sbi->catatonic || process_group(current) == sbi->oz_pgrp; | 125 | return sbi->catatonic || task_pgrp(current) == sbi->oz_pgrp; |
126 | } | 126 | } |
127 | 127 | ||
128 | /* Hash operations */ | 128 | /* Hash operations */ |
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c index aa0b61ff8270..e7204d71acc9 100644 --- a/fs/autofs/inode.c +++ b/fs/autofs/inode.c | |||
@@ -34,12 +34,14 @@ void autofs_kill_sb(struct super_block *sb) | |||
34 | if (!sbi) | 34 | if (!sbi) |
35 | goto out_kill_sb; | 35 | goto out_kill_sb; |
36 | 36 | ||
37 | if ( !sbi->catatonic ) | 37 | if (!sbi->catatonic) |
38 | autofs_catatonic_mode(sbi); /* Free wait queues, close pipe */ | 38 | autofs_catatonic_mode(sbi); /* Free wait queues, close pipe */ |
39 | 39 | ||
40 | put_pid(sbi->oz_pgrp); | ||
41 | |||
40 | autofs_hash_nuke(sbi); | 42 | autofs_hash_nuke(sbi); |
41 | for ( n = 0 ; n < AUTOFS_MAX_SYMLINKS ; n++ ) { | 43 | for (n = 0; n < AUTOFS_MAX_SYMLINKS; n++) { |
42 | if ( test_bit(n, sbi->symlink_bitmap) ) | 44 | if (test_bit(n, sbi->symlink_bitmap)) |
43 | kfree(sbi->symlink[n].data); | 45 | kfree(sbi->symlink[n].data); |
44 | } | 46 | } |
45 | 47 | ||
@@ -69,7 +71,8 @@ static match_table_t autofs_tokens = { | |||
69 | {Opt_err, NULL} | 71 | {Opt_err, NULL} |
70 | }; | 72 | }; |
71 | 73 | ||
72 | static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, pid_t *pgrp, int *minproto, int *maxproto) | 74 | static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, |
75 | pid_t *pgrp, int *minproto, int *maxproto) | ||
73 | { | 76 | { |
74 | char *p; | 77 | char *p; |
75 | substring_t args[MAX_OPT_ARGS]; | 78 | substring_t args[MAX_OPT_ARGS]; |
@@ -138,9 +141,10 @@ int autofs_fill_super(struct super_block *s, void *data, int silent) | |||
138 | int pipefd; | 141 | int pipefd; |
139 | struct autofs_sb_info *sbi; | 142 | struct autofs_sb_info *sbi; |
140 | int minproto, maxproto; | 143 | int minproto, maxproto; |
144 | pid_t pgid; | ||
141 | 145 | ||
142 | sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); | 146 | sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); |
143 | if ( !sbi ) | 147 | if (!sbi) |
144 | goto fail_unlock; | 148 | goto fail_unlock; |
145 | DPRINTK(("autofs: starting up, sbi = %p\n",sbi)); | 149 | DPRINTK(("autofs: starting up, sbi = %p\n",sbi)); |
146 | 150 | ||
@@ -149,7 +153,6 @@ int autofs_fill_super(struct super_block *s, void *data, int silent) | |||
149 | sbi->pipe = NULL; | 153 | sbi->pipe = NULL; |
150 | sbi->catatonic = 1; | 154 | sbi->catatonic = 1; |
151 | sbi->exp_timeout = 0; | 155 | sbi->exp_timeout = 0; |
152 | sbi->oz_pgrp = process_group(current); | ||
153 | autofs_initialize_hash(&sbi->dirhash); | 156 | autofs_initialize_hash(&sbi->dirhash); |
154 | sbi->queues = NULL; | 157 | sbi->queues = NULL; |
155 | memset(sbi->symlink_bitmap, 0, sizeof(long)*AUTOFS_SYMLINK_BITMAP_LEN); | 158 | memset(sbi->symlink_bitmap, 0, sizeof(long)*AUTOFS_SYMLINK_BITMAP_LEN); |
@@ -169,26 +172,36 @@ int autofs_fill_super(struct super_block *s, void *data, int silent) | |||
169 | goto fail_iput; | 172 | goto fail_iput; |
170 | 173 | ||
171 | /* Can this call block? - WTF cares? s is locked. */ | 174 | /* Can this call block? - WTF cares? s is locked. */ |
172 | if ( parse_options(data,&pipefd,&root_inode->i_uid,&root_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) { | 175 | if (parse_options(data, &pipefd, &root_inode->i_uid, |
176 | &root_inode->i_gid, &pgid, &minproto, | ||
177 | &maxproto)) { | ||
173 | printk("autofs: called with bogus options\n"); | 178 | printk("autofs: called with bogus options\n"); |
174 | goto fail_dput; | 179 | goto fail_dput; |
175 | } | 180 | } |
176 | 181 | ||
177 | /* Couldn't this be tested earlier? */ | 182 | /* Couldn't this be tested earlier? */ |
178 | if ( minproto > AUTOFS_PROTO_VERSION || | 183 | if (minproto > AUTOFS_PROTO_VERSION || |
179 | maxproto < AUTOFS_PROTO_VERSION ) { | 184 | maxproto < AUTOFS_PROTO_VERSION) { |
180 | printk("autofs: kernel does not match daemon version\n"); | 185 | printk("autofs: kernel does not match daemon version\n"); |
181 | goto fail_dput; | 186 | goto fail_dput; |
182 | } | 187 | } |
183 | 188 | ||
184 | DPRINTK(("autofs: pipe fd = %d, pgrp = %u\n", pipefd, sbi->oz_pgrp)); | 189 | DPRINTK(("autofs: pipe fd = %d, pgrp = %u\n", pipefd, pgid)); |
190 | sbi->oz_pgrp = find_get_pid(pgid); | ||
191 | |||
192 | if (!sbi->oz_pgrp) { | ||
193 | printk("autofs: could not find process group %d\n", pgid); | ||
194 | goto fail_dput; | ||
195 | } | ||
196 | |||
185 | pipe = fget(pipefd); | 197 | pipe = fget(pipefd); |
186 | 198 | ||
187 | if ( !pipe ) { | 199 | if (!pipe) { |
188 | printk("autofs: could not open pipe file descriptor\n"); | 200 | printk("autofs: could not open pipe file descriptor\n"); |
189 | goto fail_dput; | 201 | goto fail_put_pid; |
190 | } | 202 | } |
191 | if ( !pipe->f_op || !pipe->f_op->write ) | 203 | |
204 | if (!pipe->f_op || !pipe->f_op->write) | ||
192 | goto fail_fput; | 205 | goto fail_fput; |
193 | sbi->pipe = pipe; | 206 | sbi->pipe = pipe; |
194 | sbi->catatonic = 0; | 207 | sbi->catatonic = 0; |
@@ -202,6 +215,8 @@ int autofs_fill_super(struct super_block *s, void *data, int silent) | |||
202 | fail_fput: | 215 | fail_fput: |
203 | printk("autofs: pipe file descriptor does not contain proper ops\n"); | 216 | printk("autofs: pipe file descriptor does not contain proper ops\n"); |
204 | fput(pipe); | 217 | fput(pipe); |
218 | fail_put_pid: | ||
219 | put_pid(sbi->oz_pgrp); | ||
205 | fail_dput: | 220 | fail_dput: |
206 | dput(root); | 221 | dput(root); |
207 | goto fail_free; | 222 | goto fail_free; |
@@ -230,7 +245,7 @@ static void autofs_read_inode(struct inode *inode) | |||
230 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | 245 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; |
231 | inode->i_blocks = 0; | 246 | inode->i_blocks = 0; |
232 | 247 | ||
233 | if ( ino == AUTOFS_ROOT_INO ) { | 248 | if (ino == AUTOFS_ROOT_INO) { |
234 | inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; | 249 | inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; |
235 | inode->i_op = &autofs_root_inode_operations; | 250 | inode->i_op = &autofs_root_inode_operations; |
236 | inode->i_fop = &autofs_root_operations; | 251 | inode->i_fop = &autofs_root_operations; |
@@ -241,12 +256,12 @@ static void autofs_read_inode(struct inode *inode) | |||
241 | inode->i_uid = inode->i_sb->s_root->d_inode->i_uid; | 256 | inode->i_uid = inode->i_sb->s_root->d_inode->i_uid; |
242 | inode->i_gid = inode->i_sb->s_root->d_inode->i_gid; | 257 | inode->i_gid = inode->i_sb->s_root->d_inode->i_gid; |
243 | 258 | ||
244 | if ( ino >= AUTOFS_FIRST_SYMLINK && ino < AUTOFS_FIRST_DIR_INO ) { | 259 | if (ino >= AUTOFS_FIRST_SYMLINK && ino < AUTOFS_FIRST_DIR_INO) { |
245 | /* Symlink inode - should be in symlink list */ | 260 | /* Symlink inode - should be in symlink list */ |
246 | struct autofs_symlink *sl; | 261 | struct autofs_symlink *sl; |
247 | 262 | ||
248 | n = ino - AUTOFS_FIRST_SYMLINK; | 263 | n = ino - AUTOFS_FIRST_SYMLINK; |
249 | if ( n >= AUTOFS_MAX_SYMLINKS || !test_bit(n,sbi->symlink_bitmap)) { | 264 | if (n >= AUTOFS_MAX_SYMLINKS || !test_bit(n,sbi->symlink_bitmap)) { |
250 | printk("autofs: Looking for bad symlink inode %u\n", (unsigned int) ino); | 265 | printk("autofs: Looking for bad symlink inode %u\n", (unsigned int) ino); |
251 | return; | 266 | return; |
252 | } | 267 | } |
diff --git a/fs/autofs/root.c b/fs/autofs/root.c index f2597205939d..c1489533277a 100644 --- a/fs/autofs/root.c +++ b/fs/autofs/root.c | |||
@@ -67,8 +67,8 @@ static int autofs_root_readdir(struct file *filp, void *dirent, filldir_t filldi | |||
67 | filp->f_pos = ++nr; | 67 | filp->f_pos = ++nr; |
68 | /* fall through */ | 68 | /* fall through */ |
69 | default: | 69 | default: |
70 | while ( onr = nr, ent = autofs_hash_enum(dirhash,&nr,ent) ) { | 70 | while (onr = nr, ent = autofs_hash_enum(dirhash,&nr,ent)) { |
71 | if ( !ent->dentry || d_mountpoint(ent->dentry) ) { | 71 | if (!ent->dentry || d_mountpoint(ent->dentry)) { |
72 | if (filldir(dirent,ent->name,ent->len,onr,ent->ino,DT_UNKNOWN) < 0) | 72 | if (filldir(dirent,ent->name,ent->len,onr,ent->ino,DT_UNKNOWN) < 0) |
73 | goto out; | 73 | goto out; |
74 | filp->f_pos = nr; | 74 | filp->f_pos = nr; |
@@ -88,10 +88,10 @@ static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, str | |||
88 | struct autofs_dir_ent *ent; | 88 | struct autofs_dir_ent *ent; |
89 | int status = 0; | 89 | int status = 0; |
90 | 90 | ||
91 | if ( !(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name)) ) { | 91 | if (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name))) { |
92 | do { | 92 | do { |
93 | if ( status && dentry->d_inode ) { | 93 | if (status && dentry->d_inode) { |
94 | if ( status != -ENOENT ) | 94 | if (status != -ENOENT) |
95 | printk("autofs warning: lookup failure on positive dentry, status = %d, name = %s\n", status, dentry->d_name.name); | 95 | printk("autofs warning: lookup failure on positive dentry, status = %d, name = %s\n", status, dentry->d_name.name); |
96 | return 0; /* Try to get the kernel to invalidate this dentry */ | 96 | return 0; /* Try to get the kernel to invalidate this dentry */ |
97 | } | 97 | } |
@@ -106,7 +106,7 @@ static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, str | |||
106 | return 1; | 106 | return 1; |
107 | } | 107 | } |
108 | status = autofs_wait(sbi, &dentry->d_name); | 108 | status = autofs_wait(sbi, &dentry->d_name); |
109 | } while (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name)) ); | 109 | } while (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name))); |
110 | } | 110 | } |
111 | 111 | ||
112 | /* Abuse this field as a pointer to the directory entry, used to | 112 | /* Abuse this field as a pointer to the directory entry, used to |
@@ -124,13 +124,13 @@ static int try_to_fill_dentry(struct dentry *dentry, struct super_block *sb, str | |||
124 | 124 | ||
125 | /* If this is a directory that isn't a mount point, bitch at the | 125 | /* If this is a directory that isn't a mount point, bitch at the |
126 | daemon and fix it in user space */ | 126 | daemon and fix it in user space */ |
127 | if ( S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry) ) { | 127 | if (S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry)) { |
128 | return !autofs_wait(sbi, &dentry->d_name); | 128 | return !autofs_wait(sbi, &dentry->d_name); |
129 | } | 129 | } |
130 | 130 | ||
131 | /* We don't update the usages for the autofs daemon itself, this | 131 | /* We don't update the usages for the autofs daemon itself, this |
132 | is necessary for recursive autofs mounts */ | 132 | is necessary for recursive autofs mounts */ |
133 | if ( !autofs_oz_mode(sbi) ) { | 133 | if (!autofs_oz_mode(sbi)) { |
134 | autofs_update_usage(&sbi->dirhash,ent); | 134 | autofs_update_usage(&sbi->dirhash,ent); |
135 | } | 135 | } |
136 | 136 | ||
@@ -157,7 +157,7 @@ static int autofs_revalidate(struct dentry * dentry, struct nameidata *nd) | |||
157 | sbi = autofs_sbi(dir->i_sb); | 157 | sbi = autofs_sbi(dir->i_sb); |
158 | 158 | ||
159 | /* Pending dentry */ | 159 | /* Pending dentry */ |
160 | if ( dentry->d_flags & DCACHE_AUTOFS_PENDING ) { | 160 | if (dentry->d_flags & DCACHE_AUTOFS_PENDING) { |
161 | if (autofs_oz_mode(sbi)) | 161 | if (autofs_oz_mode(sbi)) |
162 | res = 1; | 162 | res = 1; |
163 | else | 163 | else |
@@ -173,7 +173,7 @@ static int autofs_revalidate(struct dentry * dentry, struct nameidata *nd) | |||
173 | } | 173 | } |
174 | 174 | ||
175 | /* Check for a non-mountpoint directory */ | 175 | /* Check for a non-mountpoint directory */ |
176 | if ( S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry) ) { | 176 | if (S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry)) { |
177 | if (autofs_oz_mode(sbi)) | 177 | if (autofs_oz_mode(sbi)) |
178 | res = 1; | 178 | res = 1; |
179 | else | 179 | else |
@@ -183,9 +183,9 @@ static int autofs_revalidate(struct dentry * dentry, struct nameidata *nd) | |||
183 | } | 183 | } |
184 | 184 | ||
185 | /* Update the usage list */ | 185 | /* Update the usage list */ |
186 | if ( !autofs_oz_mode(sbi) ) { | 186 | if (!autofs_oz_mode(sbi)) { |
187 | ent = (struct autofs_dir_ent *) dentry->d_time; | 187 | ent = (struct autofs_dir_ent *) dentry->d_time; |
188 | if ( ent ) | 188 | if (ent) |
189 | autofs_update_usage(&sbi->dirhash,ent); | 189 | autofs_update_usage(&sbi->dirhash,ent); |
190 | } | 190 | } |
191 | unlock_kernel(); | 191 | unlock_kernel(); |
@@ -213,8 +213,10 @@ static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentr | |||
213 | sbi = autofs_sbi(dir->i_sb); | 213 | sbi = autofs_sbi(dir->i_sb); |
214 | 214 | ||
215 | oz_mode = autofs_oz_mode(sbi); | 215 | oz_mode = autofs_oz_mode(sbi); |
216 | DPRINTK(("autofs_lookup: pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d\n", | 216 | DPRINTK(("autofs_lookup: pid = %u, pgrp = %u, catatonic = %d, " |
217 | current->pid, process_group(current), sbi->catatonic, oz_mode)); | 217 | "oz_mode = %d\n", pid_nr(task_pid(current)), |
218 | process_group(current), sbi->catatonic, | ||
219 | oz_mode)); | ||
218 | 220 | ||
219 | /* | 221 | /* |
220 | * Mark the dentry incomplete, but add it. This is needed so | 222 | * Mark the dentry incomplete, but add it. This is needed so |
@@ -258,7 +260,7 @@ static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentr | |||
258 | * doesn't do the right thing for all system calls, but it should | 260 | * doesn't do the right thing for all system calls, but it should |
259 | * be OK for the operations we permit from an autofs. | 261 | * be OK for the operations we permit from an autofs. |
260 | */ | 262 | */ |
261 | if ( dentry->d_inode && d_unhashed(dentry) ) | 263 | if (dentry->d_inode && d_unhashed(dentry)) |
262 | return ERR_PTR(-ENOENT); | 264 | return ERR_PTR(-ENOENT); |
263 | 265 | ||
264 | return NULL; | 266 | return NULL; |
@@ -277,18 +279,18 @@ static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const c | |||
277 | autofs_say(dentry->d_name.name,dentry->d_name.len); | 279 | autofs_say(dentry->d_name.name,dentry->d_name.len); |
278 | 280 | ||
279 | lock_kernel(); | 281 | lock_kernel(); |
280 | if ( !autofs_oz_mode(sbi) ) { | 282 | if (!autofs_oz_mode(sbi)) { |
281 | unlock_kernel(); | 283 | unlock_kernel(); |
282 | return -EACCES; | 284 | return -EACCES; |
283 | } | 285 | } |
284 | 286 | ||
285 | if ( autofs_hash_lookup(dh, &dentry->d_name) ) { | 287 | if (autofs_hash_lookup(dh, &dentry->d_name)) { |
286 | unlock_kernel(); | 288 | unlock_kernel(); |
287 | return -EEXIST; | 289 | return -EEXIST; |
288 | } | 290 | } |
289 | 291 | ||
290 | n = find_first_zero_bit(sbi->symlink_bitmap,AUTOFS_MAX_SYMLINKS); | 292 | n = find_first_zero_bit(sbi->symlink_bitmap,AUTOFS_MAX_SYMLINKS); |
291 | if ( n >= AUTOFS_MAX_SYMLINKS ) { | 293 | if (n >= AUTOFS_MAX_SYMLINKS) { |
292 | unlock_kernel(); | 294 | unlock_kernel(); |
293 | return -ENOSPC; | 295 | return -ENOSPC; |
294 | } | 296 | } |
@@ -297,14 +299,14 @@ static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const c | |||
297 | sl = &sbi->symlink[n]; | 299 | sl = &sbi->symlink[n]; |
298 | sl->len = strlen(symname); | 300 | sl->len = strlen(symname); |
299 | sl->data = kmalloc(slsize = sl->len+1, GFP_KERNEL); | 301 | sl->data = kmalloc(slsize = sl->len+1, GFP_KERNEL); |
300 | if ( !sl->data ) { | 302 | if (!sl->data) { |
301 | clear_bit(n,sbi->symlink_bitmap); | 303 | clear_bit(n,sbi->symlink_bitmap); |
302 | unlock_kernel(); | 304 | unlock_kernel(); |
303 | return -ENOSPC; | 305 | return -ENOSPC; |
304 | } | 306 | } |
305 | 307 | ||
306 | ent = kmalloc(sizeof(struct autofs_dir_ent), GFP_KERNEL); | 308 | ent = kmalloc(sizeof(struct autofs_dir_ent), GFP_KERNEL); |
307 | if ( !ent ) { | 309 | if (!ent) { |
308 | kfree(sl->data); | 310 | kfree(sl->data); |
309 | clear_bit(n,sbi->symlink_bitmap); | 311 | clear_bit(n,sbi->symlink_bitmap); |
310 | unlock_kernel(); | 312 | unlock_kernel(); |
@@ -312,7 +314,7 @@ static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const c | |||
312 | } | 314 | } |
313 | 315 | ||
314 | ent->name = kmalloc(dentry->d_name.len+1, GFP_KERNEL); | 316 | ent->name = kmalloc(dentry->d_name.len+1, GFP_KERNEL); |
315 | if ( !ent->name ) { | 317 | if (!ent->name) { |
316 | kfree(sl->data); | 318 | kfree(sl->data); |
317 | kfree(ent); | 319 | kfree(ent); |
318 | clear_bit(n,sbi->symlink_bitmap); | 320 | clear_bit(n,sbi->symlink_bitmap); |
@@ -354,23 +356,23 @@ static int autofs_root_unlink(struct inode *dir, struct dentry *dentry) | |||
354 | 356 | ||
355 | /* This allows root to remove symlinks */ | 357 | /* This allows root to remove symlinks */ |
356 | lock_kernel(); | 358 | lock_kernel(); |
357 | if ( !autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) ) { | 359 | if (!autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN)) { |
358 | unlock_kernel(); | 360 | unlock_kernel(); |
359 | return -EACCES; | 361 | return -EACCES; |
360 | } | 362 | } |
361 | 363 | ||
362 | ent = autofs_hash_lookup(dh, &dentry->d_name); | 364 | ent = autofs_hash_lookup(dh, &dentry->d_name); |
363 | if ( !ent ) { | 365 | if (!ent) { |
364 | unlock_kernel(); | 366 | unlock_kernel(); |
365 | return -ENOENT; | 367 | return -ENOENT; |
366 | } | 368 | } |
367 | 369 | ||
368 | n = ent->ino - AUTOFS_FIRST_SYMLINK; | 370 | n = ent->ino - AUTOFS_FIRST_SYMLINK; |
369 | if ( n >= AUTOFS_MAX_SYMLINKS ) { | 371 | if (n >= AUTOFS_MAX_SYMLINKS) { |
370 | unlock_kernel(); | 372 | unlock_kernel(); |
371 | return -EISDIR; /* It's a directory, dummy */ | 373 | return -EISDIR; /* It's a directory, dummy */ |
372 | } | 374 | } |
373 | if ( !test_bit(n,sbi->symlink_bitmap) ) { | 375 | if (!test_bit(n,sbi->symlink_bitmap)) { |
374 | unlock_kernel(); | 376 | unlock_kernel(); |
375 | return -EINVAL; /* Nonexistent symlink? Shouldn't happen */ | 377 | return -EINVAL; /* Nonexistent symlink? Shouldn't happen */ |
376 | } | 378 | } |
@@ -392,23 +394,23 @@ static int autofs_root_rmdir(struct inode *dir, struct dentry *dentry) | |||
392 | struct autofs_dir_ent *ent; | 394 | struct autofs_dir_ent *ent; |
393 | 395 | ||
394 | lock_kernel(); | 396 | lock_kernel(); |
395 | if ( !autofs_oz_mode(sbi) ) { | 397 | if (!autofs_oz_mode(sbi)) { |
396 | unlock_kernel(); | 398 | unlock_kernel(); |
397 | return -EACCES; | 399 | return -EACCES; |
398 | } | 400 | } |
399 | 401 | ||
400 | ent = autofs_hash_lookup(dh, &dentry->d_name); | 402 | ent = autofs_hash_lookup(dh, &dentry->d_name); |
401 | if ( !ent ) { | 403 | if (!ent) { |
402 | unlock_kernel(); | 404 | unlock_kernel(); |
403 | return -ENOENT; | 405 | return -ENOENT; |
404 | } | 406 | } |
405 | 407 | ||
406 | if ( (unsigned int)ent->ino < AUTOFS_FIRST_DIR_INO ) { | 408 | if ((unsigned int)ent->ino < AUTOFS_FIRST_DIR_INO) { |
407 | unlock_kernel(); | 409 | unlock_kernel(); |
408 | return -ENOTDIR; /* Not a directory */ | 410 | return -ENOTDIR; /* Not a directory */ |
409 | } | 411 | } |
410 | 412 | ||
411 | if ( ent->dentry != dentry ) { | 413 | if (ent->dentry != dentry) { |
412 | printk("autofs_rmdir: odentry != dentry for entry %s\n", dentry->d_name.name); | 414 | printk("autofs_rmdir: odentry != dentry for entry %s\n", dentry->d_name.name); |
413 | } | 415 | } |
414 | 416 | ||
@@ -429,18 +431,18 @@ static int autofs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
429 | ino_t ino; | 431 | ino_t ino; |
430 | 432 | ||
431 | lock_kernel(); | 433 | lock_kernel(); |
432 | if ( !autofs_oz_mode(sbi) ) { | 434 | if (!autofs_oz_mode(sbi)) { |
433 | unlock_kernel(); | 435 | unlock_kernel(); |
434 | return -EACCES; | 436 | return -EACCES; |
435 | } | 437 | } |
436 | 438 | ||
437 | ent = autofs_hash_lookup(dh, &dentry->d_name); | 439 | ent = autofs_hash_lookup(dh, &dentry->d_name); |
438 | if ( ent ) { | 440 | if (ent) { |
439 | unlock_kernel(); | 441 | unlock_kernel(); |
440 | return -EEXIST; | 442 | return -EEXIST; |
441 | } | 443 | } |
442 | 444 | ||
443 | if ( sbi->next_dir_ino < AUTOFS_FIRST_DIR_INO ) { | 445 | if (sbi->next_dir_ino < AUTOFS_FIRST_DIR_INO) { |
444 | printk("autofs: Out of inode numbers -- what the heck did you do??\n"); | 446 | printk("autofs: Out of inode numbers -- what the heck did you do??\n"); |
445 | unlock_kernel(); | 447 | unlock_kernel(); |
446 | return -ENOSPC; | 448 | return -ENOSPC; |
@@ -448,13 +450,13 @@ static int autofs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
448 | ino = sbi->next_dir_ino++; | 450 | ino = sbi->next_dir_ino++; |
449 | 451 | ||
450 | ent = kmalloc(sizeof(struct autofs_dir_ent), GFP_KERNEL); | 452 | ent = kmalloc(sizeof(struct autofs_dir_ent), GFP_KERNEL); |
451 | if ( !ent ) { | 453 | if (!ent) { |
452 | unlock_kernel(); | 454 | unlock_kernel(); |
453 | return -ENOSPC; | 455 | return -ENOSPC; |
454 | } | 456 | } |
455 | 457 | ||
456 | ent->name = kmalloc(dentry->d_name.len+1, GFP_KERNEL); | 458 | ent->name = kmalloc(dentry->d_name.len+1, GFP_KERNEL); |
457 | if ( !ent->name ) { | 459 | if (!ent->name) { |
458 | kfree(ent); | 460 | kfree(ent); |
459 | unlock_kernel(); | 461 | unlock_kernel(); |
460 | return -ENOSPC; | 462 | return -ENOSPC; |
@@ -483,7 +485,7 @@ static inline int autofs_get_set_timeout(struct autofs_sb_info *sbi, | |||
483 | put_user(sbi->exp_timeout / HZ, p)) | 485 | put_user(sbi->exp_timeout / HZ, p)) |
484 | return -EFAULT; | 486 | return -EFAULT; |
485 | 487 | ||
486 | if ( ntimeout > ULONG_MAX/HZ ) | 488 | if (ntimeout > ULONG_MAX/HZ) |
487 | sbi->exp_timeout = 0; | 489 | sbi->exp_timeout = 0; |
488 | else | 490 | else |
489 | sbi->exp_timeout = ntimeout * HZ; | 491 | sbi->exp_timeout = ntimeout * HZ; |
@@ -511,15 +513,14 @@ static inline int autofs_expire_run(struct super_block *sb, | |||
511 | pkt.hdr.proto_version = AUTOFS_PROTO_VERSION; | 513 | pkt.hdr.proto_version = AUTOFS_PROTO_VERSION; |
512 | pkt.hdr.type = autofs_ptype_expire; | 514 | pkt.hdr.type = autofs_ptype_expire; |
513 | 515 | ||
514 | if ( !sbi->exp_timeout || | 516 | if (!sbi->exp_timeout || !(ent = autofs_expire(sb,sbi,mnt))) |
515 | !(ent = autofs_expire(sb,sbi,mnt)) ) | ||
516 | return -EAGAIN; | 517 | return -EAGAIN; |
517 | 518 | ||
518 | pkt.len = ent->len; | 519 | pkt.len = ent->len; |
519 | memcpy(pkt.name, ent->name, pkt.len); | 520 | memcpy(pkt.name, ent->name, pkt.len); |
520 | pkt.name[pkt.len] = '\0'; | 521 | pkt.name[pkt.len] = '\0'; |
521 | 522 | ||
522 | if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) ) | 523 | if (copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire))) |
523 | return -EFAULT; | 524 | return -EFAULT; |
524 | 525 | ||
525 | return 0; | 526 | return 0; |
@@ -537,11 +538,11 @@ static int autofs_root_ioctl(struct inode *inode, struct file *filp, | |||
537 | 538 | ||
538 | DPRINTK(("autofs_ioctl: cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u\n",cmd,arg,sbi,process_group(current))); | 539 | DPRINTK(("autofs_ioctl: cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u\n",cmd,arg,sbi,process_group(current))); |
539 | 540 | ||
540 | if ( _IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) || | 541 | if (_IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) || |
541 | _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT ) | 542 | _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT) |
542 | return -ENOTTY; | 543 | return -ENOTTY; |
543 | 544 | ||
544 | if ( !autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) ) | 545 | if (!autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN)) |
545 | return -EPERM; | 546 | return -EPERM; |
546 | 547 | ||
547 | switch(cmd) { | 548 | switch(cmd) { |
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index 5769a2f9ad60..692364e8ffc3 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c | |||
@@ -218,8 +218,7 @@ static match_table_t tokens = { | |||
218 | }; | 218 | }; |
219 | 219 | ||
220 | static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, | 220 | static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, |
221 | pid_t *pgrp, unsigned int *type, | 221 | pid_t *pgrp, unsigned int *type, int *minproto, int *maxproto) |
222 | int *minproto, int *maxproto) | ||
223 | { | 222 | { |
224 | char *p; | 223 | char *p; |
225 | substring_t args[MAX_OPT_ARGS]; | 224 | substring_t args[MAX_OPT_ARGS]; |
@@ -314,7 +313,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) | |||
314 | struct autofs_info *ino; | 313 | struct autofs_info *ino; |
315 | 314 | ||
316 | sbi = kmalloc(sizeof(*sbi), GFP_KERNEL); | 315 | sbi = kmalloc(sizeof(*sbi), GFP_KERNEL); |
317 | if ( !sbi ) | 316 | if (!sbi) |
318 | goto fail_unlock; | 317 | goto fail_unlock; |
319 | DPRINTK("starting up, sbi = %p",sbi); | 318 | DPRINTK("starting up, sbi = %p",sbi); |
320 | 319 | ||
@@ -363,10 +362,9 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) | |||
363 | root->d_fsdata = ino; | 362 | root->d_fsdata = ino; |
364 | 363 | ||
365 | /* Can this call block? */ | 364 | /* Can this call block? */ |
366 | if (parse_options(data, &pipefd, | 365 | if (parse_options(data, &pipefd, &root_inode->i_uid, &root_inode->i_gid, |
367 | &root_inode->i_uid, &root_inode->i_gid, | 366 | &sbi->oz_pgrp, &sbi->type, &sbi->min_proto, |
368 | &sbi->oz_pgrp, &sbi->type, | 367 | &sbi->max_proto)) { |
369 | &sbi->min_proto, &sbi->max_proto)) { | ||
370 | printk("autofs: called with bogus options\n"); | 368 | printk("autofs: called with bogus options\n"); |
371 | goto fail_dput; | 369 | goto fail_dput; |
372 | } | 370 | } |
@@ -396,11 +394,11 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) | |||
396 | DPRINTK("pipe fd = %d, pgrp = %u", pipefd, sbi->oz_pgrp); | 394 | DPRINTK("pipe fd = %d, pgrp = %u", pipefd, sbi->oz_pgrp); |
397 | pipe = fget(pipefd); | 395 | pipe = fget(pipefd); |
398 | 396 | ||
399 | if ( !pipe ) { | 397 | if (!pipe) { |
400 | printk("autofs: could not open pipe file descriptor\n"); | 398 | printk("autofs: could not open pipe file descriptor\n"); |
401 | goto fail_dput; | 399 | goto fail_dput; |
402 | } | 400 | } |
403 | if ( !pipe->f_op || !pipe->f_op->write ) | 401 | if (!pipe->f_op || !pipe->f_op->write) |
404 | goto fail_fput; | 402 | goto fail_fput; |
405 | sbi->pipe = pipe; | 403 | sbi->pipe = pipe; |
406 | sbi->pipefd = pipefd; | 404 | sbi->pipefd = pipefd; |
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 15170f4e13a7..2d4c8a3e604e 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -759,7 +759,7 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry) | |||
759 | struct autofs_info *p_ino; | 759 | struct autofs_info *p_ino; |
760 | 760 | ||
761 | /* This allows root to remove symlinks */ | 761 | /* This allows root to remove symlinks */ |
762 | if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) ) | 762 | if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN)) |
763 | return -EACCES; | 763 | return -EACCES; |
764 | 764 | ||
765 | if (atomic_dec_and_test(&ino->count)) { | 765 | if (atomic_dec_and_test(&ino->count)) { |
@@ -833,7 +833,7 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
833 | struct autofs_info *p_ino; | 833 | struct autofs_info *p_ino; |
834 | struct inode *inode; | 834 | struct inode *inode; |
835 | 835 | ||
836 | if ( !autofs4_oz_mode(sbi) ) | 836 | if (!autofs4_oz_mode(sbi)) |
837 | return -EACCES; | 837 | return -EACCES; |
838 | 838 | ||
839 | DPRINTK("dentry %p, creating %.*s", | 839 | DPRINTK("dentry %p, creating %.*s", |
@@ -871,11 +871,11 @@ static inline int autofs4_get_set_timeout(struct autofs_sb_info *sbi, | |||
871 | int rv; | 871 | int rv; |
872 | unsigned long ntimeout; | 872 | unsigned long ntimeout; |
873 | 873 | ||
874 | if ( (rv = get_user(ntimeout, p)) || | 874 | if ((rv = get_user(ntimeout, p)) || |
875 | (rv = put_user(sbi->exp_timeout/HZ, p)) ) | 875 | (rv = put_user(sbi->exp_timeout/HZ, p))) |
876 | return rv; | 876 | return rv; |
877 | 877 | ||
878 | if ( ntimeout > ULONG_MAX/HZ ) | 878 | if (ntimeout > ULONG_MAX/HZ) |
879 | sbi->exp_timeout = 0; | 879 | sbi->exp_timeout = 0; |
880 | else | 880 | else |
881 | sbi->exp_timeout = ntimeout * HZ; | 881 | sbi->exp_timeout = ntimeout * HZ; |
@@ -906,7 +906,7 @@ static inline int autofs4_ask_reghost(struct autofs_sb_info *sbi, int __user *p) | |||
906 | DPRINTK("returning %d", sbi->needs_reghost); | 906 | DPRINTK("returning %d", sbi->needs_reghost); |
907 | 907 | ||
908 | status = put_user(sbi->needs_reghost, p); | 908 | status = put_user(sbi->needs_reghost, p); |
909 | if ( status ) | 909 | if (status) |
910 | return status; | 910 | return status; |
911 | 911 | ||
912 | sbi->needs_reghost = 0; | 912 | sbi->needs_reghost = 0; |
@@ -975,11 +975,11 @@ static int autofs4_root_ioctl(struct inode *inode, struct file *filp, | |||
975 | DPRINTK("cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u", | 975 | DPRINTK("cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u", |
976 | cmd,arg,sbi,process_group(current)); | 976 | cmd,arg,sbi,process_group(current)); |
977 | 977 | ||
978 | if ( _IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) || | 978 | if (_IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) || |
979 | _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT ) | 979 | _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT) |
980 | return -ENOTTY; | 980 | return -ENOTTY; |
981 | 981 | ||
982 | if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) ) | 982 | if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN)) |
983 | return -EPERM; | 983 | return -EPERM; |
984 | 984 | ||
985 | switch(cmd) { | 985 | switch(cmd) { |
diff --git a/fs/compat.c b/fs/compat.c index 9cf75df9b2bb..7b21b0a82596 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <linux/tsacct_kern.h> | 46 | #include <linux/tsacct_kern.h> |
47 | #include <linux/security.h> | 47 | #include <linux/security.h> |
48 | #include <linux/highmem.h> | 48 | #include <linux/highmem.h> |
49 | #include <linux/signal.h> | ||
49 | #include <linux/poll.h> | 50 | #include <linux/poll.h> |
50 | #include <linux/mm.h> | 51 | #include <linux/mm.h> |
51 | #include <linux/eventpoll.h> | 52 | #include <linux/eventpoll.h> |
@@ -2199,3 +2200,51 @@ asmlinkage long compat_sys_epoll_pwait(int epfd, | |||
2199 | #endif /* TIF_RESTORE_SIGMASK */ | 2200 | #endif /* TIF_RESTORE_SIGMASK */ |
2200 | 2201 | ||
2201 | #endif /* CONFIG_EPOLL */ | 2202 | #endif /* CONFIG_EPOLL */ |
2203 | |||
2204 | #ifdef CONFIG_SIGNALFD | ||
2205 | |||
2206 | asmlinkage long compat_sys_signalfd(int ufd, | ||
2207 | const compat_sigset_t __user *sigmask, | ||
2208 | compat_size_t sigsetsize) | ||
2209 | { | ||
2210 | compat_sigset_t ss32; | ||
2211 | sigset_t tmp; | ||
2212 | sigset_t __user *ksigmask; | ||
2213 | |||
2214 | if (sigsetsize != sizeof(compat_sigset_t)) | ||
2215 | return -EINVAL; | ||
2216 | if (copy_from_user(&ss32, sigmask, sizeof(ss32))) | ||
2217 | return -EFAULT; | ||
2218 | sigset_from_compat(&tmp, &ss32); | ||
2219 | ksigmask = compat_alloc_user_space(sizeof(sigset_t)); | ||
2220 | if (copy_to_user(ksigmask, &tmp, sizeof(sigset_t))) | ||
2221 | return -EFAULT; | ||
2222 | |||
2223 | return sys_signalfd(ufd, ksigmask, sizeof(sigset_t)); | ||
2224 | } | ||
2225 | |||
2226 | #endif /* CONFIG_SIGNALFD */ | ||
2227 | |||
2228 | #ifdef CONFIG_TIMERFD | ||
2229 | |||
2230 | asmlinkage long compat_sys_timerfd(int ufd, int clockid, int flags, | ||
2231 | const struct compat_itimerspec __user *utmr) | ||
2232 | { | ||
2233 | long res; | ||
2234 | struct itimerspec t; | ||
2235 | struct itimerspec __user *ut; | ||
2236 | |||
2237 | res = -EFAULT; | ||
2238 | if (get_compat_itimerspec(&t, utmr)) | ||
2239 | goto err_exit; | ||
2240 | ut = compat_alloc_user_space(sizeof(*ut)); | ||
2241 | if (copy_to_user(ut, &t, sizeof(t)) ) | ||
2242 | goto err_exit; | ||
2243 | |||
2244 | res = sys_timerfd(ufd, clockid, flags, ut); | ||
2245 | err_exit: | ||
2246 | return res; | ||
2247 | } | ||
2248 | |||
2249 | #endif /* CONFIG_TIMERFD */ | ||
2250 | |||
diff --git a/fs/eventfd.c b/fs/eventfd.c new file mode 100644 index 000000000000..480e2b3c4166 --- /dev/null +++ b/fs/eventfd.c | |||
@@ -0,0 +1,228 @@ | |||
1 | /* | ||
2 | * fs/eventfd.c | ||
3 | * | ||
4 | * Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org> | ||
5 | * | ||
6 | */ | ||
7 | |||
8 | #include <linux/file.h> | ||
9 | #include <linux/poll.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/fs.h> | ||
12 | #include <linux/sched.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/list.h> | ||
15 | #include <linux/spinlock.h> | ||
16 | #include <linux/anon_inodes.h> | ||
17 | #include <linux/eventfd.h> | ||
18 | |||
19 | struct eventfd_ctx { | ||
20 | spinlock_t lock; | ||
21 | wait_queue_head_t wqh; | ||
22 | /* | ||
23 | * Every time that a write(2) is performed on an eventfd, the | ||
24 | * value of the __u64 being written is added to "count" and a | ||
25 | * wakeup is performed on "wqh". A read(2) will return the "count" | ||
26 | * value to userspace, and will reset "count" to zero. The kernel | ||
27 | * size eventfd_signal() also, adds to the "count" counter and | ||
28 | * issue a wakeup. | ||
29 | */ | ||
30 | __u64 count; | ||
31 | }; | ||
32 | |||
33 | /* | ||
34 | * Adds "n" to the eventfd counter "count". Returns "n" in case of | ||
35 | * success, or a value lower then "n" in case of coutner overflow. | ||
36 | * This function is supposed to be called by the kernel in paths | ||
37 | * that do not allow sleeping. In this function we allow the counter | ||
38 | * to reach the ULLONG_MAX value, and we signal this as overflow | ||
39 | * condition by returining a POLLERR to poll(2). | ||
40 | */ | ||
41 | int eventfd_signal(struct file *file, int n) | ||
42 | { | ||
43 | struct eventfd_ctx *ctx = file->private_data; | ||
44 | unsigned long flags; | ||
45 | |||
46 | if (n < 0) | ||
47 | return -EINVAL; | ||
48 | spin_lock_irqsave(&ctx->lock, flags); | ||
49 | if (ULLONG_MAX - ctx->count < n) | ||
50 | n = (int) (ULLONG_MAX - ctx->count); | ||
51 | ctx->count += n; | ||
52 | if (waitqueue_active(&ctx->wqh)) | ||
53 | wake_up_locked(&ctx->wqh); | ||
54 | spin_unlock_irqrestore(&ctx->lock, flags); | ||
55 | |||
56 | return n; | ||
57 | } | ||
58 | |||
59 | static int eventfd_release(struct inode *inode, struct file *file) | ||
60 | { | ||
61 | kfree(file->private_data); | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static unsigned int eventfd_poll(struct file *file, poll_table *wait) | ||
66 | { | ||
67 | struct eventfd_ctx *ctx = file->private_data; | ||
68 | unsigned int events = 0; | ||
69 | unsigned long flags; | ||
70 | |||
71 | poll_wait(file, &ctx->wqh, wait); | ||
72 | |||
73 | spin_lock_irqsave(&ctx->lock, flags); | ||
74 | if (ctx->count > 0) | ||
75 | events |= POLLIN; | ||
76 | if (ctx->count == ULLONG_MAX) | ||
77 | events |= POLLERR; | ||
78 | if (ULLONG_MAX - 1 > ctx->count) | ||
79 | events |= POLLOUT; | ||
80 | spin_unlock_irqrestore(&ctx->lock, flags); | ||
81 | |||
82 | return events; | ||
83 | } | ||
84 | |||
85 | static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count, | ||
86 | loff_t *ppos) | ||
87 | { | ||
88 | struct eventfd_ctx *ctx = file->private_data; | ||
89 | ssize_t res; | ||
90 | __u64 ucnt; | ||
91 | DECLARE_WAITQUEUE(wait, current); | ||
92 | |||
93 | if (count < sizeof(ucnt)) | ||
94 | return -EINVAL; | ||
95 | spin_lock_irq(&ctx->lock); | ||
96 | res = -EAGAIN; | ||
97 | ucnt = ctx->count; | ||
98 | if (ucnt > 0) | ||
99 | res = sizeof(ucnt); | ||
100 | else if (!(file->f_flags & O_NONBLOCK)) { | ||
101 | __add_wait_queue(&ctx->wqh, &wait); | ||
102 | for (res = 0;;) { | ||
103 | set_current_state(TASK_INTERRUPTIBLE); | ||
104 | if (ctx->count > 0) { | ||
105 | ucnt = ctx->count; | ||
106 | res = sizeof(ucnt); | ||
107 | break; | ||
108 | } | ||
109 | if (signal_pending(current)) { | ||
110 | res = -ERESTARTSYS; | ||
111 | break; | ||
112 | } | ||
113 | spin_unlock_irq(&ctx->lock); | ||
114 | schedule(); | ||
115 | spin_lock_irq(&ctx->lock); | ||
116 | } | ||
117 | __remove_wait_queue(&ctx->wqh, &wait); | ||
118 | __set_current_state(TASK_RUNNING); | ||
119 | } | ||
120 | if (res > 0) { | ||
121 | ctx->count = 0; | ||
122 | if (waitqueue_active(&ctx->wqh)) | ||
123 | wake_up_locked(&ctx->wqh); | ||
124 | } | ||
125 | spin_unlock_irq(&ctx->lock); | ||
126 | if (res > 0 && put_user(ucnt, (__u64 __user *) buf)) | ||
127 | return -EFAULT; | ||
128 | |||
129 | return res; | ||
130 | } | ||
131 | |||
132 | static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t count, | ||
133 | loff_t *ppos) | ||
134 | { | ||
135 | struct eventfd_ctx *ctx = file->private_data; | ||
136 | ssize_t res; | ||
137 | __u64 ucnt; | ||
138 | DECLARE_WAITQUEUE(wait, current); | ||
139 | |||
140 | if (count < sizeof(ucnt)) | ||
141 | return -EINVAL; | ||
142 | if (copy_from_user(&ucnt, buf, sizeof(ucnt))) | ||
143 | return -EFAULT; | ||
144 | if (ucnt == ULLONG_MAX) | ||
145 | return -EINVAL; | ||
146 | spin_lock_irq(&ctx->lock); | ||
147 | res = -EAGAIN; | ||
148 | if (ULLONG_MAX - ctx->count > ucnt) | ||
149 | res = sizeof(ucnt); | ||
150 | else if (!(file->f_flags & O_NONBLOCK)) { | ||
151 | __add_wait_queue(&ctx->wqh, &wait); | ||
152 | for (res = 0;;) { | ||
153 | set_current_state(TASK_INTERRUPTIBLE); | ||
154 | if (ULLONG_MAX - ctx->count > ucnt) { | ||
155 | res = sizeof(ucnt); | ||
156 | break; | ||
157 | } | ||
158 | if (signal_pending(current)) { | ||
159 | res = -ERESTARTSYS; | ||
160 | break; | ||
161 | } | ||
162 | spin_unlock_irq(&ctx->lock); | ||
163 | schedule(); | ||
164 | spin_lock_irq(&ctx->lock); | ||
165 | } | ||
166 | __remove_wait_queue(&ctx->wqh, &wait); | ||
167 | __set_current_state(TASK_RUNNING); | ||
168 | } | ||
169 | if (res > 0) { | ||
170 | ctx->count += ucnt; | ||
171 | if (waitqueue_active(&ctx->wqh)) | ||
172 | wake_up_locked(&ctx->wqh); | ||
173 | } | ||
174 | spin_unlock_irq(&ctx->lock); | ||
175 | |||
176 | return res; | ||
177 | } | ||
178 | |||
179 | static const struct file_operations eventfd_fops = { | ||
180 | .release = eventfd_release, | ||
181 | .poll = eventfd_poll, | ||
182 | .read = eventfd_read, | ||
183 | .write = eventfd_write, | ||
184 | }; | ||
185 | |||
186 | struct file *eventfd_fget(int fd) | ||
187 | { | ||
188 | struct file *file; | ||
189 | |||
190 | file = fget(fd); | ||
191 | if (!file) | ||
192 | return ERR_PTR(-EBADF); | ||
193 | if (file->f_op != &eventfd_fops) { | ||
194 | fput(file); | ||
195 | return ERR_PTR(-EINVAL); | ||
196 | } | ||
197 | |||
198 | return file; | ||
199 | } | ||
200 | |||
201 | asmlinkage long sys_eventfd(unsigned int count) | ||
202 | { | ||
203 | int error, fd; | ||
204 | struct eventfd_ctx *ctx; | ||
205 | struct file *file; | ||
206 | struct inode *inode; | ||
207 | |||
208 | ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); | ||
209 | if (!ctx) | ||
210 | return -ENOMEM; | ||
211 | |||
212 | init_waitqueue_head(&ctx->wqh); | ||
213 | spin_lock_init(&ctx->lock); | ||
214 | ctx->count = count; | ||
215 | |||
216 | /* | ||
217 | * When we call this, the initialization must be complete, since | ||
218 | * anon_inode_getfd() will install the fd. | ||
219 | */ | ||
220 | error = anon_inode_getfd(&fd, &inode, &file, "[eventfd]", | ||
221 | &eventfd_fops, ctx); | ||
222 | if (!error) | ||
223 | return fd; | ||
224 | |||
225 | kfree(ctx); | ||
226 | return error; | ||
227 | } | ||
228 | |||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c index b5c7ca584939..1aad34ea61a4 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c | |||
@@ -11,7 +11,6 @@ | |||
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | 14 | #include <linux/init.h> |
16 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
17 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
@@ -34,6 +33,7 @@ | |||
34 | #include <linux/mount.h> | 33 | #include <linux/mount.h> |
35 | #include <linux/bitops.h> | 34 | #include <linux/bitops.h> |
36 | #include <linux/mutex.h> | 35 | #include <linux/mutex.h> |
36 | #include <linux/anon_inodes.h> | ||
37 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
38 | #include <asm/system.h> | 38 | #include <asm/system.h> |
39 | #include <asm/io.h> | 39 | #include <asm/io.h> |
@@ -41,7 +41,6 @@ | |||
41 | #include <asm/atomic.h> | 41 | #include <asm/atomic.h> |
42 | #include <asm/semaphore.h> | 42 | #include <asm/semaphore.h> |
43 | 43 | ||
44 | |||
45 | /* | 44 | /* |
46 | * LOCKING: | 45 | * LOCKING: |
47 | * There are three level of locking required by epoll : | 46 | * There are three level of locking required by epoll : |
@@ -74,9 +73,6 @@ | |||
74 | * a greater scalability. | 73 | * a greater scalability. |
75 | */ | 74 | */ |
76 | 75 | ||
77 | |||
78 | #define EVENTPOLLFS_MAGIC 0x03111965 /* My birthday should work for this :) */ | ||
79 | |||
80 | #define DEBUG_EPOLL 0 | 76 | #define DEBUG_EPOLL 0 |
81 | 77 | ||
82 | #if DEBUG_EPOLL > 0 | 78 | #if DEBUG_EPOLL > 0 |
@@ -106,7 +102,6 @@ | |||
106 | 102 | ||
107 | #define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event)) | 103 | #define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event)) |
108 | 104 | ||
109 | |||
110 | struct epoll_filefd { | 105 | struct epoll_filefd { |
111 | struct file *file; | 106 | struct file *file; |
112 | int fd; | 107 | int fd; |
@@ -224,43 +219,6 @@ struct ep_pqueue { | |||
224 | struct epitem *epi; | 219 | struct epitem *epi; |
225 | }; | 220 | }; |
226 | 221 | ||
227 | |||
228 | |||
229 | static void ep_poll_safewake_init(struct poll_safewake *psw); | ||
230 | static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq); | ||
231 | static int ep_getfd(int *efd, struct inode **einode, struct file **efile, | ||
232 | struct eventpoll *ep); | ||
233 | static int ep_alloc(struct eventpoll **pep); | ||
234 | static void ep_free(struct eventpoll *ep); | ||
235 | static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd); | ||
236 | static void ep_use_epitem(struct epitem *epi); | ||
237 | static void ep_release_epitem(struct epitem *epi); | ||
238 | static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead, | ||
239 | poll_table *pt); | ||
240 | static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi); | ||
241 | static int ep_insert(struct eventpoll *ep, struct epoll_event *event, | ||
242 | struct file *tfile, int fd); | ||
243 | static int ep_modify(struct eventpoll *ep, struct epitem *epi, | ||
244 | struct epoll_event *event); | ||
245 | static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi); | ||
246 | static int ep_unlink(struct eventpoll *ep, struct epitem *epi); | ||
247 | static int ep_remove(struct eventpoll *ep, struct epitem *epi); | ||
248 | static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *key); | ||
249 | static int ep_eventpoll_close(struct inode *inode, struct file *file); | ||
250 | static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait); | ||
251 | static int ep_send_events(struct eventpoll *ep, struct list_head *txlist, | ||
252 | struct epoll_event __user *events, int maxevents); | ||
253 | static int ep_events_transfer(struct eventpoll *ep, | ||
254 | struct epoll_event __user *events, | ||
255 | int maxevents); | ||
256 | static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, | ||
257 | int maxevents, long timeout); | ||
258 | static int eventpollfs_delete_dentry(struct dentry *dentry); | ||
259 | static struct inode *ep_eventpoll_inode(void); | ||
260 | static int eventpollfs_get_sb(struct file_system_type *fs_type, | ||
261 | int flags, const char *dev_name, | ||
262 | void *data, struct vfsmount *mnt); | ||
263 | |||
264 | /* | 222 | /* |
265 | * This semaphore is used to serialize ep_free() and eventpoll_release_file(). | 223 | * This semaphore is used to serialize ep_free() and eventpoll_release_file(). |
266 | */ | 224 | */ |
@@ -275,37 +233,6 @@ static struct kmem_cache *epi_cache __read_mostly; | |||
275 | /* Slab cache used to allocate "struct eppoll_entry" */ | 233 | /* Slab cache used to allocate "struct eppoll_entry" */ |
276 | static struct kmem_cache *pwq_cache __read_mostly; | 234 | static struct kmem_cache *pwq_cache __read_mostly; |
277 | 235 | ||
278 | /* Virtual fs used to allocate inodes for eventpoll files */ | ||
279 | static struct vfsmount *eventpoll_mnt __read_mostly; | ||
280 | |||
281 | /* File callbacks that implement the eventpoll file behaviour */ | ||
282 | static const struct file_operations eventpoll_fops = { | ||
283 | .release = ep_eventpoll_close, | ||
284 | .poll = ep_eventpoll_poll | ||
285 | }; | ||
286 | |||
287 | /* | ||
288 | * This is used to register the virtual file system from where | ||
289 | * eventpoll inodes are allocated. | ||
290 | */ | ||
291 | static struct file_system_type eventpoll_fs_type = { | ||
292 | .name = "eventpollfs", | ||
293 | .get_sb = eventpollfs_get_sb, | ||
294 | .kill_sb = kill_anon_super, | ||
295 | }; | ||
296 | |||
297 | /* Very basic directory entry operations for the eventpoll virtual file system */ | ||
298 | static struct dentry_operations eventpollfs_dentry_operations = { | ||
299 | .d_delete = eventpollfs_delete_dentry, | ||
300 | }; | ||
301 | |||
302 | |||
303 | |||
304 | /* Fast test to see if the file is an evenpoll file */ | ||
305 | static inline int is_file_epoll(struct file *f) | ||
306 | { | ||
307 | return f->f_op == &eventpoll_fops; | ||
308 | } | ||
309 | 236 | ||
310 | /* Setup the structure that is used as key for the rb-tree */ | 237 | /* Setup the structure that is used as key for the rb-tree */ |
311 | static inline void ep_set_ffd(struct epoll_filefd *ffd, | 238 | static inline void ep_set_ffd(struct epoll_filefd *ffd, |
@@ -374,7 +301,6 @@ static void ep_poll_safewake_init(struct poll_safewake *psw) | |||
374 | spin_lock_init(&psw->lock); | 301 | spin_lock_init(&psw->lock); |
375 | } | 302 | } |
376 | 303 | ||
377 | |||
378 | /* | 304 | /* |
379 | * Perform a safe wake up of the poll wait list. The problem is that | 305 | * Perform a safe wake up of the poll wait list. The problem is that |
380 | * with the new callback'd wake up system, it is possible that the | 306 | * with the new callback'd wake up system, it is possible that the |
@@ -429,399 +355,144 @@ static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq) | |||
429 | spin_unlock_irqrestore(&psw->lock, flags); | 355 | spin_unlock_irqrestore(&psw->lock, flags); |
430 | } | 356 | } |
431 | 357 | ||
432 | |||
433 | /* | 358 | /* |
434 | * This is called from eventpoll_release() to unlink files from the eventpoll | 359 | * This function unregister poll callbacks from the associated file descriptor. |
435 | * interface. We need to have this facility to cleanup correctly files that are | 360 | * Since this must be called without holding "ep->lock" the atomic exchange trick |
436 | * closed without being removed from the eventpoll interface. | 361 | * will protect us from multiple unregister. |
437 | */ | 362 | */ |
438 | void eventpoll_release_file(struct file *file) | 363 | static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi) |
439 | { | 364 | { |
440 | struct list_head *lsthead = &file->f_ep_links; | 365 | int nwait; |
441 | struct eventpoll *ep; | 366 | struct list_head *lsthead = &epi->pwqlist; |
442 | struct epitem *epi; | 367 | struct eppoll_entry *pwq; |
443 | 368 | ||
444 | /* | 369 | /* This is called without locks, so we need the atomic exchange */ |
445 | * We don't want to get "file->f_ep_lock" because it is not | 370 | nwait = xchg(&epi->nwait, 0); |
446 | * necessary. It is not necessary because we're in the "struct file" | ||
447 | * cleanup path, and this means that noone is using this file anymore. | ||
448 | * The only hit might come from ep_free() but by holding the semaphore | ||
449 | * will correctly serialize the operation. We do need to acquire | ||
450 | * "ep->sem" after "epmutex" because ep_remove() requires it when called | ||
451 | * from anywhere but ep_free(). | ||
452 | */ | ||
453 | mutex_lock(&epmutex); | ||
454 | 371 | ||
455 | while (!list_empty(lsthead)) { | 372 | if (nwait) { |
456 | epi = list_first_entry(lsthead, struct epitem, fllink); | 373 | while (!list_empty(lsthead)) { |
374 | pwq = list_first_entry(lsthead, struct eppoll_entry, llink); | ||
457 | 375 | ||
458 | ep = epi->ep; | 376 | list_del_init(&pwq->llink); |
459 | list_del_init(&epi->fllink); | 377 | remove_wait_queue(pwq->whead, &pwq->wait); |
460 | down_write(&ep->sem); | 378 | kmem_cache_free(pwq_cache, pwq); |
461 | ep_remove(ep, epi); | 379 | } |
462 | up_write(&ep->sem); | ||
463 | } | 380 | } |
464 | |||
465 | mutex_unlock(&epmutex); | ||
466 | } | 381 | } |
467 | 382 | ||
468 | |||
469 | /* | 383 | /* |
470 | * It opens an eventpoll file descriptor by suggesting a storage of "size" | 384 | * Unlink the "struct epitem" from all places it might have been hooked up. |
471 | * file descriptors. The size parameter is just an hint about how to size | 385 | * This function must be called with write IRQ lock on "ep->lock". |
472 | * data structures. It won't prevent the user to store more than "size" | ||
473 | * file descriptors inside the epoll interface. It is the kernel part of | ||
474 | * the userspace epoll_create(2). | ||
475 | */ | 386 | */ |
476 | asmlinkage long sys_epoll_create(int size) | 387 | static int ep_unlink(struct eventpoll *ep, struct epitem *epi) |
477 | { | 388 | { |
478 | int error, fd = -1; | 389 | int error; |
479 | struct eventpoll *ep; | ||
480 | struct inode *inode; | ||
481 | struct file *file; | ||
482 | |||
483 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n", | ||
484 | current, size)); | ||
485 | |||
486 | /* | ||
487 | * Sanity check on the size parameter, and create the internal data | ||
488 | * structure ( "struct eventpoll" ). | ||
489 | */ | ||
490 | error = -EINVAL; | ||
491 | if (size <= 0 || (error = ep_alloc(&ep)) != 0) | ||
492 | goto eexit_1; | ||
493 | 390 | ||
494 | /* | 391 | /* |
495 | * Creates all the items needed to setup an eventpoll file. That is, | 392 | * It can happen that this one is called for an item already unlinked. |
496 | * a file structure, and inode and a free file descriptor. | 393 | * The check protect us from doing a double unlink ( crash ). |
497 | */ | 394 | */ |
498 | error = ep_getfd(&fd, &inode, &file, ep); | 395 | error = -ENOENT; |
499 | if (error) | 396 | if (!ep_rb_linked(&epi->rbn)) |
500 | goto eexit_2; | 397 | goto error_return; |
501 | |||
502 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n", | ||
503 | current, size, fd)); | ||
504 | |||
505 | return fd; | ||
506 | |||
507 | eexit_2: | ||
508 | ep_free(ep); | ||
509 | kfree(ep); | ||
510 | eexit_1: | ||
511 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n", | ||
512 | current, size, error)); | ||
513 | return error; | ||
514 | } | ||
515 | |||
516 | |||
517 | /* | ||
518 | * The following function implements the controller interface for | ||
519 | * the eventpoll file that enables the insertion/removal/change of | ||
520 | * file descriptors inside the interest set. It represents | ||
521 | * the kernel part of the user space epoll_ctl(2). | ||
522 | */ | ||
523 | asmlinkage long | ||
524 | sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event) | ||
525 | { | ||
526 | int error; | ||
527 | struct file *file, *tfile; | ||
528 | struct eventpoll *ep; | ||
529 | struct epitem *epi; | ||
530 | struct epoll_event epds; | ||
531 | |||
532 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p)\n", | ||
533 | current, epfd, op, fd, event)); | ||
534 | |||
535 | error = -EFAULT; | ||
536 | if (ep_op_has_event(op) && | ||
537 | copy_from_user(&epds, event, sizeof(struct epoll_event))) | ||
538 | goto eexit_1; | ||
539 | |||
540 | /* Get the "struct file *" for the eventpoll file */ | ||
541 | error = -EBADF; | ||
542 | file = fget(epfd); | ||
543 | if (!file) | ||
544 | goto eexit_1; | ||
545 | |||
546 | /* Get the "struct file *" for the target file */ | ||
547 | tfile = fget(fd); | ||
548 | if (!tfile) | ||
549 | goto eexit_2; | ||
550 | |||
551 | /* The target file descriptor must support poll */ | ||
552 | error = -EPERM; | ||
553 | if (!tfile->f_op || !tfile->f_op->poll) | ||
554 | goto eexit_3; | ||
555 | 398 | ||
556 | /* | 399 | /* |
557 | * We have to check that the file structure underneath the file descriptor | 400 | * Clear the event mask for the unlinked item. This will avoid item |
558 | * the user passed to us _is_ an eventpoll file. And also we do not permit | 401 | * notifications to be sent after the unlink operation from inside |
559 | * adding an epoll file descriptor inside itself. | 402 | * the kernel->userspace event transfer loop. |
560 | */ | 403 | */ |
561 | error = -EINVAL; | 404 | epi->event.events = 0; |
562 | if (file == tfile || !is_file_epoll(file)) | ||
563 | goto eexit_3; | ||
564 | 405 | ||
565 | /* | 406 | /* |
566 | * At this point it is safe to assume that the "private_data" contains | 407 | * At this point is safe to do the job, unlink the item from our rb-tree. |
567 | * our own data structure. | 408 | * This operation togheter with the above check closes the door to |
409 | * double unlinks. | ||
568 | */ | 410 | */ |
569 | ep = file->private_data; | 411 | ep_rb_erase(&epi->rbn, &ep->rbr); |
570 | |||
571 | down_write(&ep->sem); | ||
572 | |||
573 | /* Try to lookup the file inside our RB tree */ | ||
574 | epi = ep_find(ep, tfile, fd); | ||
575 | |||
576 | error = -EINVAL; | ||
577 | switch (op) { | ||
578 | case EPOLL_CTL_ADD: | ||
579 | if (!epi) { | ||
580 | epds.events |= POLLERR | POLLHUP; | ||
581 | |||
582 | error = ep_insert(ep, &epds, tfile, fd); | ||
583 | } else | ||
584 | error = -EEXIST; | ||
585 | break; | ||
586 | case EPOLL_CTL_DEL: | ||
587 | if (epi) | ||
588 | error = ep_remove(ep, epi); | ||
589 | else | ||
590 | error = -ENOENT; | ||
591 | break; | ||
592 | case EPOLL_CTL_MOD: | ||
593 | if (epi) { | ||
594 | epds.events |= POLLERR | POLLHUP; | ||
595 | error = ep_modify(ep, epi, &epds); | ||
596 | } else | ||
597 | error = -ENOENT; | ||
598 | break; | ||
599 | } | ||
600 | 412 | ||
601 | /* | 413 | /* |
602 | * The function ep_find() increments the usage count of the structure | 414 | * If the item we are going to remove is inside the ready file descriptors |
603 | * so, if this is not NULL, we need to release it. | 415 | * we want to remove it from this list to avoid stale events. |
604 | */ | 416 | */ |
605 | if (epi) | 417 | if (ep_is_linked(&epi->rdllink)) |
606 | ep_release_epitem(epi); | 418 | list_del_init(&epi->rdllink); |
607 | 419 | ||
608 | up_write(&ep->sem); | 420 | error = 0; |
421 | error_return: | ||
609 | 422 | ||
610 | eexit_3: | 423 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_unlink(%p, %p) = %d\n", |
611 | fput(tfile); | 424 | current, ep, epi->ffd.file, error)); |
612 | eexit_2: | ||
613 | fput(file); | ||
614 | eexit_1: | ||
615 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p) = %d\n", | ||
616 | current, epfd, op, fd, event, error)); | ||
617 | 425 | ||
618 | return error; | 426 | return error; |
619 | } | 427 | } |
620 | 428 | ||
621 | |||
622 | /* | 429 | /* |
623 | * Implement the event wait interface for the eventpoll file. It is the kernel | 430 | * Increment the usage count of the "struct epitem" making it sure |
624 | * part of the user space epoll_wait(2). | 431 | * that the user will have a valid pointer to reference. |
625 | */ | 432 | */ |
626 | asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events, | 433 | static void ep_use_epitem(struct epitem *epi) |
627 | int maxevents, int timeout) | ||
628 | { | 434 | { |
629 | int error; | 435 | atomic_inc(&epi->usecnt); |
630 | struct file *file; | ||
631 | struct eventpoll *ep; | ||
632 | |||
633 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d)\n", | ||
634 | current, epfd, events, maxevents, timeout)); | ||
635 | |||
636 | /* The maximum number of event must be greater than zero */ | ||
637 | if (maxevents <= 0 || maxevents > EP_MAX_EVENTS) | ||
638 | return -EINVAL; | ||
639 | |||
640 | /* Verify that the area passed by the user is writeable */ | ||
641 | if (!access_ok(VERIFY_WRITE, events, maxevents * sizeof(struct epoll_event))) { | ||
642 | error = -EFAULT; | ||
643 | goto eexit_1; | ||
644 | } | ||
645 | |||
646 | /* Get the "struct file *" for the eventpoll file */ | ||
647 | error = -EBADF; | ||
648 | file = fget(epfd); | ||
649 | if (!file) | ||
650 | goto eexit_1; | ||
651 | |||
652 | /* | ||
653 | * We have to check that the file structure underneath the fd | ||
654 | * the user passed to us _is_ an eventpoll file. | ||
655 | */ | ||
656 | error = -EINVAL; | ||
657 | if (!is_file_epoll(file)) | ||
658 | goto eexit_2; | ||
659 | |||
660 | /* | ||
661 | * At this point it is safe to assume that the "private_data" contains | ||
662 | * our own data structure. | ||
663 | */ | ||
664 | ep = file->private_data; | ||
665 | |||
666 | /* Time to fish for events ... */ | ||
667 | error = ep_poll(ep, events, maxevents, timeout); | ||
668 | |||
669 | eexit_2: | ||
670 | fput(file); | ||
671 | eexit_1: | ||
672 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d) = %d\n", | ||
673 | current, epfd, events, maxevents, timeout, error)); | ||
674 | |||
675 | return error; | ||
676 | } | 436 | } |
677 | 437 | ||
678 | |||
679 | #ifdef TIF_RESTORE_SIGMASK | ||
680 | |||
681 | /* | 438 | /* |
682 | * Implement the event wait interface for the eventpoll file. It is the kernel | 439 | * Decrement ( release ) the usage count by signaling that the user |
683 | * part of the user space epoll_pwait(2). | 440 | * has finished using the structure. It might lead to freeing the |
441 | * structure itself if the count goes to zero. | ||
684 | */ | 442 | */ |
685 | asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events, | 443 | static void ep_release_epitem(struct epitem *epi) |
686 | int maxevents, int timeout, const sigset_t __user *sigmask, | ||
687 | size_t sigsetsize) | ||
688 | { | 444 | { |
689 | int error; | 445 | if (atomic_dec_and_test(&epi->usecnt)) |
690 | sigset_t ksigmask, sigsaved; | 446 | kmem_cache_free(epi_cache, epi); |
691 | |||
692 | /* | ||
693 | * If the caller wants a certain signal mask to be set during the wait, | ||
694 | * we apply it here. | ||
695 | */ | ||
696 | if (sigmask) { | ||
697 | if (sigsetsize != sizeof(sigset_t)) | ||
698 | return -EINVAL; | ||
699 | if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask))) | ||
700 | return -EFAULT; | ||
701 | sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP)); | ||
702 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | ||
703 | } | ||
704 | |||
705 | error = sys_epoll_wait(epfd, events, maxevents, timeout); | ||
706 | |||
707 | /* | ||
708 | * If we changed the signal mask, we need to restore the original one. | ||
709 | * In case we've got a signal while waiting, we do not restore the | ||
710 | * signal mask yet, and we allow do_signal() to deliver the signal on | ||
711 | * the way back to userspace, before the signal mask is restored. | ||
712 | */ | ||
713 | if (sigmask) { | ||
714 | if (error == -EINTR) { | ||
715 | memcpy(¤t->saved_sigmask, &sigsaved, | ||
716 | sizeof(sigsaved)); | ||
717 | set_thread_flag(TIF_RESTORE_SIGMASK); | ||
718 | } else | ||
719 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
720 | } | ||
721 | |||
722 | return error; | ||
723 | } | 447 | } |
724 | 448 | ||
725 | #endif /* #ifdef TIF_RESTORE_SIGMASK */ | ||
726 | |||
727 | |||
728 | /* | 449 | /* |
729 | * Creates the file descriptor to be used by the epoll interface. | 450 | * Removes a "struct epitem" from the eventpoll RB tree and deallocates |
451 | * all the associated resources. | ||
730 | */ | 452 | */ |
731 | static int ep_getfd(int *efd, struct inode **einode, struct file **efile, | 453 | static int ep_remove(struct eventpoll *ep, struct epitem *epi) |
732 | struct eventpoll *ep) | ||
733 | { | 454 | { |
734 | struct qstr this; | 455 | int error; |
735 | char name[32]; | 456 | unsigned long flags; |
736 | struct dentry *dentry; | 457 | struct file *file = epi->ffd.file; |
737 | struct inode *inode; | ||
738 | struct file *file; | ||
739 | int error, fd; | ||
740 | |||
741 | /* Get an ready to use file */ | ||
742 | error = -ENFILE; | ||
743 | file = get_empty_filp(); | ||
744 | if (!file) | ||
745 | goto eexit_1; | ||
746 | |||
747 | /* Allocates an inode from the eventpoll file system */ | ||
748 | inode = ep_eventpoll_inode(); | ||
749 | if (IS_ERR(inode)) { | ||
750 | error = PTR_ERR(inode); | ||
751 | goto eexit_2; | ||
752 | } | ||
753 | |||
754 | /* Allocates a free descriptor to plug the file onto */ | ||
755 | error = get_unused_fd(); | ||
756 | if (error < 0) | ||
757 | goto eexit_3; | ||
758 | fd = error; | ||
759 | 458 | ||
760 | /* | 459 | /* |
761 | * Link the inode to a directory entry by creating a unique name | 460 | * Removes poll wait queue hooks. We _have_ to do this without holding |
762 | * using the inode number. | 461 | * the "ep->lock" otherwise a deadlock might occur. This because of the |
462 | * sequence of the lock acquisition. Here we do "ep->lock" then the wait | ||
463 | * queue head lock when unregistering the wait queue. The wakeup callback | ||
464 | * will run by holding the wait queue head lock and will call our callback | ||
465 | * that will try to get "ep->lock". | ||
763 | */ | 466 | */ |
764 | error = -ENOMEM; | 467 | ep_unregister_pollwait(ep, epi); |
765 | sprintf(name, "[%lu]", inode->i_ino); | ||
766 | this.name = name; | ||
767 | this.len = strlen(name); | ||
768 | this.hash = inode->i_ino; | ||
769 | dentry = d_alloc(eventpoll_mnt->mnt_sb->s_root, &this); | ||
770 | if (!dentry) | ||
771 | goto eexit_4; | ||
772 | dentry->d_op = &eventpollfs_dentry_operations; | ||
773 | d_add(dentry, inode); | ||
774 | file->f_path.mnt = mntget(eventpoll_mnt); | ||
775 | file->f_path.dentry = dentry; | ||
776 | file->f_mapping = inode->i_mapping; | ||
777 | |||
778 | file->f_pos = 0; | ||
779 | file->f_flags = O_RDONLY; | ||
780 | file->f_op = &eventpoll_fops; | ||
781 | file->f_mode = FMODE_READ; | ||
782 | file->f_version = 0; | ||
783 | file->private_data = ep; | ||
784 | |||
785 | /* Install the new setup file into the allocated fd. */ | ||
786 | fd_install(fd, file); | ||
787 | |||
788 | *efd = fd; | ||
789 | *einode = inode; | ||
790 | *efile = file; | ||
791 | return 0; | ||
792 | 468 | ||
793 | eexit_4: | 469 | /* Remove the current item from the list of epoll hooks */ |
794 | put_unused_fd(fd); | 470 | spin_lock(&file->f_ep_lock); |
795 | eexit_3: | 471 | if (ep_is_linked(&epi->fllink)) |
796 | iput(inode); | 472 | list_del_init(&epi->fllink); |
797 | eexit_2: | 473 | spin_unlock(&file->f_ep_lock); |
798 | put_filp(file); | ||
799 | eexit_1: | ||
800 | return error; | ||
801 | } | ||
802 | 474 | ||
475 | /* We need to acquire the write IRQ lock before calling ep_unlink() */ | ||
476 | write_lock_irqsave(&ep->lock, flags); | ||
803 | 477 | ||
804 | static int ep_alloc(struct eventpoll **pep) | 478 | /* Really unlink the item from the RB tree */ |
805 | { | 479 | error = ep_unlink(ep, epi); |
806 | struct eventpoll *ep = kzalloc(sizeof(*ep), GFP_KERNEL); | ||
807 | 480 | ||
808 | if (!ep) | 481 | write_unlock_irqrestore(&ep->lock, flags); |
809 | return -ENOMEM; | ||
810 | 482 | ||
811 | rwlock_init(&ep->lock); | 483 | if (error) |
812 | init_rwsem(&ep->sem); | 484 | goto error_return; |
813 | init_waitqueue_head(&ep->wq); | ||
814 | init_waitqueue_head(&ep->poll_wait); | ||
815 | INIT_LIST_HEAD(&ep->rdllist); | ||
816 | ep->rbr = RB_ROOT; | ||
817 | 485 | ||
818 | *pep = ep; | 486 | /* At this point it is safe to free the eventpoll item */ |
487 | ep_release_epitem(epi); | ||
819 | 488 | ||
820 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_alloc() ep=%p\n", | 489 | error = 0; |
821 | current, ep)); | 490 | error_return: |
822 | return 0; | 491 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_remove(%p, %p) = %d\n", |
823 | } | 492 | current, ep, file, error)); |
824 | 493 | ||
494 | return error; | ||
495 | } | ||
825 | 496 | ||
826 | static void ep_free(struct eventpoll *ep) | 497 | static void ep_free(struct eventpoll *ep) |
827 | { | 498 | { |
@@ -865,6 +536,104 @@ static void ep_free(struct eventpoll *ep) | |||
865 | mutex_unlock(&epmutex); | 536 | mutex_unlock(&epmutex); |
866 | } | 537 | } |
867 | 538 | ||
539 | static int ep_eventpoll_release(struct inode *inode, struct file *file) | ||
540 | { | ||
541 | struct eventpoll *ep = file->private_data; | ||
542 | |||
543 | if (ep) { | ||
544 | ep_free(ep); | ||
545 | kfree(ep); | ||
546 | } | ||
547 | |||
548 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: close() ep=%p\n", current, ep)); | ||
549 | return 0; | ||
550 | } | ||
551 | |||
552 | static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait) | ||
553 | { | ||
554 | unsigned int pollflags = 0; | ||
555 | unsigned long flags; | ||
556 | struct eventpoll *ep = file->private_data; | ||
557 | |||
558 | /* Insert inside our poll wait queue */ | ||
559 | poll_wait(file, &ep->poll_wait, wait); | ||
560 | |||
561 | /* Check our condition */ | ||
562 | read_lock_irqsave(&ep->lock, flags); | ||
563 | if (!list_empty(&ep->rdllist)) | ||
564 | pollflags = POLLIN | POLLRDNORM; | ||
565 | read_unlock_irqrestore(&ep->lock, flags); | ||
566 | |||
567 | return pollflags; | ||
568 | } | ||
569 | |||
570 | /* File callbacks that implement the eventpoll file behaviour */ | ||
571 | static const struct file_operations eventpoll_fops = { | ||
572 | .release = ep_eventpoll_release, | ||
573 | .poll = ep_eventpoll_poll | ||
574 | }; | ||
575 | |||
576 | /* Fast test to see if the file is an evenpoll file */ | ||
577 | static inline int is_file_epoll(struct file *f) | ||
578 | { | ||
579 | return f->f_op == &eventpoll_fops; | ||
580 | } | ||
581 | |||
582 | /* | ||
583 | * This is called from eventpoll_release() to unlink files from the eventpoll | ||
584 | * interface. We need to have this facility to cleanup correctly files that are | ||
585 | * closed without being removed from the eventpoll interface. | ||
586 | */ | ||
587 | void eventpoll_release_file(struct file *file) | ||
588 | { | ||
589 | struct list_head *lsthead = &file->f_ep_links; | ||
590 | struct eventpoll *ep; | ||
591 | struct epitem *epi; | ||
592 | |||
593 | /* | ||
594 | * We don't want to get "file->f_ep_lock" because it is not | ||
595 | * necessary. It is not necessary because we're in the "struct file" | ||
596 | * cleanup path, and this means that noone is using this file anymore. | ||
597 | * The only hit might come from ep_free() but by holding the semaphore | ||
598 | * will correctly serialize the operation. We do need to acquire | ||
599 | * "ep->sem" after "epmutex" because ep_remove() requires it when called | ||
600 | * from anywhere but ep_free(). | ||
601 | */ | ||
602 | mutex_lock(&epmutex); | ||
603 | |||
604 | while (!list_empty(lsthead)) { | ||
605 | epi = list_first_entry(lsthead, struct epitem, fllink); | ||
606 | |||
607 | ep = epi->ep; | ||
608 | list_del_init(&epi->fllink); | ||
609 | down_write(&ep->sem); | ||
610 | ep_remove(ep, epi); | ||
611 | up_write(&ep->sem); | ||
612 | } | ||
613 | |||
614 | mutex_unlock(&epmutex); | ||
615 | } | ||
616 | |||
617 | static int ep_alloc(struct eventpoll **pep) | ||
618 | { | ||
619 | struct eventpoll *ep = kzalloc(sizeof(*ep), GFP_KERNEL); | ||
620 | |||
621 | if (!ep) | ||
622 | return -ENOMEM; | ||
623 | |||
624 | rwlock_init(&ep->lock); | ||
625 | init_rwsem(&ep->sem); | ||
626 | init_waitqueue_head(&ep->wq); | ||
627 | init_waitqueue_head(&ep->poll_wait); | ||
628 | INIT_LIST_HEAD(&ep->rdllist); | ||
629 | ep->rbr = RB_ROOT; | ||
630 | |||
631 | *pep = ep; | ||
632 | |||
633 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_alloc() ep=%p\n", | ||
634 | current, ep)); | ||
635 | return 0; | ||
636 | } | ||
868 | 637 | ||
869 | /* | 638 | /* |
870 | * Search the file inside the eventpoll tree. It add usage count to | 639 | * Search the file inside the eventpoll tree. It add usage count to |
@@ -902,30 +671,58 @@ static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd) | |||
902 | return epir; | 671 | return epir; |
903 | } | 672 | } |
904 | 673 | ||
905 | |||
906 | /* | 674 | /* |
907 | * Increment the usage count of the "struct epitem" making it sure | 675 | * This is the callback that is passed to the wait queue wakeup |
908 | * that the user will have a valid pointer to reference. | 676 | * machanism. It is called by the stored file descriptors when they |
677 | * have events to report. | ||
909 | */ | 678 | */ |
910 | static void ep_use_epitem(struct epitem *epi) | 679 | static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *key) |
911 | { | 680 | { |
681 | int pwake = 0; | ||
682 | unsigned long flags; | ||
683 | struct epitem *epi = ep_item_from_wait(wait); | ||
684 | struct eventpoll *ep = epi->ep; | ||
912 | 685 | ||
913 | atomic_inc(&epi->usecnt); | 686 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: poll_callback(%p) epi=%p ep=%p\n", |
914 | } | 687 | current, epi->ffd.file, epi, ep)); |
915 | 688 | ||
689 | write_lock_irqsave(&ep->lock, flags); | ||
916 | 690 | ||
917 | /* | 691 | /* |
918 | * Decrement ( release ) the usage count by signaling that the user | 692 | * If the event mask does not contain any poll(2) event, we consider the |
919 | * has finished using the structure. It might lead to freeing the | 693 | * descriptor to be disabled. This condition is likely the effect of the |
920 | * structure itself if the count goes to zero. | 694 | * EPOLLONESHOT bit that disables the descriptor when an event is received, |
921 | */ | 695 | * until the next EPOLL_CTL_MOD will be issued. |
922 | static void ep_release_epitem(struct epitem *epi) | 696 | */ |
923 | { | 697 | if (!(epi->event.events & ~EP_PRIVATE_BITS)) |
698 | goto is_disabled; | ||
924 | 699 | ||
925 | if (atomic_dec_and_test(&epi->usecnt)) | 700 | /* If this file is already in the ready list we exit soon */ |
926 | kmem_cache_free(epi_cache, epi); | 701 | if (ep_is_linked(&epi->rdllink)) |
927 | } | 702 | goto is_linked; |
928 | 703 | ||
704 | list_add_tail(&epi->rdllink, &ep->rdllist); | ||
705 | |||
706 | is_linked: | ||
707 | /* | ||
708 | * Wake up ( if active ) both the eventpoll wait list and the ->poll() | ||
709 | * wait list. | ||
710 | */ | ||
711 | if (waitqueue_active(&ep->wq)) | ||
712 | __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE | | ||
713 | TASK_INTERRUPTIBLE); | ||
714 | if (waitqueue_active(&ep->poll_wait)) | ||
715 | pwake++; | ||
716 | |||
717 | is_disabled: | ||
718 | write_unlock_irqrestore(&ep->lock, flags); | ||
719 | |||
720 | /* We have to call this outside the lock */ | ||
721 | if (pwake) | ||
722 | ep_poll_safewake(&psw, &ep->poll_wait); | ||
723 | |||
724 | return 1; | ||
725 | } | ||
929 | 726 | ||
930 | /* | 727 | /* |
931 | * This is the callback that is used to add our wait queue to the | 728 | * This is the callback that is used to add our wait queue to the |
@@ -950,7 +747,6 @@ static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead, | |||
950 | } | 747 | } |
951 | } | 748 | } |
952 | 749 | ||
953 | |||
954 | static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi) | 750 | static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi) |
955 | { | 751 | { |
956 | int kcmp; | 752 | int kcmp; |
@@ -970,7 +766,6 @@ static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi) | |||
970 | rb_insert_color(&epi->rbn, &ep->rbr); | 766 | rb_insert_color(&epi->rbn, &ep->rbr); |
971 | } | 767 | } |
972 | 768 | ||
973 | |||
974 | static int ep_insert(struct eventpoll *ep, struct epoll_event *event, | 769 | static int ep_insert(struct eventpoll *ep, struct epoll_event *event, |
975 | struct file *tfile, int fd) | 770 | struct file *tfile, int fd) |
976 | { | 771 | { |
@@ -981,7 +776,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, | |||
981 | 776 | ||
982 | error = -ENOMEM; | 777 | error = -ENOMEM; |
983 | if (!(epi = kmem_cache_alloc(epi_cache, GFP_KERNEL))) | 778 | if (!(epi = kmem_cache_alloc(epi_cache, GFP_KERNEL))) |
984 | goto eexit_1; | 779 | goto error_return; |
985 | 780 | ||
986 | /* Item initialization follow here ... */ | 781 | /* Item initialization follow here ... */ |
987 | ep_rb_initnode(&epi->rbn); | 782 | ep_rb_initnode(&epi->rbn); |
@@ -1011,7 +806,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, | |||
1011 | * high memory pressure. | 806 | * high memory pressure. |
1012 | */ | 807 | */ |
1013 | if (epi->nwait < 0) | 808 | if (epi->nwait < 0) |
1014 | goto eexit_2; | 809 | goto error_unregister; |
1015 | 810 | ||
1016 | /* Add the current item to the list of active epoll hook for this file */ | 811 | /* Add the current item to the list of active epoll hook for this file */ |
1017 | spin_lock(&tfile->f_ep_lock); | 812 | spin_lock(&tfile->f_ep_lock); |
@@ -1046,7 +841,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, | |||
1046 | 841 | ||
1047 | return 0; | 842 | return 0; |
1048 | 843 | ||
1049 | eexit_2: | 844 | error_unregister: |
1050 | ep_unregister_pollwait(ep, epi); | 845 | ep_unregister_pollwait(ep, epi); |
1051 | 846 | ||
1052 | /* | 847 | /* |
@@ -1059,11 +854,10 @@ eexit_2: | |||
1059 | write_unlock_irqrestore(&ep->lock, flags); | 854 | write_unlock_irqrestore(&ep->lock, flags); |
1060 | 855 | ||
1061 | kmem_cache_free(epi_cache, epi); | 856 | kmem_cache_free(epi_cache, epi); |
1062 | eexit_1: | 857 | error_return: |
1063 | return error; | 858 | return error; |
1064 | } | 859 | } |
1065 | 860 | ||
1066 | |||
1067 | /* | 861 | /* |
1068 | * Modify the interest event mask by dropping an event if the new mask | 862 | * Modify the interest event mask by dropping an event if the new mask |
1069 | * has a match in the current file status. | 863 | * has a match in the current file status. |
@@ -1126,216 +920,6 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even | |||
1126 | return 0; | 920 | return 0; |
1127 | } | 921 | } |
1128 | 922 | ||
1129 | |||
1130 | /* | ||
1131 | * This function unregister poll callbacks from the associated file descriptor. | ||
1132 | * Since this must be called without holding "ep->lock" the atomic exchange trick | ||
1133 | * will protect us from multiple unregister. | ||
1134 | */ | ||
1135 | static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi) | ||
1136 | { | ||
1137 | int nwait; | ||
1138 | struct list_head *lsthead = &epi->pwqlist; | ||
1139 | struct eppoll_entry *pwq; | ||
1140 | |||
1141 | /* This is called without locks, so we need the atomic exchange */ | ||
1142 | nwait = xchg(&epi->nwait, 0); | ||
1143 | |||
1144 | if (nwait) { | ||
1145 | while (!list_empty(lsthead)) { | ||
1146 | pwq = list_first_entry(lsthead, struct eppoll_entry, llink); | ||
1147 | |||
1148 | list_del_init(&pwq->llink); | ||
1149 | remove_wait_queue(pwq->whead, &pwq->wait); | ||
1150 | kmem_cache_free(pwq_cache, pwq); | ||
1151 | } | ||
1152 | } | ||
1153 | } | ||
1154 | |||
1155 | |||
1156 | /* | ||
1157 | * Unlink the "struct epitem" from all places it might have been hooked up. | ||
1158 | * This function must be called with write IRQ lock on "ep->lock". | ||
1159 | */ | ||
1160 | static int ep_unlink(struct eventpoll *ep, struct epitem *epi) | ||
1161 | { | ||
1162 | int error; | ||
1163 | |||
1164 | /* | ||
1165 | * It can happen that this one is called for an item already unlinked. | ||
1166 | * The check protect us from doing a double unlink ( crash ). | ||
1167 | */ | ||
1168 | error = -ENOENT; | ||
1169 | if (!ep_rb_linked(&epi->rbn)) | ||
1170 | goto eexit_1; | ||
1171 | |||
1172 | /* | ||
1173 | * Clear the event mask for the unlinked item. This will avoid item | ||
1174 | * notifications to be sent after the unlink operation from inside | ||
1175 | * the kernel->userspace event transfer loop. | ||
1176 | */ | ||
1177 | epi->event.events = 0; | ||
1178 | |||
1179 | /* | ||
1180 | * At this point is safe to do the job, unlink the item from our rb-tree. | ||
1181 | * This operation togheter with the above check closes the door to | ||
1182 | * double unlinks. | ||
1183 | */ | ||
1184 | ep_rb_erase(&epi->rbn, &ep->rbr); | ||
1185 | |||
1186 | /* | ||
1187 | * If the item we are going to remove is inside the ready file descriptors | ||
1188 | * we want to remove it from this list to avoid stale events. | ||
1189 | */ | ||
1190 | if (ep_is_linked(&epi->rdllink)) | ||
1191 | list_del_init(&epi->rdllink); | ||
1192 | |||
1193 | error = 0; | ||
1194 | eexit_1: | ||
1195 | |||
1196 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_unlink(%p, %p) = %d\n", | ||
1197 | current, ep, epi->ffd.file, error)); | ||
1198 | |||
1199 | return error; | ||
1200 | } | ||
1201 | |||
1202 | |||
1203 | /* | ||
1204 | * Removes a "struct epitem" from the eventpoll RB tree and deallocates | ||
1205 | * all the associated resources. | ||
1206 | */ | ||
1207 | static int ep_remove(struct eventpoll *ep, struct epitem *epi) | ||
1208 | { | ||
1209 | int error; | ||
1210 | unsigned long flags; | ||
1211 | struct file *file = epi->ffd.file; | ||
1212 | |||
1213 | /* | ||
1214 | * Removes poll wait queue hooks. We _have_ to do this without holding | ||
1215 | * the "ep->lock" otherwise a deadlock might occur. This because of the | ||
1216 | * sequence of the lock acquisition. Here we do "ep->lock" then the wait | ||
1217 | * queue head lock when unregistering the wait queue. The wakeup callback | ||
1218 | * will run by holding the wait queue head lock and will call our callback | ||
1219 | * that will try to get "ep->lock". | ||
1220 | */ | ||
1221 | ep_unregister_pollwait(ep, epi); | ||
1222 | |||
1223 | /* Remove the current item from the list of epoll hooks */ | ||
1224 | spin_lock(&file->f_ep_lock); | ||
1225 | if (ep_is_linked(&epi->fllink)) | ||
1226 | list_del_init(&epi->fllink); | ||
1227 | spin_unlock(&file->f_ep_lock); | ||
1228 | |||
1229 | /* We need to acquire the write IRQ lock before calling ep_unlink() */ | ||
1230 | write_lock_irqsave(&ep->lock, flags); | ||
1231 | |||
1232 | /* Really unlink the item from the RB tree */ | ||
1233 | error = ep_unlink(ep, epi); | ||
1234 | |||
1235 | write_unlock_irqrestore(&ep->lock, flags); | ||
1236 | |||
1237 | if (error) | ||
1238 | goto eexit_1; | ||
1239 | |||
1240 | /* At this point it is safe to free the eventpoll item */ | ||
1241 | ep_release_epitem(epi); | ||
1242 | |||
1243 | error = 0; | ||
1244 | eexit_1: | ||
1245 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_remove(%p, %p) = %d\n", | ||
1246 | current, ep, file, error)); | ||
1247 | |||
1248 | return error; | ||
1249 | } | ||
1250 | |||
1251 | |||
1252 | /* | ||
1253 | * This is the callback that is passed to the wait queue wakeup | ||
1254 | * machanism. It is called by the stored file descriptors when they | ||
1255 | * have events to report. | ||
1256 | */ | ||
1257 | static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *key) | ||
1258 | { | ||
1259 | int pwake = 0; | ||
1260 | unsigned long flags; | ||
1261 | struct epitem *epi = ep_item_from_wait(wait); | ||
1262 | struct eventpoll *ep = epi->ep; | ||
1263 | |||
1264 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: poll_callback(%p) epi=%p ep=%p\n", | ||
1265 | current, epi->ffd.file, epi, ep)); | ||
1266 | |||
1267 | write_lock_irqsave(&ep->lock, flags); | ||
1268 | |||
1269 | /* | ||
1270 | * If the event mask does not contain any poll(2) event, we consider the | ||
1271 | * descriptor to be disabled. This condition is likely the effect of the | ||
1272 | * EPOLLONESHOT bit that disables the descriptor when an event is received, | ||
1273 | * until the next EPOLL_CTL_MOD will be issued. | ||
1274 | */ | ||
1275 | if (!(epi->event.events & ~EP_PRIVATE_BITS)) | ||
1276 | goto is_disabled; | ||
1277 | |||
1278 | /* If this file is already in the ready list we exit soon */ | ||
1279 | if (ep_is_linked(&epi->rdllink)) | ||
1280 | goto is_linked; | ||
1281 | |||
1282 | list_add_tail(&epi->rdllink, &ep->rdllist); | ||
1283 | |||
1284 | is_linked: | ||
1285 | /* | ||
1286 | * Wake up ( if active ) both the eventpoll wait list and the ->poll() | ||
1287 | * wait list. | ||
1288 | */ | ||
1289 | if (waitqueue_active(&ep->wq)) | ||
1290 | __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE | | ||
1291 | TASK_INTERRUPTIBLE); | ||
1292 | if (waitqueue_active(&ep->poll_wait)) | ||
1293 | pwake++; | ||
1294 | |||
1295 | is_disabled: | ||
1296 | write_unlock_irqrestore(&ep->lock, flags); | ||
1297 | |||
1298 | /* We have to call this outside the lock */ | ||
1299 | if (pwake) | ||
1300 | ep_poll_safewake(&psw, &ep->poll_wait); | ||
1301 | |||
1302 | return 1; | ||
1303 | } | ||
1304 | |||
1305 | |||
1306 | static int ep_eventpoll_close(struct inode *inode, struct file *file) | ||
1307 | { | ||
1308 | struct eventpoll *ep = file->private_data; | ||
1309 | |||
1310 | if (ep) { | ||
1311 | ep_free(ep); | ||
1312 | kfree(ep); | ||
1313 | } | ||
1314 | |||
1315 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: close() ep=%p\n", current, ep)); | ||
1316 | return 0; | ||
1317 | } | ||
1318 | |||
1319 | |||
1320 | static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait) | ||
1321 | { | ||
1322 | unsigned int pollflags = 0; | ||
1323 | unsigned long flags; | ||
1324 | struct eventpoll *ep = file->private_data; | ||
1325 | |||
1326 | /* Insert inside our poll wait queue */ | ||
1327 | poll_wait(file, &ep->poll_wait, wait); | ||
1328 | |||
1329 | /* Check our condition */ | ||
1330 | read_lock_irqsave(&ep->lock, flags); | ||
1331 | if (!list_empty(&ep->rdllist)) | ||
1332 | pollflags = POLLIN | POLLRDNORM; | ||
1333 | read_unlock_irqrestore(&ep->lock, flags); | ||
1334 | |||
1335 | return pollflags; | ||
1336 | } | ||
1337 | |||
1338 | |||
1339 | /* | 923 | /* |
1340 | * This function is called without holding the "ep->lock" since the call to | 924 | * This function is called without holding the "ep->lock" since the call to |
1341 | * __copy_to_user() might sleep, and also f_op->poll() might reenable the IRQ | 925 | * __copy_to_user() might sleep, and also f_op->poll() might reenable the IRQ |
@@ -1447,7 +1031,6 @@ static int ep_send_events(struct eventpoll *ep, struct list_head *txlist, | |||
1447 | return eventcnt == 0 ? error: eventcnt; | 1031 | return eventcnt == 0 ? error: eventcnt; |
1448 | } | 1032 | } |
1449 | 1033 | ||
1450 | |||
1451 | /* | 1034 | /* |
1452 | * Perform the transfer of events to user space. | 1035 | * Perform the transfer of events to user space. |
1453 | */ | 1036 | */ |
@@ -1483,7 +1066,6 @@ static int ep_events_transfer(struct eventpoll *ep, | |||
1483 | return eventcnt; | 1066 | return eventcnt; |
1484 | } | 1067 | } |
1485 | 1068 | ||
1486 | |||
1487 | static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, | 1069 | static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, |
1488 | int maxevents, long timeout) | 1070 | int maxevents, long timeout) |
1489 | { | 1071 | { |
@@ -1553,52 +1135,262 @@ retry: | |||
1553 | return res; | 1135 | return res; |
1554 | } | 1136 | } |
1555 | 1137 | ||
1556 | static int eventpollfs_delete_dentry(struct dentry *dentry) | 1138 | /* |
1139 | * It opens an eventpoll file descriptor by suggesting a storage of "size" | ||
1140 | * file descriptors. The size parameter is just an hint about how to size | ||
1141 | * data structures. It won't prevent the user to store more than "size" | ||
1142 | * file descriptors inside the epoll interface. It is the kernel part of | ||
1143 | * the userspace epoll_create(2). | ||
1144 | */ | ||
1145 | asmlinkage long sys_epoll_create(int size) | ||
1557 | { | 1146 | { |
1147 | int error, fd = -1; | ||
1148 | struct eventpoll *ep; | ||
1149 | struct inode *inode; | ||
1150 | struct file *file; | ||
1558 | 1151 | ||
1559 | return 1; | 1152 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n", |
1153 | current, size)); | ||
1154 | |||
1155 | /* | ||
1156 | * Sanity check on the size parameter, and create the internal data | ||
1157 | * structure ( "struct eventpoll" ). | ||
1158 | */ | ||
1159 | error = -EINVAL; | ||
1160 | if (size <= 0 || (error = ep_alloc(&ep)) != 0) | ||
1161 | goto error_return; | ||
1162 | |||
1163 | /* | ||
1164 | * Creates all the items needed to setup an eventpoll file. That is, | ||
1165 | * a file structure, and inode and a free file descriptor. | ||
1166 | */ | ||
1167 | error = anon_inode_getfd(&fd, &inode, &file, "[eventpoll]", | ||
1168 | &eventpoll_fops, ep); | ||
1169 | if (error) | ||
1170 | goto error_free; | ||
1171 | |||
1172 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n", | ||
1173 | current, size, fd)); | ||
1174 | |||
1175 | return fd; | ||
1176 | |||
1177 | error_free: | ||
1178 | ep_free(ep); | ||
1179 | kfree(ep); | ||
1180 | error_return: | ||
1181 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n", | ||
1182 | current, size, error)); | ||
1183 | return error; | ||
1560 | } | 1184 | } |
1561 | 1185 | ||
1562 | static struct inode *ep_eventpoll_inode(void) | 1186 | /* |
1187 | * The following function implements the controller interface for | ||
1188 | * the eventpoll file that enables the insertion/removal/change of | ||
1189 | * file descriptors inside the interest set. It represents | ||
1190 | * the kernel part of the user space epoll_ctl(2). | ||
1191 | */ | ||
1192 | asmlinkage long sys_epoll_ctl(int epfd, int op, int fd, | ||
1193 | struct epoll_event __user *event) | ||
1563 | { | 1194 | { |
1564 | int error = -ENOMEM; | 1195 | int error; |
1565 | struct inode *inode = new_inode(eventpoll_mnt->mnt_sb); | 1196 | struct file *file, *tfile; |
1197 | struct eventpoll *ep; | ||
1198 | struct epitem *epi; | ||
1199 | struct epoll_event epds; | ||
1200 | |||
1201 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p)\n", | ||
1202 | current, epfd, op, fd, event)); | ||
1203 | |||
1204 | error = -EFAULT; | ||
1205 | if (ep_op_has_event(op) && | ||
1206 | copy_from_user(&epds, event, sizeof(struct epoll_event))) | ||
1207 | goto error_return; | ||
1208 | |||
1209 | /* Get the "struct file *" for the eventpoll file */ | ||
1210 | error = -EBADF; | ||
1211 | file = fget(epfd); | ||
1212 | if (!file) | ||
1213 | goto error_return; | ||
1214 | |||
1215 | /* Get the "struct file *" for the target file */ | ||
1216 | tfile = fget(fd); | ||
1217 | if (!tfile) | ||
1218 | goto error_fput; | ||
1219 | |||
1220 | /* The target file descriptor must support poll */ | ||
1221 | error = -EPERM; | ||
1222 | if (!tfile->f_op || !tfile->f_op->poll) | ||
1223 | goto error_tgt_fput; | ||
1224 | |||
1225 | /* | ||
1226 | * We have to check that the file structure underneath the file descriptor | ||
1227 | * the user passed to us _is_ an eventpoll file. And also we do not permit | ||
1228 | * adding an epoll file descriptor inside itself. | ||
1229 | */ | ||
1230 | error = -EINVAL; | ||
1231 | if (file == tfile || !is_file_epoll(file)) | ||
1232 | goto error_tgt_fput; | ||
1566 | 1233 | ||
1567 | if (!inode) | 1234 | /* |
1568 | goto eexit_1; | 1235 | * At this point it is safe to assume that the "private_data" contains |
1236 | * our own data structure. | ||
1237 | */ | ||
1238 | ep = file->private_data; | ||
1239 | |||
1240 | down_write(&ep->sem); | ||
1569 | 1241 | ||
1570 | inode->i_fop = &eventpoll_fops; | 1242 | /* Try to lookup the file inside our RB tree */ |
1243 | epi = ep_find(ep, tfile, fd); | ||
1244 | |||
1245 | error = -EINVAL; | ||
1246 | switch (op) { | ||
1247 | case EPOLL_CTL_ADD: | ||
1248 | if (!epi) { | ||
1249 | epds.events |= POLLERR | POLLHUP; | ||
1571 | 1250 | ||
1251 | error = ep_insert(ep, &epds, tfile, fd); | ||
1252 | } else | ||
1253 | error = -EEXIST; | ||
1254 | break; | ||
1255 | case EPOLL_CTL_DEL: | ||
1256 | if (epi) | ||
1257 | error = ep_remove(ep, epi); | ||
1258 | else | ||
1259 | error = -ENOENT; | ||
1260 | break; | ||
1261 | case EPOLL_CTL_MOD: | ||
1262 | if (epi) { | ||
1263 | epds.events |= POLLERR | POLLHUP; | ||
1264 | error = ep_modify(ep, epi, &epds); | ||
1265 | } else | ||
1266 | error = -ENOENT; | ||
1267 | break; | ||
1268 | } | ||
1572 | /* | 1269 | /* |
1573 | * Mark the inode dirty from the very beginning, | 1270 | * The function ep_find() increments the usage count of the structure |
1574 | * that way it will never be moved to the dirty | 1271 | * so, if this is not NULL, we need to release it. |
1575 | * list because mark_inode_dirty() will think | ||
1576 | * that it already _is_ on the dirty list. | ||
1577 | */ | 1272 | */ |
1578 | inode->i_state = I_DIRTY; | 1273 | if (epi) |
1579 | inode->i_mode = S_IRUSR | S_IWUSR; | 1274 | ep_release_epitem(epi); |
1580 | inode->i_uid = current->fsuid; | 1275 | up_write(&ep->sem); |
1581 | inode->i_gid = current->fsgid; | 1276 | |
1582 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 1277 | error_tgt_fput: |
1583 | return inode; | 1278 | fput(tfile); |
1584 | 1279 | error_fput: | |
1585 | eexit_1: | 1280 | fput(file); |
1586 | return ERR_PTR(error); | 1281 | error_return: |
1282 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p) = %d\n", | ||
1283 | current, epfd, op, fd, event, error)); | ||
1284 | |||
1285 | return error; | ||
1587 | } | 1286 | } |
1588 | 1287 | ||
1589 | static int | 1288 | /* |
1590 | eventpollfs_get_sb(struct file_system_type *fs_type, int flags, | 1289 | * Implement the event wait interface for the eventpoll file. It is the kernel |
1591 | const char *dev_name, void *data, struct vfsmount *mnt) | 1290 | * part of the user space epoll_wait(2). |
1291 | */ | ||
1292 | asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events, | ||
1293 | int maxevents, int timeout) | ||
1592 | { | 1294 | { |
1593 | return get_sb_pseudo(fs_type, "eventpoll:", NULL, EVENTPOLLFS_MAGIC, | 1295 | int error; |
1594 | mnt); | 1296 | struct file *file; |
1297 | struct eventpoll *ep; | ||
1298 | |||
1299 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d)\n", | ||
1300 | current, epfd, events, maxevents, timeout)); | ||
1301 | |||
1302 | /* The maximum number of event must be greater than zero */ | ||
1303 | if (maxevents <= 0 || maxevents > EP_MAX_EVENTS) | ||
1304 | return -EINVAL; | ||
1305 | |||
1306 | /* Verify that the area passed by the user is writeable */ | ||
1307 | if (!access_ok(VERIFY_WRITE, events, maxevents * sizeof(struct epoll_event))) { | ||
1308 | error = -EFAULT; | ||
1309 | goto error_return; | ||
1310 | } | ||
1311 | |||
1312 | /* Get the "struct file *" for the eventpoll file */ | ||
1313 | error = -EBADF; | ||
1314 | file = fget(epfd); | ||
1315 | if (!file) | ||
1316 | goto error_return; | ||
1317 | |||
1318 | /* | ||
1319 | * We have to check that the file structure underneath the fd | ||
1320 | * the user passed to us _is_ an eventpoll file. | ||
1321 | */ | ||
1322 | error = -EINVAL; | ||
1323 | if (!is_file_epoll(file)) | ||
1324 | goto error_fput; | ||
1325 | |||
1326 | /* | ||
1327 | * At this point it is safe to assume that the "private_data" contains | ||
1328 | * our own data structure. | ||
1329 | */ | ||
1330 | ep = file->private_data; | ||
1331 | |||
1332 | /* Time to fish for events ... */ | ||
1333 | error = ep_poll(ep, events, maxevents, timeout); | ||
1334 | |||
1335 | error_fput: | ||
1336 | fput(file); | ||
1337 | error_return: | ||
1338 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d) = %d\n", | ||
1339 | current, epfd, events, maxevents, timeout, error)); | ||
1340 | |||
1341 | return error; | ||
1595 | } | 1342 | } |
1596 | 1343 | ||
1344 | #ifdef TIF_RESTORE_SIGMASK | ||
1597 | 1345 | ||
1598 | static int __init eventpoll_init(void) | 1346 | /* |
1347 | * Implement the event wait interface for the eventpoll file. It is the kernel | ||
1348 | * part of the user space epoll_pwait(2). | ||
1349 | */ | ||
1350 | asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events, | ||
1351 | int maxevents, int timeout, const sigset_t __user *sigmask, | ||
1352 | size_t sigsetsize) | ||
1599 | { | 1353 | { |
1600 | int error; | 1354 | int error; |
1355 | sigset_t ksigmask, sigsaved; | ||
1356 | |||
1357 | /* | ||
1358 | * If the caller wants a certain signal mask to be set during the wait, | ||
1359 | * we apply it here. | ||
1360 | */ | ||
1361 | if (sigmask) { | ||
1362 | if (sigsetsize != sizeof(sigset_t)) | ||
1363 | return -EINVAL; | ||
1364 | if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask))) | ||
1365 | return -EFAULT; | ||
1366 | sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP)); | ||
1367 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | ||
1368 | } | ||
1369 | |||
1370 | error = sys_epoll_wait(epfd, events, maxevents, timeout); | ||
1371 | |||
1372 | /* | ||
1373 | * If we changed the signal mask, we need to restore the original one. | ||
1374 | * In case we've got a signal while waiting, we do not restore the | ||
1375 | * signal mask yet, and we allow do_signal() to deliver the signal on | ||
1376 | * the way back to userspace, before the signal mask is restored. | ||
1377 | */ | ||
1378 | if (sigmask) { | ||
1379 | if (error == -EINTR) { | ||
1380 | memcpy(¤t->saved_sigmask, &sigsaved, | ||
1381 | sizeof(sigsaved)); | ||
1382 | set_thread_flag(TIF_RESTORE_SIGMASK); | ||
1383 | } else | ||
1384 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
1385 | } | ||
1386 | |||
1387 | return error; | ||
1388 | } | ||
1601 | 1389 | ||
1390 | #endif /* #ifdef TIF_RESTORE_SIGMASK */ | ||
1391 | |||
1392 | static int __init eventpoll_init(void) | ||
1393 | { | ||
1602 | mutex_init(&epmutex); | 1394 | mutex_init(&epmutex); |
1603 | 1395 | ||
1604 | /* Initialize the structure used to perform safe poll wait head wake ups */ | 1396 | /* Initialize the structure used to perform safe poll wait head wake ups */ |
@@ -1614,39 +1406,7 @@ static int __init eventpoll_init(void) | |||
1614 | sizeof(struct eppoll_entry), 0, | 1406 | sizeof(struct eppoll_entry), 0, |
1615 | EPI_SLAB_DEBUG|SLAB_PANIC, NULL, NULL); | 1407 | EPI_SLAB_DEBUG|SLAB_PANIC, NULL, NULL); |
1616 | 1408 | ||
1617 | /* | ||
1618 | * Register the virtual file system that will be the source of inodes | ||
1619 | * for the eventpoll files | ||
1620 | */ | ||
1621 | error = register_filesystem(&eventpoll_fs_type); | ||
1622 | if (error) | ||
1623 | goto epanic; | ||
1624 | |||
1625 | /* Mount the above commented virtual file system */ | ||
1626 | eventpoll_mnt = kern_mount(&eventpoll_fs_type); | ||
1627 | error = PTR_ERR(eventpoll_mnt); | ||
1628 | if (IS_ERR(eventpoll_mnt)) | ||
1629 | goto epanic; | ||
1630 | |||
1631 | DNPRINTK(3, (KERN_INFO "[%p] eventpoll: successfully initialized.\n", | ||
1632 | current)); | ||
1633 | return 0; | 1409 | return 0; |
1634 | |||
1635 | epanic: | ||
1636 | panic("eventpoll_init() failed\n"); | ||
1637 | } | 1410 | } |
1411 | fs_initcall(eventpoll_init); | ||
1638 | 1412 | ||
1639 | |||
1640 | static void __exit eventpoll_exit(void) | ||
1641 | { | ||
1642 | /* Undo all operations done inside eventpoll_init() */ | ||
1643 | unregister_filesystem(&eventpoll_fs_type); | ||
1644 | mntput(eventpoll_mnt); | ||
1645 | kmem_cache_destroy(pwq_cache); | ||
1646 | kmem_cache_destroy(epi_cache); | ||
1647 | } | ||
1648 | |||
1649 | module_init(eventpoll_init); | ||
1650 | module_exit(eventpoll_exit); | ||
1651 | |||
1652 | MODULE_LICENSE("GPL"); | ||
@@ -50,6 +50,7 @@ | |||
50 | #include <linux/tsacct_kern.h> | 50 | #include <linux/tsacct_kern.h> |
51 | #include <linux/cn_proc.h> | 51 | #include <linux/cn_proc.h> |
52 | #include <linux/audit.h> | 52 | #include <linux/audit.h> |
53 | #include <linux/signalfd.h> | ||
53 | 54 | ||
54 | #include <asm/uaccess.h> | 55 | #include <asm/uaccess.h> |
55 | #include <asm/mmu_context.h> | 56 | #include <asm/mmu_context.h> |
@@ -582,6 +583,13 @@ static int de_thread(struct task_struct *tsk) | |||
582 | int count; | 583 | int count; |
583 | 584 | ||
584 | /* | 585 | /* |
586 | * Tell all the sighand listeners that this sighand has | ||
587 | * been detached. The signalfd_detach() function grabs the | ||
588 | * sighand lock, if signal listeners are present on the sighand. | ||
589 | */ | ||
590 | signalfd_detach(tsk); | ||
591 | |||
592 | /* | ||
585 | * If we don't share sighandlers, then we aren't sharing anything | 593 | * If we don't share sighandlers, then we aren't sharing anything |
586 | * and we can just re-use it all. | 594 | * and we can just re-use it all. |
587 | */ | 595 | */ |
@@ -702,7 +710,7 @@ static int de_thread(struct task_struct *tsk) | |||
702 | */ | 710 | */ |
703 | detach_pid(tsk, PIDTYPE_PID); | 711 | detach_pid(tsk, PIDTYPE_PID); |
704 | tsk->pid = leader->pid; | 712 | tsk->pid = leader->pid; |
705 | attach_pid(tsk, PIDTYPE_PID, tsk->pid); | 713 | attach_pid(tsk, PIDTYPE_PID, find_pid(tsk->pid)); |
706 | transfer_pid(leader, tsk, PIDTYPE_PGID); | 714 | transfer_pid(leader, tsk, PIDTYPE_PGID); |
707 | transfer_pid(leader, tsk, PIDTYPE_SID); | 715 | transfer_pid(leader, tsk, PIDTYPE_SID); |
708 | list_replace_rcu(&leader->tasks, &tsk->tasks); | 716 | list_replace_rcu(&leader->tasks, &tsk->tasks); |
@@ -757,8 +765,7 @@ no_thread_group: | |||
757 | spin_unlock(&oldsighand->siglock); | 765 | spin_unlock(&oldsighand->siglock); |
758 | write_unlock_irq(&tasklist_lock); | 766 | write_unlock_irq(&tasklist_lock); |
759 | 767 | ||
760 | if (atomic_dec_and_test(&oldsighand->count)) | 768 | __cleanup_sighand(oldsighand); |
761 | kmem_cache_free(sighand_cachep, oldsighand); | ||
762 | } | 769 | } |
763 | 770 | ||
764 | BUG_ON(!thread_group_leader(tsk)); | 771 | BUG_ON(!thread_group_leader(tsk)); |
diff --git a/fs/mpage.c b/fs/mpage.c index 0fb914fc2ee0..c1698f2291aa 100644 --- a/fs/mpage.c +++ b/fs/mpage.c | |||
@@ -454,11 +454,18 @@ EXPORT_SYMBOL(mpage_readpage); | |||
454 | * written, so it can intelligently allocate a suitably-sized BIO. For now, | 454 | * written, so it can intelligently allocate a suitably-sized BIO. For now, |
455 | * just allocate full-size (16-page) BIOs. | 455 | * just allocate full-size (16-page) BIOs. |
456 | */ | 456 | */ |
457 | static struct bio * | 457 | struct mpage_data { |
458 | __mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block, | 458 | struct bio *bio; |
459 | sector_t *last_block_in_bio, int *ret, struct writeback_control *wbc, | 459 | sector_t last_block_in_bio; |
460 | writepage_t writepage_fn) | 460 | get_block_t *get_block; |
461 | unsigned use_writepage; | ||
462 | }; | ||
463 | |||
464 | static int __mpage_writepage(struct page *page, struct writeback_control *wbc, | ||
465 | void *data) | ||
461 | { | 466 | { |
467 | struct mpage_data *mpd = data; | ||
468 | struct bio *bio = mpd->bio; | ||
462 | struct address_space *mapping = page->mapping; | 469 | struct address_space *mapping = page->mapping; |
463 | struct inode *inode = page->mapping->host; | 470 | struct inode *inode = page->mapping->host; |
464 | const unsigned blkbits = inode->i_blkbits; | 471 | const unsigned blkbits = inode->i_blkbits; |
@@ -476,6 +483,7 @@ __mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block, | |||
476 | int length; | 483 | int length; |
477 | struct buffer_head map_bh; | 484 | struct buffer_head map_bh; |
478 | loff_t i_size = i_size_read(inode); | 485 | loff_t i_size = i_size_read(inode); |
486 | int ret = 0; | ||
479 | 487 | ||
480 | if (page_has_buffers(page)) { | 488 | if (page_has_buffers(page)) { |
481 | struct buffer_head *head = page_buffers(page); | 489 | struct buffer_head *head = page_buffers(page); |
@@ -538,7 +546,7 @@ __mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block, | |||
538 | 546 | ||
539 | map_bh.b_state = 0; | 547 | map_bh.b_state = 0; |
540 | map_bh.b_size = 1 << blkbits; | 548 | map_bh.b_size = 1 << blkbits; |
541 | if (get_block(inode, block_in_file, &map_bh, 1)) | 549 | if (mpd->get_block(inode, block_in_file, &map_bh, 1)) |
542 | goto confused; | 550 | goto confused; |
543 | if (buffer_new(&map_bh)) | 551 | if (buffer_new(&map_bh)) |
544 | unmap_underlying_metadata(map_bh.b_bdev, | 552 | unmap_underlying_metadata(map_bh.b_bdev, |
@@ -584,7 +592,7 @@ page_is_mapped: | |||
584 | /* | 592 | /* |
585 | * This page will go to BIO. Do we need to send this BIO off first? | 593 | * This page will go to BIO. Do we need to send this BIO off first? |
586 | */ | 594 | */ |
587 | if (bio && *last_block_in_bio != blocks[0] - 1) | 595 | if (bio && mpd->last_block_in_bio != blocks[0] - 1) |
588 | bio = mpage_bio_submit(WRITE, bio); | 596 | bio = mpage_bio_submit(WRITE, bio); |
589 | 597 | ||
590 | alloc_new: | 598 | alloc_new: |
@@ -641,7 +649,7 @@ alloc_new: | |||
641 | boundary_block, 1 << blkbits); | 649 | boundary_block, 1 << blkbits); |
642 | } | 650 | } |
643 | } else { | 651 | } else { |
644 | *last_block_in_bio = blocks[blocks_per_page - 1]; | 652 | mpd->last_block_in_bio = blocks[blocks_per_page - 1]; |
645 | } | 653 | } |
646 | goto out; | 654 | goto out; |
647 | 655 | ||
@@ -649,18 +657,19 @@ confused: | |||
649 | if (bio) | 657 | if (bio) |
650 | bio = mpage_bio_submit(WRITE, bio); | 658 | bio = mpage_bio_submit(WRITE, bio); |
651 | 659 | ||
652 | if (writepage_fn) { | 660 | if (mpd->use_writepage) { |
653 | *ret = (*writepage_fn)(page, wbc); | 661 | ret = mapping->a_ops->writepage(page, wbc); |
654 | } else { | 662 | } else { |
655 | *ret = -EAGAIN; | 663 | ret = -EAGAIN; |
656 | goto out; | 664 | goto out; |
657 | } | 665 | } |
658 | /* | 666 | /* |
659 | * The caller has a ref on the inode, so *mapping is stable | 667 | * The caller has a ref on the inode, so *mapping is stable |
660 | */ | 668 | */ |
661 | mapping_set_error(mapping, *ret); | 669 | mapping_set_error(mapping, ret); |
662 | out: | 670 | out: |
663 | return bio; | 671 | mpd->bio = bio; |
672 | return ret; | ||
664 | } | 673 | } |
665 | 674 | ||
666 | /** | 675 | /** |
@@ -683,120 +692,27 @@ out: | |||
683 | * the call was made get new I/O started against them. If wbc->sync_mode is | 692 | * the call was made get new I/O started against them. If wbc->sync_mode is |
684 | * WB_SYNC_ALL then we were called for data integrity and we must wait for | 693 | * WB_SYNC_ALL then we were called for data integrity and we must wait for |
685 | * existing IO to complete. | 694 | * existing IO to complete. |
686 | * | ||
687 | * If you fix this you should check generic_writepages() also! | ||
688 | */ | 695 | */ |
689 | int | 696 | int |
690 | mpage_writepages(struct address_space *mapping, | 697 | mpage_writepages(struct address_space *mapping, |
691 | struct writeback_control *wbc, get_block_t get_block) | 698 | struct writeback_control *wbc, get_block_t get_block) |
692 | { | 699 | { |
693 | struct backing_dev_info *bdi = mapping->backing_dev_info; | 700 | int ret; |
694 | struct bio *bio = NULL; | 701 | |
695 | sector_t last_block_in_bio = 0; | 702 | if (!get_block) |
696 | int ret = 0; | 703 | ret = generic_writepages(mapping, wbc); |
697 | int done = 0; | 704 | else { |
698 | int (*writepage)(struct page *page, struct writeback_control *wbc); | 705 | struct mpage_data mpd = { |
699 | struct pagevec pvec; | 706 | .bio = NULL, |
700 | int nr_pages; | 707 | .last_block_in_bio = 0, |
701 | pgoff_t index; | 708 | .get_block = get_block, |
702 | pgoff_t end; /* Inclusive */ | 709 | .use_writepage = 1, |
703 | int scanned = 0; | 710 | }; |
704 | int range_whole = 0; | 711 | |
705 | 712 | ret = write_cache_pages(mapping, wbc, __mpage_writepage, &mpd); | |
706 | if (wbc->nonblocking && bdi_write_congested(bdi)) { | 713 | if (mpd.bio) |
707 | wbc->encountered_congestion = 1; | 714 | mpage_bio_submit(WRITE, mpd.bio); |
708 | return 0; | ||
709 | } | ||
710 | |||
711 | writepage = NULL; | ||
712 | if (get_block == NULL) | ||
713 | writepage = mapping->a_ops->writepage; | ||
714 | |||
715 | pagevec_init(&pvec, 0); | ||
716 | if (wbc->range_cyclic) { | ||
717 | index = mapping->writeback_index; /* Start from prev offset */ | ||
718 | end = -1; | ||
719 | } else { | ||
720 | index = wbc->range_start >> PAGE_CACHE_SHIFT; | ||
721 | end = wbc->range_end >> PAGE_CACHE_SHIFT; | ||
722 | if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) | ||
723 | range_whole = 1; | ||
724 | scanned = 1; | ||
725 | } | 715 | } |
726 | retry: | ||
727 | while (!done && (index <= end) && | ||
728 | (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, | ||
729 | PAGECACHE_TAG_DIRTY, | ||
730 | min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) { | ||
731 | unsigned i; | ||
732 | |||
733 | scanned = 1; | ||
734 | for (i = 0; i < nr_pages; i++) { | ||
735 | struct page *page = pvec.pages[i]; | ||
736 | |||
737 | /* | ||
738 | * At this point we hold neither mapping->tree_lock nor | ||
739 | * lock on the page itself: the page may be truncated or | ||
740 | * invalidated (changing page->mapping to NULL), or even | ||
741 | * swizzled back from swapper_space to tmpfs file | ||
742 | * mapping | ||
743 | */ | ||
744 | |||
745 | lock_page(page); | ||
746 | |||
747 | if (unlikely(page->mapping != mapping)) { | ||
748 | unlock_page(page); | ||
749 | continue; | ||
750 | } | ||
751 | |||
752 | if (!wbc->range_cyclic && page->index > end) { | ||
753 | done = 1; | ||
754 | unlock_page(page); | ||
755 | continue; | ||
756 | } | ||
757 | |||
758 | if (wbc->sync_mode != WB_SYNC_NONE) | ||
759 | wait_on_page_writeback(page); | ||
760 | |||
761 | if (PageWriteback(page) || | ||
762 | !clear_page_dirty_for_io(page)) { | ||
763 | unlock_page(page); | ||
764 | continue; | ||
765 | } | ||
766 | |||
767 | if (writepage) { | ||
768 | ret = (*writepage)(page, wbc); | ||
769 | mapping_set_error(mapping, ret); | ||
770 | } else { | ||
771 | bio = __mpage_writepage(bio, page, get_block, | ||
772 | &last_block_in_bio, &ret, wbc, | ||
773 | page->mapping->a_ops->writepage); | ||
774 | } | ||
775 | if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE)) | ||
776 | unlock_page(page); | ||
777 | if (ret || (--(wbc->nr_to_write) <= 0)) | ||
778 | done = 1; | ||
779 | if (wbc->nonblocking && bdi_write_congested(bdi)) { | ||
780 | wbc->encountered_congestion = 1; | ||
781 | done = 1; | ||
782 | } | ||
783 | } | ||
784 | pagevec_release(&pvec); | ||
785 | cond_resched(); | ||
786 | } | ||
787 | if (!scanned && !done) { | ||
788 | /* | ||
789 | * We hit the last page and there is more work to be done: wrap | ||
790 | * back to the start of the file | ||
791 | */ | ||
792 | scanned = 1; | ||
793 | index = 0; | ||
794 | goto retry; | ||
795 | } | ||
796 | if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) | ||
797 | mapping->writeback_index = index; | ||
798 | if (bio) | ||
799 | mpage_bio_submit(WRITE, bio); | ||
800 | return ret; | 716 | return ret; |
801 | } | 717 | } |
802 | EXPORT_SYMBOL(mpage_writepages); | 718 | EXPORT_SYMBOL(mpage_writepages); |
@@ -804,15 +720,15 @@ EXPORT_SYMBOL(mpage_writepages); | |||
804 | int mpage_writepage(struct page *page, get_block_t get_block, | 720 | int mpage_writepage(struct page *page, get_block_t get_block, |
805 | struct writeback_control *wbc) | 721 | struct writeback_control *wbc) |
806 | { | 722 | { |
807 | int ret = 0; | 723 | struct mpage_data mpd = { |
808 | struct bio *bio; | 724 | .bio = NULL, |
809 | sector_t last_block_in_bio = 0; | 725 | .last_block_in_bio = 0, |
810 | 726 | .get_block = get_block, | |
811 | bio = __mpage_writepage(NULL, page, get_block, | 727 | .use_writepage = 0, |
812 | &last_block_in_bio, &ret, wbc, NULL); | 728 | }; |
813 | if (bio) | 729 | int ret = __mpage_writepage(page, wbc, &mpd); |
814 | mpage_bio_submit(WRITE, bio); | 730 | if (mpd.bio) |
815 | 731 | mpage_bio_submit(WRITE, mpd.bio); | |
816 | return ret; | 732 | return ret; |
817 | } | 733 | } |
818 | EXPORT_SYMBOL(mpage_writepage); | 734 | EXPORT_SYMBOL(mpage_writepage); |
diff --git a/fs/partitions/Kconfig b/fs/partitions/Kconfig index 01207042048b..7638a1c42a7d 100644 --- a/fs/partitions/Kconfig +++ b/fs/partitions/Kconfig | |||
@@ -239,7 +239,7 @@ config EFI_PARTITION | |||
239 | 239 | ||
240 | config SYSV68_PARTITION | 240 | config SYSV68_PARTITION |
241 | bool "SYSV68 partition table support" if PARTITION_ADVANCED | 241 | bool "SYSV68 partition table support" if PARTITION_ADVANCED |
242 | default y if M68K | 242 | default y if VME |
243 | help | 243 | help |
244 | Say Y here if you would like to be able to read the hard disk | 244 | Say Y here if you would like to be able to read the hard disk |
245 | partition table format used by Motorola Delta machines (using | 245 | partition table format used by Motorola Delta machines (using |
diff --git a/fs/partitions/efi.c b/fs/partitions/efi.c index 1bea610078b3..e7b07006bc41 100644 --- a/fs/partitions/efi.c +++ b/fs/partitions/efi.c | |||
@@ -152,7 +152,7 @@ last_lba(struct block_device *bdev) | |||
152 | } | 152 | } |
153 | 153 | ||
154 | static inline int | 154 | static inline int |
155 | pmbr_part_valid(struct partition *part, u64 lastlba) | 155 | pmbr_part_valid(struct partition *part) |
156 | { | 156 | { |
157 | if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT && | 157 | if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT && |
158 | le32_to_cpu(part->start_sect) == 1UL) | 158 | le32_to_cpu(part->start_sect) == 1UL) |
@@ -163,7 +163,6 @@ pmbr_part_valid(struct partition *part, u64 lastlba) | |||
163 | /** | 163 | /** |
164 | * is_pmbr_valid(): test Protective MBR for validity | 164 | * is_pmbr_valid(): test Protective MBR for validity |
165 | * @mbr: pointer to a legacy mbr structure | 165 | * @mbr: pointer to a legacy mbr structure |
166 | * @lastlba: last_lba for the whole device | ||
167 | * | 166 | * |
168 | * Description: Returns 1 if PMBR is valid, 0 otherwise. | 167 | * Description: Returns 1 if PMBR is valid, 0 otherwise. |
169 | * Validity depends on two things: | 168 | * Validity depends on two things: |
@@ -171,13 +170,13 @@ pmbr_part_valid(struct partition *part, u64 lastlba) | |||
171 | * 2) One partition of type 0xEE is found | 170 | * 2) One partition of type 0xEE is found |
172 | */ | 171 | */ |
173 | static int | 172 | static int |
174 | is_pmbr_valid(legacy_mbr *mbr, u64 lastlba) | 173 | is_pmbr_valid(legacy_mbr *mbr) |
175 | { | 174 | { |
176 | int i; | 175 | int i; |
177 | if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE) | 176 | if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE) |
178 | return 0; | 177 | return 0; |
179 | for (i = 0; i < 4; i++) | 178 | for (i = 0; i < 4; i++) |
180 | if (pmbr_part_valid(&mbr->partition_record[i], lastlba)) | 179 | if (pmbr_part_valid(&mbr->partition_record[i])) |
181 | return 1; | 180 | return 1; |
182 | return 0; | 181 | return 0; |
183 | } | 182 | } |
@@ -516,7 +515,7 @@ find_valid_gpt(struct block_device *bdev, gpt_header **gpt, gpt_entry **ptes) | |||
516 | int good_pgpt = 0, good_agpt = 0, good_pmbr = 0; | 515 | int good_pgpt = 0, good_agpt = 0, good_pmbr = 0; |
517 | gpt_header *pgpt = NULL, *agpt = NULL; | 516 | gpt_header *pgpt = NULL, *agpt = NULL; |
518 | gpt_entry *pptes = NULL, *aptes = NULL; | 517 | gpt_entry *pptes = NULL, *aptes = NULL; |
519 | legacy_mbr *legacymbr = NULL; | 518 | legacy_mbr *legacymbr; |
520 | u64 lastlba; | 519 | u64 lastlba; |
521 | if (!bdev || !gpt || !ptes) | 520 | if (!bdev || !gpt || !ptes) |
522 | return 0; | 521 | return 0; |
@@ -528,9 +527,8 @@ find_valid_gpt(struct block_device *bdev, gpt_header **gpt, gpt_entry **ptes) | |||
528 | if (legacymbr) { | 527 | if (legacymbr) { |
529 | read_lba(bdev, 0, (u8 *) legacymbr, | 528 | read_lba(bdev, 0, (u8 *) legacymbr, |
530 | sizeof (*legacymbr)); | 529 | sizeof (*legacymbr)); |
531 | good_pmbr = is_pmbr_valid(legacymbr, lastlba); | 530 | good_pmbr = is_pmbr_valid(legacymbr); |
532 | kfree(legacymbr); | 531 | kfree(legacymbr); |
533 | legacymbr=NULL; | ||
534 | } | 532 | } |
535 | if (!good_pmbr) | 533 | if (!good_pmbr) |
536 | goto fail; | 534 | goto fail; |
diff --git a/fs/signalfd.c b/fs/signalfd.c new file mode 100644 index 000000000000..7cfeab412b45 --- /dev/null +++ b/fs/signalfd.c | |||
@@ -0,0 +1,349 @@ | |||
1 | /* | ||
2 | * fs/signalfd.c | ||
3 | * | ||
4 | * Copyright (C) 2003 Linus Torvalds | ||
5 | * | ||
6 | * Mon Mar 5, 2007: Davide Libenzi <davidel@xmailserver.org> | ||
7 | * Changed ->read() to return a siginfo strcture instead of signal number. | ||
8 | * Fixed locking in ->poll(). | ||
9 | * Added sighand-detach notification. | ||
10 | * Added fd re-use in sys_signalfd() syscall. | ||
11 | * Now using anonymous inode source. | ||
12 | * Thanks to Oleg Nesterov for useful code review and suggestions. | ||
13 | * More comments and suggestions from Arnd Bergmann. | ||
14 | */ | ||
15 | |||
16 | #include <linux/file.h> | ||
17 | #include <linux/poll.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/fs.h> | ||
20 | #include <linux/sched.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/signal.h> | ||
23 | #include <linux/list.h> | ||
24 | #include <linux/anon_inodes.h> | ||
25 | #include <linux/signalfd.h> | ||
26 | |||
27 | struct signalfd_ctx { | ||
28 | struct list_head lnk; | ||
29 | wait_queue_head_t wqh; | ||
30 | sigset_t sigmask; | ||
31 | struct task_struct *tsk; | ||
32 | }; | ||
33 | |||
34 | struct signalfd_lockctx { | ||
35 | struct task_struct *tsk; | ||
36 | unsigned long flags; | ||
37 | }; | ||
38 | |||
39 | /* | ||
40 | * Tries to acquire the sighand lock. We do not increment the sighand | ||
41 | * use count, and we do not even pin the task struct, so we need to | ||
42 | * do it inside an RCU read lock, and we must be prepared for the | ||
43 | * ctx->tsk going to NULL (in signalfd_deliver()), and for the sighand | ||
44 | * being detached. We return 0 if the sighand has been detached, or | ||
45 | * 1 if we were able to pin the sighand lock. | ||
46 | */ | ||
47 | static int signalfd_lock(struct signalfd_ctx *ctx, struct signalfd_lockctx *lk) | ||
48 | { | ||
49 | struct sighand_struct *sighand = NULL; | ||
50 | |||
51 | rcu_read_lock(); | ||
52 | lk->tsk = rcu_dereference(ctx->tsk); | ||
53 | if (likely(lk->tsk != NULL)) | ||
54 | sighand = lock_task_sighand(lk->tsk, &lk->flags); | ||
55 | rcu_read_unlock(); | ||
56 | |||
57 | if (sighand && !ctx->tsk) { | ||
58 | unlock_task_sighand(lk->tsk, &lk->flags); | ||
59 | sighand = NULL; | ||
60 | } | ||
61 | |||
62 | return sighand != NULL; | ||
63 | } | ||
64 | |||
65 | static void signalfd_unlock(struct signalfd_lockctx *lk) | ||
66 | { | ||
67 | unlock_task_sighand(lk->tsk, &lk->flags); | ||
68 | } | ||
69 | |||
70 | /* | ||
71 | * This must be called with the sighand lock held. | ||
72 | */ | ||
73 | void signalfd_deliver(struct task_struct *tsk, int sig) | ||
74 | { | ||
75 | struct sighand_struct *sighand = tsk->sighand; | ||
76 | struct signalfd_ctx *ctx, *tmp; | ||
77 | |||
78 | BUG_ON(!sig); | ||
79 | list_for_each_entry_safe(ctx, tmp, &sighand->signalfd_list, lnk) { | ||
80 | /* | ||
81 | * We use a negative signal value as a way to broadcast that the | ||
82 | * sighand has been orphaned, so that we can notify all the | ||
83 | * listeners about this. Remember the ctx->sigmask is inverted, | ||
84 | * so if the user is interested in a signal, that corresponding | ||
85 | * bit will be zero. | ||
86 | */ | ||
87 | if (sig < 0) { | ||
88 | if (ctx->tsk == tsk) { | ||
89 | ctx->tsk = NULL; | ||
90 | list_del_init(&ctx->lnk); | ||
91 | wake_up(&ctx->wqh); | ||
92 | } | ||
93 | } else { | ||
94 | if (!sigismember(&ctx->sigmask, sig)) | ||
95 | wake_up(&ctx->wqh); | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | |||
100 | static void signalfd_cleanup(struct signalfd_ctx *ctx) | ||
101 | { | ||
102 | struct signalfd_lockctx lk; | ||
103 | |||
104 | /* | ||
105 | * This is tricky. If the sighand is gone, we do not need to remove | ||
106 | * context from the list, the list itself won't be there anymore. | ||
107 | */ | ||
108 | if (signalfd_lock(ctx, &lk)) { | ||
109 | list_del(&ctx->lnk); | ||
110 | signalfd_unlock(&lk); | ||
111 | } | ||
112 | kfree(ctx); | ||
113 | } | ||
114 | |||
115 | static int signalfd_release(struct inode *inode, struct file *file) | ||
116 | { | ||
117 | signalfd_cleanup(file->private_data); | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | static unsigned int signalfd_poll(struct file *file, poll_table *wait) | ||
122 | { | ||
123 | struct signalfd_ctx *ctx = file->private_data; | ||
124 | unsigned int events = 0; | ||
125 | struct signalfd_lockctx lk; | ||
126 | |||
127 | poll_wait(file, &ctx->wqh, wait); | ||
128 | |||
129 | /* | ||
130 | * Let the caller get a POLLIN in this case, ala socket recv() when | ||
131 | * the peer disconnects. | ||
132 | */ | ||
133 | if (signalfd_lock(ctx, &lk)) { | ||
134 | if (next_signal(&lk.tsk->pending, &ctx->sigmask) > 0 || | ||
135 | next_signal(&lk.tsk->signal->shared_pending, | ||
136 | &ctx->sigmask) > 0) | ||
137 | events |= POLLIN; | ||
138 | signalfd_unlock(&lk); | ||
139 | } else | ||
140 | events |= POLLIN; | ||
141 | |||
142 | return events; | ||
143 | } | ||
144 | |||
145 | /* | ||
146 | * Copied from copy_siginfo_to_user() in kernel/signal.c | ||
147 | */ | ||
148 | static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, | ||
149 | siginfo_t const *kinfo) | ||
150 | { | ||
151 | long err; | ||
152 | |||
153 | BUILD_BUG_ON(sizeof(struct signalfd_siginfo) != 128); | ||
154 | |||
155 | /* | ||
156 | * Unused memebers should be zero ... | ||
157 | */ | ||
158 | err = __clear_user(uinfo, sizeof(*uinfo)); | ||
159 | |||
160 | /* | ||
161 | * If you change siginfo_t structure, please be sure | ||
162 | * this code is fixed accordingly. | ||
163 | */ | ||
164 | err |= __put_user(kinfo->si_signo, &uinfo->signo); | ||
165 | err |= __put_user(kinfo->si_errno, &uinfo->err); | ||
166 | err |= __put_user((short)kinfo->si_code, &uinfo->code); | ||
167 | switch (kinfo->si_code & __SI_MASK) { | ||
168 | case __SI_KILL: | ||
169 | err |= __put_user(kinfo->si_pid, &uinfo->pid); | ||
170 | err |= __put_user(kinfo->si_uid, &uinfo->uid); | ||
171 | break; | ||
172 | case __SI_TIMER: | ||
173 | err |= __put_user(kinfo->si_tid, &uinfo->tid); | ||
174 | err |= __put_user(kinfo->si_overrun, &uinfo->overrun); | ||
175 | err |= __put_user((long)kinfo->si_ptr, &uinfo->svptr); | ||
176 | break; | ||
177 | case __SI_POLL: | ||
178 | err |= __put_user(kinfo->si_band, &uinfo->band); | ||
179 | err |= __put_user(kinfo->si_fd, &uinfo->fd); | ||
180 | break; | ||
181 | case __SI_FAULT: | ||
182 | err |= __put_user((long)kinfo->si_addr, &uinfo->addr); | ||
183 | #ifdef __ARCH_SI_TRAPNO | ||
184 | err |= __put_user(kinfo->si_trapno, &uinfo->trapno); | ||
185 | #endif | ||
186 | break; | ||
187 | case __SI_CHLD: | ||
188 | err |= __put_user(kinfo->si_pid, &uinfo->pid); | ||
189 | err |= __put_user(kinfo->si_uid, &uinfo->uid); | ||
190 | err |= __put_user(kinfo->si_status, &uinfo->status); | ||
191 | err |= __put_user(kinfo->si_utime, &uinfo->utime); | ||
192 | err |= __put_user(kinfo->si_stime, &uinfo->stime); | ||
193 | break; | ||
194 | case __SI_RT: /* This is not generated by the kernel as of now. */ | ||
195 | case __SI_MESGQ: /* But this is */ | ||
196 | err |= __put_user(kinfo->si_pid, &uinfo->pid); | ||
197 | err |= __put_user(kinfo->si_uid, &uinfo->uid); | ||
198 | err |= __put_user((long)kinfo->si_ptr, &uinfo->svptr); | ||
199 | break; | ||
200 | default: /* this is just in case for now ... */ | ||
201 | err |= __put_user(kinfo->si_pid, &uinfo->pid); | ||
202 | err |= __put_user(kinfo->si_uid, &uinfo->uid); | ||
203 | break; | ||
204 | } | ||
205 | |||
206 | return err ? -EFAULT: sizeof(*uinfo); | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * Returns either the size of a "struct signalfd_siginfo", or zero if the | ||
211 | * sighand we are attached to, has been orphaned. The "count" parameter | ||
212 | * must be at least the size of a "struct signalfd_siginfo". | ||
213 | */ | ||
214 | static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count, | ||
215 | loff_t *ppos) | ||
216 | { | ||
217 | struct signalfd_ctx *ctx = file->private_data; | ||
218 | ssize_t res = 0; | ||
219 | int locked, signo; | ||
220 | siginfo_t info; | ||
221 | struct signalfd_lockctx lk; | ||
222 | DECLARE_WAITQUEUE(wait, current); | ||
223 | |||
224 | if (count < sizeof(struct signalfd_siginfo)) | ||
225 | return -EINVAL; | ||
226 | locked = signalfd_lock(ctx, &lk); | ||
227 | if (!locked) | ||
228 | return 0; | ||
229 | res = -EAGAIN; | ||
230 | signo = dequeue_signal(lk.tsk, &ctx->sigmask, &info); | ||
231 | if (signo == 0 && !(file->f_flags & O_NONBLOCK)) { | ||
232 | add_wait_queue(&ctx->wqh, &wait); | ||
233 | for (;;) { | ||
234 | set_current_state(TASK_INTERRUPTIBLE); | ||
235 | signo = dequeue_signal(lk.tsk, &ctx->sigmask, &info); | ||
236 | if (signo != 0) | ||
237 | break; | ||
238 | if (signal_pending(current)) { | ||
239 | res = -ERESTARTSYS; | ||
240 | break; | ||
241 | } | ||
242 | signalfd_unlock(&lk); | ||
243 | schedule(); | ||
244 | locked = signalfd_lock(ctx, &lk); | ||
245 | if (unlikely(!locked)) { | ||
246 | /* | ||
247 | * Let the caller read zero byte, ala socket | ||
248 | * recv() when the peer disconnect. This test | ||
249 | * must be done before doing a dequeue_signal(), | ||
250 | * because if the sighand has been orphaned, | ||
251 | * the dequeue_signal() call is going to crash. | ||
252 | */ | ||
253 | res = 0; | ||
254 | break; | ||
255 | } | ||
256 | } | ||
257 | remove_wait_queue(&ctx->wqh, &wait); | ||
258 | __set_current_state(TASK_RUNNING); | ||
259 | } | ||
260 | if (likely(locked)) | ||
261 | signalfd_unlock(&lk); | ||
262 | if (likely(signo)) | ||
263 | res = signalfd_copyinfo((struct signalfd_siginfo __user *) buf, | ||
264 | &info); | ||
265 | |||
266 | return res; | ||
267 | } | ||
268 | |||
269 | static const struct file_operations signalfd_fops = { | ||
270 | .release = signalfd_release, | ||
271 | .poll = signalfd_poll, | ||
272 | .read = signalfd_read, | ||
273 | }; | ||
274 | |||
275 | /* | ||
276 | * Create a file descriptor that is associated with our signal | ||
277 | * state. We can pass it around to others if we want to, but | ||
278 | * it will always be _our_ signal state. | ||
279 | */ | ||
280 | asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask) | ||
281 | { | ||
282 | int error; | ||
283 | sigset_t sigmask; | ||
284 | struct signalfd_ctx *ctx; | ||
285 | struct sighand_struct *sighand; | ||
286 | struct file *file; | ||
287 | struct inode *inode; | ||
288 | struct signalfd_lockctx lk; | ||
289 | |||
290 | if (sizemask != sizeof(sigset_t) || | ||
291 | copy_from_user(&sigmask, user_mask, sizeof(sigmask))) | ||
292 | return error = -EINVAL; | ||
293 | sigdelsetmask(&sigmask, sigmask(SIGKILL) | sigmask(SIGSTOP)); | ||
294 | signotset(&sigmask); | ||
295 | |||
296 | if (ufd == -1) { | ||
297 | ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); | ||
298 | if (!ctx) | ||
299 | return -ENOMEM; | ||
300 | |||
301 | init_waitqueue_head(&ctx->wqh); | ||
302 | ctx->sigmask = sigmask; | ||
303 | ctx->tsk = current; | ||
304 | |||
305 | sighand = current->sighand; | ||
306 | /* | ||
307 | * Add this fd to the list of signal listeners. | ||
308 | */ | ||
309 | spin_lock_irq(&sighand->siglock); | ||
310 | list_add_tail(&ctx->lnk, &sighand->signalfd_list); | ||
311 | spin_unlock_irq(&sighand->siglock); | ||
312 | |||
313 | /* | ||
314 | * When we call this, the initialization must be complete, since | ||
315 | * anon_inode_getfd() will install the fd. | ||
316 | */ | ||
317 | error = anon_inode_getfd(&ufd, &inode, &file, "[signalfd]", | ||
318 | &signalfd_fops, ctx); | ||
319 | if (error) | ||
320 | goto err_fdalloc; | ||
321 | } else { | ||
322 | file = fget(ufd); | ||
323 | if (!file) | ||
324 | return -EBADF; | ||
325 | ctx = file->private_data; | ||
326 | if (file->f_op != &signalfd_fops) { | ||
327 | fput(file); | ||
328 | return -EINVAL; | ||
329 | } | ||
330 | /* | ||
331 | * We need to be prepared of the fact that the sighand this fd | ||
332 | * is attached to, has been detched. In that case signalfd_lock() | ||
333 | * will return 0, and we'll just skip setting the new mask. | ||
334 | */ | ||
335 | if (signalfd_lock(ctx, &lk)) { | ||
336 | ctx->sigmask = sigmask; | ||
337 | signalfd_unlock(&lk); | ||
338 | } | ||
339 | wake_up(&ctx->wqh); | ||
340 | fput(file); | ||
341 | } | ||
342 | |||
343 | return ufd; | ||
344 | |||
345 | err_fdalloc: | ||
346 | signalfd_cleanup(ctx); | ||
347 | return error; | ||
348 | } | ||
349 | |||
diff --git a/fs/timerfd.c b/fs/timerfd.c new file mode 100644 index 000000000000..e329e37f15a8 --- /dev/null +++ b/fs/timerfd.c | |||
@@ -0,0 +1,227 @@ | |||
1 | /* | ||
2 | * fs/timerfd.c | ||
3 | * | ||
4 | * Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org> | ||
5 | * | ||
6 | * | ||
7 | * Thanks to Thomas Gleixner for code reviews and useful comments. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/file.h> | ||
12 | #include <linux/poll.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/fs.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/list.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | #include <linux/time.h> | ||
20 | #include <linux/hrtimer.h> | ||
21 | #include <linux/anon_inodes.h> | ||
22 | #include <linux/timerfd.h> | ||
23 | |||
24 | struct timerfd_ctx { | ||
25 | struct hrtimer tmr; | ||
26 | ktime_t tintv; | ||
27 | spinlock_t lock; | ||
28 | wait_queue_head_t wqh; | ||
29 | int expired; | ||
30 | }; | ||
31 | |||
32 | /* | ||
33 | * This gets called when the timer event triggers. We set the "expired" | ||
34 | * flag, but we do not re-arm the timer (in case it's necessary, | ||
35 | * tintv.tv64 != 0) until the timer is read. | ||
36 | */ | ||
37 | static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr) | ||
38 | { | ||
39 | struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx, tmr); | ||
40 | unsigned long flags; | ||
41 | |||
42 | spin_lock_irqsave(&ctx->lock, flags); | ||
43 | ctx->expired = 1; | ||
44 | wake_up_locked(&ctx->wqh); | ||
45 | spin_unlock_irqrestore(&ctx->lock, flags); | ||
46 | |||
47 | return HRTIMER_NORESTART; | ||
48 | } | ||
49 | |||
50 | static void timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags, | ||
51 | const struct itimerspec *ktmr) | ||
52 | { | ||
53 | enum hrtimer_mode htmode; | ||
54 | ktime_t texp; | ||
55 | |||
56 | htmode = (flags & TFD_TIMER_ABSTIME) ? | ||
57 | HRTIMER_MODE_ABS: HRTIMER_MODE_REL; | ||
58 | |||
59 | texp = timespec_to_ktime(ktmr->it_value); | ||
60 | ctx->expired = 0; | ||
61 | ctx->tintv = timespec_to_ktime(ktmr->it_interval); | ||
62 | hrtimer_init(&ctx->tmr, clockid, htmode); | ||
63 | ctx->tmr.expires = texp; | ||
64 | ctx->tmr.function = timerfd_tmrproc; | ||
65 | if (texp.tv64 != 0) | ||
66 | hrtimer_start(&ctx->tmr, texp, htmode); | ||
67 | } | ||
68 | |||
69 | static int timerfd_release(struct inode *inode, struct file *file) | ||
70 | { | ||
71 | struct timerfd_ctx *ctx = file->private_data; | ||
72 | |||
73 | hrtimer_cancel(&ctx->tmr); | ||
74 | kfree(ctx); | ||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static unsigned int timerfd_poll(struct file *file, poll_table *wait) | ||
79 | { | ||
80 | struct timerfd_ctx *ctx = file->private_data; | ||
81 | unsigned int events = 0; | ||
82 | unsigned long flags; | ||
83 | |||
84 | poll_wait(file, &ctx->wqh, wait); | ||
85 | |||
86 | spin_lock_irqsave(&ctx->lock, flags); | ||
87 | if (ctx->expired) | ||
88 | events |= POLLIN; | ||
89 | spin_unlock_irqrestore(&ctx->lock, flags); | ||
90 | |||
91 | return events; | ||
92 | } | ||
93 | |||
94 | static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count, | ||
95 | loff_t *ppos) | ||
96 | { | ||
97 | struct timerfd_ctx *ctx = file->private_data; | ||
98 | ssize_t res; | ||
99 | u32 ticks = 0; | ||
100 | DECLARE_WAITQUEUE(wait, current); | ||
101 | |||
102 | if (count < sizeof(ticks)) | ||
103 | return -EINVAL; | ||
104 | spin_lock_irq(&ctx->lock); | ||
105 | res = -EAGAIN; | ||
106 | if (!ctx->expired && !(file->f_flags & O_NONBLOCK)) { | ||
107 | __add_wait_queue(&ctx->wqh, &wait); | ||
108 | for (res = 0;;) { | ||
109 | set_current_state(TASK_INTERRUPTIBLE); | ||
110 | if (ctx->expired) { | ||
111 | res = 0; | ||
112 | break; | ||
113 | } | ||
114 | if (signal_pending(current)) { | ||
115 | res = -ERESTARTSYS; | ||
116 | break; | ||
117 | } | ||
118 | spin_unlock_irq(&ctx->lock); | ||
119 | schedule(); | ||
120 | spin_lock_irq(&ctx->lock); | ||
121 | } | ||
122 | __remove_wait_queue(&ctx->wqh, &wait); | ||
123 | __set_current_state(TASK_RUNNING); | ||
124 | } | ||
125 | if (ctx->expired) { | ||
126 | ctx->expired = 0; | ||
127 | if (ctx->tintv.tv64 != 0) { | ||
128 | /* | ||
129 | * If tintv.tv64 != 0, this is a periodic timer that | ||
130 | * needs to be re-armed. We avoid doing it in the timer | ||
131 | * callback to avoid DoS attacks specifying a very | ||
132 | * short timer period. | ||
133 | */ | ||
134 | ticks = (u32) | ||
135 | hrtimer_forward(&ctx->tmr, | ||
136 | hrtimer_cb_get_time(&ctx->tmr), | ||
137 | ctx->tintv); | ||
138 | hrtimer_restart(&ctx->tmr); | ||
139 | } else | ||
140 | ticks = 1; | ||
141 | } | ||
142 | spin_unlock_irq(&ctx->lock); | ||
143 | if (ticks) | ||
144 | res = put_user(ticks, buf) ? -EFAULT: sizeof(ticks); | ||
145 | return res; | ||
146 | } | ||
147 | |||
148 | static const struct file_operations timerfd_fops = { | ||
149 | .release = timerfd_release, | ||
150 | .poll = timerfd_poll, | ||
151 | .read = timerfd_read, | ||
152 | }; | ||
153 | |||
154 | asmlinkage long sys_timerfd(int ufd, int clockid, int flags, | ||
155 | const struct itimerspec __user *utmr) | ||
156 | { | ||
157 | int error; | ||
158 | struct timerfd_ctx *ctx; | ||
159 | struct file *file; | ||
160 | struct inode *inode; | ||
161 | struct itimerspec ktmr; | ||
162 | |||
163 | if (copy_from_user(&ktmr, utmr, sizeof(ktmr))) | ||
164 | return -EFAULT; | ||
165 | |||
166 | if (clockid != CLOCK_MONOTONIC && | ||
167 | clockid != CLOCK_REALTIME) | ||
168 | return -EINVAL; | ||
169 | if (!timespec_valid(&ktmr.it_value) || | ||
170 | !timespec_valid(&ktmr.it_interval)) | ||
171 | return -EINVAL; | ||
172 | |||
173 | if (ufd == -1) { | ||
174 | ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); | ||
175 | if (!ctx) | ||
176 | return -ENOMEM; | ||
177 | |||
178 | init_waitqueue_head(&ctx->wqh); | ||
179 | spin_lock_init(&ctx->lock); | ||
180 | |||
181 | timerfd_setup(ctx, clockid, flags, &ktmr); | ||
182 | |||
183 | /* | ||
184 | * When we call this, the initialization must be complete, since | ||
185 | * anon_inode_getfd() will install the fd. | ||
186 | */ | ||
187 | error = anon_inode_getfd(&ufd, &inode, &file, "[timerfd]", | ||
188 | &timerfd_fops, ctx); | ||
189 | if (error) | ||
190 | goto err_tmrcancel; | ||
191 | } else { | ||
192 | file = fget(ufd); | ||
193 | if (!file) | ||
194 | return -EBADF; | ||
195 | ctx = file->private_data; | ||
196 | if (file->f_op != &timerfd_fops) { | ||
197 | fput(file); | ||
198 | return -EINVAL; | ||
199 | } | ||
200 | /* | ||
201 | * We need to stop the existing timer before reprogramming | ||
202 | * it to the new values. | ||
203 | */ | ||
204 | for (;;) { | ||
205 | spin_lock_irq(&ctx->lock); | ||
206 | if (hrtimer_try_to_cancel(&ctx->tmr) >= 0) | ||
207 | break; | ||
208 | spin_unlock_irq(&ctx->lock); | ||
209 | cpu_relax(); | ||
210 | } | ||
211 | /* | ||
212 | * Re-program the timer to the new value ... | ||
213 | */ | ||
214 | timerfd_setup(ctx, clockid, flags, &ktmr); | ||
215 | |||
216 | spin_unlock_irq(&ctx->lock); | ||
217 | fput(file); | ||
218 | } | ||
219 | |||
220 | return ufd; | ||
221 | |||
222 | err_tmrcancel: | ||
223 | hrtimer_cancel(&ctx->tmr); | ||
224 | kfree(ctx); | ||
225 | return error; | ||
226 | } | ||
227 | |||
diff --git a/include/asm-alpha/poll.h b/include/asm-alpha/poll.h index 76f89356b6a7..c98509d3149e 100644 --- a/include/asm-alpha/poll.h +++ b/include/asm-alpha/poll.h | |||
@@ -1,25 +1 @@ | |||
1 | #ifndef __ALPHA_POLL_H | #include <asm-generic/poll.h> | |
2 | #define __ALPHA_POLL_H | ||
3 | |||
4 | #define POLLIN (1 << 0) | ||
5 | #define POLLPRI (1 << 1) | ||
6 | #define POLLOUT (1 << 2) | ||
7 | #define POLLERR (1 << 3) | ||
8 | #define POLLHUP (1 << 4) | ||
9 | #define POLLNVAL (1 << 5) | ||
10 | #define POLLRDNORM (1 << 6) | ||
11 | #define POLLRDBAND (1 << 7) | ||
12 | #define POLLWRNORM (1 << 8) | ||
13 | #define POLLWRBAND (1 << 9) | ||
14 | #define POLLMSG (1 << 10) | ||
15 | #define POLLREMOVE (1 << 12) | ||
16 | #define POLLRDHUP (1 << 13) | ||
17 | |||
18 | |||
19 | struct pollfd { | ||
20 | int fd; | ||
21 | short events; | ||
22 | short revents; | ||
23 | }; | ||
24 | |||
25 | #endif | ||
diff --git a/include/asm-arm/poll.h b/include/asm-arm/poll.h index 5030b2b232a3..c98509d3149e 100644 --- a/include/asm-arm/poll.h +++ b/include/asm-arm/poll.h | |||
@@ -1,27 +1 @@ | |||
1 | #ifndef __ASMARM_POLL_H | #include <asm-generic/poll.h> | |
2 | #define __ASMARM_POLL_H | ||
3 | |||
4 | /* These are specified by iBCS2 */ | ||
5 | #define POLLIN 0x0001 | ||
6 | #define POLLPRI 0x0002 | ||
7 | #define POLLOUT 0x0004 | ||
8 | #define POLLERR 0x0008 | ||
9 | #define POLLHUP 0x0010 | ||
10 | #define POLLNVAL 0x0020 | ||
11 | |||
12 | /* The rest seem to be more-or-less nonstandard. Check them! */ | ||
13 | #define POLLRDNORM 0x0040 | ||
14 | #define POLLRDBAND 0x0080 | ||
15 | #define POLLWRNORM 0x0100 | ||
16 | #define POLLWRBAND 0x0200 | ||
17 | #define POLLMSG 0x0400 | ||
18 | #define POLLREMOVE 0x1000 | ||
19 | #define POLLRDHUP 0x2000 | ||
20 | |||
21 | struct pollfd { | ||
22 | int fd; | ||
23 | short events; | ||
24 | short revents; | ||
25 | }; | ||
26 | |||
27 | #endif | ||
diff --git a/include/asm-arm26/poll.h b/include/asm-arm26/poll.h index 9ccb7f4190ca..1170e7065f6a 100644 --- a/include/asm-arm26/poll.h +++ b/include/asm-arm26/poll.h | |||
@@ -1,26 +1,8 @@ | |||
1 | #ifndef __ASMARM_POLL_H | 1 | #ifndef __ASMARM_POLL_H |
2 | #define __ASMARM_POLL_H | 2 | #define __ASMARM_POLL_H |
3 | 3 | ||
4 | /* These are specified by iBCS2 */ | 4 | #include <asm-generic/poll.h> |
5 | #define POLLIN 0x0001 | ||
6 | #define POLLPRI 0x0002 | ||
7 | #define POLLOUT 0x0004 | ||
8 | #define POLLERR 0x0008 | ||
9 | #define POLLHUP 0x0010 | ||
10 | #define POLLNVAL 0x0020 | ||
11 | 5 | ||
12 | /* The rest seem to be more-or-less nonstandard. Check them! */ | 6 | #undef POLLREMOVE |
13 | #define POLLRDNORM 0x0040 | ||
14 | #define POLLRDBAND 0x0080 | ||
15 | #define POLLWRNORM 0x0100 | ||
16 | #define POLLWRBAND 0x0200 | ||
17 | #define POLLMSG 0x0400 | ||
18 | #define POLLRDHUP 0x2000 | ||
19 | |||
20 | struct pollfd { | ||
21 | int fd; | ||
22 | short events; | ||
23 | short revents; | ||
24 | }; | ||
25 | 7 | ||
26 | #endif | 8 | #endif |
diff --git a/include/asm-avr32/poll.h b/include/asm-avr32/poll.h index 736e29755dfc..c98509d3149e 100644 --- a/include/asm-avr32/poll.h +++ b/include/asm-avr32/poll.h | |||
@@ -1,27 +1 @@ | |||
1 | #ifndef __ASM_AVR32_POLL_H | #include <asm-generic/poll.h> | |
2 | #define __ASM_AVR32_POLL_H | ||
3 | |||
4 | /* These are specified by iBCS2 */ | ||
5 | #define POLLIN 0x0001 | ||
6 | #define POLLPRI 0x0002 | ||
7 | #define POLLOUT 0x0004 | ||
8 | #define POLLERR 0x0008 | ||
9 | #define POLLHUP 0x0010 | ||
10 | #define POLLNVAL 0x0020 | ||
11 | |||
12 | /* The rest seem to be more-or-less nonstandard. Check them! */ | ||
13 | #define POLLRDNORM 0x0040 | ||
14 | #define POLLRDBAND 0x0080 | ||
15 | #define POLLWRNORM 0x0100 | ||
16 | #define POLLWRBAND 0x0200 | ||
17 | #define POLLMSG 0x0400 | ||
18 | #define POLLREMOVE 0x1000 | ||
19 | #define POLLRDHUP 0x2000 | ||
20 | |||
21 | struct pollfd { | ||
22 | int fd; | ||
23 | short events; | ||
24 | short revents; | ||
25 | }; | ||
26 | |||
27 | #endif /* __ASM_AVR32_POLL_H */ | ||
diff --git a/include/asm-cris/poll.h b/include/asm-cris/poll.h index 1b25d4cf498c..c98509d3149e 100644 --- a/include/asm-cris/poll.h +++ b/include/asm-cris/poll.h | |||
@@ -1,26 +1 @@ | |||
1 | #ifndef __ASM_CRIS_POLL_H | #include <asm-generic/poll.h> | |
2 | #define __ASM_CRIS_POLL_H | ||
3 | |||
4 | /* taken from asm-alpha */ | ||
5 | |||
6 | #define POLLIN 1 | ||
7 | #define POLLPRI 2 | ||
8 | #define POLLOUT 4 | ||
9 | #define POLLERR 8 | ||
10 | #define POLLHUP 16 | ||
11 | #define POLLNVAL 32 | ||
12 | #define POLLRDNORM 64 | ||
13 | #define POLLRDBAND 128 | ||
14 | #define POLLWRNORM 256 | ||
15 | #define POLLWRBAND 512 | ||
16 | #define POLLMSG 1024 | ||
17 | #define POLLREMOVE 4096 | ||
18 | #define POLLRDHUP 8192 | ||
19 | |||
20 | struct pollfd { | ||
21 | int fd; | ||
22 | short events; | ||
23 | short revents; | ||
24 | }; | ||
25 | |||
26 | #endif | ||
diff --git a/include/asm-frv/poll.h b/include/asm-frv/poll.h index c8fe8801d075..0d01479ccc56 100644 --- a/include/asm-frv/poll.h +++ b/include/asm-frv/poll.h | |||
@@ -1,24 +1,12 @@ | |||
1 | #ifndef _ASM_POLL_H | 1 | #ifndef _ASM_POLL_H |
2 | #define _ASM_POLL_H | 2 | #define _ASM_POLL_H |
3 | 3 | ||
4 | #define POLLIN 1 | ||
5 | #define POLLPRI 2 | ||
6 | #define POLLOUT 4 | ||
7 | #define POLLERR 8 | ||
8 | #define POLLHUP 16 | ||
9 | #define POLLNVAL 32 | ||
10 | #define POLLRDNORM 64 | ||
11 | #define POLLWRNORM POLLOUT | 4 | #define POLLWRNORM POLLOUT |
12 | #define POLLRDBAND 128 | ||
13 | #define POLLWRBAND 256 | 5 | #define POLLWRBAND 256 |
14 | #define POLLMSG 0x0400 | ||
15 | #define POLLRDHUP 0x2000 | ||
16 | 6 | ||
17 | struct pollfd { | 7 | #include <asm-generic/poll.h> |
18 | int fd; | 8 | |
19 | short events; | 9 | #undef POLLREMOVE |
20 | short revents; | ||
21 | }; | ||
22 | 10 | ||
23 | #endif | 11 | #endif |
24 | 12 | ||
diff --git a/include/asm-generic/Kbuild b/include/asm-generic/Kbuild index fa14f8cd30c5..5bfeef761649 100644 --- a/include/asm-generic/Kbuild +++ b/include/asm-generic/Kbuild | |||
@@ -4,6 +4,7 @@ header-y += fcntl.h | |||
4 | header-y += ioctl.h | 4 | header-y += ioctl.h |
5 | header-y += ipc.h | 5 | header-y += ipc.h |
6 | header-y += mman.h | 6 | header-y += mman.h |
7 | header-y += poll.h | ||
7 | header-y += signal.h | 8 | header-y += signal.h |
8 | header-y += statfs.h | 9 | header-y += statfs.h |
9 | 10 | ||
diff --git a/include/asm-generic/poll.h b/include/asm-generic/poll.h new file mode 100644 index 000000000000..44bce836d350 --- /dev/null +++ b/include/asm-generic/poll.h | |||
@@ -0,0 +1,37 @@ | |||
1 | #ifndef __ASM_GENERIC_POLL_H | ||
2 | #define __ASM_GENERIC_POLL_H | ||
3 | |||
4 | /* These are specified by iBCS2 */ | ||
5 | #define POLLIN 0x0001 | ||
6 | #define POLLPRI 0x0002 | ||
7 | #define POLLOUT 0x0004 | ||
8 | #define POLLERR 0x0008 | ||
9 | #define POLLHUP 0x0010 | ||
10 | #define POLLNVAL 0x0020 | ||
11 | |||
12 | /* The rest seem to be more-or-less nonstandard. Check them! */ | ||
13 | #define POLLRDNORM 0x0040 | ||
14 | #define POLLRDBAND 0x0080 | ||
15 | #ifndef POLLWRNORM | ||
16 | #define POLLWRNORM 0x0100 | ||
17 | #endif | ||
18 | #ifndef POLLWRBAND | ||
19 | #define POLLWRBAND 0x0200 | ||
20 | #endif | ||
21 | #ifndef POLLMSG | ||
22 | #define POLLMSG 0x0400 | ||
23 | #endif | ||
24 | #ifndef POLLREMOVE | ||
25 | #define POLLREMOVE 0x1000 | ||
26 | #endif | ||
27 | #ifndef POLLRDHUP | ||
28 | #define POLLRDHUP 0x2000 | ||
29 | #endif | ||
30 | |||
31 | struct pollfd { | ||
32 | int fd; | ||
33 | short events; | ||
34 | short revents; | ||
35 | }; | ||
36 | |||
37 | #endif /* __ASM_GENERIC_POLL_H */ | ||
diff --git a/include/asm-h8300/poll.h b/include/asm-h8300/poll.h index fc52103b276a..f61540c22d94 100644 --- a/include/asm-h8300/poll.h +++ b/include/asm-h8300/poll.h | |||
@@ -1,23 +1,11 @@ | |||
1 | #ifndef __H8300_POLL_H | 1 | #ifndef __H8300_POLL_H |
2 | #define __H8300_POLL_H | 2 | #define __H8300_POLL_H |
3 | 3 | ||
4 | #define POLLIN 1 | ||
5 | #define POLLPRI 2 | ||
6 | #define POLLOUT 4 | ||
7 | #define POLLERR 8 | ||
8 | #define POLLHUP 16 | ||
9 | #define POLLNVAL 32 | ||
10 | #define POLLRDNORM 64 | ||
11 | #define POLLWRNORM POLLOUT | 4 | #define POLLWRNORM POLLOUT |
12 | #define POLLRDBAND 128 | ||
13 | #define POLLWRBAND 256 | 5 | #define POLLWRBAND 256 |
14 | #define POLLMSG 0x0400 | ||
15 | #define POLLRDHUP 0x2000 | ||
16 | 6 | ||
17 | struct pollfd { | 7 | #include <asm-generic/poll.h> |
18 | int fd; | 8 | |
19 | short events; | 9 | #undef POLLREMOVE |
20 | short revents; | ||
21 | }; | ||
22 | 10 | ||
23 | #endif | 11 | #endif |
diff --git a/include/asm-h8300/unistd.h b/include/asm-h8300/unistd.h index 7ddd414f8d16..99f3c3561ecb 100644 --- a/include/asm-h8300/unistd.h +++ b/include/asm-h8300/unistd.h | |||
@@ -21,7 +21,7 @@ | |||
21 | #define __NR_time 13 | 21 | #define __NR_time 13 |
22 | #define __NR_mknod 14 | 22 | #define __NR_mknod 14 |
23 | #define __NR_chmod 15 | 23 | #define __NR_chmod 15 |
24 | #define __NR_chown 16 | 24 | #define __NR_lchown 16 |
25 | #define __NR_break 17 | 25 | #define __NR_break 17 |
26 | #define __NR_oldstat 18 | 26 | #define __NR_oldstat 18 |
27 | #define __NR_lseek 19 | 27 | #define __NR_lseek 19 |
@@ -115,10 +115,10 @@ | |||
115 | #define __NR_lstat 107 | 115 | #define __NR_lstat 107 |
116 | #define __NR_fstat 108 | 116 | #define __NR_fstat 108 |
117 | #define __NR_olduname 109 | 117 | #define __NR_olduname 109 |
118 | #define __NR_iopl /* 110 */ not supported | 118 | #define __NR_iopl 110 |
119 | #define __NR_vhangup 111 | 119 | #define __NR_vhangup 111 |
120 | #define __NR_idle /* 112 */ Obsolete | 120 | #define __NR_idle 112 |
121 | #define __NR_vm86 /* 113 */ not supported | 121 | #define __NR_vm86old 113 |
122 | #define __NR_wait4 114 | 122 | #define __NR_wait4 114 |
123 | #define __NR_swapoff 115 | 123 | #define __NR_swapoff 115 |
124 | #define __NR_sysinfo 116 | 124 | #define __NR_sysinfo 116 |
@@ -128,7 +128,7 @@ | |||
128 | #define __NR_clone 120 | 128 | #define __NR_clone 120 |
129 | #define __NR_setdomainname 121 | 129 | #define __NR_setdomainname 121 |
130 | #define __NR_uname 122 | 130 | #define __NR_uname 122 |
131 | #define __NR_cacheflush 123 | 131 | #define __NR_modify_ldt 123 |
132 | #define __NR_adjtimex 124 | 132 | #define __NR_adjtimex 124 |
133 | #define __NR_mprotect 125 | 133 | #define __NR_mprotect 125 |
134 | #define __NR_sigprocmask 126 | 134 | #define __NR_sigprocmask 126 |
@@ -171,7 +171,7 @@ | |||
171 | #define __NR_mremap 163 | 171 | #define __NR_mremap 163 |
172 | #define __NR_setresuid 164 | 172 | #define __NR_setresuid 164 |
173 | #define __NR_getresuid 165 | 173 | #define __NR_getresuid 165 |
174 | #define __NR_getpagesize 166 | 174 | #define __NR_vm86 166 |
175 | #define __NR_query_module 167 | 175 | #define __NR_query_module 167 |
176 | #define __NR_poll 168 | 176 | #define __NR_poll 168 |
177 | #define __NR_nfsservctl 169 | 177 | #define __NR_nfsservctl 169 |
@@ -187,7 +187,7 @@ | |||
187 | #define __NR_rt_sigsuspend 179 | 187 | #define __NR_rt_sigsuspend 179 |
188 | #define __NR_pread64 180 | 188 | #define __NR_pread64 180 |
189 | #define __NR_pwrite64 181 | 189 | #define __NR_pwrite64 181 |
190 | #define __NR_lchown 182 | 190 | #define __NR_chown 182 |
191 | #define __NR_getcwd 183 | 191 | #define __NR_getcwd 183 |
192 | #define __NR_capget 184 | 192 | #define __NR_capget 184 |
193 | #define __NR_capset 185 | 193 | #define __NR_capset 185 |
@@ -203,7 +203,7 @@ | |||
203 | #define __NR_stat64 195 | 203 | #define __NR_stat64 195 |
204 | #define __NR_lstat64 196 | 204 | #define __NR_lstat64 196 |
205 | #define __NR_fstat64 197 | 205 | #define __NR_fstat64 197 |
206 | #define __NR_chown32 198 | 206 | #define __NR_lchown32 198 |
207 | #define __NR_getuid32 199 | 207 | #define __NR_getuid32 199 |
208 | #define __NR_getgid32 200 | 208 | #define __NR_getgid32 200 |
209 | #define __NR_geteuid32 201 | 209 | #define __NR_geteuid32 201 |
@@ -217,15 +217,18 @@ | |||
217 | #define __NR_getresuid32 209 | 217 | #define __NR_getresuid32 209 |
218 | #define __NR_setresgid32 210 | 218 | #define __NR_setresgid32 210 |
219 | #define __NR_getresgid32 211 | 219 | #define __NR_getresgid32 211 |
220 | #define __NR_lchown32 212 | 220 | #define __NR_chown32 212 |
221 | #define __NR_setuid32 213 | 221 | #define __NR_setuid32 213 |
222 | #define __NR_setgid32 214 | 222 | #define __NR_setgid32 214 |
223 | #define __NR_setfsuid32 215 | 223 | #define __NR_setfsuid32 215 |
224 | #define __NR_setfsgid32 216 | 224 | #define __NR_setfsgid32 216 |
225 | #define __NR_pivot_root 217 | 225 | #define __NR_pivot_root 217 |
226 | #define __NR_mincore 218 | ||
227 | #define __NR_madvise 219 | ||
228 | #define __NR_madvise1 219 | ||
226 | #define __NR_getdents64 220 | 229 | #define __NR_getdents64 220 |
227 | #define __NR_fcntl64 221 | 230 | #define __NR_fcntl64 221 |
228 | #define __NR_security 223 | 231 | /* 223 is unused */ |
229 | #define __NR_gettid 224 | 232 | #define __NR_gettid 224 |
230 | #define __NR_readahead 225 | 233 | #define __NR_readahead 225 |
231 | #define __NR_setxattr 226 | 234 | #define __NR_setxattr 226 |
@@ -252,13 +255,13 @@ | |||
252 | #define __NR_io_getevents 247 | 255 | #define __NR_io_getevents 247 |
253 | #define __NR_io_submit 248 | 256 | #define __NR_io_submit 248 |
254 | #define __NR_io_cancel 249 | 257 | #define __NR_io_cancel 249 |
255 | #define __NR_alloc_hugepages 250 | 258 | #define __NR_fadvise64 250 |
256 | #define __NR_free_hugepages 251 | 259 | /* 251 is available for reuse (was briefly sys_set_zone_reclaim) */ |
257 | #define __NR_exit_group 252 | 260 | #define __NR_exit_group 252 |
258 | #define __NR_lookup_dcookie 253 | 261 | #define __NR_lookup_dcookie 253 |
259 | #define __NR_sys_epoll_create 254 | 262 | #define __NR_epoll_create 254 |
260 | #define __NR_sys_epoll_ctl 255 | 263 | #define __NR_epoll_ctl 255 |
261 | #define __NR_sys_epoll_wait 256 | 264 | #define __NR_epoll_wait 256 |
262 | #define __NR_remap_file_pages 257 | 265 | #define __NR_remap_file_pages 257 |
263 | #define __NR_set_tid_address 258 | 266 | #define __NR_set_tid_address 258 |
264 | #define __NR_timer_create 259 | 267 | #define __NR_timer_create 259 |
@@ -291,10 +294,41 @@ | |||
291 | #define __NR_add_key 286 | 294 | #define __NR_add_key 286 |
292 | #define __NR_request_key 287 | 295 | #define __NR_request_key 287 |
293 | #define __NR_keyctl 288 | 296 | #define __NR_keyctl 288 |
297 | #define __NR_ioprio_set 289 | ||
298 | #define __NR_ioprio_get 290 | ||
299 | #define __NR_inotify_init 291 | ||
300 | #define __NR_inotify_add_watch 292 | ||
301 | #define __NR_inotify_rm_watch 293 | ||
302 | #define __NR_migrate_pages 294 | ||
303 | #define __NR_openat 295 | ||
304 | #define __NR_mkdirat 296 | ||
305 | #define __NR_mknodat 297 | ||
306 | #define __NR_fchownat 298 | ||
307 | #define __NR_futimesat 299 | ||
308 | #define __NR_fstatat64 300 | ||
309 | #define __NR_unlinkat 301 | ||
310 | #define __NR_renameat 302 | ||
311 | #define __NR_linkat 303 | ||
312 | #define __NR_symlinkat 304 | ||
313 | #define __NR_readlinkat 305 | ||
314 | #define __NR_fchmodat 306 | ||
315 | #define __NR_faccessat 307 | ||
316 | #define __NR_pselect6 308 | ||
317 | #define __NR_ppoll 309 | ||
318 | #define __NR_unshare 310 | ||
319 | #define __NR_set_robust_list 311 | ||
320 | #define __NR_get_robust_list 312 | ||
321 | #define __NR_splice 313 | ||
322 | #define __NR_sync_file_range 314 | ||
323 | #define __NR_tee 315 | ||
324 | #define __NR_vmsplice 316 | ||
325 | #define __NR_move_pages 317 | ||
326 | #define __NR_getcpu 318 | ||
327 | #define __NR_epoll_pwait 319 | ||
294 | 328 | ||
295 | #ifdef __KERNEL__ | 329 | #ifdef __KERNEL__ |
296 | 330 | ||
297 | #define NR_syscalls 289 | 331 | #define NR_syscalls 320 |
298 | 332 | ||
299 | #define __ARCH_WANT_IPC_PARSE_VERSION | 333 | #define __ARCH_WANT_IPC_PARSE_VERSION |
300 | #define __ARCH_WANT_OLD_READDIR | 334 | #define __ARCH_WANT_OLD_READDIR |
diff --git a/include/asm-i386/alternative.h b/include/asm-i386/alternative.h index 0f70b379b029..eb7da5402bfa 100644 --- a/include/asm-i386/alternative.h +++ b/include/asm-i386/alternative.h | |||
@@ -98,6 +98,12 @@ static inline void alternatives_smp_switch(int smp) {} | |||
98 | ".previous" : output : [feat] "i" (feature), ##input) | 98 | ".previous" : output : [feat] "i" (feature), ##input) |
99 | 99 | ||
100 | /* | 100 | /* |
101 | * use this macro(s) if you need more than one output parameter | ||
102 | * in alternative_io | ||
103 | */ | ||
104 | #define ASM_OUTPUT2(a, b) a, b | ||
105 | |||
106 | /* | ||
101 | * Alternative inline assembly for SMP. | 107 | * Alternative inline assembly for SMP. |
102 | * | 108 | * |
103 | * The LOCK_PREFIX macro defined here replaces the LOCK and | 109 | * The LOCK_PREFIX macro defined here replaces the LOCK and |
diff --git a/include/asm-i386/poll.h b/include/asm-i386/poll.h index 2cd4929abd40..c98509d3149e 100644 --- a/include/asm-i386/poll.h +++ b/include/asm-i386/poll.h | |||
@@ -1,27 +1 @@ | |||
1 | #ifndef __i386_POLL_H | #include <asm-generic/poll.h> | |
2 | #define __i386_POLL_H | ||
3 | |||
4 | /* These are specified by iBCS2 */ | ||
5 | #define POLLIN 0x0001 | ||
6 | #define POLLPRI 0x0002 | ||
7 | #define POLLOUT 0x0004 | ||
8 | #define POLLERR 0x0008 | ||
9 | #define POLLHUP 0x0010 | ||
10 | #define POLLNVAL 0x0020 | ||
11 | |||
12 | /* The rest seem to be more-or-less nonstandard. Check them! */ | ||
13 | #define POLLRDNORM 0x0040 | ||
14 | #define POLLRDBAND 0x0080 | ||
15 | #define POLLWRNORM 0x0100 | ||
16 | #define POLLWRBAND 0x0200 | ||
17 | #define POLLMSG 0x0400 | ||
18 | #define POLLREMOVE 0x1000 | ||
19 | #define POLLRDHUP 0x2000 | ||
20 | |||
21 | struct pollfd { | ||
22 | int fd; | ||
23 | short events; | ||
24 | short revents; | ||
25 | }; | ||
26 | |||
27 | #endif | ||
diff --git a/include/asm-i386/tsc.h b/include/asm-i386/tsc.h index 3f3c1fa000b4..62c091ffcccc 100644 --- a/include/asm-i386/tsc.h +++ b/include/asm-i386/tsc.h | |||
@@ -35,14 +35,16 @@ static inline cycles_t get_cycles(void) | |||
35 | static __always_inline cycles_t get_cycles_sync(void) | 35 | static __always_inline cycles_t get_cycles_sync(void) |
36 | { | 36 | { |
37 | unsigned long long ret; | 37 | unsigned long long ret; |
38 | unsigned eax; | 38 | unsigned eax, edx; |
39 | 39 | ||
40 | /* | 40 | /* |
41 | * Use RDTSCP if possible; it is guaranteed to be synchronous | 41 | * Use RDTSCP if possible; it is guaranteed to be synchronous |
42 | * and doesn't cause a VMEXIT on Hypervisors | 42 | * and doesn't cause a VMEXIT on Hypervisors |
43 | */ | 43 | */ |
44 | alternative_io(ASM_NOP3, ".byte 0x0f,0x01,0xf9", X86_FEATURE_RDTSCP, | 44 | alternative_io(ASM_NOP3, ".byte 0x0f,0x01,0xf9", X86_FEATURE_RDTSCP, |
45 | "=A" (ret), "0" (0ULL) : "ecx", "memory"); | 45 | ASM_OUTPUT2("=a" (eax), "=d" (edx)), |
46 | "a" (0U), "d" (0U) : "ecx", "memory"); | ||
47 | ret = (((unsigned long long)edx) << 32) | ((unsigned long long)eax); | ||
46 | if (ret) | 48 | if (ret) |
47 | return ret; | 49 | return ret; |
48 | 50 | ||
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index bd21e795197c..e84ace1ec8bf 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h | |||
@@ -326,10 +326,13 @@ | |||
326 | #define __NR_getcpu 318 | 326 | #define __NR_getcpu 318 |
327 | #define __NR_epoll_pwait 319 | 327 | #define __NR_epoll_pwait 319 |
328 | #define __NR_utimensat 320 | 328 | #define __NR_utimensat 320 |
329 | #define __NR_signalfd 321 | ||
330 | #define __NR_timerfd 322 | ||
331 | #define __NR_eventfd 323 | ||
329 | 332 | ||
330 | #ifdef __KERNEL__ | 333 | #ifdef __KERNEL__ |
331 | 334 | ||
332 | #define NR_syscalls 321 | 335 | #define NR_syscalls 324 |
333 | 336 | ||
334 | #define __ARCH_WANT_IPC_PARSE_VERSION | 337 | #define __ARCH_WANT_IPC_PARSE_VERSION |
335 | #define __ARCH_WANT_OLD_READDIR | 338 | #define __ARCH_WANT_OLD_READDIR |
diff --git a/include/asm-ia64/poll.h b/include/asm-ia64/poll.h index bcaf9f140242..c98509d3149e 100644 --- a/include/asm-ia64/poll.h +++ b/include/asm-ia64/poll.h | |||
@@ -1,32 +1 @@ | |||
1 | #ifndef _ASM_IA64_POLL_H | #include <asm-generic/poll.h> | |
2 | #define _ASM_IA64_POLL_H | ||
3 | |||
4 | /* | ||
5 | * poll(2) bit definitions. Based on <asm-i386/poll.h>. | ||
6 | * | ||
7 | * Modified 1998, 1999, 2002 | ||
8 | * David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co | ||
9 | */ | ||
10 | |||
11 | #define POLLIN 0x0001 | ||
12 | #define POLLPRI 0x0002 | ||
13 | #define POLLOUT 0x0004 | ||
14 | #define POLLERR 0x0008 | ||
15 | #define POLLHUP 0x0010 | ||
16 | #define POLLNVAL 0x0020 | ||
17 | |||
18 | #define POLLRDNORM 0x0040 | ||
19 | #define POLLRDBAND 0x0080 | ||
20 | #define POLLWRNORM 0x0100 | ||
21 | #define POLLWRBAND 0x0200 | ||
22 | #define POLLMSG 0x0400 | ||
23 | #define POLLREMOVE 0x1000 | ||
24 | #define POLLRDHUP 0x2000 | ||
25 | |||
26 | struct pollfd { | ||
27 | int fd; | ||
28 | short events; | ||
29 | short revents; | ||
30 | }; | ||
31 | |||
32 | #endif /* _ASM_IA64_POLL_H */ | ||
diff --git a/include/asm-m32r/pgtable-2level.h b/include/asm-m32r/pgtable-2level.h index 750925726a10..bca3475f9595 100644 --- a/include/asm-m32r/pgtable-2level.h +++ b/include/asm-m32r/pgtable-2level.h | |||
@@ -71,8 +71,8 @@ static inline pmd_t *pmd_offset(pgd_t * dir, unsigned long address) | |||
71 | #define pfn_pmd(pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) | 71 | #define pfn_pmd(pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) |
72 | 72 | ||
73 | #define PTE_FILE_MAX_BITS 29 | 73 | #define PTE_FILE_MAX_BITS 29 |
74 | #define pte_to_pgoff(pte) (((pte_val(pte) >> 2) & 0xef) | (((pte_val(pte) >> 10)) << 7)) | 74 | #define pte_to_pgoff(pte) (((pte_val(pte) >> 2) & 0x7f) | (((pte_val(pte) >> 10)) << 7)) |
75 | #define pgoff_to_pte(off) ((pte_t) { (((off) & 0xef) << 2) | (((off) >> 7) << 10) | _PAGE_FILE }) | 75 | #define pgoff_to_pte(off) ((pte_t) { (((off) & 0x7f) << 2) | (((off) >> 7) << 10) | _PAGE_FILE }) |
76 | 76 | ||
77 | #endif /* __KERNEL__ */ | 77 | #endif /* __KERNEL__ */ |
78 | #endif /* _ASM_M32R_PGTABLE_2LEVEL_H */ | 78 | #endif /* _ASM_M32R_PGTABLE_2LEVEL_H */ |
diff --git a/include/asm-m32r/pgtable.h b/include/asm-m32r/pgtable.h index 8b2a2f17e695..6604303fc47c 100644 --- a/include/asm-m32r/pgtable.h +++ b/include/asm-m32r/pgtable.h | |||
@@ -366,7 +366,7 @@ static inline void pmd_set(pmd_t * pmdp, pte_t * ptep) | |||
366 | #define pte_unmap_nested(pte) do { } while (0) | 366 | #define pte_unmap_nested(pte) do { } while (0) |
367 | 367 | ||
368 | /* Encode and de-code a swap entry */ | 368 | /* Encode and de-code a swap entry */ |
369 | #define __swp_type(x) (((x).val >> 2) & 0x3f) | 369 | #define __swp_type(x) (((x).val >> 2) & 0x1f) |
370 | #define __swp_offset(x) ((x).val >> 10) | 370 | #define __swp_offset(x) ((x).val >> 10) |
371 | #define __swp_entry(type, offset) \ | 371 | #define __swp_entry(type, offset) \ |
372 | ((swp_entry_t) { ((type) << 2) | ((offset) << 10) }) | 372 | ((swp_entry_t) { ((type) << 2) | ((offset) << 10) }) |
diff --git a/include/asm-m32r/poll.h b/include/asm-m32r/poll.h index 9e0e700e727c..c98509d3149e 100644 --- a/include/asm-m32r/poll.h +++ b/include/asm-m32r/poll.h | |||
@@ -1,32 +1 @@ | |||
1 | #ifndef _ASM_M32R_POLL_H | #include <asm-generic/poll.h> | |
2 | #define _ASM_M32R_POLL_H | ||
3 | |||
4 | /* | ||
5 | * poll(2) bit definitions. Based on <asm-i386/poll.h>. | ||
6 | * | ||
7 | * Modified 2004 | ||
8 | * Hirokazu Takata <takata at linux-m32r.org> | ||
9 | */ | ||
10 | |||
11 | #define POLLIN 0x0001 | ||
12 | #define POLLPRI 0x0002 | ||
13 | #define POLLOUT 0x0004 | ||
14 | #define POLLERR 0x0008 | ||
15 | #define POLLHUP 0x0010 | ||
16 | #define POLLNVAL 0x0020 | ||
17 | |||
18 | #define POLLRDNORM 0x0040 | ||
19 | #define POLLRDBAND 0x0080 | ||
20 | #define POLLWRNORM 0x0100 | ||
21 | #define POLLWRBAND 0x0200 | ||
22 | #define POLLMSG 0x0400 | ||
23 | #define POLLREMOVE 0x1000 | ||
24 | #define POLLRDHUP 0x2000 | ||
25 | |||
26 | struct pollfd { | ||
27 | int fd; | ||
28 | short events; | ||
29 | short revents; | ||
30 | }; | ||
31 | |||
32 | #endif /* _ASM_M32R_POLL_H */ | ||
diff --git a/include/asm-m32r/system.h b/include/asm-m32r/system.h index f62f5c9abba6..b291b2f72954 100644 --- a/include/asm-m32r/system.h +++ b/include/asm-m32r/system.h | |||
@@ -21,12 +21,22 @@ | |||
21 | * `next' and `prev' should be struct task_struct, but it isn't always defined | 21 | * `next' and `prev' should be struct task_struct, but it isn't always defined |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #if defined(CONFIG_FRAME_POINTER) || \ | ||
25 | !defined(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER) | ||
26 | #define M32R_PUSH_FP " push fp\n" | ||
27 | #define M32R_POP_FP " pop fp\n" | ||
28 | #else | ||
29 | #define M32R_PUSH_FP "" | ||
30 | #define M32R_POP_FP "" | ||
31 | #endif | ||
32 | |||
24 | #define switch_to(prev, next, last) do { \ | 33 | #define switch_to(prev, next, last) do { \ |
25 | __asm__ __volatile__ ( \ | 34 | __asm__ __volatile__ ( \ |
26 | " seth lr, #high(1f) \n" \ | 35 | " seth lr, #high(1f) \n" \ |
27 | " or3 lr, lr, #low(1f) \n" \ | 36 | " or3 lr, lr, #low(1f) \n" \ |
28 | " st lr, @%4 ; store old LR \n" \ | 37 | " st lr, @%4 ; store old LR \n" \ |
29 | " ld lr, @%5 ; load new LR \n" \ | 38 | " ld lr, @%5 ; load new LR \n" \ |
39 | M32R_PUSH_FP \ | ||
30 | " st sp, @%2 ; store old SP \n" \ | 40 | " st sp, @%2 ; store old SP \n" \ |
31 | " ld sp, @%3 ; load new SP \n" \ | 41 | " ld sp, @%3 ; load new SP \n" \ |
32 | " push %1 ; store `prev' on new stack \n" \ | 42 | " push %1 ; store `prev' on new stack \n" \ |
@@ -34,6 +44,7 @@ | |||
34 | " .fillinsn \n" \ | 44 | " .fillinsn \n" \ |
35 | "1: \n" \ | 45 | "1: \n" \ |
36 | " pop %0 ; restore `__last' from new stack \n" \ | 46 | " pop %0 ; restore `__last' from new stack \n" \ |
47 | M32R_POP_FP \ | ||
37 | : "=r" (last) \ | 48 | : "=r" (last) \ |
38 | : "0" (prev), \ | 49 | : "0" (prev), \ |
39 | "r" (&(prev->thread.sp)), "r" (&(next->thread.sp)), \ | 50 | "r" (&(prev->thread.sp)), "r" (&(next->thread.sp)), \ |
diff --git a/include/asm-m68k/poll.h b/include/asm-m68k/poll.h index 0fb8843647f8..f080fcdb61bf 100644 --- a/include/asm-m68k/poll.h +++ b/include/asm-m68k/poll.h | |||
@@ -1,24 +1,9 @@ | |||
1 | #ifndef __m68k_POLL_H | 1 | #ifndef __m68k_POLL_H |
2 | #define __m68k_POLL_H | 2 | #define __m68k_POLL_H |
3 | 3 | ||
4 | #define POLLIN 1 | ||
5 | #define POLLPRI 2 | ||
6 | #define POLLOUT 4 | ||
7 | #define POLLERR 8 | ||
8 | #define POLLHUP 16 | ||
9 | #define POLLNVAL 32 | ||
10 | #define POLLRDNORM 64 | ||
11 | #define POLLWRNORM POLLOUT | 4 | #define POLLWRNORM POLLOUT |
12 | #define POLLRDBAND 128 | ||
13 | #define POLLWRBAND 256 | 5 | #define POLLWRBAND 256 |
14 | #define POLLMSG 0x0400 | ||
15 | #define POLLREMOVE 0x1000 | ||
16 | #define POLLRDHUP 0x2000 | ||
17 | 6 | ||
18 | struct pollfd { | 7 | #include <asm-generic/poll.h> |
19 | int fd; | ||
20 | short events; | ||
21 | short revents; | ||
22 | }; | ||
23 | 8 | ||
24 | #endif | 9 | #endif |
diff --git a/include/asm-mips/poll.h b/include/asm-mips/poll.h index 70881f8c5c50..47b952080431 100644 --- a/include/asm-mips/poll.h +++ b/include/asm-mips/poll.h | |||
@@ -1,28 +1,9 @@ | |||
1 | #ifndef __ASM_POLL_H | 1 | #ifndef __ASM_POLL_H |
2 | #define __ASM_POLL_H | 2 | #define __ASM_POLL_H |
3 | 3 | ||
4 | #define POLLIN 0x0001 | ||
5 | #define POLLPRI 0x0002 | ||
6 | #define POLLOUT 0x0004 | ||
7 | |||
8 | #define POLLERR 0x0008 | ||
9 | #define POLLHUP 0x0010 | ||
10 | #define POLLNVAL 0x0020 | ||
11 | |||
12 | #define POLLRDNORM 0x0040 | ||
13 | #define POLLRDBAND 0x0080 | ||
14 | #define POLLWRNORM POLLOUT | 4 | #define POLLWRNORM POLLOUT |
15 | #define POLLWRBAND 0x0100 | 5 | #define POLLWRBAND 0x0100 |
16 | 6 | ||
17 | /* These seem to be more or less nonstandard ... */ | 7 | #include <asm-generic/poll.h> |
18 | #define POLLMSG 0x0400 | ||
19 | #define POLLREMOVE 0x1000 | ||
20 | #define POLLRDHUP 0x2000 | ||
21 | |||
22 | struct pollfd { | ||
23 | int fd; | ||
24 | short events; | ||
25 | short revents; | ||
26 | }; | ||
27 | 8 | ||
28 | #endif /* __ASM_POLL_H */ | 9 | #endif /* __ASM_POLL_H */ |
diff --git a/include/asm-parisc/poll.h b/include/asm-parisc/poll.h index 20e4d03c74cb..c98509d3149e 100644 --- a/include/asm-parisc/poll.h +++ b/include/asm-parisc/poll.h | |||
@@ -1,27 +1 @@ | |||
1 | #ifndef __PARISC_POLL_H | #include <asm-generic/poll.h> | |
2 | #define __PARISC_POLL_H | ||
3 | |||
4 | /* These are specified by iBCS2 */ | ||
5 | #define POLLIN 0x0001 | ||
6 | #define POLLPRI 0x0002 | ||
7 | #define POLLOUT 0x0004 | ||
8 | #define POLLERR 0x0008 | ||
9 | #define POLLHUP 0x0010 | ||
10 | #define POLLNVAL 0x0020 | ||
11 | |||
12 | /* The rest seem to be more-or-less nonstandard. Check them! */ | ||
13 | #define POLLRDNORM 0x0040 | ||
14 | #define POLLRDBAND 0x0080 | ||
15 | #define POLLWRNORM 0x0100 | ||
16 | #define POLLWRBAND 0x0200 | ||
17 | #define POLLMSG 0x0400 | ||
18 | #define POLLREMOVE 0x1000 | ||
19 | #define POLLRDHUP 0x2000 | ||
20 | |||
21 | struct pollfd { | ||
22 | int fd; | ||
23 | short events; | ||
24 | short revents; | ||
25 | }; | ||
26 | |||
27 | #endif | ||
diff --git a/include/asm-powerpc/hw_irq.h b/include/asm-powerpc/hw_irq.h index 9e4dd98eb220..a7b60bf639e0 100644 --- a/include/asm-powerpc/hw_irq.h +++ b/include/asm-powerpc/hw_irq.h | |||
@@ -48,8 +48,15 @@ extern void iseries_handle_interrupts(void); | |||
48 | 48 | ||
49 | #define irqs_disabled() (local_get_flags() == 0) | 49 | #define irqs_disabled() (local_get_flags() == 0) |
50 | 50 | ||
51 | #define hard_irq_enable() __mtmsrd(mfmsr() | MSR_EE, 1) | 51 | #define __hard_irq_enable() __mtmsrd(mfmsr() | MSR_EE, 1) |
52 | #define hard_irq_disable() __mtmsrd(mfmsr() & ~MSR_EE, 1) | 52 | #define __hard_irq_disable() __mtmsrd(mfmsr() & ~MSR_EE, 1) |
53 | |||
54 | #define hard_irq_disable() \ | ||
55 | do { \ | ||
56 | __hard_irq_disable(); \ | ||
57 | get_paca()->soft_enabled = 0; \ | ||
58 | get_paca()->hard_enabled = 0; \ | ||
59 | } while(0) | ||
53 | 60 | ||
54 | #else | 61 | #else |
55 | 62 | ||
diff --git a/include/asm-powerpc/poll.h b/include/asm-powerpc/poll.h index 9c7d12631033..c98509d3149e 100644 --- a/include/asm-powerpc/poll.h +++ b/include/asm-powerpc/poll.h | |||
@@ -1,24 +1 @@ | |||
1 | #ifndef _ASM_POWERPC_POLL_H | #include <asm-generic/poll.h> | |
2 | #define _ASM_POWERPC_POLL_H | ||
3 | |||
4 | #define POLLIN 0x0001 | ||
5 | #define POLLPRI 0x0002 | ||
6 | #define POLLOUT 0x0004 | ||
7 | #define POLLERR 0x0008 | ||
8 | #define POLLHUP 0x0010 | ||
9 | #define POLLNVAL 0x0020 | ||
10 | #define POLLRDNORM 0x0040 | ||
11 | #define POLLRDBAND 0x0080 | ||
12 | #define POLLWRNORM 0x0100 | ||
13 | #define POLLWRBAND 0x0200 | ||
14 | #define POLLMSG 0x0400 | ||
15 | #define POLLREMOVE 0x1000 | ||
16 | #define POLLRDHUP 0x2000 | ||
17 | |||
18 | struct pollfd { | ||
19 | int fd; | ||
20 | short events; | ||
21 | short revents; | ||
22 | }; | ||
23 | |||
24 | #endif /* _ASM_POWERPC_POLL_H */ | ||
diff --git a/include/asm-s390/poll.h b/include/asm-s390/poll.h index 6f7f65ac7d27..c98509d3149e 100644 --- a/include/asm-s390/poll.h +++ b/include/asm-s390/poll.h | |||
@@ -1,35 +1 @@ | |||
1 | /* | #include <asm-generic/poll.h> | |
2 | * include/asm-s390/poll.h | ||
3 | * | ||
4 | * S390 version | ||
5 | * | ||
6 | * Derived from "include/asm-i386/poll.h" | ||
7 | */ | ||
8 | |||
9 | #ifndef __S390_POLL_H | ||
10 | #define __S390_POLL_H | ||
11 | |||
12 | /* These are specified by iBCS2 */ | ||
13 | #define POLLIN 0x0001 | ||
14 | #define POLLPRI 0x0002 | ||
15 | #define POLLOUT 0x0004 | ||
16 | #define POLLERR 0x0008 | ||
17 | #define POLLHUP 0x0010 | ||
18 | #define POLLNVAL 0x0020 | ||
19 | |||
20 | /* The rest seem to be more-or-less nonstandard. Check them! */ | ||
21 | #define POLLRDNORM 0x0040 | ||
22 | #define POLLRDBAND 0x0080 | ||
23 | #define POLLWRNORM 0x0100 | ||
24 | #define POLLWRBAND 0x0200 | ||
25 | #define POLLMSG 0x0400 | ||
26 | #define POLLREMOVE 0x1000 | ||
27 | #define POLLRDHUP 0x2000 | ||
28 | |||
29 | struct pollfd { | ||
30 | int fd; | ||
31 | short events; | ||
32 | short revents; | ||
33 | }; | ||
34 | |||
35 | #endif | ||
diff --git a/include/asm-sh/poll.h b/include/asm-sh/poll.h index dbca9b32f4a6..c98509d3149e 100644 --- a/include/asm-sh/poll.h +++ b/include/asm-sh/poll.h | |||
@@ -1,27 +1 @@ | |||
1 | #ifndef __ASM_SH_POLL_H | #include <asm-generic/poll.h> | |
2 | #define __ASM_SH_POLL_H | ||
3 | |||
4 | /* These are specified by iBCS2 */ | ||
5 | #define POLLIN 0x0001 | ||
6 | #define POLLPRI 0x0002 | ||
7 | #define POLLOUT 0x0004 | ||
8 | #define POLLERR 0x0008 | ||
9 | #define POLLHUP 0x0010 | ||
10 | #define POLLNVAL 0x0020 | ||
11 | |||
12 | /* The rest seem to be more-or-less nonstandard. Check them! */ | ||
13 | #define POLLRDNORM 0x0040 | ||
14 | #define POLLRDBAND 0x0080 | ||
15 | #define POLLWRNORM 0x0100 | ||
16 | #define POLLWRBAND 0x0200 | ||
17 | #define POLLMSG 0x0400 | ||
18 | #define POLLREMOVE 0x1000 | ||
19 | #define POLLRDHUP 0x2000 | ||
20 | |||
21 | struct pollfd { | ||
22 | int fd; | ||
23 | short events; | ||
24 | short revents; | ||
25 | }; | ||
26 | |||
27 | #endif /* __ASM_SH_POLL_H */ | ||
diff --git a/include/asm-sh64/poll.h b/include/asm-sh64/poll.h index 3a6cbad08d28..ca2950267c53 100644 --- a/include/asm-sh64/poll.h +++ b/include/asm-sh64/poll.h | |||
@@ -1,37 +1,8 @@ | |||
1 | #ifndef __ASM_SH64_POLL_H | 1 | #ifndef __ASM_SH64_POLL_H |
2 | #define __ASM_SH64_POLL_H | 2 | #define __ASM_SH64_POLL_H |
3 | 3 | ||
4 | /* | 4 | #include <asm-generic/poll.h> |
5 | * This file is subject to the terms and conditions of the GNU General Public | ||
6 | * License. See the file "COPYING" in the main directory of this archive | ||
7 | * for more details. | ||
8 | * | ||
9 | * include/asm-sh64/poll.h | ||
10 | * | ||
11 | * Copyright (C) 2000, 2001 Paolo Alberelli | ||
12 | * | ||
13 | */ | ||
14 | 5 | ||
15 | /* These are specified by iBCS2 */ | 6 | #undef POLLREMOVE |
16 | #define POLLIN 0x0001 | ||
17 | #define POLLPRI 0x0002 | ||
18 | #define POLLOUT 0x0004 | ||
19 | #define POLLERR 0x0008 | ||
20 | #define POLLHUP 0x0010 | ||
21 | #define POLLNVAL 0x0020 | ||
22 | |||
23 | /* The rest seem to be more-or-less nonstandard. Check them! */ | ||
24 | #define POLLRDNORM 0x0040 | ||
25 | #define POLLRDBAND 0x0080 | ||
26 | #define POLLWRNORM 0x0100 | ||
27 | #define POLLWRBAND 0x0200 | ||
28 | #define POLLMSG 0x0400 | ||
29 | #define POLLRDHUP 0x2000 | ||
30 | |||
31 | struct pollfd { | ||
32 | int fd; | ||
33 | short events; | ||
34 | short revents; | ||
35 | }; | ||
36 | 7 | ||
37 | #endif /* __ASM_SH64_POLL_H */ | 8 | #endif /* __ASM_SH64_POLL_H */ |
diff --git a/include/asm-sparc/poll.h b/include/asm-sparc/poll.h index 26f13fb35497..091d3ad2e830 100644 --- a/include/asm-sparc/poll.h +++ b/include/asm-sparc/poll.h | |||
@@ -1,24 +1,12 @@ | |||
1 | #ifndef __SPARC_POLL_H | 1 | #ifndef __SPARC_POLL_H |
2 | #define __SPARC_POLL_H | 2 | #define __SPARC_POLL_H |
3 | 3 | ||
4 | #define POLLIN 1 | ||
5 | #define POLLPRI 2 | ||
6 | #define POLLOUT 4 | ||
7 | #define POLLERR 8 | ||
8 | #define POLLHUP 16 | ||
9 | #define POLLNVAL 32 | ||
10 | #define POLLRDNORM 64 | ||
11 | #define POLLWRNORM POLLOUT | 4 | #define POLLWRNORM POLLOUT |
12 | #define POLLRDBAND 128 | ||
13 | #define POLLWRBAND 256 | 5 | #define POLLWRBAND 256 |
14 | #define POLLMSG 512 | 6 | #define POLLMSG 512 |
15 | #define POLLREMOVE 1024 | 7 | #define POLLREMOVE 1024 |
16 | #define POLLRDHUP 2048 | 8 | #define POLLRDHUP 2048 |
17 | 9 | ||
18 | struct pollfd { | 10 | #include <asm-generic/poll.h> |
19 | int fd; | ||
20 | short events; | ||
21 | short revents; | ||
22 | }; | ||
23 | 11 | ||
24 | #endif | 12 | #endif |
diff --git a/include/asm-sparc64/poll.h b/include/asm-sparc64/poll.h index ab6b0d1bb4ad..ebeeb3816c40 100644 --- a/include/asm-sparc64/poll.h +++ b/include/asm-sparc64/poll.h | |||
@@ -1,24 +1,12 @@ | |||
1 | #ifndef __SPARC64_POLL_H | 1 | #ifndef __SPARC64_POLL_H |
2 | #define __SPARC64_POLL_H | 2 | #define __SPARC64_POLL_H |
3 | 3 | ||
4 | #define POLLIN 1 | ||
5 | #define POLLPRI 2 | ||
6 | #define POLLOUT 4 | ||
7 | #define POLLERR 8 | ||
8 | #define POLLHUP 16 | ||
9 | #define POLLNVAL 32 | ||
10 | #define POLLRDNORM 64 | ||
11 | #define POLLWRNORM POLLOUT | 4 | #define POLLWRNORM POLLOUT |
12 | #define POLLRDBAND 128 | ||
13 | #define POLLWRBAND 256 | 5 | #define POLLWRBAND 256 |
14 | #define POLLMSG 512 | 6 | #define POLLMSG 512 |
15 | #define POLLREMOVE 1024 | 7 | #define POLLREMOVE 1024 |
16 | #define POLLRDHUP 2048 | 8 | #define POLLRDHUP 2048 |
17 | 9 | ||
18 | struct pollfd { | 10 | #include <asm-generic/poll.h> |
19 | int fd; | ||
20 | short events; | ||
21 | short revents; | ||
22 | }; | ||
23 | 11 | ||
24 | #endif | 12 | #endif |
diff --git a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h index 261e2f4528f6..18a13ba74605 100644 --- a/include/asm-um/thread_info.h +++ b/include/asm-um/thread_info.h | |||
@@ -22,6 +22,7 @@ struct thread_info { | |||
22 | 0-0xBFFFFFFF for user | 22 | 0-0xBFFFFFFF for user |
23 | 0-0xFFFFFFFF for kernel */ | 23 | 0-0xFFFFFFFF for kernel */ |
24 | struct restart_block restart_block; | 24 | struct restart_block restart_block; |
25 | struct thread_info *real_thread; /* Points to non-IRQ stack */ | ||
25 | }; | 26 | }; |
26 | 27 | ||
27 | #define INIT_THREAD_INFO(tsk) \ | 28 | #define INIT_THREAD_INFO(tsk) \ |
@@ -35,6 +36,7 @@ struct thread_info { | |||
35 | .restart_block = { \ | 36 | .restart_block = { \ |
36 | .fn = do_no_restart_syscall, \ | 37 | .fn = do_no_restart_syscall, \ |
37 | }, \ | 38 | }, \ |
39 | .real_thread = NULL, \ | ||
38 | } | 40 | } |
39 | 41 | ||
40 | #define init_thread_info (init_thread_union.thread_info) | 42 | #define init_thread_info (init_thread_union.thread_info) |
diff --git a/include/asm-v850/poll.h b/include/asm-v850/poll.h index c10176c2c28f..803cad0b9b59 100644 --- a/include/asm-v850/poll.h +++ b/include/asm-v850/poll.h | |||
@@ -1,24 +1,9 @@ | |||
1 | #ifndef __V850_POLL_H__ | 1 | #ifndef __V850_POLL_H__ |
2 | #define __V850_POLL_H__ | 2 | #define __V850_POLL_H__ |
3 | 3 | ||
4 | #define POLLIN 0x0001 | ||
5 | #define POLLPRI 0x0002 | ||
6 | #define POLLOUT 0x0004 | ||
7 | #define POLLERR 0x0008 | ||
8 | #define POLLHUP 0x0010 | ||
9 | #define POLLNVAL 0x0020 | ||
10 | #define POLLRDNORM 0x0040 | ||
11 | #define POLLWRNORM POLLOUT | 4 | #define POLLWRNORM POLLOUT |
12 | #define POLLRDBAND 0x0080 | ||
13 | #define POLLWRBAND 0x0100 | 5 | #define POLLWRBAND 0x0100 |
14 | #define POLLMSG 0x0400 | ||
15 | #define POLLREMOVE 0x1000 | ||
16 | #define POLLRDHUP 0x2000 | ||
17 | 6 | ||
18 | struct pollfd { | 7 | #include <asm-generic/poll.h> |
19 | int fd; | ||
20 | short events; | ||
21 | short revents; | ||
22 | }; | ||
23 | 8 | ||
24 | #endif /* __V850_POLL_H__ */ | 9 | #endif /* __V850_POLL_H__ */ |
diff --git a/include/asm-x86_64/alternative.h b/include/asm-x86_64/alternative.h index a09fe85c268e..a09427640764 100644 --- a/include/asm-x86_64/alternative.h +++ b/include/asm-x86_64/alternative.h | |||
@@ -103,6 +103,12 @@ static inline void alternatives_smp_switch(int smp) {} | |||
103 | ".previous" : output : [feat] "i" (feature), ##input) | 103 | ".previous" : output : [feat] "i" (feature), ##input) |
104 | 104 | ||
105 | /* | 105 | /* |
106 | * use this macro(s) if you need more than one output parameter | ||
107 | * in alternative_io | ||
108 | */ | ||
109 | #define ASM_OUTPUT2(a, b) a, b | ||
110 | |||
111 | /* | ||
106 | * Alternative inline assembly for SMP. | 112 | * Alternative inline assembly for SMP. |
107 | * | 113 | * |
108 | * The LOCK_PREFIX macro defined here replaces the LOCK and | 114 | * The LOCK_PREFIX macro defined here replaces the LOCK and |
diff --git a/include/asm-x86_64/page.h b/include/asm-x86_64/page.h index dee632fa457d..e327c830da0c 100644 --- a/include/asm-x86_64/page.h +++ b/include/asm-x86_64/page.h | |||
@@ -80,6 +80,15 @@ extern unsigned long phys_base; | |||
80 | #define __PHYSICAL_START CONFIG_PHYSICAL_START | 80 | #define __PHYSICAL_START CONFIG_PHYSICAL_START |
81 | #define __KERNEL_ALIGN 0x200000 | 81 | #define __KERNEL_ALIGN 0x200000 |
82 | 82 | ||
83 | /* | ||
84 | * Make sure kernel is aligned to 2MB address. Catching it at compile | ||
85 | * time is better. Change your config file and compile the kernel | ||
86 | * for a 2MB aligned address (CONFIG_PHYSICAL_START) | ||
87 | */ | ||
88 | #if (CONFIG_PHYSICAL_START % __KERNEL_ALIGN) != 0 | ||
89 | #error "CONFIG_PHYSICAL_START must be a multiple of 2MB" | ||
90 | #endif | ||
91 | |||
83 | #define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START) | 92 | #define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START) |
84 | #define __START_KERNEL_map _AC(0xffffffff80000000, UL) | 93 | #define __START_KERNEL_map _AC(0xffffffff80000000, UL) |
85 | #define __PAGE_OFFSET _AC(0xffff810000000000, UL) | 94 | #define __PAGE_OFFSET _AC(0xffff810000000000, UL) |
diff --git a/include/asm-x86_64/poll.h b/include/asm-x86_64/poll.h index c0475a9d8bb8..c98509d3149e 100644 --- a/include/asm-x86_64/poll.h +++ b/include/asm-x86_64/poll.h | |||
@@ -1,27 +1 @@ | |||
1 | #ifndef __x86_64_POLL_H | #include <asm-generic/poll.h> | |
2 | #define __x86_64_POLL_H | ||
3 | |||
4 | /* These are specified by iBCS2 */ | ||
5 | #define POLLIN 0x0001 | ||
6 | #define POLLPRI 0x0002 | ||
7 | #define POLLOUT 0x0004 | ||
8 | #define POLLERR 0x0008 | ||
9 | #define POLLHUP 0x0010 | ||
10 | #define POLLNVAL 0x0020 | ||
11 | |||
12 | /* The rest seem to be more-or-less nonstandard. Check them! */ | ||
13 | #define POLLRDNORM 0x0040 | ||
14 | #define POLLRDBAND 0x0080 | ||
15 | #define POLLWRNORM 0x0100 | ||
16 | #define POLLWRBAND 0x0200 | ||
17 | #define POLLMSG 0x0400 | ||
18 | #define POLLREMOVE 0x1000 | ||
19 | #define POLLRDHUP 0x2000 | ||
20 | |||
21 | struct pollfd { | ||
22 | int fd; | ||
23 | short events; | ||
24 | short revents; | ||
25 | }; | ||
26 | |||
27 | #endif | ||
diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h index 595703949df3..ae1ed05f2814 100644 --- a/include/asm-x86_64/unistd.h +++ b/include/asm-x86_64/unistd.h | |||
@@ -621,6 +621,15 @@ __SYSCALL(__NR_vmsplice, sys_vmsplice) | |||
621 | __SYSCALL(__NR_move_pages, sys_move_pages) | 621 | __SYSCALL(__NR_move_pages, sys_move_pages) |
622 | #define __NR_utimensat 280 | 622 | #define __NR_utimensat 280 |
623 | __SYSCALL(__NR_utimensat, sys_utimensat) | 623 | __SYSCALL(__NR_utimensat, sys_utimensat) |
624 | #define __IGNORE_getcpu /* implemented as a vsyscall */ | ||
625 | #define __NR_epoll_pwait 281 | ||
626 | __SYSCALL(__NR_epoll_pwait, sys_epoll_pwait) | ||
627 | #define __NR_signalfd 282 | ||
628 | __SYSCALL(__NR_signalfd, sys_signalfd) | ||
629 | #define __NR_timerfd 282 | ||
630 | __SYSCALL(__NR_timerfd, sys_timerfd) | ||
631 | #define __NR_eventfd 283 | ||
632 | __SYSCALL(__NR_eventfd, sys_eventfd) | ||
624 | 633 | ||
625 | #ifndef __NO_STUBS | 634 | #ifndef __NO_STUBS |
626 | #define __ARCH_WANT_OLD_READDIR | 635 | #define __ARCH_WANT_OLD_READDIR |
diff --git a/include/asm-xtensa/poll.h b/include/asm-xtensa/poll.h index 6fd94773e866..9d2d5993f068 100644 --- a/include/asm-xtensa/poll.h +++ b/include/asm-xtensa/poll.h | |||
@@ -11,28 +11,10 @@ | |||
11 | #ifndef _XTENSA_POLL_H | 11 | #ifndef _XTENSA_POLL_H |
12 | #define _XTENSA_POLL_H | 12 | #define _XTENSA_POLL_H |
13 | 13 | ||
14 | |||
15 | #define POLLIN 0x0001 | ||
16 | #define POLLPRI 0x0002 | ||
17 | #define POLLOUT 0x0004 | ||
18 | |||
19 | #define POLLERR 0x0008 | ||
20 | #define POLLHUP 0x0010 | ||
21 | #define POLLNVAL 0x0020 | ||
22 | |||
23 | #define POLLRDNORM 0x0040 | ||
24 | #define POLLRDBAND 0x0080 | ||
25 | #define POLLWRNORM POLLOUT | 14 | #define POLLWRNORM POLLOUT |
26 | #define POLLWRBAND 0x0100 | 15 | #define POLLWRBAND 0x0100 |
27 | |||
28 | #define POLLMSG 0x0400 | ||
29 | #define POLLREMOVE 0x0800 | 16 | #define POLLREMOVE 0x0800 |
30 | #define POLLRDHUP 0x2000 | ||
31 | 17 | ||
32 | struct pollfd { | 18 | #include <asm-generic/poll.h> |
33 | int fd; | ||
34 | short events; | ||
35 | short revents; | ||
36 | }; | ||
37 | 19 | ||
38 | #endif /* _XTENSA_POLL_H */ | 20 | #endif /* _XTENSA_POLL_H */ |
diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 94cc04a143f2..bcd01f269f60 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild | |||
@@ -140,7 +140,6 @@ header-y += snmp.h | |||
140 | header-y += sockios.h | 140 | header-y += sockios.h |
141 | header-y += som.h | 141 | header-y += som.h |
142 | header-y += sound.h | 142 | header-y += sound.h |
143 | header-y += synclink.h | ||
144 | header-y += taskstats.h | 143 | header-y += taskstats.h |
145 | header-y += telephony.h | 144 | header-y += telephony.h |
146 | header-y += termios.h | 145 | header-y += termios.h |
@@ -191,6 +190,7 @@ unifdef-y += errno.h | |||
191 | unifdef-y += errqueue.h | 190 | unifdef-y += errqueue.h |
192 | unifdef-y += ethtool.h | 191 | unifdef-y += ethtool.h |
193 | unifdef-y += eventpoll.h | 192 | unifdef-y += eventpoll.h |
193 | unifdef-y += signalfd.h | ||
194 | unifdef-y += ext2_fs.h | 194 | unifdef-y += ext2_fs.h |
195 | unifdef-y += ext3_fs.h | 195 | unifdef-y += ext3_fs.h |
196 | unifdef-y += fb.h | 196 | unifdef-y += fb.h |
@@ -320,6 +320,7 @@ unifdef-y += sonypi.h | |||
320 | unifdef-y += soundcard.h | 320 | unifdef-y += soundcard.h |
321 | unifdef-y += stat.h | 321 | unifdef-y += stat.h |
322 | unifdef-y += stddef.h | 322 | unifdef-y += stddef.h |
323 | unifdef-y += synclink.h | ||
323 | unifdef-y += sysctl.h | 324 | unifdef-y += sysctl.h |
324 | unifdef-y += tcp.h | 325 | unifdef-y += tcp.h |
325 | unifdef-y += time.h | 326 | unifdef-y += time.h |
diff --git a/include/linux/aio.h b/include/linux/aio.h index 43dc2ebfaa0e..b903fc02bdb7 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h | |||
@@ -119,6 +119,12 @@ struct kiocb { | |||
119 | 119 | ||
120 | struct list_head ki_list; /* the aio core uses this | 120 | struct list_head ki_list; /* the aio core uses this |
121 | * for cancellation */ | 121 | * for cancellation */ |
122 | |||
123 | /* | ||
124 | * If the aio_resfd field of the userspace iocb is not zero, | ||
125 | * this is the underlying file* to deliver event to. | ||
126 | */ | ||
127 | struct file *ki_eventfd; | ||
122 | }; | 128 | }; |
123 | 129 | ||
124 | #define is_sync_kiocb(iocb) ((iocb)->ki_key == KIOCB_SYNC_KEY) | 130 | #define is_sync_kiocb(iocb) ((iocb)->ki_key == KIOCB_SYNC_KEY) |
diff --git a/include/linux/aio_abi.h b/include/linux/aio_abi.h index e3ca0a485cc6..9e0172931315 100644 --- a/include/linux/aio_abi.h +++ b/include/linux/aio_abi.h | |||
@@ -45,6 +45,14 @@ enum { | |||
45 | IOCB_CMD_PWRITEV = 8, | 45 | IOCB_CMD_PWRITEV = 8, |
46 | }; | 46 | }; |
47 | 47 | ||
48 | /* | ||
49 | * Valid flags for the "aio_flags" member of the "struct iocb". | ||
50 | * | ||
51 | * IOCB_FLAG_RESFD - Set if the "aio_resfd" member of the "struct iocb" | ||
52 | * is valid. | ||
53 | */ | ||
54 | #define IOCB_FLAG_RESFD (1 << 0) | ||
55 | |||
48 | /* read() from /dev/aio returns these structures. */ | 56 | /* read() from /dev/aio returns these structures. */ |
49 | struct io_event { | 57 | struct io_event { |
50 | __u64 data; /* the data field from the iocb */ | 58 | __u64 data; /* the data field from the iocb */ |
@@ -84,7 +92,15 @@ struct iocb { | |||
84 | 92 | ||
85 | /* extra parameters */ | 93 | /* extra parameters */ |
86 | __u64 aio_reserved2; /* TODO: use this for a (struct sigevent *) */ | 94 | __u64 aio_reserved2; /* TODO: use this for a (struct sigevent *) */ |
87 | __u64 aio_reserved3; | 95 | |
96 | /* flags for the "struct iocb" */ | ||
97 | __u32 aio_flags; | ||
98 | |||
99 | /* | ||
100 | * if the IOCB_FLAG_RESFD flag of "aio_flags" is set, this is an | ||
101 | * eventfd to signal AIO readiness to | ||
102 | */ | ||
103 | __u32 aio_resfd; | ||
88 | }; /* 64 bytes */ | 104 | }; /* 64 bytes */ |
89 | 105 | ||
90 | #undef IFBIG | 106 | #undef IFBIG |
diff --git a/include/linux/anon_inodes.h b/include/linux/anon_inodes.h new file mode 100644 index 000000000000..b2e1ba325b9a --- /dev/null +++ b/include/linux/anon_inodes.h | |||
@@ -0,0 +1,16 @@ | |||
1 | /* | ||
2 | * include/linux/anon_inodes.h | ||
3 | * | ||
4 | * Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org> | ||
5 | * | ||
6 | */ | ||
7 | |||
8 | #ifndef _LINUX_ANON_INODES_H | ||
9 | #define _LINUX_ANON_INODES_H | ||
10 | |||
11 | int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile, | ||
12 | const char *name, const struct file_operations *fops, | ||
13 | void *priv); | ||
14 | |||
15 | #endif /* _LINUX_ANON_INODES_H */ | ||
16 | |||
diff --git a/include/linux/compat.h b/include/linux/compat.h index 70a157a130bb..636502c02734 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h | |||
@@ -225,6 +225,11 @@ static inline int compat_timespec_compare(struct compat_timespec *lhs, | |||
225 | return lhs->tv_nsec - rhs->tv_nsec; | 225 | return lhs->tv_nsec - rhs->tv_nsec; |
226 | } | 226 | } |
227 | 227 | ||
228 | extern int get_compat_itimerspec(struct itimerspec *dst, | ||
229 | const struct compat_itimerspec __user *src); | ||
230 | extern int put_compat_itimerspec(struct compat_itimerspec __user *dst, | ||
231 | const struct itimerspec *src); | ||
232 | |||
228 | asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp); | 233 | asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp); |
229 | 234 | ||
230 | extern int compat_printk(const char *fmt, ...); | 235 | extern int compat_printk(const char *fmt, ...); |
diff --git a/include/linux/eventfd.h b/include/linux/eventfd.h new file mode 100644 index 000000000000..0d6ecc60b94d --- /dev/null +++ b/include/linux/eventfd.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * include/linux/eventfd.h | ||
3 | * | ||
4 | * Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org> | ||
5 | * | ||
6 | */ | ||
7 | |||
8 | #ifndef _LINUX_EVENTFD_H | ||
9 | #define _LINUX_EVENTFD_H | ||
10 | |||
11 | |||
12 | #ifdef __KERNEL__ | ||
13 | |||
14 | #ifdef CONFIG_EVENTFD | ||
15 | |||
16 | struct file *eventfd_fget(int fd); | ||
17 | int eventfd_signal(struct file *file, int n); | ||
18 | |||
19 | #else /* CONFIG_EVENTFD */ | ||
20 | |||
21 | #define eventfd_fget(fd) ERR_PTR(-ENOSYS) | ||
22 | #define eventfd_signal(f, n) 0 | ||
23 | |||
24 | #endif /* CONFIG_EVENTFD */ | ||
25 | |||
26 | #endif /* __KERNEL__ */ | ||
27 | |||
28 | #endif /* _LINUX_EVENTFD_H */ | ||
29 | |||
diff --git a/include/linux/hid.h b/include/linux/hid.h index 37076b116ed0..827ee748fd4c 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h | |||
@@ -275,6 +275,7 @@ struct hid_item { | |||
275 | #define HID_QUIRK_LOGITECH_DESCRIPTOR 0x00100000 | 275 | #define HID_QUIRK_LOGITECH_DESCRIPTOR 0x00100000 |
276 | #define HID_QUIRK_DUPLICATE_USAGES 0x00200000 | 276 | #define HID_QUIRK_DUPLICATE_USAGES 0x00200000 |
277 | #define HID_QUIRK_RESET_LEDS 0x00400000 | 277 | #define HID_QUIRK_RESET_LEDS 0x00400000 |
278 | #define HID_QUIRK_SWAPPED_MIN_MAX 0x00800000 | ||
278 | 279 | ||
279 | /* | 280 | /* |
280 | * This is the global environment of the parser. This information is | 281 | * This is the global environment of the parser. This information is |
diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 45170b2fa253..276ccaa2670c 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h | |||
@@ -65,9 +65,9 @@ | |||
65 | .posix_timers = LIST_HEAD_INIT(sig.posix_timers), \ | 65 | .posix_timers = LIST_HEAD_INIT(sig.posix_timers), \ |
66 | .cpu_timers = INIT_CPU_TIMERS(sig.cpu_timers), \ | 66 | .cpu_timers = INIT_CPU_TIMERS(sig.cpu_timers), \ |
67 | .rlim = INIT_RLIMITS, \ | 67 | .rlim = INIT_RLIMITS, \ |
68 | .pgrp = 1, \ | 68 | .pgrp = 0, \ |
69 | .tty_old_pgrp = NULL, \ | 69 | .tty_old_pgrp = NULL, \ |
70 | { .__session = 1}, \ | 70 | { .__session = 0}, \ |
71 | } | 71 | } |
72 | 72 | ||
73 | extern struct nsproxy init_nsproxy; | 73 | extern struct nsproxy init_nsproxy; |
@@ -84,10 +84,33 @@ extern struct nsproxy init_nsproxy; | |||
84 | .count = ATOMIC_INIT(1), \ | 84 | .count = ATOMIC_INIT(1), \ |
85 | .action = { { { .sa_handler = NULL, } }, }, \ | 85 | .action = { { { .sa_handler = NULL, } }, }, \ |
86 | .siglock = __SPIN_LOCK_UNLOCKED(sighand.siglock), \ | 86 | .siglock = __SPIN_LOCK_UNLOCKED(sighand.siglock), \ |
87 | .signalfd_list = LIST_HEAD_INIT(sighand.signalfd_list), \ | ||
87 | } | 88 | } |
88 | 89 | ||
89 | extern struct group_info init_groups; | 90 | extern struct group_info init_groups; |
90 | 91 | ||
92 | #define INIT_STRUCT_PID { \ | ||
93 | .count = ATOMIC_INIT(1), \ | ||
94 | .nr = 0, \ | ||
95 | /* Don't put this struct pid in pid_hash */ \ | ||
96 | .pid_chain = { .next = NULL, .pprev = NULL }, \ | ||
97 | .tasks = { \ | ||
98 | { .first = &init_task.pids[PIDTYPE_PID].node }, \ | ||
99 | { .first = &init_task.pids[PIDTYPE_PGID].node }, \ | ||
100 | { .first = &init_task.pids[PIDTYPE_SID].node }, \ | ||
101 | }, \ | ||
102 | .rcu = RCU_HEAD_INIT, \ | ||
103 | } | ||
104 | |||
105 | #define INIT_PID_LINK(type) \ | ||
106 | { \ | ||
107 | .node = { \ | ||
108 | .next = NULL, \ | ||
109 | .pprev = &init_struct_pid.tasks[type].first, \ | ||
110 | }, \ | ||
111 | .pid = &init_struct_pid, \ | ||
112 | } | ||
113 | |||
91 | /* | 114 | /* |
92 | * INIT_TASK is used to set up the first task table, touch at | 115 | * INIT_TASK is used to set up the first task table, touch at |
93 | * your own risk!. Base=0, limit=0x1fffff (=2MB) | 116 | * your own risk!. Base=0, limit=0x1fffff (=2MB) |
@@ -139,6 +162,11 @@ extern struct group_info init_groups; | |||
139 | .cpu_timers = INIT_CPU_TIMERS(tsk.cpu_timers), \ | 162 | .cpu_timers = INIT_CPU_TIMERS(tsk.cpu_timers), \ |
140 | .fs_excl = ATOMIC_INIT(0), \ | 163 | .fs_excl = ATOMIC_INIT(0), \ |
141 | .pi_lock = __SPIN_LOCK_UNLOCKED(tsk.pi_lock), \ | 164 | .pi_lock = __SPIN_LOCK_UNLOCKED(tsk.pi_lock), \ |
165 | .pids = { \ | ||
166 | [PIDTYPE_PID] = INIT_PID_LINK(PIDTYPE_PID), \ | ||
167 | [PIDTYPE_PGID] = INIT_PID_LINK(PIDTYPE_PGID), \ | ||
168 | [PIDTYPE_SID] = INIT_PID_LINK(PIDTYPE_SID), \ | ||
169 | }, \ | ||
142 | INIT_TRACE_IRQFLAGS \ | 170 | INIT_TRACE_IRQFLAGS \ |
143 | INIT_LOCKDEP \ | 171 | INIT_LOCKDEP \ |
144 | } | 172 | } |
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index f7b01b9a35b3..5323f6275854 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h | |||
@@ -241,6 +241,16 @@ static inline void __deprecated save_and_cli(unsigned long *x) | |||
241 | #define save_and_cli(x) save_and_cli(&x) | 241 | #define save_and_cli(x) save_and_cli(&x) |
242 | #endif /* CONFIG_SMP */ | 242 | #endif /* CONFIG_SMP */ |
243 | 243 | ||
244 | /* Some architectures might implement lazy enabling/disabling of | ||
245 | * interrupts. In some cases, such as stop_machine, we might want | ||
246 | * to ensure that after a local_irq_disable(), interrupts have | ||
247 | * really been disabled in hardware. Such architectures need to | ||
248 | * implement the following hook. | ||
249 | */ | ||
250 | #ifndef hard_irq_disable | ||
251 | #define hard_irq_disable() do { } while(0) | ||
252 | #endif | ||
253 | |||
244 | /* PLEASE, avoid to allocate new softirqs, if you need not _really_ high | 254 | /* PLEASE, avoid to allocate new softirqs, if you need not _really_ high |
245 | frequency threaded job scheduling. For almost all the purposes | 255 | frequency threaded job scheduling. For almost all the purposes |
246 | tasklets are more than enough. F.e. all serial device BHs et | 256 | tasklets are more than enough. F.e. all serial device BHs et |
diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 8645181fca0f..eec0d13169a6 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h | |||
@@ -213,6 +213,17 @@ extern enum system_states { | |||
213 | 213 | ||
214 | extern void dump_stack(void); | 214 | extern void dump_stack(void); |
215 | 215 | ||
216 | enum { | ||
217 | DUMP_PREFIX_NONE, | ||
218 | DUMP_PREFIX_ADDRESS, | ||
219 | DUMP_PREFIX_OFFSET | ||
220 | }; | ||
221 | extern void hex_dump_to_buffer(const void *buf, size_t len, char *linebuf, | ||
222 | size_t linebuflen); | ||
223 | extern void print_hex_dump(const char *level, int prefix_type, | ||
224 | void *buf, size_t len); | ||
225 | #define hex_asc(x) "0123456789abcdef"[x] | ||
226 | |||
216 | #ifdef DEBUG | 227 | #ifdef DEBUG |
217 | /* If you are writing a driver, please use dev_dbg instead */ | 228 | /* If you are writing a driver, please use dev_dbg instead */ |
218 | #define pr_debug(fmt,arg...) \ | 229 | #define pr_debug(fmt,arg...) \ |
diff --git a/include/linux/magic.h b/include/linux/magic.h index a9c6567fe70c..9d713c03e3da 100644 --- a/include/linux/magic.h +++ b/include/linux/magic.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #define ISOFS_SUPER_MAGIC 0x9660 | 14 | #define ISOFS_SUPER_MAGIC 0x9660 |
15 | #define JFFS2_SUPER_MAGIC 0x72b6 | 15 | #define JFFS2_SUPER_MAGIC 0x72b6 |
16 | #define KVMFS_SUPER_MAGIC 0x19700426 | 16 | #define KVMFS_SUPER_MAGIC 0x19700426 |
17 | #define ANON_INODE_FS_MAGIC 0x09041934 | ||
17 | 18 | ||
18 | #define MINIX_SUPER_MAGIC 0x137F /* original minix fs */ | 19 | #define MINIX_SUPER_MAGIC 0x137F /* original minix fs */ |
19 | #define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */ | 20 | #define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */ |
diff --git a/include/linux/module.h b/include/linux/module.h index 792d483c9af7..e6e0f86ef5fc 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
@@ -124,7 +124,7 @@ extern struct module __this_module; | |||
124 | */ | 124 | */ |
125 | #define MODULE_LICENSE(_license) MODULE_INFO(license, _license) | 125 | #define MODULE_LICENSE(_license) MODULE_INFO(license, _license) |
126 | 126 | ||
127 | /* Author, ideally of form NAME <EMAIL>[, NAME <EMAIL>]*[ and NAME <EMAIL>] */ | 127 | /* Author, ideally of form NAME[, NAME]*[ and NAME] */ |
128 | #define MODULE_AUTHOR(_author) MODULE_INFO(author, _author) | 128 | #define MODULE_AUTHOR(_author) MODULE_INFO(author, _author) |
129 | 129 | ||
130 | /* What your module does. */ | 130 | /* What your module does. */ |
diff --git a/include/linux/mpage.h b/include/linux/mpage.h index cc5fb75af78a..068a0c9946af 100644 --- a/include/linux/mpage.h +++ b/include/linux/mpage.h | |||
@@ -12,7 +12,6 @@ | |||
12 | #ifdef CONFIG_BLOCK | 12 | #ifdef CONFIG_BLOCK |
13 | 13 | ||
14 | struct writeback_control; | 14 | struct writeback_control; |
15 | typedef int (writepage_t)(struct page *page, struct writeback_control *wbc); | ||
16 | 15 | ||
17 | int mpage_readpages(struct address_space *mapping, struct list_head *pages, | 16 | int mpage_readpages(struct address_space *mapping, struct list_head *pages, |
18 | unsigned nr_pages, get_block_t get_block); | 17 | unsigned nr_pages, get_block_t get_block); |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 30446222b396..f671cd2f133f 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -467,6 +467,8 @@ struct net_device | |||
467 | /* device index hash chain */ | 467 | /* device index hash chain */ |
468 | struct hlist_node index_hlist; | 468 | struct hlist_node index_hlist; |
469 | 469 | ||
470 | struct net_device *link_watch_next; | ||
471 | |||
470 | /* register/unregister state machine */ | 472 | /* register/unregister state machine */ |
471 | enum { NETREG_UNINITIALIZED=0, | 473 | enum { NETREG_UNINITIALIZED=0, |
472 | NETREG_REGISTERED, /* completed register_netdevice */ | 474 | NETREG_REGISTERED, /* completed register_netdevice */ |
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 022edfa97ed9..7e733a6ba4f6 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h | |||
@@ -54,6 +54,14 @@ struct xt_entry_target | |||
54 | unsigned char data[0]; | 54 | unsigned char data[0]; |
55 | }; | 55 | }; |
56 | 56 | ||
57 | #define XT_TARGET_INIT(__name, __size) \ | ||
58 | { \ | ||
59 | .target.u.user = { \ | ||
60 | .target_size = XT_ALIGN(__size), \ | ||
61 | .name = __name, \ | ||
62 | }, \ | ||
63 | } | ||
64 | |||
57 | struct xt_standard_target | 65 | struct xt_standard_target |
58 | { | 66 | { |
59 | struct xt_entry_target target; | 67 | struct xt_entry_target target; |
diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h index 24c8786d12e9..584cd1b18f12 100644 --- a/include/linux/netfilter_arp/arp_tables.h +++ b/include/linux/netfilter_arp/arp_tables.h | |||
@@ -238,6 +238,47 @@ static __inline__ struct arpt_entry_target *arpt_get_target(struct arpt_entry *e | |||
238 | */ | 238 | */ |
239 | #ifdef __KERNEL__ | 239 | #ifdef __KERNEL__ |
240 | 240 | ||
241 | /* Standard entry. */ | ||
242 | struct arpt_standard | ||
243 | { | ||
244 | struct arpt_entry entry; | ||
245 | struct arpt_standard_target target; | ||
246 | }; | ||
247 | |||
248 | struct arpt_error_target | ||
249 | { | ||
250 | struct arpt_entry_target target; | ||
251 | char errorname[ARPT_FUNCTION_MAXNAMELEN]; | ||
252 | }; | ||
253 | |||
254 | struct arpt_error | ||
255 | { | ||
256 | struct arpt_entry entry; | ||
257 | struct arpt_error_target target; | ||
258 | }; | ||
259 | |||
260 | #define ARPT_ENTRY_INIT(__size) \ | ||
261 | { \ | ||
262 | .target_offset = sizeof(struct arpt_entry), \ | ||
263 | .next_offset = (__size), \ | ||
264 | } | ||
265 | |||
266 | #define ARPT_STANDARD_INIT(__verdict) \ | ||
267 | { \ | ||
268 | .entry = ARPT_ENTRY_INIT(sizeof(struct arpt_standard)), \ | ||
269 | .target = XT_TARGET_INIT(ARPT_STANDARD_TARGET, \ | ||
270 | sizeof(struct arpt_standard_target)), \ | ||
271 | .target.verdict = -(__verdict) - 1, \ | ||
272 | } | ||
273 | |||
274 | #define ARPT_ERROR_INIT \ | ||
275 | { \ | ||
276 | .entry = ARPT_ENTRY_INIT(sizeof(struct arpt_error)), \ | ||
277 | .target = XT_TARGET_INIT(ARPT_ERROR_TARGET, \ | ||
278 | sizeof(struct arpt_error_target)), \ | ||
279 | .target.errorname = "ERROR", \ | ||
280 | } | ||
281 | |||
241 | #define arpt_register_target(tgt) \ | 282 | #define arpt_register_target(tgt) \ |
242 | ({ (tgt)->family = NF_ARP; \ | 283 | ({ (tgt)->family = NF_ARP; \ |
243 | xt_register_target(tgt); }) | 284 | xt_register_target(tgt); }) |
diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h index 9527296595cd..2f46dd728ee1 100644 --- a/include/linux/netfilter_ipv4/ip_tables.h +++ b/include/linux/netfilter_ipv4/ip_tables.h | |||
@@ -295,6 +295,28 @@ struct ipt_error | |||
295 | struct ipt_error_target target; | 295 | struct ipt_error_target target; |
296 | }; | 296 | }; |
297 | 297 | ||
298 | #define IPT_ENTRY_INIT(__size) \ | ||
299 | { \ | ||
300 | .target_offset = sizeof(struct ipt_entry), \ | ||
301 | .next_offset = (__size), \ | ||
302 | } | ||
303 | |||
304 | #define IPT_STANDARD_INIT(__verdict) \ | ||
305 | { \ | ||
306 | .entry = IPT_ENTRY_INIT(sizeof(struct ipt_standard)), \ | ||
307 | .target = XT_TARGET_INIT(IPT_STANDARD_TARGET, \ | ||
308 | sizeof(struct xt_standard_target)), \ | ||
309 | .target.verdict = -(__verdict) - 1, \ | ||
310 | } | ||
311 | |||
312 | #define IPT_ERROR_INIT \ | ||
313 | { \ | ||
314 | .entry = IPT_ENTRY_INIT(sizeof(struct ipt_error)), \ | ||
315 | .target = XT_TARGET_INIT(IPT_ERROR_TARGET, \ | ||
316 | sizeof(struct ipt_error_target)), \ | ||
317 | .target.errorname = "ERROR", \ | ||
318 | } | ||
319 | |||
298 | extern unsigned int ipt_do_table(struct sk_buff **pskb, | 320 | extern unsigned int ipt_do_table(struct sk_buff **pskb, |
299 | unsigned int hook, | 321 | unsigned int hook, |
300 | const struct net_device *in, | 322 | const struct net_device *in, |
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h index 61aa10412fc8..4686f8342cbd 100644 --- a/include/linux/netfilter_ipv6/ip6_tables.h +++ b/include/linux/netfilter_ipv6/ip6_tables.h | |||
@@ -123,6 +123,28 @@ struct ip6t_error | |||
123 | struct ip6t_error_target target; | 123 | struct ip6t_error_target target; |
124 | }; | 124 | }; |
125 | 125 | ||
126 | #define IP6T_ENTRY_INIT(__size) \ | ||
127 | { \ | ||
128 | .target_offset = sizeof(struct ip6t_entry), \ | ||
129 | .next_offset = (__size), \ | ||
130 | } | ||
131 | |||
132 | #define IP6T_STANDARD_INIT(__verdict) \ | ||
133 | { \ | ||
134 | .entry = IP6T_ENTRY_INIT(sizeof(struct ip6t_standard)), \ | ||
135 | .target = XT_TARGET_INIT(IP6T_STANDARD_TARGET, \ | ||
136 | sizeof(struct ip6t_standard_target)), \ | ||
137 | .target.verdict = -(__verdict) - 1, \ | ||
138 | } | ||
139 | |||
140 | #define IP6T_ERROR_INIT \ | ||
141 | { \ | ||
142 | .entry = IP6T_ENTRY_INIT(sizeof(struct ip6t_error)), \ | ||
143 | .target = XT_TARGET_INIT(IP6T_ERROR_TARGET, \ | ||
144 | sizeof(struct ip6t_error_target)), \ | ||
145 | .target.errorname = "ERROR", \ | ||
146 | } | ||
147 | |||
126 | /* | 148 | /* |
127 | * New IP firewall options for [gs]etsockopt at the RAW IP level. | 149 | * New IP firewall options for [gs]etsockopt at the RAW IP level. |
128 | * Unlike BSD Linux inherits IP options so you don't have to use | 150 | * Unlike BSD Linux inherits IP options so you don't have to use |
diff --git a/include/linux/pid.h b/include/linux/pid.h index 2ac27f9997dd..1e0e4e3423a6 100644 --- a/include/linux/pid.h +++ b/include/linux/pid.h | |||
@@ -51,6 +51,8 @@ struct pid | |||
51 | struct rcu_head rcu; | 51 | struct rcu_head rcu; |
52 | }; | 52 | }; |
53 | 53 | ||
54 | extern struct pid init_struct_pid; | ||
55 | |||
54 | struct pid_link | 56 | struct pid_link |
55 | { | 57 | { |
56 | struct hlist_node node; | 58 | struct hlist_node node; |
@@ -76,8 +78,7 @@ extern struct pid *get_task_pid(struct task_struct *task, enum pid_type type); | |||
76 | * write-held. | 78 | * write-held. |
77 | */ | 79 | */ |
78 | extern int FASTCALL(attach_pid(struct task_struct *task, | 80 | extern int FASTCALL(attach_pid(struct task_struct *task, |
79 | enum pid_type type, int nr)); | 81 | enum pid_type type, struct pid *pid)); |
80 | |||
81 | extern void FASTCALL(detach_pid(struct task_struct *task, enum pid_type)); | 82 | extern void FASTCALL(detach_pid(struct task_struct *task, enum pid_type)); |
82 | extern void FASTCALL(transfer_pid(struct task_struct *old, | 83 | extern void FASTCALL(transfer_pid(struct task_struct *old, |
83 | struct task_struct *new, enum pid_type)); | 84 | struct task_struct *new, enum pid_type)); |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 17b72d88c4cb..97c0c7da58ef 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -391,6 +391,7 @@ struct sighand_struct { | |||
391 | atomic_t count; | 391 | atomic_t count; |
392 | struct k_sigaction action[_NSIG]; | 392 | struct k_sigaction action[_NSIG]; |
393 | spinlock_t siglock; | 393 | spinlock_t siglock; |
394 | struct list_head signalfd_list; | ||
394 | }; | 395 | }; |
395 | 396 | ||
396 | struct pacct_struct { | 397 | struct pacct_struct { |
@@ -469,6 +470,7 @@ struct signal_struct { | |||
469 | cputime_t utime, stime, cutime, cstime; | 470 | cputime_t utime, stime, cutime, cstime; |
470 | unsigned long nvcsw, nivcsw, cnvcsw, cnivcsw; | 471 | unsigned long nvcsw, nivcsw, cnvcsw, cnivcsw; |
471 | unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt; | 472 | unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt; |
473 | unsigned long inblock, oublock, cinblock, coublock; | ||
472 | 474 | ||
473 | /* | 475 | /* |
474 | * Cumulative ns of scheduled CPU time for dead threads in the | 476 | * Cumulative ns of scheduled CPU time for dead threads in the |
diff --git a/include/linux/signal.h b/include/linux/signal.h index 3fa0fab4a04b..9a5eac508e5e 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h | |||
@@ -233,6 +233,7 @@ static inline int valid_signal(unsigned long sig) | |||
233 | return sig <= _NSIG ? 1 : 0; | 233 | return sig <= _NSIG ? 1 : 0; |
234 | } | 234 | } |
235 | 235 | ||
236 | extern int next_signal(struct sigpending *pending, sigset_t *mask); | ||
236 | extern int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p); | 237 | extern int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p); |
237 | extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *); | 238 | extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *); |
238 | extern long do_sigpending(void __user *, unsigned long); | 239 | extern long do_sigpending(void __user *, unsigned long); |
diff --git a/include/linux/signalfd.h b/include/linux/signalfd.h new file mode 100644 index 000000000000..510429495690 --- /dev/null +++ b/include/linux/signalfd.h | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * include/linux/signalfd.h | ||
3 | * | ||
4 | * Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org> | ||
5 | * | ||
6 | */ | ||
7 | |||
8 | #ifndef _LINUX_SIGNALFD_H | ||
9 | #define _LINUX_SIGNALFD_H | ||
10 | |||
11 | |||
12 | struct signalfd_siginfo { | ||
13 | __u32 signo; | ||
14 | __s32 err; | ||
15 | __s32 code; | ||
16 | __u32 pid; | ||
17 | __u32 uid; | ||
18 | __s32 fd; | ||
19 | __u32 tid; | ||
20 | __u32 band; | ||
21 | __u32 overrun; | ||
22 | __u32 trapno; | ||
23 | __s32 status; | ||
24 | __s32 svint; | ||
25 | __u64 svptr; | ||
26 | __u64 utime; | ||
27 | __u64 stime; | ||
28 | __u64 addr; | ||
29 | |||
30 | /* | ||
31 | * Pad strcture to 128 bytes. Remember to update the | ||
32 | * pad size when you add new memebers. We use a fixed | ||
33 | * size structure to avoid compatibility problems with | ||
34 | * future versions, and we leave extra space for additional | ||
35 | * members. We use fixed size members because this strcture | ||
36 | * comes out of a read(2) and we really don't want to have | ||
37 | * a compat on read(2). | ||
38 | */ | ||
39 | __u8 __pad[48]; | ||
40 | }; | ||
41 | |||
42 | |||
43 | #ifdef __KERNEL__ | ||
44 | |||
45 | #ifdef CONFIG_SIGNALFD | ||
46 | |||
47 | /* | ||
48 | * Deliver the signal to listening signalfd. This must be called | ||
49 | * with the sighand lock held. Same are the following that end up | ||
50 | * calling signalfd_deliver(). | ||
51 | */ | ||
52 | void signalfd_deliver(struct task_struct *tsk, int sig); | ||
53 | |||
54 | /* | ||
55 | * No need to fall inside signalfd_deliver() if no signal listeners | ||
56 | * are available. | ||
57 | */ | ||
58 | static inline void signalfd_notify(struct task_struct *tsk, int sig) | ||
59 | { | ||
60 | if (unlikely(!list_empty(&tsk->sighand->signalfd_list))) | ||
61 | signalfd_deliver(tsk, sig); | ||
62 | } | ||
63 | |||
64 | /* | ||
65 | * The signal -1 is used to notify the signalfd that the sighand | ||
66 | * is on its way to be detached. | ||
67 | */ | ||
68 | static inline void signalfd_detach_locked(struct task_struct *tsk) | ||
69 | { | ||
70 | if (unlikely(!list_empty(&tsk->sighand->signalfd_list))) | ||
71 | signalfd_deliver(tsk, -1); | ||
72 | } | ||
73 | |||
74 | static inline void signalfd_detach(struct task_struct *tsk) | ||
75 | { | ||
76 | struct sighand_struct *sighand = tsk->sighand; | ||
77 | |||
78 | if (unlikely(!list_empty(&sighand->signalfd_list))) { | ||
79 | spin_lock_irq(&sighand->siglock); | ||
80 | signalfd_deliver(tsk, -1); | ||
81 | spin_unlock_irq(&sighand->siglock); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | #else /* CONFIG_SIGNALFD */ | ||
86 | |||
87 | #define signalfd_deliver(t, s) do { } while (0) | ||
88 | #define signalfd_notify(t, s) do { } while (0) | ||
89 | #define signalfd_detach_locked(t) do { } while (0) | ||
90 | #define signalfd_detach(t) do { } while (0) | ||
91 | |||
92 | #endif /* CONFIG_SIGNALFD */ | ||
93 | |||
94 | #endif /* __KERNEL__ */ | ||
95 | |||
96 | #endif /* _LINUX_SIGNALFD_H */ | ||
97 | |||
diff --git a/include/linux/synclink.h b/include/linux/synclink.h index c8b042667af1..5562fbf72095 100644 --- a/include/linux/synclink.h +++ b/include/linux/synclink.h | |||
@@ -291,4 +291,28 @@ struct gpio_desc { | |||
291 | #define MGSL_IOCGGPIO _IOR(MGSL_MAGIC_IOC,17,struct gpio_desc) | 291 | #define MGSL_IOCGGPIO _IOR(MGSL_MAGIC_IOC,17,struct gpio_desc) |
292 | #define MGSL_IOCWAITGPIO _IOWR(MGSL_MAGIC_IOC,18,struct gpio_desc) | 292 | #define MGSL_IOCWAITGPIO _IOWR(MGSL_MAGIC_IOC,18,struct gpio_desc) |
293 | 293 | ||
294 | #ifdef __KERNEL__ | ||
295 | /* provide 32 bit ioctl compatibility on 64 bit systems */ | ||
296 | #ifdef CONFIG_COMPAT | ||
297 | #include <linux/compat.h> | ||
298 | struct MGSL_PARAMS32 { | ||
299 | compat_ulong_t mode; | ||
300 | unsigned char loopback; | ||
301 | unsigned short flags; | ||
302 | unsigned char encoding; | ||
303 | compat_ulong_t clock_speed; | ||
304 | unsigned char addr_filter; | ||
305 | unsigned short crc_type; | ||
306 | unsigned char preamble_length; | ||
307 | unsigned char preamble; | ||
308 | compat_ulong_t data_rate; | ||
309 | unsigned char data_bits; | ||
310 | unsigned char stop_bits; | ||
311 | unsigned char parity; | ||
312 | }; | ||
313 | #define MGSL_IOCSPARAMS32 _IOW(MGSL_MAGIC_IOC,0,struct MGSL_PARAMS32) | ||
314 | #define MGSL_IOCGPARAMS32 _IOR(MGSL_MAGIC_IOC,1,struct MGSL_PARAMS32) | ||
315 | #endif | ||
316 | #endif | ||
317 | |||
294 | #endif /* _SYNCLINK_H_ */ | 318 | #endif /* _SYNCLINK_H_ */ |
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 3139f4412297..b02070eac422 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h | |||
@@ -604,6 +604,10 @@ asmlinkage long sys_get_robust_list(int pid, | |||
604 | asmlinkage long sys_set_robust_list(struct robust_list_head __user *head, | 604 | asmlinkage long sys_set_robust_list(struct robust_list_head __user *head, |
605 | size_t len); | 605 | size_t len); |
606 | asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache); | 606 | asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache); |
607 | asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask); | ||
608 | asmlinkage long sys_timerfd(int ufd, int clockid, int flags, | ||
609 | const struct itimerspec __user *utmr); | ||
610 | asmlinkage long sys_eventfd(unsigned int count); | ||
607 | 611 | ||
608 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]); | 612 | int kernel_execve(const char *filename, char *const argv[], char *const envp[]); |
609 | 613 | ||
diff --git a/include/linux/task_io_accounting_ops.h b/include/linux/task_io_accounting_ops.h index df2a319106b2..1218733ec6b5 100644 --- a/include/linux/task_io_accounting_ops.h +++ b/include/linux/task_io_accounting_ops.h | |||
@@ -10,11 +10,29 @@ static inline void task_io_account_read(size_t bytes) | |||
10 | current->ioac.read_bytes += bytes; | 10 | current->ioac.read_bytes += bytes; |
11 | } | 11 | } |
12 | 12 | ||
13 | /* | ||
14 | * We approximate number of blocks, because we account bytes only. | ||
15 | * A 'block' is 512 bytes | ||
16 | */ | ||
17 | static inline unsigned long task_io_get_inblock(const struct task_struct *p) | ||
18 | { | ||
19 | return p->ioac.read_bytes >> 9; | ||
20 | } | ||
21 | |||
13 | static inline void task_io_account_write(size_t bytes) | 22 | static inline void task_io_account_write(size_t bytes) |
14 | { | 23 | { |
15 | current->ioac.write_bytes += bytes; | 24 | current->ioac.write_bytes += bytes; |
16 | } | 25 | } |
17 | 26 | ||
27 | /* | ||
28 | * We approximate number of blocks, because we account bytes only. | ||
29 | * A 'block' is 512 bytes | ||
30 | */ | ||
31 | static inline unsigned long task_io_get_oublock(const struct task_struct *p) | ||
32 | { | ||
33 | return p->ioac.write_bytes >> 9; | ||
34 | } | ||
35 | |||
18 | static inline void task_io_account_cancelled_write(size_t bytes) | 36 | static inline void task_io_account_cancelled_write(size_t bytes) |
19 | { | 37 | { |
20 | current->ioac.cancelled_write_bytes += bytes; | 38 | current->ioac.cancelled_write_bytes += bytes; |
@@ -31,10 +49,20 @@ static inline void task_io_account_read(size_t bytes) | |||
31 | { | 49 | { |
32 | } | 50 | } |
33 | 51 | ||
52 | static inline unsigned long task_io_get_inblock(const struct task_struct *p) | ||
53 | { | ||
54 | return 0; | ||
55 | } | ||
56 | |||
34 | static inline void task_io_account_write(size_t bytes) | 57 | static inline void task_io_account_write(size_t bytes) |
35 | { | 58 | { |
36 | } | 59 | } |
37 | 60 | ||
61 | static inline unsigned long task_io_get_oublock(const struct task_struct *p) | ||
62 | { | ||
63 | return 0; | ||
64 | } | ||
65 | |||
38 | static inline void task_io_account_cancelled_write(size_t bytes) | 66 | static inline void task_io_account_cancelled_write(size_t bytes) |
39 | { | 67 | { |
40 | } | 68 | } |
diff --git a/include/linux/timerfd.h b/include/linux/timerfd.h new file mode 100644 index 000000000000..cf2b10d75731 --- /dev/null +++ b/include/linux/timerfd.h | |||
@@ -0,0 +1,17 @@ | |||
1 | /* | ||
2 | * include/linux/timerfd.h | ||
3 | * | ||
4 | * Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org> | ||
5 | * | ||
6 | */ | ||
7 | |||
8 | #ifndef _LINUX_TIMERFD_H | ||
9 | #define _LINUX_TIMERFD_H | ||
10 | |||
11 | |||
12 | #define TFD_TIMER_ABSTIME (1 << 0) | ||
13 | |||
14 | |||
15 | |||
16 | #endif /* _LINUX_TIMERFD_H */ | ||
17 | |||
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 659487e3ebeb..85c95cd39bc3 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h | |||
@@ -52,6 +52,11 @@ | |||
52 | * This routine allows the tty driver to implement | 52 | * This routine allows the tty driver to implement |
53 | * device-specific ioctl's. If the ioctl number passed in cmd | 53 | * device-specific ioctl's. If the ioctl number passed in cmd |
54 | * is not recognized by the driver, it should return ENOIOCTLCMD. | 54 | * is not recognized by the driver, it should return ENOIOCTLCMD. |
55 | * | ||
56 | * long (*compat_ioctl)(struct tty_struct *tty, struct file * file, | ||
57 | * unsigned int cmd, unsigned long arg); | ||
58 | * | ||
59 | * implement ioctl processing for 32 bit process on 64 bit system | ||
55 | * | 60 | * |
56 | * void (*set_termios)(struct tty_struct *tty, struct ktermios * old); | 61 | * void (*set_termios)(struct tty_struct *tty, struct ktermios * old); |
57 | * | 62 | * |
@@ -132,6 +137,8 @@ struct tty_operations { | |||
132 | int (*chars_in_buffer)(struct tty_struct *tty); | 137 | int (*chars_in_buffer)(struct tty_struct *tty); |
133 | int (*ioctl)(struct tty_struct *tty, struct file * file, | 138 | int (*ioctl)(struct tty_struct *tty, struct file * file, |
134 | unsigned int cmd, unsigned long arg); | 139 | unsigned int cmd, unsigned long arg); |
140 | long (*compat_ioctl)(struct tty_struct *tty, struct file * file, | ||
141 | unsigned int cmd, unsigned long arg); | ||
135 | void (*set_termios)(struct tty_struct *tty, struct ktermios * old); | 142 | void (*set_termios)(struct tty_struct *tty, struct ktermios * old); |
136 | void (*throttle)(struct tty_struct * tty); | 143 | void (*throttle)(struct tty_struct * tty); |
137 | void (*unthrottle)(struct tty_struct * tty); | 144 | void (*unthrottle)(struct tty_struct * tty); |
@@ -193,6 +200,8 @@ struct tty_driver { | |||
193 | int (*chars_in_buffer)(struct tty_struct *tty); | 200 | int (*chars_in_buffer)(struct tty_struct *tty); |
194 | int (*ioctl)(struct tty_struct *tty, struct file * file, | 201 | int (*ioctl)(struct tty_struct *tty, struct file * file, |
195 | unsigned int cmd, unsigned long arg); | 202 | unsigned int cmd, unsigned long arg); |
203 | long (*compat_ioctl)(struct tty_struct *tty, struct file * file, | ||
204 | unsigned int cmd, unsigned long arg); | ||
196 | void (*set_termios)(struct tty_struct *tty, struct ktermios * old); | 205 | void (*set_termios)(struct tty_struct *tty, struct ktermios * old); |
197 | void (*throttle)(struct tty_struct * tty); | 206 | void (*throttle)(struct tty_struct * tty); |
198 | void (*unthrottle)(struct tty_struct * tty); | 207 | void (*unthrottle)(struct tty_struct * tty); |
diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index d75932e27710..6226504d9108 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h | |||
@@ -59,6 +59,11 @@ | |||
59 | * low-level driver can "grab" an ioctl request before the line | 59 | * low-level driver can "grab" an ioctl request before the line |
60 | * discpline has a chance to see it. | 60 | * discpline has a chance to see it. |
61 | * | 61 | * |
62 | * long (*compat_ioctl)(struct tty_struct * tty, struct file * file, | ||
63 | * unsigned int cmd, unsigned long arg); | ||
64 | * | ||
65 | * Process ioctl calls from 32-bit process on 64-bit system | ||
66 | * | ||
62 | * void (*set_termios)(struct tty_struct *tty, struct ktermios * old); | 67 | * void (*set_termios)(struct tty_struct *tty, struct ktermios * old); |
63 | * | 68 | * |
64 | * This function notifies the line discpline that a change has | 69 | * This function notifies the line discpline that a change has |
@@ -118,6 +123,8 @@ struct tty_ldisc { | |||
118 | const unsigned char * buf, size_t nr); | 123 | const unsigned char * buf, size_t nr); |
119 | int (*ioctl)(struct tty_struct * tty, struct file * file, | 124 | int (*ioctl)(struct tty_struct * tty, struct file * file, |
120 | unsigned int cmd, unsigned long arg); | 125 | unsigned int cmd, unsigned long arg); |
126 | long (*compat_ioctl)(struct tty_struct * tty, struct file * file, | ||
127 | unsigned int cmd, unsigned long arg); | ||
121 | void (*set_termios)(struct tty_struct *tty, struct ktermios * old); | 128 | void (*set_termios)(struct tty_struct *tty, struct ktermios * old); |
122 | unsigned int (*poll)(struct tty_struct *, struct file *, | 129 | unsigned int (*poll)(struct tty_struct *, struct file *, |
123 | struct poll_table_struct *); | 130 | struct poll_table_struct *); |
diff --git a/include/linux/writeback.h b/include/linux/writeback.h index daa6c125f66e..050915b59576 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h | |||
@@ -111,9 +111,15 @@ balance_dirty_pages_ratelimited(struct address_space *mapping) | |||
111 | balance_dirty_pages_ratelimited_nr(mapping, 1); | 111 | balance_dirty_pages_ratelimited_nr(mapping, 1); |
112 | } | 112 | } |
113 | 113 | ||
114 | typedef int (*writepage_t)(struct page *page, struct writeback_control *wbc, | ||
115 | void *data); | ||
116 | |||
114 | int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0); | 117 | int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0); |
115 | extern int generic_writepages(struct address_space *mapping, | 118 | int generic_writepages(struct address_space *mapping, |
116 | struct writeback_control *wbc); | 119 | struct writeback_control *wbc); |
120 | int write_cache_pages(struct address_space *mapping, | ||
121 | struct writeback_control *wbc, writepage_t writepage, | ||
122 | void *data); | ||
117 | int do_writepages(struct address_space *mapping, struct writeback_control *wbc); | 123 | int do_writepages(struct address_space *mapping, struct writeback_control *wbc); |
118 | int sync_page_range(struct inode *inode, struct address_space *mapping, | 124 | int sync_page_range(struct inode *inode, struct address_space *mapping, |
119 | loff_t pos, loff_t count); | 125 | loff_t pos, loff_t count); |
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 1c6b8bd09b9a..4732432f8eb0 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h | |||
@@ -183,13 +183,6 @@ extern void nf_conntrack_hash_insert(struct nf_conn *ct); | |||
183 | 183 | ||
184 | extern void nf_conntrack_flush(void); | 184 | extern void nf_conntrack_flush(void); |
185 | 185 | ||
186 | extern struct nf_conntrack_helper * | ||
187 | nf_ct_helper_find_get( const struct nf_conntrack_tuple *tuple); | ||
188 | extern void nf_ct_helper_put(struct nf_conntrack_helper *helper); | ||
189 | |||
190 | extern struct nf_conntrack_helper * | ||
191 | __nf_conntrack_helper_find_byname(const char *name); | ||
192 | |||
193 | extern int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse, | 186 | extern int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse, |
194 | const struct nf_conntrack_tuple *orig); | 187 | const struct nf_conntrack_tuple *orig); |
195 | 188 | ||
diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h index f32f714e5d92..96a58d8e1d3f 100644 --- a/include/net/netfilter/nf_conntrack_l3proto.h +++ b/include/net/netfilter/nf_conntrack_l3proto.h | |||
@@ -56,9 +56,6 @@ struct nf_conntrack_l3proto | |||
56 | */ | 56 | */ |
57 | int (*new)(struct nf_conn *conntrack, const struct sk_buff *skb); | 57 | int (*new)(struct nf_conn *conntrack, const struct sk_buff *skb); |
58 | 58 | ||
59 | /* Called when a conntrack entry is destroyed */ | ||
60 | void (*destroy)(struct nf_conn *conntrack); | ||
61 | |||
62 | /* | 59 | /* |
63 | * Called before tracking. | 60 | * Called before tracking. |
64 | * *dataoff: offset of protocol header (TCP, UDP,...) in *pskb | 61 | * *dataoff: offset of protocol header (TCP, UDP,...) in *pskb |
diff --git a/include/net/netfilter/nf_nat_rule.h b/include/net/netfilter/nf_nat_rule.h index e76565459ad9..f9743187d57f 100644 --- a/include/net/netfilter/nf_nat_rule.h +++ b/include/net/netfilter/nf_nat_rule.h | |||
@@ -10,16 +10,11 @@ extern int nf_nat_rule_find(struct sk_buff **pskb, | |||
10 | unsigned int hooknum, | 10 | unsigned int hooknum, |
11 | const struct net_device *in, | 11 | const struct net_device *in, |
12 | const struct net_device *out, | 12 | const struct net_device *out, |
13 | struct nf_conn *ct, | 13 | struct nf_conn *ct); |
14 | struct nf_nat_info *info); | ||
15 | 14 | ||
16 | extern unsigned int | 15 | extern unsigned int |
17 | alloc_null_binding(struct nf_conn *ct, | 16 | alloc_null_binding(struct nf_conn *ct, unsigned int hooknum); |
18 | struct nf_nat_info *info, | ||
19 | unsigned int hooknum); | ||
20 | 17 | ||
21 | extern unsigned int | 18 | extern unsigned int |
22 | alloc_null_binding_confirmed(struct nf_conn *ct, | 19 | alloc_null_binding_confirmed(struct nf_conn *ct, unsigned int hooknum); |
23 | struct nf_nat_info *info, | ||
24 | unsigned int hooknum); | ||
25 | #endif /* _NF_NAT_RULE_H */ | 20 | #endif /* _NF_NAT_RULE_H */ |
diff --git a/include/net/udp.h b/include/net/udp.h index 98755ebaf163..496f89d45c8b 100644 --- a/include/net/udp.h +++ b/include/net/udp.h | |||
@@ -119,9 +119,16 @@ static inline void udp_lib_close(struct sock *sk, long timeout) | |||
119 | } | 119 | } |
120 | 120 | ||
121 | 121 | ||
122 | struct udp_get_port_ops { | ||
123 | int (*saddr_cmp)(const struct sock *sk1, const struct sock *sk2); | ||
124 | int (*saddr_any)(const struct sock *sk); | ||
125 | unsigned int (*hash_port_and_rcv_saddr)(__u16 port, | ||
126 | const struct sock *sk); | ||
127 | }; | ||
128 | |||
122 | /* net/ipv4/udp.c */ | 129 | /* net/ipv4/udp.c */ |
123 | extern int udp_get_port(struct sock *sk, unsigned short snum, | 130 | extern int udp_get_port(struct sock *sk, unsigned short snum, |
124 | int (*saddr_cmp)(const struct sock *, const struct sock *)); | 131 | const struct udp_get_port_ops *ops); |
125 | extern void udp_err(struct sk_buff *, u32); | 132 | extern void udp_err(struct sk_buff *, u32); |
126 | 133 | ||
127 | extern int udp_sendmsg(struct kiocb *iocb, struct sock *sk, | 134 | extern int udp_sendmsg(struct kiocb *iocb, struct sock *sk, |
diff --git a/include/net/udplite.h b/include/net/udplite.h index 635b0eafca95..50b4b424d1ca 100644 --- a/include/net/udplite.h +++ b/include/net/udplite.h | |||
@@ -120,5 +120,5 @@ static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb) | |||
120 | 120 | ||
121 | extern void udplite4_register(void); | 121 | extern void udplite4_register(void); |
122 | extern int udplite_get_port(struct sock *sk, unsigned short snum, | 122 | extern int udplite_get_port(struct sock *sk, unsigned short snum, |
123 | int (*scmp)(const struct sock *, const struct sock *)); | 123 | const struct udp_get_port_ops *ops); |
124 | #endif /* _UDPLITE_H */ | 124 | #endif /* _UDPLITE_H */ |
diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h new file mode 100644 index 000000000000..4eea63761a3f --- /dev/null +++ b/include/video/atmel_lcdc.h | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * Header file for AT91/AT32 LCD Controller | ||
3 | * | ||
4 | * Data structure and register user interface | ||
5 | * | ||
6 | * Copyright (C) 2007 Atmel Corporation | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | #ifndef __ATMEL_LCDC_H__ | ||
23 | #define __ATMEL_LCDC_H__ | ||
24 | |||
25 | /* LCD Controller info data structure */ | ||
26 | struct atmel_lcdfb_info { | ||
27 | spinlock_t lock; | ||
28 | struct fb_info *info; | ||
29 | void __iomem *mmio; | ||
30 | unsigned long irq_base; | ||
31 | |||
32 | unsigned int guard_time; | ||
33 | struct platform_device *pdev; | ||
34 | struct clk *bus_clk; | ||
35 | struct clk *lcdc_clk; | ||
36 | unsigned int default_bpp; | ||
37 | unsigned int default_lcdcon2; | ||
38 | unsigned int default_dmacon; | ||
39 | void (*atmel_lcdfb_power_control)(int on); | ||
40 | struct fb_monspecs *default_monspecs; | ||
41 | u32 pseudo_palette[16]; | ||
42 | }; | ||
43 | |||
44 | #define ATMEL_LCDC_DMABADDR1 0x00 | ||
45 | #define ATMEL_LCDC_DMABADDR2 0x04 | ||
46 | #define ATMEL_LCDC_DMAFRMPT1 0x08 | ||
47 | #define ATMEL_LCDC_DMAFRMPT2 0x0c | ||
48 | #define ATMEL_LCDC_DMAFRMADD1 0x10 | ||
49 | #define ATMEL_LCDC_DMAFRMADD2 0x14 | ||
50 | |||
51 | #define ATMEL_LCDC_DMAFRMCFG 0x18 | ||
52 | #define ATMEL_LCDC_FRSIZE (0x7fffff << 0) | ||
53 | #define ATMEL_LCDC_BLENGTH_OFFSET 24 | ||
54 | #define ATMEL_LCDC_BLENGTH (0x7f << ATMEL_LCDC_BLENGTH_OFFSET) | ||
55 | |||
56 | #define ATMEL_LCDC_DMACON 0x1c | ||
57 | #define ATMEL_LCDC_DMAEN (0x1 << 0) | ||
58 | #define ATMEL_LCDC_DMARST (0x1 << 1) | ||
59 | #define ATMEL_LCDC_DMABUSY (0x1 << 2) | ||
60 | #define ATMEL_LCDC_DMAUPDT (0x1 << 3) | ||
61 | #define ATMEL_LCDC_DMA2DEN (0x1 << 4) | ||
62 | |||
63 | #define ATMEL_LCDC_DMA2DCFG 0x20 | ||
64 | #define ATMEL_LCDC_ADDRINC_OFFSET 0 | ||
65 | #define ATMEL_LCDC_ADDRINC (0xffff) | ||
66 | #define ATMEL_LCDC_PIXELOFF_OFFSET 24 | ||
67 | #define ATMEL_LCDC_PIXELOFF (0x1f << 24) | ||
68 | |||
69 | #define ATMEL_LCDC_LCDCON1 0x0800 | ||
70 | #define ATMEL_LCDC_BYPASS (1 << 0) | ||
71 | #define ATMEL_LCDC_CLKVAL_OFFSET 12 | ||
72 | #define ATMEL_LCDC_CLKVAL (0x1ff << ATMEL_LCDC_CLKVAL_OFFSET) | ||
73 | #define ATMEL_LCDC_LINCNT (0x7ff << 21) | ||
74 | |||
75 | #define ATMEL_LCDC_LCDCON2 0x0804 | ||
76 | #define ATMEL_LCDC_DISTYPE (3 << 0) | ||
77 | #define ATMEL_LCDC_DISTYPE_STNMONO (0 << 0) | ||
78 | #define ATMEL_LCDC_DISTYPE_STNCOLOR (1 << 0) | ||
79 | #define ATMEL_LCDC_DISTYPE_TFT (2 << 0) | ||
80 | #define ATMEL_LCDC_SCANMOD (1 << 2) | ||
81 | #define ATMEL_LCDC_SCANMOD_SINGLE (0 << 2) | ||
82 | #define ATMEL_LCDC_SCANMOD_DUAL (1 << 2) | ||
83 | #define ATMEL_LCDC_IFWIDTH (3 << 3) | ||
84 | #define ATMEL_LCDC_IFWIDTH_4 (0 << 3) | ||
85 | #define ATMEL_LCDC_IFWIDTH_8 (1 << 3) | ||
86 | #define ATMEL_LCDC_IFWIDTH_16 (2 << 3) | ||
87 | #define ATMEL_LCDC_PIXELSIZE (7 << 5) | ||
88 | #define ATMEL_LCDC_PIXELSIZE_1 (0 << 5) | ||
89 | #define ATMEL_LCDC_PIXELSIZE_2 (1 << 5) | ||
90 | #define ATMEL_LCDC_PIXELSIZE_4 (2 << 5) | ||
91 | #define ATMEL_LCDC_PIXELSIZE_8 (3 << 5) | ||
92 | #define ATMEL_LCDC_PIXELSIZE_16 (4 << 5) | ||
93 | #define ATMEL_LCDC_PIXELSIZE_24 (5 << 5) | ||
94 | #define ATMEL_LCDC_PIXELSIZE_32 (6 << 5) | ||
95 | #define ATMEL_LCDC_INVVD (1 << 8) | ||
96 | #define ATMEL_LCDC_INVVD_NORMAL (0 << 8) | ||
97 | #define ATMEL_LCDC_INVVD_INVERTED (1 << 8) | ||
98 | #define ATMEL_LCDC_INVFRAME (1 << 9 ) | ||
99 | #define ATMEL_LCDC_INVFRAME_NORMAL (0 << 9) | ||
100 | #define ATMEL_LCDC_INVFRAME_INVERTED (1 << 9) | ||
101 | #define ATMEL_LCDC_INVLINE (1 << 10) | ||
102 | #define ATMEL_LCDC_INVLINE_NORMAL (0 << 10) | ||
103 | #define ATMEL_LCDC_INVLINE_INVERTED (1 << 10) | ||
104 | #define ATMEL_LCDC_INVCLK (1 << 11) | ||
105 | #define ATMEL_LCDC_INVCLK_NORMAL (0 << 11) | ||
106 | #define ATMEL_LCDC_INVCLK_INVERTED (1 << 11) | ||
107 | #define ATMEL_LCDC_INVDVAL (1 << 12) | ||
108 | #define ATMEL_LCDC_INVDVAL_NORMAL (0 << 12) | ||
109 | #define ATMEL_LCDC_INVDVAL_INVERTED (1 << 12) | ||
110 | #define ATMEL_LCDC_CLKMOD (1 << 15) | ||
111 | #define ATMEL_LCDC_CLKMOD_ACTIVEDISPLAY (0 << 15) | ||
112 | #define ATMEL_LCDC_CLKMOD_ALWAYSACTIVE (1 << 15) | ||
113 | #define ATMEL_LCDC_MEMOR (1 << 31) | ||
114 | #define ATMEL_LCDC_MEMOR_BIG (0 << 31) | ||
115 | #define ATMEL_LCDC_MEMOR_LITTLE (1 << 31) | ||
116 | |||
117 | #define ATMEL_LCDC_TIM1 0x0808 | ||
118 | #define ATMEL_LCDC_VFP (0xff << 0) | ||
119 | #define ATMEL_LCDC_VBP_OFFSET 8 | ||
120 | #define ATMEL_LCDC_VBP (0xff << ATMEL_LCDC_VBP_OFFSET) | ||
121 | #define ATMEL_LCDC_VPW_OFFSET 16 | ||
122 | #define ATMEL_LCDC_VPW (0x3f << ATMEL_LCDC_VPW_OFFSET) | ||
123 | #define ATMEL_LCDC_VHDLY_OFFSET 24 | ||
124 | #define ATMEL_LCDC_VHDLY (0xf << ATMEL_LCDC_VHDLY_OFFSET) | ||
125 | |||
126 | #define ATMEL_LCDC_TIM2 0x080c | ||
127 | #define ATMEL_LCDC_HBP (0xff << 0) | ||
128 | #define ATMEL_LCDC_HPW_OFFSET 8 | ||
129 | #define ATMEL_LCDC_HPW (0x3f << ATMEL_LCDC_HPW_OFFSET) | ||
130 | #define ATMEL_LCDC_HFP_OFFSET 21 | ||
131 | #define ATMEL_LCDC_HFP (0x7ff << ATMEL_LCDC_HFP_OFFSET) | ||
132 | |||
133 | #define ATMEL_LCDC_LCDFRMCFG 0x0810 | ||
134 | #define ATMEL_LCDC_LINEVAL (0x7ff << 0) | ||
135 | #define ATMEL_LCDC_HOZVAL_OFFSET 21 | ||
136 | #define ATMEL_LCDC_HOZVAL (0x7ff << ATMEL_LCDC_HOZVAL_OFFSET) | ||
137 | |||
138 | #define ATMEL_LCDC_FIFO 0x0814 | ||
139 | #define ATMEL_LCDC_FIFOTH (0xffff) | ||
140 | |||
141 | #define ATMEL_LCDC_MVAL 0x0818 | ||
142 | |||
143 | #define ATMEL_LCDC_DP1_2 0x081c | ||
144 | #define ATMEL_LCDC_DP4_7 0x0820 | ||
145 | #define ATMEL_LCDC_DP3_5 0x0824 | ||
146 | #define ATMEL_LCDC_DP2_3 0x0828 | ||
147 | #define ATMEL_LCDC_DP5_7 0x082c | ||
148 | #define ATMEL_LCDC_DP3_4 0x0830 | ||
149 | #define ATMEL_LCDC_DP4_5 0x0834 | ||
150 | #define ATMEL_LCDC_DP6_7 0x0838 | ||
151 | #define ATMEL_LCDC_DP1_2_VAL (0xff) | ||
152 | #define ATMEL_LCDC_DP4_7_VAL (0xfffffff) | ||
153 | #define ATMEL_LCDC_DP3_5_VAL (0xfffff) | ||
154 | #define ATMEL_LCDC_DP2_3_VAL (0xfff) | ||
155 | #define ATMEL_LCDC_DP5_7_VAL (0xfffffff) | ||
156 | #define ATMEL_LCDC_DP3_4_VAL (0xffff) | ||
157 | #define ATMEL_LCDC_DP4_5_VAL (0xfffff) | ||
158 | #define ATMEL_LCDC_DP6_7_VAL (0xfffffff) | ||
159 | |||
160 | #define ATMEL_LCDC_PWRCON 0x083c | ||
161 | #define ATMEL_LCDC_PWR (1 << 0) | ||
162 | #define ATMEL_LCDC_GUARDT_OFFSET 1 | ||
163 | #define ATMEL_LCDC_GUARDT (0x7f << ATMEL_LCDC_GUARDT_OFFSET) | ||
164 | #define ATMEL_LCDC_BUSY (1 << 31) | ||
165 | |||
166 | #define ATMEL_LCDC_CONTRAST_CTR 0x0840 | ||
167 | #define ATMEL_LCDC_PS (3 << 0) | ||
168 | #define ATMEL_LCDC_PS_DIV1 (0 << 0) | ||
169 | #define ATMEL_LCDC_PS_DIV2 (1 << 0) | ||
170 | #define ATMEL_LCDC_PS_DIV4 (2 << 0) | ||
171 | #define ATMEL_LCDC_PS_DIV8 (3 << 0) | ||
172 | #define ATMEL_LCDC_POL (1 << 2) | ||
173 | #define ATMEL_LCDC_POL_NEGATIVE (0 << 2) | ||
174 | #define ATMEL_LCDC_POL_POSITIVE (1 << 2) | ||
175 | #define ATMEL_LCDC_ENA (1 << 3) | ||
176 | #define ATMEL_LCDC_ENA_PWMDISABLE (0 << 3) | ||
177 | #define ATMEL_LCDC_ENA_PWMENABLE (1 << 3) | ||
178 | |||
179 | #define ATMEL_LCDC_CONTRAST_VAL 0x0844 | ||
180 | #define ATMEL_LCDC_CVAL (0xff) | ||
181 | |||
182 | #define ATMEL_LCDC_IER 0x0848 | ||
183 | #define ATMEL_LCDC_IDR 0x084c | ||
184 | #define ATMEL_LCDC_IMR 0x0850 | ||
185 | #define ATMEL_LCDC_ISR 0x0854 | ||
186 | #define ATMEL_LCDC_ICR 0x0858 | ||
187 | #define ATMEL_LCDC_LNI (1 << 0) | ||
188 | #define ATMEL_LCDC_LSTLNI (1 << 1) | ||
189 | #define ATMEL_LCDC_EOFI (1 << 2) | ||
190 | #define ATMEL_LCDC_UFLWI (1 << 4) | ||
191 | #define ATMEL_LCDC_OWRI (1 << 5) | ||
192 | #define ATMEL_LCDC_MERI (1 << 6) | ||
193 | |||
194 | #define ATMEL_LCDC_LUT(n) (0x0c00 + ((n)*4)) | ||
195 | |||
196 | #endif /* __ATMEL_LCDC_H__ */ | ||
diff --git a/include/video/pm3fb.h b/include/video/pm3fb.h index 94c7d2da90ea..d52e45a1e9b8 100644 --- a/include/video/pm3fb.h +++ b/include/video/pm3fb.h | |||
@@ -7,9 +7,6 @@ | |||
7 | * This file is subject to the terms and conditions of the GNU General Public | 7 | * This file is subject to the terms and conditions of the GNU General Public |
8 | * License. See the file COPYING in the main directory of this archive for | 8 | * License. See the file COPYING in the main directory of this archive for |
9 | * more details. | 9 | * more details. |
10 | * | ||
11 | * $Header: /cvsroot/linux/drivers/video/pm3fb.h,v 1.1 2002/02/25 19:11:06 marcelo Exp $ | ||
12 | * | ||
13 | */ | 10 | */ |
14 | 11 | ||
15 | #ifndef PM3FB_H | 12 | #ifndef PM3FB_H |
@@ -1119,117 +1116,10 @@ | |||
1119 | /* ***** pm3fb useful define and macro ***** */ | 1116 | /* ***** pm3fb useful define and macro ***** */ |
1120 | /* ***************************************** */ | 1117 | /* ***************************************** */ |
1121 | 1118 | ||
1122 | /* permedia3 -specific definitions */ | ||
1123 | #define PM3_SCALE_TO_CLOCK(pr, fe, po) ((2 * PM3_REF_CLOCK * fe) / (pr * (1 << (po)))) | ||
1124 | |||
1125 | /* in case it's not in linux/pci.h */ | ||
1126 | #ifndef PCI_DEVICE_ID_3DLABS_PERMEDIA3 | ||
1127 | #define PCI_DEVICE_ID_3DLABS_PERMEDIA3 0x000a | ||
1128 | #endif | ||
1129 | |||
1130 | /* max number of simultaneous board */ | ||
1131 | #define PM3_MAX_BOARD 4 | ||
1132 | |||
1133 | /* max size of options */ | 1119 | /* max size of options */ |
1134 | #define PM3_OPTIONS_SIZE 256 | 1120 | #define PM3_OPTIONS_SIZE 256 |
1135 | 1121 | ||
1136 | /* max size of font name */ | 1122 | /* max size of font name */ |
1137 | #define PM3_FONTNAME_SIZE 40 | 1123 | #define PM3_FONTNAME_SIZE 40 |
1138 | 1124 | ||
1139 | /* do we want accelerated console */ | ||
1140 | #define PM3FB_USE_ACCEL 1 | ||
1141 | |||
1142 | /* for driver debugging ONLY */ | ||
1143 | /* 0 = assert only, 1 = error, 2 = info, 3+ = verbose */ | ||
1144 | /* define PM3FB_MASTER_DEBUG 1 */ | ||
1145 | #if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 3) | ||
1146 | #define PM3FB_TRACE | ||
1147 | #endif /* defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 3) */ | ||
1148 | |||
1149 | #ifdef PM3FB_MASTER_DEBUG | ||
1150 | #define DPRINTK(l,a,b...) do { if ((l) <= PM3FB_MASTER_DEBUG) printk("pm3fb: %s: " a, __FUNCTION__ , ## b); } while (0) | ||
1151 | #define DASSERT(t,a,b...) do { if (!(t)) printk("pm3fb: _assert failed: %s: " a, __FUNCTION__ , ## b); } while (0) | ||
1152 | #ifdef PM3FB_TRACE | ||
1153 | #define DTRACE printk("pm3fb: _enter %s\n", __FUNCTION__) | ||
1154 | #else /* PM3FB_TRACE */ | ||
1155 | #define DTRACE | ||
1156 | #endif /* PM3FB_TRACE */ | ||
1157 | #else /* PM3FB_MASTER_DEBUG */ | ||
1158 | #define DPRINTK(l,a,b...) | ||
1159 | #define DASSERT(t,a,b...) | ||
1160 | #define DTRACE | ||
1161 | #endif /* PM3FB_MASTER_DEBUG */ | ||
1162 | |||
1163 | #if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) | ||
1164 | #define PM3_SHOW_CUR_MODE pm3fb_show_cur_mode(l_fb_info) | ||
1165 | #else | ||
1166 | #define PM3_SHOW_CUR_MODE /* pm3fb_show_cur_mode() */ | ||
1167 | #endif | ||
1168 | |||
1169 | /* ******************************************** */ | ||
1170 | /* ***** A bunch of register-access macro ***** */ | ||
1171 | /* ******************************************** */ | ||
1172 | |||
1173 | #define PM3_WRITE_REG(r, v) fb_writel(v, (l_fb_info->vIOBase + r)) | ||
1174 | #define PM3_READ_REG(r) fb_readl((l_fb_info->vIOBase + r)) | ||
1175 | |||
1176 | |||
1177 | #define depth2bpp(d) ((d + 7L) & ~7L) | ||
1178 | #define depth2ByPP(d) (depth2bpp(d) / 8) | ||
1179 | |||
1180 | #define depth_supported(d) ((d == 8) || (d == 12) || (d == 15) || (d == 16) || (d==32)) | ||
1181 | |||
1182 | |||
1183 | #define PM3_WAIT(n) \ | ||
1184 | do{ \ | ||
1185 | while(PM3_READ_REG(PM3InFIFOSpace)<(n)); \ | ||
1186 | } while(0) | ||
1187 | |||
1188 | #define PM3_DELAY(x) do { \ | ||
1189 | int delay = x; \ | ||
1190 | unsigned char tmp; \ | ||
1191 | while(delay--){tmp = PM3_READ_REG(PM3InFIFOSpace);}; \ | ||
1192 | } while(0) | ||
1193 | |||
1194 | #define PM3_SLOW_WRITE_REG(r,v) \ | ||
1195 | do{ \ | ||
1196 | DASSERT((l_fb_info->vIOBase != (unsigned char*)(-1)), "l_fb_info->vIOBase mapped in slow write\n"); \ | ||
1197 | mb(); \ | ||
1198 | PM3_WAIT(1); \ | ||
1199 | mb(); \ | ||
1200 | PM3_WRITE_REG(r,v); \ | ||
1201 | } while(0) | ||
1202 | |||
1203 | #define PM3_SET_INDEX(index) \ | ||
1204 | do{ \ | ||
1205 | PM3_SLOW_WRITE_REG(PM3RD_IndexHigh,(((index)>>8)&0xff)); \ | ||
1206 | PM3_SLOW_WRITE_REG(PM3RD_IndexLow,((index)&0xff)); \ | ||
1207 | } while(0) | ||
1208 | |||
1209 | #define PM3_WRITE_DAC_REG(r, v) \ | ||
1210 | do { \ | ||
1211 | DASSERT((l_fb_info->vIOBase != (unsigned char*)(-1)), "l_fb_info->vIOBase mapped in write dac reg\n"); \ | ||
1212 | PM3_SET_INDEX(r); \ | ||
1213 | mb(); \ | ||
1214 | PM3_WRITE_REG(PM3RD_IndexedData, v); \ | ||
1215 | } while (0) | ||
1216 | |||
1217 | /* next one is really a function, added as a macro to be consistent */ | ||
1218 | #define PM3_READ_DAC_REG(r) pm3fb_read_dac_reg(l_fb_info, r) | ||
1219 | |||
1220 | |||
1221 | #define PM3_COLOR(c) \ | ||
1222 | do { \ | ||
1223 | if (l_fb_info->current_par->depth == 8) \ | ||
1224 | { \ | ||
1225 | c = (c & 0xFF); \ | ||
1226 | c = c | (c << 8); \ | ||
1227 | } \ | ||
1228 | if ((l_fb_info->current_par->depth == 8) || (depth2bpp(l_fb_info->current_par->depth) == 16)) \ | ||
1229 | { \ | ||
1230 | c = (c & 0xFFFF); \ | ||
1231 | c = c | (c << 16); \ | ||
1232 | } \ | ||
1233 | } while (0) | ||
1234 | |||
1235 | #endif /* PM3FB_H */ | 1125 | #endif /* PM3FB_H */ |
diff --git a/init/Kconfig b/init/Kconfig index 322b1f8c21b3..4e009fde4b69 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
@@ -475,13 +475,53 @@ config FUTEX | |||
475 | support for "fast userspace mutexes". The resulting kernel may not | 475 | support for "fast userspace mutexes". The resulting kernel may not |
476 | run glibc-based applications correctly. | 476 | run glibc-based applications correctly. |
477 | 477 | ||
478 | config ANON_INODES | ||
479 | bool "Enable anonymous inode source" if EMBEDDED | ||
480 | default y | ||
481 | help | ||
482 | Anonymous inode source for pseudo-files like epoll, signalfd, | ||
483 | timerfd and eventfd. | ||
484 | |||
485 | If unsure, say Y. | ||
486 | |||
478 | config EPOLL | 487 | config EPOLL |
479 | bool "Enable eventpoll support" if EMBEDDED | 488 | bool "Enable eventpoll support" if EMBEDDED |
480 | default y | 489 | default y |
490 | depends on ANON_INODES | ||
481 | help | 491 | help |
482 | Disabling this option will cause the kernel to be built without | 492 | Disabling this option will cause the kernel to be built without |
483 | support for epoll family of system calls. | 493 | support for epoll family of system calls. |
484 | 494 | ||
495 | config SIGNALFD | ||
496 | bool "Enable signalfd() system call" if EMBEDDED | ||
497 | depends on ANON_INODES | ||
498 | default y | ||
499 | help | ||
500 | Enable the signalfd() system call that allows to receive signals | ||
501 | on a file descriptor. | ||
502 | |||
503 | If unsure, say Y. | ||
504 | |||
505 | config TIMERFD | ||
506 | bool "Enable timerfd() system call" if EMBEDDED | ||
507 | depends on ANON_INODES | ||
508 | default y | ||
509 | help | ||
510 | Enable the timerfd() system call that allows to receive timer | ||
511 | events on a file descriptor. | ||
512 | |||
513 | If unsure, say Y. | ||
514 | |||
515 | config EVENTFD | ||
516 | bool "Enable eventfd() system call" if EMBEDDED | ||
517 | depends on ANON_INODES | ||
518 | default y | ||
519 | help | ||
520 | Enable the eventfd() system call that allows to receive both | ||
521 | kernel notification (ie. KAIO) or userspace notifications. | ||
522 | |||
523 | If unsure, say Y. | ||
524 | |||
485 | config SHMEM | 525 | config SHMEM |
486 | bool "Use full shmem filesystem" if EMBEDDED | 526 | bool "Use full shmem filesystem" if EMBEDDED |
487 | default y | 527 | default y |
diff --git a/init/main.c b/init/main.c index e8d080cab443..1940fa75e82e 100644 --- a/init/main.c +++ b/init/main.c | |||
@@ -801,6 +801,7 @@ static int __init kernel_init(void * unused) | |||
801 | */ | 801 | */ |
802 | init_pid_ns.child_reaper = current; | 802 | init_pid_ns.child_reaper = current; |
803 | 803 | ||
804 | __set_special_pids(1, 1); | ||
804 | cad_pid = task_pid(current); | 805 | cad_pid = task_pid(current); |
805 | 806 | ||
806 | smp_prepare_cpus(max_cpus); | 807 | smp_prepare_cpus(max_cpus); |
diff --git a/kernel/compat.c b/kernel/compat.c index cebb4c28c039..3bae3742c2aa 100644 --- a/kernel/compat.c +++ b/kernel/compat.c | |||
@@ -475,8 +475,8 @@ asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len, | |||
475 | return min_length; | 475 | return min_length; |
476 | } | 476 | } |
477 | 477 | ||
478 | static int get_compat_itimerspec(struct itimerspec *dst, | 478 | int get_compat_itimerspec(struct itimerspec *dst, |
479 | struct compat_itimerspec __user *src) | 479 | const struct compat_itimerspec __user *src) |
480 | { | 480 | { |
481 | if (get_compat_timespec(&dst->it_interval, &src->it_interval) || | 481 | if (get_compat_timespec(&dst->it_interval, &src->it_interval) || |
482 | get_compat_timespec(&dst->it_value, &src->it_value)) | 482 | get_compat_timespec(&dst->it_value, &src->it_value)) |
@@ -484,8 +484,8 @@ static int get_compat_itimerspec(struct itimerspec *dst, | |||
484 | return 0; | 484 | return 0; |
485 | } | 485 | } |
486 | 486 | ||
487 | static int put_compat_itimerspec(struct compat_itimerspec __user *dst, | 487 | int put_compat_itimerspec(struct compat_itimerspec __user *dst, |
488 | struct itimerspec *src) | 488 | const struct itimerspec *src) |
489 | { | 489 | { |
490 | if (put_compat_timespec(&src->it_interval, &dst->it_interval) || | 490 | if (put_compat_timespec(&src->it_interval, &dst->it_interval) || |
491 | put_compat_timespec(&src->it_value, &dst->it_value)) | 491 | put_compat_timespec(&src->it_value, &dst->it_value)) |
diff --git a/kernel/exit.c b/kernel/exit.c index b0c6f0c3a2df..c6d14b8008dd 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/pid_namespace.h> | 24 | #include <linux/pid_namespace.h> |
25 | #include <linux/ptrace.h> | 25 | #include <linux/ptrace.h> |
26 | #include <linux/profile.h> | 26 | #include <linux/profile.h> |
27 | #include <linux/signalfd.h> | ||
27 | #include <linux/mount.h> | 28 | #include <linux/mount.h> |
28 | #include <linux/proc_fs.h> | 29 | #include <linux/proc_fs.h> |
29 | #include <linux/kthread.h> | 30 | #include <linux/kthread.h> |
@@ -42,6 +43,7 @@ | |||
42 | #include <linux/audit.h> /* for audit_free() */ | 43 | #include <linux/audit.h> /* for audit_free() */ |
43 | #include <linux/resource.h> | 44 | #include <linux/resource.h> |
44 | #include <linux/blkdev.h> | 45 | #include <linux/blkdev.h> |
46 | #include <linux/task_io_accounting_ops.h> | ||
45 | 47 | ||
46 | #include <asm/uaccess.h> | 48 | #include <asm/uaccess.h> |
47 | #include <asm/unistd.h> | 49 | #include <asm/unistd.h> |
@@ -82,6 +84,14 @@ static void __exit_signal(struct task_struct *tsk) | |||
82 | sighand = rcu_dereference(tsk->sighand); | 84 | sighand = rcu_dereference(tsk->sighand); |
83 | spin_lock(&sighand->siglock); | 85 | spin_lock(&sighand->siglock); |
84 | 86 | ||
87 | /* | ||
88 | * Notify that this sighand has been detached. This must | ||
89 | * be called with the tsk->sighand lock held. Also, this | ||
90 | * access tsk->sighand internally, so it must be called | ||
91 | * before tsk->sighand is reset. | ||
92 | */ | ||
93 | signalfd_detach_locked(tsk); | ||
94 | |||
85 | posix_cpu_timers_exit(tsk); | 95 | posix_cpu_timers_exit(tsk); |
86 | if (atomic_dec_and_test(&sig->count)) | 96 | if (atomic_dec_and_test(&sig->count)) |
87 | posix_cpu_timers_exit_group(tsk); | 97 | posix_cpu_timers_exit_group(tsk); |
@@ -113,6 +123,8 @@ static void __exit_signal(struct task_struct *tsk) | |||
113 | sig->nvcsw += tsk->nvcsw; | 123 | sig->nvcsw += tsk->nvcsw; |
114 | sig->nivcsw += tsk->nivcsw; | 124 | sig->nivcsw += tsk->nivcsw; |
115 | sig->sched_time += tsk->sched_time; | 125 | sig->sched_time += tsk->sched_time; |
126 | sig->inblock += task_io_get_inblock(tsk); | ||
127 | sig->oublock += task_io_get_oublock(tsk); | ||
116 | sig = NULL; /* Marker for below. */ | 128 | sig = NULL; /* Marker for below. */ |
117 | } | 129 | } |
118 | 130 | ||
@@ -299,12 +311,12 @@ void __set_special_pids(pid_t session, pid_t pgrp) | |||
299 | if (process_session(curr) != session) { | 311 | if (process_session(curr) != session) { |
300 | detach_pid(curr, PIDTYPE_SID); | 312 | detach_pid(curr, PIDTYPE_SID); |
301 | set_signal_session(curr->signal, session); | 313 | set_signal_session(curr->signal, session); |
302 | attach_pid(curr, PIDTYPE_SID, session); | 314 | attach_pid(curr, PIDTYPE_SID, find_pid(session)); |
303 | } | 315 | } |
304 | if (process_group(curr) != pgrp) { | 316 | if (process_group(curr) != pgrp) { |
305 | detach_pid(curr, PIDTYPE_PGID); | 317 | detach_pid(curr, PIDTYPE_PGID); |
306 | curr->signal->pgrp = pgrp; | 318 | curr->signal->pgrp = pgrp; |
307 | attach_pid(curr, PIDTYPE_PGID, pgrp); | 319 | attach_pid(curr, PIDTYPE_PGID, find_pid(pgrp)); |
308 | } | 320 | } |
309 | } | 321 | } |
310 | 322 | ||
@@ -1193,6 +1205,12 @@ static int wait_task_zombie(struct task_struct *p, int noreap, | |||
1193 | p->nvcsw + sig->nvcsw + sig->cnvcsw; | 1205 | p->nvcsw + sig->nvcsw + sig->cnvcsw; |
1194 | psig->cnivcsw += | 1206 | psig->cnivcsw += |
1195 | p->nivcsw + sig->nivcsw + sig->cnivcsw; | 1207 | p->nivcsw + sig->nivcsw + sig->cnivcsw; |
1208 | psig->cinblock += | ||
1209 | task_io_get_inblock(p) + | ||
1210 | sig->inblock + sig->cinblock; | ||
1211 | psig->coublock += | ||
1212 | task_io_get_oublock(p) + | ||
1213 | sig->oublock + sig->coublock; | ||
1196 | spin_unlock_irq(&p->parent->sighand->siglock); | 1214 | spin_unlock_irq(&p->parent->sighand->siglock); |
1197 | } | 1215 | } |
1198 | 1216 | ||
diff --git a/kernel/fork.c b/kernel/fork.c index 5dd3979747f5..49530e40ea8b 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -875,6 +875,7 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts | |||
875 | sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero; | 875 | sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero; |
876 | sig->nvcsw = sig->nivcsw = sig->cnvcsw = sig->cnivcsw = 0; | 876 | sig->nvcsw = sig->nivcsw = sig->cnvcsw = sig->cnivcsw = 0; |
877 | sig->min_flt = sig->maj_flt = sig->cmin_flt = sig->cmaj_flt = 0; | 877 | sig->min_flt = sig->maj_flt = sig->cmin_flt = sig->cmaj_flt = 0; |
878 | sig->inblock = sig->oublock = sig->cinblock = sig->coublock = 0; | ||
878 | sig->sched_time = 0; | 879 | sig->sched_time = 0; |
879 | INIT_LIST_HEAD(&sig->cpu_timers[0]); | 880 | INIT_LIST_HEAD(&sig->cpu_timers[0]); |
880 | INIT_LIST_HEAD(&sig->cpu_timers[1]); | 881 | INIT_LIST_HEAD(&sig->cpu_timers[1]); |
@@ -955,7 +956,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
955 | unsigned long stack_size, | 956 | unsigned long stack_size, |
956 | int __user *parent_tidptr, | 957 | int __user *parent_tidptr, |
957 | int __user *child_tidptr, | 958 | int __user *child_tidptr, |
958 | int pid) | 959 | struct pid *pid) |
959 | { | 960 | { |
960 | int retval; | 961 | int retval; |
961 | struct task_struct *p = NULL; | 962 | struct task_struct *p = NULL; |
@@ -1022,7 +1023,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1022 | p->did_exec = 0; | 1023 | p->did_exec = 0; |
1023 | delayacct_tsk_init(p); /* Must remain after dup_task_struct() */ | 1024 | delayacct_tsk_init(p); /* Must remain after dup_task_struct() */ |
1024 | copy_flags(clone_flags, p); | 1025 | copy_flags(clone_flags, p); |
1025 | p->pid = pid; | 1026 | p->pid = pid_nr(pid); |
1026 | retval = -EFAULT; | 1027 | retval = -EFAULT; |
1027 | if (clone_flags & CLONE_PARENT_SETTID) | 1028 | if (clone_flags & CLONE_PARENT_SETTID) |
1028 | if (put_user(p->pid, parent_tidptr)) | 1029 | if (put_user(p->pid, parent_tidptr)) |
@@ -1251,13 +1252,13 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
1251 | p->signal->tty = current->signal->tty; | 1252 | p->signal->tty = current->signal->tty; |
1252 | p->signal->pgrp = process_group(current); | 1253 | p->signal->pgrp = process_group(current); |
1253 | set_signal_session(p->signal, process_session(current)); | 1254 | set_signal_session(p->signal, process_session(current)); |
1254 | attach_pid(p, PIDTYPE_PGID, process_group(p)); | 1255 | attach_pid(p, PIDTYPE_PGID, task_pgrp(current)); |
1255 | attach_pid(p, PIDTYPE_SID, process_session(p)); | 1256 | attach_pid(p, PIDTYPE_SID, task_session(current)); |
1256 | 1257 | ||
1257 | list_add_tail_rcu(&p->tasks, &init_task.tasks); | 1258 | list_add_tail_rcu(&p->tasks, &init_task.tasks); |
1258 | __get_cpu_var(process_counts)++; | 1259 | __get_cpu_var(process_counts)++; |
1259 | } | 1260 | } |
1260 | attach_pid(p, PIDTYPE_PID, p->pid); | 1261 | attach_pid(p, PIDTYPE_PID, pid); |
1261 | nr_threads++; | 1262 | nr_threads++; |
1262 | } | 1263 | } |
1263 | 1264 | ||
@@ -1321,7 +1322,8 @@ struct task_struct * __cpuinit fork_idle(int cpu) | |||
1321 | struct task_struct *task; | 1322 | struct task_struct *task; |
1322 | struct pt_regs regs; | 1323 | struct pt_regs regs; |
1323 | 1324 | ||
1324 | task = copy_process(CLONE_VM, 0, idle_regs(®s), 0, NULL, NULL, 0); | 1325 | task = copy_process(CLONE_VM, 0, idle_regs(®s), 0, NULL, NULL, |
1326 | &init_struct_pid); | ||
1325 | if (!IS_ERR(task)) | 1327 | if (!IS_ERR(task)) |
1326 | init_idle(task, cpu); | 1328 | init_idle(task, cpu); |
1327 | 1329 | ||
@@ -1371,7 +1373,7 @@ long do_fork(unsigned long clone_flags, | |||
1371 | clone_flags |= CLONE_PTRACE; | 1373 | clone_flags |= CLONE_PTRACE; |
1372 | } | 1374 | } |
1373 | 1375 | ||
1374 | p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, nr); | 1376 | p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, pid); |
1375 | /* | 1377 | /* |
1376 | * Do this prior waking up the new thread - the thread pointer | 1378 | * Do this prior waking up the new thread - the thread pointer |
1377 | * might get invalid after that point, if the thread exits quickly. | 1379 | * might get invalid after that point, if the thread exits quickly. |
@@ -1420,12 +1422,15 @@ long do_fork(unsigned long clone_flags, | |||
1420 | #define ARCH_MIN_MMSTRUCT_ALIGN 0 | 1422 | #define ARCH_MIN_MMSTRUCT_ALIGN 0 |
1421 | #endif | 1423 | #endif |
1422 | 1424 | ||
1423 | static void sighand_ctor(void *data, struct kmem_cache *cachep, unsigned long flags) | 1425 | static void sighand_ctor(void *data, struct kmem_cache *cachep, |
1426 | unsigned long flags) | ||
1424 | { | 1427 | { |
1425 | struct sighand_struct *sighand = data; | 1428 | struct sighand_struct *sighand = data; |
1426 | 1429 | ||
1427 | if (flags & SLAB_CTOR_CONSTRUCTOR) | 1430 | if (flags & SLAB_CTOR_CONSTRUCTOR) { |
1428 | spin_lock_init(&sighand->siglock); | 1431 | spin_lock_init(&sighand->siglock); |
1432 | INIT_LIST_HEAD(&sighand->signalfd_list); | ||
1433 | } | ||
1429 | } | 1434 | } |
1430 | 1435 | ||
1431 | void __init proc_caches_init(void) | 1436 | void __init proc_caches_init(void) |
@@ -1451,7 +1456,6 @@ void __init proc_caches_init(void) | |||
1451 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); | 1456 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); |
1452 | } | 1457 | } |
1453 | 1458 | ||
1454 | |||
1455 | /* | 1459 | /* |
1456 | * Check constraints on flags passed to the unshare system call and | 1460 | * Check constraints on flags passed to the unshare system call and |
1457 | * force unsharing of additional process context as appropriate. | 1461 | * force unsharing of additional process context as appropriate. |
diff --git a/kernel/pid.c b/kernel/pid.c index d3ad724afa83..eb66bd2953ab 100644 --- a/kernel/pid.c +++ b/kernel/pid.c | |||
@@ -27,11 +27,13 @@ | |||
27 | #include <linux/bootmem.h> | 27 | #include <linux/bootmem.h> |
28 | #include <linux/hash.h> | 28 | #include <linux/hash.h> |
29 | #include <linux/pid_namespace.h> | 29 | #include <linux/pid_namespace.h> |
30 | #include <linux/init_task.h> | ||
30 | 31 | ||
31 | #define pid_hashfn(nr) hash_long((unsigned long)nr, pidhash_shift) | 32 | #define pid_hashfn(nr) hash_long((unsigned long)nr, pidhash_shift) |
32 | static struct hlist_head *pid_hash; | 33 | static struct hlist_head *pid_hash; |
33 | static int pidhash_shift; | 34 | static int pidhash_shift; |
34 | static struct kmem_cache *pid_cachep; | 35 | static struct kmem_cache *pid_cachep; |
36 | struct pid init_struct_pid = INIT_STRUCT_PID; | ||
35 | 37 | ||
36 | int pid_max = PID_MAX_DEFAULT; | 38 | int pid_max = PID_MAX_DEFAULT; |
37 | 39 | ||
@@ -247,13 +249,16 @@ struct pid * fastcall find_pid(int nr) | |||
247 | } | 249 | } |
248 | EXPORT_SYMBOL_GPL(find_pid); | 250 | EXPORT_SYMBOL_GPL(find_pid); |
249 | 251 | ||
250 | int fastcall attach_pid(struct task_struct *task, enum pid_type type, int nr) | 252 | /* |
253 | * attach_pid() must be called with the tasklist_lock write-held. | ||
254 | */ | ||
255 | int fastcall attach_pid(struct task_struct *task, enum pid_type type, | ||
256 | struct pid *pid) | ||
251 | { | 257 | { |
252 | struct pid_link *link; | 258 | struct pid_link *link; |
253 | struct pid *pid; | ||
254 | 259 | ||
255 | link = &task->pids[type]; | 260 | link = &task->pids[type]; |
256 | link->pid = pid = find_pid(nr); | 261 | link->pid = pid; |
257 | hlist_add_head_rcu(&link->node, &pid->tasks[type]); | 262 | hlist_add_head_rcu(&link->node, &pid->tasks[type]); |
258 | 263 | ||
259 | return 0; | 264 | return 0; |
diff --git a/kernel/signal.c b/kernel/signal.c index c43a3f19d477..364fc95bf97c 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/syscalls.h> | 21 | #include <linux/syscalls.h> |
22 | #include <linux/ptrace.h> | 22 | #include <linux/ptrace.h> |
23 | #include <linux/signal.h> | 23 | #include <linux/signal.h> |
24 | #include <linux/signalfd.h> | ||
24 | #include <linux/capability.h> | 25 | #include <linux/capability.h> |
25 | #include <linux/freezer.h> | 26 | #include <linux/freezer.h> |
26 | #include <linux/pid_namespace.h> | 27 | #include <linux/pid_namespace.h> |
@@ -113,8 +114,7 @@ void recalc_sigpending(void) | |||
113 | 114 | ||
114 | /* Given the mask, find the first available signal that should be serviced. */ | 115 | /* Given the mask, find the first available signal that should be serviced. */ |
115 | 116 | ||
116 | static int | 117 | int next_signal(struct sigpending *pending, sigset_t *mask) |
117 | next_signal(struct sigpending *pending, sigset_t *mask) | ||
118 | { | 118 | { |
119 | unsigned long i, *s, *m, x; | 119 | unsigned long i, *s, *m, x; |
120 | int sig = 0; | 120 | int sig = 0; |
@@ -632,6 +632,12 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t, | |||
632 | int ret = 0; | 632 | int ret = 0; |
633 | 633 | ||
634 | /* | 634 | /* |
635 | * Deliver the signal to listening signalfds. This must be called | ||
636 | * with the sighand lock held. | ||
637 | */ | ||
638 | signalfd_notify(t, sig); | ||
639 | |||
640 | /* | ||
635 | * fast-pathed signals for kernel-internal things like SIGSTOP | 641 | * fast-pathed signals for kernel-internal things like SIGSTOP |
636 | * or SIGKILL. | 642 | * or SIGKILL. |
637 | */ | 643 | */ |
@@ -1282,6 +1288,11 @@ int send_sigqueue(int sig, struct sigqueue *q, struct task_struct *p) | |||
1282 | ret = 1; | 1288 | ret = 1; |
1283 | goto out; | 1289 | goto out; |
1284 | } | 1290 | } |
1291 | /* | ||
1292 | * Deliver the signal to listening signalfds. This must be called | ||
1293 | * with the sighand lock held. | ||
1294 | */ | ||
1295 | signalfd_notify(p, sig); | ||
1285 | 1296 | ||
1286 | list_add_tail(&q->list, &p->pending.list); | 1297 | list_add_tail(&q->list, &p->pending.list); |
1287 | sigaddset(&p->pending.signal, sig); | 1298 | sigaddset(&p->pending.signal, sig); |
@@ -1325,6 +1336,11 @@ send_group_sigqueue(int sig, struct sigqueue *q, struct task_struct *p) | |||
1325 | q->info.si_overrun++; | 1336 | q->info.si_overrun++; |
1326 | goto out; | 1337 | goto out; |
1327 | } | 1338 | } |
1339 | /* | ||
1340 | * Deliver the signal to listening signalfds. This must be called | ||
1341 | * with the sighand lock held. | ||
1342 | */ | ||
1343 | signalfd_notify(p, sig); | ||
1328 | 1344 | ||
1329 | /* | 1345 | /* |
1330 | * Put this signal on the shared-pending queue. | 1346 | * Put this signal on the shared-pending queue. |
@@ -1985,6 +2001,8 @@ int copy_siginfo_to_user(siginfo_t __user *to, siginfo_t *from) | |||
1985 | /* | 2001 | /* |
1986 | * If you change siginfo_t structure, please be sure | 2002 | * If you change siginfo_t structure, please be sure |
1987 | * this code is fixed accordingly. | 2003 | * this code is fixed accordingly. |
2004 | * Please remember to update the signalfd_copyinfo() function | ||
2005 | * inside fs/signalfd.c too, in case siginfo_t changes. | ||
1988 | * It should never copy any pad contained in the structure | 2006 | * It should never copy any pad contained in the structure |
1989 | * to avoid security leaks, but must copy the generic | 2007 | * to avoid security leaks, but must copy the generic |
1990 | * 3 ints plus the relevant union member. | 2008 | * 3 ints plus the relevant union member. |
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c index daabb74ee0bc..fcee2a8e6da3 100644 --- a/kernel/stop_machine.c +++ b/kernel/stop_machine.c | |||
@@ -8,6 +8,8 @@ | |||
8 | #include <linux/sched.h> | 8 | #include <linux/sched.h> |
9 | #include <linux/stop_machine.h> | 9 | #include <linux/stop_machine.h> |
10 | #include <linux/syscalls.h> | 10 | #include <linux/syscalls.h> |
11 | #include <linux/interrupt.h> | ||
12 | |||
11 | #include <asm/atomic.h> | 13 | #include <asm/atomic.h> |
12 | #include <asm/semaphore.h> | 14 | #include <asm/semaphore.h> |
13 | #include <asm/uaccess.h> | 15 | #include <asm/uaccess.h> |
@@ -45,6 +47,7 @@ static int stopmachine(void *cpu) | |||
45 | if (stopmachine_state == STOPMACHINE_DISABLE_IRQ | 47 | if (stopmachine_state == STOPMACHINE_DISABLE_IRQ |
46 | && !irqs_disabled) { | 48 | && !irqs_disabled) { |
47 | local_irq_disable(); | 49 | local_irq_disable(); |
50 | hard_irq_disable(); | ||
48 | irqs_disabled = 1; | 51 | irqs_disabled = 1; |
49 | /* Ack: irqs disabled. */ | 52 | /* Ack: irqs disabled. */ |
50 | smp_mb(); /* Must read state first. */ | 53 | smp_mb(); /* Must read state first. */ |
@@ -124,6 +127,7 @@ static int stop_machine(void) | |||
124 | 127 | ||
125 | /* Make them disable irqs. */ | 128 | /* Make them disable irqs. */ |
126 | local_irq_disable(); | 129 | local_irq_disable(); |
130 | hard_irq_disable(); | ||
127 | stopmachine_set_state(STOPMACHINE_DISABLE_IRQ); | 131 | stopmachine_set_state(STOPMACHINE_DISABLE_IRQ); |
128 | 132 | ||
129 | return 0; | 133 | return 0; |
diff --git a/kernel/sys.c b/kernel/sys.c index cdb7e9457ba6..872271ccc384 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/prctl.h> | 14 | #include <linux/prctl.h> |
15 | #include <linux/highuid.h> | 15 | #include <linux/highuid.h> |
16 | #include <linux/fs.h> | 16 | #include <linux/fs.h> |
17 | #include <linux/resource.h> | ||
17 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
18 | #include <linux/kexec.h> | 19 | #include <linux/kexec.h> |
19 | #include <linux/workqueue.h> | 20 | #include <linux/workqueue.h> |
@@ -29,6 +30,7 @@ | |||
29 | #include <linux/signal.h> | 30 | #include <linux/signal.h> |
30 | #include <linux/cn_proc.h> | 31 | #include <linux/cn_proc.h> |
31 | #include <linux/getcpu.h> | 32 | #include <linux/getcpu.h> |
33 | #include <linux/task_io_accounting_ops.h> | ||
32 | 34 | ||
33 | #include <linux/compat.h> | 35 | #include <linux/compat.h> |
34 | #include <linux/syscalls.h> | 36 | #include <linux/syscalls.h> |
@@ -658,7 +660,7 @@ asmlinkage long sys_setpriority(int which, int who, int niceval) | |||
658 | int error = -EINVAL; | 660 | int error = -EINVAL; |
659 | struct pid *pgrp; | 661 | struct pid *pgrp; |
660 | 662 | ||
661 | if (which > 2 || which < 0) | 663 | if (which > PRIO_USER || which < PRIO_PROCESS) |
662 | goto out; | 664 | goto out; |
663 | 665 | ||
664 | /* normalize: avoid signed division (rounding problems) */ | 666 | /* normalize: avoid signed division (rounding problems) */ |
@@ -722,7 +724,7 @@ asmlinkage long sys_getpriority(int which, int who) | |||
722 | long niceval, retval = -ESRCH; | 724 | long niceval, retval = -ESRCH; |
723 | struct pid *pgrp; | 725 | struct pid *pgrp; |
724 | 726 | ||
725 | if (which > 2 || which < 0) | 727 | if (which > PRIO_USER || which < PRIO_PROCESS) |
726 | return -EINVAL; | 728 | return -EINVAL; |
727 | 729 | ||
728 | read_lock(&tasklist_lock); | 730 | read_lock(&tasklist_lock); |
@@ -1486,7 +1488,7 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) | |||
1486 | if (process_group(p) != pgid) { | 1488 | if (process_group(p) != pgid) { |
1487 | detach_pid(p, PIDTYPE_PGID); | 1489 | detach_pid(p, PIDTYPE_PGID); |
1488 | p->signal->pgrp = pgid; | 1490 | p->signal->pgrp = pgid; |
1489 | attach_pid(p, PIDTYPE_PGID, pgid); | 1491 | attach_pid(p, PIDTYPE_PGID, find_pid(pgid)); |
1490 | } | 1492 | } |
1491 | 1493 | ||
1492 | err = 0; | 1494 | err = 0; |
@@ -2082,6 +2084,8 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) | |||
2082 | r->ru_nivcsw = p->signal->cnivcsw; | 2084 | r->ru_nivcsw = p->signal->cnivcsw; |
2083 | r->ru_minflt = p->signal->cmin_flt; | 2085 | r->ru_minflt = p->signal->cmin_flt; |
2084 | r->ru_majflt = p->signal->cmaj_flt; | 2086 | r->ru_majflt = p->signal->cmaj_flt; |
2087 | r->ru_inblock = p->signal->cinblock; | ||
2088 | r->ru_oublock = p->signal->coublock; | ||
2085 | 2089 | ||
2086 | if (who == RUSAGE_CHILDREN) | 2090 | if (who == RUSAGE_CHILDREN) |
2087 | break; | 2091 | break; |
@@ -2093,6 +2097,8 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) | |||
2093 | r->ru_nivcsw += p->signal->nivcsw; | 2097 | r->ru_nivcsw += p->signal->nivcsw; |
2094 | r->ru_minflt += p->signal->min_flt; | 2098 | r->ru_minflt += p->signal->min_flt; |
2095 | r->ru_majflt += p->signal->maj_flt; | 2099 | r->ru_majflt += p->signal->maj_flt; |
2100 | r->ru_inblock += p->signal->inblock; | ||
2101 | r->ru_oublock += p->signal->oublock; | ||
2096 | t = p; | 2102 | t = p; |
2097 | do { | 2103 | do { |
2098 | utime = cputime_add(utime, t->utime); | 2104 | utime = cputime_add(utime, t->utime); |
@@ -2101,6 +2107,8 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) | |||
2101 | r->ru_nivcsw += t->nivcsw; | 2107 | r->ru_nivcsw += t->nivcsw; |
2102 | r->ru_minflt += t->min_flt; | 2108 | r->ru_minflt += t->min_flt; |
2103 | r->ru_majflt += t->maj_flt; | 2109 | r->ru_majflt += t->maj_flt; |
2110 | r->ru_inblock += task_io_get_inblock(t); | ||
2111 | r->ru_oublock += task_io_get_oublock(t); | ||
2104 | t = next_thread(t); | 2112 | t = next_thread(t); |
2105 | } while (t != p); | 2113 | } while (t != p); |
2106 | break; | 2114 | break; |
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index d7306d0f3dfc..b6d77a8a1ca9 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c | |||
@@ -141,3 +141,8 @@ cond_syscall(compat_sys_migrate_pages); | |||
141 | cond_syscall(sys_bdflush); | 141 | cond_syscall(sys_bdflush); |
142 | cond_syscall(sys_ioprio_set); | 142 | cond_syscall(sys_ioprio_set); |
143 | cond_syscall(sys_ioprio_get); | 143 | cond_syscall(sys_ioprio_get); |
144 | |||
145 | /* New file descriptors */ | ||
146 | cond_syscall(sys_signalfd); | ||
147 | cond_syscall(sys_timerfd); | ||
148 | cond_syscall(sys_eventfd); | ||
diff --git a/lib/Makefile b/lib/Makefile index 1f65b4613e09..c8c8e20784ce 100644 --- a/lib/Makefile +++ b/lib/Makefile | |||
@@ -13,7 +13,7 @@ lib-$(CONFIG_SMP) += cpumask.o | |||
13 | lib-y += kobject.o kref.o kobject_uevent.o klist.o | 13 | lib-y += kobject.o kref.o kobject_uevent.o klist.o |
14 | 14 | ||
15 | obj-y += div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ | 15 | obj-y += div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ |
16 | bust_spinlocks.o | 16 | bust_spinlocks.o hexdump.o |
17 | 17 | ||
18 | ifeq ($(CONFIG_DEBUG_KOBJECT),y) | 18 | ifeq ($(CONFIG_DEBUG_KOBJECT),y) |
19 | CFLAGS_kobject.o += -DDEBUG | 19 | CFLAGS_kobject.o += -DDEBUG |
diff --git a/lib/hexdump.c b/lib/hexdump.c new file mode 100644 index 000000000000..e6da5b7fc29a --- /dev/null +++ b/lib/hexdump.c | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * lib/hexdump.c | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. See README and COPYING for | ||
7 | * more details. | ||
8 | */ | ||
9 | |||
10 | #include <linux/types.h> | ||
11 | #include <linux/ctype.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/module.h> | ||
14 | |||
15 | /** | ||
16 | * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory | ||
17 | * @buf: data blob to dump | ||
18 | * @len: number of bytes in the @buf | ||
19 | * @linebuf: where to put the converted data | ||
20 | * @linebuflen: total size of @linebuf, including space for terminating NUL | ||
21 | * | ||
22 | * hex_dump_to_buffer() works on one "line" of output at a time, i.e., | ||
23 | * 16 bytes of input data converted to hex + ASCII output. | ||
24 | * | ||
25 | * Given a buffer of u8 data, hex_dump_to_buffer() converts the input data | ||
26 | * to a hex + ASCII dump at the supplied memory location. | ||
27 | * The converted output is always NUL-terminated. | ||
28 | * | ||
29 | * E.g.: | ||
30 | * hex_dump_to_buffer(frame->data, frame->len, linebuf, sizeof(linebuf)); | ||
31 | * | ||
32 | * example output buffer: | ||
33 | * 40414243 44454647 48494a4b 4c4d4e4f @ABCDEFGHIJKLMNO | ||
34 | */ | ||
35 | void hex_dump_to_buffer(const void *buf, size_t len, char *linebuf, | ||
36 | size_t linebuflen) | ||
37 | { | ||
38 | const u8 *ptr = buf; | ||
39 | u8 ch; | ||
40 | int j, lx = 0; | ||
41 | |||
42 | for (j = 0; (j < 16) && (j < len) && (lx + 3) < linebuflen; j++) { | ||
43 | if (j && !(j % 4)) | ||
44 | linebuf[lx++] = ' '; | ||
45 | ch = ptr[j]; | ||
46 | linebuf[lx++] = hex_asc(ch >> 4); | ||
47 | linebuf[lx++] = hex_asc(ch & 0x0f); | ||
48 | } | ||
49 | if ((lx + 2) < linebuflen) { | ||
50 | linebuf[lx++] = ' '; | ||
51 | linebuf[lx++] = ' '; | ||
52 | } | ||
53 | for (j = 0; (j < 16) && (j < len) && (lx + 2) < linebuflen; j++) | ||
54 | linebuf[lx++] = isprint(ptr[j]) ? ptr[j] : '.'; | ||
55 | linebuf[lx++] = '\0'; | ||
56 | } | ||
57 | EXPORT_SYMBOL(hex_dump_to_buffer); | ||
58 | |||
59 | /** | ||
60 | * print_hex_dump - print a text hex dump to syslog for a binary blob of data | ||
61 | * @level: kernel log level (e.g. KERN_DEBUG) | ||
62 | * @prefix_type: controls whether prefix of an offset, address, or none | ||
63 | * is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE) | ||
64 | * @buf: data blob to dump | ||
65 | * @len: number of bytes in the @buf | ||
66 | * | ||
67 | * Given a buffer of u8 data, print_hex_dump() prints a hex + ASCII dump | ||
68 | * to the kernel log at the specified kernel log level, with an optional | ||
69 | * leading prefix. | ||
70 | * | ||
71 | * E.g.: | ||
72 | * print_hex_dump(KERN_DEBUG, DUMP_PREFIX_ADDRESS, frame->data, frame->len); | ||
73 | * | ||
74 | * Example output using %DUMP_PREFIX_OFFSET: | ||
75 | * 0009ab42: 40414243 44454647 48494a4b 4c4d4e4f @ABCDEFGHIJKLMNO | ||
76 | * Example output using %DUMP_PREFIX_ADDRESS: | ||
77 | * ffffffff88089af0: 70717273 74757677 78797a7b 7c7d7e7f pqrstuvwxyz{|}~. | ||
78 | */ | ||
79 | void print_hex_dump(const char *level, int prefix_type, void *buf, size_t len) | ||
80 | { | ||
81 | u8 *ptr = buf; | ||
82 | int i, linelen, remaining = len; | ||
83 | unsigned char linebuf[100]; | ||
84 | |||
85 | for (i = 0; i < len; i += 16) { | ||
86 | linelen = min(remaining, 16); | ||
87 | remaining -= 16; | ||
88 | hex_dump_to_buffer(ptr + i, linelen, linebuf, sizeof(linebuf)); | ||
89 | |||
90 | switch (prefix_type) { | ||
91 | case DUMP_PREFIX_ADDRESS: | ||
92 | printk("%s%*p: %s\n", level, | ||
93 | (int)(2 * sizeof(void *)), ptr + i, linebuf); | ||
94 | break; | ||
95 | case DUMP_PREFIX_OFFSET: | ||
96 | printk("%s%.8x: %s\n", level, i, linebuf); | ||
97 | break; | ||
98 | default: | ||
99 | printk("%s%s\n", level, linebuf); | ||
100 | break; | ||
101 | } | ||
102 | } | ||
103 | } | ||
104 | EXPORT_SYMBOL(print_hex_dump); | ||
diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 63cd88840eb2..eec1481ba44f 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c | |||
@@ -588,31 +588,27 @@ void __init page_writeback_init(void) | |||
588 | } | 588 | } |
589 | 589 | ||
590 | /** | 590 | /** |
591 | * generic_writepages - walk the list of dirty pages of the given address space and writepage() all of them. | 591 | * write_cache_pages - walk the list of dirty pages of the given address space and write all of them. |
592 | * @mapping: address space structure to write | 592 | * @mapping: address space structure to write |
593 | * @wbc: subtract the number of written pages from *@wbc->nr_to_write | 593 | * @wbc: subtract the number of written pages from *@wbc->nr_to_write |
594 | * @writepage: function called for each page | ||
595 | * @data: data passed to writepage function | ||
594 | * | 596 | * |
595 | * This is a library function, which implements the writepages() | 597 | * If a page is already under I/O, write_cache_pages() skips it, even |
596 | * address_space_operation. | ||
597 | * | ||
598 | * If a page is already under I/O, generic_writepages() skips it, even | ||
599 | * if it's dirty. This is desirable behaviour for memory-cleaning writeback, | 598 | * if it's dirty. This is desirable behaviour for memory-cleaning writeback, |
600 | * but it is INCORRECT for data-integrity system calls such as fsync(). fsync() | 599 | * but it is INCORRECT for data-integrity system calls such as fsync(). fsync() |
601 | * and msync() need to guarantee that all the data which was dirty at the time | 600 | * and msync() need to guarantee that all the data which was dirty at the time |
602 | * the call was made get new I/O started against them. If wbc->sync_mode is | 601 | * the call was made get new I/O started against them. If wbc->sync_mode is |
603 | * WB_SYNC_ALL then we were called for data integrity and we must wait for | 602 | * WB_SYNC_ALL then we were called for data integrity and we must wait for |
604 | * existing IO to complete. | 603 | * existing IO to complete. |
605 | * | ||
606 | * Derived from mpage_writepages() - if you fix this you should check that | ||
607 | * also! | ||
608 | */ | 604 | */ |
609 | int generic_writepages(struct address_space *mapping, | 605 | int write_cache_pages(struct address_space *mapping, |
610 | struct writeback_control *wbc) | 606 | struct writeback_control *wbc, writepage_t writepage, |
607 | void *data) | ||
611 | { | 608 | { |
612 | struct backing_dev_info *bdi = mapping->backing_dev_info; | 609 | struct backing_dev_info *bdi = mapping->backing_dev_info; |
613 | int ret = 0; | 610 | int ret = 0; |
614 | int done = 0; | 611 | int done = 0; |
615 | int (*writepage)(struct page *page, struct writeback_control *wbc); | ||
616 | struct pagevec pvec; | 612 | struct pagevec pvec; |
617 | int nr_pages; | 613 | int nr_pages; |
618 | pgoff_t index; | 614 | pgoff_t index; |
@@ -625,12 +621,6 @@ int generic_writepages(struct address_space *mapping, | |||
625 | return 0; | 621 | return 0; |
626 | } | 622 | } |
627 | 623 | ||
628 | writepage = mapping->a_ops->writepage; | ||
629 | |||
630 | /* deal with chardevs and other special file */ | ||
631 | if (!writepage) | ||
632 | return 0; | ||
633 | |||
634 | pagevec_init(&pvec, 0); | 624 | pagevec_init(&pvec, 0); |
635 | if (wbc->range_cyclic) { | 625 | if (wbc->range_cyclic) { |
636 | index = mapping->writeback_index; /* Start from prev offset */ | 626 | index = mapping->writeback_index; /* Start from prev offset */ |
@@ -682,8 +672,7 @@ retry: | |||
682 | continue; | 672 | continue; |
683 | } | 673 | } |
684 | 674 | ||
685 | ret = (*writepage)(page, wbc); | 675 | ret = (*writepage)(page, wbc, data); |
686 | mapping_set_error(mapping, ret); | ||
687 | 676 | ||
688 | if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE)) | 677 | if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE)) |
689 | unlock_page(page); | 678 | unlock_page(page); |
@@ -710,6 +699,38 @@ retry: | |||
710 | mapping->writeback_index = index; | 699 | mapping->writeback_index = index; |
711 | return ret; | 700 | return ret; |
712 | } | 701 | } |
702 | EXPORT_SYMBOL(write_cache_pages); | ||
703 | |||
704 | /* | ||
705 | * Function used by generic_writepages to call the real writepage | ||
706 | * function and set the mapping flags on error | ||
707 | */ | ||
708 | static int __writepage(struct page *page, struct writeback_control *wbc, | ||
709 | void *data) | ||
710 | { | ||
711 | struct address_space *mapping = data; | ||
712 | int ret = mapping->a_ops->writepage(page, wbc); | ||
713 | mapping_set_error(mapping, ret); | ||
714 | return ret; | ||
715 | } | ||
716 | |||
717 | /** | ||
718 | * generic_writepages - walk the list of dirty pages of the given address space and writepage() all of them. | ||
719 | * @mapping: address space structure to write | ||
720 | * @wbc: subtract the number of written pages from *@wbc->nr_to_write | ||
721 | * | ||
722 | * This is a library function, which implements the writepages() | ||
723 | * address_space_operation. | ||
724 | */ | ||
725 | int generic_writepages(struct address_space *mapping, | ||
726 | struct writeback_control *wbc) | ||
727 | { | ||
728 | /* deal with chardevs and other special file */ | ||
729 | if (!mapping->a_ops->writepage) | ||
730 | return 0; | ||
731 | |||
732 | return write_cache_pages(mapping, wbc, __writepage, mapping); | ||
733 | } | ||
713 | 734 | ||
714 | EXPORT_SYMBOL(generic_writepages); | 735 | EXPORT_SYMBOL(generic_writepages); |
715 | 736 | ||
diff --git a/mm/thrash.c b/mm/thrash.c index 9ef9071f99bc..c4c5205a9c35 100644 --- a/mm/thrash.c +++ b/mm/thrash.c | |||
@@ -48,9 +48,8 @@ void grab_swap_token(void) | |||
48 | if (current_interval < current->mm->last_interval) | 48 | if (current_interval < current->mm->last_interval) |
49 | current->mm->token_priority++; | 49 | current->mm->token_priority++; |
50 | else { | 50 | else { |
51 | current->mm->token_priority--; | 51 | if (likely(current->mm->token_priority > 0)) |
52 | if (unlikely(current->mm->token_priority < 0)) | 52 | current->mm->token_priority--; |
53 | current->mm->token_priority = 0; | ||
54 | } | 53 | } |
55 | /* Check if we deserve the token */ | 54 | /* Check if we deserve the token */ |
56 | if (current->mm->token_priority > | 55 | if (current->mm->token_priority > |
diff --git a/mm/vmstat.c b/mm/vmstat.c index 9832d9a41d8c..8faf27e5aa98 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c | |||
@@ -698,7 +698,7 @@ static void __devinit start_cpu_timer(int cpu) | |||
698 | { | 698 | { |
699 | struct delayed_work *vmstat_work = &per_cpu(vmstat_work, cpu); | 699 | struct delayed_work *vmstat_work = &per_cpu(vmstat_work, cpu); |
700 | 700 | ||
701 | INIT_DELAYED_WORK(vmstat_work, vmstat_update); | 701 | INIT_DELAYED_WORK_DEFERRABLE(vmstat_work, vmstat_update); |
702 | schedule_delayed_work_on(cpu, vmstat_work, HZ + cpu); | 702 | schedule_delayed_work_on(cpu, vmstat_work, HZ + cpu); |
703 | } | 703 | } |
704 | 704 | ||
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index d342e89b8bdd..ceadfcf457c1 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c | |||
@@ -174,7 +174,7 @@ static inline int hidp_queue_event(struct hidp_session *session, struct input_de | |||
174 | 174 | ||
175 | static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | 175 | static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) |
176 | { | 176 | { |
177 | struct hid_device *hid = dev->private; | 177 | struct hid_device *hid = input_get_drvdata(dev); |
178 | struct hidp_session *session = hid->driver_data; | 178 | struct hidp_session *session = hid->driver_data; |
179 | 179 | ||
180 | return hidp_queue_event(session, dev, type, code, value); | 180 | return hidp_queue_event(session, dev, type, code, value); |
@@ -182,7 +182,7 @@ static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigne | |||
182 | 182 | ||
183 | static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | 183 | static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) |
184 | { | 184 | { |
185 | struct hidp_session *session = dev->private; | 185 | struct hidp_session *session = input_get_drvdata(dev); |
186 | 186 | ||
187 | return hidp_queue_event(session, dev, type, code, value); | 187 | return hidp_queue_event(session, dev, type, code, value); |
188 | } | 188 | } |
@@ -630,7 +630,7 @@ static inline void hidp_setup_input(struct hidp_session *session, struct hidp_co | |||
630 | struct input_dev *input = session->input; | 630 | struct input_dev *input = session->input; |
631 | int i; | 631 | int i; |
632 | 632 | ||
633 | input->private = session; | 633 | input_set_drvdata(input, session); |
634 | 634 | ||
635 | input->name = "Bluetooth HID Boot Protocol Device"; | 635 | input->name = "Bluetooth HID Boot Protocol Device"; |
636 | 636 | ||
@@ -663,7 +663,7 @@ static inline void hidp_setup_input(struct hidp_session *session, struct hidp_co | |||
663 | input->relbit[0] |= BIT(REL_WHEEL); | 663 | input->relbit[0] |= BIT(REL_WHEEL); |
664 | } | 664 | } |
665 | 665 | ||
666 | input->cdev.dev = hidp_get_device(session); | 666 | input->dev.parent = hidp_get_device(session); |
667 | 667 | ||
668 | input->event = hidp_input_event; | 668 | input->event = hidp_input_event; |
669 | 669 | ||
@@ -737,10 +737,8 @@ static inline void hidp_setup_hid(struct hidp_session *session, struct hidp_conn | |||
737 | list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list) | 737 | list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list) |
738 | hidp_send_report(session, report); | 738 | hidp_send_report(session, report); |
739 | 739 | ||
740 | if (hidinput_connect(hid) == 0) { | 740 | if (hidinput_connect(hid) == 0) |
741 | hid->claimed |= HID_CLAIMED_INPUT; | 741 | hid->claimed |= HID_CLAIMED_INPUT; |
742 | hid_ff_init(hid); | ||
743 | } | ||
744 | } | 742 | } |
745 | 743 | ||
746 | int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock) | 744 | int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock) |
@@ -864,7 +862,7 @@ failed: | |||
864 | if (session->hid) | 862 | if (session->hid) |
865 | hid_free_device(session->hid); | 863 | hid_free_device(session->hid); |
866 | 864 | ||
867 | kfree(session->input); | 865 | input_free_device(session->input); |
868 | kfree(session); | 866 | kfree(session); |
869 | return err; | 867 | return err; |
870 | } | 868 | } |
diff --git a/net/core/link_watch.c b/net/core/link_watch.c index e3c26a9ccad6..a5e372b9ec4d 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/rtnetlink.h> | 19 | #include <linux/rtnetlink.h> |
20 | #include <linux/jiffies.h> | 20 | #include <linux/jiffies.h> |
21 | #include <linux/spinlock.h> | 21 | #include <linux/spinlock.h> |
22 | #include <linux/list.h> | ||
23 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
24 | #include <linux/workqueue.h> | 23 | #include <linux/workqueue.h> |
25 | #include <linux/bitops.h> | 24 | #include <linux/bitops.h> |
@@ -27,8 +26,7 @@ | |||
27 | 26 | ||
28 | 27 | ||
29 | enum lw_bits { | 28 | enum lw_bits { |
30 | LW_RUNNING = 0, | 29 | LW_URGENT = 0, |
31 | LW_SE_USED | ||
32 | }; | 30 | }; |
33 | 31 | ||
34 | static unsigned long linkwatch_flags; | 32 | static unsigned long linkwatch_flags; |
@@ -37,17 +35,9 @@ static unsigned long linkwatch_nextevent; | |||
37 | static void linkwatch_event(struct work_struct *dummy); | 35 | static void linkwatch_event(struct work_struct *dummy); |
38 | static DECLARE_DELAYED_WORK(linkwatch_work, linkwatch_event); | 36 | static DECLARE_DELAYED_WORK(linkwatch_work, linkwatch_event); |
39 | 37 | ||
40 | static LIST_HEAD(lweventlist); | 38 | static struct net_device *lweventlist; |
41 | static DEFINE_SPINLOCK(lweventlist_lock); | 39 | static DEFINE_SPINLOCK(lweventlist_lock); |
42 | 40 | ||
43 | struct lw_event { | ||
44 | struct list_head list; | ||
45 | struct net_device *dev; | ||
46 | }; | ||
47 | |||
48 | /* Avoid kmalloc() for most systems */ | ||
49 | static struct lw_event singleevent; | ||
50 | |||
51 | static unsigned char default_operstate(const struct net_device *dev) | 41 | static unsigned char default_operstate(const struct net_device *dev) |
52 | { | 42 | { |
53 | if (!netif_carrier_ok(dev)) | 43 | if (!netif_carrier_ok(dev)) |
@@ -87,25 +77,102 @@ static void rfc2863_policy(struct net_device *dev) | |||
87 | } | 77 | } |
88 | 78 | ||
89 | 79 | ||
90 | /* Must be called with the rtnl semaphore held */ | 80 | static int linkwatch_urgent_event(struct net_device *dev) |
91 | void linkwatch_run_queue(void) | ||
92 | { | 81 | { |
93 | struct list_head head, *n, *next; | 82 | return netif_running(dev) && netif_carrier_ok(dev) && |
83 | dev->qdisc != dev->qdisc_sleeping; | ||
84 | } | ||
85 | |||
86 | |||
87 | static void linkwatch_add_event(struct net_device *dev) | ||
88 | { | ||
89 | unsigned long flags; | ||
90 | |||
91 | spin_lock_irqsave(&lweventlist_lock, flags); | ||
92 | dev->link_watch_next = lweventlist; | ||
93 | lweventlist = dev; | ||
94 | spin_unlock_irqrestore(&lweventlist_lock, flags); | ||
95 | } | ||
96 | |||
97 | |||
98 | static void linkwatch_schedule_work(int urgent) | ||
99 | { | ||
100 | unsigned long delay = linkwatch_nextevent - jiffies; | ||
101 | |||
102 | if (test_bit(LW_URGENT, &linkwatch_flags)) | ||
103 | return; | ||
104 | |||
105 | /* Minimise down-time: drop delay for up event. */ | ||
106 | if (urgent) { | ||
107 | if (test_and_set_bit(LW_URGENT, &linkwatch_flags)) | ||
108 | return; | ||
109 | delay = 0; | ||
110 | } | ||
111 | |||
112 | /* If we wrap around we'll delay it by at most HZ. */ | ||
113 | if (delay > HZ) | ||
114 | delay = 0; | ||
115 | |||
116 | /* | ||
117 | * This is true if we've scheduled it immeditately or if we don't | ||
118 | * need an immediate execution and it's already pending. | ||
119 | */ | ||
120 | if (schedule_delayed_work(&linkwatch_work, delay) == !delay) | ||
121 | return; | ||
122 | |||
123 | /* Don't bother if there is nothing urgent. */ | ||
124 | if (!test_bit(LW_URGENT, &linkwatch_flags)) | ||
125 | return; | ||
126 | |||
127 | /* It's already running which is good enough. */ | ||
128 | if (!cancel_delayed_work(&linkwatch_work)) | ||
129 | return; | ||
130 | |||
131 | /* Otherwise we reschedule it again for immediate exection. */ | ||
132 | schedule_delayed_work(&linkwatch_work, 0); | ||
133 | } | ||
134 | |||
135 | |||
136 | static void __linkwatch_run_queue(int urgent_only) | ||
137 | { | ||
138 | struct net_device *next; | ||
139 | |||
140 | /* | ||
141 | * Limit the number of linkwatch events to one | ||
142 | * per second so that a runaway driver does not | ||
143 | * cause a storm of messages on the netlink | ||
144 | * socket. This limit does not apply to up events | ||
145 | * while the device qdisc is down. | ||
146 | */ | ||
147 | if (!urgent_only) | ||
148 | linkwatch_nextevent = jiffies + HZ; | ||
149 | /* Limit wrap-around effect on delay. */ | ||
150 | else if (time_after(linkwatch_nextevent, jiffies + HZ)) | ||
151 | linkwatch_nextevent = jiffies; | ||
152 | |||
153 | clear_bit(LW_URGENT, &linkwatch_flags); | ||
94 | 154 | ||
95 | spin_lock_irq(&lweventlist_lock); | 155 | spin_lock_irq(&lweventlist_lock); |
96 | list_replace_init(&lweventlist, &head); | 156 | next = lweventlist; |
157 | lweventlist = NULL; | ||
97 | spin_unlock_irq(&lweventlist_lock); | 158 | spin_unlock_irq(&lweventlist_lock); |
98 | 159 | ||
99 | list_for_each_safe(n, next, &head) { | 160 | while (next) { |
100 | struct lw_event *event = list_entry(n, struct lw_event, list); | 161 | struct net_device *dev = next; |
101 | struct net_device *dev = event->dev; | ||
102 | 162 | ||
103 | if (event == &singleevent) { | 163 | next = dev->link_watch_next; |
104 | clear_bit(LW_SE_USED, &linkwatch_flags); | 164 | |
105 | } else { | 165 | if (urgent_only && !linkwatch_urgent_event(dev)) { |
106 | kfree(event); | 166 | linkwatch_add_event(dev); |
167 | continue; | ||
107 | } | 168 | } |
108 | 169 | ||
170 | /* | ||
171 | * Make sure the above read is complete since it can be | ||
172 | * rewritten as soon as we clear the bit below. | ||
173 | */ | ||
174 | smp_mb__before_clear_bit(); | ||
175 | |||
109 | /* We are about to handle this device, | 176 | /* We are about to handle this device, |
110 | * so new events can be accepted | 177 | * so new events can be accepted |
111 | */ | 178 | */ |
@@ -124,58 +191,39 @@ void linkwatch_run_queue(void) | |||
124 | 191 | ||
125 | dev_put(dev); | 192 | dev_put(dev); |
126 | } | 193 | } |
194 | |||
195 | if (lweventlist) | ||
196 | linkwatch_schedule_work(0); | ||
127 | } | 197 | } |
128 | 198 | ||
129 | 199 | ||
130 | static void linkwatch_event(struct work_struct *dummy) | 200 | /* Must be called with the rtnl semaphore held */ |
201 | void linkwatch_run_queue(void) | ||
131 | { | 202 | { |
132 | /* Limit the number of linkwatch events to one | 203 | __linkwatch_run_queue(0); |
133 | * per second so that a runaway driver does not | 204 | } |
134 | * cause a storm of messages on the netlink | ||
135 | * socket | ||
136 | */ | ||
137 | linkwatch_nextevent = jiffies + HZ; | ||
138 | clear_bit(LW_RUNNING, &linkwatch_flags); | ||
139 | 205 | ||
206 | |||
207 | static void linkwatch_event(struct work_struct *dummy) | ||
208 | { | ||
140 | rtnl_lock(); | 209 | rtnl_lock(); |
141 | linkwatch_run_queue(); | 210 | __linkwatch_run_queue(time_after(linkwatch_nextevent, jiffies)); |
142 | rtnl_unlock(); | 211 | rtnl_unlock(); |
143 | } | 212 | } |
144 | 213 | ||
145 | 214 | ||
146 | void linkwatch_fire_event(struct net_device *dev) | 215 | void linkwatch_fire_event(struct net_device *dev) |
147 | { | 216 | { |
148 | if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) { | 217 | int urgent = linkwatch_urgent_event(dev); |
149 | unsigned long flags; | ||
150 | struct lw_event *event; | ||
151 | |||
152 | if (test_and_set_bit(LW_SE_USED, &linkwatch_flags)) { | ||
153 | event = kmalloc(sizeof(struct lw_event), GFP_ATOMIC); | ||
154 | |||
155 | if (unlikely(event == NULL)) { | ||
156 | clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state); | ||
157 | return; | ||
158 | } | ||
159 | } else { | ||
160 | event = &singleevent; | ||
161 | } | ||
162 | 218 | ||
219 | if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) { | ||
163 | dev_hold(dev); | 220 | dev_hold(dev); |
164 | event->dev = dev; | ||
165 | |||
166 | spin_lock_irqsave(&lweventlist_lock, flags); | ||
167 | list_add_tail(&event->list, &lweventlist); | ||
168 | spin_unlock_irqrestore(&lweventlist_lock, flags); | ||
169 | 221 | ||
170 | if (!test_and_set_bit(LW_RUNNING, &linkwatch_flags)) { | 222 | linkwatch_add_event(dev); |
171 | unsigned long delay = linkwatch_nextevent - jiffies; | 223 | } else if (!urgent) |
224 | return; | ||
172 | 225 | ||
173 | /* If we wrap around we'll delay it by at most HZ. */ | 226 | linkwatch_schedule_work(urgent); |
174 | if (delay > HZ) | ||
175 | delay = 0; | ||
176 | schedule_delayed_work(&linkwatch_work, delay); | ||
177 | } | ||
178 | } | ||
179 | } | 227 | } |
180 | 228 | ||
181 | EXPORT_SYMBOL(linkwatch_fire_event); | 229 | EXPORT_SYMBOL(linkwatch_fire_event); |
diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c index 7edea2a1696c..75c023062533 100644 --- a/net/ipv4/netfilter/arptable_filter.c +++ b/net/ipv4/netfilter/arptable_filter.c | |||
@@ -15,128 +15,34 @@ MODULE_DESCRIPTION("arptables filter table"); | |||
15 | #define FILTER_VALID_HOOKS ((1 << NF_ARP_IN) | (1 << NF_ARP_OUT) | \ | 15 | #define FILTER_VALID_HOOKS ((1 << NF_ARP_IN) | (1 << NF_ARP_OUT) | \ |
16 | (1 << NF_ARP_FORWARD)) | 16 | (1 << NF_ARP_FORWARD)) |
17 | 17 | ||
18 | /* Standard entry. */ | ||
19 | struct arpt_standard | ||
20 | { | ||
21 | struct arpt_entry entry; | ||
22 | struct arpt_standard_target target; | ||
23 | }; | ||
24 | |||
25 | struct arpt_error_target | ||
26 | { | ||
27 | struct arpt_entry_target target; | ||
28 | char errorname[ARPT_FUNCTION_MAXNAMELEN]; | ||
29 | }; | ||
30 | |||
31 | struct arpt_error | ||
32 | { | ||
33 | struct arpt_entry entry; | ||
34 | struct arpt_error_target target; | ||
35 | }; | ||
36 | |||
37 | static struct | 18 | static struct |
38 | { | 19 | { |
39 | struct arpt_replace repl; | 20 | struct arpt_replace repl; |
40 | struct arpt_standard entries[3]; | 21 | struct arpt_standard entries[3]; |
41 | struct arpt_error term; | 22 | struct arpt_error term; |
42 | } initial_table __initdata | 23 | } initial_table __initdata = { |
43 | = { { "filter", FILTER_VALID_HOOKS, 4, | 24 | .repl = { |
44 | sizeof(struct arpt_standard) * 3 + sizeof(struct arpt_error), | 25 | .name = "filter", |
45 | { [NF_ARP_IN] = 0, | 26 | .valid_hooks = FILTER_VALID_HOOKS, |
46 | [NF_ARP_OUT] = sizeof(struct arpt_standard), | 27 | .num_entries = 4, |
47 | [NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard), }, | 28 | .size = sizeof(struct arpt_standard) * 3 + sizeof(struct arpt_error), |
48 | { [NF_ARP_IN] = 0, | 29 | .hook_entry = { |
49 | [NF_ARP_OUT] = sizeof(struct arpt_standard), | 30 | [NF_ARP_IN] = 0, |
50 | [NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard), }, | 31 | [NF_ARP_OUT] = sizeof(struct arpt_standard), |
51 | 0, NULL, { } }, | 32 | [NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard), |
52 | { | 33 | }, |
53 | /* ARP_IN */ | 34 | .underflow = { |
54 | { | 35 | [NF_ARP_IN] = 0, |
55 | { | 36 | [NF_ARP_OUT] = sizeof(struct arpt_standard), |
56 | { | 37 | [NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard), |
57 | { 0 }, { 0 }, { 0 }, { 0 }, | 38 | }, |
58 | 0, 0, | 39 | }, |
59 | { { 0, }, { 0, } }, | 40 | .entries = { |
60 | { { 0, }, { 0, } }, | 41 | ARPT_STANDARD_INIT(NF_ACCEPT), /* ARP_IN */ |
61 | 0, 0, | 42 | ARPT_STANDARD_INIT(NF_ACCEPT), /* ARP_OUT */ |
62 | 0, 0, | 43 | ARPT_STANDARD_INIT(NF_ACCEPT), /* ARP_FORWARD */ |
63 | 0, 0, | 44 | }, |
64 | "", "", { 0 }, { 0 }, | 45 | .term = ARPT_ERROR_INIT, |
65 | 0, 0 | ||
66 | }, | ||
67 | sizeof(struct arpt_entry), | ||
68 | sizeof(struct arpt_standard), | ||
69 | 0, | ||
70 | { 0, 0 }, { } }, | ||
71 | { { { { ARPT_ALIGN(sizeof(struct arpt_standard_target)), "" } }, { } }, | ||
72 | -NF_ACCEPT - 1 } | ||
73 | }, | ||
74 | /* ARP_OUT */ | ||
75 | { | ||
76 | { | ||
77 | { | ||
78 | { 0 }, { 0 }, { 0 }, { 0 }, | ||
79 | 0, 0, | ||
80 | { { 0, }, { 0, } }, | ||
81 | { { 0, }, { 0, } }, | ||
82 | 0, 0, | ||
83 | 0, 0, | ||
84 | 0, 0, | ||
85 | "", "", { 0 }, { 0 }, | ||
86 | 0, 0 | ||
87 | }, | ||
88 | sizeof(struct arpt_entry), | ||
89 | sizeof(struct arpt_standard), | ||
90 | 0, | ||
91 | { 0, 0 }, { } }, | ||
92 | { { { { ARPT_ALIGN(sizeof(struct arpt_standard_target)), "" } }, { } }, | ||
93 | -NF_ACCEPT - 1 } | ||
94 | }, | ||
95 | /* ARP_FORWARD */ | ||
96 | { | ||
97 | { | ||
98 | { | ||
99 | { 0 }, { 0 }, { 0 }, { 0 }, | ||
100 | 0, 0, | ||
101 | { { 0, }, { 0, } }, | ||
102 | { { 0, }, { 0, } }, | ||
103 | 0, 0, | ||
104 | 0, 0, | ||
105 | 0, 0, | ||
106 | "", "", { 0 }, { 0 }, | ||
107 | 0, 0 | ||
108 | }, | ||
109 | sizeof(struct arpt_entry), | ||
110 | sizeof(struct arpt_standard), | ||
111 | 0, | ||
112 | { 0, 0 }, { } }, | ||
113 | { { { { ARPT_ALIGN(sizeof(struct arpt_standard_target)), "" } }, { } }, | ||
114 | -NF_ACCEPT - 1 } | ||
115 | } | ||
116 | }, | ||
117 | /* ERROR */ | ||
118 | { | ||
119 | { | ||
120 | { | ||
121 | { 0 }, { 0 }, { 0 }, { 0 }, | ||
122 | 0, 0, | ||
123 | { { 0, }, { 0, } }, | ||
124 | { { 0, }, { 0, } }, | ||
125 | 0, 0, | ||
126 | 0, 0, | ||
127 | 0, 0, | ||
128 | "", "", { 0 }, { 0 }, | ||
129 | 0, 0 | ||
130 | }, | ||
131 | sizeof(struct arpt_entry), | ||
132 | sizeof(struct arpt_error), | ||
133 | 0, | ||
134 | { 0, 0 }, { } }, | ||
135 | { { { { ARPT_ALIGN(sizeof(struct arpt_error_target)), ARPT_ERROR_TARGET } }, | ||
136 | { } }, | ||
137 | "ERROR" | ||
138 | } | ||
139 | } | ||
140 | }; | 46 | }; |
141 | 47 | ||
142 | static struct arpt_table packet_filter = { | 48 | static struct arpt_table packet_filter = { |
diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c index 42728909eba0..4f51c1d7d2d6 100644 --- a/net/ipv4/netfilter/iptable_filter.c +++ b/net/ipv4/netfilter/iptable_filter.c | |||
@@ -26,53 +26,29 @@ static struct | |||
26 | struct ipt_replace repl; | 26 | struct ipt_replace repl; |
27 | struct ipt_standard entries[3]; | 27 | struct ipt_standard entries[3]; |
28 | struct ipt_error term; | 28 | struct ipt_error term; |
29 | } initial_table __initdata | 29 | } initial_table __initdata = { |
30 | = { { "filter", FILTER_VALID_HOOKS, 4, | 30 | .repl = { |
31 | sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error), | 31 | .name = "filter", |
32 | { [NF_IP_LOCAL_IN] = 0, | 32 | .valid_hooks = FILTER_VALID_HOOKS, |
33 | [NF_IP_FORWARD] = sizeof(struct ipt_standard), | 33 | .num_entries = 4, |
34 | [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 }, | 34 | .size = sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error), |
35 | { [NF_IP_LOCAL_IN] = 0, | 35 | .hook_entry = { |
36 | [NF_IP_FORWARD] = sizeof(struct ipt_standard), | 36 | [NF_IP_LOCAL_IN] = 0, |
37 | [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 }, | 37 | [NF_IP_FORWARD] = sizeof(struct ipt_standard), |
38 | 0, NULL, { } }, | 38 | [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2, |
39 | { | 39 | }, |
40 | /* LOCAL_IN */ | 40 | .underflow = { |
41 | { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | 41 | [NF_IP_LOCAL_IN] = 0, |
42 | 0, | 42 | [NF_IP_FORWARD] = sizeof(struct ipt_standard), |
43 | sizeof(struct ipt_entry), | 43 | [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2, |
44 | sizeof(struct ipt_standard), | 44 | }, |
45 | 0, { 0, 0 }, { } }, | 45 | }, |
46 | { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, | 46 | .entries = { |
47 | -NF_ACCEPT - 1 } }, | 47 | IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */ |
48 | /* FORWARD */ | 48 | IPT_STANDARD_INIT(NF_ACCEPT), /* FORWARD */ |
49 | { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | 49 | IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ |
50 | 0, | 50 | }, |
51 | sizeof(struct ipt_entry), | 51 | .term = IPT_ERROR_INIT, /* ERROR */ |
52 | sizeof(struct ipt_standard), | ||
53 | 0, { 0, 0 }, { } }, | ||
54 | { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, | ||
55 | -NF_ACCEPT - 1 } }, | ||
56 | /* LOCAL_OUT */ | ||
57 | { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | ||
58 | 0, | ||
59 | sizeof(struct ipt_entry), | ||
60 | sizeof(struct ipt_standard), | ||
61 | 0, { 0, 0 }, { } }, | ||
62 | { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, | ||
63 | -NF_ACCEPT - 1 } } | ||
64 | }, | ||
65 | /* ERROR */ | ||
66 | { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | ||
67 | 0, | ||
68 | sizeof(struct ipt_entry), | ||
69 | sizeof(struct ipt_error), | ||
70 | 0, { 0, 0 }, { } }, | ||
71 | { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } }, | ||
72 | { } }, | ||
73 | "ERROR" | ||
74 | } | ||
75 | } | ||
76 | }; | 52 | }; |
77 | 53 | ||
78 | static struct xt_table packet_filter = { | 54 | static struct xt_table packet_filter = { |
@@ -105,7 +81,8 @@ ipt_local_out_hook(unsigned int hook, | |||
105 | if ((*pskb)->len < sizeof(struct iphdr) | 81 | if ((*pskb)->len < sizeof(struct iphdr) |
106 | || ip_hdrlen(*pskb) < sizeof(struct iphdr)) { | 82 | || ip_hdrlen(*pskb) < sizeof(struct iphdr)) { |
107 | if (net_ratelimit()) | 83 | if (net_ratelimit()) |
108 | printk("ipt_hook: happy cracking.\n"); | 84 | printk("iptable_filter: ignoring short SOCK_RAW " |
85 | "packet.\n"); | ||
109 | return NF_ACCEPT; | 86 | return NF_ACCEPT; |
110 | } | 87 | } |
111 | 88 | ||
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index 9278802f2742..902446f7cbca 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c | |||
@@ -33,73 +33,35 @@ static struct | |||
33 | struct ipt_replace repl; | 33 | struct ipt_replace repl; |
34 | struct ipt_standard entries[5]; | 34 | struct ipt_standard entries[5]; |
35 | struct ipt_error term; | 35 | struct ipt_error term; |
36 | } initial_table __initdata | 36 | } initial_table __initdata = { |
37 | = { { "mangle", MANGLE_VALID_HOOKS, 6, | 37 | .repl = { |
38 | sizeof(struct ipt_standard) * 5 + sizeof(struct ipt_error), | 38 | .name = "mangle", |
39 | { [NF_IP_PRE_ROUTING] = 0, | 39 | .valid_hooks = MANGLE_VALID_HOOKS, |
40 | [NF_IP_LOCAL_IN] = sizeof(struct ipt_standard), | 40 | .num_entries = 6, |
41 | [NF_IP_FORWARD] = sizeof(struct ipt_standard) * 2, | 41 | .size = sizeof(struct ipt_standard) * 5 + sizeof(struct ipt_error), |
42 | [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 3, | 42 | .hook_entry = { |
43 | [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard) * 4 }, | 43 | [NF_IP_PRE_ROUTING] = 0, |
44 | { [NF_IP_PRE_ROUTING] = 0, | 44 | [NF_IP_LOCAL_IN] = sizeof(struct ipt_standard), |
45 | [NF_IP_LOCAL_IN] = sizeof(struct ipt_standard), | 45 | [NF_IP_FORWARD] = sizeof(struct ipt_standard) * 2, |
46 | [NF_IP_FORWARD] = sizeof(struct ipt_standard) * 2, | 46 | [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 3, |
47 | [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 3, | 47 | [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard) * 4, |
48 | [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard) * 4 }, | 48 | }, |
49 | 0, NULL, { } }, | 49 | .underflow = { |
50 | { | 50 | [NF_IP_PRE_ROUTING] = 0, |
51 | /* PRE_ROUTING */ | 51 | [NF_IP_LOCAL_IN] = sizeof(struct ipt_standard), |
52 | { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | 52 | [NF_IP_FORWARD] = sizeof(struct ipt_standard) * 2, |
53 | 0, | 53 | [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 3, |
54 | sizeof(struct ipt_entry), | 54 | [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard) * 4, |
55 | sizeof(struct ipt_standard), | 55 | }, |
56 | 0, { 0, 0 }, { } }, | 56 | }, |
57 | { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, | 57 | .entries = { |
58 | -NF_ACCEPT - 1 } }, | 58 | IPT_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */ |
59 | /* LOCAL_IN */ | 59 | IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */ |
60 | { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | 60 | IPT_STANDARD_INIT(NF_ACCEPT), /* FORWARD */ |
61 | 0, | 61 | IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ |
62 | sizeof(struct ipt_entry), | 62 | IPT_STANDARD_INIT(NF_ACCEPT), /* POST_ROUTING */ |
63 | sizeof(struct ipt_standard), | 63 | }, |
64 | 0, { 0, 0 }, { } }, | 64 | .term = IPT_ERROR_INIT, /* ERROR */ |
65 | { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, | ||
66 | -NF_ACCEPT - 1 } }, | ||
67 | /* FORWARD */ | ||
68 | { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | ||
69 | 0, | ||
70 | sizeof(struct ipt_entry), | ||
71 | sizeof(struct ipt_standard), | ||
72 | 0, { 0, 0 }, { } }, | ||
73 | { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, | ||
74 | -NF_ACCEPT - 1 } }, | ||
75 | /* LOCAL_OUT */ | ||
76 | { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | ||
77 | 0, | ||
78 | sizeof(struct ipt_entry), | ||
79 | sizeof(struct ipt_standard), | ||
80 | 0, { 0, 0 }, { } }, | ||
81 | { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, | ||
82 | -NF_ACCEPT - 1 } }, | ||
83 | /* POST_ROUTING */ | ||
84 | { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | ||
85 | 0, | ||
86 | sizeof(struct ipt_entry), | ||
87 | sizeof(struct ipt_standard), | ||
88 | 0, { 0, 0 }, { } }, | ||
89 | { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, | ||
90 | -NF_ACCEPT - 1 } }, | ||
91 | }, | ||
92 | /* ERROR */ | ||
93 | { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | ||
94 | 0, | ||
95 | sizeof(struct ipt_entry), | ||
96 | sizeof(struct ipt_error), | ||
97 | 0, { 0, 0 }, { } }, | ||
98 | { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } }, | ||
99 | { } }, | ||
100 | "ERROR" | ||
101 | } | ||
102 | } | ||
103 | }; | 65 | }; |
104 | 66 | ||
105 | static struct xt_table packet_mangler = { | 67 | static struct xt_table packet_mangler = { |
@@ -138,7 +100,8 @@ ipt_local_hook(unsigned int hook, | |||
138 | if ((*pskb)->len < sizeof(struct iphdr) | 100 | if ((*pskb)->len < sizeof(struct iphdr) |
139 | || ip_hdrlen(*pskb) < sizeof(struct iphdr)) { | 101 | || ip_hdrlen(*pskb) < sizeof(struct iphdr)) { |
140 | if (net_ratelimit()) | 102 | if (net_ratelimit()) |
141 | printk("ipt_hook: happy cracking.\n"); | 103 | printk("iptable_mangle: ignoring short SOCK_RAW " |
104 | "packet.\n"); | ||
142 | return NF_ACCEPT; | 105 | return NF_ACCEPT; |
143 | } | 106 | } |
144 | 107 | ||
diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c index 18c3d4c9ff51..d6e503395684 100644 --- a/net/ipv4/netfilter/iptable_raw.c +++ b/net/ipv4/netfilter/iptable_raw.c | |||
@@ -5,6 +5,7 @@ | |||
5 | */ | 5 | */ |
6 | #include <linux/module.h> | 6 | #include <linux/module.h> |
7 | #include <linux/netfilter_ipv4/ip_tables.h> | 7 | #include <linux/netfilter_ipv4/ip_tables.h> |
8 | #include <net/ip.h> | ||
8 | 9 | ||
9 | #define RAW_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT)) | 10 | #define RAW_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT)) |
10 | 11 | ||
@@ -21,62 +22,18 @@ static struct | |||
21 | .size = sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error), | 22 | .size = sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error), |
22 | .hook_entry = { | 23 | .hook_entry = { |
23 | [NF_IP_PRE_ROUTING] = 0, | 24 | [NF_IP_PRE_ROUTING] = 0, |
24 | [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) }, | 25 | [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) |
26 | }, | ||
25 | .underflow = { | 27 | .underflow = { |
26 | [NF_IP_PRE_ROUTING] = 0, | 28 | [NF_IP_PRE_ROUTING] = 0, |
27 | [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) }, | 29 | [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) |
30 | }, | ||
28 | }, | 31 | }, |
29 | .entries = { | 32 | .entries = { |
30 | /* PRE_ROUTING */ | 33 | IPT_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */ |
31 | { | 34 | IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ |
32 | .entry = { | ||
33 | .target_offset = sizeof(struct ipt_entry), | ||
34 | .next_offset = sizeof(struct ipt_standard), | ||
35 | }, | ||
36 | .target = { | ||
37 | .target = { | ||
38 | .u = { | ||
39 | .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)), | ||
40 | }, | ||
41 | }, | ||
42 | .verdict = -NF_ACCEPT - 1, | ||
43 | }, | ||
44 | }, | ||
45 | |||
46 | /* LOCAL_OUT */ | ||
47 | { | ||
48 | .entry = { | ||
49 | .target_offset = sizeof(struct ipt_entry), | ||
50 | .next_offset = sizeof(struct ipt_standard), | ||
51 | }, | ||
52 | .target = { | ||
53 | .target = { | ||
54 | .u = { | ||
55 | .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)), | ||
56 | }, | ||
57 | }, | ||
58 | .verdict = -NF_ACCEPT - 1, | ||
59 | }, | ||
60 | }, | ||
61 | }, | 35 | }, |
62 | /* ERROR */ | 36 | .term = IPT_ERROR_INIT, /* ERROR */ |
63 | .term = { | ||
64 | .entry = { | ||
65 | .target_offset = sizeof(struct ipt_entry), | ||
66 | .next_offset = sizeof(struct ipt_error), | ||
67 | }, | ||
68 | .target = { | ||
69 | .target = { | ||
70 | .u = { | ||
71 | .user = { | ||
72 | .target_size = IPT_ALIGN(sizeof(struct ipt_error_target)), | ||
73 | .name = IPT_ERROR_TARGET, | ||
74 | }, | ||
75 | }, | ||
76 | }, | ||
77 | .errorname = "ERROR", | ||
78 | }, | ||
79 | } | ||
80 | }; | 37 | }; |
81 | 38 | ||
82 | static struct xt_table packet_raw = { | 39 | static struct xt_table packet_raw = { |
@@ -98,6 +55,24 @@ ipt_hook(unsigned int hook, | |||
98 | return ipt_do_table(pskb, hook, in, out, &packet_raw); | 55 | return ipt_do_table(pskb, hook, in, out, &packet_raw); |
99 | } | 56 | } |
100 | 57 | ||
58 | static unsigned int | ||
59 | ipt_local_hook(unsigned int hook, | ||
60 | struct sk_buff **pskb, | ||
61 | const struct net_device *in, | ||
62 | const struct net_device *out, | ||
63 | int (*okfn)(struct sk_buff *)) | ||
64 | { | ||
65 | /* root is playing with raw sockets. */ | ||
66 | if ((*pskb)->len < sizeof(struct iphdr) || | ||
67 | ip_hdrlen(*pskb) < sizeof(struct iphdr)) { | ||
68 | if (net_ratelimit()) | ||
69 | printk("iptable_raw: ignoring short SOCK_RAW" | ||
70 | "packet.\n"); | ||
71 | return NF_ACCEPT; | ||
72 | } | ||
73 | return ipt_do_table(pskb, hook, in, out, &packet_raw); | ||
74 | } | ||
75 | |||
101 | /* 'raw' is the very first table. */ | 76 | /* 'raw' is the very first table. */ |
102 | static struct nf_hook_ops ipt_ops[] = { | 77 | static struct nf_hook_ops ipt_ops[] = { |
103 | { | 78 | { |
@@ -108,7 +83,7 @@ static struct nf_hook_ops ipt_ops[] = { | |||
108 | .owner = THIS_MODULE, | 83 | .owner = THIS_MODULE, |
109 | }, | 84 | }, |
110 | { | 85 | { |
111 | .hook = ipt_hook, | 86 | .hook = ipt_local_hook, |
112 | .pf = PF_INET, | 87 | .pf = PF_INET, |
113 | .hooknum = NF_IP_LOCAL_OUT, | 88 | .hooknum = NF_IP_LOCAL_OUT, |
114 | .priority = NF_IP_PRI_RAW, | 89 | .priority = NF_IP_PRI_RAW, |
diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c index 2534f718ab92..6740736c5e79 100644 --- a/net/ipv4/netfilter/nf_nat_rule.c +++ b/net/ipv4/netfilter/nf_nat_rule.c | |||
@@ -46,77 +46,20 @@ static struct | |||
46 | .hook_entry = { | 46 | .hook_entry = { |
47 | [NF_IP_PRE_ROUTING] = 0, | 47 | [NF_IP_PRE_ROUTING] = 0, |
48 | [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard), | 48 | [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard), |
49 | [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 }, | 49 | [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 |
50 | }, | ||
50 | .underflow = { | 51 | .underflow = { |
51 | [NF_IP_PRE_ROUTING] = 0, | 52 | [NF_IP_PRE_ROUTING] = 0, |
52 | [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard), | 53 | [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard), |
53 | [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 }, | 54 | [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 |
55 | }, | ||
54 | }, | 56 | }, |
55 | .entries = { | 57 | .entries = { |
56 | /* PRE_ROUTING */ | 58 | IPT_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */ |
57 | { | 59 | IPT_STANDARD_INIT(NF_ACCEPT), /* POST_ROUTING */ |
58 | .entry = { | 60 | IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ |
59 | .target_offset = sizeof(struct ipt_entry), | ||
60 | .next_offset = sizeof(struct ipt_standard), | ||
61 | }, | ||
62 | .target = { | ||
63 | .target = { | ||
64 | .u = { | ||
65 | .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)), | ||
66 | }, | ||
67 | }, | ||
68 | .verdict = -NF_ACCEPT - 1, | ||
69 | }, | ||
70 | }, | ||
71 | /* POST_ROUTING */ | ||
72 | { | ||
73 | .entry = { | ||
74 | .target_offset = sizeof(struct ipt_entry), | ||
75 | .next_offset = sizeof(struct ipt_standard), | ||
76 | }, | ||
77 | .target = { | ||
78 | .target = { | ||
79 | .u = { | ||
80 | .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)), | ||
81 | }, | ||
82 | }, | ||
83 | .verdict = -NF_ACCEPT - 1, | ||
84 | }, | ||
85 | }, | ||
86 | /* LOCAL_OUT */ | ||
87 | { | ||
88 | .entry = { | ||
89 | .target_offset = sizeof(struct ipt_entry), | ||
90 | .next_offset = sizeof(struct ipt_standard), | ||
91 | }, | ||
92 | .target = { | ||
93 | .target = { | ||
94 | .u = { | ||
95 | .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)), | ||
96 | }, | ||
97 | }, | ||
98 | .verdict = -NF_ACCEPT - 1, | ||
99 | }, | ||
100 | }, | ||
101 | }, | 61 | }, |
102 | /* ERROR */ | 62 | .term = IPT_ERROR_INIT, /* ERROR */ |
103 | .term = { | ||
104 | .entry = { | ||
105 | .target_offset = sizeof(struct ipt_entry), | ||
106 | .next_offset = sizeof(struct ipt_error), | ||
107 | }, | ||
108 | .target = { | ||
109 | .target = { | ||
110 | .u = { | ||
111 | .user = { | ||
112 | .target_size = IPT_ALIGN(sizeof(struct ipt_error_target)), | ||
113 | .name = IPT_ERROR_TARGET, | ||
114 | }, | ||
115 | }, | ||
116 | }, | ||
117 | .errorname = "ERROR", | ||
118 | }, | ||
119 | } | ||
120 | }; | 63 | }; |
121 | 64 | ||
122 | static struct xt_table nat_table = { | 65 | static struct xt_table nat_table = { |
@@ -230,9 +173,7 @@ static int ipt_dnat_checkentry(const char *tablename, | |||
230 | } | 173 | } |
231 | 174 | ||
232 | inline unsigned int | 175 | inline unsigned int |
233 | alloc_null_binding(struct nf_conn *ct, | 176 | alloc_null_binding(struct nf_conn *ct, unsigned int hooknum) |
234 | struct nf_nat_info *info, | ||
235 | unsigned int hooknum) | ||
236 | { | 177 | { |
237 | /* Force range to this IP; let proto decide mapping for | 178 | /* Force range to this IP; let proto decide mapping for |
238 | per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). | 179 | per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). |
@@ -251,9 +192,7 @@ alloc_null_binding(struct nf_conn *ct, | |||
251 | } | 192 | } |
252 | 193 | ||
253 | unsigned int | 194 | unsigned int |
254 | alloc_null_binding_confirmed(struct nf_conn *ct, | 195 | alloc_null_binding_confirmed(struct nf_conn *ct, unsigned int hooknum) |
255 | struct nf_nat_info *info, | ||
256 | unsigned int hooknum) | ||
257 | { | 196 | { |
258 | __be32 ip | 197 | __be32 ip |
259 | = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC | 198 | = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC |
@@ -275,8 +214,7 @@ int nf_nat_rule_find(struct sk_buff **pskb, | |||
275 | unsigned int hooknum, | 214 | unsigned int hooknum, |
276 | const struct net_device *in, | 215 | const struct net_device *in, |
277 | const struct net_device *out, | 216 | const struct net_device *out, |
278 | struct nf_conn *ct, | 217 | struct nf_conn *ct) |
279 | struct nf_nat_info *info) | ||
280 | { | 218 | { |
281 | int ret; | 219 | int ret; |
282 | 220 | ||
@@ -285,7 +223,7 @@ int nf_nat_rule_find(struct sk_buff **pskb, | |||
285 | if (ret == NF_ACCEPT) { | 223 | if (ret == NF_ACCEPT) { |
286 | if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum))) | 224 | if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum))) |
287 | /* NUL mapping */ | 225 | /* NUL mapping */ |
288 | ret = alloc_null_binding(ct, info, hooknum); | 226 | ret = alloc_null_binding(ct, hooknum); |
289 | } | 227 | } |
290 | return ret; | 228 | return ret; |
291 | } | 229 | } |
diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c index 64bbed2ba780..55dac36dbc85 100644 --- a/net/ipv4/netfilter/nf_nat_standalone.c +++ b/net/ipv4/netfilter/nf_nat_standalone.c | |||
@@ -80,7 +80,6 @@ nf_nat_fn(unsigned int hooknum, | |||
80 | struct nf_conn *ct; | 80 | struct nf_conn *ct; |
81 | enum ip_conntrack_info ctinfo; | 81 | enum ip_conntrack_info ctinfo; |
82 | struct nf_conn_nat *nat; | 82 | struct nf_conn_nat *nat; |
83 | struct nf_nat_info *info; | ||
84 | /* maniptype == SRC for postrouting. */ | 83 | /* maniptype == SRC for postrouting. */ |
85 | enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); | 84 | enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); |
86 | 85 | ||
@@ -129,7 +128,6 @@ nf_nat_fn(unsigned int hooknum, | |||
129 | } | 128 | } |
130 | /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ | 129 | /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ |
131 | case IP_CT_NEW: | 130 | case IP_CT_NEW: |
132 | info = &nat->info; | ||
133 | 131 | ||
134 | /* Seen it before? This can happen for loopback, retrans, | 132 | /* Seen it before? This can happen for loopback, retrans, |
135 | or local packets.. */ | 133 | or local packets.. */ |
@@ -138,14 +136,13 @@ nf_nat_fn(unsigned int hooknum, | |||
138 | 136 | ||
139 | if (unlikely(nf_ct_is_confirmed(ct))) | 137 | if (unlikely(nf_ct_is_confirmed(ct))) |
140 | /* NAT module was loaded late */ | 138 | /* NAT module was loaded late */ |
141 | ret = alloc_null_binding_confirmed(ct, info, | 139 | ret = alloc_null_binding_confirmed(ct, hooknum); |
142 | hooknum); | ||
143 | else if (hooknum == NF_IP_LOCAL_IN) | 140 | else if (hooknum == NF_IP_LOCAL_IN) |
144 | /* LOCAL_IN hook doesn't have a chain! */ | 141 | /* LOCAL_IN hook doesn't have a chain! */ |
145 | ret = alloc_null_binding(ct, info, hooknum); | 142 | ret = alloc_null_binding(ct, hooknum); |
146 | else | 143 | else |
147 | ret = nf_nat_rule_find(pskb, hooknum, in, out, | 144 | ret = nf_nat_rule_find(pskb, hooknum, in, out, |
148 | ct, info); | 145 | ct); |
149 | 146 | ||
150 | if (ret != NF_ACCEPT) { | 147 | if (ret != NF_ACCEPT) { |
151 | return ret; | 148 | return ret; |
@@ -160,10 +157,8 @@ nf_nat_fn(unsigned int hooknum, | |||
160 | /* ESTABLISHED */ | 157 | /* ESTABLISHED */ |
161 | NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || | 158 | NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || |
162 | ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY)); | 159 | ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY)); |
163 | info = &nat->info; | ||
164 | } | 160 | } |
165 | 161 | ||
166 | NF_CT_ASSERT(info); | ||
167 | return nf_nat_packet(ct, ctinfo, hooknum, pskb); | 162 | return nf_nat_packet(ct, ctinfo, hooknum, pskb); |
168 | } | 163 | } |
169 | 164 | ||
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 66026df1cc76..4c7e95fa090d 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -118,15 +118,15 @@ static int udp_port_rover; | |||
118 | * Note about this hash function : | 118 | * Note about this hash function : |
119 | * Typical use is probably daddr = 0, only dport is going to vary hash | 119 | * Typical use is probably daddr = 0, only dport is going to vary hash |
120 | */ | 120 | */ |
121 | static inline unsigned int hash_port_and_addr(__u16 port, __be32 addr) | 121 | static inline unsigned int udp_hash_port(__u16 port) |
122 | { | 122 | { |
123 | addr ^= addr >> 16; | 123 | return port; |
124 | addr ^= addr >> 8; | ||
125 | return port ^ addr; | ||
126 | } | 124 | } |
127 | 125 | ||
128 | static inline int __udp_lib_port_inuse(unsigned int hash, int port, | 126 | static inline int __udp_lib_port_inuse(unsigned int hash, int port, |
129 | __be32 daddr, struct hlist_head udptable[]) | 127 | const struct sock *this_sk, |
128 | struct hlist_head udptable[], | ||
129 | const struct udp_get_port_ops *ops) | ||
130 | { | 130 | { |
131 | struct sock *sk; | 131 | struct sock *sk; |
132 | struct hlist_node *node; | 132 | struct hlist_node *node; |
@@ -138,7 +138,10 @@ static inline int __udp_lib_port_inuse(unsigned int hash, int port, | |||
138 | inet = inet_sk(sk); | 138 | inet = inet_sk(sk); |
139 | if (inet->num != port) | 139 | if (inet->num != port) |
140 | continue; | 140 | continue; |
141 | if (inet->rcv_saddr == daddr) | 141 | if (this_sk) { |
142 | if (ops->saddr_cmp(sk, this_sk)) | ||
143 | return 1; | ||
144 | } else if (ops->saddr_any(sk)) | ||
142 | return 1; | 145 | return 1; |
143 | } | 146 | } |
144 | return 0; | 147 | return 0; |
@@ -151,12 +154,11 @@ static inline int __udp_lib_port_inuse(unsigned int hash, int port, | |||
151 | * @snum: port number to look up | 154 | * @snum: port number to look up |
152 | * @udptable: hash list table, must be of UDP_HTABLE_SIZE | 155 | * @udptable: hash list table, must be of UDP_HTABLE_SIZE |
153 | * @port_rover: pointer to record of last unallocated port | 156 | * @port_rover: pointer to record of last unallocated port |
154 | * @saddr_comp: AF-dependent comparison of bound local IP addresses | 157 | * @ops: AF-dependent address operations |
155 | */ | 158 | */ |
156 | int __udp_lib_get_port(struct sock *sk, unsigned short snum, | 159 | int __udp_lib_get_port(struct sock *sk, unsigned short snum, |
157 | struct hlist_head udptable[], int *port_rover, | 160 | struct hlist_head udptable[], int *port_rover, |
158 | int (*saddr_comp)(const struct sock *sk1, | 161 | const struct udp_get_port_ops *ops) |
159 | const struct sock *sk2 ) ) | ||
160 | { | 162 | { |
161 | struct hlist_node *node; | 163 | struct hlist_node *node; |
162 | struct hlist_head *head; | 164 | struct hlist_head *head; |
@@ -176,8 +178,7 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum, | |||
176 | for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) { | 178 | for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) { |
177 | int size; | 179 | int size; |
178 | 180 | ||
179 | hash = hash_port_and_addr(result, | 181 | hash = ops->hash_port_and_rcv_saddr(result, sk); |
180 | inet_sk(sk)->rcv_saddr); | ||
181 | head = &udptable[hash & (UDP_HTABLE_SIZE - 1)]; | 182 | head = &udptable[hash & (UDP_HTABLE_SIZE - 1)]; |
182 | if (hlist_empty(head)) { | 183 | if (hlist_empty(head)) { |
183 | if (result > sysctl_local_port_range[1]) | 184 | if (result > sysctl_local_port_range[1]) |
@@ -203,17 +204,16 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum, | |||
203 | result = sysctl_local_port_range[0] | 204 | result = sysctl_local_port_range[0] |
204 | + ((result - sysctl_local_port_range[0]) & | 205 | + ((result - sysctl_local_port_range[0]) & |
205 | (UDP_HTABLE_SIZE - 1)); | 206 | (UDP_HTABLE_SIZE - 1)); |
206 | hash = hash_port_and_addr(result, 0); | 207 | hash = udp_hash_port(result); |
207 | if (__udp_lib_port_inuse(hash, result, | 208 | if (__udp_lib_port_inuse(hash, result, |
208 | 0, udptable)) | 209 | NULL, udptable, ops)) |
209 | continue; | 210 | continue; |
210 | if (!inet_sk(sk)->rcv_saddr) | 211 | if (ops->saddr_any(sk)) |
211 | break; | 212 | break; |
212 | 213 | ||
213 | hash = hash_port_and_addr(result, | 214 | hash = ops->hash_port_and_rcv_saddr(result, sk); |
214 | inet_sk(sk)->rcv_saddr); | ||
215 | if (! __udp_lib_port_inuse(hash, result, | 215 | if (! __udp_lib_port_inuse(hash, result, |
216 | inet_sk(sk)->rcv_saddr, udptable)) | 216 | sk, udptable, ops)) |
217 | break; | 217 | break; |
218 | } | 218 | } |
219 | if (i >= (1 << 16) / UDP_HTABLE_SIZE) | 219 | if (i >= (1 << 16) / UDP_HTABLE_SIZE) |
@@ -221,7 +221,7 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum, | |||
221 | gotit: | 221 | gotit: |
222 | *port_rover = snum = result; | 222 | *port_rover = snum = result; |
223 | } else { | 223 | } else { |
224 | hash = hash_port_and_addr(snum, 0); | 224 | hash = udp_hash_port(snum); |
225 | head = &udptable[hash & (UDP_HTABLE_SIZE - 1)]; | 225 | head = &udptable[hash & (UDP_HTABLE_SIZE - 1)]; |
226 | 226 | ||
227 | sk_for_each(sk2, node, head) | 227 | sk_for_each(sk2, node, head) |
@@ -231,12 +231,11 @@ gotit: | |||
231 | (!sk2->sk_reuse || !sk->sk_reuse) && | 231 | (!sk2->sk_reuse || !sk->sk_reuse) && |
232 | (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || | 232 | (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || |
233 | sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && | 233 | sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && |
234 | (*saddr_comp)(sk, sk2)) | 234 | ops->saddr_cmp(sk, sk2)) |
235 | goto fail; | 235 | goto fail; |
236 | 236 | ||
237 | if (inet_sk(sk)->rcv_saddr) { | 237 | if (!ops->saddr_any(sk)) { |
238 | hash = hash_port_and_addr(snum, | 238 | hash = ops->hash_port_and_rcv_saddr(snum, sk); |
239 | inet_sk(sk)->rcv_saddr); | ||
240 | head = &udptable[hash & (UDP_HTABLE_SIZE - 1)]; | 239 | head = &udptable[hash & (UDP_HTABLE_SIZE - 1)]; |
241 | 240 | ||
242 | sk_for_each(sk2, node, head) | 241 | sk_for_each(sk2, node, head) |
@@ -248,7 +247,7 @@ gotit: | |||
248 | !sk->sk_bound_dev_if || | 247 | !sk->sk_bound_dev_if || |
249 | sk2->sk_bound_dev_if == | 248 | sk2->sk_bound_dev_if == |
250 | sk->sk_bound_dev_if) && | 249 | sk->sk_bound_dev_if) && |
251 | (*saddr_comp)(sk, sk2)) | 250 | ops->saddr_cmp(sk, sk2)) |
252 | goto fail; | 251 | goto fail; |
253 | } | 252 | } |
254 | } | 253 | } |
@@ -266,12 +265,12 @@ fail: | |||
266 | } | 265 | } |
267 | 266 | ||
268 | int udp_get_port(struct sock *sk, unsigned short snum, | 267 | int udp_get_port(struct sock *sk, unsigned short snum, |
269 | int (*scmp)(const struct sock *, const struct sock *)) | 268 | const struct udp_get_port_ops *ops) |
270 | { | 269 | { |
271 | return __udp_lib_get_port(sk, snum, udp_hash, &udp_port_rover, scmp); | 270 | return __udp_lib_get_port(sk, snum, udp_hash, &udp_port_rover, ops); |
272 | } | 271 | } |
273 | 272 | ||
274 | int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) | 273 | static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) |
275 | { | 274 | { |
276 | struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); | 275 | struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); |
277 | 276 | ||
@@ -280,9 +279,33 @@ int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) | |||
280 | inet1->rcv_saddr == inet2->rcv_saddr )); | 279 | inet1->rcv_saddr == inet2->rcv_saddr )); |
281 | } | 280 | } |
282 | 281 | ||
282 | static int ipv4_rcv_saddr_any(const struct sock *sk) | ||
283 | { | ||
284 | return !inet_sk(sk)->rcv_saddr; | ||
285 | } | ||
286 | |||
287 | static inline unsigned int ipv4_hash_port_and_addr(__u16 port, __be32 addr) | ||
288 | { | ||
289 | addr ^= addr >> 16; | ||
290 | addr ^= addr >> 8; | ||
291 | return port ^ addr; | ||
292 | } | ||
293 | |||
294 | static unsigned int ipv4_hash_port_and_rcv_saddr(__u16 port, | ||
295 | const struct sock *sk) | ||
296 | { | ||
297 | return ipv4_hash_port_and_addr(port, inet_sk(sk)->rcv_saddr); | ||
298 | } | ||
299 | |||
300 | const struct udp_get_port_ops udp_ipv4_ops = { | ||
301 | .saddr_cmp = ipv4_rcv_saddr_equal, | ||
302 | .saddr_any = ipv4_rcv_saddr_any, | ||
303 | .hash_port_and_rcv_saddr = ipv4_hash_port_and_rcv_saddr, | ||
304 | }; | ||
305 | |||
283 | static inline int udp_v4_get_port(struct sock *sk, unsigned short snum) | 306 | static inline int udp_v4_get_port(struct sock *sk, unsigned short snum) |
284 | { | 307 | { |
285 | return udp_get_port(sk, snum, ipv4_rcv_saddr_equal); | 308 | return udp_get_port(sk, snum, &udp_ipv4_ops); |
286 | } | 309 | } |
287 | 310 | ||
288 | /* UDP is nearly always wildcards out the wazoo, it makes no sense to try | 311 | /* UDP is nearly always wildcards out the wazoo, it makes no sense to try |
@@ -297,8 +320,8 @@ static struct sock *__udp4_lib_lookup(__be32 saddr, __be16 sport, | |||
297 | unsigned int hash, hashwild; | 320 | unsigned int hash, hashwild; |
298 | int score, best = -1, hport = ntohs(dport); | 321 | int score, best = -1, hport = ntohs(dport); |
299 | 322 | ||
300 | hash = hash_port_and_addr(hport, daddr); | 323 | hash = ipv4_hash_port_and_addr(hport, daddr); |
301 | hashwild = hash_port_and_addr(hport, 0); | 324 | hashwild = udp_hash_port(hport); |
302 | 325 | ||
303 | read_lock(&udp_hash_lock); | 326 | read_lock(&udp_hash_lock); |
304 | 327 | ||
@@ -1198,8 +1221,8 @@ static int __udp4_lib_mcast_deliver(struct sk_buff *skb, | |||
1198 | struct sock *sk, *skw, *sknext; | 1221 | struct sock *sk, *skw, *sknext; |
1199 | int dif; | 1222 | int dif; |
1200 | int hport = ntohs(uh->dest); | 1223 | int hport = ntohs(uh->dest); |
1201 | unsigned int hash = hash_port_and_addr(hport, daddr); | 1224 | unsigned int hash = ipv4_hash_port_and_addr(hport, daddr); |
1202 | unsigned int hashwild = hash_port_and_addr(hport, 0); | 1225 | unsigned int hashwild = udp_hash_port(hport); |
1203 | 1226 | ||
1204 | dif = skb->dev->ifindex; | 1227 | dif = skb->dev->ifindex; |
1205 | 1228 | ||
diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h index 820a477cfaa6..06d94195e644 100644 --- a/net/ipv4/udp_impl.h +++ b/net/ipv4/udp_impl.h | |||
@@ -5,14 +5,14 @@ | |||
5 | #include <net/protocol.h> | 5 | #include <net/protocol.h> |
6 | #include <net/inet_common.h> | 6 | #include <net/inet_common.h> |
7 | 7 | ||
8 | extern const struct udp_get_port_ops udp_ipv4_ops; | ||
9 | |||
8 | extern int __udp4_lib_rcv(struct sk_buff *, struct hlist_head [], int ); | 10 | extern int __udp4_lib_rcv(struct sk_buff *, struct hlist_head [], int ); |
9 | extern void __udp4_lib_err(struct sk_buff *, u32, struct hlist_head []); | 11 | extern void __udp4_lib_err(struct sk_buff *, u32, struct hlist_head []); |
10 | 12 | ||
11 | extern int __udp_lib_get_port(struct sock *sk, unsigned short snum, | 13 | extern int __udp_lib_get_port(struct sock *sk, unsigned short snum, |
12 | struct hlist_head udptable[], int *port_rover, | 14 | struct hlist_head udptable[], int *port_rover, |
13 | int (*)(const struct sock*,const struct sock*)); | 15 | const struct udp_get_port_ops *ops); |
14 | extern int ipv4_rcv_saddr_equal(const struct sock *, const struct sock *); | ||
15 | |||
16 | 16 | ||
17 | extern int udp_setsockopt(struct sock *sk, int level, int optname, | 17 | extern int udp_setsockopt(struct sock *sk, int level, int optname, |
18 | char __user *optval, int optlen); | 18 | char __user *optval, int optlen); |
diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index f34fd686a8f1..3653b32dce2d 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c | |||
@@ -19,14 +19,15 @@ struct hlist_head udplite_hash[UDP_HTABLE_SIZE]; | |||
19 | static int udplite_port_rover; | 19 | static int udplite_port_rover; |
20 | 20 | ||
21 | int udplite_get_port(struct sock *sk, unsigned short p, | 21 | int udplite_get_port(struct sock *sk, unsigned short p, |
22 | int (*c)(const struct sock *, const struct sock *)) | 22 | const struct udp_get_port_ops *ops) |
23 | { | 23 | { |
24 | return __udp_lib_get_port(sk, p, udplite_hash, &udplite_port_rover, c); | 24 | return __udp_lib_get_port(sk, p, udplite_hash, |
25 | &udplite_port_rover, ops); | ||
25 | } | 26 | } |
26 | 27 | ||
27 | static int udplite_v4_get_port(struct sock *sk, unsigned short snum) | 28 | static int udplite_v4_get_port(struct sock *sk, unsigned short snum) |
28 | { | 29 | { |
29 | return udplite_get_port(sk, snum, ipv4_rcv_saddr_equal); | 30 | return udplite_get_port(sk, snum, &udp_ipv4_ops); |
30 | } | 31 | } |
31 | 32 | ||
32 | static int udplite_rcv(struct sk_buff *skb) | 33 | static int udplite_rcv(struct sk_buff *skb) |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index d02685c6bc69..c7ea248fae2e 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -4204,6 +4204,10 @@ int __init addrconf_init(void) | |||
4204 | return err; | 4204 | return err; |
4205 | 4205 | ||
4206 | ip6_null_entry.rt6i_idev = in6_dev_get(&loopback_dev); | 4206 | ip6_null_entry.rt6i_idev = in6_dev_get(&loopback_dev); |
4207 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | ||
4208 | ip6_prohibit_entry.rt6i_idev = in6_dev_get(&loopback_dev); | ||
4209 | ip6_blk_hole_entry.rt6i_idev = in6_dev_get(&loopback_dev); | ||
4210 | #endif | ||
4207 | 4211 | ||
4208 | register_netdevice_notifier(&ipv6_dev_notf); | 4212 | register_netdevice_notifier(&ipv6_dev_notf); |
4209 | 4213 | ||
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 6d8e4ac7bdad..14be0b9b77a5 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c | |||
@@ -660,6 +660,14 @@ EXPORT_SYMBOL_GPL(ipv6_invert_rthdr); | |||
660 | Hop-by-hop options. | 660 | Hop-by-hop options. |
661 | **********************************/ | 661 | **********************************/ |
662 | 662 | ||
663 | /* | ||
664 | * Note: we cannot rely on skb->dst before we assign it in ip6_route_input(). | ||
665 | */ | ||
666 | static inline struct inet6_dev *ipv6_skb_idev(struct sk_buff *skb) | ||
667 | { | ||
668 | return skb->dst ? ip6_dst_idev(skb->dst) : __in6_dev_get(skb->dev); | ||
669 | } | ||
670 | |||
663 | /* Router Alert as of RFC 2711 */ | 671 | /* Router Alert as of RFC 2711 */ |
664 | 672 | ||
665 | static int ipv6_hop_ra(struct sk_buff **skbp, int optoff) | 673 | static int ipv6_hop_ra(struct sk_buff **skbp, int optoff) |
@@ -688,25 +696,25 @@ static int ipv6_hop_jumbo(struct sk_buff **skbp, int optoff) | |||
688 | if (nh[optoff + 1] != 4 || (optoff & 3) != 2) { | 696 | if (nh[optoff + 1] != 4 || (optoff & 3) != 2) { |
689 | LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", | 697 | LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", |
690 | nh[optoff+1]); | 698 | nh[optoff+1]); |
691 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), | 699 | IP6_INC_STATS_BH(ipv6_skb_idev(skb), |
692 | IPSTATS_MIB_INHDRERRORS); | 700 | IPSTATS_MIB_INHDRERRORS); |
693 | goto drop; | 701 | goto drop; |
694 | } | 702 | } |
695 | 703 | ||
696 | pkt_len = ntohl(*(__be32 *)(nh + optoff + 2)); | 704 | pkt_len = ntohl(*(__be32 *)(nh + optoff + 2)); |
697 | if (pkt_len <= IPV6_MAXPLEN) { | 705 | if (pkt_len <= IPV6_MAXPLEN) { |
698 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS); | 706 | IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INHDRERRORS); |
699 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2); | 707 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2); |
700 | return 0; | 708 | return 0; |
701 | } | 709 | } |
702 | if (ipv6_hdr(skb)->payload_len) { | 710 | if (ipv6_hdr(skb)->payload_len) { |
703 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS); | 711 | IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INHDRERRORS); |
704 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff); | 712 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff); |
705 | return 0; | 713 | return 0; |
706 | } | 714 | } |
707 | 715 | ||
708 | if (pkt_len > skb->len - sizeof(struct ipv6hdr)) { | 716 | if (pkt_len > skb->len - sizeof(struct ipv6hdr)) { |
709 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INTRUNCATEDPKTS); | 717 | IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INTRUNCATEDPKTS); |
710 | goto drop; | 718 | goto drop; |
711 | } | 719 | } |
712 | 720 | ||
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index f508171bab73..4704b5fc3085 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -463,10 +463,17 @@ int ip6_forward(struct sk_buff *skb) | |||
463 | */ | 463 | */ |
464 | if (xrlim_allow(dst, 1*HZ)) | 464 | if (xrlim_allow(dst, 1*HZ)) |
465 | ndisc_send_redirect(skb, n, target); | 465 | ndisc_send_redirect(skb, n, target); |
466 | } else if (ipv6_addr_type(&hdr->saddr)&(IPV6_ADDR_MULTICAST|IPV6_ADDR_LOOPBACK | 466 | } else { |
467 | |IPV6_ADDR_LINKLOCAL)) { | 467 | int addrtype = ipv6_addr_type(&hdr->saddr); |
468 | |||
468 | /* This check is security critical. */ | 469 | /* This check is security critical. */ |
469 | goto error; | 470 | if (addrtype & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LOOPBACK)) |
471 | goto error; | ||
472 | if (addrtype & IPV6_ADDR_LINKLOCAL) { | ||
473 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, | ||
474 | ICMPV6_NOT_NEIGHBOUR, 0, skb->dev); | ||
475 | goto error; | ||
476 | } | ||
470 | } | 477 | } |
471 | 478 | ||
472 | if (skb->len > dst_mtu(dst)) { | 479 | if (skb->len > dst_mtu(dst)) { |
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index 76f0cf66f95c..7e32e2aaf7f7 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c | |||
@@ -24,53 +24,29 @@ static struct | |||
24 | struct ip6t_replace repl; | 24 | struct ip6t_replace repl; |
25 | struct ip6t_standard entries[3]; | 25 | struct ip6t_standard entries[3]; |
26 | struct ip6t_error term; | 26 | struct ip6t_error term; |
27 | } initial_table __initdata | 27 | } initial_table __initdata = { |
28 | = { { "filter", FILTER_VALID_HOOKS, 4, | 28 | .repl = { |
29 | sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error), | 29 | .name = "filter", |
30 | { [NF_IP6_LOCAL_IN] = 0, | 30 | .valid_hooks = FILTER_VALID_HOOKS, |
31 | [NF_IP6_FORWARD] = sizeof(struct ip6t_standard), | 31 | .num_entries = 4, |
32 | [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2 }, | 32 | .size = sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error), |
33 | { [NF_IP6_LOCAL_IN] = 0, | 33 | .hook_entry = { |
34 | [NF_IP6_FORWARD] = sizeof(struct ip6t_standard), | 34 | [NF_IP6_LOCAL_IN] = 0, |
35 | [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2 }, | 35 | [NF_IP6_FORWARD] = sizeof(struct ip6t_standard), |
36 | 0, NULL, { } }, | 36 | [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2 |
37 | { | 37 | }, |
38 | /* LOCAL_IN */ | 38 | .underflow = { |
39 | { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | 39 | [NF_IP6_LOCAL_IN] = 0, |
40 | 0, | 40 | [NF_IP6_FORWARD] = sizeof(struct ip6t_standard), |
41 | sizeof(struct ip6t_entry), | 41 | [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2 |
42 | sizeof(struct ip6t_standard), | 42 | }, |
43 | 0, { 0, 0 }, { } }, | 43 | }, |
44 | { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, | 44 | .entries = { |
45 | -NF_ACCEPT - 1 } }, | 45 | IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */ |
46 | /* FORWARD */ | 46 | IP6T_STANDARD_INIT(NF_ACCEPT), /* FORWARD */ |
47 | { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | 47 | IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ |
48 | 0, | 48 | }, |
49 | sizeof(struct ip6t_entry), | 49 | .term = IP6T_ERROR_INIT, /* ERROR */ |
50 | sizeof(struct ip6t_standard), | ||
51 | 0, { 0, 0 }, { } }, | ||
52 | { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, | ||
53 | -NF_ACCEPT - 1 } }, | ||
54 | /* LOCAL_OUT */ | ||
55 | { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | ||
56 | 0, | ||
57 | sizeof(struct ip6t_entry), | ||
58 | sizeof(struct ip6t_standard), | ||
59 | 0, { 0, 0 }, { } }, | ||
60 | { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, | ||
61 | -NF_ACCEPT - 1 } } | ||
62 | }, | ||
63 | /* ERROR */ | ||
64 | { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | ||
65 | 0, | ||
66 | sizeof(struct ip6t_entry), | ||
67 | sizeof(struct ip6t_error), | ||
68 | 0, { 0, 0 }, { } }, | ||
69 | { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } }, | ||
70 | { } }, | ||
71 | "ERROR" | ||
72 | } | ||
73 | } | ||
74 | }; | 50 | }; |
75 | 51 | ||
76 | static struct xt_table packet_filter = { | 52 | static struct xt_table packet_filter = { |
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index a9f10e32c163..f2d26495f413 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c | |||
@@ -32,73 +32,35 @@ static struct | |||
32 | struct ip6t_replace repl; | 32 | struct ip6t_replace repl; |
33 | struct ip6t_standard entries[5]; | 33 | struct ip6t_standard entries[5]; |
34 | struct ip6t_error term; | 34 | struct ip6t_error term; |
35 | } initial_table __initdata | 35 | } initial_table __initdata = { |
36 | = { { "mangle", MANGLE_VALID_HOOKS, 6, | 36 | .repl = { |
37 | sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error), | 37 | .name = "mangle", |
38 | { [NF_IP6_PRE_ROUTING] = 0, | 38 | .valid_hooks = MANGLE_VALID_HOOKS, |
39 | [NF_IP6_LOCAL_IN] = sizeof(struct ip6t_standard), | 39 | .num_entries = 6, |
40 | [NF_IP6_FORWARD] = sizeof(struct ip6t_standard) * 2, | 40 | .size = sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error), |
41 | [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 3, | 41 | .hook_entry = { |
42 | [NF_IP6_POST_ROUTING] = sizeof(struct ip6t_standard) * 4}, | 42 | [NF_IP6_PRE_ROUTING] = 0, |
43 | { [NF_IP6_PRE_ROUTING] = 0, | 43 | [NF_IP6_LOCAL_IN] = sizeof(struct ip6t_standard), |
44 | [NF_IP6_LOCAL_IN] = sizeof(struct ip6t_standard), | 44 | [NF_IP6_FORWARD] = sizeof(struct ip6t_standard) * 2, |
45 | [NF_IP6_FORWARD] = sizeof(struct ip6t_standard) * 2, | 45 | [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 3, |
46 | [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 3, | 46 | [NF_IP6_POST_ROUTING] = sizeof(struct ip6t_standard) * 4, |
47 | [NF_IP6_POST_ROUTING] = sizeof(struct ip6t_standard) * 4}, | 47 | }, |
48 | 0, NULL, { } }, | 48 | .underflow = { |
49 | { | 49 | [NF_IP6_PRE_ROUTING] = 0, |
50 | /* PRE_ROUTING */ | 50 | [NF_IP6_LOCAL_IN] = sizeof(struct ip6t_standard), |
51 | { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | 51 | [NF_IP6_FORWARD] = sizeof(struct ip6t_standard) * 2, |
52 | 0, | 52 | [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 3, |
53 | sizeof(struct ip6t_entry), | 53 | [NF_IP6_POST_ROUTING] = sizeof(struct ip6t_standard) * 4, |
54 | sizeof(struct ip6t_standard), | 54 | }, |
55 | 0, { 0, 0 }, { } }, | 55 | }, |
56 | { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, | 56 | .entries = { |
57 | -NF_ACCEPT - 1 } }, | 57 | IP6T_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */ |
58 | /* LOCAL_IN */ | 58 | IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */ |
59 | { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | 59 | IP6T_STANDARD_INIT(NF_ACCEPT), /* FORWARD */ |
60 | 0, | 60 | IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ |
61 | sizeof(struct ip6t_entry), | 61 | IP6T_STANDARD_INIT(NF_ACCEPT), /* POST_ROUTING */ |
62 | sizeof(struct ip6t_standard), | 62 | }, |
63 | 0, { 0, 0 }, { } }, | 63 | .term = IP6T_ERROR_INIT, /* ERROR */ |
64 | { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, | ||
65 | -NF_ACCEPT - 1 } }, | ||
66 | /* FORWARD */ | ||
67 | { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | ||
68 | 0, | ||
69 | sizeof(struct ip6t_entry), | ||
70 | sizeof(struct ip6t_standard), | ||
71 | 0, { 0, 0 }, { } }, | ||
72 | { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, | ||
73 | -NF_ACCEPT - 1 } }, | ||
74 | /* LOCAL_OUT */ | ||
75 | { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | ||
76 | 0, | ||
77 | sizeof(struct ip6t_entry), | ||
78 | sizeof(struct ip6t_standard), | ||
79 | 0, { 0, 0 }, { } }, | ||
80 | { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, | ||
81 | -NF_ACCEPT - 1 } }, | ||
82 | /* POST_ROUTING */ | ||
83 | { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | ||
84 | 0, | ||
85 | sizeof(struct ip6t_entry), | ||
86 | sizeof(struct ip6t_standard), | ||
87 | 0, { 0, 0 }, { } }, | ||
88 | { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, | ||
89 | -NF_ACCEPT - 1 } } | ||
90 | }, | ||
91 | /* ERROR */ | ||
92 | { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, | ||
93 | 0, | ||
94 | sizeof(struct ip6t_entry), | ||
95 | sizeof(struct ip6t_error), | ||
96 | 0, { 0, 0 }, { } }, | ||
97 | { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } }, | ||
98 | { } }, | ||
99 | "ERROR" | ||
100 | } | ||
101 | } | ||
102 | }; | 64 | }; |
103 | 65 | ||
104 | static struct xt_table packet_mangler = { | 66 | static struct xt_table packet_mangler = { |
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index a3eb5b8ce18d..0acda45d455d 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c | |||
@@ -35,56 +35,10 @@ static struct | |||
35 | }, | 35 | }, |
36 | }, | 36 | }, |
37 | .entries = { | 37 | .entries = { |
38 | /* PRE_ROUTING */ | 38 | IP6T_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */ |
39 | { | 39 | IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */ |
40 | .entry = { | ||
41 | .target_offset = sizeof(struct ip6t_entry), | ||
42 | .next_offset = sizeof(struct ip6t_standard), | ||
43 | }, | ||
44 | .target = { | ||
45 | .target = { | ||
46 | .u = { | ||
47 | .target_size = IP6T_ALIGN(sizeof(struct ip6t_standard_target)), | ||
48 | }, | ||
49 | }, | ||
50 | .verdict = -NF_ACCEPT - 1, | ||
51 | }, | ||
52 | }, | ||
53 | |||
54 | /* LOCAL_OUT */ | ||
55 | { | ||
56 | .entry = { | ||
57 | .target_offset = sizeof(struct ip6t_entry), | ||
58 | .next_offset = sizeof(struct ip6t_standard), | ||
59 | }, | ||
60 | .target = { | ||
61 | .target = { | ||
62 | .u = { | ||
63 | .target_size = IP6T_ALIGN(sizeof(struct ip6t_standard_target)), | ||
64 | }, | ||
65 | }, | ||
66 | .verdict = -NF_ACCEPT - 1, | ||
67 | }, | ||
68 | }, | ||
69 | }, | 40 | }, |
70 | /* ERROR */ | 41 | .term = IP6T_ERROR_INIT, /* ERROR */ |
71 | .term = { | ||
72 | .entry = { | ||
73 | .target_offset = sizeof(struct ip6t_entry), | ||
74 | .next_offset = sizeof(struct ip6t_error), | ||
75 | }, | ||
76 | .target = { | ||
77 | .target = { | ||
78 | .u = { | ||
79 | .user = { | ||
80 | .target_size = IP6T_ALIGN(sizeof(struct ip6t_error_target)), | ||
81 | .name = IP6T_ERROR_TARGET, | ||
82 | }, | ||
83 | }, | ||
84 | }, | ||
85 | .errorname = "ERROR", | ||
86 | }, | ||
87 | } | ||
88 | }; | 42 | }; |
89 | 43 | ||
90 | static struct xt_table packet_raw = { | 44 | static struct xt_table packet_raw = { |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index b083c09e3d2d..a7ae59c954d5 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -52,9 +52,28 @@ | |||
52 | 52 | ||
53 | DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly; | 53 | DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly; |
54 | 54 | ||
55 | static int ipv6_rcv_saddr_any(const struct sock *sk) | ||
56 | { | ||
57 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
58 | |||
59 | return ipv6_addr_any(&np->rcv_saddr); | ||
60 | } | ||
61 | |||
62 | static unsigned int ipv6_hash_port_and_rcv_saddr(__u16 port, | ||
63 | const struct sock *sk) | ||
64 | { | ||
65 | return port; | ||
66 | } | ||
67 | |||
68 | const struct udp_get_port_ops udp_ipv6_ops = { | ||
69 | .saddr_cmp = ipv6_rcv_saddr_equal, | ||
70 | .saddr_any = ipv6_rcv_saddr_any, | ||
71 | .hash_port_and_rcv_saddr = ipv6_hash_port_and_rcv_saddr, | ||
72 | }; | ||
73 | |||
55 | static inline int udp_v6_get_port(struct sock *sk, unsigned short snum) | 74 | static inline int udp_v6_get_port(struct sock *sk, unsigned short snum) |
56 | { | 75 | { |
57 | return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); | 76 | return udp_get_port(sk, snum, &udp_ipv6_ops); |
58 | } | 77 | } |
59 | 78 | ||
60 | static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport, | 79 | static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport, |
diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h index 6e252f318f7c..36b0c11a28a3 100644 --- a/net/ipv6/udp_impl.h +++ b/net/ipv6/udp_impl.h | |||
@@ -6,6 +6,8 @@ | |||
6 | #include <net/addrconf.h> | 6 | #include <net/addrconf.h> |
7 | #include <net/inet_common.h> | 7 | #include <net/inet_common.h> |
8 | 8 | ||
9 | extern const struct udp_get_port_ops udp_ipv6_ops; | ||
10 | |||
9 | extern int __udp6_lib_rcv(struct sk_buff **, struct hlist_head [], int ); | 11 | extern int __udp6_lib_rcv(struct sk_buff **, struct hlist_head [], int ); |
10 | extern void __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *, | 12 | extern void __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *, |
11 | int , int , int , __be32 , struct hlist_head []); | 13 | int , int , int , __be32 , struct hlist_head []); |
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index f54016a55004..c40a51362f89 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c | |||
@@ -37,7 +37,7 @@ static struct inet6_protocol udplitev6_protocol = { | |||
37 | 37 | ||
38 | static int udplite_v6_get_port(struct sock *sk, unsigned short snum) | 38 | static int udplite_v6_get_port(struct sock *sk, unsigned short snum) |
39 | { | 39 | { |
40 | return udplite_get_port(sk, snum, ipv6_rcv_saddr_equal); | 40 | return udplite_get_port(sk, snum, &udp_ipv6_ops); |
41 | } | 41 | } |
42 | 42 | ||
43 | struct proto udplitev6_prot = { | 43 | struct proto udplitev6_prot = { |
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 822917debeff..3e07e9d6fa42 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c | |||
@@ -17,6 +17,7 @@ | |||
17 | * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE, | 17 | * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE, |
18 | * SSID) | 18 | * SSID) |
19 | */ | 19 | */ |
20 | #include <linux/delay.h> | ||
20 | #include <linux/if_ether.h> | 21 | #include <linux/if_ether.h> |
21 | #include <linux/skbuff.h> | 22 | #include <linux/skbuff.h> |
22 | #include <linux/netdevice.h> | 23 | #include <linux/netdevice.h> |
@@ -27,7 +28,6 @@ | |||
27 | #include <linux/rtnetlink.h> | 28 | #include <linux/rtnetlink.h> |
28 | #include <net/iw_handler.h> | 29 | #include <net/iw_handler.h> |
29 | #include <asm/types.h> | 30 | #include <asm/types.h> |
30 | #include <asm/delay.h> | ||
31 | 31 | ||
32 | #include <net/mac80211.h> | 32 | #include <net/mac80211.h> |
33 | #include "ieee80211_i.h" | 33 | #include "ieee80211_i.h" |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index e132c8ae8784..e8b5c2d7db62 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -299,7 +299,6 @@ destroy_conntrack(struct nf_conntrack *nfct) | |||
299 | { | 299 | { |
300 | struct nf_conn *ct = (struct nf_conn *)nfct; | 300 | struct nf_conn *ct = (struct nf_conn *)nfct; |
301 | struct nf_conn_help *help = nfct_help(ct); | 301 | struct nf_conn_help *help = nfct_help(ct); |
302 | struct nf_conntrack_l3proto *l3proto; | ||
303 | struct nf_conntrack_l4proto *l4proto; | 302 | struct nf_conntrack_l4proto *l4proto; |
304 | typeof(nf_conntrack_destroyed) destroyed; | 303 | typeof(nf_conntrack_destroyed) destroyed; |
305 | 304 | ||
@@ -317,10 +316,6 @@ destroy_conntrack(struct nf_conntrack *nfct) | |||
317 | * destroy_conntrack() MUST NOT be called with a write lock | 316 | * destroy_conntrack() MUST NOT be called with a write lock |
318 | * to nf_conntrack_lock!!! -HW */ | 317 | * to nf_conntrack_lock!!! -HW */ |
319 | rcu_read_lock(); | 318 | rcu_read_lock(); |
320 | l3proto = __nf_ct_l3proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num); | ||
321 | if (l3proto && l3proto->destroy) | ||
322 | l3proto->destroy(ct); | ||
323 | |||
324 | l4proto = __nf_ct_l4proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num, | 319 | l4proto = __nf_ct_l4proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num, |
325 | ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum); | 320 | ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum); |
326 | if (l4proto && l4proto->destroy) | 321 | if (l4proto && l4proto->destroy) |
@@ -893,8 +888,13 @@ void nf_conntrack_alter_reply(struct nf_conn *ct, | |||
893 | NF_CT_DUMP_TUPLE(newreply); | 888 | NF_CT_DUMP_TUPLE(newreply); |
894 | 889 | ||
895 | ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; | 890 | ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; |
896 | if (!ct->master && help && help->expecting == 0) | 891 | if (!ct->master && help && help->expecting == 0) { |
897 | help->helper = __nf_ct_helper_find(newreply); | 892 | struct nf_conntrack_helper *helper; |
893 | helper = __nf_ct_helper_find(newreply); | ||
894 | if (helper) | ||
895 | memset(&help->help, 0, sizeof(help->help)); | ||
896 | help->helper = helper; | ||
897 | } | ||
898 | write_unlock_bh(&nf_conntrack_lock); | 898 | write_unlock_bh(&nf_conntrack_lock); |
899 | } | 899 | } |
900 | EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply); | 900 | EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply); |
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index aa1a97ee514b..d6d39e241327 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -830,11 +830,6 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[]) | |||
830 | char *helpname; | 830 | char *helpname; |
831 | int err; | 831 | int err; |
832 | 832 | ||
833 | if (!help) { | ||
834 | /* FIXME: we need to reallocate and rehash */ | ||
835 | return -EBUSY; | ||
836 | } | ||
837 | |||
838 | /* don't change helper of sibling connections */ | 833 | /* don't change helper of sibling connections */ |
839 | if (ct->master) | 834 | if (ct->master) |
840 | return -EINVAL; | 835 | return -EINVAL; |
@@ -843,25 +838,34 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[]) | |||
843 | if (err < 0) | 838 | if (err < 0) |
844 | return err; | 839 | return err; |
845 | 840 | ||
846 | helper = __nf_conntrack_helper_find_byname(helpname); | 841 | if (!strcmp(helpname, "")) { |
847 | if (!helper) { | 842 | if (help && help->helper) { |
848 | if (!strcmp(helpname, "")) | ||
849 | helper = NULL; | ||
850 | else | ||
851 | return -EINVAL; | ||
852 | } | ||
853 | |||
854 | if (help->helper) { | ||
855 | if (!helper) { | ||
856 | /* we had a helper before ... */ | 843 | /* we had a helper before ... */ |
857 | nf_ct_remove_expectations(ct); | 844 | nf_ct_remove_expectations(ct); |
858 | help->helper = NULL; | 845 | help->helper = NULL; |
859 | } else { | ||
860 | /* need to zero data of old helper */ | ||
861 | memset(&help->help, 0, sizeof(help->help)); | ||
862 | } | 846 | } |
847 | |||
848 | return 0; | ||
863 | } | 849 | } |
864 | 850 | ||
851 | if (!help) { | ||
852 | /* FIXME: we need to reallocate and rehash */ | ||
853 | return -EBUSY; | ||
854 | } | ||
855 | |||
856 | helper = __nf_conntrack_helper_find_byname(helpname); | ||
857 | if (helper == NULL) | ||
858 | return -EINVAL; | ||
859 | |||
860 | if (help->helper == helper) | ||
861 | return 0; | ||
862 | |||
863 | if (help->helper) | ||
864 | /* we had a helper before ... */ | ||
865 | nf_ct_remove_expectations(ct); | ||
866 | |||
867 | /* need to zero data of old helper */ | ||
868 | memset(&help->help, 0, sizeof(help->help)); | ||
865 | help->helper = helper; | 869 | help->helper = helper; |
866 | 870 | ||
867 | return 0; | 871 | return 0; |
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c index f4ea8fe07a53..189ded5f378b 100644 --- a/net/netfilter/xt_conntrack.c +++ b/net/netfilter/xt_conntrack.c | |||
@@ -134,12 +134,66 @@ static void destroy(const struct xt_match *match, void *matchinfo) | |||
134 | nf_ct_l3proto_module_put(match->family); | 134 | nf_ct_l3proto_module_put(match->family); |
135 | } | 135 | } |
136 | 136 | ||
137 | #ifdef CONFIG_COMPAT | ||
138 | struct compat_xt_conntrack_info | ||
139 | { | ||
140 | compat_uint_t statemask; | ||
141 | compat_uint_t statusmask; | ||
142 | struct ip_conntrack_old_tuple tuple[IP_CT_DIR_MAX]; | ||
143 | struct in_addr sipmsk[IP_CT_DIR_MAX]; | ||
144 | struct in_addr dipmsk[IP_CT_DIR_MAX]; | ||
145 | compat_ulong_t expires_min; | ||
146 | compat_ulong_t expires_max; | ||
147 | u_int8_t flags; | ||
148 | u_int8_t invflags; | ||
149 | }; | ||
150 | |||
151 | static void compat_from_user(void *dst, void *src) | ||
152 | { | ||
153 | struct compat_xt_conntrack_info *cm = src; | ||
154 | struct xt_conntrack_info m = { | ||
155 | .statemask = cm->statemask, | ||
156 | .statusmask = cm->statusmask, | ||
157 | .expires_min = cm->expires_min, | ||
158 | .expires_max = cm->expires_max, | ||
159 | .flags = cm->flags, | ||
160 | .invflags = cm->invflags, | ||
161 | }; | ||
162 | memcpy(m.tuple, cm->tuple, sizeof(m.tuple)); | ||
163 | memcpy(m.sipmsk, cm->sipmsk, sizeof(m.sipmsk)); | ||
164 | memcpy(m.dipmsk, cm->dipmsk, sizeof(m.dipmsk)); | ||
165 | memcpy(dst, &m, sizeof(m)); | ||
166 | } | ||
167 | |||
168 | static int compat_to_user(void __user *dst, void *src) | ||
169 | { | ||
170 | struct xt_conntrack_info *m = src; | ||
171 | struct compat_xt_conntrack_info cm = { | ||
172 | .statemask = m->statemask, | ||
173 | .statusmask = m->statusmask, | ||
174 | .expires_min = m->expires_min, | ||
175 | .expires_max = m->expires_max, | ||
176 | .flags = m->flags, | ||
177 | .invflags = m->invflags, | ||
178 | }; | ||
179 | memcpy(cm.tuple, m->tuple, sizeof(cm.tuple)); | ||
180 | memcpy(cm.sipmsk, m->sipmsk, sizeof(cm.sipmsk)); | ||
181 | memcpy(cm.dipmsk, m->dipmsk, sizeof(cm.dipmsk)); | ||
182 | return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0; | ||
183 | } | ||
184 | #endif | ||
185 | |||
137 | static struct xt_match conntrack_match = { | 186 | static struct xt_match conntrack_match = { |
138 | .name = "conntrack", | 187 | .name = "conntrack", |
139 | .match = match, | 188 | .match = match, |
140 | .checkentry = checkentry, | 189 | .checkentry = checkentry, |
141 | .destroy = destroy, | 190 | .destroy = destroy, |
142 | .matchsize = sizeof(struct xt_conntrack_info), | 191 | .matchsize = sizeof(struct xt_conntrack_info), |
192 | #ifdef CONFIG_COMPAT | ||
193 | .compatsize = sizeof(struct compat_xt_conntrack_info), | ||
194 | .compat_from_user = compat_from_user, | ||
195 | .compat_to_user = compat_to_user, | ||
196 | #endif | ||
143 | .family = AF_INET, | 197 | .family = AF_INET, |
144 | .me = THIS_MODULE, | 198 | .me = THIS_MODULE, |
145 | }; | 199 | }; |
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 3385ee592541..f28bb2dc58d0 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c | |||
@@ -71,12 +71,9 @@ void qdisc_unlock_tree(struct net_device *dev) | |||
71 | 71 | ||
72 | 72 | ||
73 | /* Kick device. | 73 | /* Kick device. |
74 | Note, that this procedure can be called by a watchdog timer, so that | ||
75 | we do not check dev->tbusy flag here. | ||
76 | 74 | ||
77 | Returns: 0 - queue is empty. | 75 | Returns: 0 - queue is empty or throttled. |
78 | >0 - queue is not empty, but throttled. | 76 | >0 - queue is not empty. |
79 | <0 - queue is not empty. Device is throttled, if dev->tbusy != 0. | ||
80 | 77 | ||
81 | NOTE: Called under dev->queue_lock with locally disabled BH. | 78 | NOTE: Called under dev->queue_lock with locally disabled BH. |
82 | */ | 79 | */ |
@@ -115,7 +112,7 @@ static inline int qdisc_restart(struct net_device *dev) | |||
115 | kfree_skb(skb); | 112 | kfree_skb(skb); |
116 | if (net_ratelimit()) | 113 | if (net_ratelimit()) |
117 | printk(KERN_DEBUG "Dead loop on netdevice %s, fix it urgently!\n", dev->name); | 114 | printk(KERN_DEBUG "Dead loop on netdevice %s, fix it urgently!\n", dev->name); |
118 | return -1; | 115 | goto out; |
119 | } | 116 | } |
120 | __get_cpu_var(netdev_rx_stat).cpu_collision++; | 117 | __get_cpu_var(netdev_rx_stat).cpu_collision++; |
121 | goto requeue; | 118 | goto requeue; |
@@ -135,10 +132,12 @@ static inline int qdisc_restart(struct net_device *dev) | |||
135 | netif_tx_unlock(dev); | 132 | netif_tx_unlock(dev); |
136 | } | 133 | } |
137 | spin_lock(&dev->queue_lock); | 134 | spin_lock(&dev->queue_lock); |
138 | return -1; | 135 | q = dev->qdisc; |
136 | goto out; | ||
139 | } | 137 | } |
140 | if (ret == NETDEV_TX_LOCKED && nolock) { | 138 | if (ret == NETDEV_TX_LOCKED && nolock) { |
141 | spin_lock(&dev->queue_lock); | 139 | spin_lock(&dev->queue_lock); |
140 | q = dev->qdisc; | ||
142 | goto collision; | 141 | goto collision; |
143 | } | 142 | } |
144 | } | 143 | } |
@@ -163,26 +162,28 @@ static inline int qdisc_restart(struct net_device *dev) | |||
163 | */ | 162 | */ |
164 | 163 | ||
165 | requeue: | 164 | requeue: |
166 | if (skb->next) | 165 | if (unlikely(q == &noop_qdisc)) |
166 | kfree_skb(skb); | ||
167 | else if (skb->next) | ||
167 | dev->gso_skb = skb; | 168 | dev->gso_skb = skb; |
168 | else | 169 | else |
169 | q->ops->requeue(skb, q); | 170 | q->ops->requeue(skb, q); |
170 | netif_schedule(dev); | 171 | netif_schedule(dev); |
171 | return 1; | 172 | return 0; |
172 | } | 173 | } |
174 | |||
175 | out: | ||
173 | BUG_ON((int) q->q.qlen < 0); | 176 | BUG_ON((int) q->q.qlen < 0); |
174 | return q->q.qlen; | 177 | return q->q.qlen; |
175 | } | 178 | } |
176 | 179 | ||
177 | void __qdisc_run(struct net_device *dev) | 180 | void __qdisc_run(struct net_device *dev) |
178 | { | 181 | { |
179 | if (unlikely(dev->qdisc == &noop_qdisc)) | 182 | do { |
180 | goto out; | 183 | if (!qdisc_restart(dev)) |
181 | 184 | break; | |
182 | while (qdisc_restart(dev) < 0 && !netif_queue_stopped(dev)) | 185 | } while (!netif_queue_stopped(dev)); |
183 | /* NOTHING */; | ||
184 | 186 | ||
185 | out: | ||
186 | clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state); | 187 | clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state); |
187 | } | 188 | } |
188 | 189 | ||
@@ -544,6 +545,7 @@ void dev_activate(struct net_device *dev) | |||
544 | void dev_deactivate(struct net_device *dev) | 545 | void dev_deactivate(struct net_device *dev) |
545 | { | 546 | { |
546 | struct Qdisc *qdisc; | 547 | struct Qdisc *qdisc; |
548 | struct sk_buff *skb; | ||
547 | 549 | ||
548 | spin_lock_bh(&dev->queue_lock); | 550 | spin_lock_bh(&dev->queue_lock); |
549 | qdisc = dev->qdisc; | 551 | qdisc = dev->qdisc; |
@@ -551,8 +553,12 @@ void dev_deactivate(struct net_device *dev) | |||
551 | 553 | ||
552 | qdisc_reset(qdisc); | 554 | qdisc_reset(qdisc); |
553 | 555 | ||
556 | skb = dev->gso_skb; | ||
557 | dev->gso_skb = NULL; | ||
554 | spin_unlock_bh(&dev->queue_lock); | 558 | spin_unlock_bh(&dev->queue_lock); |
555 | 559 | ||
560 | kfree_skb(skb); | ||
561 | |||
556 | dev_watchdog_down(dev); | 562 | dev_watchdog_down(dev); |
557 | 563 | ||
558 | /* Wait for outstanding dev_queue_xmit calls. */ | 564 | /* Wait for outstanding dev_queue_xmit calls. */ |
@@ -561,11 +567,6 @@ void dev_deactivate(struct net_device *dev) | |||
561 | /* Wait for outstanding qdisc_run calls. */ | 567 | /* Wait for outstanding qdisc_run calls. */ |
562 | while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state)) | 568 | while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state)) |
563 | yield(); | 569 | yield(); |
564 | |||
565 | if (dev->gso_skb) { | ||
566 | kfree_skb(dev->gso_skb); | ||
567 | dev->gso_skb = NULL; | ||
568 | } | ||
569 | } | 570 | } |
570 | 571 | ||
571 | void dev_init_scheduler(struct net_device *dev) | 572 | void dev_init_scheduler(struct net_device *dev) |
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index d24914db7861..f05ad9a30b4c 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c | |||
@@ -94,14 +94,13 @@ teql_enqueue(struct sk_buff *skb, struct Qdisc* sch) | |||
94 | struct net_device *dev = sch->dev; | 94 | struct net_device *dev = sch->dev; |
95 | struct teql_sched_data *q = qdisc_priv(sch); | 95 | struct teql_sched_data *q = qdisc_priv(sch); |
96 | 96 | ||
97 | __skb_queue_tail(&q->q, skb); | 97 | if (q->q.qlen < dev->tx_queue_len) { |
98 | if (q->q.qlen <= dev->tx_queue_len) { | 98 | __skb_queue_tail(&q->q, skb); |
99 | sch->bstats.bytes += skb->len; | 99 | sch->bstats.bytes += skb->len; |
100 | sch->bstats.packets++; | 100 | sch->bstats.packets++; |
101 | return 0; | 101 | return 0; |
102 | } | 102 | } |
103 | 103 | ||
104 | __skb_unlink(skb, &q->q); | ||
105 | kfree_skb(skb); | 104 | kfree_skb(skb); |
106 | sch->qstats.drops++; | 105 | sch->qstats.drops++; |
107 | return NET_XMIT_DROP; | 106 | return NET_XMIT_DROP; |
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 83a76ba9d7b3..4dcdabf56473 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -4164,6 +4164,7 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len, | |||
4164 | rwlock_t *addr_lock; | 4164 | rwlock_t *addr_lock; |
4165 | int err = 0; | 4165 | int err = 0; |
4166 | void *addrs; | 4166 | void *addrs; |
4167 | void *buf; | ||
4167 | int bytes_copied = 0; | 4168 | int bytes_copied = 0; |
4168 | 4169 | ||
4169 | if (len != sizeof(struct sctp_getaddrs_old)) | 4170 | if (len != sizeof(struct sctp_getaddrs_old)) |
@@ -4217,13 +4218,14 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len, | |||
4217 | } | 4218 | } |
4218 | } | 4219 | } |
4219 | 4220 | ||
4221 | buf = addrs; | ||
4220 | list_for_each(pos, &bp->address_list) { | 4222 | list_for_each(pos, &bp->address_list) { |
4221 | addr = list_entry(pos, struct sctp_sockaddr_entry, list); | 4223 | addr = list_entry(pos, struct sctp_sockaddr_entry, list); |
4222 | memcpy(&temp, &addr->a, sizeof(temp)); | 4224 | memcpy(&temp, &addr->a, sizeof(temp)); |
4223 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); | 4225 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); |
4224 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; | 4226 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; |
4225 | memcpy(addrs, &temp, addrlen); | 4227 | memcpy(buf, &temp, addrlen); |
4226 | to += addrlen; | 4228 | buf += addrlen; |
4227 | bytes_copied += addrlen; | 4229 | bytes_copied += addrlen; |
4228 | cnt ++; | 4230 | cnt ++; |
4229 | if (cnt >= getaddrs.addr_num) break; | 4231 | if (cnt >= getaddrs.addr_num) break; |
@@ -4266,6 +4268,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | |||
4266 | size_t space_left; | 4268 | size_t space_left; |
4267 | int bytes_copied = 0; | 4269 | int bytes_copied = 0; |
4268 | void *addrs; | 4270 | void *addrs; |
4271 | void *buf; | ||
4269 | 4272 | ||
4270 | if (len <= sizeof(struct sctp_getaddrs)) | 4273 | if (len <= sizeof(struct sctp_getaddrs)) |
4271 | return -EINVAL; | 4274 | return -EINVAL; |
@@ -4316,6 +4319,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | |||
4316 | } | 4319 | } |
4317 | } | 4320 | } |
4318 | 4321 | ||
4322 | buf = addrs; | ||
4319 | list_for_each(pos, &bp->address_list) { | 4323 | list_for_each(pos, &bp->address_list) { |
4320 | addr = list_entry(pos, struct sctp_sockaddr_entry, list); | 4324 | addr = list_entry(pos, struct sctp_sockaddr_entry, list); |
4321 | memcpy(&temp, &addr->a, sizeof(temp)); | 4325 | memcpy(&temp, &addr->a, sizeof(temp)); |
@@ -4325,8 +4329,8 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | |||
4325 | err = -ENOMEM; /*fixme: right error?*/ | 4329 | err = -ENOMEM; /*fixme: right error?*/ |
4326 | goto error; | 4330 | goto error; |
4327 | } | 4331 | } |
4328 | memcpy(addrs, &temp, addrlen); | 4332 | memcpy(buf, &temp, addrlen); |
4329 | to += addrlen; | 4333 | buf += addrlen; |
4330 | bytes_copied += addrlen; | 4334 | bytes_copied += addrlen; |
4331 | cnt ++; | 4335 | cnt ++; |
4332 | space_left -= addrlen; | 4336 | space_left -= addrlen; |
@@ -5227,7 +5231,12 @@ int sctp_inet_listen(struct socket *sock, int backlog) | |||
5227 | /* Allocate HMAC for generating cookie. */ | 5231 | /* Allocate HMAC for generating cookie. */ |
5228 | if (sctp_hmac_alg) { | 5232 | if (sctp_hmac_alg) { |
5229 | tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC); | 5233 | tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC); |
5230 | if (!tfm) { | 5234 | if (IS_ERR(tfm)) { |
5235 | if (net_ratelimit()) { | ||
5236 | printk(KERN_INFO | ||
5237 | "SCTP: failed to load transform for %s: %ld\n", | ||
5238 | sctp_hmac_alg, PTR_ERR(tfm)); | ||
5239 | } | ||
5231 | err = -ENOSYS; | 5240 | err = -ENOSYS; |
5232 | goto out; | 5241 | goto out; |
5233 | } | 5242 | } |
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index 661ea2dd78ba..bfecb353ab3d 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c | |||
@@ -141,11 +141,6 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( | |||
141 | * an ABORT, so we need to include it in the sac_info. | 141 | * an ABORT, so we need to include it in the sac_info. |
142 | */ | 142 | */ |
143 | if (chunk) { | 143 | if (chunk) { |
144 | /* sctp_inqu_pop() has allready pulled off the chunk | ||
145 | * header. We need to put it back temporarily | ||
146 | */ | ||
147 | skb_push(chunk->skb, sizeof(sctp_chunkhdr_t)); | ||
148 | |||
149 | /* Copy the chunk data to a new skb and reserve enough | 144 | /* Copy the chunk data to a new skb and reserve enough |
150 | * head room to use as notification. | 145 | * head room to use as notification. |
151 | */ | 146 | */ |
@@ -155,9 +150,6 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( | |||
155 | if (!skb) | 150 | if (!skb) |
156 | goto fail; | 151 | goto fail; |
157 | 152 | ||
158 | /* put back the chunk header now that we have a copy */ | ||
159 | skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t)); | ||
160 | |||
161 | /* Embed the event fields inside the cloned skb. */ | 153 | /* Embed the event fields inside the cloned skb. */ |
162 | event = sctp_skb2event(skb); | 154 | event = sctp_skb2event(skb); |
163 | sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize); | 155 | sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize); |
@@ -168,7 +160,8 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change( | |||
168 | 160 | ||
169 | /* Trim the buffer to the right length. */ | 161 | /* Trim the buffer to the right length. */ |
170 | skb_trim(skb, sizeof(struct sctp_assoc_change) + | 162 | skb_trim(skb, sizeof(struct sctp_assoc_change) + |
171 | ntohs(chunk->chunk_hdr->length)); | 163 | ntohs(chunk->chunk_hdr->length) - |
164 | sizeof(sctp_chunkhdr_t)); | ||
172 | } else { | 165 | } else { |
173 | event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), | 166 | event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), |
174 | MSG_NOTIFICATION, gfp); | 167 | MSG_NOTIFICATION, gfp); |