]> nv-tegra.nvidia Code Review - linux-2.6.git/commitdiff
Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Fri, 11 May 2007 16:59:50 +0000 (09:59 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Fri, 11 May 2007 16:59:50 +0000 (09:59 -0700)
* 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus: (28 commits)
  [MIPS] Rework cobalt_board_id
  [MIPS] Use RTC_CMOS for Cobalt
  [MIPS] Use platform_device for Cobalt UART
  [MIPS] Separate Alchemy processor based boards config
  [MIPS] Fix build error in atomic64_cmpxchg
  [MIPS] Run checksyscalls for N32 and O32 ABI
  [MIPS] tlbex: use __maybe_unused
  [MIPS] excite: use __maybe_unused
  [MIPS] Add extern cobalt_board_id
  [MIPS] Remove unused CONFIG_TOSHIBA_BOARDS
  [MIPS] Rename tb0229_defconfig to tb0219_defconfig
  [MIPS] Update tb0229_defconfig; add CONFIG_GPIO_TB0219.
  [MIPS] Add minimum defconfig for RBHMA4200
  [MIPS] SB1: Build fix.
  [MIPS] Drop __devinit tag from allocate_irqno() and free_irqno()
  [MIPS] clocksource: use CLOCKSOURCE_MASK() macro
  [MIPS] Remove LIMITED_DMA support
  [MIPS] Remove Momenco Jaguar ATX support
  [MIPS] Remove Momenco Ocelot G support
  [MIPS] FPU hazard handling
  ...

232 files changed:
Documentation/SubmitChecklist
Documentation/gpio.txt
arch/frv/kernel/gdb-stub.c
arch/h8300/kernel/syscalls.S
arch/i386/kernel/syscall_table.S
arch/ia64/ia32/audit.c
arch/ia64/kernel/audit.c
arch/m32r/Kconfig
arch/m32r/mm/mmu.S
arch/powerpc/kernel/audit.c
arch/powerpc/kernel/compat_audit.c
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/swsusp.c
arch/powerpc/platforms/cell/pervasive.c
arch/s390/kernel/audit.c
arch/s390/kernel/compat_audit.c
arch/sparc64/kernel/audit.c
arch/sparc64/kernel/compat_audit.c
arch/um/Kconfig
arch/um/defconfig
arch/um/include/common-offsets.h
arch/um/include/kern_util.h
arch/um/include/os.h
arch/um/kernel/dyn.lds.S
arch/um/kernel/init_task.c
arch/um/kernel/irq.c
arch/um/kernel/skas/process.c
arch/um/kernel/tt/exec_kern.c
arch/um/kernel/tt/process_kern.c
arch/um/kernel/um_arch.c
arch/um/kernel/uml.lds.S
arch/um/os-Linux/signal.c
arch/um/os-Linux/skas/process.c
arch/um/os-Linux/sys-i386/signal.c
arch/um/os-Linux/sys-x86_64/signal.c
arch/um/os-Linux/util.c
arch/x86_64/ia32/audit.c
arch/x86_64/ia32/ia32entry.S
arch/x86_64/kernel/audit.c
arch/x86_64/kernel/head64.c
block/ll_rw_blk.c
drivers/bluetooth/hci_ldisc.c
drivers/bluetooth/hci_uart.h
drivers/char/n_tty.c
drivers/char/rio/riocmd.c
drivers/char/rocket.c
drivers/char/rocket_int.h
drivers/char/synclink_gt.c
drivers/char/tty_io.c
drivers/hid/hid-input.c
drivers/hid/usbhid/Kconfig
drivers/hid/usbhid/hid-core.c
drivers/hid/usbhid/hid-lgff.c
drivers/hid/usbhid/hid-plff.c
drivers/hid/usbhid/hid-quirks.c
drivers/hid/usbhid/hid-tmff.c
drivers/hid/usbhid/hid-zpff.c
drivers/hid/usbhid/hiddev.c
drivers/hid/usbhid/usbkbd.c
drivers/hid/usbhid/usbmouse.c
drivers/input/evdev.c
drivers/md/md.c
drivers/net/irda/Kconfig
drivers/net/irda/Makefile
drivers/net/irda/kingsun-sir.c [new file with mode: 0644]
drivers/rtc/Kconfig
drivers/rtc/rtc-rs5c313.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/mpc52xx_psc_spi.c [new file with mode: 0644]
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/atmel_lcdfb.c [new file with mode: 0644]
drivers/video/console/Kconfig
drivers/video/nvidia/nv_hw.c
drivers/video/nvidia/nvidia.c
drivers/video/pm2fb.c
drivers/video/pm3fb.c
drivers/video/riva/rivafb-i2c.c
fs/Makefile
fs/afs/afs.h
fs/afs/afs_fs.h
fs/afs/dir.c
fs/afs/file.c
fs/afs/fsclient.c
fs/afs/inode.c
fs/afs/internal.h
fs/afs/super.c
fs/afs/vnode.c
fs/afs/write.c
fs/aio.c
fs/anon_inodes.c [new file with mode: 0644]
fs/autofs/autofs_i.h
fs/autofs/inode.c
fs/autofs/root.c
fs/autofs4/inode.c
fs/autofs4/root.c
fs/compat.c
fs/eventfd.c [new file with mode: 0644]
fs/eventpoll.c
fs/exec.c
fs/mpage.c
fs/namei.c
fs/partitions/Kconfig
fs/partitions/efi.c
fs/signalfd.c [new file with mode: 0644]
fs/timerfd.c [new file with mode: 0644]
fs/xattr.c
include/asm-alpha/poll.h
include/asm-arm/poll.h
include/asm-arm26/poll.h
include/asm-avr32/poll.h
include/asm-cris/poll.h
include/asm-frv/poll.h
include/asm-generic/Kbuild
include/asm-generic/audit_signal.h [new file with mode: 0644]
include/asm-generic/poll.h [new file with mode: 0644]
include/asm-h8300/poll.h
include/asm-h8300/unistd.h
include/asm-i386/alternative.h
include/asm-i386/poll.h
include/asm-i386/tsc.h
include/asm-i386/unistd.h
include/asm-ia64/poll.h
include/asm-m32r/pgtable-2level.h
include/asm-m32r/pgtable.h
include/asm-m32r/poll.h
include/asm-m32r/system.h
include/asm-m68k/poll.h
include/asm-mips/poll.h
include/asm-parisc/poll.h
include/asm-powerpc/hw_irq.h
include/asm-powerpc/poll.h
include/asm-s390/poll.h
include/asm-sh/poll.h
include/asm-sh64/poll.h
include/asm-sparc/poll.h
include/asm-sparc64/poll.h
include/asm-um/thread_info.h
include/asm-v850/poll.h
include/asm-x86_64/alternative.h
include/asm-x86_64/page.h
include/asm-x86_64/poll.h
include/asm-x86_64/unistd.h
include/asm-xtensa/poll.h
include/linux/Kbuild
include/linux/aio.h
include/linux/aio_abi.h
include/linux/anon_inodes.h [new file with mode: 0644]
include/linux/audit.h
include/linux/compat.h
include/linux/eventfd.h [new file with mode: 0644]
include/linux/genhd.h
include/linux/hid.h
include/linux/init_task.h
include/linux/interrupt.h
include/linux/kernel.h
include/linux/magic.h
include/linux/module.h
include/linux/mpage.h
include/linux/netdevice.h
include/linux/netfilter/x_tables.h
include/linux/netfilter_arp/arp_tables.h
include/linux/netfilter_ipv4/ip_tables.h
include/linux/netfilter_ipv6/ip6_tables.h
include/linux/pid.h
include/linux/sched.h
include/linux/signal.h
include/linux/signalfd.h [new file with mode: 0644]
include/linux/synclink.h
include/linux/syscalls.h
include/linux/task_io_accounting_ops.h
include/linux/timerfd.h [new file with mode: 0644]
include/linux/tty_driver.h
include/linux/tty_ldisc.h
include/linux/writeback.h
include/net/netfilter/nf_conntrack.h
include/net/netfilter/nf_conntrack_l3proto.h
include/net/netfilter/nf_nat_rule.h
include/net/udp.h
include/net/udplite.h
include/video/atmel_lcdc.h [new file with mode: 0644]
include/video/pm3fb.h
init/Kconfig
init/main.c
ipc/mqueue.c
kernel/audit.h
kernel/auditfilter.c
kernel/auditsc.c
kernel/compat.c
kernel/exit.c
kernel/fork.c
kernel/pid.c
kernel/ptrace.c
kernel/signal.c
kernel/stop_machine.c
kernel/sys.c
kernel/sys_ni.c
lib/Makefile
lib/audit.c
lib/hexdump.c [new file with mode: 0644]
mm/page-writeback.c
mm/thrash.c
mm/vmstat.c
net/bluetooth/hidp/core.c
net/core/link_watch.c
net/ipv4/netfilter/arptable_filter.c
net/ipv4/netfilter/iptable_filter.c
net/ipv4/netfilter/iptable_mangle.c
net/ipv4/netfilter/iptable_raw.c
net/ipv4/netfilter/nf_nat_rule.c
net/ipv4/netfilter/nf_nat_standalone.c
net/ipv4/udp.c
net/ipv4/udp_impl.h
net/ipv4/udplite.c
net/ipv6/addrconf.c
net/ipv6/exthdrs.c
net/ipv6/ip6_output.c
net/ipv6/netfilter/ip6table_filter.c
net/ipv6/netfilter/ip6table_mangle.c
net/ipv6/netfilter/ip6table_raw.c
net/ipv6/udp.c
net/ipv6/udp_impl.h
net/ipv6/udplite.c
net/mac80211/ieee80211_sta.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/xt_conntrack.c
net/sched/sch_generic.c
net/sched/sch_teql.c
net/sctp/socket.c
net/sctp/ulpevent.c

index 6491b2c45dd48af654e411278559d537ec237330..3af3e65cf43b54ccfb150824e9338b8567234812 100644 (file)
@@ -73,9 +73,9 @@ kernel patches.
     If the new code is substantial, addition of subsystem-specific fault
     injection might be appropriate.
 
-22: Newly-added code has been compiled with `gcc -W'.  This will generate
-    lots of noise, but is good for finding bugs like "warning: comparison
-    between signed and unsigned".
+22: Newly-added code has been compiled with `gcc -W' (use "make
+    EXTRA_CFLAGS=-W").  This will generate lots of noise, but is good for
+    finding bugs like "warning: comparison between signed and unsigned".
 
 23: Tested after it has been merged into the -mm patchset to make sure
     that it still works with all of the other queued patches and various
index f8528db967fa758ad3afbfcc5f5fed4d170d1b7f..e8be0abb346c1bb95e254d7b9f78072d4e6a0d4c 100644 (file)
@@ -66,7 +66,9 @@ registers; another might implement it by delegating through abstractions
 used for several very different kinds of GPIO controller.
 
 That said, if the convention is supported on their platform, drivers should
-use it when possible:
+use it when possible.  Platforms should declare GENERIC_GPIO support in
+Kconfig (boolean true), which multi-platform drivers can depend on when
+using the include file:
 
        #include <asm/gpio.h>
 
index 9550f37fb62c112b1a58d2908ab9363493acc55c..1e7a101cbf4c8c645c894adfdf9f718f6b0e76eb 100644 (file)
@@ -1195,7 +1195,7 @@ static void gdbstub_check_breakpoint(void)
 /*
  *
  */
-static void __attribute__((unused)) gdbstub_show_regs(void)
+static void __maybe_unused gdbstub_show_regs(void)
 {
        unsigned long *reg;
        int loop;
@@ -1223,7 +1223,7 @@ static void __attribute__((unused)) gdbstub_show_regs(void)
 /*
  * dump debugging regs
  */
-static void __attribute__((unused)) gdbstub_dump_debugregs(void)
+static void __maybe_unused gdbstub_dump_debugregs(void)
 {
        gdbstub_printk("DCR    %08lx  ", __debug_status.dcr);
        gdbstub_printk("BRR    %08lx\n", __debug_status.brr);
@@ -2079,25 +2079,25 @@ void gdbstub_exit(int status)
  * GDB wants to call malloc() and free() to allocate memory for calling kernel
  * functions directly from its command line
  */
-static void *malloc(size_t size) __attribute__((unused));
+static void *malloc(size_t size) __maybe_unused;
 static void *malloc(size_t size)
 {
        return kmalloc(size, GFP_ATOMIC);
 }
 
-static void free(void *p) __attribute__((unused));
+static void free(void *p) __maybe_unused;
 static void free(void *p)
 {
        kfree(p);
 }
 
-static uint32_t ___get_HSR0(void) __attribute__((unused));
+static uint32_t ___get_HSR0(void) __maybe_unused;
 static uint32_t ___get_HSR0(void)
 {
        return __get_HSR(0);
 }
 
-static uint32_t ___set_HSR0(uint32_t x) __attribute__((unused));
+static uint32_t ___set_HSR0(uint32_t x) __maybe_unused;
 static uint32_t ___set_HSR0(uint32_t x)
 {
        __set_HSR(0, x);
index dab98fd99e63efa3ee58504a40c4a10ae930583f..54e21c3f2057359df65ae62bc10b6d7e67c89288 100644 (file)
@@ -31,7 +31,7 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_mknod)
        .long SYMBOL_NAME(sys_chmod)            /* 15 */
        .long SYMBOL_NAME(sys_chown16)
-       .long SYMBOL_NAME(sys_ni_syscall)                               /* old break syscall holder */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* old break syscall holder */
        .long SYMBOL_NAME(sys_stat)
        .long SYMBOL_NAME(sys_lseek)
        .long SYMBOL_NAME(sys_getpid)           /* 20 */
@@ -45,11 +45,11 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_fstat)
        .long SYMBOL_NAME(sys_pause)
        .long SYMBOL_NAME(sys_utime)            /* 30 */
-       .long SYMBOL_NAME(sys_ni_syscall)                               /* old stty syscall holder */
-       .long SYMBOL_NAME(sys_ni_syscall)                               /* old gtty syscall holder */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* old stty syscall holder */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* old gtty syscall holder */
        .long SYMBOL_NAME(sys_access)
        .long SYMBOL_NAME(sys_nice)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* 35 */                /* old ftime syscall holder */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* 35 old ftime syscall holder */
        .long SYMBOL_NAME(sys_sync)
        .long SYMBOL_NAME(sys_kill)
        .long SYMBOL_NAME(sys_rename)
@@ -58,7 +58,7 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_dup)
        .long SYMBOL_NAME(sys_pipe)
        .long SYMBOL_NAME(sys_times)
-       .long SYMBOL_NAME(sys_ni_syscall)                               /* old prof syscall holder */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* old prof syscall holder */
        .long SYMBOL_NAME(sys_brk)              /* 45 */
        .long SYMBOL_NAME(sys_setgid16)
        .long SYMBOL_NAME(sys_getgid16)
@@ -66,13 +66,13 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_geteuid16)
        .long SYMBOL_NAME(sys_getegid16)        /* 50 */
        .long SYMBOL_NAME(sys_acct)
-       .long SYMBOL_NAME(sys_umount)                                   /* recycled never used phys() */
-       .long SYMBOL_NAME(sys_ni_syscall)                               /* old lock syscall holder */
+       .long SYMBOL_NAME(sys_umount)           /* recycled never used phys() */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* old lock syscall holder */
        .long SYMBOL_NAME(sys_ioctl)
        .long SYMBOL_NAME(sys_fcntl)            /* 55 */
-       .long SYMBOL_NAME(sys_ni_syscall)                               /* old mpx syscall holder */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* old mpx syscall holder */
        .long SYMBOL_NAME(sys_setpgid)
-       .long SYMBOL_NAME(sys_ni_syscall)                               /* old ulimit syscall holder */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* old ulimit syscall holder */
        .long SYMBOL_NAME(sys_ni_syscall)
        .long SYMBOL_NAME(sys_umask)            /* 60 */
        .long SYMBOL_NAME(sys_chroot)
@@ -112,7 +112,7 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_fchown16)         /* 95 */
        .long SYMBOL_NAME(sys_getpriority)
        .long SYMBOL_NAME(sys_setpriority)
-       .long SYMBOL_NAME(sys_ni_syscall)                               /* old profil syscall holder */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* old profil syscall holder */
        .long SYMBOL_NAME(sys_statfs)
        .long SYMBOL_NAME(sys_fstatfs)          /* 100 */
        .long SYMBOL_NAME(sys_ni_syscall)       /* ioperm for i386 */
@@ -202,8 +202,8 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_capset)           /* 185 */
        .long SYMBOL_NAME(sys_sigaltstack)
        .long SYMBOL_NAME(sys_sendfile)
-       .long SYMBOL_NAME(sys_ni_syscall)               /* streams1 */
-       .long SYMBOL_NAME(sys_ni_syscall)               /* streams2 */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* streams1 */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* streams2 */
        .long SYMBOL_NAME(sys_vfork)            /* 190 */
        .long SYMBOL_NAME(sys_getrlimit)
        .long SYMBOL_NAME(sys_mmap2)
@@ -236,10 +236,10 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_ni_syscall)
        .long SYMBOL_NAME(sys_getdents64)       /* 220 */
        .long SYMBOL_NAME(sys_fcntl64)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* reserved for TUX */
-       .long SYMBOL_NAME(sys_ni_syscall)
+       .long SYMBOL_NAME(sys_ni_syscall)       /* reserved TUX */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* reserved Security */
        .long SYMBOL_NAME(sys_gettid)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* 225 */ /* sys_readahead */
+       .long SYMBOL_NAME(sys_readahead)        /* 225 */
        .long SYMBOL_NAME(sys_setxattr)
        .long SYMBOL_NAME(sys_lsetxattr)
        .long SYMBOL_NAME(sys_fsetxattr)
@@ -257,8 +257,8 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_futex)            /* 240 */
        .long SYMBOL_NAME(sys_sched_setaffinity)
        .long SYMBOL_NAME(sys_sched_getaffinity)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_set_thread_area */
-       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_get_thread_area */
+       .long SYMBOL_NAME(sys_ni_syscall)
+       .long SYMBOL_NAME(sys_ni_syscall)
        .long SYMBOL_NAME(sys_io_setup)         /* 245 */
        .long SYMBOL_NAME(sys_io_destroy)
        .long SYMBOL_NAME(sys_io_getevents)
@@ -288,8 +288,8 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_utimes)
        .long SYMBOL_NAME(sys_fadvise64_64)
        .long SYMBOL_NAME(sys_ni_syscall)       /* sys_vserver */
-       .long SYMBOL_NAME(sys_mbind)
-       .long SYMBOL_NAME(sys_get_mempolicy)
+       .long SYMBOL_NAME(sys_ni_syscall)
+       .long SYMBOL_NAME(sys_get_mempolicy)    /* 275 */
        .long SYMBOL_NAME(sys_set_mempolicy)
        .long SYMBOL_NAME(sys_mq_open)
        .long SYMBOL_NAME(sys_mq_unlink)
@@ -297,16 +297,42 @@ SYMBOL_NAME_LABEL(sys_call_table)
        .long SYMBOL_NAME(sys_mq_timedreceive)  /* 280 */
        .long SYMBOL_NAME(sys_mq_notify)
        .long SYMBOL_NAME(sys_mq_getsetattr)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* reserved for kexec */
        .long SYMBOL_NAME(sys_waitid)
-       .long SYMBOL_NAME(sys_ni_syscall)       /* 285 */ /* available */
-       .long SYMBOL_NAME(sys_add_key)
+       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_kexec_load */
+       .long SYMBOL_NAME(sys_add_key)          /* 285 */
        .long SYMBOL_NAME(sys_request_key)
        .long SYMBOL_NAME(sys_keyctl)
-
-       .rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4
-               .long SYMBOL_NAME(sys_ni_syscall)
-       .endr
+       .long SYMBOL_NAME(sys_ioprio_set)
+       .long SYMBOL_NAME(sys_ioprio_get)       /* 290 */
+       .long SYMBOL_NAME(sys_inotify_init)
+       .long SYMBOL_NAME(sys_inotify_add_watch)
+       .long SYMBOL_NAME(sys_inotify_rm_watch)
+       .long SYMBOL_NAME(sys_migrate_pages)
+       .long SYMBOL_NAME(sys_openat)           /* 295 */
+       .long SYMBOL_NAME(sys_mkdirat)
+       .long SYMBOL_NAME(sys_mknodat)
+       .long SYMBOL_NAME(sys_fchownat)
+       .long SYMBOL_NAME(sys_futimesat)
+       .long SYMBOL_NAME(sys_fstatat64)        /* 300 */
+       .long SYMBOL_NAME(sys_unlinkat)
+       .long SYMBOL_NAME(sys_renameat)
+       .long SYMBOL_NAME(sys_linkat)
+       .long SYMBOL_NAME(sys_symlinkat)
+       .long SYMBOL_NAME(sys_readlinkat)       /* 305 */
+       .long SYMBOL_NAME(sys_fchmodat)
+       .long SYMBOL_NAME(sys_faccessat)
+       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_pselect6 */
+       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_ppoll */
+       .long SYMBOL_NAME(sys_unshare)          /* 310 */
+       .long SYMBOL_NAME(sys_set_robust_list)
+       .long SYMBOL_NAME(sys_get_robust_list)
+       .long SYMBOL_NAME(sys_splice)
+       .long SYMBOL_NAME(sys_sync_file_range)
+       .long SYMBOL_NAME(sys_tee)              /* 315 */
+       .long SYMBOL_NAME(sys_vmsplice)
+       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_move_pages */
+       .long SYMBOL_NAME(sys_getcpu)
+       .long SYMBOL_NAME(sys_ni_syscall)       /* sys_epoll_pwait */
 
        .macro  call_sp addr
        mov.l   #SYMBOL_NAME(\addr),er6
index 0772678ceecf376753f834753441821c83ca3d53..bf6adce52267c2b94d2c4dac064f508a43c6492b 100644 (file)
@@ -320,3 +320,6 @@ ENTRY(sys_call_table)
        .long sys_getcpu
        .long sys_epoll_pwait
        .long sys_utimensat             /* 320 */
+       .long sys_signalfd
+       .long sys_timerfd
+       .long sys_eventfd
index 92d7d0c8d93fb238dcf32831dcbfc5719078efd6..8850fe40ea34240a340f11e10eb07e6af8641895 100644 (file)
@@ -20,6 +20,11 @@ unsigned ia32_read_class[] = {
 ~0U
 };
 
