(2006-08-06) rescue-bootcd
This commit is contained in:
1
extra/linux-2.6.10/drivers/input/.built-in.o.cmd
Normal file
1
extra/linux-2.6.10/drivers/input/.built-in.o.cmd
Normal file
@@ -0,0 +1 @@
|
||||
cmd_drivers/input/built-in.o := ld -m elf_i386 -r -o drivers/input/built-in.o drivers/input/input.o drivers/input/mousedev.o drivers/input/keyboard/built-in.o drivers/input/mouse/built-in.o
|
||||
279
extra/linux-2.6.10/drivers/input/.input.o.cmd
Normal file
279
extra/linux-2.6.10/drivers/input/.input.o.cmd
Normal file
@@ -0,0 +1,279 @@
|
||||
cmd_drivers/input/input.o := gcc -Wp,-MD,drivers/input/.input.o.d -nostdinc -iwithprefix include -D__KERNEL__ -Iinclude -Wall -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -O2 -fomit-frame-pointer -pipe -msoft-float -mpreferred-stack-boundary=2 -fno-unit-at-a-time -march=pentium-mmx -Iinclude/asm-i386/mach-default -Wdeclaration-after-statement -DKBUILD_BASENAME=input -DKBUILD_MODNAME=input -c -o drivers/input/input.o drivers/input/input.c
|
||||
|
||||
deps_drivers/input/input.o := \
|
||||
drivers/input/input.c \
|
||||
$(wildcard include/config/proc/fs.h) \
|
||||
$(wildcard include/config/hotplug.h) \
|
||||
include/linux/init.h \
|
||||
$(wildcard include/config/modules.h) \
|
||||
include/linux/config.h \
|
||||
$(wildcard include/config/h.h) \
|
||||
include/linux/compiler.h \
|
||||
include/linux/compiler-gcc3.h \
|
||||
include/linux/compiler-gcc.h \
|
||||
include/linux/sched.h \
|
||||
$(wildcard include/config/keys.h) \
|
||||
$(wildcard include/config/schedstats.h) \
|
||||
$(wildcard include/config/smp.h) \
|
||||
$(wildcard include/config/numa.h) \
|
||||
$(wildcard include/config/security.h) \
|
||||
$(wildcard include/config/preempt.h) \
|
||||
$(wildcard include/config/magic/sysrq.h) \
|
||||
include/asm/param.h \
|
||||
include/linux/capability.h \
|
||||
include/linux/types.h \
|
||||
$(wildcard include/config/uid16.h) \
|
||||
include/linux/posix_types.h \
|
||||
include/linux/stddef.h \
|
||||
include/asm/posix_types.h \
|
||||
include/asm/types.h \
|
||||
$(wildcard include/config/highmem64g.h) \
|
||||
$(wildcard include/config/lbd.h) \
|
||||
include/linux/spinlock.h \
|
||||
$(wildcard include/config/debug/spinlock.h) \
|
||||
$(wildcard include/config/lockmeter.h) \
|
||||
include/linux/preempt.h \
|
||||
include/linux/linkage.h \
|
||||
include/asm/linkage.h \
|
||||
$(wildcard include/config/regparm.h) \
|
||||
$(wildcard include/config/x86/alignment/16.h) \
|
||||
include/linux/thread_info.h \
|
||||
include/linux/bitops.h \
|
||||
include/asm/bitops.h \
|
||||
include/asm/thread_info.h \
|
||||
$(wildcard include/config/4kstacks.h) \
|
||||
$(wildcard include/config/debug/stack/usage.h) \
|
||||
include/asm/page.h \
|
||||
$(wildcard include/config/x86/use/3dnow.h) \
|
||||
$(wildcard include/config/x86/pae.h) \
|
||||
$(wildcard include/config/hugetlb/page.h) \
|
||||
$(wildcard include/config/highmem4g.h) \
|
||||
$(wildcard include/config/discontigmem.h) \
|
||||
include/asm/processor.h \
|
||||
$(wildcard include/config/mk8.h) \
|
||||
$(wildcard include/config/mk7.h) \
|
||||
include/asm/vm86.h \
|
||||
include/asm/math_emu.h \
|
||||
include/asm/sigcontext.h \
|
||||
include/asm/segment.h \
|
||||
include/asm/cpufeature.h \
|
||||
include/asm/msr.h \
|
||||
include/asm/system.h \
|
||||
$(wildcard include/config/x86/cmpxchg.h) \
|
||||
$(wildcard include/config/x86/oostore.h) \
|
||||
include/linux/kernel.h \
|
||||
$(wildcard include/config/debug/spinlock/sleep.h) \
|
||||
/usr/lib/gcc/i686-pc-linux-gnu/3.4.1/include/stdarg.h \
|
||||
include/asm/byteorder.h \
|
||||
$(wildcard include/config/x86/bswap.h) \
|
||||
include/linux/byteorder/little_endian.h \
|
||||
include/linux/byteorder/swab.h \
|
||||
include/linux/byteorder/generic.h \
|
||||
include/asm/bug.h \
|
||||
include/asm-generic/bug.h \
|
||||
include/linux/cache.h \
|
||||
include/asm/cache.h \
|
||||
$(wildcard include/config/x86/l1/cache/shift.h) \
|
||||
include/linux/threads.h \
|
||||
$(wildcard include/config/nr/cpus.h) \
|
||||
include/asm/percpu.h \
|
||||
include/asm-generic/percpu.h \
|
||||
include/linux/stringify.h \
|
||||
include/linux/timex.h \
|
||||
$(wildcard include/config/time/interpolation.h) \
|
||||
include/linux/time.h \
|
||||
include/linux/seqlock.h \
|
||||
include/asm/timex.h \
|
||||
$(wildcard include/config/x86/elan.h) \
|
||||
$(wildcard include/config/x86/tsc.h) \
|
||||
$(wildcard include/config/x86/generic.h) \
|
||||
include/linux/jiffies.h \
|
||||
include/asm/div64.h \
|
||||
include/linux/rbtree.h \
|
||||
include/linux/cpumask.h \
|
||||
$(wildcard include/config/hotplug/cpu.h) \
|
||||
include/linux/bitmap.h \
|
||||
include/linux/string.h \
|
||||
include/asm/string.h \
|
||||
include/asm/semaphore.h \
|
||||
include/asm/atomic.h \
|
||||
$(wildcard include/config/m386.h) \
|
||||
include/linux/wait.h \
|
||||
include/linux/list.h \
|
||||
include/linux/prefetch.h \
|
||||
include/asm/current.h \
|
||||
include/linux/rwsem.h \
|
||||
$(wildcard include/config/rwsem/generic/spinlock.h) \
|
||||
include/asm/rwsem.h \
|
||||
include/asm/ptrace.h \
|
||||
$(wildcard include/config/frame/pointer.h) \
|
||||
include/asm/mmu.h \
|
||||
include/linux/smp.h \
|
||||
include/linux/sem.h \
|
||||
$(wildcard include/config/sysvipc.h) \
|
||||
include/linux/ipc.h \
|
||||
include/asm/ipcbuf.h \
|
||||
include/asm/sembuf.h \
|
||||
include/linux/signal.h \
|
||||
include/asm/signal.h \
|
||||
include/asm/siginfo.h \
|
||||
include/asm-generic/siginfo.h \
|
||||
include/linux/resource.h \
|
||||
include/asm/resource.h \
|
||||
include/linux/securebits.h \
|
||||
include/linux/fs_struct.h \
|
||||
include/linux/completion.h \
|
||||
include/linux/pid.h \
|
||||
include/linux/percpu.h \
|
||||
include/linux/slab.h \
|
||||
$(wildcard include/config/.h) \
|
||||
include/linux/gfp.h \
|
||||
include/linux/mmzone.h \
|
||||
$(wildcard include/config/force/max/zoneorder.h) \
|
||||
include/linux/numa.h \
|
||||
include/linux/topology.h \
|
||||
$(wildcard include/config/sched/smt.h) \
|
||||
include/asm/topology.h \
|
||||
include/asm-generic/topology.h \
|
||||
include/linux/kmalloc_sizes.h \
|
||||
$(wildcard include/config/mmu.h) \
|
||||
$(wildcard include/config/large/allocs.h) \
|
||||
include/linux/param.h \
|
||||
include/linux/timer.h \
|
||||
include/linux/aio.h \
|
||||
include/linux/workqueue.h \
|
||||
include/linux/aio_abi.h \
|
||||
include/linux/smp_lock.h \
|
||||
$(wildcard include/config/lock/kernel.h) \
|
||||
include/linux/input.h \
|
||||
include/linux/fs.h \
|
||||
$(wildcard include/config/dnotify.h) \
|
||||
$(wildcard include/config/quota.h) \
|
||||
$(wildcard include/config/epoll.h) \
|
||||
$(wildcard include/config/auditsyscall.h) \
|
||||
include/linux/limits.h \
|
||||
include/linux/kdev_t.h \
|
||||
include/linux/ioctl.h \
|
||||
include/asm/ioctl.h \
|
||||
include/linux/dcache.h \
|
||||
include/linux/rcupdate.h \
|
||||
include/linux/stat.h \
|
||||
include/asm/stat.h \
|
||||
include/linux/prio_tree.h \
|
||||
include/linux/kobject.h \
|
||||
include/linux/sysfs.h \
|
||||
$(wildcard include/config/sysfs.h) \
|
||||
include/linux/kref.h \
|
||||
include/linux/kobject_uevent.h \
|
||||
$(wildcard include/config/kobject/uevent.h) \
|
||||
include/linux/radix-tree.h \
|
||||
include/linux/audit.h \
|
||||
$(wildcard include/config/audit.h) \
|
||||
include/linux/quota.h \
|
||||
include/linux/errno.h \
|
||||
include/asm/errno.h \
|
||||
include/asm-generic/errno.h \
|
||||
include/asm-generic/errno-base.h \
|
||||
include/linux/dqblk_xfs.h \
|
||||
include/linux/dqblk_v1.h \
|
||||
include/linux/dqblk_v2.h \
|
||||
include/linux/nfs_fs_i.h \
|
||||
include/linux/nfs.h \
|
||||
include/linux/sunrpc/msg_prot.h \
|
||||
include/linux/fcntl.h \
|
||||
include/asm/fcntl.h \
|
||||
include/linux/err.h \
|
||||
include/linux/module.h \
|
||||
$(wildcard include/config/modversions.h) \
|
||||
$(wildcard include/config/module/unload.h) \
|
||||
$(wildcard include/config/kallsyms.h) \
|
||||
include/linux/kmod.h \
|
||||
$(wildcard include/config/kmod.h) \
|
||||
include/linux/elf.h \
|
||||
include/asm/elf.h \
|
||||
include/asm/user.h \
|
||||
include/linux/utsname.h \
|
||||
include/linux/moduleparam.h \
|
||||
include/asm/local.h \
|
||||
include/asm/module.h \
|
||||
$(wildcard include/config/m486.h) \
|
||||
$(wildcard include/config/m586.h) \
|
||||
$(wildcard include/config/m586tsc.h) \
|
||||
$(wildcard include/config/m586mmx.h) \
|
||||
$(wildcard include/config/m686.h) \
|
||||
$(wildcard include/config/mpentiumii.h) \
|
||||
$(wildcard include/config/mpentiumiii.h) \
|
||||
$(wildcard include/config/mpentiumm.h) \
|
||||
$(wildcard include/config/mpentium4.h) \
|
||||
$(wildcard include/config/mk6.h) \
|
||||
$(wildcard include/config/mcrusoe.h) \
|
||||
$(wildcard include/config/mefficeon.h) \
|
||||
$(wildcard include/config/mwinchipc6.h) \
|
||||
$(wildcard include/config/mwinchip2.h) \
|
||||
$(wildcard include/config/mwinchip3d.h) \
|
||||
$(wildcard include/config/mcyrixiii.h) \
|
||||
$(wildcard include/config/mviac3/2.h) \
|
||||
include/linux/random.h \
|
||||
include/linux/major.h \
|
||||
include/linux/pm.h \
|
||||
$(wildcard include/config/pm.h) \
|
||||
include/linux/proc_fs.h \
|
||||
$(wildcard include/config/proc/devicetree.h) \
|
||||
$(wildcard include/config/proc/kcore.h) \
|
||||
include/linux/interrupt.h \
|
||||
$(wildcard include/config/generic/hardirqs.h) \
|
||||
$(wildcard include/config/generic/irq/probe.h) \
|
||||
include/linux/hardirq.h \
|
||||
include/asm/hardirq.h \
|
||||
include/linux/irq.h \
|
||||
$(wildcard include/config/arch/s390.h) \
|
||||
include/asm/irq.h \
|
||||
$(wildcard include/config/x86/local/apic.h) \
|
||||
$(wildcard include/config/irqbalance.h) \
|
||||
include/asm-i386/mach-default/irq_vectors.h \
|
||||
include/asm-i386/mach-default/irq_vectors_limits.h \
|
||||
$(wildcard include/config/pci/msi.h) \
|
||||
$(wildcard include/config/x86/io/apic.h) \
|
||||
include/asm/hw_irq.h \
|
||||
include/linux/profile.h \
|
||||
$(wildcard include/config/profiling.h) \
|
||||
include/asm/sections.h \
|
||||
include/asm-generic/sections.h \
|
||||
include/linux/irq_cpustat.h \
|
||||
include/linux/poll.h \
|
||||
include/asm/poll.h \
|
||||
include/linux/mm.h \
|
||||
$(wildcard include/config/sysctl.h) \
|
||||
$(wildcard include/config/stack/growsup.h) \
|
||||
$(wildcard include/config/highmem.h) \
|
||||
$(wildcard include/config/shmem.h) \
|
||||
$(wildcard include/config/debug/pagealloc.h) \
|
||||
$(wildcard include/config/arch/gate/area.h) \
|
||||
include/asm/pgtable.h \
|
||||
$(wildcard include/config/highpte.h) \
|
||||
include/asm/fixmap.h \
|
||||
$(wildcard include/config/x86/visws/apic.h) \
|
||||
$(wildcard include/config/x86/f00f/bug.h) \
|
||||
$(wildcard include/config/x86/cyclone/timer.h) \
|
||||
$(wildcard include/config/acpi/boot.h) \
|
||||
$(wildcard include/config/pci/mmconfig.h) \
|
||||
include/asm/acpi.h \
|
||||
$(wildcard include/config/acpi/pci.h) \
|
||||
$(wildcard include/config/acpi/sleep.h) \
|
||||
include/asm/apicdef.h \
|
||||
include/asm/pgtable-2level-defs.h \
|
||||
include/asm/pgtable-2level.h \
|
||||
include/asm-generic/pgtable.h \
|
||||
include/linux/page-flags.h \
|
||||
$(wildcard include/config/swap.h) \
|
||||
include/asm/uaccess.h \
|
||||
$(wildcard include/config/x86/intel/usercopy.h) \
|
||||
$(wildcard include/config/x86/wp/works/ok.h) \
|
||||
include/linux/device.h \
|
||||
include/linux/ioport.h \
|
||||
include/linux/devfs_fs_kernel.h \
|
||||
$(wildcard include/config/devfs/fs.h) \
|
||||
|
||||
drivers/input/input.o: $(deps_drivers/input/input.o)
|
||||
|
||||
$(deps_drivers/input/input.o):
|
||||
261
extra/linux-2.6.10/drivers/input/.mousedev.o.cmd
Normal file
261
extra/linux-2.6.10/drivers/input/.mousedev.o.cmd
Normal file
@@ -0,0 +1,261 @@
|
||||
cmd_drivers/input/mousedev.o := gcc -Wp,-MD,drivers/input/.mousedev.o.d -nostdinc -iwithprefix include -D__KERNEL__ -Iinclude -Wall -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -O2 -fomit-frame-pointer -pipe -msoft-float -mpreferred-stack-boundary=2 -fno-unit-at-a-time -march=pentium-mmx -Iinclude/asm-i386/mach-default -Wdeclaration-after-statement -DKBUILD_BASENAME=mousedev -DKBUILD_MODNAME=mousedev -c -o drivers/input/mousedev.o drivers/input/mousedev.c
|
||||
|
||||
deps_drivers/input/mousedev.o := \
|
||||
drivers/input/mousedev.c \
|
||||
$(wildcard include/config/input/mousedev/psaux.h) \
|
||||
$(wildcard include/config/input/mousedev/screen/x.h) \
|
||||
$(wildcard include/config/input/mousedev/screen/y.h) \
|
||||
include/linux/slab.h \
|
||||
$(wildcard include/config/.h) \
|
||||
$(wildcard include/config/numa.h) \
|
||||
include/linux/config.h \
|
||||
$(wildcard include/config/h.h) \
|
||||
include/linux/gfp.h \
|
||||
include/linux/mmzone.h \
|
||||
$(wildcard include/config/force/max/zoneorder.h) \
|
||||
$(wildcard include/config/smp.h) \
|
||||
$(wildcard include/config/discontigmem.h) \
|
||||
include/linux/spinlock.h \
|
||||
$(wildcard include/config/preempt.h) \
|
||||
$(wildcard include/config/debug/spinlock.h) \
|
||||
$(wildcard include/config/lockmeter.h) \
|
||||
include/linux/preempt.h \
|
||||
include/linux/linkage.h \
|
||||
include/asm/linkage.h \
|
||||
$(wildcard include/config/regparm.h) \
|
||||
$(wildcard include/config/x86/alignment/16.h) \
|
||||
include/linux/compiler.h \
|
||||
include/linux/compiler-gcc3.h \
|
||||
include/linux/compiler-gcc.h \
|
||||
include/linux/thread_info.h \
|
||||
include/linux/bitops.h \
|
||||
include/asm/types.h \
|
||||
$(wildcard include/config/highmem64g.h) \
|
||||
$(wildcard include/config/lbd.h) \
|
||||
include/asm/bitops.h \
|
||||
include/asm/thread_info.h \
|
||||
$(wildcard include/config/4kstacks.h) \
|
||||
$(wildcard include/config/debug/stack/usage.h) \
|
||||
include/asm/page.h \
|
||||
$(wildcard include/config/x86/use/3dnow.h) \
|
||||
$(wildcard include/config/x86/pae.h) \
|
||||
$(wildcard include/config/hugetlb/page.h) \
|
||||
$(wildcard include/config/highmem4g.h) \
|
||||
include/asm/processor.h \
|
||||
$(wildcard include/config/mk8.h) \
|
||||
$(wildcard include/config/mk7.h) \
|
||||
include/asm/vm86.h \
|
||||
include/asm/math_emu.h \
|
||||
include/asm/sigcontext.h \
|
||||
include/asm/segment.h \
|
||||
include/asm/cpufeature.h \
|
||||
include/asm/msr.h \
|
||||
include/asm/system.h \
|
||||
$(wildcard include/config/x86/cmpxchg.h) \
|
||||
$(wildcard include/config/x86/oostore.h) \
|
||||
include/linux/kernel.h \
|
||||
$(wildcard include/config/debug/spinlock/sleep.h) \
|
||||
/usr/lib/gcc/i686-pc-linux-gnu/3.4.1/include/stdarg.h \
|
||||
include/linux/stddef.h \
|
||||
include/linux/types.h \
|
||||
$(wildcard include/config/uid16.h) \
|
||||
include/linux/posix_types.h \
|
||||
include/asm/posix_types.h \
|
||||
include/asm/byteorder.h \
|
||||
$(wildcard include/config/x86/bswap.h) \
|
||||
include/linux/byteorder/little_endian.h \
|
||||
include/linux/byteorder/swab.h \
|
||||
include/linux/byteorder/generic.h \
|
||||
include/asm/bug.h \
|
||||
include/asm-generic/bug.h \
|
||||
include/linux/cache.h \
|
||||
include/asm/cache.h \
|
||||
$(wildcard include/config/x86/l1/cache/shift.h) \
|
||||
include/linux/threads.h \
|
||||
$(wildcard include/config/nr/cpus.h) \
|
||||
include/asm/percpu.h \
|
||||
include/asm-generic/percpu.h \
|
||||
include/linux/stringify.h \
|
||||
include/linux/list.h \
|
||||
include/linux/prefetch.h \
|
||||
include/linux/wait.h \
|
||||
include/asm/current.h \
|
||||
include/linux/numa.h \
|
||||
include/asm/atomic.h \
|
||||
$(wildcard include/config/m386.h) \
|
||||
include/linux/topology.h \
|
||||
$(wildcard include/config/sched/smt.h) \
|
||||
include/linux/cpumask.h \
|
||||
$(wildcard include/config/hotplug/cpu.h) \
|
||||
include/linux/bitmap.h \
|
||||
include/linux/string.h \
|
||||
include/asm/string.h \
|
||||
include/linux/smp.h \
|
||||
include/asm/topology.h \
|
||||
include/asm-generic/topology.h \
|
||||
include/linux/init.h \
|
||||
$(wildcard include/config/modules.h) \
|
||||
$(wildcard include/config/hotplug.h) \
|
||||
include/linux/kmalloc_sizes.h \
|
||||
$(wildcard include/config/mmu.h) \
|
||||
$(wildcard include/config/large/allocs.h) \
|
||||
include/linux/poll.h \
|
||||
include/asm/poll.h \
|
||||
include/linux/mm.h \
|
||||
$(wildcard include/config/sysctl.h) \
|
||||
$(wildcard include/config/stack/growsup.h) \
|
||||
$(wildcard include/config/highmem.h) \
|
||||
$(wildcard include/config/shmem.h) \
|
||||
$(wildcard include/config/proc/fs.h) \
|
||||
$(wildcard include/config/debug/pagealloc.h) \
|
||||
$(wildcard include/config/arch/gate/area.h) \
|
||||
include/linux/sched.h \
|
||||
$(wildcard include/config/keys.h) \
|
||||
$(wildcard include/config/schedstats.h) \
|
||||
$(wildcard include/config/security.h) \
|
||||
$(wildcard include/config/magic/sysrq.h) \
|
||||
include/asm/param.h \
|
||||
include/linux/capability.h \
|
||||
include/linux/timex.h \
|
||||
$(wildcard include/config/time/interpolation.h) \
|
||||
include/linux/time.h \
|
||||
include/linux/seqlock.h \
|
||||
include/asm/timex.h \
|
||||
$(wildcard include/config/x86/elan.h) \
|
||||
$(wildcard include/config/x86/tsc.h) \
|
||||
$(wildcard include/config/x86/generic.h) \
|
||||
include/linux/jiffies.h \
|
||||
include/asm/div64.h \
|
||||
include/linux/rbtree.h \
|
||||
include/asm/semaphore.h \
|
||||
include/linux/rwsem.h \
|
||||
$(wildcard include/config/rwsem/generic/spinlock.h) \
|
||||
include/asm/rwsem.h \
|
||||
include/asm/ptrace.h \
|
||||
$(wildcard include/config/frame/pointer.h) \
|
||||
include/asm/mmu.h \
|
||||
include/linux/sem.h \
|
||||
$(wildcard include/config/sysvipc.h) \
|
||||
include/linux/ipc.h \
|
||||
include/asm/ipcbuf.h \
|
||||
include/asm/sembuf.h \
|
||||
include/linux/signal.h \
|
||||
include/asm/signal.h \
|
||||
include/asm/siginfo.h \
|
||||
include/asm-generic/siginfo.h \
|
||||
include/linux/resource.h \
|
||||
include/asm/resource.h \
|
||||
include/linux/securebits.h \
|
||||
include/linux/fs_struct.h \
|
||||
include/linux/completion.h \
|
||||
include/linux/pid.h \
|
||||
include/linux/percpu.h \
|
||||
include/linux/param.h \
|
||||
include/linux/timer.h \
|
||||
include/linux/aio.h \
|
||||
include/linux/workqueue.h \
|
||||
include/linux/aio_abi.h \
|
||||
include/linux/errno.h \
|
||||
include/asm/errno.h \
|
||||
include/asm-generic/errno.h \
|
||||
include/asm-generic/errno-base.h \
|
||||
include/linux/prio_tree.h \
|
||||
include/linux/fs.h \
|
||||
$(wildcard include/config/dnotify.h) \
|
||||
$(wildcard include/config/quota.h) \
|
||||
$(wildcard include/config/epoll.h) \
|
||||
$(wildcard include/config/auditsyscall.h) \
|
||||
include/linux/limits.h \
|
||||
include/linux/kdev_t.h \
|
||||
include/linux/ioctl.h \
|
||||
include/asm/ioctl.h \
|
||||
include/linux/dcache.h \
|
||||
include/linux/rcupdate.h \
|
||||
include/linux/stat.h \
|
||||
include/asm/stat.h \
|
||||
include/linux/kobject.h \
|
||||
include/linux/sysfs.h \
|
||||
$(wildcard include/config/sysfs.h) \
|
||||
include/linux/kref.h \
|
||||
include/linux/kobject_uevent.h \
|
||||
$(wildcard include/config/kobject/uevent.h) \
|
||||
include/linux/radix-tree.h \
|
||||
include/linux/audit.h \
|
||||
$(wildcard include/config/audit.h) \
|
||||
include/linux/quota.h \
|
||||
include/linux/dqblk_xfs.h \
|
||||
include/linux/dqblk_v1.h \
|
||||
include/linux/dqblk_v2.h \
|
||||
include/linux/nfs_fs_i.h \
|
||||
include/linux/nfs.h \
|
||||
include/linux/sunrpc/msg_prot.h \
|
||||
include/linux/fcntl.h \
|
||||
include/asm/fcntl.h \
|
||||
include/linux/err.h \
|
||||
include/asm/pgtable.h \
|
||||
$(wildcard include/config/highpte.h) \
|
||||
include/asm/fixmap.h \
|
||||
$(wildcard include/config/x86/local/apic.h) \
|
||||
$(wildcard include/config/x86/io/apic.h) \
|
||||
$(wildcard include/config/x86/visws/apic.h) \
|
||||
$(wildcard include/config/x86/f00f/bug.h) \
|
||||
$(wildcard include/config/x86/cyclone/timer.h) \
|
||||
$(wildcard include/config/acpi/boot.h) \
|
||||
$(wildcard include/config/pci/mmconfig.h) \
|
||||
include/asm/acpi.h \
|
||||
$(wildcard include/config/acpi/pci.h) \
|
||||
$(wildcard include/config/acpi/sleep.h) \
|
||||
include/asm/apicdef.h \
|
||||
include/asm/pgtable-2level-defs.h \
|
||||
include/asm/pgtable-2level.h \
|
||||
include/asm-generic/pgtable.h \
|
||||
include/linux/page-flags.h \
|
||||
$(wildcard include/config/swap.h) \
|
||||
include/asm/uaccess.h \
|
||||
$(wildcard include/config/x86/intel/usercopy.h) \
|
||||
$(wildcard include/config/x86/wp/works/ok.h) \
|
||||
include/linux/module.h \
|
||||
$(wildcard include/config/modversions.h) \
|
||||
$(wildcard include/config/module/unload.h) \
|
||||
$(wildcard include/config/kallsyms.h) \
|
||||
include/linux/kmod.h \
|
||||
$(wildcard include/config/kmod.h) \
|
||||
include/linux/elf.h \
|
||||
include/asm/elf.h \
|
||||
include/asm/user.h \
|
||||
include/linux/utsname.h \
|
||||
include/linux/moduleparam.h \
|
||||
include/asm/local.h \
|
||||
include/asm/module.h \
|
||||
$(wildcard include/config/m486.h) \
|
||||
$(wildcard include/config/m586.h) \
|
||||
$(wildcard include/config/m586tsc.h) \
|
||||
$(wildcard include/config/m586mmx.h) \
|
||||
$(wildcard include/config/m686.h) \
|
||||
$(wildcard include/config/mpentiumii.h) \
|
||||
$(wildcard include/config/mpentiumiii.h) \
|
||||
$(wildcard include/config/mpentiumm.h) \
|
||||
$(wildcard include/config/mpentium4.h) \
|
||||
$(wildcard include/config/mk6.h) \
|
||||
$(wildcard include/config/mcrusoe.h) \
|
||||
$(wildcard include/config/mefficeon.h) \
|
||||
$(wildcard include/config/mwinchipc6.h) \
|
||||
$(wildcard include/config/mwinchip2.h) \
|
||||
$(wildcard include/config/mwinchip3d.h) \
|
||||
$(wildcard include/config/mcyrixiii.h) \
|
||||
$(wildcard include/config/mviac3/2.h) \
|
||||
include/linux/input.h \
|
||||
include/linux/smp_lock.h \
|
||||
$(wildcard include/config/lock/kernel.h) \
|
||||
include/linux/random.h \
|
||||
include/linux/major.h \
|
||||
include/linux/device.h \
|
||||
include/linux/ioport.h \
|
||||
include/linux/pm.h \
|
||||
$(wildcard include/config/pm.h) \
|
||||
include/linux/devfs_fs_kernel.h \
|
||||
$(wildcard include/config/devfs/fs.h) \
|
||||
|
||||
drivers/input/mousedev.o: $(deps_drivers/input/mousedev.o)
|
||||
|
||||
$(deps_drivers/input/mousedev.o):
|
||||
156
extra/linux-2.6.10/drivers/input/Kconfig
Normal file
156
extra/linux-2.6.10/drivers/input/Kconfig
Normal file
@@ -0,0 +1,156 @@
|
||||
#
|
||||
# Input device configuration
|
||||
#
|
||||
|
||||
menu "Input device support"
|
||||
|
||||
config INPUT
|
||||
tristate "Input devices (needed for keyboard, mouse, ...)" if EMBEDDED
|
||||
default y
|
||||
---help---
|
||||
Say Y here if you have any input device (mouse, keyboard, tablet,
|
||||
joystick, steering wheel ...) connected to your system and want
|
||||
it to be available to applications. This includes standard PS/2
|
||||
keyboard and mouse.
|
||||
|
||||
Say N here if you have a headless (no monitor, no keyboard) system.
|
||||
|
||||
More information is available: <file:Documentation/input/input.txt>
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called input.
|
||||
|
||||
comment "Userland interfaces"
|
||||
|
||||
config INPUT_MOUSEDEV
|
||||
tristate "Mouse interface" if EMBEDDED
|
||||
default y
|
||||
depends on INPUT
|
||||
---help---
|
||||
Say Y here if you want your mouse to be accessible as char devices
|
||||
13:32+ - /dev/input/mouseX and 13:63 - /dev/input/mice as an
|
||||
emulated IntelliMouse Explorer PS/2 mouse. That way, all user space
|
||||
programs (includung SVGAlib, GPM and X) will be able to use your
|
||||
mouse.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called mousedev.
|
||||
|
||||
config INPUT_MOUSEDEV_PSAUX
|
||||
bool "Provide legacy /dev/psaux device"
|
||||
default y
|
||||
depends on INPUT_MOUSEDEV
|
||||
---help---
|
||||
Say Y here if you want your mouse also be accessible as char device
|
||||
10:1 - /dev/psaux. The data available through /dev/psaux is exactly
|
||||
the same as the data from /dev/input/mice.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
|
||||
config INPUT_MOUSEDEV_SCREEN_X
|
||||
int "Horizontal screen resolution"
|
||||
depends on INPUT_MOUSEDEV
|
||||
default "1024"
|
||||
help
|
||||
If you're using a digitizer, or a graphic tablet, and want to use
|
||||
it as a mouse then the mousedev driver needs to know the X window
|
||||
screen resolution you are using to correctly scale the data. If
|
||||
you're not using a digitizer, this value is ignored.
|
||||
|
||||
config INPUT_MOUSEDEV_SCREEN_Y
|
||||
int "Vertical screen resolution"
|
||||
depends on INPUT_MOUSEDEV
|
||||
default "768"
|
||||
help
|
||||
If you're using a digitizer, or a graphic tablet, and want to use
|
||||
it as a mouse then the mousedev driver needs to know the X window
|
||||
screen resolution you are using to correctly scale the data. If
|
||||
you're not using a digitizer, this value is ignored.
|
||||
|
||||
config INPUT_JOYDEV
|
||||
tristate "Joystick interface"
|
||||
depends on INPUT
|
||||
---help---
|
||||
Say Y here if you want your joystick or gamepad to be
|
||||
accessible as char device 13:0+ - /dev/input/jsX device.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
More information is available: <file:Documentation/input/joystick.txt>
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called joydev.
|
||||
|
||||
config INPUT_TSDEV
|
||||
tristate "Touchscreen interface"
|
||||
depends on INPUT
|
||||
---help---
|
||||
Say Y here if you have an application that only can understand the
|
||||
Compaq touchscreen protocol for absolute pointer data. This is
|
||||
useful namely for embedded configurations.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called tsdev.
|
||||
|
||||
config INPUT_TSDEV_SCREEN_X
|
||||
int "Horizontal screen resolution"
|
||||
depends on INPUT_TSDEV
|
||||
default "240"
|
||||
|
||||
config INPUT_TSDEV_SCREEN_Y
|
||||
int "Vertical screen resolution"
|
||||
depends on INPUT_TSDEV
|
||||
default "320"
|
||||
|
||||
config INPUT_EVDEV
|
||||
tristate "Event interface"
|
||||
depends on INPUT
|
||||
help
|
||||
Say Y here if you want your input device events be accessible
|
||||
under char device 13:64+ - /dev/input/eventX in a generic way.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called evdev.
|
||||
|
||||
config INPUT_EVBUG
|
||||
tristate "Event debugging"
|
||||
depends on INPUT
|
||||
---help---
|
||||
Say Y here if you have a problem with the input subsystem and
|
||||
want all events (keypresses, mouse movements), to be output to
|
||||
the system log. While this is useful for debugging, it's also
|
||||
a security threat - your keypresses include your passwords, of
|
||||
course.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called evbug.
|
||||
|
||||
comment "Input I/O drivers"
|
||||
|
||||
source "drivers/input/gameport/Kconfig"
|
||||
|
||||
source "drivers/input/serio/Kconfig"
|
||||
|
||||
comment "Input Device Drivers"
|
||||
|
||||
source "drivers/input/keyboard/Kconfig"
|
||||
|
||||
source "drivers/input/mouse/Kconfig"
|
||||
|
||||
source "drivers/input/joystick/Kconfig"
|
||||
|
||||
source "drivers/input/touchscreen/Kconfig"
|
||||
|
||||
source "drivers/input/misc/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
19
extra/linux-2.6.10/drivers/input/Makefile
Normal file
19
extra/linux-2.6.10/drivers/input/Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
#
|
||||
# Makefile for the input core drivers.
|
||||
#
|
||||
|
||||
# Each configuration option enables a list of files.
|
||||
|
||||
obj-$(CONFIG_INPUT) += input.o
|
||||
obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
|
||||
obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
|
||||
obj-$(CONFIG_INPUT_EVDEV) += evdev.o
|
||||
obj-$(CONFIG_INPUT_TSDEV) += tsdev.o
|
||||
obj-$(CONFIG_INPUT_POWER) += power.o
|
||||
obj-$(CONFIG_INPUT_EVBUG) += evbug.o
|
||||
|
||||
obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/
|
||||
obj-$(CONFIG_INPUT_MOUSE) += mouse/
|
||||
obj-$(CONFIG_INPUT_JOYSTICK) += joystick/
|
||||
obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/
|
||||
obj-$(CONFIG_INPUT_MISC) += misc/
|
||||
BIN
extra/linux-2.6.10/drivers/input/built-in.o
Normal file
BIN
extra/linux-2.6.10/drivers/input/built-in.o
Normal file
Binary file not shown.
103
extra/linux-2.6.10/drivers/input/evbug.c
Normal file
103
extra/linux-2.6.10/drivers/input/evbug.c
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* $Id: evbug.c,v 1.10 2001/09/25 10:12:07 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1999-2001 Vojtech Pavlik
|
||||
*/
|
||||
|
||||
/*
|
||||
* Input driver event debug module - dumps all events into syslog
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Input driver event debug module");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static char evbug_name[] = "evbug";
|
||||
|
||||
static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", handle->dev->phys, type, code, value);
|
||||
}
|
||||
|
||||
static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
|
||||
{
|
||||
struct input_handle *handle;
|
||||
|
||||
if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
|
||||
return NULL;
|
||||
memset(handle, 0, sizeof(struct input_handle));
|
||||
|
||||
handle->dev = dev;
|
||||
handle->handler = handler;
|
||||
handle->name = evbug_name;
|
||||
|
||||
input_open_device(handle);
|
||||
|
||||
printk(KERN_DEBUG "evbug.c: Connected device: \"%s\", %s\n", dev->name, dev->phys);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
static void evbug_disconnect(struct input_handle *handle)
|
||||
{
|
||||
printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", handle->dev->phys);
|
||||
|
||||
input_close_device(handle);
|
||||
|
||||
kfree(handle);
|
||||
}
|
||||
|
||||
static struct input_device_id evbug_ids[] = {
|
||||
{ .driver_info = 1 }, /* Matches all devices */
|
||||
{ }, /* Terminating zero entry */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(input, evbug_ids);
|
||||
|
||||
static struct input_handler evbug_handler = {
|
||||
.event = evbug_event,
|
||||
.connect = evbug_connect,
|
||||
.disconnect = evbug_disconnect,
|
||||
.name = "evbug",
|
||||
.id_table = evbug_ids,
|
||||
};
|
||||
|
||||
int __init evbug_init(void)
|
||||
{
|
||||
input_register_handler(&evbug_handler);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit evbug_exit(void)
|
||||
{
|
||||
input_unregister_handler(&evbug_handler);
|
||||
}
|
||||
|
||||
module_init(evbug_init);
|
||||
module_exit(evbug_exit);
|
||||
486
extra/linux-2.6.10/drivers/input/evdev.c
Normal file
486
extra/linux-2.6.10/drivers/input/evdev.c
Normal file
@@ -0,0 +1,486 @@
|
||||
/*
|
||||
* Event char devices, giving access to raw input device events.
|
||||
*
|
||||
* Copyright (c) 1999-2002 Vojtech Pavlik
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#define EVDEV_MINOR_BASE 64
|
||||
#define EVDEV_MINORS 32
|
||||
#define EVDEV_BUFFER_SIZE 64
|
||||
|
||||
#include <linux/poll.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/devfs_fs_kernel.h>
|
||||
|
||||
struct evdev {
|
||||
int exist;
|
||||
int open;
|
||||
int minor;
|
||||
char name[16];
|
||||
struct input_handle handle;
|
||||
wait_queue_head_t wait;
|
||||
struct evdev_list *grab;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct evdev_list {
|
||||
struct input_event buffer[EVDEV_BUFFER_SIZE];
|
||||
int head;
|
||||
int tail;
|
||||
struct fasync_struct *fasync;
|
||||
struct evdev *evdev;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
static struct evdev *evdev_table[EVDEV_MINORS];
|
||||
|
||||
static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
struct evdev *evdev = handle->private;
|
||||
struct evdev_list *list;
|
||||
|
||||
if (evdev->grab) {
|
||||
list = evdev->grab;
|
||||
|
||||
do_gettimeofday(&list->buffer[list->head].time);
|
||||
list->buffer[list->head].type = type;
|
||||
list->buffer[list->head].code = code;
|
||||
list->buffer[list->head].value = value;
|
||||
list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);
|
||||
|
||||
kill_fasync(&list->fasync, SIGIO, POLL_IN);
|
||||
} else
|
||||
list_for_each_entry(list, &evdev->list, node) {
|
||||
|
||||
do_gettimeofday(&list->buffer[list->head].time);
|
||||
list->buffer[list->head].type = type;
|
||||
list->buffer[list->head].code = code;
|
||||
list->buffer[list->head].value = value;
|
||||
list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);
|
||||
|
||||
kill_fasync(&list->fasync, SIGIO, POLL_IN);
|
||||
}
|
||||
|
||||
wake_up_interruptible(&evdev->wait);
|
||||
}
|
||||
|
||||
static int evdev_fasync(int fd, struct file *file, int on)
|
||||
{
|
||||
int retval;
|
||||
struct evdev_list *list = file->private_data;
|
||||
retval = fasync_helper(fd, file, on, &list->fasync);
|
||||
return retval < 0 ? retval : 0;
|
||||
}
|
||||
|
||||
static int evdev_flush(struct file * file)
|
||||
{
|
||||
struct evdev_list *list = file->private_data;
|
||||
if (!list->evdev->exist) return -ENODEV;
|
||||
return input_flush_device(&list->evdev->handle, file);
|
||||
}
|
||||
|
||||
static void evdev_free(struct evdev *evdev)
|
||||
{
|
||||
evdev_table[evdev->minor] = NULL;
|
||||
kfree(evdev);
|
||||
}
|
||||
|
||||
static int evdev_release(struct inode * inode, struct file * file)
|
||||
{
|
||||
struct evdev_list *list = file->private_data;
|
||||
|
||||
if (list->evdev->grab == list) {
|
||||
input_release_device(&list->evdev->handle);
|
||||
list->evdev->grab = NULL;
|
||||
}
|
||||
|
||||
evdev_fasync(-1, file, 0);
|
||||
list_del(&list->node);
|
||||
|
||||
if (!--list->evdev->open) {
|
||||
if (list->evdev->exist)
|
||||
input_close_device(&list->evdev->handle);
|
||||
else
|
||||
evdev_free(list->evdev);
|
||||
}
|
||||
|
||||
kfree(list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int evdev_open(struct inode * inode, struct file * file)
|
||||
{
|
||||
struct evdev_list *list;
|
||||
int i = iminor(inode) - EVDEV_MINOR_BASE;
|
||||
int accept_err;
|
||||
|
||||
if (i >= EVDEV_MINORS || !evdev_table[i] || !evdev_table[i]->exist)
|
||||
return -ENODEV;
|
||||
|
||||
if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file)))
|
||||
return accept_err;
|
||||
|
||||
if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL)))
|
||||
return -ENOMEM;
|
||||
memset(list, 0, sizeof(struct evdev_list));
|
||||
|
||||
list->evdev = evdev_table[i];
|
||||
list_add_tail(&list->node, &evdev_table[i]->list);
|
||||
file->private_data = list;
|
||||
|
||||
if (!list->evdev->open++)
|
||||
if (list->evdev->exist)
|
||||
input_open_device(&list->evdev->handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct evdev_list *list = file->private_data;
|
||||
struct input_event event;
|
||||
int retval = 0;
|
||||
|
||||
if (!list->evdev->exist) return -ENODEV;
|
||||
|
||||
while (retval < count) {
|
||||
|
||||
if (copy_from_user(&event, buffer + retval, sizeof(struct input_event)))
|
||||
return -EFAULT;
|
||||
input_event(list->evdev->handle.dev, event.type, event.code, event.value);
|
||||
retval += sizeof(struct input_event);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct evdev_list *list = file->private_data;
|
||||
int retval;
|
||||
|
||||
if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
|
||||
return -EAGAIN;
|
||||
|
||||
retval = wait_event_interruptible(list->evdev->wait,
|
||||
list->head != list->tail || (!list->evdev->exist));
|
||||
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!list->evdev->exist)
|
||||
return -ENODEV;
|
||||
|
||||
while (list->head != list->tail && retval + sizeof(struct input_event) <= count) {
|
||||
if (copy_to_user(buffer + retval, list->buffer + list->tail,
|
||||
sizeof(struct input_event))) return -EFAULT;
|
||||
list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
|
||||
retval += sizeof(struct input_event);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* No kernel lock - fine */
|
||||
static unsigned int evdev_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct evdev_list *list = file->private_data;
|
||||
poll_wait(file, &list->evdev->wait, wait);
|
||||
if (list->head != list->tail)
|
||||
return POLLIN | POLLRDNORM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct evdev_list *list = file->private_data;
|
||||
struct evdev *evdev = list->evdev;
|
||||
struct input_dev *dev = evdev->handle.dev;
|
||||
struct input_absinfo abs;
|
||||
void __user *p = (void __user *)arg;
|
||||
int __user *ip = (int __user *)arg;
|
||||
int i, t, u, v;
|
||||
|
||||
if (!evdev->exist) return -ENODEV;
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case EVIOCGVERSION:
|
||||
return put_user(EV_VERSION, ip);
|
||||
|
||||
case EVIOCGID:
|
||||
return copy_to_user(p, &dev->id, sizeof(struct input_id)) ? -EFAULT : 0;
|
||||
|
||||
case EVIOCGKEYCODE:
|
||||
if (get_user(t, ip)) return -EFAULT;
|
||||
if (t < 0 || t > dev->keycodemax || !dev->keycodesize) return -EINVAL;
|
||||
if (put_user(INPUT_KEYCODE(dev, t), ip + 1)) return -EFAULT;
|
||||
return 0;
|
||||
|
||||
case EVIOCSKEYCODE:
|
||||
if (get_user(t, ip)) return -EFAULT;
|
||||
if (t < 0 || t > dev->keycodemax || !dev->keycodesize) return -EINVAL;
|
||||
if (get_user(v, ip + 1)) return -EFAULT;
|
||||
u = SET_INPUT_KEYCODE(dev, t, v);
|
||||
clear_bit(u, dev->keybit);
|
||||
set_bit(v, dev->keybit);
|
||||
for (i = 0; i < dev->keycodemax; i++)
|
||||
if (INPUT_KEYCODE(dev,i) == u)
|
||||
set_bit(u, dev->keybit);
|
||||
return 0;
|
||||
|
||||
case EVIOCSFF:
|
||||
if (dev->upload_effect) {
|
||||
struct ff_effect effect;
|
||||
int err;
|
||||
|
||||
if (copy_from_user(&effect, p, sizeof(effect)))
|
||||
return -EFAULT;
|
||||
err = dev->upload_effect(dev, &effect);
|
||||
if (put_user(effect.id, &(((struct ff_effect __user *)arg)->id)))
|
||||
return -EFAULT;
|
||||
return err;
|
||||
}
|
||||
else return -ENOSYS;
|
||||
|
||||
case EVIOCRMFF:
|
||||
if (dev->erase_effect) {
|
||||
return dev->erase_effect(dev, (int)arg);
|
||||
}
|
||||
else return -ENOSYS;
|
||||
|
||||
case EVIOCGEFFECTS:
|
||||
if (put_user(dev->ff_effects_max, ip))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
|
||||
case EVIOCGRAB:
|
||||
if (arg) {
|
||||
if (evdev->grab)
|
||||
return -EBUSY;
|
||||
if (input_grab_device(&evdev->handle))
|
||||
return -EBUSY;
|
||||
evdev->grab = list;
|
||||
return 0;
|
||||
} else {
|
||||
if (evdev->grab != list)
|
||||
return -EINVAL;
|
||||
input_release_device(&evdev->handle);
|
||||
evdev->grab = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
|
||||
if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ)
|
||||
return -EINVAL;
|
||||
|
||||
if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
|
||||
|
||||
long *bits;
|
||||
int len;
|
||||
|
||||
switch (_IOC_NR(cmd) & EV_MAX) {
|
||||
case 0: bits = dev->evbit; len = EV_MAX; break;
|
||||
case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
|
||||
case EV_REL: bits = dev->relbit; len = REL_MAX; break;
|
||||
case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
|
||||
case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
|
||||
case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
|
||||
case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
|
||||
case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
|
||||
default: return -EINVAL;
|
||||
}
|
||||
len = NBITS(len) * sizeof(long);
|
||||
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
|
||||
return copy_to_user(p, bits, len) ? -EFAULT : len;
|
||||
}
|
||||
|
||||
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) {
|
||||
int len;
|
||||
len = NBITS(KEY_MAX) * sizeof(long);
|
||||
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
|
||||
return copy_to_user(p, dev->key, len) ? -EFAULT : len;
|
||||
}
|
||||
|
||||
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) {
|
||||
int len;
|
||||
len = NBITS(LED_MAX) * sizeof(long);
|
||||
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
|
||||
return copy_to_user(p, dev->led, len) ? -EFAULT : len;
|
||||
}
|
||||
|
||||
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) {
|
||||
int len;
|
||||
len = NBITS(SND_MAX) * sizeof(long);
|
||||
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
|
||||
return copy_to_user(p, dev->snd, len) ? -EFAULT : len;
|
||||
}
|
||||
|
||||
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
|
||||
int len;
|
||||
if (!dev->name) return -ENOENT;
|
||||
len = strlen(dev->name) + 1;
|
||||
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
|
||||
return copy_to_user(p, dev->name, len) ? -EFAULT : len;
|
||||
}
|
||||
|
||||
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) {
|
||||
int len;
|
||||
if (!dev->phys) return -ENOENT;
|
||||
len = strlen(dev->phys) + 1;
|
||||
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
|
||||
return copy_to_user(p, dev->phys, len) ? -EFAULT : len;
|
||||
}
|
||||
|
||||
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
|
||||
int len;
|
||||
if (!dev->uniq) return -ENOENT;
|
||||
len = strlen(dev->uniq) + 1;
|
||||
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
|
||||
return copy_to_user(p, dev->uniq, len) ? -EFAULT : len;
|
||||
}
|
||||
|
||||
if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
|
||||
|
||||
int t = _IOC_NR(cmd) & ABS_MAX;
|
||||
|
||||
abs.value = dev->abs[t];
|
||||
abs.minimum = dev->absmin[t];
|
||||
abs.maximum = dev->absmax[t];
|
||||
abs.fuzz = dev->absfuzz[t];
|
||||
abs.flat = dev->absflat[t];
|
||||
|
||||
if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
|
||||
|
||||
int t = _IOC_NR(cmd) & ABS_MAX;
|
||||
|
||||
if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
|
||||
return -EFAULT;
|
||||
|
||||
dev->abs[t] = abs.value;
|
||||
dev->absmin[t] = abs.minimum;
|
||||
dev->absmax[t] = abs.maximum;
|
||||
dev->absfuzz[t] = abs.fuzz;
|
||||
dev->absflat[t] = abs.flat;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct file_operations evdev_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = evdev_read,
|
||||
.write = evdev_write,
|
||||
.poll = evdev_poll,
|
||||
.open = evdev_open,
|
||||
.release = evdev_release,
|
||||
.ioctl = evdev_ioctl,
|
||||
.fasync = evdev_fasync,
|
||||
.flush = evdev_flush
|
||||
};
|
||||
|
||||
static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
|
||||
{
|
||||
struct evdev *evdev;
|
||||
int minor;
|
||||
|
||||
for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
|
||||
if (minor == EVDEV_MINORS) {
|
||||
printk(KERN_ERR "evdev: no more free evdev devices\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(evdev = kmalloc(sizeof(struct evdev), GFP_KERNEL)))
|
||||
return NULL;
|
||||
memset(evdev, 0, sizeof(struct evdev));
|
||||
|
||||
INIT_LIST_HEAD(&evdev->list);
|
||||
init_waitqueue_head(&evdev->wait);
|
||||
|
||||
evdev->exist = 1;
|
||||
evdev->minor = minor;
|
||||
evdev->handle.dev = dev;
|
||||
evdev->handle.name = evdev->name;
|
||||
evdev->handle.handler = handler;
|
||||
evdev->handle.private = evdev;
|
||||
sprintf(evdev->name, "event%d", minor);
|
||||
|
||||
evdev_table[minor] = evdev;
|
||||
|
||||
devfs_mk_cdev(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
|
||||
S_IFCHR|S_IRUGO|S_IWUSR, "input/event%d", minor);
|
||||
class_simple_device_add(input_class,
|
||||
MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
|
||||
dev->dev, "event%d", minor);
|
||||
|
||||
return &evdev->handle;
|
||||
}
|
||||
|
||||
static void evdev_disconnect(struct input_handle *handle)
|
||||
{
|
||||
struct evdev *evdev = handle->private;
|
||||
|
||||
class_simple_device_remove(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor));
|
||||
devfs_remove("input/event%d", evdev->minor);
|
||||
evdev->exist = 0;
|
||||
|
||||
if (evdev->open) {
|
||||
input_close_device(handle);
|
||||
wake_up_interruptible(&evdev->wait);
|
||||
} else
|
||||
evdev_free(evdev);
|
||||
}
|
||||
|
||||
static struct input_device_id evdev_ids[] = {
|
||||
{ .driver_info = 1 }, /* Matches all devices */
|
||||
{ }, /* Terminating zero entry */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(input, evdev_ids);
|
||||
|
||||
static struct input_handler evdev_handler = {
|
||||
.event = evdev_event,
|
||||
.connect = evdev_connect,
|
||||
.disconnect = evdev_disconnect,
|
||||
.fops = &evdev_fops,
|
||||
.minor = EVDEV_MINOR_BASE,
|
||||
.name = "evdev",
|
||||
.id_table = evdev_ids,
|
||||
};
|
||||
|
||||
static int __init evdev_init(void)
|
||||
{
|
||||
input_register_handler(&evdev_handler);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit evdev_exit(void)
|
||||
{
|
||||
input_unregister_handler(&evdev_handler);
|
||||
}
|
||||
|
||||
module_init(evdev_init);
|
||||
module_exit(evdev_exit);
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Input driver event char devices");
|
||||
MODULE_LICENSE("GPL");
|
||||
90
extra/linux-2.6.10/drivers/input/gameport/Kconfig
Normal file
90
extra/linux-2.6.10/drivers/input/gameport/Kconfig
Normal file
@@ -0,0 +1,90 @@
|
||||
#
|
||||
# Gameport configuration
|
||||
#
|
||||
config GAMEPORT
|
||||
tristate "Gameport support"
|
||||
---help---
|
||||
Gameport support is for the standard 15-pin PC gameport. If you
|
||||
have a joystick, gamepad, gameport card, a soundcard with a gameport
|
||||
or anything else that uses the gameport, say Y or M here and also to
|
||||
at least one of the hardware specific drivers.
|
||||
|
||||
For Ensoniq AudioPCI (ES1370), AudioPCI 97 (ES1371), ESS Solo1,
|
||||
S3 SonicVibes, Trident 4DWave, SiS7018, and ALi 5451 gameport
|
||||
support is provided by the sound drivers, so you won't need any
|
||||
from the below listed modules. You still need to say Y here.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called gameport.
|
||||
|
||||
|
||||
# Yes, SOUND_GAMEPORT looks a bit odd. Yes, it ends up being turned on
|
||||
# in every .config. Please don't touch it. It is here to handle an
|
||||
# unusual dependency between GAMEPORT and sound drivers.
|
||||
#
|
||||
# Some sound drivers call gameport functions. If GAMEPORT is
|
||||
# not selected, empty stubs are provided for the functions and all is
|
||||
# well.
|
||||
# If GAMEPORT is built in, everything is fine.
|
||||
# If GAMEPORT is a module, however, it would need to be loaded for the
|
||||
# sound driver to be able to link properly. Therefore, the sound
|
||||
# driver must be a module as well in that case. Since there's no way
|
||||
# to express that directly in Kconfig, we use SOUND_GAMEPORT to
|
||||
# express it. SOUND_GAMEPORT boils down to "if GAMEPORT is 'm',
|
||||
# anything that depends on SOUND_GAMEPORT must be 'm' as well. if
|
||||
# GAMEPORT is 'y' or 'n', it can be anything".
|
||||
config SOUND_GAMEPORT
|
||||
tristate
|
||||
default y if GAMEPORT!=m
|
||||
default m if GAMEPORT=m
|
||||
|
||||
config GAMEPORT_NS558
|
||||
tristate "Classic ISA and PnP gameport support"
|
||||
depends on GAMEPORT
|
||||
help
|
||||
Say Y here if you have an ISA or PnP gameport.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ns558.
|
||||
|
||||
config GAMEPORT_L4
|
||||
tristate "PDPI Lightning 4 gamecard support"
|
||||
depends on GAMEPORT
|
||||
help
|
||||
Say Y here if you have a PDPI Lightning 4 gamecard.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called lightning.
|
||||
|
||||
config GAMEPORT_EMU10K1
|
||||
tristate "SB Live and Audigy gameport support"
|
||||
depends on GAMEPORT
|
||||
help
|
||||
Say Y here if you have a SoundBlaster Live! or SoundBlaster
|
||||
Audigy card and want to use its gameport.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called emu10k1-gp.
|
||||
|
||||
config GAMEPORT_VORTEX
|
||||
tristate "Aureal Vortex, Vortex 2 gameport support"
|
||||
depends on GAMEPORT
|
||||
help
|
||||
Say Y here if you have an Aureal Vortex 1 or 2 card and want
|
||||
to use its gameport.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called vortex.
|
||||
|
||||
config GAMEPORT_FM801
|
||||
tristate "ForteMedia FM801 gameport support"
|
||||
depends on GAMEPORT
|
||||
|
||||
config GAMEPORT_CS461x
|
||||
tristate "Crystal SoundFusion gameport support"
|
||||
depends on GAMEPORT
|
||||
|
||||
13
extra/linux-2.6.10/drivers/input/gameport/Makefile
Normal file
13
extra/linux-2.6.10/drivers/input/gameport/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
#
|
||||
# Makefile for the gameport drivers.
|
||||
#
|
||||
|
||||
# Each configuration option enables a list of files.
|
||||
|
||||
obj-$(CONFIG_GAMEPORT) += gameport.o
|
||||
obj-$(CONFIG_GAMEPORT_CS461X) += cs461x.o
|
||||
obj-$(CONFIG_GAMEPORT_EMU10K1) += emu10k1-gp.o
|
||||
obj-$(CONFIG_GAMEPORT_FM801) += fm801-gp.o
|
||||
obj-$(CONFIG_GAMEPORT_L4) += lightning.o
|
||||
obj-$(CONFIG_GAMEPORT_NS558) += ns558.o
|
||||
obj-$(CONFIG_GAMEPORT_VORTEX) += vortex.o
|
||||
333
extra/linux-2.6.10/drivers/input/gameport/cs461x.c
Normal file
333
extra/linux-2.6.10/drivers/input/gameport/cs461x.c
Normal file
@@ -0,0 +1,333 @@
|
||||
/*
|
||||
The all defines and part of code (such as cs461x_*) are
|
||||
contributed from ALSA 0.5.8 sources.
|
||||
See http://www.alsa-project.org/ for sources
|
||||
|
||||
Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610
|
||||
*/
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/config.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/gameport.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
MODULE_AUTHOR("Victor Krapivin <vik@belcaf.minsk.by>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
These options are experimental
|
||||
|
||||
#define CS461X_FULL_MAP
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PCI_VENDOR_ID_CIRRUS
|
||||
#define PCI_VENDOR_ID_CIRRUS 0x1013
|
||||
#endif
|
||||
#ifndef PCI_DEVICE_ID_CIRRUS_4610
|
||||
#define PCI_DEVICE_ID_CIRRUS_4610 0x6001
|
||||
#endif
|
||||
#ifndef PCI_DEVICE_ID_CIRRUS_4612
|
||||
#define PCI_DEVICE_ID_CIRRUS_4612 0x6003
|
||||
#endif
|
||||
#ifndef PCI_DEVICE_ID_CIRRUS_4615
|
||||
#define PCI_DEVICE_ID_CIRRUS_4615 0x6004
|
||||
#endif
|
||||
|
||||
/* Registers */
|
||||
|
||||
#define BA0_JSPT 0x00000480
|
||||
#define BA0_JSCTL 0x00000484
|
||||
#define BA0_JSC1 0x00000488
|
||||
#define BA0_JSC2 0x0000048C
|
||||
#define BA0_JSIO 0x000004A0
|
||||
|
||||
/* Bits for JSPT */
|
||||
|
||||
#define JSPT_CAX 0x00000001
|
||||
#define JSPT_CAY 0x00000002
|
||||
#define JSPT_CBX 0x00000004
|
||||
#define JSPT_CBY 0x00000008
|
||||
#define JSPT_BA1 0x00000010
|
||||
#define JSPT_BA2 0x00000020
|
||||
#define JSPT_BB1 0x00000040
|
||||
#define JSPT_BB2 0x00000080
|
||||
|
||||
/* Bits for JSCTL */
|
||||
|
||||
#define JSCTL_SP_MASK 0x00000003
|
||||
#define JSCTL_SP_SLOW 0x00000000
|
||||
#define JSCTL_SP_MEDIUM_SLOW 0x00000001
|
||||
#define JSCTL_SP_MEDIUM_FAST 0x00000002
|
||||
#define JSCTL_SP_FAST 0x00000003
|
||||
#define JSCTL_ARE 0x00000004
|
||||
|
||||
/* Data register pairs masks */
|
||||
|
||||
#define JSC1_Y1V_MASK 0x0000FFFF
|
||||
#define JSC1_X1V_MASK 0xFFFF0000
|
||||
#define JSC1_Y1V_SHIFT 0
|
||||
#define JSC1_X1V_SHIFT 16
|
||||
#define JSC2_Y2V_MASK 0x0000FFFF
|
||||
#define JSC2_X2V_MASK 0xFFFF0000
|
||||
#define JSC2_Y2V_SHIFT 0
|
||||
#define JSC2_X2V_SHIFT 16
|
||||
|
||||
/* JS GPIO */
|
||||
|
||||
#define JSIO_DAX 0x00000001
|
||||
#define JSIO_DAY 0x00000002
|
||||
#define JSIO_DBX 0x00000004
|
||||
#define JSIO_DBY 0x00000008
|
||||
#define JSIO_AXOE 0x00000010
|
||||
#define JSIO_AYOE 0x00000020
|
||||
#define JSIO_BXOE 0x00000040
|
||||
#define JSIO_BYOE 0x00000080
|
||||
|
||||
/*
|
||||
The card initialization code is obfuscated; the module cs461x
|
||||
need to be loaded after ALSA modules initialized and something
|
||||
played on the CS 4610 chip (see sources for details of CS4610
|
||||
initialization code from ALSA)
|
||||
*/
|
||||
|
||||
/* Card specific definitions */
|
||||
|
||||
#define CS461X_BA0_SIZE 0x2000
|
||||
#define CS461X_BA1_DATA0_SIZE 0x3000
|
||||
#define CS461X_BA1_DATA1_SIZE 0x3800
|
||||
#define CS461X_BA1_PRG_SIZE 0x7000
|
||||
#define CS461X_BA1_REG_SIZE 0x0100
|
||||
|
||||
#define BA1_SP_DMEM0 0x00000000
|
||||
#define BA1_SP_DMEM1 0x00010000
|
||||
#define BA1_SP_PMEM 0x00020000
|
||||
#define BA1_SP_REG 0x00030000
|
||||
|
||||
#define BA1_DWORD_SIZE (13 * 1024 + 512)
|
||||
#define BA1_MEMORY_COUNT 3
|
||||
|
||||
/*
|
||||
Only one CS461x card is still suppoted; the code requires
|
||||
redesign to avoid this limitatuion.
|
||||
*/
|
||||
|
||||
static unsigned long ba0_addr;
|
||||
static unsigned int *ba0;
|
||||
|
||||
static char phys[32];
|
||||
static char name[] = "CS416x Gameport";
|
||||
|
||||
#ifdef CS461X_FULL_MAP
|
||||
static unsigned long ba1_addr;
|
||||
static union ba1_t {
|
||||
struct {
|
||||
unsigned int *data0;
|
||||
unsigned int *data1;
|
||||
unsigned int *pmem;
|
||||
unsigned int *reg;
|
||||
} name;
|
||||
unsigned int *idx[4];
|
||||
} ba1;
|
||||
|
||||
static void cs461x_poke(unsigned long reg, unsigned int val)
|
||||
{
|
||||
ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff] = val;
|
||||
}
|
||||
|
||||
static unsigned int cs461x_peek(unsigned long reg)
|
||||
{
|
||||
return ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void cs461x_pokeBA0(unsigned long reg, unsigned int val)
|
||||
{
|
||||
ba0[reg >> 2] = val;
|
||||
}
|
||||
|
||||
static unsigned int cs461x_peekBA0(unsigned long reg)
|
||||
{
|
||||
return ba0[reg >> 2];
|
||||
}
|
||||
|
||||
static int cs461x_free(struct pci_dev *pdev)
|
||||
{
|
||||
struct gameport *port = pci_get_drvdata(pdev);
|
||||
if(port){
|
||||
gameport_unregister_port(port);
|
||||
kfree(port);
|
||||
}
|
||||
if (ba0) iounmap(ba0);
|
||||
#ifdef CS461X_FULL_MAP
|
||||
if (ba1.name.data0) iounmap(ba1.name.data0);
|
||||
if (ba1.name.data1) iounmap(ba1.name.data1);
|
||||
if (ba1.name.pmem) iounmap(ba1.name.pmem);
|
||||
if (ba1.name.reg) iounmap(ba1.name.reg);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cs461x_gameport_trigger(struct gameport *gameport)
|
||||
{
|
||||
cs461x_pokeBA0(BA0_JSPT, 0xFF); //outb(gameport->io, 0xFF);
|
||||
}
|
||||
|
||||
static unsigned char cs461x_gameport_read(struct gameport *gameport)
|
||||
{
|
||||
return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io);
|
||||
}
|
||||
|
||||
static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
|
||||
{
|
||||
unsigned js1, js2, jst;
|
||||
|
||||
js1 = cs461x_peekBA0(BA0_JSC1);
|
||||
js2 = cs461x_peekBA0(BA0_JSC2);
|
||||
jst = cs461x_peekBA0(BA0_JSPT);
|
||||
|
||||
*buttons = (~jst >> 4) & 0x0F;
|
||||
|
||||
axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF;
|
||||
axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF;
|
||||
axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF;
|
||||
axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF;
|
||||
|
||||
for(jst=0;jst<4;++jst)
|
||||
if(axes[jst]==0xFFFF) axes[jst] = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs461x_gameport_open(struct gameport *gameport, int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case GAMEPORT_MODE_COOKED:
|
||||
case GAMEPORT_MODE_RAW:
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pci_device_id cs461x_pci_tbl[] = {
|
||||
{ PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4610 */
|
||||
{ PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4612 */
|
||||
{ PCI_VENDOR_ID_CIRRUS, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4615 */
|
||||
{ 0, }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl);
|
||||
|
||||
static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
int rc;
|
||||
struct gameport* port;
|
||||
|
||||
rc = pci_enable_device(pdev);
|
||||
if (rc) {
|
||||
printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
|
||||
pdev->bus->number, pdev->devfn, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
ba0_addr = pci_resource_start(pdev, 0);
|
||||
#ifdef CS461X_FULL_MAP
|
||||
ba1_addr = pci_resource_start(pdev, 1);
|
||||
#endif
|
||||
if (ba0_addr == 0 || ba0_addr == ~0
|
||||
#ifdef CS461X_FULL_MAP
|
||||
|| ba1_addr == 0 || ba1_addr == ~0
|
||||
#endif
|
||||
) {
|
||||
printk(KERN_ERR "cs461x: wrong address - ba0 = 0x%lx\n", ba0_addr);
|
||||
#ifdef CS461X_FULL_MAP
|
||||
printk(KERN_ERR "cs461x: wrong address - ba1 = 0x%lx\n", ba1_addr);
|
||||
#endif
|
||||
cs461x_free(pdev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ba0 = ioremap(ba0_addr, CS461X_BA0_SIZE);
|
||||
#ifdef CS461X_FULL_MAP
|
||||
ba1.name.data0 = ioremap(ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
|
||||
ba1.name.data1 = ioremap(ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
|
||||
ba1.name.pmem = ioremap(ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
|
||||
ba1.name.reg = ioremap(ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
|
||||
|
||||
if (ba0 == NULL || ba1.name.data0 == NULL ||
|
||||
ba1.name.data1 == NULL || ba1.name.pmem == NULL ||
|
||||
ba1.name.reg == NULL) {
|
||||
cs461x_free(pdev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
#else
|
||||
if (ba0 == NULL){
|
||||
cs461x_free(pdev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(port = kmalloc(sizeof(struct gameport), GFP_KERNEL))) {
|
||||
printk(KERN_ERR "Memory allocation failed.\n");
|
||||
cs461x_free(pdev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(port, 0, sizeof(struct gameport));
|
||||
|
||||
pci_set_drvdata(pdev, port);
|
||||
|
||||
port->open = cs461x_gameport_open;
|
||||
port->trigger = cs461x_gameport_trigger;
|
||||
port->read = cs461x_gameport_read;
|
||||
port->cooked_read = cs461x_gameport_cooked_read;
|
||||
|
||||
sprintf(phys, "pci%s/gameport0", pci_name(pdev));
|
||||
|
||||
port->name = name;
|
||||
port->phys = phys;
|
||||
port->id.bustype = BUS_PCI;
|
||||
port->id.vendor = pdev->vendor;
|
||||
port->id.product = pdev->device;
|
||||
|
||||
cs461x_pokeBA0(BA0_JSIO, 0xFF); // ?
|
||||
cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
|
||||
|
||||
gameport_register_port(port);
|
||||
|
||||
printk(KERN_INFO "gameport: %s on pci%s speed %d kHz\n",
|
||||
name, pci_name(pdev), port->speed);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __devexit cs461x_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
cs461x_free(pdev);
|
||||
}
|
||||
|
||||
static struct pci_driver cs461x_pci_driver = {
|
||||
.name = "CS461x_gameport",
|
||||
.id_table = cs461x_pci_tbl,
|
||||
.probe = cs461x_pci_probe,
|
||||
.remove = __devexit_p(cs461x_pci_remove),
|
||||
};
|
||||
|
||||
int __init cs461x_init(void)
|
||||
{
|
||||
return pci_module_init(&cs461x_pci_driver);
|
||||
}
|
||||
|
||||
void __exit cs461x_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&cs461x_pci_driver);
|
||||
}
|
||||
|
||||
module_init(cs461x_init);
|
||||
module_exit(cs461x_exit);
|
||||
|
||||
132
extra/linux-2.6.10/drivers/input/gameport/emu10k1-gp.c
Normal file
132
extra/linux-2.6.10/drivers/input/gameport/emu10k1-gp.c
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* $Id: emu10k1-gp.c,v 1.8 2002/01/22 20:40:46 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 2001 Vojtech Pavlik
|
||||
*/
|
||||
|
||||
/*
|
||||
* EMU10k1 - SB Live / Audigy - gameport driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/config.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/gameport.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("EMU10k1 gameport driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
struct emu {
|
||||
struct pci_dev *dev;
|
||||
struct gameport gameport;
|
||||
int size;
|
||||
char phys[32];
|
||||
};
|
||||
|
||||
static struct pci_device_id emu_tbl[] = {
|
||||
|
||||
{ 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */
|
||||
{ 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */
|
||||
{ 0x1102, 0x7004, PCI_ANY_ID, PCI_ANY_ID }, /* Dell SB Live */
|
||||
{ 0x1102, 0x7005, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy LS gameport */
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, emu_tbl);
|
||||
|
||||
static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
int ioport, iolen;
|
||||
struct emu *emu;
|
||||
|
||||
if (pci_enable_device(pdev))
|
||||
return -EBUSY;
|
||||
|
||||
ioport = pci_resource_start(pdev, 0);
|
||||
iolen = pci_resource_len(pdev, 0);
|
||||
|
||||
if (!request_region(ioport, iolen, "emu10k1-gp"))
|
||||
return -EBUSY;
|
||||
|
||||
if (!(emu = kmalloc(sizeof(struct emu), GFP_KERNEL))) {
|
||||
printk(KERN_ERR "emu10k1-gp: Memory allocation failed.\n");
|
||||
release_region(ioport, iolen);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(emu, 0, sizeof(struct emu));
|
||||
|
||||
sprintf(emu->phys, "pci%s/gameport0", pci_name(pdev));
|
||||
|
||||
emu->size = iolen;
|
||||
emu->dev = pdev;
|
||||
|
||||
emu->gameport.io = ioport;
|
||||
emu->gameport.name = pci_name(pdev);
|
||||
emu->gameport.phys = emu->phys;
|
||||
emu->gameport.id.bustype = BUS_PCI;
|
||||
emu->gameport.id.vendor = pdev->vendor;
|
||||
emu->gameport.id.product = pdev->device;
|
||||
|
||||
pci_set_drvdata(pdev, emu);
|
||||
|
||||
gameport_register_port(&emu->gameport);
|
||||
|
||||
printk(KERN_INFO "gameport: pci%s speed %d kHz\n",
|
||||
pci_name(pdev), emu->gameport.speed);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __devexit emu_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct emu *emu = pci_get_drvdata(pdev);
|
||||
gameport_unregister_port(&emu->gameport);
|
||||
release_region(emu->gameport.io, emu->size);
|
||||
kfree(emu);
|
||||
}
|
||||
|
||||
static struct pci_driver emu_driver = {
|
||||
.name = "Emu10k1_gameport",
|
||||
.id_table = emu_tbl,
|
||||
.probe = emu_probe,
|
||||
.remove = __devexit_p(emu_remove),
|
||||
};
|
||||
|
||||
int __init emu_init(void)
|
||||
{
|
||||
return pci_module_init(&emu_driver);
|
||||
}
|
||||
|
||||
void __exit emu_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&emu_driver);
|
||||
}
|
||||
|
||||
module_init(emu_init);
|
||||
module_exit(emu_exit);
|
||||
162
extra/linux-2.6.10/drivers/input/gameport/fm801-gp.c
Normal file
162
extra/linux-2.6.10/drivers/input/gameport/fm801-gp.c
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* FM801 gameport driver for Linux
|
||||
*
|
||||
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gameport.h>
|
||||
|
||||
#define PCI_VENDOR_ID_FORTEMEDIA 0x1319
|
||||
#define PCI_DEVICE_ID_FM801_GP 0x0802
|
||||
|
||||
#define HAVE_COOKED
|
||||
|
||||
struct fm801_gp {
|
||||
struct gameport gameport;
|
||||
struct resource *res_port;
|
||||
char phys[32];
|
||||
char name[32];
|
||||
};
|
||||
|
||||
#ifdef HAVE_COOKED
|
||||
static int fm801_gp_cooked_read(struct gameport *gameport, int *axes, int *buttons)
|
||||
{
|
||||
unsigned short w;
|
||||
|
||||
w = inw(gameport->io + 2);
|
||||
*buttons = (~w >> 14) & 0x03;
|
||||
axes[0] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
|
||||
w = inw(gameport->io + 4);
|
||||
axes[1] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
|
||||
w = inw(gameport->io + 6);
|
||||
*buttons |= ((~w >> 14) & 0x03) << 2;
|
||||
axes[2] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
|
||||
w = inw(gameport->io + 8);
|
||||
axes[3] = (w == 0xffff) ? -1 : ((w & 0x1fff) << 5);
|
||||
outw(0xff, gameport->io); /* reset */
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int fm801_gp_open(struct gameport *gameport, int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
#ifdef HAVE_COOKED
|
||||
case GAMEPORT_MODE_COOKED:
|
||||
return 0;
|
||||
#endif
|
||||
case GAMEPORT_MODE_RAW:
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device_id *id)
|
||||
{
|
||||
struct fm801_gp *gp;
|
||||
|
||||
if (! (gp = kmalloc(sizeof(*gp), GFP_KERNEL))) {
|
||||
printk("cannot malloc for fm801-gp\n");
|
||||
return -1;
|
||||
}
|
||||
memset(gp, 0, sizeof(*gp));
|
||||
|
||||
gp->gameport.open = fm801_gp_open;
|
||||
#ifdef HAVE_COOKED
|
||||
gp->gameport.cooked_read = fm801_gp_cooked_read;
|
||||
#endif
|
||||
|
||||
pci_enable_device(pci);
|
||||
gp->gameport.io = pci_resource_start(pci, 0);
|
||||
if ((gp->res_port = request_region(gp->gameport.io, 0x10, "FM801 GP")) == NULL) {
|
||||
printk("unable to grab region 0x%x-0x%x\n", gp->gameport.io, gp->gameport.io + 0x0f);
|
||||
kfree(gp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
gp->gameport.phys = gp->phys;
|
||||
gp->gameport.name = gp->name;
|
||||
gp->gameport.id.bustype = BUS_PCI;
|
||||
gp->gameport.id.vendor = pci->vendor;
|
||||
gp->gameport.id.product = pci->device;
|
||||
|
||||
pci_set_drvdata(pci, gp);
|
||||
|
||||
outb(0x60, gp->gameport.io + 0x0d); /* enable joystick 1 and 2 */
|
||||
|
||||
gameport_register_port(&gp->gameport);
|
||||
|
||||
printk(KERN_INFO "gameport: at pci%s speed %d kHz\n",
|
||||
pci_name(pci), gp->gameport.speed);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __devexit fm801_gp_remove(struct pci_dev *pci)
|
||||
{
|
||||
struct fm801_gp *gp = pci_get_drvdata(pci);
|
||||
if (gp) {
|
||||
gameport_unregister_port(&gp->gameport);
|
||||
release_resource(gp->res_port);
|
||||
kfree(gp);
|
||||
}
|
||||
}
|
||||
|
||||
static struct pci_device_id fm801_gp_id_table[] = {
|
||||
{ PCI_VENDOR_ID_FORTEMEDIA, PCI_DEVICE_ID_FM801_GP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static struct pci_driver fm801_gp_driver = {
|
||||
.name = "FM801_gameport",
|
||||
.id_table = fm801_gp_id_table,
|
||||
.probe = fm801_gp_probe,
|
||||
.remove = __devexit_p(fm801_gp_remove),
|
||||
};
|
||||
|
||||
int __init fm801_gp_init(void)
|
||||
{
|
||||
return pci_module_init(&fm801_gp_driver);
|
||||
}
|
||||
|
||||
void __exit fm801_gp_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&fm801_gp_driver);
|
||||
}
|
||||
|
||||
module_init(fm801_gp_init);
|
||||
module_exit(fm801_gp_exit);
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, fm801_gp_id_table);
|
||||
|
||||
MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
|
||||
MODULE_LICENSE("GPL");
|
||||
180
extra/linux-2.6.10/drivers/input/gameport/gameport.c
Normal file
180
extra/linux-2.6.10/drivers/input/gameport/gameport.c
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Generic gameport layer
|
||||
*
|
||||
* Copyright (c) 1999-2002 Vojtech Pavlik
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/gameport.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Generic gameport layer");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
EXPORT_SYMBOL(gameport_register_port);
|
||||
EXPORT_SYMBOL(gameport_unregister_port);
|
||||
EXPORT_SYMBOL(gameport_register_device);
|
||||
EXPORT_SYMBOL(gameport_unregister_device);
|
||||
EXPORT_SYMBOL(gameport_open);
|
||||
EXPORT_SYMBOL(gameport_close);
|
||||
EXPORT_SYMBOL(gameport_rescan);
|
||||
EXPORT_SYMBOL(gameport_cooked_read);
|
||||
|
||||
static LIST_HEAD(gameport_list);
|
||||
static LIST_HEAD(gameport_dev_list);
|
||||
|
||||
#ifdef __i386__
|
||||
|
||||
#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193182/HZ:0))
|
||||
#define GET_TIME(x) do { x = get_time_pit(); } while (0)
|
||||
|
||||
static unsigned int get_time_pit(void)
|
||||
{
|
||||
extern spinlock_t i8253_lock;
|
||||
unsigned long flags;
|
||||
unsigned int count;
|
||||
|
||||
spin_lock_irqsave(&i8253_lock, flags);
|
||||
outb_p(0x00, 0x43);
|
||||
count = inb_p(0x40);
|
||||
count |= inb_p(0x40) << 8;
|
||||
spin_unlock_irqrestore(&i8253_lock, flags);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* gameport_measure_speed() measures the gameport i/o speed.
|
||||
*/
|
||||
|
||||
static int gameport_measure_speed(struct gameport *gameport)
|
||||
{
|
||||
#ifdef __i386__
|
||||
|
||||
unsigned int i, t, t1, t2, t3, tx;
|
||||
unsigned long flags;
|
||||
|
||||
if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))
|
||||
return 0;
|
||||
|
||||
tx = 1 << 30;
|
||||
|
||||
for(i = 0; i < 50; i++) {
|
||||
local_irq_save(flags);
|
||||
GET_TIME(t1);
|
||||
for(t = 0; t < 50; t++) gameport_read(gameport);
|
||||
GET_TIME(t2);
|
||||
GET_TIME(t3);
|
||||
local_irq_restore(flags);
|
||||
udelay(i * 10);
|
||||
if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t;
|
||||
}
|
||||
|
||||
gameport_close(gameport);
|
||||
return 59659 / (tx < 1 ? 1 : tx);
|
||||
|
||||
#else
|
||||
|
||||
unsigned int j, t = 0;
|
||||
|
||||
j = jiffies; while (j == jiffies);
|
||||
j = jiffies; while (j == jiffies) { t++; gameport_read(gameport); }
|
||||
|
||||
gameport_close(gameport);
|
||||
return t * HZ / 1000;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
static void gameport_find_dev(struct gameport *gameport)
|
||||
{
|
||||
struct gameport_dev *dev;
|
||||
|
||||
list_for_each_entry(dev, &gameport_dev_list, node) {
|
||||
if (gameport->dev)
|
||||
break;
|
||||
if (dev->connect)
|
||||
dev->connect(gameport, dev);
|
||||
}
|
||||
}
|
||||
|
||||
void gameport_rescan(struct gameport *gameport)
|
||||
{
|
||||
gameport_close(gameport);
|
||||
gameport_find_dev(gameport);
|
||||
}
|
||||
|
||||
void gameport_register_port(struct gameport *gameport)
|
||||
{
|
||||
list_add_tail(&gameport->node, &gameport_list);
|
||||
gameport->speed = gameport_measure_speed(gameport);
|
||||
gameport_find_dev(gameport);
|
||||
}
|
||||
|
||||
void gameport_unregister_port(struct gameport *gameport)
|
||||
{
|
||||
list_del_init(&gameport->node);
|
||||
if (gameport->dev && gameport->dev->disconnect)
|
||||
gameport->dev->disconnect(gameport);
|
||||
}
|
||||
|
||||
void gameport_register_device(struct gameport_dev *dev)
|
||||
{
|
||||
struct gameport *gameport;
|
||||
|
||||
list_add_tail(&dev->node, &gameport_dev_list);
|
||||
list_for_each_entry(gameport, &gameport_list, node)
|
||||
if (!gameport->dev && dev->connect)
|
||||
dev->connect(gameport, dev);
|
||||
}
|
||||
|
||||
void gameport_unregister_device(struct gameport_dev *dev)
|
||||
{
|
||||
struct gameport *gameport;
|
||||
|
||||
list_del_init(&dev->node);
|
||||
list_for_each_entry(gameport, &gameport_list, node) {
|
||||
if (gameport->dev == dev && dev->disconnect)
|
||||
dev->disconnect(gameport);
|
||||
gameport_find_dev(gameport);
|
||||
}
|
||||
}
|
||||
|
||||
int gameport_open(struct gameport *gameport, struct gameport_dev *dev, int mode)
|
||||
{
|
||||
if (gameport->open) {
|
||||
if (gameport->open(gameport, mode))
|
||||
return -1;
|
||||
} else {
|
||||
if (mode != GAMEPORT_MODE_RAW)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (gameport->dev)
|
||||
return -1;
|
||||
|
||||
gameport->dev = dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gameport_close(struct gameport *gameport)
|
||||
{
|
||||
gameport->dev = NULL;
|
||||
if (gameport->close)
|
||||
gameport->close(gameport);
|
||||
}
|
||||
304
extra/linux-2.6.10/drivers/input/gameport/lightning.c
Normal file
304
extra/linux-2.6.10/drivers/input/gameport/lightning.c
Normal file
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* $Id: lightning.c,v 1.20 2002/01/22 20:41:31 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1998-2001 Vojtech Pavlik
|
||||
*/
|
||||
|
||||
/*
|
||||
* PDPI Lightning 4 gamecard driver for Linux.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/gameport.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define L4_PORT 0x201
|
||||
#define L4_SELECT_ANALOG 0xa4
|
||||
#define L4_SELECT_DIGITAL 0xa5
|
||||
#define L4_SELECT_SECONDARY 0xa6
|
||||
#define L4_CMD_ID 0x80
|
||||
#define L4_CMD_GETCAL 0x92
|
||||
#define L4_CMD_SETCAL 0x93
|
||||
#define L4_ID 0x04
|
||||
#define L4_BUSY 0x01
|
||||
#define L4_TIMEOUT 80 /* 80 us */
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("PDPI Lightning 4 gamecard driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
struct l4 {
|
||||
struct gameport gameport;
|
||||
unsigned char port;
|
||||
char phys[32];
|
||||
} *l4_port[8];
|
||||
|
||||
char l4_name[] = "PDPI Lightning 4";
|
||||
|
||||
/*
|
||||
* l4_wait_ready() waits for the L4 to become ready.
|
||||
*/
|
||||
|
||||
static int l4_wait_ready(void)
|
||||
{
|
||||
unsigned int t;
|
||||
t = L4_TIMEOUT;
|
||||
while ((inb(L4_PORT) & L4_BUSY) && t > 0) t--;
|
||||
return -(t<=0);
|
||||
}
|
||||
|
||||
/*
|
||||
* l4_cooked_read() reads data from the Lightning 4.
|
||||
*/
|
||||
|
||||
static int l4_cooked_read(struct gameport *gameport, int *axes, int *buttons)
|
||||
{
|
||||
struct l4 *l4 = gameport->driver;
|
||||
unsigned char status;
|
||||
int i, result = -1;
|
||||
|
||||
outb(L4_SELECT_ANALOG, L4_PORT);
|
||||
outb(L4_SELECT_DIGITAL + (l4->port >> 2), L4_PORT);
|
||||
|
||||
if (inb(L4_PORT) & L4_BUSY) goto fail;
|
||||
outb(l4->port & 3, L4_PORT);
|
||||
|
||||
if (l4_wait_ready()) goto fail;
|
||||
status = inb(L4_PORT);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
if (status & (1 << i)) {
|
||||
if (l4_wait_ready()) goto fail;
|
||||
axes[i] = inb(L4_PORT);
|
||||
if (axes[i] > 252) axes[i] = -1;
|
||||
}
|
||||
|
||||
if (status & 0x10) {
|
||||
if (l4_wait_ready()) goto fail;
|
||||
*buttons = inb(L4_PORT) & 0x0f;
|
||||
}
|
||||
|
||||
result = 0;
|
||||
|
||||
fail: outb(L4_SELECT_ANALOG, L4_PORT);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int l4_open(struct gameport *gameport, int mode)
|
||||
{
|
||||
struct l4 *l4 = gameport->driver;
|
||||
if (l4->port != 0 && mode != GAMEPORT_MODE_COOKED)
|
||||
return -1;
|
||||
outb(L4_SELECT_ANALOG, L4_PORT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* l4_getcal() reads the L4 with calibration values.
|
||||
*/
|
||||
|
||||
static int l4_getcal(int port, int *cal)
|
||||
{
|
||||
int i, result = -1;
|
||||
|
||||
outb(L4_SELECT_ANALOG, L4_PORT);
|
||||
outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
|
||||
|
||||
if (inb(L4_PORT) & L4_BUSY) goto fail;
|
||||
outb(L4_CMD_GETCAL, L4_PORT);
|
||||
|
||||
if (l4_wait_ready()) goto fail;
|
||||
if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2)) goto fail;
|
||||
|
||||
if (l4_wait_ready()) goto fail;
|
||||
outb(port & 3, L4_PORT);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (l4_wait_ready()) goto fail;
|
||||
cal[i] = inb(L4_PORT);
|
||||
}
|
||||
|
||||
result = 0;
|
||||
|
||||
fail: outb(L4_SELECT_ANALOG, L4_PORT);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* l4_setcal() programs the L4 with calibration values.
|
||||
*/
|
||||
|
||||
static int l4_setcal(int port, int *cal)
|
||||
{
|
||||
int i, result = -1;
|
||||
|
||||
outb(L4_SELECT_ANALOG, L4_PORT);
|
||||
outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
|
||||
|
||||
if (inb(L4_PORT) & L4_BUSY) goto fail;
|
||||
outb(L4_CMD_SETCAL, L4_PORT);
|
||||
|
||||
if (l4_wait_ready()) goto fail;
|
||||
if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2)) goto fail;
|
||||
|
||||
if (l4_wait_ready()) goto fail;
|
||||
outb(port & 3, L4_PORT);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (l4_wait_ready()) goto fail;
|
||||
outb(cal[i], L4_PORT);
|
||||
}
|
||||
|
||||
result = 0;
|
||||
|
||||
fail: outb(L4_SELECT_ANALOG, L4_PORT);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* l4_calibrate() calibrates the L4 for the attached device, so
|
||||
* that the device's resistance fits into the L4's 8-bit range.
|
||||
*/
|
||||
|
||||
static int l4_calibrate(struct gameport *gameport, int *axes, int *max)
|
||||
{
|
||||
int i, t;
|
||||
int cal[4];
|
||||
struct l4 *l4 = gameport->driver;
|
||||
|
||||
if (l4_getcal(l4->port, cal))
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
t = (max[i] * cal[i]) / 200;
|
||||
t = (t < 1) ? 1 : ((t > 255) ? 255 : t);
|
||||
axes[i] = (axes[i] < 0) ? -1 : (axes[i] * cal[i]) / t;
|
||||
axes[i] = (axes[i] > 252) ? 252 : axes[i];
|
||||
cal[i] = t;
|
||||
}
|
||||
|
||||
if (l4_setcal(l4->port, cal))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init l4_init(void)
|
||||
{
|
||||
int cal[4] = {255,255,255,255};
|
||||
int i, j, rev, cards = 0;
|
||||
struct gameport *gameport;
|
||||
struct l4 *l4;
|
||||
|
||||
if (!request_region(L4_PORT, 1, "lightning"))
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
|
||||
outb(L4_SELECT_ANALOG, L4_PORT);
|
||||
outb(L4_SELECT_DIGITAL + i, L4_PORT);
|
||||
|
||||
if (inb(L4_PORT) & L4_BUSY) continue;
|
||||
outb(L4_CMD_ID, L4_PORT);
|
||||
|
||||
if (l4_wait_ready()) continue;
|
||||
if (inb(L4_PORT) != L4_SELECT_DIGITAL + i) continue;
|
||||
|
||||
if (l4_wait_ready()) continue;
|
||||
if (inb(L4_PORT) != L4_ID) continue;
|
||||
|
||||
if (l4_wait_ready()) continue;
|
||||
rev = inb(L4_PORT);
|
||||
|
||||
if (!rev) continue;
|
||||
|
||||
if (!(l4_port[i * 4] = kmalloc(sizeof(struct l4) * 4, GFP_KERNEL))) {
|
||||
printk(KERN_ERR "lightning: Out of memory allocating ports.\n");
|
||||
continue;
|
||||
}
|
||||
memset(l4_port[i * 4], 0, sizeof(struct l4) * 4);
|
||||
|
||||
for (j = 0; j < 4; j++) {
|
||||
|
||||
l4 = l4_port[i * 4 + j] = l4_port[i * 4] + j;
|
||||
l4->port = i * 4 + j;
|
||||
|
||||
sprintf(l4->phys, "isa%04x/gameport%d", L4_PORT, 4 * i + j);
|
||||
|
||||
gameport = &l4->gameport;
|
||||
gameport->driver = l4;
|
||||
gameport->open = l4_open;
|
||||
gameport->cooked_read = l4_cooked_read;
|
||||
gameport->calibrate = l4_calibrate;
|
||||
|
||||
gameport->name = l4_name;
|
||||
gameport->phys = l4->phys;
|
||||
gameport->id.bustype = BUS_ISA;
|
||||
|
||||
if (!i && !j)
|
||||
gameport->io = L4_PORT;
|
||||
|
||||
if (rev > 0x28) /* on 2.9+ the setcal command works correctly */
|
||||
l4_setcal(l4->port, cal);
|
||||
|
||||
gameport_register_port(gameport);
|
||||
}
|
||||
|
||||
printk(KERN_INFO "gameport: PDPI Lightning 4 %s card v%d.%d at %#x\n",
|
||||
i ? "secondary" : "primary", rev >> 4, rev, L4_PORT);
|
||||
|
||||
cards++;
|
||||
}
|
||||
|
||||
outb(L4_SELECT_ANALOG, L4_PORT);
|
||||
|
||||
if (!cards) {
|
||||
release_region(L4_PORT, 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit l4_exit(void)
|
||||
{
|
||||
int i;
|
||||
int cal[4] = {59, 59, 59, 59};
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
if (l4_port[i]) {
|
||||
l4_setcal(l4_port[i]->port, cal);
|
||||
gameport_unregister_port(&l4_port[i]->gameport);
|
||||
}
|
||||
outb(L4_SELECT_ANALOG, L4_PORT);
|
||||
release_region(L4_PORT, 1);
|
||||
}
|
||||
|
||||
module_init(l4_init);
|
||||
module_exit(l4_exit);
|
||||
304
extra/linux-2.6.10/drivers/input/gameport/ns558.c
Normal file
304
extra/linux-2.6.10/drivers/input/gameport/ns558.c
Normal file
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* $Id: ns558.c,v 1.43 2002/01/24 19:23:21 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1999-2001 Vojtech Pavlik
|
||||
* Copyright (c) 1999 Brian Gerst
|
||||
*/
|
||||
|
||||
/*
|
||||
* NS558 based standard IBM game port driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/config.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gameport.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pnp.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Classic gameport (ISA/PnP) driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define NS558_ISA 1
|
||||
#define NS558_PNP 2
|
||||
|
||||
static int ns558_isa_portlist[] = { 0x201, 0x200, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209,
|
||||
0x20b, 0x20c, 0x20e, 0x20f, 0x211, 0x219, 0x101, 0 };
|
||||
|
||||
struct ns558 {
|
||||
int type;
|
||||
int size;
|
||||
struct pnp_dev *dev;
|
||||
struct list_head node;
|
||||
struct gameport gameport;
|
||||
char phys[32];
|
||||
char name[32];
|
||||
};
|
||||
|
||||
static LIST_HEAD(ns558_list);
|
||||
|
||||
/*
|
||||
* ns558_isa_probe() tries to find an isa gameport at the
|
||||
* specified address, and also checks for mirrors.
|
||||
* A joystick must be attached for this to work.
|
||||
*/
|
||||
|
||||
static void ns558_isa_probe(int io)
|
||||
{
|
||||
int i, j, b;
|
||||
unsigned char c, u, v;
|
||||
struct ns558 *port;
|
||||
|
||||
/*
|
||||
* No one should be using this address.
|
||||
*/
|
||||
|
||||
if (!request_region(io, 1, "ns558-isa"))
|
||||
return;
|
||||
|
||||
/*
|
||||
* We must not be able to write arbitrary values to the port.
|
||||
* The lower two axis bits must be 1 after a write.
|
||||
*/
|
||||
|
||||
c = inb(io);
|
||||
outb(~c & ~3, io);
|
||||
if (~(u = v = inb(io)) & 3) {
|
||||
outb(c, io);
|
||||
i = 0;
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* After a trigger, there must be at least some bits changing.
|
||||
*/
|
||||
|
||||
for (i = 0; i < 1000; i++) v &= inb(io);
|
||||
|
||||
if (u == v) {
|
||||
outb(c, io);
|
||||
i = 0;
|
||||
goto out;
|
||||
}
|
||||
msleep(3);
|
||||
/*
|
||||
* After some time (4ms) the axes shouldn't change anymore.
|
||||
*/
|
||||
|
||||
u = inb(io);
|
||||
for (i = 0; i < 1000; i++)
|
||||
if ((u ^ inb(io)) & 0xf) {
|
||||
outb(c, io);
|
||||
i = 0;
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* And now find the number of mirrors of the port.
|
||||
*/
|
||||
|
||||
for (i = 1; i < 5; i++) {
|
||||
|
||||
release_region(io & (-1 << (i-1)), (1 << (i-1)));
|
||||
|
||||
if (!request_region(io & (-1 << i), (1 << i), "ns558-isa")) /* Don't disturb anyone */
|
||||
break;
|
||||
|
||||
outb(0xff, io & (-1 << i));
|
||||
for (j = b = 0; j < 1000; j++)
|
||||
if (inb(io & (-1 << i)) != inb((io & (-1 << i)) + (1 << i) - 1)) b++;
|
||||
msleep(3);
|
||||
|
||||
if (b > 300) { /* We allow 30% difference */
|
||||
release_region(io & (-1 << i), (1 << i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
i--;
|
||||
|
||||
if (i != 4) {
|
||||
if (!request_region(io & (-1 << i), (1 << i), "ns558-isa"))
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
|
||||
printk(KERN_ERR "ns558: Memory allocation failed.\n");
|
||||
goto out;
|
||||
}
|
||||
memset(port, 0, sizeof(struct ns558));
|
||||
|
||||
port->type = NS558_ISA;
|
||||
port->size = (1 << i);
|
||||
port->gameport.io = io;
|
||||
port->gameport.phys = port->phys;
|
||||
port->gameport.name = port->name;
|
||||
port->gameport.id.bustype = BUS_ISA;
|
||||
|
||||
sprintf(port->phys, "isa%04x/gameport0", io & (-1 << i));
|
||||
sprintf(port->name, "NS558 ISA");
|
||||
|
||||
gameport_register_port(&port->gameport);
|
||||
|
||||
printk(KERN_INFO "gameport: NS558 ISA at %#x", port->gameport.io);
|
||||
if (port->size > 1) printk(" size %d", port->size);
|
||||
printk(" speed %d kHz\n", port->gameport.speed);
|
||||
|
||||
list_add(&port->node, &ns558_list);
|
||||
return;
|
||||
out:
|
||||
release_region(io & (-1 << i), (1 << i));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PNP
|
||||
|
||||
static struct pnp_device_id pnp_devids[] = {
|
||||
{ .id = "@P@0001", .driver_data = 0 }, /* ALS 100 */
|
||||
{ .id = "@P@0020", .driver_data = 0 }, /* ALS 200 */
|
||||
{ .id = "@P@1001", .driver_data = 0 }, /* ALS 100+ */
|
||||
{ .id = "@P@2001", .driver_data = 0 }, /* ALS 120 */
|
||||
{ .id = "ASB16fd", .driver_data = 0 }, /* AdLib NSC16 */
|
||||
{ .id = "AZT3001", .driver_data = 0 }, /* AZT1008 */
|
||||
{ .id = "CDC0001", .driver_data = 0 }, /* Opl3-SAx */
|
||||
{ .id = "CSC0001", .driver_data = 0 }, /* CS4232 */
|
||||
{ .id = "CSC000f", .driver_data = 0 }, /* CS4236 */
|
||||
{ .id = "CSC0101", .driver_data = 0 }, /* CS4327 */
|
||||
{ .id = "CTL7001", .driver_data = 0 }, /* SB16 */
|
||||
{ .id = "CTL7002", .driver_data = 0 }, /* AWE64 */
|
||||
{ .id = "CTL7005", .driver_data = 0 }, /* Vibra16 */
|
||||
{ .id = "ENS2020", .driver_data = 0 }, /* SoundscapeVIVO */
|
||||
{ .id = "ESS0001", .driver_data = 0 }, /* ES1869 */
|
||||
{ .id = "ESS0005", .driver_data = 0 }, /* ES1878 */
|
||||
{ .id = "ESS6880", .driver_data = 0 }, /* ES688 */
|
||||
{ .id = "IBM0012", .driver_data = 0 }, /* CS4232 */
|
||||
{ .id = "OPT0001", .driver_data = 0 }, /* OPTi Audio16 */
|
||||
{ .id = "YMH0006", .driver_data = 0 }, /* Opl3-SA */
|
||||
{ .id = "YMH0022", .driver_data = 0 }, /* Opl3-SAx */
|
||||
{ .id = "PNPb02f", .driver_data = 0 }, /* Generic */
|
||||
{ .id = "", },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pnp, pnp_devids);
|
||||
|
||||
static int ns558_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *did)
|
||||
{
|
||||
int ioport, iolen;
|
||||
struct ns558 *port;
|
||||
|
||||
if (!pnp_port_valid(dev, 0)) {
|
||||
printk(KERN_WARNING "ns558: No i/o ports on a gameport? Weird\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ioport = pnp_port_start(dev,0);
|
||||
iolen = pnp_port_len(dev,0);
|
||||
|
||||
if (!request_region(ioport, iolen, "ns558-pnp"))
|
||||
return -EBUSY;
|
||||
|
||||
if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
|
||||
printk(KERN_ERR "ns558: Memory allocation failed.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(port, 0, sizeof(struct ns558));
|
||||
|
||||
port->type = NS558_PNP;
|
||||
port->size = iolen;
|
||||
port->dev = dev;
|
||||
|
||||
port->gameport.io = ioport;
|
||||
port->gameport.phys = port->phys;
|
||||
port->gameport.name = port->name;
|
||||
port->gameport.id.bustype = BUS_ISAPNP;
|
||||
port->gameport.id.version = 0x100;
|
||||
|
||||
sprintf(port->phys, "pnp%s/gameport0", dev->dev.bus_id);
|
||||
sprintf(port->name, "%s", "NS558 PnP Gameport");
|
||||
|
||||
gameport_register_port(&port->gameport);
|
||||
|
||||
printk(KERN_INFO "gameport: NS558 PnP at pnp%s io %#x",
|
||||
dev->dev.bus_id, port->gameport.io);
|
||||
if (iolen > 1) printk(" size %d", iolen);
|
||||
printk(" speed %d kHz\n", port->gameport.speed);
|
||||
|
||||
list_add_tail(&port->node, &ns558_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pnp_driver ns558_pnp_driver = {
|
||||
.name = "ns558",
|
||||
.id_table = pnp_devids,
|
||||
.probe = ns558_pnp_probe,
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
static struct pnp_driver ns558_pnp_driver;
|
||||
|
||||
#endif
|
||||
|
||||
int __init ns558_init(void)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
/*
|
||||
* Probe for ISA ports.
|
||||
*/
|
||||
|
||||
while (ns558_isa_portlist[i])
|
||||
ns558_isa_probe(ns558_isa_portlist[i++]);
|
||||
|
||||
pnp_register_driver(&ns558_pnp_driver);
|
||||
return list_empty(&ns558_list) ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
void __exit ns558_exit(void)
|
||||
{
|
||||
struct ns558 *port;
|
||||
|
||||
list_for_each_entry(port, &ns558_list, node) {
|
||||
gameport_unregister_port(&port->gameport);
|
||||
switch (port->type) {
|
||||
|
||||
#ifdef CONFIG_PNP
|
||||
case NS558_PNP:
|
||||
/* fall through */
|
||||
#endif
|
||||
case NS558_ISA:
|
||||
release_region(port->gameport.io & ~(port->size - 1), port->size);
|
||||
kfree(port);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
pnp_unregister_driver(&ns558_pnp_driver);
|
||||
}
|
||||
|
||||
module_init(ns558_init);
|
||||
module_exit(ns558_exit);
|
||||
186
extra/linux-2.6.10/drivers/input/gameport/vortex.c
Normal file
186
extra/linux-2.6.10/drivers/input/gameport/vortex.c
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* $Id: vortex.c,v 1.5 2002/07/01 15:39:30 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 2000-2001 Vojtech Pavlik
|
||||
*
|
||||
* Based on the work of:
|
||||
* Raymond Ingles
|
||||
*/
|
||||
|
||||
/*
|
||||
* Trident 4DWave and Aureal Vortex gameport driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gameport.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Aureal Vortex and Vortex2 gameport driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define VORTEX_GCR 0x0c /* Gameport control register */
|
||||
#define VORTEX_LEG 0x08 /* Legacy port location */
|
||||
#define VORTEX_AXD 0x10 /* Axes start */
|
||||
#define VORTEX_DATA_WAIT 20 /* 20 ms */
|
||||
|
||||
struct vortex {
|
||||
struct gameport gameport;
|
||||
struct pci_dev *dev;
|
||||
unsigned char __iomem *base;
|
||||
unsigned char __iomem *io;
|
||||
char phys[32];
|
||||
};
|
||||
|
||||
static unsigned char vortex_read(struct gameport *gameport)
|
||||
{
|
||||
struct vortex *vortex = gameport->driver;
|
||||
return readb(vortex->io + VORTEX_LEG);
|
||||
}
|
||||
|
||||
static void vortex_trigger(struct gameport *gameport)
|
||||
{
|
||||
struct vortex *vortex = gameport->driver;
|
||||
writeb(0xff, vortex->io + VORTEX_LEG);
|
||||
}
|
||||
|
||||
static int vortex_cooked_read(struct gameport *gameport, int *axes, int *buttons)
|
||||
{
|
||||
struct vortex *vortex = gameport->driver;
|
||||
int i;
|
||||
|
||||
*buttons = (~readb(vortex->base + VORTEX_LEG) >> 4) & 0xf;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
axes[i] = readw(vortex->io + VORTEX_AXD + i * sizeof(u32));
|
||||
if (axes[i] == 0x1fff) axes[i] = -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vortex_open(struct gameport *gameport, int mode)
|
||||
{
|
||||
struct vortex *vortex = gameport->driver;
|
||||
|
||||
switch (mode) {
|
||||
case GAMEPORT_MODE_COOKED:
|
||||
writeb(0x40, vortex->io + VORTEX_GCR);
|
||||
msleep(VORTEX_DATA_WAIT);
|
||||
return 0;
|
||||
case GAMEPORT_MODE_RAW:
|
||||
writeb(0x00, vortex->io + VORTEX_GCR);
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit vortex_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
{
|
||||
struct vortex *vortex;
|
||||
int i;
|
||||
|
||||
if (!(vortex = kmalloc(sizeof(struct vortex), GFP_KERNEL)))
|
||||
return -1;
|
||||
memset(vortex, 0, sizeof(struct vortex));
|
||||
|
||||
vortex->dev = dev;
|
||||
sprintf(vortex->phys, "pci%s/gameport0", pci_name(dev));
|
||||
|
||||
pci_set_drvdata(dev, vortex);
|
||||
|
||||
vortex->gameport.driver = vortex;
|
||||
vortex->gameport.fuzz = 64;
|
||||
|
||||
vortex->gameport.read = vortex_read;
|
||||
vortex->gameport.trigger = vortex_trigger;
|
||||
vortex->gameport.cooked_read = vortex_cooked_read;
|
||||
vortex->gameport.open = vortex_open;
|
||||
|
||||
vortex->gameport.name = pci_name(dev);
|
||||
vortex->gameport.phys = vortex->phys;
|
||||
vortex->gameport.id.bustype = BUS_PCI;
|
||||
vortex->gameport.id.vendor = dev->vendor;
|
||||
vortex->gameport.id.product = dev->device;
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
if (~pci_resource_flags(dev, i) & IORESOURCE_IO)
|
||||
break;
|
||||
|
||||
pci_enable_device(dev);
|
||||
|
||||
vortex->base = ioremap(pci_resource_start(vortex->dev, i),
|
||||
pci_resource_len(vortex->dev, i));
|
||||
vortex->io = vortex->base + id->driver_data;
|
||||
|
||||
gameport_register_port(&vortex->gameport);
|
||||
|
||||
printk(KERN_INFO "gameport at pci%s speed %d kHz\n",
|
||||
pci_name(dev), vortex->gameport.speed);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __devexit vortex_remove(struct pci_dev *dev)
|
||||
{
|
||||
struct vortex *vortex = pci_get_drvdata(dev);
|
||||
gameport_unregister_port(&vortex->gameport);
|
||||
iounmap(vortex->base);
|
||||
kfree(vortex);
|
||||
}
|
||||
|
||||
static struct pci_device_id vortex_id_table[] =
|
||||
{{ 0x12eb, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x11000 },
|
||||
{ 0x12eb, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x28800 },
|
||||
{ 0 }};
|
||||
|
||||
static struct pci_driver vortex_driver = {
|
||||
.name = "vortex_gameport",
|
||||
.id_table = vortex_id_table,
|
||||
.probe = vortex_probe,
|
||||
.remove = __devexit_p(vortex_remove),
|
||||
};
|
||||
|
||||
int __init vortex_init(void)
|
||||
{
|
||||
return pci_module_init(&vortex_driver);
|
||||
}
|
||||
|
||||
void __exit vortex_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&vortex_driver);
|
||||
}
|
||||
|
||||
module_init(vortex_init);
|
||||
module_exit(vortex_exit);
|
||||
766
extra/linux-2.6.10/drivers/input/input.c
Normal file
766
extra/linux-2.6.10/drivers/input/input.c
Normal file
@@ -0,0 +1,766 @@
|
||||
/*
|
||||
* The input core
|
||||
*
|
||||
* Copyright (c) 1999-2002 Vojtech Pavlik
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/kobject_uevent.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/devfs_fs_kernel.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
|
||||
MODULE_DESCRIPTION("Input core");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
EXPORT_SYMBOL(input_register_device);
|
||||
EXPORT_SYMBOL(input_unregister_device);
|
||||
EXPORT_SYMBOL(input_register_handler);
|
||||
EXPORT_SYMBOL(input_unregister_handler);
|
||||
EXPORT_SYMBOL(input_grab_device);
|
||||
EXPORT_SYMBOL(input_release_device);
|
||||
EXPORT_SYMBOL(input_open_device);
|
||||
EXPORT_SYMBOL(input_close_device);
|
||||
EXPORT_SYMBOL(input_accept_process);
|
||||
EXPORT_SYMBOL(input_flush_device);
|
||||
EXPORT_SYMBOL(input_event);
|
||||
EXPORT_SYMBOL(input_class);
|
||||
|
||||
#define INPUT_DEVICES 256
|
||||
|
||||
static LIST_HEAD(input_dev_list);
|
||||
static LIST_HEAD(input_handler_list);
|
||||
|
||||
static struct input_handler *input_table[8];
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
static struct proc_dir_entry *proc_bus_input_dir;
|
||||
DECLARE_WAIT_QUEUE_HEAD(input_devices_poll_wait);
|
||||
static int input_devices_state;
|
||||
#endif
|
||||
|
||||
static inline unsigned int ms_to_jiffies(unsigned int ms)
|
||||
{
|
||||
unsigned int j;
|
||||
j = (ms * HZ + 500) / 1000;
|
||||
return (j > 0) ? j : 1;
|
||||
}
|
||||
|
||||
|
||||
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
struct input_handle *handle;
|
||||
|
||||
if (dev->pm_dev)
|
||||
pm_access(dev->pm_dev);
|
||||
|
||||
if (type > EV_MAX || !test_bit(type, dev->evbit))
|
||||
return;
|
||||
|
||||
add_mouse_randomness((type << 4) ^ code ^ (code >> 4) ^ value);
|
||||
|
||||
switch (type) {
|
||||
|
||||
case EV_SYN:
|
||||
switch (code) {
|
||||
case SYN_CONFIG:
|
||||
if (dev->event) dev->event(dev, type, code, value);
|
||||
break;
|
||||
|
||||
case SYN_REPORT:
|
||||
if (dev->sync) return;
|
||||
dev->sync = 1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_KEY:
|
||||
|
||||
if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value)
|
||||
return;
|
||||
|
||||
if (value == 2)
|
||||
break;
|
||||
|
||||
change_bit(code, dev->key);
|
||||
|
||||
if (test_bit(EV_REP, dev->evbit) && dev->rep[REP_PERIOD] && dev->timer.data && value) {
|
||||
dev->repeat_key = code;
|
||||
mod_timer(&dev->timer, jiffies + ms_to_jiffies(dev->rep[REP_DELAY]));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case EV_ABS:
|
||||
|
||||
if (code > ABS_MAX || !test_bit(code, dev->absbit))
|
||||
return;
|
||||
|
||||
if (dev->absfuzz[code]) {
|
||||
if ((value > dev->abs[code] - (dev->absfuzz[code] >> 1)) &&
|
||||
(value < dev->abs[code] + (dev->absfuzz[code] >> 1)))
|
||||
return;
|
||||
|
||||
if ((value > dev->abs[code] - dev->absfuzz[code]) &&
|
||||
(value < dev->abs[code] + dev->absfuzz[code]))
|
||||
value = (dev->abs[code] * 3 + value) >> 2;
|
||||
|
||||
if ((value > dev->abs[code] - (dev->absfuzz[code] << 1)) &&
|
||||
(value < dev->abs[code] + (dev->absfuzz[code] << 1)))
|
||||
value = (dev->abs[code] + value) >> 1;
|
||||
}
|
||||
|
||||
if (dev->abs[code] == value)
|
||||
return;
|
||||
|
||||
dev->abs[code] = value;
|
||||
break;
|
||||
|
||||
case EV_REL:
|
||||
|
||||
if (code > REL_MAX || !test_bit(code, dev->relbit) || (value == 0))
|
||||
return;
|
||||
|
||||
break;
|
||||
|
||||
case EV_MSC:
|
||||
|
||||
if (code > MSC_MAX || !test_bit(code, dev->mscbit))
|
||||
return;
|
||||
|
||||
if (dev->event) dev->event(dev, type, code, value);
|
||||
|
||||
break;
|
||||
|
||||
case EV_LED:
|
||||
|
||||
if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value)
|
||||
return;
|
||||
|
||||
change_bit(code, dev->led);
|
||||
if (dev->event) dev->event(dev, type, code, value);
|
||||
|
||||
break;
|
||||
|
||||
case EV_SND:
|
||||
|
||||
if (code > SND_MAX || !test_bit(code, dev->sndbit))
|
||||
return;
|
||||
|
||||
if (dev->event) dev->event(dev, type, code, value);
|
||||
|
||||
break;
|
||||
|
||||
case EV_REP:
|
||||
|
||||
if (code > REP_MAX || value < 0 || dev->rep[code] == value) return;
|
||||
|
||||
dev->rep[code] = value;
|
||||
if (dev->event) dev->event(dev, type, code, value);
|
||||
|
||||
break;
|
||||
|
||||
case EV_FF:
|
||||
if (dev->event) dev->event(dev, type, code, value);
|
||||
break;
|
||||
}
|
||||
|
||||
if (type != EV_SYN)
|
||||
dev->sync = 0;
|
||||
|
||||
if (dev->grab)
|
||||
dev->grab->handler->event(dev->grab, type, code, value);
|
||||
else
|
||||
list_for_each_entry(handle, &dev->h_list, d_node)
|
||||
if (handle->open)
|
||||
handle->handler->event(handle, type, code, value);
|
||||
}
|
||||
|
||||
static void input_repeat_key(unsigned long data)
|
||||
{
|
||||
struct input_dev *dev = (void *) data;
|
||||
|
||||
if (!test_bit(dev->repeat_key, dev->key))
|
||||
return;
|
||||
|
||||
input_event(dev, EV_KEY, dev->repeat_key, 2);
|
||||
input_sync(dev);
|
||||
|
||||
mod_timer(&dev->timer, jiffies + ms_to_jiffies(dev->rep[REP_PERIOD]));
|
||||
}
|
||||
|
||||
int input_accept_process(struct input_handle *handle, struct file *file)
|
||||
{
|
||||
if (handle->dev->accept)
|
||||
return handle->dev->accept(handle->dev, file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int input_grab_device(struct input_handle *handle)
|
||||
{
|
||||
if (handle->dev->grab)
|
||||
return -EBUSY;
|
||||
|
||||
handle->dev->grab = handle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void input_release_device(struct input_handle *handle)
|
||||
{
|
||||
if (handle->dev->grab == handle)
|
||||
handle->dev->grab = NULL;
|
||||
}
|
||||
|
||||
int input_open_device(struct input_handle *handle)
|
||||
{
|
||||
if (handle->dev->pm_dev)
|
||||
pm_access(handle->dev->pm_dev);
|
||||
handle->open++;
|
||||
if (handle->dev->open)
|
||||
return handle->dev->open(handle->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int input_flush_device(struct input_handle* handle, struct file* file)
|
||||
{
|
||||
if (handle->dev->flush)
|
||||
return handle->dev->flush(handle->dev, file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void input_close_device(struct input_handle *handle)
|
||||
{
|
||||
input_release_device(handle);
|
||||
if (handle->dev->pm_dev)
|
||||
pm_dev_idle(handle->dev->pm_dev);
|
||||
if (handle->dev->close)
|
||||
handle->dev->close(handle->dev);
|
||||
handle->open--;
|
||||
}
|
||||
|
||||
static void input_link_handle(struct input_handle *handle)
|
||||
{
|
||||
list_add_tail(&handle->d_node, &handle->dev->h_list);
|
||||
list_add_tail(&handle->h_node, &handle->handler->h_list);
|
||||
}
|
||||
|
||||
#define MATCH_BIT(bit, max) \
|
||||
for (i = 0; i < NBITS(max); i++) \
|
||||
if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \
|
||||
break; \
|
||||
if (i != NBITS(max)) \
|
||||
continue;
|
||||
|
||||
static struct input_device_id *input_match_device(struct input_device_id *id, struct input_dev *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (; id->flags || id->driver_info; id++) {
|
||||
|
||||
if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
|
||||
if (id->id.bustype != dev->id.bustype)
|
||||
continue;
|
||||
|
||||
if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)
|
||||
if (id->id.vendor != dev->id.vendor)
|
||||
continue;
|
||||
|
||||
if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)
|
||||
if (id->id.product != dev->id.product)
|
||||
continue;
|
||||
|
||||
if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)
|
||||
if (id->id.version != dev->id.version)
|
||||
continue;
|
||||
|
||||
MATCH_BIT(evbit, EV_MAX);
|
||||
MATCH_BIT(keybit, KEY_MAX);
|
||||
MATCH_BIT(relbit, REL_MAX);
|
||||
MATCH_BIT(absbit, ABS_MAX);
|
||||
MATCH_BIT(mscbit, MSC_MAX);
|
||||
MATCH_BIT(ledbit, LED_MAX);
|
||||
MATCH_BIT(sndbit, SND_MAX);
|
||||
MATCH_BIT(ffbit, FF_MAX);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Input hotplugging interface - loading event handlers based on
|
||||
* device bitfields.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_HOTPLUG
|
||||
|
||||
/*
|
||||
* Input hotplugging invokes what /proc/sys/kernel/hotplug says
|
||||
* (normally /sbin/hotplug) when input devices get added or removed.
|
||||
*
|
||||
* This invokes a user mode policy agent, typically helping to load driver
|
||||
* or other modules, configure the device, and more. Drivers can provide
|
||||
* a MODULE_DEVICE_TABLE to help with module loading subtasks.
|
||||
*
|
||||
*/
|
||||
|
||||
#define SPRINTF_BIT_A(bit, name, max) \
|
||||
do { \
|
||||
envp[i++] = scratch; \
|
||||
scratch += sprintf(scratch, name); \
|
||||
for (j = NBITS(max) - 1; j >= 0; j--) \
|
||||
if (dev->bit[j]) break; \
|
||||
for (; j >= 0; j--) \
|
||||
scratch += sprintf(scratch, "%lx ", dev->bit[j]); \
|
||||
scratch++; \
|
||||
} while (0)
|
||||
|
||||
#define SPRINTF_BIT_A2(bit, name, max, ev) \
|
||||
do { \
|
||||
if (test_bit(ev, dev->evbit)) \
|
||||
SPRINTF_BIT_A(bit, name, max); \
|
||||
} while (0)
|
||||
|
||||
static void input_call_hotplug(char *verb, struct input_dev *dev)
|
||||
{
|
||||
char *argv[3], **envp, *buf, *scratch;
|
||||
int i = 0, j, value;
|
||||
|
||||
if (!hotplug_path[0]) {
|
||||
printk(KERN_ERR "input.c: calling hotplug without a hotplug agent defined\n");
|
||||
return;
|
||||
}
|
||||
if (in_interrupt()) {
|
||||
printk(KERN_ERR "input.c: calling hotplug from interrupt\n");
|
||||
return;
|
||||
}
|
||||
if (!current->fs->root) {
|
||||
printk(KERN_WARNING "input.c: calling hotplug without valid filesystem\n");
|
||||
return;
|
||||
}
|
||||
if (!(envp = (char **) kmalloc(20 * sizeof(char *), GFP_KERNEL))) {
|
||||
printk(KERN_ERR "input.c: not enough memory allocating hotplug environment\n");
|
||||
return;
|
||||
}
|
||||
if (!(buf = kmalloc(1024, GFP_KERNEL))) {
|
||||
kfree (envp);
|
||||
printk(KERN_ERR "input.c: not enough memory allocating hotplug environment\n");
|
||||
return;
|
||||
}
|
||||
|
||||
argv[0] = hotplug_path;
|
||||
argv[1] = "input";
|
||||
argv[2] = NULL;
|
||||
|
||||
envp[i++] = "HOME=/";
|
||||
envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
|
||||
|
||||
scratch = buf;
|
||||
|
||||
envp[i++] = scratch;
|
||||
scratch += sprintf(scratch, "ACTION=%s", verb) + 1;
|
||||
|
||||
envp[i++] = scratch;
|
||||
scratch += sprintf(scratch, "PRODUCT=%x/%x/%x/%x",
|
||||
dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version) + 1;
|
||||
|
||||
if (dev->name) {
|
||||
envp[i++] = scratch;
|
||||
scratch += sprintf(scratch, "NAME=%s", dev->name) + 1;
|
||||
}
|
||||
|
||||
if (dev->phys) {
|
||||
envp[i++] = scratch;
|
||||
scratch += sprintf(scratch, "PHYS=%s", dev->phys) + 1;
|
||||
}
|
||||
|
||||
SPRINTF_BIT_A(evbit, "EV=", EV_MAX);
|
||||
SPRINTF_BIT_A2(keybit, "KEY=", KEY_MAX, EV_KEY);
|
||||
SPRINTF_BIT_A2(relbit, "REL=", REL_MAX, EV_REL);
|
||||
SPRINTF_BIT_A2(absbit, "ABS=", ABS_MAX, EV_ABS);
|
||||
SPRINTF_BIT_A2(mscbit, "MSC=", MSC_MAX, EV_MSC);
|
||||
SPRINTF_BIT_A2(ledbit, "LED=", LED_MAX, EV_LED);
|
||||
SPRINTF_BIT_A2(sndbit, "SND=", SND_MAX, EV_SND);
|
||||
SPRINTF_BIT_A2(ffbit, "FF=", FF_MAX, EV_FF);
|
||||
|
||||
envp[i++] = NULL;
|
||||
|
||||
#ifdef INPUT_DEBUG
|
||||
printk(KERN_DEBUG "input.c: calling %s %s [%s %s %s %s %s]\n",
|
||||
argv[0], argv[1], envp[0], envp[1], envp[2], envp[3], envp[4]);
|
||||
#endif
|
||||
|
||||
value = call_usermodehelper(argv [0], argv, envp, 0);
|
||||
|
||||
kfree(buf);
|
||||
kfree(envp);
|
||||
|
||||
#ifdef INPUT_DEBUG
|
||||
if (value != 0)
|
||||
printk(KERN_DEBUG "input.c: hotplug returned %d\n", value);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void input_register_device(struct input_dev *dev)
|
||||
{
|
||||
struct input_handle *handle;
|
||||
struct input_handler *handler;
|
||||
struct input_device_id *id;
|
||||
|
||||
set_bit(EV_SYN, dev->evbit);
|
||||
|
||||
/*
|
||||
* If delay and period are pre-set by the driver, then autorepeating
|
||||
* is handled by the driver itself and we don't do it in input.c.
|
||||
*/
|
||||
|
||||
init_timer(&dev->timer);
|
||||
if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {
|
||||
dev->timer.data = (long) dev;
|
||||
dev->timer.function = input_repeat_key;
|
||||
dev->rep[REP_DELAY] = 250;
|
||||
dev->rep[REP_PERIOD] = 33;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&dev->h_list);
|
||||
list_add_tail(&dev->node, &input_dev_list);
|
||||
|
||||
list_for_each_entry(handler, &input_handler_list, node)
|
||||
if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
|
||||
if ((id = input_match_device(handler->id_table, dev)))
|
||||
if ((handle = handler->connect(handler, dev, id)))
|
||||
input_link_handle(handle);
|
||||
|
||||
#ifdef CONFIG_HOTPLUG
|
||||
input_call_hotplug("add", dev);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
input_devices_state++;
|
||||
wake_up(&input_devices_poll_wait);
|
||||
#endif
|
||||
}
|
||||
|
||||
void input_unregister_device(struct input_dev *dev)
|
||||
{
|
||||
struct list_head * node, * next;
|
||||
|
||||
if (!dev) return;
|
||||
|
||||
if (dev->pm_dev)
|
||||
pm_unregister(dev->pm_dev);
|
||||
|
||||
del_timer_sync(&dev->timer);
|
||||
|
||||
list_for_each_safe(node, next, &dev->h_list) {
|
||||
struct input_handle * handle = to_handle(node);
|
||||
list_del_init(&handle->d_node);
|
||||
list_del_init(&handle->h_node);
|
||||
handle->handler->disconnect(handle);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG
|
||||
input_call_hotplug("remove", dev);
|
||||
#endif
|
||||
|
||||
list_del_init(&dev->node);
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
input_devices_state++;
|
||||
wake_up(&input_devices_poll_wait);
|
||||
#endif
|
||||
}
|
||||
|
||||
void input_register_handler(struct input_handler *handler)
|
||||
{
|
||||
struct input_dev *dev;
|
||||
struct input_handle *handle;
|
||||
struct input_device_id *id;
|
||||
|
||||
if (!handler) return;
|
||||
|
||||
INIT_LIST_HEAD(&handler->h_list);
|
||||
|
||||
if (handler->fops != NULL)
|
||||
input_table[handler->minor >> 5] = handler;
|
||||
|
||||
list_add_tail(&handler->node, &input_handler_list);
|
||||
|
||||
list_for_each_entry(dev, &input_dev_list, node)
|
||||
if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
|
||||
if ((id = input_match_device(handler->id_table, dev)))
|
||||
if ((handle = handler->connect(handler, dev, id)))
|
||||
input_link_handle(handle);
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
input_devices_state++;
|
||||
wake_up(&input_devices_poll_wait);
|
||||
#endif
|
||||
}
|
||||
|
||||
void input_unregister_handler(struct input_handler *handler)
|
||||
{
|
||||
struct list_head * node, * next;
|
||||
|
||||
list_for_each_safe(node, next, &handler->h_list) {
|
||||
struct input_handle * handle = to_handle_h(node);
|
||||
list_del_init(&handle->h_node);
|
||||
list_del_init(&handle->d_node);
|
||||
handler->disconnect(handle);
|
||||
}
|
||||
|
||||
list_del_init(&handler->node);
|
||||
|
||||
if (handler->fops != NULL)
|
||||
input_table[handler->minor >> 5] = NULL;
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
input_devices_state++;
|
||||
wake_up(&input_devices_poll_wait);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int input_open_file(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct input_handler *handler = input_table[iminor(inode) >> 5];
|
||||
struct file_operations *old_fops, *new_fops = NULL;
|
||||
int err;
|
||||
|
||||
/* No load-on-demand here? */
|
||||
if (!handler || !(new_fops = fops_get(handler->fops)))
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* That's _really_ odd. Usually NULL ->open means "nothing special",
|
||||
* not "no device". Oh, well...
|
||||
*/
|
||||
if (!new_fops->open) {
|
||||
fops_put(new_fops);
|
||||
return -ENODEV;
|
||||
}
|
||||
old_fops = file->f_op;
|
||||
file->f_op = new_fops;
|
||||
|
||||
err = new_fops->open(inode, file);
|
||||
|
||||
if (err) {
|
||||
fops_put(file->f_op);
|
||||
file->f_op = fops_get(old_fops);
|
||||
}
|
||||
fops_put(old_fops);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct file_operations input_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = input_open_file,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
|
||||
#define SPRINTF_BIT_B(bit, name, max) \
|
||||
do { \
|
||||
len += sprintf(buf + len, "B: %s", name); \
|
||||
for (i = NBITS(max) - 1; i >= 0; i--) \
|
||||
if (dev->bit[i]) break; \
|
||||
for (; i >= 0; i--) \
|
||||
len += sprintf(buf + len, "%lx ", dev->bit[i]); \
|
||||
len += sprintf(buf + len, "\n"); \
|
||||
} while (0)
|
||||
|
||||
#define SPRINTF_BIT_B2(bit, name, max, ev) \
|
||||
do { \
|
||||
if (test_bit(ev, dev->evbit)) \
|
||||
SPRINTF_BIT_B(bit, name, max); \
|
||||
} while (0)
|
||||
|
||||
|
||||
static unsigned int input_devices_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
int state = input_devices_state;
|
||||
poll_wait(file, &input_devices_poll_wait, wait);
|
||||
if (state != input_devices_state)
|
||||
return POLLIN | POLLRDNORM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int input_devices_read(char *buf, char **start, off_t pos, int count, int *eof, void *data)
|
||||
{
|
||||
struct input_dev *dev;
|
||||
struct input_handle *handle;
|
||||
|
||||
off_t at = 0;
|
||||
int i, len, cnt = 0;
|
||||
|
||||
list_for_each_entry(dev, &input_dev_list, node) {
|
||||
|
||||
len = sprintf(buf, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n",
|
||||
dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version);
|
||||
|
||||
len += sprintf(buf + len, "N: Name=\"%s\"\n", dev->name ? dev->name : "");
|
||||
len += sprintf(buf + len, "P: Phys=%s\n", dev->phys ? dev->phys : "");
|
||||
len += sprintf(buf + len, "H: Handlers=");
|
||||
|
||||
list_for_each_entry(handle, &dev->h_list, d_node)
|
||||
len += sprintf(buf + len, "%s ", handle->name);
|
||||
|
||||
len += sprintf(buf + len, "\n");
|
||||
|
||||
SPRINTF_BIT_B(evbit, "EV=", EV_MAX);
|
||||
SPRINTF_BIT_B2(keybit, "KEY=", KEY_MAX, EV_KEY);
|
||||
SPRINTF_BIT_B2(relbit, "REL=", REL_MAX, EV_REL);
|
||||
SPRINTF_BIT_B2(absbit, "ABS=", ABS_MAX, EV_ABS);
|
||||
SPRINTF_BIT_B2(mscbit, "MSC=", MSC_MAX, EV_MSC);
|
||||
SPRINTF_BIT_B2(ledbit, "LED=", LED_MAX, EV_LED);
|
||||
SPRINTF_BIT_B2(sndbit, "SND=", SND_MAX, EV_SND);
|
||||
SPRINTF_BIT_B2(ffbit, "FF=", FF_MAX, EV_FF);
|
||||
|
||||
len += sprintf(buf + len, "\n");
|
||||
|
||||
at += len;
|
||||
|
||||
if (at >= pos) {
|
||||
if (!*start) {
|
||||
*start = buf + (pos - (at - len));
|
||||
cnt = at - pos;
|
||||
} else cnt += len;
|
||||
buf += len;
|
||||
if (cnt >= count)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (&dev->node == &input_dev_list)
|
||||
*eof = 1;
|
||||
|
||||
return (count > cnt) ? cnt : count;
|
||||
}
|
||||
|
||||
static int input_handlers_read(char *buf, char **start, off_t pos, int count, int *eof, void *data)
|
||||
{
|
||||
struct input_handler *handler;
|
||||
|
||||
off_t at = 0;
|
||||
int len = 0, cnt = 0;
|
||||
int i = 0;
|
||||
|
||||
list_for_each_entry(handler, &input_handler_list, node) {
|
||||
|
||||
if (handler->fops)
|
||||
len = sprintf(buf, "N: Number=%d Name=%s Minor=%d\n",
|
||||
i++, handler->name, handler->minor);
|
||||
else
|
||||
len = sprintf(buf, "N: Number=%d Name=%s\n",
|
||||
i++, handler->name);
|
||||
|
||||
at += len;
|
||||
|
||||
if (at >= pos) {
|
||||
if (!*start) {
|
||||
*start = buf + (pos - (at - len));
|
||||
cnt = at - pos;
|
||||
} else cnt += len;
|
||||
buf += len;
|
||||
if (cnt >= count)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (&handler->node == &input_handler_list)
|
||||
*eof = 1;
|
||||
|
||||
return (count > cnt) ? cnt : count;
|
||||
}
|
||||
|
||||
static int __init input_proc_init(void)
|
||||
{
|
||||
struct proc_dir_entry *entry;
|
||||
|
||||
proc_bus_input_dir = proc_mkdir("input", proc_bus);
|
||||
if (proc_bus_input_dir == NULL)
|
||||
return -ENOMEM;
|
||||
proc_bus_input_dir->owner = THIS_MODULE;
|
||||
entry = create_proc_read_entry("devices", 0, proc_bus_input_dir, input_devices_read, NULL);
|
||||
if (entry == NULL) {
|
||||
remove_proc_entry("input", proc_bus);
|
||||
return -ENOMEM;
|
||||
}
|
||||
entry->owner = THIS_MODULE;
|
||||
entry->proc_fops->poll = input_devices_poll;
|
||||
entry = create_proc_read_entry("handlers", 0, proc_bus_input_dir, input_handlers_read, NULL);
|
||||
if (entry == NULL) {
|
||||
remove_proc_entry("devices", proc_bus_input_dir);
|
||||
remove_proc_entry("input", proc_bus);
|
||||
return -ENOMEM;
|
||||
}
|
||||
entry->owner = THIS_MODULE;
|
||||
return 0;
|
||||
}
|
||||
#else /* !CONFIG_PROC_FS */
|
||||
static inline int input_proc_init(void) { return 0; }
|
||||
#endif
|
||||
|
||||
struct class_simple *input_class;
|
||||
|
||||
static int __init input_init(void)
|
||||
{
|
||||
int retval = -ENOMEM;
|
||||
|
||||
input_class = class_simple_create(THIS_MODULE, "input");
|
||||
if (IS_ERR(input_class))
|
||||
return PTR_ERR(input_class);
|
||||
input_proc_init();
|
||||
retval = register_chrdev(INPUT_MAJOR, "input", &input_fops);
|
||||
if (retval) {
|
||||
printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR);
|
||||
remove_proc_entry("devices", proc_bus_input_dir);
|
||||
remove_proc_entry("handlers", proc_bus_input_dir);
|
||||
remove_proc_entry("input", proc_bus);
|
||||
class_simple_destroy(input_class);
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = devfs_mk_dir("input");
|
||||
if (retval) {
|
||||
remove_proc_entry("devices", proc_bus_input_dir);
|
||||
remove_proc_entry("handlers", proc_bus_input_dir);
|
||||
remove_proc_entry("input", proc_bus);
|
||||
unregister_chrdev(INPUT_MAJOR, "input");
|
||||
class_simple_destroy(input_class);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __exit input_exit(void)
|
||||
{
|
||||
remove_proc_entry("devices", proc_bus_input_dir);
|
||||
remove_proc_entry("handlers", proc_bus_input_dir);
|
||||
remove_proc_entry("input", proc_bus);
|
||||
|
||||
devfs_remove("input");
|
||||
unregister_chrdev(INPUT_MAJOR, "input");
|
||||
class_simple_destroy(input_class);
|
||||
}
|
||||
|
||||
subsys_initcall(input_init);
|
||||
module_exit(input_exit);
|
||||
BIN
extra/linux-2.6.10/drivers/input/input.o
Normal file
BIN
extra/linux-2.6.10/drivers/input/input.o
Normal file
Binary file not shown.
530
extra/linux-2.6.10/drivers/input/joydev.c
Normal file
530
extra/linux-2.6.10/drivers/input/joydev.c
Normal file
@@ -0,0 +1,530 @@
|
||||
/*
|
||||
* Joystick device driver for the input driver suite.
|
||||
*
|
||||
* Copyright (c) 1999-2002 Vojtech Pavlik
|
||||
* Copyright (c) 1999 Colin Van Dyke
|
||||
*
|
||||
* 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 <asm/io.h>
|
||||
#include <asm/system.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/joystick.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/devfs_fs_kernel.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Joystick device interfaces");
|
||||
MODULE_SUPPORTED_DEVICE("input/js");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define JOYDEV_MINOR_BASE 0
|
||||
#define JOYDEV_MINORS 16
|
||||
#define JOYDEV_BUFFER_SIZE 64
|
||||
|
||||
#define MSECS(t) (1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ)
|
||||
|
||||
struct joydev {
|
||||
int exist;
|
||||
int open;
|
||||
int minor;
|
||||
char name[16];
|
||||
struct input_handle handle;
|
||||
wait_queue_head_t wait;
|
||||
struct list_head list;
|
||||
struct js_corr corr[ABS_MAX];
|
||||
struct JS_DATA_SAVE_TYPE glue;
|
||||
int nabs;
|
||||
int nkey;
|
||||
__u16 keymap[KEY_MAX - BTN_MISC];
|
||||
__u16 keypam[KEY_MAX - BTN_MISC];
|
||||
__u8 absmap[ABS_MAX];
|
||||
__u8 abspam[ABS_MAX];
|
||||
__s16 abs[ABS_MAX];
|
||||
};
|
||||
|
||||
struct joydev_list {
|
||||
struct js_event buffer[JOYDEV_BUFFER_SIZE];
|
||||
int head;
|
||||
int tail;
|
||||
int startup;
|
||||
struct fasync_struct *fasync;
|
||||
struct joydev *joydev;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
static struct joydev *joydev_table[JOYDEV_MINORS];
|
||||
|
||||
static int joydev_correct(int value, struct js_corr *corr)
|
||||
{
|
||||
switch (corr->type) {
|
||||
case JS_CORR_NONE:
|
||||
break;
|
||||
case JS_CORR_BROKEN:
|
||||
value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 :
|
||||
((corr->coef[3] * (value - corr->coef[1])) >> 14)) :
|
||||
((corr->coef[2] * (value - corr->coef[0])) >> 14);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (value < -32767) return -32767;
|
||||
if (value > 32767) return 32767;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
struct joydev *joydev = handle->private;
|
||||
struct joydev_list *list;
|
||||
struct js_event event;
|
||||
|
||||
switch (type) {
|
||||
|
||||
case EV_KEY:
|
||||
if (code < BTN_MISC || value == 2) return;
|
||||
event.type = JS_EVENT_BUTTON;
|
||||
event.number = joydev->keymap[code - BTN_MISC];
|
||||
event.value = value;
|
||||
break;
|
||||
|
||||
case EV_ABS:
|
||||
event.type = JS_EVENT_AXIS;
|
||||
event.number = joydev->absmap[code];
|
||||
event.value = joydev_correct(value, joydev->corr + event.number);
|
||||
if (event.value == joydev->abs[event.number]) return;
|
||||
joydev->abs[event.number] = event.value;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
event.time = MSECS(jiffies);
|
||||
|
||||
list_for_each_entry(list, &joydev->list, node) {
|
||||
|
||||
memcpy(list->buffer + list->head, &event, sizeof(struct js_event));
|
||||
|
||||
if (list->startup == joydev->nabs + joydev->nkey)
|
||||
if (list->tail == (list->head = (list->head + 1) & (JOYDEV_BUFFER_SIZE - 1)))
|
||||
list->startup = 0;
|
||||
|
||||
kill_fasync(&list->fasync, SIGIO, POLL_IN);
|
||||
}
|
||||
|
||||
wake_up_interruptible(&joydev->wait);
|
||||
}
|
||||
|
||||
static int joydev_fasync(int fd, struct file *file, int on)
|
||||
{
|
||||
int retval;
|
||||
struct joydev_list *list = file->private_data;
|
||||
retval = fasync_helper(fd, file, on, &list->fasync);
|
||||
return retval < 0 ? retval : 0;
|
||||
}
|
||||
|
||||
static void joydev_free(struct joydev *joydev)
|
||||
{
|
||||
joydev_table[joydev->minor] = NULL;
|
||||
kfree(joydev);
|
||||
}
|
||||
|
||||
static int joydev_release(struct inode * inode, struct file * file)
|
||||
{
|
||||
struct joydev_list *list = file->private_data;
|
||||
|
||||
joydev_fasync(-1, file, 0);
|
||||
|
||||
list_del(&list->node);
|
||||
|
||||
if (!--list->joydev->open) {
|
||||
if (list->joydev->exist)
|
||||
input_close_device(&list->joydev->handle);
|
||||
else
|
||||
joydev_free(list->joydev);
|
||||
}
|
||||
|
||||
kfree(list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int joydev_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct joydev_list *list;
|
||||
int i = iminor(inode) - JOYDEV_MINOR_BASE;
|
||||
|
||||
if (i >= JOYDEV_MINORS || !joydev_table[i])
|
||||
return -ENODEV;
|
||||
|
||||
if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL)))
|
||||
return -ENOMEM;
|
||||
memset(list, 0, sizeof(struct joydev_list));
|
||||
|
||||
list->joydev = joydev_table[i];
|
||||
list_add_tail(&list->node, &joydev_table[i]->list);
|
||||
file->private_data = list;
|
||||
|
||||
if (!list->joydev->open++)
|
||||
if (list->joydev->exist)
|
||||
input_open_device(&list->joydev->handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t joydev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct joydev_list *list = file->private_data;
|
||||
struct joydev *joydev = list->joydev;
|
||||
struct input_dev *input = joydev->handle.dev;
|
||||
int retval = 0;
|
||||
|
||||
if (!list->joydev->exist)
|
||||
return -ENODEV;
|
||||
|
||||
if (count < sizeof(struct js_event))
|
||||
return -EINVAL;
|
||||
|
||||
if (count == sizeof(struct JS_DATA_TYPE)) {
|
||||
|
||||
struct JS_DATA_TYPE data;
|
||||
int i;
|
||||
|
||||
for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++)
|
||||
data.buttons |= test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0;
|
||||
data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x;
|
||||
data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y;
|
||||
|
||||
if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
|
||||
return -EFAULT;
|
||||
|
||||
list->startup = 0;
|
||||
list->tail = list->head;
|
||||
|
||||
return sizeof(struct JS_DATA_TYPE);
|
||||
}
|
||||
|
||||
if (list->startup == joydev->nabs + joydev->nkey
|
||||
&& list->head == list->tail && (file->f_flags & O_NONBLOCK))
|
||||
return -EAGAIN;
|
||||
|
||||
retval = wait_event_interruptible(list->joydev->wait,
|
||||
!list->joydev->exist ||
|
||||
list->startup < joydev->nabs + joydev->nkey ||
|
||||
list->head != list->tail);
|
||||
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!list->joydev->exist)
|
||||
return -ENODEV;
|
||||
|
||||
while (list->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) {
|
||||
|
||||
struct js_event event;
|
||||
|
||||
event.time = MSECS(jiffies);
|
||||
|
||||
if (list->startup < joydev->nkey) {
|
||||
event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
|
||||
event.number = list->startup;
|
||||
event.value = !!test_bit(joydev->keypam[event.number], input->key);
|
||||
} else {
|
||||
event.type = JS_EVENT_AXIS | JS_EVENT_INIT;
|
||||
event.number = list->startup - joydev->nkey;
|
||||
event.value = joydev->abs[event.number];
|
||||
}
|
||||
|
||||
if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
|
||||
return -EFAULT;
|
||||
|
||||
list->startup++;
|
||||
retval += sizeof(struct js_event);
|
||||
}
|
||||
|
||||
while (list->head != list->tail && retval + sizeof(struct js_event) <= count) {
|
||||
|
||||
if (copy_to_user(buf + retval, list->buffer + list->tail, sizeof(struct js_event)))
|
||||
return -EFAULT;
|
||||
|
||||
list->tail = (list->tail + 1) & (JOYDEV_BUFFER_SIZE - 1);
|
||||
retval += sizeof(struct js_event);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* No kernel lock - fine */
|
||||
static unsigned int joydev_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct joydev_list *list = file->private_data;
|
||||
poll_wait(file, &list->joydev->wait, wait);
|
||||
if (list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey)
|
||||
return POLLIN | POLLRDNORM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct joydev_list *list = file->private_data;
|
||||
struct joydev *joydev = list->joydev;
|
||||
struct input_dev *dev = joydev->handle.dev;
|
||||
void __user *argp = (void __user *)arg;
|
||||
int i, j;
|
||||
|
||||
if (!joydev->exist) return -ENODEV;
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case JS_SET_CAL:
|
||||
return copy_from_user(&joydev->glue.JS_CORR, argp,
|
||||
sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
|
||||
case JS_GET_CAL:
|
||||
return copy_to_user(argp, &joydev->glue.JS_CORR,
|
||||
sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
|
||||
case JS_SET_TIMEOUT:
|
||||
return get_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
|
||||
case JS_GET_TIMEOUT:
|
||||
return put_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
|
||||
case JS_SET_TIMELIMIT:
|
||||
return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
|
||||
case JS_GET_TIMELIMIT:
|
||||
return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
|
||||
case JS_SET_ALL:
|
||||
return copy_from_user(&joydev->glue, argp,
|
||||
sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
|
||||
case JS_GET_ALL:
|
||||
return copy_to_user(argp, &joydev->glue,
|
||||
sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
|
||||
|
||||
case JSIOCGVERSION:
|
||||
return put_user(JS_VERSION, (__u32 __user *) arg);
|
||||
case JSIOCGAXES:
|
||||
return put_user(joydev->nabs, (__u8 __user *) arg);
|
||||
case JSIOCGBUTTONS:
|
||||
return put_user(joydev->nkey, (__u8 __user *) arg);
|
||||
case JSIOCSCORR:
|
||||
if (copy_from_user(joydev->corr, argp,
|
||||
sizeof(struct js_corr) * joydev->nabs))
|
||||
return -EFAULT;
|
||||
for (i = 0; i < joydev->nabs; i++) {
|
||||
j = joydev->abspam[i];
|
||||
joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
|
||||
}
|
||||
return 0;
|
||||
case JSIOCGCORR:
|
||||
return copy_to_user(argp, joydev->corr,
|
||||
sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
|
||||
case JSIOCSAXMAP:
|
||||
if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * ABS_MAX))
|
||||
return -EFAULT;
|
||||
for (i = 0; i < joydev->nabs; i++) {
|
||||
if (joydev->abspam[i] > ABS_MAX) return -EINVAL;
|
||||
joydev->absmap[joydev->abspam[i]] = i;
|
||||
}
|
||||
return 0;
|
||||
case JSIOCGAXMAP:
|
||||
return copy_to_user(argp, joydev->abspam,
|
||||
sizeof(__u8) * ABS_MAX) ? -EFAULT : 0;
|
||||
case JSIOCSBTNMAP:
|
||||
if (copy_from_user(joydev->keypam, argp, sizeof(__u16) * (KEY_MAX - BTN_MISC)))
|
||||
return -EFAULT;
|
||||
for (i = 0; i < joydev->nkey; i++) {
|
||||
if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) return -EINVAL;
|
||||
joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
|
||||
}
|
||||
return 0;
|
||||
case JSIOCGBTNMAP:
|
||||
return copy_to_user(argp, joydev->keypam,
|
||||
sizeof(__u16) * (KEY_MAX - BTN_MISC)) ? -EFAULT : 0;
|
||||
default:
|
||||
if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
|
||||
int len;
|
||||
if (!dev->name) return 0;
|
||||
len = strlen(dev->name) + 1;
|
||||
if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
|
||||
if (copy_to_user(argp, dev->name, len)) return -EFAULT;
|
||||
return len;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct file_operations joydev_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = joydev_read,
|
||||
.write = joydev_write,
|
||||
.poll = joydev_poll,
|
||||
.open = joydev_open,
|
||||
.release = joydev_release,
|
||||
.ioctl = joydev_ioctl,
|
||||
.fasync = joydev_fasync,
|
||||
};
|
||||
|
||||
static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
|
||||
{
|
||||
struct joydev *joydev;
|
||||
int i, j, t, minor;
|
||||
|
||||
for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
|
||||
if (minor == JOYDEV_MINORS) {
|
||||
printk(KERN_ERR "joydev: no more free joydev devices\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(joydev = kmalloc(sizeof(struct joydev), GFP_KERNEL)))
|
||||
return NULL;
|
||||
memset(joydev, 0, sizeof(struct joydev));
|
||||
|
||||
INIT_LIST_HEAD(&joydev->list);
|
||||
init_waitqueue_head(&joydev->wait);
|
||||
|
||||
joydev->minor = minor;
|
||||
joydev->exist = 1;
|
||||
joydev->handle.dev = dev;
|
||||
joydev->handle.name = joydev->name;
|
||||
joydev->handle.handler = handler;
|
||||
joydev->handle.private = joydev;
|
||||
sprintf(joydev->name, "js%d", minor);
|
||||
|
||||
for (i = 0; i < ABS_MAX; i++)
|
||||
if (test_bit(i, dev->absbit)) {
|
||||
joydev->absmap[i] = joydev->nabs;
|
||||
joydev->abspam[joydev->nabs] = i;
|
||||
joydev->nabs++;
|
||||
}
|
||||
|
||||
for (i = BTN_JOYSTICK - BTN_MISC; i < KEY_MAX - BTN_MISC; i++)
|
||||
if (test_bit(i + BTN_MISC, dev->keybit)) {
|
||||
joydev->keymap[i] = joydev->nkey;
|
||||
joydev->keypam[joydev->nkey] = i + BTN_MISC;
|
||||
joydev->nkey++;
|
||||
}
|
||||
|
||||
for (i = 0; i < BTN_JOYSTICK - BTN_MISC; i++)
|
||||
if (test_bit(i + BTN_MISC, dev->keybit)) {
|
||||
joydev->keymap[i] = joydev->nkey;
|
||||
joydev->keypam[joydev->nkey] = i + BTN_MISC;
|
||||
joydev->nkey++;
|
||||
}
|
||||
|
||||
for (i = 0; i < joydev->nabs; i++) {
|
||||
j = joydev->abspam[i];
|
||||
if (dev->absmax[j] == dev->absmin[j]) {
|
||||
joydev->corr[i].type = JS_CORR_NONE;
|
||||
joydev->abs[i] = dev->abs[j];
|
||||
continue;
|
||||
}
|
||||
joydev->corr[i].type = JS_CORR_BROKEN;
|
||||
joydev->corr[i].prec = dev->absfuzz[j];
|
||||
joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j];
|
||||
joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j];
|
||||
if (!(t = ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j])))
|
||||
continue;
|
||||
joydev->corr[i].coef[2] = (1 << 29) / t;
|
||||
joydev->corr[i].coef[3] = (1 << 29) / t;
|
||||
|
||||
joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
|
||||
}
|
||||
|
||||
joydev_table[minor] = joydev;
|
||||
|
||||
devfs_mk_cdev(MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
|
||||
S_IFCHR|S_IRUGO|S_IWUSR, "input/js%d", minor);
|
||||
class_simple_device_add(input_class,
|
||||
MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
|
||||
dev->dev, "js%d", minor);
|
||||
|
||||
return &joydev->handle;
|
||||
}
|
||||
|
||||
static void joydev_disconnect(struct input_handle *handle)
|
||||
{
|
||||
struct joydev *joydev = handle->private;
|
||||
|
||||
class_simple_device_remove(MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor));
|
||||
devfs_remove("input/js%d", joydev->minor);
|
||||
joydev->exist = 0;
|
||||
|
||||
if (joydev->open)
|
||||
input_close_device(handle);
|
||||
else
|
||||
joydev_free(joydev);
|
||||
}
|
||||
|
||||
static struct input_device_id joydev_blacklist[] = {
|
||||
{
|
||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
|
||||
.evbit = { BIT(EV_KEY) },
|
||||
.keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
|
||||
}, /* Avoid itouchpads, touchscreens and tablets */
|
||||
{ }, /* Terminating entry */
|
||||
};
|
||||
|
||||
static struct input_device_id joydev_ids[] = {
|
||||
{
|
||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
|
||||
.evbit = { BIT(EV_ABS) },
|
||||
.absbit = { BIT(ABS_X) },
|
||||
},
|
||||
{
|
||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
|
||||
.evbit = { BIT(EV_ABS) },
|
||||
.absbit = { BIT(ABS_WHEEL) },
|
||||
},
|
||||
{
|
||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
|
||||
.evbit = { BIT(EV_ABS) },
|
||||
.absbit = { BIT(ABS_THROTTLE) },
|
||||
},
|
||||
{ }, /* Terminating entry */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(input, joydev_ids);
|
||||
|
||||
static struct input_handler joydev_handler = {
|
||||
.event = joydev_event,
|
||||
.connect = joydev_connect,
|
||||
.disconnect = joydev_disconnect,
|
||||
.fops = &joydev_fops,
|
||||
.minor = JOYDEV_MINOR_BASE,
|
||||
.name = "joydev",
|
||||
.id_table = joydev_ids,
|
||||
.blacklist = joydev_blacklist,
|
||||
};
|
||||
|
||||
static int __init joydev_init(void)
|
||||
{
|
||||
input_register_handler(&joydev_handler);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit joydev_exit(void)
|
||||
{
|
||||
input_unregister_handler(&joydev_handler);
|
||||
}
|
||||
|
||||
module_init(joydev_init);
|
||||
module_exit(joydev_exit);
|
||||
260
extra/linux-2.6.10/drivers/input/joystick/Kconfig
Normal file
260
extra/linux-2.6.10/drivers/input/joystick/Kconfig
Normal file
@@ -0,0 +1,260 @@
|
||||
#
|
||||
# Joystick driver configuration
|
||||
#
|
||||
config INPUT_JOYSTICK
|
||||
bool "Joysticks"
|
||||
depends on INPUT
|
||||
help
|
||||
If you have a joystick, 6dof controller, gamepad, steering wheel,
|
||||
weapon control system or something like that you can say Y here
|
||||
and the list of supported devices will be displayed. This option
|
||||
doesn't affect the kernel.
|
||||
|
||||
Please read the file <file:Documentation/input/joystick.txt> which
|
||||
contains more information.
|
||||
|
||||
config JOYSTICK_ANALOG
|
||||
tristate "Classic PC analog joysticks and gamepads"
|
||||
depends on INPUT && INPUT_JOYSTICK && GAMEPORT
|
||||
---help---
|
||||
Say Y here if you have a joystick that connects to the PC
|
||||
gameport. In addition to the usual PC analog joystick, this driver
|
||||
supports many extensions, including joysticks with throttle control,
|
||||
with rudders, additional hats and buttons compatible with CH
|
||||
Flightstick Pro, ThrustMaster FCS, 6 and 8 button gamepads, or
|
||||
Saitek Cyborg joysticks.
|
||||
|
||||
Please read the file <file:Documentation/input/joystick.txt> which
|
||||
contains more information.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called analog.
|
||||
|
||||
config JOYSTICK_A3D
|
||||
tristate "Assasin 3D and MadCatz Panther devices"
|
||||
depends on INPUT && INPUT_JOYSTICK && GAMEPORT
|
||||
help
|
||||
Say Y here if you have an FPGaming or MadCatz controller using the
|
||||
A3D protocol over the PC gameport.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called a3d.
|
||||
|
||||
config JOYSTICK_ADI
|
||||
tristate "Logitech ADI digital joysticks and gamepads"
|
||||
depends on INPUT && INPUT_JOYSTICK && GAMEPORT
|
||||
help
|
||||
Say Y here if you have a Logitech controller using the ADI
|
||||
protocol over the PC gameport.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called adi.
|
||||
|
||||
config JOYSTICK_COBRA
|
||||
tristate "Creative Labs Blaster Cobra gamepad"
|
||||
depends on INPUT && INPUT_JOYSTICK && GAMEPORT
|
||||
help
|
||||
Say Y here if you have a Creative Labs Blaster Cobra gamepad.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called cobra.
|
||||
|
||||
config JOYSTICK_GF2K
|
||||
tristate "Genius Flight2000 Digital joysticks and gamepads"
|
||||
depends on INPUT && INPUT_JOYSTICK && GAMEPORT
|
||||
help
|
||||
Say Y here if you have a Genius Flight2000 or MaxFighter digitally
|
||||
communicating joystick or gamepad.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called gf2k.
|
||||
|
||||
config JOYSTICK_GRIP
|
||||
tristate "Gravis GrIP joysticks and gamepads"
|
||||
depends on INPUT && INPUT_JOYSTICK && GAMEPORT
|
||||
help
|
||||
Say Y here if you have a Gravis controller using the GrIP protocol
|
||||
over the PC gameport.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called grip.
|
||||
|
||||
config JOYSTICK_GRIP_MP
|
||||
tristate "Gravis GrIP MultiPort"
|
||||
depends on INPUT && INPUT_JOYSTICK && GAMEPORT
|
||||
help
|
||||
Say Y here if you have the original Gravis GrIP MultiPort, a hub
|
||||
that connects to the gameport and you connect gamepads to it.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called grip_mp.
|
||||
|
||||
config JOYSTICK_GUILLEMOT
|
||||
tristate "Guillemot joysticks and gamepads"
|
||||
depends on INPUT && INPUT_JOYSTICK && GAMEPORT
|
||||
help
|
||||
Say Y here if you have a Guillemot joystick using a digital
|
||||
protocol over the PC gameport.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called guillemot.
|
||||
|
||||
config JOYSTICK_INTERACT
|
||||
tristate "InterAct digital joysticks and gamepads"
|
||||
depends on INPUT && INPUT_JOYSTICK && GAMEPORT
|
||||
help
|
||||
Say Y here if you have an InterAct gameport or joystick
|
||||
communicating digitally over the gameport.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called interact.
|
||||
|
||||
config JOYSTICK_SIDEWINDER
|
||||
tristate "Microsoft SideWinder digital joysticks and gamepads"
|
||||
depends on INPUT && INPUT_JOYSTICK && GAMEPORT
|
||||
help
|
||||
Say Y here if you have a Microsoft controller using the Digital
|
||||
Overdrive protocol over PC gameport.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called sidewinder.
|
||||
|
||||
config JOYSTICK_TMDC
|
||||
tristate "ThrustMaster DirectConnect joysticks and gamepads"
|
||||
depends on INPUT && INPUT_JOYSTICK && GAMEPORT
|
||||
help
|
||||
Say Y here if you have a ThrustMaster controller using the
|
||||
DirectConnect (BSP) protocol over the PC gameport.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called tmdc.
|
||||
|
||||
source "drivers/input/joystick/iforce/Kconfig"
|
||||
|
||||
config JOYSTICK_WARRIOR
|
||||
tristate "Logitech WingMan Warrior joystick"
|
||||
depends on INPUT && INPUT_JOYSTICK
|
||||
select SERIO
|
||||
help
|
||||
Say Y here if you have a Logitech WingMan Warrior joystick connected
|
||||
to your computer's serial port.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called warrior.
|
||||
|
||||
config JOYSTICK_MAGELLAN
|
||||
tristate "LogiCad3d Magellan/SpaceMouse 6dof controllers"
|
||||
depends on INPUT && INPUT_JOYSTICK
|
||||
select SERIO
|
||||
help
|
||||
Say Y here if you have a Magellan or Space Mouse 6DOF controller
|
||||
connected to your computer's serial port.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called magellan.
|
||||
|
||||
config JOYSTICK_SPACEORB
|
||||
tristate "SpaceTec SpaceOrb/Avenger 6dof controllers"
|
||||
depends on INPUT && INPUT_JOYSTICK
|
||||
select SERIO
|
||||
help
|
||||
Say Y here if you have a SpaceOrb 360 or SpaceBall Avenger 6DOF
|
||||
controller connected to your computer's serial port.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called spaceorb.
|
||||
|
||||
config JOYSTICK_SPACEBALL
|
||||
tristate "SpaceTec SpaceBall 6dof controllers"
|
||||
depends on INPUT && INPUT_JOYSTICK
|
||||
select SERIO
|
||||
help
|
||||
Say Y here if you have a SpaceTec SpaceBall 2003/3003/4000 FLX
|
||||
controller connected to your computer's serial port. For the
|
||||
SpaceBall 4000 USB model, use the USB HID driver.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called spaceball.
|
||||
|
||||
config JOYSTICK_STINGER
|
||||
tristate "Gravis Stinger gamepad"
|
||||
depends on INPUT && INPUT_JOYSTICK
|
||||
select SERIO
|
||||
help
|
||||
Say Y here if you have a Gravis Stinger connected to one of your
|
||||
serial ports.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called stinger.
|
||||
|
||||
config JOYSTICK_TWIDDLER
|
||||
tristate "Twiddler as a joystick"
|
||||
depends on INPUT && INPUT_JOYSTICK
|
||||
select SERIO
|
||||
help
|
||||
Say Y here if you have a Handykey Twiddler connected to your
|
||||
computer's serial port and want to use it as a joystick.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called twidjoy.
|
||||
|
||||
config JOYSTICK_DB9
|
||||
tristate "Multisystem, Sega Genesis, Saturn joysticks and gamepads"
|
||||
depends on INPUT && INPUT_JOYSTICK && PARPORT
|
||||
---help---
|
||||
Say Y here if you have a Sega Master System gamepad, Sega Genesis
|
||||
gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga,
|
||||
Commodore, Amstrad CPC joystick connected to your parallel port.
|
||||
For more information on how to use the driver please read
|
||||
<file:Documentation/input/joystick-parport.txt>.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called db9.
|
||||
|
||||
config JOYSTICK_GAMECON
|
||||
tristate "Multisystem, NES, SNES, N64, PSX joysticks and gamepads"
|
||||
depends on INPUT && INPUT_JOYSTICK && PARPORT
|
||||
---help---
|
||||
Say Y here if you have a Nintendo Entertainment System gamepad,
|
||||
Super Nintendo Entertainment System gamepad, Nintendo 64 gamepad,
|
||||
Sony PlayStation gamepad or a Multisystem -- Atari, Amiga,
|
||||
Commodore, Amstrad CPC joystick connected to your parallel port.
|
||||
For more information on how to use the driver please read
|
||||
<file:Documentation/input/joystick-parport.txt>.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called gamecon.
|
||||
|
||||
config JOYSTICK_TURBOGRAFX
|
||||
tristate "Multisystem joysticks via TurboGraFX device"
|
||||
depends on INPUT && INPUT_JOYSTICK && PARPORT
|
||||
help
|
||||
Say Y here if you have the TurboGraFX interface by Steffen Schwenke,
|
||||
and want to use it with Multisystem -- Atari, Amiga, Commodore,
|
||||
Amstrad CPC joystick. For more information on how to use the driver
|
||||
please read <file:Documentation/input/joystick-parport.txt>.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called turbografx.
|
||||
|
||||
config JOYSTICK_AMIGA
|
||||
tristate "Amiga joysticks"
|
||||
depends on AMIGA && INPUT && INPUT_JOYSTICK
|
||||
help
|
||||
Say Y here if you have an Amiga with a digital joystick connected
|
||||
to it.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called amijoy.
|
||||
|
||||
config JOYSTICK_JOYDUMP
|
||||
tristate "Gameport data dumper"
|
||||
depends on INPUT && INPUT_JOYSTICK && GAMEPORT
|
||||
help
|
||||
Say Y here if you want to dump data from your joystick into the system
|
||||
log for debugging purposes. Say N if you are making a production
|
||||
configuration or aren't sure.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called joydump.
|
||||
|
||||
30
extra/linux-2.6.10/drivers/input/joystick/Makefile
Normal file
30
extra/linux-2.6.10/drivers/input/joystick/Makefile
Normal file
@@ -0,0 +1,30 @@
|
||||
#
|
||||
# Makefile for the input core drivers.
|
||||
#
|
||||
|
||||
# Each configuration option enables a list of files.
|
||||
|
||||
obj-$(CONFIG_JOYSTICK_A3D) += a3d.o
|
||||
obj-$(CONFIG_JOYSTICK_ADI) += adi.o
|
||||
obj-$(CONFIG_JOYSTICK_AMIGA) += amijoy.o
|
||||
obj-$(CONFIG_JOYSTICK_ANALOG) += analog.o
|
||||
obj-$(CONFIG_JOYSTICK_COBRA) += cobra.o
|
||||
obj-$(CONFIG_JOYSTICK_DB9) += db9.o
|
||||
obj-$(CONFIG_JOYSTICK_GAMECON) += gamecon.o
|
||||
obj-$(CONFIG_JOYSTICK_GF2K) += gf2k.o
|
||||
obj-$(CONFIG_JOYSTICK_GRIP) += grip.o
|
||||
obj-$(CONFIG_JOYSTICK_GRIP_MP) += grip_mp.o
|
||||
obj-$(CONFIG_JOYSTICK_GUILLEMOT) += guillemot.o
|
||||
obj-$(CONFIG_JOYSTICK_INTERACT) += interact.o
|
||||
obj-$(CONFIG_JOYSTICK_JOYDUMP) += joydump.o
|
||||
obj-$(CONFIG_JOYSTICK_MAGELLAN) += magellan.o
|
||||
obj-$(CONFIG_JOYSTICK_SIDEWINDER) += sidewinder.o
|
||||
obj-$(CONFIG_JOYSTICK_SPACEBALL) += spaceball.o
|
||||
obj-$(CONFIG_JOYSTICK_SPACEORB) += spaceorb.o
|
||||
obj-$(CONFIG_JOYSTICK_STINGER) += stinger.o
|
||||
obj-$(CONFIG_JOYSTICK_TMDC) += tmdc.o
|
||||
obj-$(CONFIG_JOYSTICK_TURBOGRAFX) += turbografx.o
|
||||
obj-$(CONFIG_JOYSTICK_TWIDJOY) += twidjoy.o
|
||||
obj-$(CONFIG_JOYSTICK_WARRIOR) += warrior.o
|
||||
|
||||
obj-$(CONFIG_JOYSTICK_IFORCE) += iforce/
|
||||
405
extra/linux-2.6.10/drivers/input/joystick/a3d.c
Normal file
405
extra/linux-2.6.10/drivers/input/joystick/a3d.c
Normal file
@@ -0,0 +1,405 @@
|
||||
/*
|
||||
* $Id: a3d.c,v 1.21 2002/01/22 20:11:50 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1998-2001 Vojtech Pavlik
|
||||
*/
|
||||
|
||||
/*
|
||||
* FP-Gaming Assasin 3D joystick driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/gameport.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("FP-Gaming Assasin 3D joystick driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define A3D_MAX_START 400 /* 400 us */
|
||||
#define A3D_MAX_STROBE 60 /* 40 us */
|
||||
#define A3D_DELAY_READ 3 /* 3 ms */
|
||||
#define A3D_MAX_LENGTH 40 /* 40*3 bits */
|
||||
#define A3D_REFRESH_TIME HZ/50 /* 20 ms */
|
||||
|
||||
#define A3D_MODE_A3D 1 /* Assassin 3D */
|
||||
#define A3D_MODE_PAN 2 /* Panther */
|
||||
#define A3D_MODE_OEM 3 /* Panther OEM version */
|
||||
#define A3D_MODE_PXL 4 /* Panther XL */
|
||||
|
||||
char *a3d_names[] = { NULL, "FP-Gaming Assassin 3D", "MadCatz Panther", "OEM Panther",
|
||||
"MadCatz Panther XL", "MadCatz Panther XL w/ rudder" };
|
||||
|
||||
struct a3d {
|
||||
struct gameport *gameport;
|
||||
struct gameport adc;
|
||||
struct input_dev dev;
|
||||
struct timer_list timer;
|
||||
int axes[4];
|
||||
int buttons;
|
||||
int mode;
|
||||
int length;
|
||||
int used;
|
||||
int reads;
|
||||
int bads;
|
||||
char phys[32];
|
||||
char adcphys[32];
|
||||
};
|
||||
|
||||
/*
|
||||
* a3d_read_packet() reads an Assassin 3D packet.
|
||||
*/
|
||||
|
||||
static int a3d_read_packet(struct gameport *gameport, int length, char *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned char u, v;
|
||||
unsigned int t, s;
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
t = gameport_time(gameport, A3D_MAX_START);
|
||||
s = gameport_time(gameport, A3D_MAX_STROBE);
|
||||
|
||||
local_irq_save(flags);
|
||||
gameport_trigger(gameport);
|
||||
v = gameport_read(gameport);
|
||||
|
||||
while (t > 0 && i < length) {
|
||||
t--;
|
||||
u = v; v = gameport_read(gameport);
|
||||
if (~v & u & 0x10) {
|
||||
data[i++] = v >> 5;
|
||||
t = s;
|
||||
}
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* a3d_csum() computes checksum of triplet packet
|
||||
*/
|
||||
|
||||
static int a3d_csum(char *data, int count)
|
||||
{
|
||||
int i, csum = 0;
|
||||
for (i = 0; i < count - 2; i++) csum += data[i];
|
||||
return (csum & 0x3f) != ((data[count - 2] << 3) | data[count - 1]);
|
||||
}
|
||||
|
||||
static void a3d_read(struct a3d *a3d, unsigned char *data)
|
||||
{
|
||||
struct input_dev *dev = &a3d->dev;
|
||||
|
||||
switch (a3d->mode) {
|
||||
|
||||
case A3D_MODE_A3D:
|
||||
case A3D_MODE_OEM:
|
||||
case A3D_MODE_PAN:
|
||||
|
||||
input_report_rel(dev, REL_X, ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7));
|
||||
input_report_rel(dev, REL_Y, ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7));
|
||||
|
||||
input_report_key(dev, BTN_RIGHT, data[2] & 1);
|
||||
input_report_key(dev, BTN_LEFT, data[3] & 2);
|
||||
input_report_key(dev, BTN_MIDDLE, data[3] & 4);
|
||||
|
||||
input_sync(dev);
|
||||
|
||||
a3d->axes[0] = ((signed char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128;
|
||||
a3d->axes[1] = ((signed char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128;
|
||||
a3d->axes[2] = ((signed char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128;
|
||||
a3d->axes[3] = ((signed char)((data[20] << 6) | (data[21] << 3) | (data[22]))) + 128;
|
||||
|
||||
a3d->buttons = ((data[3] << 3) | data[4]) & 0xf;
|
||||
|
||||
return;
|
||||
|
||||
case A3D_MODE_PXL:
|
||||
|
||||
input_report_rel(dev, REL_X, ((data[ 9] << 6) | (data[10] << 3) | data[11]) - ((data[ 9] & 4) << 7));
|
||||
input_report_rel(dev, REL_Y, ((data[12] << 6) | (data[13] << 3) | data[14]) - ((data[12] & 4) << 7));
|
||||
|
||||
input_report_key(dev, BTN_RIGHT, data[2] & 1);
|
||||
input_report_key(dev, BTN_LEFT, data[3] & 2);
|
||||
input_report_key(dev, BTN_MIDDLE, data[3] & 4);
|
||||
input_report_key(dev, BTN_SIDE, data[7] & 2);
|
||||
input_report_key(dev, BTN_EXTRA, data[7] & 4);
|
||||
|
||||
input_report_abs(dev, ABS_X, ((signed char)((data[15] << 6) | (data[16] << 3) | (data[17]))) + 128);
|
||||
input_report_abs(dev, ABS_Y, ((signed char)((data[18] << 6) | (data[19] << 3) | (data[20]))) + 128);
|
||||
input_report_abs(dev, ABS_RUDDER, ((signed char)((data[21] << 6) | (data[22] << 3) | (data[23]))) + 128);
|
||||
input_report_abs(dev, ABS_THROTTLE, ((signed char)((data[24] << 6) | (data[25] << 3) | (data[26]))) + 128);
|
||||
|
||||
input_report_abs(dev, ABS_HAT0X, ( data[5] & 1) - ((data[5] >> 2) & 1));
|
||||
input_report_abs(dev, ABS_HAT0Y, ((data[5] >> 1) & 1) - ((data[6] >> 2) & 1));
|
||||
input_report_abs(dev, ABS_HAT1X, ((data[4] >> 1) & 1) - ( data[3] & 1));
|
||||
input_report_abs(dev, ABS_HAT1Y, ((data[4] >> 2) & 1) - ( data[4] & 1));
|
||||
|
||||
input_report_key(dev, BTN_TRIGGER, data[8] & 1);
|
||||
input_report_key(dev, BTN_THUMB, data[8] & 2);
|
||||
input_report_key(dev, BTN_TOP, data[8] & 4);
|
||||
input_report_key(dev, BTN_PINKIE, data[7] & 1);
|
||||
|
||||
input_sync(dev);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* a3d_timer() reads and analyzes A3D joystick data.
|
||||
*/
|
||||
|
||||
static void a3d_timer(unsigned long private)
|
||||
{
|
||||
struct a3d *a3d = (void *) private;
|
||||
unsigned char data[A3D_MAX_LENGTH];
|
||||
a3d->reads++;
|
||||
if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length
|
||||
|| data[0] != a3d->mode || a3d_csum(data, a3d->length))
|
||||
a3d->bads++; else a3d_read(a3d, data);
|
||||
mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
|
||||
}
|
||||
|
||||
/*
|
||||
* a3d_adc_cooked_read() copies the acis and button data to the
|
||||
* callers arrays. It could do the read itself, but the caller could
|
||||
* call this more than 50 times a second, which would use too much CPU.
|
||||
*/
|
||||
|
||||
int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *buttons)
|
||||
{
|
||||
struct a3d *a3d = gameport->driver;
|
||||
int i;
|
||||
for (i = 0; i < 4; i++)
|
||||
axes[i] = (a3d->axes[i] < 254) ? a3d->axes[i] : -1;
|
||||
*buttons = a3d->buttons;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* a3d_adc_open() is the gameport open routine. It refuses to serve
|
||||
* any but cooked data.
|
||||
*/
|
||||
|
||||
int a3d_adc_open(struct gameport *gameport, int mode)
|
||||
{
|
||||
struct a3d *a3d = gameport->driver;
|
||||
if (mode != GAMEPORT_MODE_COOKED)
|
||||
return -1;
|
||||
if (!a3d->used++)
|
||||
mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* a3d_adc_close() is a callback from the input close routine.
|
||||
*/
|
||||
|
||||
static void a3d_adc_close(struct gameport *gameport)
|
||||
{
|
||||
struct a3d *a3d = gameport->driver;
|
||||
if (!--a3d->used)
|
||||
del_timer(&a3d->timer);
|
||||
}
|
||||
|
||||
/*
|
||||
* a3d_open() is a callback from the input open routine.
|
||||
*/
|
||||
|
||||
static int a3d_open(struct input_dev *dev)
|
||||
{
|
||||
struct a3d *a3d = dev->private;
|
||||
if (!a3d->used++)
|
||||
mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* a3d_close() is a callback from the input close routine.
|
||||
*/
|
||||
|
||||
static void a3d_close(struct input_dev *dev)
|
||||
{
|
||||
struct a3d *a3d = dev->private;
|
||||
if (!--a3d->used)
|
||||
del_timer(&a3d->timer);
|
||||
}
|
||||
|
||||
/*
|
||||
* a3d_connect() probes for A3D joysticks.
|
||||
*/
|
||||
|
||||
static void a3d_connect(struct gameport *gameport, struct gameport_dev *dev)
|
||||
{
|
||||
struct a3d *a3d;
|
||||
unsigned char data[A3D_MAX_LENGTH];
|
||||
int i;
|
||||
|
||||
if (!(a3d = kmalloc(sizeof(struct a3d), GFP_KERNEL)))
|
||||
return;
|
||||
memset(a3d, 0, sizeof(struct a3d));
|
||||
|
||||
gameport->private = a3d;
|
||||
|
||||
a3d->gameport = gameport;
|
||||
init_timer(&a3d->timer);
|
||||
a3d->timer.data = (long) a3d;
|
||||
a3d->timer.function = a3d_timer;
|
||||
|
||||
if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
|
||||
goto fail1;
|
||||
|
||||
i = a3d_read_packet(gameport, A3D_MAX_LENGTH, data);
|
||||
|
||||
if (!i || a3d_csum(data, i))
|
||||
goto fail2;
|
||||
|
||||
a3d->mode = data[0];
|
||||
|
||||
if (!a3d->mode || a3d->mode > 5) {
|
||||
printk(KERN_WARNING "a3d.c: Unknown A3D device detected "
|
||||
"(%s, id=%d), contact <vojtech@ucw.cz>\n", gameport->phys, a3d->mode);
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
sprintf(a3d->phys, "%s/input0", gameport->phys);
|
||||
sprintf(a3d->adcphys, "%s/gameport0", gameport->phys);
|
||||
|
||||
if (a3d->mode == A3D_MODE_PXL) {
|
||||
|
||||
int axes[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER };
|
||||
|
||||
a3d->length = 33;
|
||||
|
||||
init_input_dev(&a3d->dev);
|
||||
|
||||
a3d->dev.evbit[0] |= BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
|
||||
a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
|
||||
a3d->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_RUDDER)
|
||||
| BIT(ABS_HAT0X) | BIT(ABS_HAT0Y) | BIT(ABS_HAT1X) | BIT(ABS_HAT1Y);
|
||||
|
||||
a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE)
|
||||
| BIT(BTN_SIDE) | BIT(BTN_EXTRA);
|
||||
|
||||
a3d->dev.keybit[LONG(BTN_JOYSTICK)] |= BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_PINKIE);
|
||||
|
||||
a3d_read(a3d, data);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (i < 2) {
|
||||
a3d->dev.absmin[axes[i]] = 48;
|
||||
a3d->dev.absmax[axes[i]] = a3d->dev.abs[axes[i]] * 2 - 48;
|
||||
a3d->dev.absflat[axes[i]] = 8;
|
||||
} else {
|
||||
a3d->dev.absmin[axes[i]] = 2;
|
||||
a3d->dev.absmax[axes[i]] = 253;
|
||||
}
|
||||
a3d->dev.absmin[ABS_HAT0X + i] = -1;
|
||||
a3d->dev.absmax[ABS_HAT0X + i] = 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
a3d->length = 29;
|
||||
|
||||
init_input_dev(&a3d->dev);
|
||||
|
||||
a3d->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_REL);
|
||||
a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
|
||||
a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE);
|
||||
|
||||
a3d->adc.driver = a3d;
|
||||
a3d->adc.open = a3d_adc_open;
|
||||
a3d->adc.close = a3d_adc_close;
|
||||
a3d->adc.cooked_read = a3d_adc_cooked_read;
|
||||
a3d->adc.fuzz = 1;
|
||||
|
||||
a3d->adc.name = a3d_names[a3d->mode];
|
||||
a3d->adc.phys = a3d->adcphys;
|
||||
a3d->adc.id.bustype = BUS_GAMEPORT;
|
||||
a3d->adc.id.vendor = GAMEPORT_ID_VENDOR_MADCATZ;
|
||||
a3d->adc.id.product = a3d->mode;
|
||||
a3d->adc.id.version = 0x0100;
|
||||
|
||||
a3d_read(a3d, data);
|
||||
|
||||
gameport_register_port(&a3d->adc);
|
||||
printk(KERN_INFO "gameport: %s on %s\n", a3d_names[a3d->mode], gameport->phys);
|
||||
}
|
||||
|
||||
a3d->dev.private = a3d;
|
||||
a3d->dev.open = a3d_open;
|
||||
a3d->dev.close = a3d_close;
|
||||
|
||||
a3d->dev.name = a3d_names[a3d->mode];
|
||||
a3d->dev.phys = a3d->phys;
|
||||
a3d->dev.id.bustype = BUS_GAMEPORT;
|
||||
a3d->dev.id.vendor = GAMEPORT_ID_VENDOR_MADCATZ;
|
||||
a3d->dev.id.product = a3d->mode;
|
||||
a3d->dev.id.version = 0x0100;
|
||||
|
||||
input_register_device(&a3d->dev);
|
||||
printk(KERN_INFO "input: %s on %s\n", a3d_names[a3d->mode], a3d->phys);
|
||||
|
||||
return;
|
||||
fail2: gameport_close(gameport);
|
||||
fail1: kfree(a3d);
|
||||
}
|
||||
|
||||
static void a3d_disconnect(struct gameport *gameport)
|
||||
{
|
||||
|
||||
struct a3d *a3d = gameport->private;
|
||||
input_unregister_device(&a3d->dev);
|
||||
if (a3d->mode < A3D_MODE_PXL)
|
||||
gameport_unregister_port(&a3d->adc);
|
||||
gameport_close(gameport);
|
||||
kfree(a3d);
|
||||
}
|
||||
|
||||
static struct gameport_dev a3d_dev = {
|
||||
.connect = a3d_connect,
|
||||
.disconnect = a3d_disconnect,
|
||||
};
|
||||
|
||||
int __init a3d_init(void)
|
||||
{
|
||||
gameport_register_device(&a3d_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit a3d_exit(void)
|
||||
{
|
||||
gameport_unregister_device(&a3d_dev);
|
||||
}
|
||||
|
||||
module_init(a3d_init);
|
||||
module_exit(a3d_exit);
|
||||
564
extra/linux-2.6.10/drivers/input/joystick/adi.c
Normal file
564
extra/linux-2.6.10/drivers/input/joystick/adi.c
Normal file
@@ -0,0 +1,564 @@
|
||||
/*
|
||||
* $Id: adi.c,v 1.23 2002/01/22 20:26:17 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1998-2001 Vojtech Pavlik
|
||||
*/
|
||||
|
||||
/*
|
||||
* Logitech ADI joystick family driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/gameport.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Logitech ADI joystick family driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
* Times, array sizes, flags, ids.
|
||||
*/
|
||||
|
||||
#define ADI_MAX_START 200 /* Trigger to packet timeout [200us] */
|
||||
#define ADI_MAX_STROBE 40 /* Single bit timeout [40us] */
|
||||
#define ADI_REFRESH_TIME HZ/50 /* How often to poll the joystick [20 ms] */
|
||||
#define ADI_INIT_DELAY 10 /* Delay after init packet [10ms] */
|
||||
#define ADI_DATA_DELAY 4 /* Delay after data packet [4ms] */
|
||||
|
||||
#define ADI_MAX_LENGTH 256
|
||||
#define ADI_MIN_LENGTH 8
|
||||
#define ADI_MIN_LEN_LENGTH 10
|
||||
#define ADI_MIN_ID_LENGTH 66
|
||||
#define ADI_MAX_NAME_LENGTH 48
|
||||
#define ADI_MAX_CNAME_LENGTH 16
|
||||
#define ADI_MAX_PHYS_LENGTH 32
|
||||
|
||||
#define ADI_FLAG_HAT 0x04
|
||||
#define ADI_FLAG_10BIT 0x08
|
||||
|
||||
#define ADI_ID_TPD 0x01
|
||||
#define ADI_ID_WGP 0x06
|
||||
#define ADI_ID_WGPE 0x08
|
||||
#define ADI_ID_MAX 0x0a
|
||||
|
||||
/*
|
||||
* Names, buttons, axes ...
|
||||
*/
|
||||
|
||||
static char *adi_names[] = { "WingMan Extreme Digital", "ThunderPad Digital", "SideCar", "CyberMan 2",
|
||||
"WingMan Interceptor", "WingMan Formula", "WingMan GamePad",
|
||||
"WingMan Extreme Digital 3D", "WingMan GamePad Extreme",
|
||||
"WingMan GamePad USB", "Unknown Device %#x" };
|
||||
|
||||
static char adi_wmgpe_abs[] = { ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y };
|
||||
static char adi_wmi_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
|
||||
static char adi_wmed3d_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RZ, ABS_HAT0X, ABS_HAT0Y };
|
||||
static char adi_cm2_abs[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ };
|
||||
static char adi_wmf_abs[] = { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
|
||||
|
||||
static short adi_wmgpe_key[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT };
|
||||
static short adi_wmi_key[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
|
||||
static short adi_wmed3d_key[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2 };
|
||||
static short adi_cm2_key[] = { BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 };
|
||||
|
||||
static char* adi_abs[] = { adi_wmi_abs, adi_wmgpe_abs, adi_wmf_abs, adi_cm2_abs, adi_wmi_abs, adi_wmf_abs,
|
||||
adi_wmgpe_abs, adi_wmed3d_abs, adi_wmgpe_abs, adi_wmgpe_abs, adi_wmi_abs };
|
||||
|
||||
static short* adi_key[] = { adi_wmi_key, adi_wmgpe_key, adi_cm2_key, adi_cm2_key, adi_wmi_key, adi_cm2_key,
|
||||
adi_wmgpe_key, adi_wmed3d_key, adi_wmgpe_key, adi_wmgpe_key, adi_wmi_key };
|
||||
|
||||
/*
|
||||
* Hat to axis conversion arrays.
|
||||
*/
|
||||
|
||||
static struct {
|
||||
int x;
|
||||
int y;
|
||||
} adi_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
|
||||
|
||||
/*
|
||||
* Per-port information.
|
||||
*/
|
||||
|
||||
struct adi {
|
||||
struct input_dev dev;
|
||||
int length;
|
||||
int ret;
|
||||
int idx;
|
||||
unsigned char id;
|
||||
char buttons;
|
||||
char axes10;
|
||||
char axes8;
|
||||
signed char pad;
|
||||
char hats;
|
||||
char *abs;
|
||||
short *key;
|
||||
char name[ADI_MAX_NAME_LENGTH];
|
||||
char cname[ADI_MAX_CNAME_LENGTH];
|
||||
char phys[ADI_MAX_PHYS_LENGTH];
|
||||
unsigned char data[ADI_MAX_LENGTH];
|
||||
};
|
||||
|
||||
struct adi_port {
|
||||
struct gameport *gameport;
|
||||
struct timer_list timer;
|
||||
struct adi adi[2];
|
||||
int bad;
|
||||
int reads;
|
||||
int used;
|
||||
};
|
||||
|
||||
/*
|
||||
* adi_read_packet() reads a Logitech ADI packet.
|
||||
*/
|
||||
|
||||
static void adi_read_packet(struct adi_port *port)
|
||||
{
|
||||
struct adi *adi = port->adi;
|
||||
struct gameport *gameport = port->gameport;
|
||||
unsigned char u, v, w, x, z;
|
||||
int t[2], s[2], i;
|
||||
unsigned long flags;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
adi[i].ret = -1;
|
||||
t[i] = gameport_time(gameport, ADI_MAX_START);
|
||||
s[i] = 0;
|
||||
}
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
gameport_trigger(gameport);
|
||||
v = z = gameport_read(gameport);
|
||||
|
||||
do {
|
||||
u = v;
|
||||
w = u ^ (v = x = gameport_read(gameport));
|
||||
for (i = 0; i < 2; i++, w >>= 2, x >>= 2) {
|
||||
t[i]--;
|
||||
if ((w & 0x30) && s[i]) {
|
||||
if ((w & 0x30) < 0x30 && adi[i].ret < ADI_MAX_LENGTH && t[i] > 0) {
|
||||
adi[i].data[++adi[i].ret] = w;
|
||||
t[i] = gameport_time(gameport, ADI_MAX_STROBE);
|
||||
} else t[i] = 0;
|
||||
} else if (!(x & 0x30)) s[i] = 1;
|
||||
}
|
||||
} while (t[0] > 0 || t[1] > 0);
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* adi_move_bits() detects a possible 2-stream mode, and moves
|
||||
* the bits accordingly.
|
||||
*/
|
||||
|
||||
static void adi_move_bits(struct adi_port *port, int length)
|
||||
{
|
||||
int i;
|
||||
struct adi *adi = port->adi;
|
||||
|
||||
adi[0].idx = adi[1].idx = 0;
|
||||
|
||||
if (adi[0].ret <= 0 || adi[1].ret <= 0) return;
|
||||
if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return;
|
||||
|
||||
for (i = 1; i <= adi[1].ret; i++)
|
||||
adi[0].data[((length - 1) >> 1) + i + 1] = adi[1].data[i];
|
||||
|
||||
adi[0].ret += adi[1].ret;
|
||||
adi[1].ret = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* adi_get_bits() gathers bits from the data packet.
|
||||
*/
|
||||
|
||||
static inline int adi_get_bits(struct adi *adi, int count)
|
||||
{
|
||||
int bits = 0;
|
||||
int i;
|
||||
if ((adi->idx += count) > adi->ret) return 0;
|
||||
for (i = 0; i < count; i++)
|
||||
bits |= ((adi->data[adi->idx - i] >> 5) & 1) << i;
|
||||
return bits;
|
||||
}
|
||||
|
||||
/*
|
||||
* adi_decode() decodes Logitech joystick data into input events.
|
||||
*/
|
||||
|
||||
static int adi_decode(struct adi *adi)
|
||||
{
|
||||
struct input_dev *dev = &adi->dev;
|
||||
char *abs = adi->abs;
|
||||
short *key = adi->key;
|
||||
int i, t;
|
||||
|
||||
if (adi->ret < adi->length || adi->id != (adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4)))
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < adi->axes10; i++)
|
||||
input_report_abs(dev, *abs++, adi_get_bits(adi, 10));
|
||||
|
||||
for (i = 0; i < adi->axes8; i++)
|
||||
input_report_abs(dev, *abs++, adi_get_bits(adi, 8));
|
||||
|
||||
for (i = 0; i < adi->buttons && i < 63; i++) {
|
||||
if (i == adi->pad) {
|
||||
t = adi_get_bits(adi, 4);
|
||||
input_report_abs(dev, *abs++, ((t >> 2) & 1) - ( t & 1));
|
||||
input_report_abs(dev, *abs++, ((t >> 1) & 1) - ((t >> 3) & 1));
|
||||
}
|
||||
input_report_key(dev, *key++, adi_get_bits(adi, 1));
|
||||
}
|
||||
|
||||
for (i = 0; i < adi->hats; i++) {
|
||||
if ((t = adi_get_bits(adi, 4)) > 8) t = 0;
|
||||
input_report_abs(dev, *abs++, adi_hat_to_axis[t].x);
|
||||
input_report_abs(dev, *abs++, adi_hat_to_axis[t].y);
|
||||
}
|
||||
|
||||
for (i = 63; i < adi->buttons; i++)
|
||||
input_report_key(dev, *key++, adi_get_bits(adi, 1));
|
||||
|
||||
input_sync(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* adi_read() reads the data packet and decodes it.
|
||||
*/
|
||||
|
||||
static int adi_read(struct adi_port *port)
|
||||
{
|
||||
int i;
|
||||
int result = 0;
|
||||
|
||||
adi_read_packet(port);
|
||||
adi_move_bits(port, port->adi[0].length);
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
if (port->adi[i].length)
|
||||
result |= adi_decode(port->adi + i);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* adi_timer() repeatedly polls the Logitech joysticks.
|
||||
*/
|
||||
|
||||
static void adi_timer(unsigned long data)
|
||||
{
|
||||
struct adi_port *port = (void *) data;
|
||||
port->bad -= adi_read(port);
|
||||
port->reads++;
|
||||
mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME);
|
||||
}
|
||||
|
||||
/*
|
||||
* adi_open() is a callback from the input open routine.
|
||||
*/
|
||||
|
||||
static int adi_open(struct input_dev *dev)
|
||||
{
|
||||
struct adi_port *port = dev->private;
|
||||
if (!port->used++)
|
||||
mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* adi_close() is a callback from the input close routine.
|
||||
*/
|
||||
|
||||
static void adi_close(struct input_dev *dev)
|
||||
{
|
||||
struct adi_port *port = dev->private;
|
||||
if (!--port->used)
|
||||
del_timer(&port->timer);
|
||||
}
|
||||
|
||||
/*
|
||||
* adi_init_digital() sends a trigger & delay sequence
|
||||
* to reset and initialize a Logitech joystick into digital mode.
|
||||
*/
|
||||
|
||||
static void adi_init_digital(struct gameport *gameport)
|
||||
{
|
||||
int seq[] = { 3, -2, -3, 10, -6, -11, -7, -9, 11, 0 };
|
||||
int i;
|
||||
|
||||
for (i = 0; seq[i]; i++) {
|
||||
gameport_trigger(gameport);
|
||||
if (seq[i] > 0) msleep(seq[i]);
|
||||
if (seq[i] < 0) mdelay(-seq[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void adi_id_decode(struct adi *adi, struct adi_port *port)
|
||||
{
|
||||
int i, t;
|
||||
|
||||
if (adi->ret < ADI_MIN_ID_LENGTH) /* Minimum ID packet length */
|
||||
return;
|
||||
|
||||
if (adi->ret < (t = adi_get_bits(adi, 10))) {
|
||||
printk(KERN_WARNING "adi: Short ID packet: reported: %d != read: %d\n", t, adi->ret);
|
||||
return;
|
||||
}
|
||||
|
||||
adi->id = adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4);
|
||||
|
||||
if ((t = adi_get_bits(adi, 4)) & ADI_FLAG_HAT) adi->hats++;
|
||||
|
||||
adi->length = adi_get_bits(adi, 10);
|
||||
|
||||
if (adi->length >= ADI_MAX_LENGTH || adi->length < ADI_MIN_LENGTH) {
|
||||
printk(KERN_WARNING "adi: Bad data packet length (%d).\n", adi->length);
|
||||
adi->length = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
adi->axes8 = adi_get_bits(adi, 4);
|
||||
adi->buttons = adi_get_bits(adi, 6);
|
||||
|
||||
if (adi_get_bits(adi, 6) != 8 && adi->hats) {
|
||||
printk(KERN_WARNING "adi: Other than 8-dir POVs not supported yet.\n");
|
||||
adi->length = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
adi->buttons += adi_get_bits(adi, 6);
|
||||
adi->hats += adi_get_bits(adi, 4);
|
||||
|
||||
i = adi_get_bits(adi, 4);
|
||||
|
||||
if (t & ADI_FLAG_10BIT) {
|
||||
adi->axes10 = adi->axes8 - i;
|
||||
adi->axes8 = i;
|
||||
}
|
||||
|
||||
t = adi_get_bits(adi, 4);
|
||||
|
||||
for (i = 0; i < t; i++)
|
||||
adi->cname[i] = adi_get_bits(adi, 8);
|
||||
adi->cname[i] = 0;
|
||||
|
||||
t = 8 + adi->buttons + adi->axes10 * 10 + adi->axes8 * 8 + adi->hats * 4;
|
||||
if (adi->length != t && adi->length != t + (t & 1)) {
|
||||
printk(KERN_WARNING "adi: Expected length %d != data length %d\n", t, adi->length);
|
||||
adi->length = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (adi->id) {
|
||||
case ADI_ID_TPD:
|
||||
adi->pad = 4;
|
||||
adi->buttons -= 4;
|
||||
break;
|
||||
case ADI_ID_WGP:
|
||||
adi->pad = 0;
|
||||
adi->buttons -= 4;
|
||||
break;
|
||||
default:
|
||||
adi->pad = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void adi_init_input(struct adi *adi, struct adi_port *port, int half)
|
||||
{
|
||||
int i, t;
|
||||
char buf[ADI_MAX_NAME_LENGTH];
|
||||
|
||||
if (!adi->length) return;
|
||||
|
||||
init_input_dev(&adi->dev);
|
||||
|
||||
t = adi->id < ADI_ID_MAX ? adi->id : ADI_ID_MAX;
|
||||
|
||||
sprintf(buf, adi_names[t], adi->id);
|
||||
sprintf(adi->name, "Logitech %s", buf);
|
||||
sprintf(adi->phys, "%s/input%d", port->gameport->phys, half);
|
||||
|
||||
adi->abs = adi_abs[t];
|
||||
adi->key = adi_key[t];
|
||||
|
||||
adi->dev.open = adi_open;
|
||||
adi->dev.close = adi_close;
|
||||
|
||||
adi->dev.name = adi->name;
|
||||
adi->dev.phys = adi->phys;
|
||||
adi->dev.id.bustype = BUS_GAMEPORT;
|
||||
adi->dev.id.vendor = GAMEPORT_ID_VENDOR_LOGITECH;
|
||||
adi->dev.id.product = adi->id;
|
||||
adi->dev.id.version = 0x0100;
|
||||
|
||||
adi->dev.private = port;
|
||||
adi->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
|
||||
for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++)
|
||||
set_bit(adi->abs[i], adi->dev.absbit);
|
||||
|
||||
for (i = 0; i < adi->buttons; i++)
|
||||
set_bit(adi->key[i], adi->dev.keybit);
|
||||
}
|
||||
|
||||
static void adi_init_center(struct adi *adi)
|
||||
{
|
||||
int i, t, x;
|
||||
|
||||
if (!adi->length) return;
|
||||
|
||||
for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++) {
|
||||
|
||||
t = adi->abs[i];
|
||||
x = adi->dev.abs[t];
|
||||
|
||||
if (t == ABS_THROTTLE || t == ABS_RUDDER || adi->id == ADI_ID_WGPE) {
|
||||
if (i < adi->axes10) x = 512; else x = 128;
|
||||
}
|
||||
|
||||
if (i < adi->axes10) {
|
||||
adi->dev.absmax[t] = x * 2 - 64;
|
||||
adi->dev.absmin[t] = 64;
|
||||
adi->dev.absfuzz[t] = 2;
|
||||
adi->dev.absflat[t] = 16;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i < adi->axes10 + adi->axes8) {
|
||||
adi->dev.absmax[t] = x * 2 - 48;
|
||||
adi->dev.absmin[t] = 48;
|
||||
adi->dev.absfuzz[t] = 1;
|
||||
adi->dev.absflat[t] = 16;
|
||||
continue;
|
||||
}
|
||||
|
||||
adi->dev.absmax[t] = 1;
|
||||
adi->dev.absmin[t] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* adi_connect() probes for Logitech ADI joysticks.
|
||||
*/
|
||||
|
||||
static void adi_connect(struct gameport *gameport, struct gameport_dev *dev)
|
||||
{
|
||||
struct adi_port *port;
|
||||
int i;
|
||||
|
||||
if (!(port = kmalloc(sizeof(struct adi_port), GFP_KERNEL)))
|
||||
return;
|
||||
memset(port, 0, sizeof(struct adi_port));
|
||||
|
||||
gameport->private = port;
|
||||
|
||||
port->gameport = gameport;
|
||||
init_timer(&port->timer);
|
||||
port->timer.data = (long) port;
|
||||
port->timer.function = adi_timer;
|
||||
|
||||
if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
|
||||
kfree(port);
|
||||
return;
|
||||
}
|
||||
|
||||
adi_init_digital(gameport);
|
||||
adi_read_packet(port);
|
||||
|
||||
if (port->adi[0].ret >= ADI_MIN_LEN_LENGTH)
|
||||
adi_move_bits(port, adi_get_bits(port->adi, 10));
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
adi_id_decode(port->adi + i, port);
|
||||
adi_init_input(port->adi + i, port, i);
|
||||
}
|
||||
|
||||
if (!port->adi[0].length && !port->adi[1].length) {
|
||||
gameport_close(gameport);
|
||||
kfree(port);
|
||||
return;
|
||||
}
|
||||
|
||||
msleep(ADI_INIT_DELAY);
|
||||
if (adi_read(port)) {
|
||||
msleep(ADI_DATA_DELAY);
|
||||
adi_read(port);
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
if (port->adi[i].length > 0) {
|
||||
adi_init_center(port->adi + i);
|
||||
input_register_device(&port->adi[i].dev);
|
||||
printk(KERN_INFO "input: %s [%s] on %s\n",
|
||||
port->adi[i].name, port->adi[i].cname, gameport->phys);
|
||||
}
|
||||
}
|
||||
|
||||
static void adi_disconnect(struct gameport *gameport)
|
||||
{
|
||||
int i;
|
||||
|
||||
struct adi_port *port = gameport->private;
|
||||
for (i = 0; i < 2; i++)
|
||||
if (port->adi[i].length > 0)
|
||||
input_unregister_device(&port->adi[i].dev);
|
||||
gameport_close(gameport);
|
||||
kfree(port);
|
||||
}
|
||||
|
||||
/*
|
||||
* The gameport device structure.
|
||||
*/
|
||||
|
||||
static struct gameport_dev adi_dev = {
|
||||
.connect = adi_connect,
|
||||
.disconnect = adi_disconnect,
|
||||
};
|
||||
|
||||
int __init adi_init(void)
|
||||
{
|
||||
gameport_register_device(&adi_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit adi_exit(void)
|
||||
{
|
||||
gameport_unregister_device(&adi_dev);
|
||||
}
|
||||
|
||||
module_init(adi_init);
|
||||
module_exit(adi_exit);
|
||||
161
extra/linux-2.6.10/drivers/input/joystick/amijoy.c
Normal file
161
extra/linux-2.6.10/drivers/input/joystick/amijoy.c
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* $Id: amijoy.c,v 1.13 2002/01/22 20:26:32 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1998-2001 Vojtech Pavlik
|
||||
*/
|
||||
|
||||
/*
|
||||
* Driver for Amiga joysticks for Linux/m68k
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/amigahw.h>
|
||||
#include <asm/amigaints.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Driver for Amiga joysticks");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int amijoy[2] = { 0, 1 };
|
||||
module_param_array_named(map, amijoy, uint, NULL, 0);
|
||||
MODULE_PARM_DESC(map, "Map of attached joysticks in form of <a>,<b> (default is 0,1)");
|
||||
|
||||
__obsolete_setup("amijoy=");
|
||||
|
||||
static int amijoy_used[2] = { 0, 0 };
|
||||
static struct input_dev amijoy_dev[2];
|
||||
static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" };
|
||||
|
||||
static char *amijoy_name = "Amiga joystick";
|
||||
|
||||
static irqreturn_t amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp)
|
||||
{
|
||||
int i, data = 0, button = 0;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
if (amijoy[i]) {
|
||||
|
||||
switch (i) {
|
||||
case 0: data = ~custom.joy0dat; button = (~ciaa.pra >> 6) & 1; break;
|
||||
case 1: data = ~custom.joy1dat; button = (~ciaa.pra >> 7) & 1; break;
|
||||
}
|
||||
|
||||
input_regs(amijoy_dev + i, fp);
|
||||
|
||||
input_report_key(amijoy_dev + i, BTN_TRIGGER, button);
|
||||
|
||||
input_report_abs(amijoy_dev + i, ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1));
|
||||
data = ~(data ^ (data << 1));
|
||||
input_report_abs(amijoy_dev + i, ABS_Y, ((data >> 1) & 1) - ((data >> 9) & 1));
|
||||
|
||||
input_sync(amijoy_dev + i);
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int amijoy_open(struct input_dev *dev)
|
||||
{
|
||||
int *used = dev->private;
|
||||
|
||||
if ((*used)++)
|
||||
return 0;
|
||||
|
||||
if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
|
||||
(*used)--;
|
||||
printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amijoy_close(struct input_dev *dev)
|
||||
{
|
||||
int *used = dev->private;
|
||||
|
||||
if (!--(*used))
|
||||
free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt);
|
||||
}
|
||||
|
||||
static int __init amijoy_init(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
if (amijoy[i]) {
|
||||
if (!request_mem_region(CUSTOM_PHYSADDR+10+i*2, 2,
|
||||
"amijoy [Denise]")) {
|
||||
if (i == 1 && amijoy[0]) {
|
||||
input_unregister_device(amijoy_dev);
|
||||
release_mem_region(CUSTOM_PHYSADDR+10, 2);
|
||||
}
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
amijoy_dev[i].open = amijoy_open;
|
||||
amijoy_dev[i].close = amijoy_close;
|
||||
amijoy_dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
amijoy_dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
|
||||
amijoy_dev[i].keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
|
||||
for (j = 0; j < 2; j++) {
|
||||
amijoy_dev[i].absmin[ABS_X + j] = -1;
|
||||
amijoy_dev[i].absmax[ABS_X + j] = 1;
|
||||
}
|
||||
|
||||
amijoy_dev[i].name = amijoy_name;
|
||||
amijoy_dev[i].phys = amijoy_phys[i];
|
||||
amijoy_dev[i].id.bustype = BUS_AMIGA;
|
||||
amijoy_dev[i].id.vendor = 0x0001;
|
||||
amijoy_dev[i].id.product = 0x0003;
|
||||
amijoy_dev[i].id.version = 0x0100;
|
||||
|
||||
amijoy_dev[i].private = amijoy_used + i;
|
||||
|
||||
input_register_device(amijoy_dev + i);
|
||||
printk(KERN_INFO "input: %s at joy%ddat\n", amijoy_name, i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit amijoy_exit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
if (amijoy[i]) {
|
||||
input_unregister_device(amijoy_dev + i);
|
||||
release_mem_region(CUSTOM_PHYSADDR+10+i*2, 2);
|
||||
}
|
||||
}
|
||||
|
||||
module_init(amijoy_init);
|
||||
module_exit(amijoy_exit);
|
||||
762
extra/linux-2.6.10/drivers/input/joystick/analog.c
Normal file
762
extra/linux-2.6.10/drivers/input/joystick/analog.c
Normal file
@@ -0,0 +1,762 @@
|
||||
/*
|
||||
* $Id: analog.c,v 1.68 2002/01/22 20:18:32 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1996-2001 Vojtech Pavlik
|
||||
*/
|
||||
|
||||
/*
|
||||
* Analog joystick and gamepad driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/gameport.h>
|
||||
#include <asm/timex.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Analog joystick and gamepad driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
* Option parsing.
|
||||
*/
|
||||
|
||||
#define ANALOG_PORTS 16
|
||||
|
||||
static char *js[ANALOG_PORTS];
|
||||
static int js_nargs;
|
||||
static int analog_options[ANALOG_PORTS];
|
||||
module_param_array_named(map, js, charp, &js_nargs, 0);
|
||||
MODULE_PARM_DESC(map, "Describes analog joysticks type/capabilities");
|
||||
|
||||
__obsolete_setup("js=");
|
||||
|
||||
/*
|
||||
* Times, feature definitions.
|
||||
*/
|
||||
|
||||
#define ANALOG_RUDDER 0x00004
|
||||
#define ANALOG_THROTTLE 0x00008
|
||||
#define ANALOG_AXES_STD 0x0000f
|
||||
#define ANALOG_BTNS_STD 0x000f0
|
||||
|
||||
#define ANALOG_BTNS_CHF 0x00100
|
||||
#define ANALOG_HAT1_CHF 0x00200
|
||||
#define ANALOG_HAT2_CHF 0x00400
|
||||
#define ANALOG_HAT_FCS 0x00800
|
||||
#define ANALOG_HATS_ALL 0x00e00
|
||||
#define ANALOG_BTN_TL 0x01000
|
||||
#define ANALOG_BTN_TR 0x02000
|
||||
#define ANALOG_BTN_TL2 0x04000
|
||||
#define ANALOG_BTN_TR2 0x08000
|
||||
#define ANALOG_BTNS_TLR 0x03000
|
||||
#define ANALOG_BTNS_TLR2 0x0c000
|
||||
#define ANALOG_BTNS_GAMEPAD 0x0f000
|
||||
|
||||
#define ANALOG_HBTN_CHF 0x10000
|
||||
#define ANALOG_ANY_CHF 0x10700
|
||||
#define ANALOG_SAITEK 0x20000
|
||||
#define ANALOG_EXTENSIONS 0x7ff00
|
||||
#define ANALOG_GAMEPAD 0x80000
|
||||
|
||||
#define ANALOG_MAX_TIME 3 /* 3 ms */
|
||||
#define ANALOG_LOOP_TIME 2000 /* 2 * loop */
|
||||
#define ANALOG_REFRESH_TIME HZ/100 /* 10 ms */
|
||||
#define ANALOG_SAITEK_DELAY 200 /* 200 us */
|
||||
#define ANALOG_SAITEK_TIME 2000 /* 2000 us */
|
||||
#define ANALOG_AXIS_TIME 2 /* 2 * refresh */
|
||||
#define ANALOG_INIT_RETRIES 8 /* 8 times */
|
||||
#define ANALOG_FUZZ_BITS 2 /* 2 bit more */
|
||||
#define ANALOG_FUZZ_MAGIC 36 /* 36 u*ms/loop */
|
||||
|
||||
#define ANALOG_MAX_NAME_LENGTH 128
|
||||
#define ANALOG_MAX_PHYS_LENGTH 32
|
||||
|
||||
static short analog_axes[] = { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE };
|
||||
static short analog_hats[] = { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
|
||||
static short analog_pads[] = { BTN_Y, BTN_Z, BTN_TL, BTN_TR };
|
||||
static short analog_exts[] = { ANALOG_HAT1_CHF, ANALOG_HAT2_CHF, ANALOG_HAT_FCS };
|
||||
static short analog_pad_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_TL2, BTN_TR2, BTN_SELECT, BTN_START, BTN_MODE, BTN_BASE };
|
||||
static short analog_joy_btn[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2,
|
||||
BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_BASE6 };
|
||||
|
||||
static unsigned char analog_chf[] = { 0xf, 0x0, 0x1, 0x9, 0x2, 0x4, 0xc, 0x8, 0x3, 0x5, 0xb, 0x7, 0xd, 0xe, 0xa, 0x6 };
|
||||
|
||||
struct analog {
|
||||
struct input_dev dev;
|
||||
int mask;
|
||||
short *buttons;
|
||||
char name[ANALOG_MAX_NAME_LENGTH];
|
||||
char phys[ANALOG_MAX_PHYS_LENGTH];
|
||||
};
|
||||
|
||||
struct analog_port {
|
||||
struct gameport *gameport;
|
||||
struct timer_list timer;
|
||||
struct analog analog[2];
|
||||
unsigned char mask;
|
||||
char saitek;
|
||||
char cooked;
|
||||
int bads;
|
||||
int reads;
|
||||
int speed;
|
||||
int loop;
|
||||
int fuzz;
|
||||
int axes[4];
|
||||
int buttons;
|
||||
int initial[4];
|
||||
int used;
|
||||
int axtime;
|
||||
};
|
||||
|
||||
/*
|
||||
* Time macros.
|
||||
*/
|
||||
|
||||
#ifdef __i386__
|
||||
#define GET_TIME(x) do { if (cpu_has_tsc) rdtscl(x); else x = get_time_pit(); } while (0)
|
||||
#define DELTA(x,y) (cpu_has_tsc ? ((y) - (x)) : ((x) - (y) + ((x) < (y) ? CLOCK_TICK_RATE / HZ : 0)))
|
||||
#define TIME_NAME (cpu_has_tsc?"TSC":"PIT")
|
||||
static unsigned int get_time_pit(void)
|
||||
{
|
||||
extern spinlock_t i8253_lock;
|
||||
unsigned long flags;
|
||||
unsigned int count;
|
||||
|
||||
spin_lock_irqsave(&i8253_lock, flags);
|
||||
outb_p(0x00, 0x43);
|
||||
count = inb_p(0x40);
|
||||
count |= inb_p(0x40) << 8;
|
||||
spin_unlock_irqrestore(&i8253_lock, flags);
|
||||
|
||||
return count;
|
||||
}
|
||||
#elif defined(__x86_64__)
|
||||
#define GET_TIME(x) rdtscl(x)
|
||||
#define DELTA(x,y) ((y)-(x))
|
||||
#define TIME_NAME "TSC"
|
||||
#elif defined(__alpha__)
|
||||
#define GET_TIME(x) do { x = get_cycles(); } while (0)
|
||||
#define DELTA(x,y) ((y)-(x))
|
||||
#define TIME_NAME "PCC"
|
||||
#else
|
||||
#define FAKE_TIME
|
||||
static unsigned long analog_faketime = 0;
|
||||
#define GET_TIME(x) do { x = analog_faketime++; } while(0)
|
||||
#define DELTA(x,y) ((y)-(x))
|
||||
#define TIME_NAME "Unreliable"
|
||||
#warning Precise timer not defined for this architecture.
|
||||
#endif
|
||||
|
||||
/*
|
||||
* analog_decode() decodes analog joystick data and reports input events.
|
||||
*/
|
||||
|
||||
static void analog_decode(struct analog *analog, int *axes, int *initial, int buttons)
|
||||
{
|
||||
struct input_dev *dev = &analog->dev;
|
||||
int i, j;
|
||||
|
||||
if (analog->mask & ANALOG_HAT_FCS)
|
||||
for (i = 0; i < 4; i++)
|
||||
if (axes[3] < ((initial[3] * ((i << 1) + 1)) >> 3)) {
|
||||
buttons |= 1 << (i + 14);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = j = 0; i < 6; i++)
|
||||
if (analog->mask & (0x10 << i))
|
||||
input_report_key(dev, analog->buttons[j++], (buttons >> i) & 1);
|
||||
|
||||
if (analog->mask & ANALOG_HBTN_CHF)
|
||||
for (i = 0; i < 4; i++)
|
||||
input_report_key(dev, analog->buttons[j++], (buttons >> (i + 10)) & 1);
|
||||
|
||||
if (analog->mask & ANALOG_BTN_TL)
|
||||
input_report_key(dev, analog_pads[0], axes[2] < (initial[2] >> 1));
|
||||
if (analog->mask & ANALOG_BTN_TR)
|
||||
input_report_key(dev, analog_pads[1], axes[3] < (initial[3] >> 1));
|
||||
if (analog->mask & ANALOG_BTN_TL2)
|
||||
input_report_key(dev, analog_pads[2], axes[2] > (initial[2] + (initial[2] >> 1)));
|
||||
if (analog->mask & ANALOG_BTN_TR2)
|
||||
input_report_key(dev, analog_pads[3], axes[3] > (initial[3] + (initial[3] >> 1)));
|
||||
|
||||
for (i = j = 0; i < 4; i++)
|
||||
if (analog->mask & (1 << i))
|
||||
input_report_abs(dev, analog_axes[j++], axes[i]);
|
||||
|
||||
for (i = j = 0; i < 3; i++)
|
||||
if (analog->mask & analog_exts[i]) {
|
||||
input_report_abs(dev, analog_hats[j++],
|
||||
((buttons >> ((i << 2) + 7)) & 1) - ((buttons >> ((i << 2) + 9)) & 1));
|
||||
input_report_abs(dev, analog_hats[j++],
|
||||
((buttons >> ((i << 2) + 8)) & 1) - ((buttons >> ((i << 2) + 6)) & 1));
|
||||
}
|
||||
|
||||
input_sync(dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* analog_cooked_read() reads analog joystick data.
|
||||
*/
|
||||
|
||||
static int analog_cooked_read(struct analog_port *port)
|
||||
{
|
||||
struct gameport *gameport = port->gameport;
|
||||
unsigned int time[4], start, loop, now, loopout, timeout;
|
||||
unsigned char data[4], this, last;
|
||||
unsigned long flags;
|
||||
int i, j;
|
||||
|
||||
loopout = (ANALOG_LOOP_TIME * port->loop) / 1000;
|
||||
timeout = ANALOG_MAX_TIME * port->speed;
|
||||
|
||||
local_irq_save(flags);
|
||||
gameport_trigger(gameport);
|
||||
GET_TIME(now);
|
||||
local_irq_restore(flags);
|
||||
|
||||
start = now;
|
||||
this = port->mask;
|
||||
i = 0;
|
||||
|
||||
do {
|
||||
loop = now;
|
||||
last = this;
|
||||
|
||||
local_irq_disable();
|
||||
this = gameport_read(gameport) & port->mask;
|
||||
GET_TIME(now);
|
||||
local_irq_restore(flags);
|
||||
|
||||
if ((last ^ this) && (DELTA(loop, now) < loopout)) {
|
||||
data[i] = last ^ this;
|
||||
time[i] = now;
|
||||
i++;
|
||||
}
|
||||
|
||||
} while (this && (i < 4) && (DELTA(start, now) < timeout));
|
||||
|
||||
this <<= 4;
|
||||
|
||||
for (--i; i >= 0; i--) {
|
||||
this |= data[i];
|
||||
for (j = 0; j < 4; j++)
|
||||
if (data[i] & (1 << j))
|
||||
port->axes[j] = (DELTA(start, time[i]) << ANALOG_FUZZ_BITS) / port->loop;
|
||||
}
|
||||
|
||||
return -(this != port->mask);
|
||||
}
|
||||
|
||||
static int analog_button_read(struct analog_port *port, char saitek, char chf)
|
||||
{
|
||||
unsigned char u;
|
||||
int t = 1, i = 0;
|
||||
int strobe = gameport_time(port->gameport, ANALOG_SAITEK_TIME);
|
||||
|
||||
u = gameport_read(port->gameport);
|
||||
|
||||
if (!chf) {
|
||||
port->buttons = (~u >> 4) & 0xf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
port->buttons = 0;
|
||||
|
||||
while ((~u & 0xf0) && (i < 16) && t) {
|
||||
port->buttons |= 1 << analog_chf[(~u >> 4) & 0xf];
|
||||
if (!saitek) return 0;
|
||||
udelay(ANALOG_SAITEK_DELAY);
|
||||
t = strobe;
|
||||
gameport_trigger(port->gameport);
|
||||
while (((u = gameport_read(port->gameport)) & port->mask) && t) t--;
|
||||
i++;
|
||||
}
|
||||
|
||||
return -(!t || (i == 16));
|
||||
}
|
||||
|
||||
/*
|
||||
* analog_timer() repeatedly polls the Analog joysticks.
|
||||
*/
|
||||
|
||||
static void analog_timer(unsigned long data)
|
||||
{
|
||||
struct analog_port *port = (void *) data;
|
||||
int i;
|
||||
|
||||
char saitek = !!(port->analog[0].mask & ANALOG_SAITEK);
|
||||
char chf = !!(port->analog[0].mask & ANALOG_ANY_CHF);
|
||||
|
||||
if (port->cooked) {
|
||||
port->bads -= gameport_cooked_read(port->gameport, port->axes, &port->buttons);
|
||||
if (chf)
|
||||
port->buttons = port->buttons ? (1 << analog_chf[port->buttons]) : 0;
|
||||
port->reads++;
|
||||
} else {
|
||||
if (!port->axtime--) {
|
||||
port->bads -= analog_cooked_read(port);
|
||||
port->bads -= analog_button_read(port, saitek, chf);
|
||||
port->reads++;
|
||||
port->axtime = ANALOG_AXIS_TIME - 1;
|
||||
} else {
|
||||
if (!saitek)
|
||||
analog_button_read(port, saitek, chf);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
if (port->analog[i].mask)
|
||||
analog_decode(port->analog + i, port->axes, port->initial, port->buttons);
|
||||
|
||||
mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME);
|
||||
}
|
||||
|
||||
/*
|
||||
* analog_open() is a callback from the input open routine.
|
||||
*/
|
||||
|
||||
static int analog_open(struct input_dev *dev)
|
||||
{
|
||||
struct analog_port *port = dev->private;
|
||||
if (!port->used++)
|
||||
mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* analog_close() is a callback from the input close routine.
|
||||
*/
|
||||
|
||||
static void analog_close(struct input_dev *dev)
|
||||
{
|
||||
struct analog_port *port = dev->private;
|
||||
if (!--port->used)
|
||||
del_timer(&port->timer);
|
||||
}
|
||||
|
||||
/*
|
||||
* analog_calibrate_timer() calibrates the timer and computes loop
|
||||
* and timeout values for a joystick port.
|
||||
*/
|
||||
|
||||
static void analog_calibrate_timer(struct analog_port *port)
|
||||
{
|
||||
struct gameport *gameport = port->gameport;
|
||||
unsigned int i, t, tx, t1, t2, t3;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
GET_TIME(t1);
|
||||
#ifdef FAKE_TIME
|
||||
analog_faketime += 830;
|
||||
#endif
|
||||
udelay(1000);
|
||||
GET_TIME(t2);
|
||||
GET_TIME(t3);
|
||||
local_irq_restore(flags);
|
||||
|
||||
port->speed = DELTA(t1, t2) - DELTA(t2, t3);
|
||||
|
||||
tx = ~0;
|
||||
|
||||
for (i = 0; i < 50; i++) {
|
||||
local_irq_save(flags);
|
||||
GET_TIME(t1);
|
||||
for (t = 0; t < 50; t++) { gameport_read(gameport); GET_TIME(t2); }
|
||||
GET_TIME(t3);
|
||||
local_irq_restore(flags);
|
||||
udelay(i);
|
||||
t = DELTA(t1, t2) - DELTA(t2, t3);
|
||||
if (t < tx) tx = t;
|
||||
}
|
||||
|
||||
port->loop = tx / 50;
|
||||
}
|
||||
|
||||
/*
|
||||
* analog_name() constructs a name for an analog joystick.
|
||||
*/
|
||||
|
||||
static void analog_name(struct analog *analog)
|
||||
{
|
||||
sprintf(analog->name, "Analog %d-axis %d-button",
|
||||
hweight8(analog->mask & ANALOG_AXES_STD),
|
||||
hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALOG_BTNS_CHF) * 2 +
|
||||
hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & ANALOG_HBTN_CHF) * 4);
|
||||
|
||||
if (analog->mask & ANALOG_HATS_ALL)
|
||||
sprintf(analog->name, "%s %d-hat",
|
||||
analog->name, hweight16(analog->mask & ANALOG_HATS_ALL));
|
||||
|
||||
if (analog->mask & ANALOG_HAT_FCS)
|
||||
strcat(analog->name, " FCS");
|
||||
if (analog->mask & ANALOG_ANY_CHF)
|
||||
strcat(analog->name, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF");
|
||||
|
||||
strcat(analog->name, (analog->mask & ANALOG_GAMEPAD) ? " gamepad": " joystick");
|
||||
}
|
||||
|
||||
/*
|
||||
* analog_init_device()
|
||||
*/
|
||||
|
||||
static void analog_init_device(struct analog_port *port, struct analog *analog, int index)
|
||||
{
|
||||
int i, j, t, v, w, x, y, z;
|
||||
|
||||
analog_name(analog);
|
||||
sprintf(analog->phys, "%s/input%d", port->gameport->phys, index);
|
||||
analog->buttons = (analog->mask & ANALOG_GAMEPAD) ? analog_pad_btn : analog_joy_btn;
|
||||
|
||||
init_input_dev(&analog->dev);
|
||||
|
||||
analog->dev.name = analog->name;
|
||||
analog->dev.phys = analog->phys;
|
||||
analog->dev.id.bustype = BUS_GAMEPORT;
|
||||
analog->dev.id.vendor = GAMEPORT_ID_VENDOR_ANALOG;
|
||||
analog->dev.id.product = analog->mask >> 4;
|
||||
analog->dev.id.version = 0x0100;
|
||||
|
||||
analog->dev.open = analog_open;
|
||||
analog->dev.close = analog_close;
|
||||
analog->dev.private = port;
|
||||
analog->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
|
||||
for (i = j = 0; i < 4; i++)
|
||||
if (analog->mask & (1 << i)) {
|
||||
|
||||
t = analog_axes[j];
|
||||
x = port->axes[i];
|
||||
y = (port->axes[0] + port->axes[1]) >> 1;
|
||||
z = y - port->axes[i];
|
||||
z = z > 0 ? z : -z;
|
||||
v = (x >> 3);
|
||||
w = (x >> 3);
|
||||
|
||||
set_bit(t, analog->dev.absbit);
|
||||
|
||||
if ((i == 2 || i == 3) && (j == 2 || j == 3) && (z > (y >> 3)))
|
||||
x = y;
|
||||
|
||||
if (analog->mask & ANALOG_SAITEK) {
|
||||
if (i == 2) x = port->axes[i];
|
||||
v = x - (x >> 2);
|
||||
w = (x >> 4);
|
||||
}
|
||||
|
||||
analog->dev.absmax[t] = (x << 1) - v;
|
||||
analog->dev.absmin[t] = v;
|
||||
analog->dev.absfuzz[t] = port->fuzz;
|
||||
analog->dev.absflat[t] = w;
|
||||
|
||||
j++;
|
||||
}
|
||||
|
||||
for (i = j = 0; i < 3; i++)
|
||||
if (analog->mask & analog_exts[i])
|
||||
for (x = 0; x < 2; x++) {
|
||||
t = analog_hats[j++];
|
||||
set_bit(t, analog->dev.absbit);
|
||||
analog->dev.absmax[t] = 1;
|
||||
analog->dev.absmin[t] = -1;
|
||||
}
|
||||
|
||||
for (i = j = 0; i < 4; i++)
|
||||
if (analog->mask & (0x10 << i))
|
||||
set_bit(analog->buttons[j++], analog->dev.keybit);
|
||||
|
||||
if (analog->mask & ANALOG_BTNS_CHF)
|
||||
for (i = 0; i < 2; i++)
|
||||
set_bit(analog->buttons[j++], analog->dev.keybit);
|
||||
|
||||
if (analog->mask & ANALOG_HBTN_CHF)
|
||||
for (i = 0; i < 4; i++)
|
||||
set_bit(analog->buttons[j++], analog->dev.keybit);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
if (analog->mask & (ANALOG_BTN_TL << i))
|
||||
set_bit(analog_pads[i], analog->dev.keybit);
|
||||
|
||||
analog_decode(analog, port->axes, port->initial, port->buttons);
|
||||
|
||||
input_register_device(&analog->dev);
|
||||
|
||||
printk(KERN_INFO "input: %s at %s", analog->name, port->gameport->phys);
|
||||
|
||||
if (port->cooked)
|
||||
printk(" [ADC port]\n");
|
||||
else
|
||||
printk(" [%s timer, %d %sHz clock, %d ns res]\n", TIME_NAME,
|
||||
port->speed > 10000 ? (port->speed + 800) / 1000 : port->speed,
|
||||
port->speed > 10000 ? "M" : "k",
|
||||
port->speed > 10000 ? (port->loop * 1000) / (port->speed / 1000)
|
||||
: (port->loop * 1000000) / port->speed);
|
||||
}
|
||||
|
||||
/*
|
||||
* analog_init_devices() sets up device-specific values and registers the input devices.
|
||||
*/
|
||||
|
||||
static int analog_init_masks(struct analog_port *port)
|
||||
{
|
||||
int i;
|
||||
struct analog *analog = port->analog;
|
||||
int max[4];
|
||||
|
||||
if (!port->mask)
|
||||
return -1;
|
||||
|
||||
if ((port->mask & 3) != 3 && port->mask != 0xc) {
|
||||
printk(KERN_WARNING "analog.c: Unknown joystick device found "
|
||||
"(data=%#x, %s), probably not analog joystick.\n",
|
||||
port->mask, port->gameport->phys);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
i = analog_options[0]; /* FIXME !!! - need to specify options for different ports */
|
||||
|
||||
analog[0].mask = i & 0xfffff;
|
||||
|
||||
analog[0].mask &= ~(ANALOG_AXES_STD | ANALOG_HAT_FCS | ANALOG_BTNS_GAMEPAD)
|
||||
| port->mask | ((port->mask << 8) & ANALOG_HAT_FCS)
|
||||
| ((port->mask << 10) & ANALOG_BTNS_TLR) | ((port->mask << 12) & ANALOG_BTNS_TLR2);
|
||||
|
||||
analog[0].mask &= ~(ANALOG_HAT2_CHF)
|
||||
| ((analog[0].mask & ANALOG_HBTN_CHF) ? 0 : ANALOG_HAT2_CHF);
|
||||
|
||||
analog[0].mask &= ~(ANALOG_THROTTLE | ANALOG_BTN_TR | ANALOG_BTN_TR2)
|
||||
| ((~analog[0].mask & ANALOG_HAT_FCS) >> 8)
|
||||
| ((~analog[0].mask & ANALOG_HAT_FCS) << 2)
|
||||
| ((~analog[0].mask & ANALOG_HAT_FCS) << 4);
|
||||
|
||||
analog[0].mask &= ~(ANALOG_THROTTLE | ANALOG_RUDDER)
|
||||
| (((~analog[0].mask & ANALOG_BTNS_TLR ) >> 10)
|
||||
& ((~analog[0].mask & ANALOG_BTNS_TLR2) >> 12));
|
||||
|
||||
analog[1].mask = ((i >> 20) & 0xff) | ((i >> 12) & 0xf0000);
|
||||
|
||||
analog[1].mask &= (analog[0].mask & ANALOG_EXTENSIONS) ? ANALOG_GAMEPAD
|
||||
: (((ANALOG_BTNS_STD | port->mask) & ~analog[0].mask) | ANALOG_GAMEPAD);
|
||||
|
||||
if (port->cooked) {
|
||||
|
||||
for (i = 0; i < 4; i++) max[i] = port->axes[i] << 1;
|
||||
|
||||
if ((analog[0].mask & 0x7) == 0x7) max[2] = (max[0] + max[1]) >> 1;
|
||||
if ((analog[0].mask & 0xb) == 0xb) max[3] = (max[0] + max[1]) >> 1;
|
||||
if ((analog[0].mask & ANALOG_BTN_TL) && !(analog[0].mask & ANALOG_BTN_TL2)) max[2] >>= 1;
|
||||
if ((analog[0].mask & ANALOG_BTN_TR) && !(analog[0].mask & ANALOG_BTN_TR2)) max[3] >>= 1;
|
||||
if ((analog[0].mask & ANALOG_HAT_FCS)) max[3] >>= 1;
|
||||
|
||||
gameport_calibrate(port->gameport, port->axes, max);
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
port->initial[i] = port->axes[i];
|
||||
|
||||
return -!(analog[0].mask || analog[1].mask);
|
||||
}
|
||||
|
||||
static int analog_init_port(struct gameport *gameport, struct gameport_dev *dev, struct analog_port *port)
|
||||
{
|
||||
int i, t, u, v;
|
||||
|
||||
gameport->private = port;
|
||||
port->gameport = gameport;
|
||||
init_timer(&port->timer);
|
||||
port->timer.data = (long) port;
|
||||
port->timer.function = analog_timer;
|
||||
|
||||
if (!gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
|
||||
|
||||
analog_calibrate_timer(port);
|
||||
|
||||
gameport_trigger(gameport);
|
||||
t = gameport_read(gameport);
|
||||
msleep(ANALOG_MAX_TIME);
|
||||
port->mask = (gameport_read(gameport) ^ t) & t & 0xf;
|
||||
port->fuzz = (port->speed * ANALOG_FUZZ_MAGIC) / port->loop / 1000 + ANALOG_FUZZ_BITS;
|
||||
|
||||
for (i = 0; i < ANALOG_INIT_RETRIES; i++) {
|
||||
if (!analog_cooked_read(port)) break;
|
||||
msleep(ANALOG_MAX_TIME);
|
||||
}
|
||||
|
||||
u = v = 0;
|
||||
|
||||
msleep(ANALOG_MAX_TIME);
|
||||
t = gameport_time(gameport, ANALOG_MAX_TIME * 1000);
|
||||
gameport_trigger(gameport);
|
||||
while ((gameport_read(port->gameport) & port->mask) && (u < t)) u++;
|
||||
udelay(ANALOG_SAITEK_DELAY);
|
||||
t = gameport_time(gameport, ANALOG_SAITEK_TIME);
|
||||
gameport_trigger(gameport);
|
||||
while ((gameport_read(port->gameport) & port->mask) && (v < t)) v++;
|
||||
|
||||
if (v < (u >> 1)) { /* FIXME - more than one port */
|
||||
analog_options[0] |= /* FIXME - more than one port */
|
||||
ANALOG_SAITEK | ANALOG_BTNS_CHF | ANALOG_HBTN_CHF | ANALOG_HAT1_CHF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
gameport_close(gameport);
|
||||
}
|
||||
|
||||
if (!gameport_open(gameport, dev, GAMEPORT_MODE_COOKED)) {
|
||||
|
||||
for (i = 0; i < ANALOG_INIT_RETRIES; i++)
|
||||
if (!gameport_cooked_read(gameport, port->axes, &port->buttons))
|
||||
break;
|
||||
for (i = 0; i < 4; i++)
|
||||
if (port->axes[i] != -1) port->mask |= 1 << i;
|
||||
|
||||
port->fuzz = gameport->fuzz;
|
||||
port->cooked = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void analog_connect(struct gameport *gameport, struct gameport_dev *dev)
|
||||
{
|
||||
struct analog_port *port;
|
||||
int i;
|
||||
|
||||
if (!(port = kmalloc(sizeof(struct analog_port), GFP_KERNEL)))
|
||||
return;
|
||||
memset(port, 0, sizeof(struct analog_port));
|
||||
|
||||
if (analog_init_port(gameport, dev, port)) {
|
||||
kfree(port);
|
||||
return;
|
||||
}
|
||||
|
||||
if (analog_init_masks(port)) {
|
||||
gameport_close(gameport);
|
||||
kfree(port);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
if (port->analog[i].mask)
|
||||
analog_init_device(port, port->analog + i, i);
|
||||
}
|
||||
|
||||
static void analog_disconnect(struct gameport *gameport)
|
||||
{
|
||||
int i;
|
||||
|
||||
struct analog_port *port = gameport->private;
|
||||
for (i = 0; i < 2; i++)
|
||||
if (port->analog[i].mask)
|
||||
input_unregister_device(&port->analog[i].dev);
|
||||
gameport_close(gameport);
|
||||
printk(KERN_INFO "analog.c: %d out of %d reads (%d%%) on %s failed\n",
|
||||
port->bads, port->reads, port->reads ? (port->bads * 100 / port->reads) : 0,
|
||||
port->gameport->phys);
|
||||
kfree(port);
|
||||
}
|
||||
|
||||
struct analog_types {
|
||||
char *name;
|
||||
int value;
|
||||
};
|
||||
|
||||
struct analog_types analog_types[] = {
|
||||
{ "none", 0x00000000 },
|
||||
{ "auto", 0x000000ff },
|
||||
{ "2btn", 0x0000003f },
|
||||
{ "y-joy", 0x0cc00033 },
|
||||
{ "y-pad", 0x8cc80033 },
|
||||
{ "fcs", 0x000008f7 },
|
||||
{ "chf", 0x000002ff },
|
||||
{ "fullchf", 0x000007ff },
|
||||
{ "gamepad", 0x000830f3 },
|
||||
{ "gamepad8", 0x0008f0f3 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static void analog_parse_options(void)
|
||||
{
|
||||
int i, j;
|
||||
char *end;
|
||||
|
||||
for (i = 0; i < js_nargs; i++) {
|
||||
|
||||
for (j = 0; analog_types[j].name; j++)
|
||||
if (!strcmp(analog_types[j].name, js[i])) {
|
||||
analog_options[i] = analog_types[j].value;
|
||||
break;
|
||||
}
|
||||
if (analog_types[j].name) continue;
|
||||
|
||||
analog_options[i] = simple_strtoul(js[i], &end, 0);
|
||||
if (end != js[i]) continue;
|
||||
|
||||
analog_options[i] = 0xff;
|
||||
if (!strlen(js[i])) continue;
|
||||
|
||||
printk(KERN_WARNING "analog.c: Bad config for port %d - \"%s\"\n", i, js[i]);
|
||||
}
|
||||
|
||||
for (; i < ANALOG_PORTS; i++)
|
||||
analog_options[i] = 0xff;
|
||||
}
|
||||
|
||||
/*
|
||||
* The gameport device structure.
|
||||
*/
|
||||
|
||||
static struct gameport_dev analog_dev = {
|
||||
.connect = analog_connect,
|
||||
.disconnect = analog_disconnect,
|
||||
};
|
||||
|
||||
int __init analog_init(void)
|
||||
{
|
||||
analog_parse_options();
|
||||
gameport_register_device(&analog_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit analog_exit(void)
|
||||
{
|
||||
gameport_unregister_device(&analog_dev);
|
||||
}
|
||||
|
||||
module_init(analog_init);
|
||||
module_exit(analog_exit);
|
||||
256
extra/linux-2.6.10/drivers/input/joystick/cobra.c
Normal file
256
extra/linux-2.6.10/drivers/input/joystick/cobra.c
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* $Id: cobra.c,v 1.19 2002/01/22 20:26:52 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1999-2001 Vojtech Pavlik
|
||||
*/
|
||||
|
||||
/*
|
||||
* Creative Labs Blaster GamePad Cobra driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/gameport.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Creative Labs Blaster GamePad Cobra driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define COBRA_MAX_STROBE 45 /* 45 us max wait for first strobe */
|
||||
#define COBRA_REFRESH_TIME HZ/50 /* 20 ms between reads */
|
||||
#define COBRA_LENGTH 36
|
||||
|
||||
static char* cobra_name = "Creative Labs Blaster GamePad Cobra";
|
||||
|
||||
static int cobra_btn[] = { BTN_START, BTN_SELECT, BTN_TL, BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL2, BTN_TR2, 0 };
|
||||
|
||||
struct cobra {
|
||||
struct gameport *gameport;
|
||||
struct timer_list timer;
|
||||
struct input_dev dev[2];
|
||||
int used;
|
||||
int reads;
|
||||
int bads;
|
||||
unsigned char exists;
|
||||
char phys[2][32];
|
||||
};
|
||||
|
||||
static unsigned char cobra_read_packet(struct gameport *gameport, unsigned int *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned char u, v, w;
|
||||
__u64 buf[2];
|
||||
int r[2], t[2];
|
||||
int i, j, ret;
|
||||
|
||||
int strobe = gameport_time(gameport, COBRA_MAX_STROBE);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
r[i] = buf[i] = 0;
|
||||
t[i] = COBRA_MAX_STROBE;
|
||||
}
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
u = gameport_read(gameport);
|
||||
|
||||
do {
|
||||
t[0]--; t[1]--;
|
||||
v = gameport_read(gameport);
|
||||
for (i = 0, w = u ^ v; i < 2 && w; i++, w >>= 2)
|
||||
if (w & 0x30) {
|
||||
if ((w & 0x30) < 0x30 && r[i] < COBRA_LENGTH && t[i] > 0) {
|
||||
buf[i] |= (__u64)((w >> 5) & 1) << r[i]++;
|
||||
t[i] = strobe;
|
||||
u = v;
|
||||
} else t[i] = 0;
|
||||
}
|
||||
} while (t[0] > 0 || t[1] > 0);
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
ret = 0;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
|
||||
if (r[i] != COBRA_LENGTH) continue;
|
||||
|
||||
for (j = 0; j < COBRA_LENGTH && (buf[i] & 0x04104107f) ^ 0x041041040; j++)
|
||||
buf[i] = (buf[i] >> 1) | ((__u64)(buf[i] & 1) << (COBRA_LENGTH - 1));
|
||||
|
||||
if (j < COBRA_LENGTH) ret |= (1 << i);
|
||||
|
||||
data[i] = ((buf[i] >> 7) & 0x000001f) | ((buf[i] >> 8) & 0x00003e0)
|
||||
| ((buf[i] >> 9) & 0x0007c00) | ((buf[i] >> 10) & 0x00f8000)
|
||||
| ((buf[i] >> 11) & 0x1f00000);
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cobra_timer(unsigned long private)
|
||||
{
|
||||
struct cobra *cobra = (void *) private;
|
||||
struct input_dev *dev;
|
||||
unsigned int data[2];
|
||||
int i, j, r;
|
||||
|
||||
cobra->reads++;
|
||||
|
||||
if ((r = cobra_read_packet(cobra->gameport, data)) != cobra->exists)
|
||||
cobra->bads++;
|
||||
else
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
if (cobra->exists & r & (1 << i)) {
|
||||
|
||||
dev = cobra->dev + i;
|
||||
|
||||
input_report_abs(dev, ABS_X, ((data[i] >> 4) & 1) - ((data[i] >> 3) & 1));
|
||||
input_report_abs(dev, ABS_Y, ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1));
|
||||
|
||||
for (j = 0; cobra_btn[j]; j++)
|
||||
input_report_key(dev, cobra_btn[j], data[i] & (0x20 << j));
|
||||
|
||||
input_sync(dev);
|
||||
|
||||
}
|
||||
|
||||
mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);
|
||||
}
|
||||
|
||||
static int cobra_open(struct input_dev *dev)
|
||||
{
|
||||
struct cobra *cobra = dev->private;
|
||||
if (!cobra->used++)
|
||||
mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cobra_close(struct input_dev *dev)
|
||||
{
|
||||
struct cobra *cobra = dev->private;
|
||||
if (!--cobra->used)
|
||||
del_timer(&cobra->timer);
|
||||
}
|
||||
|
||||
static void cobra_connect(struct gameport *gameport, struct gameport_dev *dev)
|
||||
{
|
||||
struct cobra *cobra;
|
||||
unsigned int data[2];
|
||||
int i, j;
|
||||
|
||||
if (!(cobra = kmalloc(sizeof(struct cobra), GFP_KERNEL)))
|
||||
return;
|
||||
memset(cobra, 0, sizeof(struct cobra));
|
||||
|
||||
gameport->private = cobra;
|
||||
|
||||
cobra->gameport = gameport;
|
||||
init_timer(&cobra->timer);
|
||||
cobra->timer.data = (long) cobra;
|
||||
cobra->timer.function = cobra_timer;
|
||||
|
||||
if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
|
||||
goto fail1;
|
||||
|
||||
cobra->exists = cobra_read_packet(gameport, data);
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
if ((cobra->exists >> i) & data[i] & 1) {
|
||||
printk(KERN_WARNING "cobra.c: Device %d on %s has the Ext bit set. ID is: %d"
|
||||
" Contact vojtech@ucw.cz\n", i, gameport->phys, (data[i] >> 2) & 7);
|
||||
cobra->exists &= ~(1 << i);
|
||||
}
|
||||
|
||||
if (!cobra->exists)
|
||||
goto fail2;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
if ((cobra->exists >> i) & 1) {
|
||||
|
||||
sprintf(cobra->phys[i], "%s/input%d", gameport->phys, i);
|
||||
|
||||
cobra->dev[i].private = cobra;
|
||||
cobra->dev[i].open = cobra_open;
|
||||
cobra->dev[i].close = cobra_close;
|
||||
|
||||
cobra->dev[i].name = cobra_name;
|
||||
cobra->dev[i].phys = cobra->phys[i];
|
||||
cobra->dev[i].id.bustype = BUS_GAMEPORT;
|
||||
cobra->dev[i].id.vendor = GAMEPORT_ID_VENDOR_CREATIVE;
|
||||
cobra->dev[i].id.product = 0x0008;
|
||||
cobra->dev[i].id.version = 0x0100;
|
||||
|
||||
cobra->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
cobra->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
|
||||
|
||||
for (j = 0; cobra_btn[j]; j++)
|
||||
set_bit(cobra_btn[j], cobra->dev[i].keybit);
|
||||
|
||||
cobra->dev[i].absmin[ABS_X] = -1; cobra->dev[i].absmax[ABS_X] = 1;
|
||||
cobra->dev[i].absmin[ABS_Y] = -1; cobra->dev[i].absmax[ABS_Y] = 1;
|
||||
|
||||
input_register_device(cobra->dev + i);
|
||||
printk(KERN_INFO "input: %s on %s\n", cobra_name, gameport->phys);
|
||||
}
|
||||
|
||||
return;
|
||||
fail2: gameport_close(gameport);
|
||||
fail1: kfree(cobra);
|
||||
}
|
||||
|
||||
static void cobra_disconnect(struct gameport *gameport)
|
||||
{
|
||||
int i;
|
||||
|
||||
struct cobra *cobra = gameport->private;
|
||||
for (i = 0; i < 2; i++)
|
||||
if ((cobra->exists >> i) & 1)
|
||||
input_unregister_device(cobra->dev + i);
|
||||
gameport_close(gameport);
|
||||
kfree(cobra);
|
||||
}
|
||||
|
||||
static struct gameport_dev cobra_dev = {
|
||||
.connect = cobra_connect,
|
||||
.disconnect = cobra_disconnect,
|
||||
};
|
||||
|
||||
int __init cobra_init(void)
|
||||
{
|
||||
gameport_register_device(&cobra_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit cobra_exit(void)
|
||||
{
|
||||
gameport_unregister_device(&cobra_dev);
|
||||
}
|
||||
|
||||
module_init(cobra_init);
|
||||
module_exit(cobra_exit);
|
||||
647
extra/linux-2.6.10/drivers/input/joystick/db9.c
Normal file
647
extra/linux-2.6.10/drivers/input/joystick/db9.c
Normal file
@@ -0,0 +1,647 @@
|
||||
/*
|
||||
* $Id: db9.c,v 1.13 2002/04/07 20:13:37 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1999-2001 Vojtech Pavlik
|
||||
*
|
||||
* Based on the work of:
|
||||
* Andree Borrmann Mats Sjövall
|
||||
*/
|
||||
|
||||
/*
|
||||
* Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/parport.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int db9[] __initdata = { -1, 0 };
|
||||
static int db9_nargs __initdata = 0;
|
||||
module_param_array_named(dev, db9, int, &db9_nargs, 0);
|
||||
MODULE_PARM_DESC(dev, "Describes first attached device (<parport#>,<type>)");
|
||||
|
||||
static int db9_2[] __initdata = { -1, 0 };
|
||||
static int db9_nargs_2 __initdata = 0;
|
||||
module_param_array_named(dev2, db9_2, int, &db9_nargs_2, 0);
|
||||
MODULE_PARM_DESC(dev2, "Describes second attached device (<parport#>,<type>)");
|
||||
|
||||
static int db9_3[] __initdata = { -1, 0 };
|
||||
static int db9_nargs_3 __initdata = 0;
|
||||
module_param_array_named(dev3, db9_3, int, &db9_nargs_3, 0);
|
||||
MODULE_PARM_DESC(dev3, "Describes third attached device (<parport#>,<type>)");
|
||||
|
||||
__obsolete_setup("db9=");
|
||||
__obsolete_setup("db9_2=");
|
||||
__obsolete_setup("db9_3=");
|
||||
|
||||
#define DB9_MULTI_STICK 0x01
|
||||
#define DB9_MULTI2_STICK 0x02
|
||||
#define DB9_GENESIS_PAD 0x03
|
||||
#define DB9_GENESIS5_PAD 0x05
|
||||
#define DB9_GENESIS6_PAD 0x06
|
||||
#define DB9_SATURN_PAD 0x07
|
||||
#define DB9_MULTI_0802 0x08
|
||||
#define DB9_MULTI_0802_2 0x09
|
||||
#define DB9_CD32_PAD 0x0A
|
||||
#define DB9_SATURN_DPP 0x0B
|
||||
#define DB9_SATURN_DPP_2 0x0C
|
||||
#define DB9_MAX_PAD 0x0D
|
||||
|
||||
#define DB9_UP 0x01
|
||||
#define DB9_DOWN 0x02
|
||||
#define DB9_LEFT 0x04
|
||||
#define DB9_RIGHT 0x08
|
||||
#define DB9_FIRE1 0x10
|
||||
#define DB9_FIRE2 0x20
|
||||
#define DB9_FIRE3 0x40
|
||||
#define DB9_FIRE4 0x80
|
||||
|
||||
#define DB9_NORMAL 0x0a
|
||||
#define DB9_NOSELECT 0x08
|
||||
|
||||
#define DB9_MAX_DEVICES 2
|
||||
|
||||
#define DB9_GENESIS6_DELAY 14
|
||||
#define DB9_REFRESH_TIME HZ/100
|
||||
|
||||
struct db9 {
|
||||
struct input_dev dev[DB9_MAX_DEVICES];
|
||||
struct timer_list timer;
|
||||
struct pardevice *pd;
|
||||
int mode;
|
||||
int used;
|
||||
char phys[2][32];
|
||||
};
|
||||
|
||||
static struct db9 *db9_base[3];
|
||||
|
||||
static short db9_multi_btn[] = { BTN_TRIGGER, BTN_THUMB };
|
||||
static short db9_genesis_btn[] = { BTN_START, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_MODE };
|
||||
static short db9_cd32_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START };
|
||||
|
||||
static char db9_buttons[DB9_MAX_PAD] = { 0, 1, 2, 4, 0, 6, 8, 9, 1, 1, 7, 9, 9 };
|
||||
static short *db9_btn[DB9_MAX_PAD] = { NULL, db9_multi_btn, db9_multi_btn, db9_genesis_btn, NULL, db9_genesis_btn,
|
||||
db9_genesis_btn, db9_cd32_btn, db9_multi_btn, db9_multi_btn, db9_cd32_btn,
|
||||
db9_cd32_btn, db9_cd32_btn };
|
||||
static char *db9_name[DB9_MAX_PAD] = { NULL, "Multisystem joystick", "Multisystem joystick (2 fire)", "Genesis pad",
|
||||
NULL, "Genesis 5 pad", "Genesis 6 pad", "Saturn pad", "Multisystem (0.8.0.2) joystick",
|
||||
"Multisystem (0.8.0.2-dual) joystick", "Amiga CD-32 pad", "Saturn dpp", "Saturn dpp dual" };
|
||||
|
||||
static const int db9_max_pads[DB9_MAX_PAD] = { 0, 1, 1, 1, 0, 1, 1, 6, 1, 2, 1, 6, 12 };
|
||||
static const int db9_num_axis[DB9_MAX_PAD] = { 0, 2, 2, 2, 0, 2, 2, 7, 2, 2, 2 ,7, 7 };
|
||||
static const short db9_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_RZ, ABS_Z, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y };
|
||||
static const int db9_bidirectional[DB9_MAX_PAD] = { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0 };
|
||||
static const int db9_reverse[DB9_MAX_PAD] = { 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0 };
|
||||
|
||||
/*
|
||||
* Saturn controllers
|
||||
*/
|
||||
#define DB9_SATURN_DELAY 300
|
||||
static const int db9_saturn_byte[] = { 1, 1, 1, 2, 2, 2, 2, 2, 1 };
|
||||
static const unsigned char db9_saturn_mask[] = { 0x04, 0x01, 0x02, 0x40, 0x20, 0x10, 0x08, 0x80, 0x08 };
|
||||
|
||||
/*
|
||||
* db9_saturn_write_sub() writes 2 bit data.
|
||||
*/
|
||||
static void db9_saturn_write_sub(struct parport *port, int type, unsigned char data, int powered, int pwr_sub)
|
||||
{
|
||||
unsigned char c;
|
||||
|
||||
switch (type) {
|
||||
case 1: /* DPP1 */
|
||||
c = 0x80 | 0x30 | (powered ? 0x08 : 0) | (pwr_sub ? 0x04 : 0) | data;
|
||||
parport_write_data(port, c);
|
||||
break;
|
||||
case 2: /* DPP2 */
|
||||
c = 0x40 | data << 4 | (powered ? 0x08 : 0) | (pwr_sub ? 0x04 : 0) | 0x03;
|
||||
parport_write_data(port, c);
|
||||
break;
|
||||
case 0: /* DB9 */
|
||||
c = ((((data & 2) ? 2 : 0) | ((data & 1) ? 4 : 0)) ^ 0x02) | !powered;
|
||||
parport_write_control(port, c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* gc_saturn_read_sub() reads 4 bit data.
|
||||
*/
|
||||
static unsigned char db9_saturn_read_sub(struct parport *port, int type)
|
||||
{
|
||||
unsigned char data;
|
||||
|
||||
if (type) {
|
||||
/* DPP */
|
||||
data = parport_read_status(port) ^ 0x80;
|
||||
return (data & 0x80 ? 1 : 0) | (data & 0x40 ? 2 : 0)
|
||||
| (data & 0x20 ? 4 : 0) | (data & 0x10 ? 8 : 0);
|
||||
} else {
|
||||
/* DB9 */
|
||||
data = parport_read_data(port) & 0x0f;
|
||||
return (data & 0x8 ? 1 : 0) | (data & 0x4 ? 2 : 0)
|
||||
| (data & 0x2 ? 4 : 0) | (data & 0x1 ? 8 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* db9_saturn_read_analog() sends clock and reads 8 bit data.
|
||||
*/
|
||||
static unsigned char db9_saturn_read_analog(struct parport *port, int type, int powered)
|
||||
{
|
||||
unsigned char data;
|
||||
|
||||
db9_saturn_write_sub(port, type, 0, powered, 0);
|
||||
udelay(DB9_SATURN_DELAY);
|
||||
data = db9_saturn_read_sub(port, type) << 4;
|
||||
db9_saturn_write_sub(port, type, 2, powered, 0);
|
||||
udelay(DB9_SATURN_DELAY);
|
||||
data |= db9_saturn_read_sub(port, type);
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
* db9_saturn_read_packet() reads whole saturn packet at connector
|
||||
* and returns device identifier code.
|
||||
*/
|
||||
static unsigned char db9_saturn_read_packet(struct parport *port, unsigned char *data, int type, int powered)
|
||||
{
|
||||
int i, j;
|
||||
unsigned char tmp;
|
||||
|
||||
db9_saturn_write_sub(port, type, 3, powered, 0);
|
||||
data[0] = db9_saturn_read_sub(port, type);
|
||||
switch (data[0] & 0x0f) {
|
||||
case 0xf:
|
||||
/* 1111 no pad */
|
||||
return data[0] = 0xff;
|
||||
case 0x4: case 0x4 | 0x8:
|
||||
/* ?100 : digital controller */
|
||||
db9_saturn_write_sub(port, type, 0, powered, 1);
|
||||
data[2] = db9_saturn_read_sub(port, type) << 4;
|
||||
db9_saturn_write_sub(port, type, 2, powered, 1);
|
||||
data[1] = db9_saturn_read_sub(port, type) << 4;
|
||||
db9_saturn_write_sub(port, type, 1, powered, 1);
|
||||
data[1] |= db9_saturn_read_sub(port, type);
|
||||
db9_saturn_write_sub(port, type, 3, powered, 1);
|
||||
/* data[2] |= db9_saturn_read_sub(port, type); */
|
||||
data[2] |= data[0];
|
||||
return data[0] = 0x02;
|
||||
case 0x1:
|
||||
/* 0001 : analog controller or multitap */
|
||||
db9_saturn_write_sub(port, type, 2, powered, 0);
|
||||
udelay(DB9_SATURN_DELAY);
|
||||
data[0] = db9_saturn_read_analog(port, type, powered);
|
||||
if (data[0] != 0x41) {
|
||||
/* read analog controller */
|
||||
for (i = 0; i < (data[0] & 0x0f); i++)
|
||||
data[i + 1] = db9_saturn_read_analog(port, type, powered);
|
||||
db9_saturn_write_sub(port, type, 3, powered, 0);
|
||||
return data[0];
|
||||
} else {
|
||||
/* read multitap */
|
||||
if (db9_saturn_read_analog(port, type, powered) != 0x60)
|
||||
return data[0] = 0xff;
|
||||
for (i = 0; i < 60; i += 10) {
|
||||
data[i] = db9_saturn_read_analog(port, type, powered);
|
||||
if (data[i] != 0xff)
|
||||
/* read each pad */
|
||||
for (j = 0; j < (data[i] & 0x0f); j++)
|
||||
data[i + j + 1] = db9_saturn_read_analog(port, type, powered);
|
||||
}
|
||||
db9_saturn_write_sub(port, type, 3, powered, 0);
|
||||
return 0x41;
|
||||
}
|
||||
case 0x0:
|
||||
/* 0000 : mouse */
|
||||
db9_saturn_write_sub(port, type, 2, powered, 0);
|
||||
udelay(DB9_SATURN_DELAY);
|
||||
tmp = db9_saturn_read_analog(port, type, powered);
|
||||
if (tmp == 0xff) {
|
||||
for (i = 0; i < 3; i++)
|
||||
data[i + 1] = db9_saturn_read_analog(port, type, powered);
|
||||
db9_saturn_write_sub(port, type, 3, powered, 0);
|
||||
return data[0] = 0xe3;
|
||||
}
|
||||
default:
|
||||
return data[0];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* db9_saturn_report() analyzes packet and reports.
|
||||
*/
|
||||
static int db9_saturn_report(unsigned char id, unsigned char data[60], struct input_dev *dev, int n, int max_pads)
|
||||
{
|
||||
int tmp, i, j;
|
||||
|
||||
tmp = (id == 0x41) ? 60 : 10;
|
||||
for (j = 0; (j < tmp) && (n < max_pads); j += 10, n++) {
|
||||
switch (data[j]) {
|
||||
case 0x16: /* multi controller (analog 4 axis) */
|
||||
input_report_abs(dev + n, db9_abs[5], data[j + 6]);
|
||||
case 0x15: /* mission stick (analog 3 axis) */
|
||||
input_report_abs(dev + n, db9_abs[3], data[j + 4]);
|
||||
input_report_abs(dev + n, db9_abs[4], data[j + 5]);
|
||||
case 0x13: /* racing controller (analog 1 axis) */
|
||||
input_report_abs(dev + n, db9_abs[2], data[j + 3]);
|
||||
case 0x34: /* saturn keyboard (udlr ZXC ASD QE Esc) */
|
||||
case 0x02: /* digital pad (digital 2 axis + buttons) */
|
||||
input_report_abs(dev + n, db9_abs[0], !(data[j + 1] & 128) - !(data[j + 1] & 64));
|
||||
input_report_abs(dev + n, db9_abs[1], !(data[j + 1] & 32) - !(data[j + 1] & 16));
|
||||
for (i = 0; i < 9; i++)
|
||||
input_report_key(dev + n, db9_cd32_btn[i], ~data[j + db9_saturn_byte[i]] & db9_saturn_mask[i]);
|
||||
break;
|
||||
case 0x19: /* mission stick x2 (analog 6 axis + buttons) */
|
||||
input_report_abs(dev + n, db9_abs[0], !(data[j + 1] & 128) - !(data[j + 1] & 64));
|
||||
input_report_abs(dev + n, db9_abs[1], !(data[j + 1] & 32) - !(data[j + 1] & 16));
|
||||
for (i = 0; i < 9; i++)
|
||||
input_report_key(dev + n, db9_cd32_btn[i], ~data[j + db9_saturn_byte[i]] & db9_saturn_mask[i]);
|
||||
input_report_abs(dev + n, db9_abs[2], data[j + 3]);
|
||||
input_report_abs(dev + n, db9_abs[3], data[j + 4]);
|
||||
input_report_abs(dev + n, db9_abs[4], data[j + 5]);
|
||||
/*
|
||||
input_report_abs(dev + n, db9_abs[8], (data[j + 6] & 128 ? 0 : 1) - (data[j + 6] & 64 ? 0 : 1));
|
||||
input_report_abs(dev + n, db9_abs[9], (data[j + 6] & 32 ? 0 : 1) - (data[j + 6] & 16 ? 0 : 1));
|
||||
*/
|
||||
input_report_abs(dev + n, db9_abs[6], data[j + 7]);
|
||||
input_report_abs(dev + n, db9_abs[7], data[j + 8]);
|
||||
input_report_abs(dev + n, db9_abs[5], data[j + 9]);
|
||||
break;
|
||||
case 0xd3: /* sankyo ff (analog 1 axis + stop btn) */
|
||||
input_report_key(dev + n, BTN_A, data[j + 3] & 0x80);
|
||||
input_report_abs(dev + n, db9_abs[2], data[j + 3] & 0x7f);
|
||||
break;
|
||||
case 0xe3: /* shuttle mouse (analog 2 axis + buttons. signed value) */
|
||||
input_report_key(dev + n, BTN_START, data[j + 1] & 0x08);
|
||||
input_report_key(dev + n, BTN_A, data[j + 1] & 0x04);
|
||||
input_report_key(dev + n, BTN_C, data[j + 1] & 0x02);
|
||||
input_report_key(dev + n, BTN_B, data[j + 1] & 0x01);
|
||||
input_report_abs(dev + n, db9_abs[2], data[j + 2] ^ 0x80);
|
||||
input_report_abs(dev + n, db9_abs[3], (0xff-(data[j + 3] ^ 0x80))+1); /* */
|
||||
break;
|
||||
case 0xff:
|
||||
default: /* no pad */
|
||||
input_report_abs(dev + n, db9_abs[0], 0);
|
||||
input_report_abs(dev + n, db9_abs[1], 0);
|
||||
for (i = 0; i < 9; i++)
|
||||
input_report_key(dev + n, db9_cd32_btn[i], 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static int db9_saturn(int mode, struct parport *port, struct input_dev *dev)
|
||||
{
|
||||
unsigned char id, data[60];
|
||||
int type, n, max_pads;
|
||||
int tmp, i;
|
||||
|
||||
switch (mode) {
|
||||
case DB9_SATURN_PAD:
|
||||
type = 0;
|
||||
n = 1;
|
||||
break;
|
||||
case DB9_SATURN_DPP:
|
||||
type = 1;
|
||||
n = 1;
|
||||
break;
|
||||
case DB9_SATURN_DPP_2:
|
||||
type = 1;
|
||||
n = 2;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
max_pads = min(db9_max_pads[mode], DB9_MAX_DEVICES);
|
||||
for (tmp = 0, i = 0; i < n; i++) {
|
||||
id = db9_saturn_read_packet(port, data, type + i, 1);
|
||||
tmp = db9_saturn_report(id, data, dev, tmp, max_pads);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void db9_timer(unsigned long private)
|
||||
{
|
||||
struct db9 *db9 = (void *) private;
|
||||
struct parport *port = db9->pd->port;
|
||||
struct input_dev *dev = db9->dev;
|
||||
int data, i;
|
||||
|
||||
switch(db9->mode) {
|
||||
case DB9_MULTI_0802_2:
|
||||
|
||||
data = parport_read_data(port) >> 3;
|
||||
|
||||
input_report_abs(dev + 1, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
|
||||
input_report_abs(dev + 1, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
|
||||
input_report_key(dev + 1, BTN_TRIGGER, ~data & DB9_FIRE1);
|
||||
|
||||
case DB9_MULTI_0802:
|
||||
|
||||
data = parport_read_status(port) >> 3;
|
||||
|
||||
input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
|
||||
input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
|
||||
input_report_key(dev, BTN_TRIGGER, data & DB9_FIRE1);
|
||||
break;
|
||||
|
||||
case DB9_MULTI_STICK:
|
||||
|
||||
data = parport_read_data(port);
|
||||
|
||||
input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
|
||||
input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
|
||||
input_report_key(dev, BTN_TRIGGER, ~data & DB9_FIRE1);
|
||||
break;
|
||||
|
||||
case DB9_MULTI2_STICK:
|
||||
|
||||
data = parport_read_data(port);
|
||||
|
||||
input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
|
||||
input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
|
||||
input_report_key(dev, BTN_TRIGGER, ~data & DB9_FIRE1);
|
||||
input_report_key(dev, BTN_THUMB, ~data & DB9_FIRE2);
|
||||
break;
|
||||
|
||||
case DB9_GENESIS_PAD:
|
||||
|
||||
parport_write_control(port, DB9_NOSELECT);
|
||||
data = parport_read_data(port);
|
||||
|
||||
input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
|
||||
input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
|
||||
input_report_key(dev, BTN_B, ~data & DB9_FIRE1);
|
||||
input_report_key(dev, BTN_C, ~data & DB9_FIRE2);
|
||||
|
||||
parport_write_control(port, DB9_NORMAL);
|
||||
data=parport_read_data(port);
|
||||
|
||||
input_report_key(dev, BTN_A, ~data & DB9_FIRE1);
|
||||
input_report_key(dev, BTN_START, ~data & DB9_FIRE2);
|
||||
break;
|
||||
|
||||
case DB9_GENESIS5_PAD:
|
||||
|
||||
parport_write_control(port, DB9_NOSELECT);
|
||||
data=parport_read_data(port);
|
||||
|
||||
input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
|
||||
input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
|
||||
input_report_key(dev, BTN_B, ~data & DB9_FIRE1);
|
||||
input_report_key(dev, BTN_C, ~data & DB9_FIRE2);
|
||||
|
||||
parport_write_control(port, DB9_NORMAL);
|
||||
data=parport_read_data(port);
|
||||
|
||||
input_report_key(dev, BTN_A, ~data & DB9_FIRE1);
|
||||
input_report_key(dev, BTN_X, ~data & DB9_FIRE2);
|
||||
input_report_key(dev, BTN_Y, ~data & DB9_LEFT);
|
||||
input_report_key(dev, BTN_START, ~data & DB9_RIGHT);
|
||||
break;
|
||||
|
||||
case DB9_GENESIS6_PAD:
|
||||
|
||||
parport_write_control(port, DB9_NOSELECT); /* 1 */
|
||||
udelay(DB9_GENESIS6_DELAY);
|
||||
data=parport_read_data(port);
|
||||
|
||||
input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
|
||||
input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
|
||||
input_report_key(dev, BTN_B, ~data & DB9_FIRE1);
|
||||
input_report_key(dev, BTN_C, ~data & DB9_FIRE2);
|
||||
|
||||
parport_write_control(port, DB9_NORMAL);
|
||||
udelay(DB9_GENESIS6_DELAY);
|
||||
data=parport_read_data(port);
|
||||
|
||||
input_report_key(dev, BTN_A, ~data & DB9_FIRE1);
|
||||
input_report_key(dev, BTN_START, ~data & DB9_FIRE2);
|
||||
|
||||
parport_write_control(port, DB9_NOSELECT); /* 2 */
|
||||
udelay(DB9_GENESIS6_DELAY);
|
||||
parport_write_control(port, DB9_NORMAL);
|
||||
udelay(DB9_GENESIS6_DELAY);
|
||||
parport_write_control(port, DB9_NOSELECT); /* 3 */
|
||||
udelay(DB9_GENESIS6_DELAY);
|
||||
data=parport_read_data(port);
|
||||
|
||||
input_report_key(dev, BTN_X, ~data & DB9_LEFT);
|
||||
input_report_key(dev, BTN_Y, ~data & DB9_DOWN);
|
||||
input_report_key(dev, BTN_Z, ~data & DB9_UP);
|
||||
input_report_key(dev, BTN_MODE, ~data & DB9_RIGHT);
|
||||
|
||||
parport_write_control(port, DB9_NORMAL);
|
||||
udelay(DB9_GENESIS6_DELAY);
|
||||
parport_write_control(port, DB9_NOSELECT); /* 4 */
|
||||
udelay(DB9_GENESIS6_DELAY);
|
||||
parport_write_control(port, DB9_NORMAL);
|
||||
break;
|
||||
|
||||
case DB9_SATURN_PAD:
|
||||
case DB9_SATURN_DPP:
|
||||
case DB9_SATURN_DPP_2:
|
||||
|
||||
db9_saturn(db9->mode, port, dev);
|
||||
break;
|
||||
|
||||
case DB9_CD32_PAD:
|
||||
|
||||
data=parport_read_data(port);
|
||||
|
||||
input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
|
||||
input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
|
||||
|
||||
parport_write_control(port, 0x0a);
|
||||
|
||||
for (i = 0; i < 7; i++) {
|
||||
data = parport_read_data(port);
|
||||
parport_write_control(port, 0x02);
|
||||
parport_write_control(port, 0x0a);
|
||||
input_report_key(dev, db9_cd32_btn[i], ~data & DB9_FIRE2);
|
||||
}
|
||||
|
||||
parport_write_control(port, 0x00);
|
||||
break;
|
||||
}
|
||||
|
||||
input_sync(dev);
|
||||
|
||||
mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
|
||||
}
|
||||
|
||||
static int db9_open(struct input_dev *dev)
|
||||
{
|
||||
struct db9 *db9 = dev->private;
|
||||
struct parport *port = db9->pd->port;
|
||||
|
||||
if (!db9->used++) {
|
||||
parport_claim(db9->pd);
|
||||
parport_write_data(port, 0xff);
|
||||
if (db9_reverse[db9->mode]) {
|
||||
parport_data_reverse(port);
|
||||
parport_write_control(port, DB9_NORMAL);
|
||||
}
|
||||
mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void db9_close(struct input_dev *dev)
|
||||
{
|
||||
struct db9 *db9 = dev->private;
|
||||
struct parport *port = db9->pd->port;
|
||||
|
||||
if (!--db9->used) {
|
||||
del_timer(&db9->timer);
|
||||
parport_write_control(port, 0x00);
|
||||
parport_data_forward(port);
|
||||
parport_release(db9->pd);
|
||||
}
|
||||
}
|
||||
|
||||
static struct db9 __init *db9_probe(int *config, int nargs)
|
||||
{
|
||||
struct db9 *db9;
|
||||
struct parport *pp;
|
||||
int i, j;
|
||||
|
||||
if (config[0] < 0)
|
||||
return NULL;
|
||||
|
||||
if (nargs < 2) {
|
||||
printk(KERN_ERR "db9.c: Device type must be specified.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (config[1] < 1 || config[1] >= DB9_MAX_PAD || !db9_buttons[config[1]]) {
|
||||
printk(KERN_ERR "db9.c: bad config\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pp = parport_find_number(config[0]);
|
||||
if (!pp) {
|
||||
printk(KERN_ERR "db9.c: no such parport\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (db9_bidirectional[config[1]]) {
|
||||
if (!(pp->modes & PARPORT_MODE_TRISTATE)) {
|
||||
printk(KERN_ERR "db9.c: specified parport is not bidirectional\n");
|
||||
parport_put_port(pp);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(db9 = kmalloc(sizeof(struct db9), GFP_KERNEL))) {
|
||||
parport_put_port(pp);
|
||||
return NULL;
|
||||
}
|
||||
memset(db9, 0, sizeof(struct db9));
|
||||
|
||||
db9->mode = config[1];
|
||||
init_timer(&db9->timer);
|
||||
db9->timer.data = (long) db9;
|
||||
db9->timer.function = db9_timer;
|
||||
|
||||
db9->pd = parport_register_device(pp, "db9", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
|
||||
parport_put_port(pp);
|
||||
|
||||
if (!db9->pd) {
|
||||
printk(KERN_ERR "db9.c: parport busy already - lp.o loaded?\n");
|
||||
kfree(db9);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < (min(db9_max_pads[db9->mode], DB9_MAX_DEVICES)); i++) {
|
||||
|
||||
sprintf(db9->phys[i], "%s/input%d", db9->pd->port->name, i);
|
||||
|
||||
db9->dev[i].private = db9;
|
||||
db9->dev[i].open = db9_open;
|
||||
db9->dev[i].close = db9_close;
|
||||
|
||||
db9->dev[i].name = db9_name[db9->mode];
|
||||
db9->dev[i].phys = db9->phys[i];
|
||||
db9->dev[i].id.bustype = BUS_PARPORT;
|
||||
db9->dev[i].id.vendor = 0x0002;
|
||||
db9->dev[i].id.product = config[1];
|
||||
db9->dev[i].id.version = 0x0100;
|
||||
|
||||
db9->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
for (j = 0; j < db9_buttons[db9->mode]; j++)
|
||||
set_bit(db9_btn[db9->mode][j], db9->dev[i].keybit);
|
||||
for (j = 0; j < db9_num_axis[db9->mode]; j++) {
|
||||
set_bit(db9_abs[j], db9->dev[i].absbit);
|
||||
if (j < 2) {
|
||||
db9->dev[i].absmin[db9_abs[j]] = -1;
|
||||
db9->dev[i].absmax[db9_abs[j]] = 1;
|
||||
} else {
|
||||
db9->dev[i].absmin[db9_abs[j]] = 1;
|
||||
db9->dev[i].absmax[db9_abs[j]] = 255;
|
||||
db9->dev[i].absflat[db9_abs[j]] = 0;
|
||||
}
|
||||
}
|
||||
input_register_device(db9->dev + i);
|
||||
printk(KERN_INFO "input: %s on %s\n", db9->dev[i].name, db9->pd->port->name);
|
||||
}
|
||||
|
||||
return db9;
|
||||
}
|
||||
|
||||
int __init db9_init(void)
|
||||
{
|
||||
db9_base[0] = db9_probe(db9, db9_nargs);
|
||||
db9_base[1] = db9_probe(db9_2, db9_nargs_2);
|
||||
db9_base[2] = db9_probe(db9_3, db9_nargs_3);
|
||||
|
||||
if (db9_base[0] || db9_base[1] || db9_base[2])
|
||||
return 0;
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
void __exit db9_exit(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
if (db9_base[i]) {
|
||||
for (j = 0; j < min(db9_max_pads[db9_base[i]->mode], DB9_MAX_DEVICES); j++)
|
||||
input_unregister_device(db9_base[i]->dev + j);
|
||||
parport_unregister_device(db9_base[i]->pd);
|
||||
}
|
||||
}
|
||||
|
||||
module_init(db9_init);
|
||||
module_exit(db9_exit);
|
||||
694
extra/linux-2.6.10/drivers/input/joystick/gamecon.c
Normal file
694
extra/linux-2.6.10/drivers/input/joystick/gamecon.c
Normal file
@@ -0,0 +1,694 @@
|
||||
/*
|
||||
* NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux
|
||||
*
|
||||
* Copyright (c) 1999-2004 Vojtech Pavlik <vojtech@suse.cz>
|
||||
* Copyright (c) 2004 Peter Nelson <rufus-kernel@hackish.org>
|
||||
*
|
||||
* Based on the work of:
|
||||
* Andree Borrmann John Dahlstrom
|
||||
* David Kuder Nathan Hand
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/parport.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("NES, SNES, N64, MultiSystem, PSX gamepad driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int gc[] __initdata = { -1, 0, 0, 0, 0, 0 };
|
||||
static int gc_nargs __initdata = 0;
|
||||
module_param_array_named(map, gc, int, &gc_nargs, 0);
|
||||
MODULE_PARM_DESC(map, "Describers first set of devices (<parport#>,<pad1>,<pad2>,..<pad5>)");
|
||||
|
||||
static int gc_2[] __initdata = { -1, 0, 0, 0, 0, 0 };
|
||||
static int gc_nargs_2 __initdata = 0;
|
||||
module_param_array_named(map2, gc_2, int, &gc_nargs_2, 0);
|
||||
MODULE_PARM_DESC(map2, "Describers second set of devices");
|
||||
|
||||
static int gc_3[] __initdata = { -1, 0, 0, 0, 0, 0 };
|
||||
static int gc_nargs_3 __initdata = 0;
|
||||
module_param_array_named(map3, gc_3, int, &gc_nargs_3, 0);
|
||||
MODULE_PARM_DESC(map3, "Describers third set of devices");
|
||||
|
||||
__obsolete_setup("gc=");
|
||||
__obsolete_setup("gc_2=");
|
||||
__obsolete_setup("gc_3=");
|
||||
|
||||
/* see also gs_psx_delay parameter in PSX support section */
|
||||
|
||||
#define GC_SNES 1
|
||||
#define GC_NES 2
|
||||
#define GC_NES4 3
|
||||
#define GC_MULTI 4
|
||||
#define GC_MULTI2 5
|
||||
#define GC_N64 6
|
||||
#define GC_PSX 7
|
||||
#define GC_DDR 8
|
||||
|
||||
#define GC_MAX 8
|
||||
|
||||
#define GC_REFRESH_TIME HZ/100
|
||||
|
||||
struct gc {
|
||||
struct pardevice *pd;
|
||||
struct input_dev dev[5];
|
||||
struct timer_list timer;
|
||||
unsigned char pads[GC_MAX + 1];
|
||||
int used;
|
||||
char phys[5][32];
|
||||
};
|
||||
|
||||
static struct gc *gc_base[3];
|
||||
|
||||
static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
|
||||
|
||||
static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick",
|
||||
"Multisystem 2-button joystick", "N64 controller", "PSX controller"
|
||||
"PSX DDR controller" };
|
||||
/*
|
||||
* N64 support.
|
||||
*/
|
||||
|
||||
static unsigned char gc_n64_bytes[] = { 0, 1, 13, 15, 14, 12, 10, 11, 2, 3 };
|
||||
static short gc_n64_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TRIGGER, BTN_START };
|
||||
|
||||
#define GC_N64_LENGTH 32 /* N64 bit length, not including stop bit */
|
||||
#define GC_N64_REQUEST_LENGTH 37 /* transmit request sequence is 9 bits long */
|
||||
#define GC_N64_DELAY 133 /* delay between transmit request, and response ready (us) */
|
||||
#define GC_N64_REQUEST 0x1dd1111111ULL /* the request data command (encoded for 000000011) */
|
||||
#define GC_N64_DWS 3 /* delay between write segments (required for sound playback because of ISA DMA) */
|
||||
/* GC_N64_DWS > 24 is known to fail */
|
||||
#define GC_N64_POWER_W 0xe2 /* power during write (transmit request) */
|
||||
#define GC_N64_POWER_R 0xfd /* power during read */
|
||||
#define GC_N64_OUT 0x1d /* output bits to the 4 pads */
|
||||
/* Reading the main axes of any N64 pad is known to fail if the corresponding bit */
|
||||
/* in GC_N64_OUT is pulled low on the output port (by any routine) for more */
|
||||
/* than 123 us */
|
||||
#define GC_N64_CLOCK 0x02 /* clock bits for read */
|
||||
|
||||
/*
|
||||
* gc_n64_read_packet() reads an N64 packet.
|
||||
* Each pad uses one bit per byte. So all pads connected to this port are read in parallel.
|
||||
*/
|
||||
|
||||
static void gc_n64_read_packet(struct gc *gc, unsigned char *data)
|
||||
{
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Request the pad to transmit data
|
||||
*/
|
||||
|
||||
local_irq_save(flags);
|
||||
for (i = 0; i < GC_N64_REQUEST_LENGTH; i++) {
|
||||
parport_write_data(gc->pd->port, GC_N64_POWER_W | ((GC_N64_REQUEST >> i) & 1 ? GC_N64_OUT : 0));
|
||||
udelay(GC_N64_DWS);
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
|
||||
/*
|
||||
* Wait for the pad response to be loaded into the 33-bit register of the adapter
|
||||
*/
|
||||
|
||||
udelay(GC_N64_DELAY);
|
||||
|
||||
/*
|
||||
* Grab data (ignoring the last bit, which is a stop bit)
|
||||
*/
|
||||
|
||||
for (i = 0; i < GC_N64_LENGTH; i++) {
|
||||
parport_write_data(gc->pd->port, GC_N64_POWER_R);
|
||||
data[i] = parport_read_status(gc->pd->port);
|
||||
parport_write_data(gc->pd->port, GC_N64_POWER_R | GC_N64_CLOCK);
|
||||
}
|
||||
|
||||
/*
|
||||
* We must wait 200 ms here for the controller to reinitialize before the next read request.
|
||||
* No worries as long as gc_read is polled less frequently than this.
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* NES/SNES support.
|
||||
*/
|
||||
|
||||
#define GC_NES_DELAY 6 /* Delay between bits - 6us */
|
||||
#define GC_NES_LENGTH 8 /* The NES pads use 8 bits of data */
|
||||
#define GC_SNES_LENGTH 12 /* The SNES true length is 16, but the last 4 bits are unused */
|
||||
|
||||
#define GC_NES_POWER 0xfc
|
||||
#define GC_NES_CLOCK 0x01
|
||||
#define GC_NES_LATCH 0x02
|
||||
|
||||
static unsigned char gc_nes_bytes[] = { 0, 1, 2, 3 };
|
||||
static unsigned char gc_snes_bytes[] = { 8, 0, 2, 3, 9, 1, 10, 11 };
|
||||
static short gc_snes_btn[] = { BTN_A, BTN_B, BTN_SELECT, BTN_START, BTN_X, BTN_Y, BTN_TL, BTN_TR };
|
||||
|
||||
/*
|
||||
* gc_nes_read_packet() reads a NES/SNES packet.
|
||||
* Each pad uses one bit per byte. So all pads connected to
|
||||
* this port are read in parallel.
|
||||
*/
|
||||
|
||||
static void gc_nes_read_packet(struct gc *gc, int length, unsigned char *data)
|
||||
{
|
||||
int i;
|
||||
|
||||
parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK | GC_NES_LATCH);
|
||||
udelay(GC_NES_DELAY * 2);
|
||||
parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK);
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
udelay(GC_NES_DELAY);
|
||||
parport_write_data(gc->pd->port, GC_NES_POWER);
|
||||
data[i] = parport_read_status(gc->pd->port) ^ 0x7f;
|
||||
udelay(GC_NES_DELAY);
|
||||
parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Multisystem joystick support
|
||||
*/
|
||||
|
||||
#define GC_MULTI_LENGTH 5 /* Multi system joystick packet length is 5 */
|
||||
#define GC_MULTI2_LENGTH 6 /* One more bit for one more button */
|
||||
|
||||
/*
|
||||
* gc_multi_read_packet() reads a Multisystem joystick packet.
|
||||
*/
|
||||
|
||||
static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
parport_write_data(gc->pd->port, ~(1 << i));
|
||||
data[i] = parport_read_status(gc->pd->port) ^ 0x7f;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* PSX support
|
||||
*
|
||||
* See documentation at:
|
||||
* http://www.dim.com/~mackys/psxmemcard/ps-eng2.txt
|
||||
* http://www.gamesx.com/controldata/psxcont/psxcont.htm
|
||||
* ftp://milano.usal.es/pablo/
|
||||
*
|
||||
*/
|
||||
|
||||
#define GC_PSX_DELAY 25 /* 25 usec */
|
||||
#define GC_PSX_LENGTH 8 /* talk to the controller in bytes */
|
||||
|
||||
#define GC_PSX_MOUSE 1 /* Mouse */
|
||||
#define GC_PSX_NEGCON 2 /* NegCon */
|
||||
#define GC_PSX_NORMAL 4 /* Digital / Analog or Rumble in Digital mode */
|
||||
#define GC_PSX_ANALOG 5 /* Analog in Analog mode / Rumble in Green mode */
|
||||
#define GC_PSX_RUMBLE 7 /* Rumble in Red mode */
|
||||
|
||||
#define GC_PSX_CLOCK 0x04 /* Pin 4 */
|
||||
#define GC_PSX_COMMAND 0x01 /* Pin 2 */
|
||||
#define GC_PSX_POWER 0xf8 /* Pins 5-9 */
|
||||
#define GC_PSX_SELECT 0x02 /* Pin 3 */
|
||||
|
||||
#define GC_PSX_ID(x) ((x) >> 4) /* High nibble is device type */
|
||||
#define GC_PSX_LEN(x) ((x) & 0xf) /* Low nibble is length in words */
|
||||
|
||||
static int gc_psx_delay = GC_PSX_DELAY;
|
||||
module_param_named(psx_delay, gc_psx_delay, uint, 0);
|
||||
MODULE_PARM_DESC(psx_delay, "Delay when accessing Sony PSX controller (usecs)");
|
||||
|
||||
__obsolete_setup("gc_psx_delay=");
|
||||
|
||||
static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y };
|
||||
static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y,
|
||||
BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR };
|
||||
static short gc_psx_ddr_btn[] = { BTN_0, BTN_1, BTN_2, BTN_3 };
|
||||
|
||||
/*
|
||||
* gc_psx_command() writes 8bit command and reads 8bit data from
|
||||
* the psx pad.
|
||||
*/
|
||||
|
||||
static void gc_psx_command(struct gc *gc, int b, unsigned char data[GC_PSX_LENGTH])
|
||||
{
|
||||
int i, j, cmd, read;
|
||||
for (i = 0; i < 5; i++)
|
||||
data[i] = 0;
|
||||
|
||||
for (i = 0; i < 8; i++, b >>= 1) {
|
||||
cmd = (b & 1) ? GC_PSX_COMMAND : 0;
|
||||
parport_write_data(gc->pd->port, cmd | GC_PSX_POWER);
|
||||
udelay(gc_psx_delay);
|
||||
read = parport_read_status(gc->pd->port) ^ 0x80;
|
||||
for (j = 0; j < 5; j++)
|
||||
data[j] |= (read & gc_status_bit[j] & gc->pads[GC_PSX]) ? (1 << i) : 0;
|
||||
parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER);
|
||||
udelay(gc_psx_delay);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* gc_psx_read_packet() reads a whole psx packet and returns
|
||||
* device identifier code.
|
||||
*/
|
||||
|
||||
static void gc_psx_read_packet(struct gc *gc, unsigned char data[5][GC_PSX_LENGTH], unsigned char id[5])
|
||||
{
|
||||
int i, j, max_len = 0;
|
||||
unsigned long flags;
|
||||
unsigned char data2[5];
|
||||
|
||||
parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); /* Select pad */
|
||||
udelay(gc_psx_delay);
|
||||
parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER); /* Deselect, begin command */
|
||||
udelay(gc_psx_delay);
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
gc_psx_command(gc, 0x01, data2); /* Access pad */
|
||||
gc_psx_command(gc, 0x42, id); /* Get device ids */
|
||||
gc_psx_command(gc, 0, data2); /* Dump status */
|
||||
|
||||
for (i =0; i < 5; i++) /* Find the longest pad */
|
||||
if((gc_status_bit[i] & gc->pads[GC_PSX]) && (GC_PSX_LEN(id[i]) > max_len))
|
||||
max_len = GC_PSX_LEN(id[i]);
|
||||
|
||||
for (i = 0; i < max_len * 2; i++) { /* Read in all the data */
|
||||
gc_psx_command(gc, 0, data2);
|
||||
for (j = 0; j < 5; j++)
|
||||
data[j][i] = data2[j];
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);
|
||||
|
||||
for(i = 0; i < 5; i++) /* Set id's to the real value */
|
||||
id[i] = GC_PSX_ID(id[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* gc_timer() reads and analyzes console pads data.
|
||||
*/
|
||||
|
||||
#define GC_MAX_LENGTH GC_N64_LENGTH
|
||||
|
||||
static void gc_timer(unsigned long private)
|
||||
{
|
||||
struct gc *gc = (void *) private;
|
||||
struct input_dev *dev = gc->dev;
|
||||
unsigned char data[GC_MAX_LENGTH];
|
||||
unsigned char data_psx[5][GC_PSX_LENGTH];
|
||||
int i, j, s;
|
||||
|
||||
/*
|
||||
* N64 pads - must be read first, any read confuses them for 200 us
|
||||
*/
|
||||
|
||||
if (gc->pads[GC_N64]) {
|
||||
|
||||
gc_n64_read_packet(gc, data);
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
|
||||
s = gc_status_bit[i];
|
||||
|
||||
if (s & gc->pads[GC_N64] & ~(data[8] | data[9])) {
|
||||
|
||||
signed char axes[2];
|
||||
axes[0] = axes[1] = 0;
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
if (data[23 - j] & s) axes[0] |= 1 << j;
|
||||
if (data[31 - j] & s) axes[1] |= 1 << j;
|
||||
}
|
||||
|
||||
input_report_abs(dev + i, ABS_X, axes[0]);
|
||||
input_report_abs(dev + i, ABS_Y, -axes[1]);
|
||||
|
||||
input_report_abs(dev + i, ABS_HAT0X, !(s & data[6]) - !(s & data[7]));
|
||||
input_report_abs(dev + i, ABS_HAT0Y, !(s & data[4]) - !(s & data[5]));
|
||||
|
||||
for (j = 0; j < 10; j++)
|
||||
input_report_key(dev + i, gc_n64_btn[j], s & data[gc_n64_bytes[j]]);
|
||||
|
||||
input_sync(dev + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* NES and SNES pads
|
||||
*/
|
||||
|
||||
if (gc->pads[GC_NES] || gc->pads[GC_SNES]) {
|
||||
|
||||
gc_nes_read_packet(gc, gc->pads[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH, data);
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
|
||||
s = gc_status_bit[i];
|
||||
|
||||
if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) {
|
||||
input_report_abs(dev + i, ABS_X, !(s & data[6]) - !(s & data[7]));
|
||||
input_report_abs(dev + i, ABS_Y, !(s & data[4]) - !(s & data[5]));
|
||||
}
|
||||
|
||||
if (s & gc->pads[GC_NES])
|
||||
for (j = 0; j < 4; j++)
|
||||
input_report_key(dev + i, gc_snes_btn[j], s & data[gc_nes_bytes[j]]);
|
||||
|
||||
if (s & gc->pads[GC_SNES])
|
||||
for (j = 0; j < 8; j++)
|
||||
input_report_key(dev + i, gc_snes_btn[j], s & data[gc_snes_bytes[j]]);
|
||||
|
||||
input_sync(dev + i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Multi and Multi2 joysticks
|
||||
*/
|
||||
|
||||
if (gc->pads[GC_MULTI] || gc->pads[GC_MULTI2]) {
|
||||
|
||||
gc_multi_read_packet(gc, gc->pads[GC_MULTI2] ? GC_MULTI2_LENGTH : GC_MULTI_LENGTH, data);
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
|
||||
s = gc_status_bit[i];
|
||||
|
||||
if (s & (gc->pads[GC_MULTI] | gc->pads[GC_MULTI2])) {
|
||||
input_report_abs(dev + i, ABS_X, !(s & data[2]) - !(s & data[3]));
|
||||
input_report_abs(dev + i, ABS_Y, !(s & data[0]) - !(s & data[1]));
|
||||
input_report_key(dev + i, BTN_TRIGGER, s & data[4]);
|
||||
}
|
||||
|
||||
if (s & gc->pads[GC_MULTI2])
|
||||
input_report_key(dev + i, BTN_THUMB, s & data[5]);
|
||||
|
||||
input_sync(dev + i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* PSX controllers
|
||||
*/
|
||||
|
||||
if (gc->pads[GC_PSX] || gc->pads[GC_DDR]) {
|
||||
|
||||
gc_psx_read_packet(gc, data_psx, data);
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
switch (data[i]) {
|
||||
|
||||
case GC_PSX_RUMBLE:
|
||||
|
||||
input_report_key(dev + i, BTN_THUMBL, ~data_psx[i][0] & 0x04);
|
||||
input_report_key(dev + i, BTN_THUMBR, ~data_psx[i][0] & 0x02);
|
||||
|
||||
case GC_PSX_NEGCON:
|
||||
case GC_PSX_ANALOG:
|
||||
|
||||
if(gc->pads[GC_DDR] & gc_status_bit[i]) {
|
||||
for(j = 0; j < 4; j++)
|
||||
input_report_key(dev + i, gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j));
|
||||
} else {
|
||||
for (j = 0; j < 4; j++)
|
||||
input_report_abs(dev + i, gc_psx_abs[j+2], data_psx[i][j + 2]);
|
||||
|
||||
input_report_abs(dev + i, ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128);
|
||||
input_report_abs(dev + i, ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128);
|
||||
}
|
||||
|
||||
for (j = 0; j < 8; j++)
|
||||
input_report_key(dev + i, gc_psx_btn[j], ~data_psx[i][1] & (1 << j));
|
||||
|
||||
input_report_key(dev + i, BTN_START, ~data_psx[i][0] & 0x08);
|
||||
input_report_key(dev + i, BTN_SELECT, ~data_psx[i][0] & 0x01);
|
||||
|
||||
input_sync(dev + i);
|
||||
|
||||
break;
|
||||
|
||||
case GC_PSX_NORMAL:
|
||||
if(gc->pads[GC_DDR] & gc_status_bit[i]) {
|
||||
for(j = 0; j < 4; j++)
|
||||
input_report_key(dev + i, gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j));
|
||||
} else {
|
||||
input_report_abs(dev + i, ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128);
|
||||
input_report_abs(dev + i, ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128);
|
||||
|
||||
/* for some reason if the extra axes are left unset they drift */
|
||||
/* for (j = 0; j < 4; j++)
|
||||
input_report_abs(dev + i, gc_psx_abs[j+2], 128);
|
||||
* This needs to be debugged properly,
|
||||
* maybe fuzz processing needs to be done in input_sync()
|
||||
* --vojtech
|
||||
*/
|
||||
}
|
||||
|
||||
for (j = 0; j < 8; j++)
|
||||
input_report_key(dev + i, gc_psx_btn[j], ~data_psx[i][1] & (1 << j));
|
||||
|
||||
input_report_key(dev + i, BTN_START, ~data_psx[i][0] & 0x08);
|
||||
input_report_key(dev + i, BTN_SELECT, ~data_psx[i][0] & 0x01);
|
||||
|
||||
input_sync(dev + i);
|
||||
|
||||
break;
|
||||
|
||||
case 0: /* not a pad, ignore */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
|
||||
}
|
||||
|
||||
static int gc_open(struct input_dev *dev)
|
||||
{
|
||||
struct gc *gc = dev->private;
|
||||
if (!gc->used++) {
|
||||
parport_claim(gc->pd);
|
||||
parport_write_control(gc->pd->port, 0x04);
|
||||
mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gc_close(struct input_dev *dev)
|
||||
{
|
||||
struct gc *gc = dev->private;
|
||||
if (!--gc->used) {
|
||||
del_timer(&gc->timer);
|
||||
parport_write_control(gc->pd->port, 0x00);
|
||||
parport_release(gc->pd);
|
||||
}
|
||||
}
|
||||
|
||||
static struct gc __init *gc_probe(int *config, int nargs)
|
||||
{
|
||||
struct gc *gc;
|
||||
struct parport *pp;
|
||||
int i, j;
|
||||
|
||||
if (config[0] < 0)
|
||||
return NULL;
|
||||
|
||||
if (nargs < 2) {
|
||||
printk(KERN_ERR "gamecon.c: at least one device must be specified\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pp = parport_find_number(config[0]);
|
||||
|
||||
if (!pp) {
|
||||
printk(KERN_ERR "gamecon.c: no such parport\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(gc = kmalloc(sizeof(struct gc), GFP_KERNEL))) {
|
||||
parport_put_port(pp);
|
||||
return NULL;
|
||||
}
|
||||
memset(gc, 0, sizeof(struct gc));
|
||||
|
||||
gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
|
||||
|
||||
parport_put_port(pp);
|
||||
|
||||
if (!gc->pd) {
|
||||
printk(KERN_ERR "gamecon.c: parport busy already - lp.o loaded?\n");
|
||||
kfree(gc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
parport_claim(gc->pd);
|
||||
|
||||
init_timer(&gc->timer);
|
||||
gc->timer.data = (long) gc;
|
||||
gc->timer.function = gc_timer;
|
||||
|
||||
for (i = 0; i < nargs - 1; i++) {
|
||||
|
||||
if (!config[i + 1])
|
||||
continue;
|
||||
|
||||
if (config[i + 1] < 1 || config[i + 1] > GC_MAX) {
|
||||
printk(KERN_WARNING "gamecon.c: Pad type %d unknown\n", config[i + 1]);
|
||||
continue;
|
||||
}
|
||||
|
||||
gc->dev[i].private = gc;
|
||||
gc->dev[i].open = gc_open;
|
||||
gc->dev[i].close = gc_close;
|
||||
|
||||
gc->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
|
||||
for (j = 0; j < 2; j++) {
|
||||
set_bit(ABS_X + j, gc->dev[i].absbit);
|
||||
gc->dev[i].absmin[ABS_X + j] = -1;
|
||||
gc->dev[i].absmax[ABS_X + j] = 1;
|
||||
}
|
||||
|
||||
gc->pads[0] |= gc_status_bit[i];
|
||||
gc->pads[config[i + 1]] |= gc_status_bit[i];
|
||||
|
||||
switch(config[i + 1]) {
|
||||
|
||||
case GC_N64:
|
||||
for (j = 0; j < 10; j++)
|
||||
set_bit(gc_n64_btn[j], gc->dev[i].keybit);
|
||||
|
||||
for (j = 0; j < 2; j++) {
|
||||
set_bit(ABS_X + j, gc->dev[i].absbit);
|
||||
gc->dev[i].absmin[ABS_X + j] = -127;
|
||||
gc->dev[i].absmax[ABS_X + j] = 126;
|
||||
gc->dev[i].absflat[ABS_X + j] = 2;
|
||||
set_bit(ABS_HAT0X + j, gc->dev[i].absbit);
|
||||
gc->dev[i].absmin[ABS_HAT0X + j] = -1;
|
||||
gc->dev[i].absmax[ABS_HAT0X + j] = 1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case GC_SNES:
|
||||
for (j = 4; j < 8; j++)
|
||||
set_bit(gc_snes_btn[j], gc->dev[i].keybit);
|
||||
case GC_NES:
|
||||
for (j = 0; j < 4; j++)
|
||||
set_bit(gc_snes_btn[j], gc->dev[i].keybit);
|
||||
break;
|
||||
|
||||
case GC_MULTI2:
|
||||
set_bit(BTN_THUMB, gc->dev[i].keybit);
|
||||
case GC_MULTI:
|
||||
set_bit(BTN_TRIGGER, gc->dev[i].keybit);
|
||||
break;
|
||||
|
||||
case GC_PSX:
|
||||
case GC_DDR:
|
||||
if(config[i + 1] == GC_DDR) {
|
||||
for (j = 0; j < 4; j++)
|
||||
set_bit(gc_psx_ddr_btn[j], gc->dev[i].keybit);
|
||||
} else {
|
||||
for (j = 0; j < 6; j++) {
|
||||
set_bit(gc_psx_abs[j], gc->dev[i].absbit);
|
||||
gc->dev[i].absmin[gc_psx_abs[j]] = 4;
|
||||
gc->dev[i].absmax[gc_psx_abs[j]] = 252;
|
||||
gc->dev[i].absflat[gc_psx_abs[j]] = 2;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < 12; j++)
|
||||
set_bit(gc_psx_btn[j], gc->dev[i].keybit);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
sprintf(gc->phys[i], "%s/input%d", gc->pd->port->name, i);
|
||||
|
||||
gc->dev[i].name = gc_names[config[i + 1]];
|
||||
gc->dev[i].phys = gc->phys[i];
|
||||
gc->dev[i].id.bustype = BUS_PARPORT;
|
||||
gc->dev[i].id.vendor = 0x0001;
|
||||
gc->dev[i].id.product = config[i + 1];
|
||||
gc->dev[i].id.version = 0x0100;
|
||||
}
|
||||
|
||||
parport_release(gc->pd);
|
||||
|
||||
if (!gc->pads[0]) {
|
||||
parport_unregister_device(gc->pd);
|
||||
kfree(gc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
if (gc->pads[0] & gc_status_bit[i]) {
|
||||
input_register_device(gc->dev + i);
|
||||
printk(KERN_INFO "input: %s on %s\n", gc->dev[i].name, gc->pd->port->name);
|
||||
}
|
||||
|
||||
return gc;
|
||||
}
|
||||
|
||||
int __init gc_init(void)
|
||||
{
|
||||
gc_base[0] = gc_probe(gc, gc_nargs);
|
||||
gc_base[1] = gc_probe(gc_2, gc_nargs_2);
|
||||
gc_base[2] = gc_probe(gc_3, gc_nargs_3);
|
||||
|
||||
if (gc_base[0] || gc_base[1] || gc_base[2])
|
||||
return 0;
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
void __exit gc_exit(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
if (gc_base[i]) {
|
||||
for (j = 0; j < 5; j++)
|
||||
if (gc_base[i]->pads[0] & gc_status_bit[j])
|
||||
input_unregister_device(gc_base[i]->dev + j);
|
||||
parport_unregister_device(gc_base[i]->pd);
|
||||
}
|
||||
}
|
||||
|
||||
module_init(gc_init);
|
||||
module_exit(gc_exit);
|
||||
366
extra/linux-2.6.10/drivers/input/joystick/gf2k.c
Normal file
366
extra/linux-2.6.10/drivers/input/joystick/gf2k.c
Normal file
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* $Id: gf2k.c,v 1.19 2002/01/22 20:27:43 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1998-2001 Vojtech Pavlik
|
||||
*/
|
||||
|
||||
/*
|
||||
* Genius Flight 2000 joystick driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/gameport.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Genius Flight 2000 joystick driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define GF2K_START 400 /* The time we wait for the first bit [400 us] */
|
||||
#define GF2K_STROBE 40 /* The time we wait for the first bit [40 us] */
|
||||
#define GF2K_TIMEOUT 4 /* Wait for everything to settle [4 ms] */
|
||||
#define GF2K_LENGTH 80 /* Max number of triplets in a packet */
|
||||
#define GF2K_REFRESH HZ/50 /* Time between joystick polls [20 ms] */
|
||||
|
||||
/*
|
||||
* Genius joystick ids ...
|
||||
*/
|
||||
|
||||
#define GF2K_ID_G09 1
|
||||
#define GF2K_ID_F30D 2
|
||||
#define GF2K_ID_F30 3
|
||||
#define GF2K_ID_F31D 4
|
||||
#define GF2K_ID_F305 5
|
||||
#define GF2K_ID_F23P 6
|
||||
#define GF2K_ID_F31 7
|
||||
#define GF2K_ID_MAX 7
|
||||
|
||||
static char gf2k_length[] = { 40, 40, 40, 40, 40, 40, 40, 40 };
|
||||
static char gf2k_hat_to_axis[][2] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
|
||||
|
||||
static char *gf2k_names[] = {"", "Genius G-09D", "Genius F-30D", "Genius F-30", "Genius MaxFighter F-31D",
|
||||
"Genius F-30-5", "Genius Flight2000 F-23", "Genius F-31"};
|
||||
static unsigned char gf2k_hats[] = { 0, 2, 0, 0, 2, 0, 2, 0 };
|
||||
static unsigned char gf2k_axes[] = { 0, 2, 0, 0, 4, 0, 4, 0 };
|
||||
static unsigned char gf2k_joys[] = { 0, 0, 0, 0,10, 0, 8, 0 };
|
||||
static unsigned char gf2k_pads[] = { 0, 6, 0, 0, 0, 0, 0, 0 };
|
||||
static unsigned char gf2k_lens[] = { 0,18, 0, 0,18, 0,18, 0 };
|
||||
|
||||
static unsigned char gf2k_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_GAS, ABS_BRAKE };
|
||||
static short gf2k_btn_joy[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 };
|
||||
static short gf2k_btn_pad[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_START, BTN_SELECT };
|
||||
|
||||
|
||||
static short gf2k_seq_reset[] = { 240, 340, 0 };
|
||||
static short gf2k_seq_digital[] = { 590, 320, 860, 0 };
|
||||
|
||||
struct gf2k {
|
||||
struct gameport *gameport;
|
||||
struct timer_list timer;
|
||||
struct input_dev dev;
|
||||
int reads;
|
||||
int bads;
|
||||
int used;
|
||||
unsigned char id;
|
||||
unsigned char length;
|
||||
char phys[32];
|
||||
};
|
||||
|
||||
/*
|
||||
* gf2k_read_packet() reads a Genius Flight2000 packet.
|
||||
*/
|
||||
|
||||
static int gf2k_read_packet(struct gameport *gameport, int length, char *data)
|
||||
{
|
||||
unsigned char u, v;
|
||||
int i;
|
||||
unsigned int t, p;
|
||||
unsigned long flags;
|
||||
|
||||
t = gameport_time(gameport, GF2K_START);
|
||||
p = gameport_time(gameport, GF2K_STROBE);
|
||||
|
||||
i = 0;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
gameport_trigger(gameport);
|
||||
v = gameport_read(gameport);
|
||||
|
||||
while (t > 0 && i < length) {
|
||||
t--; u = v;
|
||||
v = gameport_read(gameport);
|
||||
if (v & ~u & 0x10) {
|
||||
data[i++] = v >> 5;
|
||||
t = p;
|
||||
}
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* gf2k_trigger_seq() initializes a Genius Flight2000 joystick
|
||||
* into digital mode.
|
||||
*/
|
||||
|
||||
static void gf2k_trigger_seq(struct gameport *gameport, short *seq)
|
||||
{
|
||||
|
||||
unsigned long flags;
|
||||
int i, t;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
i = 0;
|
||||
do {
|
||||
gameport_trigger(gameport);
|
||||
t = gameport_time(gameport, GF2K_TIMEOUT * 1000);
|
||||
while ((gameport_read(gameport) & 1) && t) t--;
|
||||
udelay(seq[i]);
|
||||
} while (seq[++i]);
|
||||
|
||||
gameport_trigger(gameport);
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* js_sw_get_bits() composes bits from the triplet buffer into a __u64.
|
||||
* Parameter 'pos' is bit number inside packet where to start at, 'num' is number
|
||||
* of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits
|
||||
* is number of bits per triplet.
|
||||
*/
|
||||
|
||||
#define GB(p,n,s) gf2k_get_bits(data, p, n, s)
|
||||
|
||||
static int gf2k_get_bits(unsigned char *buf, int pos, int num, int shift)
|
||||
{
|
||||
__u64 data = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num / 3 + 2; i++)
|
||||
data |= buf[pos / 3 + i] << (i * 3);
|
||||
data >>= pos % 3;
|
||||
data &= (1 << num) - 1;
|
||||
data <<= shift;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static void gf2k_read(struct gf2k *gf2k, unsigned char *data)
|
||||
{
|
||||
struct input_dev *dev = &gf2k->dev;
|
||||
int i, t;
|
||||
|
||||
for (i = 0; i < 4 && i < gf2k_axes[gf2k->id]; i++)
|
||||
input_report_abs(dev, gf2k_abs[i], GB(i<<3,8,0) | GB(i+46,1,8) | GB(i+50,1,9));
|
||||
|
||||
for (i = 0; i < 2 && i < gf2k_axes[gf2k->id] - 4; i++)
|
||||
input_report_abs(dev, gf2k_abs[i], GB(i*9+60,8,0) | GB(i+54,1,9));
|
||||
|
||||
t = GB(40,4,0);
|
||||
|
||||
for (i = 0; i < gf2k_hats[gf2k->id]; i++)
|
||||
input_report_abs(dev, ABS_HAT0X + i, gf2k_hat_to_axis[t][i]);
|
||||
|
||||
t = GB(44,2,0) | GB(32,8,2) | GB(78,2,10);
|
||||
|
||||
for (i = 0; i < gf2k_joys[gf2k->id]; i++)
|
||||
input_report_key(dev, gf2k_btn_joy[i], (t >> i) & 1);
|
||||
|
||||
for (i = 0; i < gf2k_pads[gf2k->id]; i++)
|
||||
input_report_key(dev, gf2k_btn_pad[i], (t >> i) & 1);
|
||||
|
||||
input_sync(dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* gf2k_timer() reads and analyzes Genius joystick data.
|
||||
*/
|
||||
|
||||
static void gf2k_timer(unsigned long private)
|
||||
{
|
||||
struct gf2k *gf2k = (void *) private;
|
||||
unsigned char data[GF2K_LENGTH];
|
||||
|
||||
gf2k->reads++;
|
||||
|
||||
if (gf2k_read_packet(gf2k->gameport, gf2k_length[gf2k->id], data) < gf2k_length[gf2k->id]) {
|
||||
gf2k->bads++;
|
||||
} else gf2k_read(gf2k, data);
|
||||
|
||||
mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH);
|
||||
}
|
||||
|
||||
static int gf2k_open(struct input_dev *dev)
|
||||
{
|
||||
struct gf2k *gf2k = dev->private;
|
||||
if (!gf2k->used++)
|
||||
mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gf2k_close(struct input_dev *dev)
|
||||
{
|
||||
struct gf2k *gf2k = dev->private;
|
||||
if (!--gf2k->used)
|
||||
del_timer(&gf2k->timer);
|
||||
}
|
||||
|
||||
/*
|
||||
* gf2k_connect() probes for Genius id joysticks.
|
||||
*/
|
||||
|
||||
static void gf2k_connect(struct gameport *gameport, struct gameport_dev *dev)
|
||||
{
|
||||
struct gf2k *gf2k;
|
||||
unsigned char data[GF2K_LENGTH];
|
||||
int i;
|
||||
|
||||
if (!(gf2k = kmalloc(sizeof(struct gf2k), GFP_KERNEL)))
|
||||
return;
|
||||
memset(gf2k, 0, sizeof(struct gf2k));
|
||||
|
||||
gameport->private = gf2k;
|
||||
|
||||
gf2k->gameport = gameport;
|
||||
init_timer(&gf2k->timer);
|
||||
gf2k->timer.data = (long) gf2k;
|
||||
gf2k->timer.function = gf2k_timer;
|
||||
|
||||
if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
|
||||
goto fail1;
|
||||
|
||||
gf2k_trigger_seq(gameport, gf2k_seq_reset);
|
||||
|
||||
msleep(GF2K_TIMEOUT);
|
||||
|
||||
gf2k_trigger_seq(gameport, gf2k_seq_digital);
|
||||
|
||||
msleep(GF2K_TIMEOUT);
|
||||
|
||||
if (gf2k_read_packet(gameport, GF2K_LENGTH, data) < 12)
|
||||
goto fail2;
|
||||
|
||||
if (!(gf2k->id = GB(7,2,0) | GB(3,3,2) | GB(0,3,5)))
|
||||
goto fail2;
|
||||
|
||||
#ifdef RESET_WORKS
|
||||
if ((gf2k->id != (GB(19,2,0) | GB(15,3,2) | GB(12,3,5))) ||
|
||||
(gf2k->id != (GB(31,2,0) | GB(27,3,2) | GB(24,3,5))))
|
||||
goto fail2;
|
||||
#else
|
||||
gf2k->id = 6;
|
||||
#endif
|
||||
|
||||
if (gf2k->id > GF2K_ID_MAX || !gf2k_axes[gf2k->id]) {
|
||||
printk(KERN_WARNING "gf2k.c: Not yet supported joystick on %s. [id: %d type:%s]\n",
|
||||
gameport->phys, gf2k->id, gf2k->id > GF2K_ID_MAX ? "Unknown" : gf2k_names[gf2k->id]);
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
sprintf(gf2k->phys, "%s/input0", gameport->phys);
|
||||
|
||||
gf2k->length = gf2k_lens[gf2k->id];
|
||||
|
||||
init_input_dev(&gf2k->dev);
|
||||
|
||||
gf2k->dev.private = gf2k;
|
||||
gf2k->dev.open = gf2k_open;
|
||||
gf2k->dev.close = gf2k_close;
|
||||
gf2k->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
|
||||
gf2k->dev.name = gf2k_names[gf2k->id];
|
||||
gf2k->dev.phys = gf2k->phys;
|
||||
gf2k->dev.id.bustype = BUS_GAMEPORT;
|
||||
gf2k->dev.id.vendor = GAMEPORT_ID_VENDOR_GENIUS;
|
||||
gf2k->dev.id.product = gf2k->id;
|
||||
gf2k->dev.id.version = 0x0100;
|
||||
|
||||
for (i = 0; i < gf2k_axes[gf2k->id]; i++)
|
||||
set_bit(gf2k_abs[i], gf2k->dev.absbit);
|
||||
|
||||
for (i = 0; i < gf2k_hats[gf2k->id]; i++) {
|
||||
set_bit(ABS_HAT0X + i, gf2k->dev.absbit);
|
||||
gf2k->dev.absmin[ABS_HAT0X + i] = -1;
|
||||
gf2k->dev.absmax[ABS_HAT0X + i] = 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < gf2k_joys[gf2k->id]; i++)
|
||||
set_bit(gf2k_btn_joy[i], gf2k->dev.keybit);
|
||||
|
||||
for (i = 0; i < gf2k_pads[gf2k->id]; i++)
|
||||
set_bit(gf2k_btn_pad[i], gf2k->dev.keybit);
|
||||
|
||||
gf2k_read_packet(gameport, gf2k->length, data);
|
||||
gf2k_read(gf2k, data);
|
||||
|
||||
for (i = 0; i < gf2k_axes[gf2k->id]; i++) {
|
||||
gf2k->dev.absmax[gf2k_abs[i]] = (i < 2) ? gf2k->dev.abs[gf2k_abs[i]] * 2 - 32 :
|
||||
gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32;
|
||||
gf2k->dev.absmin[gf2k_abs[i]] = 32;
|
||||
gf2k->dev.absfuzz[gf2k_abs[i]] = 8;
|
||||
gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0;
|
||||
}
|
||||
|
||||
input_register_device(&gf2k->dev);
|
||||
printk(KERN_INFO "input: %s on %s\n", gf2k_names[gf2k->id], gameport->phys);
|
||||
|
||||
return;
|
||||
fail2: gameport_close(gameport);
|
||||
fail1: kfree(gf2k);
|
||||
}
|
||||
|
||||
static void gf2k_disconnect(struct gameport *gameport)
|
||||
{
|
||||
struct gf2k *gf2k = gameport->private;
|
||||
input_unregister_device(&gf2k->dev);
|
||||
gameport_close(gameport);
|
||||
kfree(gf2k);
|
||||
}
|
||||
|
||||
static struct gameport_dev gf2k_dev = {
|
||||
.connect = gf2k_connect,
|
||||
.disconnect = gf2k_disconnect,
|
||||
};
|
||||
|
||||
int __init gf2k_init(void)
|
||||
{
|
||||
gameport_register_device(&gf2k_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit gf2k_exit(void)
|
||||
{
|
||||
gameport_unregister_device(&gf2k_dev);
|
||||
}
|
||||
|
||||
module_init(gf2k_init);
|
||||
module_exit(gf2k_exit);
|
||||
429
extra/linux-2.6.10/drivers/input/joystick/grip.c
Normal file
429
extra/linux-2.6.10/drivers/input/joystick/grip.c
Normal file
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
* $Id: grip.c,v 1.21 2002/01/22 20:27:57 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1998-2001 Vojtech Pavlik
|
||||
*/
|
||||
|
||||
/*
|
||||
* Gravis/Kensington GrIP protocol joystick and gamepad driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gameport.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Gravis GrIP protocol joystick driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define GRIP_MODE_GPP 1
|
||||
#define GRIP_MODE_BD 2
|
||||
#define GRIP_MODE_XT 3
|
||||
#define GRIP_MODE_DC 4
|
||||
|
||||
#define GRIP_LENGTH_GPP 24
|
||||
#define GRIP_STROBE_GPP 200 /* 200 us */
|
||||
#define GRIP_LENGTH_XT 4
|
||||
#define GRIP_STROBE_XT 64 /* 64 us */
|
||||
#define GRIP_MAX_CHUNKS_XT 10
|
||||
#define GRIP_MAX_BITS_XT 30
|
||||
|
||||
#define GRIP_REFRESH_TIME HZ/50 /* 20 ms */
|
||||
|
||||
struct grip {
|
||||
struct gameport *gameport;
|
||||
struct timer_list timer;
|
||||
struct input_dev dev[2];
|
||||
unsigned char mode[2];
|
||||
int used;
|
||||
int reads;
|
||||
int bads;
|
||||
char phys[2][32];
|
||||
};
|
||||
|
||||
static int grip_btn_gpp[] = { BTN_START, BTN_SELECT, BTN_TR2, BTN_Y, 0, BTN_TL2, BTN_A, BTN_B, BTN_X, 0, BTN_TL, BTN_TR, -1 };
|
||||
static int grip_btn_bd[] = { BTN_THUMB, BTN_THUMB2, BTN_TRIGGER, BTN_TOP, BTN_BASE, -1 };
|
||||
static int grip_btn_xt[] = { BTN_TRIGGER, BTN_THUMB, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_SELECT, BTN_START, BTN_MODE, -1 };
|
||||
static int grip_btn_dc[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, -1 };
|
||||
|
||||
static int grip_abs_gpp[] = { ABS_X, ABS_Y, -1 };
|
||||
static int grip_abs_bd[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
|
||||
static int grip_abs_xt[] = { ABS_X, ABS_Y, ABS_BRAKE, ABS_GAS, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, -1 };
|
||||
static int grip_abs_dc[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
|
||||
|
||||
static char *grip_name[] = { NULL, "Gravis GamePad Pro", "Gravis Blackhawk Digital",
|
||||
"Gravis Xterminator Digital", "Gravis Xterminator DualControl" };
|
||||
static int *grip_abs[] = { NULL, grip_abs_gpp, grip_abs_bd, grip_abs_xt, grip_abs_dc };
|
||||
static int *grip_btn[] = { NULL, grip_btn_gpp, grip_btn_bd, grip_btn_xt, grip_btn_dc };
|
||||
static char grip_anx[] = { 0, 0, 3, 5, 5 };
|
||||
static char grip_cen[] = { 0, 0, 2, 2, 4 };
|
||||
|
||||
/*
|
||||
* grip_gpp_read_packet() reads a Gravis GamePad Pro packet.
|
||||
*/
|
||||
|
||||
static int grip_gpp_read_packet(struct gameport *gameport, int shift, unsigned int *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned char u, v;
|
||||
unsigned int t;
|
||||
int i;
|
||||
|
||||
int strobe = gameport_time(gameport, GRIP_STROBE_GPP);
|
||||
|
||||
data[0] = 0;
|
||||
t = strobe;
|
||||
i = 0;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
v = gameport_read(gameport) >> shift;
|
||||
|
||||
do {
|
||||
t--;
|
||||
u = v; v = (gameport_read(gameport) >> shift) & 3;
|
||||
if (~v & u & 1) {
|
||||
data[0] |= (v >> 1) << i++;
|
||||
t = strobe;
|
||||
}
|
||||
} while (i < GRIP_LENGTH_GPP && t > 0);
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
if (i < GRIP_LENGTH_GPP) return -1;
|
||||
|
||||
for (i = 0; i < GRIP_LENGTH_GPP && (data[0] & 0xfe4210) ^ 0x7c0000; i++)
|
||||
data[0] = data[0] >> 1 | (data[0] & 1) << (GRIP_LENGTH_GPP - 1);
|
||||
|
||||
return -(i == GRIP_LENGTH_GPP);
|
||||
}
|
||||
|
||||
/*
|
||||
* grip_xt_read_packet() reads a Gravis Xterminator packet.
|
||||
*/
|
||||
|
||||
static int grip_xt_read_packet(struct gameport *gameport, int shift, unsigned int *data)
|
||||
{
|
||||
unsigned int i, j, buf, crc;
|
||||
unsigned char u, v, w;
|
||||
unsigned long flags;
|
||||
unsigned int t;
|
||||
char status;
|
||||
|
||||
int strobe = gameport_time(gameport, GRIP_STROBE_XT);
|
||||
|
||||
data[0] = data[1] = data[2] = data[3] = 0;
|
||||
status = buf = i = j = 0;
|
||||
t = strobe;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
v = w = (gameport_read(gameport) >> shift) & 3;
|
||||
|
||||
do {
|
||||
t--;
|
||||
u = (gameport_read(gameport) >> shift) & 3;
|
||||
|
||||
if (u ^ v) {
|
||||
|
||||
if ((u ^ v) & 1) {
|
||||
buf = (buf << 1) | (u >> 1);
|
||||
t = strobe;
|
||||
i++;
|
||||
} else
|
||||
|
||||
if ((((u ^ v) & (v ^ w)) >> 1) & ~(u | v | w) & 1) {
|
||||
if (i == 20) {
|
||||
crc = buf ^ (buf >> 7) ^ (buf >> 14);
|
||||
if (!((crc ^ (0x25cb9e70 >> ((crc >> 2) & 0x1c))) & 0xf)) {
|
||||
data[buf >> 18] = buf >> 4;
|
||||
status |= 1 << (buf >> 18);
|
||||
}
|
||||
j++;
|
||||
}
|
||||
t = strobe;
|
||||
buf = 0;
|
||||
i = 0;
|
||||
}
|
||||
w = v;
|
||||
v = u;
|
||||
}
|
||||
|
||||
} while (status != 0xf && i < GRIP_MAX_BITS_XT && j < GRIP_MAX_CHUNKS_XT && t > 0);
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
return -(status != 0xf);
|
||||
}
|
||||
|
||||
/*
|
||||
* grip_timer() repeatedly polls the joysticks and generates events.
|
||||
*/
|
||||
|
||||
static void grip_timer(unsigned long private)
|
||||
{
|
||||
struct grip *grip = (void*) private;
|
||||
unsigned int data[GRIP_LENGTH_XT];
|
||||
struct input_dev *dev;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
|
||||
dev = grip->dev + i;
|
||||
grip->reads++;
|
||||
|
||||
switch (grip->mode[i]) {
|
||||
|
||||
case GRIP_MODE_GPP:
|
||||
|
||||
if (grip_gpp_read_packet(grip->gameport, (i << 1) + 4, data)) {
|
||||
grip->bads++;
|
||||
break;
|
||||
}
|
||||
|
||||
input_report_abs(dev, ABS_X, ((*data >> 15) & 1) - ((*data >> 16) & 1));
|
||||
input_report_abs(dev, ABS_Y, ((*data >> 13) & 1) - ((*data >> 12) & 1));
|
||||
|
||||
for (j = 0; j < 12; j++)
|
||||
if (grip_btn_gpp[j])
|
||||
input_report_key(dev, grip_btn_gpp[j], (*data >> j) & 1);
|
||||
|
||||
break;
|
||||
|
||||
case GRIP_MODE_BD:
|
||||
|
||||
if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) {
|
||||
grip->bads++;
|
||||
break;
|
||||
}
|
||||
|
||||
input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f);
|
||||
input_report_abs(dev, ABS_Y, 63 - ((data[0] >> 8) & 0x3f));
|
||||
input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f);
|
||||
|
||||
input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1));
|
||||
input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1));
|
||||
|
||||
for (j = 0; j < 5; j++)
|
||||
input_report_key(dev, grip_btn_bd[j], (data[3] >> (j + 4)) & 1);
|
||||
|
||||
break;
|
||||
|
||||
case GRIP_MODE_XT:
|
||||
|
||||
if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) {
|
||||
grip->bads++;
|
||||
break;
|
||||
}
|
||||
|
||||
input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f);
|
||||
input_report_abs(dev, ABS_Y, 63 - ((data[0] >> 8) & 0x3f));
|
||||
input_report_abs(dev, ABS_BRAKE, (data[1] >> 2) & 0x3f);
|
||||
input_report_abs(dev, ABS_GAS, (data[1] >> 8) & 0x3f);
|
||||
input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f);
|
||||
|
||||
input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1));
|
||||
input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1));
|
||||
input_report_abs(dev, ABS_HAT1X, ((data[2] >> 5) & 1) - ((data[2] >> 4) & 1));
|
||||
input_report_abs(dev, ABS_HAT1Y, ((data[2] >> 6) & 1) - ((data[2] >> 7) & 1));
|
||||
|
||||
for (j = 0; j < 11; j++)
|
||||
input_report_key(dev, grip_btn_xt[j], (data[3] >> (j + 3)) & 1);
|
||||
break;
|
||||
|
||||
case GRIP_MODE_DC:
|
||||
|
||||
if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) {
|
||||
grip->bads++;
|
||||
break;
|
||||
}
|
||||
|
||||
input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f);
|
||||
input_report_abs(dev, ABS_Y, (data[0] >> 8) & 0x3f);
|
||||
input_report_abs(dev, ABS_RX, (data[1] >> 2) & 0x3f);
|
||||
input_report_abs(dev, ABS_RY, (data[1] >> 8) & 0x3f);
|
||||
input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f);
|
||||
|
||||
input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1));
|
||||
input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1));
|
||||
|
||||
for (j = 0; j < 9; j++)
|
||||
input_report_key(dev, grip_btn_dc[j], (data[3] >> (j + 3)) & 1);
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
|
||||
input_sync(dev);
|
||||
}
|
||||
|
||||
mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
|
||||
}
|
||||
|
||||
static int grip_open(struct input_dev *dev)
|
||||
{
|
||||
struct grip *grip = dev->private;
|
||||
if (!grip->used++)
|
||||
mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void grip_close(struct input_dev *dev)
|
||||
{
|
||||
struct grip *grip = dev->private;
|
||||
if (!--grip->used)
|
||||
del_timer(&grip->timer);
|
||||
}
|
||||
|
||||
static void grip_connect(struct gameport *gameport, struct gameport_dev *dev)
|
||||
{
|
||||
struct grip *grip;
|
||||
unsigned int data[GRIP_LENGTH_XT];
|
||||
int i, j, t;
|
||||
|
||||
if (!(grip = kmalloc(sizeof(struct grip), GFP_KERNEL)))
|
||||
return;
|
||||
memset(grip, 0, sizeof(struct grip));
|
||||
|
||||
gameport->private = grip;
|
||||
|
||||
grip->gameport = gameport;
|
||||
init_timer(&grip->timer);
|
||||
grip->timer.data = (long) grip;
|
||||
grip->timer.function = grip_timer;
|
||||
|
||||
if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
|
||||
goto fail1;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (!grip_gpp_read_packet(gameport, (i << 1) + 4, data)) {
|
||||
grip->mode[i] = GRIP_MODE_GPP;
|
||||
continue;
|
||||
}
|
||||
if (!grip_xt_read_packet(gameport, (i << 1) + 4, data)) {
|
||||
if (!(data[3] & 7)) {
|
||||
grip->mode[i] = GRIP_MODE_BD;
|
||||
continue;
|
||||
}
|
||||
if (!(data[2] & 0xf0)) {
|
||||
grip->mode[i] = GRIP_MODE_XT;
|
||||
continue;
|
||||
}
|
||||
grip->mode[i] = GRIP_MODE_DC;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!grip->mode[0] && !grip->mode[1])
|
||||
goto fail2;
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
if (grip->mode[i]) {
|
||||
|
||||
sprintf(grip->phys[i], "%s/input%d", gameport->phys, i);
|
||||
|
||||
grip->dev[i].private = grip;
|
||||
|
||||
grip->dev[i].open = grip_open;
|
||||
grip->dev[i].close = grip_close;
|
||||
|
||||
grip->dev[i].name = grip_name[grip->mode[i]];
|
||||
grip->dev[i].phys = grip->phys[i];
|
||||
grip->dev[i].id.bustype = BUS_GAMEPORT;
|
||||
grip->dev[i].id.vendor = GAMEPORT_ID_VENDOR_GRAVIS;
|
||||
grip->dev[i].id.product = grip->mode[i];
|
||||
grip->dev[i].id.version = 0x0100;
|
||||
|
||||
grip->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
|
||||
for (j = 0; (t = grip_abs[grip->mode[i]][j]) >= 0; j++) {
|
||||
|
||||
set_bit(t, grip->dev[i].absbit);
|
||||
|
||||
if (j < grip_cen[grip->mode[i]]) {
|
||||
grip->dev[i].absmin[t] = 14;
|
||||
grip->dev[i].absmax[t] = 52;
|
||||
grip->dev[i].absfuzz[t] = 1;
|
||||
grip->dev[i].absflat[t] = 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (j < grip_anx[grip->mode[i]]) {
|
||||
grip->dev[i].absmin[t] = 3;
|
||||
grip->dev[i].absmax[t] = 57;
|
||||
grip->dev[i].absfuzz[t] = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
grip->dev[i].absmin[t] = -1;
|
||||
grip->dev[i].absmax[t] = 1;
|
||||
}
|
||||
|
||||
for (j = 0; (t = grip_btn[grip->mode[i]][j]) >= 0; j++)
|
||||
if (t > 0)
|
||||
set_bit(t, grip->dev[i].keybit);
|
||||
|
||||
input_register_device(grip->dev + i);
|
||||
|
||||
printk(KERN_INFO "input: %s on %s\n",
|
||||
grip_name[grip->mode[i]], gameport->phys);
|
||||
}
|
||||
|
||||
return;
|
||||
fail2: gameport_close(gameport);
|
||||
fail1: kfree(grip);
|
||||
}
|
||||
|
||||
static void grip_disconnect(struct gameport *gameport)
|
||||
{
|
||||
int i;
|
||||
|
||||
struct grip *grip = gameport->private;
|
||||
for (i = 0; i < 2; i++)
|
||||
if (grip->mode[i])
|
||||
input_unregister_device(grip->dev + i);
|
||||
gameport_close(gameport);
|
||||
kfree(grip);
|
||||
}
|
||||
|
||||
static struct gameport_dev grip_dev = {
|
||||
.connect = grip_connect,
|
||||
.disconnect = grip_disconnect,
|
||||
};
|
||||
|
||||
int __init grip_init(void)
|
||||
{
|
||||
gameport_register_device(&grip_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit grip_exit(void)
|
||||
{
|
||||
gameport_unregister_device(&grip_dev);
|
||||
}
|
||||
|
||||
module_init(grip_init);
|
||||
module_exit(grip_exit);
|
||||
674
extra/linux-2.6.10/drivers/input/joystick/grip_mp.c
Normal file
674
extra/linux-2.6.10/drivers/input/joystick/grip_mp.c
Normal file
@@ -0,0 +1,674 @@
|
||||
/*
|
||||
* $Id: grip_mp.c,v 1.9 2002/07/20 19:28:45 bonnland Exp $
|
||||
*
|
||||
* Driver for the Gravis Grip Multiport, a gamepad "hub" that
|
||||
* connects up to four 9-pin digital gamepads/joysticks.
|
||||
* Driver tested on SMP and UP kernel versions 2.4.18-4 and 2.4.18-5.
|
||||
*
|
||||
* Thanks to Chris Gassib for helpful advice.
|
||||
*
|
||||
* Copyright (c) 2002 Brian Bonnlander, Bill Soudan
|
||||
* Copyright (c) 1998-2000 Vojtech Pavlik
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gameport.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/proc_fs.h>
|
||||
|
||||
MODULE_AUTHOR("Brian Bonnlander");
|
||||
MODULE_DESCRIPTION("Gravis Grip Multiport driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#ifdef GRIP_DEBUG
|
||||
#define dbg(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg)
|
||||
#else
|
||||
#define dbg(format, arg...) do {} while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Grip multiport state
|
||||
*/
|
||||
|
||||
struct grip_mp {
|
||||
struct gameport *gameport;
|
||||
struct timer_list timer;
|
||||
struct input_dev dev[4];
|
||||
int mode[4];
|
||||
int registered[4];
|
||||
int used;
|
||||
int reads;
|
||||
int bads;
|
||||
|
||||
/* individual gamepad states */
|
||||
int buttons[4];
|
||||
int xaxes[4];
|
||||
int yaxes[4];
|
||||
int dirty[4]; /* has the state been updated? */
|
||||
};
|
||||
|
||||
/*
|
||||
* Multiport packet interpretation
|
||||
*/
|
||||
|
||||
#define PACKET_FULL 0x80000000 /* packet is full */
|
||||
#define PACKET_IO_FAST 0x40000000 /* 3 bits per gameport read */
|
||||
#define PACKET_IO_SLOW 0x20000000 /* 1 bit per gameport read */
|
||||
#define PACKET_MP_MORE 0x04000000 /* multiport wants to send more */
|
||||
#define PACKET_MP_DONE 0x02000000 /* multiport done sending */
|
||||
|
||||
/*
|
||||
* Packet status code interpretation
|
||||
*/
|
||||
|
||||
#define IO_GOT_PACKET 0x0100 /* Got a packet */
|
||||
#define IO_MODE_FAST 0x0200 /* Used 3 data bits per gameport read */
|
||||
#define IO_SLOT_CHANGE 0x0800 /* Multiport physical slot status changed */
|
||||
#define IO_DONE 0x1000 /* Multiport is done sending packets */
|
||||
#define IO_RETRY 0x4000 /* Try again later to get packet */
|
||||
#define IO_RESET 0x8000 /* Force multiport to resend all packets */
|
||||
|
||||
/*
|
||||
* Gamepad configuration data. Other 9-pin digital joystick devices
|
||||
* may work with the multiport, so this may not be an exhaustive list!
|
||||
* Commodore 64 joystick remains untested.
|
||||
*/
|
||||
|
||||
#define GRIP_INIT_DELAY 2000 /* 2 ms */
|
||||
#define GRIP_REFRESH_TIME HZ/50 /* 20 ms */
|
||||
|
||||
#define GRIP_MODE_NONE 0
|
||||
#define GRIP_MODE_RESET 1
|
||||
#define GRIP_MODE_GP 2
|
||||
#define GRIP_MODE_C64 3
|
||||
|
||||
static int grip_btn_gp[] = { BTN_TR, BTN_TL, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, -1 };
|
||||
static int grip_btn_c64[] = { BTN_JOYSTICK, -1 };
|
||||
|
||||
static int grip_abs_gp[] = { ABS_X, ABS_Y, -1 };
|
||||
static int grip_abs_c64[] = { ABS_X, ABS_Y, -1 };
|
||||
|
||||
static int *grip_abs[] = { NULL, NULL, grip_abs_gp, grip_abs_c64 };
|
||||
static int *grip_btn[] = { NULL, NULL, grip_btn_gp, grip_btn_c64 };
|
||||
|
||||
static char *grip_name[] = { NULL, NULL, "Gravis Grip Pad", "Commodore 64 Joystick" };
|
||||
|
||||
static const int init_seq[] = {
|
||||
1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
|
||||
1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1 };
|
||||
|
||||
/* Maps multiport directional values to X,Y axis values (each axis encoded in 3 bits) */
|
||||
|
||||
static int axis_map[] = { 5, 9, 1, 5, 6, 10, 2, 6, 4, 8, 0, 4, 5, 9, 1, 5 };
|
||||
|
||||
static void register_slot(int i, struct grip_mp *grip);
|
||||
|
||||
/*
|
||||
* Returns whether an odd or even number of bits are on in pkt.
|
||||
*/
|
||||
|
||||
static int bit_parity(u32 pkt)
|
||||
{
|
||||
int x = pkt ^ (pkt >> 16);
|
||||
x ^= x >> 8;
|
||||
x ^= x >> 4;
|
||||
x ^= x >> 2;
|
||||
x ^= x >> 1;
|
||||
return x & 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Poll gameport; return true if all bits set in 'onbits' are on and
|
||||
* all bits set in 'offbits' are off.
|
||||
*/
|
||||
|
||||
static inline int poll_until(u8 onbits, u8 offbits, int u_sec, struct gameport* gp, u8 *data)
|
||||
{
|
||||
int i, nloops;
|
||||
|
||||
nloops = gameport_time(gp, u_sec);
|
||||
for (i = 0; i < nloops; i++) {
|
||||
*data = gameport_read(gp);
|
||||
if ((*data & onbits) == onbits &&
|
||||
(~(*data) & offbits) == offbits)
|
||||
return 1;
|
||||
}
|
||||
dbg("gameport timed out after %d microseconds.\n", u_sec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets a 28-bit packet from the multiport.
|
||||
*
|
||||
* After getting a packet successfully, commands encoded by sendcode may
|
||||
* be sent to the multiport.
|
||||
*
|
||||
* The multiport clock value is reflected in gameport bit B4.
|
||||
*
|
||||
* Returns a packet status code indicating whether packet is valid, the transfer
|
||||
* mode, and any error conditions.
|
||||
*
|
||||
* sendflags: current I/O status
|
||||
* sendcode: data to send to the multiport if sendflags is nonzero
|
||||
*/
|
||||
|
||||
static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet)
|
||||
{
|
||||
u8 raw_data; /* raw data from gameport */
|
||||
u8 data_mask; /* packet data bits from raw_data */
|
||||
u32 pkt; /* packet temporary storage */
|
||||
int bits_per_read; /* num packet bits per gameport read */
|
||||
int portvals = 0; /* used for port value sanity check */
|
||||
int i;
|
||||
|
||||
/* Gameport bits B0, B4, B5 should first be off, then B4 should come on. */
|
||||
|
||||
*packet = 0;
|
||||
raw_data = gameport_read(gameport);
|
||||
if (raw_data & 1)
|
||||
return IO_RETRY;
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
raw_data = gameport_read(gameport);
|
||||
portvals |= 1 << ((raw_data >> 4) & 3); /* Demux B4, B5 */
|
||||
}
|
||||
|
||||
if (portvals == 1) { /* B4, B5 off */
|
||||
raw_data = gameport_read(gameport);
|
||||
portvals = raw_data & 0xf0;
|
||||
|
||||
if (raw_data & 0x31)
|
||||
return IO_RESET;
|
||||
gameport_trigger(gameport);
|
||||
|
||||
if (!poll_until(0x10, 0, 308, gameport, &raw_data))
|
||||
return IO_RESET;
|
||||
} else
|
||||
return IO_RETRY;
|
||||
|
||||
/* Determine packet transfer mode and prepare for packet construction. */
|
||||
|
||||
if (raw_data & 0x20) { /* 3 data bits/read */
|
||||
portvals |= raw_data >> 4; /* Compare B4-B7 before & after trigger */
|
||||
|
||||
if (portvals != 0xb)
|
||||
return 0;
|
||||
data_mask = 7;
|
||||
bits_per_read = 3;
|
||||
pkt = (PACKET_FULL | PACKET_IO_FAST) >> 28;
|
||||
} else { /* 1 data bit/read */
|
||||
data_mask = 1;
|
||||
bits_per_read = 1;
|
||||
pkt = (PACKET_FULL | PACKET_IO_SLOW) >> 28;
|
||||
}
|
||||
|
||||
/* Construct a packet. Final data bits must be zero. */
|
||||
|
||||
while (1) {
|
||||
if (!poll_until(0, 0x10, 77, gameport, &raw_data))
|
||||
return IO_RESET;
|
||||
raw_data = (raw_data >> 5) & data_mask;
|
||||
|
||||
if (pkt & PACKET_FULL)
|
||||
break;
|
||||
pkt = (pkt << bits_per_read) | raw_data;
|
||||
|
||||
if (!poll_until(0x10, 0, 77, gameport, &raw_data))
|
||||
return IO_RESET;
|
||||
}
|
||||
|
||||
if (raw_data)
|
||||
return IO_RESET;
|
||||
|
||||
/* If 3 bits/read used, drop from 30 bits to 28. */
|
||||
|
||||
if (bits_per_read == 3) {
|
||||
pkt = (pkt & 0xffff0000) | ((pkt << 1) & 0xffff);
|
||||
pkt = (pkt >> 2) | 0xf0000000;
|
||||
}
|
||||
|
||||
if (bit_parity(pkt) == 1)
|
||||
return IO_RESET;
|
||||
|
||||
/* Acknowledge packet receipt */
|
||||
|
||||
if (!poll_until(0x30, 0, 77, gameport, &raw_data))
|
||||
return IO_RESET;
|
||||
|
||||
raw_data = gameport_read(gameport);
|
||||
|
||||
if (raw_data & 1)
|
||||
return IO_RESET;
|
||||
|
||||
gameport_trigger(gameport);
|
||||
|
||||
if (!poll_until(0, 0x20, 77, gameport, &raw_data))
|
||||
return IO_RESET;
|
||||
|
||||
/* Return if we just wanted the packet or multiport wants to send more */
|
||||
|
||||
*packet = pkt;
|
||||
if ((sendflags == 0) || ((sendflags & IO_RETRY) && !(pkt & PACKET_MP_DONE)))
|
||||
return IO_GOT_PACKET;
|
||||
|
||||
if (pkt & PACKET_MP_MORE)
|
||||
return IO_GOT_PACKET | IO_RETRY;
|
||||
|
||||
/* Multiport is done sending packets and is ready to receive data */
|
||||
|
||||
if (!poll_until(0x20, 0, 77, gameport, &raw_data))
|
||||
return IO_GOT_PACKET | IO_RESET;
|
||||
|
||||
raw_data = gameport_read(gameport);
|
||||
if (raw_data & 1)
|
||||
return IO_GOT_PACKET | IO_RESET;
|
||||
|
||||
/* Trigger gameport based on bits in sendcode */
|
||||
|
||||
gameport_trigger(gameport);
|
||||
do {
|
||||
if (!poll_until(0x20, 0x10, 116, gameport, &raw_data))
|
||||
return IO_GOT_PACKET | IO_RESET;
|
||||
|
||||
if (!poll_until(0x30, 0, 193, gameport, &raw_data))
|
||||
return IO_GOT_PACKET | IO_RESET;
|
||||
|
||||
if (raw_data & 1)
|
||||
return IO_GOT_PACKET | IO_RESET;
|
||||
|
||||
if (sendcode & 1)
|
||||
gameport_trigger(gameport);
|
||||
|
||||
sendcode >>= 1;
|
||||
} while (sendcode);
|
||||
|
||||
return IO_GOT_PACKET | IO_MODE_FAST;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disables and restores interrupts for mp_io(), which does the actual I/O.
|
||||
*/
|
||||
|
||||
static int multiport_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet)
|
||||
{
|
||||
int status;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
status = mp_io(gameport, sendflags, sendcode, packet);
|
||||
local_irq_restore(flags);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Puts multiport into digital mode. Multiport LED turns green.
|
||||
*
|
||||
* Returns true if a valid digital packet was received, false otherwise.
|
||||
*/
|
||||
|
||||
static int dig_mode_start(struct gameport *gameport, u32 *packet)
|
||||
{
|
||||
int i, seq_len = sizeof(init_seq)/sizeof(int);
|
||||
int flags, tries = 0, bads = 0;
|
||||
|
||||
for (i = 0; i < seq_len; i++) { /* Send magic sequence */
|
||||
if (init_seq[i])
|
||||
gameport_trigger(gameport);
|
||||
udelay(GRIP_INIT_DELAY);
|
||||
}
|
||||
|
||||
for (i = 0; i < 16; i++) /* Wait for multiport to settle */
|
||||
udelay(GRIP_INIT_DELAY);
|
||||
|
||||
while (tries < 64 && bads < 8) { /* Reset multiport and try getting a packet */
|
||||
|
||||
flags = multiport_io(gameport, IO_RESET, 0x27, packet);
|
||||
|
||||
if (flags & IO_MODE_FAST)
|
||||
return 1;
|
||||
|
||||
if (flags & IO_RETRY)
|
||||
tries++;
|
||||
else
|
||||
bads++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Packet structure: B0-B15 => gamepad state
|
||||
* B16-B20 => gamepad device type
|
||||
* B21-B24 => multiport slot index (1-4)
|
||||
*
|
||||
* Known device types: 0x1f (grip pad), 0x0 (no device). Others may exist.
|
||||
*
|
||||
* Returns the packet status.
|
||||
*/
|
||||
|
||||
static int get_and_decode_packet(struct grip_mp *grip, int flags)
|
||||
{
|
||||
u32 packet;
|
||||
int joytype = 0;
|
||||
int slot = 0;
|
||||
|
||||
/* Get a packet and check for validity */
|
||||
|
||||
flags &= IO_RESET | IO_RETRY;
|
||||
flags = multiport_io(grip->gameport, flags, 0, &packet);
|
||||
grip->reads++;
|
||||
|
||||
if (packet & PACKET_MP_DONE)
|
||||
flags |= IO_DONE;
|
||||
|
||||
if (flags && !(flags & IO_GOT_PACKET)) {
|
||||
grip->bads++;
|
||||
return flags;
|
||||
}
|
||||
|
||||
/* Ignore non-gamepad packets, e.g. multiport hardware version */
|
||||
|
||||
slot = ((packet >> 21) & 0xf) - 1;
|
||||
if ((slot < 0) || (slot > 3))
|
||||
return flags;
|
||||
|
||||
/*
|
||||
* Handle "reset" packets, which occur at startup, and when gamepads
|
||||
* are removed or plugged in. May contain configuration of a new gamepad.
|
||||
*/
|
||||
|
||||
joytype = (packet >> 16) & 0x1f;
|
||||
if (!joytype) {
|
||||
|
||||
if (grip->registered[slot]) {
|
||||
printk(KERN_INFO "grip_mp: removing %s, slot %d\n",
|
||||
grip_name[grip->mode[slot]], slot);
|
||||
input_unregister_device(grip->dev + slot);
|
||||
grip->registered[slot] = 0;
|
||||
}
|
||||
dbg("Reset: grip multiport slot %d\n", slot);
|
||||
grip->mode[slot] = GRIP_MODE_RESET;
|
||||
flags |= IO_SLOT_CHANGE;
|
||||
return flags;
|
||||
}
|
||||
|
||||
/* Interpret a grip pad packet */
|
||||
|
||||
if (joytype == 0x1f) {
|
||||
|
||||
int dir = (packet >> 8) & 0xf; /* eight way directional value */
|
||||
grip->buttons[slot] = (~packet) & 0xff;
|
||||
grip->yaxes[slot] = ((axis_map[dir] >> 2) & 3) - 1;
|
||||
grip->xaxes[slot] = (axis_map[dir] & 3) - 1;
|
||||
grip->dirty[slot] = 1;
|
||||
|
||||
if (grip->mode[slot] == GRIP_MODE_RESET)
|
||||
flags |= IO_SLOT_CHANGE;
|
||||
|
||||
grip->mode[slot] = GRIP_MODE_GP;
|
||||
|
||||
if (!grip->registered[slot]) {
|
||||
dbg("New Grip pad in multiport slot %d.\n", slot);
|
||||
register_slot(slot, grip);
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
/* Handle non-grip device codes. For now, just print diagnostics. */
|
||||
|
||||
{
|
||||
static int strange_code = 0;
|
||||
if (strange_code != joytype) {
|
||||
printk(KERN_INFO "Possible non-grip pad/joystick detected.\n");
|
||||
printk(KERN_INFO "Got joy type 0x%x and packet 0x%x.\n", joytype, packet);
|
||||
strange_code = joytype;
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if all multiport slot states appear valid.
|
||||
*/
|
||||
|
||||
static int slots_valid(struct grip_mp *grip)
|
||||
{
|
||||
int flags, slot, invalid = 0, active = 0;
|
||||
|
||||
flags = get_and_decode_packet(grip, 0);
|
||||
if (!(flags & IO_GOT_PACKET))
|
||||
return 0;
|
||||
|
||||
for (slot = 0; slot < 4; slot++) {
|
||||
if (grip->mode[slot] == GRIP_MODE_RESET)
|
||||
invalid = 1;
|
||||
if (grip->mode[slot] != GRIP_MODE_NONE)
|
||||
active = 1;
|
||||
}
|
||||
|
||||
/* Return true if no active slot but multiport sent all its data */
|
||||
if (!active)
|
||||
return (flags & IO_DONE) ? 1 : 0;
|
||||
|
||||
/* Return false if invalid device code received */
|
||||
return invalid ? 0 : 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns whether the multiport was placed into digital mode and
|
||||
* able to communicate its state successfully.
|
||||
*/
|
||||
|
||||
static int multiport_init(struct grip_mp *grip)
|
||||
{
|
||||
int dig_mode, initialized = 0, tries = 0;
|
||||
u32 packet;
|
||||
|
||||
dig_mode = dig_mode_start(grip->gameport, &packet);
|
||||
while (!dig_mode && tries < 4) {
|
||||
dig_mode = dig_mode_start(grip->gameport, &packet);
|
||||
tries++;
|
||||
}
|
||||
|
||||
if (dig_mode)
|
||||
dbg("multiport_init(): digital mode achieved.\n");
|
||||
else {
|
||||
dbg("multiport_init(): unable to achieve digital mode.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get packets, store multiport state, and check state's validity */
|
||||
for (tries = 0; tries < 4096; tries++) {
|
||||
if ( slots_valid(grip) ) {
|
||||
initialized = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dbg("multiport_init(): initialized == %d\n", initialized);
|
||||
return initialized;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reports joystick state to the linux input layer.
|
||||
*/
|
||||
|
||||
static void report_slot(struct grip_mp *grip, int slot)
|
||||
{
|
||||
struct input_dev *dev = &(grip->dev[slot]);
|
||||
int i, buttons = grip->buttons[slot];
|
||||
|
||||
/* Store button states with linux input driver */
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
input_report_key(dev, grip_btn_gp[i], (buttons >> i) & 1);
|
||||
|
||||
/* Store axis states with linux driver */
|
||||
|
||||
input_report_abs(dev, ABS_X, grip->xaxes[slot]);
|
||||
input_report_abs(dev, ABS_Y, grip->yaxes[slot]);
|
||||
|
||||
/* Tell the receiver of the events to process them */
|
||||
|
||||
input_sync(dev);
|
||||
|
||||
grip->dirty[slot] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the multiport state.
|
||||
*/
|
||||
|
||||
static void get_and_report_mp_state(struct grip_mp *grip)
|
||||
{
|
||||
int i, npkts, flags;
|
||||
|
||||
for (npkts = 0; npkts < 4; npkts++) {
|
||||
flags = IO_RETRY;
|
||||
for (i = 0; i < 32; i++) {
|
||||
flags = get_and_decode_packet(grip, flags);
|
||||
if ((flags & IO_GOT_PACKET) || !(flags & IO_RETRY))
|
||||
break;
|
||||
}
|
||||
if (flags & IO_DONE)
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
if (grip->dirty[i])
|
||||
report_slot(grip, i);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when a joystick device file is opened
|
||||
*/
|
||||
|
||||
static int grip_open(struct input_dev *dev)
|
||||
{
|
||||
struct grip_mp *grip = dev->private;
|
||||
if (!grip->used++)
|
||||
mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when a joystick device file is closed
|
||||
*/
|
||||
|
||||
static void grip_close(struct input_dev *dev)
|
||||
{
|
||||
struct grip_mp *grip = dev->private;
|
||||
if (!--grip->used)
|
||||
del_timer(&grip->timer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tell the linux input layer about a newly plugged-in gamepad.
|
||||
*/
|
||||
|
||||
static void register_slot(int slot, struct grip_mp *grip)
|
||||
{
|
||||
int j, t;
|
||||
|
||||
grip->dev[slot].private = grip;
|
||||
grip->dev[slot].open = grip_open;
|
||||
grip->dev[slot].close = grip_close;
|
||||
grip->dev[slot].name = grip_name[grip->mode[slot]];
|
||||
grip->dev[slot].id.bustype = BUS_GAMEPORT;
|
||||
grip->dev[slot].id.vendor = GAMEPORT_ID_VENDOR_GRAVIS;
|
||||
grip->dev[slot].id.product = 0x0100 + grip->mode[slot];
|
||||
grip->dev[slot].id.version = 0x0100;
|
||||
grip->dev[slot].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
|
||||
for (j = 0; (t = grip_abs[grip->mode[slot]][j]) >= 0; j++) {
|
||||
set_bit(t, grip->dev[slot].absbit);
|
||||
grip->dev[slot].absmin[t] = -1;
|
||||
grip->dev[slot].absmax[t] = 1;
|
||||
}
|
||||
|
||||
for (j = 0; (t = grip_btn[grip->mode[slot]][j]) >= 0; j++)
|
||||
if (t > 0)
|
||||
set_bit(t, grip->dev[slot].keybit);
|
||||
|
||||
input_register_device(grip->dev + slot);
|
||||
grip->registered[slot] = 1;
|
||||
|
||||
if (grip->dirty[slot]) /* report initial state, if any */
|
||||
report_slot(grip, slot);
|
||||
|
||||
printk(KERN_INFO "grip_mp: added %s, slot %d\n",
|
||||
grip_name[grip->mode[slot]], slot);
|
||||
}
|
||||
|
||||
/*
|
||||
* Repeatedly polls the multiport and generates events.
|
||||
*/
|
||||
|
||||
static void grip_timer(unsigned long private)
|
||||
{
|
||||
struct grip_mp *grip = (void*) private;
|
||||
get_and_report_mp_state(grip);
|
||||
mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
|
||||
}
|
||||
|
||||
static void grip_connect(struct gameport *gameport, struct gameport_dev *dev)
|
||||
{
|
||||
struct grip_mp *grip;
|
||||
|
||||
if (!(grip = kmalloc(sizeof(struct grip_mp), GFP_KERNEL)))
|
||||
return;
|
||||
memset(grip, 0, sizeof(struct grip_mp));
|
||||
gameport->private = grip;
|
||||
grip->gameport = gameport;
|
||||
init_timer(&grip->timer);
|
||||
grip->timer.data = (long) grip;
|
||||
grip->timer.function = grip_timer;
|
||||
|
||||
if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
|
||||
goto fail1;
|
||||
if (!multiport_init(grip))
|
||||
goto fail2;
|
||||
if (!grip->mode[0] && !grip->mode[1] && /* nothing plugged in */
|
||||
!grip->mode[2] && !grip->mode[3])
|
||||
goto fail2;
|
||||
return;
|
||||
|
||||
fail2: gameport_close(gameport);
|
||||
fail1: kfree(grip);
|
||||
}
|
||||
|
||||
static void grip_disconnect(struct gameport *gameport)
|
||||
{
|
||||
int i;
|
||||
|
||||
struct grip_mp *grip = gameport->private;
|
||||
for (i = 0; i < 4; i++)
|
||||
if (grip->registered[i])
|
||||
input_unregister_device(grip->dev + i);
|
||||
gameport_close(gameport);
|
||||
kfree(grip);
|
||||
}
|
||||
|
||||
static struct gameport_dev grip_dev = {
|
||||
.connect = grip_connect,
|
||||
.disconnect = grip_disconnect,
|
||||
};
|
||||
|
||||
static int grip_init(void)
|
||||
{
|
||||
gameport_register_device(&grip_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void grip_exit(void)
|
||||
{
|
||||
gameport_unregister_device(&grip_dev);
|
||||
}
|
||||
|
||||
module_init(grip_init);
|
||||
module_exit(grip_exit);
|
||||
286
extra/linux-2.6.10/drivers/input/joystick/guillemot.c
Normal file
286
extra/linux-2.6.10/drivers/input/joystick/guillemot.c
Normal file
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* $Id: guillemot.c,v 1.10 2002/01/22 20:28:12 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 2001 Vojtech Pavlik
|
||||
*/
|
||||
|
||||
/*
|
||||
* Guillemot Digital Interface Protocol driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/gameport.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Guillemot Digital joystick driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define GUILLEMOT_MAX_START 600 /* 600 us */
|
||||
#define GUILLEMOT_MAX_STROBE 60 /* 60 us */
|
||||
#define GUILLEMOT_MAX_LENGTH 17 /* 17 bytes */
|
||||
#define GUILLEMOT_REFRESH_TIME HZ/50 /* 20 ms */
|
||||
|
||||
static short guillemot_abs_pad[] =
|
||||
{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, -1 };
|
||||
|
||||
static short guillemot_btn_pad[] =
|
||||
{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_MODE, BTN_SELECT, -1 };
|
||||
|
||||
static struct {
|
||||
int x;
|
||||
int y;
|
||||
} guillemot_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
|
||||
|
||||
struct guillemot_type {
|
||||
unsigned char id;
|
||||
short *abs;
|
||||
short *btn;
|
||||
int hat;
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct guillemot {
|
||||
struct gameport *gameport;
|
||||
struct input_dev dev;
|
||||
struct timer_list timer;
|
||||
int used;
|
||||
int bads;
|
||||
int reads;
|
||||
struct guillemot_type *type;
|
||||
unsigned char length;
|
||||
char phys[32];
|
||||
};
|
||||
|
||||
static struct guillemot_type guillemot_type[] = {
|
||||
{ 0x00, guillemot_abs_pad, guillemot_btn_pad, 1, "Guillemot Pad" },
|
||||
{ 0 }};
|
||||
|
||||
/*
|
||||
* guillemot_read_packet() reads Guillemot joystick data.
|
||||
*/
|
||||
|
||||
static int guillemot_read_packet(struct gameport *gameport, u8 *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned char u, v;
|
||||
unsigned int t, s;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < GUILLEMOT_MAX_LENGTH; i++)
|
||||
data[i] = 0;
|
||||
|
||||
i = 0;
|
||||
t = gameport_time(gameport, GUILLEMOT_MAX_START);
|
||||
s = gameport_time(gameport, GUILLEMOT_MAX_STROBE);
|
||||
|
||||
local_irq_save(flags);
|
||||
gameport_trigger(gameport);
|
||||
v = gameport_read(gameport);
|
||||
|
||||
while (t > 0 && i < GUILLEMOT_MAX_LENGTH * 8) {
|
||||
t--;
|
||||
u = v; v = gameport_read(gameport);
|
||||
if (v & ~u & 0x10) {
|
||||
data[i >> 3] |= ((v >> 5) & 1) << (i & 7);
|
||||
i++;
|
||||
t = s;
|
||||
}
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* guillemot_timer() reads and analyzes Guillemot joystick data.
|
||||
*/
|
||||
|
||||
static void guillemot_timer(unsigned long private)
|
||||
{
|
||||
struct guillemot *guillemot = (struct guillemot *) private;
|
||||
struct input_dev *dev = &guillemot->dev;
|
||||
u8 data[GUILLEMOT_MAX_LENGTH];
|
||||
int i;
|
||||
|
||||
guillemot->reads++;
|
||||
|
||||
if (guillemot_read_packet(guillemot->gameport, data) != GUILLEMOT_MAX_LENGTH * 8 ||
|
||||
data[0] != 0x55 || data[16] != 0xaa) {
|
||||
guillemot->bads++;
|
||||
} else {
|
||||
|
||||
for (i = 0; i < 6 && guillemot->type->abs[i] >= 0; i++)
|
||||
input_report_abs(dev, guillemot->type->abs[i], data[i + 5]);
|
||||
|
||||
if (guillemot->type->hat) {
|
||||
input_report_abs(dev, ABS_HAT0X, guillemot_hat_to_axis[data[4] >> 4].x);
|
||||
input_report_abs(dev, ABS_HAT0Y, guillemot_hat_to_axis[data[4] >> 4].y);
|
||||
}
|
||||
|
||||
for (i = 0; i < 16 && guillemot->type->btn[i] >= 0; i++)
|
||||
input_report_key(dev, guillemot->type->btn[i], (data[2 + (i >> 3)] >> (i & 7)) & 1);
|
||||
}
|
||||
|
||||
input_sync(dev);
|
||||
|
||||
mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME);
|
||||
}
|
||||
|
||||
/*
|
||||
* guillemot_open() is a callback from the input open routine.
|
||||
*/
|
||||
|
||||
static int guillemot_open(struct input_dev *dev)
|
||||
{
|
||||
struct guillemot *guillemot = dev->private;
|
||||
if (!guillemot->used++)
|
||||
mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* guillemot_close() is a callback from the input close routine.
|
||||
*/
|
||||
|
||||
static void guillemot_close(struct input_dev *dev)
|
||||
{
|
||||
struct guillemot *guillemot = dev->private;
|
||||
if (!--guillemot->used)
|
||||
del_timer(&guillemot->timer);
|
||||
}
|
||||
|
||||
/*
|
||||
* guillemot_connect() probes for Guillemot joysticks.
|
||||
*/
|
||||
|
||||
static void guillemot_connect(struct gameport *gameport, struct gameport_dev *dev)
|
||||
{
|
||||
struct guillemot *guillemot;
|
||||
u8 data[GUILLEMOT_MAX_LENGTH];
|
||||
int i, t;
|
||||
|
||||
if (!(guillemot = kmalloc(sizeof(struct guillemot), GFP_KERNEL)))
|
||||
return;
|
||||
memset(guillemot, 0, sizeof(struct guillemot));
|
||||
|
||||
gameport->private = guillemot;
|
||||
|
||||
guillemot->gameport = gameport;
|
||||
init_timer(&guillemot->timer);
|
||||
guillemot->timer.data = (long) guillemot;
|
||||
guillemot->timer.function = guillemot_timer;
|
||||
|
||||
if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
|
||||
goto fail1;
|
||||
|
||||
i = guillemot_read_packet(gameport, data);
|
||||
|
||||
if (i != GUILLEMOT_MAX_LENGTH * 8 || data[0] != 0x55 || data[16] != 0xaa)
|
||||
goto fail2;
|
||||
|
||||
for (i = 0; guillemot_type[i].name; i++)
|
||||
if (guillemot_type[i].id == data[11])
|
||||
break;
|
||||
|
||||
if (!guillemot_type[i].name) {
|
||||
printk(KERN_WARNING "guillemot.c: Unknown joystick on %s. [ %02x%02x:%04x, ver %d.%02d ]\n",
|
||||
gameport->phys, data[12], data[13], data[11], data[14], data[15]);
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
sprintf(guillemot->phys, "%s/input0", gameport->phys);
|
||||
|
||||
guillemot->type = guillemot_type + i;
|
||||
|
||||
guillemot->dev.private = guillemot;
|
||||
guillemot->dev.open = guillemot_open;
|
||||
guillemot->dev.close = guillemot_close;
|
||||
|
||||
guillemot->dev.name = guillemot_type[i].name;
|
||||
guillemot->dev.phys = guillemot->phys;
|
||||
guillemot->dev.id.bustype = BUS_GAMEPORT;
|
||||
guillemot->dev.id.vendor = GAMEPORT_ID_VENDOR_GUILLEMOT;
|
||||
guillemot->dev.id.product = guillemot_type[i].id;
|
||||
guillemot->dev.id.version = (int)data[14] << 8 | data[15];
|
||||
|
||||
guillemot->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
|
||||
for (i = 0; (t = guillemot->type->abs[i]) >= 0; i++) {
|
||||
set_bit(t, guillemot->dev.absbit);
|
||||
guillemot->dev.absmin[t] = 0;
|
||||
guillemot->dev.absmax[t] = 255;
|
||||
}
|
||||
|
||||
if (guillemot->type->hat)
|
||||
for (i = 0; i < 2; i++) {
|
||||
t = ABS_HAT0X + i;
|
||||
set_bit(t, guillemot->dev.absbit);
|
||||
guillemot->dev.absmin[t] = -1;
|
||||
guillemot->dev.absmax[t] = 1;
|
||||
}
|
||||
|
||||
for (i = 0; (t = guillemot->type->btn[i]) >= 0; i++)
|
||||
set_bit(t, guillemot->dev.keybit);
|
||||
|
||||
input_register_device(&guillemot->dev);
|
||||
printk(KERN_INFO "input: %s ver %d.%02d on %s\n",
|
||||
guillemot->type->name, data[14], data[15], gameport->phys);
|
||||
|
||||
return;
|
||||
fail2: gameport_close(gameport);
|
||||
fail1: kfree(guillemot);
|
||||
}
|
||||
|
||||
static void guillemot_disconnect(struct gameport *gameport)
|
||||
{
|
||||
struct guillemot *guillemot = gameport->private;
|
||||
printk(KERN_INFO "guillemot.c: Failed %d reads out of %d on %s\n", guillemot->reads, guillemot->bads, guillemot->phys);
|
||||
input_unregister_device(&guillemot->dev);
|
||||
gameport_close(gameport);
|
||||
kfree(guillemot);
|
||||
}
|
||||
|
||||
static struct gameport_dev guillemot_dev = {
|
||||
.connect = guillemot_connect,
|
||||
.disconnect = guillemot_disconnect,
|
||||
};
|
||||
|
||||
int __init guillemot_init(void)
|
||||
{
|
||||
gameport_register_device(&guillemot_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit guillemot_exit(void)
|
||||
{
|
||||
gameport_unregister_device(&guillemot_dev);
|
||||
}
|
||||
|
||||
module_init(guillemot_init);
|
||||
module_exit(guillemot_exit);
|
||||
31
extra/linux-2.6.10/drivers/input/joystick/iforce/Kconfig
Normal file
31
extra/linux-2.6.10/drivers/input/joystick/iforce/Kconfig
Normal file
@@ -0,0 +1,31 @@
|
||||
#
|
||||
# I-Force driver configuration
|
||||
#
|
||||
config JOYSTICK_IFORCE
|
||||
tristate "I-Force devices"
|
||||
depends on INPUT && INPUT_JOYSTICK
|
||||
help
|
||||
Say Y here if you have an I-Force joystick or steering wheel
|
||||
|
||||
You also must choose at least one of the two options below.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called iforce.
|
||||
|
||||
config JOYSTICK_IFORCE_USB
|
||||
bool "I-Force USB joysticks and wheels"
|
||||
depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || USB=y) && USB
|
||||
help
|
||||
Say Y here if you have an I-Force joystick or steering wheel
|
||||
connected to your USB port.
|
||||
|
||||
config JOYSTICK_IFORCE_232
|
||||
bool "I-Force Serial joysticks and wheels"
|
||||
depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || SERIO=y) && SERIO
|
||||
help
|
||||
Say Y here if you have an I-Force joystick or steering wheel
|
||||
connected to your serial (COM) port.
|
||||
|
||||
You will need an additional utility called inputattach, see
|
||||
Documentation/input/joystick.txt and ff.txt.
|
||||
|
||||
20
extra/linux-2.6.10/drivers/input/joystick/iforce/Makefile
Normal file
20
extra/linux-2.6.10/drivers/input/joystick/iforce/Makefile
Normal file
@@ -0,0 +1,20 @@
|
||||
#
|
||||
# Makefile for the I-Force driver
|
||||
#
|
||||
# By Johann Deneux <deneux@ifrance.com>
|
||||
#
|
||||
|
||||
# Goal definition
|
||||
iforce-objs := iforce-ff.o iforce-main.o iforce-packets.o
|
||||
|
||||
obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o
|
||||
|
||||
ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y)
|
||||
iforce-objs += iforce-serio.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y)
|
||||
iforce-objs += iforce-usb.o
|
||||
endif
|
||||
|
||||
EXTRA_CFLAGS = -Werror-implicit-function-declaration
|
||||
543
extra/linux-2.6.10/drivers/input/joystick/iforce/iforce-ff.c
Normal file
543
extra/linux-2.6.10/drivers/input/joystick/iforce/iforce-ff.c
Normal file
@@ -0,0 +1,543 @@
|
||||
/*
|
||||
* $Id: iforce-ff.c,v 1.9 2002/02/02 19:28:35 jdeneux Exp $
|
||||
*
|
||||
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
|
||||
* Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
|
||||
*
|
||||
* USB/RS232 I-Force joysticks and wheels.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include "iforce.h"
|
||||
|
||||
/*
|
||||
* Set the magnitude of a constant force effect
|
||||
* Return error code
|
||||
*
|
||||
* Note: caller must ensure exclusive access to device
|
||||
*/
|
||||
|
||||
static int make_magnitude_modifier(struct iforce* iforce,
|
||||
struct resource* mod_chunk, int no_alloc, __s16 level)
|
||||
{
|
||||
unsigned char data[3];
|
||||
|
||||
if (!no_alloc) {
|
||||
down(&iforce->mem_mutex);
|
||||
if (allocate_resource(&(iforce->device_memory), mod_chunk, 2,
|
||||
iforce->device_memory.start, iforce->device_memory.end, 2L,
|
||||
NULL, NULL)) {
|
||||
up(&iforce->mem_mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
up(&iforce->mem_mutex);
|
||||
}
|
||||
|
||||
data[0] = LO(mod_chunk->start);
|
||||
data[1] = HI(mod_chunk->start);
|
||||
data[2] = HIFIX80(level);
|
||||
|
||||
iforce_send_packet(iforce, FF_CMD_MAGNITUDE, data);
|
||||
|
||||
iforce_dump_packet("magnitude: ", FF_CMD_MAGNITUDE, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Upload the component of an effect dealing with the period, phase and magnitude
|
||||
*/
|
||||
|
||||
static int make_period_modifier(struct iforce* iforce,
|
||||
struct resource* mod_chunk, int no_alloc,
|
||||
__s16 magnitude, __s16 offset, u16 period, u16 phase)
|
||||
{
|
||||
unsigned char data[7];
|
||||
|
||||
period = TIME_SCALE(period);
|
||||
|
||||
if (!no_alloc) {
|
||||
down(&iforce->mem_mutex);
|
||||
if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c,
|
||||
iforce->device_memory.start, iforce->device_memory.end, 2L,
|
||||
NULL, NULL)) {
|
||||
up(&iforce->mem_mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
up(&iforce->mem_mutex);
|
||||
}
|
||||
|
||||
data[0] = LO(mod_chunk->start);
|
||||
data[1] = HI(mod_chunk->start);
|
||||
|
||||
data[2] = HIFIX80(magnitude);
|
||||
data[3] = HIFIX80(offset);
|
||||
data[4] = HI(phase);
|
||||
|
||||
data[5] = LO(period);
|
||||
data[6] = HI(period);
|
||||
|
||||
iforce_send_packet(iforce, FF_CMD_PERIOD, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Uploads the part of an effect setting the envelope of the force
|
||||
*/
|
||||
|
||||
static int make_envelope_modifier(struct iforce* iforce,
|
||||
struct resource* mod_chunk, int no_alloc,
|
||||
u16 attack_duration, __s16 initial_level,
|
||||
u16 fade_duration, __s16 final_level)
|
||||
{
|
||||
unsigned char data[8];
|
||||
|
||||
attack_duration = TIME_SCALE(attack_duration);
|
||||
fade_duration = TIME_SCALE(fade_duration);
|
||||
|
||||
if (!no_alloc) {
|
||||
down(&iforce->mem_mutex);
|
||||
if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e,
|
||||
iforce->device_memory.start, iforce->device_memory.end, 2L,
|
||||
NULL, NULL)) {
|
||||
up(&iforce->mem_mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
up(&iforce->mem_mutex);
|
||||
}
|
||||
|
||||
data[0] = LO(mod_chunk->start);
|
||||
data[1] = HI(mod_chunk->start);
|
||||
|
||||
data[2] = LO(attack_duration);
|
||||
data[3] = HI(attack_duration);
|
||||
data[4] = HI(initial_level);
|
||||
|
||||
data[5] = LO(fade_duration);
|
||||
data[6] = HI(fade_duration);
|
||||
data[7] = HI(final_level);
|
||||
|
||||
iforce_send_packet(iforce, FF_CMD_ENVELOPE, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Component of spring, friction, inertia... effects
|
||||
*/
|
||||
|
||||
static int make_condition_modifier(struct iforce* iforce,
|
||||
struct resource* mod_chunk, int no_alloc,
|
||||
__u16 rsat, __u16 lsat, __s16 rk, __s16 lk, u16 db, __s16 center)
|
||||
{
|
||||
unsigned char data[10];
|
||||
|
||||
if (!no_alloc) {
|
||||
down(&iforce->mem_mutex);
|
||||
if (allocate_resource(&(iforce->device_memory), mod_chunk, 8,
|
||||
iforce->device_memory.start, iforce->device_memory.end, 2L,
|
||||
NULL, NULL)) {
|
||||
up(&iforce->mem_mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
up(&iforce->mem_mutex);
|
||||
}
|
||||
|
||||
data[0] = LO(mod_chunk->start);
|
||||
data[1] = HI(mod_chunk->start);
|
||||
|
||||
data[2] = (100*rk)>>15; /* Dangerous: the sign is extended by gcc on plateforms providing an arith shift */
|
||||
data[3] = (100*lk)>>15; /* This code is incorrect on cpus lacking arith shift */
|
||||
|
||||
center = (500*center)>>15;
|
||||
data[4] = LO(center);
|
||||
data[5] = HI(center);
|
||||
|
||||
db = (1000*db)>>16;
|
||||
data[6] = LO(db);
|
||||
data[7] = HI(db);
|
||||
|
||||
data[8] = (100*rsat)>>16;
|
||||
data[9] = (100*lsat)>>16;
|
||||
|
||||
iforce_send_packet(iforce, FF_CMD_CONDITION, data);
|
||||
iforce_dump_packet("condition", FF_CMD_CONDITION, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned char find_button(struct iforce *iforce, signed short button)
|
||||
{
|
||||
int i;
|
||||
for (i = 1; iforce->type->btn[i] >= 0; i++)
|
||||
if (iforce->type->btn[i] == button)
|
||||
return i + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Analyse the changes in an effect, and tell if we need to send an condition
|
||||
* parameter packet
|
||||
*/
|
||||
static int need_condition_modifier(struct iforce* iforce, struct ff_effect* new)
|
||||
{
|
||||
int id = new->id;
|
||||
struct ff_effect* old = &iforce->core_effects[id].effect;
|
||||
int ret=0;
|
||||
int i;
|
||||
|
||||
if (new->type != FF_SPRING && new->type != FF_FRICTION) {
|
||||
printk(KERN_WARNING "iforce.c: bad effect type in need_condition_modifier\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for(i=0; i<2; i++) {
|
||||
ret |= old->u.condition[i].right_saturation != new->u.condition[i].right_saturation
|
||||
|| old->u.condition[i].left_saturation != new->u.condition[i].left_saturation
|
||||
|| old->u.condition[i].right_coeff != new->u.condition[i].right_coeff
|
||||
|| old->u.condition[i].left_coeff != new->u.condition[i].left_coeff
|
||||
|| old->u.condition[i].deadband != new->u.condition[i].deadband
|
||||
|| old->u.condition[i].center != new->u.condition[i].center;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Analyse the changes in an effect, and tell if we need to send a magnitude
|
||||
* parameter packet
|
||||
*/
|
||||
static int need_magnitude_modifier(struct iforce* iforce, struct ff_effect* effect)
|
||||
{
|
||||
int id = effect->id;
|
||||
struct ff_effect* old = &iforce->core_effects[id].effect;
|
||||
|
||||
if (effect->type != FF_CONSTANT) {
|
||||
printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return (old->u.constant.level != effect->u.constant.level);
|
||||
}
|
||||
|
||||
/*
|
||||
* Analyse the changes in an effect, and tell if we need to send an envelope
|
||||
* parameter packet
|
||||
*/
|
||||
static int need_envelope_modifier(struct iforce* iforce, struct ff_effect* effect)
|
||||
{
|
||||
int id = effect->id;
|
||||
struct ff_effect* old = &iforce->core_effects[id].effect;
|
||||
|
||||
switch (effect->type) {
|
||||
case FF_CONSTANT:
|
||||
if (old->u.constant.envelope.attack_length != effect->u.constant.envelope.attack_length
|
||||
|| old->u.constant.envelope.attack_level != effect->u.constant.envelope.attack_level
|
||||
|| old->u.constant.envelope.fade_length != effect->u.constant.envelope.fade_length
|
||||
|| old->u.constant.envelope.fade_level != effect->u.constant.envelope.fade_level)
|
||||
return TRUE;
|
||||
break;
|
||||
|
||||
case FF_PERIODIC:
|
||||
if (old->u.periodic.envelope.attack_length != effect->u.periodic.envelope.attack_length
|
||||
|| old->u.periodic.envelope.attack_level != effect->u.periodic.envelope.attack_level
|
||||
|| old->u.periodic.envelope.fade_length != effect->u.periodic.envelope.fade_length
|
||||
|| old->u.periodic.envelope.fade_level != effect->u.periodic.envelope.fade_level)
|
||||
return TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n");
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Analyse the changes in an effect, and tell if we need to send a periodic
|
||||
* parameter effect
|
||||
*/
|
||||
static int need_period_modifier(struct iforce* iforce, struct ff_effect* new)
|
||||
{
|
||||
int id = new->id;
|
||||
struct ff_effect* old = &iforce->core_effects[id].effect;
|
||||
|
||||
if (new->type != FF_PERIODIC) {
|
||||
printk(KERN_WARNING "iforce.c: bad effect type in need_periodic_modifier\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return (old->u.periodic.period != new->u.periodic.period
|
||||
|| old->u.periodic.magnitude != new->u.periodic.magnitude
|
||||
|| old->u.periodic.offset != new->u.periodic.offset
|
||||
|| old->u.periodic.phase != new->u.periodic.phase);
|
||||
}
|
||||
|
||||
/*
|
||||
* Analyse the changes in an effect, and tell if we need to send an effect
|
||||
* packet
|
||||
*/
|
||||
static int need_core(struct iforce* iforce, struct ff_effect* new)
|
||||
{
|
||||
int id = new->id;
|
||||
struct ff_effect* old = &iforce->core_effects[id].effect;
|
||||
|
||||
if (old->direction != new->direction
|
||||
|| old->trigger.button != new->trigger.button
|
||||
|| old->trigger.interval != new->trigger.interval
|
||||
|| old->replay.length != new->replay.length
|
||||
|| old->replay.delay != new->replay.delay)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
/*
|
||||
* Send the part common to all effects to the device
|
||||
*/
|
||||
static int make_core(struct iforce* iforce, u16 id, u16 mod_id1, u16 mod_id2,
|
||||
u8 effect_type, u8 axes, u16 duration, u16 delay, u16 button,
|
||||
u16 interval, u16 direction)
|
||||
{
|
||||
unsigned char data[14];
|
||||
|
||||
duration = TIME_SCALE(duration);
|
||||
delay = TIME_SCALE(delay);
|
||||
interval = TIME_SCALE(interval);
|
||||
|
||||
data[0] = LO(id);
|
||||
data[1] = effect_type;
|
||||
data[2] = LO(axes) | find_button(iforce, button);
|
||||
|
||||
data[3] = LO(duration);
|
||||
data[4] = HI(duration);
|
||||
|
||||
data[5] = HI(direction);
|
||||
|
||||
data[6] = LO(interval);
|
||||
data[7] = HI(interval);
|
||||
|
||||
data[8] = LO(mod_id1);
|
||||
data[9] = HI(mod_id1);
|
||||
data[10] = LO(mod_id2);
|
||||
data[11] = HI(mod_id2);
|
||||
|
||||
data[12] = LO(delay);
|
||||
data[13] = HI(delay);
|
||||
|
||||
/* Stop effect */
|
||||
/* iforce_control_playback(iforce, id, 0);*/
|
||||
|
||||
iforce_send_packet(iforce, FF_CMD_EFFECT, data);
|
||||
|
||||
/* If needed, restart effect */
|
||||
if (test_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[id].flags)) {
|
||||
/* BUG: perhaps we should replay n times, instead of 1. But we do not know n */
|
||||
iforce_control_playback(iforce, id, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Upload a periodic effect to the device
|
||||
* See also iforce_upload_constant.
|
||||
*/
|
||||
int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int is_update)
|
||||
{
|
||||
u8 wave_code;
|
||||
int core_id = effect->id;
|
||||
struct iforce_core_effect* core_effect = iforce->core_effects + core_id;
|
||||
struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk);
|
||||
struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk);
|
||||
int param1_err = 1;
|
||||
int param2_err = 1;
|
||||
int core_err = 0;
|
||||
|
||||
if (!is_update || need_period_modifier(iforce, effect)) {
|
||||
param1_err = make_period_modifier(iforce, mod1_chunk,
|
||||
is_update,
|
||||
effect->u.periodic.magnitude, effect->u.periodic.offset,
|
||||
effect->u.periodic.period, effect->u.periodic.phase);
|
||||
if (param1_err) return param1_err;
|
||||
set_bit(FF_MOD1_IS_USED, core_effect->flags);
|
||||
}
|
||||
|
||||
if (!is_update || need_envelope_modifier(iforce, effect)) {
|
||||
param2_err = make_envelope_modifier(iforce, mod2_chunk,
|
||||
is_update,
|
||||
effect->u.periodic.envelope.attack_length,
|
||||
effect->u.periodic.envelope.attack_level,
|
||||
effect->u.periodic.envelope.fade_length,
|
||||
effect->u.periodic.envelope.fade_level);
|
||||
if (param2_err) return param2_err;
|
||||
set_bit(FF_MOD2_IS_USED, core_effect->flags);
|
||||
}
|
||||
|
||||
switch (effect->u.periodic.waveform) {
|
||||
case FF_SQUARE: wave_code = 0x20; break;
|
||||
case FF_TRIANGLE: wave_code = 0x21; break;
|
||||
case FF_SINE: wave_code = 0x22; break;
|
||||
case FF_SAW_UP: wave_code = 0x23; break;
|
||||
case FF_SAW_DOWN: wave_code = 0x24; break;
|
||||
default: wave_code = 0x20; break;
|
||||
}
|
||||
|
||||
if (!is_update || need_core(iforce, effect)) {
|
||||
core_err = make_core(iforce, effect->id,
|
||||
mod1_chunk->start,
|
||||
mod2_chunk->start,
|
||||
wave_code,
|
||||
0x20,
|
||||
effect->replay.length,
|
||||
effect->replay.delay,
|
||||
effect->trigger.button,
|
||||
effect->trigger.interval,
|
||||
effect->direction);
|
||||
}
|
||||
|
||||
/* If one of the parameter creation failed, we already returned an
|
||||
* error code.
|
||||
* If the core creation failed, we return its error code.
|
||||
* Else: if one parameter at least was created, we return 0
|
||||
* else we return 1;
|
||||
*/
|
||||
return core_err < 0 ? core_err : (param1_err && param2_err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Upload a constant force effect
|
||||
* Return value:
|
||||
* <0 Error code
|
||||
* 0 Ok, effect created or updated
|
||||
* 1 effect did not change since last upload, and no packet was therefore sent
|
||||
*/
|
||||
int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect, int is_update)
|
||||
{
|
||||
int core_id = effect->id;
|
||||
struct iforce_core_effect* core_effect = iforce->core_effects + core_id;
|
||||
struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk);
|
||||
struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk);
|
||||
int param1_err = 1;
|
||||
int param2_err = 1;
|
||||
int core_err = 0;
|
||||
|
||||
if (!is_update || need_magnitude_modifier(iforce, effect)) {
|
||||
param1_err = make_magnitude_modifier(iforce, mod1_chunk,
|
||||
is_update,
|
||||
effect->u.constant.level);
|
||||
if (param1_err) return param1_err;
|
||||
set_bit(FF_MOD1_IS_USED, core_effect->flags);
|
||||
}
|
||||
|
||||
if (!is_update || need_envelope_modifier(iforce, effect)) {
|
||||
param2_err = make_envelope_modifier(iforce, mod2_chunk,
|
||||
is_update,
|
||||
effect->u.constant.envelope.attack_length,
|
||||
effect->u.constant.envelope.attack_level,
|
||||
effect->u.constant.envelope.fade_length,
|
||||
effect->u.constant.envelope.fade_level);
|
||||
if (param2_err) return param2_err;
|
||||
set_bit(FF_MOD2_IS_USED, core_effect->flags);
|
||||
}
|
||||
|
||||
if (!is_update || need_core(iforce, effect)) {
|
||||
core_err = make_core(iforce, effect->id,
|
||||
mod1_chunk->start,
|
||||
mod2_chunk->start,
|
||||
0x00,
|
||||
0x20,
|
||||
effect->replay.length,
|
||||
effect->replay.delay,
|
||||
effect->trigger.button,
|
||||
effect->trigger.interval,
|
||||
effect->direction);
|
||||
}
|
||||
|
||||
/* If one of the parameter creation failed, we already returned an
|
||||
* error code.
|
||||
* If the core creation failed, we return its error code.
|
||||
* Else: if one parameter at least was created, we return 0
|
||||
* else we return 1;
|
||||
*/
|
||||
return core_err < 0 ? core_err : (param1_err && param2_err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Upload an condition effect. Those are for example friction, inertia, springs...
|
||||
*/
|
||||
int iforce_upload_condition(struct iforce* iforce, struct ff_effect* effect, int is_update)
|
||||
{
|
||||
int core_id = effect->id;
|
||||
struct iforce_core_effect* core_effect = iforce->core_effects + core_id;
|
||||
struct resource* mod1_chunk = &(core_effect->mod1_chunk);
|
||||
struct resource* mod2_chunk = &(core_effect->mod2_chunk);
|
||||
u8 type;
|
||||
int param_err = 1;
|
||||
int core_err = 0;
|
||||
|
||||
switch (effect->type) {
|
||||
case FF_SPRING: type = 0x40; break;
|
||||
case FF_DAMPER: type = 0x41; break;
|
||||
default: return -1;
|
||||
}
|
||||
|
||||
if (!is_update || need_condition_modifier(iforce, effect)) {
|
||||
param_err = make_condition_modifier(iforce, mod1_chunk,
|
||||
is_update,
|
||||
effect->u.condition[0].right_saturation,
|
||||
effect->u.condition[0].left_saturation,
|
||||
effect->u.condition[0].right_coeff,
|
||||
effect->u.condition[0].left_coeff,
|
||||
effect->u.condition[0].deadband,
|
||||
effect->u.condition[0].center);
|
||||
if (param_err) return param_err;
|
||||
set_bit(FF_MOD1_IS_USED, core_effect->flags);
|
||||
|
||||
param_err = make_condition_modifier(iforce, mod2_chunk,
|
||||
is_update,
|
||||
effect->u.condition[1].right_saturation,
|
||||
effect->u.condition[1].left_saturation,
|
||||
effect->u.condition[1].right_coeff,
|
||||
effect->u.condition[1].left_coeff,
|
||||
effect->u.condition[1].deadband,
|
||||
effect->u.condition[1].center);
|
||||
if (param_err) return param_err;
|
||||
set_bit(FF_MOD2_IS_USED, core_effect->flags);
|
||||
|
||||
}
|
||||
|
||||
if (!is_update || need_core(iforce, effect)) {
|
||||
core_err = make_core(iforce, effect->id,
|
||||
mod1_chunk->start, mod2_chunk->start,
|
||||
type, 0xc0,
|
||||
effect->replay.length, effect->replay.delay,
|
||||
effect->trigger.button, effect->trigger.interval,
|
||||
effect->direction);
|
||||
}
|
||||
|
||||
/* If the parameter creation failed, we already returned an
|
||||
* error code.
|
||||
* If the core creation failed, we return its error code.
|
||||
* Else: if a parameter was created, we return 0
|
||||
* else we return 1;
|
||||
*/
|
||||
return core_err < 0 ? core_err : param_err;
|
||||
}
|
||||
543
extra/linux-2.6.10/drivers/input/joystick/iforce/iforce-main.c
Normal file
543
extra/linux-2.6.10/drivers/input/joystick/iforce/iforce-main.c
Normal file
@@ -0,0 +1,543 @@
|
||||
/*
|
||||
* $Id: iforce-main.c,v 1.19 2002/07/07 10:22:50 jdeneux Exp $
|
||||
*
|
||||
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
|
||||
* Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
|
||||
*
|
||||
* USB/RS232 I-Force joysticks and wheels.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include "iforce.h"
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <deneux@ifrance.com>");
|
||||
MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static signed short btn_joystick[] =
|
||||
{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,
|
||||
BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 };
|
||||
|
||||
static signed short btn_avb_pegasus[] =
|
||||
{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,
|
||||
BTN_BASE2, BTN_BASE3, BTN_BASE4, -1 };
|
||||
|
||||
static signed short btn_wheel[] =
|
||||
{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,
|
||||
BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 };
|
||||
|
||||
static signed short btn_avb_tw[] =
|
||||
{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE,
|
||||
BTN_BASE2, BTN_BASE3, BTN_BASE4, -1 };
|
||||
|
||||
static signed short btn_avb_wheel[] =
|
||||
{ BTN_GEAR_DOWN, BTN_GEAR_UP, BTN_BASE, BTN_BASE2, BTN_BASE3,
|
||||
BTN_BASE4, BTN_BASE5, BTN_BASE6, -1 };
|
||||
|
||||
static signed short abs_joystick[] =
|
||||
{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
|
||||
|
||||
static signed short abs_avb_pegasus[] =
|
||||
{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_HAT0X, ABS_HAT0Y,
|
||||
ABS_HAT1X, ABS_HAT1Y, -1 };
|
||||
|
||||
static signed short abs_wheel[] =
|
||||
{ ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, -1 };
|
||||
|
||||
static signed short ff_iforce[] =
|
||||
{ FF_PERIODIC, FF_CONSTANT, FF_SPRING, FF_DAMPER,
|
||||
FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, FF_SAW_DOWN, FF_GAIN,
|
||||
FF_AUTOCENTER, -1 };
|
||||
|
||||
static struct iforce_device iforce_device[] = {
|
||||
{ 0x044f, 0xa01c, "Thrustmaster Motor Sport GT", btn_wheel, abs_wheel, ff_iforce },
|
||||
{ 0x046d, 0xc281, "Logitech WingMan Force", btn_joystick, abs_joystick, ff_iforce },
|
||||
{ 0x046d, 0xc291, "Logitech WingMan Formula Force", btn_wheel, abs_wheel, ff_iforce },
|
||||
{ 0x05ef, 0x020a, "AVB Top Shot Pegasus", btn_avb_pegasus, abs_avb_pegasus, ff_iforce },
|
||||
{ 0x05ef, 0x8884, "AVB Mag Turbo Force", btn_avb_wheel, abs_wheel, ff_iforce },
|
||||
{ 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel", btn_avb_tw, abs_wheel, ff_iforce }, //?
|
||||
{ 0x061c, 0xc0a4, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce }, //?
|
||||
{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, //?
|
||||
{ 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //?
|
||||
{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce }
|
||||
};
|
||||
|
||||
|
||||
|
||||
static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
struct iforce* iforce = (struct iforce*)(dev->private);
|
||||
unsigned char data[3];
|
||||
|
||||
if (type != EV_FF)
|
||||
return -1;
|
||||
|
||||
switch (code) {
|
||||
|
||||
case FF_GAIN:
|
||||
|
||||
data[0] = value >> 9;
|
||||
iforce_send_packet(iforce, FF_CMD_GAIN, data);
|
||||
|
||||
return 0;
|
||||
|
||||
case FF_AUTOCENTER:
|
||||
|
||||
data[0] = 0x03;
|
||||
data[1] = value >> 9;
|
||||
iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data);
|
||||
|
||||
data[0] = 0x04;
|
||||
data[1] = 0x01;
|
||||
iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data);
|
||||
|
||||
return 0;
|
||||
|
||||
default: /* Play or stop an effect */
|
||||
|
||||
if (!CHECK_OWNERSHIP(code, iforce)) {
|
||||
return -1;
|
||||
}
|
||||
if (value > 0) {
|
||||
set_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags);
|
||||
}
|
||||
else {
|
||||
clear_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags);
|
||||
}
|
||||
|
||||
iforce_control_playback(iforce, code, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function called when an ioctl is performed on the event dev entry.
|
||||
* It uploads an effect to the device
|
||||
*/
|
||||
static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect)
|
||||
{
|
||||
struct iforce* iforce = (struct iforce*)(dev->private);
|
||||
int id;
|
||||
int ret;
|
||||
int is_update;
|
||||
|
||||
/* Check this effect type is supported by this device */
|
||||
if (!test_bit(effect->type, iforce->dev.ffbit))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* If we want to create a new effect, get a free id
|
||||
*/
|
||||
if (effect->id == -1) {
|
||||
|
||||
for (id=0; id < FF_EFFECTS_MAX; ++id)
|
||||
if (!test_and_set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags)) break;
|
||||
|
||||
if ( id == FF_EFFECTS_MAX || id >= iforce->dev.ff_effects_max)
|
||||
return -ENOMEM;
|
||||
|
||||
effect->id = id;
|
||||
iforce->core_effects[id].owner = current->pid;
|
||||
iforce->core_effects[id].flags[0] = (1<<FF_CORE_IS_USED); /* Only IS_USED bit must be set */
|
||||
|
||||
is_update = FALSE;
|
||||
}
|
||||
else {
|
||||
/* We want to update an effect */
|
||||
if (!CHECK_OWNERSHIP(effect->id, iforce)) return -EACCES;
|
||||
|
||||
/* Parameter type cannot be updated */
|
||||
if (effect->type != iforce->core_effects[effect->id].effect.type)
|
||||
return -EINVAL;
|
||||
|
||||
/* Check the effect is not already being updated */
|
||||
if (test_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags)) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
is_update = TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Upload the effect
|
||||
*/
|
||||
switch (effect->type) {
|
||||
|
||||
case FF_PERIODIC:
|
||||
ret = iforce_upload_periodic(iforce, effect, is_update);
|
||||
break;
|
||||
|
||||
case FF_CONSTANT:
|
||||
ret = iforce_upload_constant(iforce, effect, is_update);
|
||||
break;
|
||||
|
||||
case FF_SPRING:
|
||||
case FF_DAMPER:
|
||||
ret = iforce_upload_condition(iforce, effect, is_update);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ret == 0) {
|
||||
/* A packet was sent, forbid new updates until we are notified
|
||||
* that the packet was updated
|
||||
*/
|
||||
set_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags);
|
||||
}
|
||||
iforce->core_effects[effect->id].effect = *effect;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Erases an effect: it frees the effect id and mark as unused the memory
|
||||
* allocated for the parameters
|
||||
*/
|
||||
static int iforce_erase_effect(struct input_dev *dev, int effect_id)
|
||||
{
|
||||
struct iforce* iforce = (struct iforce*)(dev->private);
|
||||
int err = 0;
|
||||
struct iforce_core_effect* core_effect;
|
||||
|
||||
/* Check who is trying to erase this effect */
|
||||
if (iforce->core_effects[effect_id].owner != current->pid) {
|
||||
printk(KERN_WARNING "iforce-main.c: %d tried to erase an effect belonging to %d\n", current->pid, iforce->core_effects[effect_id].owner);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
core_effect = iforce->core_effects + effect_id;
|
||||
|
||||
if (test_bit(FF_MOD1_IS_USED, core_effect->flags))
|
||||
err = release_resource(&(iforce->core_effects[effect_id].mod1_chunk));
|
||||
|
||||
if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags))
|
||||
err = release_resource(&(iforce->core_effects[effect_id].mod2_chunk));
|
||||
|
||||
/*TODO: remember to change that if more FF_MOD* bits are added */
|
||||
core_effect->flags[0] = 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int iforce_open(struct input_dev *dev)
|
||||
{
|
||||
struct iforce *iforce = dev->private;
|
||||
|
||||
switch (iforce->bus) {
|
||||
#ifdef CONFIG_JOYSTICK_IFORCE_USB
|
||||
case IFORCE_USB:
|
||||
iforce->irq->dev = iforce->usbdev;
|
||||
if (usb_submit_urb(iforce->irq, GFP_KERNEL))
|
||||
return -EIO;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Enable force feedback */
|
||||
iforce_send_packet(iforce, FF_CMD_ENABLE, "\004");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iforce_flush(struct input_dev *dev, struct file *file)
|
||||
{
|
||||
struct iforce *iforce = dev->private;
|
||||
int i;
|
||||
|
||||
/* Erase all effects this process owns */
|
||||
for (i=0; i<dev->ff_effects_max; ++i) {
|
||||
|
||||
if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) &&
|
||||
current->pid == iforce->core_effects[i].owner) {
|
||||
|
||||
/* Stop effect */
|
||||
input_report_ff(dev, i, 0);
|
||||
|
||||
/* Free ressources assigned to effect */
|
||||
if (iforce_erase_effect(dev, i)) {
|
||||
printk(KERN_WARNING "iforce_flush: erase effect %d failed\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iforce_release(struct input_dev *dev)
|
||||
{
|
||||
struct iforce *iforce = dev->private;
|
||||
int i;
|
||||
|
||||
/* Check: no effect should be present in memory */
|
||||
for (i=0; i<dev->ff_effects_max; ++i) {
|
||||
if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags))
|
||||
break;
|
||||
}
|
||||
if (i<dev->ff_effects_max) {
|
||||
printk(KERN_WARNING "iforce_release: Device still owns effects\n");
|
||||
}
|
||||
|
||||
/* Disable force feedback playback */
|
||||
iforce_send_packet(iforce, FF_CMD_ENABLE, "\001");
|
||||
|
||||
switch (iforce->bus) {
|
||||
#ifdef CONFIG_JOYSTICK_IFORCE_USB
|
||||
case IFORCE_USB:
|
||||
usb_unlink_urb(iforce->irq);
|
||||
|
||||
/* The device was unplugged before the file
|
||||
* was released */
|
||||
if (iforce->usbdev == NULL) {
|
||||
iforce_delete_device(iforce);
|
||||
kfree(iforce);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void iforce_delete_device(struct iforce *iforce)
|
||||
{
|
||||
switch (iforce->bus) {
|
||||
#ifdef CONFIG_JOYSTICK_IFORCE_USB
|
||||
case IFORCE_USB:
|
||||
iforce_usb_delete(iforce);
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_JOYSTICK_IFORCE_232
|
||||
case IFORCE_232:
|
||||
//TODO: Wait for the last packets to be sent
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int iforce_init_device(struct iforce *iforce)
|
||||
{
|
||||
unsigned char c[] = "CEOV";
|
||||
int i;
|
||||
|
||||
init_waitqueue_head(&iforce->wait);
|
||||
spin_lock_init(&iforce->xmit_lock);
|
||||
init_MUTEX(&iforce->mem_mutex);
|
||||
iforce->xmit.buf = iforce->xmit_data;
|
||||
|
||||
iforce->dev.ff_effects_max = 10;
|
||||
|
||||
/*
|
||||
* Input device fields.
|
||||
*/
|
||||
|
||||
iforce->dev.id.bustype = BUS_USB;
|
||||
iforce->dev.private = iforce;
|
||||
iforce->dev.name = "Unknown I-Force device";
|
||||
iforce->dev.open = iforce_open;
|
||||
iforce->dev.close = iforce_release;
|
||||
iforce->dev.flush = iforce_flush;
|
||||
iforce->dev.event = iforce_input_event;
|
||||
iforce->dev.upload_effect = iforce_upload_effect;
|
||||
iforce->dev.erase_effect = iforce_erase_effect;
|
||||
|
||||
/*
|
||||
* On-device memory allocation.
|
||||
*/
|
||||
|
||||
iforce->device_memory.name = "I-Force device effect memory";
|
||||
iforce->device_memory.start = 0;
|
||||
iforce->device_memory.end = 200;
|
||||
iforce->device_memory.flags = IORESOURCE_MEM;
|
||||
iforce->device_memory.parent = NULL;
|
||||
iforce->device_memory.child = NULL;
|
||||
iforce->device_memory.sibling = NULL;
|
||||
|
||||
/*
|
||||
* Wait until device ready - until it sends its first response.
|
||||
*/
|
||||
|
||||
for (i = 0; i < 20; i++)
|
||||
if (!iforce_get_id_packet(iforce, "O"))
|
||||
break;
|
||||
|
||||
if (i == 20) { /* 5 seconds */
|
||||
printk(KERN_ERR "iforce-main.c: Timeout waiting for response from device.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get device info.
|
||||
*/
|
||||
|
||||
if (!iforce_get_id_packet(iforce, "M"))
|
||||
iforce->dev.id.vendor = (iforce->edata[2] << 8) | iforce->edata[1];
|
||||
else
|
||||
printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet M\n");
|
||||
|
||||
if (!iforce_get_id_packet(iforce, "P"))
|
||||
iforce->dev.id.product = (iforce->edata[2] << 8) | iforce->edata[1];
|
||||
else
|
||||
printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet P\n");
|
||||
|
||||
if (!iforce_get_id_packet(iforce, "B"))
|
||||
iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1];
|
||||
else
|
||||
printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet B\n");
|
||||
|
||||
if (!iforce_get_id_packet(iforce, "N"))
|
||||
iforce->dev.ff_effects_max = iforce->edata[1];
|
||||
else
|
||||
printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet N\n");
|
||||
|
||||
/* Check if the device can store more effects than the driver can really handle */
|
||||
if (iforce->dev.ff_effects_max > FF_EFFECTS_MAX) {
|
||||
printk(KERN_WARNING "input??: Device can handle %d effects, but N_EFFECTS_MAX is set to %d in iforce.h\n",
|
||||
iforce->dev.ff_effects_max, FF_EFFECTS_MAX);
|
||||
iforce->dev.ff_effects_max = FF_EFFECTS_MAX;
|
||||
}
|
||||
|
||||
/*
|
||||
* Display additional info.
|
||||
*/
|
||||
|
||||
for (i = 0; c[i]; i++)
|
||||
if (!iforce_get_id_packet(iforce, c + i))
|
||||
iforce_dump_packet("info", iforce->ecmd, iforce->edata);
|
||||
|
||||
/*
|
||||
* Disable spring, enable force feedback.
|
||||
* FIXME: We should use iforce_set_autocenter() et al here.
|
||||
*/
|
||||
|
||||
iforce_send_packet(iforce, FF_CMD_AUTOCENTER, "\004\000");
|
||||
|
||||
/*
|
||||
* Find appropriate device entry
|
||||
*/
|
||||
|
||||
for (i = 0; iforce_device[i].idvendor; i++)
|
||||
if (iforce_device[i].idvendor == iforce->dev.id.vendor &&
|
||||
iforce_device[i].idproduct == iforce->dev.id.product)
|
||||
break;
|
||||
|
||||
iforce->type = iforce_device + i;
|
||||
iforce->dev.name = iforce->type->name;
|
||||
|
||||
/*
|
||||
* Set input device bitfields and ranges.
|
||||
*/
|
||||
|
||||
iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF) | BIT(EV_FF_STATUS);
|
||||
|
||||
for (i = 0; iforce->type->btn[i] >= 0; i++) {
|
||||
signed short t = iforce->type->btn[i];
|
||||
set_bit(t, iforce->dev.keybit);
|
||||
}
|
||||
set_bit(BTN_DEAD, iforce->dev.keybit);
|
||||
|
||||
for (i = 0; iforce->type->abs[i] >= 0; i++) {
|
||||
|
||||
signed short t = iforce->type->abs[i];
|
||||
set_bit(t, iforce->dev.absbit);
|
||||
|
||||
switch (t) {
|
||||
|
||||
case ABS_X:
|
||||
case ABS_Y:
|
||||
case ABS_WHEEL:
|
||||
|
||||
iforce->dev.absmax[t] = 1920;
|
||||
iforce->dev.absmin[t] = -1920;
|
||||
iforce->dev.absflat[t] = 128;
|
||||
iforce->dev.absfuzz[t] = 16;
|
||||
|
||||
set_bit(t, iforce->dev.ffbit);
|
||||
break;
|
||||
|
||||
case ABS_THROTTLE:
|
||||
case ABS_GAS:
|
||||
case ABS_BRAKE:
|
||||
|
||||
iforce->dev.absmax[t] = 255;
|
||||
iforce->dev.absmin[t] = 0;
|
||||
break;
|
||||
|
||||
case ABS_RUDDER:
|
||||
|
||||
iforce->dev.absmax[t] = 127;
|
||||
iforce->dev.absmin[t] = -128;
|
||||
break;
|
||||
|
||||
case ABS_HAT0X:
|
||||
case ABS_HAT0Y:
|
||||
case ABS_HAT1X:
|
||||
case ABS_HAT1Y:
|
||||
iforce->dev.absmax[t] = 1;
|
||||
iforce->dev.absmin[t] = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; iforce->type->ff[i] >= 0; i++)
|
||||
set_bit(iforce->type->ff[i], iforce->dev.ffbit);
|
||||
|
||||
/*
|
||||
* Register input device.
|
||||
*/
|
||||
|
||||
input_register_device(&iforce->dev);
|
||||
|
||||
printk(KERN_DEBUG "iforce->dev.open = %p\n", iforce->dev.open);
|
||||
|
||||
printk(KERN_INFO "input: %s [%d effects, %ld bytes memory]\n",
|
||||
iforce->dev.name, iforce->dev.ff_effects_max,
|
||||
iforce->device_memory.end);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init iforce_init(void)
|
||||
{
|
||||
#ifdef CONFIG_JOYSTICK_IFORCE_USB
|
||||
usb_register(&iforce_usb_driver);
|
||||
#endif
|
||||
#ifdef CONFIG_JOYSTICK_IFORCE_232
|
||||
serio_register_driver(&iforce_serio_drv);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit iforce_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_JOYSTICK_IFORCE_USB
|
||||
usb_deregister(&iforce_usb_driver);
|
||||
#endif
|
||||
#ifdef CONFIG_JOYSTICK_IFORCE_232
|
||||
serio_unregister_driver(&iforce_serio_drv);
|
||||
#endif
|
||||
}
|
||||
|
||||
module_init(iforce_init);
|
||||
module_exit(iforce_exit);
|
||||
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
* $Id: iforce-packets.c,v 1.16 2002/07/07 10:22:50 jdeneux Exp $
|
||||
*
|
||||
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
|
||||
* Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
|
||||
*
|
||||
* USB/RS232 I-Force joysticks and wheels.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include "iforce.h"
|
||||
|
||||
static struct {
|
||||
__s32 x;
|
||||
__s32 y;
|
||||
} iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
|
||||
|
||||
|
||||
void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data)
|
||||
{
|
||||
int i;
|
||||
|
||||
printk(KERN_DEBUG "iforce.c: %s ( cmd = %04x, data = ", msg, cmd);
|
||||
for (i = 0; i < LO(cmd); i++)
|
||||
printk("%02x ", data[i]);
|
||||
printk(")\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a packet of bytes to the device
|
||||
*/
|
||||
int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data)
|
||||
{
|
||||
/* Copy data to buffer */
|
||||
int n = LO(cmd);
|
||||
int c;
|
||||
int empty;
|
||||
int head, tail;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Update head and tail of xmit buffer
|
||||
*/
|
||||
spin_lock_irqsave(&iforce->xmit_lock, flags);
|
||||
|
||||
head = iforce->xmit.head;
|
||||
tail = iforce->xmit.tail;
|
||||
|
||||
if (CIRC_SPACE(head, tail, XMIT_SIZE) < n+2) {
|
||||
printk(KERN_WARNING "iforce.c: not enough space in xmit buffer to send new packet\n");
|
||||
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
|
||||
return -1;
|
||||
}
|
||||
|
||||
empty = head == tail;
|
||||
XMIT_INC(iforce->xmit.head, n+2);
|
||||
|
||||
/*
|
||||
* Store packet in xmit buffer
|
||||
*/
|
||||
iforce->xmit.buf[head] = HI(cmd);
|
||||
XMIT_INC(head, 1);
|
||||
iforce->xmit.buf[head] = LO(cmd);
|
||||
XMIT_INC(head, 1);
|
||||
|
||||
c = CIRC_SPACE_TO_END(head, tail, XMIT_SIZE);
|
||||
if (n < c) c=n;
|
||||
|
||||
memcpy(&iforce->xmit.buf[head],
|
||||
data,
|
||||
c);
|
||||
if (n != c) {
|
||||
memcpy(&iforce->xmit.buf[0],
|
||||
data + c,
|
||||
n - c);
|
||||
}
|
||||
XMIT_INC(head, n);
|
||||
|
||||
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
|
||||
/*
|
||||
* If necessary, start the transmission
|
||||
*/
|
||||
switch (iforce->bus) {
|
||||
|
||||
#ifdef CONFIG_JOYSTICK_IFORCE_232
|
||||
case IFORCE_232:
|
||||
if (empty)
|
||||
iforce_serial_xmit(iforce);
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_JOYSTICK_IFORCE_USB
|
||||
case IFORCE_USB:
|
||||
|
||||
if (iforce->usbdev && empty &&
|
||||
!test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) {
|
||||
|
||||
iforce_usb_xmit(iforce);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Start or stop an effect */
|
||||
int iforce_control_playback(struct iforce* iforce, u16 id, unsigned int value)
|
||||
{
|
||||
unsigned char data[3];
|
||||
|
||||
printk(KERN_DEBUG "iforce-packets.c: control_playback %d %d\n", id, value);
|
||||
|
||||
data[0] = LO(id);
|
||||
data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0;
|
||||
data[2] = LO(value);
|
||||
return iforce_send_packet(iforce, FF_CMD_PLAY, data);
|
||||
}
|
||||
|
||||
/* Mark an effect that was being updated as ready. That means it can be updated
|
||||
* again */
|
||||
static int mark_core_as_ready(struct iforce *iforce, unsigned short addr)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<iforce->dev.ff_effects_max; ++i) {
|
||||
if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) &&
|
||||
(iforce->core_effects[i].mod1_chunk.start == addr ||
|
||||
iforce->core_effects[i].mod2_chunk.start == addr)) {
|
||||
clear_bit(FF_CORE_UPDATE, iforce->core_effects[i].flags);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
printk(KERN_WARNING "iforce-packets.c: unused effect %04x updated !!!\n", addr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data, struct pt_regs *regs)
|
||||
{
|
||||
struct input_dev *dev = &iforce->dev;
|
||||
int i;
|
||||
static int being_used = 0;
|
||||
|
||||
if (being_used)
|
||||
printk(KERN_WARNING "iforce-packets.c: re-entrant call to iforce_process %d\n", being_used);
|
||||
being_used++;
|
||||
|
||||
#ifdef CONFIG_JOYSTICK_IFORCE_232
|
||||
if (HI(iforce->expect_packet) == HI(cmd)) {
|
||||
iforce->expect_packet = 0;
|
||||
iforce->ecmd = cmd;
|
||||
memcpy(iforce->edata, data, IFORCE_MAX_LENGTH);
|
||||
wake_up(&iforce->wait);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!iforce->type) {
|
||||
being_used--;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (HI(cmd)) {
|
||||
|
||||
case 0x01: /* joystick position data */
|
||||
case 0x03: /* wheel position data */
|
||||
|
||||
input_regs(dev, regs);
|
||||
|
||||
if (HI(cmd) == 1) {
|
||||
input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0]));
|
||||
input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2]));
|
||||
input_report_abs(dev, ABS_THROTTLE, 255 - data[4]);
|
||||
if (LO(cmd) >= 8 && test_bit(ABS_RUDDER ,dev->absbit))
|
||||
input_report_abs(dev, ABS_RUDDER, (__s8)data[7]);
|
||||
} else {
|
||||
input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0]));
|
||||
input_report_abs(dev, ABS_GAS, 255 - data[2]);
|
||||
input_report_abs(dev, ABS_BRAKE, 255 - data[3]);
|
||||
}
|
||||
|
||||
input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x);
|
||||
input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y);
|
||||
|
||||
for (i = 0; iforce->type->btn[i] >= 0; i++)
|
||||
input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7)));
|
||||
|
||||
/* If there are untouched bits left, interpret them as the second hat */
|
||||
if (i <= 8) {
|
||||
int btns = data[6];
|
||||
if (test_bit(ABS_HAT1X, dev->absbit)) {
|
||||
if (btns & 8) input_report_abs(dev, ABS_HAT1X, -1);
|
||||
else if (btns & 2) input_report_abs(dev, ABS_HAT1X, 1);
|
||||
else input_report_abs(dev, ABS_HAT1X, 0);
|
||||
}
|
||||
if (test_bit(ABS_HAT1Y, dev->absbit)) {
|
||||
if (btns & 1) input_report_abs(dev, ABS_HAT1Y, -1);
|
||||
else if (btns & 4) input_report_abs(dev, ABS_HAT1Y, 1);
|
||||
else input_report_abs(dev, ABS_HAT1Y, 0);
|
||||
}
|
||||
}
|
||||
|
||||
input_sync(dev);
|
||||
|
||||
break;
|
||||
|
||||
case 0x02: /* status report */
|
||||
input_regs(dev, regs);
|
||||
input_report_key(dev, BTN_DEAD, data[0] & 0x02);
|
||||
input_sync(dev);
|
||||
|
||||
/* Check if an effect was just started or stopped */
|
||||
i = data[1] & 0x7f;
|
||||
if (data[1] & 0x80) {
|
||||
if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
|
||||
/* Report play event */
|
||||
input_report_ff_status(dev, i, FF_STATUS_PLAYING);
|
||||
}
|
||||
}
|
||||
else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
|
||||
/* Report stop event */
|
||||
input_report_ff_status(dev, i, FF_STATUS_STOPPED);
|
||||
}
|
||||
if (LO(cmd) > 3) {
|
||||
int j;
|
||||
for (j=3; j<LO(cmd); j+=2) {
|
||||
mark_core_as_ready(iforce, data[j] | (data[j+1]<<8));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
being_used--;
|
||||
}
|
||||
|
||||
int iforce_get_id_packet(struct iforce *iforce, char *packet)
|
||||
{
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
int timeout = HZ; /* 1 second */
|
||||
|
||||
switch (iforce->bus) {
|
||||
|
||||
case IFORCE_USB:
|
||||
|
||||
#ifdef CONFIG_JOYSTICK_IFORCE_USB
|
||||
iforce->cr.bRequest = packet[0];
|
||||
iforce->ctrl->dev = iforce->usbdev;
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
add_wait_queue(&iforce->wait, &wait);
|
||||
|
||||
if (usb_submit_urb(iforce->ctrl, GFP_ATOMIC)) {
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&iforce->wait, &wait);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (timeout && iforce->ctrl->status == -EINPROGRESS)
|
||||
timeout = schedule_timeout(timeout);
|
||||
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&iforce->wait, &wait);
|
||||
|
||||
if (!timeout) {
|
||||
usb_unlink_urb(iforce->ctrl);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
printk(KERN_ERR "iforce_get_id_packet: iforce->bus = USB!\n");
|
||||
#endif
|
||||
break;
|
||||
|
||||
case IFORCE_232:
|
||||
|
||||
#ifdef CONFIG_JOYSTICK_IFORCE_232
|
||||
iforce->expect_packet = FF_CMD_QUERY;
|
||||
iforce_send_packet(iforce, FF_CMD_QUERY, packet);
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
add_wait_queue(&iforce->wait, &wait);
|
||||
|
||||
while (timeout && iforce->expect_packet)
|
||||
timeout = schedule_timeout(timeout);
|
||||
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&iforce->wait, &wait);
|
||||
|
||||
if (!timeout) {
|
||||
iforce->expect_packet = 0;
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
printk(KERN_ERR "iforce_get_id_packet: iforce->bus = SERIO!\n");
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_ERR "iforce_get_id_packet: iforce->bus = %d\n",
|
||||
iforce->bus);
|
||||
break;
|
||||
}
|
||||
|
||||
return -(iforce->edata[0] != packet[0]);
|
||||
}
|
||||
|
||||
170
extra/linux-2.6.10/drivers/input/joystick/iforce/iforce-serio.c
Normal file
170
extra/linux-2.6.10/drivers/input/joystick/iforce/iforce-serio.c
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* $Id: iforce-serio.c,v 1.4 2002/01/28 22:45:00 jdeneux Exp $
|
||||
*
|
||||
* Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz>
|
||||
* Copyright (c) 2001 Johann Deneux <deneux@ifrance.com>
|
||||
*
|
||||
* USB/RS232 I-Force joysticks and wheels.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include "iforce.h"
|
||||
|
||||
void iforce_serial_xmit(struct iforce *iforce)
|
||||
{
|
||||
unsigned char cs;
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
if (test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) {
|
||||
set_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&iforce->xmit_lock, flags);
|
||||
|
||||
again:
|
||||
if (iforce->xmit.head == iforce->xmit.tail) {
|
||||
clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
|
||||
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
cs = 0x2b;
|
||||
|
||||
serio_write(iforce->serio, 0x2b);
|
||||
|
||||
serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]);
|
||||
cs ^= iforce->xmit.buf[iforce->xmit.tail];
|
||||
XMIT_INC(iforce->xmit.tail, 1);
|
||||
|
||||
for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) {
|
||||
serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]);
|
||||
cs ^= iforce->xmit.buf[iforce->xmit.tail];
|
||||
XMIT_INC(iforce->xmit.tail, 1);
|
||||
}
|
||||
|
||||
serio_write(iforce->serio, cs);
|
||||
|
||||
if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags))
|
||||
goto again;
|
||||
|
||||
clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
|
||||
|
||||
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
|
||||
}
|
||||
|
||||
static void iforce_serio_write_wakeup(struct serio *serio)
|
||||
{
|
||||
iforce_serial_xmit((struct iforce *)serio->private);
|
||||
}
|
||||
|
||||
static irqreturn_t iforce_serio_irq(struct serio *serio,
|
||||
unsigned char data, unsigned int flags, struct pt_regs *regs)
|
||||
{
|
||||
struct iforce* iforce = serio->private;
|
||||
|
||||
if (!iforce->pkt) {
|
||||
if (data == 0x2b)
|
||||
iforce->pkt = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!iforce->id) {
|
||||
if (data > 3 && data != 0xff)
|
||||
iforce->pkt = 0;
|
||||
else
|
||||
iforce->id = data;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!iforce->len) {
|
||||
if (data > IFORCE_MAX_LENGTH) {
|
||||
iforce->pkt = 0;
|
||||
iforce->id = 0;
|
||||
} else {
|
||||
iforce->len = data;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (iforce->idx < iforce->len) {
|
||||
iforce->csum += iforce->data[iforce->idx++] = data;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (iforce->idx == iforce->len) {
|
||||
iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data, regs);
|
||||
iforce->pkt = 0;
|
||||
iforce->id = 0;
|
||||
iforce->len = 0;
|
||||
iforce->idx = 0;
|
||||
iforce->csum = 0;
|
||||
}
|
||||
out:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void iforce_serio_connect(struct serio *serio, struct serio_driver *drv)
|
||||
{
|
||||
struct iforce *iforce;
|
||||
if (serio->type != (SERIO_RS232 | SERIO_IFORCE))
|
||||
return;
|
||||
|
||||
if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return;
|
||||
memset(iforce, 0, sizeof(struct iforce));
|
||||
|
||||
iforce->bus = IFORCE_232;
|
||||
iforce->serio = serio;
|
||||
serio->private = iforce;
|
||||
|
||||
if (serio_open(serio, drv)) {
|
||||
kfree(iforce);
|
||||
return;
|
||||
}
|
||||
|
||||
if (iforce_init_device(iforce)) {
|
||||
serio_close(serio);
|
||||
kfree(iforce);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void iforce_serio_disconnect(struct serio *serio)
|
||||
{
|
||||
struct iforce* iforce = serio->private;
|
||||
|
||||
input_unregister_device(&iforce->dev);
|
||||
serio_close(serio);
|
||||
kfree(iforce);
|
||||
}
|
||||
|
||||
struct serio_driver iforce_serio_drv = {
|
||||
.driver = {
|
||||
.name = "iforce",
|
||||
},
|
||||
.description = "RS232 I-Force joysticks and wheels driver",
|
||||
.write_wakeup = iforce_serio_write_wakeup,
|
||||
.interrupt = iforce_serio_irq,
|
||||
.connect = iforce_serio_connect,
|
||||
.disconnect = iforce_serio_disconnect,
|
||||
};
|
||||
243
extra/linux-2.6.10/drivers/input/joystick/iforce/iforce-usb.c
Normal file
243
extra/linux-2.6.10/drivers/input/joystick/iforce/iforce-usb.c
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* $Id: iforce-usb.c,v 1.16 2002/06/09 11:08:04 jdeneux Exp $
|
||||
*
|
||||
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
|
||||
* Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
|
||||
*
|
||||
* USB/RS232 I-Force joysticks and wheels.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include "iforce.h"
|
||||
|
||||
void iforce_usb_xmit(struct iforce *iforce)
|
||||
{
|
||||
int n, c;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&iforce->xmit_lock, flags);
|
||||
|
||||
if (iforce->xmit.head == iforce->xmit.tail) {
|
||||
clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
|
||||
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
((char *)iforce->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail];
|
||||
XMIT_INC(iforce->xmit.tail, 1);
|
||||
n = iforce->xmit.buf[iforce->xmit.tail];
|
||||
XMIT_INC(iforce->xmit.tail, 1);
|
||||
|
||||
iforce->out->transfer_buffer_length = n + 1;
|
||||
iforce->out->dev = iforce->usbdev;
|
||||
|
||||
/* Copy rest of data then */
|
||||
c = CIRC_CNT_TO_END(iforce->xmit.head, iforce->xmit.tail, XMIT_SIZE);
|
||||
if (n < c) c=n;
|
||||
|
||||
memcpy(iforce->out->transfer_buffer + 1,
|
||||
&iforce->xmit.buf[iforce->xmit.tail],
|
||||
c);
|
||||
if (n != c) {
|
||||
memcpy(iforce->out->transfer_buffer + 1 + c,
|
||||
&iforce->xmit.buf[0],
|
||||
n-c);
|
||||
}
|
||||
XMIT_INC(iforce->xmit.tail, n);
|
||||
|
||||
if ( (n=usb_submit_urb(iforce->out, GFP_ATOMIC)) ) {
|
||||
printk(KERN_WARNING "iforce-usb.c: iforce_usb_xmit: usb_submit_urb failed %d\n", n);
|
||||
}
|
||||
|
||||
/* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended.
|
||||
* As long as the urb completion handler is not called, the transmiting
|
||||
* is considered to be running */
|
||||
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
|
||||
}
|
||||
|
||||
static void iforce_usb_irq(struct urb *urb, struct pt_regs *regs)
|
||||
{
|
||||
struct iforce *iforce = urb->context;
|
||||
int status;
|
||||
|
||||
switch (urb->status) {
|
||||
case 0:
|
||||
/* success */
|
||||
break;
|
||||
case -ECONNRESET:
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
/* this urb is terminated, clean up */
|
||||
dbg("%s - urb shutting down with status: %d",
|
||||
__FUNCTION__, urb->status);
|
||||
return;
|
||||
default:
|
||||
dbg("%s - urb has status of: %d", __FUNCTION__, urb->status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
iforce_process_packet(iforce,
|
||||
(iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1, regs);
|
||||
|
||||
exit:
|
||||
status = usb_submit_urb (urb, GFP_ATOMIC);
|
||||
if (status)
|
||||
err ("%s - usb_submit_urb failed with result %d",
|
||||
__FUNCTION__, status);
|
||||
}
|
||||
|
||||
static void iforce_usb_out(struct urb *urb, struct pt_regs *regs)
|
||||
{
|
||||
struct iforce *iforce = urb->context;
|
||||
|
||||
if (urb->status) {
|
||||
printk(KERN_DEBUG "iforce_usb_out: urb->status %d, exiting", urb->status);
|
||||
return;
|
||||
}
|
||||
|
||||
iforce_usb_xmit(iforce);
|
||||
|
||||
wake_up(&iforce->wait);
|
||||
}
|
||||
|
||||
static void iforce_usb_ctrl(struct urb *urb, struct pt_regs *regs)
|
||||
{
|
||||
struct iforce *iforce = urb->context;
|
||||
if (urb->status) return;
|
||||
iforce->ecmd = 0xff00 | urb->actual_length;
|
||||
wake_up(&iforce->wait);
|
||||
}
|
||||
|
||||
static int iforce_usb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *dev = interface_to_usbdev(intf);
|
||||
struct usb_host_interface *interface;
|
||||
struct usb_endpoint_descriptor *epirq, *epout;
|
||||
struct iforce *iforce;
|
||||
|
||||
interface = intf->cur_altsetting;
|
||||
|
||||
epirq = &interface->endpoint[0].desc;
|
||||
epout = &interface->endpoint[1].desc;
|
||||
|
||||
if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL)))
|
||||
goto fail;
|
||||
|
||||
memset(iforce, 0, sizeof(struct iforce));
|
||||
|
||||
if (!(iforce->irq = usb_alloc_urb(0, GFP_KERNEL))) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(iforce->out = usb_alloc_urb(0, GFP_KERNEL))) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(iforce->ctrl = usb_alloc_urb(0, GFP_KERNEL))) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
iforce->bus = IFORCE_USB;
|
||||
iforce->usbdev = dev;
|
||||
|
||||
iforce->cr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE;
|
||||
iforce->cr.wIndex = 0;
|
||||
iforce->cr.wLength = 16;
|
||||
|
||||
usb_fill_int_urb(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
|
||||
iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval);
|
||||
|
||||
usb_fill_bulk_urb(iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress),
|
||||
iforce + 1, 32, iforce_usb_out, iforce);
|
||||
|
||||
usb_fill_control_urb(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0),
|
||||
(void*) &iforce->cr, iforce->edata, 16, iforce_usb_ctrl, iforce);
|
||||
|
||||
if (iforce_init_device(iforce)) goto fail;
|
||||
|
||||
usb_set_intfdata(intf, iforce);
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (iforce) {
|
||||
if (iforce->irq) usb_free_urb(iforce->irq);
|
||||
if (iforce->out) usb_free_urb(iforce->out);
|
||||
if (iforce->ctrl) usb_free_urb(iforce->ctrl);
|
||||
kfree(iforce);
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Called by iforce_delete() */
|
||||
void iforce_usb_delete(struct iforce* iforce)
|
||||
{
|
||||
usb_unlink_urb(iforce->irq);
|
||||
/* Is it ok to unlink those ? */
|
||||
usb_unlink_urb(iforce->out);
|
||||
usb_unlink_urb(iforce->ctrl);
|
||||
|
||||
usb_free_urb(iforce->irq);
|
||||
usb_free_urb(iforce->out);
|
||||
usb_free_urb(iforce->ctrl);
|
||||
}
|
||||
|
||||
static void iforce_usb_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct iforce *iforce = usb_get_intfdata(intf);
|
||||
int open = 0; /* FIXME! iforce->dev.handle->open; */
|
||||
|
||||
usb_set_intfdata(intf, NULL);
|
||||
if (iforce) {
|
||||
iforce->usbdev = NULL;
|
||||
input_unregister_device(&iforce->dev);
|
||||
|
||||
if (!open) {
|
||||
iforce_delete_device(iforce);
|
||||
kfree(iforce);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct usb_device_id iforce_usb_ids [] = {
|
||||
{ USB_DEVICE(0x044f, 0xa01c) }, /* Thrustmaster Motor Sport GT */
|
||||
{ USB_DEVICE(0x046d, 0xc281) }, /* Logitech WingMan Force */
|
||||
{ USB_DEVICE(0x046d, 0xc291) }, /* Logitech WingMan Formula Force */
|
||||
{ USB_DEVICE(0x05ef, 0x020a) }, /* AVB Top Shot Pegasus */
|
||||
{ USB_DEVICE(0x05ef, 0x8884) }, /* AVB Mag Turbo Force */
|
||||
{ USB_DEVICE(0x05ef, 0x8888) }, /* AVB Top Shot FFB Racing Wheel */
|
||||
{ USB_DEVICE(0x061c, 0xc0a4) }, /* ACT LABS Force RS */
|
||||
{ USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */
|
||||
{ USB_DEVICE(0x06f8, 0x0004) }, /* Guillemot Force Feedback Racing Wheel */
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE (usb, iforce_usb_ids);
|
||||
|
||||
struct usb_driver iforce_usb_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "iforce",
|
||||
.probe = iforce_usb_probe,
|
||||
.disconnect = iforce_usb_disconnect,
|
||||
.id_table = iforce_usb_ids,
|
||||
};
|
||||
191
extra/linux-2.6.10/drivers/input/joystick/iforce/iforce.h
Normal file
191
extra/linux-2.6.10/drivers/input/joystick/iforce/iforce.h
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* $Id: iforce.h,v 1.13 2002/07/07 10:22:50 jdeneux Exp $
|
||||
*
|
||||
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
|
||||
* Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
|
||||
*
|
||||
* USB/RS232 I-Force joysticks and wheels.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/serio.h>
|
||||
#include <linux/config.h>
|
||||
#include <linux/circ_buf.h>
|
||||
#include <asm/semaphore.h>
|
||||
|
||||
/* This module provides arbitrary resource management routines.
|
||||
* I use it to manage the device's memory.
|
||||
* Despite the name of this module, I am *not* going to access the ioports.
|
||||
*/
|
||||
#include <linux/ioport.h>
|
||||
|
||||
#define IFORCE_MAX_LENGTH 16
|
||||
|
||||
/* iforce::bus */
|
||||
#define IFORCE_232 1
|
||||
#define IFORCE_USB 2
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
#define FF_EFFECTS_MAX 32
|
||||
|
||||
/* Each force feedback effect is made of one core effect, which can be
|
||||
* associated to at most to effect modifiers
|
||||
*/
|
||||
#define FF_MOD1_IS_USED 0
|
||||
#define FF_MOD2_IS_USED 1
|
||||
#define FF_CORE_IS_USED 2
|
||||
#define FF_CORE_IS_PLAYED 3 /* Effect is currently being played */
|
||||
#define FF_CORE_SHOULD_PLAY 4 /* User wants the effect to be played */
|
||||
#define FF_CORE_UPDATE 5 /* Effect is being updated */
|
||||
#define FF_MODCORE_MAX 5
|
||||
|
||||
#define CHECK_OWNERSHIP(i, iforce) \
|
||||
((i) < FF_EFFECTS_MAX && i >= 0 && \
|
||||
test_bit(FF_CORE_IS_USED, (iforce)->core_effects[(i)].flags) && \
|
||||
(current->pid == 0 || \
|
||||
(iforce)->core_effects[(i)].owner == current->pid))
|
||||
|
||||
struct iforce_core_effect {
|
||||
/* Information about where modifiers are stored in the device's memory */
|
||||
struct resource mod1_chunk;
|
||||
struct resource mod2_chunk;
|
||||
unsigned long flags[NBITS(FF_MODCORE_MAX)];
|
||||
pid_t owner;
|
||||
/* Used to keep track of parameters of an effect. They are needed
|
||||
* to know what parts of an effect changed in an update operation.
|
||||
* We try to send only parameter packets if possible, as sending
|
||||
* effect parameter requires the effect to be stoped and restarted
|
||||
*/
|
||||
struct ff_effect effect;
|
||||
};
|
||||
|
||||
#define FF_CMD_EFFECT 0x010e
|
||||
#define FF_CMD_ENVELOPE 0x0208
|
||||
#define FF_CMD_MAGNITUDE 0x0303
|
||||
#define FF_CMD_PERIOD 0x0407
|
||||
#define FF_CMD_CONDITION 0x050a
|
||||
|
||||
#define FF_CMD_AUTOCENTER 0x4002
|
||||
#define FF_CMD_PLAY 0x4103
|
||||
#define FF_CMD_ENABLE 0x4201
|
||||
#define FF_CMD_GAIN 0x4301
|
||||
|
||||
#define FF_CMD_QUERY 0xff01
|
||||
|
||||
/* Buffer for async write */
|
||||
#define XMIT_SIZE 256
|
||||
#define XMIT_INC(var, n) (var)+=n; (var)&= XMIT_SIZE -1
|
||||
/* iforce::xmit_flags */
|
||||
#define IFORCE_XMIT_RUNNING 0
|
||||
#define IFORCE_XMIT_AGAIN 1
|
||||
|
||||
struct iforce_device {
|
||||
u16 idvendor;
|
||||
u16 idproduct;
|
||||
char *name;
|
||||
signed short *btn;
|
||||
signed short *abs;
|
||||
signed short *ff;
|
||||
};
|
||||
|
||||
struct iforce {
|
||||
struct input_dev dev; /* Input device interface */
|
||||
struct iforce_device *type;
|
||||
int bus;
|
||||
|
||||
unsigned char data[IFORCE_MAX_LENGTH];
|
||||
unsigned char edata[IFORCE_MAX_LENGTH];
|
||||
u16 ecmd;
|
||||
u16 expect_packet;
|
||||
|
||||
#ifdef CONFIG_JOYSTICK_IFORCE_232
|
||||
struct serio *serio; /* RS232 transfer */
|
||||
int idx, pkt, len, id;
|
||||
unsigned char csum;
|
||||
#endif
|
||||
#ifdef CONFIG_JOYSTICK_IFORCE_USB
|
||||
struct usb_device *usbdev; /* USB transfer */
|
||||
struct urb *irq, *out, *ctrl;
|
||||
struct usb_ctrlrequest cr;
|
||||
#endif
|
||||
spinlock_t xmit_lock;
|
||||
/* Buffer used for asynchronous sending of bytes to the device */
|
||||
struct circ_buf xmit;
|
||||
unsigned char xmit_data[XMIT_SIZE];
|
||||
long xmit_flags[1];
|
||||
|
||||
/* Force Feedback */
|
||||
wait_queue_head_t wait;
|
||||
struct resource device_memory;
|
||||
struct iforce_core_effect core_effects[FF_EFFECTS_MAX];
|
||||
struct semaphore mem_mutex;
|
||||
};
|
||||
|
||||
/* Get hi and low bytes of a 16-bits int */
|
||||
#define HI(a) ((unsigned char)((a) >> 8))
|
||||
#define LO(a) ((unsigned char)((a) & 0xff))
|
||||
|
||||
/* For many parameters, it seems that 0x80 is a special value that should
|
||||
* be avoided. Instead, we replace this value by 0x7f
|
||||
*/
|
||||
#define HIFIX80(a) ((unsigned char)(((a)<0? (a)+255 : (a))>>8))
|
||||
|
||||
/* Encode a time value */
|
||||
#define TIME_SCALE(a) (a)
|
||||
|
||||
|
||||
/* Public functions */
|
||||
/* iforce-serio.c */
|
||||
void iforce_serial_xmit(struct iforce *iforce);
|
||||
|
||||
/* iforce-usb.c */
|
||||
void iforce_usb_xmit(struct iforce *iforce);
|
||||
void iforce_usb_delete(struct iforce *iforce);
|
||||
|
||||
/* iforce-main.c */
|
||||
int iforce_init_device(struct iforce *iforce);
|
||||
void iforce_delete_device(struct iforce *iforce);
|
||||
|
||||
/* iforce-packets.c */
|
||||
int iforce_control_playback(struct iforce*, u16 id, unsigned int);
|
||||
void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data, struct pt_regs *regs);
|
||||
int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data);
|
||||
void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) ;
|
||||
int iforce_get_id_packet(struct iforce *iforce, char *packet);
|
||||
|
||||
/* iforce-ff.c */
|
||||
int iforce_upload_periodic(struct iforce*, struct ff_effect*, int is_update);
|
||||
int iforce_upload_constant(struct iforce*, struct ff_effect*, int is_update);
|
||||
int iforce_upload_condition(struct iforce*, struct ff_effect*, int is_update);
|
||||
|
||||
/* Public variables */
|
||||
extern struct serio_driver iforce_serio_drv;
|
||||
extern struct usb_driver iforce_usb_driver;
|
||||
314
extra/linux-2.6.10/drivers/input/joystick/interact.c
Normal file
314
extra/linux-2.6.10/drivers/input/joystick/interact.c
Normal file
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* $Id: interact.c,v 1.16 2002/01/22 20:28:25 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 2001 Vojtech Pavlik
|
||||
*
|
||||
* Based on the work of:
|
||||
* Toby Deshane
|
||||
*/
|
||||
|
||||
/*
|
||||
* InterAct digital gamepad/joystick driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/gameport.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("InterAct digital joystick driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define INTERACT_MAX_START 400 /* 400 us */
|
||||
#define INTERACT_MAX_STROBE 40 /* 40 us */
|
||||
#define INTERACT_MAX_LENGTH 32 /* 32 bits */
|
||||
#define INTERACT_REFRESH_TIME HZ/50 /* 20 ms */
|
||||
|
||||
#define INTERACT_TYPE_HHFX 0 /* HammerHead/FX */
|
||||
#define INTERACT_TYPE_PP8D 1 /* ProPad 8 */
|
||||
|
||||
struct interact {
|
||||
struct gameport *gameport;
|
||||
struct input_dev dev;
|
||||
struct timer_list timer;
|
||||
int used;
|
||||
int bads;
|
||||
int reads;
|
||||
unsigned char type;
|
||||
unsigned char length;
|
||||
char phys[32];
|
||||
};
|
||||
|
||||
static short interact_abs_hhfx[] =
|
||||
{ ABS_RX, ABS_RY, ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y, -1 };
|
||||
static short interact_abs_pp8d[] =
|
||||
{ ABS_X, ABS_Y, -1 };
|
||||
|
||||
static short interact_btn_hhfx[] =
|
||||
{ BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL, BTN_TL2, BTN_TR2, BTN_MODE, BTN_SELECT, -1 };
|
||||
static short interact_btn_pp8d[] =
|
||||
{ BTN_C, BTN_TL, BTN_TR, BTN_A, BTN_B, BTN_Y, BTN_Z, BTN_X, -1 };
|
||||
|
||||
struct interact_type {
|
||||
int id;
|
||||
short *abs;
|
||||
short *btn;
|
||||
char *name;
|
||||
unsigned char length;
|
||||
unsigned char b8;
|
||||
};
|
||||
|
||||
static struct interact_type interact_type[] = {
|
||||
{ 0x6202, interact_abs_hhfx, interact_btn_hhfx, "InterAct HammerHead/FX", 32, 4 },
|
||||
{ 0x53f8, interact_abs_pp8d, interact_btn_pp8d, "InterAct ProPad 8 Digital", 16, 0 },
|
||||
{ 0 }};
|
||||
|
||||
/*
|
||||
* interact_read_packet() reads and InterAct joystick data.
|
||||
*/
|
||||
|
||||
static int interact_read_packet(struct gameport *gameport, int length, u32 *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned char u, v;
|
||||
unsigned int t, s;
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
data[0] = data[1] = data[2] = 0;
|
||||
t = gameport_time(gameport, INTERACT_MAX_START);
|
||||
s = gameport_time(gameport, INTERACT_MAX_STROBE);
|
||||
|
||||
local_irq_save(flags);
|
||||
gameport_trigger(gameport);
|
||||
v = gameport_read(gameport);
|
||||
|
||||
while (t > 0 && i < length) {
|
||||
t--;
|
||||
u = v; v = gameport_read(gameport);
|
||||
if (v & ~u & 0x40) {
|
||||
data[0] = (data[0] << 1) | ((v >> 4) & 1);
|
||||
data[1] = (data[1] << 1) | ((v >> 5) & 1);
|
||||
data[2] = (data[2] << 1) | ((v >> 7) & 1);
|
||||
i++;
|
||||
t = s;
|
||||
}
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* interact_timer() reads and analyzes InterAct joystick data.
|
||||
*/
|
||||
|
||||
static void interact_timer(unsigned long private)
|
||||
{
|
||||
struct interact *interact = (struct interact *) private;
|
||||
struct input_dev *dev = &interact->dev;
|
||||
u32 data[3];
|
||||
int i;
|
||||
|
||||
interact->reads++;
|
||||
|
||||
if (interact_read_packet(interact->gameport, interact->length, data) < interact->length) {
|
||||
interact->bads++;
|
||||
} else {
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
data[i] <<= INTERACT_MAX_LENGTH - interact->length;
|
||||
|
||||
switch (interact->type) {
|
||||
|
||||
case INTERACT_TYPE_HHFX:
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
input_report_abs(dev, interact_abs_hhfx[i], (data[i & 1] >> ((i >> 1) << 3)) & 0xff);
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
input_report_abs(dev, ABS_HAT0Y - i,
|
||||
((data[1] >> ((i << 1) + 17)) & 1) - ((data[1] >> ((i << 1) + 16)) & 1));
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
input_report_key(dev, interact_btn_hhfx[i], (data[0] >> (i + 16)) & 1);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
input_report_key(dev, interact_btn_hhfx[i + 8], (data[1] >> (i + 20)) & 1);
|
||||
|
||||
break;
|
||||
|
||||
case INTERACT_TYPE_PP8D:
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
input_report_abs(dev, interact_abs_pp8d[i],
|
||||
((data[0] >> ((i << 1) + 20)) & 1) - ((data[0] >> ((i << 1) + 21)) & 1));
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
input_report_key(dev, interact_btn_pp8d[i], (data[1] >> (i + 16)) & 1);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
input_sync(dev);
|
||||
|
||||
mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* interact_open() is a callback from the input open routine.
|
||||
*/
|
||||
|
||||
static int interact_open(struct input_dev *dev)
|
||||
{
|
||||
struct interact *interact = dev->private;
|
||||
if (!interact->used++)
|
||||
mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* interact_close() is a callback from the input close routine.
|
||||
*/
|
||||
|
||||
static void interact_close(struct input_dev *dev)
|
||||
{
|
||||
struct interact *interact = dev->private;
|
||||
if (!--interact->used)
|
||||
del_timer(&interact->timer);
|
||||
}
|
||||
|
||||
/*
|
||||
* interact_connect() probes for InterAct joysticks.
|
||||
*/
|
||||
|
||||
static void interact_connect(struct gameport *gameport, struct gameport_dev *dev)
|
||||
{
|
||||
struct interact *interact;
|
||||
__u32 data[3];
|
||||
int i, t;
|
||||
|
||||
if (!(interact = kmalloc(sizeof(struct interact), GFP_KERNEL)))
|
||||
return;
|
||||
memset(interact, 0, sizeof(struct interact));
|
||||
|
||||
gameport->private = interact;
|
||||
|
||||
interact->gameport = gameport;
|
||||
init_timer(&interact->timer);
|
||||
interact->timer.data = (long) interact;
|
||||
interact->timer.function = interact_timer;
|
||||
|
||||
if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
|
||||
goto fail1;
|
||||
|
||||
i = interact_read_packet(gameport, INTERACT_MAX_LENGTH * 2, data);
|
||||
|
||||
if (i != 32 || (data[0] >> 24) != 0x0c || (data[1] >> 24) != 0x02) {
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
for (i = 0; interact_type[i].length; i++)
|
||||
if (interact_type[i].id == (data[2] >> 16))
|
||||
break;
|
||||
|
||||
if (!interact_type[i].length) {
|
||||
printk(KERN_WARNING "interact.c: Unknown joystick on %s. [len %d d0 %08x d1 %08x i2 %08x]\n",
|
||||
gameport->phys, i, data[0], data[1], data[2]);
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
sprintf(interact->phys, "%s/input0", gameport->phys);
|
||||
|
||||
interact->type = i;
|
||||
interact->length = interact_type[i].length;
|
||||
|
||||
interact->dev.private = interact;
|
||||
interact->dev.open = interact_open;
|
||||
interact->dev.close = interact_close;
|
||||
|
||||
interact->dev.name = interact_type[i].name;
|
||||
interact->dev.phys = interact->phys;
|
||||
interact->dev.id.bustype = BUS_GAMEPORT;
|
||||
interact->dev.id.vendor = GAMEPORT_ID_VENDOR_INTERACT;
|
||||
interact->dev.id.product = interact_type[i].id;
|
||||
interact->dev.id.version = 0x0100;
|
||||
|
||||
interact->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
|
||||
for (i = 0; (t = interact_type[interact->type].abs[i]) >= 0; i++) {
|
||||
set_bit(t, interact->dev.absbit);
|
||||
if (i < interact_type[interact->type].b8) {
|
||||
interact->dev.absmin[t] = 0;
|
||||
interact->dev.absmax[t] = 255;
|
||||
} else {
|
||||
interact->dev.absmin[t] = -1;
|
||||
interact->dev.absmax[t] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; (t = interact_type[interact->type].btn[i]) >= 0; i++)
|
||||
set_bit(t, interact->dev.keybit);
|
||||
|
||||
input_register_device(&interact->dev);
|
||||
printk(KERN_INFO "input: %s on %s\n",
|
||||
interact_type[interact->type].name, gameport->phys);
|
||||
|
||||
return;
|
||||
fail2: gameport_close(gameport);
|
||||
fail1: kfree(interact);
|
||||
}
|
||||
|
||||
static void interact_disconnect(struct gameport *gameport)
|
||||
{
|
||||
struct interact *interact = gameport->private;
|
||||
input_unregister_device(&interact->dev);
|
||||
gameport_close(gameport);
|
||||
kfree(interact);
|
||||
}
|
||||
|
||||
static struct gameport_dev interact_dev = {
|
||||
.connect = interact_connect,
|
||||
.disconnect = interact_disconnect,
|
||||
};
|
||||
|
||||
int __init interact_init(void)
|
||||
{
|
||||
gameport_register_device(&interact_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit interact_exit(void)
|
||||
{
|
||||
gameport_unregister_device(&interact_dev);
|
||||
}
|
||||
|
||||
module_init(interact_init);
|
||||
module_exit(interact_exit);
|
||||
151
extra/linux-2.6.10/drivers/input/joystick/joydump.c
Normal file
151
extra/linux-2.6.10/drivers/input/joystick/joydump.c
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* $Id: joydump.c,v 1.1 2002/01/23 06:56:16 jsimmons Exp $
|
||||
*
|
||||
* Copyright (c) 1996-2001 Vojtech Pavlik
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is just a very simple driver that can dump the data
|
||||
* out of the joystick port into the syslog ...
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/gameport.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Gameport data dumper module");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define BUF_SIZE 256
|
||||
|
||||
struct joydump {
|
||||
unsigned int time;
|
||||
unsigned char data;
|
||||
};
|
||||
|
||||
static void __devinit joydump_connect(struct gameport *gameport, struct gameport_dev *dev)
|
||||
{
|
||||
struct joydump buf[BUF_SIZE];
|
||||
int axes[4], buttons;
|
||||
int i, j, t, timeout;
|
||||
unsigned long flags;
|
||||
unsigned char u;
|
||||
|
||||
printk(KERN_INFO "joydump: ,------------------- START ------------------.\n");
|
||||
printk(KERN_INFO "joydump: | Dumping gameport%s.\n", gameport->phys);
|
||||
printk(KERN_INFO "joydump: | Speed: %4d kHz. |\n", gameport->speed);
|
||||
|
||||
if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
|
||||
|
||||
printk(KERN_INFO "joydump: | Raw mode not available - trying cooked. |\n");
|
||||
|
||||
if (gameport_open(gameport, dev, GAMEPORT_MODE_COOKED)) {
|
||||
|
||||
printk(KERN_INFO "joydump: | Cooked not available either. Failing. |\n");
|
||||
printk(KERN_INFO "joydump: `-------------------- END -------------------'\n");
|
||||
return;
|
||||
}
|
||||
|
||||
gameport_cooked_read(gameport, axes, &buttons);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
printk(KERN_INFO "joydump: | Axis %d: %4d. |\n", i, axes[i]);
|
||||
printk(KERN_INFO "joydump: | Buttons %02x. |\n", buttons);
|
||||
printk(KERN_INFO "joydump: `-------------------- END -------------------'\n");
|
||||
}
|
||||
|
||||
timeout = gameport_time(gameport, 10000); /* 10 ms */
|
||||
t = 0;
|
||||
i = 1;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
u = gameport_read(gameport);
|
||||
|
||||
buf[0].data = u;
|
||||
buf[0].time = t;
|
||||
|
||||
gameport_trigger(gameport);
|
||||
|
||||
while (i < BUF_SIZE && t < timeout) {
|
||||
|
||||
buf[i].data = gameport_read(gameport);
|
||||
|
||||
if (buf[i].data ^ u) {
|
||||
u = buf[i].data;
|
||||
buf[i].time = t;
|
||||
i++;
|
||||
}
|
||||
t++;
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
/*
|
||||
* Dump data.
|
||||
*/
|
||||
|
||||
t = i;
|
||||
|
||||
printk(KERN_INFO "joydump: >------------------- DATA -------------------<\n");
|
||||
printk(KERN_INFO "joydump: | index: %3d delta: %3d.%02d us data: ", 0, 0, 0);
|
||||
for (j = 7; j >= 0; j--)
|
||||
printk("%d",(buf[0].data >> j) & 1);
|
||||
printk(" |\n");
|
||||
for (i = 1; i < t; i++) {
|
||||
printk(KERN_INFO "joydump: | index: %3d delta: %3d us data: ",
|
||||
i, buf[i].time - buf[i-1].time);
|
||||
for (j = 7; j >= 0; j--)
|
||||
printk("%d",(buf[i].data >> j) & 1);
|
||||
printk(" |\n");
|
||||
}
|
||||
|
||||
printk(KERN_INFO "joydump: `-------------------- END -------------------'\n");
|
||||
}
|
||||
|
||||
static void __devexit joydump_disconnect(struct gameport *gameport)
|
||||
{
|
||||
gameport_close(gameport);
|
||||
}
|
||||
|
||||
static struct gameport_dev joydump_dev = {
|
||||
.connect = joydump_connect,
|
||||
.disconnect = joydump_disconnect,
|
||||
};
|
||||
|
||||
static int __init joydump_init(void)
|
||||
{
|
||||
gameport_register_device(&joydump_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit joydump_exit(void)
|
||||
{
|
||||
gameport_unregister_device(&joydump_dev);
|
||||
}
|
||||
|
||||
module_init(joydump_init);
|
||||
module_exit(joydump_exit);
|
||||
230
extra/linux-2.6.10/drivers/input/joystick/magellan.c
Normal file
230
extra/linux-2.6.10/drivers/input/joystick/magellan.c
Normal file
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* $Id: magellan.c,v 1.16 2002/01/22 20:28:39 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1999-2001 Vojtech Pavlik
|
||||
*/
|
||||
|
||||
/*
|
||||
* Magellan and Space Mouse 6dof controller driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/serio.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#define DRIVER_DESC "Magellan and SpaceMouse 6dof controller driver"
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
* Definitions & global arrays.
|
||||
*/
|
||||
|
||||
#define MAGELLAN_MAX_LENGTH 32
|
||||
|
||||
static int magellan_buttons[] = { BTN_0, BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 };
|
||||
static int magellan_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ };
|
||||
static char *magellan_name = "LogiCad3D Magellan / SpaceMouse";
|
||||
|
||||
/*
|
||||
* Per-Magellan data.
|
||||
*/
|
||||
|
||||
struct magellan {
|
||||
struct input_dev dev;
|
||||
int idx;
|
||||
unsigned char data[MAGELLAN_MAX_LENGTH];
|
||||
char phys[32];
|
||||
};
|
||||
|
||||
/*
|
||||
* magellan_crunch_nibbles() verifies that the bytes sent from the Magellan
|
||||
* have correct upper nibbles for the lower ones, if not, the packet will
|
||||
* be thrown away. It also strips these upper halves to simplify further
|
||||
* processing.
|
||||
*/
|
||||
|
||||
static int magellan_crunch_nibbles(unsigned char *data, int count)
|
||||
{
|
||||
static unsigned char nibbles[16] = "0AB3D56GH9:K<MN?";
|
||||
|
||||
do {
|
||||
if (data[count] == nibbles[data[count] & 0xf])
|
||||
data[count] = data[count] & 0xf;
|
||||
else
|
||||
return -1;
|
||||
} while (--count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void magellan_process_packet(struct magellan* magellan, struct pt_regs *regs)
|
||||
{
|
||||
struct input_dev *dev = &magellan->dev;
|
||||
unsigned char *data = magellan->data;
|
||||
int i, t;
|
||||
|
||||
if (!magellan->idx) return;
|
||||
|
||||
input_regs(dev, regs);
|
||||
|
||||
switch (magellan->data[0]) {
|
||||
|
||||
case 'd': /* Axis data */
|
||||
if (magellan->idx != 25) return;
|
||||
if (magellan_crunch_nibbles(data, 24)) return;
|
||||
for (i = 0; i < 6; i++)
|
||||
input_report_abs(dev, magellan_axes[i],
|
||||
(data[(i << 2) + 1] << 12 | data[(i << 2) + 2] << 8 |
|
||||
data[(i << 2) + 3] << 4 | data[(i << 2) + 4]) - 32768);
|
||||
break;
|
||||
|
||||
case 'k': /* Button data */
|
||||
if (magellan->idx != 4) return;
|
||||
if (magellan_crunch_nibbles(data, 3)) return;
|
||||
t = (data[1] << 1) | (data[2] << 5) | data[3];
|
||||
for (i = 0; i < 9; i++) input_report_key(dev, magellan_buttons[i], (t >> i) & 1);
|
||||
break;
|
||||
}
|
||||
|
||||
input_sync(dev);
|
||||
}
|
||||
|
||||
static irqreturn_t magellan_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags, struct pt_regs *regs)
|
||||
{
|
||||
struct magellan* magellan = serio->private;
|
||||
|
||||
if (data == '\r') {
|
||||
magellan_process_packet(magellan, regs);
|
||||
magellan->idx = 0;
|
||||
} else {
|
||||
if (magellan->idx < MAGELLAN_MAX_LENGTH)
|
||||
magellan->data[magellan->idx++] = data;
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* magellan_disconnect() is the opposite of magellan_connect()
|
||||
*/
|
||||
|
||||
static void magellan_disconnect(struct serio *serio)
|
||||
{
|
||||
struct magellan* magellan = serio->private;
|
||||
input_unregister_device(&magellan->dev);
|
||||
serio_close(serio);
|
||||
kfree(magellan);
|
||||
}
|
||||
|
||||
/*
|
||||
* magellan_connect() is the routine that is called when someone adds a
|
||||
* new serio device. It looks for the Magellan, and if found, registers
|
||||
* it as an input device.
|
||||
*/
|
||||
|
||||
static void magellan_connect(struct serio *serio, struct serio_driver *drv)
|
||||
{
|
||||
struct magellan *magellan;
|
||||
int i, t;
|
||||
|
||||
if (serio->type != (SERIO_RS232 | SERIO_MAGELLAN))
|
||||
return;
|
||||
|
||||
if (!(magellan = kmalloc(sizeof(struct magellan), GFP_KERNEL)))
|
||||
return;
|
||||
|
||||
memset(magellan, 0, sizeof(struct magellan));
|
||||
|
||||
magellan->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
|
||||
for (i = 0; i < 9; i++)
|
||||
set_bit(magellan_buttons[i], magellan->dev.keybit);
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
t = magellan_axes[i];
|
||||
set_bit(t, magellan->dev.absbit);
|
||||
magellan->dev.absmin[t] = -360;
|
||||
magellan->dev.absmax[t] = 360;
|
||||
}
|
||||
|
||||
sprintf(magellan->phys, "%s/input0", serio->phys);
|
||||
|
||||
init_input_dev(&magellan->dev);
|
||||
magellan->dev.private = magellan;
|
||||
magellan->dev.name = magellan_name;
|
||||
magellan->dev.phys = magellan->phys;
|
||||
magellan->dev.id.bustype = BUS_RS232;
|
||||
magellan->dev.id.vendor = SERIO_MAGELLAN;
|
||||
magellan->dev.id.product = 0x0001;
|
||||
magellan->dev.id.version = 0x0100;
|
||||
|
||||
serio->private = magellan;
|
||||
|
||||
if (serio_open(serio, drv)) {
|
||||
kfree(magellan);
|
||||
return;
|
||||
}
|
||||
|
||||
input_register_device(&magellan->dev);
|
||||
|
||||
printk(KERN_INFO "input: %s on %s\n", magellan_name, serio->phys);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* The serio device structure.
|
||||
*/
|
||||
|
||||
static struct serio_driver magellan_drv = {
|
||||
.driver = {
|
||||
.name = "magellan",
|
||||
},
|
||||
.description = DRIVER_DESC,
|
||||
.interrupt = magellan_interrupt,
|
||||
.connect = magellan_connect,
|
||||
.disconnect = magellan_disconnect,
|
||||
};
|
||||
|
||||
/*
|
||||
* The functions for inserting/removing us as a module.
|
||||
*/
|
||||
|
||||
int __init magellan_init(void)
|
||||
{
|
||||
serio_register_driver(&magellan_drv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit magellan_exit(void)
|
||||
{
|
||||
serio_unregister_driver(&magellan_drv);
|
||||
}
|
||||
|
||||
module_init(magellan_init);
|
||||
module_exit(magellan_exit);
|
||||
780
extra/linux-2.6.10/drivers/input/joystick/sidewinder.c
Normal file
780
extra/linux-2.6.10/drivers/input/joystick/sidewinder.c
Normal file
@@ -0,0 +1,780 @@
|
||||
/*
|
||||
* $Id: sidewinder.c,v 1.29 2002/01/22 20:28:51 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1998-2001 Vojtech Pavlik
|
||||
*/
|
||||
|
||||
/*
|
||||
* Microsoft SideWinder joystick family driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/gameport.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Microsoft SideWinder joystick family driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
* These are really magic values. Changing them can make a problem go away,
|
||||
* as well as break everything.
|
||||
*/
|
||||
|
||||
#define SW_DEBUG
|
||||
|
||||
#define SW_START 400 /* The time we wait for the first bit [400 us] */
|
||||
#define SW_STROBE 45 /* Max time per bit [45 us] */
|
||||
#define SW_TIMEOUT 4000 /* Wait for everything to settle [4 ms] */
|
||||
#define SW_KICK 45 /* Wait after A0 fall till kick [45 us] */
|
||||
#define SW_END 8 /* Number of bits before end of packet to kick */
|
||||
#define SW_FAIL 16 /* Number of packet read errors to fail and reinitialize */
|
||||
#define SW_BAD 2 /* Number of packet read errors to switch off 3d Pro optimization */
|
||||
#define SW_OK 64 /* Number of packet read successes to switch optimization back on */
|
||||
#define SW_LENGTH 512 /* Max number of bits in a packet */
|
||||
#define SW_REFRESH HZ/50 /* Time to wait between updates of joystick data [20 ms] */
|
||||
|
||||
#ifdef SW_DEBUG
|
||||
#define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg)
|
||||
#else
|
||||
#define dbg(format, arg...) do {} while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* SideWinder joystick types ...
|
||||
*/
|
||||
|
||||
#define SW_ID_3DP 0
|
||||
#define SW_ID_GP 1
|
||||
#define SW_ID_PP 2
|
||||
#define SW_ID_FFP 3
|
||||
#define SW_ID_FSP 4
|
||||
#define SW_ID_FFW 5
|
||||
|
||||
/*
|
||||
* Names, buttons, axes ...
|
||||
*/
|
||||
|
||||
static char *sw_name[] = { "3D Pro", "GamePad", "Precision Pro", "Force Feedback Pro", "FreeStyle Pro",
|
||||
"Force Feedback Wheel" };
|
||||
|
||||
static char sw_abs[][7] = {
|
||||
{ ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
|
||||
{ ABS_X, ABS_Y },
|
||||
{ ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
|
||||
{ ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
|
||||
{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
|
||||
{ ABS_RX, ABS_RUDDER, ABS_THROTTLE }};
|
||||
|
||||
static char sw_bit[][7] = {
|
||||
{ 10, 10, 9, 10, 1, 1 },
|
||||
{ 1, 1 },
|
||||
{ 10, 10, 6, 7, 1, 1 },
|
||||
{ 10, 10, 6, 7, 1, 1 },
|
||||
{ 10, 10, 6, 1, 1 },
|
||||
{ 10, 7, 7, 1, 1 }};
|
||||
|
||||
static short sw_btn[][12] = {
|
||||
{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_MODE },
|
||||
{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE },
|
||||
{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT },
|
||||
{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT },
|
||||
{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT },
|
||||
{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 }};
|
||||
|
||||
static struct {
|
||||
int x;
|
||||
int y;
|
||||
} sw_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
|
||||
|
||||
struct sw {
|
||||
struct gameport *gameport;
|
||||
struct timer_list timer;
|
||||
struct input_dev dev[4];
|
||||
char name[64];
|
||||
char phys[4][32];
|
||||
int length;
|
||||
int type;
|
||||
int bits;
|
||||
int number;
|
||||
int fail;
|
||||
int ok;
|
||||
int reads;
|
||||
int bads;
|
||||
int used;
|
||||
};
|
||||
|
||||
/*
|
||||
* sw_read_packet() is a function which reads either a data packet, or an
|
||||
* identification packet from a SideWinder joystick. The protocol is very,
|
||||
* very, very braindamaged. Microsoft patented it in US patent #5628686.
|
||||
*/
|
||||
|
||||
static int sw_read_packet(struct gameport *gameport, unsigned char *buf, int length, int id)
|
||||
{
|
||||
unsigned long flags;
|
||||
int timeout, bitout, sched, i, kick, start, strobe;
|
||||
unsigned char pending, u, v;
|
||||
|
||||
i = -id; /* Don't care about data, only want ID */
|
||||
timeout = id ? gameport_time(gameport, SW_TIMEOUT) : 0; /* Set up global timeout for ID packet */
|
||||
kick = id ? gameport_time(gameport, SW_KICK) : 0; /* Set up kick timeout for ID packet */
|
||||
start = gameport_time(gameport, SW_START);
|
||||
strobe = gameport_time(gameport, SW_STROBE);
|
||||
bitout = start;
|
||||
pending = 0;
|
||||
sched = 0;
|
||||
|
||||
local_irq_save(flags); /* Quiet, please */
|
||||
|
||||
gameport_trigger(gameport); /* Trigger */
|
||||
v = gameport_read(gameport);
|
||||
|
||||
do {
|
||||
bitout--;
|
||||
u = v;
|
||||
v = gameport_read(gameport);
|
||||
} while (!(~v & u & 0x10) && (bitout > 0)); /* Wait for first falling edge on clock */
|
||||
|
||||
if (bitout > 0) bitout = strobe; /* Extend time if not timed out */
|
||||
|
||||
while ((timeout > 0 || bitout > 0) && (i < length)) {
|
||||
|
||||
timeout--;
|
||||
bitout--; /* Decrement timers */
|
||||
sched--;
|
||||
|
||||
u = v;
|
||||
v = gameport_read(gameport);
|
||||
|
||||
if ((~u & v & 0x10) && (bitout > 0)) { /* Rising edge on clock - data bit */
|
||||
if (i >= 0) /* Want this data */
|
||||
buf[i] = v >> 5; /* Store it */
|
||||
i++; /* Advance index */
|
||||
bitout = strobe; /* Extend timeout for next bit */
|
||||
}
|
||||
|
||||
if (kick && (~v & u & 0x01)) { /* Falling edge on axis 0 */
|
||||
sched = kick; /* Schedule second trigger */
|
||||
kick = 0; /* Don't schedule next time on falling edge */
|
||||
pending = 1; /* Mark schedule */
|
||||
}
|
||||
|
||||
if (pending && sched < 0 && (i > -SW_END)) { /* Second trigger time */
|
||||
gameport_trigger(gameport); /* Trigger */
|
||||
bitout = start; /* Long bit timeout */
|
||||
pending = 0; /* Unmark schedule */
|
||||
timeout = 0; /* Switch from global to bit timeouts */
|
||||
}
|
||||
}
|
||||
|
||||
local_irq_restore(flags); /* Done - relax */
|
||||
|
||||
#ifdef SW_DEBUG
|
||||
{
|
||||
int j;
|
||||
printk(KERN_DEBUG "sidewinder.c: Read %d triplets. [", i);
|
||||
for (j = 0; j < i; j++) printk("%d", buf[j]);
|
||||
printk("]\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* sw_get_bits() and GB() compose bits from the triplet buffer into a __u64.
|
||||
* Parameter 'pos' is bit number inside packet where to start at, 'num' is number
|
||||
* of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits
|
||||
* is number of bits per triplet.
|
||||
*/
|
||||
|
||||
#define GB(pos,num) sw_get_bits(buf, pos, num, sw->bits)
|
||||
|
||||
static __u64 sw_get_bits(unsigned char *buf, int pos, int num, char bits)
|
||||
{
|
||||
__u64 data = 0;
|
||||
int tri = pos % bits; /* Start position */
|
||||
int i = pos / bits;
|
||||
int bit = 0;
|
||||
|
||||
while (num--) {
|
||||
data |= (__u64)((buf[i] >> tri++) & 1) << bit++; /* Transfer bit */
|
||||
if (tri == bits) {
|
||||
i++; /* Next triplet */
|
||||
tri = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
* sw_init_digital() initializes a SideWinder 3D Pro joystick
|
||||
* into digital mode.
|
||||
*/
|
||||
|
||||
static void sw_init_digital(struct gameport *gameport)
|
||||
{
|
||||
int seq[] = { 140, 140+725, 140+300, 0 };
|
||||
unsigned long flags;
|
||||
int i, t;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
i = 0;
|
||||
do {
|
||||
gameport_trigger(gameport); /* Trigger */
|
||||
t = gameport_time(gameport, SW_TIMEOUT);
|
||||
while ((gameport_read(gameport) & 1) && t) t--; /* Wait for axis to fall back to 0 */
|
||||
udelay(seq[i]); /* Delay magic time */
|
||||
} while (seq[++i]);
|
||||
|
||||
gameport_trigger(gameport); /* Last trigger */
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* sw_parity() computes parity of __u64
|
||||
*/
|
||||
|
||||
static int sw_parity(__u64 t)
|
||||
{
|
||||
int x = t ^ (t >> 32);
|
||||
x ^= x >> 16;
|
||||
x ^= x >> 8;
|
||||
x ^= x >> 4;
|
||||
x ^= x >> 2;
|
||||
x ^= x >> 1;
|
||||
return x & 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* sw_ccheck() checks synchronization bits and computes checksum of nibbles.
|
||||
*/
|
||||
|
||||
static int sw_check(__u64 t)
|
||||
{
|
||||
unsigned char sum = 0;
|
||||
|
||||
if ((t & 0x8080808080808080ULL) ^ 0x80) /* Sync */
|
||||
return -1;
|
||||
|
||||
while (t) { /* Sum */
|
||||
sum += t & 0xf;
|
||||
t >>= 4;
|
||||
}
|
||||
|
||||
return sum & 0xf;
|
||||
}
|
||||
|
||||
/*
|
||||
* sw_parse() analyzes SideWinder joystick data, and writes the results into
|
||||
* the axes and buttons arrays.
|
||||
*/
|
||||
|
||||
static int sw_parse(unsigned char *buf, struct sw *sw)
|
||||
{
|
||||
int hat, i, j;
|
||||
struct input_dev *dev = sw->dev;
|
||||
|
||||
switch (sw->type) {
|
||||
|
||||
case SW_ID_3DP:
|
||||
|
||||
if (sw_check(GB(0,64)) || (hat = (GB(6,1) << 3) | GB(60,3)) > 8) return -1;
|
||||
|
||||
input_report_abs(dev, ABS_X, (GB( 3,3) << 7) | GB(16,7));
|
||||
input_report_abs(dev, ABS_Y, (GB( 0,3) << 7) | GB(24,7));
|
||||
input_report_abs(dev, ABS_RZ, (GB(35,2) << 7) | GB(40,7));
|
||||
input_report_abs(dev, ABS_THROTTLE, (GB(32,3) << 7) | GB(48,7));
|
||||
|
||||
input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
|
||||
input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
|
||||
|
||||
for (j = 0; j < 7; j++)
|
||||
input_report_key(dev, sw_btn[SW_ID_3DP][j], !GB(j+8,1));
|
||||
|
||||
input_report_key(dev, BTN_BASE4, !GB(38,1));
|
||||
input_report_key(dev, BTN_BASE5, !GB(37,1));
|
||||
|
||||
input_sync(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
case SW_ID_GP:
|
||||
|
||||
for (i = 0; i < sw->number; i ++) {
|
||||
|
||||
if (sw_parity(GB(i*15,15))) return -1;
|
||||
|
||||
input_report_abs(dev + i, ABS_X, GB(i*15+3,1) - GB(i*15+2,1));
|
||||
input_report_abs(dev + i, ABS_Y, GB(i*15+0,1) - GB(i*15+1,1));
|
||||
|
||||
for (j = 0; j < 10; j++)
|
||||
input_report_key(dev + i, sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1));
|
||||
|
||||
input_sync(dev + i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
case SW_ID_PP:
|
||||
case SW_ID_FFP:
|
||||
|
||||
if (!sw_parity(GB(0,48)) || (hat = GB(42,4)) > 8) return -1;
|
||||
|
||||
input_report_abs(dev, ABS_X, GB( 9,10));
|
||||
input_report_abs(dev, ABS_Y, GB(19,10));
|
||||
input_report_abs(dev, ABS_RZ, GB(36, 6));
|
||||
input_report_abs(dev, ABS_THROTTLE, GB(29, 7));
|
||||
|
||||
input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
|
||||
input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
|
||||
|
||||
for (j = 0; j < 9; j++)
|
||||
input_report_key(dev, sw_btn[SW_ID_PP][j], !GB(j,1));
|
||||
|
||||
input_sync(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
case SW_ID_FSP:
|
||||
|
||||
if (!sw_parity(GB(0,43)) || (hat = GB(28,4)) > 8) return -1;
|
||||
|
||||
input_report_abs(dev, ABS_X, GB( 0,10));
|
||||
input_report_abs(dev, ABS_Y, GB(16,10));
|
||||
input_report_abs(dev, ABS_THROTTLE, GB(32, 6));
|
||||
|
||||
input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
|
||||
input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
|
||||
|
||||
for (j = 0; j < 6; j++)
|
||||
input_report_key(dev, sw_btn[SW_ID_FSP][j], !GB(j+10,1));
|
||||
|
||||
input_report_key(dev, BTN_TR, !GB(26,1));
|
||||
input_report_key(dev, BTN_START, !GB(27,1));
|
||||
input_report_key(dev, BTN_MODE, !GB(38,1));
|
||||
input_report_key(dev, BTN_SELECT, !GB(39,1));
|
||||
|
||||
input_sync(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
case SW_ID_FFW:
|
||||
|
||||
if (!sw_parity(GB(0,33))) return -1;
|
||||
|
||||
input_report_abs(dev, ABS_RX, GB( 0,10));
|
||||
input_report_abs(dev, ABS_RUDDER, GB(10, 6));
|
||||
input_report_abs(dev, ABS_THROTTLE, GB(16, 6));
|
||||
|
||||
for (j = 0; j < 8; j++)
|
||||
input_report_key(dev, sw_btn[SW_ID_FFW][j], !GB(j+22,1));
|
||||
|
||||
input_sync(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* sw_read() reads SideWinder joystick data, and reinitializes
|
||||
* the joystick in case of persistent problems. This is the function that is
|
||||
* called from the generic code to poll the joystick.
|
||||
*/
|
||||
|
||||
static int sw_read(struct sw *sw)
|
||||
{
|
||||
unsigned char buf[SW_LENGTH];
|
||||
int i;
|
||||
|
||||
i = sw_read_packet(sw->gameport, buf, sw->length, 0);
|
||||
|
||||
if (sw->type == SW_ID_3DP && sw->length == 66 && i != 66) { /* Broken packet, try to fix */
|
||||
|
||||
if (i == 64 && !sw_check(sw_get_bits(buf,0,64,1))) { /* Last init failed, 1 bit mode */
|
||||
printk(KERN_WARNING "sidewinder.c: Joystick in wrong mode on %s"
|
||||
" - going to reinitialize.\n", sw->gameport->phys);
|
||||
sw->fail = SW_FAIL; /* Reinitialize */
|
||||
i = 128; /* Bogus value */
|
||||
}
|
||||
|
||||
if (i < 66 && GB(0,64) == GB(i*3-66,64)) /* 1 == 3 */
|
||||
i = 66; /* Everything is fine */
|
||||
|
||||
if (i < 66 && GB(0,64) == GB(66,64)) /* 1 == 2 */
|
||||
i = 66; /* Everything is fine */
|
||||
|
||||
if (i < 66 && GB(i*3-132,64) == GB(i*3-66,64)) { /* 2 == 3 */
|
||||
memmove(buf, buf + i - 22, 22); /* Move data */
|
||||
i = 66; /* Carry on */
|
||||
}
|
||||
}
|
||||
|
||||
if (i == sw->length && !sw_parse(buf, sw)) { /* Parse data */
|
||||
|
||||
sw->fail = 0;
|
||||
sw->ok++;
|
||||
|
||||
if (sw->type == SW_ID_3DP && sw->length == 66 /* Many packets OK */
|
||||
&& sw->ok > SW_OK) {
|
||||
|
||||
printk(KERN_INFO "sidewinder.c: No more trouble on %s"
|
||||
" - enabling optimization again.\n", sw->gameport->phys);
|
||||
sw->length = 22;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sw->ok = 0;
|
||||
sw->fail++;
|
||||
|
||||
if (sw->type == SW_ID_3DP && sw->length == 22 && sw->fail > SW_BAD) { /* Consecutive bad packets */
|
||||
|
||||
printk(KERN_INFO "sidewinder.c: Many bit errors on %s"
|
||||
" - disabling optimization.\n", sw->gameport->phys);
|
||||
sw->length = 66;
|
||||
}
|
||||
|
||||
if (sw->fail < SW_FAIL) return -1; /* Not enough, don't reinitialize yet */
|
||||
|
||||
printk(KERN_WARNING "sidewinder.c: Too many bit errors on %s"
|
||||
" - reinitializing joystick.\n", sw->gameport->phys);
|
||||
|
||||
if (!i && sw->type == SW_ID_3DP) { /* 3D Pro can be in analog mode */
|
||||
udelay(3 * SW_TIMEOUT);
|
||||
sw_init_digital(sw->gameport);
|
||||
}
|
||||
|
||||
udelay(SW_TIMEOUT);
|
||||
i = sw_read_packet(sw->gameport, buf, SW_LENGTH, 0); /* Read normal data packet */
|
||||
udelay(SW_TIMEOUT);
|
||||
sw_read_packet(sw->gameport, buf, SW_LENGTH, i); /* Read ID packet, this initializes the stick */
|
||||
|
||||
sw->fail = SW_FAIL;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void sw_timer(unsigned long private)
|
||||
{
|
||||
struct sw *sw = (void *) private;
|
||||
|
||||
sw->reads++;
|
||||
if (sw_read(sw)) sw->bads++;
|
||||
mod_timer(&sw->timer, jiffies + SW_REFRESH);
|
||||
}
|
||||
|
||||
static int sw_open(struct input_dev *dev)
|
||||
{
|
||||
struct sw *sw = dev->private;
|
||||
if (!sw->used++)
|
||||
mod_timer(&sw->timer, jiffies + SW_REFRESH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sw_close(struct input_dev *dev)
|
||||
{
|
||||
struct sw *sw = dev->private;
|
||||
if (!--sw->used)
|
||||
del_timer(&sw->timer);
|
||||
}
|
||||
|
||||
/*
|
||||
* sw_print_packet() prints the contents of a SideWinder packet.
|
||||
*/
|
||||
|
||||
static void sw_print_packet(char *name, int length, unsigned char *buf, char bits)
|
||||
{
|
||||
int i;
|
||||
|
||||
printk(KERN_INFO "sidewinder.c: %s packet, %d bits. [", name, length);
|
||||
for (i = (((length + 3) >> 2) - 1); i >= 0; i--)
|
||||
printk("%x", (int)sw_get_bits(buf, i << 2, 4, bits));
|
||||
printk("]\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* sw_3dp_id() translates the 3DP id into a human legible string.
|
||||
* Unfortunately I don't know how to do this for the other SW types.
|
||||
*/
|
||||
|
||||
static void sw_3dp_id(unsigned char *buf, char *comment)
|
||||
{
|
||||
int i;
|
||||
char pnp[8], rev[9];
|
||||
|
||||
for (i = 0; i < 7; i++) /* ASCII PnP ID */
|
||||
pnp[i] = sw_get_bits(buf, 24+8*i, 8, 1);
|
||||
|
||||
for (i = 0; i < 8; i++) /* ASCII firmware revision */
|
||||
rev[i] = sw_get_bits(buf, 88+8*i, 8, 1);
|
||||
|
||||
pnp[7] = rev[8] = 0;
|
||||
|
||||
sprintf(comment, " [PnP %d.%02d id %s rev %s]",
|
||||
(int) ((sw_get_bits(buf, 8, 6, 1) << 6) | /* Two 6-bit values */
|
||||
sw_get_bits(buf, 16, 6, 1)) / 100,
|
||||
(int) ((sw_get_bits(buf, 8, 6, 1) << 6) |
|
||||
sw_get_bits(buf, 16, 6, 1)) % 100,
|
||||
pnp, rev);
|
||||
}
|
||||
|
||||
/*
|
||||
* sw_guess_mode() checks the upper two button bits for toggling -
|
||||
* indication of that the joystick is in 3-bit mode. This is documented
|
||||
* behavior for 3DP ID packet, and for example the FSP does this in
|
||||
* normal packets instead. Fun ...
|
||||
*/
|
||||
|
||||
static int sw_guess_mode(unsigned char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
unsigned char xor = 0;
|
||||
for (i = 1; i < len; i++) xor |= (buf[i - 1] ^ buf[i]) & 6;
|
||||
return !!xor * 2 + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* sw_connect() probes for SideWinder type joysticks.
|
||||
*/
|
||||
|
||||
static void sw_connect(struct gameport *gameport, struct gameport_dev *dev)
|
||||
{
|
||||
struct sw *sw;
|
||||
int i, j, k, l;
|
||||
unsigned char *buf = NULL; /* [SW_LENGTH] */
|
||||
unsigned char *idbuf = NULL; /* [SW_LENGTH] */
|
||||
unsigned char m = 1;
|
||||
char comment[40];
|
||||
|
||||
comment[0] = 0;
|
||||
|
||||
if (!(sw = kmalloc(sizeof(struct sw), GFP_KERNEL))) return;
|
||||
memset(sw, 0, sizeof(struct sw));
|
||||
|
||||
buf = kmalloc(SW_LENGTH, GFP_KERNEL);
|
||||
idbuf = kmalloc(SW_LENGTH, GFP_KERNEL);
|
||||
if (!buf || !idbuf)
|
||||
goto fail1;
|
||||
|
||||
gameport->private = sw;
|
||||
|
||||
sw->gameport = gameport;
|
||||
init_timer(&sw->timer);
|
||||
sw->timer.data = (long) sw;
|
||||
sw->timer.function = sw_timer;
|
||||
|
||||
if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
|
||||
goto fail1;
|
||||
|
||||
dbg("Init 0: Opened %s, io %#x, speed %d",
|
||||
gameport->phys, gameport->io, gameport->speed);
|
||||
|
||||
i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read normal packet */
|
||||
udelay(SW_TIMEOUT);
|
||||
dbg("Init 1: Mode %d. Length %d.", m , i);
|
||||
|
||||
if (!i) { /* No data. 3d Pro analog mode? */
|
||||
sw_init_digital(gameport); /* Switch to digital */
|
||||
udelay(SW_TIMEOUT);
|
||||
i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Retry reading packet */
|
||||
udelay(SW_TIMEOUT);
|
||||
dbg("Init 1b: Length %d.", i);
|
||||
if (!i) goto fail2; /* No data -> FAIL */
|
||||
}
|
||||
|
||||
j = sw_read_packet(gameport, idbuf, SW_LENGTH, i); /* Read ID. This initializes the stick */
|
||||
m |= sw_guess_mode(idbuf, j); /* ID packet should carry mode info [3DP] */
|
||||
dbg("Init 2: Mode %d. ID Length %d.", m , j);
|
||||
|
||||
if (!j) { /* Read ID failed. Happens in 1-bit mode on PP */
|
||||
udelay(SW_TIMEOUT);
|
||||
i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Retry reading packet */
|
||||
dbg("Init 2b: Mode %d. Length %d.", m, i);
|
||||
if (!i) goto fail2;
|
||||
udelay(SW_TIMEOUT);
|
||||
j = sw_read_packet(gameport, idbuf, SW_LENGTH, i); /* Retry reading ID */
|
||||
dbg("Init 2c: ID Length %d.", j);
|
||||
}
|
||||
|
||||
sw->type = -1;
|
||||
k = SW_FAIL; /* Try SW_FAIL times */
|
||||
l = 0;
|
||||
|
||||
do {
|
||||
k--;
|
||||
udelay(SW_TIMEOUT);
|
||||
i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read data packet */
|
||||
dbg("Init 3: Mode %d. Length %d. Last %d. Tries %d.", m, i, l, k);
|
||||
|
||||
if (i > l) { /* Longer? As we can only lose bits, it makes */
|
||||
/* no sense to try detection for a packet shorter */
|
||||
l = i; /* than the previous one */
|
||||
|
||||
sw->number = 1;
|
||||
sw->gameport = gameport;
|
||||
sw->length = i;
|
||||
sw->bits = m;
|
||||
|
||||
dbg("Init 3a: Case %d.\n", i * m);
|
||||
|
||||
switch (i * m) {
|
||||
case 60:
|
||||
sw->number++;
|
||||
case 45: /* Ambiguous packet length */
|
||||
if (j <= 40) { /* ID length less or eq 40 -> FSP */
|
||||
case 43:
|
||||
sw->type = SW_ID_FSP;
|
||||
break;
|
||||
}
|
||||
sw->number++;
|
||||
case 30:
|
||||
sw->number++;
|
||||
case 15:
|
||||
sw->type = SW_ID_GP;
|
||||
break;
|
||||
case 33:
|
||||
case 31:
|
||||
sw->type = SW_ID_FFW;
|
||||
break;
|
||||
case 48: /* Ambiguous */
|
||||
if (j == 14) { /* ID length 14*3 -> FFP */
|
||||
sw->type = SW_ID_FFP;
|
||||
sprintf(comment, " [AC %s]", sw_get_bits(idbuf,38,1,3) ? "off" : "on");
|
||||
} else
|
||||
sw->type = SW_ID_PP;
|
||||
break;
|
||||
case 66:
|
||||
sw->bits = 3;
|
||||
case 198:
|
||||
sw->length = 22;
|
||||
case 64:
|
||||
sw->type = SW_ID_3DP;
|
||||
if (j == 160) sw_3dp_id(idbuf, comment);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} while (k && (sw->type == -1));
|
||||
|
||||
if (sw->type == -1) {
|
||||
printk(KERN_WARNING "sidewinder.c: unknown joystick device detected "
|
||||
"on %s, contact <vojtech@ucw.cz>\n", gameport->phys);
|
||||
sw_print_packet("ID", j * 3, idbuf, 3);
|
||||
sw_print_packet("Data", i * m, buf, m);
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
#ifdef SW_DEBUG
|
||||
sw_print_packet("ID", j * 3, idbuf, 3);
|
||||
sw_print_packet("Data", i * m, buf, m);
|
||||
#endif
|
||||
|
||||
k = i;
|
||||
l = j;
|
||||
|
||||
for (i = 0; i < sw->number; i++) {
|
||||
int bits, code;
|
||||
|
||||
sprintf(sw->name, "Microsoft SideWinder %s", sw_name[sw->type]);
|
||||
sprintf(sw->phys[i], "%s/input%d", gameport->phys, i);
|
||||
|
||||
sw->dev[i].private = sw;
|
||||
|
||||
sw->dev[i].open = sw_open;
|
||||
sw->dev[i].close = sw_close;
|
||||
|
||||
sw->dev[i].name = sw->name;
|
||||
sw->dev[i].phys = sw->phys[i];
|
||||
sw->dev[i].id.bustype = BUS_GAMEPORT;
|
||||
sw->dev[i].id.vendor = GAMEPORT_ID_VENDOR_MICROSOFT;
|
||||
sw->dev[i].id.product = sw->type;
|
||||
sw->dev[i].id.version = 0x0100;
|
||||
|
||||
sw->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
|
||||
for (j = 0; (bits = sw_bit[sw->type][j]); j++) {
|
||||
code = sw_abs[sw->type][j];
|
||||
set_bit(code, sw->dev[i].absbit);
|
||||
sw->dev[i].absmax[code] = (1 << bits) - 1;
|
||||
sw->dev[i].absmin[code] = (bits == 1) ? -1 : 0;
|
||||
sw->dev[i].absfuzz[code] = ((bits >> 1) >= 2) ? (1 << ((bits >> 1) - 2)) : 0;
|
||||
if (code != ABS_THROTTLE)
|
||||
sw->dev[i].absflat[code] = (bits >= 5) ? (1 << (bits - 5)) : 0;
|
||||
}
|
||||
|
||||
for (j = 0; (code = sw_btn[sw->type][j]); j++)
|
||||
set_bit(code, sw->dev[i].keybit);
|
||||
|
||||
input_register_device(sw->dev + i);
|
||||
printk(KERN_INFO "input: %s%s on %s [%d-bit id %d data %d]\n",
|
||||
sw->name, comment, gameport->phys, m, l, k);
|
||||
}
|
||||
|
||||
return;
|
||||
fail2: gameport_close(gameport);
|
||||
fail1: kfree(sw);
|
||||
kfree(buf);
|
||||
kfree(idbuf);
|
||||
}
|
||||
|
||||
static void sw_disconnect(struct gameport *gameport)
|
||||
{
|
||||
int i;
|
||||
|
||||
struct sw *sw = gameport->private;
|
||||
for (i = 0; i < sw->number; i++)
|
||||
input_unregister_device(sw->dev + i);
|
||||
gameport_close(gameport);
|
||||
kfree(sw);
|
||||
}
|
||||
|
||||
static struct gameport_dev sw_dev = {
|
||||
.connect = sw_connect,
|
||||
.disconnect = sw_disconnect,
|
||||
};
|
||||
|
||||
int __init sw_init(void)
|
||||
{
|
||||
gameport_register_device(&sw_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit sw_exit(void)
|
||||
{
|
||||
gameport_unregister_device(&sw_dev);
|
||||
}
|
||||
|
||||
module_init(sw_init);
|
||||
module_exit(sw_exit);
|
||||
300
extra/linux-2.6.10/drivers/input/joystick/spaceball.c
Normal file
300
extra/linux-2.6.10/drivers/input/joystick/spaceball.c
Normal file
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* $Id: spaceball.c,v 1.17 2002/01/22 20:29:03 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1999-2001 Vojtech Pavlik
|
||||
*
|
||||
* Based on the work of:
|
||||
* David Thompson
|
||||
* Joseph Krahn
|
||||
*/
|
||||
|
||||
/*
|
||||
* SpaceTec SpaceBall 2003/3003/4000 FLX driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/serio.h>
|
||||
|
||||
#define DRIVER_DESC "SpaceTec SpaceBall 2003/3003/4000 FLX driver"
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
* Constants.
|
||||
*/
|
||||
|
||||
#define SPACEBALL_MAX_LENGTH 128
|
||||
#define SPACEBALL_MAX_ID 8
|
||||
|
||||
#define SPACEBALL_1003 1
|
||||
#define SPACEBALL_2003B 3
|
||||
#define SPACEBALL_2003C 4
|
||||
#define SPACEBALL_3003C 7
|
||||
#define SPACEBALL_4000FLX 8
|
||||
#define SPACEBALL_4000FLX_L 9
|
||||
|
||||
static int spaceball_axes[] = { ABS_X, ABS_Z, ABS_Y, ABS_RX, ABS_RZ, ABS_RY };
|
||||
static char *spaceball_names[] = {
|
||||
"?", "SpaceTec SpaceBall 1003", "SpaceTec SpaceBall 2003", "SpaceTec SpaceBall 2003B",
|
||||
"SpaceTec SpaceBall 2003C", "SpaceTec SpaceBall 3003", "SpaceTec SpaceBall SpaceController",
|
||||
"SpaceTec SpaceBall 3003C", "SpaceTec SpaceBall 4000FLX", "SpaceTec SpaceBall 4000FLX Lefty" };
|
||||
|
||||
/*
|
||||
* Per-Ball data.
|
||||
*/
|
||||
|
||||
struct spaceball {
|
||||
struct input_dev dev;
|
||||
struct serio *serio;
|
||||
int idx;
|
||||
int escape;
|
||||
unsigned char data[SPACEBALL_MAX_LENGTH];
|
||||
char phys[32];
|
||||
};
|
||||
|
||||
/*
|
||||
* spaceball_process_packet() decodes packets the driver receives from the
|
||||
* SpaceBall.
|
||||
*/
|
||||
|
||||
static void spaceball_process_packet(struct spaceball* spaceball, struct pt_regs *regs)
|
||||
{
|
||||
struct input_dev *dev = &spaceball->dev;
|
||||
unsigned char *data = spaceball->data;
|
||||
int i;
|
||||
|
||||
if (spaceball->idx < 2) return;
|
||||
|
||||
input_regs(dev, regs);
|
||||
|
||||
switch (spaceball->data[0]) {
|
||||
|
||||
case 'D': /* Ball data */
|
||||
if (spaceball->idx != 15) return;
|
||||
for (i = 0; i < 6; i++)
|
||||
input_report_abs(dev, spaceball_axes[i],
|
||||
(__s16)((data[2 * i + 3] << 8) | data[2 * i + 2]));
|
||||
break;
|
||||
|
||||
case 'K': /* Button data */
|
||||
if (spaceball->idx != 3) return;
|
||||
input_report_key(dev, BTN_1, (data[2] & 0x01) || (data[2] & 0x20));
|
||||
input_report_key(dev, BTN_2, data[2] & 0x02);
|
||||
input_report_key(dev, BTN_3, data[2] & 0x04);
|
||||
input_report_key(dev, BTN_4, data[2] & 0x08);
|
||||
input_report_key(dev, BTN_5, data[1] & 0x01);
|
||||
input_report_key(dev, BTN_6, data[1] & 0x02);
|
||||
input_report_key(dev, BTN_7, data[1] & 0x04);
|
||||
input_report_key(dev, BTN_8, data[1] & 0x10);
|
||||
break;
|
||||
|
||||
case '.': /* Advanced button data */
|
||||
if (spaceball->idx != 3) return;
|
||||
input_report_key(dev, BTN_1, data[2] & 0x01);
|
||||
input_report_key(dev, BTN_2, data[2] & 0x02);
|
||||
input_report_key(dev, BTN_3, data[2] & 0x04);
|
||||
input_report_key(dev, BTN_4, data[2] & 0x08);
|
||||
input_report_key(dev, BTN_5, data[2] & 0x10);
|
||||
input_report_key(dev, BTN_6, data[2] & 0x20);
|
||||
input_report_key(dev, BTN_7, data[2] & 0x80);
|
||||
input_report_key(dev, BTN_8, data[1] & 0x01);
|
||||
input_report_key(dev, BTN_9, data[1] & 0x02);
|
||||
input_report_key(dev, BTN_A, data[1] & 0x04);
|
||||
input_report_key(dev, BTN_B, data[1] & 0x08);
|
||||
input_report_key(dev, BTN_C, data[1] & 0x10);
|
||||
input_report_key(dev, BTN_MODE, data[1] & 0x20);
|
||||
break;
|
||||
|
||||
case 'E': /* Device error */
|
||||
spaceball->data[spaceball->idx - 1] = 0;
|
||||
printk(KERN_ERR "spaceball: Device error. [%s]\n", spaceball->data + 1);
|
||||
break;
|
||||
|
||||
case '?': /* Bad command packet */
|
||||
spaceball->data[spaceball->idx - 1] = 0;
|
||||
printk(KERN_ERR "spaceball: Bad command. [%s]\n", spaceball->data + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
input_sync(dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Spaceball 4000 FLX packets all start with a one letter packet-type decriptor,
|
||||
* and end in 0x0d. It uses '^' as an escape for CR, XOFF and XON characters which
|
||||
* can occur in the axis values.
|
||||
*/
|
||||
|
||||
static irqreturn_t spaceball_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags, struct pt_regs *regs)
|
||||
{
|
||||
struct spaceball *spaceball = serio->private;
|
||||
|
||||
switch (data) {
|
||||
case 0xd:
|
||||
spaceball_process_packet(spaceball, regs);
|
||||
spaceball->idx = 0;
|
||||
spaceball->escape = 0;
|
||||
break;
|
||||
case '^':
|
||||
if (!spaceball->escape) {
|
||||
spaceball->escape = 1;
|
||||
break;
|
||||
}
|
||||
spaceball->escape = 0;
|
||||
case 'M':
|
||||
case 'Q':
|
||||
case 'S':
|
||||
if (spaceball->escape) {
|
||||
spaceball->escape = 0;
|
||||
data &= 0x1f;
|
||||
}
|
||||
default:
|
||||
if (spaceball->escape)
|
||||
spaceball->escape = 0;
|
||||
if (spaceball->idx < SPACEBALL_MAX_LENGTH)
|
||||
spaceball->data[spaceball->idx++] = data;
|
||||
break;
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* spaceball_disconnect() is the opposite of spaceball_connect()
|
||||
*/
|
||||
|
||||
static void spaceball_disconnect(struct serio *serio)
|
||||
{
|
||||
struct spaceball* spaceball = serio->private;
|
||||
input_unregister_device(&spaceball->dev);
|
||||
serio_close(serio);
|
||||
kfree(spaceball);
|
||||
}
|
||||
|
||||
/*
|
||||
* spaceball_connect() is the routine that is called when someone adds a
|
||||
* new serio device. It looks for the Magellan, and if found, registers
|
||||
* it as an input device.
|
||||
*/
|
||||
|
||||
static void spaceball_connect(struct serio *serio, struct serio_driver *drv)
|
||||
{
|
||||
struct spaceball *spaceball;
|
||||
int i, t, id;
|
||||
|
||||
if ((serio->type & ~SERIO_ID) != (SERIO_RS232 | SERIO_SPACEBALL))
|
||||
return;
|
||||
|
||||
if ((id = (serio->type & SERIO_ID) >> 8) > SPACEBALL_MAX_ID)
|
||||
return;
|
||||
|
||||
if (!(spaceball = kmalloc(sizeof(struct spaceball), GFP_KERNEL)))
|
||||
return;
|
||||
memset(spaceball, 0, sizeof(struct spaceball));
|
||||
|
||||
spaceball->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
|
||||
switch (id) {
|
||||
case SPACEBALL_4000FLX:
|
||||
case SPACEBALL_4000FLX_L:
|
||||
spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_9);
|
||||
spaceball->dev.keybit[LONG(BTN_A)] |= BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_MODE);
|
||||
default:
|
||||
spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4)
|
||||
| BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7) | BIT(BTN_8);
|
||||
case SPACEBALL_3003C:
|
||||
spaceball->dev.keybit[LONG(BTN_0)] |= BIT(BTN_1) | BIT(BTN_8);
|
||||
}
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
t = spaceball_axes[i];
|
||||
set_bit(t, spaceball->dev.absbit);
|
||||
spaceball->dev.absmin[t] = i < 3 ? -8000 : -1600;
|
||||
spaceball->dev.absmax[t] = i < 3 ? 8000 : 1600;
|
||||
spaceball->dev.absflat[t] = i < 3 ? 40 : 8;
|
||||
spaceball->dev.absfuzz[t] = i < 3 ? 8 : 2;
|
||||
}
|
||||
|
||||
spaceball->serio = serio;
|
||||
spaceball->dev.private = spaceball;
|
||||
|
||||
sprintf(spaceball->phys, "%s/input0", serio->phys);
|
||||
|
||||
init_input_dev(&spaceball->dev);
|
||||
spaceball->dev.name = spaceball_names[id];
|
||||
spaceball->dev.phys = spaceball->phys;
|
||||
spaceball->dev.id.bustype = BUS_RS232;
|
||||
spaceball->dev.id.vendor = SERIO_SPACEBALL;
|
||||
spaceball->dev.id.product = id;
|
||||
spaceball->dev.id.version = 0x0100;
|
||||
|
||||
serio->private = spaceball;
|
||||
|
||||
if (serio_open(serio, drv)) {
|
||||
kfree(spaceball);
|
||||
return;
|
||||
}
|
||||
|
||||
input_register_device(&spaceball->dev);
|
||||
|
||||
printk(KERN_INFO "input: %s on serio%s\n",
|
||||
spaceball_names[id], serio->phys);
|
||||
}
|
||||
|
||||
/*
|
||||
* The serio device structure.
|
||||
*/
|
||||
|
||||
static struct serio_driver spaceball_drv = {
|
||||
.driver = {
|
||||
.name = "spaceball",
|
||||
},
|
||||
.description = DRIVER_DESC,
|
||||
.interrupt = spaceball_interrupt,
|
||||
.connect = spaceball_connect,
|
||||
.disconnect = spaceball_disconnect,
|
||||
};
|
||||
|
||||
/*
|
||||
* The functions for inserting/removing us as a module.
|
||||
*/
|
||||
|
||||
int __init spaceball_init(void)
|
||||
{
|
||||
serio_register_driver(&spaceball_drv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit spaceball_exit(void)
|
||||
{
|
||||
serio_unregister_driver(&spaceball_drv);
|
||||
}
|
||||
|
||||
module_init(spaceball_init);
|
||||
module_exit(spaceball_exit);
|
||||
244
extra/linux-2.6.10/drivers/input/joystick/spaceorb.c
Normal file
244
extra/linux-2.6.10/drivers/input/joystick/spaceorb.c
Normal file
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* $Id: spaceorb.c,v 1.15 2002/01/22 20:29:19 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1999-2001 Vojtech Pavlik
|
||||
*
|
||||
* Based on the work of:
|
||||
* David Thompson
|
||||
*/
|
||||
|
||||
/*
|
||||
* SpaceTec SpaceOrb 360 and Avenger 6dof controller driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/serio.h>
|
||||
|
||||
#define DRIVER_DESC "SpaceTec SpaceOrb 360 and Avenger 6dof controller driver"
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
* Constants.
|
||||
*/
|
||||
|
||||
#define SPACEORB_MAX_LENGTH 64
|
||||
|
||||
static int spaceorb_buttons[] = { BTN_TL, BTN_TR, BTN_Y, BTN_X, BTN_B, BTN_A };
|
||||
static int spaceorb_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ };
|
||||
static char *spaceorb_name = "SpaceTec SpaceOrb 360 / Avenger";
|
||||
|
||||
/*
|
||||
* Per-Orb data.
|
||||
*/
|
||||
|
||||
struct spaceorb {
|
||||
struct input_dev dev;
|
||||
struct serio *serio;
|
||||
int idx;
|
||||
unsigned char data[SPACEORB_MAX_LENGTH];
|
||||
char phys[32];
|
||||
};
|
||||
|
||||
static unsigned char spaceorb_xor[] = "SpaceWare";
|
||||
|
||||
static unsigned char *spaceorb_errors[] = { "EEPROM storing 0 failed", "Receive queue overflow", "Transmit queue timeout",
|
||||
"Bad packet", "Power brown-out", "EEPROM checksum error", "Hardware fault" };
|
||||
|
||||
/*
|
||||
* spaceorb_process_packet() decodes packets the driver receives from the
|
||||
* SpaceOrb.
|
||||
*/
|
||||
|
||||
static void spaceorb_process_packet(struct spaceorb *spaceorb, struct pt_regs *regs)
|
||||
{
|
||||
struct input_dev *dev = &spaceorb->dev;
|
||||
unsigned char *data = spaceorb->data;
|
||||
unsigned char c = 0;
|
||||
int axes[6];
|
||||
int i;
|
||||
|
||||
if (spaceorb->idx < 2) return;
|
||||
for (i = 0; i < spaceorb->idx; i++) c ^= data[i];
|
||||
if (c) return;
|
||||
|
||||
input_regs(dev, regs);
|
||||
|
||||
switch (data[0]) {
|
||||
|
||||
case 'R': /* Reset packet */
|
||||
spaceorb->data[spaceorb->idx - 1] = 0;
|
||||
for (i = 1; i < spaceorb->idx && spaceorb->data[i] == ' '; i++);
|
||||
printk(KERN_INFO "input: %s [%s] on %s\n",
|
||||
spaceorb_name, spaceorb->data + i, spaceorb->serio->phys);
|
||||
break;
|
||||
|
||||
case 'D': /* Ball + button data */
|
||||
if (spaceorb->idx != 12) return;
|
||||
for (i = 0; i < 9; i++) spaceorb->data[i+2] ^= spaceorb_xor[i];
|
||||
axes[0] = ( data[2] << 3) | (data[ 3] >> 4);
|
||||
axes[1] = ((data[3] & 0x0f) << 6) | (data[ 4] >> 1);
|
||||
axes[2] = ((data[4] & 0x01) << 9) | (data[ 5] << 2) | (data[4] >> 5);
|
||||
axes[3] = ((data[6] & 0x1f) << 5) | (data[ 7] >> 2);
|
||||
axes[4] = ((data[7] & 0x03) << 8) | (data[ 8] << 1) | (data[7] >> 6);
|
||||
axes[5] = ((data[9] & 0x3f) << 4) | (data[10] >> 3);
|
||||
for (i = 0; i < 6; i++)
|
||||
input_report_abs(dev, spaceorb_axes[i], axes[i] - ((axes[i] & 0x200) ? 1024 : 0));
|
||||
for (i = 0; i < 6; i++)
|
||||
input_report_key(dev, spaceorb_buttons[i], (data[1] >> i) & 1);
|
||||
break;
|
||||
|
||||
case 'K': /* Button data */
|
||||
if (spaceorb->idx != 5) return;
|
||||
for (i = 0; i < 7; i++)
|
||||
input_report_key(dev, spaceorb_buttons[i], (data[2] >> i) & 1);
|
||||
|
||||
break;
|
||||
|
||||
case 'E': /* Error packet */
|
||||
if (spaceorb->idx != 4) return;
|
||||
printk(KERN_ERR "joy-spaceorb: Device error. [ ");
|
||||
for (i = 0; i < 7; i++) if (data[1] & (1 << i)) printk("%s ", spaceorb_errors[i]);
|
||||
printk("]\n");
|
||||
break;
|
||||
}
|
||||
|
||||
input_sync(dev);
|
||||
}
|
||||
|
||||
static irqreturn_t spaceorb_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags, struct pt_regs *regs)
|
||||
{
|
||||
struct spaceorb* spaceorb = serio->private;
|
||||
|
||||
if (~data & 0x80) {
|
||||
if (spaceorb->idx) spaceorb_process_packet(spaceorb, regs);
|
||||
spaceorb->idx = 0;
|
||||
}
|
||||
if (spaceorb->idx < SPACEORB_MAX_LENGTH)
|
||||
spaceorb->data[spaceorb->idx++] = data & 0x7f;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* spaceorb_disconnect() is the opposite of spaceorb_connect()
|
||||
*/
|
||||
|
||||
static void spaceorb_disconnect(struct serio *serio)
|
||||
{
|
||||
struct spaceorb* spaceorb = serio->private;
|
||||
input_unregister_device(&spaceorb->dev);
|
||||
serio_close(serio);
|
||||
kfree(spaceorb);
|
||||
}
|
||||
|
||||
/*
|
||||
* spaceorb_connect() is the routine that is called when someone adds a
|
||||
* new serio device. It looks for the SpaceOrb/Avenger, and if found, registers
|
||||
* it as an input device.
|
||||
*/
|
||||
|
||||
static void spaceorb_connect(struct serio *serio, struct serio_driver *drv)
|
||||
{
|
||||
struct spaceorb *spaceorb;
|
||||
int i, t;
|
||||
|
||||
if (serio->type != (SERIO_RS232 | SERIO_SPACEORB))
|
||||
return;
|
||||
|
||||
if (!(spaceorb = kmalloc(sizeof(struct spaceorb), GFP_KERNEL)))
|
||||
return;
|
||||
memset(spaceorb, 0, sizeof(struct spaceorb));
|
||||
|
||||
spaceorb->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
set_bit(spaceorb_buttons[i], spaceorb->dev.keybit);
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
t = spaceorb_axes[i];
|
||||
set_bit(t, spaceorb->dev.absbit);
|
||||
spaceorb->dev.absmin[t] = -508;
|
||||
spaceorb->dev.absmax[t] = 508;
|
||||
}
|
||||
|
||||
spaceorb->serio = serio;
|
||||
spaceorb->dev.private = spaceorb;
|
||||
|
||||
sprintf(spaceorb->phys, "%s/input0", serio->phys);
|
||||
|
||||
init_input_dev(&spaceorb->dev);
|
||||
spaceorb->dev.name = spaceorb_name;
|
||||
spaceorb->dev.phys = spaceorb->phys;
|
||||
spaceorb->dev.id.bustype = BUS_RS232;
|
||||
spaceorb->dev.id.vendor = SERIO_SPACEORB;
|
||||
spaceorb->dev.id.product = 0x0001;
|
||||
spaceorb->dev.id.version = 0x0100;
|
||||
|
||||
serio->private = spaceorb;
|
||||
|
||||
if (serio_open(serio, drv)) {
|
||||
kfree(spaceorb);
|
||||
return;
|
||||
}
|
||||
|
||||
input_register_device(&spaceorb->dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* The serio device structure.
|
||||
*/
|
||||
|
||||
static struct serio_driver spaceorb_drv = {
|
||||
.driver = {
|
||||
.name = "spaceorb",
|
||||
},
|
||||
.description = DRIVER_DESC,
|
||||
.interrupt = spaceorb_interrupt,
|
||||
.connect = spaceorb_connect,
|
||||
.disconnect = spaceorb_disconnect,
|
||||
};
|
||||
|
||||
/*
|
||||
* The functions for inserting/removing us as a module.
|
||||
*/
|
||||
|
||||
int __init spaceorb_init(void)
|
||||
{
|
||||
serio_register_driver(&spaceorb_drv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit spaceorb_exit(void)
|
||||
{
|
||||
serio_unregister_driver(&spaceorb_drv);
|
||||
}
|
||||
|
||||
module_init(spaceorb_init);
|
||||
module_exit(spaceorb_exit);
|
||||
218
extra/linux-2.6.10/drivers/input/joystick/stinger.c
Normal file
218
extra/linux-2.6.10/drivers/input/joystick/stinger.c
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* $Id: stinger.c,v 1.10 2002/01/22 20:29:31 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 2000-2001 Vojtech Pavlik
|
||||
* Copyright (c) 2000 Mark Fletcher
|
||||
*/
|
||||
|
||||
/*
|
||||
* Gravis Stinger gamepad driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free warftware; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/serio.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#define DRIVER_DESC "Gravis Stinger gamepad driver"
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
* Constants.
|
||||
*/
|
||||
|
||||
#define STINGER_MAX_LENGTH 8
|
||||
|
||||
static char *stinger_name = "Gravis Stinger";
|
||||
|
||||
/*
|
||||
* Per-Stinger data.
|
||||
*/
|
||||
|
||||
struct stinger {
|
||||
struct input_dev dev;
|
||||
int idx;
|
||||
unsigned char data[STINGER_MAX_LENGTH];
|
||||
char phys[32];
|
||||
};
|
||||
|
||||
/*
|
||||
* stinger_process_packet() decodes packets the driver receives from the
|
||||
* Stinger. It updates the data accordingly.
|
||||
*/
|
||||
|
||||
static void stinger_process_packet(struct stinger *stinger, struct pt_regs *regs)
|
||||
{
|
||||
struct input_dev *dev = &stinger->dev;
|
||||
unsigned char *data = stinger->data;
|
||||
|
||||
if (!stinger->idx) return;
|
||||
|
||||
input_regs(dev, regs);
|
||||
|
||||
input_report_key(dev, BTN_A, ((data[0] & 0x20) >> 5));
|
||||
input_report_key(dev, BTN_B, ((data[0] & 0x10) >> 4));
|
||||
input_report_key(dev, BTN_C, ((data[0] & 0x08) >> 3));
|
||||
input_report_key(dev, BTN_X, ((data[0] & 0x04) >> 2));
|
||||
input_report_key(dev, BTN_Y, ((data[3] & 0x20) >> 5));
|
||||
input_report_key(dev, BTN_Z, ((data[3] & 0x10) >> 4));
|
||||
input_report_key(dev, BTN_TL, ((data[3] & 0x08) >> 3));
|
||||
input_report_key(dev, BTN_TR, ((data[3] & 0x04) >> 2));
|
||||
input_report_key(dev, BTN_SELECT, ((data[3] & 0x02) >> 1));
|
||||
input_report_key(dev, BTN_START, (data[3] & 0x01));
|
||||
|
||||
input_report_abs(dev, ABS_X, (data[1] & 0x3F) - ((data[0] & 0x01) << 6));
|
||||
input_report_abs(dev, ABS_Y, ((data[0] & 0x02) << 5) - (data[2] & 0x3F));
|
||||
|
||||
input_sync(dev);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* stinger_interrupt() is called by the low level driver when characters
|
||||
* are ready for us. We then buffer them for further processing, or call the
|
||||
* packet processing routine.
|
||||
*/
|
||||
|
||||
static irqreturn_t stinger_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags, struct pt_regs *regs)
|
||||
{
|
||||
struct stinger* stinger = serio->private;
|
||||
|
||||
/* All Stinger packets are 4 bytes */
|
||||
|
||||
if (stinger->idx < STINGER_MAX_LENGTH)
|
||||
stinger->data[stinger->idx++] = data;
|
||||
|
||||
if (stinger->idx == 4) {
|
||||
stinger_process_packet(stinger, regs);
|
||||
stinger->idx = 0;
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* stinger_disconnect() is the opposite of stinger_connect()
|
||||
*/
|
||||
|
||||
static void stinger_disconnect(struct serio *serio)
|
||||
{
|
||||
struct stinger* stinger = serio->private;
|
||||
input_unregister_device(&stinger->dev);
|
||||
serio_close(serio);
|
||||
kfree(stinger);
|
||||
}
|
||||
|
||||
/*
|
||||
* stinger_connect() is the routine that is called when someone adds a
|
||||
* new serio device. It looks for the Stinger, and if found, registers
|
||||
* it as an input device.
|
||||
*/
|
||||
|
||||
static void stinger_connect(struct serio *serio, struct serio_driver *drv)
|
||||
{
|
||||
struct stinger *stinger;
|
||||
int i;
|
||||
|
||||
if (serio->type != (SERIO_RS232 | SERIO_STINGER))
|
||||
return;
|
||||
|
||||
if (!(stinger = kmalloc(sizeof(struct stinger), GFP_KERNEL)))
|
||||
return;
|
||||
|
||||
memset(stinger, 0, sizeof(struct stinger));
|
||||
|
||||
stinger->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
stinger->dev.keybit[LONG(BTN_A)] = BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_X) | \
|
||||
BIT(BTN_Y) | BIT(BTN_Z) | BIT(BTN_TL) | BIT(BTN_TR) | \
|
||||
BIT(BTN_START) | BIT(BTN_SELECT);
|
||||
stinger->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
|
||||
|
||||
sprintf(stinger->phys, "%s/serio0", serio->phys);
|
||||
|
||||
init_input_dev(&stinger->dev);
|
||||
stinger->dev.name = stinger_name;
|
||||
stinger->dev.phys = stinger->phys;
|
||||
stinger->dev.id.bustype = BUS_RS232;
|
||||
stinger->dev.id.vendor = SERIO_STINGER;
|
||||
stinger->dev.id.product = 0x0001;
|
||||
stinger->dev.id.version = 0x0100;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
stinger->dev.absmax[ABS_X+i] = 64;
|
||||
stinger->dev.absmin[ABS_X+i] = -64;
|
||||
stinger->dev.absflat[ABS_X+i] = 4;
|
||||
}
|
||||
|
||||
stinger->dev.private = stinger;
|
||||
serio->private = stinger;
|
||||
|
||||
if (serio_open(serio, drv)) {
|
||||
kfree(stinger);
|
||||
return;
|
||||
}
|
||||
|
||||
input_register_device(&stinger->dev);
|
||||
|
||||
printk(KERN_INFO "input: %s on %s\n", stinger_name, serio->phys);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* The serio device structure.
|
||||
*/
|
||||
|
||||
static struct serio_driver stinger_drv = {
|
||||
.driver = {
|
||||
.name = "stinger",
|
||||
},
|
||||
.description = DRIVER_DESC,
|
||||
.interrupt = stinger_interrupt,
|
||||
.connect = stinger_connect,
|
||||
.disconnect = stinger_disconnect,
|
||||
};
|
||||
|
||||
/*
|
||||
* The functions for inserting/removing us as a module.
|
||||
*/
|
||||
|
||||
int __init stinger_init(void)
|
||||
{
|
||||
serio_register_driver(&stinger_drv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit stinger_exit(void)
|
||||
{
|
||||
serio_unregister_driver(&stinger_drv);
|
||||
}
|
||||
|
||||
module_init(stinger_init);
|
||||
module_exit(stinger_exit);
|
||||
382
extra/linux-2.6.10/drivers/input/joystick/tmdc.c
Normal file
382
extra/linux-2.6.10/drivers/input/joystick/tmdc.c
Normal file
@@ -0,0 +1,382 @@
|
||||
/*
|
||||
* $Id: tmdc.c,v 1.31 2002/01/22 20:29:52 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1998-2001 Vojtech Pavlik
|
||||
*
|
||||
* Based on the work of:
|
||||
* Trystan Larey-Williams
|
||||
*/
|
||||
|
||||
/*
|
||||
* ThrustMaster DirectConnect (BSP) joystick family driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/gameport.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("ThrustMaster DirectConnect joystick driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define TMDC_MAX_START 400 /* 400 us */
|
||||
#define TMDC_MAX_STROBE 45 /* 45 us */
|
||||
#define TMDC_MAX_LENGTH 13
|
||||
#define TMDC_REFRESH_TIME HZ/50 /* 20 ms */
|
||||
|
||||
#define TMDC_MODE_M3DI 1
|
||||
#define TMDC_MODE_3DRP 3
|
||||
#define TMDC_MODE_AT 4
|
||||
#define TMDC_MODE_FM 8
|
||||
#define TMDC_MODE_FGP 163
|
||||
|
||||
#define TMDC_BYTE_ID 10
|
||||
#define TMDC_BYTE_REV 11
|
||||
#define TMDC_BYTE_DEF 12
|
||||
|
||||
#define TMDC_ABS 7
|
||||
#define TMDC_ABS_HAT 4
|
||||
#define TMDC_BTN 16
|
||||
|
||||
static unsigned char tmdc_byte_a[16] = { 0, 1, 3, 4, 6, 7 };
|
||||
static unsigned char tmdc_byte_d[16] = { 2, 5, 8, 9 };
|
||||
|
||||
static signed char tmdc_abs[TMDC_ABS] =
|
||||
{ ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE, ABS_RX, ABS_RY, ABS_RZ };
|
||||
static signed char tmdc_abs_hat[TMDC_ABS_HAT] =
|
||||
{ ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y };
|
||||
static signed char tmdc_abs_at[TMDC_ABS] =
|
||||
{ ABS_X, ABS_Y, ABS_RUDDER, -1, ABS_THROTTLE };
|
||||
static signed char tmdc_abs_fm[TMDC_ABS] =
|
||||
{ ABS_RX, ABS_RY, ABS_X, ABS_Y };
|
||||
|
||||
static short tmdc_btn_pad[TMDC_BTN] =
|
||||
{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR };
|
||||
static short tmdc_btn_joy[TMDC_BTN] =
|
||||
{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE,
|
||||
BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z };
|
||||
static short tmdc_btn_fm[TMDC_BTN] =
|
||||
{ BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 };
|
||||
static short tmdc_btn_at[TMDC_BTN] =
|
||||
{ BTN_TRIGGER, BTN_THUMB2, BTN_PINKIE, BTN_THUMB, BTN_BASE6, BTN_BASE5, BTN_BASE4,
|
||||
BTN_BASE3, BTN_BASE2, BTN_BASE };
|
||||
|
||||
static struct {
|
||||
int x;
|
||||
int y;
|
||||
} tmdc_hat_to_axis[] = {{ 0, 0}, { 1, 0}, { 0,-1}, {-1, 0}, { 0, 1}};
|
||||
|
||||
struct tmdc {
|
||||
struct gameport *gameport;
|
||||
struct timer_list timer;
|
||||
struct input_dev dev[2];
|
||||
char name[2][64];
|
||||
char phys[2][32];
|
||||
int mode[2];
|
||||
signed char *abs[2];
|
||||
short *btn[2];
|
||||
unsigned char absc[2];
|
||||
unsigned char btnc[2][4];
|
||||
unsigned char btno[2][4];
|
||||
int used;
|
||||
int reads;
|
||||
int bads;
|
||||
unsigned char exists;
|
||||
};
|
||||
|
||||
/*
|
||||
* tmdc_read_packet() reads a ThrustMaster packet.
|
||||
*/
|
||||
|
||||
static int tmdc_read_packet(struct gameport *gameport, unsigned char data[2][TMDC_MAX_LENGTH])
|
||||
{
|
||||
unsigned char u, v, w, x;
|
||||
unsigned long flags;
|
||||
int i[2], j[2], t[2], p, k;
|
||||
|
||||
p = gameport_time(gameport, TMDC_MAX_STROBE);
|
||||
|
||||
for (k = 0; k < 2; k++) {
|
||||
t[k] = gameport_time(gameport, TMDC_MAX_START);
|
||||
i[k] = j[k] = 0;
|
||||
}
|
||||
|
||||
local_irq_save(flags);
|
||||
gameport_trigger(gameport);
|
||||
|
||||
w = gameport_read(gameport) >> 4;
|
||||
|
||||
do {
|
||||
x = w;
|
||||
w = gameport_read(gameport) >> 4;
|
||||
|
||||
for (k = 0, v = w, u = x; k < 2; k++, v >>= 2, u >>= 2) {
|
||||
if (~v & u & 2) {
|
||||
if (t[k] <= 0 || i[k] >= TMDC_MAX_LENGTH) continue;
|
||||
t[k] = p;
|
||||
if (j[k] == 0) { /* Start bit */
|
||||
if (~v & 1) t[k] = 0;
|
||||
data[k][i[k]] = 0; j[k]++; continue;
|
||||
}
|
||||
if (j[k] == 9) { /* Stop bit */
|
||||
if (v & 1) t[k] = 0;
|
||||
j[k] = 0; i[k]++; continue;
|
||||
}
|
||||
data[k][i[k]] |= (~v & 1) << (j[k]++ - 1); /* Data bit */
|
||||
}
|
||||
t[k]--;
|
||||
}
|
||||
} while (t[0] > 0 || t[1] > 0);
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
return (i[0] == TMDC_MAX_LENGTH) | ((i[1] == TMDC_MAX_LENGTH) << 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* tmdc_read() reads and analyzes ThrustMaster joystick data.
|
||||
*/
|
||||
|
||||
static void tmdc_timer(unsigned long private)
|
||||
{
|
||||
unsigned char data[2][TMDC_MAX_LENGTH];
|
||||
struct tmdc *tmdc = (void *) private;
|
||||
struct input_dev *dev;
|
||||
unsigned char r, bad = 0;
|
||||
int i, j, k, l;
|
||||
|
||||
tmdc->reads++;
|
||||
|
||||
if ((r = tmdc_read_packet(tmdc->gameport, data)) != tmdc->exists)
|
||||
bad = 1;
|
||||
else
|
||||
|
||||
for (j = 0; j < 2; j++)
|
||||
if (r & (1 << j) & tmdc->exists) {
|
||||
|
||||
if (data[j][TMDC_BYTE_ID] != tmdc->mode[j]) {
|
||||
bad = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
dev = tmdc->dev + j;
|
||||
|
||||
for (i = 0; i < tmdc->absc[j]; i++) {
|
||||
if (tmdc->abs[j][i] < 0) continue;
|
||||
input_report_abs(dev, tmdc->abs[j][i], data[j][tmdc_byte_a[i]]);
|
||||
}
|
||||
|
||||
switch (tmdc->mode[j]) {
|
||||
|
||||
case TMDC_MODE_M3DI:
|
||||
|
||||
i = tmdc_byte_d[0];
|
||||
input_report_abs(dev, ABS_HAT0X, ((data[j][i] >> 3) & 1) - ((data[j][i] >> 1) & 1));
|
||||
input_report_abs(dev, ABS_HAT0Y, ((data[j][i] >> 2) & 1) - ( data[j][i] & 1));
|
||||
break;
|
||||
|
||||
case TMDC_MODE_AT:
|
||||
|
||||
i = tmdc_byte_a[3];
|
||||
input_report_abs(dev, ABS_HAT0X, tmdc_hat_to_axis[(data[j][i] - 141) / 25].x);
|
||||
input_report_abs(dev, ABS_HAT0Y, tmdc_hat_to_axis[(data[j][i] - 141) / 25].y);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
for (k = l = 0; k < 4; k++) {
|
||||
for (i = 0; i < tmdc->btnc[j][k]; i++)
|
||||
input_report_key(dev, tmdc->btn[j][i + l],
|
||||
((data[j][tmdc_byte_d[k]] >> (i + tmdc->btno[j][k])) & 1));
|
||||
l += tmdc->btnc[j][k];
|
||||
}
|
||||
|
||||
input_sync(dev);
|
||||
}
|
||||
|
||||
tmdc->bads += bad;
|
||||
|
||||
mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME);
|
||||
}
|
||||
|
||||
static int tmdc_open(struct input_dev *dev)
|
||||
{
|
||||
struct tmdc *tmdc = dev->private;
|
||||
if (!tmdc->used++)
|
||||
mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tmdc_close(struct input_dev *dev)
|
||||
{
|
||||
struct tmdc *tmdc = dev->private;
|
||||
if (!--tmdc->used)
|
||||
del_timer(&tmdc->timer);
|
||||
}
|
||||
|
||||
/*
|
||||
* tmdc_probe() probes for ThrustMaster type joysticks.
|
||||
*/
|
||||
|
||||
static void tmdc_connect(struct gameport *gameport, struct gameport_dev *dev)
|
||||
{
|
||||
struct models {
|
||||
unsigned char id;
|
||||
char *name;
|
||||
char abs;
|
||||
char hats;
|
||||
char btnc[4];
|
||||
char btno[4];
|
||||
signed char *axes;
|
||||
short *buttons;
|
||||
} models[] = { { 1, "ThrustMaster Millenium 3D Inceptor", 6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy },
|
||||
{ 3, "ThrustMaster Rage 3D Gamepad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad },
|
||||
{ 4, "ThrustMaster Attack Throttle", 5, 2, { 4, 6 }, { 4, 2 }, tmdc_abs_at, tmdc_btn_at },
|
||||
{ 8, "ThrustMaster FragMaster", 4, 0, { 8, 2 }, { 0, 0 }, tmdc_abs_fm, tmdc_btn_fm },
|
||||
{ 163, "Thrustmaster Fusion GamePad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad },
|
||||
{ 0, "Unknown %d-axis, %d-button TM device %d", 0, 0, { 0, 0 }, { 0, 0 }, tmdc_abs, tmdc_btn_joy }};
|
||||
|
||||
unsigned char data[2][TMDC_MAX_LENGTH];
|
||||
struct tmdc *tmdc;
|
||||
int i, j, k, l, m;
|
||||
|
||||
if (!(tmdc = kmalloc(sizeof(struct tmdc), GFP_KERNEL)))
|
||||
return;
|
||||
memset(tmdc, 0, sizeof(struct tmdc));
|
||||
|
||||
gameport->private = tmdc;
|
||||
|
||||
tmdc->gameport = gameport;
|
||||
init_timer(&tmdc->timer);
|
||||
tmdc->timer.data = (long) tmdc;
|
||||
tmdc->timer.function = tmdc_timer;
|
||||
|
||||
if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
|
||||
goto fail1;
|
||||
|
||||
if (!(tmdc->exists = tmdc_read_packet(gameport, data)))
|
||||
goto fail2;
|
||||
|
||||
for (j = 0; j < 2; j++)
|
||||
if (tmdc->exists & (1 << j)) {
|
||||
|
||||
tmdc->mode[j] = data[j][TMDC_BYTE_ID];
|
||||
|
||||
for (m = 0; models[m].id && models[m].id != tmdc->mode[j]; m++);
|
||||
|
||||
tmdc->abs[j] = models[m].axes;
|
||||
tmdc->btn[j] = models[m].buttons;
|
||||
|
||||
if (!models[m].id) {
|
||||
models[m].abs = data[j][TMDC_BYTE_DEF] >> 4;
|
||||
for (k = 0; k < 4; k++)
|
||||
models[m].btnc[k] = k < (data[j][TMDC_BYTE_DEF] & 0xf) ? 8 : 0;
|
||||
}
|
||||
|
||||
tmdc->absc[j] = models[m].abs;
|
||||
for (k = 0; k < 4; k++) {
|
||||
tmdc->btnc[j][k] = models[m].btnc[k];
|
||||
tmdc->btno[j][k] = models[m].btno[k];
|
||||
}
|
||||
|
||||
sprintf(tmdc->name[j], models[m].name, models[m].abs,
|
||||
(data[j][TMDC_BYTE_DEF] & 0xf) << 3, tmdc->mode[j]);
|
||||
|
||||
sprintf(tmdc->phys[j], "%s/input%d", gameport->phys, j);
|
||||
|
||||
tmdc->dev[j].private = tmdc;
|
||||
tmdc->dev[j].open = tmdc_open;
|
||||
tmdc->dev[j].close = tmdc_close;
|
||||
|
||||
tmdc->dev[j].name = tmdc->name[j];
|
||||
tmdc->dev[j].phys = tmdc->phys[j];
|
||||
tmdc->dev[j].id.bustype = BUS_GAMEPORT;
|
||||
tmdc->dev[j].id.vendor = GAMEPORT_ID_VENDOR_THRUSTMASTER;
|
||||
tmdc->dev[j].id.product = models[m].id;
|
||||
tmdc->dev[j].id.version = 0x0100;
|
||||
|
||||
tmdc->dev[j].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
|
||||
for (i = 0; i < models[m].abs && i < TMDC_ABS; i++) {
|
||||
if (tmdc->abs[j][i] < 0) continue;
|
||||
set_bit(tmdc->abs[j][i], tmdc->dev[j].absbit);
|
||||
tmdc->dev[j].absmin[tmdc->abs[j][i]] = 8;
|
||||
tmdc->dev[j].absmax[tmdc->abs[j][i]] = 248;
|
||||
tmdc->dev[j].absfuzz[tmdc->abs[j][i]] = 2;
|
||||
tmdc->dev[j].absflat[tmdc->abs[j][i]] = 4;
|
||||
}
|
||||
|
||||
for (i = 0; i < models[m].hats && i < TMDC_ABS_HAT; i++) {
|
||||
set_bit(tmdc_abs_hat[i], tmdc->dev[j].absbit);
|
||||
tmdc->dev[j].absmin[tmdc_abs_hat[i]] = -1;
|
||||
tmdc->dev[j].absmax[tmdc_abs_hat[i]] = 1;
|
||||
}
|
||||
|
||||
for (k = l = 0; k < 4; k++) {
|
||||
for (i = 0; i < models[m].btnc[k] && i < TMDC_BTN; i++)
|
||||
set_bit(tmdc->btn[j][i + l], tmdc->dev[j].keybit);
|
||||
l += models[m].btnc[k];
|
||||
}
|
||||
|
||||
input_register_device(tmdc->dev + j);
|
||||
printk(KERN_INFO "input: %s on %s\n", tmdc->name[j], gameport->phys);
|
||||
}
|
||||
|
||||
return;
|
||||
fail2: gameport_close(gameport);
|
||||
fail1: kfree(tmdc);
|
||||
}
|
||||
|
||||
static void tmdc_disconnect(struct gameport *gameport)
|
||||
{
|
||||
struct tmdc *tmdc = gameport->private;
|
||||
int i;
|
||||
for (i = 0; i < 2; i++)
|
||||
if (tmdc->exists & (1 << i))
|
||||
input_unregister_device(tmdc->dev + i);
|
||||
gameport_close(gameport);
|
||||
kfree(tmdc);
|
||||
}
|
||||
|
||||
static struct gameport_dev tmdc_dev = {
|
||||
.connect = tmdc_connect,
|
||||
.disconnect = tmdc_disconnect,
|
||||
};
|
||||
|
||||
int __init tmdc_init(void)
|
||||
{
|
||||
gameport_register_device(&tmdc_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit tmdc_exit(void)
|
||||
{
|
||||
gameport_unregister_device(&tmdc_dev);
|
||||
}
|
||||
|
||||
module_init(tmdc_init);
|
||||
module_exit(tmdc_exit);
|
||||
258
extra/linux-2.6.10/drivers/input/joystick/turbografx.c
Normal file
258
extra/linux-2.6.10/drivers/input/joystick/turbografx.c
Normal file
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* $Id: turbografx.c,v 1.14 2002/01/22 20:30:39 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1998-2001 Vojtech Pavlik
|
||||
*
|
||||
* Based on the work of:
|
||||
* Steffen Schwenke
|
||||
*/
|
||||
|
||||
/*
|
||||
* TurboGraFX parallel port interface driver for Linux.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/parport.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("TurboGraFX parallel port interface driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int tgfx[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
|
||||
static int tgfx_nargs __initdata = 0;
|
||||
module_param_array_named(map, tgfx, int, &tgfx_nargs, 0);
|
||||
MODULE_PARM_DESC(map, "Describes first set of devices (<parport#>,<js1>,<js2>,..<js7>");
|
||||
|
||||
static int tgfx_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
|
||||
static int tgfx_nargs_2 __initdata = 0;
|
||||
module_param_array_named(map2, tgfx_2, int, &tgfx_nargs_2, 0);
|
||||
MODULE_PARM_DESC(map2, "Describes second set of devices");
|
||||
|
||||
static int tgfx_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
|
||||
static int tgfx_nargs_3 __initdata = 0;
|
||||
module_param_array_named(map3, tgfx_3, int, &tgfx_nargs_3, 0);
|
||||
MODULE_PARM_DESC(map3, "Describes third set of devices");
|
||||
|
||||
__obsolete_setup("tgfx=");
|
||||
__obsolete_setup("tgfx_2=");
|
||||
__obsolete_setup("tgfx_3=");
|
||||
|
||||
#define TGFX_REFRESH_TIME HZ/100 /* 10 ms */
|
||||
|
||||
#define TGFX_TRIGGER 0x08
|
||||
#define TGFX_UP 0x10
|
||||
#define TGFX_DOWN 0x20
|
||||
#define TGFX_LEFT 0x40
|
||||
#define TGFX_RIGHT 0x80
|
||||
|
||||
#define TGFX_THUMB 0x02
|
||||
#define TGFX_THUMB2 0x04
|
||||
#define TGFX_TOP 0x01
|
||||
#define TGFX_TOP2 0x08
|
||||
|
||||
static int tgfx_buttons[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2 };
|
||||
static char *tgfx_name = "TurboGraFX Multisystem joystick";
|
||||
|
||||
struct tgfx {
|
||||
struct pardevice *pd;
|
||||
struct timer_list timer;
|
||||
struct input_dev dev[7];
|
||||
char phys[7][32];
|
||||
int sticks;
|
||||
int used;
|
||||
} *tgfx_base[3];
|
||||
|
||||
/*
|
||||
* tgfx_timer() reads and analyzes TurboGraFX joystick data.
|
||||
*/
|
||||
|
||||
static void tgfx_timer(unsigned long private)
|
||||
{
|
||||
struct tgfx *tgfx = (void *) private;
|
||||
struct input_dev *dev;
|
||||
int data1, data2, i;
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
if (tgfx->sticks & (1 << i)) {
|
||||
|
||||
dev = tgfx->dev + i;
|
||||
|
||||
parport_write_data(tgfx->pd->port, ~(1 << i));
|
||||
data1 = parport_read_status(tgfx->pd->port) ^ 0x7f;
|
||||
data2 = parport_read_control(tgfx->pd->port) ^ 0x04; /* CAVEAT parport */
|
||||
|
||||
input_report_abs(dev, ABS_X, !!(data1 & TGFX_RIGHT) - !!(data1 & TGFX_LEFT));
|
||||
input_report_abs(dev, ABS_Y, !!(data1 & TGFX_DOWN ) - !!(data1 & TGFX_UP ));
|
||||
|
||||
input_report_key(dev, BTN_TRIGGER, (data1 & TGFX_TRIGGER));
|
||||
input_report_key(dev, BTN_THUMB, (data2 & TGFX_THUMB ));
|
||||
input_report_key(dev, BTN_THUMB2, (data2 & TGFX_THUMB2 ));
|
||||
input_report_key(dev, BTN_TOP, (data2 & TGFX_TOP ));
|
||||
input_report_key(dev, BTN_TOP2, (data2 & TGFX_TOP2 ));
|
||||
|
||||
input_sync(dev);
|
||||
}
|
||||
|
||||
mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
|
||||
}
|
||||
|
||||
static int tgfx_open(struct input_dev *dev)
|
||||
{
|
||||
struct tgfx *tgfx = dev->private;
|
||||
if (!tgfx->used++) {
|
||||
parport_claim(tgfx->pd);
|
||||
parport_write_control(tgfx->pd->port, 0x04);
|
||||
mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tgfx_close(struct input_dev *dev)
|
||||
{
|
||||
struct tgfx *tgfx = dev->private;
|
||||
if (!--tgfx->used) {
|
||||
del_timer(&tgfx->timer);
|
||||
parport_write_control(tgfx->pd->port, 0x00);
|
||||
parport_release(tgfx->pd);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* tgfx_probe() probes for tg gamepads.
|
||||
*/
|
||||
|
||||
static struct tgfx __init *tgfx_probe(int *config, int nargs)
|
||||
{
|
||||
struct tgfx *tgfx;
|
||||
struct parport *pp;
|
||||
int i, j;
|
||||
|
||||
if (config[0] < 0)
|
||||
return NULL;
|
||||
|
||||
if (nargs < 2) {
|
||||
printk(KERN_ERR "turbografx.c: at least one joystick must be specified\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pp = parport_find_number(config[0]);
|
||||
|
||||
if (!pp) {
|
||||
printk(KERN_ERR "turbografx.c: no such parport\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(tgfx = kmalloc(sizeof(struct tgfx), GFP_KERNEL))) {
|
||||
parport_put_port(pp);
|
||||
return NULL;
|
||||
}
|
||||
memset(tgfx, 0, sizeof(struct tgfx));
|
||||
|
||||
tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
|
||||
|
||||
parport_put_port(pp);
|
||||
|
||||
if (!tgfx->pd) {
|
||||
printk(KERN_ERR "turbografx.c: parport busy already - lp.o loaded?\n");
|
||||
kfree(tgfx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
init_timer(&tgfx->timer);
|
||||
tgfx->timer.data = (long) tgfx;
|
||||
tgfx->timer.function = tgfx_timer;
|
||||
|
||||
tgfx->sticks = 0;
|
||||
|
||||
for (i = 0; i < nargs - 1; i++)
|
||||
if (config[i+1] > 0 && config[i+1] < 6) {
|
||||
|
||||
tgfx->sticks |= (1 << i);
|
||||
|
||||
tgfx->dev[i].private = tgfx;
|
||||
tgfx->dev[i].open = tgfx_open;
|
||||
tgfx->dev[i].close = tgfx_close;
|
||||
|
||||
sprintf(tgfx->phys[i], "%s/input0", tgfx->pd->port->name);
|
||||
|
||||
tgfx->dev[i].name = tgfx_name;
|
||||
tgfx->dev[i].phys = tgfx->phys[i];
|
||||
tgfx->dev[i].id.bustype = BUS_PARPORT;
|
||||
tgfx->dev[i].id.vendor = 0x0003;
|
||||
tgfx->dev[i].id.product = config[i+1];
|
||||
tgfx->dev[i].id.version = 0x0100;
|
||||
|
||||
tgfx->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
tgfx->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
|
||||
|
||||
for (j = 0; j < config[i+1]; j++)
|
||||
set_bit(tgfx_buttons[j], tgfx->dev[i].keybit);
|
||||
|
||||
tgfx->dev[i].absmin[ABS_X] = -1; tgfx->dev[i].absmax[ABS_X] = 1;
|
||||
tgfx->dev[i].absmin[ABS_Y] = -1; tgfx->dev[i].absmax[ABS_Y] = 1;
|
||||
|
||||
input_register_device(tgfx->dev + i);
|
||||
printk(KERN_INFO "input: %d-button Multisystem joystick on %s\n",
|
||||
config[i+1], tgfx->pd->port->name);
|
||||
}
|
||||
|
||||
if (!tgfx->sticks) {
|
||||
parport_unregister_device(tgfx->pd);
|
||||
kfree(tgfx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return tgfx;
|
||||
}
|
||||
|
||||
int __init tgfx_init(void)
|
||||
{
|
||||
tgfx_base[0] = tgfx_probe(tgfx, tgfx_nargs);
|
||||
tgfx_base[1] = tgfx_probe(tgfx_2, tgfx_nargs_2);
|
||||
tgfx_base[2] = tgfx_probe(tgfx_3, tgfx_nargs_3);
|
||||
|
||||
if (tgfx_base[0] || tgfx_base[1] || tgfx_base[2])
|
||||
return 0;
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
void __exit tgfx_exit(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
if (tgfx_base[i]) {
|
||||
for (j = 0; j < 7; j++)
|
||||
if (tgfx_base[i]->sticks & (1 << j))
|
||||
input_unregister_device(tgfx_base[i]->dev + j);
|
||||
parport_unregister_device(tgfx_base[i]->pd);
|
||||
}
|
||||
}
|
||||
|
||||
module_init(tgfx_init);
|
||||
module_exit(tgfx_exit);
|
||||
275
extra/linux-2.6.10/drivers/input/joystick/twidjoy.c
Normal file
275
extra/linux-2.6.10/drivers/input/joystick/twidjoy.c
Normal file
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* $Id: twidjoy.c,v 1.5 2002/01/22 20:31:53 vojtech Exp $
|
||||
*
|
||||
* derived from CVS-ID "stinger.c,v 1.5 2001/05/29 12:57:18 vojtech Exp"
|
||||
*
|
||||
* Copyright (c) 2001 Arndt Schoenewald
|
||||
* Copyright (c) 2000-2001 Vojtech Pavlik
|
||||
* Copyright (c) 2000 Mark Fletcher
|
||||
*
|
||||
* Sponsored by Quelltext AG (http://www.quelltext-ag.de), Dortmund, Germany
|
||||
*/
|
||||
|
||||
/*
|
||||
* Driver to use Handykey's Twiddler (the first edition, i.e. the one with
|
||||
* the RS232 interface) as a joystick under Linux
|
||||
*
|
||||
* The Twiddler is a one-handed chording keyboard featuring twelve buttons on
|
||||
* the front, six buttons on the top, and a built-in tilt sensor. The buttons
|
||||
* on the front, which are grouped as four rows of three buttons, are pressed
|
||||
* by the four fingers (this implies only one button per row can be held down
|
||||
* at the same time) and the buttons on the top are for the thumb. The tilt
|
||||
* sensor delivers X and Y axis data depending on how the Twiddler is held.
|
||||
* Additional information can be found at http://www.handykey.com.
|
||||
*
|
||||
* This driver does not use the Twiddler for its intended purpose, i.e. as
|
||||
* a chording keyboard, but as a joystick: pressing and releasing a button
|
||||
* immediately sends a corresponding button event, and tilting it generates
|
||||
* corresponding ABS_X and ABS_Y events. This turns the Twiddler into a game
|
||||
* controller with amazing 18 buttons :-)
|
||||
*
|
||||
* Note: The Twiddler2 (the successor of the Twiddler that connects directly
|
||||
* to the PS/2 keyboard and mouse ports) is NOT supported by this driver!
|
||||
*
|
||||
* For questions or feedback regarding this driver module please contact:
|
||||
* Arndt Schoenewald <arndt@quelltext.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/serio.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
MODULE_DESCRIPTION("Handykey Twiddler keyboard as a joystick driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
* Constants.
|
||||
*/
|
||||
|
||||
#define TWIDJOY_MAX_LENGTH 5
|
||||
|
||||
static char *twidjoy_name = "Handykey Twiddler";
|
||||
|
||||
static struct twidjoy_button_spec {
|
||||
int bitshift;
|
||||
int bitmask;
|
||||
int buttons[3];
|
||||
}
|
||||
twidjoy_buttons[] = {
|
||||
{ 0, 3, { BTN_A, BTN_B, BTN_C } },
|
||||
{ 2, 3, { BTN_X, BTN_Y, BTN_Z } },
|
||||
{ 4, 3, { BTN_TL, BTN_TR, BTN_TR2 } },
|
||||
{ 6, 3, { BTN_SELECT, BTN_START, BTN_MODE } },
|
||||
{ 8, 1, { BTN_BASE5 } },
|
||||
{ 9, 1, { BTN_BASE } },
|
||||
{ 10, 1, { BTN_BASE3 } },
|
||||
{ 11, 1, { BTN_BASE4 } },
|
||||
{ 12, 1, { BTN_BASE2 } },
|
||||
{ 13, 1, { BTN_BASE6 } },
|
||||
{ 0, 0, { 0 } }
|
||||
};
|
||||
|
||||
/*
|
||||
* Per-Twiddler data.
|
||||
*/
|
||||
|
||||
struct twidjoy {
|
||||
struct input_dev dev;
|
||||
int idx;
|
||||
unsigned char data[TWIDJOY_MAX_LENGTH];
|
||||
char phys[32];
|
||||
};
|
||||
|
||||
/*
|
||||
* twidjoy_process_packet() decodes packets the driver receives from the
|
||||
* Twiddler. It updates the data accordingly.
|
||||
*/
|
||||
|
||||
static void twidjoy_process_packet(struct twidjoy *twidjoy, struct pt_regs *regs)
|
||||
{
|
||||
if (twidjoy->idx == TWIDJOY_MAX_LENGTH) {
|
||||
struct input_dev *dev = &twidjoy->dev;
|
||||
unsigned char *data = twidjoy->data;
|
||||
struct twidjoy_button_spec *bp;
|
||||
int button_bits, abs_x, abs_y;
|
||||
|
||||
button_bits = ((data[1] & 0x7f) << 7) | (data[0] & 0x7f);
|
||||
|
||||
input_regs(dev, regs);
|
||||
|
||||
for (bp = twidjoy_buttons; bp->bitmask; bp++) {
|
||||
int value = (button_bits & (bp->bitmask << bp->bitshift)) >> bp->bitshift;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < bp->bitmask; i++)
|
||||
input_report_key(dev, bp->buttons[i], i+1 == value);
|
||||
}
|
||||
|
||||
abs_x = ((data[4] & 0x07) << 5) | ((data[3] & 0x7C) >> 2);
|
||||
if (data[4] & 0x08) abs_x -= 256;
|
||||
|
||||
abs_y = ((data[3] & 0x01) << 7) | ((data[2] & 0x7F) >> 0);
|
||||
if (data[3] & 0x02) abs_y -= 256;
|
||||
|
||||
input_report_abs(dev, ABS_X, -abs_x);
|
||||
input_report_abs(dev, ABS_Y, +abs_y);
|
||||
|
||||
input_sync(dev);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* twidjoy_interrupt() is called by the low level driver when characters
|
||||
* are ready for us. We then buffer them for further processing, or call the
|
||||
* packet processing routine.
|
||||
*/
|
||||
|
||||
static irqreturn_t twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs)
|
||||
{
|
||||
struct twidjoy *twidjoy = serio->private;
|
||||
|
||||
/* All Twiddler packets are 5 bytes. The fact that the first byte
|
||||
* has a MSB of 0 and all other bytes have a MSB of 1 can be used
|
||||
* to check and regain sync. */
|
||||
|
||||
if ((data & 0x80) == 0)
|
||||
twidjoy->idx = 0; /* this byte starts a new packet */
|
||||
else if (twidjoy->idx == 0)
|
||||
return IRQ_HANDLED; /* wrong MSB -- ignore this byte */
|
||||
|
||||
if (twidjoy->idx < TWIDJOY_MAX_LENGTH)
|
||||
twidjoy->data[twidjoy->idx++] = data;
|
||||
|
||||
if (twidjoy->idx == TWIDJOY_MAX_LENGTH) {
|
||||
twidjoy_process_packet(twidjoy, regs);
|
||||
twidjoy->idx = 0;
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* twidjoy_disconnect() is the opposite of twidjoy_connect()
|
||||
*/
|
||||
|
||||
static void twidjoy_disconnect(struct serio *serio)
|
||||
{
|
||||
struct twidjoy *twidjoy = serio->private;
|
||||
input_unregister_device(&twidjoy->dev);
|
||||
serio_close(serio);
|
||||
kfree(twidjoy);
|
||||
}
|
||||
|
||||
/*
|
||||
* twidjoy_connect() is the routine that is called when someone adds a
|
||||
* new serio device. It looks for the Twiddler, and if found, registers
|
||||
* it as an input device.
|
||||
*/
|
||||
|
||||
static void twidjoy_connect(struct serio *serio, struct serio_driver *drv)
|
||||
{
|
||||
struct twidjoy_button_spec *bp;
|
||||
struct twidjoy *twidjoy;
|
||||
int i;
|
||||
|
||||
if (serio->type != (SERIO_RS232 | SERIO_TWIDJOY))
|
||||
return;
|
||||
|
||||
if (!(twidjoy = kmalloc(sizeof(struct twidjoy), GFP_KERNEL)))
|
||||
return;
|
||||
|
||||
memset(twidjoy, 0, sizeof(struct twidjoy));
|
||||
|
||||
sprintf(twidjoy->phys, "%s/input0", serio->phys);
|
||||
|
||||
init_input_dev(&twidjoy->dev);
|
||||
twidjoy->dev.name = twidjoy_name;
|
||||
twidjoy->dev.phys = twidjoy->phys;
|
||||
twidjoy->dev.id.bustype = BUS_RS232;
|
||||
twidjoy->dev.id.vendor = SERIO_TWIDJOY;
|
||||
twidjoy->dev.id.product = 0x0001;
|
||||
twidjoy->dev.id.version = 0x0100;
|
||||
|
||||
twidjoy->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
|
||||
for (bp = twidjoy_buttons; bp->bitmask; bp++) {
|
||||
for (i = 0; i < bp->bitmask; i++)
|
||||
set_bit(bp->buttons[i], twidjoy->dev.keybit);
|
||||
}
|
||||
|
||||
twidjoy->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
twidjoy->dev.absmax[ABS_X+i] = 50;
|
||||
twidjoy->dev.absmin[ABS_X+i] = -50;
|
||||
|
||||
/* TODO: arndt 20010708: Are these values appropriate? */
|
||||
twidjoy->dev.absfuzz[ABS_X+i] = 4;
|
||||
twidjoy->dev.absflat[ABS_X+i] = 4;
|
||||
}
|
||||
|
||||
twidjoy->dev.private = twidjoy;
|
||||
serio->private = twidjoy;
|
||||
|
||||
if (serio_open(serio, drv)) {
|
||||
kfree(twidjoy);
|
||||
return;
|
||||
}
|
||||
|
||||
input_register_device(&twidjoy->dev);
|
||||
|
||||
printk(KERN_INFO "input: %s on %s\n", twidjoy_name, serio->phys);
|
||||
}
|
||||
|
||||
/*
|
||||
* The serio device structure.
|
||||
*/
|
||||
|
||||
static struct serio_driver twidjoy_drv = {
|
||||
.driver = {
|
||||
.name = "twidjoy",
|
||||
},
|
||||
.description = DRIVER_DESC,
|
||||
.interrupt = twidjoy_interrupt,
|
||||
.connect = twidjoy_connect,
|
||||
.disconnect = twidjoy_disconnect,
|
||||
};
|
||||
|
||||
/*
|
||||
* The functions for inserting/removing us as a module.
|
||||
*/
|
||||
|
||||
int __init twidjoy_init(void)
|
||||
{
|
||||
serio_register_driver(&twidjoy_drv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit twidjoy_exit(void)
|
||||
{
|
||||
serio_unregister_driver(&twidjoy_drv);
|
||||
}
|
||||
|
||||
module_init(twidjoy_init);
|
||||
module_exit(twidjoy_exit);
|
||||
230
extra/linux-2.6.10/drivers/input/joystick/warrior.c
Normal file
230
extra/linux-2.6.10/drivers/input/joystick/warrior.c
Normal file
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* $Id: warrior.c,v 1.14 2002/01/22 20:32:10 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1999-2001 Vojtech Pavlik
|
||||
*/
|
||||
|
||||
/*
|
||||
* Logitech WingMan Warrior joystick driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free warftware; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/serio.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#define DRIVER_DESC "Logitech WingMan Warrior joystick driver"
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
* Constants.
|
||||
*/
|
||||
|
||||
#define WARRIOR_MAX_LENGTH 16
|
||||
static char warrior_lengths[] = { 0, 4, 12, 3, 4, 4, 0, 0 };
|
||||
static char *warrior_name = "Logitech WingMan Warrior";
|
||||
|
||||
/*
|
||||
* Per-Warrior data.
|
||||
*/
|
||||
|
||||
struct warrior {
|
||||
struct input_dev dev;
|
||||
int idx, len;
|
||||
unsigned char data[WARRIOR_MAX_LENGTH];
|
||||
char phys[32];
|
||||
};
|
||||
|
||||
/*
|
||||
* warrior_process_packet() decodes packets the driver receives from the
|
||||
* Warrior. It updates the data accordingly.
|
||||
*/
|
||||
|
||||
static void warrior_process_packet(struct warrior *warrior, struct pt_regs *regs)
|
||||
{
|
||||
struct input_dev *dev = &warrior->dev;
|
||||
unsigned char *data = warrior->data;
|
||||
|
||||
if (!warrior->idx) return;
|
||||
|
||||
input_regs(dev, regs);
|
||||
|
||||
switch ((data[0] >> 4) & 7) {
|
||||
case 1: /* Button data */
|
||||
input_report_key(dev, BTN_TRIGGER, data[3] & 1);
|
||||
input_report_key(dev, BTN_THUMB, (data[3] >> 1) & 1);
|
||||
input_report_key(dev, BTN_TOP, (data[3] >> 2) & 1);
|
||||
input_report_key(dev, BTN_TOP2, (data[3] >> 3) & 1);
|
||||
break;
|
||||
case 3: /* XY-axis info->data */
|
||||
input_report_abs(dev, ABS_X, ((data[0] & 8) << 5) - (data[2] | ((data[0] & 4) << 5)));
|
||||
input_report_abs(dev, ABS_Y, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7));
|
||||
break;
|
||||
case 5: /* Throttle, spinner, hat info->data */
|
||||
input_report_abs(dev, ABS_THROTTLE, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7));
|
||||
input_report_abs(dev, ABS_HAT0X, (data[3] & 2 ? 1 : 0) - (data[3] & 1 ? 1 : 0));
|
||||
input_report_abs(dev, ABS_HAT0Y, (data[3] & 8 ? 1 : 0) - (data[3] & 4 ? 1 : 0));
|
||||
input_report_rel(dev, REL_DIAL, (data[2] | ((data[0] & 4) << 5)) - ((data[0] & 8) << 5));
|
||||
break;
|
||||
}
|
||||
input_sync(dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* warrior_interrupt() is called by the low level driver when characters
|
||||
* are ready for us. We then buffer them for further processing, or call the
|
||||
* packet processing routine.
|
||||
*/
|
||||
|
||||
static irqreturn_t warrior_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags, struct pt_regs *regs)
|
||||
{
|
||||
struct warrior* warrior = serio->private;
|
||||
|
||||
if (data & 0x80) {
|
||||
if (warrior->idx) warrior_process_packet(warrior, regs);
|
||||
warrior->idx = 0;
|
||||
warrior->len = warrior_lengths[(data >> 4) & 7];
|
||||
}
|
||||
|
||||
if (warrior->idx < warrior->len)
|
||||
warrior->data[warrior->idx++] = data;
|
||||
|
||||
if (warrior->idx == warrior->len) {
|
||||
if (warrior->idx) warrior_process_packet(warrior, regs);
|
||||
warrior->idx = 0;
|
||||
warrior->len = 0;
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* warrior_disconnect() is the opposite of warrior_connect()
|
||||
*/
|
||||
|
||||
static void warrior_disconnect(struct serio *serio)
|
||||
{
|
||||
struct warrior* warrior = serio->private;
|
||||
input_unregister_device(&warrior->dev);
|
||||
serio_close(serio);
|
||||
kfree(warrior);
|
||||
}
|
||||
|
||||
/*
|
||||
* warrior_connect() is the routine that is called when someone adds a
|
||||
* new serio device. It looks for the Warrior, and if found, registers
|
||||
* it as an input device.
|
||||
*/
|
||||
|
||||
static void warrior_connect(struct serio *serio, struct serio_driver *drv)
|
||||
{
|
||||
struct warrior *warrior;
|
||||
int i;
|
||||
|
||||
if (serio->type != (SERIO_RS232 | SERIO_WARRIOR))
|
||||
return;
|
||||
|
||||
if (!(warrior = kmalloc(sizeof(struct warrior), GFP_KERNEL)))
|
||||
return;
|
||||
|
||||
memset(warrior, 0, sizeof(struct warrior));
|
||||
|
||||
warrior->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
|
||||
warrior->dev.keybit[LONG(BTN_TRIGGER)] = BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_TOP2);
|
||||
warrior->dev.relbit[0] = BIT(REL_DIAL);
|
||||
warrior->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y);
|
||||
|
||||
sprintf(warrior->phys, "%s/input0", serio->phys);
|
||||
|
||||
init_input_dev(&warrior->dev);
|
||||
warrior->dev.name = warrior_name;
|
||||
warrior->dev.phys = warrior->phys;
|
||||
warrior->dev.id.bustype = BUS_RS232;
|
||||
warrior->dev.id.vendor = SERIO_WARRIOR;
|
||||
warrior->dev.id.product = 0x0001;
|
||||
warrior->dev.id.version = 0x0100;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
warrior->dev.absmax[ABS_X+i] = -64;
|
||||
warrior->dev.absmin[ABS_X+i] = 64;
|
||||
warrior->dev.absflat[ABS_X+i] = 8;
|
||||
}
|
||||
|
||||
warrior->dev.absmax[ABS_THROTTLE] = -112;
|
||||
warrior->dev.absmin[ABS_THROTTLE] = 112;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
warrior->dev.absmax[ABS_HAT0X+i] = -1;
|
||||
warrior->dev.absmin[ABS_HAT0X+i] = 1;
|
||||
}
|
||||
|
||||
warrior->dev.private = warrior;
|
||||
|
||||
serio->private = warrior;
|
||||
|
||||
if (serio_open(serio, drv)) {
|
||||
kfree(warrior);
|
||||
return;
|
||||
}
|
||||
|
||||
input_register_device(&warrior->dev);
|
||||
|
||||
printk(KERN_INFO "input: Logitech WingMan Warrior on %s\n", serio->phys);
|
||||
}
|
||||
|
||||
/*
|
||||
* The serio device structure.
|
||||
*/
|
||||
|
||||
static struct serio_driver warrior_drv = {
|
||||
.driver = {
|
||||
.name = "warrior",
|
||||
},
|
||||
.description = DRIVER_DESC,
|
||||
.interrupt = warrior_interrupt,
|
||||
.connect = warrior_connect,
|
||||
.disconnect = warrior_disconnect,
|
||||
};
|
||||
|
||||
/*
|
||||
* The functions for inserting/removing us as a module.
|
||||
*/
|
||||
|
||||
int __init warrior_init(void)
|
||||
{
|
||||
serio_register_driver(&warrior_drv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit warrior_exit(void)
|
||||
{
|
||||
serio_unregister_driver(&warrior_drv);
|
||||
}
|
||||
|
||||
module_init(warrior_init);
|
||||
module_exit(warrior_exit);
|
||||
246
extra/linux-2.6.10/drivers/input/keyboard/.atkbd.o.cmd
Normal file
246
extra/linux-2.6.10/drivers/input/keyboard/.atkbd.o.cmd
Normal file
@@ -0,0 +1,246 @@
|
||||
cmd_drivers/input/keyboard/atkbd.o := gcc -Wp,-MD,drivers/input/keyboard/.atkbd.o.d -nostdinc -iwithprefix include -D__KERNEL__ -Iinclude -Wall -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -O2 -fomit-frame-pointer -pipe -msoft-float -mpreferred-stack-boundary=2 -fno-unit-at-a-time -march=pentium-mmx -Iinclude/asm-i386/mach-default -Wdeclaration-after-statement -DKBUILD_BASENAME=atkbd -DKBUILD_MODNAME=atkbd -c -o drivers/input/keyboard/atkbd.o drivers/input/keyboard/atkbd.c
|
||||
|
||||
deps_drivers/input/keyboard/atkbd.o := \
|
||||
drivers/input/keyboard/atkbd.c \
|
||||
include/linux/delay.h \
|
||||
include/asm/delay.h \
|
||||
include/linux/module.h \
|
||||
$(wildcard include/config/modules.h) \
|
||||
$(wildcard include/config/modversions.h) \
|
||||
$(wildcard include/config/module/unload.h) \
|
||||
$(wildcard include/config/kallsyms.h) \
|
||||
include/linux/config.h \
|
||||
$(wildcard include/config/h.h) \
|
||||
include/linux/sched.h \
|
||||
$(wildcard include/config/keys.h) \
|
||||
$(wildcard include/config/schedstats.h) \
|
||||
$(wildcard include/config/smp.h) \
|
||||
$(wildcard include/config/numa.h) \
|
||||
$(wildcard include/config/security.h) \
|
||||
$(wildcard include/config/preempt.h) \
|
||||
$(wildcard include/config/magic/sysrq.h) \
|
||||
include/asm/param.h \
|
||||
include/linux/capability.h \
|
||||
include/linux/types.h \
|
||||
$(wildcard include/config/uid16.h) \
|
||||
include/linux/posix_types.h \
|
||||
include/linux/stddef.h \
|
||||
include/linux/compiler.h \
|
||||
include/linux/compiler-gcc3.h \
|
||||
include/linux/compiler-gcc.h \
|
||||
include/asm/posix_types.h \
|
||||
include/asm/types.h \
|
||||
$(wildcard include/config/highmem64g.h) \
|
||||
$(wildcard include/config/lbd.h) \
|
||||
include/linux/spinlock.h \
|
||||
$(wildcard include/config/debug/spinlock.h) \
|
||||
$(wildcard include/config/lockmeter.h) \
|
||||
include/linux/preempt.h \
|
||||
include/linux/linkage.h \
|
||||
include/asm/linkage.h \
|
||||
$(wildcard include/config/regparm.h) \
|
||||
$(wildcard include/config/x86/alignment/16.h) \
|
||||
include/linux/thread_info.h \
|
||||
include/linux/bitops.h \
|
||||
include/asm/bitops.h \
|
||||
include/asm/thread_info.h \
|
||||
$(wildcard include/config/4kstacks.h) \
|
||||
$(wildcard include/config/debug/stack/usage.h) \
|
||||
include/asm/page.h \
|
||||
$(wildcard include/config/x86/use/3dnow.h) \
|
||||
$(wildcard include/config/x86/pae.h) \
|
||||
$(wildcard include/config/hugetlb/page.h) \
|
||||
$(wildcard include/config/highmem4g.h) \
|
||||
$(wildcard include/config/discontigmem.h) \
|
||||
include/asm/processor.h \
|
||||
$(wildcard include/config/mk8.h) \
|
||||
$(wildcard include/config/mk7.h) \
|
||||
include/asm/vm86.h \
|
||||
include/asm/math_emu.h \
|
||||
include/asm/sigcontext.h \
|
||||
include/asm/segment.h \
|
||||
include/asm/cpufeature.h \
|
||||
include/asm/msr.h \
|
||||
include/asm/system.h \
|
||||
$(wildcard include/config/x86/cmpxchg.h) \
|
||||
$(wildcard include/config/x86/oostore.h) \
|
||||
include/linux/kernel.h \
|
||||
$(wildcard include/config/debug/spinlock/sleep.h) \
|
||||
/usr/lib/gcc/i686-pc-linux-gnu/3.4.1/include/stdarg.h \
|
||||
include/asm/byteorder.h \
|
||||
$(wildcard include/config/x86/bswap.h) \
|
||||
include/linux/byteorder/little_endian.h \
|
||||
include/linux/byteorder/swab.h \
|
||||
include/linux/byteorder/generic.h \
|
||||
include/asm/bug.h \
|
||||
include/asm-generic/bug.h \
|
||||
include/linux/cache.h \
|
||||
include/asm/cache.h \
|
||||
$(wildcard include/config/x86/l1/cache/shift.h) \
|
||||
include/linux/threads.h \
|
||||
$(wildcard include/config/nr/cpus.h) \
|
||||
include/asm/percpu.h \
|
||||
include/asm-generic/percpu.h \
|
||||
include/linux/stringify.h \
|
||||
include/linux/timex.h \
|
||||
$(wildcard include/config/time/interpolation.h) \
|
||||
include/linux/time.h \
|
||||
include/linux/seqlock.h \
|
||||
include/asm/timex.h \
|
||||
$(wildcard include/config/x86/elan.h) \
|
||||
$(wildcard include/config/x86/tsc.h) \
|
||||
$(wildcard include/config/x86/generic.h) \
|
||||
include/linux/jiffies.h \
|
||||
include/asm/div64.h \
|
||||
include/linux/rbtree.h \
|
||||
include/linux/cpumask.h \
|
||||
$(wildcard include/config/hotplug/cpu.h) \
|
||||
include/linux/bitmap.h \
|
||||
include/linux/string.h \
|
||||
include/asm/string.h \
|
||||
include/asm/semaphore.h \
|
||||
include/asm/atomic.h \
|
||||
$(wildcard include/config/m386.h) \
|
||||
include/linux/wait.h \
|
||||
include/linux/list.h \
|
||||
include/linux/prefetch.h \
|
||||
include/asm/current.h \
|
||||
include/linux/rwsem.h \
|
||||
$(wildcard include/config/rwsem/generic/spinlock.h) \
|
||||
include/asm/rwsem.h \
|
||||
include/asm/ptrace.h \
|
||||
$(wildcard include/config/frame/pointer.h) \
|
||||
include/asm/mmu.h \
|
||||
include/linux/smp.h \
|
||||
include/linux/sem.h \
|
||||
$(wildcard include/config/sysvipc.h) \
|
||||
include/linux/ipc.h \
|
||||
include/asm/ipcbuf.h \
|
||||
include/asm/sembuf.h \
|
||||
include/linux/signal.h \
|
||||
include/asm/signal.h \
|
||||
include/asm/siginfo.h \
|
||||
include/asm-generic/siginfo.h \
|
||||
include/linux/resource.h \
|
||||
include/asm/resource.h \
|
||||
include/linux/securebits.h \
|
||||
include/linux/fs_struct.h \
|
||||
include/linux/completion.h \
|
||||
include/linux/pid.h \
|
||||
include/linux/percpu.h \
|
||||
include/linux/slab.h \
|
||||
$(wildcard include/config/.h) \
|
||||
include/linux/gfp.h \
|
||||
include/linux/mmzone.h \
|
||||
$(wildcard include/config/force/max/zoneorder.h) \
|
||||
include/linux/numa.h \
|
||||
include/linux/topology.h \
|
||||
$(wildcard include/config/sched/smt.h) \
|
||||
include/asm/topology.h \
|
||||
include/asm-generic/topology.h \
|
||||
include/linux/init.h \
|
||||
$(wildcard include/config/hotplug.h) \
|
||||
include/linux/kmalloc_sizes.h \
|
||||
$(wildcard include/config/mmu.h) \
|
||||
$(wildcard include/config/large/allocs.h) \
|
||||
include/linux/param.h \
|
||||
include/linux/timer.h \
|
||||
include/linux/aio.h \
|
||||
include/linux/workqueue.h \
|
||||
include/linux/aio_abi.h \
|
||||
include/linux/stat.h \
|
||||
include/asm/stat.h \
|
||||
include/linux/kmod.h \
|
||||
$(wildcard include/config/kmod.h) \
|
||||
include/linux/errno.h \
|
||||
include/asm/errno.h \
|
||||
include/asm-generic/errno.h \
|
||||
include/asm-generic/errno-base.h \
|
||||
include/linux/elf.h \
|
||||
include/asm/elf.h \
|
||||
include/asm/user.h \
|
||||
include/linux/utsname.h \
|
||||
include/linux/kobject.h \
|
||||
include/linux/sysfs.h \
|
||||
$(wildcard include/config/sysfs.h) \
|
||||
include/linux/kref.h \
|
||||
include/linux/kobject_uevent.h \
|
||||
$(wildcard include/config/kobject/uevent.h) \
|
||||
include/linux/moduleparam.h \
|
||||
include/asm/local.h \
|
||||
include/asm/module.h \
|
||||
$(wildcard include/config/m486.h) \
|
||||
$(wildcard include/config/m586.h) \
|
||||
$(wildcard include/config/m586tsc.h) \
|
||||
$(wildcard include/config/m586mmx.h) \
|
||||
$(wildcard include/config/m686.h) \
|
||||
$(wildcard include/config/mpentiumii.h) \
|
||||
$(wildcard include/config/mpentiumiii.h) \
|
||||
$(wildcard include/config/mpentiumm.h) \
|
||||
$(wildcard include/config/mpentium4.h) \
|
||||
$(wildcard include/config/mk6.h) \
|
||||
$(wildcard include/config/mcrusoe.h) \
|
||||
$(wildcard include/config/mefficeon.h) \
|
||||
$(wildcard include/config/mwinchipc6.h) \
|
||||
$(wildcard include/config/mwinchip2.h) \
|
||||
$(wildcard include/config/mwinchip3d.h) \
|
||||
$(wildcard include/config/mcyrixiii.h) \
|
||||
$(wildcard include/config/mviac3/2.h) \
|
||||
include/linux/interrupt.h \
|
||||
$(wildcard include/config/generic/hardirqs.h) \
|
||||
$(wildcard include/config/generic/irq/probe.h) \
|
||||
include/linux/hardirq.h \
|
||||
include/linux/smp_lock.h \
|
||||
$(wildcard include/config/lock/kernel.h) \
|
||||
include/asm/hardirq.h \
|
||||
include/linux/irq.h \
|
||||
$(wildcard include/config/arch/s390.h) \
|
||||
include/asm/irq.h \
|
||||
$(wildcard include/config/x86/local/apic.h) \
|
||||
$(wildcard include/config/irqbalance.h) \
|
||||
include/asm-i386/mach-default/irq_vectors.h \
|
||||
include/asm-i386/mach-default/irq_vectors_limits.h \
|
||||
$(wildcard include/config/pci/msi.h) \
|
||||
$(wildcard include/config/x86/io/apic.h) \
|
||||
include/asm/hw_irq.h \
|
||||
include/linux/profile.h \
|
||||
$(wildcard include/config/proc/fs.h) \
|
||||
$(wildcard include/config/profiling.h) \
|
||||
include/asm/sections.h \
|
||||
include/asm-generic/sections.h \
|
||||
include/linux/irq_cpustat.h \
|
||||
include/linux/input.h \
|
||||
include/linux/fs.h \
|
||||
$(wildcard include/config/dnotify.h) \
|
||||
$(wildcard include/config/quota.h) \
|
||||
$(wildcard include/config/epoll.h) \
|
||||
$(wildcard include/config/auditsyscall.h) \
|
||||
include/linux/limits.h \
|
||||
include/linux/kdev_t.h \
|
||||
include/linux/ioctl.h \
|
||||
include/asm/ioctl.h \
|
||||
include/linux/dcache.h \
|
||||
include/linux/rcupdate.h \
|
||||
include/linux/prio_tree.h \
|
||||
include/linux/radix-tree.h \
|
||||
include/linux/audit.h \
|
||||
$(wildcard include/config/audit.h) \
|
||||
include/linux/quota.h \
|
||||
include/linux/dqblk_xfs.h \
|
||||
include/linux/dqblk_v1.h \
|
||||
include/linux/dqblk_v2.h \
|
||||
include/linux/nfs_fs_i.h \
|
||||
include/linux/nfs.h \
|
||||
include/linux/sunrpc/msg_prot.h \
|
||||
include/linux/fcntl.h \
|
||||
include/asm/fcntl.h \
|
||||
include/linux/err.h \
|
||||
include/linux/serio.h \
|
||||
include/linux/device.h \
|
||||
include/linux/ioport.h \
|
||||
include/linux/pm.h \
|
||||
$(wildcard include/config/pm.h) \
|
||||
|
||||
drivers/input/keyboard/atkbd.o: $(deps_drivers/input/keyboard/atkbd.o)
|
||||
|
||||
$(deps_drivers/input/keyboard/atkbd.o):
|
||||
@@ -0,0 +1 @@
|
||||
cmd_drivers/input/keyboard/built-in.o := ld -m elf_i386 -r -o drivers/input/keyboard/built-in.o drivers/input/keyboard/atkbd.o
|
||||
98
extra/linux-2.6.10/drivers/input/keyboard/Kconfig
Normal file
98
extra/linux-2.6.10/drivers/input/keyboard/Kconfig
Normal file
@@ -0,0 +1,98 @@
|
||||
#
|
||||
# Input core configuration
|
||||
#
|
||||
config INPUT_KEYBOARD
|
||||
bool "Keyboards" if EMBEDDED || !X86
|
||||
default y
|
||||
depends on INPUT
|
||||
help
|
||||
Say Y here, and a list of supported keyboards will be displayed.
|
||||
This option doesn't affect the kernel.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config KEYBOARD_ATKBD
|
||||
tristate "AT keyboard support" if !PC
|
||||
default y
|
||||
depends on INPUT && INPUT_KEYBOARD
|
||||
select SERIO
|
||||
select SERIO_I8042 if PC
|
||||
select SERIO_GSCPS2 if GSC
|
||||
help
|
||||
Say Y here if you want to use a standard AT or PS/2 keyboard. Usually
|
||||
you'll need this, unless you have a different type keyboard (USB, ADB
|
||||
or other). This also works for AT and PS/2 keyboards connected over a
|
||||
PS/2 to serial converter.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called atkbd.
|
||||
|
||||
config KEYBOARD_SUNKBD
|
||||
tristate "Sun Type 4 and Type 5 keyboard support"
|
||||
depends on INPUT && INPUT_KEYBOARD
|
||||
select SERIO
|
||||
help
|
||||
Say Y here if you want to use a Sun Type 4 or Type 5 keyboard,
|
||||
connected either to the Sun keyboard connector or to an serial
|
||||
(RS-232) port via a simple adapter.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called sunkbd.
|
||||
|
||||
config KEYBOARD_LKKBD
|
||||
tristate "DECstation/VAXstation LK201/LK401 keyboard support"
|
||||
depends on INPUT && INPUT_KEYBOARD
|
||||
select SERIO
|
||||
help
|
||||
Say Y here if you want to use a LK201 or LK401 style serial
|
||||
keyboard. This keyboard is also useable on PCs if you attach
|
||||
it with the inputattach program. The connector pinout is
|
||||
described within lkkbd.c.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called lkkbd.
|
||||
|
||||
config KEYBOARD_XTKBD
|
||||
tristate "XT Keyboard support"
|
||||
depends on INPUT && INPUT_KEYBOARD
|
||||
select SERIO
|
||||
help
|
||||
Say Y here if you want to use the old IBM PC/XT keyboard (or
|
||||
compatible) on your system. This is only possible with a
|
||||
parallel port keyboard adapter, you cannot connect it to the
|
||||
keyboard port on a PC that runs Linux.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called xtkbd.
|
||||
|
||||
config KEYBOARD_NEWTON
|
||||
tristate "Newton keyboard"
|
||||
depends on INPUT && INPUT_KEYBOARD
|
||||
select SERIO
|
||||
help
|
||||
Say Y here if you have a Newton keyboard on a serial port.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called newtonkbd.
|
||||
|
||||
config KEYBOARD_MAPLE
|
||||
tristate "Maple bus keyboard support"
|
||||
depends on SH_DREAMCAST && INPUT && INPUT_KEYBOARD && MAPLE
|
||||
help
|
||||
Say Y here if you have a DreamCast console running Linux and have
|
||||
a keyboard attached to its Maple bus.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called maple_keyb.
|
||||
|
||||
config KEYBOARD_AMIGA
|
||||
tristate "Amiga keyboard"
|
||||
depends on AMIGA && INPUT && INPUT_KEYBOARD
|
||||
help
|
||||
Say Y here if you are running Linux on any AMIGA and have a keyboard
|
||||
attached.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called amikbd.
|
||||
14
extra/linux-2.6.10/drivers/input/keyboard/Makefile
Normal file
14
extra/linux-2.6.10/drivers/input/keyboard/Makefile
Normal file
@@ -0,0 +1,14 @@
|
||||
#
|
||||
# Makefile for the input core drivers.
|
||||
#
|
||||
|
||||
# Each configuration option enables a list of files.
|
||||
|
||||
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
|
||||
obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o
|
||||
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
|
||||
obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o
|
||||
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
|
||||
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
|
||||
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
|
||||
obj-$(CONFIG_KEYBOARD_98KBD) += 98kbd.o
|
||||
241
extra/linux-2.6.10/drivers/input/keyboard/amikbd.c
Normal file
241
extra/linux-2.6.10/drivers/input/keyboard/amikbd.c
Normal file
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* $Id: amikbd.c,v 1.13 2002/02/01 16:02:24 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 2000-2001 Vojtech Pavlik
|
||||
*
|
||||
* Based on the work of:
|
||||
* Hamish Macdonald
|
||||
*/
|
||||
|
||||
/*
|
||||
* Amiga keyboard driver for Linux/m68k
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <asm/amigaints.h>
|
||||
#include <asm/amigahw.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Amiga keyboard driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static unsigned char amikbd_keycode[0x78] = {
|
||||
[0] = KEY_GRAVE,
|
||||
[1] = KEY_1,
|
||||
[2] = KEY_2,
|
||||
[3] = KEY_3,
|
||||
[4] = KEY_4,
|
||||
[5] = KEY_5,
|
||||
[6] = KEY_6,
|
||||
[7] = KEY_7,
|
||||
[8] = KEY_8,
|
||||
[9] = KEY_9,
|
||||
[10] = KEY_0,
|
||||
[11] = KEY_MINUS,
|
||||
[12] = KEY_EQUAL,
|
||||
[13] = KEY_BACKSLASH,
|
||||
[15] = KEY_KP0,
|
||||
[16] = KEY_Q,
|
||||
[17] = KEY_W,
|
||||
[18] = KEY_E,
|
||||
[19] = KEY_R,
|
||||
[20] = KEY_T,
|
||||
[21] = KEY_Y,
|
||||
[22] = KEY_U,
|
||||
[23] = KEY_I,
|
||||
[24] = KEY_O,
|
||||
[25] = KEY_P,
|
||||
[26] = KEY_LEFTBRACE,
|
||||
[27] = KEY_RIGHTBRACE,
|
||||
[29] = KEY_KP1,
|
||||
[30] = KEY_KP2,
|
||||
[31] = KEY_KP3,
|
||||
[32] = KEY_A,
|
||||
[33] = KEY_S,
|
||||
[34] = KEY_D,
|
||||
[35] = KEY_F,
|
||||
[36] = KEY_G,
|
||||
[37] = KEY_H,
|
||||
[38] = KEY_J,
|
||||
[39] = KEY_K,
|
||||
[40] = KEY_L,
|
||||
[41] = KEY_SEMICOLON,
|
||||
[42] = KEY_APOSTROPHE,
|
||||
[43] = KEY_BACKSLASH,
|
||||
[45] = KEY_KP4,
|
||||
[46] = KEY_KP5,
|
||||
[47] = KEY_KP6,
|
||||
[48] = KEY_102ND,
|
||||
[49] = KEY_Z,
|
||||
[50] = KEY_X,
|
||||
[51] = KEY_C,
|
||||
[52] = KEY_V,
|
||||
[53] = KEY_B,
|
||||
[54] = KEY_N,
|
||||
[55] = KEY_M,
|
||||
[56] = KEY_COMMA,
|
||||
[57] = KEY_DOT,
|
||||
[58] = KEY_SLASH,
|
||||
[60] = KEY_KPDOT,
|
||||
[61] = KEY_KP7,
|
||||
[62] = KEY_KP8,
|
||||
[63] = KEY_KP9,
|
||||
[64] = KEY_SPACE,
|
||||
[65] = KEY_BACKSPACE,
|
||||
[66] = KEY_TAB,
|
||||
[67] = KEY_KPENTER,
|
||||
[68] = KEY_ENTER,
|
||||
[69] = KEY_ESC,
|
||||
[70] = KEY_DELETE,
|
||||
[74] = KEY_KPMINUS,
|
||||
[76] = KEY_UP,
|
||||
[77] = KEY_DOWN,
|
||||
[78] = KEY_RIGHT,
|
||||
[79] = KEY_LEFT,
|
||||
[80] = KEY_F1,
|
||||
[81] = KEY_F2,
|
||||
[82] = KEY_F3,
|
||||
[83] = KEY_F4,
|
||||
[84] = KEY_F5,
|
||||
[85] = KEY_F6,
|
||||
[86] = KEY_F7,
|
||||
[87] = KEY_F8,
|
||||
[88] = KEY_F9,
|
||||
[89] = KEY_F10,
|
||||
[90] = KEY_KPLEFTPAREN,
|
||||
[91] = KEY_KPRIGHTPAREN,
|
||||
[92] = KEY_KPSLASH,
|
||||
[93] = KEY_KPASTERISK,
|
||||
[94] = KEY_KPPLUS,
|
||||
[95] = KEY_HELP,
|
||||
[96] = KEY_LEFTSHIFT,
|
||||
[97] = KEY_RIGHTSHIFT,
|
||||
[98] = KEY_CAPSLOCK,
|
||||
[99] = KEY_LEFTCTRL,
|
||||
[100] = KEY_LEFTALT,
|
||||
[101] = KEY_RIGHTALT,
|
||||
[102] = KEY_LEFTMETA,
|
||||
[103] = KEY_RIGHTMETA
|
||||
};
|
||||
|
||||
static const char *amikbd_messages[8] = {
|
||||
[0] = KERN_ALERT "amikbd: Ctrl-Amiga-Amiga reset warning!!\n",
|
||||
[1] = KERN_WARNING "amikbd: keyboard lost sync\n",
|
||||
[2] = KERN_WARNING "amikbd: keyboard buffer overflow\n",
|
||||
[3] = KERN_WARNING "amikbd: keyboard controller failure\n",
|
||||
[4] = KERN_ERR "amikbd: keyboard selftest failure\n",
|
||||
[5] = KERN_INFO "amikbd: initiate power-up key stream\n",
|
||||
[6] = KERN_INFO "amikbd: terminate power-up key stream\n",
|
||||
[7] = KERN_WARNING "amikbd: keyboard interrupt\n"
|
||||
};
|
||||
|
||||
static struct input_dev amikbd_dev;
|
||||
|
||||
static char *amikbd_name = "Amiga keyboard";
|
||||
static char *amikbd_phys = "amikbd/input0";
|
||||
|
||||
static irqreturn_t amikbd_interrupt(int irq, void *dummy, struct pt_regs *fp)
|
||||
{
|
||||
unsigned char scancode, down;
|
||||
|
||||
scancode = ~ciaa.sdr; /* get and invert scancode (keyboard is active low) */
|
||||
ciaa.cra |= 0x40; /* switch SP pin to output for handshake */
|
||||
udelay(85); /* wait until 85 us have expired */
|
||||
ciaa.cra &= ~0x40; /* switch CIA serial port to input mode */
|
||||
|
||||
down = !(scancode & 1); /* lowest bit is release bit */
|
||||
scancode >>= 1;
|
||||
|
||||
if (scancode < 0x78) { /* scancodes < 0x78 are keys */
|
||||
|
||||
scancode = amikbd_keycode[scancode];
|
||||
|
||||
input_regs(&amikbd_dev, fp);
|
||||
|
||||
if (scancode == KEY_CAPSLOCK) { /* CapsLock is a toggle switch key on Amiga */
|
||||
input_report_key(&amikbd_dev, scancode, 1);
|
||||
input_report_key(&amikbd_dev, scancode, 0);
|
||||
input_sync(&amikbd_dev);
|
||||
} else {
|
||||
input_report_key(&amikbd_dev, scancode, down);
|
||||
input_sync(&amikbd_dev);
|
||||
}
|
||||
} else /* scancodes >= 0x78 are error codes */
|
||||
printk(amikbd_messages[scancode - 0x78]);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __init amikbd_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!AMIGAHW_PRESENT(AMI_KEYBOARD))
|
||||
return -EIO;
|
||||
|
||||
if (!request_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100, "amikeyb"))
|
||||
return -EBUSY;
|
||||
|
||||
init_input_dev(&amikbd_dev);
|
||||
|
||||
amikbd_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
||||
amikbd_dev.keycode = amikbd_keycode;
|
||||
amikbd_dev.keycodesize = sizeof(unsigned char);
|
||||
amikbd_dev.keycodemax = ARRAY_SIZE(amikbd_keycode);
|
||||
|
||||
for (i = 0; i < 0x78; i++)
|
||||
if (amikbd_keycode[i])
|
||||
set_bit(amikbd_keycode[i], amikbd_dev.keybit);
|
||||
|
||||
ciaa.cra &= ~0x41; /* serial data in, turn off TA */
|
||||
request_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt, 0, "amikbd", amikbd_interrupt);
|
||||
|
||||
amikbd_dev.name = amikbd_name;
|
||||
amikbd_dev.phys = amikbd_phys;
|
||||
amikbd_dev.id.bustype = BUS_AMIGA;
|
||||
amikbd_dev.id.vendor = 0x0001;
|
||||
amikbd_dev.id.product = 0x0001;
|
||||
amikbd_dev.id.version = 0x0100;
|
||||
|
||||
input_register_device(&amikbd_dev);
|
||||
|
||||
printk(KERN_INFO "input: %s\n", amikbd_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit amikbd_exit(void)
|
||||
{
|
||||
input_unregister_device(&amikbd_dev);
|
||||
free_irq(IRQ_AMIGA_CIAA_SP, amikbd_interrupt);
|
||||
release_mem_region(CIAA_PHYSADDR-1+0xb00, 0x100);
|
||||
}
|
||||
|
||||
module_init(amikbd_init);
|
||||
module_exit(amikbd_exit);
|
||||
1001
extra/linux-2.6.10/drivers/input/keyboard/atkbd.c
Normal file
1001
extra/linux-2.6.10/drivers/input/keyboard/atkbd.c
Normal file
File diff suppressed because it is too large
Load Diff
BIN
extra/linux-2.6.10/drivers/input/keyboard/atkbd.o
Normal file
BIN
extra/linux-2.6.10/drivers/input/keyboard/atkbd.o
Normal file
Binary file not shown.
BIN
extra/linux-2.6.10/drivers/input/keyboard/built-in.o
Normal file
BIN
extra/linux-2.6.10/drivers/input/keyboard/built-in.o
Normal file
Binary file not shown.
113
extra/linux-2.6.10/drivers/input/keyboard/hpps2atkbd.h
Normal file
113
extra/linux-2.6.10/drivers/input/keyboard/hpps2atkbd.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* drivers/input/keyboard/hpps2atkbd.h
|
||||
*
|
||||
* Copyright (c) 2004 Helge Deller <deller@gmx.de>
|
||||
* Copyright (c) 2002 Laurent Canet <canetl@esiee.fr>
|
||||
* Copyright (c) 2002 Thibaut Varene <varenet@esiee.fr>
|
||||
* Copyright (c) 2000 Xavier Debacker <debackex@esiee.fr>
|
||||
*
|
||||
* HP PS/2 AT-compatible Keyboard, found in PA/RISC Workstations & Laptops
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
/* undefine if you have a RDI PRECISIONBOOK */
|
||||
#define STANDARD_KEYBOARD
|
||||
|
||||
#if defined(STANDARD_KEYBOARD)
|
||||
# define CONFLICT(x,y) x
|
||||
#else
|
||||
# define CONFLICT(x,y) y
|
||||
#endif
|
||||
|
||||
/* sadly RDI (Tadpole) decided to ship a different keyboard layout
|
||||
than HP for their PS/2 laptop keyboard which leads to conflicting
|
||||
keycodes between a normal HP PS/2 keyboard and a RDI Precisionbook.
|
||||
HP: RDI: */
|
||||
#define C_07 CONFLICT( KEY_F12, KEY_F1 )
|
||||
#define C_11 CONFLICT( KEY_LEFTALT, KEY_LEFTCTRL )
|
||||
#define C_14 CONFLICT( KEY_LEFTCTRL, KEY_CAPSLOCK )
|
||||
#define C_58 CONFLICT( KEY_CAPSLOCK, KEY_RIGHTCTRL )
|
||||
#define C_61 CONFLICT( KEY_102ND, KEY_LEFT )
|
||||
|
||||
/* Raw SET 2 scancode table */
|
||||
|
||||
/* 00 */ KEY_RESERVED, KEY_F9, KEY_RESERVED, KEY_F5, KEY_F3, KEY_F1, KEY_F2, C_07,
|
||||
/* 08 */ KEY_ESC, KEY_F10, KEY_F8, KEY_F6, KEY_F4, KEY_TAB, KEY_GRAVE, KEY_F2,
|
||||
/* 10 */ KEY_RESERVED, C_11, KEY_LEFTSHIFT, KEY_RESERVED, C_14, KEY_Q, KEY_1, KEY_F3,
|
||||
/* 18 */ KEY_RESERVED, KEY_LEFTALT, KEY_Z, KEY_S, KEY_A, KEY_W, KEY_2, KEY_F4,
|
||||
/* 20 */ KEY_RESERVED, KEY_C, KEY_X, KEY_D, KEY_E, KEY_4, KEY_3, KEY_F5,
|
||||
/* 28 */ KEY_RESERVED, KEY_SPACE, KEY_V, KEY_F, KEY_T, KEY_R, KEY_5, KEY_F6,
|
||||
/* 30 */ KEY_RESERVED, KEY_N, KEY_B, KEY_H, KEY_G, KEY_Y, KEY_6, KEY_F7,
|
||||
/* 38 */ KEY_RESERVED, KEY_RIGHTALT, KEY_M, KEY_J, KEY_U, KEY_7, KEY_8, KEY_F8,
|
||||
/* 40 */ KEY_RESERVED, KEY_COMMA, KEY_K, KEY_I, KEY_O, KEY_0, KEY_9, KEY_F9,
|
||||
/* 48 */ KEY_RESERVED, KEY_DOT, KEY_SLASH, KEY_L, KEY_SEMICOLON, KEY_P, KEY_MINUS, KEY_F10,
|
||||
/* 50 */ KEY_RESERVED, KEY_RESERVED, KEY_APOSTROPHE,KEY_RESERVED, KEY_LEFTBRACE, KEY_EQUAL, KEY_F11, KEY_SYSRQ,
|
||||
/* 58 */ C_58, KEY_RIGHTSHIFT,KEY_ENTER, KEY_RIGHTBRACE,KEY_BACKSLASH, KEY_BACKSLASH,KEY_F12, KEY_SCROLLLOCK,
|
||||
/* 60 */ KEY_DOWN, C_61, KEY_PAUSE, KEY_UP, KEY_DELETE, KEY_END, KEY_BACKSPACE, KEY_INSERT,
|
||||
/* 68 */ KEY_RESERVED, KEY_KP1, KEY_RIGHT, KEY_KP4, KEY_KP7, KEY_PAGEDOWN, KEY_HOME, KEY_PAGEUP,
|
||||
/* 70 */ KEY_KP0, KEY_KPDOT, KEY_KP2, KEY_KP5, KEY_KP6, KEY_KP8, KEY_ESC, KEY_NUMLOCK,
|
||||
/* 78 */ KEY_F11, KEY_KPPLUS, KEY_KP3, KEY_KPMINUS, KEY_KPASTERISK,KEY_KP9, KEY_SCROLLLOCK,KEY_103RD,
|
||||
/* 80 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* 88 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* 90 */ KEY_RESERVED, KEY_RIGHTALT, KEY_SYSRQ, KEY_RESERVED, KEY_RIGHTCTRL, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* 98 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_CAPSLOCK, KEY_RESERVED, KEY_LEFTMETA,
|
||||
/* a0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RIGHTMETA,
|
||||
/* a8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_COMPOSE,
|
||||
/* b0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* b8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* c0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* c8 */ KEY_RESERVED, KEY_RESERVED, KEY_KPSLASH, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* d0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* d8 */ KEY_RESERVED, KEY_RESERVED, KEY_KPENTER, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* e0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* e8 */ KEY_RESERVED, KEY_END, KEY_RESERVED, KEY_LEFT, KEY_HOME, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* f0 */ KEY_INSERT, KEY_DELETE, KEY_DOWN, KEY_RESERVED, KEY_RIGHT, KEY_UP, KEY_RESERVED, KEY_PAUSE,
|
||||
/* f8 */ KEY_RESERVED, KEY_RESERVED, KEY_PAGEDOWN, KEY_RESERVED, KEY_SYSRQ, KEY_PAGEUP, KEY_RESERVED, KEY_RESERVED,
|
||||
|
||||
/* These are offset for escaped keycodes: */
|
||||
|
||||
/* 00 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_F7, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* 08 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* 10 */ KEY_RESERVED, KEY_RIGHTALT, KEY_RESERVED, KEY_RESERVED, KEY_RIGHTCTRL, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* 18 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* 20 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* 28 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* 30 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* 38 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* 40 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* 48 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* 50 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* 58 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* 60 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* 68 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* 70 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* 78 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* 80 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* 88 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* 90 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* 98 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* a0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* a8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* b0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* b8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* c0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* c8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* d0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* d8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* e0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* e8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* f0 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED,
|
||||
/* f8 */ KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED
|
||||
|
||||
#undef STANDARD_KEYBOARD
|
||||
#undef CONFLICT
|
||||
#undef C_07
|
||||
#undef C_11
|
||||
#undef C_14
|
||||
#undef C_58
|
||||
#undef C_61
|
||||
|
||||
736
extra/linux-2.6.10/drivers/input/keyboard/lkkbd.c
Normal file
736
extra/linux-2.6.10/drivers/input/keyboard/lkkbd.c
Normal file
@@ -0,0 +1,736 @@
|
||||
/*
|
||||
* Copyright (C) 2004 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
|
||||
*/
|
||||
|
||||
/*
|
||||
* LK keyboard driver for Linux, based on sunkbd.c (C) by Vojtech Pavlik
|
||||
*/
|
||||
|
||||
/*
|
||||
* DEC LK201 and LK401 keyboard driver for Linux (primary for DECstations
|
||||
* and VAXstations, but can also be used on any standard RS232 with an
|
||||
* adaptor).
|
||||
*
|
||||
* DISCLAIMER: This works for _me_. If you break anything by using the
|
||||
* information given below, I will _not_ be liable!
|
||||
*
|
||||
* RJ11 pinout: To DB9: Or DB25:
|
||||
* 1 - RxD <----> Pin 3 (TxD) <-> Pin 2 (TxD)
|
||||
* 2 - GND <----> Pin 5 (GND) <-> Pin 7 (GND)
|
||||
* 4 - TxD <----> Pin 2 (RxD) <-> Pin 3 (RxD)
|
||||
* 3 - +12V (from HDD drive connector), DON'T connect to DB9 or DB25!!!
|
||||
*
|
||||
* Pin numbers for DB9 and DB25 are noted on the plug (quite small:). For
|
||||
* RJ11, it's like this:
|
||||
*
|
||||
* __=__ Hold the plug in front of you, cable downwards,
|
||||
* /___/| nose is hidden behind the plug. Now, pin 1 is at
|
||||
* |1234|| the left side, pin 4 at the right and 2 and 3 are
|
||||
* |IIII|| in between, of course:)
|
||||
* | ||
|
||||
* |____|/
|
||||
* || So the adaptor consists of three connected cables
|
||||
* || for data transmission (RxD and TxD) and signal ground.
|
||||
* Additionally, you have to get +12V from somewhere.
|
||||
* Most easily, you'll get that from a floppy or HDD power connector.
|
||||
* It's the yellow cable there (black is ground and red is +5V).
|
||||
*
|
||||
* The keyboard and all the commands it understands are documented in
|
||||
* "VCB02 Video Subsystem - Technical Manual", EK-104AA-TM-001. This
|
||||
* document is LK201 specific, but LK401 is mostly compatible. It comes
|
||||
* up in LK201 mode and doesn't report any of the additional keys it
|
||||
* has. These need to be switched on with the LK_CMD_ENABLE_LK401
|
||||
* command. You'll find this document (scanned .pdf file) on MANX,
|
||||
* a search engine specific to DEC documentation. Try
|
||||
* http://www.vt100.net/manx/details?pn=EK-104AA-TM-001;id=21;cp=1
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* email or by paper mail:
|
||||
* Jan-Benedict Glaw, Lilienstraße 16, 33790 Hörste (near Halle/Westf.),
|
||||
* Germany.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/serio.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#define DRIVER_DESC "LK keyboard driver"
|
||||
|
||||
MODULE_AUTHOR ("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
|
||||
MODULE_DESCRIPTION (DRIVER_DESC);
|
||||
MODULE_LICENSE ("GPL");
|
||||
|
||||
/*
|
||||
* Known parameters:
|
||||
* bell_volume
|
||||
* keyclick_volume
|
||||
* ctrlclick_volume
|
||||
*
|
||||
* Please notice that there's not yet an API to set these at runtime.
|
||||
*/
|
||||
static int bell_volume = 100; /* % */
|
||||
module_param (bell_volume, int, 0);
|
||||
MODULE_PARM_DESC (bell_volume, "Bell volume (in %). default is 100%");
|
||||
|
||||
static int keyclick_volume = 100; /* % */
|
||||
module_param (keyclick_volume, int, 0);
|
||||
MODULE_PARM_DESC (keyclick_volume, "Keyclick volume (in %), default is 100%");
|
||||
|
||||
static int ctrlclick_volume = 100; /* % */
|
||||
module_param (ctrlclick_volume, int, 0);
|
||||
MODULE_PARM_DESC (ctrlclick_volume, "Ctrlclick volume (in %), default is 100%");
|
||||
|
||||
static int lk201_compose_is_alt = 0;
|
||||
module_param (lk201_compose_is_alt, int, 0);
|
||||
MODULE_PARM_DESC (lk201_compose_is_alt, "If set non-zero, LK201' Compose key "
|
||||
"will act as an Alt key");
|
||||
|
||||
|
||||
|
||||
#undef LKKBD_DEBUG
|
||||
#ifdef LKKBD_DEBUG
|
||||
#define DBG(x...) printk (x)
|
||||
#else
|
||||
#define DBG(x...) do {} while (0)
|
||||
#endif
|
||||
|
||||
/* LED control */
|
||||
#define LK_LED_WAIT 0x81
|
||||
#define LK_LED_COMPOSE 0x82
|
||||
#define LK_LED_SHIFTLOCK 0x84
|
||||
#define LK_LED_SCROLLLOCK 0x88
|
||||
#define LK_CMD_LED_ON 0x13
|
||||
#define LK_CMD_LED_OFF 0x11
|
||||
|
||||
/* Mode control */
|
||||
#define LK_MODE_DOWN 0x80
|
||||
#define LK_MODE_AUTODOWN 0x82
|
||||
#define LK_MODE_UPDOWN 0x86
|
||||
#define LK_CMD_SET_MODE(mode,div) ((mode) | ((div) << 3))
|
||||
|
||||
/* Misc commands */
|
||||
#define LK_CMD_ENABLE_KEYCLICK 0x1b
|
||||
#define LK_CMD_DISABLE_KEYCLICK 0x99
|
||||
#define LK_CMD_DISABLE_BELL 0xa1
|
||||
#define LK_CMD_SOUND_BELL 0xa7
|
||||
#define LK_CMD_ENABLE_BELL 0x23
|
||||
#define LK_CMD_DISABLE_CTRCLICK 0xb9
|
||||
#define LK_CMD_ENABLE_CTRCLICK 0xbb
|
||||
#define LK_CMD_SET_DEFAULTS 0xd3
|
||||
#define LK_CMD_POWERCYCLE_RESET 0xfd
|
||||
#define LK_CMD_ENABLE_LK401 0xe9
|
||||
#define LK_CMD_REQUEST_ID 0xab
|
||||
|
||||
/* Misc responses from keyboard */
|
||||
#define LK_STUCK_KEY 0x3d
|
||||
#define LK_SELFTEST_FAILED 0x3e
|
||||
#define LK_ALL_KEYS_UP 0xb3
|
||||
#define LK_METRONOME 0xb4
|
||||
#define LK_OUTPUT_ERROR 0xb5
|
||||
#define LK_INPUT_ERROR 0xb6
|
||||
#define LK_KBD_LOCKED 0xb7
|
||||
#define LK_KBD_TEST_MODE_ACK 0xb8
|
||||
#define LK_PREFIX_KEY_DOWN 0xb9
|
||||
#define LK_MODE_CHANGE_ACK 0xba
|
||||
#define LK_RESPONSE_RESERVED 0xbb
|
||||
|
||||
#define LK_NUM_KEYCODES 256
|
||||
#define LK_NUM_IGNORE_BYTES 6
|
||||
typedef u_int16_t lk_keycode_t;
|
||||
|
||||
|
||||
|
||||
static lk_keycode_t lkkbd_keycode[LK_NUM_KEYCODES] = {
|
||||
[0x56] = KEY_F1,
|
||||
[0x57] = KEY_F2,
|
||||
[0x58] = KEY_F3,
|
||||
[0x59] = KEY_F4,
|
||||
[0x5a] = KEY_F5,
|
||||
[0x64] = KEY_F6,
|
||||
[0x65] = KEY_F7,
|
||||
[0x66] = KEY_F8,
|
||||
[0x67] = KEY_F9,
|
||||
[0x68] = KEY_F10,
|
||||
[0x71] = KEY_F11,
|
||||
[0x72] = KEY_F12,
|
||||
[0x73] = KEY_F13,
|
||||
[0x74] = KEY_F14,
|
||||
[0x7c] = KEY_F15,
|
||||
[0x7d] = KEY_F16,
|
||||
[0x80] = KEY_F17,
|
||||
[0x81] = KEY_F18,
|
||||
[0x82] = KEY_F19,
|
||||
[0x83] = KEY_F20,
|
||||
[0x8a] = KEY_FIND,
|
||||
[0x8b] = KEY_INSERT,
|
||||
[0x8c] = KEY_DELETE,
|
||||
[0x8d] = KEY_SELECT,
|
||||
[0x8e] = KEY_PAGEUP,
|
||||
[0x8f] = KEY_PAGEDOWN,
|
||||
[0x92] = KEY_KP0,
|
||||
[0x94] = KEY_KPDOT,
|
||||
[0x95] = KEY_KPENTER,
|
||||
[0x96] = KEY_KP1,
|
||||
[0x97] = KEY_KP2,
|
||||
[0x98] = KEY_KP3,
|
||||
[0x99] = KEY_KP4,
|
||||
[0x9a] = KEY_KP5,
|
||||
[0x9b] = KEY_KP6,
|
||||
[0x9c] = KEY_KPCOMMA,
|
||||
[0x9d] = KEY_KP7,
|
||||
[0x9e] = KEY_KP8,
|
||||
[0x9f] = KEY_KP9,
|
||||
[0xa0] = KEY_KPMINUS,
|
||||
[0xa1] = KEY_PROG1,
|
||||
[0xa2] = KEY_PROG2,
|
||||
[0xa3] = KEY_PROG3,
|
||||
[0xa4] = KEY_PROG4,
|
||||
[0xa7] = KEY_LEFT,
|
||||
[0xa8] = KEY_RIGHT,
|
||||
[0xa9] = KEY_DOWN,
|
||||
[0xaa] = KEY_UP,
|
||||
[0xab] = KEY_RIGHTSHIFT,
|
||||
[0xac] = KEY_LEFTALT,
|
||||
[0xad] = KEY_COMPOSE, /* Right Compose, that is. */
|
||||
[0xae] = KEY_LEFTSHIFT, /* Same as KEY_RIGHTSHIFT on LK201 */
|
||||
[0xaf] = KEY_LEFTCTRL,
|
||||
[0xb0] = KEY_CAPSLOCK,
|
||||
[0xb1] = KEY_COMPOSE, /* Left Compose, that is. */
|
||||
[0xb2] = KEY_RIGHTALT,
|
||||
[0xbc] = KEY_BACKSPACE,
|
||||
[0xbd] = KEY_ENTER,
|
||||
[0xbe] = KEY_TAB,
|
||||
[0xbf] = KEY_ESC,
|
||||
[0xc0] = KEY_1,
|
||||
[0xc1] = KEY_Q,
|
||||
[0xc2] = KEY_A,
|
||||
[0xc3] = KEY_Z,
|
||||
[0xc5] = KEY_2,
|
||||
[0xc6] = KEY_W,
|
||||
[0xc7] = KEY_S,
|
||||
[0xc8] = KEY_X,
|
||||
[0xc9] = KEY_102ND,
|
||||
[0xcb] = KEY_3,
|
||||
[0xcc] = KEY_E,
|
||||
[0xcd] = KEY_D,
|
||||
[0xce] = KEY_C,
|
||||
[0xd0] = KEY_4,
|
||||
[0xd1] = KEY_R,
|
||||
[0xd2] = KEY_F,
|
||||
[0xd3] = KEY_V,
|
||||
[0xd4] = KEY_SPACE,
|
||||
[0xd6] = KEY_5,
|
||||
[0xd7] = KEY_T,
|
||||
[0xd8] = KEY_G,
|
||||
[0xd9] = KEY_B,
|
||||
[0xdb] = KEY_6,
|
||||
[0xdc] = KEY_Y,
|
||||
[0xdd] = KEY_H,
|
||||
[0xde] = KEY_N,
|
||||
[0xe0] = KEY_7,
|
||||
[0xe1] = KEY_U,
|
||||
[0xe2] = KEY_J,
|
||||
[0xe3] = KEY_M,
|
||||
[0xe5] = KEY_8,
|
||||
[0xe6] = KEY_I,
|
||||
[0xe7] = KEY_K,
|
||||
[0xe8] = KEY_COMMA,
|
||||
[0xea] = KEY_9,
|
||||
[0xeb] = KEY_O,
|
||||
[0xec] = KEY_L,
|
||||
[0xed] = KEY_DOT,
|
||||
[0xef] = KEY_0,
|
||||
[0xf0] = KEY_P,
|
||||
[0xf2] = KEY_SEMICOLON,
|
||||
[0xf3] = KEY_SLASH,
|
||||
[0xf5] = KEY_EQUAL,
|
||||
[0xf6] = KEY_RIGHTBRACE,
|
||||
[0xf7] = KEY_BACKSLASH,
|
||||
[0xf9] = KEY_MINUS,
|
||||
[0xfa] = KEY_LEFTBRACE,
|
||||
[0xfb] = KEY_APOSTROPHE,
|
||||
};
|
||||
|
||||
#define CHECK_LED(LED, BITS) do { \
|
||||
if (test_bit (LED, lk->dev.led)) \
|
||||
leds_on |= BITS; \
|
||||
else \
|
||||
leds_off |= BITS; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Per-keyboard data
|
||||
*/
|
||||
struct lkkbd {
|
||||
lk_keycode_t keycode[LK_NUM_KEYCODES];
|
||||
int ignore_bytes;
|
||||
unsigned char id[LK_NUM_IGNORE_BYTES];
|
||||
struct input_dev dev;
|
||||
struct serio *serio;
|
||||
struct work_struct tq;
|
||||
char name[64];
|
||||
char phys[32];
|
||||
char type;
|
||||
int bell_volume;
|
||||
int keyclick_volume;
|
||||
int ctrlclick_volume;
|
||||
};
|
||||
|
||||
/*
|
||||
* Calculate volume parameter byte for a given volume.
|
||||
*/
|
||||
static unsigned char
|
||||
volume_to_hw (int volume_percent)
|
||||
{
|
||||
unsigned char ret = 0;
|
||||
|
||||
if (volume_percent < 0)
|
||||
volume_percent = 0;
|
||||
if (volume_percent > 100)
|
||||
volume_percent = 100;
|
||||
|
||||
if (volume_percent >= 0)
|
||||
ret = 7;
|
||||
if (volume_percent >= 13) /* 12.5 */
|
||||
ret = 6;
|
||||
if (volume_percent >= 25)
|
||||
ret = 5;
|
||||
if (volume_percent >= 38) /* 37.5 */
|
||||
ret = 4;
|
||||
if (volume_percent >= 50)
|
||||
ret = 3;
|
||||
if (volume_percent >= 63) /* 62.5 */
|
||||
ret = 2; /* This is the default volume */
|
||||
if (volume_percent >= 75)
|
||||
ret = 1;
|
||||
if (volume_percent >= 88) /* 87.5 */
|
||||
ret = 0;
|
||||
|
||||
ret |= 0x80;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
lkkbd_detection_done (struct lkkbd *lk)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Reset setting for Compose key. Let Compose be KEY_COMPOSE.
|
||||
*/
|
||||
lk->keycode[0xb1] = KEY_COMPOSE;
|
||||
|
||||
/*
|
||||
* Print keyboard name and modify Compose=Alt on user's request.
|
||||
*/
|
||||
switch (lk->id[4]) {
|
||||
case 1:
|
||||
sprintf (lk->name, "DEC LK201 keyboard");
|
||||
|
||||
if (lk201_compose_is_alt)
|
||||
lk->keycode[0xb1] = KEY_LEFTALT;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
sprintf (lk->name, "DEC LK401 keyboard");
|
||||
break;
|
||||
|
||||
default:
|
||||
sprintf (lk->name, "Unknown DEC keyboard");
|
||||
printk (KERN_ERR "lkkbd: keyboard on %s is unknown, "
|
||||
"please report to Jan-Benedict Glaw "
|
||||
"<jbglaw@lug-owl.de>\n", lk->phys);
|
||||
printk (KERN_ERR "lkkbd: keyboard ID'ed as:");
|
||||
for (i = 0; i < LK_NUM_IGNORE_BYTES; i++)
|
||||
printk (" 0x%02x", lk->id[i]);
|
||||
printk ("\n");
|
||||
break;
|
||||
}
|
||||
printk (KERN_INFO "lkkbd: keyboard on %s identified as: %s\n",
|
||||
lk->phys, lk->name);
|
||||
|
||||
/*
|
||||
* Report errors during keyboard boot-up.
|
||||
*/
|
||||
switch (lk->id[2]) {
|
||||
case 0x00:
|
||||
/* All okay */
|
||||
break;
|
||||
|
||||
case LK_STUCK_KEY:
|
||||
printk (KERN_ERR "lkkbd: Stuck key on keyboard at "
|
||||
"%s\n", lk->phys);
|
||||
break;
|
||||
|
||||
case LK_SELFTEST_FAILED:
|
||||
printk (KERN_ERR "lkkbd: Selftest failed on keyboard "
|
||||
"at %s, keyboard may not work "
|
||||
"properly\n", lk->phys);
|
||||
break;
|
||||
|
||||
default:
|
||||
printk (KERN_ERR "lkkbd: Unknown error %02x on "
|
||||
"keyboard at %s\n", lk->id[2],
|
||||
lk->phys);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to hint user if there's a stuck key.
|
||||
*/
|
||||
if (lk->id[2] == LK_STUCK_KEY && lk->id[3] != 0)
|
||||
printk (KERN_ERR "Scancode of stuck key is 0x%02x, keycode "
|
||||
"is 0x%04x\n", lk->id[3],
|
||||
lk->keycode[lk->id[3]]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* lkkbd_interrupt() is called by the low level driver when a character
|
||||
* is received.
|
||||
*/
|
||||
static irqreturn_t
|
||||
lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
struct lkkbd *lk = serio->private;
|
||||
int i;
|
||||
|
||||
DBG (KERN_INFO "Got byte 0x%02x\n", data);
|
||||
|
||||
if (lk->ignore_bytes > 0) {
|
||||
DBG (KERN_INFO "Ignoring a byte on %s\n",
|
||||
lk->name);
|
||||
lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data;
|
||||
|
||||
if (lk->ignore_bytes == 0)
|
||||
lkkbd_detection_done (lk);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
switch (data) {
|
||||
case LK_ALL_KEYS_UP:
|
||||
input_regs (&lk->dev, regs);
|
||||
for (i = 0; i < ARRAY_SIZE (lkkbd_keycode); i++)
|
||||
if (lk->keycode[i] != KEY_RESERVED)
|
||||
input_report_key (&lk->dev, lk->keycode[i], 0);
|
||||
input_sync (&lk->dev);
|
||||
break;
|
||||
case LK_METRONOME:
|
||||
DBG (KERN_INFO "Got LK_METRONOME and don't "
|
||||
"know how to handle...\n");
|
||||
break;
|
||||
case LK_OUTPUT_ERROR:
|
||||
DBG (KERN_INFO "Got LK_OUTPUT_ERROR and don't "
|
||||
"know how to handle...\n");
|
||||
break;
|
||||
case LK_INPUT_ERROR:
|
||||
DBG (KERN_INFO "Got LK_INPUT_ERROR and don't "
|
||||
"know how to handle...\n");
|
||||
break;
|
||||
case LK_KBD_LOCKED:
|
||||
DBG (KERN_INFO "Got LK_KBD_LOCKED and don't "
|
||||
"know how to handle...\n");
|
||||
break;
|
||||
case LK_KBD_TEST_MODE_ACK:
|
||||
DBG (KERN_INFO "Got LK_KBD_TEST_MODE_ACK and don't "
|
||||
"know how to handle...\n");
|
||||
break;
|
||||
case LK_PREFIX_KEY_DOWN:
|
||||
DBG (KERN_INFO "Got LK_PREFIX_KEY_DOWN and don't "
|
||||
"know how to handle...\n");
|
||||
break;
|
||||
case LK_MODE_CHANGE_ACK:
|
||||
DBG (KERN_INFO "Got LK_MODE_CHANGE_ACK and ignored "
|
||||
"it properly...\n");
|
||||
break;
|
||||
case LK_RESPONSE_RESERVED:
|
||||
DBG (KERN_INFO "Got LK_RESPONSE_RESERVED and don't "
|
||||
"know how to handle...\n");
|
||||
break;
|
||||
case 0x01:
|
||||
DBG (KERN_INFO "Got 0x01, scheduling re-initialization\n");
|
||||
lk->ignore_bytes = LK_NUM_IGNORE_BYTES;
|
||||
lk->id[LK_NUM_IGNORE_BYTES - lk->ignore_bytes--] = data;
|
||||
schedule_work (&lk->tq);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (lk->keycode[data] != KEY_RESERVED) {
|
||||
input_regs (&lk->dev, regs);
|
||||
if (!test_bit (lk->keycode[data], lk->dev.key))
|
||||
input_report_key (&lk->dev, lk->keycode[data], 1);
|
||||
else
|
||||
input_report_key (&lk->dev, lk->keycode[data], 0);
|
||||
input_sync (&lk->dev);
|
||||
} else
|
||||
printk (KERN_WARNING "%s: Unknown key with "
|
||||
"scancode 0x%02x on %s.\n",
|
||||
__FILE__, data, lk->name);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* lkkbd_event() handles events from the input module.
|
||||
*/
|
||||
static int
|
||||
lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code,
|
||||
int value)
|
||||
{
|
||||
struct lkkbd *lk = dev->private;
|
||||
unsigned char leds_on = 0;
|
||||
unsigned char leds_off = 0;
|
||||
|
||||
switch (type) {
|
||||
case EV_LED:
|
||||
CHECK_LED (LED_CAPSL, LK_LED_SHIFTLOCK);
|
||||
CHECK_LED (LED_COMPOSE, LK_LED_COMPOSE);
|
||||
CHECK_LED (LED_SCROLLL, LK_LED_SCROLLLOCK);
|
||||
CHECK_LED (LED_SLEEP, LK_LED_WAIT);
|
||||
if (leds_on != 0) {
|
||||
lk->serio->write (lk->serio, LK_CMD_LED_ON);
|
||||
lk->serio->write (lk->serio, leds_on);
|
||||
}
|
||||
if (leds_off != 0) {
|
||||
lk->serio->write (lk->serio, LK_CMD_LED_OFF);
|
||||
lk->serio->write (lk->serio, leds_off);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case EV_SND:
|
||||
switch (code) {
|
||||
case SND_CLICK:
|
||||
if (value == 0) {
|
||||
DBG ("%s: Deactivating key clicks\n", __FUNCTION__);
|
||||
lk->serio->write (lk->serio, LK_CMD_DISABLE_KEYCLICK);
|
||||
lk->serio->write (lk->serio, LK_CMD_DISABLE_CTRCLICK);
|
||||
} else {
|
||||
DBG ("%s: Activating key clicks\n", __FUNCTION__);
|
||||
lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK);
|
||||
lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume));
|
||||
lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK);
|
||||
lk->serio->write (lk->serio, volume_to_hw (lk->ctrlclick_volume));
|
||||
}
|
||||
return 0;
|
||||
|
||||
case SND_BELL:
|
||||
if (value != 0)
|
||||
lk->serio->write (lk->serio, LK_CMD_SOUND_BELL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
printk (KERN_ERR "%s (): Got unknown type %d, code %d, value %d\n",
|
||||
__FUNCTION__, type, code, value);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* lkkbd_reinit() sets leds and beeps to a state the computer remembers they
|
||||
* were in.
|
||||
*/
|
||||
static void
|
||||
lkkbd_reinit (void *data)
|
||||
{
|
||||
struct lkkbd *lk = data;
|
||||
int division;
|
||||
unsigned char leds_on = 0;
|
||||
unsigned char leds_off = 0;
|
||||
|
||||
/* Ask for ID */
|
||||
lk->serio->write (lk->serio, LK_CMD_REQUEST_ID);
|
||||
|
||||
/* Reset parameters */
|
||||
lk->serio->write (lk->serio, LK_CMD_SET_DEFAULTS);
|
||||
|
||||
/* Set LEDs */
|
||||
CHECK_LED (LED_CAPSL, LK_LED_SHIFTLOCK);
|
||||
CHECK_LED (LED_COMPOSE, LK_LED_COMPOSE);
|
||||
CHECK_LED (LED_SCROLLL, LK_LED_SCROLLLOCK);
|
||||
CHECK_LED (LED_SLEEP, LK_LED_WAIT);
|
||||
if (leds_on != 0) {
|
||||
lk->serio->write (lk->serio, LK_CMD_LED_ON);
|
||||
lk->serio->write (lk->serio, leds_on);
|
||||
}
|
||||
if (leds_off != 0) {
|
||||
lk->serio->write (lk->serio, LK_CMD_LED_OFF);
|
||||
lk->serio->write (lk->serio, leds_off);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to activate extended LK401 mode. This command will
|
||||
* only work with a LK401 keyboard and grants access to
|
||||
* LAlt, RAlt, RCompose and RShift.
|
||||
*/
|
||||
lk->serio->write (lk->serio, LK_CMD_ENABLE_LK401);
|
||||
|
||||
/* Set all keys to UPDOWN mode */
|
||||
for (division = 1; division <= 14; division++)
|
||||
lk->serio->write (lk->serio, LK_CMD_SET_MODE (LK_MODE_UPDOWN,
|
||||
division));
|
||||
|
||||
/* Enable bell and set volume */
|
||||
lk->serio->write (lk->serio, LK_CMD_ENABLE_BELL);
|
||||
lk->serio->write (lk->serio, volume_to_hw (lk->bell_volume));
|
||||
|
||||
/* Enable/disable keyclick (and possibly set volume) */
|
||||
if (test_bit (SND_CLICK, lk->dev.snd)) {
|
||||
lk->serio->write (lk->serio, LK_CMD_ENABLE_KEYCLICK);
|
||||
lk->serio->write (lk->serio, volume_to_hw (lk->keyclick_volume));
|
||||
lk->serio->write (lk->serio, LK_CMD_ENABLE_CTRCLICK);
|
||||
lk->serio->write (lk->serio, volume_to_hw (lk->ctrlclick_volume));
|
||||
} else {
|
||||
lk->serio->write (lk->serio, LK_CMD_DISABLE_KEYCLICK);
|
||||
lk->serio->write (lk->serio, LK_CMD_DISABLE_CTRCLICK);
|
||||
}
|
||||
|
||||
/* Sound the bell if needed */
|
||||
if (test_bit (SND_BELL, lk->dev.snd))
|
||||
lk->serio->write (lk->serio, LK_CMD_SOUND_BELL);
|
||||
}
|
||||
|
||||
/*
|
||||
* lkkbd_connect() probes for a LK keyboard and fills the necessary structures.
|
||||
*/
|
||||
static void
|
||||
lkkbd_connect (struct serio *serio, struct serio_driver *drv)
|
||||
{
|
||||
struct lkkbd *lk;
|
||||
int i;
|
||||
|
||||
if ((serio->type & SERIO_TYPE) != SERIO_RS232)
|
||||
return;
|
||||
if ((serio->type & SERIO_PROTO) != SERIO_LKKBD)
|
||||
return;
|
||||
|
||||
if (!(lk = kmalloc (sizeof (struct lkkbd), GFP_KERNEL)))
|
||||
return;
|
||||
memset (lk, 0, sizeof (struct lkkbd));
|
||||
|
||||
init_input_dev (&lk->dev);
|
||||
set_bit (EV_KEY, lk->dev.evbit);
|
||||
set_bit (EV_LED, lk->dev.evbit);
|
||||
set_bit (EV_SND, lk->dev.evbit);
|
||||
set_bit (EV_REP, lk->dev.evbit);
|
||||
set_bit (LED_CAPSL, lk->dev.ledbit);
|
||||
set_bit (LED_SLEEP, lk->dev.ledbit);
|
||||
set_bit (LED_COMPOSE, lk->dev.ledbit);
|
||||
set_bit (LED_SCROLLL, lk->dev.ledbit);
|
||||
set_bit (SND_BELL, lk->dev.sndbit);
|
||||
set_bit (SND_CLICK, lk->dev.sndbit);
|
||||
|
||||
lk->serio = serio;
|
||||
|
||||
INIT_WORK (&lk->tq, lkkbd_reinit, lk);
|
||||
|
||||
lk->bell_volume = bell_volume;
|
||||
lk->keyclick_volume = keyclick_volume;
|
||||
lk->ctrlclick_volume = ctrlclick_volume;
|
||||
|
||||
lk->dev.keycode = lk->keycode;
|
||||
lk->dev.keycodesize = sizeof (lk_keycode_t);
|
||||
lk->dev.keycodemax = LK_NUM_KEYCODES;
|
||||
|
||||
lk->dev.event = lkkbd_event;
|
||||
lk->dev.private = lk;
|
||||
|
||||
serio->private = lk;
|
||||
|
||||
if (serio_open (serio, drv)) {
|
||||
kfree (lk);
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf (lk->name, "DEC LK keyboard");
|
||||
sprintf (lk->phys, "%s/input0", serio->phys);
|
||||
|
||||
memcpy (lk->keycode, lkkbd_keycode, sizeof (lk_keycode_t) * LK_NUM_KEYCODES);
|
||||
for (i = 0; i < LK_NUM_KEYCODES; i++)
|
||||
set_bit (lk->keycode[i], lk->dev.keybit);
|
||||
|
||||
lk->dev.name = lk->name;
|
||||
lk->dev.phys = lk->phys;
|
||||
lk->dev.id.bustype = BUS_RS232;
|
||||
lk->dev.id.vendor = SERIO_LKKBD;
|
||||
lk->dev.id.product = 0;
|
||||
lk->dev.id.version = 0x0100;
|
||||
|
||||
input_register_device (&lk->dev);
|
||||
|
||||
printk (KERN_INFO "input: %s on %s, initiating reset\n", lk->name, serio->phys);
|
||||
lk->serio->write (lk->serio, LK_CMD_POWERCYCLE_RESET);
|
||||
}
|
||||
|
||||
/*
|
||||
* lkkbd_disconnect() unregisters and closes behind us.
|
||||
*/
|
||||
static void
|
||||
lkkbd_disconnect (struct serio *serio)
|
||||
{
|
||||
struct lkkbd *lk = serio->private;
|
||||
|
||||
input_unregister_device (&lk->dev);
|
||||
serio_close (serio);
|
||||
kfree (lk);
|
||||
}
|
||||
|
||||
static struct serio_driver lkkbd_drv = {
|
||||
.driver = {
|
||||
.name = "lkkbd",
|
||||
},
|
||||
.description = DRIVER_DESC,
|
||||
.connect = lkkbd_connect,
|
||||
.disconnect = lkkbd_disconnect,
|
||||
.interrupt = lkkbd_interrupt,
|
||||
};
|
||||
|
||||
/*
|
||||
* The functions for insering/removing us as a module.
|
||||
*/
|
||||
int __init
|
||||
lkkbd_init (void)
|
||||
{
|
||||
serio_register_driver(&lkkbd_drv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit
|
||||
lkkbd_exit (void)
|
||||
{
|
||||
serio_unregister_driver(&lkkbd_drv);
|
||||
}
|
||||
|
||||
module_init (lkkbd_init);
|
||||
module_exit (lkkbd_exit);
|
||||
|
||||
190
extra/linux-2.6.10/drivers/input/keyboard/maple_keyb.c
Normal file
190
extra/linux-2.6.10/drivers/input/keyboard/maple_keyb.c
Normal file
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* $Id: maple_keyb.c,v 1.4 2004/03/22 01:18:15 lethal Exp $
|
||||
* SEGA Dreamcast keyboard driver
|
||||
* Based on drivers/usb/usbkbd.c
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/maple.h>
|
||||
|
||||
MODULE_AUTHOR("YAEGASHI Takeshi <t@keshi.org>");
|
||||
MODULE_DESCRIPTION("SEGA Dreamcast keyboard driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static unsigned char dc_kbd_keycode[256] = {
|
||||
0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
|
||||
50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
|
||||
4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
|
||||
27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
|
||||
65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
|
||||
105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
|
||||
72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
|
||||
191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
|
||||
115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0,
|
||||
122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
|
||||
150,158,159,128,136,177,178,176,142,152,173,140
|
||||
};
|
||||
|
||||
|
||||
struct dc_kbd {
|
||||
struct input_dev dev;
|
||||
unsigned char new[8];
|
||||
unsigned char old[8];
|
||||
int open;
|
||||
};
|
||||
|
||||
|
||||
static void dc_scan_kbd(struct dc_kbd *kbd)
|
||||
{
|
||||
int i;
|
||||
struct input_dev *dev = &kbd->dev;
|
||||
|
||||
for(i=0; i<8; i++)
|
||||
input_report_key(dev,
|
||||
dc_kbd_keycode[i+224],
|
||||
(kbd->new[0]>>i)&1);
|
||||
|
||||
for(i=2; i<8; i++) {
|
||||
|
||||
if(kbd->old[i]>3&&memscan(kbd->new+2, kbd->old[i], 6)==NULL) {
|
||||
if(dc_kbd_keycode[kbd->old[i]])
|
||||
input_report_key(dev,
|
||||
dc_kbd_keycode[kbd->old[i]],
|
||||
0);
|
||||
else
|
||||
printk("Unknown key (scancode %#x) released.",
|
||||
kbd->old[i]);
|
||||
}
|
||||
|
||||
if(kbd->new[i]>3&&memscan(kbd->old+2, kbd->new[i], 6)!=NULL) {
|
||||
if(dc_kbd_keycode[kbd->new[i]])
|
||||
input_report_key(dev,
|
||||
dc_kbd_keycode[kbd->new[i]],
|
||||
1);
|
||||
else
|
||||
printk("Unknown key (scancode %#x) pressed.",
|
||||
kbd->new[i]);
|
||||
}
|
||||
}
|
||||
|
||||
input_sync(dev);
|
||||
|
||||
memcpy(kbd->old, kbd->new, 8);
|
||||
}
|
||||
|
||||
|
||||
static void dc_kbd_callback(struct mapleq *mq)
|
||||
{
|
||||
struct maple_device *mapledev = mq->dev;
|
||||
struct dc_kbd *kbd = mapledev->private_data;
|
||||
unsigned long *buf = mq->recvbuf;
|
||||
|
||||
if (buf[1] == mapledev->function) {
|
||||
memcpy(kbd->new, buf+2, 8);
|
||||
dc_scan_kbd(kbd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int dc_kbd_open(struct input_dev *dev)
|
||||
{
|
||||
struct dc_kbd *kbd = dev->private;
|
||||
kbd->open++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void dc_kbd_close(struct input_dev *dev)
|
||||
{
|
||||
struct dc_kbd *kbd = dev->private;
|
||||
kbd->open--;
|
||||
}
|
||||
|
||||
|
||||
static int dc_kbd_connect(struct maple_device *dev)
|
||||
{
|
||||
int i;
|
||||
unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]);
|
||||
struct dc_kbd *kbd;
|
||||
|
||||
if (!(kbd = kmalloc(sizeof(struct dc_kbd), GFP_KERNEL)))
|
||||
return -1;
|
||||
memset(kbd, 0, sizeof(struct dc_kbd));
|
||||
|
||||
dev->private_data = kbd;
|
||||
|
||||
kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
||||
|
||||
init_input_dev(&kbd->dev);
|
||||
|
||||
for (i=0; i<255; i++)
|
||||
set_bit(dc_kbd_keycode[i], kbd->dev.keybit);
|
||||
|
||||
clear_bit(0, kbd->dev.keybit);
|
||||
|
||||
kbd->dev.private = kbd;
|
||||
kbd->dev.open = dc_kbd_open;
|
||||
kbd->dev.close = dc_kbd_close;
|
||||
kbd->dev.event = NULL;
|
||||
|
||||
kbd->dev.name = dev->product_name;
|
||||
kbd->dev.id.bustype = BUS_MAPLE;
|
||||
|
||||
input_register_device(&kbd->dev);
|
||||
|
||||
maple_getcond_callback(dev, dc_kbd_callback, 1, MAPLE_FUNC_KEYBOARD);
|
||||
|
||||
printk(KERN_INFO "input: keyboard(0x%lx): %s\n", data, kbd->dev.name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void dc_kbd_disconnect(struct maple_device *dev)
|
||||
{
|
||||
struct dc_kbd *kbd = dev->private_data;
|
||||
|
||||
input_unregister_device(&kbd->dev);
|
||||
kfree(kbd);
|
||||
}
|
||||
|
||||
|
||||
static struct maple_driver dc_kbd_driver = {
|
||||
.function = MAPLE_FUNC_KEYBOARD,
|
||||
.name = "Dreamcast keyboard",
|
||||
.connect = dc_kbd_connect,
|
||||
.disconnect = dc_kbd_disconnect,
|
||||
};
|
||||
|
||||
|
||||
static int __init dc_kbd_init(void)
|
||||
{
|
||||
maple_register_driver(&dc_kbd_driver);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void __exit dc_kbd_exit(void)
|
||||
{
|
||||
maple_unregister_driver(&dc_kbd_driver);
|
||||
}
|
||||
|
||||
|
||||
module_init(dc_kbd_init);
|
||||
module_exit(dc_kbd_exit);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
165
extra/linux-2.6.10/drivers/input/keyboard/newtonkbd.c
Normal file
165
extra/linux-2.6.10/drivers/input/keyboard/newtonkbd.c
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (c) 2000 Justin Cormack
|
||||
*/
|
||||
|
||||
/*
|
||||
* Newton keyboard driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <j.cormack@doc.ic.ac.uk>, or by paper mail:
|
||||
* Justin Cormack, 68 Dartmouth Park Road, London NW5 1SN, UK.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/serio.h>
|
||||
|
||||
#define DRIVER_DESC "Newton keyboard driver"
|
||||
|
||||
MODULE_AUTHOR("Justin Cormack <j.cormack@doc.ic.ac.uk>");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define NKBD_KEY 0x7f
|
||||
#define NKBD_PRESS 0x80
|
||||
|
||||
static unsigned char nkbd_keycode[128] = {
|
||||
KEY_A, KEY_S, KEY_D, KEY_F, KEY_H, KEY_G, KEY_Z, KEY_X,
|
||||
KEY_C, KEY_V, 0, KEY_B, KEY_Q, KEY_W, KEY_E, KEY_R,
|
||||
KEY_Y, KEY_T, KEY_1, KEY_2, KEY_3, KEY_4, KEY_6, KEY_5,
|
||||
KEY_EQUAL, KEY_9, KEY_7, KEY_MINUS, KEY_8, KEY_0, KEY_RIGHTBRACE, KEY_O,
|
||||
KEY_U, KEY_LEFTBRACE, KEY_I, KEY_P, KEY_ENTER, KEY_L, KEY_J, KEY_APOSTROPHE,
|
||||
KEY_K, KEY_SEMICOLON, KEY_BACKSLASH, KEY_COMMA, KEY_SLASH, KEY_N, KEY_M, KEY_DOT,
|
||||
KEY_TAB, KEY_SPACE, KEY_GRAVE, KEY_DELETE, 0, 0, 0, KEY_LEFTMETA,
|
||||
KEY_LEFTSHIFT, KEY_CAPSLOCK, KEY_LEFTALT, KEY_LEFTCTRL, KEY_RIGHTSHIFT, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
KEY_LEFT, KEY_RIGHT, KEY_DOWN, KEY_UP, 0
|
||||
};
|
||||
|
||||
static char *nkbd_name = "Newton Keyboard";
|
||||
|
||||
struct nkbd {
|
||||
unsigned char keycode[128];
|
||||
struct input_dev dev;
|
||||
struct serio *serio;
|
||||
char phys[32];
|
||||
};
|
||||
|
||||
irqreturn_t nkbd_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags, struct pt_regs *regs)
|
||||
{
|
||||
struct nkbd *nkbd = serio->private;
|
||||
|
||||
/* invalid scan codes are probably the init sequence, so we ignore them */
|
||||
if (nkbd->keycode[data & NKBD_KEY]) {
|
||||
input_regs(&nkbd->dev, regs);
|
||||
input_report_key(&nkbd->dev, nkbd->keycode[data & NKBD_KEY], data & NKBD_PRESS);
|
||||
input_sync(&nkbd->dev);
|
||||
}
|
||||
|
||||
else if (data == 0xe7) /* end of init sequence */
|
||||
printk(KERN_INFO "input: %s on %s\n", nkbd_name, serio->phys);
|
||||
return IRQ_HANDLED;
|
||||
|
||||
}
|
||||
|
||||
void nkbd_connect(struct serio *serio, struct serio_driver *drv)
|
||||
{
|
||||
struct nkbd *nkbd;
|
||||
int i;
|
||||
|
||||
if (serio->type != (SERIO_RS232 | SERIO_NEWTON))
|
||||
return;
|
||||
|
||||
if (!(nkbd = kmalloc(sizeof(struct nkbd), GFP_KERNEL)))
|
||||
return;
|
||||
|
||||
memset(nkbd, 0, sizeof(struct nkbd));
|
||||
|
||||
nkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
||||
|
||||
nkbd->serio = serio;
|
||||
|
||||
init_input_dev(&nkbd->dev);
|
||||
nkbd->dev.keycode = nkbd->keycode;
|
||||
nkbd->dev.keycodesize = sizeof(unsigned char);
|
||||
nkbd->dev.keycodemax = ARRAY_SIZE(nkbd_keycode);
|
||||
nkbd->dev.private = nkbd;
|
||||
serio->private = nkbd;
|
||||
|
||||
if (serio_open(serio, drv)) {
|
||||
kfree(nkbd);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(nkbd->keycode, nkbd_keycode, sizeof(nkbd->keycode));
|
||||
for (i = 0; i < 128; i++)
|
||||
set_bit(nkbd->keycode[i], nkbd->dev.keybit);
|
||||
clear_bit(0, nkbd->dev.keybit);
|
||||
|
||||
sprintf(nkbd->phys, "%s/input0", serio->phys);
|
||||
|
||||
nkbd->dev.name = nkbd_name;
|
||||
nkbd->dev.phys = nkbd->phys;
|
||||
nkbd->dev.id.bustype = BUS_RS232;
|
||||
nkbd->dev.id.vendor = SERIO_NEWTON;
|
||||
nkbd->dev.id.product = 0x0001;
|
||||
nkbd->dev.id.version = 0x0100;
|
||||
|
||||
input_register_device(&nkbd->dev);
|
||||
|
||||
printk(KERN_INFO "input: %s on %s\n", nkbd_name, serio->phys);
|
||||
}
|
||||
|
||||
void nkbd_disconnect(struct serio *serio)
|
||||
{
|
||||
struct nkbd *nkbd = serio->private;
|
||||
input_unregister_device(&nkbd->dev);
|
||||
serio_close(serio);
|
||||
kfree(nkbd);
|
||||
}
|
||||
|
||||
struct serio_driver nkbd_drv = {
|
||||
.driver = {
|
||||
.name = "newtonkbd",
|
||||
},
|
||||
.description = DRIVER_DESC,
|
||||
.interrupt = nkbd_interrupt,
|
||||
.connect = nkbd_connect,
|
||||
.disconnect = nkbd_disconnect,
|
||||
};
|
||||
|
||||
int __init nkbd_init(void)
|
||||
{
|
||||
serio_register_driver(&nkbd_drv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit nkbd_exit(void)
|
||||
{
|
||||
serio_unregister_driver(&nkbd_drv);
|
||||
}
|
||||
|
||||
module_init(nkbd_init);
|
||||
module_exit(nkbd_exit);
|
||||
332
extra/linux-2.6.10/drivers/input/keyboard/sunkbd.c
Normal file
332
extra/linux-2.6.10/drivers/input/keyboard/sunkbd.c
Normal file
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
* $Id: sunkbd.c,v 1.14 2001/09/25 10:12:07 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1999-2001 Vojtech Pavlik
|
||||
*/
|
||||
|
||||
/*
|
||||
* Sun keyboard driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/serio.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#define DRIVER_DESC "Sun keyboard driver"
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static unsigned char sunkbd_keycode[128] = {
|
||||
0,128,114,129,115, 59, 60, 68, 61, 87, 62, 88, 63,100, 64, 0,
|
||||
65, 66, 67, 56,103,119, 99, 70,105,130,131,108,106, 1, 2, 3,
|
||||
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 41, 14,110,113, 98, 55,
|
||||
116,132, 83,133,102, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
|
||||
26, 27,111,127, 71, 72, 73, 74,134,135,107, 0, 29, 30, 31, 32,
|
||||
33, 34, 35, 36, 37, 38, 39, 40, 43, 28, 96, 75, 76, 77, 82,136,
|
||||
104,137, 69, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,101,
|
||||
79, 80, 81, 0, 0, 0,138, 58,125, 57,126,109, 86, 78
|
||||
};
|
||||
|
||||
#define SUNKBD_CMD_RESET 0x1
|
||||
#define SUNKBD_CMD_BELLON 0x2
|
||||
#define SUNKBD_CMD_BELLOFF 0x3
|
||||
#define SUNKBD_CMD_CLICK 0xa
|
||||
#define SUNKBD_CMD_NOCLICK 0xb
|
||||
#define SUNKBD_CMD_SETLED 0xe
|
||||
#define SUNKBD_CMD_LAYOUT 0xf
|
||||
|
||||
#define SUNKBD_RET_RESET 0xff
|
||||
#define SUNKBD_RET_ALLUP 0x7f
|
||||
#define SUNKBD_RET_LAYOUT 0xfe
|
||||
|
||||
#define SUNKBD_LAYOUT_5_MASK 0x20
|
||||
#define SUNKBD_RELEASE 0x80
|
||||
#define SUNKBD_KEY 0x7f
|
||||
|
||||
/*
|
||||
* Per-keyboard data.
|
||||
*/
|
||||
|
||||
struct sunkbd {
|
||||
unsigned char keycode[128];
|
||||
struct input_dev dev;
|
||||
struct serio *serio;
|
||||
struct work_struct tq;
|
||||
wait_queue_head_t wait;
|
||||
char name[64];
|
||||
char phys[32];
|
||||
char type;
|
||||
volatile s8 reset;
|
||||
volatile s8 layout;
|
||||
};
|
||||
|
||||
/*
|
||||
* sunkbd_interrupt() is called by the low level driver when a character
|
||||
* is received.
|
||||
*/
|
||||
|
||||
static irqreturn_t sunkbd_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags, struct pt_regs *regs)
|
||||
{
|
||||
struct sunkbd* sunkbd = serio->private;
|
||||
|
||||
if (sunkbd->reset <= -1) { /* If cp[i] is 0xff, sunkbd->reset will stay -1. */
|
||||
sunkbd->reset = data; /* The keyboard sends 0xff 0xff 0xID on powerup */
|
||||
wake_up_interruptible(&sunkbd->wait);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (sunkbd->layout == -1) {
|
||||
sunkbd->layout = data;
|
||||
wake_up_interruptible(&sunkbd->wait);
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (data) {
|
||||
|
||||
case SUNKBD_RET_RESET:
|
||||
schedule_work(&sunkbd->tq);
|
||||
sunkbd->reset = -1;
|
||||
break;
|
||||
|
||||
case SUNKBD_RET_LAYOUT:
|
||||
sunkbd->layout = -1;
|
||||
break;
|
||||
|
||||
case SUNKBD_RET_ALLUP: /* All keys released */
|
||||
break;
|
||||
|
||||
default:
|
||||
if (sunkbd->keycode[data & SUNKBD_KEY]) {
|
||||
input_regs(&sunkbd->dev, regs);
|
||||
input_report_key(&sunkbd->dev, sunkbd->keycode[data & SUNKBD_KEY], !(data & SUNKBD_RELEASE));
|
||||
input_sync(&sunkbd->dev);
|
||||
} else {
|
||||
printk(KERN_WARNING "sunkbd.c: Unknown key (scancode %#x) %s.\n",
|
||||
data & SUNKBD_KEY, data & SUNKBD_RELEASE ? "released" : "pressed");
|
||||
}
|
||||
}
|
||||
out:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* sunkbd_event() handles events from the input module.
|
||||
*/
|
||||
|
||||
static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
struct sunkbd *sunkbd = dev->private;
|
||||
|
||||
switch (type) {
|
||||
|
||||
case EV_LED:
|
||||
|
||||
sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED);
|
||||
sunkbd->serio->write(sunkbd->serio,
|
||||
(!!test_bit(LED_CAPSL, dev->led) << 3) | (!!test_bit(LED_SCROLLL, dev->led) << 2) |
|
||||
(!!test_bit(LED_COMPOSE, dev->led) << 1) | !!test_bit(LED_NUML, dev->led));
|
||||
return 0;
|
||||
|
||||
case EV_SND:
|
||||
|
||||
switch (code) {
|
||||
|
||||
case SND_CLICK:
|
||||
sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value);
|
||||
return 0;
|
||||
|
||||
case SND_BELL:
|
||||
sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* sunkbd_initialize() checks for a Sun keyboard attached, and determines
|
||||
* its type.
|
||||
*/
|
||||
|
||||
static int sunkbd_initialize(struct sunkbd *sunkbd)
|
||||
{
|
||||
sunkbd->reset = -2;
|
||||
sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_RESET);
|
||||
wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
|
||||
if (sunkbd->reset <0)
|
||||
return -1;
|
||||
|
||||
sunkbd->type = sunkbd->reset;
|
||||
|
||||
if (sunkbd->type == 4) { /* Type 4 keyboard */
|
||||
sunkbd->layout = -2;
|
||||
sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_LAYOUT);
|
||||
wait_event_interruptible_timeout(sunkbd->wait, sunkbd->layout >= 0, HZ/4);
|
||||
if (sunkbd->layout < 0) return -1;
|
||||
if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK) sunkbd->type = 5;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* sunkbd_reinit() sets leds and beeps to a state the computer remembers they
|
||||
* were in.
|
||||
*/
|
||||
|
||||
static void sunkbd_reinit(void *data)
|
||||
{
|
||||
struct sunkbd *sunkbd = data;
|
||||
|
||||
wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
|
||||
|
||||
sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_SETLED);
|
||||
sunkbd->serio->write(sunkbd->serio,
|
||||
(!!test_bit(LED_CAPSL, sunkbd->dev.led) << 3) | (!!test_bit(LED_SCROLLL, sunkbd->dev.led) << 2) |
|
||||
(!!test_bit(LED_COMPOSE, sunkbd->dev.led) << 1) | !!test_bit(LED_NUML, sunkbd->dev.led));
|
||||
sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev.snd));
|
||||
sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev.snd));
|
||||
}
|
||||
|
||||
/*
|
||||
* sunkbd_connect() probes for a Sun keyboard and fills the necessary structures.
|
||||
*/
|
||||
|
||||
static void sunkbd_connect(struct serio *serio, struct serio_driver *drv)
|
||||
{
|
||||
struct sunkbd *sunkbd;
|
||||
int i;
|
||||
|
||||
if ((serio->type & SERIO_TYPE) != SERIO_RS232)
|
||||
return;
|
||||
|
||||
if ((serio->type & SERIO_PROTO) && (serio->type & SERIO_PROTO) != SERIO_SUNKBD)
|
||||
return;
|
||||
|
||||
if (!(sunkbd = kmalloc(sizeof(struct sunkbd), GFP_KERNEL)))
|
||||
return;
|
||||
|
||||
memset(sunkbd, 0, sizeof(struct sunkbd));
|
||||
|
||||
init_input_dev(&sunkbd->dev);
|
||||
init_waitqueue_head(&sunkbd->wait);
|
||||
|
||||
sunkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP);
|
||||
sunkbd->dev.ledbit[0] = BIT(LED_CAPSL) | BIT(LED_COMPOSE) | BIT(LED_SCROLLL) | BIT(LED_NUML);
|
||||
sunkbd->dev.sndbit[0] = BIT(SND_CLICK) | BIT(SND_BELL);
|
||||
|
||||
sunkbd->serio = serio;
|
||||
|
||||
INIT_WORK(&sunkbd->tq, sunkbd_reinit, sunkbd);
|
||||
|
||||
sunkbd->dev.keycode = sunkbd->keycode;
|
||||
sunkbd->dev.keycodesize = sizeof(unsigned char);
|
||||
sunkbd->dev.keycodemax = ARRAY_SIZE(sunkbd_keycode);
|
||||
|
||||
sunkbd->dev.event = sunkbd_event;
|
||||
sunkbd->dev.private = sunkbd;
|
||||
|
||||
serio->private = sunkbd;
|
||||
|
||||
if (serio_open(serio, drv)) {
|
||||
kfree(sunkbd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sunkbd_initialize(sunkbd) < 0) {
|
||||
serio_close(serio);
|
||||
kfree(sunkbd);
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf(sunkbd->name, "Sun Type %d keyboard", sunkbd->type);
|
||||
|
||||
memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode));
|
||||
for (i = 0; i < 128; i++)
|
||||
set_bit(sunkbd->keycode[i], sunkbd->dev.keybit);
|
||||
clear_bit(0, sunkbd->dev.keybit);
|
||||
|
||||
sprintf(sunkbd->phys, "%s/input0", serio->phys);
|
||||
|
||||
sunkbd->dev.name = sunkbd->name;
|
||||
sunkbd->dev.phys = sunkbd->phys;
|
||||
sunkbd->dev.id.bustype = BUS_RS232;
|
||||
sunkbd->dev.id.vendor = SERIO_SUNKBD;
|
||||
sunkbd->dev.id.product = sunkbd->type;
|
||||
sunkbd->dev.id.version = 0x0100;
|
||||
|
||||
input_register_device(&sunkbd->dev);
|
||||
|
||||
printk(KERN_INFO "input: %s on %s\n", sunkbd->name, serio->phys);
|
||||
}
|
||||
|
||||
/*
|
||||
* sunkbd_disconnect() unregisters and closes behind us.
|
||||
*/
|
||||
|
||||
static void sunkbd_disconnect(struct serio *serio)
|
||||
{
|
||||
struct sunkbd *sunkbd = serio->private;
|
||||
input_unregister_device(&sunkbd->dev);
|
||||
serio_close(serio);
|
||||
kfree(sunkbd);
|
||||
}
|
||||
|
||||
static struct serio_driver sunkbd_drv = {
|
||||
.driver = {
|
||||
.name = "sunkbd",
|
||||
},
|
||||
.description = DRIVER_DESC,
|
||||
.interrupt = sunkbd_interrupt,
|
||||
.connect = sunkbd_connect,
|
||||
.disconnect = sunkbd_disconnect,
|
||||
};
|
||||
|
||||
/*
|
||||
* The functions for insering/removing us as a module.
|
||||
*/
|
||||
|
||||
int __init sunkbd_init(void)
|
||||
{
|
||||
serio_register_driver(&sunkbd_drv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit sunkbd_exit(void)
|
||||
{
|
||||
serio_unregister_driver(&sunkbd_drv);
|
||||
}
|
||||
|
||||
module_init(sunkbd_init);
|
||||
module_exit(sunkbd_exit);
|
||||
170
extra/linux-2.6.10/drivers/input/keyboard/xtkbd.c
Normal file
170
extra/linux-2.6.10/drivers/input/keyboard/xtkbd.c
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* $Id: xtkbd.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1999-2001 Vojtech Pavlik
|
||||
*/
|
||||
|
||||
/*
|
||||
* XT keyboard driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/serio.h>
|
||||
|
||||
#define DRIVER_DESC "XT keyboard driver"
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define XTKBD_EMUL0 0xe0
|
||||
#define XTKBD_EMUL1 0xe1
|
||||
#define XTKBD_KEY 0x7f
|
||||
#define XTKBD_RELEASE 0x80
|
||||
|
||||
static unsigned char xtkbd_keycode[256] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
|
||||
80, 81, 82, 83, 0, 0, 0, 87, 88, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 87, 88, 0, 0, 0, 0,110,111,103,108,105,
|
||||
106
|
||||
};
|
||||
|
||||
static char *xtkbd_name = "XT Keyboard";
|
||||
|
||||
struct xtkbd {
|
||||
unsigned char keycode[256];
|
||||
struct input_dev dev;
|
||||
struct serio *serio;
|
||||
char phys[32];
|
||||
};
|
||||
|
||||
irqreturn_t xtkbd_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags, struct pt_regs *regs)
|
||||
{
|
||||
struct xtkbd *xtkbd = serio->private;
|
||||
|
||||
switch (data) {
|
||||
case XTKBD_EMUL0:
|
||||
case XTKBD_EMUL1:
|
||||
break;
|
||||
default:
|
||||
|
||||
if (xtkbd->keycode[data & XTKBD_KEY]) {
|
||||
input_regs(&xtkbd->dev, regs);
|
||||
input_report_key(&xtkbd->dev, xtkbd->keycode[data & XTKBD_KEY], !(data & XTKBD_RELEASE));
|
||||
input_sync(&xtkbd->dev);
|
||||
} else {
|
||||
printk(KERN_WARNING "xtkbd.c: Unknown key (scancode %#x) %s.\n",
|
||||
data & XTKBD_KEY, data & XTKBD_RELEASE ? "released" : "pressed");
|
||||
}
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
void xtkbd_connect(struct serio *serio, struct serio_driver *drv)
|
||||
{
|
||||
struct xtkbd *xtkbd;
|
||||
int i;
|
||||
|
||||
if ((serio->type & SERIO_TYPE) != SERIO_XT)
|
||||
return;
|
||||
|
||||
if (!(xtkbd = kmalloc(sizeof(struct xtkbd), GFP_KERNEL)))
|
||||
return;
|
||||
|
||||
memset(xtkbd, 0, sizeof(struct xtkbd));
|
||||
|
||||
xtkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
|
||||
|
||||
xtkbd->serio = serio;
|
||||
|
||||
init_input_dev(&xtkbd->dev);
|
||||
xtkbd->dev.keycode = xtkbd->keycode;
|
||||
xtkbd->dev.keycodesize = sizeof(unsigned char);
|
||||
xtkbd->dev.keycodemax = ARRAY_SIZE(xtkbd_keycode);
|
||||
xtkbd->dev.private = xtkbd;
|
||||
|
||||
serio->private = xtkbd;
|
||||
|
||||
if (serio_open(serio, drv)) {
|
||||
kfree(xtkbd);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(xtkbd->keycode, xtkbd_keycode, sizeof(xtkbd->keycode));
|
||||
for (i = 0; i < 255; i++)
|
||||
set_bit(xtkbd->keycode[i], xtkbd->dev.keybit);
|
||||
clear_bit(0, xtkbd->dev.keybit);
|
||||
|
||||
sprintf(xtkbd->phys, "%s/input0", serio->phys);
|
||||
|
||||
xtkbd->dev.name = xtkbd_name;
|
||||
xtkbd->dev.phys = xtkbd->phys;
|
||||
xtkbd->dev.id.bustype = BUS_XTKBD;
|
||||
xtkbd->dev.id.vendor = 0x0001;
|
||||
xtkbd->dev.id.product = 0x0001;
|
||||
xtkbd->dev.id.version = 0x0100;
|
||||
|
||||
input_register_device(&xtkbd->dev);
|
||||
|
||||
printk(KERN_INFO "input: %s on %s\n", xtkbd_name, serio->phys);
|
||||
}
|
||||
|
||||
void xtkbd_disconnect(struct serio *serio)
|
||||
{
|
||||
struct xtkbd *xtkbd = serio->private;
|
||||
input_unregister_device(&xtkbd->dev);
|
||||
serio_close(serio);
|
||||
kfree(xtkbd);
|
||||
}
|
||||
|
||||
struct serio_driver xtkbd_drv = {
|
||||
.driver = {
|
||||
.name = "xtkbd",
|
||||
},
|
||||
.description = DRIVER_DESC,
|
||||
.interrupt = xtkbd_interrupt,
|
||||
.connect = xtkbd_connect,
|
||||
.disconnect = xtkbd_disconnect,
|
||||
};
|
||||
|
||||
int __init xtkbd_init(void)
|
||||
{
|
||||
serio_register_driver(&xtkbd_drv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit xtkbd_exit(void)
|
||||
{
|
||||
serio_unregister_driver(&xtkbd_drv);
|
||||
}
|
||||
|
||||
module_init(xtkbd_init);
|
||||
module_exit(xtkbd_exit);
|
||||
52
extra/linux-2.6.10/drivers/input/misc/Kconfig
Normal file
52
extra/linux-2.6.10/drivers/input/misc/Kconfig
Normal file
@@ -0,0 +1,52 @@
|
||||
#
|
||||
# Input misc drivers configuration
|
||||
#
|
||||
config INPUT_MISC
|
||||
bool "Misc"
|
||||
depends on INPUT
|
||||
help
|
||||
|
||||
Say Y here, and a list of miscellaneous input drivers will be displayed.
|
||||
Everything that didn't fit into the other categories is here. This option
|
||||
doesn't affect the kernel.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config INPUT_PCSPKR
|
||||
tristate "PC Speaker support"
|
||||
depends on (ALPHA || X86 || X86_64 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES) && INPUT && INPUT_MISC
|
||||
help
|
||||
Say Y here if you want the standard PC Speaker to be used for
|
||||
bells and whistles.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called pcspkr.
|
||||
|
||||
config INPUT_SPARCSPKR
|
||||
tristate "SPARC Speaker support"
|
||||
depends on (SPARC32 || SPARC64) && INPUT && INPUT_MISC && PCI
|
||||
help
|
||||
Say Y here if you want the standard Speaker on Sparc PCI systems
|
||||
to be used for bells and whistles.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called sparcspkr.
|
||||
|
||||
config INPUT_M68K_BEEP
|
||||
tristate "M68k Beeper support"
|
||||
depends on M68K && INPUT && INPUT_MISC
|
||||
|
||||
config INPUT_UINPUT
|
||||
tristate "User level driver support"
|
||||
depends on INPUT && INPUT_MISC
|
||||
help
|
||||
Say Y here if you want to support user level drivers for input
|
||||
subsystem accessible under char device 10:223 - /dev/input/uinput.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called uinput.
|
||||
|
||||
11
extra/linux-2.6.10/drivers/input/misc/Makefile
Normal file
11
extra/linux-2.6.10/drivers/input/misc/Makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# Makefile for the input misc drivers.
|
||||
#
|
||||
|
||||
# Each configuration option enables a list of files.
|
||||
|
||||
obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o
|
||||
obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
|
||||
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
|
||||
obj-$(CONFIG_INPUT_98SPKR) += 98spkr.o
|
||||
obj-$(CONFIG_INPUT_UINPUT) += uinput.o
|
||||
83
extra/linux-2.6.10/drivers/input/misc/m68kspkr.c
Normal file
83
extra/linux-2.6.10/drivers/input/misc/m68kspkr.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* m68k beeper driver for Linux
|
||||
*
|
||||
* Copyright (c) 2002 Richard Zidlicky
|
||||
* Copyright (c) 2002 Vojtech Pavlik
|
||||
* Copyright (c) 1992 Orest Zborowski
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
MODULE_AUTHOR("Richard Zidlicky <rz@linux-m68k.org>");
|
||||
MODULE_DESCRIPTION("m68k beeper driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static char m68kspkr_name[] = "m68k beeper";
|
||||
static char m68kspkr_phys[] = "m68k/generic";
|
||||
static struct input_dev m68kspkr_dev;
|
||||
|
||||
static int m68kspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
|
||||
if (type != EV_SND)
|
||||
return -1;
|
||||
|
||||
switch (code) {
|
||||
case SND_BELL: if (value) value = 1000;
|
||||
case SND_TONE: break;
|
||||
default: return -1;
|
||||
}
|
||||
|
||||
if (value > 20 && value < 32767)
|
||||
count = 1193182 / value;
|
||||
|
||||
mach_beep(count, -1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init m68kspkr_init(void)
|
||||
{
|
||||
if (!mach_beep){
|
||||
printk("%s: no lowlevel beep support\n", m68kspkr_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
m68kspkr_dev.evbit[0] = BIT(EV_SND);
|
||||
m68kspkr_dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
|
||||
m68kspkr_dev.event = m68kspkr_event;
|
||||
|
||||
m68kspkr_dev.name = m68kspkr_name;
|
||||
m68kspkr_dev.phys = m68kspkr_phys;
|
||||
m68kspkr_dev.id.bustype = BUS_HOST;
|
||||
m68kspkr_dev.id.vendor = 0x001f;
|
||||
m68kspkr_dev.id.product = 0x0001;
|
||||
m68kspkr_dev.id.version = 0x0100;
|
||||
|
||||
input_register_device(&m68kspkr_dev);
|
||||
|
||||
printk(KERN_INFO "input: %s\n", m68kspkr_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit m68kspkr_exit(void)
|
||||
{
|
||||
input_unregister_device(&m68kspkr_dev);
|
||||
}
|
||||
|
||||
module_init(m68kspkr_init);
|
||||
module_exit(m68kspkr_exit);
|
||||
95
extra/linux-2.6.10/drivers/input/misc/pcspkr.c
Normal file
95
extra/linux-2.6.10/drivers/input/misc/pcspkr.c
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* PC Speaker beeper driver for Linux
|
||||
*
|
||||
* Copyright (c) 2002 Vojtech Pavlik
|
||||
* Copyright (c) 1992 Orest Zborowski
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <asm/8253pit.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("PC Speaker beeper driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static char pcspkr_name[] = "PC Speaker";
|
||||
static char pcspkr_phys[] = "isa0061/input0";
|
||||
static struct input_dev pcspkr_dev;
|
||||
|
||||
spinlock_t i8253_beep_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (type != EV_SND)
|
||||
return -1;
|
||||
|
||||
switch (code) {
|
||||
case SND_BELL: if (value) value = 1000;
|
||||
case SND_TONE: break;
|
||||
default: return -1;
|
||||
}
|
||||
|
||||
if (value > 20 && value < 32767)
|
||||
count = PIT_TICK_RATE / value;
|
||||
|
||||
spin_lock_irqsave(&i8253_beep_lock, flags);
|
||||
|
||||
if (count) {
|
||||
/* enable counter 2 */
|
||||
outb_p(inb_p(0x61) | 3, 0x61);
|
||||
/* set command for counter 2, 2 byte write */
|
||||
outb_p(0xB6, 0x43);
|
||||
/* select desired HZ */
|
||||
outb_p(count & 0xff, 0x42);
|
||||
outb((count >> 8) & 0xff, 0x42);
|
||||
} else {
|
||||
/* disable counter 2 */
|
||||
outb(inb_p(0x61) & 0xFC, 0x61);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&i8253_beep_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init pcspkr_init(void)
|
||||
{
|
||||
pcspkr_dev.evbit[0] = BIT(EV_SND);
|
||||
pcspkr_dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
|
||||
pcspkr_dev.event = pcspkr_event;
|
||||
|
||||
pcspkr_dev.name = pcspkr_name;
|
||||
pcspkr_dev.phys = pcspkr_phys;
|
||||
pcspkr_dev.id.bustype = BUS_ISA;
|
||||
pcspkr_dev.id.vendor = 0x001f;
|
||||
pcspkr_dev.id.product = 0x0001;
|
||||
pcspkr_dev.id.version = 0x0100;
|
||||
|
||||
input_register_device(&pcspkr_dev);
|
||||
|
||||
printk(KERN_INFO "input: %s\n", pcspkr_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit pcspkr_exit(void)
|
||||
{
|
||||
input_unregister_device(&pcspkr_dev);
|
||||
}
|
||||
|
||||
module_init(pcspkr_init);
|
||||
module_exit(pcspkr_exit);
|
||||
189
extra/linux-2.6.10/drivers/input/misc/sparcspkr.c
Normal file
189
extra/linux-2.6.10/drivers/input/misc/sparcspkr.c
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Driver for PC-speaker like devices found on various Sparc systems.
|
||||
*
|
||||
* Copyright (c) 2002 Vojtech Pavlik
|
||||
* Copyright (c) 2002 David S. Miller (davem@redhat.com)
|
||||
*/
|
||||
#include <linux/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/ebus.h>
|
||||
#ifdef CONFIG_SPARC64
|
||||
#include <asm/isa.h>
|
||||
#endif
|
||||
|
||||
MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
|
||||
MODULE_DESCRIPTION("PC Speaker beeper driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static unsigned long beep_iobase;
|
||||
|
||||
static char *sparcspkr_isa_name = "Sparc ISA Speaker";
|
||||
static char *sparcspkr_ebus_name = "Sparc EBUS Speaker";
|
||||
static char *sparcspkr_phys = "sparc/input0";
|
||||
static struct input_dev sparcspkr_dev;
|
||||
|
||||
spinlock_t beep_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
static void __init init_sparcspkr_struct(void)
|
||||
{
|
||||
sparcspkr_dev.evbit[0] = BIT(EV_SND);
|
||||
sparcspkr_dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
|
||||
|
||||
sparcspkr_dev.phys = sparcspkr_phys;
|
||||
sparcspkr_dev.id.bustype = BUS_ISA;
|
||||
sparcspkr_dev.id.vendor = 0x001f;
|
||||
sparcspkr_dev.id.product = 0x0001;
|
||||
sparcspkr_dev.id.version = 0x0100;
|
||||
}
|
||||
|
||||
static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (type != EV_SND)
|
||||
return -1;
|
||||
|
||||
switch (code) {
|
||||
case SND_BELL: if (value) value = 1000;
|
||||
case SND_TONE: break;
|
||||
default: return -1;
|
||||
}
|
||||
|
||||
if (value > 20 && value < 32767)
|
||||
count = 1193182 / value;
|
||||
|
||||
spin_lock_irqsave(&beep_lock, flags);
|
||||
|
||||
/* EBUS speaker only has on/off state, the frequency does not
|
||||
* appear to be programmable.
|
||||
*/
|
||||
if (count) {
|
||||
if (beep_iobase & 0x2UL)
|
||||
outb(1, beep_iobase);
|
||||
else
|
||||
outl(1, beep_iobase);
|
||||
} else {
|
||||
if (beep_iobase & 0x2UL)
|
||||
outb(0, beep_iobase);
|
||||
else
|
||||
outl(0, beep_iobase);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&beep_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init init_ebus_beep(struct linux_ebus_device *edev)
|
||||
{
|
||||
beep_iobase = edev->resource[0].start;
|
||||
|
||||
init_sparcspkr_struct();
|
||||
|
||||
sparcspkr_dev.name = sparcspkr_ebus_name;
|
||||
sparcspkr_dev.event = ebus_spkr_event;
|
||||
|
||||
input_register_device(&sparcspkr_dev);
|
||||
|
||||
printk(KERN_INFO "input: %s\n", sparcspkr_ebus_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPARC64
|
||||
static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (type != EV_SND)
|
||||
return -1;
|
||||
|
||||
switch (code) {
|
||||
case SND_BELL: if (value) value = 1000;
|
||||
case SND_TONE: break;
|
||||
default: return -1;
|
||||
}
|
||||
|
||||
if (value > 20 && value < 32767)
|
||||
count = 1193182 / value;
|
||||
|
||||
spin_lock_irqsave(&beep_lock, flags);
|
||||
|
||||
if (count) {
|
||||
/* enable counter 2 */
|
||||
outb(inb(beep_iobase + 0x61) | 3, beep_iobase + 0x61);
|
||||
/* set command for counter 2, 2 byte write */
|
||||
outb(0xB6, beep_iobase + 0x43);
|
||||
/* select desired HZ */
|
||||
outb(count & 0xff, beep_iobase + 0x42);
|
||||
outb((count >> 8) & 0xff, beep_iobase + 0x42);
|
||||
} else {
|
||||
/* disable counter 2 */
|
||||
outb(inb_p(beep_iobase + 0x61) & 0xFC, beep_iobase + 0x61);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&beep_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init init_isa_beep(struct sparc_isa_device *isa_dev)
|
||||
{
|
||||
beep_iobase = isa_dev->resource.start;
|
||||
|
||||
init_sparcspkr_struct();
|
||||
|
||||
sparcspkr_dev.name = sparcspkr_isa_name;
|
||||
sparcspkr_dev.event = isa_spkr_event;
|
||||
sparcspkr_dev.id.bustype = BUS_ISA;
|
||||
|
||||
input_register_device(&sparcspkr_dev);
|
||||
|
||||
printk(KERN_INFO "input: %s\n", sparcspkr_isa_name);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init sparcspkr_init(void)
|
||||
{
|
||||
struct linux_ebus *ebus;
|
||||
struct linux_ebus_device *edev = NULL;
|
||||
#ifdef CONFIG_SPARC64
|
||||
struct sparc_isa_bridge *isa_br;
|
||||
struct sparc_isa_device *isa_dev;
|
||||
#endif
|
||||
|
||||
for_each_ebus(ebus) {
|
||||
for_each_ebusdev(edev, ebus) {
|
||||
if (!strcmp(edev->prom_name, "beep"))
|
||||
return init_ebus_beep(edev);
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_SPARC64
|
||||
for_each_isa(isa_br) {
|
||||
for_each_isadev(isa_dev, isa_br) {
|
||||
/* A hack, the beep device's base lives in
|
||||
* the DMA isa node.
|
||||
*/
|
||||
if (!strcmp(isa_dev->prom_name, "dma"))
|
||||
return init_isa_beep(isa_dev);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static void __exit sparcspkr_exit(void)
|
||||
{
|
||||
input_unregister_device(&sparcspkr_dev);
|
||||
}
|
||||
|
||||
module_init(sparcspkr_init);
|
||||
module_exit(sparcspkr_exit);
|
||||
431
extra/linux-2.6.10/drivers/input/misc/uinput.c
Normal file
431
extra/linux-2.6.10/drivers/input/misc/uinput.c
Normal file
@@ -0,0 +1,431 @@
|
||||
/*
|
||||
* User level driver support for input subsystem
|
||||
*
|
||||
* Heavily based on evdev.c by Vojtech Pavlik
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
|
||||
*
|
||||
* Changes/Revisions:
|
||||
* 0.1 20/06/2002
|
||||
* - first public version
|
||||
*/
|
||||
#include <linux/poll.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/uinput.h>
|
||||
|
||||
static int uinput_dev_open(struct input_dev *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uinput_dev_close(struct input_dev *dev)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
struct uinput_device *udev;
|
||||
|
||||
udev = (struct uinput_device *)dev->private;
|
||||
|
||||
udev->buff[udev->head].type = type;
|
||||
udev->buff[udev->head].code = code;
|
||||
udev->buff[udev->head].value = value;
|
||||
do_gettimeofday(&udev->buff[udev->head].time);
|
||||
udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE;
|
||||
|
||||
wake_up_interruptible(&udev->waitq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uinput_create_device(struct uinput_device *udev)
|
||||
{
|
||||
if (!udev->dev->name) {
|
||||
printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
udev->dev->open = uinput_dev_open;
|
||||
udev->dev->close = uinput_dev_close;
|
||||
udev->dev->event = uinput_dev_event;
|
||||
udev->dev->upload_effect = uinput_dev_upload_effect;
|
||||
udev->dev->erase_effect = uinput_dev_erase_effect;
|
||||
udev->dev->private = udev;
|
||||
|
||||
init_waitqueue_head(&(udev->waitq));
|
||||
|
||||
input_register_device(udev->dev);
|
||||
|
||||
set_bit(UIST_CREATED, &(udev->state));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uinput_destroy_device(struct uinput_device *udev)
|
||||
{
|
||||
if (!test_bit(UIST_CREATED, &(udev->state))) {
|
||||
printk(KERN_WARNING "%s: create the device first\n", UINPUT_NAME);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
input_unregister_device(udev->dev);
|
||||
|
||||
clear_bit(UIST_CREATED, &(udev->state));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uinput_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct uinput_device *newdev;
|
||||
struct input_dev *newinput;
|
||||
|
||||
newdev = kmalloc(sizeof(struct uinput_device), GFP_KERNEL);
|
||||
if (!newdev)
|
||||
goto error;
|
||||
memset(newdev, 0, sizeof(struct uinput_device));
|
||||
|
||||
newinput = kmalloc(sizeof(struct input_dev), GFP_KERNEL);
|
||||
if (!newinput)
|
||||
goto cleanup;
|
||||
memset(newinput, 0, sizeof(struct input_dev));
|
||||
|
||||
newdev->dev = newinput;
|
||||
|
||||
file->private_data = newdev;
|
||||
|
||||
return 0;
|
||||
cleanup:
|
||||
kfree(newdev);
|
||||
error:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int uinput_validate_absbits(struct input_dev *dev)
|
||||
{
|
||||
unsigned int cnt;
|
||||
int retval = 0;
|
||||
|
||||
for (cnt = 0; cnt < ABS_MAX; cnt++) {
|
||||
if (!test_bit(cnt, dev->absbit))
|
||||
continue;
|
||||
|
||||
if (/*!dev->absmin[cnt] || !dev->absmax[cnt] || */
|
||||
(dev->absmax[cnt] <= dev->absmin[cnt])) {
|
||||
printk(KERN_DEBUG
|
||||
"%s: invalid abs[%02x] min:%d max:%d\n",
|
||||
UINPUT_NAME, cnt,
|
||||
dev->absmin[cnt], dev->absmax[cnt]);
|
||||
retval = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((dev->absflat[cnt] < dev->absmin[cnt]) ||
|
||||
(dev->absflat[cnt] > dev->absmax[cnt])) {
|
||||
printk(KERN_DEBUG
|
||||
"%s: absflat[%02x] out of range: %d "
|
||||
"(min:%d/max:%d)\n",
|
||||
UINPUT_NAME, cnt, dev->absflat[cnt],
|
||||
dev->absmin[cnt], dev->absmax[cnt]);
|
||||
retval = -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int uinput_alloc_device(struct file *file, const char __user *buffer, size_t count)
|
||||
{
|
||||
struct uinput_user_dev *user_dev;
|
||||
struct input_dev *dev;
|
||||
struct uinput_device *udev;
|
||||
int size,
|
||||
retval;
|
||||
|
||||
retval = count;
|
||||
|
||||
udev = (struct uinput_device *)file->private_data;
|
||||
dev = udev->dev;
|
||||
|
||||
user_dev = kmalloc(sizeof(*user_dev), GFP_KERNEL);
|
||||
if (!user_dev) {
|
||||
retval = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (copy_from_user(user_dev, buffer, sizeof(struct uinput_user_dev))) {
|
||||
retval = -EFAULT;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (NULL != dev->name)
|
||||
kfree(dev->name);
|
||||
|
||||
size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1;
|
||||
dev->name = kmalloc(size, GFP_KERNEL);
|
||||
if (!dev->name) {
|
||||
retval = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
strlcpy(dev->name, user_dev->name, size);
|
||||
dev->id.bustype = user_dev->id.bustype;
|
||||
dev->id.vendor = user_dev->id.vendor;
|
||||
dev->id.product = user_dev->id.product;
|
||||
dev->id.version = user_dev->id.version;
|
||||
dev->ff_effects_max = user_dev->ff_effects_max;
|
||||
|
||||
size = sizeof(int) * (ABS_MAX + 1);
|
||||
memcpy(dev->absmax, user_dev->absmax, size);
|
||||
memcpy(dev->absmin, user_dev->absmin, size);
|
||||
memcpy(dev->absfuzz, user_dev->absfuzz, size);
|
||||
memcpy(dev->absflat, user_dev->absflat, size);
|
||||
|
||||
/* check if absmin/absmax/absfuzz/absflat are filled as
|
||||
* told in Documentation/input/input-programming.txt */
|
||||
if (test_bit(EV_ABS, dev->evbit)) {
|
||||
retval = uinput_validate_absbits(dev);
|
||||
if (retval < 0)
|
||||
kfree(dev->name);
|
||||
}
|
||||
|
||||
exit:
|
||||
kfree(user_dev);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct uinput_device *udev = file->private_data;
|
||||
|
||||
if (test_bit(UIST_CREATED, &(udev->state))) {
|
||||
struct input_event ev;
|
||||
|
||||
if (copy_from_user(&ev, buffer, sizeof(struct input_event)))
|
||||
return -EFAULT;
|
||||
input_event(udev->dev, ev.type, ev.code, ev.value);
|
||||
}
|
||||
else
|
||||
count = uinput_alloc_device(file, buffer, count);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct uinput_device *udev = file->private_data;
|
||||
int retval = 0;
|
||||
|
||||
if (!test_bit(UIST_CREATED, &(udev->state)))
|
||||
return -ENODEV;
|
||||
|
||||
if ((udev->head == udev->tail) && (file->f_flags & O_NONBLOCK))
|
||||
return -EAGAIN;
|
||||
|
||||
retval = wait_event_interruptible(udev->waitq,
|
||||
(udev->head != udev->tail) ||
|
||||
!test_bit(UIST_CREATED, &(udev->state)));
|
||||
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!test_bit(UIST_CREATED, &(udev->state)))
|
||||
return -ENODEV;
|
||||
|
||||
while ((udev->head != udev->tail) &&
|
||||
(retval + sizeof(struct input_event) <= count)) {
|
||||
if (copy_to_user(buffer + retval, &(udev->buff[udev->tail]),
|
||||
sizeof(struct input_event))) return -EFAULT;
|
||||
udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE;
|
||||
retval += sizeof(struct input_event);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static unsigned int uinput_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct uinput_device *udev = file->private_data;
|
||||
|
||||
if (!test_bit(UIST_CREATED, &(udev->state)))
|
||||
return 0;
|
||||
|
||||
poll_wait(file, &udev->waitq, wait);
|
||||
|
||||
if (udev->head != udev->tail)
|
||||
return POLLIN | POLLRDNORM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uinput_burn_device(struct uinput_device *udev)
|
||||
{
|
||||
if (test_bit(UIST_CREATED, &(udev->state)))
|
||||
uinput_destroy_device(udev);
|
||||
|
||||
kfree(udev->dev);
|
||||
kfree(udev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uinput_close(struct inode *inode, struct file *file)
|
||||
{
|
||||
return uinput_burn_device((struct uinput_device *)file->private_data);
|
||||
}
|
||||
|
||||
static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int retval = 0;
|
||||
struct uinput_device *udev;
|
||||
|
||||
udev = (struct uinput_device *)file->private_data;
|
||||
|
||||
/* device attributes can not be changed after the device is created */
|
||||
if (cmd >= UI_SET_EVBIT && test_bit(UIST_CREATED, &(udev->state)))
|
||||
return -EINVAL;
|
||||
|
||||
switch (cmd) {
|
||||
case UI_DEV_CREATE:
|
||||
retval = uinput_create_device(udev);
|
||||
break;
|
||||
|
||||
case UI_DEV_DESTROY:
|
||||
retval = uinput_destroy_device(udev);
|
||||
break;
|
||||
|
||||
case UI_SET_EVBIT:
|
||||
if (arg > EV_MAX) {
|
||||
retval = -EINVAL;
|
||||
break;
|
||||
}
|
||||
set_bit(arg, udev->dev->evbit);
|
||||
break;
|
||||
|
||||
case UI_SET_KEYBIT:
|
||||
if (arg > KEY_MAX) {
|
||||
retval = -EINVAL;
|
||||
break;
|
||||
}
|
||||
set_bit(arg, udev->dev->keybit);
|
||||
break;
|
||||
|
||||
case UI_SET_RELBIT:
|
||||
if (arg > REL_MAX) {
|
||||
retval = -EINVAL;
|
||||
break;
|
||||
}
|
||||
set_bit(arg, udev->dev->relbit);
|
||||
break;
|
||||
|
||||
case UI_SET_ABSBIT:
|
||||
if (arg > ABS_MAX) {
|
||||
retval = -EINVAL;
|
||||
break;
|
||||
}
|
||||
set_bit(arg, udev->dev->absbit);
|
||||
break;
|
||||
|
||||
case UI_SET_MSCBIT:
|
||||
if (arg > MSC_MAX) {
|
||||
retval = -EINVAL;
|
||||
break;
|
||||
}
|
||||
set_bit(arg, udev->dev->mscbit);
|
||||
break;
|
||||
|
||||
case UI_SET_LEDBIT:
|
||||
if (arg > LED_MAX) {
|
||||
retval = -EINVAL;
|
||||
break;
|
||||
}
|
||||
set_bit(arg, udev->dev->ledbit);
|
||||
break;
|
||||
|
||||
case UI_SET_SNDBIT:
|
||||
if (arg > SND_MAX) {
|
||||
retval = -EINVAL;
|
||||
break;
|
||||
}
|
||||
set_bit(arg, udev->dev->sndbit);
|
||||
break;
|
||||
|
||||
case UI_SET_FFBIT:
|
||||
if (arg > FF_MAX) {
|
||||
retval = -EINVAL;
|
||||
break;
|
||||
}
|
||||
set_bit(arg, udev->dev->ffbit);
|
||||
break;
|
||||
|
||||
default:
|
||||
retval = -EFAULT;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
struct file_operations uinput_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = uinput_open,
|
||||
.release = uinput_close,
|
||||
.read = uinput_read,
|
||||
.write = uinput_write,
|
||||
.poll = uinput_poll,
|
||||
.ioctl = uinput_ioctl,
|
||||
};
|
||||
|
||||
static struct miscdevice uinput_misc = {
|
||||
.fops = &uinput_fops,
|
||||
.minor = UINPUT_MINOR,
|
||||
.name = UINPUT_NAME,
|
||||
};
|
||||
|
||||
static int __init uinput_init(void)
|
||||
{
|
||||
return misc_register(&uinput_misc);
|
||||
}
|
||||
|
||||
static void __exit uinput_exit(void)
|
||||
{
|
||||
misc_deregister(&uinput_misc);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Aristeu Sergio Rozanski Filho");
|
||||
MODULE_DESCRIPTION("User level driver support for input subsystem");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(uinput_init);
|
||||
module_exit(uinput_exit);
|
||||
|
||||
1
extra/linux-2.6.10/drivers/input/mouse/.built-in.o.cmd
Normal file
1
extra/linux-2.6.10/drivers/input/mouse/.built-in.o.cmd
Normal file
@@ -0,0 +1 @@
|
||||
cmd_drivers/input/mouse/built-in.o := ld -m elf_i386 -r -o drivers/input/mouse/built-in.o drivers/input/mouse/psmouse.o
|
||||
246
extra/linux-2.6.10/drivers/input/mouse/.logips2pp.o.cmd
Normal file
246
extra/linux-2.6.10/drivers/input/mouse/.logips2pp.o.cmd
Normal file
@@ -0,0 +1,246 @@
|
||||
cmd_drivers/input/mouse/logips2pp.o := gcc -Wp,-MD,drivers/input/mouse/.logips2pp.o.d -nostdinc -iwithprefix include -D__KERNEL__ -Iinclude -Wall -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -O2 -fomit-frame-pointer -pipe -msoft-float -mpreferred-stack-boundary=2 -fno-unit-at-a-time -march=pentium-mmx -Iinclude/asm-i386/mach-default -Wdeclaration-after-statement -DKBUILD_BASENAME=logips2pp -DKBUILD_MODNAME=psmouse -c -o drivers/input/mouse/logips2pp.o drivers/input/mouse/logips2pp.c
|
||||
|
||||
deps_drivers/input/mouse/logips2pp.o := \
|
||||
drivers/input/mouse/logips2pp.c \
|
||||
include/linux/input.h \
|
||||
include/linux/time.h \
|
||||
include/linux/types.h \
|
||||
$(wildcard include/config/uid16.h) \
|
||||
include/linux/config.h \
|
||||
$(wildcard include/config/h.h) \
|
||||
include/linux/posix_types.h \
|
||||
include/linux/stddef.h \
|
||||
include/linux/compiler.h \
|
||||
include/linux/compiler-gcc3.h \
|
||||
include/linux/compiler-gcc.h \
|
||||
include/asm/posix_types.h \
|
||||
include/asm/types.h \
|
||||
$(wildcard include/config/highmem64g.h) \
|
||||
$(wildcard include/config/lbd.h) \
|
||||
include/linux/seqlock.h \
|
||||
include/linux/spinlock.h \
|
||||
$(wildcard include/config/smp.h) \
|
||||
$(wildcard include/config/preempt.h) \
|
||||
$(wildcard include/config/debug/spinlock.h) \
|
||||
$(wildcard include/config/lockmeter.h) \
|
||||
include/linux/preempt.h \
|
||||
include/linux/linkage.h \
|
||||
include/asm/linkage.h \
|
||||
$(wildcard include/config/regparm.h) \
|
||||
$(wildcard include/config/x86/alignment/16.h) \
|
||||
include/linux/thread_info.h \
|
||||
include/linux/bitops.h \
|
||||
include/asm/bitops.h \
|
||||
include/asm/thread_info.h \
|
||||
$(wildcard include/config/4kstacks.h) \
|
||||
$(wildcard include/config/debug/stack/usage.h) \
|
||||
include/asm/page.h \
|
||||
$(wildcard include/config/x86/use/3dnow.h) \
|
||||
$(wildcard include/config/x86/pae.h) \
|
||||
$(wildcard include/config/hugetlb/page.h) \
|
||||
$(wildcard include/config/highmem4g.h) \
|
||||
$(wildcard include/config/discontigmem.h) \
|
||||
include/asm/processor.h \
|
||||
$(wildcard include/config/mk8.h) \
|
||||
$(wildcard include/config/mk7.h) \
|
||||
include/asm/vm86.h \
|
||||
include/asm/math_emu.h \
|
||||
include/asm/sigcontext.h \
|
||||
include/asm/segment.h \
|
||||
include/asm/cpufeature.h \
|
||||
include/asm/msr.h \
|
||||
include/asm/system.h \
|
||||
$(wildcard include/config/x86/cmpxchg.h) \
|
||||
$(wildcard include/config/x86/oostore.h) \
|
||||
include/linux/kernel.h \
|
||||
$(wildcard include/config/debug/spinlock/sleep.h) \
|
||||
/usr/lib/gcc/i686-pc-linux-gnu/3.4.1/include/stdarg.h \
|
||||
include/asm/byteorder.h \
|
||||
$(wildcard include/config/x86/bswap.h) \
|
||||
include/linux/byteorder/little_endian.h \
|
||||
include/linux/byteorder/swab.h \
|
||||
include/linux/byteorder/generic.h \
|
||||
include/asm/bug.h \
|
||||
include/asm-generic/bug.h \
|
||||
include/linux/cache.h \
|
||||
include/asm/cache.h \
|
||||
$(wildcard include/config/x86/l1/cache/shift.h) \
|
||||
include/linux/threads.h \
|
||||
$(wildcard include/config/nr/cpus.h) \
|
||||
include/asm/percpu.h \
|
||||
include/asm-generic/percpu.h \
|
||||
include/linux/stringify.h \
|
||||
include/linux/list.h \
|
||||
include/linux/prefetch.h \
|
||||
include/linux/fs.h \
|
||||
$(wildcard include/config/dnotify.h) \
|
||||
$(wildcard include/config/quota.h) \
|
||||
$(wildcard include/config/epoll.h) \
|
||||
$(wildcard include/config/auditsyscall.h) \
|
||||
$(wildcard include/config/security.h) \
|
||||
include/linux/limits.h \
|
||||
include/linux/wait.h \
|
||||
include/asm/current.h \
|
||||
include/linux/kdev_t.h \
|
||||
include/linux/ioctl.h \
|
||||
include/asm/ioctl.h \
|
||||
include/linux/dcache.h \
|
||||
include/asm/atomic.h \
|
||||
$(wildcard include/config/m386.h) \
|
||||
include/linux/rcupdate.h \
|
||||
include/linux/percpu.h \
|
||||
include/linux/slab.h \
|
||||
$(wildcard include/config/.h) \
|
||||
$(wildcard include/config/numa.h) \
|
||||
include/linux/gfp.h \
|
||||
include/linux/mmzone.h \
|
||||
$(wildcard include/config/force/max/zoneorder.h) \
|
||||
include/linux/numa.h \
|
||||
include/linux/topology.h \
|
||||
$(wildcard include/config/sched/smt.h) \
|
||||
include/linux/cpumask.h \
|
||||
$(wildcard include/config/hotplug/cpu.h) \
|
||||
include/linux/bitmap.h \
|
||||
include/linux/string.h \
|
||||
include/asm/string.h \
|
||||
include/linux/smp.h \
|
||||
include/asm/topology.h \
|
||||
include/asm-generic/topology.h \
|
||||
include/linux/init.h \
|
||||
$(wildcard include/config/modules.h) \
|
||||
$(wildcard include/config/hotplug.h) \
|
||||
include/linux/kmalloc_sizes.h \
|
||||
$(wildcard include/config/mmu.h) \
|
||||
$(wildcard include/config/large/allocs.h) \
|
||||
include/linux/stat.h \
|
||||
include/asm/stat.h \
|
||||
include/linux/prio_tree.h \
|
||||
include/linux/kobject.h \
|
||||
include/linux/sysfs.h \
|
||||
$(wildcard include/config/sysfs.h) \
|
||||
include/linux/rwsem.h \
|
||||
$(wildcard include/config/rwsem/generic/spinlock.h) \
|
||||
include/asm/rwsem.h \
|
||||
include/linux/kref.h \
|
||||
include/linux/kobject_uevent.h \
|
||||
$(wildcard include/config/kobject/uevent.h) \
|
||||
include/linux/radix-tree.h \
|
||||
include/linux/audit.h \
|
||||
$(wildcard include/config/audit.h) \
|
||||
include/asm/semaphore.h \
|
||||
include/linux/quota.h \
|
||||
include/linux/errno.h \
|
||||
include/asm/errno.h \
|
||||
include/asm-generic/errno.h \
|
||||
include/asm-generic/errno-base.h \
|
||||
include/linux/dqblk_xfs.h \
|
||||
include/linux/dqblk_v1.h \
|
||||
include/linux/dqblk_v2.h \
|
||||
include/linux/nfs_fs_i.h \
|
||||
include/linux/nfs.h \
|
||||
include/linux/sunrpc/msg_prot.h \
|
||||
include/linux/fcntl.h \
|
||||
include/asm/fcntl.h \
|
||||
include/linux/err.h \
|
||||
include/linux/timer.h \
|
||||
include/linux/serio.h \
|
||||
include/linux/interrupt.h \
|
||||
$(wildcard include/config/generic/hardirqs.h) \
|
||||
$(wildcard include/config/generic/irq/probe.h) \
|
||||
include/linux/hardirq.h \
|
||||
include/linux/smp_lock.h \
|
||||
$(wildcard include/config/lock/kernel.h) \
|
||||
include/linux/sched.h \
|
||||
$(wildcard include/config/keys.h) \
|
||||
$(wildcard include/config/schedstats.h) \
|
||||
$(wildcard include/config/magic/sysrq.h) \
|
||||
include/asm/param.h \
|
||||
include/linux/capability.h \
|
||||
include/linux/timex.h \
|
||||
$(wildcard include/config/time/interpolation.h) \
|
||||
include/asm/timex.h \
|
||||
$(wildcard include/config/x86/elan.h) \
|
||||
$(wildcard include/config/x86/tsc.h) \
|
||||
$(wildcard include/config/x86/generic.h) \
|
||||
include/linux/jiffies.h \
|
||||
include/asm/div64.h \
|
||||
include/linux/rbtree.h \
|
||||
include/asm/ptrace.h \
|
||||
$(wildcard include/config/frame/pointer.h) \
|
||||
include/asm/mmu.h \
|
||||
include/linux/sem.h \
|
||||
$(wildcard include/config/sysvipc.h) \
|
||||
include/linux/ipc.h \
|
||||
include/asm/ipcbuf.h \
|
||||
include/asm/sembuf.h \
|
||||
include/linux/signal.h \
|
||||
include/asm/signal.h \
|
||||
include/asm/siginfo.h \
|
||||
include/asm-generic/siginfo.h \
|
||||
include/linux/resource.h \
|
||||
include/asm/resource.h \
|
||||
include/linux/securebits.h \
|
||||
include/linux/fs_struct.h \
|
||||
include/linux/completion.h \
|
||||
include/linux/pid.h \
|
||||
include/linux/param.h \
|
||||
include/linux/aio.h \
|
||||
include/linux/workqueue.h \
|
||||
include/linux/aio_abi.h \
|
||||
include/asm/hardirq.h \
|
||||
include/linux/irq.h \
|
||||
$(wildcard include/config/arch/s390.h) \
|
||||
include/asm/irq.h \
|
||||
$(wildcard include/config/x86/local/apic.h) \
|
||||
$(wildcard include/config/irqbalance.h) \
|
||||
include/asm-i386/mach-default/irq_vectors.h \
|
||||
include/asm-i386/mach-default/irq_vectors_limits.h \
|
||||
$(wildcard include/config/pci/msi.h) \
|
||||
$(wildcard include/config/x86/io/apic.h) \
|
||||
include/asm/hw_irq.h \
|
||||
include/linux/profile.h \
|
||||
$(wildcard include/config/proc/fs.h) \
|
||||
$(wildcard include/config/profiling.h) \
|
||||
include/asm/sections.h \
|
||||
include/asm-generic/sections.h \
|
||||
include/linux/irq_cpustat.h \
|
||||
include/linux/device.h \
|
||||
include/linux/ioport.h \
|
||||
include/linux/module.h \
|
||||
$(wildcard include/config/modversions.h) \
|
||||
$(wildcard include/config/module/unload.h) \
|
||||
$(wildcard include/config/kallsyms.h) \
|
||||
include/linux/kmod.h \
|
||||
$(wildcard include/config/kmod.h) \
|
||||
include/linux/elf.h \
|
||||
include/asm/elf.h \
|
||||
include/asm/user.h \
|
||||
include/linux/utsname.h \
|
||||
include/linux/moduleparam.h \
|
||||
include/asm/local.h \
|
||||
include/asm/module.h \
|
||||
$(wildcard include/config/m486.h) \
|
||||
$(wildcard include/config/m586.h) \
|
||||
$(wildcard include/config/m586tsc.h) \
|
||||
$(wildcard include/config/m586mmx.h) \
|
||||
$(wildcard include/config/m686.h) \
|
||||
$(wildcard include/config/mpentiumii.h) \
|
||||
$(wildcard include/config/mpentiumiii.h) \
|
||||
$(wildcard include/config/mpentiumm.h) \
|
||||
$(wildcard include/config/mpentium4.h) \
|
||||
$(wildcard include/config/mk6.h) \
|
||||
$(wildcard include/config/mcrusoe.h) \
|
||||
$(wildcard include/config/mefficeon.h) \
|
||||
$(wildcard include/config/mwinchipc6.h) \
|
||||
$(wildcard include/config/mwinchip2.h) \
|
||||
$(wildcard include/config/mwinchip3d.h) \
|
||||
$(wildcard include/config/mcyrixiii.h) \
|
||||
$(wildcard include/config/mviac3/2.h) \
|
||||
include/linux/pm.h \
|
||||
$(wildcard include/config/pm.h) \
|
||||
drivers/input/mouse/psmouse.h \
|
||||
drivers/input/mouse/logips2pp.h \
|
||||
|
||||
drivers/input/mouse/logips2pp.o: $(deps_drivers/input/mouse/logips2pp.o)
|
||||
|
||||
$(deps_drivers/input/mouse/logips2pp.o):
|
||||
249
extra/linux-2.6.10/drivers/input/mouse/.psmouse-base.o.cmd
Normal file
249
extra/linux-2.6.10/drivers/input/mouse/.psmouse-base.o.cmd
Normal file
@@ -0,0 +1,249 @@
|
||||
cmd_drivers/input/mouse/psmouse-base.o := gcc -Wp,-MD,drivers/input/mouse/.psmouse-base.o.d -nostdinc -iwithprefix include -D__KERNEL__ -Iinclude -Wall -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -O2 -fomit-frame-pointer -pipe -msoft-float -mpreferred-stack-boundary=2 -fno-unit-at-a-time -march=pentium-mmx -Iinclude/asm-i386/mach-default -Wdeclaration-after-statement -DKBUILD_BASENAME=psmouse_base -DKBUILD_MODNAME=psmouse -c -o drivers/input/mouse/psmouse-base.o drivers/input/mouse/psmouse-base.c
|
||||
|
||||
deps_drivers/input/mouse/psmouse-base.o := \
|
||||
drivers/input/mouse/psmouse-base.c \
|
||||
include/linux/delay.h \
|
||||
include/asm/delay.h \
|
||||
include/linux/module.h \
|
||||
$(wildcard include/config/modules.h) \
|
||||
$(wildcard include/config/modversions.h) \
|
||||
$(wildcard include/config/module/unload.h) \
|
||||
$(wildcard include/config/kallsyms.h) \
|
||||
include/linux/config.h \
|
||||
$(wildcard include/config/h.h) \
|
||||
include/linux/sched.h \
|
||||
$(wildcard include/config/keys.h) \
|
||||
$(wildcard include/config/schedstats.h) \
|
||||
$(wildcard include/config/smp.h) \
|
||||
$(wildcard include/config/numa.h) \
|
||||
$(wildcard include/config/security.h) \
|
||||
$(wildcard include/config/preempt.h) \
|
||||
$(wildcard include/config/magic/sysrq.h) \
|
||||
include/asm/param.h \
|
||||
include/linux/capability.h \
|
||||
include/linux/types.h \
|
||||
$(wildcard include/config/uid16.h) \
|
||||
include/linux/posix_types.h \
|
||||
include/linux/stddef.h \
|
||||
include/linux/compiler.h \
|
||||
include/linux/compiler-gcc3.h \
|
||||
include/linux/compiler-gcc.h \
|
||||
include/asm/posix_types.h \
|
||||
include/asm/types.h \
|
||||
$(wildcard include/config/highmem64g.h) \
|
||||
$(wildcard include/config/lbd.h) \
|
||||
include/linux/spinlock.h \
|
||||
$(wildcard include/config/debug/spinlock.h) \
|
||||
$(wildcard include/config/lockmeter.h) \
|
||||
include/linux/preempt.h \
|
||||
include/linux/linkage.h \
|
||||
include/asm/linkage.h \
|
||||
$(wildcard include/config/regparm.h) \
|
||||
$(wildcard include/config/x86/alignment/16.h) \
|
||||
include/linux/thread_info.h \
|
||||
include/linux/bitops.h \
|
||||
include/asm/bitops.h \
|
||||
include/asm/thread_info.h \
|
||||
$(wildcard include/config/4kstacks.h) \
|
||||
$(wildcard include/config/debug/stack/usage.h) \
|
||||
include/asm/page.h \
|
||||
$(wildcard include/config/x86/use/3dnow.h) \
|
||||
$(wildcard include/config/x86/pae.h) \
|
||||
$(wildcard include/config/hugetlb/page.h) \
|
||||
$(wildcard include/config/highmem4g.h) \
|
||||
$(wildcard include/config/discontigmem.h) \
|
||||
include/asm/processor.h \
|
||||
$(wildcard include/config/mk8.h) \
|
||||
$(wildcard include/config/mk7.h) \
|
||||
include/asm/vm86.h \
|
||||
include/asm/math_emu.h \
|
||||
include/asm/sigcontext.h \
|
||||
include/asm/segment.h \
|
||||
include/asm/cpufeature.h \
|
||||
include/asm/msr.h \
|
||||
include/asm/system.h \
|
||||
$(wildcard include/config/x86/cmpxchg.h) \
|
||||
$(wildcard include/config/x86/oostore.h) \
|
||||
include/linux/kernel.h \
|
||||
$(wildcard include/config/debug/spinlock/sleep.h) \
|
||||
/usr/lib/gcc/i686-pc-linux-gnu/3.4.1/include/stdarg.h \
|
||||
include/asm/byteorder.h \
|
||||
$(wildcard include/config/x86/bswap.h) \
|
||||
include/linux/byteorder/little_endian.h \
|
||||
include/linux/byteorder/swab.h \
|
||||
include/linux/byteorder/generic.h \
|
||||
include/asm/bug.h \
|
||||
include/asm-generic/bug.h \
|
||||
include/linux/cache.h \
|
||||
include/asm/cache.h \
|
||||
$(wildcard include/config/x86/l1/cache/shift.h) \
|
||||
include/linux/threads.h \
|
||||
$(wildcard include/config/nr/cpus.h) \
|
||||
include/asm/percpu.h \
|
||||
include/asm-generic/percpu.h \
|
||||
include/linux/stringify.h \
|
||||
include/linux/timex.h \
|
||||
$(wildcard include/config/time/interpolation.h) \
|
||||
include/linux/time.h \
|
||||
include/linux/seqlock.h \
|
||||
include/asm/timex.h \
|
||||
$(wildcard include/config/x86/elan.h) \
|
||||
$(wildcard include/config/x86/tsc.h) \
|
||||
$(wildcard include/config/x86/generic.h) \
|
||||
include/linux/jiffies.h \
|
||||
include/asm/div64.h \
|
||||
include/linux/rbtree.h \
|
||||
include/linux/cpumask.h \
|
||||
$(wildcard include/config/hotplug/cpu.h) \
|
||||
include/linux/bitmap.h \
|
||||
include/linux/string.h \
|
||||
include/asm/string.h \
|
||||
include/asm/semaphore.h \
|
||||
include/asm/atomic.h \
|
||||
$(wildcard include/config/m386.h) \
|
||||
include/linux/wait.h \
|
||||
include/linux/list.h \
|
||||
include/linux/prefetch.h \
|
||||
include/asm/current.h \
|
||||
include/linux/rwsem.h \
|
||||
$(wildcard include/config/rwsem/generic/spinlock.h) \
|
||||
include/asm/rwsem.h \
|
||||
include/asm/ptrace.h \
|
||||
$(wildcard include/config/frame/pointer.h) \
|
||||
include/asm/mmu.h \
|
||||
include/linux/smp.h \
|
||||
include/linux/sem.h \
|
||||
$(wildcard include/config/sysvipc.h) \
|
||||
include/linux/ipc.h \
|
||||
include/asm/ipcbuf.h \
|
||||
include/asm/sembuf.h \
|
||||
include/linux/signal.h \
|
||||
include/asm/signal.h \
|
||||
include/asm/siginfo.h \
|
||||
include/asm-generic/siginfo.h \
|
||||
include/linux/resource.h \
|
||||
include/asm/resource.h \
|
||||
include/linux/securebits.h \
|
||||
include/linux/fs_struct.h \
|
||||
include/linux/completion.h \
|
||||
include/linux/pid.h \
|
||||
include/linux/percpu.h \
|
||||
include/linux/slab.h \
|
||||
$(wildcard include/config/.h) \
|
||||
include/linux/gfp.h \
|
||||
include/linux/mmzone.h \
|
||||
$(wildcard include/config/force/max/zoneorder.h) \
|
||||
include/linux/numa.h \
|
||||
include/linux/topology.h \
|
||||
$(wildcard include/config/sched/smt.h) \
|
||||
include/asm/topology.h \
|
||||
include/asm-generic/topology.h \
|
||||
include/linux/init.h \
|
||||
$(wildcard include/config/hotplug.h) \
|
||||
include/linux/kmalloc_sizes.h \
|
||||
$(wildcard include/config/mmu.h) \
|
||||
$(wildcard include/config/large/allocs.h) \
|
||||
include/linux/param.h \
|
||||
include/linux/timer.h \
|
||||
include/linux/aio.h \
|
||||
include/linux/workqueue.h \
|
||||
include/linux/aio_abi.h \
|
||||
include/linux/stat.h \
|
||||
include/asm/stat.h \
|
||||
include/linux/kmod.h \
|
||||
$(wildcard include/config/kmod.h) \
|
||||
include/linux/errno.h \
|
||||
include/asm/errno.h \
|
||||
include/asm-generic/errno.h \
|
||||
include/asm-generic/errno-base.h \
|
||||
include/linux/elf.h \
|
||||
include/asm/elf.h \
|
||||
include/asm/user.h \
|
||||
include/linux/utsname.h \
|
||||
include/linux/kobject.h \
|
||||
include/linux/sysfs.h \
|
||||
$(wildcard include/config/sysfs.h) \
|
||||
include/linux/kref.h \
|
||||
include/linux/kobject_uevent.h \
|
||||
$(wildcard include/config/kobject/uevent.h) \
|
||||
include/linux/moduleparam.h \
|
||||
include/asm/local.h \
|
||||
include/asm/module.h \
|
||||
$(wildcard include/config/m486.h) \
|
||||
$(wildcard include/config/m586.h) \
|
||||
$(wildcard include/config/m586tsc.h) \
|
||||
$(wildcard include/config/m586mmx.h) \
|
||||
$(wildcard include/config/m686.h) \
|
||||
$(wildcard include/config/mpentiumii.h) \
|
||||
$(wildcard include/config/mpentiumiii.h) \
|
||||
$(wildcard include/config/mpentiumm.h) \
|
||||
$(wildcard include/config/mpentium4.h) \
|
||||
$(wildcard include/config/mk6.h) \
|
||||
$(wildcard include/config/mcrusoe.h) \
|
||||
$(wildcard include/config/mefficeon.h) \
|
||||
$(wildcard include/config/mwinchipc6.h) \
|
||||
$(wildcard include/config/mwinchip2.h) \
|
||||
$(wildcard include/config/mwinchip3d.h) \
|
||||
$(wildcard include/config/mcyrixiii.h) \
|
||||
$(wildcard include/config/mviac3/2.h) \
|
||||
include/linux/interrupt.h \
|
||||
$(wildcard include/config/generic/hardirqs.h) \
|
||||
$(wildcard include/config/generic/irq/probe.h) \
|
||||
include/linux/hardirq.h \
|
||||
include/linux/smp_lock.h \
|
||||
$(wildcard include/config/lock/kernel.h) \
|
||||
include/asm/hardirq.h \
|
||||
include/linux/irq.h \
|
||||
$(wildcard include/config/arch/s390.h) \
|
||||
include/asm/irq.h \
|
||||
$(wildcard include/config/x86/local/apic.h) \
|
||||
$(wildcard include/config/irqbalance.h) \
|
||||
include/asm-i386/mach-default/irq_vectors.h \
|
||||
include/asm-i386/mach-default/irq_vectors_limits.h \
|
||||
$(wildcard include/config/pci/msi.h) \
|
||||
$(wildcard include/config/x86/io/apic.h) \
|
||||
include/asm/hw_irq.h \
|
||||
include/linux/profile.h \
|
||||
$(wildcard include/config/proc/fs.h) \
|
||||
$(wildcard include/config/profiling.h) \
|
||||
include/asm/sections.h \
|
||||
include/asm-generic/sections.h \
|
||||
include/linux/irq_cpustat.h \
|
||||
include/linux/input.h \
|
||||
include/linux/fs.h \
|
||||
$(wildcard include/config/dnotify.h) \
|
||||
$(wildcard include/config/quota.h) \
|
||||
$(wildcard include/config/epoll.h) \
|
||||
$(wildcard include/config/auditsyscall.h) \
|
||||
include/linux/limits.h \
|
||||
include/linux/kdev_t.h \
|
||||
include/linux/ioctl.h \
|
||||
include/asm/ioctl.h \
|
||||
include/linux/dcache.h \
|
||||
include/linux/rcupdate.h \
|
||||
include/linux/prio_tree.h \
|
||||
include/linux/radix-tree.h \
|
||||
include/linux/audit.h \
|
||||
$(wildcard include/config/audit.h) \
|
||||
include/linux/quota.h \
|
||||
include/linux/dqblk_xfs.h \
|
||||
include/linux/dqblk_v1.h \
|
||||
include/linux/dqblk_v2.h \
|
||||
include/linux/nfs_fs_i.h \
|
||||
include/linux/nfs.h \
|
||||
include/linux/sunrpc/msg_prot.h \
|
||||
include/linux/fcntl.h \
|
||||
include/asm/fcntl.h \
|
||||
include/linux/err.h \
|
||||
include/linux/serio.h \
|
||||
include/linux/device.h \
|
||||
include/linux/ioport.h \
|
||||
include/linux/pm.h \
|
||||
$(wildcard include/config/pm.h) \
|
||||
drivers/input/mouse/psmouse.h \
|
||||
drivers/input/mouse/synaptics.h \
|
||||
drivers/input/mouse/logips2pp.h \
|
||||
|
||||
drivers/input/mouse/psmouse-base.o: $(deps_drivers/input/mouse/psmouse-base.o)
|
||||
|
||||
$(deps_drivers/input/mouse/psmouse-base.o):
|
||||
1
extra/linux-2.6.10/drivers/input/mouse/.psmouse.o.cmd
Normal file
1
extra/linux-2.6.10/drivers/input/mouse/.psmouse.o.cmd
Normal file
@@ -0,0 +1 @@
|
||||
cmd_drivers/input/mouse/psmouse.o := ld -m elf_i386 -r -o drivers/input/mouse/psmouse.o drivers/input/mouse/psmouse-base.o drivers/input/mouse/logips2pp.o drivers/input/mouse/synaptics.o
|
||||
246
extra/linux-2.6.10/drivers/input/mouse/.synaptics.o.cmd
Normal file
246
extra/linux-2.6.10/drivers/input/mouse/.synaptics.o.cmd
Normal file
@@ -0,0 +1,246 @@
|
||||
cmd_drivers/input/mouse/synaptics.o := gcc -Wp,-MD,drivers/input/mouse/.synaptics.o.d -nostdinc -iwithprefix include -D__KERNEL__ -Iinclude -Wall -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -O2 -fomit-frame-pointer -pipe -msoft-float -mpreferred-stack-boundary=2 -fno-unit-at-a-time -march=pentium-mmx -Iinclude/asm-i386/mach-default -Wdeclaration-after-statement -DKBUILD_BASENAME=synaptics -DKBUILD_MODNAME=psmouse -c -o drivers/input/mouse/synaptics.o drivers/input/mouse/synaptics.c
|
||||
|
||||
deps_drivers/input/mouse/synaptics.o := \
|
||||
drivers/input/mouse/synaptics.c \
|
||||
include/linux/module.h \
|
||||
$(wildcard include/config/modules.h) \
|
||||
$(wildcard include/config/modversions.h) \
|
||||
$(wildcard include/config/module/unload.h) \
|
||||
$(wildcard include/config/kallsyms.h) \
|
||||
include/linux/config.h \
|
||||
$(wildcard include/config/h.h) \
|
||||
include/linux/sched.h \
|
||||
$(wildcard include/config/keys.h) \
|
||||
$(wildcard include/config/schedstats.h) \
|
||||
$(wildcard include/config/smp.h) \
|
||||
$(wildcard include/config/numa.h) \
|
||||
$(wildcard include/config/security.h) \
|
||||
$(wildcard include/config/preempt.h) \
|
||||
$(wildcard include/config/magic/sysrq.h) \
|
||||
include/asm/param.h \
|
||||
include/linux/capability.h \
|
||||
include/linux/types.h \
|
||||
$(wildcard include/config/uid16.h) \
|
||||
include/linux/posix_types.h \
|
||||
include/linux/stddef.h \
|
||||
include/linux/compiler.h \
|
||||
include/linux/compiler-gcc3.h \
|
||||
include/linux/compiler-gcc.h \
|
||||
include/asm/posix_types.h \
|
||||
include/asm/types.h \
|
||||
$(wildcard include/config/highmem64g.h) \
|
||||
$(wildcard include/config/lbd.h) \
|
||||
include/linux/spinlock.h \
|
||||
$(wildcard include/config/debug/spinlock.h) \
|
||||
$(wildcard include/config/lockmeter.h) \
|
||||
include/linux/preempt.h \
|
||||
include/linux/linkage.h \
|
||||
include/asm/linkage.h \
|
||||
$(wildcard include/config/regparm.h) \
|
||||
$(wildcard include/config/x86/alignment/16.h) \
|
||||
include/linux/thread_info.h \
|
||||
include/linux/bitops.h \
|
||||
include/asm/bitops.h \
|
||||
include/asm/thread_info.h \
|
||||
$(wildcard include/config/4kstacks.h) \
|
||||
$(wildcard include/config/debug/stack/usage.h) \
|
||||
include/asm/page.h \
|
||||
$(wildcard include/config/x86/use/3dnow.h) \
|
||||
$(wildcard include/config/x86/pae.h) \
|
||||
$(wildcard include/config/hugetlb/page.h) \
|
||||
$(wildcard include/config/highmem4g.h) \
|
||||
$(wildcard include/config/discontigmem.h) \
|
||||
include/asm/processor.h \
|
||||
$(wildcard include/config/mk8.h) \
|
||||
$(wildcard include/config/mk7.h) \
|
||||
include/asm/vm86.h \
|
||||
include/asm/math_emu.h \
|
||||
include/asm/sigcontext.h \
|
||||
include/asm/segment.h \
|
||||
include/asm/cpufeature.h \
|
||||
include/asm/msr.h \
|
||||
include/asm/system.h \
|
||||
$(wildcard include/config/x86/cmpxchg.h) \
|
||||
$(wildcard include/config/x86/oostore.h) \
|
||||
include/linux/kernel.h \
|
||||
$(wildcard include/config/debug/spinlock/sleep.h) \
|
||||
/usr/lib/gcc/i686-pc-linux-gnu/3.4.1/include/stdarg.h \
|
||||
include/asm/byteorder.h \
|
||||
$(wildcard include/config/x86/bswap.h) \
|
||||
include/linux/byteorder/little_endian.h \
|
||||
include/linux/byteorder/swab.h \
|
||||
include/linux/byteorder/generic.h \
|
||||
include/asm/bug.h \
|
||||
include/asm-generic/bug.h \
|
||||
include/linux/cache.h \
|
||||
include/asm/cache.h \
|
||||
$(wildcard include/config/x86/l1/cache/shift.h) \
|
||||
include/linux/threads.h \
|
||||
$(wildcard include/config/nr/cpus.h) \
|
||||
include/asm/percpu.h \
|
||||
include/asm-generic/percpu.h \
|
||||
include/linux/stringify.h \
|
||||
include/linux/timex.h \
|
||||
$(wildcard include/config/time/interpolation.h) \
|
||||
include/linux/time.h \
|
||||
include/linux/seqlock.h \
|
||||
include/asm/timex.h \
|
||||
$(wildcard include/config/x86/elan.h) \
|
||||
$(wildcard include/config/x86/tsc.h) \
|
||||
$(wildcard include/config/x86/generic.h) \
|
||||
include/linux/jiffies.h \
|
||||
include/asm/div64.h \
|
||||
include/linux/rbtree.h \
|
||||
include/linux/cpumask.h \
|
||||
$(wildcard include/config/hotplug/cpu.h) \
|
||||
include/linux/bitmap.h \
|
||||
include/linux/string.h \
|
||||
include/asm/string.h \
|
||||
include/asm/semaphore.h \
|
||||
include/asm/atomic.h \
|
||||
$(wildcard include/config/m386.h) \
|
||||
include/linux/wait.h \
|
||||
include/linux/list.h \
|
||||
include/linux/prefetch.h \
|
||||
include/asm/current.h \
|
||||
include/linux/rwsem.h \
|
||||
$(wildcard include/config/rwsem/generic/spinlock.h) \
|
||||
include/asm/rwsem.h \
|
||||
include/asm/ptrace.h \
|
||||
$(wildcard include/config/frame/pointer.h) \
|
||||
include/asm/mmu.h \
|
||||
include/linux/smp.h \
|
||||
include/linux/sem.h \
|
||||
$(wildcard include/config/sysvipc.h) \
|
||||
include/linux/ipc.h \
|
||||
include/asm/ipcbuf.h \
|
||||
include/asm/sembuf.h \
|
||||
include/linux/signal.h \
|
||||
include/asm/signal.h \
|
||||
include/asm/siginfo.h \
|
||||
include/asm-generic/siginfo.h \
|
||||
include/linux/resource.h \
|
||||
include/asm/resource.h \
|
||||
include/linux/securebits.h \
|
||||
include/linux/fs_struct.h \
|
||||
include/linux/completion.h \
|
||||
include/linux/pid.h \
|
||||
include/linux/percpu.h \
|
||||
include/linux/slab.h \
|
||||
$(wildcard include/config/.h) \
|
||||
include/linux/gfp.h \
|
||||
include/linux/mmzone.h \
|
||||
$(wildcard include/config/force/max/zoneorder.h) \
|
||||
include/linux/numa.h \
|
||||
include/linux/topology.h \
|
||||
$(wildcard include/config/sched/smt.h) \
|
||||
include/asm/topology.h \
|
||||
include/asm-generic/topology.h \
|
||||
include/linux/init.h \
|
||||
$(wildcard include/config/hotplug.h) \
|
||||
include/linux/kmalloc_sizes.h \
|
||||
$(wildcard include/config/mmu.h) \
|
||||
$(wildcard include/config/large/allocs.h) \
|
||||
include/linux/param.h \
|
||||
include/linux/timer.h \
|
||||
include/linux/aio.h \
|
||||
include/linux/workqueue.h \
|
||||
include/linux/aio_abi.h \
|
||||
include/linux/stat.h \
|
||||
include/asm/stat.h \
|
||||
include/linux/kmod.h \
|
||||
$(wildcard include/config/kmod.h) \
|
||||
include/linux/errno.h \
|
||||
include/asm/errno.h \
|
||||
include/asm-generic/errno.h \
|
||||
include/asm-generic/errno-base.h \
|
||||
include/linux/elf.h \
|
||||
include/asm/elf.h \
|
||||
include/asm/user.h \
|
||||
include/linux/utsname.h \
|
||||
include/linux/kobject.h \
|
||||
include/linux/sysfs.h \
|
||||
$(wildcard include/config/sysfs.h) \
|
||||
include/linux/kref.h \
|
||||
include/linux/kobject_uevent.h \
|
||||
$(wildcard include/config/kobject/uevent.h) \
|
||||
include/linux/moduleparam.h \
|
||||
include/asm/local.h \
|
||||
include/asm/module.h \
|
||||
$(wildcard include/config/m486.h) \
|
||||
$(wildcard include/config/m586.h) \
|
||||
$(wildcard include/config/m586tsc.h) \
|
||||
$(wildcard include/config/m586mmx.h) \
|
||||
$(wildcard include/config/m686.h) \
|
||||
$(wildcard include/config/mpentiumii.h) \
|
||||
$(wildcard include/config/mpentiumiii.h) \
|
||||
$(wildcard include/config/mpentiumm.h) \
|
||||
$(wildcard include/config/mpentium4.h) \
|
||||
$(wildcard include/config/mk6.h) \
|
||||
$(wildcard include/config/mcrusoe.h) \
|
||||
$(wildcard include/config/mefficeon.h) \
|
||||
$(wildcard include/config/mwinchipc6.h) \
|
||||
$(wildcard include/config/mwinchip2.h) \
|
||||
$(wildcard include/config/mwinchip3d.h) \
|
||||
$(wildcard include/config/mcyrixiii.h) \
|
||||
$(wildcard include/config/mviac3/2.h) \
|
||||
include/linux/input.h \
|
||||
include/linux/fs.h \
|
||||
$(wildcard include/config/dnotify.h) \
|
||||
$(wildcard include/config/quota.h) \
|
||||
$(wildcard include/config/epoll.h) \
|
||||
$(wildcard include/config/auditsyscall.h) \
|
||||
include/linux/limits.h \
|
||||
include/linux/kdev_t.h \
|
||||
include/linux/ioctl.h \
|
||||
include/asm/ioctl.h \
|
||||
include/linux/dcache.h \
|
||||
include/linux/rcupdate.h \
|
||||
include/linux/prio_tree.h \
|
||||
include/linux/radix-tree.h \
|
||||
include/linux/audit.h \
|
||||
$(wildcard include/config/audit.h) \
|
||||
include/linux/quota.h \
|
||||
include/linux/dqblk_xfs.h \
|
||||
include/linux/dqblk_v1.h \
|
||||
include/linux/dqblk_v2.h \
|
||||
include/linux/nfs_fs_i.h \
|
||||
include/linux/nfs.h \
|
||||
include/linux/sunrpc/msg_prot.h \
|
||||
include/linux/fcntl.h \
|
||||
include/asm/fcntl.h \
|
||||
include/linux/err.h \
|
||||
include/linux/serio.h \
|
||||
include/linux/interrupt.h \
|
||||
$(wildcard include/config/generic/hardirqs.h) \
|
||||
$(wildcard include/config/generic/irq/probe.h) \
|
||||
include/linux/hardirq.h \
|
||||
include/linux/smp_lock.h \
|
||||
$(wildcard include/config/lock/kernel.h) \
|
||||
include/asm/hardirq.h \
|
||||
include/linux/irq.h \
|
||||
$(wildcard include/config/arch/s390.h) \
|
||||
include/asm/irq.h \
|
||||
$(wildcard include/config/x86/local/apic.h) \
|
||||
$(wildcard include/config/irqbalance.h) \
|
||||
include/asm-i386/mach-default/irq_vectors.h \
|
||||
include/asm-i386/mach-default/irq_vectors_limits.h \
|
||||
$(wildcard include/config/pci/msi.h) \
|
||||
$(wildcard include/config/x86/io/apic.h) \
|
||||
include/asm/hw_irq.h \
|
||||
include/linux/profile.h \
|
||||
$(wildcard include/config/proc/fs.h) \
|
||||
$(wildcard include/config/profiling.h) \
|
||||
include/asm/sections.h \
|
||||
include/asm-generic/sections.h \
|
||||
include/linux/irq_cpustat.h \
|
||||
include/linux/device.h \
|
||||
include/linux/ioport.h \
|
||||
include/linux/pm.h \
|
||||
$(wildcard include/config/pm.h) \
|
||||
drivers/input/mouse/psmouse.h \
|
||||
drivers/input/mouse/synaptics.h \
|
||||
|
||||
drivers/input/mouse/synaptics.o: $(deps_drivers/input/mouse/synaptics.o)
|
||||
|
||||
$(deps_drivers/input/mouse/synaptics.o):
|
||||
130
extra/linux-2.6.10/drivers/input/mouse/Kconfig
Normal file
130
extra/linux-2.6.10/drivers/input/mouse/Kconfig
Normal file
@@ -0,0 +1,130 @@
|
||||
#
|
||||
# Mouse driver configuration
|
||||
#
|
||||
config INPUT_MOUSE
|
||||
bool "Mice"
|
||||
default y
|
||||
depends on INPUT
|
||||
help
|
||||
Say Y here, and a list of supported mice will be displayed.
|
||||
This option doesn't affect the kernel.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config MOUSE_PS2
|
||||
tristate "PS/2 mouse"
|
||||
default y
|
||||
depends on INPUT && INPUT_MOUSE
|
||||
select SERIO
|
||||
select SERIO_I8042 if PC
|
||||
select SERIO_GSCPS2 if GSC
|
||||
---help---
|
||||
Say Y here if you have a PS/2 mouse connected to your system. This
|
||||
includes the standard 2 or 3-button PS/2 mouse, as well as PS/2
|
||||
mice with wheels and extra buttons, Microsoft, Logitech or Genius
|
||||
compatible.
|
||||
|
||||
Synaptics TouchPad users might be interested in a specialized
|
||||
XFree86 driver at:
|
||||
http://w1.894.telia.com/~u89404340/touchpad/index.html
|
||||
and a new verion of GPM at:
|
||||
http://www.geocities.com/dt_or/gpm/gpm.html
|
||||
to take advantage of the advanced features of the touchpad.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called psmouse.
|
||||
|
||||
config MOUSE_SERIAL
|
||||
tristate "Serial mouse"
|
||||
depends on INPUT && INPUT_MOUSE
|
||||
select SERIO
|
||||
---help---
|
||||
Say Y here if you have a serial (RS-232, COM port) mouse connected
|
||||
to your system. This includes Sun, MouseSystems, Microsoft,
|
||||
Logitech and all other compatible serial mice.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called sermouse.
|
||||
|
||||
config MOUSE_INPORT
|
||||
tristate "InPort/MS/ATIXL busmouse"
|
||||
depends on INPUT && INPUT_MOUSE && ISA
|
||||
help
|
||||
Say Y here if you have an InPort, Microsoft or ATI XL busmouse.
|
||||
They are rather rare these days.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called inport.
|
||||
|
||||
config MOUSE_ATIXL
|
||||
bool "ATI XL variant"
|
||||
depends on MOUSE_INPORT
|
||||
help
|
||||
Say Y here if your mouse is of the ATI XL variety.
|
||||
|
||||
config MOUSE_LOGIBM
|
||||
tristate "Logitech busmouse"
|
||||
depends on INPUT && INPUT_MOUSE && ISA
|
||||
help
|
||||
Say Y here if you have a Logitech busmouse.
|
||||
They are rather rare these days.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called logibm.
|
||||
|
||||
config MOUSE_PC110PAD
|
||||
tristate "IBM PC110 touchpad"
|
||||
depends on INPUT && INPUT_MOUSE && ISA
|
||||
help
|
||||
Say Y if you have the IBM PC-110 micro-notebook and want its
|
||||
touchpad supported.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called pc110pad.
|
||||
|
||||
config MOUSE_MAPLE
|
||||
tristate "Maple bus mouse"
|
||||
depends on SH_DREAMCAST && INPUT && INPUT_MOUSE && MAPLE
|
||||
help
|
||||
Say Y if you have a DreamCast console and a mouse attached to
|
||||
its Maple bus.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called maplemouse.
|
||||
|
||||
config MOUSE_AMIGA
|
||||
tristate "Amiga mouse"
|
||||
depends on AMIGA && INPUT && INPUT_MOUSE
|
||||
help
|
||||
Say Y here if you have an Amiga and want its native mouse
|
||||
supported by the kernel.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called amimouse.
|
||||
|
||||
config MOUSE_RISCPC
|
||||
tristate "Acorn RiscPC mouse"
|
||||
depends on ARCH_ACORN && INPUT && INPUT_MOUSE
|
||||
help
|
||||
Say Y here if you have the Acorn RiscPC computer and want its
|
||||
native mouse supported.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called rpcmouse.
|
||||
|
||||
config MOUSE_VSXXXAA
|
||||
tristate "DEC VSXXX-AA/GA mouse and VSXXX-AB tablet"
|
||||
depends on INPUT && INPUT_MOUSE
|
||||
select SERIO
|
||||
help
|
||||
Say Y (or M) if you want to use a DEC VSXXX-AA (hockey
|
||||
puck) or a VSXXX-GA (rectangular) mouse. Theses mice are
|
||||
typically used on DECstations or VAXstations, but can also
|
||||
be used on any box capable of RS232 (with some adaptor
|
||||
described in the source file). This driver also works with the
|
||||
digitizer (VSXXX-AB) DEC produced.
|
||||
|
||||
17
extra/linux-2.6.10/drivers/input/mouse/Makefile
Normal file
17
extra/linux-2.6.10/drivers/input/mouse/Makefile
Normal file
@@ -0,0 +1,17 @@
|
||||
#
|
||||
# Makefile for the mouse drivers.
|
||||
#
|
||||
|
||||
# Each configuration option enables a list of files.
|
||||
|
||||
obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o
|
||||
obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o
|
||||
obj-$(CONFIG_MOUSE_INPORT) += inport.o
|
||||
obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o
|
||||
obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o
|
||||
obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o
|
||||
obj-$(CONFIG_MOUSE_PS2) += psmouse.o
|
||||
obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o
|
||||
obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o
|
||||
|
||||
psmouse-objs := psmouse-base.o logips2pp.o synaptics.o
|
||||
137
extra/linux-2.6.10/drivers/input/mouse/amimouse.c
Normal file
137
extra/linux-2.6.10/drivers/input/mouse/amimouse.c
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Amiga mouse driver for Linux/m68k
|
||||
*
|
||||
* Copyright (c) 2000-2002 Vojtech Pavlik
|
||||
*
|
||||
* Based on the work of:
|
||||
* Michael Rausch James Banks
|
||||
* Matther Dillon David Giller
|
||||
* Nathan Laredo Linus Torvalds
|
||||
* Johan Myreen Jes Sorensen
|
||||
* Russell King
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/amigahw.h>
|
||||
#include <asm/amigaints.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Amiga mouse driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int amimouse_used = 0;
|
||||
static int amimouse_lastx, amimouse_lasty;
|
||||
static struct input_dev amimouse_dev;
|
||||
|
||||
static char *amimouse_name = "Amiga mouse";
|
||||
static char *amimouse_phys = "amimouse/input0";
|
||||
|
||||
static irqreturn_t amimouse_interrupt(int irq, void *dummy, struct pt_regs *fp)
|
||||
{
|
||||
unsigned short joy0dat, potgor;
|
||||
int nx, ny, dx, dy;
|
||||
|
||||
joy0dat = custom.joy0dat;
|
||||
|
||||
nx = joy0dat & 0xff;
|
||||
ny = joy0dat >> 8;
|
||||
|
||||
dx = nx - amimouse_lastx;
|
||||
dy = ny - amimouse_lasty;
|
||||
|
||||
if (dx < -127) dx = (256 + nx) - amimouse_lastx;
|
||||
if (dx > 127) dx = (nx - 256) - amimouse_lastx;
|
||||
if (dy < -127) dy = (256 + ny) - amimouse_lasty;
|
||||
if (dy > 127) dy = (ny - 256) - amimouse_lasty;
|
||||
|
||||
amimouse_lastx = nx;
|
||||
amimouse_lasty = ny;
|
||||
|
||||
potgor = custom.potgor;
|
||||
|
||||
input_regs(&amimouse_dev, fp);
|
||||
|
||||
input_report_rel(&amimouse_dev, REL_X, dx);
|
||||
input_report_rel(&amimouse_dev, REL_Y, dy);
|
||||
|
||||
input_report_key(&amimouse_dev, BTN_LEFT, ciaa.pra & 0x40);
|
||||
input_report_key(&amimouse_dev, BTN_MIDDLE, potgor & 0x0100);
|
||||
input_report_key(&amimouse_dev, BTN_RIGHT, potgor & 0x0400);
|
||||
|
||||
input_sync(&amimouse_dev);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int amimouse_open(struct input_dev *dev)
|
||||
{
|
||||
unsigned short joy0dat;
|
||||
|
||||
if (amimouse_used++)
|
||||
return 0;
|
||||
|
||||
joy0dat = custom.joy0dat;
|
||||
|
||||
amimouse_lastx = joy0dat & 0xff;
|
||||
amimouse_lasty = joy0dat >> 8;
|
||||
|
||||
if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", amimouse_interrupt)) {
|
||||
amimouse_used--;
|
||||
printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amimouse_close(struct input_dev *dev)
|
||||
{
|
||||
if (!--amimouse_used)
|
||||
free_irq(IRQ_AMIGA_VERTB, amimouse_interrupt);
|
||||
}
|
||||
|
||||
static int __init amimouse_init(void)
|
||||
{
|
||||
if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_MOUSE))
|
||||
return -ENODEV;
|
||||
|
||||
amimouse_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
|
||||
amimouse_dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
|
||||
amimouse_dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
|
||||
amimouse_dev.open = amimouse_open;
|
||||
amimouse_dev.close = amimouse_close;
|
||||
|
||||
amimouse_dev.name = amimouse_name;
|
||||
amimouse_dev.phys = amimouse_phys;
|
||||
amimouse_dev.id.bustype = BUS_AMIGA;
|
||||
amimouse_dev.id.vendor = 0x0001;
|
||||
amimouse_dev.id.product = 0x0002;
|
||||
amimouse_dev.id.version = 0x0100;
|
||||
|
||||
input_register_device(&amimouse_dev);
|
||||
|
||||
printk(KERN_INFO "input: %s at joy0dat\n", amimouse_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit amimouse_exit(void)
|
||||
{
|
||||
input_unregister_device(&amimouse_dev);
|
||||
}
|
||||
|
||||
module_init(amimouse_init);
|
||||
module_exit(amimouse_exit);
|
||||
BIN
extra/linux-2.6.10/drivers/input/mouse/built-in.o
Normal file
BIN
extra/linux-2.6.10/drivers/input/mouse/built-in.o
Normal file
Binary file not shown.
196
extra/linux-2.6.10/drivers/input/mouse/inport.c
Normal file
196
extra/linux-2.6.10/drivers/input/mouse/inport.c
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* $Id: inport.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1999-2001 Vojtech Pavlik
|
||||
*
|
||||
* Based on the work of:
|
||||
* Teemu Rantanen Derrick Cole
|
||||
* Peter Cervasio Christoph Niemann
|
||||
* Philip Blundell Russell King
|
||||
* Bob Harris
|
||||
*/
|
||||
|
||||
/*
|
||||
* Inport (ATI XL and Microsoft) busmouse driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/config.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Inport (ATI XL and Microsoft) busmouse driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define INPORT_BASE 0x23c
|
||||
#define INPORT_EXTENT 4
|
||||
|
||||
#define INPORT_CONTROL_PORT INPORT_BASE + 0
|
||||
#define INPORT_DATA_PORT INPORT_BASE + 1
|
||||
#define INPORT_SIGNATURE_PORT INPORT_BASE + 2
|
||||
|
||||
#define INPORT_REG_BTNS 0x00
|
||||
#define INPORT_REG_X 0x01
|
||||
#define INPORT_REG_Y 0x02
|
||||
#define INPORT_REG_MODE 0x07
|
||||
#define INPORT_RESET 0x80
|
||||
|
||||
#ifdef CONFIG_INPUT_ATIXL
|
||||
#define INPORT_NAME "ATI XL Mouse"
|
||||
#define INPORT_VENDOR 0x0002
|
||||
#define INPORT_SPEED_30HZ 0x01
|
||||
#define INPORT_SPEED_50HZ 0x02
|
||||
#define INPORT_SPEED_100HZ 0x03
|
||||
#define INPORT_SPEED_200HZ 0x04
|
||||
#define INPORT_MODE_BASE INPORT_SPEED_100HZ
|
||||
#define INPORT_MODE_IRQ 0x08
|
||||
#else
|
||||
#define INPORT_NAME "Microsoft InPort Mouse"
|
||||
#define INPORT_VENDOR 0x0001
|
||||
#define INPORT_MODE_BASE 0x10
|
||||
#define INPORT_MODE_IRQ 0x01
|
||||
#endif
|
||||
#define INPORT_MODE_HOLD 0x20
|
||||
|
||||
#define INPORT_IRQ 5
|
||||
|
||||
static int inport_irq = INPORT_IRQ;
|
||||
module_param_named(irq, inport_irq, uint, 0);
|
||||
MODULE_PARM_DESC(irq, "IRQ number (5=default)");
|
||||
|
||||
__obsolete_setup("inport_irq=");
|
||||
|
||||
static int inport_used;
|
||||
|
||||
static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs);
|
||||
|
||||
static int inport_open(struct input_dev *dev)
|
||||
{
|
||||
if (!inport_used++) {
|
||||
if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
|
||||
return -EBUSY;
|
||||
outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
|
||||
outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void inport_close(struct input_dev *dev)
|
||||
{
|
||||
if (!--inport_used) {
|
||||
outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
|
||||
outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
|
||||
free_irq(inport_irq, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static struct input_dev inport_dev = {
|
||||
.evbit = { BIT(EV_KEY) | BIT(EV_REL) },
|
||||
.keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) },
|
||||
.relbit = { BIT(REL_X) | BIT(REL_Y) },
|
||||
.open = inport_open,
|
||||
.close = inport_close,
|
||||
.name = INPORT_NAME,
|
||||
.phys = "isa023c/input0",
|
||||
.id = {
|
||||
.bustype = BUS_ISA,
|
||||
.vendor = INPORT_VENDOR,
|
||||
.product = 0x0001,
|
||||
.version = 0x0100,
|
||||
},
|
||||
};
|
||||
|
||||
static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
unsigned char buttons;
|
||||
|
||||
outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
|
||||
outb(INPORT_MODE_HOLD | INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
|
||||
|
||||
input_regs(&inport_dev, regs);
|
||||
|
||||
outb(INPORT_REG_X, INPORT_CONTROL_PORT);
|
||||
input_report_rel(&inport_dev, REL_X, inb(INPORT_DATA_PORT));
|
||||
|
||||
outb(INPORT_REG_Y, INPORT_CONTROL_PORT);
|
||||
input_report_rel(&inport_dev, REL_Y, inb(INPORT_DATA_PORT));
|
||||
|
||||
outb(INPORT_REG_BTNS, INPORT_CONTROL_PORT);
|
||||
buttons = inb(INPORT_DATA_PORT);
|
||||
|
||||
input_report_key(&inport_dev, BTN_MIDDLE, buttons & 1);
|
||||
input_report_key(&inport_dev, BTN_LEFT, buttons & 2);
|
||||
input_report_key(&inport_dev, BTN_RIGHT, buttons & 4);
|
||||
|
||||
outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
|
||||
outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
|
||||
|
||||
input_sync(&inport_dev);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __init inport_init(void)
|
||||
{
|
||||
unsigned char a,b,c;
|
||||
|
||||
if (!request_region(INPORT_BASE, INPORT_EXTENT, "inport")) {
|
||||
printk(KERN_ERR "inport.c: Can't allocate ports at %#x\n", INPORT_BASE);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
a = inb(INPORT_SIGNATURE_PORT);
|
||||
b = inb(INPORT_SIGNATURE_PORT);
|
||||
c = inb(INPORT_SIGNATURE_PORT);
|
||||
if (( a == b ) || ( a != c )) {
|
||||
release_region(INPORT_BASE, INPORT_EXTENT);
|
||||
printk(KERN_ERR "inport.c: Didn't find InPort mouse at %#x\n", INPORT_BASE);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
outb(INPORT_RESET, INPORT_CONTROL_PORT);
|
||||
outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
|
||||
outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
|
||||
|
||||
input_register_device(&inport_dev);
|
||||
|
||||
printk(KERN_INFO "input: " INPORT_NAME " at %#x irq %d\n", INPORT_BASE, inport_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit inport_exit(void)
|
||||
{
|
||||
input_unregister_device(&inport_dev);
|
||||
release_region(INPORT_BASE, INPORT_EXTENT);
|
||||
}
|
||||
|
||||
module_init(inport_init);
|
||||
module_exit(inport_exit);
|
||||
183
extra/linux-2.6.10/drivers/input/mouse/logibm.c
Normal file
183
extra/linux-2.6.10/drivers/input/mouse/logibm.c
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* $Id: logibm.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1999-2001 Vojtech Pavlik
|
||||
*
|
||||
* Based on the work of:
|
||||
* James Banks Matthew Dillon
|
||||
* David Giller Nathan Laredo
|
||||
* Linus Torvalds Johan Myreen
|
||||
* Cliff Matthews Philip Blundell
|
||||
* Russell King
|
||||
*/
|
||||
|
||||
/*
|
||||
* Logitech Bus Mouse Driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Logitech busmouse driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define LOGIBM_BASE 0x23c
|
||||
#define LOGIBM_EXTENT 4
|
||||
|
||||
#define LOGIBM_DATA_PORT LOGIBM_BASE + 0
|
||||
#define LOGIBM_SIGNATURE_PORT LOGIBM_BASE + 1
|
||||
#define LOGIBM_CONTROL_PORT LOGIBM_BASE + 2
|
||||
#define LOGIBM_CONFIG_PORT LOGIBM_BASE + 3
|
||||
|
||||
#define LOGIBM_ENABLE_IRQ 0x00
|
||||
#define LOGIBM_DISABLE_IRQ 0x10
|
||||
#define LOGIBM_READ_X_LOW 0x80
|
||||
#define LOGIBM_READ_X_HIGH 0xa0
|
||||
#define LOGIBM_READ_Y_LOW 0xc0
|
||||
#define LOGIBM_READ_Y_HIGH 0xe0
|
||||
|
||||
#define LOGIBM_DEFAULT_MODE 0x90
|
||||
#define LOGIBM_CONFIG_BYTE 0x91
|
||||
#define LOGIBM_SIGNATURE_BYTE 0xa5
|
||||
|
||||
#define LOGIBM_IRQ 5
|
||||
|
||||
static int logibm_irq = LOGIBM_IRQ;
|
||||
module_param_named(irq, logibm_irq, uint, 0);
|
||||
MODULE_PARM_DESC(irq, "IRQ number (5=default)");
|
||||
|
||||
__obsolete_setup("logibm_irq=");
|
||||
|
||||
static int logibm_used = 0;
|
||||
|
||||
static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs);
|
||||
|
||||
static int logibm_open(struct input_dev *dev)
|
||||
{
|
||||
if (logibm_used++)
|
||||
return 0;
|
||||
if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) {
|
||||
logibm_used--;
|
||||
printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq);
|
||||
return -EBUSY;
|
||||
}
|
||||
outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void logibm_close(struct input_dev *dev)
|
||||
{
|
||||
if (--logibm_used)
|
||||
return;
|
||||
outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
|
||||
free_irq(logibm_irq, NULL);
|
||||
}
|
||||
|
||||
static struct input_dev logibm_dev = {
|
||||
.evbit = { BIT(EV_KEY) | BIT(EV_REL) },
|
||||
.keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) },
|
||||
.relbit = { BIT(REL_X) | BIT(REL_Y) },
|
||||
.open = logibm_open,
|
||||
.close = logibm_close,
|
||||
.name = "Logitech bus mouse",
|
||||
.phys = "isa023c/input0",
|
||||
.id = {
|
||||
.bustype = BUS_ISA,
|
||||
.vendor = 0x0003,
|
||||
.product = 0x0001,
|
||||
.version = 0x0100,
|
||||
},
|
||||
};
|
||||
|
||||
static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
char dx, dy;
|
||||
unsigned char buttons;
|
||||
|
||||
outb(LOGIBM_READ_X_LOW, LOGIBM_CONTROL_PORT);
|
||||
dx = (inb(LOGIBM_DATA_PORT) & 0xf);
|
||||
outb(LOGIBM_READ_X_HIGH, LOGIBM_CONTROL_PORT);
|
||||
dx |= (inb(LOGIBM_DATA_PORT) & 0xf) << 4;
|
||||
outb(LOGIBM_READ_Y_LOW, LOGIBM_CONTROL_PORT);
|
||||
dy = (inb(LOGIBM_DATA_PORT) & 0xf);
|
||||
outb(LOGIBM_READ_Y_HIGH, LOGIBM_CONTROL_PORT);
|
||||
buttons = inb(LOGIBM_DATA_PORT);
|
||||
dy |= (buttons & 0xf) << 4;
|
||||
buttons = ~buttons >> 5;
|
||||
|
||||
input_regs(&logibm_dev, regs);
|
||||
input_report_rel(&logibm_dev, REL_X, dx);
|
||||
input_report_rel(&logibm_dev, REL_Y, dy);
|
||||
input_report_key(&logibm_dev, BTN_RIGHT, buttons & 1);
|
||||
input_report_key(&logibm_dev, BTN_MIDDLE, buttons & 2);
|
||||
input_report_key(&logibm_dev, BTN_LEFT, buttons & 4);
|
||||
input_sync(&logibm_dev);
|
||||
|
||||
outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __init logibm_init(void)
|
||||
{
|
||||
if (!request_region(LOGIBM_BASE, LOGIBM_EXTENT, "logibm")) {
|
||||
printk(KERN_ERR "logibm.c: Can't allocate ports at %#x\n", LOGIBM_BASE);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
outb(LOGIBM_CONFIG_BYTE, LOGIBM_CONFIG_PORT);
|
||||
outb(LOGIBM_SIGNATURE_BYTE, LOGIBM_SIGNATURE_PORT);
|
||||
udelay(100);
|
||||
|
||||
if (inb(LOGIBM_SIGNATURE_PORT) != LOGIBM_SIGNATURE_BYTE) {
|
||||
release_region(LOGIBM_BASE, LOGIBM_EXTENT);
|
||||
printk(KERN_ERR "logibm.c: Didn't find Logitech busmouse at %#x\n", LOGIBM_BASE);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
outb(LOGIBM_DEFAULT_MODE, LOGIBM_CONFIG_PORT);
|
||||
outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
|
||||
|
||||
input_register_device(&logibm_dev);
|
||||
|
||||
printk(KERN_INFO "input: Logitech bus mouse at %#x irq %d\n", LOGIBM_BASE, logibm_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit logibm_exit(void)
|
||||
{
|
||||
input_unregister_device(&logibm_dev);
|
||||
release_region(LOGIBM_BASE, LOGIBM_EXTENT);
|
||||
}
|
||||
|
||||
module_init(logibm_init);
|
||||
module_exit(logibm_exit);
|
||||
310
extra/linux-2.6.10/drivers/input/mouse/logips2pp.c
Normal file
310
extra/linux-2.6.10/drivers/input/mouse/logips2pp.c
Normal file
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Logitech PS/2++ mouse driver
|
||||
*
|
||||
* Copyright (c) 1999-2003 Vojtech Pavlik <vojtech@suse.cz>
|
||||
* Copyright (c) 2003 Eric Wong <eric@yhbt.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/serio.h>
|
||||
#include "psmouse.h"
|
||||
#include "logips2pp.h"
|
||||
|
||||
/* Logitech mouse types */
|
||||
#define PS2PP_KIND_WHEEL 1
|
||||
#define PS2PP_KIND_MX 2
|
||||
#define PS2PP_KIND_TP3 3
|
||||
|
||||
/* Logitech mouse features */
|
||||
#define PS2PP_WHEEL 0x01
|
||||
#define PS2PP_HWHEEL 0x02
|
||||
#define PS2PP_SIDE_BTN 0x04
|
||||
#define PS2PP_EXTRA_BTN 0x08
|
||||
#define PS2PP_TASK_BTN 0x10
|
||||
#define PS2PP_NAV_BTN 0x20
|
||||
|
||||
struct ps2pp_info {
|
||||
const int model;
|
||||
unsigned const int kind;
|
||||
unsigned const int features;
|
||||
};
|
||||
|
||||
/*
|
||||
* Process a PS2++ or PS2T++ packet.
|
||||
*/
|
||||
|
||||
void ps2pp_process_packet(struct psmouse *psmouse)
|
||||
{
|
||||
struct input_dev *dev = &psmouse->dev;
|
||||
unsigned char *packet = psmouse->packet;
|
||||
|
||||
if ((packet[0] & 0x48) == 0x48 && (packet[1] & 0x02) == 0x02) {
|
||||
|
||||
switch ((packet[1] >> 4) | (packet[0] & 0x30)) {
|
||||
|
||||
case 0x0d: /* Mouse extra info */
|
||||
|
||||
input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL,
|
||||
(int) (packet[2] & 8) - (int) (packet[2] & 7));
|
||||
input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1);
|
||||
input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1);
|
||||
|
||||
break;
|
||||
|
||||
case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */
|
||||
|
||||
input_report_key(dev, BTN_SIDE, (packet[2]) & 1);
|
||||
input_report_key(dev, BTN_EXTRA, (packet[2] >> 1) & 1);
|
||||
input_report_key(dev, BTN_BACK, (packet[2] >> 3) & 1);
|
||||
input_report_key(dev, BTN_FORWARD, (packet[2] >> 4) & 1);
|
||||
input_report_key(dev, BTN_TASK, (packet[2] >> 2) & 1);
|
||||
|
||||
break;
|
||||
|
||||
case 0x0f: /* TouchPad extra info */
|
||||
|
||||
input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL,
|
||||
(int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7));
|
||||
packet[0] = packet[2] | 0x08;
|
||||
break;
|
||||
|
||||
#ifdef DEBUG
|
||||
default:
|
||||
printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n",
|
||||
(packet[1] >> 4) | (packet[0] & 0x30));
|
||||
#endif
|
||||
}
|
||||
|
||||
packet[0] &= 0x0f;
|
||||
packet[1] = 0;
|
||||
packet[2] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ps2pp_cmd() sends a PS2++ command, sliced into two bit
|
||||
* pieces through the SETRES command. This is needed to send extended
|
||||
* commands to mice on notebooks that try to understand the PS/2 protocol
|
||||
* Ugly.
|
||||
*/
|
||||
|
||||
static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command)
|
||||
{
|
||||
if (psmouse_sliced_command(psmouse, command))
|
||||
return -1;
|
||||
|
||||
if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* SmartScroll / CruiseControl for some newer Logitech mice Defaults to
|
||||
* enabled if we do nothing to it. Of course I put this in because I want it
|
||||
* disabled :P
|
||||
* 1 - enabled (if previously disabled, also default)
|
||||
* 0/2 - disabled
|
||||
*/
|
||||
|
||||
static void ps2pp_set_smartscroll(struct psmouse *psmouse)
|
||||
{
|
||||
unsigned char param[4];
|
||||
|
||||
ps2pp_cmd(psmouse, param, 0x32);
|
||||
|
||||
param[0] = 0;
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
|
||||
|
||||
if (psmouse_smartscroll < 2) {
|
||||
/* 0 - disabled, 1 - enabled */
|
||||
param[0] = psmouse_smartscroll;
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Support 800 dpi resolution _only_ if the user wants it (there are good
|
||||
* reasons to not use it even if the mouse supports it, and of course there are
|
||||
* also good reasons to use it, let the user decide).
|
||||
*/
|
||||
|
||||
void ps2pp_set_800dpi(struct psmouse *psmouse)
|
||||
{
|
||||
unsigned char param = 3;
|
||||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
|
||||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
|
||||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
|
||||
psmouse_command(psmouse, ¶m, PSMOUSE_CMD_SETRES);
|
||||
}
|
||||
|
||||
static struct ps2pp_info *get_model_info(unsigned char model)
|
||||
{
|
||||
static struct ps2pp_info ps2pp_list[] = {
|
||||
{ 12, 0, PS2PP_SIDE_BTN},
|
||||
{ 13, 0, 0 },
|
||||
{ 40, 0, PS2PP_SIDE_BTN },
|
||||
{ 41, 0, PS2PP_SIDE_BTN },
|
||||
{ 42, 0, PS2PP_SIDE_BTN },
|
||||
{ 43, 0, PS2PP_SIDE_BTN },
|
||||
{ 50, 0, 0 },
|
||||
{ 51, 0, 0 },
|
||||
{ 52, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL },
|
||||
{ 53, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
|
||||
{ 61, PS2PP_KIND_MX,
|
||||
PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
|
||||
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, /* MX700 */
|
||||
{ 73, 0, PS2PP_SIDE_BTN },
|
||||
{ 75, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
|
||||
{ 76, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
|
||||
{ 80, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL },
|
||||
{ 81, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
|
||||
{ 83, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
|
||||
{ 88, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
|
||||
{ 96, 0, 0 },
|
||||
{ 97, PS2PP_KIND_TP3, PS2PP_WHEEL | PS2PP_HWHEEL },
|
||||
{ 100, PS2PP_KIND_MX,
|
||||
PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
|
||||
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, /* MX510 */
|
||||
{ 112, PS2PP_KIND_MX,
|
||||
PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
|
||||
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, /* MX500 */
|
||||
{ 114, PS2PP_KIND_MX,
|
||||
PS2PP_WHEEL | PS2PP_SIDE_BTN |
|
||||
PS2PP_TASK_BTN | PS2PP_EXTRA_BTN }, /* M310 */
|
||||
{ }
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; ps2pp_list[i].model; i++)
|
||||
if (model == ps2pp_list[i].model)
|
||||
return &ps2pp_list[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up input device's properties based on the detected mouse model.
|
||||
*/
|
||||
|
||||
static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_info *model_info)
|
||||
{
|
||||
if (model_info->features & PS2PP_SIDE_BTN)
|
||||
set_bit(BTN_SIDE, psmouse->dev.keybit);
|
||||
|
||||
if (model_info->features & PS2PP_EXTRA_BTN)
|
||||
set_bit(BTN_EXTRA, psmouse->dev.keybit);
|
||||
|
||||
if (model_info->features & PS2PP_TASK_BTN)
|
||||
set_bit(BTN_TASK, psmouse->dev.keybit);
|
||||
|
||||
if (model_info->features & PS2PP_NAV_BTN) {
|
||||
set_bit(BTN_FORWARD, psmouse->dev.keybit);
|
||||
set_bit(BTN_BACK, psmouse->dev.keybit);
|
||||
}
|
||||
|
||||
if (model_info->features & PS2PP_WHEEL)
|
||||
set_bit(REL_WHEEL, psmouse->dev.relbit);
|
||||
|
||||
if (model_info->features & PS2PP_HWHEEL)
|
||||
set_bit(REL_HWHEEL, psmouse->dev.relbit);
|
||||
|
||||
switch (model_info->kind) {
|
||||
case PS2PP_KIND_WHEEL:
|
||||
psmouse->name = "Wheel Mouse";
|
||||
break;
|
||||
|
||||
case PS2PP_KIND_MX:
|
||||
psmouse->name = "MX Mouse";
|
||||
break;
|
||||
|
||||
case PS2PP_KIND_TP3:
|
||||
psmouse->name = "TouchPad 3";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Logitech magic init. Detect whether the mouse is a Logitech one
|
||||
* and its exact model and try turning on extended protocol for ones
|
||||
* that support it.
|
||||
*/
|
||||
|
||||
int ps2pp_init(struct psmouse *psmouse, int set_properties)
|
||||
{
|
||||
unsigned char param[4];
|
||||
unsigned char protocol = PSMOUSE_PS2;
|
||||
unsigned char model, buttons;
|
||||
struct ps2pp_info *model_info;
|
||||
|
||||
param[0] = 0;
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
|
||||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
|
||||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
|
||||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
|
||||
param[1] = 0;
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
|
||||
|
||||
if (param[1] != 0) {
|
||||
model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
|
||||
buttons = param[1];
|
||||
model_info = get_model_info(model);
|
||||
|
||||
/*
|
||||
* Do Logitech PS2++ / PS2T++ magic init.
|
||||
*/
|
||||
if (model == 97) { /* Touch Pad 3 */
|
||||
|
||||
/* Unprotect RAM */
|
||||
param[0] = 0x11; param[1] = 0x04; param[2] = 0x68;
|
||||
psmouse_command(psmouse, param, 0x30d1);
|
||||
/* Enable features */
|
||||
param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b;
|
||||
psmouse_command(psmouse, param, 0x30d1);
|
||||
/* Enable PS2++ */
|
||||
param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3;
|
||||
psmouse_command(psmouse, param, 0x30d1);
|
||||
|
||||
param[0] = 0;
|
||||
if (!psmouse_command(psmouse, param, 0x13d1) &&
|
||||
param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) {
|
||||
protocol = PSMOUSE_PS2TPP;
|
||||
}
|
||||
|
||||
} else if (model_info != NULL) {
|
||||
|
||||
param[0] = param[1] = param[2] = 0;
|
||||
ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */
|
||||
ps2pp_cmd(psmouse, param, 0xDB);
|
||||
|
||||
if ((param[0] & 0x78) == 0x48 &&
|
||||
(param[1] & 0xf3) == 0xc2 &&
|
||||
(param[2] & 0x03) == ((param[1] >> 2) & 3)) {
|
||||
ps2pp_set_smartscroll(psmouse);
|
||||
protocol = PSMOUSE_PS2PP;
|
||||
}
|
||||
}
|
||||
|
||||
if (set_properties) {
|
||||
psmouse->vendor = "Logitech";
|
||||
psmouse->model = model;
|
||||
|
||||
if (buttons < 3)
|
||||
clear_bit(BTN_MIDDLE, psmouse->dev.keybit);
|
||||
if (buttons < 2)
|
||||
clear_bit(BTN_RIGHT, psmouse->dev.keybit);
|
||||
|
||||
if (model_info)
|
||||
ps2pp_set_model_properties(psmouse, model_info);
|
||||
}
|
||||
}
|
||||
|
||||
return protocol;
|
||||
}
|
||||
|
||||
18
extra/linux-2.6.10/drivers/input/mouse/logips2pp.h
Normal file
18
extra/linux-2.6.10/drivers/input/mouse/logips2pp.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Logitech PS/2++ mouse driver header
|
||||
*
|
||||
* Copyright (c) 2003 Vojtech Pavlik <vojtech@suse.cz>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _LOGIPS2PP_H
|
||||
#define _LOGIPS2PP_H
|
||||
|
||||
void ps2pp_process_packet(struct psmouse *psmouse);
|
||||
void ps2pp_set_800dpi(struct psmouse *psmouse);
|
||||
int ps2pp_init(struct psmouse *psmouse, int set_properties);
|
||||
|
||||
#endif
|
||||
BIN
extra/linux-2.6.10/drivers/input/mouse/logips2pp.o
Normal file
BIN
extra/linux-2.6.10/drivers/input/mouse/logips2pp.o
Normal file
Binary file not shown.
134
extra/linux-2.6.10/drivers/input/mouse/maplemouse.c
Normal file
134
extra/linux-2.6.10/drivers/input/mouse/maplemouse.c
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* $Id: maplemouse.c,v 1.2 2004/03/22 01:18:15 lethal Exp $
|
||||
* SEGA Dreamcast mouse driver
|
||||
* Based on drivers/usb/usbmouse.c
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/maple.h>
|
||||
|
||||
MODULE_AUTHOR("YAEGASHI Takeshi <t@keshi.org>");
|
||||
MODULE_DESCRIPTION("SEGA Dreamcast mouse driver");
|
||||
|
||||
struct dc_mouse {
|
||||
struct input_dev dev;
|
||||
int open;
|
||||
};
|
||||
|
||||
|
||||
static void dc_mouse_callback(struct mapleq *mq)
|
||||
{
|
||||
int buttons, relx, rely, relz;
|
||||
struct maple_device *mapledev = mq->dev;
|
||||
struct dc_mouse *mouse = mapledev->private_data;
|
||||
struct input_dev *dev = &mouse->dev;
|
||||
unsigned char *res = mq->recvbuf;
|
||||
|
||||
buttons = ~res[8];
|
||||
relx=*(unsigned short *)(res+12)-512;
|
||||
rely=*(unsigned short *)(res+14)-512;
|
||||
relz=*(unsigned short *)(res+16)-512;
|
||||
|
||||
input_report_key(dev, BTN_LEFT, buttons&4);
|
||||
input_report_key(dev, BTN_MIDDLE, buttons&9);
|
||||
input_report_key(dev, BTN_RIGHT, buttons&2);
|
||||
input_report_rel(dev, REL_X, relx);
|
||||
input_report_rel(dev, REL_Y, rely);
|
||||
input_report_rel(dev, REL_WHEEL, relz);
|
||||
input_sync(dev);
|
||||
}
|
||||
|
||||
|
||||
static int dc_mouse_open(struct input_dev *dev)
|
||||
{
|
||||
struct dc_mouse *mouse = dev->private;
|
||||
mouse->open++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void dc_mouse_close(struct input_dev *dev)
|
||||
{
|
||||
struct dc_mouse *mouse = dev->private;
|
||||
mouse->open--;
|
||||
}
|
||||
|
||||
|
||||
static int dc_mouse_connect(struct maple_device *dev)
|
||||
{
|
||||
unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]);
|
||||
struct dc_mouse *mouse;
|
||||
|
||||
if (!(mouse = kmalloc(sizeof(struct dc_mouse), GFP_KERNEL)))
|
||||
return -1;
|
||||
memset(mouse, 0, sizeof(struct dc_mouse));
|
||||
|
||||
dev->private_data = mouse;
|
||||
|
||||
mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
|
||||
mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
|
||||
mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
|
||||
|
||||
init_input_dev(&mouse->dev);
|
||||
|
||||
mouse->dev.private = mouse;
|
||||
mouse->dev.open = dc_mouse_open;
|
||||
mouse->dev.close = dc_mouse_close;
|
||||
mouse->dev.event = NULL;
|
||||
|
||||
mouse->dev.name = dev->product_name;
|
||||
mouse->dev.id.bustype = BUS_MAPLE;
|
||||
|
||||
input_register_device(&mouse->dev);
|
||||
|
||||
maple_getcond_callback(dev, dc_mouse_callback, 1, MAPLE_FUNC_MOUSE);
|
||||
|
||||
printk(KERN_INFO "input: mouse(0x%lx): %s\n", data, mouse->dev.name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void dc_mouse_disconnect(struct maple_device *dev)
|
||||
{
|
||||
struct dc_mouse *mouse = dev->private_data;
|
||||
|
||||
input_unregister_device(&mouse->dev);
|
||||
kfree(mouse);
|
||||
}
|
||||
|
||||
|
||||
static struct maple_driver dc_mouse_driver = {
|
||||
.function = MAPLE_FUNC_MOUSE,
|
||||
.name = "Dreamcast mouse",
|
||||
.connect = dc_mouse_connect,
|
||||
.disconnect = dc_mouse_disconnect,
|
||||
};
|
||||
|
||||
|
||||
static int __init dc_mouse_init(void)
|
||||
{
|
||||
maple_register_driver(&dc_mouse_driver);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void __exit dc_mouse_exit(void)
|
||||
{
|
||||
maple_unregister_driver(&dc_mouse_driver);
|
||||
}
|
||||
|
||||
|
||||
module_init(dc_mouse_init);
|
||||
module_exit(dc_mouse_exit);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
* End:
|
||||
*/
|
||||
178
extra/linux-2.6.10/drivers/input/mouse/pc110pad.c
Normal file
178
extra/linux-2.6.10/drivers/input/mouse/pc110pad.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* $Id: pc110pad.c,v 1.12 2001/09/25 10:12:07 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 2000-2001 Vojtech Pavlik
|
||||
*
|
||||
* Based on the work of:
|
||||
* Alan Cox Robin O'Leary
|
||||
*/
|
||||
|
||||
/*
|
||||
* IBM PC110 touchpad driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("IBM PC110 touchpad driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define PC110PAD_OFF 0x30
|
||||
#define PC110PAD_ON 0x38
|
||||
|
||||
static int pc110pad_irq = 10;
|
||||
static int pc110pad_io = 0x15e0;
|
||||
|
||||
static struct input_dev pc110pad_dev;
|
||||
static int pc110pad_data[3];
|
||||
static int pc110pad_count;
|
||||
static int pc110pad_used;
|
||||
|
||||
static char *pc110pad_name = "IBM PC110 TouchPad";
|
||||
static char *pc110pad_phys = "isa15e0/input0";
|
||||
|
||||
static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs)
|
||||
{
|
||||
int value = inb_p(pc110pad_io);
|
||||
int handshake = inb_p(pc110pad_io + 2);
|
||||
|
||||
outb_p(handshake | 1, pc110pad_io + 2);
|
||||
outb_p(handshake & ~1, pc110pad_io + 2);
|
||||
inb_p(0x64);
|
||||
|
||||
pc110pad_data[pc110pad_count++] = value;
|
||||
|
||||
if (pc110pad_count < 3)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
input_regs(&pc110pad_dev, regs);
|
||||
input_report_key(&pc110pad_dev, BTN_TOUCH,
|
||||
pc110pad_data[0] & 0x01);
|
||||
input_report_abs(&pc110pad_dev, ABS_X,
|
||||
pc110pad_data[1] | ((pc110pad_data[0] << 3) & 0x80) | ((pc110pad_data[0] << 1) & 0x100));
|
||||
input_report_abs(&pc110pad_dev, ABS_Y,
|
||||
pc110pad_data[2] | ((pc110pad_data[0] << 4) & 0x80));
|
||||
input_sync(&pc110pad_dev);
|
||||
|
||||
pc110pad_count = 0;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void pc110pad_close(struct input_dev *dev)
|
||||
{
|
||||
if (!--pc110pad_used)
|
||||
outb(PC110PAD_OFF, pc110pad_io + 2);
|
||||
}
|
||||
|
||||
static int pc110pad_open(struct input_dev *dev)
|
||||
{
|
||||
if (pc110pad_used++)
|
||||
return 0;
|
||||
|
||||
pc110pad_interrupt(0,NULL,NULL);
|
||||
pc110pad_interrupt(0,NULL,NULL);
|
||||
pc110pad_interrupt(0,NULL,NULL);
|
||||
outb(PC110PAD_ON, pc110pad_io + 2);
|
||||
pc110pad_count = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We try to avoid enabling the hardware if it's not
|
||||
* there, but we don't know how to test. But we do know
|
||||
* that the PC110 is not a PCI system. So if we find any
|
||||
* PCI devices in the machine, we don't have a PC110.
|
||||
*/
|
||||
static int __init pc110pad_init(void)
|
||||
{
|
||||
struct pci_dev *dev;
|
||||
|
||||
dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL);
|
||||
if (dev) {
|
||||
pci_dev_put(dev);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!request_region(pc110pad_io, 4, "pc110pad")) {
|
||||
printk(KERN_ERR "pc110pad: I/O area %#x-%#x in use.\n",
|
||||
pc110pad_io, pc110pad_io + 4);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
outb(PC110PAD_OFF, pc110pad_io + 2);
|
||||
|
||||
if (request_irq(pc110pad_irq, pc110pad_interrupt, 0, "pc110pad", NULL))
|
||||
{
|
||||
release_region(pc110pad_io, 4);
|
||||
printk(KERN_ERR "pc110pad: Unable to get irq %d.\n", pc110pad_irq);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
pc110pad_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
|
||||
pc110pad_dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
|
||||
pc110pad_dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
|
||||
|
||||
pc110pad_dev.absmax[ABS_X] = 0x1ff;
|
||||
pc110pad_dev.absmax[ABS_Y] = 0x0ff;
|
||||
|
||||
pc110pad_dev.open = pc110pad_open;
|
||||
pc110pad_dev.close = pc110pad_close;
|
||||
|
||||
pc110pad_dev.name = pc110pad_name;
|
||||
pc110pad_dev.phys = pc110pad_phys;
|
||||
pc110pad_dev.id.bustype = BUS_ISA;
|
||||
pc110pad_dev.id.vendor = 0x0003;
|
||||
pc110pad_dev.id.product = 0x0001;
|
||||
pc110pad_dev.id.version = 0x0100;
|
||||
|
||||
input_register_device(&pc110pad_dev);
|
||||
|
||||
printk(KERN_INFO "input: %s at %#x irq %d\n",
|
||||
pc110pad_name, pc110pad_io, pc110pad_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit pc110pad_exit(void)
|
||||
{
|
||||
input_unregister_device(&pc110pad_dev);
|
||||
|
||||
outb(PC110PAD_OFF, pc110pad_io + 2);
|
||||
|
||||
free_irq(pc110pad_irq, NULL);
|
||||
release_region(pc110pad_io, 4);
|
||||
}
|
||||
|
||||
module_init(pc110pad_init);
|
||||
module_exit(pc110pad_exit);
|
||||
916
extra/linux-2.6.10/drivers/input/mouse/psmouse-base.c
Normal file
916
extra/linux-2.6.10/drivers/input/mouse/psmouse-base.c
Normal file
@@ -0,0 +1,916 @@
|
||||
/*
|
||||
* PS/2 mouse driver
|
||||
*
|
||||
* Copyright (c) 1999-2002 Vojtech Pavlik
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/serio.h>
|
||||
#include <linux/init.h>
|
||||
#include "psmouse.h"
|
||||
#include "synaptics.h"
|
||||
#include "logips2pp.h"
|
||||
|
||||
#define DRIVER_DESC "PS/2 mouse driver"
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static char *psmouse_proto;
|
||||
static unsigned int psmouse_max_proto = -1U;
|
||||
module_param_named(proto, psmouse_proto, charp, 0);
|
||||
MODULE_PARM_DESC(proto, "Highest protocol extension to probe (bare, imps, exps). Useful for KVM switches.");
|
||||
|
||||
int psmouse_resolution = 200;
|
||||
module_param_named(resolution, psmouse_resolution, uint, 0);
|
||||
MODULE_PARM_DESC(resolution, "Resolution, in dpi.");
|
||||
|
||||
unsigned int psmouse_rate = 100;
|
||||
module_param_named(rate, psmouse_rate, uint, 0);
|
||||
MODULE_PARM_DESC(rate, "Report rate, in reports per second.");
|
||||
|
||||
int psmouse_smartscroll = 1;
|
||||
module_param_named(smartscroll, psmouse_smartscroll, bool, 0);
|
||||
MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
|
||||
|
||||
static unsigned int psmouse_resetafter;
|
||||
module_param_named(resetafter, psmouse_resetafter, uint, 0);
|
||||
MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
|
||||
|
||||
__obsolete_setup("psmouse_noext");
|
||||
__obsolete_setup("psmouse_resolution=");
|
||||
__obsolete_setup("psmouse_smartscroll=");
|
||||
__obsolete_setup("psmouse_resetafter=");
|
||||
__obsolete_setup("psmouse_rate=");
|
||||
|
||||
static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2"};
|
||||
|
||||
/*
|
||||
* psmouse_process_byte() analyzes the PS/2 data stream and reports
|
||||
* relevant events to the input module once full packet has arrived.
|
||||
*/
|
||||
|
||||
static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
|
||||
{
|
||||
struct input_dev *dev = &psmouse->dev;
|
||||
unsigned char *packet = psmouse->packet;
|
||||
|
||||
if (psmouse->pktcnt < 3 + (psmouse->type >= PSMOUSE_GENPS))
|
||||
return PSMOUSE_GOOD_DATA;
|
||||
|
||||
/*
|
||||
* Full packet accumulated, process it
|
||||
*/
|
||||
|
||||
input_regs(dev, regs);
|
||||
|
||||
/*
|
||||
* The PS2++ protocol is a little bit complex
|
||||
*/
|
||||
|
||||
if (psmouse->type == PSMOUSE_PS2PP || psmouse->type == PSMOUSE_PS2TPP)
|
||||
ps2pp_process_packet(psmouse);
|
||||
|
||||
/*
|
||||
* Scroll wheel on IntelliMice, scroll buttons on NetMice
|
||||
*/
|
||||
|
||||
if (psmouse->type == PSMOUSE_IMPS || psmouse->type == PSMOUSE_GENPS)
|
||||
input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]);
|
||||
|
||||
/*
|
||||
* Scroll wheel and buttons on IntelliMouse Explorer
|
||||
*/
|
||||
|
||||
if (psmouse->type == PSMOUSE_IMEX) {
|
||||
input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7));
|
||||
input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1);
|
||||
input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extra buttons on Genius NewNet 3D
|
||||
*/
|
||||
|
||||
if (psmouse->type == PSMOUSE_GENPS) {
|
||||
input_report_key(dev, BTN_SIDE, (packet[0] >> 6) & 1);
|
||||
input_report_key(dev, BTN_EXTRA, (packet[0] >> 7) & 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic PS/2 Mouse
|
||||
*/
|
||||
|
||||
input_report_key(dev, BTN_LEFT, packet[0] & 1);
|
||||
input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
|
||||
input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1);
|
||||
|
||||
input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0);
|
||||
input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0);
|
||||
|
||||
input_sync(dev);
|
||||
|
||||
return PSMOUSE_FULL_PACKET;
|
||||
}
|
||||
|
||||
/*
|
||||
* psmouse_interrupt() handles incoming characters, either gathering them into
|
||||
* packets or passing them to the command routine as command output.
|
||||
*/
|
||||
|
||||
static irqreturn_t psmouse_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags, struct pt_regs *regs)
|
||||
{
|
||||
struct psmouse *psmouse = serio->private;
|
||||
psmouse_ret_t rc;
|
||||
|
||||
if (psmouse->state == PSMOUSE_IGNORE)
|
||||
goto out;
|
||||
|
||||
if (flags & (SERIO_PARITY|SERIO_TIMEOUT)) {
|
||||
if (psmouse->state == PSMOUSE_ACTIVATED)
|
||||
printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n",
|
||||
flags & SERIO_TIMEOUT ? " timeout" : "",
|
||||
flags & SERIO_PARITY ? " bad parity" : "");
|
||||
psmouse->nak = 1;
|
||||
clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
|
||||
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
|
||||
wake_up_interruptible(&psmouse->wait);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags)) {
|
||||
switch (data) {
|
||||
case PSMOUSE_RET_ACK:
|
||||
psmouse->nak = 0;
|
||||
break;
|
||||
|
||||
case PSMOUSE_RET_NAK:
|
||||
psmouse->nak = 1;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Workaround for mice which don't ACK the Get ID command.
|
||||
* These are valid mouse IDs that we recognize.
|
||||
*/
|
||||
case 0x00:
|
||||
case 0x03:
|
||||
case 0x04:
|
||||
if (test_bit(PSMOUSE_FLAG_WAITID, &psmouse->flags)) {
|
||||
psmouse->nak = 0;
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!psmouse->nak && psmouse->cmdcnt) {
|
||||
set_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
|
||||
set_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags);
|
||||
}
|
||||
clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
|
||||
wake_up_interruptible(&psmouse->wait);
|
||||
|
||||
if (data == PSMOUSE_RET_ACK || data == PSMOUSE_RET_NAK)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags)) {
|
||||
if (psmouse->cmdcnt)
|
||||
psmouse->cmdbuf[--psmouse->cmdcnt] = data;
|
||||
|
||||
if (test_and_clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags) && psmouse->cmdcnt)
|
||||
wake_up_interruptible(&psmouse->wait);
|
||||
|
||||
if (!psmouse->cmdcnt) {
|
||||
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
|
||||
wake_up_interruptible(&psmouse->wait);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (psmouse->state == PSMOUSE_INITIALIZING)
|
||||
goto out;
|
||||
|
||||
if (psmouse->state == PSMOUSE_ACTIVATED &&
|
||||
psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) {
|
||||
printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n",
|
||||
psmouse->name, psmouse->phys, psmouse->pktcnt);
|
||||
psmouse->pktcnt = 0;
|
||||
}
|
||||
|
||||
psmouse->last = jiffies;
|
||||
psmouse->packet[psmouse->pktcnt++] = data;
|
||||
|
||||
if (psmouse->packet[0] == PSMOUSE_RET_BAT) {
|
||||
if (psmouse->pktcnt == 1)
|
||||
goto out;
|
||||
|
||||
if (psmouse->pktcnt == 2) {
|
||||
if (psmouse->packet[1] == PSMOUSE_RET_ID) {
|
||||
psmouse->state = PSMOUSE_IGNORE;
|
||||
serio_reconnect(serio);
|
||||
goto out;
|
||||
}
|
||||
if (psmouse->type == PSMOUSE_SYNAPTICS) {
|
||||
/* neither 0xAA nor 0x00 are valid first bytes
|
||||
* for a packet in absolute mode
|
||||
*/
|
||||
psmouse->pktcnt = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rc = psmouse->protocol_handler(psmouse, regs);
|
||||
|
||||
switch (rc) {
|
||||
case PSMOUSE_BAD_DATA:
|
||||
printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n",
|
||||
psmouse->name, psmouse->phys, psmouse->pktcnt);
|
||||
psmouse->pktcnt = 0;
|
||||
|
||||
if (++psmouse->out_of_sync == psmouse_resetafter) {
|
||||
psmouse->state = PSMOUSE_IGNORE;
|
||||
printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
|
||||
serio_reconnect(psmouse->serio);
|
||||
}
|
||||
break;
|
||||
|
||||
case PSMOUSE_FULL_PACKET:
|
||||
psmouse->pktcnt = 0;
|
||||
if (psmouse->out_of_sync) {
|
||||
psmouse->out_of_sync = 0;
|
||||
printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n",
|
||||
psmouse->name, psmouse->phys);
|
||||
}
|
||||
break;
|
||||
|
||||
case PSMOUSE_GOOD_DATA:
|
||||
break;
|
||||
}
|
||||
out:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* psmouse_sendbyte() sends a byte to the mouse, and waits for acknowledge.
|
||||
* It doesn't handle retransmission, though it could - because when there would
|
||||
* be need for retransmissions, the mouse has to be replaced anyway.
|
||||
*
|
||||
* psmouse_sendbyte() can only be called from a process context
|
||||
*/
|
||||
|
||||
static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte)
|
||||
{
|
||||
psmouse->nak = 1;
|
||||
set_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
|
||||
|
||||
if (serio_write(psmouse->serio, byte) == 0)
|
||||
wait_event_interruptible_timeout(psmouse->wait,
|
||||
!test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags),
|
||||
msecs_to_jiffies(200));
|
||||
|
||||
clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
|
||||
return -psmouse->nak;
|
||||
}
|
||||
|
||||
/*
|
||||
* psmouse_command() sends a command and its parameters to the mouse,
|
||||
* then waits for the response and puts it in the param array.
|
||||
*
|
||||
* psmouse_command() can only be called from a process context
|
||||
*/
|
||||
|
||||
int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
|
||||
{
|
||||
int timeout;
|
||||
int send = (command >> 12) & 0xf;
|
||||
int receive = (command >> 8) & 0xf;
|
||||
int rc = -1;
|
||||
int i;
|
||||
|
||||
timeout = msecs_to_jiffies(command == PSMOUSE_CMD_RESET_BAT ? 4000 : 500);
|
||||
|
||||
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
|
||||
if (command == PSMOUSE_CMD_GETID)
|
||||
set_bit(PSMOUSE_FLAG_WAITID, &psmouse->flags);
|
||||
|
||||
if (receive && param)
|
||||
for (i = 0; i < receive; i++)
|
||||
psmouse->cmdbuf[(receive - 1) - i] = param[i];
|
||||
|
||||
psmouse->cmdcnt = receive;
|
||||
|
||||
if (command & 0xff)
|
||||
if (psmouse_sendbyte(psmouse, command & 0xff))
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < send; i++)
|
||||
if (psmouse_sendbyte(psmouse, param[i]))
|
||||
goto out;
|
||||
|
||||
timeout = wait_event_interruptible_timeout(psmouse->wait,
|
||||
!test_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags), timeout);
|
||||
|
||||
if (psmouse->cmdcnt && timeout > 0) {
|
||||
if (command == PSMOUSE_CMD_RESET_BAT && jiffies_to_msecs(timeout) > 100)
|
||||
timeout = msecs_to_jiffies(100);
|
||||
|
||||
if (command == PSMOUSE_CMD_GETID &&
|
||||
psmouse->cmdbuf[receive - 1] != 0xab && psmouse->cmdbuf[receive - 1] != 0xac) {
|
||||
/*
|
||||
* Device behind the port is not a keyboard
|
||||
* so we don't need to wait for the 2nd byte
|
||||
* of ID response.
|
||||
*/
|
||||
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
|
||||
psmouse->cmdcnt = 0;
|
||||
}
|
||||
|
||||
wait_event_interruptible_timeout(psmouse->wait,
|
||||
!test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags), timeout);
|
||||
}
|
||||
|
||||
if (param)
|
||||
for (i = 0; i < receive; i++)
|
||||
param[i] = psmouse->cmdbuf[(receive - 1) - i];
|
||||
|
||||
if (psmouse->cmdcnt && (command != PSMOUSE_CMD_RESET_BAT || psmouse->cmdcnt != 1))
|
||||
goto out;
|
||||
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
|
||||
clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags);
|
||||
clear_bit(PSMOUSE_FLAG_WAITID, &psmouse->flags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* psmouse_sliced_command() sends an extended PS/2 command to the mouse
|
||||
* using sliced syntax, understood by advanced devices, such as Logitech
|
||||
* or Synaptics touchpads. The command is encoded as:
|
||||
* 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu
|
||||
* is the command.
|
||||
*/
|
||||
int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11))
|
||||
return -1;
|
||||
|
||||
for (i = 6; i >= 0; i -= 2) {
|
||||
unsigned char d = (command >> i) & 3;
|
||||
if (psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* psmouse_reset() resets the mouse into power-on state.
|
||||
*/
|
||||
int psmouse_reset(struct psmouse *psmouse)
|
||||
{
|
||||
unsigned char param[2];
|
||||
|
||||
if (psmouse_command(psmouse, param, PSMOUSE_CMD_RESET_BAT))
|
||||
return -1;
|
||||
|
||||
if (param[0] != PSMOUSE_RET_BAT && param[1] != PSMOUSE_RET_ID)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Genius NetMouse magic init.
|
||||
*/
|
||||
static int genius_detect(struct psmouse *psmouse)
|
||||
{
|
||||
unsigned char param[4];
|
||||
|
||||
param[0] = 3;
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
|
||||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
|
||||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
|
||||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
|
||||
|
||||
return param[0] == 0x00 && param[1] == 0x33 && param[2] == 0x55;
|
||||
}
|
||||
|
||||
/*
|
||||
* IntelliMouse magic init.
|
||||
*/
|
||||
static int intellimouse_detect(struct psmouse *psmouse)
|
||||
{
|
||||
unsigned char param[2];
|
||||
|
||||
param[0] = 200;
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
|
||||
param[0] = 100;
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
|
||||
param[0] = 80;
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_GETID);
|
||||
|
||||
return param[0] == 3;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try IntelliMouse/Explorer magic init.
|
||||
*/
|
||||
static int im_explorer_detect(struct psmouse *psmouse)
|
||||
{
|
||||
unsigned char param[2];
|
||||
|
||||
intellimouse_detect(psmouse);
|
||||
|
||||
param[0] = 200;
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
|
||||
param[0] = 200;
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
|
||||
param[0] = 80;
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_GETID);
|
||||
|
||||
return param[0] == 4;
|
||||
}
|
||||
|
||||
/*
|
||||
* psmouse_extensions() probes for any extensions to the basic PS/2 protocol
|
||||
* the mouse may have.
|
||||
*/
|
||||
|
||||
static int psmouse_extensions(struct psmouse *psmouse,
|
||||
unsigned int max_proto, int set_properties)
|
||||
{
|
||||
int synaptics_hardware = 0;
|
||||
|
||||
/*
|
||||
* Try Synaptics TouchPad
|
||||
*/
|
||||
if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse)) {
|
||||
synaptics_hardware = 1;
|
||||
|
||||
if (set_properties) {
|
||||
psmouse->vendor = "Synaptics";
|
||||
psmouse->name = "TouchPad";
|
||||
}
|
||||
|
||||
if (max_proto > PSMOUSE_IMEX) {
|
||||
if (!set_properties || synaptics_init(psmouse) == 0)
|
||||
return PSMOUSE_SYNAPTICS;
|
||||
/*
|
||||
* Some Synaptics touchpads can emulate extended protocols (like IMPS/2).
|
||||
* Unfortunately Logitech/Genius probes confuse some firmware versions so
|
||||
* we'll have to skip them.
|
||||
*/
|
||||
max_proto = PSMOUSE_IMEX;
|
||||
}
|
||||
/*
|
||||
* Make sure that touchpad is in relative mode, gestures (taps) are enabled
|
||||
*/
|
||||
synaptics_reset(psmouse);
|
||||
}
|
||||
|
||||
if (max_proto > PSMOUSE_IMEX && genius_detect(psmouse)) {
|
||||
|
||||
if (set_properties) {
|
||||
set_bit(BTN_EXTRA, psmouse->dev.keybit);
|
||||
set_bit(BTN_SIDE, psmouse->dev.keybit);
|
||||
set_bit(REL_WHEEL, psmouse->dev.relbit);
|
||||
psmouse->vendor = "Genius";
|
||||
psmouse->name = "Wheel Mouse";
|
||||
}
|
||||
|
||||
return PSMOUSE_GENPS;
|
||||
}
|
||||
|
||||
if (max_proto > PSMOUSE_IMEX) {
|
||||
int type = ps2pp_init(psmouse, set_properties);
|
||||
if (type > PSMOUSE_PS2)
|
||||
return type;
|
||||
}
|
||||
|
||||
if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse)) {
|
||||
|
||||
if (set_properties) {
|
||||
set_bit(REL_WHEEL, psmouse->dev.relbit);
|
||||
set_bit(BTN_SIDE, psmouse->dev.keybit);
|
||||
set_bit(BTN_EXTRA, psmouse->dev.keybit);
|
||||
if (!psmouse->name)
|
||||
psmouse->name = "Explorer Mouse";
|
||||
}
|
||||
|
||||
return PSMOUSE_IMEX;
|
||||
}
|
||||
|
||||
if (max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse)) {
|
||||
|
||||
if (set_properties) {
|
||||
set_bit(REL_WHEEL, psmouse->dev.relbit);
|
||||
if (!psmouse->name)
|
||||
psmouse->name = "Wheel Mouse";
|
||||
}
|
||||
|
||||
return PSMOUSE_IMPS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Okay, all failed, we have a standard mouse here. The number of the buttons
|
||||
* is still a question, though. We assume 3.
|
||||
*/
|
||||
if (synaptics_hardware) {
|
||||
/*
|
||||
* We detected Synaptics hardware but it did not respond to IMPS/2 probes.
|
||||
* We need to reset the touchpad because if there is a track point on the
|
||||
* pass through port it could get disabled while probing for protocol
|
||||
* extensions.
|
||||
*/
|
||||
psmouse_reset(psmouse);
|
||||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS);
|
||||
}
|
||||
|
||||
return PSMOUSE_PS2;
|
||||
}
|
||||
|
||||
/*
|
||||
* psmouse_probe() probes for a PS/2 mouse.
|
||||
*/
|
||||
|
||||
static int psmouse_probe(struct psmouse *psmouse)
|
||||
{
|
||||
unsigned char param[2];
|
||||
|
||||
/*
|
||||
* First, we check if it's a mouse. It should send 0x00 or 0x03
|
||||
* in case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer.
|
||||
*/
|
||||
|
||||
param[0] = 0xa5;
|
||||
|
||||
if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETID))
|
||||
return -1;
|
||||
|
||||
if (param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Then we reset and disable the mouse so that it doesn't generate events.
|
||||
*/
|
||||
|
||||
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS))
|
||||
printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", psmouse->serio->phys);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we set the mouse resolution.
|
||||
*/
|
||||
|
||||
static void psmouse_set_resolution(struct psmouse *psmouse)
|
||||
{
|
||||
unsigned char param[1];
|
||||
|
||||
if (psmouse->type == PSMOUSE_PS2PP && psmouse_resolution > 400) {
|
||||
ps2pp_set_800dpi(psmouse);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!psmouse_resolution || psmouse_resolution >= 200)
|
||||
param[0] = 3;
|
||||
else if (psmouse_resolution >= 100)
|
||||
param[0] = 2;
|
||||
else if (psmouse_resolution >= 50)
|
||||
param[0] = 1;
|
||||
else if (psmouse_resolution)
|
||||
param[0] = 0;
|
||||
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we set the mouse report rate.
|
||||
*/
|
||||
|
||||
static void psmouse_set_rate(struct psmouse *psmouse)
|
||||
{
|
||||
unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 };
|
||||
int i = 0;
|
||||
|
||||
while (rates[i] > psmouse_rate) i++;
|
||||
psmouse_command(psmouse, rates + i, PSMOUSE_CMD_SETRATE);
|
||||
}
|
||||
|
||||
/*
|
||||
* psmouse_initialize() initializes the mouse to a sane state.
|
||||
*/
|
||||
|
||||
static void psmouse_initialize(struct psmouse *psmouse)
|
||||
{
|
||||
unsigned char param[2];
|
||||
|
||||
/*
|
||||
* We set the mouse report rate, resolution and scaling.
|
||||
*/
|
||||
|
||||
if (psmouse_max_proto != PSMOUSE_PS2) {
|
||||
psmouse_set_rate(psmouse);
|
||||
psmouse_set_resolution(psmouse);
|
||||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
|
||||
}
|
||||
|
||||
/*
|
||||
* We set the mouse into streaming mode.
|
||||
*/
|
||||
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_SETSTREAM);
|
||||
}
|
||||
|
||||
/*
|
||||
* psmouse_set_state() sets new psmouse state and resets all flags and
|
||||
* counters while holding serio lock so fighting with interrupt handler
|
||||
* is not a concern.
|
||||
*/
|
||||
|
||||
static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
|
||||
{
|
||||
serio_pause_rx(psmouse->serio);
|
||||
psmouse->state = new_state;
|
||||
psmouse->pktcnt = psmouse->cmdcnt = psmouse->out_of_sync = 0;
|
||||
psmouse->flags = 0;
|
||||
serio_continue_rx(psmouse->serio);
|
||||
}
|
||||
|
||||
/*
|
||||
* psmouse_activate() enables the mouse so that we get motion reports from it.
|
||||
*/
|
||||
|
||||
static void psmouse_activate(struct psmouse *psmouse)
|
||||
{
|
||||
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
|
||||
printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", psmouse->serio->phys);
|
||||
|
||||
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* psmouse_deactivate() puts the mouse into poll mode so that we don't get motion
|
||||
* reports from it unless we explicitely request it.
|
||||
*/
|
||||
|
||||
static void psmouse_deactivate(struct psmouse *psmouse)
|
||||
{
|
||||
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE))
|
||||
printk(KERN_WARNING "psmouse.c: Failed to deactivate mouse on %s\n", psmouse->serio->phys);
|
||||
|
||||
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* psmouse_cleanup() resets the mouse into power-on state.
|
||||
*/
|
||||
|
||||
static void psmouse_cleanup(struct serio *serio)
|
||||
{
|
||||
struct psmouse *psmouse = serio->private;
|
||||
|
||||
psmouse_reset(psmouse);
|
||||
}
|
||||
|
||||
/*
|
||||
* psmouse_disconnect() closes and frees.
|
||||
*/
|
||||
|
||||
static void psmouse_disconnect(struct serio *serio)
|
||||
{
|
||||
struct psmouse *psmouse, *parent;
|
||||
|
||||
psmouse = serio->private;
|
||||
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
|
||||
|
||||
if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) {
|
||||
parent = serio->parent->private;
|
||||
if (parent->pt_deactivate)
|
||||
parent->pt_deactivate(parent);
|
||||
}
|
||||
|
||||
if (psmouse->disconnect)
|
||||
psmouse->disconnect(psmouse);
|
||||
|
||||
psmouse_set_state(psmouse, PSMOUSE_IGNORE);
|
||||
|
||||
input_unregister_device(&psmouse->dev);
|
||||
serio_close(serio);
|
||||
kfree(psmouse);
|
||||
}
|
||||
|
||||
/*
|
||||
* psmouse_connect() is a callback from the serio module when
|
||||
* an unhandled serio port is found.
|
||||
*/
|
||||
static void psmouse_connect(struct serio *serio, struct serio_driver *drv)
|
||||
{
|
||||
struct psmouse *psmouse, *parent = NULL;
|
||||
|
||||
if ((serio->type & SERIO_TYPE) != SERIO_8042 &&
|
||||
(serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If this is a pass-through port deactivate parent so the device
|
||||
* connected to this port can be successfully identified
|
||||
*/
|
||||
if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) {
|
||||
parent = serio->parent->private;
|
||||
psmouse_deactivate(parent);
|
||||
}
|
||||
|
||||
if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL)))
|
||||
goto out;
|
||||
|
||||
memset(psmouse, 0, sizeof(struct psmouse));
|
||||
|
||||
init_waitqueue_head(&psmouse->wait);
|
||||
init_input_dev(&psmouse->dev);
|
||||
psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
|
||||
psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
|
||||
psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
|
||||
psmouse->serio = serio;
|
||||
psmouse->dev.private = psmouse;
|
||||
psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
|
||||
|
||||
serio->private = psmouse;
|
||||
if (serio_open(serio, drv)) {
|
||||
kfree(psmouse);
|
||||
serio->private = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (psmouse_probe(psmouse) < 0) {
|
||||
serio_close(serio);
|
||||
kfree(psmouse);
|
||||
serio->private = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
|
||||
if (!psmouse->vendor)
|
||||
psmouse->vendor = "Generic";
|
||||
if (!psmouse->name)
|
||||
psmouse->name = "Mouse";
|
||||
if (!psmouse->protocol_handler)
|
||||
psmouse->protocol_handler = psmouse_process_byte;
|
||||
|
||||
sprintf(psmouse->devname, "%s %s %s",
|
||||
psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
|
||||
sprintf(psmouse->phys, "%s/input0",
|
||||
serio->phys);
|
||||
|
||||
psmouse->dev.name = psmouse->devname;
|
||||
psmouse->dev.phys = psmouse->phys;
|
||||
psmouse->dev.id.bustype = BUS_I8042;
|
||||
psmouse->dev.id.vendor = 0x0002;
|
||||
psmouse->dev.id.product = psmouse->type;
|
||||
psmouse->dev.id.version = psmouse->model;
|
||||
|
||||
input_register_device(&psmouse->dev);
|
||||
|
||||
printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
|
||||
|
||||
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
|
||||
|
||||
psmouse_initialize(psmouse);
|
||||
|
||||
if (parent && parent->pt_activate)
|
||||
parent->pt_activate(parent);
|
||||
|
||||
if (serio->child) {
|
||||
/*
|
||||
* Nothing to be done here, serio core will detect that
|
||||
* the driver set serio->child and will register it for us.
|
||||
*/
|
||||
printk(KERN_INFO "serio: %s port at %s\n", serio->child->name, psmouse->phys);
|
||||
}
|
||||
|
||||
psmouse_activate(psmouse);
|
||||
|
||||
out:
|
||||
/* If this is a pass-through port the parent awaits to be activated */
|
||||
if (parent)
|
||||
psmouse_activate(parent);
|
||||
}
|
||||
|
||||
|
||||
static int psmouse_reconnect(struct serio *serio)
|
||||
{
|
||||
struct psmouse *psmouse = serio->private;
|
||||
struct psmouse *parent = NULL;
|
||||
struct serio_driver *drv = serio->drv;
|
||||
int rc = -1;
|
||||
|
||||
if (!drv || !psmouse) {
|
||||
printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) {
|
||||
parent = serio->parent->private;
|
||||
psmouse_deactivate(parent);
|
||||
}
|
||||
|
||||
psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
|
||||
|
||||
if (psmouse->reconnect) {
|
||||
if (psmouse->reconnect(psmouse))
|
||||
goto out;
|
||||
} else if (psmouse_probe(psmouse) < 0 ||
|
||||
psmouse->type != psmouse_extensions(psmouse, psmouse_max_proto, 0))
|
||||
goto out;
|
||||
|
||||
/* ok, the device type (and capabilities) match the old one,
|
||||
* we can continue using it, complete intialization
|
||||
*/
|
||||
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
|
||||
|
||||
psmouse_initialize(psmouse);
|
||||
|
||||
if (parent && parent->pt_activate)
|
||||
parent->pt_activate(parent);
|
||||
|
||||
psmouse_activate(psmouse);
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
/* If this is a pass-through port the parent waits to be activated */
|
||||
if (parent)
|
||||
psmouse_activate(parent);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static struct serio_driver psmouse_drv = {
|
||||
.driver = {
|
||||
.name = "psmouse",
|
||||
},
|
||||
.description = DRIVER_DESC,
|
||||
.interrupt = psmouse_interrupt,
|
||||
.connect = psmouse_connect,
|
||||
.reconnect = psmouse_reconnect,
|
||||
.disconnect = psmouse_disconnect,
|
||||
.cleanup = psmouse_cleanup,
|
||||
};
|
||||
|
||||
static inline void psmouse_parse_proto(void)
|
||||
{
|
||||
if (psmouse_proto) {
|
||||
if (!strcmp(psmouse_proto, "bare"))
|
||||
psmouse_max_proto = PSMOUSE_PS2;
|
||||
else if (!strcmp(psmouse_proto, "imps"))
|
||||
psmouse_max_proto = PSMOUSE_IMPS;
|
||||
else if (!strcmp(psmouse_proto, "exps"))
|
||||
psmouse_max_proto = PSMOUSE_IMEX;
|
||||
else
|
||||
printk(KERN_ERR "psmouse: unknown protocol type '%s'\n", psmouse_proto);
|
||||
}
|
||||
}
|
||||
|
||||
int __init psmouse_init(void)
|
||||
{
|
||||
psmouse_parse_proto();
|
||||
serio_register_driver(&psmouse_drv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit psmouse_exit(void)
|
||||
{
|
||||
serio_unregister_driver(&psmouse_drv);
|
||||
}
|
||||
|
||||
module_init(psmouse_init);
|
||||
module_exit(psmouse_exit);
|
||||
BIN
extra/linux-2.6.10/drivers/input/mouse/psmouse-base.o
Normal file
BIN
extra/linux-2.6.10/drivers/input/mouse/psmouse-base.o
Normal file
Binary file not shown.
87
extra/linux-2.6.10/drivers/input/mouse/psmouse.h
Normal file
87
extra/linux-2.6.10/drivers/input/mouse/psmouse.h
Normal file
@@ -0,0 +1,87 @@
|
||||
#ifndef _PSMOUSE_H
|
||||
#define _PSMOUSE_H
|
||||
|
||||
#define PSMOUSE_CMD_SETSCALE11 0x00e6
|
||||
#define PSMOUSE_CMD_SETRES 0x10e8
|
||||
#define PSMOUSE_CMD_GETINFO 0x03e9
|
||||
#define PSMOUSE_CMD_SETSTREAM 0x00ea
|
||||
#define PSMOUSE_CMD_POLL 0x03eb
|
||||
#define PSMOUSE_CMD_GETID 0x02f2
|
||||
#define PSMOUSE_CMD_SETRATE 0x10f3
|
||||
#define PSMOUSE_CMD_ENABLE 0x00f4
|
||||
#define PSMOUSE_CMD_DISABLE 0x00f5
|
||||
#define PSMOUSE_CMD_RESET_DIS 0x00f6
|
||||
#define PSMOUSE_CMD_RESET_BAT 0x02ff
|
||||
|
||||
#define PSMOUSE_RET_BAT 0xaa
|
||||
#define PSMOUSE_RET_ID 0x00
|
||||
#define PSMOUSE_RET_ACK 0xfa
|
||||
#define PSMOUSE_RET_NAK 0xfe
|
||||
|
||||
#define PSMOUSE_FLAG_ACK 0 /* Waiting for ACK/NAK */
|
||||
#define PSMOUSE_FLAG_CMD 1 /* Waiting for command to finish */
|
||||
#define PSMOUSE_FLAG_CMD1 2 /* Waiting for the first byte of command response */
|
||||
#define PSMOUSE_FLAG_WAITID 3 /* Command execiting is GET ID */
|
||||
|
||||
enum psmouse_state {
|
||||
PSMOUSE_IGNORE,
|
||||
PSMOUSE_INITIALIZING,
|
||||
PSMOUSE_CMD_MODE,
|
||||
PSMOUSE_ACTIVATED,
|
||||
};
|
||||
|
||||
/* psmouse protocol handler return codes */
|
||||
typedef enum {
|
||||
PSMOUSE_BAD_DATA,
|
||||
PSMOUSE_GOOD_DATA,
|
||||
PSMOUSE_FULL_PACKET
|
||||
} psmouse_ret_t;
|
||||
|
||||
struct psmouse {
|
||||
void *private;
|
||||
struct input_dev dev;
|
||||
struct serio *serio;
|
||||
char *vendor;
|
||||
char *name;
|
||||
unsigned char cmdbuf[8];
|
||||
unsigned char packet[8];
|
||||
unsigned char cmdcnt;
|
||||
unsigned char pktcnt;
|
||||
unsigned char type;
|
||||
unsigned char model;
|
||||
unsigned long last;
|
||||
unsigned long out_of_sync;
|
||||
enum psmouse_state state;
|
||||
unsigned char nak;
|
||||
char error;
|
||||
char devname[64];
|
||||
char phys[32];
|
||||
unsigned long flags;
|
||||
|
||||
/* Used to signal completion from interrupt handler */
|
||||
wait_queue_head_t wait;
|
||||
|
||||
psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs);
|
||||
int (*reconnect)(struct psmouse *psmouse);
|
||||
void (*disconnect)(struct psmouse *psmouse);
|
||||
|
||||
void (*pt_activate)(struct psmouse *psmouse);
|
||||
void (*pt_deactivate)(struct psmouse *psmouse);
|
||||
};
|
||||
|
||||
#define PSMOUSE_PS2 1
|
||||
#define PSMOUSE_PS2PP 2
|
||||
#define PSMOUSE_PS2TPP 3
|
||||
#define PSMOUSE_GENPS 4
|
||||
#define PSMOUSE_IMPS 5
|
||||
#define PSMOUSE_IMEX 6
|
||||
#define PSMOUSE_SYNAPTICS 7
|
||||
|
||||
int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);
|
||||
int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
|
||||
int psmouse_reset(struct psmouse *psmouse);
|
||||
|
||||
extern int psmouse_smartscroll;
|
||||
extern unsigned int psmouse_rate;
|
||||
|
||||
#endif /* _PSMOUSE_H */
|
||||
BIN
extra/linux-2.6.10/drivers/input/mouse/psmouse.o
Normal file
BIN
extra/linux-2.6.10/drivers/input/mouse/psmouse.o
Normal file
Binary file not shown.
107
extra/linux-2.6.10/drivers/input/mouse/rpcmouse.c
Normal file
107
extra/linux-2.6.10/drivers/input/mouse/rpcmouse.c
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Acorn RiscPC mouse driver for Linux/ARM
|
||||
*
|
||||
* Copyright (c) 2000-2002 Vojtech Pavlik
|
||||
* Copyright (C) 1996-2002 Russell King
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This handles the Acorn RiscPCs mouse. We basically have a couple of
|
||||
* hardware registers that track the sensor count for the X-Y movement and
|
||||
* another register holding the button state. On every VSYNC interrupt we read
|
||||
* the complete state and then work out if something has changed.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/hardware/iomd.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik, Russell King");
|
||||
MODULE_DESCRIPTION("Acorn RiscPC mouse driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static short rpcmouse_lastx, rpcmouse_lasty;
|
||||
|
||||
static struct input_dev rpcmouse_dev = {
|
||||
.evbit = { BIT(EV_KEY) | BIT(EV_REL) },
|
||||
.keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) },
|
||||
.relbit = { BIT(REL_X) | BIT(REL_Y) },
|
||||
.name = "Acorn RiscPC Mouse",
|
||||
.phys = "rpcmouse/input0",
|
||||
.id = {
|
||||
.bustype = BUS_HOST,
|
||||
.vendor = 0x0005,
|
||||
.product = 0x0001,
|
||||
.version = 0x0100,
|
||||
},
|
||||
};
|
||||
|
||||
static irqreturn_t rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
struct input_dev *dev = dev_id;
|
||||
short x, y, dx, dy, b;
|
||||
|
||||
x = (short) iomd_readl(IOMD_MOUSEX);
|
||||
y = (short) iomd_readl(IOMD_MOUSEY);
|
||||
b = (short) (__raw_readl(0xe0310000) ^ 0x70);
|
||||
|
||||
dx = x - rpcmouse_lastx;
|
||||
dy = y - rpcmouse_lasty;
|
||||
|
||||
rpcmouse_lastx = x;
|
||||
rpcmouse_lasty = y;
|
||||
|
||||
input_regs(dev, regs);
|
||||
|
||||
input_report_rel(dev, REL_X, dx);
|
||||
input_report_rel(dev, REL_Y, -dy);
|
||||
|
||||
input_report_key(dev, BTN_LEFT, b & 0x40);
|
||||
input_report_key(dev, BTN_MIDDLE, b & 0x20);
|
||||
input_report_key(dev, BTN_RIGHT, b & 0x10);
|
||||
|
||||
input_sync(dev);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __init rpcmouse_init(void)
|
||||
{
|
||||
init_input_dev(&rpcmouse_dev);
|
||||
|
||||
rpcmouse_lastx = (short) iomd_readl(IOMD_MOUSEX);
|
||||
rpcmouse_lasty = (short) iomd_readl(IOMD_MOUSEY);
|
||||
|
||||
if (request_irq(IRQ_VSYNCPULSE, rpcmouse_irq, SA_SHIRQ, "rpcmouse", &rpcmouse_dev)) {
|
||||
printk(KERN_ERR "rpcmouse: unable to allocate VSYNC interrupt\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
input_register_device(&rpcmouse_dev);
|
||||
|
||||
printk(KERN_INFO "input: Acorn RiscPC mouse\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit rpcmouse_exit(void)
|
||||
{
|
||||
input_unregister_device(&rpcmouse_dev);
|
||||
free_irq(IRQ_VSYNCPULSE, &rpcmouse_dev);
|
||||
}
|
||||
|
||||
module_init(rpcmouse_init);
|
||||
module_exit(rpcmouse_exit);
|
||||
316
extra/linux-2.6.10/drivers/input/mouse/sermouse.c
Normal file
316
extra/linux-2.6.10/drivers/input/mouse/sermouse.c
Normal file
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* $Id: sermouse.c,v 1.17 2002/03/13 10:03:43 vojtech Exp $
|
||||
*
|
||||
* Copyright (c) 1999-2001 Vojtech Pavlik
|
||||
*/
|
||||
|
||||
/*
|
||||
* Serial mouse driver for Linux
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Should you need to contact me, the author, you can do so either by
|
||||
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
|
||||
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/config.h>
|
||||
#include <linux/serio.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#define DRIVER_DESC "Serial mouse driver"
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse",
|
||||
"Logitech M+ Mouse", "Microsoft MZ Mouse", "Logitech MZ+ Mouse",
|
||||
"Logitech MZ++ Mouse"};
|
||||
|
||||
struct sermouse {
|
||||
struct input_dev dev;
|
||||
signed char buf[8];
|
||||
unsigned char count;
|
||||
unsigned char type;
|
||||
unsigned long last;
|
||||
char phys[32];
|
||||
};
|
||||
|
||||
/*
|
||||
* sermouse_process_msc() analyzes the incoming MSC/Sun bytestream and
|
||||
* applies some prediction to the data, resulting in 96 updates per
|
||||
* second, which is as good as a PS/2 or USB mouse.
|
||||
*/
|
||||
|
||||
static void sermouse_process_msc(struct sermouse *sermouse, signed char data, struct pt_regs *regs)
|
||||
{
|
||||
struct input_dev *dev = &sermouse->dev;
|
||||
signed char *buf = sermouse->buf;
|
||||
|
||||
input_regs(dev, regs);
|
||||
|
||||
switch (sermouse->count) {
|
||||
|
||||
case 0:
|
||||
if ((data & 0xf8) != 0x80) return;
|
||||
input_report_key(dev, BTN_LEFT, !(data & 4));
|
||||
input_report_key(dev, BTN_RIGHT, !(data & 1));
|
||||
input_report_key(dev, BTN_MIDDLE, !(data & 2));
|
||||
break;
|
||||
|
||||
case 1:
|
||||
case 3:
|
||||
input_report_rel(dev, REL_X, data / 2);
|
||||
input_report_rel(dev, REL_Y, -buf[1]);
|
||||
buf[0] = data - data / 2;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 4:
|
||||
input_report_rel(dev, REL_X, buf[0]);
|
||||
input_report_rel(dev, REL_Y, buf[1] - data);
|
||||
buf[1] = data / 2;
|
||||
break;
|
||||
}
|
||||
|
||||
input_sync(dev);
|
||||
|
||||
if (++sermouse->count == (5 - ((sermouse->type == SERIO_SUN) << 1)))
|
||||
sermouse->count = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* sermouse_process_ms() anlyzes the incoming MS(Z/+/++) bytestream and
|
||||
* generates events. With prediction it gets 80 updates/sec, assuming
|
||||
* standard 3-byte packets and 1200 bps.
|
||||
*/
|
||||
|
||||
static void sermouse_process_ms(struct sermouse *sermouse, signed char data, struct pt_regs *regs)
|
||||
{
|
||||
struct input_dev *dev = &sermouse->dev;
|
||||
signed char *buf = sermouse->buf;
|
||||
|
||||
if (data & 0x40) sermouse->count = 0;
|
||||
|
||||
input_regs(dev, regs);
|
||||
|
||||
switch (sermouse->count) {
|
||||
|
||||
case 0:
|
||||
buf[1] = data;
|
||||
input_report_key(dev, BTN_LEFT, (data >> 5) & 1);
|
||||
input_report_key(dev, BTN_RIGHT, (data >> 4) & 1);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
buf[2] = data;
|
||||
data = (signed char) (((buf[1] << 6) & 0xc0) | (data & 0x3f));
|
||||
input_report_rel(dev, REL_X, data / 2);
|
||||
input_report_rel(dev, REL_Y, buf[4]);
|
||||
buf[3] = data - data / 2;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/* Guessing the state of the middle button on 3-button MS-protocol mice - ugly. */
|
||||
if ((sermouse->type == SERIO_MS) && !data && !buf[2] && !((buf[0] & 0xf0) ^ buf[1]))
|
||||
input_report_key(dev, BTN_MIDDLE, !test_bit(BTN_MIDDLE, dev->key));
|
||||
buf[0] = buf[1];
|
||||
|
||||
data = (signed char) (((buf[1] << 4) & 0xc0) | (data & 0x3f));
|
||||
input_report_rel(dev, REL_X, buf[3]);
|
||||
input_report_rel(dev, REL_Y, data - buf[4]);
|
||||
buf[4] = data / 2;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
|
||||
switch (sermouse->type) {
|
||||
|
||||
case SERIO_MS:
|
||||
sermouse->type = SERIO_MP;
|
||||
|
||||
case SERIO_MP:
|
||||
if ((data >> 2) & 3) break; /* M++ Wireless Extension packet. */
|
||||
input_report_key(dev, BTN_MIDDLE, (data >> 5) & 1);
|
||||
input_report_key(dev, BTN_SIDE, (data >> 4) & 1);
|
||||
break;
|
||||
|
||||
case SERIO_MZP:
|
||||
case SERIO_MZPP:
|
||||
input_report_key(dev, BTN_SIDE, (data >> 5) & 1);
|
||||
|
||||
case SERIO_MZ:
|
||||
input_report_key(dev, BTN_MIDDLE, (data >> 4) & 1);
|
||||
input_report_rel(dev, REL_WHEEL, (data & 8) - (data & 7));
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 4:
|
||||
case 6: /* MZ++ packet type. We can get these bytes for M++ too but we ignore them later. */
|
||||
buf[1] = (data >> 2) & 0x0f;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
case 7: /* Ignore anything besides MZ++ */
|
||||
if (sermouse->type != SERIO_MZPP) break;
|
||||
|
||||
switch (buf[1]) {
|
||||
|
||||
case 1: /* Extra mouse info */
|
||||
|
||||
input_report_key(dev, BTN_SIDE, (data >> 4) & 1);
|
||||
input_report_key(dev, BTN_EXTRA, (data >> 5) & 1);
|
||||
input_report_rel(dev, data & 0x80 ? REL_HWHEEL : REL_WHEEL, (data & 7) - (data & 8));
|
||||
|
||||
break;
|
||||
|
||||
default: /* We don't decode anything else yet. */
|
||||
|
||||
printk(KERN_WARNING
|
||||
"sermouse.c: Received MZ++ packet %x, don't know how to handle.\n", buf[1]);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
input_sync(dev);
|
||||
|
||||
sermouse->count++;
|
||||
}
|
||||
|
||||
/*
|
||||
* sermouse_interrupt() handles incoming characters, either gathering them into
|
||||
* packets or passing them to the command routine as command output.
|
||||
*/
|
||||
|
||||
static irqreturn_t sermouse_interrupt(struct serio *serio,
|
||||
unsigned char data, unsigned int flags, struct pt_regs *regs)
|
||||
{
|
||||
struct sermouse *sermouse = serio->private;
|
||||
|
||||
if (time_after(jiffies, sermouse->last + HZ/10)) sermouse->count = 0;
|
||||
sermouse->last = jiffies;
|
||||
|
||||
if (sermouse->type > SERIO_SUN)
|
||||
sermouse_process_ms(sermouse, data, regs);
|
||||
else
|
||||
sermouse_process_msc(sermouse, data, regs);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* sermouse_disconnect() cleans up after we don't want talk
|
||||
* to the mouse anymore.
|
||||
*/
|
||||
|
||||
static void sermouse_disconnect(struct serio *serio)
|
||||
{
|
||||
struct sermouse *sermouse = serio->private;
|
||||
input_unregister_device(&sermouse->dev);
|
||||
serio_close(serio);
|
||||
kfree(sermouse);
|
||||
}
|
||||
|
||||
/*
|
||||
* sermouse_connect() is a callback form the serio module when
|
||||
* an unhandled serio port is found.
|
||||
*/
|
||||
|
||||
static void sermouse_connect(struct serio *serio, struct serio_driver *drv)
|
||||
{
|
||||
struct sermouse *sermouse;
|
||||
unsigned char c;
|
||||
|
||||
if ((serio->type & SERIO_TYPE) != SERIO_RS232)
|
||||
return;
|
||||
|
||||
if (!(serio->type & SERIO_PROTO) || ((serio->type & SERIO_PROTO) > SERIO_MZPP))
|
||||
return;
|
||||
|
||||
if (!(sermouse = kmalloc(sizeof(struct sermouse), GFP_KERNEL)))
|
||||
return;
|
||||
|
||||
memset(sermouse, 0, sizeof(struct sermouse));
|
||||
|
||||
init_input_dev(&sermouse->dev);
|
||||
sermouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
|
||||
sermouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
|
||||
sermouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
|
||||
sermouse->dev.private = sermouse;
|
||||
|
||||
serio->private = sermouse;
|
||||
|
||||
sermouse->type = serio->type & SERIO_PROTO;
|
||||
c = (serio->type & SERIO_EXTRA) >> 16;
|
||||
|
||||
if (c & 0x01) set_bit(BTN_MIDDLE, sermouse->dev.keybit);
|
||||
if (c & 0x02) set_bit(BTN_SIDE, sermouse->dev.keybit);
|
||||
if (c & 0x04) set_bit(BTN_EXTRA, sermouse->dev.keybit);
|
||||
if (c & 0x10) set_bit(REL_WHEEL, sermouse->dev.relbit);
|
||||
if (c & 0x20) set_bit(REL_HWHEEL, sermouse->dev.relbit);
|
||||
|
||||
sprintf(sermouse->phys, "%s/input0", serio->phys);
|
||||
|
||||
sermouse->dev.name = sermouse_protocols[sermouse->type];
|
||||
sermouse->dev.phys = sermouse->phys;
|
||||
sermouse->dev.id.bustype = BUS_RS232;
|
||||
sermouse->dev.id.vendor = sermouse->type;
|
||||
sermouse->dev.id.product = c;
|
||||
sermouse->dev.id.version = 0x0100;
|
||||
|
||||
if (serio_open(serio, drv)) {
|
||||
kfree(sermouse);
|
||||
return;
|
||||
}
|
||||
|
||||
input_register_device(&sermouse->dev);
|
||||
|
||||
printk(KERN_INFO "input: %s on %s\n", sermouse_protocols[sermouse->type], serio->phys);
|
||||
}
|
||||
|
||||
static struct serio_driver sermouse_drv = {
|
||||
.driver = {
|
||||
.name = "sermouse",
|
||||
},
|
||||
.description = DRIVER_DESC,
|
||||
.interrupt = sermouse_interrupt,
|
||||
.connect = sermouse_connect,
|
||||
.disconnect = sermouse_disconnect,
|
||||
};
|
||||
|
||||
int __init sermouse_init(void)
|
||||
{
|
||||
serio_register_driver(&sermouse_drv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit sermouse_exit(void)
|
||||
{
|
||||
serio_unregister_driver(&sermouse_drv);
|
||||
}
|
||||
|
||||
module_init(sermouse_init);
|
||||
module_exit(sermouse_exit);
|
||||
615
extra/linux-2.6.10/drivers/input/mouse/synaptics.c
Normal file
615
extra/linux-2.6.10/drivers/input/mouse/synaptics.c
Normal file
@@ -0,0 +1,615 @@
|
||||
/*
|
||||
* Synaptics TouchPad PS/2 mouse driver
|
||||
*
|
||||
* 2003 Dmitry Torokhov <dtor@mail.ru>
|
||||
* Added support for pass-through port. Special thanks to Peter Berg Larsen
|
||||
* for explaining various Synaptics quirks.
|
||||
*
|
||||
* 2003 Peter Osterlund <petero2@telia.com>
|
||||
* Ported to 2.5 input device infrastructure.
|
||||
*
|
||||
* Copyright (C) 2001 Stefan Gmeiner <riddlebox@freesurf.ch>
|
||||
* start merging tpconfig and gpm code to a xfree-input module
|
||||
* adding some changes and extensions (ex. 3rd and 4th button)
|
||||
*
|
||||
* Copyright (c) 1997 C. Scott Ananian <cananian@alumni.priceton.edu>
|
||||
* Copyright (c) 1998-2000 Bruce Kalk <kall@compass.com>
|
||||
* code for the special synaptics commands (from the tpconfig-source)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* Trademarks are the property of their respective owners.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/serio.h>
|
||||
#include "psmouse.h"
|
||||
#include "synaptics.h"
|
||||
|
||||
/*
|
||||
* The x/y limits are taken from the Synaptics TouchPad interfacing Guide,
|
||||
* section 2.3.2, which says that they should be valid regardless of the
|
||||
* actual size of the sensor.
|
||||
*/
|
||||
#define XMIN_NOMINAL 1472
|
||||
#define XMAX_NOMINAL 5472
|
||||
#define YMIN_NOMINAL 1408
|
||||
#define YMAX_NOMINAL 4448
|
||||
|
||||
/*****************************************************************************
|
||||
* Synaptics communications functions
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
* Send a command to the synpatics touchpad by special commands
|
||||
*/
|
||||
static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param)
|
||||
{
|
||||
if (psmouse_sliced_command(psmouse, c))
|
||||
return -1;
|
||||
if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the synaptics touchpad mode byte by special commands
|
||||
*/
|
||||
static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode)
|
||||
{
|
||||
unsigned char param[1];
|
||||
|
||||
if (psmouse_sliced_command(psmouse, mode))
|
||||
return -1;
|
||||
param[0] = SYN_PS_SET_MODE2;
|
||||
if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the model-id bytes from the touchpad
|
||||
* see also SYN_MODEL_* macros
|
||||
*/
|
||||
static int synaptics_model_id(struct psmouse *psmouse)
|
||||
{
|
||||
struct synaptics_data *priv = psmouse->private;
|
||||
unsigned char mi[3];
|
||||
|
||||
if (synaptics_send_cmd(psmouse, SYN_QUE_MODEL, mi))
|
||||
return -1;
|
||||
priv->model_id = (mi[0]<<16) | (mi[1]<<8) | mi[2];
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the capability-bits from the touchpad
|
||||
* see also the SYN_CAP_* macros
|
||||
*/
|
||||
static int synaptics_capability(struct psmouse *psmouse)
|
||||
{
|
||||
struct synaptics_data *priv = psmouse->private;
|
||||
unsigned char cap[3];
|
||||
|
||||
if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap))
|
||||
return -1;
|
||||
priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2];
|
||||
priv->ext_cap = 0;
|
||||
if (!SYN_CAP_VALID(priv->capabilities))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Unless capExtended is set the rest of the flags should be ignored
|
||||
*/
|
||||
if (!SYN_CAP_EXTENDED(priv->capabilities))
|
||||
priv->capabilities = 0;
|
||||
|
||||
if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) {
|
||||
if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) {
|
||||
printk(KERN_ERR "Synaptics claims to have extended capabilities,"
|
||||
" but I'm not able to read them.");
|
||||
} else {
|
||||
priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2];
|
||||
|
||||
/*
|
||||
* if nExtBtn is greater than 8 it should be considered
|
||||
* invalid and treated as 0
|
||||
*/
|
||||
if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 8)
|
||||
priv->ext_cap &= 0xff0fff;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Identify Touchpad
|
||||
* See also the SYN_ID_* macros
|
||||
*/
|
||||
static int synaptics_identify(struct psmouse *psmouse)
|
||||
{
|
||||
struct synaptics_data *priv = psmouse->private;
|
||||
unsigned char id[3];
|
||||
|
||||
if (synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id))
|
||||
return -1;
|
||||
priv->identity = (id[0]<<16) | (id[1]<<8) | id[2];
|
||||
if (SYN_ID_IS_SYNAPTICS(priv->identity))
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void print_ident(struct synaptics_data *priv)
|
||||
{
|
||||
printk(KERN_INFO "Synaptics Touchpad, model: %ld\n", SYN_ID_MODEL(priv->identity));
|
||||
printk(KERN_INFO " Firmware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity),
|
||||
SYN_ID_MINOR(priv->identity));
|
||||
if (SYN_MODEL_ROT180(priv->model_id))
|
||||
printk(KERN_INFO " 180 degree mounted touchpad\n");
|
||||
if (SYN_MODEL_PORTRAIT(priv->model_id))
|
||||
printk(KERN_INFO " portrait touchpad\n");
|
||||
printk(KERN_INFO " Sensor: %ld\n", SYN_MODEL_SENSOR(priv->model_id));
|
||||
if (SYN_MODEL_NEWABS(priv->model_id))
|
||||
printk(KERN_INFO " new absolute packet format\n");
|
||||
if (SYN_MODEL_PEN(priv->model_id))
|
||||
printk(KERN_INFO " pen detection\n");
|
||||
|
||||
if (SYN_CAP_EXTENDED(priv->capabilities)) {
|
||||
printk(KERN_INFO " Touchpad has extended capability bits\n");
|
||||
if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
|
||||
printk(KERN_INFO " -> %d multi-buttons, i.e. besides standard buttons\n",
|
||||
(int)(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)));
|
||||
if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
|
||||
printk(KERN_INFO " -> middle button\n");
|
||||
if (SYN_CAP_FOUR_BUTTON(priv->capabilities))
|
||||
printk(KERN_INFO " -> four buttons\n");
|
||||
if (SYN_CAP_MULTIFINGER(priv->capabilities))
|
||||
printk(KERN_INFO " -> multifinger detection\n");
|
||||
if (SYN_CAP_PALMDETECT(priv->capabilities))
|
||||
printk(KERN_INFO " -> palm detection\n");
|
||||
if (SYN_CAP_PASS_THROUGH(priv->capabilities))
|
||||
printk(KERN_INFO " -> pass-through port\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int synaptics_query_hardware(struct psmouse *psmouse)
|
||||
{
|
||||
int retries = 0;
|
||||
|
||||
while ((retries++ < 3) && psmouse_reset(psmouse))
|
||||
printk(KERN_ERR "synaptics reset failed\n");
|
||||
|
||||
if (synaptics_identify(psmouse))
|
||||
return -1;
|
||||
if (synaptics_model_id(psmouse))
|
||||
return -1;
|
||||
if (synaptics_capability(psmouse))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int synaptics_set_mode(struct psmouse *psmouse, int mode)
|
||||
{
|
||||
struct synaptics_data *priv = psmouse->private;
|
||||
|
||||
mode |= SYN_BIT_ABSOLUTE_MODE;
|
||||
if (psmouse_rate >= 80)
|
||||
mode |= SYN_BIT_HIGH_RATE;
|
||||
if (SYN_ID_MAJOR(priv->identity) >= 4)
|
||||
mode |= SYN_BIT_DISABLE_GESTURE;
|
||||
if (SYN_CAP_EXTENDED(priv->capabilities))
|
||||
mode |= SYN_BIT_W_MODE;
|
||||
if (synaptics_mode_cmd(psmouse, mode))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Synaptics pass-through PS/2 port support
|
||||
****************************************************************************/
|
||||
static int synaptics_pt_write(struct serio *serio, unsigned char c)
|
||||
{
|
||||
struct psmouse *parent = serio->parent->private;
|
||||
char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */
|
||||
|
||||
if (psmouse_sliced_command(parent, c))
|
||||
return -1;
|
||||
if (psmouse_command(parent, &rate_param, PSMOUSE_CMD_SETRATE))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int synaptics_is_pt_packet(unsigned char *buf)
|
||||
{
|
||||
return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
|
||||
}
|
||||
|
||||
static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet)
|
||||
{
|
||||
struct psmouse *child = ptport->private;
|
||||
|
||||
if (child && child->state == PSMOUSE_ACTIVATED) {
|
||||
serio_interrupt(ptport, packet[1], 0, NULL);
|
||||
serio_interrupt(ptport, packet[4], 0, NULL);
|
||||
serio_interrupt(ptport, packet[5], 0, NULL);
|
||||
if (child->type >= PSMOUSE_GENPS)
|
||||
serio_interrupt(ptport, packet[2], 0, NULL);
|
||||
} else
|
||||
serio_interrupt(ptport, packet[1], 0, NULL);
|
||||
}
|
||||
|
||||
static void synaptics_pt_activate(struct psmouse *psmouse)
|
||||
{
|
||||
struct psmouse *child = psmouse->serio->child->private;
|
||||
|
||||
/* adjust the touchpad to child's choice of protocol */
|
||||
if (child && child->type >= PSMOUSE_GENPS) {
|
||||
if (synaptics_set_mode(psmouse, SYN_BIT_FOUR_BYTE_CLIENT))
|
||||
printk(KERN_INFO "synaptics: failed to enable 4-byte guest protocol\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void synaptics_pt_create(struct psmouse *psmouse)
|
||||
{
|
||||
struct serio *serio;
|
||||
|
||||
serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
|
||||
if (!serio) {
|
||||
printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(serio, 0, sizeof(struct serio));
|
||||
|
||||
serio->type = SERIO_PS_PSTHRU;
|
||||
strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name));
|
||||
strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name));
|
||||
serio->write = synaptics_pt_write;
|
||||
serio->parent = psmouse->serio;
|
||||
|
||||
psmouse->pt_activate = synaptics_pt_activate;
|
||||
|
||||
psmouse->serio->child = serio;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Functions to interpret the absolute mode packets
|
||||
****************************************************************************/
|
||||
|
||||
static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw)
|
||||
{
|
||||
memset(hw, 0, sizeof(struct synaptics_hw_state));
|
||||
|
||||
if (SYN_MODEL_NEWABS(priv->model_id)) {
|
||||
hw->x = (((buf[3] & 0x10) << 8) |
|
||||
((buf[1] & 0x0f) << 8) |
|
||||
buf[4]);
|
||||
hw->y = (((buf[3] & 0x20) << 7) |
|
||||
((buf[1] & 0xf0) << 4) |
|
||||
buf[5]);
|
||||
|
||||
hw->z = buf[2];
|
||||
hw->w = (((buf[0] & 0x30) >> 2) |
|
||||
((buf[0] & 0x04) >> 1) |
|
||||
((buf[3] & 0x04) >> 2));
|
||||
|
||||
hw->left = (buf[0] & 0x01) ? 1 : 0;
|
||||
hw->right = (buf[0] & 0x02) ? 1 : 0;
|
||||
|
||||
if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
|
||||
hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
|
||||
|
||||
if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
|
||||
hw->up = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0;
|
||||
hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
|
||||
}
|
||||
|
||||
if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
|
||||
((buf[0] ^ buf[3]) & 0x02)) {
|
||||
switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
|
||||
default:
|
||||
/*
|
||||
* if nExtBtn is greater than 8 it should be
|
||||
* considered invalid and treated as 0
|
||||
*/
|
||||
break;
|
||||
case 8:
|
||||
hw->ext_buttons |= ((buf[5] & 0x08)) ? 0x80 : 0;
|
||||
hw->ext_buttons |= ((buf[4] & 0x08)) ? 0x40 : 0;
|
||||
case 6:
|
||||
hw->ext_buttons |= ((buf[5] & 0x04)) ? 0x20 : 0;
|
||||
hw->ext_buttons |= ((buf[4] & 0x04)) ? 0x10 : 0;
|
||||
case 4:
|
||||
hw->ext_buttons |= ((buf[5] & 0x02)) ? 0x08 : 0;
|
||||
hw->ext_buttons |= ((buf[4] & 0x02)) ? 0x04 : 0;
|
||||
case 2:
|
||||
hw->ext_buttons |= ((buf[5] & 0x01)) ? 0x02 : 0;
|
||||
hw->ext_buttons |= ((buf[4] & 0x01)) ? 0x01 : 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hw->x = (((buf[1] & 0x1f) << 8) | buf[2]);
|
||||
hw->y = (((buf[4] & 0x1f) << 8) | buf[5]);
|
||||
|
||||
hw->z = (((buf[0] & 0x30) << 2) | (buf[3] & 0x3F));
|
||||
hw->w = (((buf[1] & 0x80) >> 4) | ((buf[0] & 0x04) >> 1));
|
||||
|
||||
hw->left = (buf[0] & 0x01) ? 1 : 0;
|
||||
hw->right = (buf[0] & 0x02) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* called for each full received packet from the touchpad
|
||||
*/
|
||||
static void synaptics_process_packet(struct psmouse *psmouse)
|
||||
{
|
||||
struct input_dev *dev = &psmouse->dev;
|
||||
struct synaptics_data *priv = psmouse->private;
|
||||
struct synaptics_hw_state hw;
|
||||
int num_fingers;
|
||||
int finger_width;
|
||||
int i;
|
||||
|
||||
synaptics_parse_hw_state(psmouse->packet, priv, &hw);
|
||||
|
||||
if (hw.z > 0) {
|
||||
num_fingers = 1;
|
||||
finger_width = 5;
|
||||
if (SYN_CAP_EXTENDED(priv->capabilities)) {
|
||||
switch (hw.w) {
|
||||
case 0 ... 1:
|
||||
if (SYN_CAP_MULTIFINGER(priv->capabilities))
|
||||
num_fingers = hw.w + 2;
|
||||
break;
|
||||
case 2:
|
||||
if (SYN_MODEL_PEN(priv->model_id))
|
||||
; /* Nothing, treat a pen as a single finger */
|
||||
break;
|
||||
case 4 ... 15:
|
||||
if (SYN_CAP_PALMDETECT(priv->capabilities))
|
||||
finger_width = hw.w;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
num_fingers = 0;
|
||||
finger_width = 0;
|
||||
}
|
||||
|
||||
/* Post events
|
||||
* BTN_TOUCH has to be first as mousedev relies on it when doing
|
||||
* absolute -> relative conversion
|
||||
*/
|
||||
if (hw.z > 30) input_report_key(dev, BTN_TOUCH, 1);
|
||||
if (hw.z < 25) input_report_key(dev, BTN_TOUCH, 0);
|
||||
|
||||
if (hw.z > 0) {
|
||||
input_report_abs(dev, ABS_X, hw.x);
|
||||
input_report_abs(dev, ABS_Y, YMAX_NOMINAL + YMIN_NOMINAL - hw.y);
|
||||
}
|
||||
input_report_abs(dev, ABS_PRESSURE, hw.z);
|
||||
|
||||
input_report_abs(dev, ABS_TOOL_WIDTH, finger_width);
|
||||
input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1);
|
||||
input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2);
|
||||
input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
|
||||
|
||||
input_report_key(dev, BTN_LEFT, hw.left);
|
||||
input_report_key(dev, BTN_RIGHT, hw.right);
|
||||
|
||||
if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
|
||||
input_report_key(dev, BTN_MIDDLE, hw.middle);
|
||||
|
||||
if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
|
||||
input_report_key(dev, BTN_FORWARD, hw.up);
|
||||
input_report_key(dev, BTN_BACK, hw.down);
|
||||
}
|
||||
|
||||
for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
|
||||
input_report_key(dev, BTN_0 + i, hw.ext_buttons & (1 << i));
|
||||
|
||||
input_sync(dev);
|
||||
}
|
||||
|
||||
static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type)
|
||||
{
|
||||
static unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 };
|
||||
static unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 };
|
||||
static unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 };
|
||||
static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
|
||||
static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
|
||||
|
||||
if (idx < 0 || idx > 4)
|
||||
return 0;
|
||||
|
||||
switch (pkt_type) {
|
||||
case SYN_NEWABS:
|
||||
case SYN_NEWABS_RELAXED:
|
||||
return (packet[idx] & newabs_rel_mask[idx]) == newabs_rslt[idx];
|
||||
|
||||
case SYN_NEWABS_STRICT:
|
||||
return (packet[idx] & newabs_mask[idx]) == newabs_rslt[idx];
|
||||
|
||||
case SYN_OLDABS:
|
||||
return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx];
|
||||
|
||||
default:
|
||||
printk(KERN_ERR "synaptics: unknown packet type %d\n", pkt_type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
if (!synaptics_validate_byte(psmouse->packet, i, SYN_NEWABS_STRICT)) {
|
||||
printk(KERN_INFO "synaptics: using relaxed packet validation\n");
|
||||
return SYN_NEWABS_RELAXED;
|
||||
}
|
||||
|
||||
return SYN_NEWABS_STRICT;
|
||||
}
|
||||
|
||||
static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
|
||||
{
|
||||
struct input_dev *dev = &psmouse->dev;
|
||||
struct synaptics_data *priv = psmouse->private;
|
||||
|
||||
input_regs(dev, regs);
|
||||
|
||||
if (psmouse->pktcnt >= 6) { /* Full packet received */
|
||||
if (unlikely(priv->pkt_type == SYN_NEWABS))
|
||||
priv->pkt_type = synaptics_detect_pkt_type(psmouse);
|
||||
|
||||
if (SYN_CAP_PASS_THROUGH(priv->capabilities) && synaptics_is_pt_packet(psmouse->packet)) {
|
||||
if (psmouse->serio->child)
|
||||
synaptics_pass_pt_packet(psmouse->serio->child, psmouse->packet);
|
||||
} else
|
||||
synaptics_process_packet(psmouse);
|
||||
|
||||
return PSMOUSE_FULL_PACKET;
|
||||
}
|
||||
|
||||
return synaptics_validate_byte(psmouse->packet, psmouse->pktcnt - 1, priv->pkt_type) ?
|
||||
PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Driver initialization/cleanup functions
|
||||
****************************************************************************/
|
||||
static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
set_bit(EV_ABS, dev->evbit);
|
||||
input_set_abs_params(dev, ABS_X, XMIN_NOMINAL, XMAX_NOMINAL, 0, 0);
|
||||
input_set_abs_params(dev, ABS_Y, YMIN_NOMINAL, YMAX_NOMINAL, 0, 0);
|
||||
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
|
||||
set_bit(ABS_TOOL_WIDTH, dev->absbit);
|
||||
|
||||
set_bit(EV_KEY, dev->evbit);
|
||||
set_bit(BTN_TOUCH, dev->keybit);
|
||||
set_bit(BTN_TOOL_FINGER, dev->keybit);
|
||||
set_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
|
||||
set_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
|
||||
|
||||
set_bit(BTN_LEFT, dev->keybit);
|
||||
set_bit(BTN_RIGHT, dev->keybit);
|
||||
|
||||
if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities))
|
||||
set_bit(BTN_MIDDLE, dev->keybit);
|
||||
|
||||
if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) {
|
||||
set_bit(BTN_FORWARD, dev->keybit);
|
||||
set_bit(BTN_BACK, dev->keybit);
|
||||
}
|
||||
|
||||
for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++)
|
||||
set_bit(BTN_0 + i, dev->keybit);
|
||||
|
||||
clear_bit(EV_REL, dev->evbit);
|
||||
clear_bit(REL_X, dev->relbit);
|
||||
clear_bit(REL_Y, dev->relbit);
|
||||
}
|
||||
|
||||
void synaptics_reset(struct psmouse *psmouse)
|
||||
{
|
||||
/* reset touchpad back to relative mode, gestures enabled */
|
||||
synaptics_mode_cmd(psmouse, 0);
|
||||
}
|
||||
|
||||
static void synaptics_disconnect(struct psmouse *psmouse)
|
||||
{
|
||||
synaptics_reset(psmouse);
|
||||
kfree(psmouse->private);
|
||||
}
|
||||
|
||||
static int synaptics_reconnect(struct psmouse *psmouse)
|
||||
{
|
||||
struct synaptics_data *priv = psmouse->private;
|
||||
struct synaptics_data old_priv = *priv;
|
||||
|
||||
if (!synaptics_detect(psmouse))
|
||||
return -1;
|
||||
|
||||
if (synaptics_query_hardware(psmouse)) {
|
||||
printk(KERN_ERR "Unable to query Synaptics hardware.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (old_priv.identity != priv->identity ||
|
||||
old_priv.model_id != priv->model_id ||
|
||||
old_priv.capabilities != priv->capabilities ||
|
||||
old_priv.ext_cap != priv->ext_cap)
|
||||
return -1;
|
||||
|
||||
if (synaptics_set_mode(psmouse, 0)) {
|
||||
printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int synaptics_detect(struct psmouse *psmouse)
|
||||
{
|
||||
unsigned char param[4];
|
||||
|
||||
param[0] = 0;
|
||||
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
|
||||
psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
|
||||
|
||||
return param[1] == 0x47;
|
||||
}
|
||||
|
||||
int synaptics_init(struct psmouse *psmouse)
|
||||
{
|
||||
struct synaptics_data *priv;
|
||||
|
||||
psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -1;
|
||||
memset(priv, 0, sizeof(struct synaptics_data));
|
||||
|
||||
if (synaptics_query_hardware(psmouse)) {
|
||||
printk(KERN_ERR "Unable to query Synaptics hardware.\n");
|
||||
goto init_fail;
|
||||
}
|
||||
|
||||
if (synaptics_set_mode(psmouse, 0)) {
|
||||
printk(KERN_ERR "Unable to initialize Synaptics hardware.\n");
|
||||
goto init_fail;
|
||||
}
|
||||
|
||||
priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
|
||||
|
||||
if (SYN_CAP_PASS_THROUGH(priv->capabilities))
|
||||
synaptics_pt_create(psmouse);
|
||||
|
||||
print_ident(priv);
|
||||
set_input_params(&psmouse->dev, priv);
|
||||
|
||||
psmouse->protocol_handler = synaptics_process_byte;
|
||||
psmouse->disconnect = synaptics_disconnect;
|
||||
psmouse->reconnect = synaptics_reconnect;
|
||||
|
||||
return 0;
|
||||
|
||||
init_fail:
|
||||
kfree(priv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
109
extra/linux-2.6.10/drivers/input/mouse/synaptics.h
Normal file
109
extra/linux-2.6.10/drivers/input/mouse/synaptics.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Synaptics TouchPad PS/2 mouse driver
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _SYNAPTICS_H
|
||||
#define _SYNAPTICS_H
|
||||
|
||||
extern int synaptics_detect(struct psmouse *psmouse);
|
||||
extern int synaptics_init(struct psmouse *psmouse);
|
||||
extern void synaptics_reset(struct psmouse *psmouse);
|
||||
|
||||
/* synaptics queries */
|
||||
#define SYN_QUE_IDENTIFY 0x00
|
||||
#define SYN_QUE_MODES 0x01
|
||||
#define SYN_QUE_CAPABILITIES 0x02
|
||||
#define SYN_QUE_MODEL 0x03
|
||||
#define SYN_QUE_SERIAL_NUMBER_PREFIX 0x06
|
||||
#define SYN_QUE_SERIAL_NUMBER_SUFFIX 0x07
|
||||
#define SYN_QUE_RESOLUTION 0x08
|
||||
#define SYN_QUE_EXT_CAPAB 0x09
|
||||
|
||||
/* synatics modes */
|
||||
#define SYN_BIT_ABSOLUTE_MODE (1 << 7)
|
||||
#define SYN_BIT_HIGH_RATE (1 << 6)
|
||||
#define SYN_BIT_SLEEP_MODE (1 << 3)
|
||||
#define SYN_BIT_DISABLE_GESTURE (1 << 2)
|
||||
#define SYN_BIT_FOUR_BYTE_CLIENT (1 << 1)
|
||||
#define SYN_BIT_W_MODE (1 << 0)
|
||||
|
||||
/* synaptics model ID bits */
|
||||
#define SYN_MODEL_ROT180(m) ((m) & (1 << 23))
|
||||
#define SYN_MODEL_PORTRAIT(m) ((m) & (1 << 22))
|
||||
#define SYN_MODEL_SENSOR(m) (((m) >> 16) & 0x3f)
|
||||
#define SYN_MODEL_HARDWARE(m) (((m) >> 9) & 0x7f)
|
||||
#define SYN_MODEL_NEWABS(m) ((m) & (1 << 7))
|
||||
#define SYN_MODEL_PEN(m) ((m) & (1 << 6))
|
||||
#define SYN_MODEL_SIMPLIC(m) ((m) & (1 << 5))
|
||||
#define SYN_MODEL_GEOMETRY(m) ((m) & 0x0f)
|
||||
|
||||
/* synaptics capability bits */
|
||||
#define SYN_CAP_EXTENDED(c) ((c) & (1 << 23))
|
||||
#define SYN_CAP_MIDDLE_BUTTON(c) ((c) & (1 << 18))
|
||||
#define SYN_CAP_PASS_THROUGH(c) ((c) & (1 << 7))
|
||||
#define SYN_CAP_SLEEP(c) ((c) & (1 << 4))
|
||||
#define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3))
|
||||
#define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1))
|
||||
#define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0))
|
||||
#define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47)
|
||||
#define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20)
|
||||
#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12)
|
||||
|
||||
/* synaptics modes query bits */
|
||||
#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
|
||||
#define SYN_MODE_RATE(m) ((m) & (1 << 6))
|
||||
#define SYN_MODE_BAUD_SLEEP(m) ((m) & (1 << 3))
|
||||
#define SYN_MODE_DISABLE_GESTURE(m) ((m) & (1 << 2))
|
||||
#define SYN_MODE_PACKSIZE(m) ((m) & (1 << 1))
|
||||
#define SYN_MODE_WMODE(m) ((m) & (1 << 0))
|
||||
|
||||
/* synaptics identify query bits */
|
||||
#define SYN_ID_MODEL(i) (((i) >> 4) & 0x0f)
|
||||
#define SYN_ID_MAJOR(i) ((i) & 0x0f)
|
||||
#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff)
|
||||
#define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47)
|
||||
|
||||
/* synaptics special commands */
|
||||
#define SYN_PS_SET_MODE2 0x14
|
||||
#define SYN_PS_CLIENT_CMD 0x28
|
||||
|
||||
/* synaptics packet types */
|
||||
#define SYN_NEWABS 0
|
||||
#define SYN_NEWABS_STRICT 1
|
||||
#define SYN_NEWABS_RELAXED 2
|
||||
#define SYN_OLDABS 3
|
||||
|
||||
/*
|
||||
* A structure to describe the state of the touchpad hardware (buttons and pad)
|
||||
*/
|
||||
|
||||
struct synaptics_hw_state {
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
int w;
|
||||
unsigned int left:1;
|
||||
unsigned int right:1;
|
||||
unsigned int middle:1;
|
||||
unsigned int up:1;
|
||||
unsigned int down:1;
|
||||
unsigned char ext_buttons;
|
||||
};
|
||||
|
||||
struct synaptics_data {
|
||||
/* Data read from the touchpad */
|
||||
unsigned long int model_id; /* Model-ID */
|
||||
unsigned long int capabilities; /* Capabilities */
|
||||
unsigned long int ext_cap; /* Extended Capabilities */
|
||||
unsigned long int identity; /* Identification */
|
||||
|
||||
/* Data for normal processing */
|
||||
int old_w; /* Previous w value */
|
||||
unsigned char pkt_type; /* packet type - old, new, etc */
|
||||
};
|
||||
|
||||
#endif /* _SYNAPTICS_H */
|
||||
BIN
extra/linux-2.6.10/drivers/input/mouse/synaptics.o
Normal file
BIN
extra/linux-2.6.10/drivers/input/mouse/synaptics.o
Normal file
Binary file not shown.
570
extra/linux-2.6.10/drivers/input/mouse/vsxxxaa.c
Normal file
570
extra/linux-2.6.10/drivers/input/mouse/vsxxxaa.c
Normal file
@@ -0,0 +1,570 @@
|
||||
/*
|
||||
* DEC VSXXX-AA and VSXXX-GA mouse driver.
|
||||
*
|
||||
* Copyright (C) 2003-2004 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
|
||||
*
|
||||
* The packet format was taken from a patch to GPM which is (C) 2001
|
||||
* by Karsten Merker <merker@linuxtag.org>
|
||||
* and Maciej W. Rozycki <macro@ds2.pg.gda.pl>
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Building an adaptor to DB9 / DB25 RS232
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* DISCLAIMER: Use this description AT YOUR OWN RISK! I'll not pay for
|
||||
* anything if you break your mouse, your computer or whatever!
|
||||
*
|
||||
* In theory, this mouse is a simple RS232 device. In practice, it has got
|
||||
* a quite uncommon plug and the requirement to additionally get a power
|
||||
* supply at +5V and -12V.
|
||||
*
|
||||
* If you look at the socket/jack (_not_ at the plug), we use this pin
|
||||
* numbering:
|
||||
* _______
|
||||
* / 7 6 5 \
|
||||
* | 4 --- 3 |
|
||||
* \ 2 1 /
|
||||
* -------
|
||||
*
|
||||
* DEC socket DB9 DB25 Note
|
||||
* 1 (GND) 5 7 -
|
||||
* 2 (RxD) 2 3 -
|
||||
* 3 (TxD) 3 2 -
|
||||
* 4 (-12V) - - Somewhere from the PSU. At ATX, it's
|
||||
* the thin blue wire at pin 12 of the
|
||||
* ATX power connector. Only required for
|
||||
* VSXXX-AA/-GA mice.
|
||||
* 5 (+5V) - - PSU (red wires of ATX power connector
|
||||
* on pin 4, 6, 19 or 20) or HDD power
|
||||
* connector (also red wire).
|
||||
* 6 (+12V) - - HDD power connector, yellow wire. Only
|
||||
* required for VSXXX-AB digitizer.
|
||||
* 7 (dev. avail.) - - The mouse shorts this one to pin 1.
|
||||
* This way, the host computer can detect
|
||||
* the mouse. To use it with the adaptor,
|
||||
* simply don't connect this pin.
|
||||
*
|
||||
* So to get a working adaptor, you need to connect the mouse with three
|
||||
* wires to a RS232 port and two or three additional wires for +5V, +12V and
|
||||
* -12V to the PSU.
|
||||
*
|
||||
* Flow specification for the link is 4800, 8o1.
|
||||
*
|
||||
* The mice and tablet are described in "VCB02 Video Subsystem - Technical
|
||||
* Manual", DEC EK-104AA-TM-001. You'll find it at MANX, a search engine
|
||||
* specific for DEC documentation. Try
|
||||
* http://www.vt100.net/manx/details?pn=EK-104AA-TM-001;id=21;cp=1
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/config.h>
|
||||
#include <linux/serio.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#define DRIVER_DESC "Serial DEC VSXXX-AA/GA mouse / DEC tablet driver"
|
||||
|
||||
MODULE_AUTHOR ("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
|
||||
MODULE_DESCRIPTION (DRIVER_DESC);
|
||||
MODULE_LICENSE ("GPL");
|
||||
|
||||
#undef VSXXXAA_DEBUG
|
||||
#ifdef VSXXXAA_DEBUG
|
||||
#define DBG(x...) printk (x)
|
||||
#else
|
||||
#define DBG(x...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define VSXXXAA_INTRO_MASK 0x80
|
||||
#define VSXXXAA_INTRO_HEAD 0x80
|
||||
#define IS_HDR_BYTE(x) (((x) & VSXXXAA_INTRO_MASK) \
|
||||
== VSXXXAA_INTRO_HEAD)
|
||||
|
||||
#define VSXXXAA_PACKET_MASK 0xe0
|
||||
#define VSXXXAA_PACKET_REL 0x80
|
||||
#define VSXXXAA_PACKET_ABS 0xc0
|
||||
#define VSXXXAA_PACKET_POR 0xa0
|
||||
#define MATCH_PACKET_TYPE(data, type) (((data) & VSXXXAA_PACKET_MASK) == type)
|
||||
|
||||
|
||||
|
||||
struct vsxxxaa {
|
||||
struct input_dev dev;
|
||||
struct serio *serio;
|
||||
#define BUFLEN 15 /* At least 5 is needed for a full tablet packet */
|
||||
unsigned char buf[BUFLEN];
|
||||
unsigned char count;
|
||||
unsigned char version;
|
||||
unsigned char country;
|
||||
unsigned char type;
|
||||
char name[64];
|
||||
char phys[32];
|
||||
};
|
||||
|
||||
static void
|
||||
vsxxxaa_drop_bytes (struct vsxxxaa *mouse, int num)
|
||||
{
|
||||
if (num >= mouse->count)
|
||||
mouse->count = 0;
|
||||
else {
|
||||
memmove (mouse->buf, mouse->buf + num - 1, BUFLEN - num);
|
||||
mouse->count -= num;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
vsxxxaa_queue_byte (struct vsxxxaa *mouse, unsigned char byte)
|
||||
{
|
||||
if (mouse->count == BUFLEN) {
|
||||
printk (KERN_ERR "%s on %s: Dropping a byte of full buffer.\n",
|
||||
mouse->name, mouse->phys);
|
||||
vsxxxaa_drop_bytes (mouse, 1);
|
||||
}
|
||||
DBG (KERN_INFO "Queueing byte 0x%02x\n", byte);
|
||||
|
||||
mouse->buf[mouse->count++] = byte;
|
||||
}
|
||||
|
||||
static void
|
||||
vsxxxaa_detection_done (struct vsxxxaa *mouse)
|
||||
{
|
||||
switch (mouse->type) {
|
||||
case 0x02:
|
||||
sprintf (mouse->name, "DEC VSXXX-AA/GA mouse");
|
||||
break;
|
||||
|
||||
case 0x04:
|
||||
sprintf (mouse->name, "DEC VSXXX-AB digitizer");
|
||||
break;
|
||||
|
||||
default:
|
||||
sprintf (mouse->name, "unknown DEC pointer device");
|
||||
break;
|
||||
}
|
||||
|
||||
printk (KERN_INFO "Found %s version 0x%02x from country 0x%02x "
|
||||
"on port %s\n", mouse->name, mouse->version,
|
||||
mouse->country, mouse->phys);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns number of bytes to be dropped, 0 if packet is okay.
|
||||
*/
|
||||
static int
|
||||
vsxxxaa_check_packet (struct vsxxxaa *mouse, int packet_len)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* First byte must be a header byte */
|
||||
if (!IS_HDR_BYTE (mouse->buf[0])) {
|
||||
DBG ("vsck: len=%d, 1st=0x%02x\n", packet_len, mouse->buf[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check all following bytes */
|
||||
if (packet_len > 1) {
|
||||
for (i = 1; i < packet_len; i++) {
|
||||
if (IS_HDR_BYTE (mouse->buf[i])) {
|
||||
printk (KERN_ERR "Need to drop %d bytes "
|
||||
"of a broken packet.\n",
|
||||
i - 1);
|
||||
DBG (KERN_INFO "check: len=%d, b[%d]=0x%02x\n",
|
||||
packet_len, i, mouse->buf[i]);
|
||||
return i - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __inline__ int
|
||||
vsxxxaa_smells_like_packet (struct vsxxxaa *mouse, unsigned char type, size_t len)
|
||||
{
|
||||
return (mouse->count >= len) && MATCH_PACKET_TYPE (mouse->buf[0], type);
|
||||
}
|
||||
|
||||
static void
|
||||
vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse, struct pt_regs *regs)
|
||||
{
|
||||
struct input_dev *dev = &mouse->dev;
|
||||
unsigned char *buf = mouse->buf;
|
||||
int left, middle, right;
|
||||
int dx, dy;
|
||||
|
||||
/*
|
||||
* Check for normal stream packets. This is three bytes,
|
||||
* with the first byte's 3 MSB set to 100.
|
||||
*
|
||||
* [0]: 1 0 0 SignX SignY Left Middle Right
|
||||
* [1]: 0 dx dx dx dx dx dx dx
|
||||
* [2]: 0 dy dy dy dy dy dy dy
|
||||
*/
|
||||
|
||||
/*
|
||||
* Low 7 bit of byte 1 are abs(dx), bit 7 is
|
||||
* 0, bit 4 of byte 0 is direction.
|
||||
*/
|
||||
dx = buf[1] & 0x7f;
|
||||
dx *= ((buf[0] >> 4) & 0x01)? 1: -1;
|
||||
|
||||
/*
|
||||
* Low 7 bit of byte 2 are abs(dy), bit 7 is
|
||||
* 0, bit 3 of byte 0 is direction.
|
||||
*/
|
||||
dy = buf[2] & 0x7f;
|
||||
dy *= ((buf[0] >> 3) & 0x01)? -1: 1;
|
||||
|
||||
/*
|
||||
* Get button state. It's the low three bits
|
||||
* (for three buttons) of byte 0.
|
||||
*/
|
||||
left = (buf[0] & 0x04)? 1: 0;
|
||||
middle = (buf[0] & 0x02)? 1: 0;
|
||||
right = (buf[0] & 0x01)? 1: 0;
|
||||
|
||||
vsxxxaa_drop_bytes (mouse, 3);
|
||||
|
||||
DBG (KERN_INFO "%s on %s: dx=%d, dy=%d, buttons=%s%s%s\n",
|
||||
mouse->name, mouse->phys, dx, dy,
|
||||
left? "L": "l", middle? "M": "m", right? "R": "r");
|
||||
|
||||
/*
|
||||
* Report what we've found so far...
|
||||
*/
|
||||
input_regs (dev, regs);
|
||||
input_report_key (dev, BTN_LEFT, left);
|
||||
input_report_key (dev, BTN_MIDDLE, middle);
|
||||
input_report_key (dev, BTN_RIGHT, right);
|
||||
input_report_key (dev, BTN_TOUCH, 0);
|
||||
input_report_rel (dev, REL_X, dx);
|
||||
input_report_rel (dev, REL_Y, dy);
|
||||
input_sync (dev);
|
||||
}
|
||||
|
||||
static void
|
||||
vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse, struct pt_regs *regs)
|
||||
{
|
||||
struct input_dev *dev = &mouse->dev;
|
||||
unsigned char *buf = mouse->buf;
|
||||
int left, middle, right, touch;
|
||||
int x, y;
|
||||
|
||||
/*
|
||||
* Tablet position / button packet
|
||||
*
|
||||
* [0]: 1 1 0 B4 B3 B2 B1 Pr
|
||||
* [1]: 0 0 X5 X4 X3 X2 X1 X0
|
||||
* [2]: 0 0 X11 X10 X9 X8 X7 X6
|
||||
* [3]: 0 0 Y5 Y4 Y3 Y2 Y1 Y0
|
||||
* [4]: 0 0 Y11 Y10 Y9 Y8 Y7 Y6
|
||||
*/
|
||||
|
||||
/*
|
||||
* Get X/Y position. Y axis needs to be inverted since VSXXX-AB
|
||||
* counts down->top while monitor counts top->bottom.
|
||||
*/
|
||||
x = ((buf[2] & 0x3f) << 6) | (buf[1] & 0x3f);
|
||||
y = ((buf[4] & 0x3f) << 6) | (buf[3] & 0x3f);
|
||||
y = 1023 - y;
|
||||
|
||||
/*
|
||||
* Get button state. It's bits <4..1> of byte 0.
|
||||
*/
|
||||
left = (buf[0] & 0x02)? 1: 0;
|
||||
middle = (buf[0] & 0x04)? 1: 0;
|
||||
right = (buf[0] & 0x08)? 1: 0;
|
||||
touch = (buf[0] & 0x10)? 1: 0;
|
||||
|
||||
vsxxxaa_drop_bytes (mouse, 5);
|
||||
|
||||
DBG (KERN_INFO "%s on %s: x=%d, y=%d, buttons=%s%s%s%s\n",
|
||||
mouse->name, mouse->phys, x, y,
|
||||
left? "L": "l", middle? "M": "m",
|
||||
right? "R": "r", touch? "T": "t");
|
||||
|
||||
/*
|
||||
* Report what we've found so far...
|
||||
*/
|
||||
input_regs (dev, regs);
|
||||
input_report_key (dev, BTN_LEFT, left);
|
||||
input_report_key (dev, BTN_MIDDLE, middle);
|
||||
input_report_key (dev, BTN_RIGHT, right);
|
||||
input_report_key (dev, BTN_TOUCH, touch);
|
||||
input_report_abs (dev, ABS_X, x);
|
||||
input_report_abs (dev, ABS_Y, y);
|
||||
input_sync (dev);
|
||||
}
|
||||
|
||||
static void
|
||||
vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse, struct pt_regs *regs)
|
||||
{
|
||||
struct input_dev *dev = &mouse->dev;
|
||||
unsigned char *buf = mouse->buf;
|
||||
int left, middle, right;
|
||||
unsigned char error;
|
||||
|
||||
/*
|
||||
* Check for Power-On-Reset packets. These are sent out
|
||||
* after plugging the mouse in, or when explicitely
|
||||
* requested by sending 'T'.
|
||||
*
|
||||
* [0]: 1 0 1 0 R3 R2 R1 R0
|
||||
* [1]: 0 M2 M1 M0 D3 D2 D1 D0
|
||||
* [2]: 0 E6 E5 E4 E3 E2 E1 E0
|
||||
* [3]: 0 0 0 0 0 Left Middle Right
|
||||
*
|
||||
* M: manufacturer location code
|
||||
* R: revision code
|
||||
* E: Error code. I'm not sure about these, but gpm's sources,
|
||||
* which support this mouse, too, tell about them:
|
||||
* E = [0x00 .. 0x1f]: no error, byte #3 is button state
|
||||
* E = 0x3d: button error, byte #3 tells which one.
|
||||
* E = <else>: other error
|
||||
* D: <0010> == mouse, <0100> == tablet
|
||||
*
|
||||
*/
|
||||
|
||||
mouse->version = buf[0] & 0x0f;
|
||||
mouse->country = (buf[1] >> 4) & 0x07;
|
||||
mouse->type = buf[1] & 0x0f;
|
||||
error = buf[2] & 0x7f;
|
||||
|
||||
/*
|
||||
* Get button state. It's the low three bits
|
||||
* (for three buttons) of byte 0. Maybe even the bit <3>
|
||||
* has some meaning if a tablet is attached.
|
||||
*/
|
||||
left = (buf[0] & 0x04)? 1: 0;
|
||||
middle = (buf[0] & 0x02)? 1: 0;
|
||||
right = (buf[0] & 0x01)? 1: 0;
|
||||
|
||||
vsxxxaa_drop_bytes (mouse, 4);
|
||||
vsxxxaa_detection_done (mouse);
|
||||
|
||||
if (error <= 0x1f) {
|
||||
/* No error. Report buttons */
|
||||
input_regs (dev, regs);
|
||||
input_report_key (dev, BTN_LEFT, left);
|
||||
input_report_key (dev, BTN_MIDDLE, middle);
|
||||
input_report_key (dev, BTN_RIGHT, right);
|
||||
input_report_key (dev, BTN_TOUCH, 0);
|
||||
input_sync (dev);
|
||||
} else {
|
||||
printk (KERN_ERR "Your %s on %s reports an undefined error, "
|
||||
"please check it...\n", mouse->name,
|
||||
mouse->phys);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the mouse was hot-plugged, we need to force differential mode
|
||||
* now... However, give it a second to recover from it's reset.
|
||||
*/
|
||||
printk (KERN_NOTICE "%s on %s: Forceing standard packet format and "
|
||||
"streaming mode\n", mouse->name, mouse->phys);
|
||||
mouse->serio->write (mouse->serio, 'S');
|
||||
mdelay (50);
|
||||
mouse->serio->write (mouse->serio, 'R');
|
||||
}
|
||||
|
||||
static void
|
||||
vsxxxaa_parse_buffer (struct vsxxxaa *mouse, struct pt_regs *regs)
|
||||
{
|
||||
unsigned char *buf = mouse->buf;
|
||||
int stray_bytes;
|
||||
|
||||
/*
|
||||
* Parse buffer to death...
|
||||
*/
|
||||
do {
|
||||
/*
|
||||
* Out of sync? Throw away what we don't understand. Each
|
||||
* packet starts with a byte whose bit 7 is set. Unhandled
|
||||
* packets (ie. which we don't know about or simply b0rk3d
|
||||
* data...) will get shifted out of the buffer after some
|
||||
* activity on the mouse.
|
||||
*/
|
||||
while (mouse->count > 0 && !IS_HDR_BYTE(buf[0])) {
|
||||
printk (KERN_ERR "%s on %s: Dropping a byte to regain "
|
||||
"sync with mouse data stream...\n",
|
||||
mouse->name, mouse->phys);
|
||||
vsxxxaa_drop_bytes (mouse, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for packets we know about.
|
||||
*/
|
||||
|
||||
if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_REL, 3)) {
|
||||
/* Check for broken packet */
|
||||
stray_bytes = vsxxxaa_check_packet (mouse, 3);
|
||||
if (stray_bytes > 0) {
|
||||
printk (KERN_ERR "Dropping %d bytes now...\n",
|
||||
stray_bytes);
|
||||
vsxxxaa_drop_bytes (mouse, stray_bytes);
|
||||
continue;
|
||||
}
|
||||
|
||||
vsxxxaa_handle_REL_packet (mouse, regs);
|
||||
continue; /* More to parse? */
|
||||
}
|
||||
|
||||
if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_ABS, 5)) {
|
||||
/* Check for broken packet */
|
||||
stray_bytes = vsxxxaa_check_packet (mouse, 5);
|
||||
if (stray_bytes > 0) {
|
||||
printk (KERN_ERR "Dropping %d bytes now...\n",
|
||||
stray_bytes);
|
||||
vsxxxaa_drop_bytes (mouse, stray_bytes);
|
||||
continue;
|
||||
}
|
||||
|
||||
vsxxxaa_handle_ABS_packet (mouse, regs);
|
||||
continue; /* More to parse? */
|
||||
}
|
||||
|
||||
if (vsxxxaa_smells_like_packet (mouse, VSXXXAA_PACKET_POR, 4)) {
|
||||
/* Check for broken packet */
|
||||
stray_bytes = vsxxxaa_check_packet (mouse, 4);
|
||||
if (stray_bytes > 0) {
|
||||
printk (KERN_ERR "Dropping %d bytes now...\n",
|
||||
stray_bytes);
|
||||
vsxxxaa_drop_bytes (mouse, stray_bytes);
|
||||
continue;
|
||||
}
|
||||
|
||||
vsxxxaa_handle_POR_packet (mouse, regs);
|
||||
continue; /* More to parse? */
|
||||
}
|
||||
|
||||
break; /* No REL, ABS or POR packet found */
|
||||
} while (1);
|
||||
}
|
||||
|
||||
static irqreturn_t
|
||||
vsxxxaa_interrupt (struct serio *serio, unsigned char data, unsigned int flags,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
struct vsxxxaa *mouse = serio->private;
|
||||
|
||||
vsxxxaa_queue_byte (mouse, data);
|
||||
vsxxxaa_parse_buffer (mouse, regs);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void
|
||||
vsxxxaa_disconnect (struct serio *serio)
|
||||
{
|
||||
struct vsxxxaa *mouse = serio->private;
|
||||
|
||||
input_unregister_device (&mouse->dev);
|
||||
serio_close (serio);
|
||||
kfree (mouse);
|
||||
}
|
||||
|
||||
static void
|
||||
vsxxxaa_connect (struct serio *serio, struct serio_driver *drv)
|
||||
{
|
||||
struct vsxxxaa *mouse;
|
||||
|
||||
if ((serio->type & SERIO_TYPE) != SERIO_RS232)
|
||||
return;
|
||||
if ((serio->type & SERIO_PROTO) != SERIO_VSXXXAA)
|
||||
return;
|
||||
|
||||
if (!(mouse = kmalloc (sizeof (struct vsxxxaa), GFP_KERNEL)))
|
||||
return;
|
||||
|
||||
memset (mouse, 0, sizeof (struct vsxxxaa));
|
||||
|
||||
init_input_dev (&mouse->dev);
|
||||
set_bit (EV_KEY, mouse->dev.evbit); /* We have buttons */
|
||||
set_bit (EV_REL, mouse->dev.evbit);
|
||||
set_bit (EV_ABS, mouse->dev.evbit);
|
||||
set_bit (BTN_LEFT, mouse->dev.keybit); /* We have 3 buttons */
|
||||
set_bit (BTN_MIDDLE, mouse->dev.keybit);
|
||||
set_bit (BTN_RIGHT, mouse->dev.keybit);
|
||||
set_bit (BTN_TOUCH, mouse->dev.keybit); /* ...and Tablet */
|
||||
set_bit (REL_X, mouse->dev.relbit);
|
||||
set_bit (REL_Y, mouse->dev.relbit);
|
||||
set_bit (ABS_X, mouse->dev.absbit);
|
||||
set_bit (ABS_Y, mouse->dev.absbit);
|
||||
|
||||
mouse->dev.absmin[ABS_X] = 0;
|
||||
mouse->dev.absmax[ABS_X] = 1023;
|
||||
mouse->dev.absmin[ABS_Y] = 0;
|
||||
mouse->dev.absmax[ABS_Y] = 1023;
|
||||
|
||||
mouse->dev.private = mouse;
|
||||
serio->private = mouse;
|
||||
|
||||
sprintf (mouse->name, "DEC VSXXX-AA/GA mouse or VSXXX-AB digitizer");
|
||||
sprintf (mouse->phys, "%s/input0", serio->phys);
|
||||
mouse->dev.name = mouse->name;
|
||||
mouse->dev.phys = mouse->phys;
|
||||
mouse->dev.id.bustype = BUS_RS232;
|
||||
mouse->serio = serio;
|
||||
|
||||
if (serio_open (serio, drv)) {
|
||||
kfree (mouse);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Request selftest. Standard packet format and differential
|
||||
* mode will be requested after the device ID'ed successfully.
|
||||
*/
|
||||
mouse->serio->write (mouse->serio, 'T'); /* Test */
|
||||
|
||||
input_register_device (&mouse->dev);
|
||||
|
||||
printk (KERN_INFO "input: %s on %s\n", mouse->name, mouse->phys);
|
||||
}
|
||||
|
||||
static struct serio_driver vsxxxaa_drv = {
|
||||
.driver = {
|
||||
.name = "vsxxxaa",
|
||||
},
|
||||
.description = DRIVER_DESC,
|
||||
.connect = vsxxxaa_connect,
|
||||
.interrupt = vsxxxaa_interrupt,
|
||||
.disconnect = vsxxxaa_disconnect,
|
||||
};
|
||||
|
||||
int __init
|
||||
vsxxxaa_init (void)
|
||||
{
|
||||
serio_register_driver(&vsxxxaa_drv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit
|
||||
vsxxxaa_exit (void)
|
||||
{
|
||||
serio_unregister_driver(&vsxxxaa_drv);
|
||||
}
|
||||
|
||||
module_init (vsxxxaa_init);
|
||||
module_exit (vsxxxaa_exit);
|
||||
|
||||
739
extra/linux-2.6.10/drivers/input/mousedev.c
Normal file
739
extra/linux-2.6.10/drivers/input/mousedev.c
Normal file
@@ -0,0 +1,739 @@
|
||||
/*
|
||||
* Input driver to ExplorerPS/2 device driver module.
|
||||
*
|
||||
* Copyright (c) 1999-2002 Vojtech Pavlik
|
||||
* Copyright (c) 2004 Dmitry Torokhov
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#define MOUSEDEV_MINOR_BASE 32
|
||||
#define MOUSEDEV_MINORS 32
|
||||
#define MOUSEDEV_MIX 31
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/config.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/devfs_fs_kernel.h>
|
||||
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
|
||||
#include <linux/miscdevice.h>
|
||||
#endif
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Mouse (ExplorerPS/2) device interfaces");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X
|
||||
#define CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
|
||||
#endif
|
||||
#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_Y
|
||||
#define CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
|
||||
#endif
|
||||
|
||||
static int xres = CONFIG_INPUT_MOUSEDEV_SCREEN_X;
|
||||
module_param(xres, uint, 0);
|
||||
MODULE_PARM_DESC(xres, "Horizontal screen resolution");
|
||||
|
||||
static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y;
|
||||
module_param(yres, uint, 0);
|
||||
MODULE_PARM_DESC(yres, "Vertical screen resolution");
|
||||
|
||||
static unsigned tap_time = 200;
|
||||
module_param(tap_time, uint, 0);
|
||||
MODULE_PARM_DESC(tap_time, "Tap time for touchpads in absolute mode (msecs)");
|
||||
|
||||
struct mousedev_hw_data {
|
||||
int dx, dy, dz;
|
||||
int x, y;
|
||||
int abs_event;
|
||||
unsigned long buttons;
|
||||
};
|
||||
|
||||
struct mousedev {
|
||||
int exist;
|
||||
int open;
|
||||
int minor;
|
||||
char name[16];
|
||||
wait_queue_head_t wait;
|
||||
struct list_head list;
|
||||
struct input_handle handle;
|
||||
|
||||
struct mousedev_hw_data packet;
|
||||
unsigned int pkt_count;
|
||||
int old_x[4], old_y[4];
|
||||
unsigned long touch;
|
||||
};
|
||||
|
||||
enum mousedev_emul {
|
||||
MOUSEDEV_EMUL_PS2,
|
||||
MOUSEDEV_EMUL_IMPS,
|
||||
MOUSEDEV_EMUL_EXPS
|
||||
};
|
||||
|
||||
struct mousedev_motion {
|
||||
int dx, dy, dz;
|
||||
unsigned long buttons;
|
||||
};
|
||||
|
||||
#define PACKET_QUEUE_LEN 16
|
||||
struct mousedev_list {
|
||||
struct fasync_struct *fasync;
|
||||
struct mousedev *mousedev;
|
||||
struct list_head node;
|
||||
|
||||
struct mousedev_motion packets[PACKET_QUEUE_LEN];
|
||||
unsigned int head, tail;
|
||||
spinlock_t packet_lock;
|
||||
int pos_x, pos_y;
|
||||
|
||||
signed char ps2[6];
|
||||
unsigned char ready, buffer, bufsiz;
|
||||
unsigned char imexseq, impsseq;
|
||||
enum mousedev_emul mode;
|
||||
};
|
||||
|
||||
#define MOUSEDEV_SEQ_LEN 6
|
||||
|
||||
static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 };
|
||||
static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 };
|
||||
|
||||
static struct input_handler mousedev_handler;
|
||||
|
||||
static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
|
||||
static struct mousedev mousedev_mix;
|
||||
|
||||
#define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
|
||||
#define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
|
||||
|
||||
static void mousedev_touchpad_event(struct mousedev *mousedev, unsigned int code, int value)
|
||||
{
|
||||
if (mousedev->touch) {
|
||||
switch (code) {
|
||||
case ABS_X:
|
||||
fx(0) = value;
|
||||
if (mousedev->pkt_count >= 2)
|
||||
mousedev->packet.dx = ((fx(0) - fx(1)) / 2 + (fx(1) - fx(2)) / 2) / 8;
|
||||
break;
|
||||
|
||||
case ABS_Y:
|
||||
fy(0) = value;
|
||||
if (mousedev->pkt_count >= 2)
|
||||
mousedev->packet.dy = -((fy(0) - fy(1)) / 2 + (fy(1) - fy(2)) / 2) / 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value)
|
||||
{
|
||||
int size;
|
||||
|
||||
switch (code) {
|
||||
case ABS_X:
|
||||
size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
|
||||
if (size == 0) size = xres;
|
||||
if (value > dev->absmax[ABS_X]) value = dev->absmax[ABS_X];
|
||||
if (value < dev->absmin[ABS_X]) value = dev->absmin[ABS_X];
|
||||
mousedev->packet.x = ((value - dev->absmin[ABS_X]) * xres) / size;
|
||||
mousedev->packet.abs_event = 1;
|
||||
break;
|
||||
|
||||
case ABS_Y:
|
||||
size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
|
||||
if (size == 0) size = yres;
|
||||
if (value > dev->absmax[ABS_Y]) value = dev->absmax[ABS_Y];
|
||||
if (value < dev->absmin[ABS_Y]) value = dev->absmin[ABS_Y];
|
||||
mousedev->packet.y = yres - ((value - dev->absmin[ABS_Y]) * yres) / size;
|
||||
mousedev->packet.abs_event = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void mousedev_rel_event(struct mousedev *mousedev, unsigned int code, int value)
|
||||
{
|
||||
switch (code) {
|
||||
case REL_X: mousedev->packet.dx += value; break;
|
||||
case REL_Y: mousedev->packet.dy -= value; break;
|
||||
case REL_WHEEL: mousedev->packet.dz -= value; break;
|
||||
}
|
||||
}
|
||||
|
||||
static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int value)
|
||||
{
|
||||
int index;
|
||||
|
||||
switch (code) {
|
||||
case BTN_TOUCH:
|
||||
case BTN_0:
|
||||
case BTN_FORWARD:
|
||||
case BTN_LEFT: index = 0; break;
|
||||
case BTN_STYLUS:
|
||||
case BTN_1:
|
||||
case BTN_RIGHT: index = 1; break;
|
||||
case BTN_2:
|
||||
case BTN_STYLUS2:
|
||||
case BTN_MIDDLE: index = 2; break;
|
||||
case BTN_3:
|
||||
case BTN_BACK:
|
||||
case BTN_SIDE: index = 3; break;
|
||||
case BTN_4:
|
||||
case BTN_EXTRA: index = 4; break;
|
||||
default: return;
|
||||
}
|
||||
|
||||
if (value) {
|
||||
set_bit(index, &mousedev->packet.buttons);
|
||||
set_bit(index, &mousedev_mix.packet.buttons);
|
||||
} else {
|
||||
clear_bit(index, &mousedev->packet.buttons);
|
||||
clear_bit(index, &mousedev_mix.packet.buttons);
|
||||
}
|
||||
}
|
||||
|
||||
static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet)
|
||||
{
|
||||
struct mousedev_list *list;
|
||||
struct mousedev_motion *p;
|
||||
unsigned long flags;
|
||||
|
||||
list_for_each_entry(list, &mousedev->list, node) {
|
||||
spin_lock_irqsave(&list->packet_lock, flags);
|
||||
|
||||
p = &list->packets[list->head];
|
||||
if (list->ready && p->buttons != packet->buttons) {
|
||||
unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN;
|
||||
if (new_head != list->tail) {
|
||||
p = &list->packets[list->head = new_head];
|
||||
memset(p, 0, sizeof(struct mousedev_motion));
|
||||
}
|
||||
}
|
||||
|
||||
if (packet->abs_event) {
|
||||
p->dx += packet->x - list->pos_x;
|
||||
p->dy += packet->y - list->pos_y;
|
||||
list->pos_x = packet->x;
|
||||
list->pos_y = packet->y;
|
||||
}
|
||||
|
||||
list->pos_x += packet->dx;
|
||||
list->pos_x = list->pos_x < 0 ? 0 : (list->pos_x >= xres ? xres : list->pos_x);
|
||||
list->pos_y += packet->dy;
|
||||
list->pos_y = list->pos_y < 0 ? 0 : (list->pos_y >= yres ? yres : list->pos_y);
|
||||
|
||||
p->dx += packet->dx;
|
||||
p->dy += packet->dy;
|
||||
p->dz += packet->dz;
|
||||
p->buttons = mousedev->packet.buttons;
|
||||
|
||||
list->ready = 1;
|
||||
|
||||
spin_unlock_irqrestore(&list->packet_lock, flags);
|
||||
kill_fasync(&list->fasync, SIGIO, POLL_IN);
|
||||
}
|
||||
|
||||
wake_up_interruptible(&mousedev->wait);
|
||||
}
|
||||
|
||||
static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
|
||||
{
|
||||
if (!value) {
|
||||
if (mousedev->touch &&
|
||||
time_before(jiffies, mousedev->touch + msecs_to_jiffies(tap_time))) {
|
||||
/*
|
||||
* Toggle left button to emulate tap.
|
||||
* We rely on the fact that mousedev_mix always has 0
|
||||
* motion packet so we won't mess current position.
|
||||
*/
|
||||
set_bit(0, &mousedev->packet.buttons);
|
||||
set_bit(0, &mousedev_mix.packet.buttons);
|
||||
mousedev_notify_readers(mousedev, &mousedev_mix.packet);
|
||||
mousedev_notify_readers(&mousedev_mix, &mousedev_mix.packet);
|
||||
clear_bit(0, &mousedev->packet.buttons);
|
||||
clear_bit(0, &mousedev_mix.packet.buttons);
|
||||
}
|
||||
mousedev->touch = mousedev->pkt_count = 0;
|
||||
}
|
||||
else
|
||||
if (!mousedev->touch)
|
||||
mousedev->touch = jiffies;
|
||||
}
|
||||
|
||||
static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
struct mousedev *mousedev = handle->private;
|
||||
|
||||
switch (type) {
|
||||
case EV_ABS:
|
||||
/* Ignore joysticks */
|
||||
if (test_bit(BTN_TRIGGER, handle->dev->keybit))
|
||||
return;
|
||||
|
||||
if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
|
||||
mousedev_touchpad_event(mousedev, code, value);
|
||||
else
|
||||
mousedev_abs_event(handle->dev, mousedev, code, value);
|
||||
|
||||
break;
|
||||
|
||||
case EV_REL:
|
||||
mousedev_rel_event(mousedev, code, value);
|
||||
break;
|
||||
|
||||
case EV_KEY:
|
||||
if (value != 2) {
|
||||
if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
|
||||
mousedev_touchpad_touch(mousedev, value);
|
||||
else
|
||||
mousedev_key_event(mousedev, code, value);
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_SYN:
|
||||
if (code == SYN_REPORT) {
|
||||
if (mousedev->touch) {
|
||||
mousedev->pkt_count++;
|
||||
/* Input system eats duplicate events, but we need all of them
|
||||
* to do correct averaging so apply present one forward
|
||||
*/
|
||||
fx(0) = fx(1);
|
||||
fy(0) = fy(1);
|
||||
}
|
||||
|
||||
mousedev_notify_readers(mousedev, &mousedev->packet);
|
||||
mousedev_notify_readers(&mousedev_mix, &mousedev->packet);
|
||||
|
||||
mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0;
|
||||
mousedev->packet.abs_event = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int mousedev_fasync(int fd, struct file *file, int on)
|
||||
{
|
||||
int retval;
|
||||
struct mousedev_list *list = file->private_data;
|
||||
retval = fasync_helper(fd, file, on, &list->fasync);
|
||||
return retval < 0 ? retval : 0;
|
||||
}
|
||||
|
||||
static void mousedev_free(struct mousedev *mousedev)
|
||||
{
|
||||
mousedev_table[mousedev->minor] = NULL;
|
||||
kfree(mousedev);
|
||||
}
|
||||
|
||||
static int mixdev_release(void)
|
||||
{
|
||||
struct input_handle *handle;
|
||||
|
||||
list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
|
||||
struct mousedev *mousedev = handle->private;
|
||||
|
||||
if (!mousedev->open) {
|
||||
if (mousedev->exist)
|
||||
input_close_device(&mousedev->handle);
|
||||
else
|
||||
mousedev_free(mousedev);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mousedev_release(struct inode * inode, struct file * file)
|
||||
{
|
||||
struct mousedev_list *list = file->private_data;
|
||||
|
||||
mousedev_fasync(-1, file, 0);
|
||||
|
||||
list_del(&list->node);
|
||||
|
||||
if (!--list->mousedev->open) {
|
||||
if (list->mousedev->minor == MOUSEDEV_MIX)
|
||||
return mixdev_release();
|
||||
|
||||
if (!mousedev_mix.open) {
|
||||
if (list->mousedev->exist)
|
||||
input_close_device(&list->mousedev->handle);
|
||||
else
|
||||
mousedev_free(list->mousedev);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mousedev_open(struct inode * inode, struct file * file)
|
||||
{
|
||||
struct mousedev_list *list;
|
||||
struct input_handle *handle;
|
||||
struct mousedev *mousedev;
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
|
||||
if (imajor(inode) == MISC_MAJOR)
|
||||
i = MOUSEDEV_MIX;
|
||||
else
|
||||
#endif
|
||||
i = iminor(inode) - MOUSEDEV_MINOR_BASE;
|
||||
|
||||
if (i >= MOUSEDEV_MINORS || !mousedev_table[i])
|
||||
return -ENODEV;
|
||||
|
||||
if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL)))
|
||||
return -ENOMEM;
|
||||
memset(list, 0, sizeof(struct mousedev_list));
|
||||
|
||||
spin_lock_init(&list->packet_lock);
|
||||
list->pos_x = xres / 2;
|
||||
list->pos_y = yres / 2;
|
||||
list->mousedev = mousedev_table[i];
|
||||
list_add_tail(&list->node, &mousedev_table[i]->list);
|
||||
file->private_data = list;
|
||||
|
||||
if (!list->mousedev->open++) {
|
||||
if (list->mousedev->minor == MOUSEDEV_MIX) {
|
||||
list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
|
||||
mousedev = handle->private;
|
||||
if (!mousedev->open && mousedev->exist)
|
||||
input_open_device(handle);
|
||||
}
|
||||
} else
|
||||
if (!mousedev_mix.open && list->mousedev->exist)
|
||||
input_open_device(&list->mousedev->handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int mousedev_limit_delta(int delta, int limit)
|
||||
{
|
||||
return delta > limit ? limit : (delta < -limit ? -limit : delta);
|
||||
}
|
||||
|
||||
static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data)
|
||||
{
|
||||
struct mousedev_motion *p;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&list->packet_lock, flags);
|
||||
p = &list->packets[list->tail];
|
||||
|
||||
ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
|
||||
ps2_data[1] = mousedev_limit_delta(p->dx, 127);
|
||||
ps2_data[2] = mousedev_limit_delta(p->dy, 127);
|
||||
p->dx -= ps2_data[1];
|
||||
p->dy -= ps2_data[2];
|
||||
|
||||
switch (list->mode) {
|
||||
case MOUSEDEV_EMUL_EXPS:
|
||||
ps2_data[3] = mousedev_limit_delta(p->dz, 127);
|
||||
p->dz -= ps2_data[3];
|
||||
ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
|
||||
list->bufsiz = 4;
|
||||
break;
|
||||
|
||||
case MOUSEDEV_EMUL_IMPS:
|
||||
ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
|
||||
ps2_data[3] = mousedev_limit_delta(p->dz, 127);
|
||||
p->dz -= ps2_data[3];
|
||||
list->bufsiz = 4;
|
||||
break;
|
||||
|
||||
case MOUSEDEV_EMUL_PS2:
|
||||
default:
|
||||
ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
|
||||
p->dz = 0;
|
||||
list->bufsiz = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!p->dx && !p->dy && !p->dz) {
|
||||
if (list->tail != list->head)
|
||||
list->tail = (list->tail + 1) % PACKET_QUEUE_LEN;
|
||||
if (list->tail == list->head)
|
||||
list->ready = 0;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&list->packet_lock, flags);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t mousedev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct mousedev_list *list = file->private_data;
|
||||
unsigned char c;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
|
||||
if (get_user(c, buffer + i))
|
||||
return -EFAULT;
|
||||
|
||||
if (c == mousedev_imex_seq[list->imexseq]) {
|
||||
if (++list->imexseq == MOUSEDEV_SEQ_LEN) {
|
||||
list->imexseq = 0;
|
||||
list->mode = MOUSEDEV_EMUL_EXPS;
|
||||
}
|
||||
} else list->imexseq = 0;
|
||||
|
||||
if (c == mousedev_imps_seq[list->impsseq]) {
|
||||
if (++list->impsseq == MOUSEDEV_SEQ_LEN) {
|
||||
list->impsseq = 0;
|
||||
list->mode = MOUSEDEV_EMUL_IMPS;
|
||||
}
|
||||
} else list->impsseq = 0;
|
||||
|
||||
list->ps2[0] = 0xfa;
|
||||
|
||||
switch (c) {
|
||||
|
||||
case 0xeb: /* Poll */
|
||||
mousedev_packet(list, &list->ps2[1]);
|
||||
list->bufsiz++; /* account for leading ACK */
|
||||
break;
|
||||
|
||||
case 0xf2: /* Get ID */
|
||||
switch (list->mode) {
|
||||
case MOUSEDEV_EMUL_PS2: list->ps2[1] = 0; break;
|
||||
case MOUSEDEV_EMUL_IMPS: list->ps2[1] = 3; break;
|
||||
case MOUSEDEV_EMUL_EXPS: list->ps2[1] = 4; break;
|
||||
}
|
||||
list->bufsiz = 2;
|
||||
break;
|
||||
|
||||
case 0xe9: /* Get info */
|
||||
list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 200;
|
||||
list->bufsiz = 4;
|
||||
break;
|
||||
|
||||
case 0xff: /* Reset */
|
||||
list->impsseq = list->imexseq = 0;
|
||||
list->mode = MOUSEDEV_EMUL_PS2;
|
||||
list->ps2[1] = 0xaa; list->ps2[2] = 0x00;
|
||||
list->bufsiz = 3;
|
||||
break;
|
||||
|
||||
default:
|
||||
list->bufsiz = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
list->buffer = list->bufsiz;
|
||||
}
|
||||
|
||||
kill_fasync(&list->fasync, SIGIO, POLL_IN);
|
||||
|
||||
wake_up_interruptible(&list->mousedev->wait);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct mousedev_list *list = file->private_data;
|
||||
int retval = 0;
|
||||
|
||||
if (!list->ready && !list->buffer && (file->f_flags & O_NONBLOCK))
|
||||
return -EAGAIN;
|
||||
|
||||
retval = wait_event_interruptible(list->mousedev->wait,
|
||||
!list->mousedev->exist || list->ready || list->buffer);
|
||||
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!list->mousedev->exist)
|
||||
return -ENODEV;
|
||||
|
||||
if (!list->buffer && list->ready) {
|
||||
mousedev_packet(list, list->ps2);
|
||||
list->buffer = list->bufsiz;
|
||||
}
|
||||
|
||||
if (count > list->buffer)
|
||||
count = list->buffer;
|
||||
|
||||
list->buffer -= count;
|
||||
|
||||
if (copy_to_user(buffer, list->ps2 + list->bufsiz - list->buffer - count, count))
|
||||
return -EFAULT;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* No kernel lock - fine */
|
||||
static unsigned int mousedev_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct mousedev_list *list = file->private_data;
|
||||
poll_wait(file, &list->mousedev->wait, wait);
|
||||
if (list->ready || list->buffer)
|
||||
return POLLIN | POLLRDNORM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct file_operations mousedev_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = mousedev_read,
|
||||
.write = mousedev_write,
|
||||
.poll = mousedev_poll,
|
||||
.open = mousedev_open,
|
||||
.release = mousedev_release,
|
||||
.fasync = mousedev_fasync,
|
||||
};
|
||||
|
||||
static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
|
||||
{
|
||||
struct mousedev *mousedev;
|
||||
int minor = 0;
|
||||
|
||||
for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
|
||||
if (minor == MOUSEDEV_MINORS) {
|
||||
printk(KERN_ERR "mousedev: no more free mousedev devices\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(mousedev = kmalloc(sizeof(struct mousedev), GFP_KERNEL)))
|
||||
return NULL;
|
||||
memset(mousedev, 0, sizeof(struct mousedev));
|
||||
|
||||
INIT_LIST_HEAD(&mousedev->list);
|
||||
init_waitqueue_head(&mousedev->wait);
|
||||
|
||||
mousedev->minor = minor;
|
||||
mousedev->exist = 1;
|
||||
mousedev->handle.dev = dev;
|
||||
mousedev->handle.name = mousedev->name;
|
||||
mousedev->handle.handler = handler;
|
||||
mousedev->handle.private = mousedev;
|
||||
sprintf(mousedev->name, "mouse%d", minor);
|
||||
|
||||
if (mousedev_mix.open)
|
||||
input_open_device(&mousedev->handle);
|
||||
|
||||
mousedev_table[minor] = mousedev;
|
||||
|
||||
devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
|
||||
S_IFCHR|S_IRUGO|S_IWUSR, "input/mouse%d", minor);
|
||||
class_simple_device_add(input_class,
|
||||
MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
|
||||
dev->dev, "mouse%d", minor);
|
||||
|
||||
return &mousedev->handle;
|
||||
}
|
||||
|
||||
static void mousedev_disconnect(struct input_handle *handle)
|
||||
{
|
||||
struct mousedev *mousedev = handle->private;
|
||||
|
||||
class_simple_device_remove(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor));
|
||||
devfs_remove("input/mouse%d", mousedev->minor);
|
||||
mousedev->exist = 0;
|
||||
|
||||
if (mousedev->open) {
|
||||
input_close_device(handle);
|
||||
} else {
|
||||
if (mousedev_mix.open)
|
||||
input_close_device(handle);
|
||||
mousedev_free(mousedev);
|
||||
}
|
||||
}
|
||||
|
||||
static struct input_device_id mousedev_ids[] = {
|
||||
{
|
||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
|
||||
.evbit = { BIT(EV_KEY) | BIT(EV_REL) },
|
||||
.keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) },
|
||||
.relbit = { BIT(REL_X) | BIT(REL_Y) },
|
||||
}, /* A mouse like device, at least one button, two relative axes */
|
||||
{
|
||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
|
||||
.evbit = { BIT(EV_KEY) | BIT(EV_REL) },
|
||||
.relbit = { BIT(REL_WHEEL) },
|
||||
}, /* A separate scrollwheel */
|
||||
{
|
||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
|
||||
.evbit = { BIT(EV_KEY) | BIT(EV_ABS) },
|
||||
.keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
|
||||
.absbit = { BIT(ABS_X) | BIT(ABS_Y) },
|
||||
}, /* A tablet like device, at least touch detection, two absolute axes */
|
||||
{
|
||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
|
||||
.evbit = { BIT(EV_KEY) | BIT(EV_ABS) },
|
||||
.keybit = { [LONG(BTN_TOOL_FINGER)] = BIT(BTN_TOOL_FINGER) },
|
||||
.absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_TOOL_WIDTH) },
|
||||
}, /* A touchpad */
|
||||
|
||||
{ }, /* Terminating entry */
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(input, mousedev_ids);
|
||||
|
||||
static struct input_handler mousedev_handler = {
|
||||
.event = mousedev_event,
|
||||
.connect = mousedev_connect,
|
||||
.disconnect = mousedev_disconnect,
|
||||
.fops = &mousedev_fops,
|
||||
.minor = MOUSEDEV_MINOR_BASE,
|
||||
.name = "mousedev",
|
||||
.id_table = mousedev_ids,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
|
||||
static struct miscdevice psaux_mouse = {
|
||||
PSMOUSE_MINOR, "psaux", &mousedev_fops
|
||||
};
|
||||
static int psaux_registered;
|
||||
#endif
|
||||
|
||||
static int __init mousedev_init(void)
|
||||
{
|
||||
input_register_handler(&mousedev_handler);
|
||||
|
||||
memset(&mousedev_mix, 0, sizeof(struct mousedev));
|
||||
INIT_LIST_HEAD(&mousedev_mix.list);
|
||||
init_waitqueue_head(&mousedev_mix.wait);
|
||||
mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
|
||||
mousedev_mix.exist = 1;
|
||||
mousedev_mix.minor = MOUSEDEV_MIX;
|
||||
|
||||
devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX),
|
||||
S_IFCHR|S_IRUGO|S_IWUSR, "input/mice");
|
||||
class_simple_device_add(input_class, MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX),
|
||||
NULL, "mice");
|
||||
|
||||
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
|
||||
if (!(psaux_registered = !misc_register(&psaux_mouse)))
|
||||
printk(KERN_WARNING "mice: could not misc_register the device\n");
|
||||
#endif
|
||||
|
||||
printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit mousedev_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
|
||||
if (psaux_registered)
|
||||
misc_deregister(&psaux_mouse);
|
||||
#endif
|
||||
devfs_remove("input/mice");
|
||||
class_simple_device_remove(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX));
|
||||
input_unregister_handler(&mousedev_handler);
|
||||
}
|
||||
|
||||
module_init(mousedev_init);
|
||||
module_exit(mousedev_exit);
|
||||
BIN
extra/linux-2.6.10/drivers/input/mousedev.o
Normal file
BIN
extra/linux-2.6.10/drivers/input/mousedev.o
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user