+unsigned ia32_signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
 int ia32_classify_syscall(unsigned syscall)
 {
        switch(syscall) {
index 04682555a28c0e81b33feb1492fae2dc9ee05a2c..f3802ae89b108c610d16e3f0b6ab7b9597c21478 100644 (file)
@@ -23,6 +23,20 @@ static unsigned chattr_class[] = {
 ~0U
 };
 
+static unsigned signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
+int audit_classify_arch(int arch)
+{
+#ifdef CONFIG_IA32_SUPPORT
+       if (arch == AUDIT_ARCH_I386)
+               return 1;
+#endif
+       return 0;
+}
+
 int audit_classify_syscall(int abi, unsigned syscall)
 {
 #ifdef CONFIG_IA32_SUPPORT
@@ -49,15 +63,18 @@ static int __init audit_classes_init(void)
        extern __u32 ia32_write_class[];
        extern __u32 ia32_read_class[];
        extern __u32 ia32_chattr_class[];
+       extern __u32 ia32_signal_class[];
        audit_register_class(AUDIT_CLASS_WRITE_32, ia32_write_class);
        audit_register_class(AUDIT_CLASS_READ_32, ia32_read_class);
        audit_register_class(AUDIT_CLASS_DIR_WRITE_32, ia32_dir_class);
        audit_register_class(AUDIT_CLASS_CHATTR_32, ia32_chattr_class);
+       audit_register_class(AUDIT_CLASS_SIGNAL_32, ia32_signal_class);
 #endif
        audit_register_class(AUDIT_CLASS_WRITE, write_class);
        audit_register_class(AUDIT_CLASS_READ, read_class);
        audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
        audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+       audit_register_class(AUDIT_CLASS_SIGNAL, signal_class);
        return 0;
 }
 
index 9740d6b8ae11c407ae56d4c88bf6b179056deceb..c3bb8a755b00a3f13cdfc891a2b42ddbe0d63b63 100644 (file)
@@ -241,6 +241,10 @@ config GENERIC_CALIBRATE_DELAY
        bool
        default y
 
+config SCHED_NO_NO_OMIT_FRAME_POINTER
+        bool
+        default y
+
 config PREEMPT
        bool "Preemptible Kernel"
        help
index 8bb74b10dca76707a2d7c52e4fb3399fd3f26fbf..49a6d16a3d585d5b2a4d567ce7256162340130cc 100644 (file)
@@ -163,7 +163,8 @@ ENTRY(tme_handler)
 
        ; pte_data = (unsigned long)pte_val(*pte);
        ld      r2, @r3                 ; r2: pte data
-       or3     r2, r2, #2              ; _PAGE_PRESENT(=2)
+       and3    r3, r2, #2              ; _PAGE_PRESENT(=2) check
+       beqz    r3, 3f
 
        .fillinsn
 5:
@@ -264,11 +265,8 @@ ENTRY(tme_handler)
 ;
        and3    r1, r1, #0xeff
        ldi     r4, #611                ; _KERNPG_TABLE(=611)
-       beq     r1, r4, 4f              ; !pmd_bad(*pmd) ?
-       .fillinsn
-3:
-       ldi     r1, #0                  ; r1: pte_data = 0
-       bra     5f
+       bne     r1, r4, 3f              ; !pmd_bad(*pmd) ?
+
        .fillinsn
 4:
        ; pte = pte_offset(pmd, address);
@@ -282,8 +280,10 @@ ENTRY(tme_handler)
        add     r4, r3                  ; r4: pte
        ; pte_data = (unsigned long)pte_val(*pte);
        ld      r1, @r4                 ; r1: pte_data
-       .fillinsn
+       and3    r3, r1, #2              ; _PAGE_PRESENT(=2) check
+       beqz    r3, 3f
 
+       .fillinsn
 ;; set tlb
 ; r0: address, r1: pte_data, r2: entry
 ; r3,r4: (free)
@@ -295,8 +295,7 @@ ENTRY(tme_handler)
        and3    r4, r4, #(MMU_CONTEXT_ASID_MASK)
        or      r3, r4
        st      r3, @r2
-       or3     r4, r1, #2              ; _PAGE_PRESENT(=2)
-       st      r4, @(4,r2)             ; set_tlb_data(entry, pte_data);
+       st      r1, @(4,r2)             ; set_tlb_data(entry, pte_data);
 
        ld      r4, @sp+
        ld      r3, @sp+
@@ -306,6 +305,11 @@ ENTRY(tme_handler)
        ld      sp, @sp+
        rte
 
+       .fillinsn
+3:
+       ldi     r1, #2                  ; r1: pte_data = 0 | _PAGE_PRESENT(=2)
+       bra     5b
+
 #else
 #error unknown isa configuration
 #endif
index 7fe5e6300e9a2e2447ef08a5970b53d12743c73f..a4dab7cab3489f7685d1829bff92f7480a476a4d 100644 (file)
@@ -23,6 +23,20 @@ static unsigned chattr_class[] = {
 ~0U
 };
 
+static unsigned signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
+int audit_classify_arch(int arch)
+{
+#ifdef CONFIG_PPC64
+       if (arch == AUDIT_ARCH_PPC)
+               return 1;
+#endif
+       return 0;
+}
+
 int audit_classify_syscall(int abi, unsigned syscall)
 {
 #ifdef CONFIG_PPC64
@@ -51,15 +65,18 @@ static int __init audit_classes_init(void)
        extern __u32 ppc32_write_class[];
        extern __u32 ppc32_read_class[];
        extern __u32 ppc32_chattr_class[];
+       extern __u32 ppc32_signal_class[];
        audit_register_class(AUDIT_CLASS_WRITE_32, ppc32_write_class);
        audit_register_class(AUDIT_CLASS_READ_32, ppc32_read_class);
        audit_register_class(AUDIT_CLASS_DIR_WRITE_32, ppc32_dir_class);
        audit_register_class(AUDIT_CLASS_CHATTR_32, ppc32_chattr_class);
+       audit_register_class(AUDIT_CLASS_SIGNAL_32, ppc32_signal_class);
 #endif
        audit_register_class(AUDIT_CLASS_WRITE, write_class);
        audit_register_class(AUDIT_CLASS_READ, read_class);
        audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
        audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+       audit_register_class(AUDIT_CLASS_SIGNAL, signal_class);
        return 0;
 }
 
index 640d4bb29321b5b20a074e5491aeaada69b021e2..108ff14e21223a0dcd91e7359356e2a602acba0a 100644 (file)
@@ -21,6 +21,11 @@ unsigned ppc32_read_class[] = {
 ~0U
 };
 
+unsigned ppc32_signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
 int ppc32_classify_syscall(unsigned syscall)
 {
        switch(syscall) {
index 9ed4931af1641253cce9dfce6c52fd6deb91c230..068377a2a8dc021b008f7cb56d3d82b2e94994cb 100644 (file)
@@ -173,7 +173,7 @@ void local_irq_restore(unsigned long en)
                lv1_get_version_info(&tmp);
        }
 
-       hard_irq_enable();
+       __hard_irq_enable();
 }
 #endif /* CONFIG_PPC64 */
 
index 064a7ba4f02c0a43e87e6ee68f96ab2ebf63f426..77b7b34b5955f0d6453e829b75454f0df145da9c 100644 (file)
@@ -36,8 +36,4 @@ void restore_processor_state(void)
 #ifdef CONFIG_PPC32
        set_context(current->active_mm->context.id, current->active_mm->pgd);
 #endif
-
-#ifdef CONFIG_PPC64
-       hard_irq_enable();
-#endif
 }
index 8c20f0fb8651f23b204f455bbf75a23581bef746..812bf563ed6509aebeb51606fe8fa068c411bc5c 100644 (file)
@@ -43,12 +43,10 @@ static void cbe_power_save(void)
        unsigned long ctrl, thread_switch_control;
 
        /*
-        * We need to hard disable interrupts, but we also need to mark them
-        * hard disabled in the PACA so that the local_irq_enable() done by
-        * our caller upon return propertly hard enables.
+        * We need to hard disable interrupts, the local_irq_enable() done by
+        * our caller upon return will hard re-enable.
         */
        hard_irq_disable();
-       get_paca()->hard_enabled = 0;
 
        ctrl = mfspr(SPRN_CTRLF);
 
index 0741d91933906ec1feccc1e335122d7fb244431c..d1c76fe10f29e0d8630979abc973a54f4e230472 100644 (file)
@@ -23,6 +23,20 @@ static unsigned chattr_class[] = {
 ~0U
 };
 
+static unsigned signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
+int audit_classify_arch(int arch)
+{
+#ifdef CONFIG_COMPAT
+       if (arch == AUDIT_ARCH_S390)
+               return 1;
+#endif
+       return 0;
+}
+
 int audit_classify_syscall(int abi, unsigned syscall)
 {
 #ifdef CONFIG_COMPAT
@@ -51,15 +65,18 @@ static int __init audit_classes_init(void)
        extern __u32 s390_write_class[];
        extern __u32 s390_read_class[];
        extern __u32 s390_chattr_class[];
+       extern __u32 s390_signal_class[];
        audit_register_class(AUDIT_CLASS_WRITE_32, s390_write_class);
        audit_register_class(AUDIT_CLASS_READ_32, s390_read_class);
        audit_register_class(AUDIT_CLASS_DIR_WRITE_32, s390_dir_class);
        audit_register_class(AUDIT_CLASS_CHATTR_32, s390_chattr_class);
+       audit_register_class(AUDIT_CLASS_SIGNAL_32, s390_signal_class);
 #endif
        audit_register_class(AUDIT_CLASS_WRITE, write_class);
        audit_register_class(AUDIT_CLASS_READ, read_class);
        audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
        audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+       audit_register_class(AUDIT_CLASS_SIGNAL, signal_class);
        return 0;
 }
 
index 16d9436bfa9103ab1d3464d5f5f02eec65ca76e0..0569f5126e499ea4bdd477301eeb8e5cc35f42df 100644 (file)
@@ -21,6 +21,11 @@ unsigned s390_read_class[] = {
 ~0U
 };
 
+unsigned s390_signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
 int s390_classify_syscall(unsigned syscall)
 {
        switch(syscall) {
index aef19cc27072c6f464c9956d20a6fe2ac851d39a..24d7f4b4178ae5fdc98a520ec786dd7523f68e85 100644 (file)
@@ -23,6 +23,20 @@ static unsigned chattr_class[] = {
 ~0U
 };
 
+static unsigned signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
+int audit_classify_arch(int arch)
+{
+#ifdef CONFIG_SPARC32_COMPAT
+       if (arch == AUDIT_ARCH_SPARC)
+               return 1;
+#endif
+       return 0;
+}
+
 int audit_classify_syscall(int abi, unsigned syscall)
 {
 #ifdef CONFIG_SPARC32_COMPAT
@@ -51,15 +65,18 @@ static int __init audit_classes_init(void)
        extern __u32 sparc32_write_class[];
        extern __u32 sparc32_read_class[];
        extern __u32 sparc32_chattr_class[];
+       extern __u32 sparc32_signal_class[];
        audit_register_class(AUDIT_CLASS_WRITE_32, sparc32_write_class);
        audit_register_class(AUDIT_CLASS_READ_32, sparc32_read_class);
        audit_register_class(AUDIT_CLASS_DIR_WRITE_32, sparc32_dir_class);
        audit_register_class(AUDIT_CLASS_CHATTR_32, sparc32_chattr_class);
+       audit_register_class(AUDIT_CLASS_SIGNAL_32, sparc32_signal_class);
 #endif
        audit_register_class(AUDIT_CLASS_WRITE, write_class);
        audit_register_class(AUDIT_CLASS_READ, read_class);
        audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
        audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+       audit_register_class(AUDIT_CLASS_SIGNAL, signal_class);
        return 0;
 }
 
index cca96c91b7807ef42db47b04b0be51b8e9671feb..c1979482aa929bbf85db4a97ca7138365b35bda6 100644 (file)
@@ -20,6 +20,11 @@ unsigned sparc32_read_class[] = {
 ~0U
 };
 
+unsigned sparc32_signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
 int sparc32_classify_syscall(unsigned syscall)
 {
        switch(syscall) {
index b9c0f307a8fa7ee9b8e866b0416c0764b88d7630..c504312219b42b8f9797c50fe1569e5f05163a84 100644 (file)
@@ -277,7 +277,8 @@ config HIGHMEM
 
 config KERNEL_STACK_ORDER
        int "Kernel stack size order"
-       default 2
+       default 1 if 64BIT
+       default 0 if !64BIT
        help
        This option determines the size of UML kernel stacks.  They will
        be 1 << order pages.  The default is OK unless you're running Valgrind
index f938fa822146bb86e2a5fbada7fcb8548102b91b..a54d0efecae1567074ca28ec77edcb70e8bb88ae 100644 (file)
@@ -86,7 +86,7 @@ CONFIG_MCONSOLE=y
 # CONFIG_MAGIC_SYSRQ is not set
 CONFIG_NEST_LEVEL=0
 # CONFIG_HIGHMEM is not set
-CONFIG_KERNEL_STACK_ORDER=2
+CONFIG_KERNEL_STACK_ORDER=0
 CONFIG_UML_REAL_TIME_CLOCK=y
 
 #
index 5593a802708321ac919247574bf16ec48856c246..541f4a8ca512ab3519a19005e490b2a9246d7ae3 100644 (file)
@@ -28,3 +28,5 @@ DEFINE(UM_NR_CPUS, NR_CPUS);
 
 /* For crypto assembler code. */
 DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx));
+
+DEFINE(UM_THREAD_SIZE, THREAD_SIZE);
index 50a49691e0e62fd3666851de8b70c2b521d1074f..8d7f7c1cb9c64e40dd96cd17f8e65fe3b9a323da 100644 (file)
@@ -117,4 +117,7 @@ extern void sigio_handler(int sig, union uml_pt_regs *regs);
 
 extern void copy_sc(union uml_pt_regs *regs, void *from);
 
+unsigned long to_irq_stack(int sig, unsigned long *mask_out);
+unsigned long from_irq_stack(int nested);
+
 #endif
index 688d181b5f8ae602fb34509cbd876fd343aa273a..4d9fb26387d565290a58ef093d34f3c25d10042b 100644 (file)
@@ -272,7 +272,6 @@ extern void do_longjmp(void *p, int val);
 
 /* util.c */
 extern void stack_protections(unsigned long address);
-extern void task_protections(unsigned long address);
 extern int raw(int fd);
 extern void setup_machinename(char *machine_out);
 extern void setup_hostinfo(char *buf, int len);
index e36f92b463ce04dc64ec0f076954e48cf0cb276a..87a4e4427d8db2e3e7a83fd8ee0667d287516029 100644 (file)
@@ -97,6 +97,8 @@ SECTIONS
   .data           : {
     . = ALIGN(KERNEL_STACK_SIZE);              /* init_task */
     *(.data.init_task)
+    . = ALIGN(KERNEL_STACK_SIZE);
+    *(.data.init_irqstack)
     *(.data .data.* .gnu.linkonce.d.*)
     SORT(CONSTRUCTORS)
   }
index cda91aa8e703162564c2163064ed7efe567649d1..d4f1d1ab252ba0757e47499db066bdb09cbf62bc 100644 (file)
@@ -1,5 +1,5 @@
-/* 
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,intel.linux}.com)
  * Licensed under the GPL
  */
 
@@ -33,28 +33,20 @@ EXPORT_SYMBOL(init_task);
 /*
  * Initial thread structure.
  *
- * We need to make sure that this is 16384-byte aligned due to the
+ * We need to make sure that this is aligned due to the
  * way process stacks are handled. This is done by having a special
  * "init_task" linker map entry..
  */
 
-union thread_union init_thread_union 
-__attribute__((__section__(".data.init_task"))) = 
-{ INIT_THREAD_INFO(init_task) };
+union thread_union init_thread_union
+       __attribute__((__section__(".data.init_task"))) =
+               { INIT_THREAD_INFO(init_task) };
+
+union thread_union cpu0_irqstack
+       __attribute__((__section__(".data.init_irqstack"))) =
+               { INIT_THREAD_INFO(init_task) };
 
 void unprotect_stack(unsigned long stack)
 {
-       os_protect_memory((void *) stack, (1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE,
-                      1, 1, 0);
+       os_protect_memory((void *) stack, THREAD_SIZE, 1, 1, 0);
 }
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
index 8f2ed369031507c8aa01992d46dbaea62b3721ca..dba04d88b4320bde93b7ce4bee3f728193fd257f 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
  * Licensed under the GPL
  * Derived (i.e. mostly copied) from arch/i386/kernel/irq.c:
@@ -32,6 +32,7 @@
 #include "sigio.h"
 #include "um_malloc.h"
 #include "misc_constants.h"
+#include "as-layout.h"
 
 /*
  * Generic, controller-independent functions:
@@ -53,7 +54,7 @@ int show_interrupts(struct seq_file *p, void *v)
        if (i < NR_IRQS) {
                spin_lock_irqsave(&irq_desc[i].lock, flags);
                action = irq_desc[i].action;
-               if (!action) 
+               if (!action)
                        goto skip;
                seq_printf(p, "%3d: ",i);
 #ifndef CONFIG_SMP
@@ -468,3 +469,113 @@ int init_aio_irq(int irq, char *name, irq_handler_t handler)
  out:
        return err;
 }
+
+/*
+ * IRQ stack entry and exit:
+ *
+ * Unlike i386, UML doesn't receive IRQs on the normal kernel stack
+ * and switch over to the IRQ stack after some preparation.  We use
+ * sigaltstack to receive signals on a separate stack from the start.
+ * These two functions make sure the rest of the kernel won't be too
+ * upset by being on a different stack.  The IRQ stack has a
+ * thread_info structure at the bottom so that current et al continue
+ * to work.
+ *
+ * to_irq_stack copies the current task's thread_info to the IRQ stack
+ * thread_info and sets the tasks's stack to point to the IRQ stack.
+ *
+ * from_irq_stack copies the thread_info struct back (flags may have
+ * been modified) and resets the task's stack pointer.
+ *
+ * Tricky bits -
+ *
+ * What happens when two signals race each other?  UML doesn't block
+ * signals with sigprocmask, SA_DEFER, or sa_mask, so a second signal
+ * could arrive while a previous one is still setting up the
+ * thread_info.
+ *
+ * There are three cases -
+ *     The first interrupt on the stack - sets up the thread_info and
+ * handles the interrupt
+ *     A nested interrupt interrupting the copying of the thread_info -
+ * can't handle the interrupt, as the stack is in an unknown state
+ *     A nested interrupt not interrupting the copying of the
+ * thread_info - doesn't do any setup, just handles the interrupt
+ *
+ * The first job is to figure out whether we interrupted stack setup.
+ * This is done by xchging the signal mask with thread_info->pending.
+ * If the value that comes back is zero, then there is no setup in
+ * progress, and the interrupt can be handled.  If the value is
+ * non-zero, then there is stack setup in progress.  In order to have
+ * the interrupt handled, we leave our signal in the mask, and it will
+ * be handled by the upper handler after it has set up the stack.
+ *
+ * Next is to figure out whether we are the outer handler or a nested
+ * one.  As part of setting up the stack, thread_info->real_thread is
+ * set to non-NULL (and is reset to NULL on exit).  This is the
+ * nesting indicator.  If it is non-NULL, then the stack is already
+ * set up and the handler can run.
+ */
+
+static unsigned long pending_mask;
+
+unsigned long to_irq_stack(int sig, unsigned long *mask_out)
+{
+       struct thread_info *ti;
+       unsigned long mask, old;
+       int nested;
+
+       mask = xchg(&pending_mask, 1 << sig);
+       if(mask != 0){
+               /* If any interrupts come in at this point, we want to
+                * make sure that their bits aren't lost by our
+                * putting our bit in.  So, this loop accumulates bits
+                * until xchg returns the same value that we put in.
+                * When that happens, there were no new interrupts,
+                * and pending_mask contains a bit for each interrupt
+                * that came in.
+                */
+               old = 1 << sig;
+               do {
+                       old |= mask;
+                       mask = xchg(&pending_mask, old);
+               } while(mask != old);
+               return 1;
+       }
+
+       ti = current_thread_info();
+       nested = (ti->real_thread != NULL);
+       if(!nested){
+               struct task_struct *task;
+               struct thread_info *tti;
+
+               task = cpu_tasks[ti->cpu].task;
+               tti = task_thread_info(task);
+               *ti = *tti;
+               ti->real_thread = tti;
+               task->stack = ti;
+       }
+
+       mask = xchg(&pending_mask, 0);
+       *mask_out |= mask | nested;
+       return 0;
+}
+
+unsigned long from_irq_stack(int nested)
+{
+       struct thread_info *ti, *to;
+       unsigned long mask;
+
+       ti = current_thread_info();
+
+       pending_mask = 1;
+
+       to = ti->real_thread;
+       current->stack = to;
+       ti->real_thread = NULL;
+       *to = *ti;
+
+       mask = xchg(&pending_mask, 0);
+       return mask & ~1;
+}
+
index a96ae1a0610e169a20ae953a1ab070a4fa8eac0c..2a69a7ce5792eedc43283e7f8adaefb7c7744314 100644 (file)
@@ -163,8 +163,12 @@ static int start_kernel_proc(void *unused)
 
 extern int userspace_pid[];
 
+extern char cpu0_irqstack[];
+
 int start_uml_skas(void)
 {
+       stack_protections((unsigned long) &cpu0_irqstack);
+       set_sigstack(cpu0_irqstack, THREAD_SIZE);
        if(proc_mm)
                userspace_pid[0] = start_userspace(0);
 
index 98e21743e604046da3e324e43215dd5b38129f62..40126cb5180103c194590b6e35d4ff9ae413317e 100644 (file)
@@ -57,7 +57,7 @@ void flush_thread_tt(void)
        enable_timer();
        free_page(stack);
        protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
-       task_protections((unsigned long) current_thread);
+       stack_protections((unsigned long) current_thread);
        force_flush_all();
        unblock_signals();
 }
index c631303cb800cf80a8593a22836b1ee47cf7f7f6..74347adf81bfbcf745f62587d21a0bdaeffb7064 100644 (file)
@@ -209,7 +209,7 @@ void finish_fork_handler(int sig)
        if(current->mm != current->parent->mm)
                protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 
                               1, 0, 1);
-       task_protections((unsigned long) current_thread);
+       stack_protections((unsigned long) current_thread);
 
        free_page(current->thread.temp_stack);
        local_irq_disable();
index 1cf954a47fd7719c83e818e53428f9de027ed99a..ecc458fe51b910d91374664660db4446723fd46d 100644 (file)
@@ -459,7 +459,7 @@ int __init linux_main(int argc, char **argv)
 
        uml_postsetup();
 
-       task_protections((unsigned long) &init_thread_info);
+       stack_protections((unsigned long) &init_thread_info);
        os_flush_stdout();
 
        return CHOOSE_MODE(start_uml_tt(), start_uml_skas());
index f6301274cf3cfea9fdb0eb3680cbe349da63fd57..bc59f97e34d00ab2886b75af77376e52d6edb432 100644 (file)
@@ -59,6 +59,8 @@ SECTIONS
   {
     . = ALIGN(KERNEL_STACK_SIZE);              /* init_task */
     *(.data.init_task)
+    . = ALIGN(KERNEL_STACK_SIZE);
+    *(.data.init_irqstack)
     *(.data)
     *(.gnu.linkonce.d*)
     CONSTRUCTORS
index 48d49341530121e004a9efadf4a0637504e3d5ba..18e5c8b67eb8cebbe84db25bed7e64e623522dc9 100644 (file)
@@ -61,15 +61,19 @@ void sig_handler(int sig, struct sigcontext *sc)
 
 static void real_alarm_handler(int sig, struct sigcontext *sc)
 {
+       union uml_pt_regs regs;
+
        if(sig == SIGALRM)
                switch_timers(0);
 
-       CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
-                        sig, sc);
+       if(sc != NULL)
+               copy_sc(&regs, sc);
+       regs.skas.is_user = 0;
+       unblock_signals();
+       timer_handler(sig, &regs);
 
        if(sig == SIGALRM)
                switch_timers(1);
-
 }
 
 void alarm_handler(int sig, struct sigcontext *sc)
@@ -113,6 +117,46 @@ void remove_sigstack(void)
 
 void (*handlers[_NSIG])(int sig, struct sigcontext *sc);
 
+void handle_signal(int sig, struct sigcontext *sc)
+{
+       unsigned long pending = 0;
+
+       do {
+               int nested, bail;
+
+               /*
+                * pending comes back with one bit set for each
+                * interrupt that arrived while setting up the stack,
+                * plus a bit for this interrupt, plus the zero bit is
+                * set if this is a nested interrupt.
+                * If bail is true, then we interrupted another
+                * handler setting up the stack.  In this case, we
+                * have to return, and the upper handler will deal
+                * with this interrupt.
+                */
+               bail = to_irq_stack(sig, &pending);
+               if(bail)
+                       return;
+
+               nested = pending & 1;
+               pending &= ~1;
+
+               while((sig = ffs(pending)) != 0){
+                       sig--;
+                       pending &= ~(1 << sig);
+                       (*handlers[sig])(sig, sc);
+               }
+
+               /* Again, pending comes back with a mask of signals
+                * that arrived while tearing down the stack.  If this
+                * is non-zero, we just go back, set up the stack
+                * again, and handle the new interrupts.
+                */
+               if(!nested)
+                       pending = from_irq_stack(nested);
+       } while(pending);
+}
+
 extern void hard_handler(int sig);
 
 void set_handler(int sig, void (*handler)(int), int flags, ...)
index 6a0e466d01e33052a2ba2b2a27ed8f9d42ac8cb2..f9d2f8545afedd12f06a2e3a216eea2757759999 100644 (file)
@@ -288,7 +288,8 @@ int start_userspace(unsigned long stub_stack)
 void userspace(union uml_pt_regs *regs)
 {
        int err, status, op, pid = userspace_pid[0];
-       int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/
+       /* To prevent races if using_sysemu changes under us.*/
+       int local_using_sysemu;
 
        while(1){
                restore_registers(pid, regs);
@@ -296,7 +297,8 @@ void userspace(union uml_pt_regs *regs)
                /* Now we set local_using_sysemu to be used for one loop */
                local_using_sysemu = get_using_sysemu();
 
-               op = SELECT_PTRACE_OPERATION(local_using_sysemu, singlestepping(NULL));
+               op = SELECT_PTRACE_OPERATION(local_using_sysemu,
+                                            singlestepping(NULL));
 
                err = ptrace(op, pid, 0, 0);
                if(err)
@@ -490,8 +492,8 @@ void map_stub_pages(int fd, unsigned long code,
 void new_thread(void *stack, jmp_buf *buf, void (*handler)(void))
 {
        (*buf)[0].JB_IP = (unsigned long) handler;
-       (*buf)[0].JB_SP = (unsigned long) stack +
-               (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) - sizeof(void *);
+       (*buf)[0].JB_SP = (unsigned long) stack + UM_THREAD_SIZE -
+               sizeof(void *);
 }
 
 #define INIT_JMP_NEW_THREAD 0
@@ -533,8 +535,7 @@ int start_idle_thread(void *stack, jmp_buf *switch_buf)
        case INIT_JMP_NEW_THREAD:
                (*switch_buf)[0].JB_IP = (unsigned long) new_thread_handler;
                (*switch_buf)[0].JB_SP = (unsigned long) stack +
-                       (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) -
-                       sizeof(void *);
+                       UM_THREAD_SIZE - sizeof(void *);
                break;
        case INIT_JMP_CALLBACK:
                (*cb_proc)(cb_arg);
index 0d3eae5183526cc53aded9ce2e6ca66b6dc9574f..f311609f93daaf7079476a067e2e2ab24bc8a202 100644 (file)
@@ -1,15 +1,13 @@
 /*
- * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2006 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
 #include <signal.h>
 
-extern void (*handlers[])(int sig, struct sigcontext *sc);
+extern void handle_signal(int sig, struct sigcontext *sc);
 
 void hard_handler(int sig)
 {
-       struct sigcontext *sc = (struct sigcontext *) (&sig + 1);
-
-       (*handlers[sig])(sig, sc);
+       handle_signal(sig, (struct sigcontext *) (&sig + 1));
 }
index 3f369e5f976b724232e4cf4a4f9fe1e90782dbe0..82a388822cd35c55b006f9dbe0d3f1230b83b620 100644 (file)
@@ -1,16 +1,16 @@
 /*
- * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2006 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
 #include <signal.h>
 
-extern void (*handlers[])(int sig, struct sigcontext *sc);
+extern void handle_signal(int sig, struct sigcontext *sc);
 
 void hard_handler(int sig)
 {
        struct ucontext *uc;
        asm("movq %%rdx, %0" : "=r" (uc));
 
-       (*handlers[sig])(sig, (struct sigcontext *) &uc->uc_mcontext);
+       handle_signal(sig, (struct sigcontext *) &uc->uc_mcontext);
 }
index c307a89ed2598cef9a0c619cc8576e353115aa54..7cbcf484e13d3337d8bbaaa06d3fed165a02f377 100644 (file)
 
 void stack_protections(unsigned long address)
 {
-       int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
-
-       if(mprotect((void *) address, UM_KERN_PAGE_SIZE, prot) < 0)
-               panic("protecting stack failed, errno = %d", errno);
-}
-
-void task_protections(unsigned long address)
-{
-       unsigned long guard = address + UM_KERN_PAGE_SIZE;
-       unsigned long stack = guard + UM_KERN_PAGE_SIZE;
-       int prot = 0, pages;
-
-#ifdef notdef
-       if(mprotect((void *) stack, UM_KERN_PAGE_SIZE, prot) < 0)
-               panic("protecting guard page failed, errno = %d", errno);
-#endif
-       pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER) - 2;
-       prot = PROT_READ | PROT_WRITE | PROT_EXEC;
-       if(mprotect((void *) stack, pages * UM_KERN_PAGE_SIZE, prot) < 0)
+       if(mprotect((void *) address, UM_THREAD_SIZE,
+                   PROT_READ | PROT_WRITE | PROT_EXEC) < 0)
                panic("protecting stack failed, errno = %d", errno);
 }
 
@@ -72,7 +55,7 @@ int raw(int fd)
 
        /* XXX tcsetattr could have applied only some changes
         * (and cfmakeraw() is a set of changes) */
-       return(0);
+       return 0;
 }
 
 void setup_machinename(char *machine_out)
index 92d7d0c8d93fb238dcf32831dcbfc5719078efd6..8850fe40ea34240a340f11e10eb07e6af8641895 100644 (file)
@@ -20,6 +20,11 @@ unsigned ia32_read_class[] = {
 ~0U
 };
 
+unsigned ia32_signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
 int ia32_classify_syscall(unsigned syscall)
 {
        switch(syscall) {
index f21068378272f0b8dbce0ce1d7f8b29ccfa0b286..52be79beb30624c9a71f49eb8ce10f6f0dd8311b 100644 (file)
@@ -716,4 +716,7 @@ ia32_sys_call_table:
        .quad sys_getcpu
        .quad sys_epoll_pwait
        .quad compat_sys_utimensat      /* 320 */
+       .quad sys_signalfd
+       .quad sys_timerfd
+       .quad sys_eventfd
 ia32_syscall_end:              
index 21f33387bef3a3427d1bab4cfe924a4bc545391d..06d3e5a14d9dd70e2f709cef205c269f0a514203 100644 (file)
@@ -23,6 +23,20 @@ static unsigned chattr_class[] = {
 ~0U
 };
 
+static unsigned signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
+int audit_classify_arch(int arch)
+{
+#ifdef CONFIG_IA32_EMULATION
+       if (arch == AUDIT_ARCH_I386)
+               return 1;
+#endif
+       return 0;
+}
+
 int audit_classify_syscall(int abi, unsigned syscall)
 {
 #ifdef CONFIG_IA32_EMULATION
@@ -49,15 +63,18 @@ static int __init audit_classes_init(void)
        extern __u32 ia32_write_class[];
        extern __u32 ia32_read_class[];
        extern __u32 ia32_chattr_class[];
+       extern __u32 ia32_signal_class[];
        audit_register_class(AUDIT_CLASS_WRITE_32, ia32_write_class);
        audit_register_class(AUDIT_CLASS_READ_32, ia32_read_class);
        audit_register_class(AUDIT_CLASS_DIR_WRITE_32, ia32_dir_class);
        audit_register_class(AUDIT_CLASS_CHATTR_32, ia32_chattr_class);
+       audit_register_class(AUDIT_CLASS_SIGNAL_32, ia32_signal_class);
 #endif
        audit_register_class(AUDIT_CLASS_WRITE, write_class);
        audit_register_class(AUDIT_CLASS_READ, read_class);
        audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
        audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+       audit_register_class(AUDIT_CLASS_SIGNAL, signal_class);
        return 0;
 }
 
index 213d90e047550e9d2d348aa28e855d94730781ca..6c34bdd22e2634df6bdb41cc1db8aba482ddf33f 100644 (file)
@@ -62,13 +62,6 @@ void __init x86_64_start_kernel(char * real_mode_data)
 {
        int i;
 
-       /*
-        * Make sure kernel is aligned to 2MB address. Catching it at compile
-        * time is better. Change your config file and compile the kernel
-        * for a 2MB aligned address (CONFIG_PHYSICAL_START)
-        */
-       BUILD_BUG_ON(CONFIG_PHYSICAL_START & (__KERNEL_ALIGN - 1));
-
        /* clear bss before set_intr_gate with early_idt_handler */
        clear_bss();
 
index 17e18897342841887ec25b45585cfe49478bf77a..74a567afb83069f1d666409c645107a2d78e516d 100644 (file)
@@ -3116,7 +3116,7 @@ static inline int should_fail_request(struct bio *bio)
  * bi_sector for remaps as it sees fit.  So the values of these fields
  * should NOT be depended on after the call to generic_make_request.
  */
-void generic_make_request(struct bio *bio)
+static inline void __generic_make_request(struct bio *bio)
 {
        request_queue_t *q;
        sector_t maxsector;
@@ -3215,6 +3215,57 @@ end_io:
        } while (ret);
 }
 
+/*
+ * We only want one ->make_request_fn to be active at a time,
+ * else stack usage with stacked devices could be a problem.
+ * So use current->bio_{list,tail} to keep a list of requests
+ * submited by a make_request_fn function.
+ * current->bio_tail is also used as a flag to say if
+ * generic_make_request is currently active in this task or not.
+ * If it is NULL, then no make_request is active.  If it is non-NULL,
+ * then a make_request is active, and new requests should be added
+ * at the tail
+ */
+void generic_make_request(struct bio *bio)
+{
+       if (current->bio_tail) {
+               /* make_request is active */
+               *(current->bio_tail) = bio;
+               bio->bi_next = NULL;
+               current->bio_tail = &bio->bi_next;
+               return;
+       }
+       /* following loop may be a bit non-obvious, and so deserves some
+        * explanation.
+        * Before entering the loop, bio->bi_next is NULL (as all callers
+        * ensure that) so we have a list with a single bio.
+        * We pretend that we have just taken it off a longer list, so
+        * we assign bio_list to the next (which is NULL) and bio_tail
+        * to &bio_list, thus initialising the bio_list of new bios to be
+        * added.  __generic_make_request may indeed add some more bios
+        * through a recursive call to generic_make_request.  If it
+        * did, we find a non-NULL value in bio_list and re-enter the loop
+        * from the top.  In this case we really did just take the bio
+        * of the top of the list (no pretending) and so fixup bio_list and
+        * bio_tail or bi_next, and call into __generic_make_request again.
+        *
+        * The loop was structured like this to make only one call to
+        * __generic_make_request (which is important as it is large and
+        * inlined) and to keep the structure simple.
+        */
+       BUG_ON(bio->bi_next);
+       do {
+               current->bio_list = bio->bi_next;
+               if (bio->bi_next == NULL)
+                       current->bio_tail = &current->bio_list;
+               else
+                       bio->bi_next = NULL;
+               __generic_make_request(bio);
+               bio = current->bio_list;
+       } while (bio);
+       current->bio_tail = NULL; /* deactivate */
+}
+
 EXPORT_SYMBOL(generic_make_request);
 
 /**
index 0f4203b499af65771ccb63bac79cae5ec2ad4f80..6055b9c0ac0f0b2f96380bebbb227b1fcaad055f 100644 (file)
@@ -307,7 +307,9 @@ static void hci_uart_tty_close(struct tty_struct *tty)
 
        if (hu) {
                struct hci_dev *hdev = hu->hdev;
-               hci_uart_close(hdev);
+
+               if (hdev)
+                       hci_uart_close(hdev);
 
                if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
                        hu->proto->close(hu);
@@ -473,12 +475,18 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
                        tty->low_latency = 1;
                } else
                        return -EBUSY;
+               break;
 
        case HCIUARTGETPROTO:
                if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
                        return hu->proto->id;
                return -EUNATCH;
 
+       case HCIUARTGETDEVICE:
+               if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
+                       return hu->hdev->id;
+               return -EUNATCH;
+
        default:
                err = n_tty_ioctl(tty, file, cmd, arg);
                break;
index b250e6789dee68abd323392daa6a831337e20989..1097ce72393f2813bc82d140df1cca0495124b30 100644 (file)
@@ -28,8 +28,9 @@
 #endif
 
 /* Ioctls */
-#define HCIUARTSETPROTO        _IOW('U', 200, int)
-#define HCIUARTGETPROTO        _IOR('U', 201, int)
+#define HCIUARTSETPROTO                _IOW('U', 200, int)
+#define HCIUARTGETPROTO                _IOR('U', 201, int)
+#define HCIUARTGETDEVICE       _IOR('U', 202, int)
 
 /* UART protocols */
 #define HCI_UART_MAX_PROTO     4
index 6ac3ca4c723c2c660c5d084b9c7834035767fbb5..b3d4ccc33a47e777d1a391ae9a85bde2f450051e 100644 (file)
@@ -1544,21 +1544,18 @@ static unsigned int normal_poll(struct tty_struct * tty, struct file * file, pol
 }
 
 struct tty_ldisc tty_ldisc_N_TTY = {
-       TTY_LDISC_MAGIC,        /* magic */
-       "n_tty",                /* name */
-       0,                      /* num */
-       0,                      /* flags */
-       n_tty_open,             /* open */
-       n_tty_close,            /* close */
-       n_tty_flush_buffer,     /* flush_buffer */
-       n_tty_chars_in_buffer,  /* chars_in_buffer */
-       read_chan,              /* read */
-       write_chan,             /* write */
-       n_tty_ioctl,            /* ioctl */
-       n_tty_set_termios,      /* set_termios */
-       normal_poll,            /* poll */
-       NULL,                   /* hangup */
-       n_tty_receive_buf,      /* receive_buf */
-       n_tty_write_wakeup      /* write_wakeup */
+       .magic           = TTY_LDISC_MAGIC,
+       .name            = "n_tty",
+       .open            = n_tty_open,
+       .close           = n_tty_close,
+       .flush_buffer    = n_tty_flush_buffer,
+       .chars_in_buffer = n_tty_chars_in_buffer,
+       .read            = read_chan,
+       .write           = write_chan,
+       .ioctl           = n_tty_ioctl,
+       .set_termios     = n_tty_set_termios,
+       .poll            = normal_poll,
+       .receive_buf     = n_tty_receive_buf,
+       .write_wakeup    = n_tty_write_wakeup
 };
 
index 245f03195b7c6da9ce7f664e974664617b4baf33..8cc60b693460a2cbdbc9a1bca28c2a73724db162 100644 (file)
@@ -402,7 +402,7 @@ static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struc
                rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: Host number %Zd, name ``%s''\n", HostP - p->RIOHosts, HostP->Name);
                rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: Rup number  0x%x\n", rup);
 
-               if (Rup >= (unsigned short) MAX_RUP) {
+               if (Rup < (unsigned short) MAX_RUP) {
                        rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: This is the RUP for RTA ``%s''\n", HostP->Mapping[Rup].Name);
                } else
                        rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: This is the RUP for link ``%c'' of host ``%s''\n", ('A' + Rup - MAX_RUP), HostP->Name);
index 61a63da420c29ee02c1c9118c04a2454817245d9..a3fd7e7ba5a977556ccae27fcb4ca2bffa0c4eee 100644 (file)
@@ -1014,9 +1014,6 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
        /*
         * Info->count is now 1; so it's safe to sleep now.
         */
-       info->session = process_session(current);
-       info->pgrp = process_group(current);
-
        if ((info->flags & ROCKET_INITIALIZED) == 0) {
                cp = &info->channel;
                sSetRxTrigger(cp, TRIG_1);
index 89b4d7b10d12584c630f17b95615b533a0182d04..b4c53dfa7951290f48be4b5e28e685d91a0b8558 100644 (file)
@@ -1158,8 +1158,6 @@ struct r_port {
        int xmit_head;
        int xmit_tail;
        int xmit_cnt;
-       int session;
-       int pgrp;
        int cd_status;
        int ignore_status_mask;
        int read_status_mask;
index 2a7736b5f2f73889643e8b797500eb1e2c34f31b..02b49bc000284028377f915dc39248ef71445d58 100644 (file)
@@ -1170,6 +1170,112 @@ static int ioctl(struct tty_struct *tty, struct file *file,
        return 0;
 }
 
+/*
+ * support for 32 bit ioctl calls on 64 bit systems
+ */
+#ifdef CONFIG_COMPAT
+static long get_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *user_params)
+{
+       struct MGSL_PARAMS32 tmp_params;
+
+       DBGINFO(("%s get_params32\n", info->device_name));
+       tmp_params.mode            = (compat_ulong_t)info->params.mode;
+       tmp_params.loopback        = info->params.loopback;
+       tmp_params.flags           = info->params.flags;
+       tmp_params.encoding        = info->params.encoding;
+       tmp_params.clock_speed     = (compat_ulong_t)info->params.clock_speed;
+       tmp_params.addr_filter     = info->params.addr_filter;
+       tmp_params.crc_type        = info->params.crc_type;
+       tmp_params.preamble_length = info->params.preamble_length;
+       tmp_params.preamble        = info->params.preamble;
+       tmp_params.data_rate       = (compat_ulong_t)info->params.data_rate;
+       tmp_params.data_bits       = info->params.data_bits;
+       tmp_params.stop_bits       = info->params.stop_bits;
+       tmp_params.parity          = info->params.parity;
+       if (copy_to_user(user_params, &tmp_params, sizeof(struct MGSL_PARAMS32)))
+               return -EFAULT;
+       return 0;
+}
+
+static long set_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *new_params)
+{
+       struct MGSL_PARAMS32 tmp_params;
+
+       DBGINFO(("%s set_params32\n", info->device_name));
+       if (copy_from_user(&tmp_params, new_params, sizeof(struct MGSL_PARAMS32)))
+               return -EFAULT;
+
+       spin_lock(&info->lock);
+       info->params.mode            = tmp_params.mode;
+       info->params.loopback        = tmp_params.loopback;
+       info->params.flags           = tmp_params.flags;
+       info->params.encoding        = tmp_params.encoding;
+       info->params.clock_speed     = tmp_params.clock_speed;
+       info->params.addr_filter     = tmp_params.addr_filter;
+       info->params.crc_type        = tmp_params.crc_type;
+       info->params.preamble_length = tmp_params.preamble_length;
+       info->params.preamble        = tmp_params.preamble;
+       info->params.data_rate       = tmp_params.data_rate;
+       info->params.data_bits       = tmp_params.data_bits;
+       info->params.stop_bits       = tmp_params.stop_bits;
+       info->params.parity          = tmp_params.parity;
+       spin_unlock(&info->lock);
+
+       change_params(info);
+
+       return 0;
+}
+
+static long slgt_compat_ioctl(struct tty_struct *tty, struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+       struct slgt_info *info = tty->driver_data;
+       int rc = -ENOIOCTLCMD;
+
+       if (sanity_check(info, tty->name, "compat_ioctl"))
+               return -ENODEV;
+       DBGINFO(("%s compat_ioctl() cmd=%08X\n", info->device_name, cmd));
+
+       switch (cmd) {
+
+       case MGSL_IOCSPARAMS32:
+               rc = set_params32(info, compat_ptr(arg));
+               break;
+
+       case MGSL_IOCGPARAMS32:
+               rc = get_params32(info, compat_ptr(arg));
+               break;
+
+       case MGSL_IOCGPARAMS:
+       case MGSL_IOCSPARAMS:
+       case MGSL_IOCGTXIDLE:
+       case MGSL_IOCGSTATS:
+       case MGSL_IOCWAITEVENT:
+       case MGSL_IOCGIF:
+       case MGSL_IOCSGPIO:
+       case MGSL_IOCGGPIO:
+       case MGSL_IOCWAITGPIO:
+       case TIOCGICOUNT:
+               rc = ioctl(tty, file, cmd, (unsigned long)(compat_ptr(arg)));
+               break;
+
+       case MGSL_IOCSTXIDLE:
+       case MGSL_IOCTXENABLE:
+       case MGSL_IOCRXENABLE:
+       case MGSL_IOCTXABORT:
+       case TIOCMIWAIT:
+       case MGSL_IOCSIF:
+               rc = ioctl(tty, file, cmd, arg);
+               break;
+       }
+
+       DBGINFO(("%s compat_ioctl() cmd=%08X rc=%d\n", info->device_name, cmd, rc));
+       return rc;
+}
+#else
+#define slgt_compat_ioctl NULL
+#endif /* ifdef CONFIG_COMPAT */
+
 /*
  * proc fs support
  */
@@ -3446,6 +3552,7 @@ static const struct tty_operations ops = {
        .chars_in_buffer = chars_in_buffer,
        .flush_buffer = flush_buffer,
        .ioctl = ioctl,
+       .compat_ioctl = slgt_compat_ioctl,
        .throttle = throttle,
        .unthrottle = unthrottle,
        .send_xchar = send_xchar,
index fc662e4ce58aebd0f4995c2b880b417549b294fe..fe62c2170d01692fe3e05430aeba5374fc8c1742 100644 (file)
@@ -151,6 +151,12 @@ static int tty_open(struct inode *, struct file *);
 static int tty_release(struct inode *, struct file *);
 int tty_ioctl(struct inode * inode, struct file * file,
              unsigned int cmd, unsigned long arg);
+#ifdef CONFIG_COMPAT
+static long tty_compat_ioctl(struct file * file, unsigned int cmd,
+                               unsigned long arg);
+#else
+#define tty_compat_ioctl NULL
+#endif
 static int tty_fasync(int fd, struct file * filp, int on);
 static void release_tty(struct tty_struct *tty, int idx);
 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)
        return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;
 }
 
-static int hung_up_tty_ioctl(struct inode * inode, struct file * file,
-                            unsigned int cmd, unsigned long arg)
+static long hung_up_tty_ioctl(struct file * file,
+                             unsigned int cmd, unsigned long arg)
 {
        return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
 }
@@ -1155,6 +1161,7 @@ static const struct file_operations tty_fops = {
        .write          = tty_write,
        .poll           = tty_poll,
        .ioctl          = tty_ioctl,
+       .compat_ioctl   = tty_compat_ioctl,
        .open           = tty_open,
        .release        = tty_release,
        .fasync         = tty_fasync,
@@ -1167,6 +1174,7 @@ static const struct file_operations ptmx_fops = {
        .write          = tty_write,
        .poll           = tty_poll,
        .ioctl          = tty_ioctl,
+       .compat_ioctl   = tty_compat_ioctl,
        .open           = ptmx_open,
        .release        = tty_release,
        .fasync         = tty_fasync,
@@ -1179,6 +1187,7 @@ static const struct file_operations console_fops = {
        .write          = redirected_tty_write,
        .poll           = tty_poll,
        .ioctl          = tty_ioctl,
+       .compat_ioctl   = tty_compat_ioctl,
        .open           = tty_open,
        .release        = tty_release,
        .fasync         = tty_fasync,
@@ -1189,7 +1198,8 @@ static const struct file_operations hung_up_tty_fops = {
        .read           = hung_up_tty_read,
        .write          = hung_up_tty_write,
        .poll           = hung_up_tty_poll,
-       .ioctl          = hung_up_tty_ioctl,
+       .unlocked_ioctl = hung_up_tty_ioctl,
+       .compat_ioctl   = hung_up_tty_ioctl,
        .release        = tty_release,
 };
 
@@ -3357,6 +3367,32 @@ int tty_ioctl(struct inode * inode, struct file * file,
        return retval;
 }
 
+#ifdef CONFIG_COMPAT
+static long tty_compat_ioctl(struct file * file, unsigned int cmd,
+                               unsigned long arg)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct tty_struct *tty = file->private_data;
+       struct tty_ldisc *ld;
+       int retval = -ENOIOCTLCMD;
+
+       if (tty_paranoia_check(tty, inode, "tty_ioctl"))
+               return -EINVAL;
+
+       if (tty->driver->compat_ioctl) {
+               retval = (tty->driver->compat_ioctl)(tty, file, cmd, arg);
+               if (retval != -ENOIOCTLCMD)
+                       return retval;
+       }
+
+       ld = tty_ldisc_ref_wait(tty);
+       if (ld->compat_ioctl)
+               retval = ld->compat_ioctl(tty, file, cmd, arg);
+       tty_ldisc_deref(ld);
+
+       return retval;
+}
+#endif
 
 /*
  * This implements the "Secure Attention Key" ---  the idea is to
@@ -3689,6 +3725,7 @@ void tty_set_operations(struct tty_driver *driver,
        driver->write_room = op->write_room;
        driver->chars_in_buffer = op->chars_in_buffer;
        driver->ioctl = op->ioctl;
+       driver->compat_ioctl = op->compat_ioctl;
        driver->set_termios = op->set_termios;
        driver->throttle = op->throttle;
        driver->unthrottle = op->unthrottle;
index a19b65ed3119873548664c160f9f6f700f45843d..7f817897b178063059be2cfde16e19caa8b6d3df 100644 (file)
@@ -240,11 +240,94 @@ static inline void hidinput_pb_setup(struct input_dev *input)
 }
 #endif
 
+static inline int match_scancode(int code, int scancode)
+{
+       if (scancode == 0)
+               return 1;
+       return ((code & (HID_USAGE_PAGE | HID_USAGE)) == scancode);
+}
+
+static inline int match_keycode(int code, int keycode)
+{
+       if (keycode == 0)
+               return 1;
+       return (code == keycode);
+}
+
+static struct hid_usage *hidinput_find_key(struct hid_device *hid,
+               int scancode, int keycode)
+{
+       int i, j, k;
+       struct hid_report *report;
+       struct hid_usage *usage;
+
+       for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
+               list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
+                       for (i = 0; i < report->maxfield; i++) {
+                               for ( j = 0; j < report->field[i]->maxusage; j++) {
+                                       usage = report->field[i]->usage + j;
+                                       if (usage->type == EV_KEY &&
+                                               match_scancode(usage->hid, scancode) &&
+                                               match_keycode(usage->code, keycode))
+                                               return usage;
+                               }
+                       }
+               }
+       }
+       return NULL;
+}
+
+static int hidinput_getkeycode(struct input_dev *dev, int scancode,
+                               int *keycode)
+{
+       struct hid_device *hid = dev->private;
+       struct hid_usage *usage;
+       
+       usage = hidinput_find_key(hid, scancode, 0);
+       if (usage) {
+               *keycode = usage->code;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int hidinput_setkeycode(struct input_dev *dev, int scancode,
+                               int keycode)
+{
+       struct hid_device *hid = dev->private;
+       struct hid_usage *usage;
+       int old_keycode;
+       
+       if (keycode < 0 || keycode > KEY_MAX)
+               return -EINVAL;
+       
+       usage = hidinput_find_key(hid, scancode, 0);
+       if (usage) {
+               old_keycode = usage->code;
+               usage->code = keycode;
+               
+               clear_bit(old_keycode, dev->keybit);
+               set_bit(usage->code, dev->keybit);
+#ifdef CONFIG_HID_DEBUG
+               printk (KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode);
+#endif
+               /* Set the keybit for the old keycode if the old keycode is used
+                * by another key */
+               if (hidinput_find_key (hid, 0, old_keycode))
+                       set_bit(old_keycode, dev->keybit);
+               
+               return 0;
+       }
+       
+       return -EINVAL;
+}
+
+
 static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
                                     struct hid_usage *usage)
 {
        struct input_dev *input = hidinput->input;
-       struct hid_device *device = input->private;
+       struct hid_device *device = input_get_drvdata(input);
        int max = 0, code;
        unsigned long *bit = NULL;
 
@@ -553,6 +636,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                                case 0x1015: map_key_clear(KEY_RECORD);         break;
                                case 0x1016: map_key_clear(KEY_PLAYER);         break;
                                case 0x1017: map_key_clear(KEY_EJECTCD);        break;
+                               case 0x1018: map_key_clear(KEY_MEDIA);          break;
                                case 0x1019: map_key_clear(KEY_PROG1);          break;
                                case 0x101a: map_key_clear(KEY_PROG2);          break;
                                case 0x101b: map_key_clear(KEY_PROG3);          break;
@@ -560,9 +644,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                                case 0x1020: map_key_clear(KEY_ZOOMOUT);        break;
                                case 0x1021: map_key_clear(KEY_ZOOMRESET);      break;
                                case 0x1023: map_key_clear(KEY_CLOSE);          break;
+                               case 0x1027: map_key_clear(KEY_MENU);           break;
                                /* this one is marked as 'Rotate' */
                                case 0x1028: map_key_clear(KEY_ANGLE);          break;
                                case 0x1029: map_key_clear(KEY_SHUFFLE);        break;
+                               case 0x102a: map_key_clear(KEY_BACK);           break;
+                               case 0x102b: map_key_clear(KEY_CYCLEWINDOWS);   break;
                                case 0x1041: map_key_clear(KEY_BATTERY);        break;
                                case 0x1042: map_key_clear(KEY_WORDPROCESSOR);  break;
                                case 0x1043: map_key_clear(KEY_SPREADSHEET);    break;
@@ -855,13 +942,15 @@ EXPORT_SYMBOL_GPL(hidinput_find_field);
 
 static int hidinput_open(struct input_dev *dev)
 {
-       struct hid_device *hid = dev->private;
+       struct hid_device *hid = input_get_drvdata(dev);
+
        return hid->hid_open(hid);
 }
 
 static void hidinput_close(struct input_dev *dev)
 {
-       struct hid_device *hid = dev->private;
+       struct hid_device *hid = input_get_drvdata(dev);
+
        hid->hid_close(hid);
 }
 
@@ -909,10 +998,12 @@ int hidinput_connect(struct hid_device *hid)
                                        return -1;
                                }
 
-                               input_dev->private = hid;
+                               input_set_drvdata(input_dev, hid);
                                input_dev->event = hid->hidinput_input_event;
                                input_dev->open = hidinput_open;
                                input_dev->close = hidinput_close;
+                               input_dev->setkeycode = hidinput_setkeycode;
+                               input_dev->getkeycode = hidinput_getkeycode;
 
                                input_dev->name = hid->name;
                                input_dev->phys = hid->phys;
@@ -921,7 +1012,7 @@ int hidinput_connect(struct hid_device *hid)
                                input_dev->id.vendor  = hid->vendor;
                                input_dev->id.product = hid->product;
                                input_dev->id.version = hid->version;
-                               input_dev->cdev.dev = hid->dev;
+                               input_dev->dev.parent = hid->dev;
                                hidinput->input = input_dev;
                                list_add_tail(&hidinput->list, &hid->inputs);
                        }
index 7c87bdc538bc1c42f2d71231e12b32f3c33d470c..1b4b572f899ba6c1f23fbb6c9685687fddfb4a99 100644 (file)
@@ -25,12 +25,12 @@ comment "Input core support is needed for USB HID input layer or HIDBP support"
        depends on USB_HID && INPUT=n
 
 config USB_HIDINPUT_POWERBOOK
-       bool "Enable support for iBook/PowerBook special keys"
+       bool "Enable support for iBook/PowerBook/MacBook/MacBookPro special keys"
        default n
        depends on USB_HID
        help
          Say Y here if you want support for the special keys (Fn, Numlock) on
-         Apple iBooks and PowerBooks.
+         Apple iBooks, PowerBooks, MacBooks and MacBook Pros.
 
          If unsure, say N.
 
index 91d610358d57e5206537953b0c12c29b5ca49081..d91b9dac6dff67843b2a8faeff47a9807f6eac45 100644 (file)
@@ -446,7 +446,7 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
 
 static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
-       struct hid_device *hid = dev->private;
+       struct hid_device *hid = input_get_drvdata(dev);
        struct hid_field *field;
        int offset;
 
@@ -626,14 +626,10 @@ static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
 {
        struct usbhid_device *usbhid = hid->driver_data;
 
-       if (usbhid->inbuf)
-               usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
-       if (usbhid->outbuf)
-               usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
-       if (usbhid->cr)
-               usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma);
-       if (usbhid->ctrlbuf)
-               usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
+       usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
+       usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
+       usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma);
+       usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
 }
 
 /*
@@ -692,6 +688,30 @@ static void hid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize)
        }
 }
 
+/*
+ * Some USB barcode readers from cypress have usage min and usage max in
+ * the wrong order
+ */
+static void hid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize)
+{
+       short fixed = 0;
+       int i;
+
+       for (i = 0; i < rsize - 4; i++) {
+               if (rdesc[i] == 0x29 && rdesc [i+2] == 0x19) {
+                       unsigned char tmp;
+
+                       rdesc[i] = 0x19; rdesc[i+2] = 0x29;
+                       tmp = rdesc[i+3];
+                       rdesc[i+3] = rdesc[i+1];
+                       rdesc[i+1] = tmp;
+               }
+       }
+
+       if (fixed)
+               info("Fixing up Cypress report descriptor");
+}
+
 static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 {
        struct usb_host_interface *interface = intf->cur_altsetting;
@@ -758,6 +778,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
        if (quirks & HID_QUIRK_LOGITECH_DESCRIPTOR)
                hid_fixup_logitech_descriptor(rdesc, rsize);
 
+       if (quirks & HID_QUIRK_SWAPPED_MIN_MAX)
+               hid_fixup_cypress_descriptor(rdesc, rsize);
+
 #ifdef CONFIG_HID_DEBUG
        printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
        for (n = 0; n < rsize; n++)
index 92d2553f17b628859448db7643682933aff167e0..c5cd4107d6aff59f833c4ec9bc79b956522fd135 100644 (file)
@@ -60,7 +60,7 @@ static const struct dev_type devices[] = {
 
 static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
 {
-       struct hid_device *hid = dev->private;
+       struct hid_device *hid = input_get_drvdata(dev);
        struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
        struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
        int x, y;
index 76d2e6e14db4a98a65a7c0c195b2495f20e388b7..d6a8f2b49bd242c3b6875320cfe32f4c5ba099a8 100644 (file)
@@ -37,7 +37,7 @@ struct plff_device {
 static int hid_plff_play(struct input_dev *dev, void *data,
                         struct ff_effect *effect)
 {
-       struct hid_device *hid = dev->private;
+       struct hid_device *hid = input_get_drvdata(dev);
        struct plff_device *plff = data;
        int left, right;
 
index 17a87555e32f73159a6af506d39466765aa16450..f6c4145dc20253a885ead58fabd0665c8497f273 100644 (file)
@@ -92,6 +92,8 @@
 #define USB_DEVICE_ID_CYPRESS_MOUSE    0x0001
 #define USB_DEVICE_ID_CYPRESS_HIDCOM   0x5500
 #define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE       0x7417
+#define USB_DEVICE_ID_CYPRESS_BARCODE_1        0xde61
+#define USB_DEVICE_ID_CYPRESS_BARCODE_2        0xde64
 
 #define USB_VENDOR_ID_DELL             0x413c
 #define USB_DEVICE_ID_DELL_W7658       0x2005
 
 #define USB_VENDOR_ID_LOGITECH         0x046d
 #define USB_DEVICE_ID_LOGITECH_RECEIVER        0xc101
+#define USB_DEVICE_ID_LOGITECH_WHEEL   0xc294
 #define USB_DEVICE_ID_S510_RECEIVER    0xc50c
 #define USB_DEVICE_ID_S510_RECEIVER_2  0xc517
 #define USB_DEVICE_ID_MX3000_RECEIVER  0xc513
@@ -422,6 +425,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
@@ -445,6 +449,9 @@ static const struct hid_blacklist {
 
        { USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS },
 
+       { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_SWAPPED_MIN_MAX },
+       { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_SWAPPED_MIN_MAX },
+
        { 0, 0 }
 };
 
index ab67331620d0976b17daea16c5e113a089a0b7ba..ab5ba6ef891cb756fd531119baeabef7211c6dcd 100644 (file)
@@ -59,7 +59,7 @@ static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum)
 
 static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
 {
-       struct hid_device *hid = dev->private;
+       struct hid_device *hid = input_get_drvdata(dev);
        struct tmff_device *tmff = data;
        int left, right;        /* Rumbling */
 
index 7bd8238ca2125b61fe71f112cf18c4721599e6cb..a7fbffcdaf363e4398155b774da7bf32156b9db3 100644 (file)
@@ -37,7 +37,7 @@ struct zpff_device {
 static int hid_zpff_play(struct input_dev *dev, void *data,
                         struct ff_effect *effect)
 {
-       struct hid_device *hid = dev->private;
+       struct hid_device *hid = input_get_drvdata(dev);
        struct zpff_device *zpff = data;
        int left, right;
 
index a8b3d66cd4988b6f133f8804de4a643faeabacc3..488d61bdbf2c1960d4d84e4cd3347f56916fcd1d 100644 (file)
@@ -51,6 +51,7 @@ struct hiddev {
        wait_queue_head_t wait;
        struct hid_device *hid;
        struct list_head list;
+       spinlock_t list_lock;
 };
 
 struct hiddev_list {
@@ -161,7 +162,9 @@ static void hiddev_send_event(struct hid_device *hid,
 {
        struct hiddev *hiddev = hid->hiddev;
        struct hiddev_list *list;
+       unsigned long flags;
 
+       spin_lock_irqsave(&hiddev->list_lock, flags);
        list_for_each_entry(list, &hiddev->list, node) {
                if (uref->field_index != HID_FIELD_INDEX_NONE ||
                    (list->flags & HIDDEV_FLAG_REPORT) != 0) {
@@ -171,6 +174,7 @@ static void hiddev_send_event(struct hid_device *hid,
                        kill_fasync(&list->fasync, SIGIO, POLL_IN);
                }
        }
+       spin_unlock_irqrestore(&hiddev->list_lock, flags);
 
        wake_up_interruptible(&hiddev->wait);
 }
@@ -235,9 +239,13 @@ static int hiddev_fasync(int fd, struct file *file, int on)
 static int hiddev_release(struct inode * inode, struct file * file)
 {
        struct hiddev_list *list = file->private_data;
+       unsigned long flags;
 
        hiddev_fasync(-1, file, 0);
+
+       spin_lock_irqsave(&list->hiddev->list_lock, flags);
        list_del(&list->node);
+       spin_unlock_irqrestore(&list->hiddev->list_lock, flags);
 
        if (!--list->hiddev->open) {
                if (list->hiddev->exist)
@@ -257,6 +265,7 @@ static int hiddev_release(struct inode * inode, struct file * file)
 static int hiddev_open(struct inode *inode, struct file *file)
 {
        struct hiddev_list *list;
+       unsigned long flags;
 
        int i = iminor(inode) - HIDDEV_MINOR_BASE;
 
@@ -267,7 +276,11 @@ static int hiddev_open(struct inode *inode, struct file *file)
                return -ENOMEM;
 
        list->hiddev = hiddev_table[i];
+
+       spin_lock_irqsave(&list->hiddev->list_lock, flags);
        list_add_tail(&list->node, &hiddev_table[i]->list);
+       spin_unlock_irqrestore(&list->hiddev->list_lock, flags);
+
        file->private_data = list;
 
        if (!list->hiddev->open++)
@@ -773,6 +786,7 @@ int hiddev_connect(struct hid_device *hid)
 
        init_waitqueue_head(&hiddev->wait);
        INIT_LIST_HEAD(&hiddev->list);
+       spin_lock_init(&hiddev->list_lock);
        hiddev->hid = hid;
        hiddev->exist = 1;
 
index 65aa12e8d7b3f309661e87820362463132ca200f..1309787807130cfa2e2121ae856ccde721da92ff 100644 (file)
@@ -133,12 +133,11 @@ resubmit:
 static int usb_kbd_event(struct input_dev *dev, unsigned int type,
                         unsigned int code, int value)
 {
-       struct usb_kbd *kbd = dev->private;
+       struct usb_kbd *kbd = input_get_drvdata(dev);
 
        if (type != EV_LED)
                return -1;
 
-
        kbd->newleds = (!!test_bit(LED_KANA,    dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
                       (!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL,   dev->led) << 1) |
                       (!!test_bit(LED_NUML,    dev->led));
@@ -175,7 +174,7 @@ static void usb_kbd_led(struct urb *urb)
 
 static int usb_kbd_open(struct input_dev *dev)
 {
-       struct usb_kbd *kbd = dev->private;
+       struct usb_kbd *kbd = input_get_drvdata(dev);
 
        kbd->irq->dev = kbd->usbdev;
        if (usb_submit_urb(kbd->irq, GFP_KERNEL))
@@ -186,7 +185,7 @@ static int usb_kbd_open(struct input_dev *dev)
 
 static void usb_kbd_close(struct input_dev *dev)
 {
-       struct usb_kbd *kbd = dev->private;
+       struct usb_kbd *kbd = input_get_drvdata(dev);
 
        usb_kill_urb(kbd->irq);
 }
@@ -211,12 +210,9 @@ static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd)
 {
        usb_free_urb(kbd->irq);
        usb_free_urb(kbd->led);
-       if (kbd->new)
-               usb_buffer_free(dev, 8, kbd->new, kbd->new_dma);
-       if (kbd->cr)
-               usb_buffer_free(dev, sizeof(struct usb_ctrlrequest), kbd->cr, kbd->cr_dma);
-       if (kbd->leds)
-               usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma);
+       usb_buffer_free(dev, 8, kbd->new, kbd->new_dma);
+       usb_buffer_free(dev, sizeof(struct usb_ctrlrequest), kbd->cr, kbd->cr_dma);
+       usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma);
 }
 
 static int usb_kbd_probe(struct usb_interface *iface,
@@ -274,8 +270,9 @@ static int usb_kbd_probe(struct usb_interface *iface,
        input_dev->name = kbd->name;
        input_dev->phys = kbd->phys;
        usb_to_input_id(dev, &input_dev->id);
-       input_dev->cdev.dev = &iface->dev;
-       input_dev->private = kbd;
+       input_dev->dev.parent = &iface->dev;
+
+       input_set_drvdata(input_dev, kbd);
 
        input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
        input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA);
index 573776d865e1d23a684c77f3a546569ae47d1c67..5345c73bcf622a2918df1982ba24749e2dfd0c68 100644 (file)
@@ -96,7 +96,7 @@ resubmit:
 
 static int usb_mouse_open(struct input_dev *dev)
 {
-       struct usb_mouse *mouse = dev->private;
+       struct usb_mouse *mouse = input_get_drvdata(dev);
 
        mouse->irq->dev = mouse->usbdev;
        if (usb_submit_urb(mouse->irq, GFP_KERNEL))
@@ -107,7 +107,7 @@ static int usb_mouse_open(struct input_dev *dev)
 
 static void usb_mouse_close(struct input_dev *dev)
 {
-       struct usb_mouse *mouse = dev->private;
+       struct usb_mouse *mouse = input_get_drvdata(dev);
 
        usb_kill_urb(mouse->irq);
 }
@@ -171,7 +171,7 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i
        input_dev->name = mouse->name;
        input_dev->phys = mouse->phys;
        usb_to_input_id(dev, &input_dev->id);
-       input_dev->cdev.dev = &intf->dev;
+       input_dev->dev.parent = &intf->dev;
 
        input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
        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
        input_dev->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA);
        input_dev->relbit[0] |= BIT(REL_WHEEL);
 
-       input_dev->private = mouse;
+       input_set_drvdata(input_dev, mouse);
+
        input_dev->open = usb_mouse_open;
        input_dev->close = usb_mouse_close;
 
index 55a72592704cf5e1a497ae2805f6ff3c3f802c85..b234729706be800789dced2c155629e2bb448d03 100644 (file)
@@ -336,7 +336,7 @@ static int bits_to_user(unsigned long *bits, unsigned int maxbit,
 
        if (compat) {
                len = NBITS_COMPAT(maxbit) * sizeof(compat_long_t);
-               if (len < maxlen)
+               if (len > maxlen)
                        len = maxlen;
 
                for (i = 0; i < len / sizeof(compat_long_t); i++)
index 65814b0340cbfb60a2676a00ac4b6928d7d67c86..c10ce91b64e9b432cbe797df44b7d605aa7a4609 100644 (file)
@@ -5103,7 +5103,7 @@ static int is_mddev_idle(mddev_t *mddev)
                 *
                 * Note: the following is an unsigned comparison.
                 */
-               if ((curr_events - rdev->last_events + 4096) > 8192) {
+               if ((long)curr_events - (long)rdev->last_events > 4096) {
                        rdev->last_events = curr_events;
                        idle = 0;
                }
index 7c8ccc09b60126a448a70c1ef4e3f77975a1f434..829da9a1d113e01768dd6ae3973a672bc3fd09ed 100644 (file)
@@ -141,6 +141,20 @@ config ACT200L_DONGLE
          To activate support for ACTiSYS IR-200L dongle you will have to
          start irattach like this: "irattach -d act200l".
 
+config KINGSUN_DONGLE
+       tristate "KingSun/DonShine DS-620 IrDA-USB dongle"
+       depends on IRDA && USB && EXPERIMENTAL
+       help
+         Say Y or M here if you want to build support for the KingSun/DonShine
+         DS-620 IrDA-USB bridge device driver.
+
+         This USB bridge does not conform to the IrDA-USB device class
+         specification, and therefore needs its own specific driver. This
+         dongle supports SIR speed only (9600 bps).
+
+         To compile it as a module, choose M here: the module will be called
+         kingsun-sir.
+
 comment "Old SIR device drivers"
 
 config IRPORT_SIR
index 5be09f1b9ee2f4b8dc056540342955405b72b215..233a2f9237307835934ecbde083ec2e82e149ad4 100644 (file)
@@ -45,6 +45,7 @@ obj-$(CONFIG_MCP2120_DONGLE)  += mcp2120-sir.o
 obj-$(CONFIG_ACT200L_DONGLE)   += act200l-sir.o
 obj-$(CONFIG_MA600_DONGLE)     += ma600-sir.o
 obj-$(CONFIG_TOIM3232_DONGLE)  += toim3232-sir.o
+obj-$(CONFIG_KINGSUN_DONGLE)   += kingsun-sir.o
 
 # The SIR helper module
 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 (file)
index 0000000..2174291
--- /dev/null
@@ -0,0 +1,657 @@
+/*****************************************************************************
+*
+* Filename:      kingsun-sir.c
+* Version:       0.1.1
+* Description:   Irda KingSun/DonShine USB Dongle
+* Status:        Experimental
+* Author:        Alex Villac�s Lasso <a_villacis@palosanto.com>
+*
+*      Based on stir4200 and mcs7780 drivers, with (strange?) differences
+*
+*      This program is free software; you can redistribute it and/or modify
+*      it under the terms of the GNU General Public License as published by
+*      the Free Software Foundation; either version 2 of the License.
+*
+*      This program is distributed in the hope that it will be useful,
+*      but WITHOUT ANY WARRANTY; without even the implied warranty of
+*      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*      GNU General Public License for more details.
+*
+*      You should have received a copy of the GNU General Public License
+*      along with this program; if not, write to the Free Software
+*      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+*****************************************************************************/
+
+/*
+ * This is my current (2007-04-25) understanding of how this dongle is supposed
+ * to work. This is based on reverse-engineering and examination of the packet
+ * data sent and received by the WinXP driver using USBSnoopy. Feel free to
+ * update here as more of this dongle is known:
+ *
+ * General: Unlike the other USB IrDA dongles, this particular dongle exposes,
+ * not two bulk (in and out) endpoints, but two *interrupt* ones. This dongle,
+ * like the bulk based ones (stir4200.c and mcs7780.c), requires polling in
+ * order to receive data.
+ * Transmission: Just like stir4200, this dongle uses a raw stream of data,
+ * which needs to be wrapped and escaped in a similar way as in stir4200.c.
+ * Reception: Poll-based, as in stir4200. Each read returns the contents of a
+ * 8-byte buffer, of which the first byte (LSB) indicates the number of bytes
+ * (1-7) of valid data contained within the remaining 7 bytes. For example, if
+ * the buffer had the following contents:
+ *  06 ff ff ff c0 01 04 aa
+ * This means that (06) there are 6 bytes of valid data. The byte 0xaa at the
+ * end is garbage (left over from a previous reception) and is discarded.
+ * If a read returns an "impossible" value as the length of valid data (such as
+ * 0x36) in the first byte, then the buffer is uninitialized (as is the case of
+ * first plug-in) and its contents should be discarded. There is currently no
+ * evidence that the top 5 bits of the 1st byte of the buffer can have values
+ * other than 0 once reception begins.
+ * Once valid bytes are collected, the assembled stream is a sequence of
+ * wrapped IrDA frames that is unwrapped and unescaped as in stir4200.c.
+ * BIG FAT WARNING: the dongle does *not* reset the RX buffer in any way after
+ * a successful read from the host, which means that in absence of further
+ * reception, repeated reads from the dongle will return the exact same
+ * contents repeatedly. Attempts to be smart and cache a previous read seem
+ * to result in corrupted packets, so this driver depends on the unwrap logic
+ * to sort out any repeated reads.
+ * Speed change: no commands observed so far to change speed, assumed fixed
+ * 9600bps (SIR).
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/usb.h>
+#include <linux/device.h>
+#include <linux/crc32.h>
+
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/crc.h>
+
+/*
+ * According to lsusb, 0x07c0 is assigned to
+ * "Code Mercenaries Hard- und Software GmbH"
+ */
+#define KING_VENDOR_ID 0x07c0
+#define KING_PRODUCT_ID 0x4200
+
+/* These are the currently known USB ids */
+static struct usb_device_id dongles[] = {
+    /* KingSun Co,Ltd  IrDA/USB Bridge */
+    { USB_DEVICE(KING_VENDOR_ID, KING_PRODUCT_ID) },
+    { }
+};
+
+MODULE_DEVICE_TABLE(usb, dongles);
+
+#define KINGSUN_MTT 0x07
+
+#define KINGSUN_FIFO_SIZE              4096
+#define KINGSUN_EP_IN                  0
+#define KINGSUN_EP_OUT                 1
+
+struct kingsun_cb {
+       struct usb_device *usbdev;      /* init: probe_irda */
+       struct net_device *netdev;      /* network layer */
+       struct irlap_cb   *irlap;       /* The link layer we are binded to */
+       struct net_device_stats stats;  /* network statistics */
+       struct qos_info   qos;
+
+       __u8              *in_buf;      /* receive buffer */
+       __u8              *out_buf;     /* transmit buffer */
+       __u8              max_rx;       /* max. atomic read from dongle
+                                          (usually 8), also size of in_buf */
+       __u8              max_tx;       /* max. atomic write to dongle
+                                          (usually 8) */
+
+       iobuff_t          rx_buff;      /* receive unwrap state machine */
+       struct timeval    rx_time;
+       spinlock_t lock;
+       int receiving;
+
+       __u8 ep_in;
+       __u8 ep_out;
+
+       struct urb       *tx_urb;
+       struct urb       *rx_urb;
+};
+
+/* Callback transmission routine */
+static void kingsun_send_irq(struct urb *urb)
+{
+       struct kingsun_cb *kingsun = urb->context;
+       struct net_device *netdev = kingsun->netdev;
+
+       /* in process of stopping, just drop data */
+       if (!netif_running(kingsun->netdev)) {
+               err("kingsun_send_irq: Network not running!");
+               return;
+       }
+
+       /* unlink, shutdown, unplug, other nasties */
+       if (urb->status != 0) {
+               err("kingsun_send_irq: urb asynchronously failed - %d",
+                   urb->status);
+       }
+       netif_wake_queue(netdev);
+}
+
+/*
+ * Called from net/core when new frame is available.
+ */
+static int kingsun_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+       struct kingsun_cb *kingsun;
+       int wraplen;
+       int ret = 0;
+
+       if (skb == NULL || netdev == NULL)
+               return -EINVAL;
+
+       netif_stop_queue(netdev);
+
+       /* the IRDA wrapping routines don't deal with non linear skb */
+       SKB_LINEAR_ASSERT(skb);
+
+       kingsun = netdev_priv(netdev);
+
+       spin_lock(&kingsun->lock);
+
+       /* Append data to the end of whatever data remains to be transmitted */
+       wraplen = async_wrap_skb(skb,
+               kingsun->out_buf,
+               KINGSUN_FIFO_SIZE);
+
+       /* Calculate how much data can be transmitted in this urb */
+       usb_fill_int_urb(kingsun->tx_urb, kingsun->usbdev,
+               usb_sndintpipe(kingsun->usbdev, kingsun->ep_out),
+               kingsun->out_buf, wraplen, kingsun_send_irq,
+               kingsun, 1);
+
+       if ((ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC))) {
+               err("kingsun_hard_xmit: failed tx_urb submit: %d", ret);
+               switch (ret) {
+               case -ENODEV:
+               case -EPIPE:
+                       break;
+               default:
+                       kingsun->stats.tx_errors++;
+                       netif_start_queue(netdev);
+               }
+       } else {
+               kingsun->stats.tx_packets++;
+               kingsun->stats.tx_bytes += skb->len;
+       }
+
+       dev_kfree_skb(skb);
+       spin_unlock(&kingsun->lock);
+
+       return ret;
+}
+
+/* Receive callback function */
+static void kingsun_rcv_irq(struct urb *urb)
+{
+       struct kingsun_cb *kingsun = urb->context;
+       int ret;
+
+       /* in process of stopping, just drop data */
+       if (!netif_running(kingsun->netdev)) {
+               kingsun->receiving = 0;
+               return;
+       }
+
+       /* unlink, shutdown, unplug, other nasties */
+       if (urb->status != 0) {
+               err("kingsun_rcv_irq: urb asynchronously failed - %d",
+                   urb->status);
+               kingsun->receiving = 0;
+               return;
+       }
+
+       if (urb->actual_length == kingsun->max_rx) {
+               __u8 *bytes = urb->transfer_buffer;
+               int i;
+
+               /* The very first byte in the buffer indicates the length of
+                  valid data in the read. This byte must be in the range
+                  1..kingsun->max_rx -1 . Values outside this range indicate
+                  an uninitialized Rx buffer when the dongle has just been
+                  plugged in. */
+               if (bytes[0] >= 1 && bytes[0] < kingsun->max_rx) {
+                       for (i = 1; i <= bytes[0]; i++) {
+                               async_unwrap_char(kingsun->netdev,
+                                                 &kingsun->stats,
+                                                 &kingsun->rx_buff, bytes[i]);
+                       }
+                       kingsun->netdev->last_rx = jiffies;
+                       do_gettimeofday(&kingsun->rx_time);
+                       kingsun->receiving =
+                               (kingsun->rx_buff.state != OUTSIDE_FRAME)
+                               ? 1 : 0;
+               }
+       } else if (urb->actual_length > 0) {
+               err("%s(): Unexpected response length, expected %d got %d",
+                   __FUNCTION__, kingsun->max_rx, urb->actual_length);
+       }
+       /* This urb has already been filled in kingsun_net_open */
+       ret = usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+/*
+ * Function kingsun_net_open (dev)
+ *
+ *    Network device is taken up. Usually this is done by "ifconfig irda0 up"
+ */
+static int kingsun_net_open(struct net_device *netdev)
+{
+       struct kingsun_cb *kingsun = netdev_priv(netdev);
+       int err = -ENOMEM;
+       char hwname[16];
+
+       /* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */
+       kingsun->receiving = 0;
+
+       /* Initialize for SIR to copy data directly into skb.  */
+       kingsun->rx_buff.in_frame = FALSE;
+       kingsun->rx_buff.state = OUTSIDE_FRAME;
+       kingsun->rx_buff.truesize = IRDA_SKB_MAX_MTU;
+       kingsun->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
+       if (!kingsun->rx_buff.skb)
+               goto free_mem;
+
+       skb_reserve(kingsun->rx_buff.skb, 1);
+       kingsun->rx_buff.head = kingsun->rx_buff.skb->data;
+       do_gettimeofday(&kingsun->rx_time);
+
+       kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!kingsun->rx_urb)
+               goto free_mem;
+
+       kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!kingsun->tx_urb)
+               goto free_mem;
+
+       /*
+        * Now that everything should be initialized properly,
+        * Open new IrLAP layer instance to take care of us...
+        */
+       sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
+       kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
+       if (!kingsun->irlap) {
+               err("kingsun-sir: irlap_open failed");
+               goto free_mem;
+       }
+
+       /* Start first reception */
+       usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev,
+                         usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in),
+                         kingsun->in_buf, kingsun->max_rx,
+                         kingsun_rcv_irq, kingsun, 1);
+       kingsun->rx_urb->status = 0;
+       err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
+       if (err) {
+               err("kingsun-sir: first urb-submit failed: %d", err);
+               goto close_irlap;
+       }
+
+       netif_start_queue(netdev);
+
+       /* Situation at this point:
+          - all work buffers allocated
+          - urbs allocated and ready to fill
+          - max rx packet known (in max_rx)
+          - unwrap state machine initialized, in state outside of any frame
+          - receive request in progress
+          - IrLAP layer started, about to hand over packets to send
+        */
+
+       return 0;
+
+ close_irlap:
+       irlap_close(kingsun->irlap);
+ free_mem:
+       if (kingsun->tx_urb) {
+               usb_free_urb(kingsun->tx_urb);
+               kingsun->tx_urb = NULL;
+       }
+       if (kingsun->rx_urb) {
+               usb_free_urb(kingsun->rx_urb);
+               kingsun->rx_urb = NULL;
+       }
+       if (kingsun->rx_buff.skb) {
+               kfree_skb(kingsun->rx_buff.skb);
+               kingsun->rx_buff.skb = NULL;
+               kingsun->rx_buff.head = NULL;
+       }
+       return err;
+}
+
+/*
+ * Function kingsun_net_close (kingsun)
+ *
+ *    Network device is taken down. Usually this is done by
+ *    "ifconfig irda0 down"
+ */
+static int kingsun_net_close(struct net_device *netdev)
+{
+       struct kingsun_cb *kingsun = netdev_priv(netdev);
+
+       /* Stop transmit processing */
+       netif_stop_queue(netdev);
+
+       /* Mop up receive && transmit urb's */
+       usb_kill_urb(kingsun->tx_urb);
+       usb_kill_urb(kingsun->rx_urb);
+
+       usb_free_urb(kingsun->tx_urb);
+       usb_free_urb(kingsun->rx_urb);
+
+       kingsun->tx_urb = NULL;
+       kingsun->rx_urb = NULL;
+
+       kfree_skb(kingsun->rx_buff.skb);
+       kingsun->rx_buff.skb = NULL;
+       kingsun->rx_buff.head = NULL;
+       kingsun->rx_buff.in_frame = FALSE;
+       kingsun->rx_buff.state = OUTSIDE_FRAME;
+       kingsun->receiving = 0;
+
+       /* Stop and remove instance of IrLAP */
+       if (kingsun->irlap)
+               irlap_close(kingsun->irlap);
+
+       kingsun->irlap = NULL;
+
+       return 0;
+}
+
+/*
+ * IOCTLs : Extra out-of-band network commands...
+ */
+static int kingsun_net_ioctl(struct net_device *netdev, struct ifreq *rq,
+                            int cmd)
+{
+       struct if_irda_req *irq = (struct if_irda_req *) rq;
+       struct kingsun_cb *kingsun = netdev_priv(netdev);
+       int ret = 0;
+
+       switch (cmd) {
+       case SIOCSBANDWIDTH: /* Set bandwidth */
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+
+               /* Check if the device is still there */
+               if (netif_device_present(kingsun->netdev))
+                       /* No observed commands for speed change */
+                       ret = -EOPNOTSUPP;
+               break;
+
+       case SIOCSMEDIABUSY: /* Set media busy */
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+
+               /* Check if the IrDA stack is still there */
+               if (netif_running(kingsun->netdev))
+                       irda_device_set_media_busy(kingsun->netdev, TRUE);
+               break;
+
+       case SIOCGRECEIVING:
+               /* Only approximately true */
+               irq->ifr_receiving = kingsun->receiving;
+               break;
+
+       default:
+               ret = -EOPNOTSUPP;
+       }
+
+       return ret;
+}
+
+/*
+ * Get device stats (for /proc/net/dev and ifconfig)
+ */
+static struct net_device_stats *
+kingsun_net_get_stats(struct net_device *netdev)
+{
+       struct kingsun_cb *kingsun = netdev_priv(netdev);
+       return &kingsun->stats;
+}
+
+/*
+ * This routine is called by the USB subsystem for each new device
+ * in the system. We need to check if the device is ours, and in
+ * this case start handling it.
+ */
+static int kingsun_probe(struct usb_interface *intf,
+                     const struct usb_device_id *id)
+{
+       struct usb_host_interface *interface;
+       struct usb_endpoint_descriptor *endpoint;
+
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct kingsun_cb *kingsun = NULL;
+       struct net_device *net = NULL;
+       int ret = -ENOMEM;
+       int pipe, maxp_in, maxp_out;
+       __u8 ep_in;
+       __u8 ep_out;
+
+       /* Check that there really are two interrupt endpoints.
+          Check based on the one in drivers/usb/input/usbmouse.c
+        */
+       interface = intf->cur_altsetting;
+       if (interface->desc.bNumEndpoints != 2) {
+               err("kingsun-sir: expected 2 endpoints, found %d",
+                   interface->desc.bNumEndpoints);
+               return -ENODEV;
+       }
+       endpoint = &interface->endpoint[KINGSUN_EP_IN].desc;
+       if (!usb_endpoint_is_int_in(endpoint)) {
+               err("kingsun-sir: endpoint 0 is not interrupt IN");
+               return -ENODEV;
+       }
+
+       ep_in = endpoint->bEndpointAddress;
+       pipe = usb_rcvintpipe(dev, ep_in);
+       maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+       if (maxp_in > 255 || maxp_in <= 1) {
+               err("%s: endpoint 0 has max packet size %d not in range",
+                   __FILE__, maxp_in);
+               return -ENODEV;
+       }
+
+       endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc;
+       if (!usb_endpoint_is_int_out(endpoint)) {
+               err("kingsun-sir: endpoint 1 is not interrupt OUT");
+               return -ENODEV;
+       }
+
+       ep_out = endpoint->bEndpointAddress;
+       pipe = usb_sndintpipe(dev, ep_out);
+       maxp_out = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+       /* Allocate network device container. */
+       net = alloc_irdadev(sizeof(*kingsun));
+       if(!net)
+               goto err_out1;
+
+       SET_MODULE_OWNER(net);
+       SET_NETDEV_DEV(net, &intf->dev);
+       kingsun = netdev_priv(net);
+       kingsun->irlap = NULL;
+       kingsun->tx_urb = NULL;
+       kingsun->rx_urb = NULL;
+       kingsun->ep_in = ep_in;
+       kingsun->ep_out = ep_out;
+       kingsun->in_buf = NULL;
+       kingsun->out_buf = NULL;
+       kingsun->max_rx = (__u8)maxp_in;
+       kingsun->max_tx = (__u8)maxp_out;
+       kingsun->netdev = net;
+       kingsun->usbdev = dev;
+       kingsun->rx_buff.in_frame = FALSE;
+       kingsun->rx_buff.state = OUTSIDE_FRAME;
+       kingsun->rx_buff.skb = NULL;
+       kingsun->receiving = 0;
+       spin_lock_init(&kingsun->lock);
+
+       /* Allocate input buffer */
+       kingsun->in_buf = (__u8 *)kmalloc(kingsun->max_rx, GFP_KERNEL);
+       if (!kingsun->in_buf)
+               goto free_mem;
+
+       /* Allocate output buffer */
+       kingsun->out_buf = (__u8 *)kmalloc(KINGSUN_FIFO_SIZE, GFP_KERNEL);
+       if (!kingsun->out_buf)
+               goto free_mem;
+
+       printk(KERN_INFO "KingSun/DonShine IRDA/USB found at address %d, "
+               "Vendor: %x, Product: %x\n",
+              dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
+              le16_to_cpu(dev->descriptor.idProduct));
+
+       /* Initialize QoS for this device */
+       irda_init_max_qos_capabilies(&kingsun->qos);
+
+       /* That's the Rx capability. */
+       kingsun->qos.baud_rate.bits       &= IR_9600;
+       kingsun->qos.min_turn_time.bits   &= KINGSUN_MTT;
+       irda_qos_bits_to_value(&kingsun->qos);
+
+       /* Override the network functions we need to use */
+       net->hard_start_xmit = kingsun_hard_xmit;
+       net->open            = kingsun_net_open;
+       net->stop            = kingsun_net_close;
+       net->get_stats       = kingsun_net_get_stats;
+       net->do_ioctl        = kingsun_net_ioctl;
+
+       ret = register_netdev(net);
+       if (ret != 0)
+               goto free_mem;
+
+       info("IrDA: Registered KingSun/DonShine device %s", net->name);
+
+       usb_set_intfdata(intf, kingsun);
+
+       /* Situation at this point:
+          - all work buffers allocated
+          - urbs not allocated, set to NULL
+          - max rx packet known (in max_rx)
+          - unwrap state machine (partially) initialized, but skb == NULL
+        */
+
+       return 0;
+
+free_mem:
+       if (kingsun->out_buf) kfree(kingsun->out_buf);
+       if (kingsun->in_buf) kfree(kingsun->in_buf);
+       free_netdev(net);
+err_out1:
+       return ret;
+}
+
+/*
+ * The current device is removed, the USB layer tell us to shut it down...
+ */
+static void kingsun_disconnect(struct usb_interface *intf)
+{
+       struct kingsun_cb *kingsun = usb_get_intfdata(intf);
+
+       if (!kingsun)
+               return;
+
+       unregister_netdev(kingsun->netdev);
+
+       /* Mop up receive && transmit urb's */
+       if (kingsun->tx_urb != NULL) {
+               usb_kill_urb(kingsun->tx_urb);
+               usb_free_urb(kingsun->tx_urb);
+               kingsun->tx_urb = NULL;
+       }
+       if (kingsun->rx_urb != NULL) {
+               usb_kill_urb(kingsun->rx_urb);
+               usb_free_urb(kingsun->rx_urb);
+               kingsun->rx_urb = NULL;
+       }
+
+       kfree(kingsun->out_buf);
+       kfree(kingsun->in_buf);
+       free_netdev(kingsun->netdev);
+
+       usb_set_intfdata(intf, NULL);
+}
+
+#ifdef CONFIG_PM
+/* USB suspend, so power off the transmitter/receiver */
+static int kingsun_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct kingsun_cb *kingsun = usb_get_intfdata(intf);
+
+       netif_device_detach(kingsun->netdev);
+       if (kingsun->tx_urb != NULL) usb_kill_urb(kingsun->tx_urb);
+       if (kingsun->rx_urb != NULL) usb_kill_urb(kingsun->rx_urb);
+       return 0;
+}
+
+/* Coming out of suspend, so reset hardware */
+static int kingsun_resume(struct usb_interface *intf)
+{
+       struct kingsun_cb *kingsun = usb_get_intfdata(intf);
+
+       if (kingsun->rx_urb != NULL)
+               usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
+       netif_device_attach(kingsun->netdev);
+
+       return 0;
+}
+#endif
+
+/*
+ * USB device callbacks
+ */
+static struct usb_driver irda_driver = {
+       .name           = "kingsun-sir",
+       .probe          = kingsun_probe,
+       .disconnect     = kingsun_disconnect,
+       .id_table       = dongles,
+#ifdef CONFIG_PM
+       .suspend        = kingsun_suspend,
+       .resume         = kingsun_resume,
+#endif
+};
+
+/*
+ * Module insertion
+ */
+static int __init kingsun_init(void)
+{
+       return usb_register(&irda_driver);
+}
+module_init(kingsun_init);
+
+/*
+ * Module removal
+ */
+static void __exit kingsun_cleanup(void)
+{
+       /* Deregister the driver and remove all pending instances */
+       usb_deregister(&irda_driver);
+}
+module_exit(kingsun_cleanup);
+
+MODULE_AUTHOR("Alex Villac�s Lasso <a_villacis@palosanto.com>");
+MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun/DonShine");
+MODULE_LICENSE("GPL");
index bfcfd10c72f678cf734489d698abbf4d0f978838..95ce8f49e382a6fcb125da728e119acc4e53e064 100644 (file)
@@ -397,7 +397,7 @@ config RTC_DRV_BFIN
 
 config RTC_DRV_RS5C313
        tristate "Ricoh RS5C313"
-       depends on RTC_CLASS && BROKEN
+       depends on RTC_CLASS && SH_LANDISK
        help
          If you say yes here you get support for the Ricoh RS5C313 RTC chips.
 
index 9d6de371495b9848e518ebb82d425a51c07167a9..66eb133bf5fddf98c6df9382b249bf3596e49989 100644 (file)
@@ -126,7 +126,7 @@ static void rs5c313_write_data(unsigned char data)
 static unsigned char rs5c313_read_data(void)
 {
        int i;
-       unsigned char data;
+       unsigned char data = 0;
 
        for (i = 0; i < 8; i++) {
                ndelay(700);
@@ -194,7 +194,7 @@ static void rs5c313_write_reg(unsigned char addr, unsigned char data)
        return;
 }
 
-static inline unsigned char rs5c313_read_cntreg(unsigned char addr)
+static inline unsigned char rs5c313_read_cntreg(void)
 {
        return rs5c313_read_reg(RS5C313_ADDR_CNTREG);
 }
@@ -212,7 +212,9 @@ static inline void rs5c313_write_intintvreg(unsigned char data)
 static int rs5c313_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
        int data;
+       int cnt;
 
+       cnt = 0;
        while (1) {
                RS5C313_CEENABLE;       /* CE:H */
 
@@ -225,6 +227,10 @@ static int rs5c313_rtc_read_time(struct device *dev, struct rtc_time *tm)
                RS5C313_CEDISABLE;
                ndelay(700);    /* CE:L */
 
+               if (cnt++ > 100) {
+                       dev_err(dev, "%s: timeout error\n", __FUNCTION__);
+                       return -EIO;
+               }
        }
 
        data = rs5c313_read_reg(RS5C313_ADDR_SEC);
@@ -266,7 +272,9 @@ static int rs5c313_rtc_read_time(struct device *dev, struct rtc_time *tm)
 static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
        int data;
+       int cnt;
 
+       cnt = 0;
        /* busy check. */
        while (1) {
                RS5C313_CEENABLE;       /* CE:H */
@@ -279,6 +287,11 @@ static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm)
                RS5C313_MISCOP;
                RS5C313_CEDISABLE;
                ndelay(700);    /* CE:L */
+
+               if (cnt++ > 100) {
+                       dev_err(dev, "%s: timeout error\n", __FUNCTION__);
+                       return -EIO;
+               }
        }
 
        data = BIN2BCD(tm->tm_sec);
@@ -317,6 +330,7 @@ static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm)
 static void rs5c313_check_xstp_bit(void)
 {
        struct rtc_time tm;
+       int cnt;
 
        RS5C313_CEENABLE;       /* CE:H */
        if (rs5c313_read_cntreg() & RS5C313_CNTREG_WTEN_XSTP) {
@@ -326,12 +340,16 @@ static void rs5c313_check_xstp_bit(void)
                rs5c313_write_cntreg(0x07);
 
                /* busy check. */
-               while (rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY)
+               for (cnt = 0; cnt < 100; cnt++) {
+                       if (!(rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY))
+                               break;
                        RS5C313_MISCOP;
+               }
 
                memset(&tm, 0, sizeof(struct rtc_time));
                tm.tm_mday      = 1;
-               tm.tm_mon       = 1;
+               tm.tm_mon       = 1 - 1;
+               tm.tm_year      = 2000 - 1900;
 
                rs5c313_rtc_set_time(NULL, &tm);
                printk(KERN_ERR "RICHO RS5C313: invalid value, resetting to "
@@ -356,7 +374,7 @@ static int rs5c313_rtc_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, rtc);
 
-       return err;
+       return 0;
 }
 
 static int __devexit rs5c313_rtc_remove(struct platform_device *pdev)
index 7c9d37f651e3bd6887f4d36217c4ae393e38d617..5e3f748f269332a6e2abdf3b0933362782b4a510 100644 (file)
@@ -107,6 +107,13 @@ config SPI_IMX
          This enables using the Freescale iMX SPI controller in master
          mode.
 
+config SPI_MPC52xx_PSC
+       tristate "Freescale MPC52xx PSC SPI controller"
+       depends on SPI_MASTER && PPC_MPC52xx && EXPERIMENTAL
+       help
+         This enables using the Freescale MPC52xx Programmable Serial
+         Controller in master SPI mode.
+
 config SPI_MPC83xx
        tristate "Freescale MPC83xx SPI controller"
        depends on SPI_MASTER && PPC_83xx && EXPERIMENTAL
index 624b6363f490bf74e7575478e3e0c7732e198449..5788d867de84051735eb10e7fd8c6077bce0cb07 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_SPI_BUTTERFLY)           += spi_butterfly.o
 obj-$(CONFIG_SPI_IMX)                  += spi_imx.o
 obj-$(CONFIG_SPI_PXA2XX)               += pxa2xx_spi.o
 obj-$(CONFIG_SPI_OMAP_UWIRE)           += omap_uwire.o
+obj-$(CONFIG_SPI_MPC52xx_PSC)          += mpc52xx_psc_spi.o
 obj-$(CONFIG_SPI_MPC83xx)              += spi_mpc83xx.o
 obj-$(CONFIG_SPI_S3C24XX_GPIO)         += spi_s3c24xx_gpio.o
 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 (file)
index 0000000..052359f
--- /dev/null
@@ -0,0 +1,654 @@
+/*
+ * MPC52xx SPC in SPI mode driver.
+ *
+ * Maintainer: Dragos Carp
+ *
+ * Copyright (C) 2006 TOPTICA Photonics AG.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+
+#if defined(CONFIG_PPC_MERGE)
+#include <asm/of_platform.h>
+#else
+#include <linux/platform_device.h>
+#endif
+
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/mpc52xx.h>
+#include <asm/mpc52xx_psc.h>
+
+#define MCLK 20000000 /* PSC port MClk in hz */
+
+struct mpc52xx_psc_spi {
+       /* fsl_spi_platform data */
+       void (*activate_cs)(u8, u8);
+       void (*deactivate_cs)(u8, u8);
+       u32 sysclk;
+
+       /* driver internal data */
+       struct mpc52xx_psc __iomem *psc;
+       unsigned int irq;
+       u8 bits_per_word;
+       u8 busy;
+
+       struct workqueue_struct *workqueue;
+       struct work_struct work;
+
+       struct list_head queue;
+       spinlock_t lock;
+
+       struct completion done;
+};
+
+/* controller state */
+struct mpc52xx_psc_spi_cs {
+       int bits_per_word;
+       int speed_hz;
+};
+
+/* set clock freq, clock ramp, bits per work
+ * if t is NULL then reset the values to the default values
+ */
+static int mpc52xx_psc_spi_transfer_setup(struct spi_device *spi,
+               struct spi_transfer *t)
+{
+       struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
+
+       cs->speed_hz = (t && t->speed_hz)
+                       ? t->speed_hz : spi->max_speed_hz;
+       cs->bits_per_word = (t && t->bits_per_word)
+                       ? t->bits_per_word : spi->bits_per_word;
+       cs->bits_per_word = ((cs->bits_per_word + 7) / 8) * 8;
+       return 0;
+}
+
+static void mpc52xx_psc_spi_activate_cs(struct spi_device *spi)
+{
+       struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
+       struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
+       struct mpc52xx_psc __iomem *psc = mps->psc;
+       u32 sicr;
+       u16 ccr;
+
+       sicr = in_be32(&psc->sicr);
+
+       /* Set clock phase and polarity */
+       if (spi->mode & SPI_CPHA)
+               sicr |= 0x00001000;
+       else
+               sicr &= ~0x00001000;
+       if (spi->mode & SPI_CPOL)
+               sicr |= 0x00002000;
+       else
+               sicr &= ~0x00002000;
+
+       if (spi->mode & SPI_LSB_FIRST)
+               sicr |= 0x10000000;
+       else
+               sicr &= ~0x10000000;
+       out_be32(&psc->sicr, sicr);
+
+       /* Set clock frequency and bits per word
+        * Because psc->ccr is defined as 16bit register instead of 32bit
+        * just set the lower byte of BitClkDiv
+        */
+       ccr = in_be16(&psc->ccr);
+       ccr &= 0xFF00;
+       if (cs->speed_hz)
+               ccr |= (MCLK / cs->speed_hz - 1) & 0xFF;
+       else /* by default SPI Clk 1MHz */
+               ccr |= (MCLK / 1000000 - 1) & 0xFF;
+       out_be16(&psc->ccr, ccr);
+       mps->bits_per_word = cs->bits_per_word;
+
+       if (mps->activate_cs)
+               mps->activate_cs(spi->chip_select,
+                               (spi->mode & SPI_CS_HIGH) ? 1 : 0);
+}
+
+static void mpc52xx_psc_spi_deactivate_cs(struct spi_device *spi)
+{
+       struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
+
+       if (mps->deactivate_cs)
+               mps->deactivate_cs(spi->chip_select,
+                               (spi->mode & SPI_CS_HIGH) ? 1 : 0);
+}
+
+#define MPC52xx_PSC_BUFSIZE (MPC52xx_PSC_RFNUM_MASK + 1)
+/* wake up when 80% fifo full */
+#define MPC52xx_PSC_RFALARM (MPC52xx_PSC_BUFSIZE * 20 / 100)
+
+static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi,
+                                               struct spi_transfer *t)
+{
+       struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
+       struct mpc52xx_psc __iomem *psc = mps->psc;
+       unsigned rb = 0;        /* number of bytes receieved */
+       unsigned sb = 0;        /* number of bytes sent */
+       unsigned char *rx_buf = (unsigned char *)t->rx_buf;
+       unsigned char *tx_buf = (unsigned char *)t->tx_buf;
+       unsigned rfalarm;
+       unsigned send_at_once = MPC52xx_PSC_BUFSIZE;
+       unsigned recv_at_once;
+       unsigned bpw = mps->bits_per_word / 8;
+
+       if (!t->tx_buf && !t->rx_buf && t->len)
+               return -EINVAL;
+
+       /* enable transmiter/receiver */
+       out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
+       while (rb < t->len) {
+               if (t->len - rb > MPC52xx_PSC_BUFSIZE) {
+                       rfalarm = MPC52xx_PSC_RFALARM;
+               } else {
+                       send_at_once = t->len - sb;
+                       rfalarm = MPC52xx_PSC_BUFSIZE - (t->len - rb);
+               }
+
+               dev_dbg(&spi->dev, "send %d bytes...\n", send_at_once);
+               if (tx_buf) {
+                       for (; send_at_once; sb++, send_at_once--) {
+                               /* set EOF flag */
+                               if (mps->bits_per_word
+                                               && (sb + 1) % bpw == 0)
+                                       out_8(&psc->ircr2, 0x01);
+                               out_8(&psc->mpc52xx_psc_buffer_8, tx_buf[sb]);
+                       }
+               } else {
+                       for (; send_at_once; sb++, send_at_once--) {
+                               /* set EOF flag */
+                               if (mps->bits_per_word
+                                               && ((sb + 1) % bpw) == 0)
+                                       out_8(&psc->ircr2, 0x01);
+                               out_8(&psc->mpc52xx_psc_buffer_8, 0);
+                       }
+               }
+
+
+               /* enable interupts and wait for wake up
+                * if just one byte is expected the Rx FIFO genererates no
+                * FFULL interrupt, so activate the RxRDY interrupt
+                */
+               out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
+               if (t->len - rb == 1) {
+                       out_8(&psc->mode, 0);
+               } else {
+                       out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL);
+                       out_be16(&psc->rfalarm, rfalarm);
+               }
+               out_be16(&psc->mpc52xx_psc_imr, MPC52xx_PSC_IMR_RXRDY);
+               wait_for_completion(&mps->done);
+               recv_at_once = in_be16(&psc->rfnum);
+               dev_dbg(&spi->dev, "%d bytes received\n", recv_at_once);
+
+               send_at_once = recv_at_once;
+               if (rx_buf) {
+                       for (; recv_at_once; rb++, recv_at_once--)
+                               rx_buf[rb] = in_8(&psc->mpc52xx_psc_buffer_8);
+               } else {
+                       for (; recv_at_once; rb++, recv_at_once--)
+                               in_8(&psc->mpc52xx_psc_buffer_8);
+               }
+       }
+       /* disable transmiter/receiver */
+       out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
+
+       return 0;
+}
+
+static void mpc52xx_psc_spi_work(struct work_struct *work)
+{
+       struct mpc52xx_psc_spi *mps =
+               container_of(work, struct mpc52xx_psc_spi, work);
+
+       spin_lock_irq(&mps->lock);
+       mps->busy = 1;
+       while (!list_empty(&mps->queue)) {
+               struct spi_message *m;
+               struct spi_device *spi;
+               struct spi_transfer *t = NULL;
+               unsigned cs_change;
+               int status;
+
+               m = container_of(mps->queue.next, struct spi_message, queue);
+               list_del_init(&m->queue);
+               spin_unlock_irq(&mps->lock);
+
+               spi = m->spi;
+               cs_change = 1;
+               status = 0;
+               list_for_each_entry (t, &m->transfers, transfer_list) {
+                       if (t->bits_per_word || t->speed_hz) {
+                               status = mpc52xx_psc_spi_transfer_setup(spi, t);
+                               if (status < 0)
+                                       break;
+                       }
+
+                       if (cs_change)
+                               mpc52xx_psc_spi_activate_cs(spi);
+                       cs_change = t->cs_change;
+
+                       status = mpc52xx_psc_spi_transfer_rxtx(spi, t);
+                       if (status)
+                               break;
+                       m->actual_length += t->len;
+
+                       if (t->delay_usecs)
+                               udelay(t->delay_usecs);
+
+                       if (cs_change)
+                               mpc52xx_psc_spi_deactivate_cs(spi);
+               }
+
+               m->status = status;
+               m->complete(m->context);
+
+               if (status || !cs_change)
+                       mpc52xx_psc_spi_deactivate_cs(spi);
+
+               mpc52xx_psc_spi_transfer_setup(spi, NULL);
+
+               spin_lock_irq(&mps->lock);
+       }
+       mps->busy = 0;
+       spin_unlock_irq(&mps->lock);
+}
+
+static int mpc52xx_psc_spi_setup(struct spi_device *spi)
+{
+       struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
+       struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
+       unsigned long flags;
+
+       if (spi->bits_per_word%8)
+               return -EINVAL;
+
+       if (!cs) {
+               cs = kzalloc(sizeof *cs, GFP_KERNEL);
+               if (!cs)
+                       return -ENOMEM;
+               spi->controller_state = cs;
+       }
+
+       cs->bits_per_word = spi->bits_per_word;
+       cs->speed_hz = spi->max_speed_hz;
+
+       spin_lock_irqsave(&mps->lock, flags);
+       if (!mps->busy)
+               mpc52xx_psc_spi_deactivate_cs(spi);
+       spin_unlock_irqrestore(&mps->lock, flags);
+
+       return 0;
+}
+
+static int mpc52xx_psc_spi_transfer(struct spi_device *spi,
+               struct spi_message *m)
+{
+       struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
+       unsigned long flags;
+
+       m->actual_length = 0;
+       m->status = -EINPROGRESS;
+
+       spin_lock_irqsave(&mps->lock, flags);
+       list_add_tail(&m->queue, &mps->queue);
+       queue_work(mps->workqueue, &mps->work);
+       spin_unlock_irqrestore(&mps->lock, flags);
+
+       return 0;
+}
+
+static void mpc52xx_psc_spi_cleanup(struct spi_device *spi)
+{
+       kfree(spi->controller_state);
+}
+
+static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps)
+{
+       struct mpc52xx_cdm __iomem *cdm;
+       struct mpc52xx_gpio __iomem *gpio;
+       struct mpc52xx_psc __iomem *psc = mps->psc;
+       u32 ul;
+       u32 mclken_div;
+       int ret = 0;
+
+#if defined(CONFIG_PPC_MERGE)
+       cdm = mpc52xx_find_and_map("mpc52xx-cdm");
+       gpio = mpc52xx_find_and_map("mpc52xx-gpio");
+#else
+       cdm = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE);
+       gpio = ioremap(MPC52xx_PA(MPC52xx_GPIO_OFFSET), MPC52xx_GPIO_SIZE);
+#endif
+       if (!cdm || !gpio) {
+               printk(KERN_ERR "Error mapping CDM/GPIO\n");
+               ret = -EFAULT;
+               goto unmap_regs;
+       }
+
+       /* default sysclk is 512MHz */
+       mclken_div = 0x8000 |
+               (((mps->sysclk ? mps->sysclk : 512000000) / MCLK) & 0x1FF);
+
+       switch (psc_id) {
+       case 1:
+               ul = in_be32(&gpio->port_config);
+               ul &= 0xFFFFFFF8;
+               ul |= 0x00000006;
+               out_be32(&gpio->port_config, ul);
+               out_be16(&cdm->mclken_div_psc1, mclken_div);
+               ul = in_be32(&cdm->clk_enables);
+               ul |= 0x00000020;
+               out_be32(&cdm->clk_enables, ul);
+               break;
+       case 2:
+               ul = in_be32(&gpio->port_config);
+               ul &= 0xFFFFFF8F;
+               ul |= 0x00000060;
+               out_be32(&gpio->port_config, ul);
+               out_be16(&cdm->mclken_div_psc2, mclken_div);
+               ul = in_be32(&cdm->clk_enables);
+               ul |= 0x00000040;
+               out_be32(&cdm->clk_enables, ul);
+               break;
+       case 3:
+               ul = in_be32(&gpio->port_config);
+               ul &= 0xFFFFF0FF;
+               ul |= 0x00000600;
+               out_be32(&gpio->port_config, ul);
+               out_be16(&cdm->mclken_div_psc3, mclken_div);
+               ul = in_be32(&cdm->clk_enables);
+               ul |= 0x00000080;
+               out_be32(&cdm->clk_enables, ul);
+               break;
+       case 6:
+               ul = in_be32(&gpio->port_config);
+               ul &= 0xFF8FFFFF;
+               ul |= 0x00700000;
+               out_be32(&gpio->port_config, ul);
+               out_be16(&cdm->mclken_div_psc6, mclken_div);
+               ul = in_be32(&cdm->clk_enables);
+               ul |= 0x00000010;
+               out_be32(&cdm->clk_enables, ul);
+               break;
+       default:
+               ret = -EINVAL;
+               goto unmap_regs;
+       }
+
+       /* Reset the PSC into a known state */
+       out_8(&psc->command, MPC52xx_PSC_RST_RX);
+       out_8(&psc->command, MPC52xx_PSC_RST_TX);
+       out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
+
+       /* Disable interrupts, interrupts are based on alarm level */
+       out_be16(&psc->mpc52xx_psc_imr, 0);
+       out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
+       out_8(&psc->rfcntl, 0);
+       out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL);
+
+       /* Configure 8bit codec mode as a SPI master and use EOF flags */
+       /* SICR_SIM_CODEC8|SICR_GENCLK|SICR_SPI|SICR_MSTR|SICR_USEEOF */
+       out_be32(&psc->sicr, 0x0180C800);
+       out_be16(&psc->ccr, 0x070F); /* by default SPI Clk 1MHz */
+
+       /* Set 2ms DTL delay */
+       out_8(&psc->ctur, 0x00);
+       out_8(&psc->ctlr, 0x84);
+
+       mps->bits_per_word = 8;
+
+unmap_regs:
+       if (cdm)
+               iounmap(cdm);
+       if (gpio)
+               iounmap(gpio);
+
+       return ret;
+}
+
+static irqreturn_t mpc52xx_psc_spi_isr(int irq, void *dev_id)
+{
+       struct mpc52xx_psc_spi *mps = (struct mpc52xx_psc_spi *)dev_id;
+       struct mpc52xx_psc __iomem *psc = mps->psc;
+
+       /* disable interrupt and wake up the work queue */
+       if (in_be16(&psc->mpc52xx_psc_isr) & MPC52xx_PSC_IMR_RXRDY) {
+               out_be16(&psc->mpc52xx_psc_imr, 0);
+               complete(&mps->done);
+               return IRQ_HANDLED;
+       }
+       return IRQ_NONE;
+}
+
+/* bus_num is used only for the case dev->platform_data == NULL */
+static int __init mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
+                               u32 size, unsigned int irq, s16 bus_num)
+{
+       struct fsl_spi_platform_data *pdata = dev->platform_data;
+       struct mpc52xx_psc_spi *mps;
+       struct spi_master *master;
+       int ret;
+
+       if (pdata == NULL)
+               return -ENODEV;
+
+       master = spi_alloc_master(dev, sizeof *mps);
+       if (master == NULL)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, master);
+       mps = spi_master_get_devdata(master);
+
+       mps->irq = irq;
+       if (pdata == NULL) {
+               dev_warn(dev, "probe called without platform data, no "
+                               "(de)activate_cs function will be called\n");
+               mps->activate_cs = NULL;
+               mps->deactivate_cs = NULL;
+               mps->sysclk = 0;
+               master->bus_num = bus_num;
+               master->num_chipselect = 255;
+       } else {
+               mps->activate_cs = pdata->activate_cs;
+               mps->deactivate_cs = pdata->deactivate_cs;
+               mps->sysclk = pdata->sysclk;
+               master->bus_num = pdata->bus_num;
+               master->num_chipselect = pdata->max_chipselect;
+       }
+       master->setup = mpc52xx_psc_spi_setup;
+       master->transfer = mpc52xx_psc_spi_transfer;
+       master->cleanup = mpc52xx_psc_spi_cleanup;
+
+       mps->psc = ioremap(regaddr, size);
+       if (!mps->psc) {
+               dev_err(dev, "could not ioremap I/O port range\n");
+               ret = -EFAULT;
+               goto free_master;
+       }
+
+       ret = request_irq(mps->irq, mpc52xx_psc_spi_isr, 0, "mpc52xx-psc-spi",
+                               mps);
+       if (ret)
+               goto free_master;
+
+       ret = mpc52xx_psc_spi_port_config(master->bus_num, mps);
+       if (ret < 0)
+               goto free_irq;
+
+       spin_lock_init(&mps->lock);
+       init_completion(&mps->done);
+       INIT_WORK(&mps->work, mpc52xx_psc_spi_work);
+       INIT_LIST_HEAD(&mps->queue);
+
+       mps->workqueue = create_singlethread_workqueue(
+               master->cdev.dev->bus_id);
+       if (mps->workqueue == NULL) {
+               ret = -EBUSY;
+               goto free_irq;
+       }
+
+       ret = spi_register_master(master);
+       if (ret < 0)
+               goto unreg_master;
+
+       return ret;
+
+unreg_master:
+       destroy_workqueue(mps->workqueue);
+free_irq:
+       free_irq(mps->irq, mps);
+free_master:
+       if (mps->psc)
+               iounmap(mps->psc);
+       spi_master_put(master);
+
+       return ret;
+}
+
+static int __exit mpc52xx_psc_spi_do_remove(struct device *dev)
+{
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);
+
+       flush_workqueue(mps->workqueue);
+       destroy_workqueue(mps->workqueue);
+       spi_unregister_master(master);
+       free_irq(mps->irq, mps);
+       if (mps->psc)
+               iounmap(mps->psc);
+
+       return 0;
+}
+
+#if !defined(CONFIG_PPC_MERGE)
+static int __init mpc52xx_psc_spi_probe(struct platform_device *dev)
+{
+       switch(dev->id) {
+       case 1:
+       case 2:
+       case 3:
+       case 6:
+               return mpc52xx_psc_spi_do_probe(&dev->dev,
+                       MPC52xx_PA(MPC52xx_PSCx_OFFSET(dev->id)),
+                       MPC52xx_PSC_SIZE, platform_get_irq(dev, 0), dev->id);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int __exit mpc52xx_psc_spi_remove(struct platform_device *dev)
+{
+       return mpc52xx_psc_spi_do_remove(&dev->dev);
+}
+
+static struct platform_driver mpc52xx_psc_spi_platform_driver = {
+       .remove = __exit_p(mpc52xx_psc_spi_remove),
+       .driver = {
+               .name = "mpc52xx-psc-spi",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init mpc52xx_psc_spi_init(void)
+{
+       return platform_driver_probe(&mpc52xx_psc_spi_platform_driver,
+                       mpc52xx_psc_spi_probe);
+}
+module_init(mpc52xx_psc_spi_init);
+
+static void __exit mpc52xx_psc_spi_exit(void)
+{
+       platform_driver_unregister(&mpc52xx_psc_spi_platform_driver);
+}
+module_exit(mpc52xx_psc_spi_exit);
+
+#else  /* defined(CONFIG_PPC_MERGE) */
+
+static int __init mpc52xx_psc_spi_of_probe(struct of_device *op,
+       const struct of_device_id *match)
+{
+       const u32 *regaddr_p;
+       u64 regaddr64, size64;
+       s16 id = -1;
+
+       regaddr_p = of_get_address(op->node, 0, &size64, NULL);
+       if (!regaddr_p) {
+               printk(KERN_ERR "Invalid PSC address\n");
+               return -EINVAL;
+       }
+       regaddr64 = of_translate_address(op->node, regaddr_p);
+
+       if (op->dev.platform_data == NULL) {
+               struct device_node *np;
+               int i = 0;
+
+               for_each_node_by_type(np, "spi") {
+                       if (of_find_device_by_node(np) == op) {
+                               id = i;
+                               break;
+                       }
+                       i++;
+               }
+       }
+
+       return mpc52xx_psc_spi_do_probe(&op->dev, (u32)regaddr64, (u32)size64,
+                                       irq_of_parse_and_map(op->node, 0), id);
+}
+
+static int __exit mpc52xx_psc_spi_of_remove(struct of_device *op)
+{
+       return mpc52xx_psc_spi_do_remove(&op->dev);
+}
+
+static struct of_device_id mpc52xx_psc_spi_of_match[] = {
+       { .type = "spi", .compatible = "mpc52xx-psc-spi", },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, mpc52xx_psc_spi_of_match);
+
+static struct of_platform_driver mpc52xx_psc_spi_of_driver = {
+       .owner = THIS_MODULE,
+       .name = "mpc52xx-psc-spi",
+       .match_table = mpc52xx_psc_spi_of_match,
+       .probe = mpc52xx_psc_spi_of_probe,
+       .remove = __exit_p(mpc52xx_psc_spi_of_remove),
+       .driver = {
+               .name = "mpc52xx-psc-spi",
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init mpc52xx_psc_spi_init(void)
+{
+       return of_register_platform_driver(&mpc52xx_psc_spi_of_driver);
+}
+module_init(mpc52xx_psc_spi_init);
+
+static void __exit mpc52xx_psc_spi_exit(void)
+{
+       of_unregister_platform_driver(&mpc52xx_psc_spi_of_driver);
+}
+module_exit(mpc52xx_psc_spi_exit);
+
+#endif /* defined(CONFIG_PPC_MERGE) */
+
+MODULE_AUTHOR("Dragos Carp");
+MODULE_DESCRIPTION("MPC52xx PSC SPI Driver");
+MODULE_LICENSE("GPL");
index f54438828cb91ade3dff0fa3d438ea47390eac8a..eebcb708cff19fcdcbc99ce8758eb4c7edcd6d7c 100644 (file)
@@ -748,6 +748,22 @@ config FB_S1D13XXX
          working with S1D13806). Product specs at
          <http://www.erd.epson.com/vdc/html/legacy_13xxx.htm>
 
+config FB_ATMEL
+       tristate "AT91/AT32 LCD Controller support"
+       depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || AVR32)
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       help
+         This enables support for the AT91/AT32 LCD Controller.
+
+config FB_INTSRAM
+       bool "Frame Buffer in internal SRAM"
+       depends on FB_ATMEL && ARCH_AT91SAM9261
+       help
+         Say Y if you want to map Frame Buffer in internal SRAM. Say N if you want
+         to let frame buffer in external SDRAM.
+
 config FB_NVIDIA
        tristate "nVidia Framebuffer Support"
        depends on FB && PCI
@@ -780,6 +796,15 @@ config FB_NVIDIA_I2C
          independently validate video mode parameters, you should say Y
          here.
 
+config FB_NVIDIA_DEBUG
+       bool "Lots of debug output"
+       depends on FB_NVIDIA
+       default n
+       help
+         Say Y here if you want the nVidia driver to output all sorts
+         of debugging information to provide to the maintainer when
+         something goes wrong.
+
 config FB_NVIDIA_BACKLIGHT
        bool "Support for backlight control"
        depends on FB_NVIDIA
@@ -819,7 +844,7 @@ config FB_RIVA_I2C
          here.
 
 config FB_RIVA_DEBUG
-       bool "Lots of debug output from Riva(nVidia) driver"
+       bool "Lots of debug output"
        depends on FB_RIVA
        default n
        help
@@ -1431,8 +1456,11 @@ config FB_ARK
          and ICS 5342 RAMDAC.
 
 config FB_PM3
-       tristate "Permedia3 support"
-       depends on FB && PCI && BROKEN
+       tristate "Permedia3 support (EXPERIMENTAL)"
+       depends on FB && PCI && EXPERIMENTAL
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
        help
          This is the frame buffer device driver for the 3DLabs Permedia3
          chipset, used in Formac ProFormance III, 3DLabs Oxygen VX1 &
index 0b70567458fb266b4c09cf7236ff8952932cb2a3..bd8b05229500cd18521e99364d4bea5881fd0639 100644 (file)
@@ -87,6 +87,7 @@ obj-$(CONFIG_FB_G364)             += g364fb.o
 obj-$(CONFIG_FB_SA1100)           += sa1100fb.o
 obj-$(CONFIG_FB_HIT)              += hitfb.o
 obj-$(CONFIG_FB_EPSON1355)       += epson1355fb.o
+obj-$(CONFIG_FB_ATMEL)           += atmel_lcdfb.o
 obj-$(CONFIG_FB_PVR2)             += pvr2fb.o
 obj-$(CONFIG_FB_VOODOO1)          += sstfb.o
 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 (file)
index 0000000..e1d5bd0
--- /dev/null
@@ -0,0 +1,752 @@
+/*
+ *  Driver for AT91/AT32 LCD Controller
+ *
+ *  Copyright (C) 2007 Atmel Corporation
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/gpio.h>
+
+#include <video/atmel_lcdc.h>
+
+#define lcdc_readl(sinfo, reg)         __raw_readl((sinfo)->mmio+(reg))
+#define lcdc_writel(sinfo, reg, val)   __raw_writel((val), (sinfo)->mmio+(reg))
+
+/* configurable parameters */
+#define ATMEL_LCDC_CVAL_DEFAULT                0xc8
+#define ATMEL_LCDC_DMA_BURST_LEN       8
+
+#if defined(CONFIG_ARCH_AT91SAM9263)
+#define ATMEL_LCDC_FIFO_SIZE           2048
+#else
+#define ATMEL_LCDC_FIFO_SIZE           512
+#endif
+
+#if defined(CONFIG_ARCH_AT91)
+#define        ATMEL_LCDFB_FBINFO_DEFAULT      FBINFO_DEFAULT
+
+static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+                                       struct fb_var_screeninfo *var)
+{
+
+}
+#elif defined(CONFIG_AVR32)
+#define        ATMEL_LCDFB_FBINFO_DEFAULT      (FBINFO_DEFAULT \
+                                       | FBINFO_PARTIAL_PAN_OK \
+                                       | FBINFO_HWACCEL_XPAN \
+                                       | FBINFO_HWACCEL_YPAN)
+
+static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+                                    struct fb_var_screeninfo *var)
+{
+       u32 dma2dcfg;
+       u32 pixeloff;
+
+       pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f;
+
+       dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8;
+       dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
+       lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
+
+       /* Update configuration */
+       lcdc_writel(sinfo, ATMEL_LCDC_DMACON,
+                   lcdc_readl(sinfo, ATMEL_LCDC_DMACON)
+                   | ATMEL_LCDC_DMAUPDT);
+}
+#endif
+
+
+static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
+       .type           = FB_TYPE_PACKED_PIXELS,
+       .visual         = FB_VISUAL_TRUECOLOR,
+       .xpanstep       = 0,
+       .ypanstep       = 0,
+       .ywrapstep      = 0,
+       .accel          = FB_ACCEL_NONE,
+};
+
+
+static void atmel_lcdfb_update_dma(struct fb_info *info,
+                              struct fb_var_screeninfo *var)
+{
+       struct atmel_lcdfb_info *sinfo = info->par;
+       struct fb_fix_screeninfo *fix = &info->fix;
+       unsigned long dma_addr;
+
+       dma_addr = (fix->smem_start + var->yoffset * fix->line_length
+                   + var->xoffset * var->bits_per_pixel / 8);
+
+       dma_addr &= ~3UL;
+
+       /* Set framebuffer DMA base address and pixel offset */
+       lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
+
+       atmel_lcdfb_update_dma2d(sinfo, var);
+}
+
+static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
+{
+       struct fb_info *info = sinfo->info;
+
+       dma_free_writecombine(info->device, info->fix.smem_len,
+                               info->screen_base, info->fix.smem_start);
+}
+
+/**
+ *     atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory
+ *     @sinfo: the frame buffer to allocate memory for
+ */
+static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
+{
+       struct fb_info *info = sinfo->info;
+       struct fb_var_screeninfo *var = &info->var;
+
+       info->fix.smem_len = (var->xres_virtual * var->yres_virtual
+                           * ((var->bits_per_pixel + 7) / 8));
+
+       info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len,
+                                       (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL);
+
+       if (!info->screen_base) {
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+/**
+ *      atmel_lcdfb_check_var - Validates a var passed in.
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *     Checks to see if the hardware supports the state requested by
+ *     var passed in. This function does not alter the hardware
+ *     state!!!  This means the data stored in struct fb_info and
+ *     struct atmel_lcdfb_info do not change. This includes the var
+ *     inside of struct fb_info.  Do NOT change these. This function
+ *     can be called on its own if we intent to only test a mode and
+ *     not actually set it. The stuff in modedb.c is a example of
+ *     this. If the var passed in is slightly off by what the
+ *     hardware can support then we alter the var PASSED in to what
+ *     we can do. If the hardware doesn't support mode change a
+ *     -EINVAL will be returned by the upper layers. You don't need
+ *     to implement this function then. If you hardware doesn't
+ *     support changing the resolution then this function is not
+ *     needed. In this case the driver would just provide a var that
+ *     represents the static state the screen is in.
+ *
+ *     Returns negative errno on error, or zero on success.
+ */
+static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
+                            struct fb_info *info)
+{
+       struct device *dev = info->device;
+       struct atmel_lcdfb_info *sinfo = info->par;
+       unsigned long clk_value_khz;
+
+       clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+
+       dev_dbg(dev, "%s:\n", __func__);
+       dev_dbg(dev, "  resolution: %ux%u\n", var->xres, var->yres);
+       dev_dbg(dev, "  pixclk:     %lu KHz\n", PICOS2KHZ(var->pixclock));
+       dev_dbg(dev, "  bpp:        %u\n", var->bits_per_pixel);
+       dev_dbg(dev, "  clk:        %lu KHz\n", clk_value_khz);
+
+       if ((PICOS2KHZ(var->pixclock) * var->bits_per_pixel / 8) > clk_value_khz) {
+               dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock));
+               return -EINVAL;
+       }
+
+       /* Force same alignment for each line */
+       var->xres = (var->xres + 3) & ~3UL;
+       var->xres_virtual = (var->xres_virtual + 3) & ~3UL;
+
+       var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
+       var->transp.msb_right = 0;
+       var->transp.offset = var->transp.length = 0;
+       var->xoffset = var->yoffset = 0;
+
+       switch (var->bits_per_pixel) {
+       case 2:
+       case 4:
+       case 8:
+               var->red.offset = var->green.offset = var->blue.offset = 0;
+               var->red.length = var->green.length = var->blue.length
+                       = var->bits_per_pixel;
+               break;
+       case 15:
+       case 16:
+               var->red.offset = 0;
+               var->green.offset = 5;
+               var->blue.offset = 10;
+               var->red.length = var->green.length = var->blue.length = 5;
+               break;
+       case 24:
+       case 32:
+               var->red.offset = 0;
+               var->green.offset = 8;
+               var->blue.offset = 16;
+               var->red.length = var->green.length = var->blue.length = 8;
+               break;
+       default:
+               dev_err(dev, "color depth %d not supported\n",
+                                       var->bits_per_pixel);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ *      atmel_lcdfb_set_par - Alters the hardware state.
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *     Using the fb_var_screeninfo in fb_info we set the resolution
+ *     of the this particular framebuffer. This function alters the
+ *     par AND the fb_fix_screeninfo stored in fb_info. It doesn't
+ *     not alter var in fb_info since we are using that data. This
+ *     means we depend on the data in var inside fb_info to be
+ *     supported by the hardware.  atmel_lcdfb_check_var is always called
+ *     before atmel_lcdfb_set_par to ensure this.  Again if you can't
+ *     change the resolution you don't need this function.
+ *
+ */
+static int atmel_lcdfb_set_par(struct fb_info *info)
+{
+       struct atmel_lcdfb_info *sinfo = info->par;
+       unsigned long value;
+       unsigned long clk_value_khz;
+
+       dev_dbg(info->device, "%s:\n", __func__);
+       dev_dbg(info->device, "  * resolution: %ux%u (%ux%u virtual)\n",
+                info->var.xres, info->var.yres,
+                info->var.xres_virtual, info->var.yres_virtual);
+
+       /* Turn off the LCD controller and the DMA controller */
+       lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
+
+       lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
+
+       if (info->var.bits_per_pixel <= 8)
+               info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+       else
+               info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+       info->fix.line_length = info->var.xres_virtual * (info->var.bits_per_pixel / 8);
+
+       /* Re-initialize the DMA engine... */
+       dev_dbg(info->device, "  * update DMA engine\n");
+       atmel_lcdfb_update_dma(info, &info->var);
+
+       /* ...set frame size and burst length = 8 words (?) */
+       value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
+       value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
+       lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
+
+       /* Now, the LCDC core... */
+
+       /* Set pixel clock */
+       clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+
+       value = clk_value_khz / PICOS2KHZ(info->var.pixclock);
+
+       if (clk_value_khz % PICOS2KHZ(info->var.pixclock))
+               value++;
+
+       value = (value / 2) - 1;
+
+       if (value <= 0) {
+               dev_notice(info->device, "Bypassing pixel clock divider\n");
+               lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
+       } else
+               lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, value << ATMEL_LCDC_CLKVAL_OFFSET);
+
+       /* Initialize control register 2 */
+       value = sinfo->default_lcdcon2;
+
+       if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
+               value |= ATMEL_LCDC_INVLINE_INVERTED;
+       if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+               value |= ATMEL_LCDC_INVFRAME_INVERTED;
+
+       switch (info->var.bits_per_pixel) {
+               case 1: value |= ATMEL_LCDC_PIXELSIZE_1; break;
+               case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
+               case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
+               case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
+               case 15: /* fall through */
+               case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
+               case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
+               case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
+               default: BUG(); break;
+       }
+       dev_dbg(info->device, "  * LCDCON2 = %08lx\n", value);
+       lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
+
+       /* Vertical timing */
+       value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
+       value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
+       value |= info->var.lower_margin;
+       dev_dbg(info->device, "  * LCDTIM1 = %08lx\n", value);
+       lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
+
+       /* Horizontal timing */
+       value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
+       value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
+       value |= (info->var.left_margin - 1);
+       dev_dbg(info->device, "  * LCDTIM2 = %08lx\n", value);
+       lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
+
+       /* Display size */
+       value = (info->var.xres - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
+       value |= info->var.yres - 1;
+       lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
+
+       /* FIFO Threshold: Use formula from data sheet */
+       value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
+       lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
+
+       /* Toggle LCD_MODE every frame */
+       lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
+
+       /* Disable all interrupts */
+       lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
+
+       /* Set contrast */
+       value = ATMEL_LCDC_PS_DIV8 | ATMEL_LCDC_POL_POSITIVE | ATMEL_LCDC_ENA_PWMENABLE;
+       lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value);
+       lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
+       /* ...wait for DMA engine to become idle... */
+       while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
+               msleep(10);
+
+       dev_dbg(info->device, "  * re-enable DMA engine\n");
+       /* ...and enable it with updated configuration */
+       lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
+
+       dev_dbg(info->device, "  * re-enable LCDC core\n");
+       lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+               (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR);
+
+       dev_dbg(info->device, "  * DONE\n");
+
+       return 0;
+}
+
+static inline unsigned int chan_to_field(unsigned int chan, const struct fb_bitfield *bf)
+{
+       chan &= 0xffff;
+       chan >>= 16 - bf->length;
+       return chan << bf->offset;
+}
+
+/**
+ *     atmel_lcdfb_setcolreg - Optional function. Sets a color register.
+ *      @regno: Which register in the CLUT we are programming
+ *      @red: The red value which can be up to 16 bits wide
+ *     @green: The green value which can be up to 16 bits wide
+ *     @blue:  The blue value which can be up to 16 bits wide.
+ *     @transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ *
+ *     Set a single color register. The values supplied have a 16 bit
+ *     magnitude which needs to be scaled in this function for the hardware.
+ *     Things to take into consideration are how many color registers, if
+ *     any, are supported with the current color visual. With truecolor mode
+ *     no color palettes are supported. Here a psuedo palette is created
+ *     which we store the value in pseudo_palette in struct fb_info. For
+ *     pseudocolor mode we have a limited color palette. To deal with this
+ *     we can program what color is displayed for a particular pixel value.
+ *     DirectColor is similar in that we can program each color field. If
+ *     we have a static colormap we don't need to implement this function.
+ *
+ *     Returns negative errno on error, or zero on success. In an
+ *     ideal world, this would have been the case, but as it turns
+ *     out, the other drivers return 1 on failure, so that's what
+ *     we're going to do.
+ */
+static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
+                            unsigned int green, unsigned int blue,
+                            unsigned int transp, struct fb_info *info)
+{
+       struct atmel_lcdfb_info *sinfo = info->par;
+       unsigned int val;
+       u32 *pal;
+       int ret = 1;
+
+       if (info->var.grayscale)
+               red = green = blue = (19595 * red + 38470 * green
+                                     + 7471 * blue) >> 16;
+
+       switch (info->fix.visual) {
+       case FB_VISUAL_TRUECOLOR:
+               if (regno < 16) {
+                       pal = info->pseudo_palette;
+
+                       val  = chan_to_field(red, &info->var.red);
+                       val |= chan_to_field(green, &info->var.green);
+                       val |= chan_to_field(blue, &info->var.blue);
+
+                       pal[regno] = val;
+                       ret = 0;
+               }
+               break;
+
+       case FB_VISUAL_PSEUDOCOLOR:
+               if (regno < 256) {
+                       val  = ((red   >> 11) & 0x001f);
+                       val |= ((green >>  6) & 0x03e0);
+                       val |= ((blue  >>  1) & 0x7c00);
+
+                       /*
+                        * TODO: intensity bit. Maybe something like
+                        *   ~(red[10] ^ green[10] ^ blue[10]) & 1
+                        */
+
+                       lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
+                       ret = 0;
+               }
+               break;
+       }
+
+       return ret;
+}
+
+static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var,
+                              struct fb_info *info)
+{
+       dev_dbg(info->device, "%s\n", __func__);
+
+       atmel_lcdfb_update_dma(info, var);
+
+       return 0;
+}
+
+static struct fb_ops atmel_lcdfb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_check_var   = atmel_lcdfb_check_var,
+       .fb_set_par     = atmel_lcdfb_set_par,
+       .fb_setcolreg   = atmel_lcdfb_setcolreg,
+       .fb_pan_display = atmel_lcdfb_pan_display,
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = cfb_imageblit,
+};
+
+static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
+{
+       struct fb_info *info = dev_id;
+       struct atmel_lcdfb_info *sinfo = info->par;
+       u32 status;
+
+       status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
+       lcdc_writel(sinfo, ATMEL_LCDC_IDR, status);
+       return IRQ_HANDLED;
+}
+
+static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo)
+{
+       struct fb_info *info = sinfo->info;
+       int ret = 0;
+
+       memset_io(info->screen_base, 0, info->fix.smem_len);
+       info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW;
+
+       dev_info(info->device,
+              "%luKiB frame buffer at %08lx (mapped at %p)\n",
+              (unsigned long)info->fix.smem_len / 1024,
+              (unsigned long)info->fix.smem_start,
+              info->screen_base);
+
+       /* Allocate colormap */
+       ret = fb_alloc_cmap(&info->cmap, 256, 0);
+       if (ret < 0)
+               dev_err(info->device, "Alloc color map failed\n");
+
+       return ret;
+}
+
+static void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo)
+{
+       if (sinfo->bus_clk)
+               clk_enable(sinfo->bus_clk);
+       clk_enable(sinfo->lcdc_clk);
+}
+
+static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo)
+{
+       if (sinfo->bus_clk)
+               clk_disable(sinfo->bus_clk);
+       clk_disable(sinfo->lcdc_clk);
+}
+
+
+static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct fb_info *info;
+       struct atmel_lcdfb_info *sinfo;
+       struct atmel_lcdfb_info *pdata_sinfo;
+       struct resource *regs = NULL;
+       struct resource *map = NULL;
+       int ret;
+
+       dev_dbg(dev, "%s BEGIN\n", __func__);
+
+       ret = -ENOMEM;
+       info = framebuffer_alloc(sizeof(struct atmel_lcdfb_info), dev);
+       if (!info) {
+               dev_err(dev, "cannot allocate memory\n");
+               goto out;
+       }
+
+       sinfo = info->par;
+
+       if (dev->platform_data) {
+               pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data;
+               sinfo->default_bpp = pdata_sinfo->default_bpp;
+               sinfo->default_dmacon = pdata_sinfo->default_dmacon;
+               sinfo->default_lcdcon2 = pdata_sinfo->default_lcdcon2;
+               sinfo->default_monspecs = pdata_sinfo->default_monspecs;
+               sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
+               sinfo->guard_time = pdata_sinfo->guard_time;
+       } else {
+               dev_err(dev, "cannot get default configuration\n");
+               goto free_info;
+       }
+       sinfo->info = info;
+       sinfo->pdev = pdev;
+
+       strcpy(info->fix.id, sinfo->pdev->name);
+       info->flags = ATMEL_LCDFB_FBINFO_DEFAULT;
+       info->pseudo_palette = sinfo->pseudo_palette;
+       info->fbops = &atmel_lcdfb_ops;
+
+       memcpy(&info->monspecs, sinfo->default_monspecs, sizeof(info->monspecs));
+       info->fix = atmel_lcdfb_fix;
+
+       /* Enable LCDC Clocks */
+       if (cpu_is_at91sam9261() || cpu_is_at32ap7000()) {
+               sinfo->bus_clk = clk_get(dev, "hck1");
+               if (IS_ERR(sinfo->bus_clk)) {
+                       ret = PTR_ERR(sinfo->bus_clk);
+                       goto free_info;
+               }
+       }
+       sinfo->lcdc_clk = clk_get(dev, "lcdc_clk");
+       if (IS_ERR(sinfo->lcdc_clk)) {
+               ret = PTR_ERR(sinfo->lcdc_clk);
+               goto put_bus_clk;
+       }
+       atmel_lcdfb_start_clock(sinfo);
+
+       ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb,
+                       info->monspecs.modedb_len, info->monspecs.modedb,
+                       sinfo->default_bpp);
+       if (!ret) {
+               dev_err(dev, "no suitable video mode found\n");
+               goto stop_clk;
+       }
+
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!regs) {
+               dev_err(dev, "resources unusable\n");
+               ret = -ENXIO;
+               goto stop_clk;
+       }
+
+       sinfo->irq_base = platform_get_irq(pdev, 0);
+       if (sinfo->irq_base < 0) {
+               dev_err(dev, "unable to get irq\n");
+               ret = sinfo->irq_base;
+               goto stop_clk;
+       }
+
+       /* Initialize video memory */
+       map = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (map) {
+               /* use a pre-allocated memory buffer */
+               info->fix.smem_start = map->start;
+               info->fix.smem_len = map->end - map->start + 1;
+               if (!request_mem_region(info->fix.smem_start,
+                                       info->fix.smem_len, pdev->name)) {
+                       ret = -EBUSY;
+                       goto stop_clk;
+               }
+
+               info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+               if (!info->screen_base)
+                       goto release_intmem;
+       } else {
+               /* alocate memory buffer */
+               ret = atmel_lcdfb_alloc_video_memory(sinfo);
+               if (ret < 0) {
+                       dev_err(dev, "cannot allocate framebuffer: %d\n", ret);
+                       goto stop_clk;
+               }
+       }
+
+       /* LCDC registers */
+       info->fix.mmio_start = regs->start;
+       info->fix.mmio_len = regs->end - regs->start + 1;
+
+       if (!request_mem_region(info->fix.mmio_start,
+                               info->fix.mmio_len, pdev->name)) {
+               ret = -EBUSY;
+               goto free_fb;
+       }
+
+       sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len);
+       if (!sinfo->mmio) {
+               dev_err(dev, "cannot map LCDC registers\n");
+               goto release_mem;
+       }
+
+       /* interrupt */
+       ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
+       if (ret) {
+               dev_err(dev, "request_irq failed: %d\n", ret);
+               goto unmap_mmio;
+       }
+
+       ret = atmel_lcdfb_init_fbinfo(sinfo);
+       if (ret < 0) {
+               dev_err(dev, "init fbinfo failed: %d\n", ret);
+               goto unregister_irqs;
+       }
+
+       /*
+        * This makes sure that our colour bitfield
+        * descriptors are correctly initialised.
+        */
+       atmel_lcdfb_check_var(&info->var, info);
+
+       ret = fb_set_var(info, &info->var);
+       if (ret) {
+               dev_warn(dev, "unable to set display parameters\n");
+               goto free_cmap;
+       }
+
+       dev_set_drvdata(dev, info);
+
+       /*
+        * Tell the world that we're ready to go
+        */
+       ret = register_framebuffer(info);
+       if (ret < 0) {
+               dev_err(dev, "failed to register framebuffer device: %d\n", ret);
+               goto free_cmap;
+       }
+
+       /* Power up the LCDC screen */
+       if (sinfo->atmel_lcdfb_power_control)
+               sinfo->atmel_lcdfb_power_control(1);
+
+       dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %lu\n",
+                      info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base);
+
+       return 0;
+
+
+free_cmap:
+       fb_dealloc_cmap(&info->cmap);
+unregister_irqs:
+       free_irq(sinfo->irq_base, info);
+unmap_mmio:
+       iounmap(sinfo->mmio);
+release_mem:
+       release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+free_fb:
+       if (map)
+               iounmap(info->screen_base);
+       else
+               atmel_lcdfb_free_video_memory(sinfo);
+
+release_intmem:
+       if (map)
+               release_mem_region(info->fix.smem_start, info->fix.smem_len);
+stop_clk:
+       atmel_lcdfb_stop_clock(sinfo);
+       clk_put(sinfo->lcdc_clk);
+put_bus_clk:
+       if (sinfo->bus_clk)
+               clk_put(sinfo->bus_clk);
+free_info:
+       framebuffer_release(info);
+out:
+       dev_dbg(dev, "%s FAILED\n", __func__);
+       return ret;
+}
+
+static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct fb_info *info = dev_get_drvdata(dev);
+       struct atmel_lcdfb_info *sinfo = info->par;
+
+       if (!sinfo)
+               return 0;
+
+       if (sinfo->atmel_lcdfb_power_control)
+               sinfo->atmel_lcdfb_power_control(0);
+       unregister_framebuffer(info);
+       atmel_lcdfb_stop_clock(sinfo);
+       clk_put(sinfo->lcdc_clk);
+       if (sinfo->bus_clk)
+               clk_put(sinfo->bus_clk);
+       fb_dealloc_cmap(&info->cmap);
+       free_irq(sinfo->irq_base, info);
+       iounmap(sinfo->mmio);
+       release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+       if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) {
+               iounmap(info->screen_base);
+               release_mem_region(info->fix.smem_start, info->fix.smem_len);
+       } else {
+               atmel_lcdfb_free_video_memory(sinfo);
+       }
+
+       dev_set_drvdata(dev, NULL);
+       framebuffer_release(info);
+
+       return 0;
+}
+
+static struct platform_driver atmel_lcdfb_driver = {
+       .remove         = __exit_p(atmel_lcdfb_remove),
+       .driver         = {
+               .name   = "atmel_lcdfb",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init atmel_lcdfb_init(void)
+{
+       return platform_driver_probe(&atmel_lcdfb_driver, atmel_lcdfb_probe);
+}
+
+static void __exit atmel_lcdfb_exit(void)
+{
+       platform_driver_unregister(&atmel_lcdfb_driver);
+}
+
+module_init(atmel_lcdfb_init);
+module_exit(atmel_lcdfb_exit);
+
+MODULE_DESCRIPTION("AT91/AT32 LCD Controller framebuffer driver");
+MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@rfo.atmel.com>");
+MODULE_LICENSE("GPL");
index aa3935df852ad6f9f04f1fce4c53091c8f0f8511..63b85bf81a651d808ab486ebb37b2bc3703c423c 100644 (file)
@@ -19,13 +19,6 @@ config VGA_CONSOLE
 
          Say Y.
 
-#      if [ "$CONFIG_PCI" = "y" -a "$CONFIG_VGA_CONSOLE" = "y" ]; then
-#         bool '   Allow VGA on any bus?' CONFIG_VGA_HOSE
-#         if [ "$CONFIG_VGA_HOSE" = "y" ]; then
-#            define_bool CONFIG_DUMMY_CONSOLE y
-#         fi
-#      fi
-
 config VGACON_SOFT_SCROLLBACK
        bool "Enable Scrollback Buffer in System RAM"
        depends on VGA_CONSOLE
index c627955aa124797cd41019816744d99c828fbca1..aff11bbf59a74c3f309e8dd0848b5c55e307afa8 100644 (file)
@@ -149,7 +149,9 @@ static void nvGetClocks(struct nvidia_par *par, unsigned int *MClk,
                pll = NV_RD32(par->PMC, 0x4024);
                M = pll & 0xFF;
                N = (pll >> 8) & 0xFF;
-               if (((par->Chipset & 0xfff0) == 0x0290) || ((par->Chipset & 0xfff0) == 0x0390) || ((par->Chipset & 0xfff0) == 0x02E0)) {
+               if (((par->Chipset & 0xfff0) == 0x0290) ||
+                       ((par->Chipset & 0xfff0) == 0x0390) ||
+                       ((par->Chipset & 0xfff0) == 0x02E0)) {
                        MB = 1;
                        NB = 1;
                } else {
index f85edf084da3e0fc3f54c34a7333a637bfabbe39..41f63658572fa7f7ea59b8e65a69950cdb522b78 100644 (file)
@@ -37,7 +37,6 @@
 #include "nv_proto.h"
 #include "nv_dma.h"
 
-#undef CONFIG_FB_NVIDIA_DEBUG
 #ifdef CONFIG_FB_NVIDIA_DEBUG
 #define NVTRACE          printk
 #else
index 1ac5264bb2c150cdfeee12b5c43203aab6bcc7c1..ab5e66890e4e7f3f60a04e0cfda7acd841c828f8 100644 (file)
@@ -204,17 +204,6 @@ static inline void WAIT_FIFO(struct pm2fb_par* p, u32 a)
 }
 #endif
 
-static void wait_pm2(struct pm2fb_par* par) {
-
-       WAIT_FIFO(par, 1);
-       pm2_WR(par, PM2R_SYNC, 0);
-       mb();
-       do {
-               while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0);
-               rmb();
-       } while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC));
-}
-
 /*
  * partial products for the supported horizontal resolutions.
  */
@@ -1050,13 +1039,30 @@ static int pm2fb_blank(int blank_mode, struct fb_info *info)
        return 0;
 }
 
+static int pm2fb_sync(struct fb_info *info)
+{
+       struct pm2fb_par *par = info->par;
+
+       WAIT_FIFO(par, 1);
+       pm2_WR(par, PM2R_SYNC, 0);
+       mb();
+       do {
+               while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0)
+                       udelay(10);
+               rmb();
+       } while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC));
+
+       return 0;
+}
+
 /*
  * block operation. copy=0: rectangle fill, copy=1: rectangle copy.
  */
-static void pm2fb_block_op(struct pm2fb_par* par, int copy,
+static void pm2fb_block_op(struct fb_info* info, int copy,
                                s32 xsrc, s32 ysrc,
                                s32 x, s32 y, s32 w, s32 h,
                                u32 color) {
+       struct pm2fb_par *par = info->par;
 
        if (!w || !h)
                return;
@@ -1076,13 +1082,11 @@ static void pm2fb_block_op(struct pm2fb_par* par, int copy,
                                (x<xsrc ? PM2F_INCREASE_X : 0) |
                                (y<ysrc ? PM2F_INCREASE_Y : 0) |
                                (copy ? 0 : PM2F_RENDER_FASTFILL));
-       wait_pm2(par);
 }
 
 static void pm2fb_fillrect (struct fb_info *info,
                                const struct fb_fillrect *region)
 {
-       struct pm2fb_par *par = info->par;
        struct fb_fillrect modded;
        int vxres, vyres;
        u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
@@ -1116,7 +1120,7 @@ static void pm2fb_fillrect (struct fb_info *info,
                color |= color << 16;
 
        if(info->var.bits_per_pixel != 24)
-               pm2fb_block_op(par, 0, 0, 0,
+               pm2fb_block_op(info, 0, 0, 0,
                                modded.dx, modded.dy,
                                modded.width, modded.height, color);
        else
@@ -1126,7 +1130,6 @@ static void pm2fb_fillrect (struct fb_info *info,
 static void pm2fb_copyarea(struct fb_info *info,
                                const struct fb_copyarea *area)
 {
-       struct pm2fb_par *par = info->par;
        struct fb_copyarea modded;
        u32 vxres, vyres;
 
@@ -1156,7 +1159,7 @@ static void pm2fb_copyarea(struct fb_info *info,
        if(modded.dy + modded.height > vyres)
                modded.height = vyres - modded.dy;
 
-       pm2fb_block_op(par, 1, modded.sx, modded.sy,
+       pm2fb_block_op(info, 1, modded.sx, modded.sy,
                        modded.dx, modded.dy,
                        modded.width, modded.height, 0);
 }
@@ -1177,6 +1180,7 @@ static struct fb_ops pm2fb_ops = {
        .fb_fillrect    = pm2fb_fillrect,
        .fb_copyarea    = pm2fb_copyarea,
        .fb_imageblit   = cfb_imageblit,
+       .fb_sync        = pm2fb_sync,
 };
 
 /*
index bd787e80177d332c29357ab86420337de9a2585e..6c4dfcb0feb9b3008431b6c4be54da6d202297fb 100644 (file)
@@ -1,55 +1,25 @@
 /*
  *  linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device
- *  
- *  Copyright (C) 2001 Romain Dolbeau <dolbeau@irisa.fr>
+ *
+ *  Copyright (C) 2001 Romain Dolbeau <romain@dolbeau.org>.
+ *
+ *  Ported to 2.6 kernel on 1 May 2007 by Krzysztof Helt <krzysztof.h1@wp.pl>
+ *     based on pm2fb.c
+ *
  *  Based on code written by:
- *           Sven Luther, <luther@dpt-info.u-strasbg.fr>
- *           Alan Hourihane, <alanh@fairlite.demon.co.uk>
- *           Russell King, <rmk@arm.linux.org.uk>
+ *        Sven Luther, <luther@dpt-info.u-strasbg.fr>
+ *        Alan Hourihane, <alanh@fairlite.demon.co.uk>
+ *        Russell King, <rmk@arm.linux.org.uk>
  *  Based on linux/drivers/video/skeletonfb.c:
  *     Copyright (C) 1997 Geert Uytterhoeven
  *  Based on linux/driver/video/pm2fb.c:
- *      Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
- *      Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
+ *     Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
+ *     Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
  *
  *  This file is subject to the terms and conditions of the GNU General Public
  *  License. See the file COPYING in the main directory of this archive for
  *  more details.
  *
- *  $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $
- *
- *  CHANGELOG:
- *  Mon Feb 11 10:35:48 MET 2002, v 1.4.11B: Cosmetic update.
- *  Wed Jan 23 14:16:59 MET 2002, v 1.4.11: Preliminary 2.5.x support, patch for 2.5.2.
- *  Wed Nov 28 11:08:29 MET 2001, v 1.4.10: potential bug fix for SDRAM-based board, patch for 2.4.16.
- *  Thu Sep 20 10:24:42 MET DST 2001, v 1.4.9: sync bug fix, preliminary flatpanel support, better timings.
- *  Tue Aug 28 10:13:01 MET DST 2001, v 1.4.8: memory timings check, minor bug fixes.
- *  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.
- *  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.
- *  Wed Jun 20 11:13:08 MET DST 2001, v 1.4.5: Fixed missing blinking cursor in 8bpp, code cleaning, memory erase IOCTL.
- *  Mon Jun 18 16:00:27 CEST 2001, v 1.4.4: Depth 12 (RGBA 4444) support, code cleaning.
- *  Fri Jun 15 13:53:01 CEST 2001, v 1.4.3: Removed warnings, depth 15 support, add 'depth' option.
- *  Thu Jun 14 10:13:52 MET DST 2001, v 1.4.2: Fixed depth switching bug, preliminary 15bpp (RGB5551) support.
- *  Thu Apr 12 11:16:45 MET DST 2001, v 1.4.1B: Doc updates.
- *  Fri Apr  6 11:12:53 MET DST 2001, v 1.4.1: Configure.help, minor cleanup
- *  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).
- *  Thu Mar 15 15:30:31 MET 2001, v 1.3.2: Fixed mirroring bug on little-endian.
- *  Wed Mar 14 21:25:54 CET 2001, v 1.3.1: Fixed bug in BlockMove (_bmov).
- *  Tue Mar 13 10:53:19 MET 2001, v 1.3.0: Character drawing hardware support (in all width between 1 and 16), fixes.
- *  Thu Mar  8 10:20:16 MET 2001, v 1.2.2: Better J2000 support, "font:" option.
- *  Tue Mar  6 21:25:04 CET 2001, v 1.2.1: Better acceleration support.
- *  Mon Mar  5 21:54:17 CET 2001, v 1.2.0: Partial acceleration support (clear & bmove)
- *  Mon Mar  5 12:52:15 CET 2001, v 1.1.3: Big pan_display fix.
- *  Sun Mar  4 22:21:50 CET 2001, v 1.1.2: (numerous) bug fixes.
- *  Fri Mar  2 15:54:07 CET 2001, v 1.1.1: Might have Appian J2000 support, resource mangement in 2.4
- *  Wed Feb 28 18:21:35 CET 2001, v 1.1.0: Might have multiple boards support (added, but not yest tested)
- *  Tue Feb 27 17:31:12 CET 2001, v 1.0.6: fixes boot-time mode select, add more default mode
- *  Tue Feb 27 14:01:36 CET 2001, v 1.0.5: fixes (1.0.4 was broken for 2.2), cleaning up
- *  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
- *  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
- *  Wed Feb 21 22:09:30 CET 2001, v 1.0.2: Code cleaning for future multiboard support, better OF support, bugs fix
- *  Wed Feb 21 19:58:56 CET 2001, v 1.0.1: OpenFirmware support, fixed memory detection, better debug support, code cleaning
- *  Wed Feb 21 14:47:06 CET 2001, v 1.0.0: First working version
  */
 
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <linux/vmalloc.h>
 #include <linux/delay.h>
-#include <linux/interrupt.h>
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/ctype.h>
-
-#include <video/fbcon.h>
-#include <video/fbcon-mfb.h>
-#include <video/fbcon-cfb2.h>
-#include <video/fbcon-cfb4.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb24.h>
-#include <video/fbcon-cfb32.h>
-#include <video/pm3fb.h>
 
-#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <video/pm3fb.h>
 
-#ifdef CONFIG_FB_OF
-#include <asm/prom.h>
+#if !defined(CONFIG_PCI)
+#error "Only generic PCI cards supported."
 #endif
 
-/* ************************************* */
-/* ***** The various "global" data ***** */
-/* ************************************* */
-
-/* those will need a rework for multiple board support */
-/* Driver name */
-static const char permedia3_name[16] = "Permedia3";
-
-/* the fb_par struct, mandatory */
-struct pm3fb_par {
-       u32 pixclock;           /* pixclock in KHz */
-
-       u32 width;              /* width of virtual screen */
-       u32 height;             /* height of virtual screen */
-
-       u32 hsstart;            /* horiz. sync start */
-       u32 hsend;              /* horiz. sync end */
-       u32 hbend;              /* horiz. blank end (also gate end) */
-       u32 htotal;             /* total width (w/ sync & blank) */
-
-       u32 vsstart;            /* vert. sync start */
-       u32 vsend;              /* vert. sync end */
-       u32 vbend;              /* vert. blank end */
-       u32 vtotal;             /* total height (w/ sync & blank) */
-
-       u32 stride;             /* screen stride */
-       u32 base;               /* screen base (xoffset+yoffset) in 128 bits unit */
-       /* NOTE : unlike other pm3 stuff above, stored *after* shiftbpp. don't ask */
-       u32 depth;              /* screen depth (8, 12, 15, 16 or 32) */
-       u32 video;              /* video control (hsync,vsync) */
-};
-
-/* memory timings */
-struct pm3fb_timings
-{
-       unsigned long caps;
-       unsigned long timings;
-       unsigned long control;
-       unsigned long refresh;
-       unsigned long powerdown;
-};
-typedef enum pm3fb_timing_result { pm3fb_timing_ok, pm3fb_timing_problem, pm3fb_timing_retry } pm3fb_timing_result;
-#define PM3FB_UNKNOWN_TIMING_VALUE ((unsigned long)-1)
-#define PM3FB_UNKNOWN_TIMINGS { PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE }
-
-/* the fb_info struct, mandatory */
-struct pm3fb_info {
-       struct fb_info_gen gen;
-       unsigned long board_num; /* internal board number */
-       unsigned long use_current;
-       struct pm3fb_par *current_par;
-       struct pci_dev *dev;    /* PCI device */
-       unsigned long board_type; /* index in the cardbase */
-       unsigned char *fb_base; /* framebuffer memory base */
-       u32 fb_size;            /* framebuffer memory size */
-       unsigned char *p_fb;    /* physical address of frame buffer */
-       unsigned char *v_fb;    /* virtual address of frame buffer */
-       unsigned char *pIOBase; /* physical address of registers region, must be rg_base or rg_base+PM2_REGS_SIZE depending on the host endianness */
-       unsigned char *vIOBase; /* address of registers after ioremap() */
-       struct {
-               u8 transp;
-               u8 red;
-               u8 green;
-               u8 blue;
-       } palette[256];
-       union {
-#ifdef FBCON_HAS_CFB16
-               u16 cmap12[16]; /* RGBA 4444 */
-               u16 cmap15[16]; /* RGBA 5551 */
-               u16 cmap16[16]; /* RGBA 5650 */
-#endif
-#ifdef FBCON_HAS_CFB32
-               u32 cmap32[16];
+#undef PM3FB_MASTER_DEBUG
+#ifdef PM3FB_MASTER_DEBUG
+#define DPRINTK(a,b...)        printk(KERN_DEBUG "pm3fb: %s: " a, __FUNCTION__ , ## b)
+#else
+#define DPRINTK(a,b...)
 #endif
-       } cmap;
-       struct pm3fb_timings memt;
-};
-
-/* regular resolution database*/
-static struct {
-       char name[16];
-       struct pm3fb_par user_mode;
-} mode_base[] __initdata = {
-       {
-               "default-800x600", {
-       49500, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625,
-                           800, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}}, {
-               "1024x768-74", {
-       78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38,
-                           806, 1024, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}}, {
-               "1024x768-74-32", {
-                       78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38,
-                       806, 1024, 0, 32,
-                       PM3VideoControl_ENABLE |
-                       PM3VideoControl_HSYNC_ACTIVE_HIGH
-                       |
-                       PM3VideoControl_VSYNC_ACTIVE_HIGH
-                       | PM3VideoControl_PIXELSIZE_32BIT}},
-/* Generated mode : "1600x1024", for the SGI 1600SW flat panel*/
-       {
-               "SGI1600SW", {
-                       108000, 1600, 1024, 16, 56, 104, 1704, 3, 6, 32,
-                       1056, 1600, 0, 8,
-                       PM3VideoControl_ENABLE|
-                       PM3VideoControl_HSYNC_ACTIVE_LOW|PM3VideoControl_VSYNC_ACTIVE_LOW|
-                       PM3VideoControl_PIXELSIZE_32BIT}}, 
-/* ##### auto-generated mode, by fbtimings2pm3 */
-/* Generated mode : "640x480-60" */
-       {
-               "640x480-60", {
-       25174, 640, 480, 16, 112, 160, 800, 10, 12, 45,
-                           525, 640, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "640x480-72" */
-       {
-               "640x480-72", {
-       31199, 640, 480, 24, 64, 192, 832, 9, 12, 40, 520,
-                           640, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "640x480-75" */
-       {
-               "640x480-75", {
-       31499, 640, 480, 16, 80, 200, 840, 1, 4, 20, 500,
-                           640, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "640x480-90" */
-       {
-               "640x480-90", {
-       39909, 640, 480, 32, 72, 192, 832, 25, 39, 53, 533,
-                           640, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "640x480-100" */
-       {
-               "640x480-100", {
-       44899, 640, 480, 32, 160, 208, 848, 22, 34, 51,
-                           531, 640, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-48-lace" */
-/* INTERLACED NOT SUPPORTED
-  {"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}}, 
-   INTERLACED NOT SUPPORTED */
-/* Generated mode : "800x600-56" */
-       {
-               "800x600-56", {
-       35999, 800, 600, 24, 96, 224, 1024, 1, 3, 25, 625,
-                           800, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-60" */
-       {
-               "800x600-60", {
-       40000, 800, 600, 40, 168, 256, 1056, 1, 5, 28, 628,
-                           800, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-70" */
-       {
-               "800x600-70", {
-       44899, 800, 600, 24, 168, 208, 1008, 9, 21, 36,
-                           636, 800, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-72" */
-       {
-               "800x600-72", {
-       50000, 800, 600, 56, 176, 240, 1040, 37, 43, 66,
-                           666, 800, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-75" */
-       {
-               "800x600-75", {
-       49497, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625,
-                           800, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-90" */
-       {
-               "800x600-90", {
-       56637, 800, 600, 8, 72, 192, 992, 8, 19, 35, 635,
-                           800, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-100", from /etc/fb.modes */
-/* DISABLED, hsstart == 0
-       {
-               "800x600-100", {
-       67499, 800, 600, 0, 64, 280, 1080, 7, 11, 25, 625,
-                           800, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-*/
-/* Generated mode : "800x600-100", from ??? */
-       {
-               "800x600-100", {
-                       69650, 800, 600, 64, 128, 288, 1088, 4, 10, 40, 640, 800, 0, 8,
-                       PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW|
-                       PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-43-lace" */
-/* INTERLACED NOT SUPPORTED
-  {"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}}, 
-   INTERLACED NOT SUPPORTED */
-/* Generated mode : "1024x768-60" */
-       {
-               "1024x768-60", {
-       64998, 1024, 768, 24, 160, 320, 1344, 3, 9, 38,
-                           806, 1024, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-70" */
-       {
-               "1024x768-70", {
-       74996, 1024, 768, 24, 160, 304, 1328, 3, 9, 38,
-                           806, 1024, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-72" */
-       {
-               "1024x768-72", {
-       74996, 10224, 768, 24, 160, 264, 10488, 3, 9, 38,
-                           806, 10224, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-75" */
-       {
-               "1024x768-75", {
-       78746, 1024, 768, 16, 112, 288, 1312, 1, 4, 32,
-                           800, 1024, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-90" */
-       {
-               "1024x768-90", {
-       100000, 1024, 768, 0, 96, 288, 1312, 21, 36, 77,
-                           845, 1024, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-100", from /etc/fb.modes */
-/* DISABLED, vsstart == 0
-       {
-               "1024x768-100", {
-       109998, 1024, 768, 0, 88, 368, 1392, 0, 8, 24, 792,
-                           1024, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-*/
-/* Generated mode : "1024x768-100", from ??? */
-       {
-               "1024x768-100", {
-                       115500, 1024, 768, 32, 224, 416, 1440, 3, 13, 34, 802, 1024, 0, 8,
-                       PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW|
-                       PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1152x864-43-lace" */
-/* INTERLACED NOT SUPPORTED
-  {"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}}, 
-   INTERLACED NOT SUPPORTED */
-/* Generated mode : "1152x864-47-lace" */
-/* INTERLACED NOT SUPPORTED
-  {"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}}, 
-   INTERLACED NOT SUPPORTED */
-/* Generated mode : "1152x864-60" */
-       {
-               "1152x864-60", {
-       80000, 1152, 864, 64, 176, 304, 1456, 6, 11, 52,
-                           916, 1152, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1152x864-70" */
-       {
-               "1152x864-70", {
-       100000, 1152, 864, 40, 192, 360, 1512, 13, 24, 81,
-                           945, 1152, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1152x864-75" */
-       {
-               "1152x864-75", {
-       109998, 1152, 864, 24, 168, 312, 1464, 45, 53, 138,
-                           1002, 1152, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1152x864-80" */
-       {
-               "1152x864-80", {
-       109998, 1152, 864, 16, 128, 288, 1440, 30, 37, 94,
-                           958, 1152, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1280x1024-43-lace" */
-/* INTERLACED NOT SUPPORTED
-  {"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}}, 
-   INTERLACED NOT SUPPORTED */
-/* Generated mode : "1280x1024-47-lace" */
-/* INTERLACED NOT SUPPORTED
-  {"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}}, 
-   INTERLACED NOT SUPPORTED */
-/* Generated mode : "1280x1024-60" */
-       {
-               "1280x1024-60", {
-       107991, 1280, 1024, 48, 160, 408, 1688, 1, 4, 42,
-                           1066, 1280, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1280x1024-70" */
-       {
-               "1280x1024-70", {
-       125992, 1280, 1024, 80, 192, 408, 1688, 1, 6, 42,
-                           1066, 1280, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1280x1024-74" */
-       {
-               "1280x1024-74", {
-       134989, 1280, 1024, 32, 176, 432, 1712, 0, 30, 40,
-                           1064, 1280, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1280x1024-75" */
-       {
-               "1280x1024-75", {
-       134989, 1280, 1024, 16, 160, 408, 1688, 1, 4, 42,
-                           1066, 1280, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_HIGH
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_HIGH
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1600x1200-60" */
-       {
-               "1600x1200-60", {
-       155981, 1600, 1200, 32, 192, 448, 2048, 10, 18, 70,
-                           1270, 1600, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1600x1200-66" */
-       {
-               "1600x1200-66", {
-       171998, 1600, 1200, 40, 176, 480, 2080, 3, 6, 53,
-                           1253, 1600, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1600x1200-76" */
-       {
-               "1600x1200-76", {
-       197980, 1600, 1200, 40, 176, 480, 2080, 3, 8, 50,
-                           1250, 1600, 0, 8,
-                           PM3VideoControl_ENABLE |
-                           PM3VideoControl_HSYNC_ACTIVE_LOW
-                           |
-                           PM3VideoControl_VSYNC_ACTIVE_LOW
-                           | PM3VideoControl_PIXELSIZE_8BIT}},
-/* ##### end of auto-generated mode */
-       {
-       "\0",}
-};
 
-/* more mandatory stuff (see skeletonfb.c + framebuffer driver HOWTO */
-static struct pm3fb_info fb_info[PM3_MAX_BOARD];
-static struct pm3fb_par current_par[PM3_MAX_BOARD];
-static int current_par_valid[PM3_MAX_BOARD];
-/* to allow explicit filtering of board */
-short bus[PM3_MAX_BOARD];
-short slot[PM3_MAX_BOARD];
-short func[PM3_MAX_BOARD];
-short disable[PM3_MAX_BOARD];
-short noaccel[PM3_MAX_BOARD];
-char fontn[PM3_MAX_BOARD][PM3_FONTNAME_SIZE];
-short depth[PM3_MAX_BOARD];
-short flatpanel[PM3_MAX_BOARD];
-static struct display disp[PM3_MAX_BOARD];
-static char g_options[PM3_OPTIONS_SIZE] __initdata = "pm3fb,dummy";
-short printtimings = 0;
-short forcesize[PM3_MAX_BOARD];
-
-/* ********************* */
-/* ***** prototype ***** */
-/* ********************* */
-/* card-specific */
-static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info);
-/* permedia3-specific */
-static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info);
-static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info);
-static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info);
-static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info,
-                                       unsigned long r);
-static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock,        /* In kHz units */
-                                         unsigned long refclock,       /* In kHz units */
-                                         unsigned char *prescale,      /* ClkPreScale */
-                                         unsigned char *feedback,      /* ClkFeedBackScale */
-                                         unsigned char *postscale
-                                         /* ClkPostScale */ );
-static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc);
-static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b);
-static void pm3fb_common_init(struct pm3fb_info *l_fb_info);
-static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info,
-                         unsigned long depth, int v);
-static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info,
-                           unsigned long depth, int v);
-static void pm3fb_mapIO(struct pm3fb_info *l_fb_info);
-static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info);
-#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2)
-static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info);
-#endif
-static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info);
-static void pm3fb_write_mode(struct pm3fb_info *l_fb_info);
-static void pm3fb_read_mode(struct pm3fb_info *l_fb_info,
-                           struct pm3fb_par *curpar);
-static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info);
-/* accelerated permedia3-specific */
-#ifdef PM3FB_USE_ACCEL
-static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info);
-static void pm3fb_init_engine(struct pm3fb_info *l_fb_info);
-#ifdef FBCON_HAS_CFB32
-static void pm3fb_cfb32_clear(struct vc_data *conp,
-                             struct display *p,
-                             int sy, int sx, int height, int width);
-static void pm3fb_cfb32_clear_margins(struct vc_data *conp,
-                                     struct display *p, int bottom_only);
-#endif /* FBCON_HAS_CFB32 */
-#ifdef FBCON_HAS_CFB16
-static void pm3fb_cfb16_clear(struct vc_data *conp,
-                             struct display *p,
-                             int sy, int sx, int height, int width);
-static void pm3fb_cfb16_clear_margins(struct vc_data *conp,
-                                     struct display *p, int bottom_only);
-#endif /* FBCON_HAS_CFB16 */
-#ifdef FBCON_HAS_CFB8
-static void pm3fb_cfb8_clear(struct vc_data *conp,
-                            struct display *p,
-                            int sy, int sx, int height, int width);
-static void pm3fb_cfb8_clear_margins(struct vc_data *conp,
-                                    struct display *p, int bottom_only);
-#endif /* FBCON_HAS_CFB8 */
-#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
-static void pm3fb_cfbX_bmove(struct display *p,
-                            int sy, int sx,
-                            int dy, int dx, int height, int width);
-static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p,
-                           int c, int yy, int xx);
-static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p,
-                            const unsigned short *s, int count, int yy,
-                            int xx);
-static void pm3fb_cfbX_revc(struct display *p, int xx, int yy);
-#endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */
-#endif /* PM3FB_USE_ACCEL */
-/* pre-init */
-static void pm3fb_mode_setup(char *mode, unsigned long board_num);
-static void pm3fb_pciid_setup(char *pciid, unsigned long board_num);
-static char *pm3fb_boardnum_setup(char *options, unsigned long *bn);
-static void pm3fb_real_setup(char *options);
-/* fbdev */
-static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix,
-                           const void *par, struct fb_info_gen *info);
-static int pm3fb_decode_var(const struct fb_var_screeninfo *var,
-                           void *par, struct fb_info_gen *info);
-static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d);
-static int pm3fb_encode_var(struct fb_var_screeninfo *var,
-                           const void *par, struct fb_info_gen *info);
-static void pm3fb_get_par(void *par, struct fb_info_gen *info);
-static void pm3fb_set_par(const void *par, struct fb_info_gen *info);
-static void pm3fb_set_color(struct pm3fb_info *l_fb_info,
-                           unsigned char regno, unsigned char r,
-                           unsigned char g, unsigned char b);
-static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
-                          unsigned *blue, unsigned *transp,
-                          struct fb_info *info);
-static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
-                          unsigned blue, unsigned transp,
-                          struct fb_info *info);
-static int pm3fb_blank(int blank_mode, struct fb_info_gen *info);
-static void pm3fb_set_disp(const void *par, struct display *disp,
-                          struct fb_info_gen *info);
-static void pm3fb_detect(void);
-static int pm3fb_pan_display(const struct fb_var_screeninfo *var,
-                            struct fb_info_gen *info);
-static int pm3fb_ioctl(struct fb_info *info, u_int cmd, u_long arg);
-
-
-/* the struct that hold them together */
-struct fbgen_hwswitch pm3fb_switch = {
-       pm3fb_detect, pm3fb_encode_fix, pm3fb_decode_var, pm3fb_encode_var,
-       pm3fb_get_par, pm3fb_set_par, pm3fb_getcolreg, 
-       pm3fb_pan_display, pm3fb_blank, pm3fb_set_disp
-};
+/*
+ * Driver data
+ */
+static char *mode_option __devinitdata;
 
-static struct fb_ops pm3fb_ops = {
-       .owner =        THIS_MODULE,
-       .fb_get_fix =   fbgen_get_fix,
-       .fb_get_var =   fbgen_get_var,
-       .fb_set_var =   fbgen_set_var,
-       .fb_get_cmap =  fbgen_get_cmap,
-       .fb_set_cmap =  fbgen_set_cmap,
-       .fb_setcolreg = pm3fb_setcolreg,
-       .fb_pan_display =fbgen_pan_display,
-       .fb_blank =     fbgen_blank,
-       .fb_ioctl =     pm3fb_ioctl,
-};
+/*
+ *  If your driver supports multiple boards, you should make the
+ *  below data types arrays, or allocate them dynamically (using kmalloc()).
+ */
 
-#ifdef PM3FB_USE_ACCEL
-#ifdef FBCON_HAS_CFB32
-static struct display_switch pm3fb_cfb32 = {
-       fbcon_cfb32_setup, pm3fb_cfbX_bmove, pm3fb_cfb32_clear,
-       pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
-       NULL /* cursor() */ , NULL /* set_font() */ ,
-       pm3fb_cfb32_clear_margins,
-       FONTWIDTHRANGE(1, 16)   /* true only if accelerated... */
-};
-#endif /* FBCON_HAS_CFB32 */
-#ifdef FBCON_HAS_CFB16
-static struct display_switch pm3fb_cfb16 = {
-       fbcon_cfb16_setup, pm3fb_cfbX_bmove, pm3fb_cfb16_clear,
-       pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
-       NULL /* cursor() */ , NULL /* set_font() */ ,
-       pm3fb_cfb16_clear_margins,
-       FONTWIDTHRANGE(1, 16)   /* true only if accelerated... */
-};
-#endif /* FBCON_HAS_CFB16 */
-#ifdef FBCON_HAS_CFB8
-static struct display_switch pm3fb_cfb8 = {
-       fbcon_cfb8_setup, pm3fb_cfbX_bmove, pm3fb_cfb8_clear,
-       pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
-       NULL /* cursor() */ , NULL /* set_font() */ ,
-       pm3fb_cfb8_clear_margins,
-       FONTWIDTHRANGE(1, 16)   /* true only if accelerated... */
-};
-#endif /* FBCON_HAS_CFB8 */
-#endif /* PM3FB_USE_ACCEL */
-
-/* ****************************** */
-/* ***** card-specific data ***** */
-/* ****************************** */
-struct pm3fb_card_timings {
-       unsigned long memsize; /* 0 for last value (i.e. default) */
-       struct pm3fb_timings memt;
+/*
+ * This structure defines the hardware state of the graphics card. Normally
+ * you place this in a header file in linux/include/video. This file usually
+ * also includes register information. That allows other driver subsystems
+ * and userland applications the ability to use the same header file to
+ * avoid duplicate work and easy porting of software.
+ */
+struct pm3_par {
+       unsigned char   __iomem *v_regs;/* virtual address of p_regs */
+       u32             video;          /* video flags before blanking */
+       u32             base;           /* screen base (xoffset+yoffset) in 128 bits unit */
+       u32             palette[16];
 };
 
-static struct pm3fb_card_timings t_FormacProFormance3[] = {
-       { 16, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} },
-       { 0, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} } /* from 16 MB PF3 */
+/*
+ * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo
+ * if we don't use modedb. If we do use modedb see pm3fb_init how to use it
+ * to get a fb_var_screeninfo. Otherwise define a default var as well.
+ */
+static struct fb_fix_screeninfo pm3fb_fix __devinitdata = {
+       .id =           "Permedia3",
+       .type =         FB_TYPE_PACKED_PIXELS,
+       .visual =       FB_VISUAL_PSEUDOCOLOR,
+       .xpanstep =     1,
+       .ypanstep =     1,
+       .ywrapstep =    0,
+       .accel =        FB_ACCEL_NONE,
 };
 
-static struct pm3fb_card_timings t_AppianJeronimo2000[] = {
-       { 32, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} },
-       { 0, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} } /* from 32MB J2000 */
-};
+/*
+ * Utility functions
+ */
 
-static struct pm3fb_card_timings t_3DLabsOxygenVX1[] = {
-       { 32, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} },
-       { 0, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} } /* from 32MB VX1 */
-};
+static inline u32 PM3_READ_REG(struct pm3_par *par, s32 off)
+{
+       return fb_readl(par->v_regs + off);
+}
 
-static struct {
-               char cardname[32]; /* recognized card name */
-               u16 subvendor; /* subvendor of the card */
-               u16 subdevice; /* subdevice of the card */
-               u8  func; /* function of the card to which the extra init apply */
-               void (*specific_setup)(struct pm3fb_info *l_fb_info); /* card/func specific setup, done before _any_ FB access */
-       struct pm3fb_card_timings *c_memt; /* defauls timings for the boards */
-} cardbase[] = {
-       { "Unknown Permedia3 board", 0xFFFF, 0xFFFF, 0xFF, NULL, NULL },
-       { "Appian Jeronimo 2000 head 1", 0x1097, 0x3d32, 1, NULL,
-         t_AppianJeronimo2000
-       },
-       { "Appian Jeronimo 2000 head 2", 0x1097, 0x3d32, 2, pm3fb_j2000_setup,
-         t_AppianJeronimo2000
-       },
-       { "Formac ProFormance 3", PCI_VENDOR_ID_3DLABS, 0x000a, 0, NULL, /* Formac use 3DLabs ID ?!? */
-         t_FormacProFormance3
-       },
-       { "3DLabs Permedia3 Create!", PCI_VENDOR_ID_3DLABS, 0x0127, 0, NULL, NULL },
-       { "3DLabs Oxygen VX1 PCI", PCI_VENDOR_ID_3DLABS, 0x0121, 0, NULL,
-         t_3DLabsOxygenVX1
-       },
-       { "3DLabs Oxygen VX1 AGP", PCI_VENDOR_ID_3DLABS, 0x0125, 0, NULL, NULL },
-       { "3DLabs Oxygen VX1-16 AGP", PCI_VENDOR_ID_3DLABS, 0x0140, 0, NULL, NULL },
-       { "3DLabs Oxygen VX1-1600SW PCI", PCI_VENDOR_ID_3DLABS, 0x0800, 0, NULL, NULL },
-       { "\0", 0x0, 0x0, 0, NULL, NULL }
-};
+static inline void PM3_WRITE_REG(struct pm3_par *par, s32 off, u32 v)
+{
+       fb_writel(v, par->v_regs + off);
+}
 
-/* ********************************** */
-/* ***** card-specific function ***** */
-/* ********************************** */
-static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info)
-{       /* the appian j2000 require more initialization of the second head */
-       /* l_fb_info must point to the _second_ head of the J2000 */
-       
-       DTRACE;
-
-       l_fb_info->memt = t_AppianJeronimo2000[0].memt; /* 32 MB, first and only j2000 ? */
-       
-       pm3fb_write_memory_timings(l_fb_info);
+static inline void PM3_WAIT(struct pm3_par *par, u32 n)
+{
+       while (PM3_READ_REG(par, PM3InFIFOSpace) < n);
 }
 
-/* *************************************** */
-/* ***** permedia3-specific function ***** */
-/* *************************************** */
-static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info)
+static inline void PM3_SLOW_WRITE_REG(struct pm3_par *par, s32 off, u32 v)
 {
-       l_fb_info->memt.caps = PM3_READ_REG(PM3LocalMemCaps);
-       l_fb_info->memt.timings = PM3_READ_REG(PM3LocalMemTimings);
-       l_fb_info->memt.control = PM3_READ_REG(PM3LocalMemControl);
-       l_fb_info->memt.refresh = PM3_READ_REG(PM3LocalMemRefresh);
-       l_fb_info->memt.powerdown = PM3_READ_REG(PM3LocalMemPowerDown);
-
-       if ((l_fb_info->memt.caps == PM3FB_UNKNOWN_TIMING_VALUE) ||
-           (l_fb_info->memt.timings == PM3FB_UNKNOWN_TIMING_VALUE) ||
-           (l_fb_info->memt.control == PM3FB_UNKNOWN_TIMING_VALUE) ||
-           (l_fb_info->memt.refresh == PM3FB_UNKNOWN_TIMING_VALUE) ||
-           (l_fb_info->memt.powerdown == PM3FB_UNKNOWN_TIMING_VALUE))
-       {
-               printk(KERN_ERR "pm3fb: invalid memory timings in permedia3 board #%ld\n", l_fb_info->board_num);
-               return(pm3fb_try_memory_timings(l_fb_info));
+       if (par->v_regs) {
+               mb();
+               PM3_WAIT(par, 1);
+               wmb();
+               PM3_WRITE_REG(par, off, v);
        }
-       return(pm3fb_timing_ok);
 }
 
-static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info)
+static inline void PM3_SET_INDEX(struct pm3_par *par, unsigned index)
 {
-       if (cardbase[l_fb_info->board_type].c_memt)
-       {
-               int i = 0, done = 0;
-               while (!done)
-               {
-                       if ((cardbase[l_fb_info->board_type].c_memt[i].memsize == l_fb_info->fb_size)
-                           || !(cardbase[l_fb_info->board_type].c_memt[i].memsize))
-                       { /* will use the 0-sized timings by default */
-                               done = 1;
-                               l_fb_info->memt = cardbase[l_fb_info->board_type].c_memt[i].memt;
-                               printk(KERN_WARNING  "pm3fb: trying to use predefined memory timings for permedia3 board #%ld (%s, %ld MB)\n",
-                                      l_fb_info->board_num,
-                                      cardbase[l_fb_info->board_type].cardname,
-                                      cardbase[l_fb_info->board_type].c_memt[i].memsize);
-                               pm3fb_write_memory_timings(l_fb_info);
-                               return(pm3fb_timing_retry);
-                       }
-                       i++;
-               }
-       } else
-               return(pm3fb_timing_problem);
-       return(pm3fb_timing_ok);
+       PM3_SLOW_WRITE_REG(par, PM3RD_IndexHigh, (index >> 8) & 0xff);
+       PM3_SLOW_WRITE_REG(par, PM3RD_IndexLow, index & 0xff);
 }
 
-static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info)
+static inline void PM3_WRITE_DAC_REG(struct pm3_par *par, unsigned r, u8 v)
 {
-       unsigned char m, n, p;
-       unsigned long clockused;
-       
-       PM3_SLOW_WRITE_REG(PM3LocalMemCaps, l_fb_info->memt.caps);
-       PM3_SLOW_WRITE_REG(PM3LocalMemTimings, l_fb_info->memt.timings);
-       PM3_SLOW_WRITE_REG(PM3LocalMemControl, l_fb_info->memt.control);
-       PM3_SLOW_WRITE_REG(PM3LocalMemRefresh, l_fb_info->memt.refresh);
-       PM3_SLOW_WRITE_REG(PM3LocalMemPowerDown, l_fb_info->memt.powerdown);
-
-       clockused =
-           pm3fb_CalculateClock(l_fb_info, 2 * 105000, PM3_REF_CLOCK, &m,
-                                &n, &p);
-
-       PM3_WRITE_DAC_REG(PM3RD_KClkPreScale, m);
-       PM3_WRITE_DAC_REG(PM3RD_KClkFeedbackScale, n);
-       PM3_WRITE_DAC_REG(PM3RD_KClkPostScale, p);
-       PM3_WRITE_DAC_REG(PM3RD_KClkControl,
-                         PM3RD_KClkControl_STATE_RUN |
-                         PM3RD_KClkControl_SOURCE_PLL |
-                         PM3RD_KClkControl_ENABLE);
-       PM3_WRITE_DAC_REG(PM3RD_MClkControl,
-                         PM3RD_MClkControl_STATE_RUN |
-                         PM3RD_MClkControl_SOURCE_KCLK |
-                         PM3RD_MClkControl_ENABLE);
-       PM3_WRITE_DAC_REG(PM3RD_SClkControl,
-                         PM3RD_SClkControl_STATE_RUN |
-                         PM3RD_SClkControl_SOURCE_PCLK |
-                         PM3RD_SClkControl_ENABLE);
+       PM3_SET_INDEX(par, r);
+       wmb();
+       PM3_WRITE_REG(par, PM3RD_IndexedData, v);
 }
 
-static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info,
-                                       unsigned long r)
+static inline void pm3fb_set_color(struct pm3_par *par, unsigned char regno,
+                       unsigned char r, unsigned char g, unsigned char b)
 {
-       DASSERT((l_fb_info->vIOBase != (unsigned char *) (-1)),
-               "l_fb_info->vIOBase mapped in read dac reg\n");
-       PM3_SET_INDEX(r);
-       mb();
-       return (PM3_READ_REG(PM3RD_IndexedData));
+       PM3_SLOW_WRITE_REG(par, PM3RD_PaletteWriteAddress, regno);
+       PM3_SLOW_WRITE_REG(par, PM3RD_PaletteData, r);
+       PM3_SLOW_WRITE_REG(par, PM3RD_PaletteData, g);
+       PM3_SLOW_WRITE_REG(par, PM3RD_PaletteData, b);
+}
+
+static void pm3fb_clear_colormap(struct pm3_par *par,
+                       unsigned char r, unsigned char g, unsigned char b)
+{
+       int i;
+
+       for (i = 0; i < 256 ; i++) /* fill color map with white */
+               pm3fb_set_color(par, i, r, g, b);
+
 }
 
 /* Calculating various clock parameter */
-static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock,        /* In kHz units */
-                                         unsigned long refclock,       /* In kHz units */
-                                         unsigned char *prescale,      /* ClkPreScale */
-                                         unsigned char *feedback,      /* ClkFeedBackScale */
-                                         unsigned char *postscale
-                                         /* ClkPostScale */ )
+static void pm3fb_calculate_clock(unsigned long reqclock,
+                               unsigned char *prescale,
+                               unsigned char *feedback,
+                               unsigned char *postscale)
 {
        int f, pre, post;
        unsigned long freq;
        long freqerr = 1000;
-       unsigned long actualclock = 0;
-
-       DTRACE;
+       long currerr;
 
        for (f = 1; f < 256; f++) {
                for (pre = 1; pre < 256; pre++) {
                        for (post = 0; post < 5; post++) {
-                               freq =
-                                   ((2 * refclock * f) /
-                                    (pre * (1 << post)));
-                               if ((reqclock > freq - freqerr)
-                                   && (reqclock < freq + freqerr)) {
-                                       freqerr =
-                                           (reqclock >
-                                            freq) ? reqclock -
-                                           freq : freq - reqclock;
+                               freq = ((2*PM3_REF_CLOCK * f) >> post) / pre;
+                               currerr = (reqclock > freq)
+                                       ? reqclock - freq
+                                       : freq - reqclock;
+                               if (currerr < freqerr) {
+                                       freqerr = currerr;
                                        *feedback = f;
                                        *prescale = pre;
                                        *postscale = post;
-                                       actualclock = freq;
                                }
                        }
                }
        }
-
-       return (actualclock);
 }
 
-static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info,
-                         unsigned long depth, int v)
+static inline int pm3fb_shift_bpp(unsigned long depth, int v)
 {
-       DTRACE;
-       
        switch (depth) {
        case 8:
                return (v >> 4);
@@ -918,181 +187,59 @@ static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info,
        case 32:
                return (v >> 2);
        }
-       DPRINTK(1, "Unsupported depth %ld\n", depth);
-       return (0);
-}
-
-static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info,
-                           unsigned long depth, int v)
-{
-       DTRACE;
-
-       switch (depth) {
-       case 8:
-               return (v << 4);
-       case 12:        
-       case 15:
-       case 16:
-               return (v << 3);
-       case 32:
-               return (v << 2);
-       }
-       DPRINTK(1, "Unsupported depth %ld\n", depth);
-       return (0);
-}
-
-static void pm3fb_mapIO(struct pm3fb_info *l_fb_info)
-{
-       DTRACE;
-
-       l_fb_info->vIOBase =
-           ioremap((unsigned long) l_fb_info->pIOBase, PM3_REGS_SIZE);
-       l_fb_info->v_fb =
-           ioremap((unsigned long) l_fb_info->p_fb, l_fb_info->fb_size);
-       DPRINTK(2, "IO mapping : IOBase %lx / %lx, fb %lx / %lx\n",
-               (unsigned long) l_fb_info->pIOBase,
-               (unsigned long) l_fb_info->vIOBase,
-               (unsigned long) l_fb_info->p_fb,
-               (unsigned long) l_fb_info->v_fb);
-}
-
-static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info)
-{
-       DTRACE;
-
-       iounmap(l_fb_info->vIOBase);
-       iounmap(l_fb_info->v_fb);
-       l_fb_info->vIOBase = (unsigned char *) -1;
-       l_fb_info->v_fb = (unsigned char *) -1;
-}
-
-#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2)
-static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info)
-{
-       DPRINTK(2, "PM3Aperture0: 0x%08x\n", PM3_READ_REG(PM3Aperture0));
-       DPRINTK(2, "PM3Aperture1: 0x%08x\n", PM3_READ_REG(PM3Aperture1));
-       DPRINTK(2, "PM3ByAperture1Mode: 0x%08x\n",
-               PM3_READ_REG(PM3ByAperture1Mode));
-       DPRINTK(2, "PM3ByAperture2Mode: 0x%08x\n",
-               PM3_READ_REG(PM3ByAperture2Mode));
-       DPRINTK(2, "PM3ChipConfig: 0x%08x\n", PM3_READ_REG(PM3ChipConfig));
-       DPRINTK(2, "PM3FIFODis: 0x%08x\n", PM3_READ_REG(PM3FIFODis));
-       DPRINTK(2, "PM3HTotal: 0x%08x\n", PM3_READ_REG(PM3HTotal));
-       DPRINTK(2, "PM3HbEnd: 0x%08x\n", PM3_READ_REG(PM3HbEnd));
-       DPRINTK(2, "PM3HgEnd: 0x%08x\n", PM3_READ_REG(PM3HgEnd));
-       DPRINTK(2, "PM3HsEnd: 0x%08x\n", PM3_READ_REG(PM3HsEnd));
-       DPRINTK(2, "PM3HsStart: 0x%08x\n", PM3_READ_REG(PM3HsStart));
-       DPRINTK(2, "PM3MemBypassWriteMask: 0x%08x\n",
-               PM3_READ_REG(PM3MemBypassWriteMask));
-       DPRINTK(2, "PM3RD_IndexControl: 0x%08x\n",
-               PM3_READ_REG(PM3RD_IndexControl));
-       DPRINTK(2, "PM3ScreenBase: 0x%08x\n", PM3_READ_REG(PM3ScreenBase));
-       DPRINTK(2, "PM3ScreenStride: 0x%08x\n",
-               PM3_READ_REG(PM3ScreenStride));
-       DPRINTK(2, "PM3VClkCtl: 0x%08x\n", PM3_READ_REG(PM3VClkCtl));
-       DPRINTK(2, "PM3VTotal: 0x%08x\n", PM3_READ_REG(PM3VTotal));
-       DPRINTK(2, "PM3VbEnd: 0x%08x\n", PM3_READ_REG(PM3VbEnd));
-       DPRINTK(2, "PM3VideoControl: 0x%08x\n",
-               PM3_READ_REG(PM3VideoControl));
-       DPRINTK(2, "PM3VsEnd: 0x%08x\n", PM3_READ_REG(PM3VsEnd));
-       DPRINTK(2, "PM3VsStart: 0x%08x\n", PM3_READ_REG(PM3VsStart));
-
-       DPRINTK(2, "PM3RD_ColorFormat: %ld\n",
-               PM3_READ_DAC_REG(PM3RD_ColorFormat));
-       DPRINTK(2, "PM3RD_DACControl: %ld\n",
-               PM3_READ_DAC_REG(PM3RD_DACControl));
-       DPRINTK(2, "PM3RD_DClk0FeedbackScale: %ld\n",
-               PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale));
-       DPRINTK(2, "PM3RD_DClk0PostScale: %ld\n",
-               PM3_READ_DAC_REG(PM3RD_DClk0PostScale));
-       DPRINTK(2, "PM3RD_DClk0PreScale: %ld\n",
-               PM3_READ_DAC_REG(PM3RD_DClk0PreScale));
-       DPRINTK(2, "[not set] PM3RD_IndexControl: %ld\n",
-               PM3_READ_DAC_REG(PM3RD_IndexControl));
-       DPRINTK(2, "PM3RD_MiscControl: %ld\n",
-               PM3_READ_DAC_REG(PM3RD_MiscControl));
-       DPRINTK(2, "PM3RD_PixelSize: %ld\n",
-               PM3_READ_DAC_REG(PM3RD_PixelSize));
-       DPRINTK(2, "PM3RD_SyncControl: %ld\n",
-               PM3_READ_DAC_REG(PM3RD_SyncControl));
-}
-
-#endif /* defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) */
-static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info)
-{
-       u16 subvendor, subdevice;
-
-       if ((!pci_read_config_word
-            (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor))
-           &&
-           (!pci_read_config_word
-            (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) {
-               /* well, nothing... */
-       } else {
-               subvendor = subdevice = (u16)-1;
-       }
-
-       printk(KERN_INFO "pm3fb: memory timings for board #%ld (subvendor: 0x%hx, subdevice: 0x%hx)\n", l_fb_info->board_num, subvendor, subdevice);
-       printk(KERN_INFO " PM3LocalMemCaps: 0x%08x\n",
-              PM3_READ_REG(PM3LocalMemCaps));
-       printk(KERN_INFO " PM3LocalMemTimings: 0x%08x\n",
-              PM3_READ_REG(PM3LocalMemTimings));
-       printk(KERN_INFO " PM3LocalMemControl: 0x%08x\n",
-              PM3_READ_REG(PM3LocalMemControl));
-       printk(KERN_INFO " PM3LocalMemRefresh: 0x%08x\n",
-              PM3_READ_REG(PM3LocalMemRefresh));
-       printk(KERN_INFO " PM3LocalMemPowerDown: 0x%08x\n",
-              PM3_READ_REG(PM3LocalMemPowerDown));
+       DPRINTK("Unsupported depth %ld\n", depth);
+       return 0;
 }
 
 /* write the mode to registers */
-static void pm3fb_write_mode(struct pm3fb_info *l_fb_info)
+static void pm3fb_write_mode(struct fb_info *info)
 {
+       struct pm3_par *par = info->par;
        char tempsync = 0x00, tempmisc = 0x00;
-       DTRACE;
-
-       PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xffffffff);
-       PM3_SLOW_WRITE_REG(PM3Aperture0, 0x00000000);
-       PM3_SLOW_WRITE_REG(PM3Aperture1, 0x00000000);
-       PM3_SLOW_WRITE_REG(PM3FIFODis, 0x00000007);
-
-       PM3_SLOW_WRITE_REG(PM3HTotal,
-                          pm3fb_Shiftbpp(l_fb_info,
-                                         l_fb_info->current_par->depth,
-                                         l_fb_info->current_par->htotal -
-                                         1));
-       PM3_SLOW_WRITE_REG(PM3HsEnd,
-                          pm3fb_Shiftbpp(l_fb_info,
-                                         l_fb_info->current_par->depth,
-                                         l_fb_info->current_par->hsend));
-       PM3_SLOW_WRITE_REG(PM3HsStart,
-                          pm3fb_Shiftbpp(l_fb_info,
-                                         l_fb_info->current_par->depth,
-                                         l_fb_info->current_par->
+       const u32 hsstart = info->var.right_margin;
+       const u32 hsend = hsstart + info->var.hsync_len;
+       const u32 hbend = hsend + info->var.left_margin;
+       const u32 xres = (info->var.xres + 31) & ~31;
+       const u32 htotal = xres + hbend;
+       const u32 vsstart = info->var.lower_margin;
+       const u32 vsend = vsstart + info->var.vsync_len;
+       const u32 vbend = vsend + info->var.upper_margin;
+       const u32 vtotal = info->var.yres + vbend;
+       const u32 width = (info->var.xres_virtual + 7) & ~7;
+
+       PM3_SLOW_WRITE_REG(par, PM3MemBypassWriteMask, 0xffffffff);
+       PM3_SLOW_WRITE_REG(par, PM3Aperture0, 0x00000000);
+       PM3_SLOW_WRITE_REG(par, PM3Aperture1, 0x00000000);
+       PM3_SLOW_WRITE_REG(par, PM3FIFODis, 0x00000007);
+
+       PM3_SLOW_WRITE_REG(par, PM3HTotal,
+                          pm3fb_shift_bpp(info->var.bits_per_pixel,
+                                         htotal - 1));
+       PM3_SLOW_WRITE_REG(par, PM3HsEnd,
+                          pm3fb_shift_bpp(info->var.bits_per_pixel,
+                                         hsend));
+       PM3_SLOW_WRITE_REG(par, PM3HsStart,
+                          pm3fb_shift_bpp(info->var.bits_per_pixel,
                                          hsstart));
-       PM3_SLOW_WRITE_REG(PM3HbEnd,
-                          pm3fb_Shiftbpp(l_fb_info,
-                                         l_fb_info->current_par->depth,
-                                         l_fb_info->current_par->hbend));
-       PM3_SLOW_WRITE_REG(PM3HgEnd,
-                          pm3fb_Shiftbpp(l_fb_info,
-                                         l_fb_info->current_par->depth,
-                                         l_fb_info->current_par->hbend));
-       PM3_SLOW_WRITE_REG(PM3ScreenStride,
-                          pm3fb_Shiftbpp(l_fb_info,
-                                         l_fb_info->current_par->depth,
-                                         l_fb_info->current_par->stride));
-       PM3_SLOW_WRITE_REG(PM3VTotal, l_fb_info->current_par->vtotal - 1);
-       PM3_SLOW_WRITE_REG(PM3VsEnd, l_fb_info->current_par->vsend - 1);
-       PM3_SLOW_WRITE_REG(PM3VsStart,
-                          l_fb_info->current_par->vsstart - 1);
-       PM3_SLOW_WRITE_REG(PM3VbEnd, l_fb_info->current_par->vbend);
-
-       switch (l_fb_info->current_par->depth) {
+       PM3_SLOW_WRITE_REG(par, PM3HbEnd,
+                          pm3fb_shift_bpp(info->var.bits_per_pixel,
+                                         hbend));
+       PM3_SLOW_WRITE_REG(par, PM3HgEnd,
+                          pm3fb_shift_bpp(info->var.bits_per_pixel,
+                                         hbend));
+       PM3_SLOW_WRITE_REG(par, PM3ScreenStride,
+                          pm3fb_shift_bpp(info->var.bits_per_pixel,
+                                         width));
+       PM3_SLOW_WRITE_REG(par, PM3VTotal, vtotal - 1);
+       PM3_SLOW_WRITE_REG(par, PM3VsEnd, vsend - 1);
+       PM3_SLOW_WRITE_REG(par, PM3VsStart, vsstart - 1);
+       PM3_SLOW_WRITE_REG(par, PM3VbEnd, vbend);
+
+       switch (info->var.bits_per_pixel) {
        case 8:
-               PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+               PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
                                   PM3ByApertureMode_PIXELSIZE_8BIT);
-               PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+               PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
                                   PM3ByApertureMode_PIXELSIZE_8BIT);
                break;
 
@@ -1100,15 +247,15 @@ static void pm3fb_write_mode(struct pm3fb_info *l_fb_info)
        case 15:
        case 16:
 #ifndef __BIG_ENDIAN
-               PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+               PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
                                   PM3ByApertureMode_PIXELSIZE_16BIT);
-               PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+               PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
                                   PM3ByApertureMode_PIXELSIZE_16BIT);
 #else
-               PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+               PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
                                   PM3ByApertureMode_PIXELSIZE_16BIT |
                                   PM3ByApertureMode_BYTESWAP_BADC);
-               PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+               PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
                                   PM3ByApertureMode_PIXELSIZE_16BIT |
                                   PM3ByApertureMode_BYTESWAP_BADC);
 #endif /* ! __BIG_ENDIAN */
@@ -1116,23 +263,23 @@ static void pm3fb_write_mode(struct pm3fb_info *l_fb_info)
 
        case 32:
 #ifndef __BIG_ENDIAN
-               PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+               PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
                                   PM3ByApertureMode_PIXELSIZE_32BIT);
-               PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+               PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
                                   PM3ByApertureMode_PIXELSIZE_32BIT);
 #else
-               PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+               PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
                                   PM3ByApertureMode_PIXELSIZE_32BIT |
                                   PM3ByApertureMode_BYTESWAP_DCBA);
-               PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+               PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
                                   PM3ByApertureMode_PIXELSIZE_32BIT |
                                   PM3ByApertureMode_BYTESWAP_DCBA);
 #endif /* ! __BIG_ENDIAN */
                break;
 
        default:
-               DPRINTK(1, "Unsupported depth %d\n",
-                       l_fb_info->current_par->depth);
+               DPRINTK("Unsupported depth %d\n",
+                       info->var.bits_per_pixel);
                break;
        }
 
@@ -1143,95 +290,86 @@ static void pm3fb_write_mode(struct pm3fb_info *l_fb_info)
         * sync options in PM3RD_SyncControl.  --rmk
         */
        {
-               unsigned int video = l_fb_info->current_par->video;
+               unsigned int video = par->video;
 
                video &= ~(PM3VideoControl_HSYNC_MASK |
                           PM3VideoControl_VSYNC_MASK);
                video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
                         PM3VideoControl_VSYNC_ACTIVE_HIGH;
-               PM3_SLOW_WRITE_REG(PM3VideoControl, video);
+               PM3_SLOW_WRITE_REG(par, PM3VideoControl, video);
        }
-       PM3_SLOW_WRITE_REG(PM3VClkCtl,
-                          (PM3_READ_REG(PM3VClkCtl) & 0xFFFFFFFC));
-       PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base);
-       PM3_SLOW_WRITE_REG(PM3ChipConfig,
-                          (PM3_READ_REG(PM3ChipConfig) & 0xFFFFFFFD));
+       PM3_SLOW_WRITE_REG(par, PM3VClkCtl,
+                          (PM3_READ_REG(par, PM3VClkCtl) & 0xFFFFFFFC));
+       PM3_SLOW_WRITE_REG(par, PM3ScreenBase, par->base);
+       PM3_SLOW_WRITE_REG(par, PM3ChipConfig,
+                          (PM3_READ_REG(par, PM3ChipConfig) & 0xFFFFFFFD));
 
        {
-               unsigned char m;        /* ClkPreScale */
-               unsigned char n;        /* ClkFeedBackScale */
-               unsigned char p;        /* ClkPostScale */
-               (void)pm3fb_CalculateClock(l_fb_info, l_fb_info->current_par->pixclock, PM3_REF_CLOCK, &m, &n, &p);
-
-               DPRINTK(2,
-                       "Pixclock: %d, Pre: %d, Feedback: %d, Post: %d\n",
-                       l_fb_info->current_par->pixclock, (int) m, (int) n,
-                       (int) p);
-
-               PM3_WRITE_DAC_REG(PM3RD_DClk0PreScale, m);
-               PM3_WRITE_DAC_REG(PM3RD_DClk0FeedbackScale, n);
-               PM3_WRITE_DAC_REG(PM3RD_DClk0PostScale, p);
+               unsigned char uninitialized_var(m);     /* ClkPreScale */
+               unsigned char uninitialized_var(n);     /* ClkFeedBackScale */
+               unsigned char uninitialized_var(p);     /* ClkPostScale */
+               unsigned long pixclock = PICOS2KHZ(info->var.pixclock);
+
+               (void)pm3fb_calculate_clock(pixclock, &m, &n, &p);
+
+               DPRINTK("Pixclock: %ld, Pre: %d, Feedback: %d, Post: %d\n",
+                       pixclock, (int) m, (int) n, (int) p);
+
+               PM3_WRITE_DAC_REG(par, PM3RD_DClk0PreScale, m);
+               PM3_WRITE_DAC_REG(par, PM3RD_DClk0FeedbackScale, n);
+               PM3_WRITE_DAC_REG(par, PM3RD_DClk0PostScale, p);
        }
        /*
-          PM3_WRITE_DAC_REG(PM3RD_IndexControl, 0x00);
+          PM3_WRITE_DAC_REG(par, PM3RD_IndexControl, 0x00);
         */
        /*
-          PM3_SLOW_WRITE_REG(PM3RD_IndexControl, 0x00);
+          PM3_SLOW_WRITE_REG(par, PM3RD_IndexControl, 0x00);
         */
-       if ((l_fb_info->current_par->video & PM3VideoControl_HSYNC_MASK) ==
+       if ((par->video & PM3VideoControl_HSYNC_MASK) ==
            PM3VideoControl_HSYNC_ACTIVE_HIGH)
                tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH;
-       if ((l_fb_info->current_par->video & PM3VideoControl_VSYNC_MASK) ==
+       if ((par->video & PM3VideoControl_VSYNC_MASK) ==
            PM3VideoControl_VSYNC_ACTIVE_HIGH)
                tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH;
-       
-       PM3_WRITE_DAC_REG(PM3RD_SyncControl, tempsync);
-       DPRINTK(2, "PM3RD_SyncControl: %d\n", tempsync);
-       
-       if (flatpanel[l_fb_info->board_num])
-       {
-               PM3_WRITE_DAC_REG(PM3RD_DACControl, PM3RD_DACControl_BLANK_PEDESTAL_ENABLE);
-               PM3_WAIT(2);
-               PM3_WRITE_REG(PM3VSConfiguration, 0x06);
-               PM3_WRITE_REG(0x5a00, 1 << 14); /* black magic... */
-               tempmisc = PM3RD_MiscControl_VSB_OUTPUT_ENABLE;
-       }
-       else
-               PM3_WRITE_DAC_REG(PM3RD_DACControl, 0x00);
 
-       switch (l_fb_info->current_par->depth) {
+       PM3_WRITE_DAC_REG(par, PM3RD_SyncControl, tempsync);
+       DPRINTK("PM3RD_SyncControl: %d\n", tempsync);
+
+       PM3_WRITE_DAC_REG(par, PM3RD_DACControl, 0x00);
+
+       switch (info->var.bits_per_pixel) {
        case 8:
-               PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+               PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
                                  PM3RD_PixelSize_8_BIT_PIXELS);
-               PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+               PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
                                  PM3RD_ColorFormat_CI8_COLOR |
                                  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
                tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
                break;
        case 12:
-               PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+               PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
                                  PM3RD_PixelSize_16_BIT_PIXELS);
-               PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+               PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
                                  PM3RD_ColorFormat_4444_COLOR |
                                  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
                                  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
                tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
                        PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
-               break;          
+               break;
        case 15:
-               PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+               PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
                                  PM3RD_PixelSize_16_BIT_PIXELS);
-               PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+               PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
                                  PM3RD_ColorFormat_5551_FRONT_COLOR |
                                  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
                                  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
                tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
                        PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
-              &n