summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Simmons <jsimmons@heisenberg.transvirtual.com>2002-07-07 22:56:15 -0700
committerJames Simmons <jsimmons@heisenberg.transvirtual.com>2002-07-07 22:56:15 -0700
commit8ef1bf6df837a5f92e2d8d50ca26c77998602ff4 (patch)
tree4b08ab0d040f739937b98081fae5cc7aa1b39c64
parentaf5c826ce279f0cf9f87ce7543e94b0d3b83a644 (diff)
parenta321a55fcbb2c21eb7bc8b7d4b294eefaea9065c (diff)
Merge http://fbdev.bkbits.net/fbdev-2.5
into heisenberg.transvirtual.com:/tmp/fbdev-2.5
-rw-r--r--Documentation/DocBook/Makefile5
-rw-r--r--Documentation/DocBook/kernel-api.tmpl1
-rw-r--r--Documentation/filesystems/Locking2
-rw-r--r--Documentation/filesystems/ntfs.txt3
-rw-r--r--Documentation/filesystems/porting18
-rw-r--r--Makefile66
-rw-r--r--Rules.make74
-rw-r--r--arch/alpha/Makefile2
-rw-r--r--arch/arm/Makefile3
-rw-r--r--arch/arm/boot/Makefile6
-rw-r--r--arch/arm/boot/compressed/Makefile2
-rw-r--r--arch/cris/Makefile6
-rw-r--r--arch/cris/boot/compressed/Makefile4
-rw-r--r--arch/cris/boot/rescue/Makefile7
-rw-r--r--arch/i386/Makefile9
-rw-r--r--arch/i386/boot/Makefile94
-rw-r--r--arch/i386/boot/compressed/Makefile49
-rw-r--r--arch/i386/boot/compressed/vmlinux.scr9
-rw-r--r--arch/ia64/Makefile5
-rw-r--r--arch/m68k/Makefile6
-rw-r--r--arch/mips/Makefile6
-rw-r--r--arch/mips/philips/nino/ramdisk/Makefile2
-rw-r--r--arch/mips64/Makefile12
-rw-r--r--arch/parisc/Makefile5
-rw-r--r--arch/ppc/Makefile2
-rw-r--r--arch/ppc64/Makefile2
-rw-r--r--arch/ppc64/boot/Makefile4
-rw-r--r--arch/s390/Makefile7
-rw-r--r--arch/s390/boot/Makefile8
-rw-r--r--arch/s390x/Makefile7
-rw-r--r--arch/s390x/boot/Makefile6
-rw-r--r--arch/sh/Makefile11
-rw-r--r--arch/sh/boot/Makefile4
-rw-r--r--arch/sh/boot/compressed/Makefile6
-rw-r--r--arch/sparc/Makefile6
-rw-r--r--arch/sparc/boot/Makefile2
-rw-r--r--arch/sparc64/Makefile4
-rw-r--r--arch/x86_64/Makefile5
-rw-r--r--arch/x86_64/boot/Makefile4
-rw-r--r--arch/x86_64/boot/compressed/Makefile2
-rw-r--r--drivers/acorn/char/Makefile13
-rw-r--r--drivers/acorn/char/defkeymap-acorn.c_shipped (renamed from drivers/acorn/char/defkeymap-acorn.c)0
-rw-r--r--drivers/char/Makefile20
-rw-r--r--drivers/char/defkeymap.c_shipped262
-rw-r--r--drivers/char/qtronixmap.c_shipped265
-rw-r--r--drivers/ide/probe.c12
-rw-r--r--drivers/input/Config.help26
-rw-r--r--drivers/input/Config.in14
-rw-r--r--drivers/input/Makefile6
-rw-r--r--drivers/input/evbug.c99
-rw-r--r--drivers/input/evdev.c18
-rw-r--r--drivers/input/gameport/Config.help12
-rw-r--r--drivers/input/gameport/Config.in2
-rw-r--r--drivers/input/gameport/Makefile3
-rw-r--r--drivers/input/gameport/fm801-gp.c162
-rw-r--r--drivers/input/gameport/gameport.c28
-rw-r--r--drivers/input/gameport/pcigame.c199
-rw-r--r--drivers/input/gameport/vortex.c185
-rw-r--r--drivers/input/input.c14
-rw-r--r--drivers/input/joydev.c10
-rw-r--r--drivers/input/joystick/Config.help29
-rw-r--r--drivers/input/joystick/Config.in4
-rw-r--r--drivers/input/joystick/Makefile6
-rw-r--r--drivers/input/joystick/adi.c4
-rw-r--r--drivers/input/joystick/db9.c12
-rw-r--r--drivers/input/joystick/gamecon.c6
-rw-r--r--drivers/input/joystick/guillemot.c285
-rw-r--r--drivers/input/joystick/iforce.c1224
-rw-r--r--drivers/input/joystick/iforce/Makefile42
-rw-r--r--drivers/input/joystick/iforce/iforce-ff.c543
-rw-r--r--drivers/input/joystick/iforce/iforce-main.c543
-rw-r--r--drivers/input/joystick/iforce/iforce-packets.c314
-rw-r--r--drivers/input/joystick/iforce/iforce-serio.c166
-rw-r--r--drivers/input/joystick/iforce/iforce-usb.c214
-rw-r--r--drivers/input/joystick/iforce/iforce.h194
-rw-r--r--drivers/input/joystick/joydump.c152
-rw-r--r--drivers/input/joystick/magellan.c2
-rw-r--r--drivers/input/joystick/twidjoy.c264
-rw-r--r--drivers/input/keybdev.c4
-rw-r--r--drivers/input/keyboard/Config.help66
-rw-r--r--drivers/input/keyboard/Config.in18
-rw-r--r--drivers/input/keyboard/Makefile16
-rw-r--r--drivers/input/keyboard/amikbd.c144
-rw-r--r--drivers/input/keyboard/atkbd.c565
-rw-r--r--drivers/input/keyboard/maple_keyb.c190
-rw-r--r--drivers/input/keyboard/ps2serkbd.c298
-rw-r--r--drivers/input/keyboard/sunkbd.c318
-rw-r--r--drivers/input/keyboard/xtkbd.c157
-rw-r--r--drivers/input/mouse/Config.help87
-rw-r--r--drivers/input/mouse/Config.in24
-rw-r--r--drivers/input/mouse/Makefile18
-rw-r--r--drivers/input/mouse/amimouse.c147
-rw-r--r--drivers/input/mouse/inport.c193
-rw-r--r--drivers/input/mouse/logibm.c182
-rw-r--r--drivers/input/mouse/maplemouse.c137
-rw-r--r--drivers/input/mouse/pc110pad.c163
-rw-r--r--drivers/input/mouse/psmouse.c652
-rw-r--r--drivers/input/mouse/rpcmouse.c111
-rw-r--r--drivers/input/mouse/sermouse.c299
-rw-r--r--drivers/input/mousedev.c27
-rw-r--r--drivers/input/power.c180
-rw-r--r--drivers/input/serio/Config.help47
-rw-r--r--drivers/input/serio/Config.in12
-rw-r--r--drivers/input/serio/Makefile4
-rw-r--r--drivers/input/serio/ct82c710.c212
-rw-r--r--drivers/input/serio/i8042.c717
-rw-r--r--drivers/input/serio/i8042.h128
-rw-r--r--drivers/input/serio/parkbd.c203
-rw-r--r--drivers/input/serio/rpckbd.c117
-rw-r--r--drivers/input/touchscreen/Config.help16
-rw-r--r--drivers/input/touchscreen/Config.in7
-rw-r--r--drivers/input/touchscreen/Makefile11
-rw-r--r--drivers/input/touchscreen/gunze.c178
-rw-r--r--drivers/input/tsdev.c443
-rw-r--r--drivers/isdn/capi/capifs.c17
-rw-r--r--drivers/message/fusion/Makefile6
-rw-r--r--drivers/net/hamradio/soundmodem/Makefile2
-rw-r--r--drivers/scsi/ips.c4
-rw-r--r--drivers/tc/Makefile13
-rw-r--r--drivers/tc/lk201-map.c_shipped265
-rw-r--r--drivers/usb/class/bluetty.c5
-rw-r--r--drivers/usb/class/printer.c23
-rw-r--r--drivers/usb/core/Makefile6
-rw-r--r--drivers/usb/core/file.c182
-rw-r--r--drivers/usb/core/inode.c19
-rw-r--r--drivers/usb/core/usb.c233
-rw-r--r--drivers/usb/host/Config.help43
-rw-r--r--drivers/usb/host/Config.in20
-rw-r--r--drivers/usb/host/ohci-dbg.c2
-rw-r--r--drivers/usb/host/ohci-hcd.c12
-rw-r--r--drivers/usb/host/uhci-hcd.c38
-rw-r--r--drivers/usb/host/usb-uhci-hcd.c18
-rw-r--r--drivers/usb/host/usb-uhci-q.c58
-rw-r--r--drivers/usb/image/mdc800.c9
-rw-r--r--drivers/usb/image/scanner.c19
-rw-r--r--drivers/usb/input/aiptek.c5
-rw-r--r--drivers/usb/input/hiddev.c22
-rw-r--r--drivers/usb/media/dabusb.c16
-rw-r--r--drivers/usb/misc/auerswald.c25
-rw-r--r--drivers/usb/misc/brlvger.c22
-rw-r--r--drivers/usb/misc/rio500.c18
-rw-r--r--drivers/usb/net/pegasus.c279
-rw-r--r--drivers/usb/net/pegasus.h17
-rw-r--r--drivers/usb/net/rtl8150.c49
-rw-r--r--drivers/usb/storage/transport.c101
-rw-r--r--drivers/usb/storage/usb.c253
-rw-r--r--drivers/usb/storage/usb.h1
-rw-r--r--drivers/usb/usb-skeleton.c29
-rw-r--r--fs/binfmt_elf.c4
-rw-r--r--fs/coda/inode.c4
-rw-r--r--fs/driverfs/inode.c7
-rw-r--r--fs/ext3/super.c2
-rw-r--r--fs/freevxfs/vxfs_super.c2
-rw-r--r--fs/hpfs/super.c5
-rw-r--r--fs/jffs/inode-v23.c9
-rw-r--r--fs/nfs/inode.c12
-rw-r--r--fs/ntfs/ChangeLog11
-rw-r--r--fs/ntfs/Makefile2
-rw-r--r--fs/ntfs/attrib.c833
-rw-r--r--fs/ntfs/mst.c4
-rw-r--r--fs/ntfs/super.c18
-rw-r--r--fs/open.c2
-rw-r--r--fs/qnx4/inode.c4
-rw-r--r--fs/ramfs/inode.c7
-rw-r--r--fs/reiserfs/buffer2.c7
-rw-r--r--fs/smbfs/inode.c8
-rw-r--r--fs/udf/super.c4
-rw-r--r--fs/ufs/super.c5
-rw-r--r--include/linux/input.h104
-rw-r--r--include/linux/usb.h23
-rw-r--r--mm/mmap.c2
-rw-r--r--net/khttpd/Makefile2
172 files changed, 11779 insertions, 3054 deletions
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 0502eeee672e..f5a24f4549f9 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -15,6 +15,10 @@ C-procfs-example = procfs_example.sgml
$(TOPDIR)/scripts/docgen $(TOPDIR)/scripts/gen-all-syms \
$(TOPDIR)/scripts/kernel-doc $(TOPDIR)/scripts/docproc: doc-progs ;
+dochelp:
+ @echo ' Linux kernel internal documentation in different formats:'
+ @echo ' sgmldocs (SGML), psdocs (Postscript), pdfdocs (PDF), htmldocs (HTML)'
+
.PHONY: doc-progs
doc-progs:
@$(MAKE) -C $(TOPDIR)/scripts doc-progs
@@ -116,6 +120,7 @@ APISOURCES := $(TOPDIR)/drivers/media/video/videodev.c \
$(TOPDIR)/drivers/usb/core/urb.c \
$(TOPDIR)/drivers/usb/core/message.c \
$(TOPDIR)/drivers/usb/core/config.c \
+ $(TOPDIR)/drivers/usb/core/file.c \
$(TOPDIR)/drivers/usb/core/usb.c \
$(TOPDIR)/drivers/video/fbmem.c \
$(TOPDIR)/drivers/video/fbcmap.c \
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index 52094d07bc19..9794214be48c 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -285,6 +285,7 @@
!Edrivers/usb/core/urb.c
!Edrivers/usb/core/config.c
!Edrivers/usb/core/message.c
+!Edrivers/usb/core/file.c
!Edrivers/usb/core/usb.c
</sect1>
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index c894fcceb996..9ed995b75fbf 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -108,7 +108,7 @@ delete_inode: no
clear_inode: no
put_super: yes yes maybe (see below)
write_super: no yes maybe (see below)
-statfs: yes no no
+statfs: no no no
remount_fs: yes yes maybe (see below)
umount_begin: yes no maybe (see below)
diff --git a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt
index 4827bc2cda6f..6d952dc7452e 100644
--- a/Documentation/filesystems/ntfs.txt
+++ b/Documentation/filesystems/ntfs.txt
@@ -247,6 +247,9 @@ ChangeLog
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
+2.0.14:
+ - Internal changes improving run list merging code and minor locking
+ change to not rely on BKL in ntfs_statfs().
2.0.13:
- Internal changes towards using iget5_locked() in preparation for
fake inodes and small cleanups to ntfs_volume structure.
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index 2dcccf3d8a3a..b5e03c88e291 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -83,7 +83,7 @@ can relax your locking.
[mandatory]
->lookup(), ->truncate(), ->create(), ->unlink(), ->mknod(), ->mkdir(),
-->rmdir(), ->link(), ->lseek(), ->symlink(), ->rename(), ->permission()
+->rmdir(), ->link(), ->lseek(), ->symlink(), ->rename()
and ->readdir() are called without BKL now. Grab it on entry, drop upon return
- that will guarantee the same locking you used to have. If your method or its
parts do not need BKL - better yet, now you can shift lock_kernel() and
@@ -234,6 +234,22 @@ As soon as it gets fixed is_read_only() will die.
---
[mandatory]
+->permission() is called without BKL now. Grab it on entry, drop upon
+return - that will guarantee the same locking you used to have. If
+your method or its parts do not need BKL - better yet, now you can
+shift lock_kernel() and unlock_kernel() so that they would protect
+exactly what needs to be protected.
+
+---
+[mandatory]
+
+->statfs() is now called without BKL held. BKL should have been
+shifted into individual fs sb_op functions where it's not clear that
+it's safe to remove it. If you don't need it, remove it.
+
+---
+[mandatory]
+
is_read_only() is gone; use bdev_read_only() instead.
---
diff --git a/Makefile b/Makefile
index f0bd4955e181..790d4b421ec9 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,14 @@
VERSION = 2
PATCHLEVEL = 5
-SUBLEVEL = 24
+SUBLEVEL = 25
EXTRAVERSION =
+# *DOCUMENTATION*
+# Too see a list of typical targets execute "make help"
+# More info can be located in ./Documentation/kbuild
+# Comments in this file is targeted only to the developer, do not
+# expect to learn how to build the kernel reading this file.
+
# We are using a recursive build, so we need to do a little thinking
# to get the ordering right.
#
@@ -140,16 +146,23 @@ export VERSION PATCHLEVEL SUBLEVEL EXTRAVERSION KERNELRELEASE ARCH \
CONFIG_SHELL TOPDIR HPATH HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC \
CPP AR NM STRIP OBJCOPY OBJDUMP MAKE MAKEFILES GENKSYMS PERL
-export CPPFLAGS EXPORT_FLAGS NOSTDINC_FLAGS
+export CPPFLAGS EXPORT_FLAGS NOSTDINC_FLAGS OBJCOPYFLAGS
export CFLAGS CFLAGS_KERNEL CFLAGS_MODULE
export AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
+src := .
+obj := .
+srctree := $(TOPDIR)
+objtree := $(TOPDIR)
+
+export srctree objtree
+
SUBDIRS := init kernel mm fs ipc lib drivers sound net
noconfig_targets := xconfig menuconfig config oldconfig randconfig \
defconfig allyesconfig allnoconfig allmodconfig \
clean mrproper distclean \
- tags TAGS sgmldocs psdocs pdfdocs htmldocs \
+ help tags TAGS sgmldocs psdocs pdfdocs htmldocs \
checkconfig checkhelp checkincludes
ifeq ($(filter $(noconfig_targets),$(MAKECMDGOALS)),)
@@ -217,7 +230,7 @@ NETWORKS := net/network.o
include arch/$(ARCH)/Makefile
-export NETWORKS DRIVERS LIBS HEAD LDFLAGS LINKFLAGS MAKEBOOT ASFLAGS
+export NETWORKS DRIVERS LIBS HEAD LDFLAGS MAKEBOOT ASFLAGS
# boot target
# ---------------------------------------------------------------------------
@@ -238,7 +251,7 @@ boot: vmlinux
vmlinux-objs := $(HEAD) $(INIT) $(CORE_FILES) $(LIBS) $(DRIVERS) $(NETWORKS)
quiet_cmd_link_vmlinux = LD $@
-cmd_link_vmlinux = $(LD) $(LINKFLAGS) $(HEAD) $(INIT) \
+cmd_link_vmlinux = $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) $(HEAD) $(INIT) \
--start-group \
$(CORE_FILES) \
$(LIBS) \
@@ -255,7 +268,7 @@ define rule_link_vmlinux
. scripts/mkversion > .tmpversion
mv -f .tmpversion .version
+$(MAKE) -C init
- $(call cmd,cmd_link_vmlinux)
+ $(call cmd,link_vmlinux)
$(cmd_link_vmlinux)
echo 'cmd_$@ := $(cmd_link_vmlinux)' > $(@D)/.$(@F).cmd
$(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
@@ -679,6 +692,43 @@ tags: FORCE
find $(SUBDIRS) init -name SCCS -prune -o -name BitKeeper -prune -o \
-name '*.[ch]' -print | xargs ctags $$CTAGSF -a
+# Brief documentation of the typical targets used
+# ---------------------------------------------------------------------------
+
+help:
+ @echo 'Cleaning targets:'
+ @echo ' clean - remove most generated files but keep the config'
+ @echo ' mrproper - remove all generated files including the config'
+ @echo ' distclean - mrproper + remove files generated by editors and patch'
+ @echo ''
+ @echo 'Configuration targets:'
+ @echo ' oldconfig - Update current config utilising a line-oriented program'
+ @echo ' menuconfig - Update current config utilising a menu based program'
+ @echo ' xconfig - Update current config utilising a X-based program'
+ @echo ' defconfig - New config with default answer to all options'
+ @echo ' allmodconfig - New config selecting modules when possible'
+ @echo ' allyesconfig - New config where all options are accepted with yes'
+ @echo ' allnoconfig - New minimal config'
+ @echo ''
+ @echo 'Other generic targets:'
+ @echo ' all - Build all targets marked with [*]'
+ @echo ' dep - Create module version information'
+ @echo '* vmlinux - Build the bare kernel'
+ @echo '* modules - Build all modules'
+ @echo ' dir/file.[ois]- Build specified target only'
+ @echo ' rpm - Build a kernel as an RPM package'
+ @echo ' tags/TAGS - Generate tags file for editors'
+ @echo ''
+ @echo 'Documentation targets:'
+ @$(MAKE) --no-print-directory -f Documentation/DocBook/Makefile dochelp
+ @echo ''
+ @echo 'Architecture specific targets ($(ARCH)):'
+ @$(MAKE) --no-print-directory -f arch/$(ARCH)/boot/Makefile archhelp
+ @echo ''
+ @echo 'Execute "make" or "make all" to build all targets marked with [*] '
+ @echo 'For further info browse Documentation/kbuild/*'
+
+
# Documentation targets
# ---------------------------------------------------------------------------
@@ -735,9 +785,9 @@ if_changed_rule = $(if $(strip $? \
$(filter-out $(cmd_$(@F)),$(cmd_$(1)))),\
@$(rule_$(1)))
-# If quiet is set, only print short version of rule
+# If quiet is set, only print short version of command
-cmd = @$(if $($(quiet)$(1)),echo ' $($(quiet)$(1))' &&) $($(1))
+cmd = @$(if $($(quiet)cmd_$(1)),echo ' $($(quiet)cmd_$(1))' &&) $(cmd_$(1))
define update-if-changed
if [ -r $@ ] && cmp -s $@ $@.tmp; then \
diff --git a/Rules.make b/Rules.make
index 961d801047ed..8df36f4b5cf6 100644
--- a/Rules.make
+++ b/Rules.make
@@ -34,7 +34,7 @@ endif
# $(srctree)/include/linux/module.h : Some file relative to the source
# dir root
#
-# Those can only be used in the section after
+# $(obj) and $(src) can only be used in the section after
# include $(TOPDIR)/Rules.make, i.e for generated files and the like.
# Intentionally.
#
@@ -43,8 +43,10 @@ endif
obj := .
src := .
-objtree := $(TOPDIR)
-srctree := $(TOPDIR)
+
+# For use in the quiet output
+
+echo_target = $(RELDIR)/$@
# Figure out what we need to build from the various variables
# ===========================================================================
@@ -269,25 +271,25 @@ c_flags = -Wp,-MD,$(depfile) $(CFLAGS) $(NOSTDINC_FLAGS) \
-DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) \
$(export_flags)
-quiet_cmd_cc_s_c = CC $(RELDIR)/$@
+quiet_cmd_cc_s_c = CC $(echo_target)
cmd_cc_s_c = $(CC) $(c_flags) -S -o $@ $<
%.s: %.c FORCE
$(call if_changed_dep,cc_s_c)
-quiet_cmd_cc_i_c = CPP $(RELDIR)/$@
+quiet_cmd_cc_i_c = CPP $(echo_target)
cmd_cc_i_c = $(CPP) $(c_flags) -o $@ $<
%.i: %.c FORCE
$(call if_changed_dep,cc_i_c)
-quiet_cmd_cc_o_c = CC $(RELDIR)/$@
+quiet_cmd_cc_o_c = CC $(echo_target)
cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
%.o: %.c FORCE
$(call if_changed_dep,cc_o_c)
-quiet_cmd_cc_lst_c = ' Generating $(RELDIR)/$@'
+quiet_cmd_cc_lst_c = ' Generating $(echo_target)'
cmd_cc_lst_c = $(CC) $(c_flags) -g -c -o $*.o $< && $(TOPDIR)/scripts/makelst $*.o $(TOPDIR)/System.map $(OBJDUMP) > $@
%.lst: %.c FORCE
@@ -304,13 +306,13 @@ $(real-objs-m:.o=.s): modkern_aflags := $(AFLAGS_MODULE)
a_flags = -Wp,-MD,$(depfile) $(AFLAGS) $(NOSTDINC_FLAGS) \
$(modkern_aflags) $(EXTRA_AFLAGS) $(AFLAGS_$(*F).o)
-quiet_cmd_as_s_S = CPP $(RELDIR)/$@
+quiet_cmd_as_s_S = CPP $(echo_target)
cmd_as_s_S = $(CPP) $(a_flags) -o $@ $<
%.s: %.S FORCE
$(call if_changed_dep,as_s_S)
-quiet_cmd_as_o_S = AS $(RELDIR)/$@
+quiet_cmd_as_o_S = AS $(echo_target)
cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $<
%.o: %.S FORCE
@@ -328,10 +330,10 @@ $(sort $(subdir-obj-y)): sub_dirs ;
# Rule to compile a set of .o files into one .o file
#
ifdef O_TARGET
-quiet_cmd_link_o_target = LD $(RELDIR)/$@
+quiet_cmd_link_o_target = LD $(echo_target)
# If the list of objects to link is empty, just create an empty O_TARGET
cmd_link_o_target = $(if $(strip $(obj-y)),\
- $(LD) $(EXTRA_LDFLAGS) -r -o $@ $(filter $(obj-y), $^),\
+ $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) -r -o $@ $(filter $(obj-y), $^),\
rm -f $@; $(AR) rcs $@)
$(O_TARGET): $(obj-y) FORCE
@@ -344,7 +346,7 @@ endif # O_TARGET
# Rule to compile a set of .o files into one .a file
#
ifdef L_TARGET
-quiet_cmd_link_l_target = AR $(RELDIR)/$@
+quiet_cmd_link_l_target = AR $(echo_target)
cmd_link_l_target = rm -f $@; $(AR) $(EXTRA_ARFLAGS) rcs $@ $(obj-y)
$(L_TARGET): $(obj-y) FORCE
@@ -357,8 +359,8 @@ endif
# Rule to link composite objects
#
-quiet_cmd_link_multi = LD $(RELDIR)/$@
-cmd_link_multi = $(LD) $(EXTRA_LDFLAGS) -r -o $@ $(filter $($(basename $@)-objs),$^)
+quiet_cmd_link_multi = LD $(echo_target)
+cmd_link_multi = $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) -r -o $@ $(filter $($(basename $@)-objs),$^)
# We would rather have a list of rules like
# foo.o: $(foo-objs)
@@ -379,22 +381,22 @@ host-progs-single := $(foreach m,$(host-progs),$(if $($(m)-objs),,$(m)))
host-progs-multi := $(foreach m,$(host-progs),$(if $($(m)-objs),$(m)))
host-progs-multi-objs := $(foreach m,$(host-progs-multi),$($(m)-objs))
-quiet_cmd_host_cc__c = HOSTCC $(RELDIR)/$@
-cmd_host_cc__c = $(HOSTCC) -Wp,-MD,.$(subst /,_,$@).d \
+quiet_cmd_host_cc__c = HOSTCC $(echo_target)
+cmd_host_cc__c = $(HOSTCC) -Wp,-MD,$(depfile) \
$(HOSTCFLAGS) $(HOST_EXTRACFLAGS) \
$(HOST_LOADLIBES) -o $@ $<
$(host-progs-single): %: %.c FORCE
$(call if_changed_dep,host_cc__c)
-quiet_cmd_host_cc_o_c = HOSTCC $(RELDIR)/$@
-cmd_host_cc_o_c = $(HOSTCC) -Wp,-MD,.$(subst /,_,$@).d \
+quiet_cmd_host_cc_o_c = HOSTCC $(echo_target)
+cmd_host_cc_o_c = $(HOSTCC) -Wp,-MD,$(depfile) \
$(HOSTCFLAGS) $(HOST_EXTRACFLAGS) -c -o $@ $<
$(host-progs-multi-objs): %.o: %.c FORCE
$(call if_changed_dep,host_cc_o_c)
-quiet_cmd_host_cc__o = HOSTLD $(RELDIR)/$@
+quiet_cmd_host_cc__o = HOSTLD $(echo_target)
cmd_host_cc__o = $(HOSTCC) $(HOSTLDFLAGS) -o $@ $($@-objs) \
$(HOST_LOADLIBES)
@@ -410,9 +412,39 @@ endif # ! fastdep
# ===========================================================================
%:: %_shipped
- @echo ' CP $(RELDIR)/$@'
+ @echo ' CP $(echo_target)'
@cp $< $@
+# Commands useful for building a boot image
+# ===========================================================================
+#
+# Use as following:
+#
+# target: source(s) FORCE
+# $(if_changed,ld/objcopy)
+#
+# and add target to EXTRA_TARGETS so that we know we have to
+# read in the saved command line
+
+# Linking
+# ---------------------------------------------------------------------------
+
+quiet_cmd_ld = LD $(echo_target)
+cmd_ld = $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) $(LDFLAGS_$@) \
+ $(filter-out FORCE,$^) -o $@
+
+# Objcopy
+# ---------------------------------------------------------------------------
+
+quiet_cmd_objcopy = OBJCPY $(echo_target)
+cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $< $@
+
+# Gzip
+# ---------------------------------------------------------------------------
+
+quiet_cmd_gzip = GZIP $(echo_target)
+cmd_gzip = gzip -f -9 < $< > $@
+
# ===========================================================================
# Generic stuff
# ===========================================================================
@@ -520,4 +552,4 @@ if_changed_rule = $(if $(strip $? \
# If quiet is set, only print short version of command
-cmd = @$(if $($(quiet)$(1)),echo ' $($(quiet)$(1))' &&) $($(1))
+cmd = @$(if $($(quiet)cmd_$(1)),echo ' $($(quiet)cmd_$(1))' &&) $(cmd_$(1))
diff --git a/arch/alpha/Makefile b/arch/alpha/Makefile
index 14aa0e55eb90..78dbb2696968 100644
--- a/arch/alpha/Makefile
+++ b/arch/alpha/Makefile
@@ -10,7 +10,7 @@
NM := $(NM) -B
-LINKFLAGS = -static -T arch/alpha/vmlinux.lds -N #-relax
+LDFLAGS_vmlinux = -static -T arch/alpha/vmlinux.lds -N #-relax
CFLAGS := $(CFLAGS) -pipe -mno-fp-regs -ffixed-8
# Determine if we can use the BWX instructions with GAS.
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index c511b3700519..9d147fe7a97b 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -7,7 +7,8 @@
#
# Copyright (C) 1995-2001 by Russell King
-LINKFLAGS :=-p -X -T arch/arm/vmlinux.lds
+LDFLAGS_vmlinux :=-p -X -T arch/arm/vmlinux.lds
+OBJCOPYFLAGS :=-O binary -R .note -R .comment -S
GZFLAGS :=-9
CFLAGS +=-pipe
diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
index 4f452f835831..6d3e078a87fd 100644
--- a/arch/arm/boot/Makefile
+++ b/arch/arm/boot/Makefile
@@ -115,15 +115,15 @@ endif
export SYSTEM ZTEXTADDR ZBSSADDR ZRELADDR INITRD_PHYS PARAMS_PHYS
Image: $(SYSTEM)
- $(OBJCOPY) -O binary -R .note -R .comment -S $(SYSTEM) $@
+ $(OBJCOPY) $(OBJCOPYFLAGS) $< $@
bzImage: zImage
zImage: compressed/vmlinux
- $(OBJCOPY) -O binary -R .note -R .comment -S compressed/vmlinux $@
+ $(OBJCOPY) $(OBJCOPYFLAGS) $< $@
bootpImage: bootp/bootp
- $(OBJCOPY) -O binary -R .note -R .comment -S bootp/bootp $@
+ $(OBJCOPY) $(OBJCOPYFLAGS) $< $@
compressed/vmlinux: $(TOPDIR)/vmlinux
@$(MAKE) -C compressed vmlinux
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 2f5c0eee43ea..67278fa673f1 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -78,7 +78,7 @@ $(HEAD): $(HEAD:.o=.S)
$(CC) $(AFLAGS) -traditional -c $(HEAD:.o=.S)
piggy.o: $(SYSTEM)
- $(OBJCOPY) -O binary -R .note -R .comment -S $(SYSTEM) piggy
+ $(OBJCOPY) $(OBJCOPYFLAGS) $(SYSTEM) piggy
gzip $(GZFLAGS) < piggy > piggy.gz
$(LD) -r -o $@ -b binary piggy.gz
rm -f piggy piggy.gz
diff --git a/arch/cris/Makefile b/arch/cris/Makefile
index 8cd602bf66dc..1b5c9af76fdd 100644
--- a/arch/cris/Makefile
+++ b/arch/cris/Makefile
@@ -31,11 +31,11 @@ LD = if [ ! -e $(LD_SCRIPT).tmp -o $(LD_SCRIPT) -nt $(LD_SCRIPT).tmp ]; then \
else true; \
fi && $(CROSS_COMPILE)ld -mcrislinux
-LINKFLAGS = -T $(LD_SCRIPT).tmp
+LDFLAGS_vmlinux = -T $(LD_SCRIPT).tmp
# objcopy is used to make binary images from the resulting linked file
-OBJCOPY := $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
+OBJCOPYFLAGS := -O binary -R .note -R .comment -S
# -mlinux enables -march=v10, -fno-underscores, -D__linux__ among others
@@ -64,7 +64,7 @@ LIBS := $(TOPDIR)/arch/cris/lib/lib.a $(LIBS) $(TOPDIR)/arch/cris/lib/lib.a $(LI
MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
vmlinux.bin: vmlinux
- $(OBJCOPY) vmlinux vmlinux.bin
+ $(OBJCOPY) $(OBJCOPYFLAGS) vmlinux vmlinux.bin
timage: vmlinux.bin
cat vmlinux.bin cramfs.img >timage
diff --git a/arch/cris/boot/compressed/Makefile b/arch/cris/boot/compressed/Makefile
index ea58c7ad6a3f..5f71c2c819e6 100644
--- a/arch/cris/boot/compressed/Makefile
+++ b/arch/cris/boot/compressed/Makefile
@@ -8,7 +8,7 @@ CC = gcc-cris -melf -I $(TOPDIR)/include
CFLAGS = -O2
LD = ld-cris
OBJCOPY = objcopy-cris
-
+OBJCOPYFLAGS = -O binary --remove-section=.bss
OBJECTS = head.o misc.o
# files to compress
@@ -18,7 +18,7 @@ all: vmlinuz
decompress.bin: $(OBJECTS)
$(LD) -T decompress.ld -o decompress.o $(OBJECTS)
- $(OBJCOPY) -O binary --remove-section=.bss decompress.o decompress.bin
+ $(OBJCOPY) $(OBJCOPYFLAGS) decompress.o decompress.bin
# save it for mkprod in the topdir.
cp decompress.bin $(TOPDIR)
diff --git a/arch/cris/boot/rescue/Makefile b/arch/cris/boot/rescue/Makefile
index 43b1fa6b8e96..e9f2ba2ad02c 100644
--- a/arch/cris/boot/rescue/Makefile
+++ b/arch/cris/boot/rescue/Makefile
@@ -8,6 +8,7 @@ CC = gcc-cris -mlinux -I $(TOPDIR)/include
CFLAGS = -O2
LD = gcc-cris -mlinux -nostdlib
OBJCOPY = objcopy-cris
+OBJCOPYFLAGS = -O binary --remove-section=.bss
all: rescue.bin testrescue.bin kimagerescue.bin
@@ -16,11 +17,11 @@ rescue: rescue.bin
rescue.bin: head.o
$(LD) -T rescue.ld -o rescue.o head.o
- $(OBJCOPY) -O binary --remove-section=.bss rescue.o rescue.bin
+ $(OBJCOPY) $(OBJCOPYFLAGS) rescue.o rescue.bin
cp rescue.bin $(TOPDIR)
testrescue.bin: testrescue.o
- $(OBJCOPY) -O binary --remove-section=.bss testrescue.o tr.bin
+ $(OBJCOPY) $(OBJCOPYFLAGS) testrescue.o tr.bin
# Pad it to 784 bytes
dd if=/dev/zero of=tmp2423 bs=1 count=784
cat tr.bin tmp2423 >testrescue_tmp.bin
@@ -28,7 +29,7 @@ testrescue.bin: testrescue.o
rm tr.bin tmp2423 testrescue_tmp.bin
kimagerescue.bin: kimagerescue.o
- $(OBJCOPY) -O binary --remove-section=.bss kimagerescue.o ktr.bin
+ $(OBJCOPY) $(OBJCOPYFLAGS) kimagerescue.o ktr.bin
# Pad it to 784 bytes, that's what the rescue loader expects
dd if=/dev/zero of=tmp2423 bs=1 count=784
cat ktr.bin tmp2423 >kimagerescue_tmp.bin
diff --git a/arch/i386/Makefile b/arch/i386/Makefile
index 7009d720d262..164f2ebc762b 100644
--- a/arch/i386/Makefile
+++ b/arch/i386/Makefile
@@ -16,10 +16,9 @@
# Added '-march' and '-mpreferred-stack-boundary' support
#
-LD=$(CROSS_COMPILE)ld -m elf_i386
-OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
-LDFLAGS=-e stext
-LINKFLAGS =-T $(TOPDIR)/arch/i386/vmlinux.lds $(LDFLAGS)
+LDFLAGS := -m elf_i386
+OBJCOPYFLAGS := -O binary -R .note -R .comment -S
+LDFLAGS_vmlinux := -T arch/i386/vmlinux.lds -e stext
CFLAGS += -pipe
@@ -103,7 +102,7 @@ SUBDIRS += arch/i386/pci
DRIVERS += arch/i386/pci/pci.o
endif
-MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+MAKEBOOT = +$(MAKE) -C arch/$(ARCH)/boot
vmlinux: arch/i386/vmlinux.lds
diff --git a/arch/i386/boot/Makefile b/arch/i386/boot/Makefile
index 82a21d608f4f..4a3d7195b05e 100644
--- a/arch/i386/boot/Makefile
+++ b/arch/i386/boot/Makefile
@@ -25,25 +25,44 @@ SVGA_MODE := -DSVGA_MODE=NORMAL_VGA
#RAMDISK := -DRAMDISK=512
+EXTRA_TARGETS := vmlinux.bin bvmlinux.bin bootsect bootsect.o \
+ setup setup.o zImage bzImage
+
+host-progs := tools/build
+
+# Default
+
+boot: bzImage
+
+include $(TOPDIR)/Rules.make
+
# ---------------------------------------------------------------------------
-BOOT_INCL = $(TOPDIR)/include/linux/config.h \
- $(TOPDIR)/include/linux/autoconf.h \
- $(TOPDIR)/include/asm/boot.h
+zImage: IMAGE_OFFSET := 0x1000
+zImage: EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK)
+bzImage: IMAGE_OFFSET := 0x100000
+bzImage: EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
+bzImage: BUILDFLAGS := -b
+
+quiet_cmd_image = BUILD $(RELDIR)/$@
+cmd_image = tools/build $(BUILDFLAGS) bootsect setup vmlinux.bin \
+ $(ROOT_DEV) > $@
-zImage: bootsect setup compressed/vmlinux tools/build
- $(OBJCOPY) compressed/vmlinux compressed/vmlinux.out
- tools/build bootsect setup compressed/vmlinux.out $(ROOT_DEV) > zImage
+zImage bzImage: bootsect setup vmlinux.bin tools/build FORCE
+ $(call if_changed,image)
-bzImage: bbootsect bsetup compressed/bvmlinux tools/build
- $(OBJCOPY) compressed/bvmlinux compressed/bvmlinux.out
- tools/build -b bbootsect bsetup compressed/bvmlinux.out $(ROOT_DEV) > bzImage
+vmlinux.bin: compressed/vmlinux FORCE
+ $(call if_changed,objcopy)
-compressed/vmlinux: $(TOPDIR)/vmlinux
- @$(MAKE) -C compressed vmlinux
+LDFLAGS_bootsect := -Ttext 0x0 -s --oformat binary
+LDFLAGS_setup := -Ttext 0x0 -s --oformat binary -e begtext
+
+setup bootsect: %: %.o FORCE
+ $(call if_changed,ld)
+
+compressed/vmlinux: FORCE
+ @$(MAKE) IMAGE_OFFSET=$(IMAGE_OFFSET) -C compressed vmlinux
-compressed/bvmlinux: $(TOPDIR)/vmlinux
- @$(MAKE) -C compressed bvmlinux
zdisk: $(BOOTIMAGE)
dd bs=8192 if=$(BOOTIMAGE) of=/dev/fd0
@@ -58,48 +77,17 @@ zlilo: $(BOOTIMAGE)
install: $(BOOTIMAGE)
sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map "$(INSTALL_PATH)"
-tools/build: tools/build.c
- $(HOSTCC) $(HOSTCFLAGS) -o $@ $< -I$(TOPDIR)/include
-
-bootsect: bootsect.o
- $(LD) -Ttext 0x0 -s --oformat binary -o $@ $<
-
-bootsect.o: bootsect.s
- $(AS) -o $@ $<
-
-bootsect.s: bootsect.S Makefile $(BOOT_INCL)
- $(CPP) $(CPPFLAGS) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
-
-bbootsect: bbootsect.o
- $(LD) -Ttext 0x0 -s --oformat binary $< -o $@
-
-bbootsect.o: bbootsect.s
- $(AS) -o $@ $<
-
-bbootsect.s: bootsect.S Makefile $(BOOT_INCL)
- $(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
-
-setup: setup.o
- $(LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $<
-
-setup.o: setup.s
- $(AS) -o $@ $<
-
-setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
- $(CPP) $(CPPFLAGS) -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
-
-bsetup: bsetup.o
- $(LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $<
-
-bsetup.o: bsetup.s
- $(AS) -o $@ $<
-
-bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
- $(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
-
clean:
@echo 'Cleaning up (boot)'
- @rm -f tools/build
+ @rm -f tools/build vmlinux.bin bvmlinux.bin
@rm -f setup bootsect zImage compressed/vmlinux.out
@rm -f bsetup bbootsect bzImage compressed/bvmlinux.out
@$(MAKE) -C compressed clean
+
+archhelp:
+ @echo '* bzImage - Compressed kernel image (arch/$(ARCH)/boot/bzImage)'
+ @echo ' install - Install kernel using'
+ @echo ' (your) ~/bin/installkernel or'
+ @echo ' (distribution) /sbin/installkernel or'
+ @echo ' install to $$(INSTALL_PATH) and run lilo'
+
diff --git a/arch/i386/boot/compressed/Makefile b/arch/i386/boot/compressed/Makefile
index 70446cc3e5c7..df0f5f75e2e4 100644
--- a/arch/i386/boot/compressed/Makefile
+++ b/arch/i386/boot/compressed/Makefile
@@ -4,47 +4,26 @@
# create a compressed vmlinux image from the original vmlinux
#
-HEAD = head.o
-SYSTEM = $(TOPDIR)/vmlinux
+EXTRA_TARGETS := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
+EXTRA_AFLAGS := -traditional
-OBJECTS = $(HEAD) misc.o
+include $(TOPDIR)/Rules.make
-ZLDFLAGS = -e startup_32
+LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32
-#
-# ZIMAGE_OFFSET is the load offset of the compression loader
-# BZIMAGE_OFFSET is the load offset of the high loaded compression loader
-#
-ZIMAGE_OFFSET = 0x1000
-BZIMAGE_OFFSET = 0x100000
-
-ZLINKFLAGS = -Ttext $(ZIMAGE_OFFSET) $(ZLDFLAGS)
-BZLINKFLAGS = -Ttext $(BZIMAGE_OFFSET) $(ZLDFLAGS)
-
-all: vmlinux
-
-vmlinux: piggy.o $(OBJECTS)
- $(LD) $(ZLINKFLAGS) -o vmlinux $(OBJECTS) piggy.o
-
-bvmlinux: piggy.o $(OBJECTS)
- $(LD) $(BZLINKFLAGS) -o bvmlinux $(OBJECTS) piggy.o
+vmlinux: head.o misc.o piggy.o FORCE
+ $(call if_changed,ld)
-head.o: head.S
- $(CC) $(AFLAGS) -traditional -c head.S
+vmlinux.bin: $(TOPDIR)/vmlinux FORCE
+ $(call if_changed,objcopy)
-comma := ,
+vmlinux.bin.gz: vmlinux.bin FORCE
+ $(call if_changed,gzip)
-misc.o: misc.c
- $(CC) $(CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c misc.c
+LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T
-piggy.o: $(SYSTEM)
- tmppiggy=_tmp_$$$$piggy; \
- rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \
- $(OBJCOPY) $(SYSTEM) $$tmppiggy; \
- gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \
- echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \
- $(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 -T $$tmppiggy.lnk; \
- rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk
+piggy.o: vmlinux.scr vmlinux.bin.gz FORCE
+ $(call if_changed,ld)
clean:
- @rm -f vmlinux bvmlinux _tmp_*
+ @rm -f vmlinux vmlinux.bin vmlinux.bin.gz
diff --git a/arch/i386/boot/compressed/vmlinux.scr b/arch/i386/boot/compressed/vmlinux.scr
new file mode 100644
index 000000000000..1ed9d791f863
--- /dev/null
+++ b/arch/i386/boot/compressed/vmlinux.scr
@@ -0,0 +1,9 @@
+SECTIONS
+{
+ .data : {
+ input_len = .;
+ LONG(input_data_end - input_data) input_data = .;
+ *(.data)
+ input_data_end = .;
+ }
+}
diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile
index d8501b04a6c4..99f42387cb9c 100644
--- a/arch/ia64/Makefile
+++ b/arch/ia64/Makefile
@@ -13,7 +13,8 @@ AWK := awk
export AWK
-LINKFLAGS = -static -T arch/$(ARCH)/vmlinux.lds
+OBJCOPYFLAGS := --strip-all
+LDFLAGS_vmlinux := -static -T arch/$(ARCH)/vmlinux.lds
AFLAGS_KERNEL := -mconstant-gp
EXTRA =
@@ -100,7 +101,7 @@ arch/$(ARCH)/vmlinux.lds: arch/$(ARCH)/vmlinux.lds.S FORCE
-traditional arch/$(ARCH)/vmlinux.lds.S > $@
compressed: vmlinux
- $(OBJCOPY) --strip-all vmlinux vmlinux-tmp
+ $(OBJCOPY) $(OBJCOPYFLAGS) vmlinux vmlinux-tmp
gzip vmlinux-tmp
mv vmlinux-tmp.gz vmlinux.gz
diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile
index ccf90876c934..c2e695afc00a 100644
--- a/arch/m68k/Makefile
+++ b/arch/m68k/Makefile
@@ -18,16 +18,16 @@ COMPILE_ARCH = $(shell uname -m)
# override top level makefile
AS += -m68020
-LD += -m m68kelf
+LDFLAGS := -m m68kelf
ifneq ($(COMPILE_ARCH),$(ARCH))
# prefix for cross-compiling binaries
CROSS_COMPILE = m68k-linux-
endif
ifndef CONFIG_SUN3
-LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux.lds
+LDFLAGS_vmlinux = -T $(TOPDIR)/arch/m68k/vmlinux.lds
else
-LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux-sun3.lds -N
+LDFLAGS_vmlinux = -T $(TOPDIR)/arch/m68k/vmlinux-sun3.lds -N
endif
# without -fno-strength-reduce the 53c7xx.c driver fails ;-(
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 7db284e77931..de853833c0d6 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -36,9 +36,9 @@ endif
# crossformat linking we rely on the elf2ecoff tool for format conversion.
#
GCCFLAGS := -G 0 -mno-abicalls -fno-pic
-LINKFLAGS += -static
+LDFLAGS_vmlinux += -static
MODFLAGS += -mlong-calls
-LD := $(LD) -G 0
+LDFLAGS := -G 0
ifdef CONFIG_REMOTE_DEBUG
CFLAGS := $(CFLAGS) -g
@@ -270,7 +270,7 @@ vmlinux: arch/$(ARCH)/ld.script
arch/$(ARCH)/ld.script: arch/$(ARCH)/ld.script.in arch/$(ARCH)/Makefile
sed -e 's/@@LOADADDR@@/$(LOADADDR)/' <$< >$@
-LINKFLAGS += -T arch/$(ARCH)/ld.script
+LDFLAGS_vmlinux += -T arch/$(ARCH)/ld.script
HEAD := arch/mips/kernel/head.o arch/mips/kernel/init_task.o
diff --git a/arch/mips/philips/nino/ramdisk/Makefile b/arch/mips/philips/nino/ramdisk/Makefile
index 1e7658863b64..caaecadfad48 100644
--- a/arch/mips/philips/nino/ramdisk/Makefile
+++ b/arch/mips/philips/nino/ramdisk/Makefile
@@ -7,6 +7,6 @@
#
ramdisk.o: ramdisk.gz ld.script
- $(LD) -T ld.script -b binary -o $@ ramdisk.gz
+ $(LD) $(LDFLAGS) -T ld.script -b binary -o $@ ramdisk.gz
include $(TOPDIR)/Rules.make
diff --git a/arch/mips64/Makefile b/arch/mips64/Makefile
index 57b5c2aa3862..0951e650926f 100644
--- a/arch/mips64/Makefile
+++ b/arch/mips64/Makefile
@@ -35,7 +35,7 @@ endif
#
CFLAGS += -I $(TOPDIR)/include/asm/gcc $(CFLAGS)
CFLAGS += -mabi=64 -G 0 -mno-abicalls -fno-pic -Wa,--trap -pipe
-LINKFLAGS += -G 0 -static # -N
+LDFLAGS_vmlinux += -G 0 -static # -N
MODFLAGS += -mlong-calls
ifdef CONFIG_REMOTE_DEBUG
@@ -118,7 +118,7 @@ endif
#
ifdef CONFIG_BOOT_ELF32
CFLAGS += -Wa,-32
-LINKFLAGS += -T arch/mips64/ld.script.elf32
+LDFLAGS_vmlinux += -T arch/mips64/ld.script.elf32
endif
#
# The 64-bit ELF tools are pretty broken so at this time we generate 64-bit
@@ -126,13 +126,13 @@ endif
#
ifdef CONFIG_BOOT_ELF64
CFLAGS += -Wa,-32
-LINKFLAGS += -T arch/mips64/ld.script.elf32
+LDFLAGS_vmlinux += -T arch/mips64/ld.script.elf32
#AS += -64
-#LD += -m elf64bmip
-#LINKFLAGS += -T arch/mips64/ld.script.elf64
+#LDFLAGS += -m elf64bmip
+#LDFLAGS_vmlinux += -T arch/mips64/ld.script.elf64
endif
-LINKFLAGS += -Ttext $(LOADADDR)
+LDFLAGS_vmlinux += -Ttext $(LOADADDR)
HEAD := arch/mips64/kernel/head.o arch/mips64/kernel/init_task.o
diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile
index 38bdaa29f31d..4beccadb8202 100644
--- a/arch/parisc/Makefile
+++ b/arch/parisc/Makefile
@@ -20,9 +20,8 @@
FINAL_LD=$(CROSS_COMPILE)ld --warn-common --warn-section-align
CPP=$(CC) -E
-OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
-LDFLAGS =
-LINKFLAGS =-T $(TOPDIR)/arch/parisc/vmlinux.lds $(LDFLAGS)
+OBJCOPY_FLAGS =-O binary -R .note -R .comment -S
+LDFLAGS_vmlinux =-T arch/parisc/vmlinux.lds
CFLAGS_PIPE := -pipe
CFLAGS_NSR := -fno-strength-reduce
diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile
index 458476b851f1..9eed867abf8c 100644
--- a/arch/ppc/Makefile
+++ b/arch/ppc/Makefile
@@ -21,7 +21,7 @@ else
KERNELLOAD =0xc0000000
endif
-LINKFLAGS = -T arch/ppc/vmlinux.lds -Ttext $(KERNELLOAD) -Bstatic
+LDFLAGS_vmlinux = -T arch/ppc/vmlinux.lds -Ttext $(KERNELLOAD) -Bstatic
CPPFLAGS := $(CPPFLAGS) -I$(TOPDIR)/arch/$(ARCH)
AFLAGS := $(AFLAGS) -I$(TOPDIR)/arch/$(ARCH)
CFLAGS := $(CFLAGS) -I$(TOPDIR)/arch/$(ARCH) -fsigned-char \
diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile
index b281c06695f8..e7bbc9d4757d 100644
--- a/arch/ppc64/Makefile
+++ b/arch/ppc64/Makefile
@@ -15,7 +15,7 @@
KERNELLOAD =0xc000000000000000
-LINKFLAGS = -T arch/ppc64/vmlinux.lds -Bstatic \
+LDFLAGS_vmlinux = -T arch/ppc64/vmlinux.lds -Bstatic \
-e $(KERNELLOAD) -Ttext $(KERNELLOAD)
CFLAGS := $(CFLAGS) -fsigned-char -msoft-float -pipe \
-Wno-uninitialized -mminimal-toc -mtraceback=full \
diff --git a/arch/ppc64/boot/Makefile b/arch/ppc64/boot/Makefile
index 0dad54b44742..d96dc878093a 100644
--- a/arch/ppc64/boot/Makefile
+++ b/arch/ppc64/boot/Makefile
@@ -36,6 +36,7 @@ BOOTAFLAGS = -D__ASSEMBLY__ $(HOSTCFLAGS)
CFLAGS = $(CPPFLAGS) -O -fno-builtin -DSTDC_HEADERS
LD_ARGS = -Ttext 0x00400000 -e _start
+OBJCOPYFLAGS := -S -O binary
OBJS = crt0.o start.o main.o zlib.o image.o imagesize.o
#LIBS = $(TOPDIR)/lib/lib.a
@@ -109,9 +110,8 @@ zImage.initrd: $(OBJS) initrd.o addnote
$(BOOTLD) $(LD_ARGS) -T zImage.lds -o $@ $(OBJS) initrd.o $(LIBS)
./addnote $@
-
vmlinux.gz: $(TOPDIR)/vmlinux
- $(OBJCOPY) -S -O binary $(TOPDIR)/vmlinux vmlinux
+ $(OBJCOPY) $(OBJCOPYFLAGS) $(TOPDIR)/vmlinux vmlinux
ls -l vmlinux | awk '{printf "/* generated -- do not edit! */\nint uncompressed_size = %d;\n", $$5}' > imagesize.c
$(CROSS_COMPILE)nm -n $(TOPDIR)/vmlinux | tail -1 | awk '{printf "long vmlinux_end = 0x%s;\n", substr($$1,8)}' >> imagesize.c
gzip -vf9 vmlinux
diff --git a/arch/s390/Makefile b/arch/s390/Makefile
index 681eb4f9a0fa..286017885528 100644
--- a/arch/s390/Makefile
+++ b/arch/s390/Makefile
@@ -13,15 +13,14 @@
# Copyright (C) 1994 by Linus Torvalds
#
-LD=$(CROSS_COMPILE)ld -m elf_s390
-OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
-LDFLAGS=-e start
+LDFLAGS := -m elf_s390
+OBJCOPYFLAGS := -O binary
ifeq ($(CONFIG_SHARED_KERNEL),y)
LINKSCRIPT := arch/s390/vmlinux-shared.lds
else
LINKSCRIPT := arch/s390/vmlinux.lds
endif
-LINKFLAGS =-T $(TOPDIR)/$(LINKSCRIPT) $(LDFLAGS)
+LDFLAGS_vmlinux := -T $(LINKSCRIPT) -e start
CFLAGS_PIPE := -pipe
CFLAGS_NSR := -fno-strength-reduce
diff --git a/arch/s390/boot/Makefile b/arch/s390/boot/Makefile
index 9bc623794c8f..47f55551632d 100644
--- a/arch/s390/boot/Makefile
+++ b/arch/s390/boot/Makefile
@@ -2,21 +2,19 @@
# arch/s390/boot/Makefile
#
-OBJCOPY = $(CROSS_COMPILE)objcopy
-
EXTRA_AFLAGS := -traditional
include $(TOPDIR)/Rules.make
%.lnk: %.o
- $(LD) -Ttext 0x0 -o $@ $<
+ $(LD) $(LDFLAGS) -Ttext 0x0 -o $@ $<
%.boot: %.lnk
- $(OBJCOPY) -O binary $< $@
+ $(OBJCOPY) $(OBJCOPYFLAGS) $< $@
image: $(TOPDIR)/vmlinux \
iplfba.boot ipleckd.boot ipldump.boot
- $(OBJCOPY) -O binary $(TOPDIR)/vmlinux image
+ $(OBJCOPY) $(OBJCOPYFLAGS) $(TOPDIR)/vmlinux image
$(NM) $(TOPDIR)/vmlinux | grep -v '\(compiled\)\|\( [aUw] \)\|\(\.\)\|\(LASH[RL]DI\)' | sort > $(TOPDIR)/System.map
listing: ../../../vmlinux
diff --git a/arch/s390x/Makefile b/arch/s390x/Makefile
index b46bf22ec984..ad6a4427b804 100644
--- a/arch/s390x/Makefile
+++ b/arch/s390x/Makefile
@@ -13,16 +13,15 @@
# Copyright (C) 1994 by Linus Torvalds
#
-LD=$(CROSS_COMPILE)ld -m elf64_s390
+LDFLAGS := -m elf64_s390
CPP=$(CC) -E
-OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
-LDFLAGS=-e start
+OBJCOPYFLAGS := -O binary
ifeq ($(CONFIG_SHARED_KERNEL),y)
LINKSCRIPT := arch/s390x/vmlinux-shared.lds
else
LINKSCRIPT := arch/s390x/vmlinux.lds
endif
-LINKFLAGS =-T $(TOPDIR)/$(LINKSCRIPT) $(LDFLAGS)
+LDFLAGS_vmlinux := -T $(LINKSCRIPT) -e start
MODFLAGS += -fpic
CFLAGS_PIPE := -pipe
diff --git a/arch/s390x/boot/Makefile b/arch/s390x/boot/Makefile
index 22d6f52c6942..3a514eedff72 100644
--- a/arch/s390x/boot/Makefile
+++ b/arch/s390x/boot/Makefile
@@ -2,8 +2,6 @@
# Makefile for the linux s390-specific parts of the memory manager.
#
-OBJCOPY = $(CROSS_COMPILE)objcopy
-
O_TARGET :=
EXTRA_AFLAGS := -traditional
@@ -14,11 +12,11 @@ include $(TOPDIR)/Rules.make
$(LD) -Ttext 0x0 -o $@ $<
%.boot: %.lnk
- $(OBJCOPY) -O binary $< $@
+ $(OBJCOPY) $(OBJCOPYFLAGS) $< $@
image: $(TOPDIR)/vmlinux \
iplfba.boot ipleckd.boot ipldump.boot
- $(OBJCOPY) -O binary $(TOPDIR)/vmlinux image
+ $(OBJCOPY) $(OBJCOPYFLAGS) $< $@
$(NM) $(TOPDIR)/vmlinux | grep -v '\(compiled\)\|\( [aUw] \)\|\(\.\)\|\(LASH[RL]DI\)' | sort > $(TOPDIR)/System.map
listing: ../../../vmlinux
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index b3c0bbe6c078..be546cb3f085 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -15,17 +15,16 @@
ifdef CONFIG_CPU_LITTLE_ENDIAN
CFLAGS += -ml
AFLAGS += -ml
-# LINKFLAGS += -EL
+# LDFLAGS_vmlinux += -EL
LDFLAGS := -EL
else
CFLAGS += -mb
AFLAGS += -mb
-# LINKFLAGS += -EB
+# LDFLAGS_vmlinux += -EB
LDFLAGS := -EB
endif
-LD =$(CROSS_COMPILE)ld $(LDFLAGS)
-OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -R .stab -R .stabstr -S
+OBJCOPYFLAGS := -O binary -R .note -R .comment -R .stab -R .stabstr -S
MODFLAGS +=
@@ -47,10 +46,10 @@ endif
# none has been choosen above.
#
LINKSCRIPT = arch/sh/vmlinux.lds
-LINKFLAGS += -T $(word 1,$(LINKSCRIPT)) -e _stext
+LDFLAGS_vmlinux += -T $(word 1,$(LINKSCRIPT)) -e _stext
ifdef LOADADDR
-LINKFLAGS += -Ttext $(word 1,$(LOADADDR))
+LDFLAGS_vmlinux += -Ttext $(word 1,$(LOADADDR))
endif
#
diff --git a/arch/sh/boot/Makefile b/arch/sh/boot/Makefile
index aeb304826d9a..4d3dd9419eb9 100644
--- a/arch/sh/boot/Makefile
+++ b/arch/sh/boot/Makefile
@@ -11,10 +11,10 @@
SYSTEM =$(TOPDIR)/vmlinux
Image: $(SYSTEM)
- $(OBJCOPY) $(SYSTEM) Image
+ $(OBJCOPY) $(OBJCOPYFLAGS) $< $@
zImage: compressed/vmlinux
- $(OBJCOPY) compressed/vmlinux zImage
+ $(OBJCOPY) $(OBJCOPYFLAGS) $< $@
compressed/vmlinux: $(TOPDIR)/vmlinux
$(MAKE) -C compressed vmlinux
diff --git a/arch/sh/boot/compressed/Makefile b/arch/sh/boot/compressed/Makefile
index 7e34e14dab2b..b2efc40bf86d 100644
--- a/arch/sh/boot/compressed/Makefile
+++ b/arch/sh/boot/compressed/Makefile
@@ -25,7 +25,7 @@ ZLINKFLAGS = -Ttext $(ZIMAGE_OFFSET) $(ZLDFLAGS)
all: vmlinux
vmlinux: piggy.o $(OBJECTS)
- $(LD) $(ZLINKFLAGS) -o vmlinux $(OBJECTS) piggy.o
+ $(LD) $(LDFLAGS) $(ZLINKFLAGS) -o vmlinux $(OBJECTS) piggy.o
head.o: head.S
$(CC) $(AFLAGS) -traditional -c head.S
@@ -33,10 +33,10 @@ head.o: head.S
piggy.o: $(SYSTEM)
tmppiggy=_tmp_$$$$piggy; \
rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \
- $(OBJCOPY) -R .empty_zero_page $(SYSTEM) $$tmppiggy; \
+ $(OBJCOPY) $(OBJCOPYFLAGS) -R .empty_zero_page $(SYSTEM) $$tmppiggy; \
gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \
echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \
- $(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-sh-linux -T $$tmppiggy.lnk; \
+ $(LD) $(LDFLAGS) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-sh-linux -T $$tmppiggy.lnk; \
rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk
clean:
diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile
index ad328c3e5bca..04ca208da275 100644
--- a/arch/sparc/Makefile
+++ b/arch/sparc/Makefile
@@ -20,7 +20,7 @@ NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; the
ifeq ($(NEW_GAS),y)
AS := $(AS) -32
-LD := $(LD) -m elf32_sparc
+LDFLAGS := -m elf32_sparc
endif
#CFLAGS := $(CFLAGS) -g -pipe -fcall-used-g5 -fcall-used-g7
@@ -30,8 +30,8 @@ else
CFLAGS := $(CFLAGS) -m32 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7
endif
-#LINKFLAGS = -N -Ttext 0xf0004000
-LINKFLAGS = -T arch/sparc/vmlinux.lds
+#LDFLAGS_vmlinux = -N -Ttext 0xf0004000
+LDFLAGS_vmlinux = -T arch/sparc/vmlinux.lds
HEAD := arch/sparc/kernel/head.o arch/sparc/kernel/init_task.o
diff --git a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile
index ea6c7052175d..3e2ceaf085fe 100644
--- a/arch/sparc/boot/Makefile
+++ b/arch/sparc/boot/Makefile
@@ -31,7 +31,7 @@ BTLIBS := $(CORE_FILES_NO_BTFIX) $(FILESYSTEMS) \
# properly as it will cause head.o to be built with the implicit
# rules not the ones in kernel/Makefile. Someone please fix. --DaveM
vmlinux.o: FORCE
- $(LD) -r $(patsubst %,$(TOPDIR)/%,$(BTOBJS)) \
+ $(LD) $(LDFLAGS) -r $(patsubst %,$(TOPDIR)/%,$(BTOBJS)) \
--start-group \
$(patsubst %,$(TOPDIR)/%,$(BTLIBS)) \
$(LIBS) \
diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile
index f1bee59d0b78..312431c6bb86 100644
--- a/arch/sparc64/Makefile
+++ b/arch/sparc64/Makefile
@@ -28,7 +28,7 @@ AR = sparc64-linux-ar
RANLIB = sparc64-linux-ranlib
else
AS := $(AS) -64
-LD := $(LD) -m elf64_sparc
+LDFLAGS := -m elf64_sparc
endif
ELFTOAOUT = elftoaout
ifneq ($(UNDECLARED_REGS),y)
@@ -53,7 +53,7 @@ ifeq ($(CONFIG_MCOUNT),y)
CFLAGS := $(CFLAGS) -pg
endif
-LINKFLAGS = -T arch/sparc64/vmlinux.lds
+LDFLAGS_vmlinux = -T arch/sparc64/vmlinux.lds
HEAD := arch/sparc64/kernel/head.o arch/sparc64/kernel/init_task.o
diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile
index b78fca37a641..fc75b3b338ee 100644
--- a/arch/x86_64/Makefile
+++ b/arch/x86_64/Makefile
@@ -34,9 +34,8 @@ export IA32_CC IA32_LD IA32_AS IA32_OBJCOPY IA32_CPP
LD=$(CROSS_COMPILE)ld -m elf_x86_64
-OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
-LDFLAGS=-e stext
-LINKFLAGS =-T $(TOPDIR)/arch/x86_64/vmlinux.lds $(LDFLAGS)
+OBJCOPYFLAGS := -O binary -R .note -R .comment -S
+LDFLAGS_vmlinux := -T arch/x86_64/vmlinux.lds -e stext
CFLAGS += -mno-red-zone
CFLAGS += -mcmodel=kernel
diff --git a/arch/x86_64/boot/Makefile b/arch/x86_64/boot/Makefile
index 92aa42546bf4..68cb973787ac 100644
--- a/arch/x86_64/boot/Makefile
+++ b/arch/x86_64/boot/Makefile
@@ -28,11 +28,11 @@ BOOT_INCL = $(TOPDIR)/include/linux/config.h \
$(TOPDIR)/include/asm/boot.h
zImage: bootsect setup compressed/vmlinux tools/build
- $(OBJCOPY) compressed/vmlinux compressed/vmlinux.out
+ $(OBJCOPY) $(OBJCOPYFLAGS) compressed/vmlinux compressed/vmlinux.out
tools/build bootsect setup compressed/vmlinux.out $(ROOT_DEV) > zImage
bzImage: bbootsect bsetup compressed/bvmlinux tools/build
- $(OBJCOPY) compressed/bvmlinux compressed/bvmlinux.out
+ $(OBJCOPY) $(OBJCOPYFLAGS) compressed/bvmlinux compressed/bvmlinux.out
tools/build -b bbootsect bsetup compressed/bvmlinux.out $(ROOT_DEV) > bzImage
bzImage-padded: bzImage
diff --git a/arch/x86_64/boot/compressed/Makefile b/arch/x86_64/boot/compressed/Makefile
index 0832d0231699..83b1b657b5e6 100644
--- a/arch/x86_64/boot/compressed/Makefile
+++ b/arch/x86_64/boot/compressed/Makefile
@@ -33,7 +33,7 @@ misc.o: misc.c
piggy.o: $(SYSTEM)
tmppiggy=_tmp_$$$$piggy; \
rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \
- $(OBJCOPY) $(SYSTEM) $$tmppiggy; \
+ $(OBJCOPY) $(OBJCOPYFLAGS) $< $$tmppiggy; \
gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \
echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \
$(IA32_LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 -T $$tmppiggy.lnk; \
diff --git a/drivers/acorn/char/Makefile b/drivers/acorn/char/Makefile
index fc00f7902cb5..06acf0a7ea75 100644
--- a/drivers/acorn/char/Makefile
+++ b/drivers/acorn/char/Makefile
@@ -20,5 +20,16 @@ obj-y += $(obj-$(MACHINE))
include $(TOPDIR)/Rules.make
-$(obj)/%.c: $(src)/%.map
+$(obj)/defkeymap-acorn.o: $(obj)/defkeymap-acorn.c
+
+# Uncomment if you're changing the keymap and have an appropriate
+# loadkeys version for the map. By default, we'll use the shipped
+# versions.
+# GENERATE_KEYMAP := 1
+
+ifdef GENERATE_KEYMAP
+
+$(obj)/defkeymap-acorn.c: $(obj)/%.c: $(src)/%.map
loadkeys --mktable $< > $@
+
+endif
diff --git a/drivers/acorn/char/defkeymap-acorn.c b/drivers/acorn/char/defkeymap-acorn.c_shipped
index 63d366cc2658..63d366cc2658 100644
--- a/drivers/acorn/char/defkeymap-acorn.c
+++ b/drivers/acorn/char/defkeymap-acorn.c_shipped
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 5a99b84a81c3..ed74453f7c64 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -219,8 +219,20 @@ include $(TOPDIR)/Rules.make
$(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE) $(obj)/conmakehash
$(obj)/conmakehash $< > $@
-$(obj)/defkeymap.c: $(src)/defkeymap.map
- set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
+$(obj)/defkeymap.o: $(obj)/defkeymap.c
-$(obj)/qtronixmap.c: $(src)/qtronixmap.map
- set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
+$(obj)/qtronixmap.o: $(obj)/qtronixmap.c
+
+# Uncomment if you're changing the keymap and have an appropriate
+# loadkeys version for the map. By default, we'll use the shipped
+# versions.
+# GENERATE_KEYMAP := 1
+
+ifdef GENERATE_KEYMAP
+
+$(obj)/defkeymap.c $(obj)/qtronixmap.c: $(obj)/%.c: $(src)/%.map
+ loadkeys --mktable $< > $@.tmp
+ sed -e 's/^static *//' $@.tmp > $@
+ rm $@.tmp
+
+endif \ No newline at end of file
diff --git a/drivers/char/defkeymap.c_shipped b/drivers/char/defkeymap.c_shipped
new file mode 100644
index 000000000000..d8ac176c251d
--- /dev/null
+++ b/drivers/char/defkeymap.c_shipped
@@ -0,0 +1,262 @@
+/* Do not edit this file! It was automatically generated by */
+/* loadkeys --mktable defkeymap.map > defkeymap.c */
+
+#include <linux/types.h>
+#include <linux/keyboard.h>
+#include <linux/kd.h>
+
+u_short plain_map[NR_KEYS] = {
+ 0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036,
+ 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf07f, 0xf009,
+ 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
+ 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73,
+ 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
+ 0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76,
+ 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf30c,
+ 0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
+ 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf209, 0xf307,
+ 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
+ 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03c, 0xf10a,
+ 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
+ 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
+ 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short shift_map[NR_KEYS] = {
+ 0xf200, 0xf01b, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e,
+ 0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07f, 0xf009,
+ 0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49,
+ 0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf201, 0xf702, 0xfb41, 0xfb53,
+ 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a,
+ 0xf022, 0xf07e, 0xf700, 0xf07c, 0xfb5a, 0xfb58, 0xfb43, 0xfb56,
+ 0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, 0xf700, 0xf30c,
+ 0xf703, 0xf020, 0xf207, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e,
+ 0xf10f, 0xf110, 0xf111, 0xf112, 0xf113, 0xf213, 0xf203, 0xf307,
+ 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
+ 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03e, 0xf10a,
+ 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
+ 0xf20b, 0xf601, 0xf602, 0xf117, 0xf600, 0xf20a, 0xf115, 0xf116,
+ 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short altgr_map[NR_KEYS] = {
+ 0xf200, 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200,
+ 0xf07b, 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200,
+ 0xfb71, 0xfb77, 0xf918, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
+ 0xfb6f, 0xfb70, 0xf200, 0xf07e, 0xf201, 0xf702, 0xf914, 0xfb73,
+ 0xf917, 0xf919, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf200,
+ 0xf200, 0xf200, 0xf700, 0xf200, 0xfb7a, 0xfb78, 0xf916, 0xfb76,
+ 0xf915, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c,
+ 0xf703, 0xf200, 0xf207, 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510,
+ 0xf511, 0xf512, 0xf513, 0xf514, 0xf515, 0xf208, 0xf202, 0xf911,
+ 0xf912, 0xf913, 0xf30b, 0xf90e, 0xf90f, 0xf910, 0xf30a, 0xf90b,
+ 0xf90c, 0xf90d, 0xf90a, 0xf310, 0xf206, 0xf200, 0xf07c, 0xf516,
+ 0xf517, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
+ 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
+ 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short ctrl_map[NR_KEYS] = {
+ 0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e,
+ 0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200,
+ 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
+ 0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf201, 0xf702, 0xf001, 0xf013,
+ 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
+ 0xf007, 0xf000, 0xf700, 0xf01c, 0xf01a, 0xf018, 0xf003, 0xf016,
+ 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf20e, 0xf07f, 0xf700, 0xf30c,
+ 0xf703, 0xf000, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
+ 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf204, 0xf307,
+ 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
+ 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf10a,
+ 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
+ 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
+ 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short shift_ctrl_map[NR_KEYS] = {
+ 0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200,
+ 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
+ 0xf00f, 0xf010, 0xf200, 0xf200, 0xf201, 0xf702, 0xf001, 0xf013,
+ 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
+ 0xf200, 0xf200, 0xf700, 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016,
+ 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c,
+ 0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf208, 0xf200, 0xf307,
+ 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
+ 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
+ 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
+ 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short alt_map[NR_KEYS] = {
+ 0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836,
+ 0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf87f, 0xf809,
+ 0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869,
+ 0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf80d, 0xf702, 0xf861, 0xf873,
+ 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf86c, 0xf83b,
+ 0xf827, 0xf860, 0xf700, 0xf85c, 0xf87a, 0xf878, 0xf863, 0xf876,
+ 0xf862, 0xf86e, 0xf86d, 0xf82c, 0xf82e, 0xf82f, 0xf700, 0xf30c,
+ 0xf703, 0xf820, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504,
+ 0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf209, 0xf907,
+ 0xf908, 0xf909, 0xf30b, 0xf904, 0xf905, 0xf906, 0xf30a, 0xf901,
+ 0xf902, 0xf903, 0xf900, 0xf310, 0xf206, 0xf200, 0xf83c, 0xf50a,
+ 0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
+ 0xf118, 0xf210, 0xf211, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
+ 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short ctrl_alt_map[NR_KEYS] = {
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809,
+ 0xf80f, 0xf810, 0xf200, 0xf200, 0xf201, 0xf702, 0xf801, 0xf813,
+ 0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200,
+ 0xf200, 0xf200, 0xf700, 0xf200, 0xf81a, 0xf818, 0xf803, 0xf816,
+ 0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c,
+ 0xf703, 0xf200, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504,
+ 0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf200, 0xf307,
+ 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
+ 0xf302, 0xf303, 0xf300, 0xf20c, 0xf206, 0xf200, 0xf200, 0xf50a,
+ 0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
+ 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf20c,
+ 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+ushort *key_maps[MAX_NR_KEYMAPS] = {
+ plain_map, shift_map, altgr_map, 0,
+ ctrl_map, shift_ctrl_map, 0, 0,
+ alt_map, 0, 0, 0,
+ ctrl_alt_map, 0
+};
+
+unsigned int keymap_count = 7;
+
+/*
+ * Philosophy: most people do not define more strings, but they who do
+ * often want quite a lot of string space. So, we statically allocate
+ * the default and allocate dynamically in chunks of 512 bytes.
+ */
+
+char func_buf[] = {
+ '\033', '[', '[', 'A', 0,
+ '\033', '[', '[', 'B', 0,
+ '\033', '[', '[', 'C', 0,
+ '\033', '[', '[', 'D', 0,
+ '\033', '[', '[', 'E', 0,
+ '\033', '[', '1', '7', '~', 0,
+ '\033', '[', '1', '8', '~', 0,
+ '\033', '[', '1', '9', '~', 0,
+ '\033', '[', '2', '0', '~', 0,
+ '\033', '[', '2', '1', '~', 0,
+ '\033', '[', '2', '3', '~', 0,
+ '\033', '[', '2', '4', '~', 0,
+ '\033', '[', '2', '5', '~', 0,
+ '\033', '[', '2', '6', '~', 0,
+ '\033', '[', '2', '8', '~', 0,
+ '\033', '[', '2', '9', '~', 0,
+ '\033', '[', '3', '1', '~', 0,
+ '\033', '[', '3', '2', '~', 0,
+ '\033', '[', '3', '3', '~', 0,
+ '\033', '[', '3', '4', '~', 0,
+ '\033', '[', '1', '~', 0,
+ '\033', '[', '2', '~', 0,
+ '\033', '[', '3', '~', 0,
+ '\033', '[', '4', '~', 0,
+ '\033', '[', '5', '~', 0,
+ '\033', '[', '6', '~', 0,
+ '\033', '[', 'M', 0,
+ '\033', '[', 'P', 0,
+};
+
+char *funcbufptr = func_buf;
+int funcbufsize = sizeof(func_buf);
+int funcbufleft = 0; /* space left */
+
+char *func_table[MAX_NR_FUNC] = {
+ func_buf + 0,
+ func_buf + 5,
+ func_buf + 10,
+ func_buf + 15,
+ func_buf + 20,
+ func_buf + 25,
+ func_buf + 31,
+ func_buf + 37,
+ func_buf + 43,
+ func_buf + 49,
+ func_buf + 55,
+ func_buf + 61,
+ func_buf + 67,
+ func_buf + 73,
+ func_buf + 79,
+ func_buf + 85,
+ func_buf + 91,
+ func_buf + 97,
+ func_buf + 103,
+ func_buf + 109,
+ func_buf + 115,
+ func_buf + 120,
+ func_buf + 125,
+ func_buf + 130,
+ func_buf + 135,
+ func_buf + 140,
+ func_buf + 145,
+ 0,
+ 0,
+ func_buf + 149,
+ 0,
+};
+
+struct kbdiacr accent_table[MAX_DIACR] = {
+ {'`', 'A', '\300'}, {'`', 'a', '\340'},
+ {'\'', 'A', '\301'}, {'\'', 'a', '\341'},
+ {'^', 'A', '\302'}, {'^', 'a', '\342'},
+ {'~', 'A', '\303'}, {'~', 'a', '\343'},
+ {'"', 'A', '\304'}, {'"', 'a', '\344'},
+ {'O', 'A', '\305'}, {'o', 'a', '\345'},
+ {'0', 'A', '\305'}, {'0', 'a', '\345'},
+ {'A', 'A', '\305'}, {'a', 'a', '\345'},
+ {'A', 'E', '\306'}, {'a', 'e', '\346'},
+ {',', 'C', '\307'}, {',', 'c', '\347'},
+ {'`', 'E', '\310'}, {'`', 'e', '\350'},
+ {'\'', 'E', '\311'}, {'\'', 'e', '\351'},
+ {'^', 'E', '\312'}, {'^', 'e', '\352'},
+ {'"', 'E', '\313'}, {'"', 'e', '\353'},
+ {'`', 'I', '\314'}, {'`', 'i', '\354'},
+ {'\'', 'I', '\315'}, {'\'', 'i', '\355'},
+ {'^', 'I', '\316'}, {'^', 'i', '\356'},
+ {'"', 'I', '\317'}, {'"', 'i', '\357'},
+ {'-', 'D', '\320'}, {'-', 'd', '\360'},
+ {'~', 'N', '\321'}, {'~', 'n', '\361'},
+ {'`', 'O', '\322'}, {'`', 'o', '\362'},
+ {'\'', 'O', '\323'}, {'\'', 'o', '\363'},
+ {'^', 'O', '\324'}, {'^', 'o', '\364'},
+ {'~', 'O', '\325'}, {'~', 'o', '\365'},
+ {'"', 'O', '\326'}, {'"', 'o', '\366'},
+ {'/', 'O', '\330'}, {'/', 'o', '\370'},
+ {'`', 'U', '\331'}, {'`', 'u', '\371'},
+ {'\'', 'U', '\332'}, {'\'', 'u', '\372'},
+ {'^', 'U', '\333'}, {'^', 'u', '\373'},
+ {'"', 'U', '\334'}, {'"', 'u', '\374'},
+ {'\'', 'Y', '\335'}, {'\'', 'y', '\375'},
+ {'T', 'H', '\336'}, {'t', 'h', '\376'},
+ {'s', 's', '\337'}, {'"', 'y', '\377'},
+ {'s', 'z', '\337'}, {'i', 'j', '\377'},
+};
+
+unsigned int accent_table_size = 68;
diff --git a/drivers/char/qtronixmap.c_shipped b/drivers/char/qtronixmap.c_shipped
new file mode 100644
index 000000000000..1e2b92b7d57a
--- /dev/null
+++ b/drivers/char/qtronixmap.c_shipped
@@ -0,0 +1,265 @@
+
+/* Do not edit this file! It was automatically generated by */
+/* loadkeys --mktable defkeymap.map > defkeymap.c */
+
+#include <linux/types.h>
+#include <linux/keyboard.h>
+#include <linux/kd.h>
+
+u_short plain_map[NR_KEYS] = {
+ 0xf200, 0xf060, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036,
+ 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf200, 0xf07f,
+ 0xf009, 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75,
+ 0xfb69, 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf05c, 0xf207, 0xfb61,
+ 0xfb73, 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c,
+ 0xf03b, 0xf027, 0xf060, 0xf201, 0xf700, 0xf200, 0xfb7a, 0xfb78,
+ 0xfb63, 0xfb76, 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f,
+ 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf020, 0xf703, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601,
+ 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200,
+ 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf01b, 0xf200,
+ 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107,
+ 0xf108, 0xf109, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200,
+};
+
+u_short shift_map[NR_KEYS] = {
+ 0xf200, 0xf07e, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e,
+ 0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf200, 0xf07f,
+ 0xf009, 0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55,
+ 0xfb49, 0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf07c, 0xf207, 0xfb41,
+ 0xfb53, 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c,
+ 0xf03a, 0xf022, 0xf07e, 0xf201, 0xf700, 0xf200, 0xfb5a, 0xfb58,
+ 0xfb43, 0xfb56, 0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f,
+ 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf020, 0xf703, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601,
+ 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf20b, 0xf20a, 0xf200,
+ 0xf200, 0xf602, 0xf213, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf01b, 0xf200,
+ 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e, 0xf10f, 0xf110, 0xf111,
+ 0xf112, 0xf113, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200,
+};
+
+u_short altgr_map[NR_KEYS] = {
+ 0xf200, 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200,
+ 0xf07b, 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75,
+ 0xfb69, 0xfb6f, 0xfb70, 0xf200, 0xf200, 0xf200, 0xf207, 0xfb61,
+ 0xfb73, 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c,
+ 0xf200, 0xf200, 0xf200, 0xf201, 0xf700, 0xf200, 0xfb7a, 0xfb78,
+ 0xfb63, 0xfb76, 0xfb62, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf200, 0xf703, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601,
+ 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200,
+ 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200,
+ 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510, 0xf511, 0xf512, 0xf513,
+ 0xf514, 0xf515, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200,
+};
+
+u_short ctrl_map[NR_KEYS] = {
+ 0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e,
+ 0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf008,
+ 0xf200, 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015,
+ 0xf009, 0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf01c, 0xf207, 0xf001,
+ 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c,
+ 0xf007, 0xf000, 0xf200, 0xf201, 0xf700, 0xf200, 0xf01a, 0xf018,
+ 0xf003, 0xf016, 0xf002, 0xf00e, 0xf20e, 0xf07f, 0xf200, 0xf200,
+ 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf000, 0xf703, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601,
+ 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200,
+ 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200,
+ 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107,
+ 0xf108, 0xf109, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200,
+};
+
+u_short shift_ctrl_map[NR_KEYS] = {
+ 0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015,
+ 0xf009, 0xf00f, 0xf010, 0xf200, 0xf200, 0xf200, 0xf207, 0xf001,
+ 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c,
+ 0xf200, 0xf200, 0xf200, 0xf201, 0xf700, 0xf200, 0xf01a, 0xf018,
+ 0xf003, 0xf016, 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf200, 0xf703, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601,
+ 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200,
+ 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200,
+};
+
+u_short alt_map[NR_KEYS] = {
+ 0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836,
+ 0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf200, 0xf87f,
+ 0xf809, 0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875,
+ 0xf869, 0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf85c, 0xf207, 0xf861,
+ 0xf873, 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf83b,
+ 0xf827, 0xf860, 0xf200, 0xf80d, 0xf700, 0xf200, 0xf87a, 0xf878,
+ 0xf863, 0xf876, 0xf862, 0xf82c, 0xf82e, 0xf82f, 0xf200, 0xf200,
+ 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf820, 0xf703, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf210,
+ 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200,
+ 0xf200, 0xf211, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200,
+ 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506, 0xf507,
+ 0xf508, 0xf509, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200,
+};
+
+u_short ctrl_alt_map[NR_KEYS] = {
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815,
+ 0xf809, 0xf80f, 0xf810, 0xf200, 0xf200, 0xf200, 0xf207, 0xf801,
+ 0xf813, 0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c,
+ 0xf200, 0xf200, 0xf200, 0xf201, 0xf700, 0xf200, 0xf81a, 0xf818,
+ 0xf803, 0xf816, 0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf200, 0xf703, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601,
+ 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200,
+ 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200,
+ 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506, 0xf507,
+ 0xf508, 0xf509, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200,
+};
+
+ushort *key_maps[MAX_NR_KEYMAPS] = {
+ plain_map, shift_map, altgr_map, 0,
+ ctrl_map, shift_ctrl_map, 0, 0,
+ alt_map, 0, 0, 0,
+ ctrl_alt_map, 0
+};
+
+unsigned int keymap_count = 7;
+
+
+/*
+ * Philosophy: most people do not define more strings, but they who do
+ * often want quite a lot of string space. So, we statically allocate
+ * the default and allocate dynamically in chunks of 512 bytes.
+ */
+
+char func_buf[] = {
+ '\033', '[', '[', 'A', 0,
+ '\033', '[', '[', 'B', 0,
+ '\033', '[', '[', 'C', 0,
+ '\033', '[', '[', 'D', 0,
+ '\033', '[', '[', 'E', 0,
+ '\033', '[', '1', '7', '~', 0,
+ '\033', '[', '1', '8', '~', 0,
+ '\033', '[', '1', '9', '~', 0,
+ '\033', '[', '2', '0', '~', 0,
+ '\033', '[', '2', '1', '~', 0,
+ '\033', '[', '2', '3', '~', 0,
+ '\033', '[', '2', '4', '~', 0,
+ '\033', '[', '2', '5', '~', 0,
+ '\033', '[', '2', '6', '~', 0,
+ '\033', '[', '2', '8', '~', 0,
+ '\033', '[', '2', '9', '~', 0,
+ '\033', '[', '3', '1', '~', 0,
+ '\033', '[', '3', '2', '~', 0,
+ '\033', '[', '3', '3', '~', 0,
+ '\033', '[', '3', '4', '~', 0,
+ '\033', '[', '1', '~', 0,
+ '\033', '[', '2', '~', 0,
+ '\033', '[', '3', '~', 0,
+ '\033', '[', '4', '~', 0,
+ '\033', '[', '5', '~', 0,
+ '\033', '[', '6', '~', 0,
+ '\033', '[', 'M', 0,
+ '\033', '[', 'P', 0,
+};
+
+
+char *funcbufptr = func_buf;
+int funcbufsize = sizeof(func_buf);
+int funcbufleft = 0; /* space left */
+
+char *func_table[MAX_NR_FUNC] = {
+ func_buf + 0,
+ func_buf + 5,
+ func_buf + 10,
+ func_buf + 15,
+ func_buf + 20,
+ func_buf + 25,
+ func_buf + 31,
+ func_buf + 37,
+ func_buf + 43,
+ func_buf + 49,
+ func_buf + 55,
+ func_buf + 61,
+ func_buf + 67,
+ func_buf + 73,
+ func_buf + 79,
+ func_buf + 85,
+ func_buf + 91,
+ func_buf + 97,
+ func_buf + 103,
+ func_buf + 109,
+ func_buf + 115,
+ func_buf + 120,
+ func_buf + 125,
+ func_buf + 130,
+ func_buf + 135,
+ func_buf + 140,
+ func_buf + 145,
+ 0,
+ 0,
+ func_buf + 149,
+ 0,
+};
+
+struct kbdiacr accent_table[MAX_DIACR] = {
+ {'`', 'A', 'À'}, {'`', 'a', 'à'},
+ {'\'', 'A', 'Á'}, {'\'', 'a', 'á'},
+ {'^', 'A', 'Â'}, {'^', 'a', 'â'},
+ {'~', 'A', 'Ã'}, {'~', 'a', 'ã'},
+ {'"', 'A', 'Ä'}, {'"', 'a', 'ä'},
+ {'O', 'A', 'Å'}, {'o', 'a', 'å'},
+ {'0', 'A', 'Å'}, {'0', 'a', 'å'},
+ {'A', 'A', 'Å'}, {'a', 'a', 'å'},
+ {'A', 'E', 'Æ'}, {'a', 'e', 'æ'},
+ {',', 'C', 'Ç'}, {',', 'c', 'ç'},
+ {'`', 'E', 'È'}, {'`', 'e', 'è'},
+ {'\'', 'E', 'É'}, {'\'', 'e', 'é'},
+ {'^', 'E', 'Ê'}, {'^', 'e', 'ê'},
+ {'"', 'E', 'Ë'}, {'"', 'e', 'ë'},
+ {'`', 'I', 'Ì'}, {'`', 'i', 'ì'},
+ {'\'', 'I', 'Í'}, {'\'', 'i', 'í'},
+ {'^', 'I', 'Î'}, {'^', 'i', 'î'},
+ {'"', 'I', 'Ï'}, {'"', 'i', 'ï'},
+ {'-', 'D', 'Ð'}, {'-', 'd', 'ð'},
+ {'~', 'N', 'Ñ'}, {'~', 'n', 'ñ'},
+ {'`', 'O', 'Ò'}, {'`', 'o', 'ò'},
+ {'\'', 'O', 'Ó'}, {'\'', 'o', 'ó'},
+ {'^', 'O', 'Ô'}, {'^', 'o', 'ô'},
+ {'~', 'O', 'Õ'}, {'~', 'o', 'õ'},
+ {'"', 'O', 'Ö'}, {'"', 'o', 'ö'},
+ {'/', 'O', 'Ø'}, {'/', 'o', 'ø'},
+ {'`', 'U', 'Ù'}, {'`', 'u', 'ù'},
+ {'\'', 'U', 'Ú'}, {'\'', 'u', 'ú'},
+ {'^', 'U', 'Û'}, {'^', 'u', 'û'},
+ {'"', 'U', 'Ü'}, {'"', 'u', 'ü'},
+ {'\'', 'Y', 'Ý'}, {'\'', 'y', 'ý'},
+ {'T', 'H', 'Þ'}, {'t', 'h', 'þ'},
+ {'s', 's', 'ß'}, {'"', 'y', 'ÿ'},
+ {'s', 'z', 'ß'}, {'i', 'j', 'ÿ'},
+};
+
+unsigned int accent_table_size = 68;
diff --git a/drivers/ide/probe.c b/drivers/ide/probe.c
index b1b026f76cfc..ab7df11e44a7 100644
--- a/drivers/ide/probe.c
+++ b/drivers/ide/probe.c
@@ -1173,18 +1173,6 @@ static void channel_init(struct ata_channel *ch)
gd->next = NULL; /* linked list of major devs */
gd->fops = ide_fops; /* file operations */
- gd->de_arr = kmalloc(sizeof(*gd->de_arr) * MAX_DRIVES, GFP_KERNEL);
- if (gd->de_arr)
- memset(gd->de_arr, 0, sizeof(*gd->de_arr) * MAX_DRIVES);
- else
- goto err_kmalloc_gd_de_arr;
-
- gd->flags = kmalloc(sizeof(*gd->flags) * MAX_DRIVES, GFP_KERNEL);
- if (gd->flags)
- memset(gd->flags, 0, sizeof(*gd->flags) * MAX_DRIVES);
- else
- goto err_kmalloc_gd_flags;
-
ch->gd = gd;
add_gendisk(gd);
diff --git a/drivers/input/Config.help b/drivers/input/Config.help
index 15bc1aab59bd..e75624d0917d 100644
--- a/drivers/input/Config.help
+++ b/drivers/input/Config.help
@@ -64,6 +64,18 @@ CONFIG_INPUT_JOYDEV
The module will be called joydev.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
+CONFIG_INPUT_TSDEV
+ 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.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called tsdev.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
CONFIG_INPUT_EVDEV
Say Y here if you want your input device events be accessible
under char device 13:64+ - /dev/input/eventX in a generic way.
@@ -72,3 +84,17 @@ CONFIG_INPUT_EVDEV
inserted in and removed from the running kernel whenever you want).
The module will be called evdev.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_INPUT_EVBUG
+ 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.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called joydev.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
diff --git a/drivers/input/Config.in b/drivers/input/Config.in
index 66b2aa72897e..7105ceb2f7a6 100644
--- a/drivers/input/Config.in
+++ b/drivers/input/Config.in
@@ -6,20 +6,34 @@ mainmenu_option next_comment
comment 'Input device support'
tristate 'Input core support' CONFIG_INPUT
+
+comment 'Userland interfaces'
dep_tristate ' Keyboard interface' CONFIG_INPUT_KEYBDEV $CONFIG_INPUT
dep_tristate ' Mouse interface' CONFIG_INPUT_MOUSEDEV $CONFIG_INPUT
+dep_mbool ' Provide legacy /dev/psaux device' CONFIG_INPUT_MOUSEDEV_PSAUX $CONFIG_INPUT
if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then
int ' Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
int ' Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
fi
dep_tristate ' Joystick interface' CONFIG_INPUT_JOYDEV $CONFIG_INPUT
+dep_tristate ' Touchscreen interface' CONFIG_INPUT_TSDEV $CONFIG_INPUT
+if [ "$CONFIG_INPUT_TSDEV" != "n" ]; then
+ int ' Horizontal screen resolution' CONFIG_INPUT_TSDEV_SCREEN_X 240
+ int ' Vertical screen resolution' CONFIG_INPUT_TSDEV_SCREEN_Y 320
+fi
dep_tristate ' Event interface' CONFIG_INPUT_EVDEV $CONFIG_INPUT
+dep_tristate ' Event debugging' CONFIG_INPUT_EVBUG $CONFIG_INPUT
+comment 'Input I/O drivers'
source drivers/input/gameport/Config.in
source drivers/input/serio/Config.in
+comment 'Input Device Drivers'
if [ "$CONFIG_INPUT" != "n" ]; then
+ source drivers/input/keyboard/Config.in
+ source drivers/input/mouse/Config.in
source drivers/input/joystick/Config.in
+ source drivers/input/touchscreen/Config.in
fi
endmenu
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index bdb70aa4a996..d6a647876456 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -13,8 +13,14 @@ obj-$(CONFIG_INPUT_KEYBDEV) += keybdev.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/
# The global Rules.make.
diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c
new file mode 100644
index 000000000000..1b91f246cd08
--- /dev/null
+++ b/drivers/input/evbug.c
@@ -0,0 +1,99 @@
+/*
+ * $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>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Input driver event debug module");
+MODULE_LICENSE("GPL");
+
+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;
+
+ 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);
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 413002ffa574..0a2f930cf585 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -1,5 +1,5 @@
/*
- * $Id: evdev.c,v 1.42 2002/01/02 11:59:56 vojtech Exp $
+ * $Id: evdev.c,v 1.48 2002/05/26 14:28:26 jdeneux Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*
@@ -40,7 +40,6 @@
struct evdev {
int exist;
int open;
- int open_for_write;
int minor;
char name[16];
struct input_handle handle;
@@ -91,7 +90,9 @@ static int evdev_fasync(int fd, struct file *file, int on)
static int evdev_flush(struct file * file)
{
- return input_flush_device(&((struct evdev_list*)file->private_data)->evdev->handle, file);
+ struct evdev_list *list = (struct evdev_list*)file->private_data;
+ if (!list->evdev->exist) return -ENODEV;
+ return input_flush_device(&list->evdev->handle, file);
}
static int evdev_release(struct inode * inode, struct file * file)
@@ -158,6 +159,8 @@ static ssize_t evdev_write(struct file * file, const char * buffer, size_t count
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)))
@@ -232,6 +235,8 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
struct input_dev *dev = evdev->handle.dev;
int retval, t, u;
+ if (!evdev->exist) return -ENODEV;
+
switch (cmd) {
case EVIOCGVERSION:
@@ -284,11 +289,11 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
int err;
if (copy_from_user((void*)(&effect), (void*)arg, sizeof(effect))) {
- return -EINVAL;
+ return -EFAULT;
}
err = dev->upload_effect(dev, &effect);
if (put_user(effect.id, &(((struct ff_effect*)arg)->id))) {
- return -EINVAL;
+ return -EFAULT;
}
return err;
}
@@ -301,7 +306,8 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
else return -ENOSYS;
case EVIOCGEFFECTS:
- put_user(dev->ff_effects_max, (int*) arg);
+ if ((retval = put_user(dev->ff_effects_max, (int*) arg)))
+ return retval;
return 0;
default:
diff --git a/drivers/input/gameport/Config.help b/drivers/input/gameport/Config.help
index 54cac2482adf..10b849c461c3 100644
--- a/drivers/input/gameport/Config.help
+++ b/drivers/input/gameport/Config.help
@@ -34,7 +34,7 @@ CONFIG_GAMEPORT_L4
The module will be called lightning.o. If you want to compile it as
a module, say M here and read <file:Documentation/modules.txt>.
-CONFIG_GAMEPORT_EMU10K1
+CONFIG_INPUT_EMU10K1
Say Y here if you have a SoundBlaster Live! or SoundBlaster
Audigy card and want to use its gameport.
@@ -43,16 +43,16 @@ CONFIG_GAMEPORT_EMU10K1
The module will be called emu10k1-gp.o. If you want to compile it as
a module, say M here and read <file:Documentation/modules.txt>.
-CONFIG_GAMEPORT_PCIGAME
- Say Y here if you have an Aureal Vortex 1 or 2 or a Trident
- 4DWave NX or DX card and want to use its gameport.
+CONFIG_GAMEPORT_VORTEX
+ Say Y here if you have an Aureal Vortex 1 or 2 card and want
+ to use its gameport.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
- The module will be called pcigame.o. If you want to compile it as a
+ The module will be called vortex.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
-CONFIG_GAMEPORT_CS461X
+CONFIG_GAMEPORT_CS461x
Say Y here if you have a Cirrus CS461x aka "Crystal SoundFusion"
PCI audio accelerator and want to use its gameport.
diff --git a/drivers/input/gameport/Config.in b/drivers/input/gameport/Config.in
index df89f6a6f189..eeb983ec42a5 100644
--- a/drivers/input/gameport/Config.in
+++ b/drivers/input/gameport/Config.in
@@ -14,6 +14,6 @@ fi
dep_tristate ' Classic ISA and PnP gameport support' CONFIG_GAMEPORT_NS558 $CONFIG_GAMEPORT
dep_tristate ' PDPI Lightning 4 gamecard support' CONFIG_GAMEPORT_L4 $CONFIG_GAMEPORT
dep_tristate ' SB Live and Audigy gameport support' CONFIG_INPUT_EMU10K1 $CONFIG_GAMEPORT
-dep_tristate ' Aureal Vortex, Vortex 2 and Trident 4DWave NX/DX gameport support' CONFIG_GAMEPORT_PCIGAME $CONFIG_GAMEPORT
+dep_tristate ' Aureal Vortex, Vortex 2 gameport support' CONFIG_GAMEPORT_VORTEX $CONFIG_GAMEPORT
dep_tristate ' ForteMedia FM801 gameport support' CONFIG_GAMEPORT_FM801 $CONFIG_GAMEPORT
dep_tristate ' Crystal SoundFusion gameport support' CONFIG_GAMEPORT_CS461x $CONFIG_GAMEPORT
diff --git a/drivers/input/gameport/Makefile b/drivers/input/gameport/Makefile
index 60509253a031..ac1991701f6a 100644
--- a/drivers/input/gameport/Makefile
+++ b/drivers/input/gameport/Makefile
@@ -11,9 +11,10 @@ export-objs := gameport.o
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_PCIGAME) += pcigame.o
+obj-$(CONFIG_GAMEPORT_VORTEX) += vortex.o
# The global Rules.make.
diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c
new file mode 100644
index 000000000000..7cd454338f83
--- /dev/null
+++ b/drivers/input/gameport/fm801-gp.c
@@ -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) {
+ kfree(gp);
+ printk("unable to grab region 0x%x-0x%x\n", gp->gameport.io, gp->gameport.io + 0x0f);
+ return -1;
+ }
+
+ gp->gameport.phys = gp->phys;
+ gp->gameport.name = gp->name;
+ gp->gameport.idbus = BUS_PCI;
+ gp->gameport.idvendor = pci->vendor;
+ gp->gameport.idproduct = 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: %s at pci%s speed %d kHz\n",
+ pci->name, pci->slot_name, 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[] __devinitdata = {
+ { 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 GP",
+ id_table: fm801_gp_id_table,
+ probe: fm801_gp_probe,
+ remove: 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");
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index 01542530e6e4..4ade83a2db99 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -54,16 +54,36 @@ EXPORT_SYMBOL(gameport_cooked_read);
static struct gameport *gameport_list;
static struct gameport_dev *gameport_dev;
+
+#ifdef __i386__
+
+#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193180/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)
{
-#if defined(__i386__) || defined(__x86_64__)
-
-#define GET_TIME(x) do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0)
-#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193180L/HZ:0))
+#ifdef __i386__
unsigned int i, t, t1, t2, t3, tx;
unsigned long flags;
diff --git a/drivers/input/gameport/pcigame.c b/drivers/input/gameport/pcigame.c
deleted file mode 100644
index 194814ca64fc..000000000000
--- a/drivers/input/gameport/pcigame.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * $Id: pcigame.c,v 1.10 2001/04/26 10:24:46 vojtech Exp $
- *
- * Copyright (c) 2000-2001 Vojtech Pavlik
- *
- * Based on the work of:
- * Raymond Ingles
- *
- * Sponsored by SuSE
- */
-
-/*
- * 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@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, 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/gameport.h>
-
-#define PCI_VENDOR_ID_AUREAL 0x12eb
-
-#define PCIGAME_DATA_WAIT 20 /* 20 ms */
-
-#define PCIGAME_4DWAVE 0
-#define PCIGAME_VORTEX 1
-#define PCIGAME_VORTEX2 2
-
-struct pcigame_data {
- int gcr; /* Gameport control register */
- int legacy; /* Legacy port location */
- int axes; /* Axes start */
- int axsize; /* Axis field size */
- int axmax; /* Axis field max value */
- int adcmode; /* Value to enable ADC mode in GCR */
-};
-
-static struct pcigame_data pcigame_data[] __devinitdata =
-{{ 0x00030, 0x00031, 0x00034, 2, 0xffff, 0x80 },
- { 0x1100c, 0x11008, 0x11010, 4, 0x1fff, 0x40 },
- { 0x2880c, 0x28808, 0x28810, 4, 0x1fff, 0x40 },
- { 0 }};
-
-struct pcigame {
- struct gameport gameport;
- struct pci_dev *dev;
- unsigned char *base;
- struct pcigame_data *data;
-};
-
-static unsigned char pcigame_read(struct gameport *gameport)
-{
- struct pcigame *pcigame = gameport->private;
- return readb(pcigame->base + pcigame->data->legacy);
-}
-
-static void pcigame_trigger(struct gameport *gameport)
-{
- struct pcigame *pcigame = gameport->private;
- writeb(0xff, pcigame->base + pcigame->data->legacy);
-}
-
-static int pcigame_cooked_read(struct gameport *gameport, int *axes, int *buttons)
-{
- struct pcigame *pcigame = gameport->private;
- int i;
-
- *buttons = (~readb(pcigame->base + pcigame->data->legacy) >> 4) & 0xf;
-
- for (i = 0; i < 4; i++) {
- axes[i] = readw(pcigame->base + pcigame->data->axes + i * pcigame->data->axsize);
- if (axes[i] == pcigame->data->axmax) axes[i] = -1;
- }
-
- return 0;
-}
-
-static int pcigame_open(struct gameport *gameport, int mode)
-{
- struct pcigame *pcigame = gameport->private;
-
- switch (mode) {
- case GAMEPORT_MODE_COOKED:
- writeb(pcigame->data->adcmode, pcigame->base + pcigame->data->gcr);
- wait_ms(PCIGAME_DATA_WAIT);
- return 0;
- case GAMEPORT_MODE_RAW:
- writeb(0, pcigame->base + pcigame->data->gcr);
- return 0;
- default:
- return -1;
- }
-
- return 0;
-}
-
-static int __devinit pcigame_probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
- struct pcigame *pcigame;
- int i;
-
- if (!(pcigame = kmalloc(sizeof(struct pcigame), GFP_KERNEL)))
- return -1;
- memset(pcigame, 0, sizeof(struct pcigame));
-
-
- pcigame->data = pcigame_data + id->driver_data;
-
- pcigame->dev = dev;
- pci_set_drvdata(dev, pcigame);
-
- pcigame->gameport.private = pcigame;
- pcigame->gameport.fuzz = 64;
-
- pcigame->gameport.read = pcigame_read;
- pcigame->gameport.trigger = pcigame_trigger;
- pcigame->gameport.cooked_read = pcigame_cooked_read;
- pcigame->gameport.open = pcigame_open;
-
- for (i = 0; i < 6; i++)
- if (~pci_resource_flags(dev, i) & IORESOURCE_IO)
- break;
-
- pci_enable_device(dev);
-
- pcigame->base = ioremap(pci_resource_start(pcigame->dev, i),
- pci_resource_len(pcigame->dev, i));
-
- gameport_register_port(&pcigame->gameport);
-
- printk(KERN_INFO "gameport%d: %s at pci%02x:%02x.%x speed %d kHz\n",
- pcigame->gameport.number, dev->name, dev->bus->number,
- PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), pcigame->gameport.speed);
-
- return 0;
-}
-
-static void __devexit pcigame_remove(struct pci_dev *dev)
-{
- struct pcigame *pcigame = pci_get_drvdata(dev);
- gameport_unregister_port(&pcigame->gameport);
- iounmap(pcigame->base);
- kfree(pcigame);
-}
-
-static struct pci_device_id pcigame_id_table[] __devinitdata =
-{{ PCI_VENDOR_ID_TRIDENT, 0x2000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE },
- { PCI_VENDOR_ID_TRIDENT, 0x2001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE },
- { PCI_VENDOR_ID_AUREAL, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_VORTEX },
- { PCI_VENDOR_ID_AUREAL, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_VORTEX2 },
- { 0 }};
-
-static struct pci_driver pcigame_driver = {
- name: "pcigame",
- id_table: pcigame_id_table,
- probe: pcigame_probe,
- remove: __devexit_p(pcigame_remove),
-};
-
-int __init pcigame_init(void)
-{
- return pci_module_init(&pcigame_driver);
-}
-
-void __exit pcigame_exit(void)
-{
- pci_unregister_driver(&pcigame_driver);
-}
-
-module_init(pcigame_init);
-module_exit(pcigame_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/input/gameport/vortex.c b/drivers/input/gameport/vortex.c
new file mode 100644
index 000000000000..c2c12e7d4a5b
--- /dev/null
+++ b/drivers/input/gameport/vortex.c
@@ -0,0 +1,185 @@
+/*
+ * $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/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 *base;
+ unsigned char *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);
+ wait_ms(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", dev->slot_name);
+
+ 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 = dev->name;
+ vortex->gameport.phys = vortex->phys;
+ vortex->gameport.idbus = BUS_PCI;
+ vortex->gameport.idvendor = dev->vendor;
+ vortex->gameport.idproduct = 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: %s at pci%s speed %d kHz\n",
+ dev->name, dev->slot_name, 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[] __devinitdata =
+{{ 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",
+ id_table: vortex_id_table,
+ probe: vortex_probe,
+ remove: 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);
diff --git a/drivers/input/input.c b/drivers/input/input.c
index e80f4a4c8732..93241c7d577e 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -61,8 +61,6 @@ static struct input_dev *input_dev;
static struct input_handler *input_handler;
static struct input_handler *input_table[8];
static devfs_handle_t input_devfs_handle;
-static int input_number;
-static long input_devices[NBITS(INPUT_DEVICES)];
#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *proc_bus_input_dir;
@@ -454,17 +452,8 @@ void input_register_device(struct input_dev *dev)
* Add the device.
*/
- if (input_number >= INPUT_DEVICES) {
- printk(KERN_WARNING "input: ran out of input device numbers!\n");
- dev->number = input_number;
- } else {
- dev->number = find_first_zero_bit(input_devices, INPUT_DEVICES);
- set_bit(dev->number, input_devices);
- }
-
dev->next = input_dev;
input_dev = dev;
- input_number++;
/*
* Notify handlers.
@@ -493,7 +482,6 @@ void input_register_device(struct input_dev *dev)
input_devices_state++;
wake_up(&input_devices_poll_wait);
#endif
-
}
void input_unregister_device(struct input_dev *dev)
@@ -509,7 +497,6 @@ void input_unregister_device(struct input_dev *dev)
if (dev->pm_dev)
pm_unregister(dev->pm_dev);
-
/*
* Kill any pending repeat timers.
*/
@@ -540,7 +527,6 @@ void input_unregister_device(struct input_dev *dev)
*/
input_find_and_remove(struct input_dev, input_dev, dev, next);
- input_number--;
/*
* Notify /proc.
*/
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index e5b845e29468..416aace2a2a1 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -1,5 +1,5 @@
/*
- * $Id: joydev.c,v 1.38 2001/12/27 10:37:41 vojtech Exp $
+ * $Id: joydev.c,v 1.43 2002/04/09 23:59:01 jsimmons Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
* Copyright (c) 1999 Colin Van Dyke
@@ -49,7 +49,7 @@ MODULE_SUPPORTED_DEVICE("input/js");
MODULE_LICENSE("GPL");
#define JOYDEV_MINOR_BASE 0
-#define JOYDEV_MINORS 32
+#define JOYDEV_MINORS 16
#define JOYDEV_BUFFER_SIZE 64
#define MSECS(t) (1000 * ((t) / HZ) + 1000 * ((t) % HZ) / HZ)
@@ -254,6 +254,10 @@ static ssize_t joydev_read(struct file *file, char *buf, size_t count, loff_t *p
while (list->head == list->tail) {
+ if (!joydev->exist) {
+ retval = -ENODEV;
+ break;
+ }
if (file->f_flags & O_NONBLOCK) {
retval = -EAGAIN;
break;
@@ -325,6 +329,8 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
struct input_dev *dev = joydev->handle.dev;
int i;
+ if (!joydev->exist) return -ENODEV;
+
switch (cmd) {
case JS_SET_CAL:
diff --git a/drivers/input/joystick/Config.help b/drivers/input/joystick/Config.help
index 1b4187bbb8a3..155f0b83064a 100644
--- a/drivers/input/joystick/Config.help
+++ b/drivers/input/joystick/Config.help
@@ -1,4 +1,4 @@
-CONFIG_JOYSTICK
+CONFIG_INPUT_JOYSTICK
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
@@ -67,6 +67,15 @@ CONFIG_JOYSTICK_GRIP
The module will be called grip.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
+CONFIG_JOYSTICK_GUILLEMOT
+ Say Y here if you have a Guillemot joystick using a digital
+ protocol over the PC gameport.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called guillemot.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
CONFIG_JOYSTICK_INTERACT
Say Y here if you have an InterAct gameport or joystick
communicating digitally over the gameport.
@@ -158,6 +167,15 @@ CONFIG_JOYSTICK_STINGER
The module will be called stinger.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
+CONFIG_JOYSTICK_TWIDDLER
+ Say Y here if you have a Handykey Twiddler connected to your
+ computer's serial port and want to use it as a joystick.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called twidjoy.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
CONFIG_JOYSTICK_DB9
Say Y here if you have a Sega Master System gamepad, Sega Genesis
gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga,
@@ -203,3 +221,12 @@ CONFIG_JOYSTICK_AMIJOY
The module will be called joy-amiga.o. If you want to compile it as
a module, say M here and read <file:Documentation/modules.txt>.
+CONFIG_INPUT_JOYDUMP
+ 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.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called joydump.o. If you want to compile it as
+ a module, say M here and read <file:Documentation/modules.txt>.
diff --git a/drivers/input/joystick/Config.in b/drivers/input/joystick/Config.in
index afd07b89dff3..bb69101b9b9e 100644
--- a/drivers/input/joystick/Config.in
+++ b/drivers/input/joystick/Config.in
@@ -10,6 +10,7 @@ dep_tristate ' Logitech ADI digital joysticks and gamepads' CONFIG_JOYSTICK_ADI
dep_tristate ' Creative Labs Blaster Cobra gamepad' CONFIG_JOYSTICK_COBRA $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
dep_tristate ' Genius Flight2000 Digital joysticks and gamepads' CONFIG_JOYSTICK_GF2K $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
dep_tristate ' Gravis GrIP joysticks and gamepads' CONFIG_JOYSTICK_GRIP $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
+dep_tristate ' Guillemot joysticks and gamepads' CONFIG_JOYSTICK_GUILLEMOT $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
dep_tristate ' InterAct digital joysticks and gamepads' CONFIG_JOYSTICK_INTERACT $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
dep_tristate ' Microsoft SideWinder digital joysticks and gamepads' CONFIG_JOYSTICK_SIDEWINDER $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_JOYSTICK_TMDC $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
@@ -21,6 +22,7 @@ dep_tristate ' LogiCad3d Magellan/SpaceMouse 6dof controllers' CONFIG_JOYSTICK_
dep_tristate ' SpaceTec SpaceOrb/Avenger 6dof controllers' CONFIG_JOYSTICK_SPACEORB $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
dep_tristate ' SpaceTec SpaceBall 6dof controllers' CONFIG_JOYSTICK_SPACEBALL $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
dep_tristate ' Gravis Stinger gamepad' CONFIG_JOYSTICK_STINGER $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
+dep_tristate ' Twiddler as a joystick' CONFIG_JOYSTICK_TWIDDLER $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
dep_tristate ' Multisystem, Sega Genesis, Saturn joysticks and gamepads' CONFIG_JOYSTICK_DB9 $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_PARPORT
dep_tristate ' Multisystem, NES, SNES, N64, PSX joysticks and gamepads' CONFIG_JOYSTICK_GAMECON $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_PARPORT
@@ -29,3 +31,5 @@ dep_tristate ' Multisystem joysticks via TurboGraFX device' CONFIG_JOYSTICK_TUR
if [ "$CONFIG_AMIGA" = "y" ]; then
dep_tristate ' Amiga joysticks' CONFIG_JOYSTICK_AMIJOY $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK
fi
+
+dep_tristate ' Gameport data dumper' CONFIG_INPUT_JOYDUMP $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK
diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile
index c70244633703..16ab6110e13c 100644
--- a/drivers/input/joystick/Makefile
+++ b/drivers/input/joystick/Makefile
@@ -31,8 +31,9 @@ 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_IFORCE) += iforce.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
@@ -40,8 +41,11 @@ 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/
+
# The global Rules.make.
include $(TOPDIR)/Rules.make
diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
index 264fe6fc4924..66ed7834a213 100644
--- a/drivers/input/joystick/adi.c
+++ b/drivers/input/joystick/adi.c
@@ -426,10 +426,10 @@ static void adi_init_input(struct adi *adi, struct adi_port *port, int half)
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);
+ set_bit(adi->abs[i], adi->dev.absbit);
for (i = 0; i < adi->buttons; i++)
- set_bit(adi->key[i], &adi->dev.keybit);
+ set_bit(adi->key[i], adi->dev.keybit);
}
static void adi_init_center(struct adi *adi)
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index 0ce114353b8e..24d75e44d904 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -1,5 +1,5 @@
/*
- * $Id: db9.c,v 1.12 2002/01/22 20:27:05 vojtech Exp $
+ * $Id: db9.c,v 1.13 2002/04/07 20:13:37 vojtech Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*
@@ -199,7 +199,7 @@ static void db9_timer(unsigned long private)
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_START, ~data & DB9_FIRE2);
parport_write_control(port, DB9_NOSELECT); /* 2 */
udelay(DB9_GENESIS6_DELAY);
@@ -209,10 +209,10 @@ static void db9_timer(unsigned long private)
udelay(DB9_GENESIS6_DELAY);
data=parport_read_data(port);
- input_report_key(dev, BTN_Y, ~data & DB9_LEFT);
- input_report_key(dev, BTN_Z, ~data & DB9_DOWN);
- input_report_key(dev, BTN_MODE, ~data & DB9_UP);
- input_report_key(dev, BTN_START, ~data & DB9_RIGHT);
+ 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);
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index 77a1036e32d4..23ebebe3adb4 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -1,5 +1,5 @@
/*
- * $Id: gamecon.c,v 1.21 2002/01/22 20:27:27 vojtech Exp $
+ * $Id: gamecon.c,v 1.22 2002/07/01 15:42:25 vojtech Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*
@@ -398,8 +398,8 @@ static void gc_timer(unsigned long private)
case GC_PSX_RUMBLE:
- input_report_key(dev + i, BTN_THUMB, ~data[0] & 0x04);
- input_report_key(dev + i, BTN_THUMB2, ~data[0] & 0x02);
+ input_report_key(dev + i, BTN_THUMBL, ~data[0] & 0x04);
+ input_report_key(dev + i, BTN_THUMBR, ~data[0] & 0x02);
case GC_PSX_NEGCON:
case GC_PSX_ANALOG:
diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c
new file mode 100644
index 000000000000..53c46728a2bf
--- /dev/null
+++ b/drivers/input/joystick/guillemot.c
@@ -0,0 +1,285 @@
+/*
+ * $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);
+
+ __save_flags(flags);
+ __cli();
+ 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;
+ }
+ }
+
+ __restore_flags(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);
+ }
+
+ 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.idbus = BUS_GAMEPORT;
+ guillemot->dev.idvendor = GAMEPORT_ID_VENDOR_GUILLEMOT;
+ guillemot->dev.idproduct = guillemot_type[i].id;
+ guillemot->dev.idversion = (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);
diff --git a/drivers/input/joystick/iforce.c b/drivers/input/joystick/iforce.c
deleted file mode 100644
index 172c5d99a954..000000000000
--- a/drivers/input/joystick/iforce.c
+++ /dev/null
@@ -1,1224 +0,0 @@
-/*
- * $Id: iforce.c,v 1.56 2001/05/27 14:41:26 jdeneux Exp $
- *
- * Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@suse.cz>
- * Copyright (c) 2001 Johann Deneux <deneux@ifrance.com>
- *
- * USB/RS232 I-Force joysticks and wheels.
- *
- * Sponsored by SuSE
- */
-
-/*
- * 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@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, 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>
-
-/* FF: 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>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>, Johann Deneux <deneux@ifrance.com>");
-MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver");
-MODULE_LICENSE("GPL");
-
-#define IFORCE_MAX_LENGTH 16
-
-#if defined(CONFIG_JOYSTICK_IFORCE_232) || defined(CONFIG_JOYSTICK_IFORCE_232_MODULE)
-#define IFORCE_232 1
-#endif
-#if defined(CONFIG_JOYSTICK_IFORCE_USB) || defined(CONFIG_JOYSTICK_IFORCE_USB_MODULE)
-#define IFORCE_USB 2
-#endif
-
-#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
-#define FF_MODCORE_MAX 3
-
-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)];
-};
-
-#define FF_CMD_EFFECT 0x010e
-#define FF_CMD_SHAPE 0x0208
-#define FF_CMD_MAGNITUDE 0x0303
-#define FF_CMD_PERIOD 0x0407
-#define FF_CMD_INTERACT 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
-
-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, BTN_DEAD, -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 abs_joystick[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -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_FRICTION,
- FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, FF_SAW_DOWN, FF_GAIN, FF_AUTOCENTER, -1 };
-
-static struct iforce_device {
- u16 idvendor;
- u16 idproduct;
- char *name;
- signed short *btn;
- signed short *abs;
- signed short *ff;
-} iforce_device[] = {
- { 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_joystick, abs_joystick, ff_iforce },
- { 0x05ef, 0x8884, "AVB Mag Turbo Force", btn_wheel, abs_wheel, ff_iforce },
- { 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce },
- { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce }
-};
-
-struct iforce {
- struct input_dev dev; /* Input device interface */
- struct iforce_device *type;
- char name[64];
- int open;
- int bus;
-
- unsigned char data[IFORCE_MAX_LENGTH];
- unsigned char edata[IFORCE_MAX_LENGTH];
- u16 ecmd;
- u16 expect_packet;
-
-#ifdef IFORCE_232
- struct serio *serio; /* RS232 transfer */
- int idx, pkt, len, id;
- unsigned char csum;
-#endif
-#ifdef IFORCE_USB
- struct usb_device *usbdev; /* USB transfer */
- struct urb *irq, *out, *ctrl;
- struct usb_ctrlrequest dr;
-#endif
- /* Force Feedback */
- wait_queue_head_t wait;
- struct resource device_memory;
- struct iforce_core_effect core_effects[FF_EFFECTS_MAX];
-};
-
-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}};
-
-/* Get hi and low bytes of a 16-bits int */
-#define HI(a) ((unsigned char)((a) >> 8))
-#define LO(a) ((unsigned char)((a) & 0xff))
-
-/* Encode a time value */
-#define TIME_SCALE(a) ((a) == 0xffff ? 0xffff : (a) * 1000 / 256)
-
-static void 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
- */
-static void send_packet(struct iforce *iforce, u16 cmd, unsigned char* data)
-{
- switch (iforce->bus) {
-
-#ifdef IFORCE_232
- case IFORCE_232: {
-
- int i;
- unsigned char csum = 0x2b ^ HI(cmd) ^ LO(cmd);
-
- serio_write(iforce->serio, 0x2b);
- serio_write(iforce->serio, HI(cmd));
- serio_write(iforce->serio, LO(cmd));
-
- for (i = 0; i < LO(cmd); i++) {
- serio_write(iforce->serio, data[i]);
- csum = csum ^ data[i];
- }
-
- serio_write(iforce->serio, csum);
- return;
- }
-#endif
-#ifdef IFORCE_USB
- case IFORCE_USB: {
-
- DECLARE_WAITQUEUE(wait, current);
- int timeout = HZ; /* 1 second */
-
- memcpy(iforce->out->transfer_buffer + 1, data, LO(cmd));
- ((char*)iforce->out->transfer_buffer)[0] = HI(cmd);
- iforce->out->transfer_buffer_length = LO(cmd) + 2;
- iforce->out->dev = iforce->usbdev;
-
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&iforce->wait, &wait);
-
- if (usb_submit_urb(iforce->out, GFP_ATOMIC)) {
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&iforce->wait, &wait);
- return;
- }
-
- while (timeout && iforce->out->status == -EINPROGRESS)
- timeout = schedule_timeout(timeout);
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&iforce->wait, &wait);
-
- if (!timeout)
- usb_unlink_urb(iforce->out);
-
- return;
- }
-#endif
- }
-}
-
-static void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data)
-{
- struct input_dev *dev = &iforce->dev;
- int i;
-
-#ifdef IFORCE_232
- if (HI(iforce->expect_packet) == HI(cmd)) {
- iforce->expect_packet = 0;
- iforce->ecmd = cmd;
- memcpy(iforce->edata, data, IFORCE_MAX_LENGTH);
- if (waitqueue_active(&iforce->wait))
- wake_up(&iforce->wait);
- }
-#endif
-
- if (!iforce->type)
- return;
-
- switch (HI(cmd)) {
-
- case 0x01: /* joystick position data */
- case 0x03: /* wheel position data */
-
- 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]);
- } 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)));
-
- break;
-
- case 0x02: /* status report */
-
- input_report_key(dev, BTN_DEAD, data[0] & 0x02);
- break;
- }
-}
-
-static int get_id_packet(struct iforce *iforce, char *packet)
-{
- DECLARE_WAITQUEUE(wait, current);
- int timeout = HZ; /* 1 second */
-
- switch (iforce->bus) {
-
-#ifdef IFORCE_USB
- case IFORCE_USB:
-
- iforce->dr.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;
- }
-
- break;
-#endif
-#ifdef IFORCE_232
- case IFORCE_232:
-
- iforce->expect_packet = FF_CMD_QUERY;
- 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;
- }
-
- break;
-#endif
- }
-
- return -(iforce->edata[0] != packet[0]);
-}
-
-static int iforce_open(struct input_dev *dev)
-{
- struct iforce *iforce = dev->private;
-
- switch (iforce->bus) {
-#ifdef IFORCE_USB
- case IFORCE_USB:
- if (iforce->open++)
- break;
- iforce->irq->dev = iforce->usbdev;
- if (usb_submit_urb(iforce->irq, GFP_KERNEL))
- return -EIO;
- break;
-#endif
- }
- return 0;
-}
-
-static void iforce_close(struct input_dev *dev)
-{
- struct iforce *iforce = dev->private;
-
- switch (iforce->bus) {
-#ifdef IFORCE_USB
- case IFORCE_USB:
- if (!--iforce->open)
- usb_unlink_urb(iforce->irq);
- break;
-#endif
- }
-}
-
-/*
- * Start or stop playing an effect
- */
-
-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];
-
- printk(KERN_DEBUG "iforce.c: input_event(type = %d, code = %d, value = %d)\n", type, code, value);
-
- if (type != EV_FF)
- return -1;
-
- switch (code) {
-
- case FF_GAIN:
-
- data[0] = value >> 9;
- send_packet(iforce, FF_CMD_GAIN, data);
-
- return 0;
-
- case FF_AUTOCENTER:
-
- data[0] = 0x03;
- data[1] = value >> 9;
- send_packet(iforce, FF_CMD_AUTOCENTER, data);
-
- data[0] = 0x04;
- data[1] = 0x01;
- send_packet(iforce, FF_CMD_AUTOCENTER, data);
-
- return 0;
-
- default: /* Play an effect */
-
- if (code >= iforce->dev.ff_effects_max)
- return -1;
-
- data[0] = LO(code);
- data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0;
- data[2] = LO(value);
- send_packet(iforce, FF_CMD_PLAY, data);
-
- return 0;
- }
-
- return -1;
-}
-
-/*
- * 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, __s16 level)
-{
- unsigned char data[3];
-
- if (allocate_resource(&(iforce->device_memory), mod_chunk, 2,
- iforce->device_memory.start, iforce->device_memory.end, 2L,
- NULL, NULL)) {
- return -ENOMEM;
- }
-
- data[0] = LO(mod_chunk->start);
- data[1] = HI(mod_chunk->start);
- data[2] = HI(level);
-
- send_packet(iforce, 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,
- __s16 magnitude, __s16 offset, u16 period, u16 phase)
-{
- unsigned char data[7];
-
- period = TIME_SCALE(period);
-
- if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c,
- iforce->device_memory.start, iforce->device_memory.end, 2L,
- NULL, NULL)) {
- return -ENOMEM;
- }
-
- data[0] = LO(mod_chunk->start);
- data[1] = HI(mod_chunk->start);
-
- data[2] = HI(magnitude);
- data[3] = HI(offset);
- data[4] = HI(phase);
-
- data[5] = LO(period);
- data[6] = HI(period);
-
- send_packet(iforce, FF_CMD_PERIOD, data);
-
- return 0;
-}
-
-/*
- * Uploads the part of an effect setting the shape of the force
- */
-
-static int make_shape_modifier(struct iforce* iforce, struct resource* mod_chunk,
- 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 (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e,
- iforce->device_memory.start, iforce->device_memory.end, 2L,
- NULL, NULL)) {
- return -ENOMEM;
- }
-
- 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);
-
- send_packet(iforce, FF_CMD_SHAPE, data);
-
- return 0;
-}
-
-/*
- * Component of spring, friction, inertia... effects
- */
-
-static int make_interactive_modifier(struct iforce* iforce,
- struct resource* mod_chunk,
- __s16 rsat, __s16 lsat, __s16 rk, __s16 lk, u16 db, __s16 center)
-{
- unsigned char data[10];
-
- if (allocate_resource(&(iforce->device_memory), mod_chunk, 8,
- iforce->device_memory.start, iforce->device_memory.end, 2L,
- NULL, NULL)) {
- return -ENOMEM;
- }
-
- data[0] = LO(mod_chunk->start);
- data[1] = HI(mod_chunk->start);
-
- data[2] = HI(rk);
- data[3] = HI(lk);
-
- data[4] = LO(center);
- data[5] = HI(center);
-
- data[6] = LO(db);
- data[7] = HI(db);
-
- data[8] = HI(rsat);
- data[9] = HI(lsat);
-
- send_packet(iforce, FF_CMD_INTERACT, 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;
-}
-
-/*
- * 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);
-
- send_packet(iforce, FF_CMD_EFFECT, data);
-
- return 0;
-}
-
-/*
- * Upload a periodic effect to the device
- */
-
-static int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect)
-{
- 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 err = 0;
-
- err = make_period_modifier(iforce, mod1_chunk,
- effect->u.periodic.magnitude, effect->u.periodic.offset,
- effect->u.periodic.period, effect->u.periodic.phase);
- if (err) return err;
- set_bit(FF_MOD1_IS_USED, core_effect->flags);
-
- err = make_shape_modifier(iforce, mod2_chunk,
- effect->u.periodic.shape.attack_length,
- effect->u.periodic.shape.attack_level,
- effect->u.periodic.shape.fade_length,
- effect->u.periodic.shape.fade_level);
- if (err) return 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;
- }
-
- 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);
-
- return err;
-}
-
-/*
- * Upload a constant force effect
- */
-static int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect)
-{
- 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 err = 0;
-
- printk(KERN_DEBUG "iforce.c: make constant effect\n");
-
- err = make_magnitude_modifier(iforce, mod1_chunk, effect->u.constant.level);
- if (err) return err;
- set_bit(FF_MOD1_IS_USED, core_effect->flags);
-
- err = make_shape_modifier(iforce, mod2_chunk,
- effect->u.constant.shape.attack_length,
- effect->u.constant.shape.attack_level,
- effect->u.constant.shape.fade_length,
- effect->u.constant.shape.fade_level);
- if (err) return err;
- set_bit(FF_MOD2_IS_USED, core_effect->flags);
-
- 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);
-
- return err;
-}
-
-/*
- * Upload an interactive effect. Those are for example friction, inertia, springs...
- */
-static int iforce_upload_interactive(struct iforce* iforce, struct ff_effect* effect)
-{
- int core_id = effect->id;
- struct iforce_core_effect* core_effect = iforce->core_effects + core_id;
- struct resource* mod_chunk = &(core_effect->mod1_chunk);
- u8 type, axes;
- u16 mod1, mod2, direction;
- int err = 0;
-
- printk(KERN_DEBUG "iforce.c: make interactive effect\n");
-
- switch (effect->type) {
- case FF_SPRING: type = 0x40; break;
- case FF_FRICTION: type = 0x41; break;
- default: return -1;
- }
-
- err = make_interactive_modifier(iforce, mod_chunk,
- effect->u.interactive.right_saturation,
- effect->u.interactive.left_saturation,
- effect->u.interactive.right_coeff,
- effect->u.interactive.left_coeff,
- effect->u.interactive.deadband,
- effect->u.interactive.center);
- if (err) return err;
- set_bit(FF_MOD1_IS_USED, core_effect->flags);
-
- switch ((test_bit(ABS_X, &effect->u.interactive.axis) ||
- test_bit(ABS_WHEEL, &effect->u.interactive.axis)) |
- (!!test_bit(ABS_Y, &effect->u.interactive.axis) << 1)) {
-
- case 0: /* Only one axis, choose orientation */
- mod1 = mod_chunk->start;
- mod2 = 0xffff;
- direction = effect->direction;
- axes = 0x20;
- break;
-
- case 1: /* Only X axis */
- mod1 = mod_chunk->start;
- mod2 = 0xffff;
- direction = 0x5a00;
- axes = 0x40;
- break;
-
- case 2: /* Only Y axis */
- mod1 = 0xffff;
- mod2 = mod_chunk->start;
- direction = 0xb400;
- axes = 0x80;
- break;
-
- case 3: /* Both X and Y axes */
- /* TODO: same setting for both axes is not mandatory */
- mod1 = mod_chunk->start;
- mod2 = mod_chunk->start;
- direction = 0x6000;
- axes = 0xc0;
- break;
-
- default:
- return -1;
- }
-
- err = make_core(iforce, effect->id,
- mod1, mod2,
- type, axes,
- effect->replay.length, effect->replay.delay,
- effect->trigger.button, effect->trigger.interval,
- direction);
-
- return err;
-}
-
-/*
- * 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;
-
- printk(KERN_DEBUG "iforce.c: upload effect\n");
-
-/*
- * Get a free id
- */
-
- for (id=0; id < FF_EFFECTS_MAX; ++id)
- if (!test_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;
- set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags);
-
-/*
- * Upload the effect
- */
-
- switch (effect->type) {
-
- case FF_PERIODIC:
- return iforce_upload_periodic(iforce, effect);
-
- case FF_CONSTANT:
- return iforce_upload_constant(iforce, effect);
-
- case FF_SPRING:
- case FF_FRICTION:
- return iforce_upload_interactive(iforce, effect);
-
- default:
- return -1;
- }
-}
-
-/*
- * 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;
-
- printk(KERN_DEBUG "iforce.c: erase effect %d\n", effect_id);
-
- 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_init_device(struct iforce *iforce)
-{
- unsigned char c[] = "CEOV";
- int i;
-
- init_waitqueue_head(&iforce->wait);
- iforce->dev.ff_effects_max = 10;
-
-/*
- * Input device fields.
- */
-
- iforce->dev.idbus = BUS_USB;
- iforce->dev.private = iforce;
- iforce->dev.name = iforce->name;
- iforce->dev.open = iforce_open;
- iforce->dev.close = iforce_close;
- 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 (!get_id_packet(iforce, "O"))
- break;
-
- if (i == 20) { /* 5 seconds */
- printk(KERN_ERR "iforce.c: Timeout waiting for response from device.\n");
- iforce_close(&iforce->dev);
- return -1;
- }
-
-/*
- * Get device info.
- */
-
- if (!get_id_packet(iforce, "M"))
- iforce->dev.idvendor = (iforce->edata[2] << 8) | iforce->edata[1];
- if (!get_id_packet(iforce, "P"))
- iforce->dev.idproduct = (iforce->edata[2] << 8) | iforce->edata[1];
- if (!get_id_packet(iforce, "B"))
- iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1];
- if (!get_id_packet(iforce, "N"))
- iforce->dev.ff_effects_max = iforce->edata[1];
-
-/*
- * Display additional info.
- */
-
- for (i = 0; c[i]; i++)
- if (!get_id_packet(iforce, c + i))
- dump_packet("info", iforce->ecmd, iforce->edata);
-
-/*
- * Disable spring, enable force feedback.
- * FIXME: We should use iforce_set_autocenter() et al here.
- */
-
- send_packet(iforce, FF_CMD_AUTOCENTER, "\004\000");
- send_packet(iforce, FF_CMD_ENABLE, "\004");
-
-/*
- * Find appropriate device entry
- */
-
- for (i = 0; iforce_device[i].idvendor; i++)
- if (iforce_device[i].idvendor == iforce->dev.idvendor &&
- iforce_device[i].idproduct == iforce->dev.idproduct)
- break;
-
- iforce->type = iforce_device + i;
-
- sprintf(iforce->name, iforce->type->name,
- iforce->dev.idproduct, iforce->dev.idvendor);
-
-/*
- * Set input device bitfields and ranges.
- */
-
- iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF);
-
- for (i = 0; iforce->type->btn[i] >= 0; i++) {
- signed short t = iforce->type->btn[i];
- set_bit(t, iforce->dev.keybit);
- if (t != BTN_DEAD)
- set_bit(FF_BTN(t), iforce->dev.ffbit);
- }
-
- 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(FF_ABS(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_HAT0X:
- case ABS_HAT0Y:
- 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);
-
- return 0;
-}
-
-#ifdef IFORCE_USB
-
-static void iforce_usb_irq(struct urb *urb)
-{
- struct iforce *iforce = urb->context;
- if (urb->status) return;
- iforce_process_packet(iforce,
- (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1);
-}
-
-static void iforce_usb_out(struct urb *urb)
-{
- struct iforce *iforce = urb->context;
- if (urb->status) return;
- if (waitqueue_active(&iforce->wait))
- wake_up(&iforce->wait);
-}
-
-static void iforce_usb_ctrl(struct urb *urb)
-{
- struct iforce *iforce = urb->context;
- if (urb->status) return;
- iforce->ecmd = 0xff00 | urb->actual_length;
- if (waitqueue_active(&iforce->wait))
- wake_up(&iforce->wait);
-}
-
-static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum,
- const struct usb_device_id *id)
-{
- struct usb_endpoint_descriptor *epirq, *epout;
- struct iforce *iforce;
-
- epirq = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
- epout = dev->config[0].interface[ifnum].altsetting[0].endpoint + 1;
-
- if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) return NULL;
- memset(iforce, 0, sizeof(struct iforce));
-
- iforce->irq = usb_alloc_urb(0, GFP_KERNEL);
- if (!iforce->irq) {
- kfree(iforce);
- return NULL;
- }
- iforce->out = usb_alloc_urb(0, GFP_KERNEL);
- if (!iforce->out) {
- usb_free_urb(iforce->irq);
- kfree(iforce);
- return NULL;
- }
- iforce->ctrl = usb_alloc_urb(0, GFP_KERNEL);
- if (!iforce->ctrl) {
- usb_free_urb(iforce->out);
- usb_free_urb(iforce->irq);
- kfree(iforce);
- return NULL;
- }
-
- iforce->bus = IFORCE_USB;
- iforce->usbdev = dev;
-
- iforce->dr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE;
- iforce->dr.wIndex = 0;
- iforce->dr.wLength = 16;
-
- FILL_INT_URB(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
- iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval);
-
- FILL_BULK_URB(iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress),
- iforce + 1, 32, iforce_usb_out, iforce);
-
- FILL_CONTROL_URB(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0),
- (void*) &iforce->dr, iforce->edata, 16, iforce_usb_ctrl, iforce);
-
- if (iforce_init_device(iforce)) {
- usb_free_urb(iforce->ctrl);
- usb_free_urb(iforce->out);
- usb_free_urb(iforce->irq);
- kfree(iforce);
- return NULL;
- }
-
- printk(KERN_INFO "input%d: %s [%d effects, %ld bytes memory] on usb%d:%d.%d\n",
- iforce->dev.number, iforce->dev.name, iforce->dev.ff_effects_max,
- iforce->device_memory.end, dev->bus->busnum, dev->devnum, ifnum);
-
- return iforce;
-}
-
-static void iforce_usb_disconnect(struct usb_device *dev, void *ptr)
-{
- struct iforce *iforce = ptr;
- usb_unlink_urb(iforce->irq);
- input_unregister_device(&iforce->dev);
- usb_free_urb(iforce->ctrl);
- usb_free_urb(iforce->out);
- usb_free_urb(iforce->irq);
- kfree(iforce);
-}
-
-static struct usb_device_id iforce_usb_ids [] = {
- { 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(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */
- { } /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, iforce_usb_ids);
-
-static struct usb_driver iforce_usb_driver = {
- name: "iforce",
- probe: iforce_usb_probe,
- disconnect: iforce_usb_disconnect,
- id_table: iforce_usb_ids,
-};
-
-#endif
-
-#ifdef IFORCE_232
-
-static void iforce_serio_irq(struct serio *serio, unsigned char data, unsigned int flags)
-{
- struct iforce* iforce = serio->private;
-
- if (!iforce->pkt) {
- if (data != 0x2b) {
- return;
- }
- iforce->pkt = 1;
- return;
- }
-
- if (!iforce->id) {
- if (data > 3 && data != 0xff) {
- iforce->pkt = 0;
- return;
- }
- iforce->id = data;
- return;
- }
-
- if (!iforce->len) {
- if (data > IFORCE_MAX_LENGTH) {
- iforce->pkt = 0;
- iforce->id = 0;
- return;
- }
- iforce->len = data;
- return;
- }
-
- if (iforce->idx < iforce->len) {
- iforce->csum += iforce->data[iforce->idx++] = data;
- return;
- }
-
- if (iforce->idx == iforce->len) {
- iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data);
- iforce->pkt = 0;
- iforce->id = 0;
- iforce->len = 0;
- iforce->idx = 0;
- iforce->csum = 0;
- }
-}
-
-static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev)
-{
- 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, dev)) {
- kfree(iforce);
- return;
- }
-
- if (iforce_init_device(iforce)) {
- serio_close(serio);
- kfree(iforce);
- return;
- }
-
- printk(KERN_INFO "input%d: %s [%d effects, %ld bytes memory] on serio%d\n",
- iforce->dev.number, iforce->dev.name, iforce->dev.ff_effects_max,
- iforce->device_memory.end, serio->number);
-}
-
-static void iforce_serio_disconnect(struct serio *serio)
-{
- struct iforce* iforce = serio->private;
-
- input_unregister_device(&iforce->dev);
- serio_close(serio);
- kfree(iforce);
-}
-
-static struct serio_dev iforce_serio_dev = {
- interrupt: iforce_serio_irq,
- connect: iforce_serio_connect,
- disconnect: iforce_serio_disconnect,
-};
-
-#endif
-
-static int __init iforce_init(void)
-{
-#ifdef IFORCE_USB
- usb_register(&iforce_usb_driver);
-#endif
-#ifdef IFORCE_232
- serio_register_device(&iforce_serio_dev);
-#endif
- return 0;
-}
-
-static void __exit iforce_exit(void)
-{
-#ifdef IFORCE_USB
- usb_deregister(&iforce_usb_driver);
-#endif
-#ifdef IFORCE_232
- serio_unregister_device(&iforce_serio_dev);
-#endif
-}
-
-module_init(iforce_init);
-module_exit(iforce_exit);
diff --git a/drivers/input/joystick/iforce/Makefile b/drivers/input/joystick/iforce/Makefile
new file mode 100644
index 000000000000..4eb258e273cd
--- /dev/null
+++ b/drivers/input/joystick/iforce/Makefile
@@ -0,0 +1,42 @@
+#
+# Makefile for the I-Force driver
+#
+
+# I-Force may need both USB and RS-232
+
+CONFIG_JOYSTICK_IFORCE := n
+
+ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y)
+ ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y)
+ CONFIG_JOYSTICK_IFORCE := y
+ endif
+endif
+
+ifeq ($(CONFIG_JOYSTICK_IFORCE_232),m)
+ CONFIG_JOYSTICK_IFORCE := m
+endif
+
+ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),m)
+ CONFIG_JOYSTICK_IFORCE := m
+endif
+
+obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
+
+# iforce.o is a multipart module.
+
+IFORCEOBJS = iforce-ff.o iforce-main.o iforce-packets.o
+
+ifneq ($(CONFIG_JOYSTICK_IFORCE_232),)
+ IFORCEOBJS += iforce-serio.o
+endif
+
+ifneq ($(CONFIG_JOYSTICK_IFORCE_USB),)
+ IFORCEOBJS += iforce-usb.o
+endif
+
+iforce.o: $(IFORCEOBJS)
+ $(LD) -i $(IFORCEOBJS) -o $@
diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c
new file mode 100644
index 000000000000..267f92f0aa2f
--- /dev/null
+++ b/drivers/input/joystick/iforce/iforce-ff.c
@@ -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;
+}
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
new file mode 100644
index 000000000000..45b7c001e066
--- /dev/null
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -0,0 +1,543 @@
+/*
+ * $Id: iforce-main.c,v 1.18 2002/06/09 11:03:03 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 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 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 IFORCE_USB
+ case IFORCE_USB:
+ iforce_usb_delete(iforce);
+ break;
+#endif
+#ifdef 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.idbus = 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.idvendor = (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.idproduct = (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.idvendor &&
+ iforce_device[i].idproduct == iforce->dev.idproduct)
+ 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 IFORCE_USB
+ usb_register(&iforce_usb_driver);
+#endif
+#ifdef IFORCE_232
+ serio_register_device(&iforce_serio_dev);
+#endif
+ return 0;
+}
+
+static void __exit iforce_exit(void)
+{
+#ifdef IFORCE_USB
+ usb_deregister(&iforce_usb_driver);
+#endif
+#ifdef IFORCE_232
+ serio_unregister_device(&iforce_serio_dev);
+#endif
+}
+
+module_init(iforce_init);
+module_exit(iforce_exit);
diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c
new file mode 100644
index 000000000000..922894bb13ea
--- /dev/null
+++ b/drivers/input/joystick/iforce/iforce-packets.c
@@ -0,0 +1,314 @@
+/*
+ * $Id: iforce-packets.c,v 1.15 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"
+
+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 IFORCE_232
+ case IFORCE_232:
+ if (empty)
+ iforce_serial_xmit(iforce);
+ break;
+#endif
+#ifdef 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 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 IFORCE_232
+ if (HI(iforce->expect_packet) == HI(cmd)) {
+ iforce->expect_packet = 0;
+ iforce->ecmd = cmd;
+ memcpy(iforce->edata, data, IFORCE_MAX_LENGTH);
+ if (waitqueue_active(&iforce->wait))
+ wake_up(&iforce->wait);
+ }
+#endif
+
+ if (!iforce->type) {
+ being_used--;
+ return;
+ }
+
+ switch (HI(cmd)) {
+
+ case 0x01: /* joystick position data */
+ case 0x03: /* wheel position data */
+
+ 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);
+ }
+ }
+
+ break;
+
+ case 0x02: /* status report */
+ input_report_key(dev, BTN_DEAD, data[0] & 0x02);
+
+ /* 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 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_KERNEL)) {
+ 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 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]);
+}
+
diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c
new file mode 100644
index 000000000000..31e21fb431f6
--- /dev/null
+++ b/drivers/input/joystick/iforce/iforce-serio.c
@@ -0,0 +1,166 @@
+/*
+ * $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 void iforce_serio_irq(struct serio *serio, unsigned char data, unsigned int flags)
+{
+ struct iforce* iforce = serio->private;
+
+ if (!iforce->pkt) {
+ if (data != 0x2b) {
+ return;
+ }
+ iforce->pkt = 1;
+ return;
+ }
+
+ if (!iforce->id) {
+ if (data > 3 && data != 0xff) {
+ iforce->pkt = 0;
+ return;
+ }
+ iforce->id = data;
+ return;
+ }
+
+ if (!iforce->len) {
+ if (data > IFORCE_MAX_LENGTH) {
+ iforce->pkt = 0;
+ iforce->id = 0;
+ return;
+ }
+ iforce->len = data;
+ return;
+ }
+
+ if (iforce->idx < iforce->len) {
+ iforce->csum += iforce->data[iforce->idx++] = data;
+ return;
+ }
+
+ if (iforce->idx == iforce->len) {
+ iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data);
+ iforce->pkt = 0;
+ iforce->id = 0;
+ iforce->len = 0;
+ iforce->idx = 0;
+ iforce->csum = 0;
+ }
+}
+
+static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev)
+{
+ 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, dev)) {
+ 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_dev iforce_serio_dev = {
+ write_wakeup: iforce_serio_write_wakeup,
+ interrupt: iforce_serio_irq,
+ connect: iforce_serio_connect,
+ disconnect: iforce_serio_disconnect,
+};
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
new file mode 100644
index 000000000000..760534a89f72
--- /dev/null
+++ b/drivers/input/joystick/iforce/iforce-usb.c
@@ -0,0 +1,214 @@
+ /*
+ * $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 iforce *iforce = urb->context;
+ if (urb->status) return;
+ iforce_process_packet(iforce,
+ (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1);
+}
+
+static void iforce_usb_out(struct urb *urb)
+{
+ 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);
+
+ if (waitqueue_active(&iforce->wait))
+ wake_up(&iforce->wait);
+}
+
+static void iforce_usb_ctrl(struct urb *urb)
+{
+ struct iforce *iforce = urb->context;
+ if (urb->status) return;
+ iforce->ecmd = 0xff00 | urb->actual_length;
+ if (waitqueue_active(&iforce->wait))
+ wake_up(&iforce->wait);
+}
+
+static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id)
+{
+ struct usb_endpoint_descriptor *epirq, *epout;
+ struct iforce *iforce;
+
+ epirq = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
+ epout = dev->config[0].interface[ifnum].altsetting[0].endpoint + 1;
+
+ 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;
+
+ return iforce;
+
+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 NULL;
+}
+
+/* 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_device *dev, void *ptr)
+{
+ struct iforce *iforce = ptr;
+ int open = iforce->dev.handle->open;
+
+ 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,
+};
diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h
new file mode 100644
index 000000000000..fec1b258225c
--- /dev/null
+++ b/drivers/input/joystick/iforce/iforce.h
@@ -0,0 +1,194 @@
+/*
+ * $Id: iforce.h,v 1.12 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 <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>
+
+/* FF: 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
+
+#if defined(CONFIG_JOYSTICK_IFORCE_232)
+#define IFORCE_232 1
+#endif
+#if defined(CONFIG_JOYSTICK_IFORCE_USB)
+#define IFORCE_USB 2
+#endif
+
+#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 IFORCE_232
+ struct serio *serio; /* RS232 transfer */
+ int idx, pkt, len, id;
+ unsigned char csum;
+#endif
+#ifdef 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);
+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_dev iforce_serio_dev;
+extern struct usb_driver iforce_usb_driver;
diff --git a/drivers/input/joystick/joydump.c b/drivers/input/joystick/joydump.c
new file mode 100644
index 000000000000..d64493c0cc04
--- /dev/null
+++ b/drivers/input/joystick/joydump.c
@@ -0,0 +1,152 @@
+/*
+ * $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;
+
+ save_flags(flags);
+ cli();
+
+ 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++;
+ }
+
+ restore_flags(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);
diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c
index 3e6139a62979..2930248b443a 100644
--- a/drivers/input/joystick/magellan.c
+++ b/drivers/input/joystick/magellan.c
@@ -156,7 +156,7 @@ static void magellan_connect(struct serio *serio, struct serio_dev *dev)
magellan->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
for (i = 0; i < 9; i++)
- set_bit(magellan_buttons[i], &magellan->dev.keybit);
+ set_bit(magellan_buttons[i], magellan->dev.keybit);
for (i = 0; i < 6; i++) {
t = magellan_axes[i];
diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c
new file mode 100644
index 000000000000..70da80e89404
--- /dev/null
+++ b/drivers/input/joystick/twidjoy.c
@@ -0,0 +1,264 @@
+/*
+ * $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>
+
+/*
+ * 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)
+{
+ 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);
+
+ 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);
+ }
+
+ 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 void twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+ 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; /* 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);
+ twidjoy->idx = 0;
+ }
+
+ return;
+}
+
+/*
+ * 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_dev *dev)
+{
+ 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);
+
+ twidjoy->dev.name = twidjoy_name;
+ twidjoy->dev.phys = twidjoy->phys;
+ twidjoy->dev.idbus = BUS_RS232;
+ twidjoy->dev.idvendor = SERIO_TWIDJOY;
+ twidjoy->dev.idproduct = 0x0001;
+ twidjoy->dev.idversion = 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, dev)) {
+ 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_dev twidjoy_dev = {
+ 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_device(&twidjoy_dev);
+ return 0;
+}
+
+void __exit twidjoy_exit(void)
+{
+ serio_unregister_device(&twidjoy_dev);
+}
+
+module_init(twidjoy_init);
+module_exit(twidjoy_exit);
diff --git a/drivers/input/keybdev.c b/drivers/input/keybdev.c
index 6731dd2542c2..8a5a93b57f7a 100644
--- a/drivers/input/keybdev.c
+++ b/drivers/input/keybdev.c
@@ -1,5 +1,5 @@
/*
- * $Id: keybdev.c,v 1.16 2002/01/09 04:21:41 lethal Exp $
+ * $Id: keybdev.c,v 1.19 2002/03/13 10:09:20 vojtech Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*
@@ -179,7 +179,7 @@ void panic_blink(void)
static unsigned long last_jiffie;
static char led;
/* Roughly 1/2s frequency. KDB uses about 1s. Make sure it is different. */
- if (jiffies - last_jiffie > HZ/2) {
+ if (time_after(jiffies, last_jiffie + HZ/2)) {
led ^= 0x01 | 0x04;
keybdev_ledfunc(led);
last_jiffie = jiffies;
diff --git a/drivers/input/keyboard/Config.help b/drivers/input/keyboard/Config.help
new file mode 100644
index 000000000000..3d7df5a61a23
--- /dev/null
+++ b/drivers/input/keyboard/Config.help
@@ -0,0 +1,66 @@
+CONFIG_INPUT_KEYBOARD
+ 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
+ Say Y here if you want to use the standard AT keyboard. Usually
+ you'll need this, unless you have a different type keyboard (USB,
+ ADB or other).
+
+ If unsure, say Y.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called atkbd.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_KEYBOARD_SUNKBD
+ 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.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called sunkbd.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_KEYBOARD_PS2SERKBD
+ Say Y here if you want to use a PS/2 to Serial converter with a
+ keyboard attached to it.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called ps2serkbd.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_KEYBOARD_XTKBD
+ 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.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called xtkbd.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_KEYBOARD_MAPLE
+ Say Y here if you have a DreamCast console running Linux and have
+ a keyboard attached to its Maple bus.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called maple_keyb.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_KEYBOARD_AMIGA
+ Say Y here if you are running Linux on any AMIGA and have a keyboard
+ attached.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called amikbd.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
diff --git a/drivers/input/keyboard/Config.in b/drivers/input/keyboard/Config.in
new file mode 100644
index 000000000000..f7f7128ee405
--- /dev/null
+++ b/drivers/input/keyboard/Config.in
@@ -0,0 +1,18 @@
+#
+# Input core configuration
+#
+
+bool 'Keyboards' CONFIG_INPUT_KEYBOARD
+
+dep_tristate ' AT keyboard support' CONFIG_KEYBOARD_ATKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
+dep_tristate ' Sun Type 4 and Type 5 keyboard support' CONFIG_KEYBOARD_SUNKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
+dep_tristate ' PS/2 to Serial converter support' CONFIG_KEYBOARD_PS2SERKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
+dep_tristate ' XT Keyboard support' CONFIG_KEYBOARD_XTKBD $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_SERIO
+
+if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then
+ dep_tristate ' Maple bus keyboard support' CONFIG_KEYBOARD_MAPLE $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD $CONFIG_MAPLE
+fi
+
+if [ "$CONFIG_AMIGA" = "y" ]; then
+ dep_tristate ' Amiga keyboard' CONFIG_KEYBOARD_AMIGA $CONFIG_INPUT $CONFIG_INPUT_KEYBOARD
+fi
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
new file mode 100644
index 000000000000..d51417534b60
--- /dev/null
+++ b/drivers/input/keyboard/Makefile
@@ -0,0 +1,16 @@
+#
+# 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_PS2SERKBD) += ps2serkbd.o
+obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
+obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
+obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c
new file mode 100644
index 000000000000..330b33615165
--- /dev/null
+++ b/drivers/input/keyboard/amikbd.c
@@ -0,0 +1,144 @@
+/*
+ * $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 <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] = {
+ 41, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 43, 0, 82,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 0, 79, 80, 81,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 0, 0, 75, 76, 77,
+ 0, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 0, 83, 71, 72, 73,
+ 57, 14, 15, 96, 28, 1,111, 0, 0, 0, 74, 0,103,108,106,105,
+ 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 98, 55, 78, 87,
+ 42, 54, 58, 29, 56,100
+}
+
+static char *amikbd_messages[] = {
+ KERN_ALERT "amikbd: Ctrl-Amiga-Amiga reset warning!!\n",
+ KERN_WARNING "amikbd: keyboard lost sync\n",
+ KERN_WARNING "amikbd: keyboard buffer overflow\n",
+ KERN_WARNING "amikbd: keyboard controller failure\n",
+ KERN_ERR "amikbd: keyboard selftest failure\n",
+ KERN_INFO "amikbd: initiate power-up key stream\n",
+ KERN_INFO "amikbd: terminate power-up key stream\n",
+ 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 void 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 = scancode >> 1;
+
+ if (scancode < 0x78) { /* scancodes < 0x78 are keys */
+
+ scancode = amikbd_keycode[scancode];
+
+ if (scancode == KEY_CAPS) { /* CapsLock is a toggle switch key on Amiga */
+ input_report_key(&amikbd_dev, scancode, 1);
+ input_report_key(&amikbd_dev, scancode, 0);
+ return;
+ }
+
+ input_report_key(&amikbd_dev, scancode, down);
+
+ return;
+ }
+
+ printk(amikbd_messages[scancode - 0x78]); /* scancodes >= 0x78 are error codes */
+}
+
+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;
+
+ amikbd_dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ amikbd_dev.keycode = 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", NULL);
+
+ amikbd_dev.name = amikbd_name;
+ amikbd_dev.phys = amikbd_phys;
+ amikbd_dev.idbus = BUS_AMIGA;
+ amikbd_dev.idvendor = 0x0001;
+ amikbd_dev.idproduct = 0x0001;
+ amikbd_dev.idversion = 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);
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
new file mode 100644
index 000000000000..e14f581a4d67
--- /dev/null
+++ b/drivers/input/keyboard/atkbd.c
@@ -0,0 +1,565 @@
+/*
+ * $Id: atkbd.c,v 1.33 2002/02/12 09:34:34 vojtech Exp $
+ *
+ * Copyright (c) 1999-2001 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
+ *
+ * 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/init.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/tqueue.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("AT and PS/2 keyboard driver");
+MODULE_PARM(atkbd_set, "1i");
+MODULE_LICENSE("GPL");
+
+static int atkbd_set = 2;
+
+/*
+ * Scancode to keycode tables. These are just the default setting, and
+ * are loadable via an userland utility.
+ */
+
+static unsigned char atkbd_set2_keycode[512] = {
+ 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41, 85,
+ 0, 56, 42, 0, 29, 16, 2, 89, 0, 0, 44, 31, 30, 17, 3, 90,
+ 0, 46, 45, 32, 18, 5, 4, 91, 0, 57, 47, 33, 20, 19, 6, 0,
+ 0, 49, 48, 35, 34, 21, 7, 0, 0, 0, 50, 36, 22, 8, 9, 0,
+ 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
+ 122, 89, 40,120, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 0,
+ 85, 86, 90, 91, 92, 93, 14, 94, 95, 79, 0, 75, 71,121, 0,123,
+ 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
+ 252, 0, 0, 65, 99, 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,251, 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,
+ 252,253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,
+ 0, 0, 92, 90, 85, 0,137, 0, 0, 0, 0, 91, 89,144,115, 0,
+ 136,100,255, 0, 97,149,164, 0,156, 0, 0,140,115, 0, 0,125,
+ 0,150, 0,154,152,163,151,126,112,166, 0,140, 0,147, 0,127,
+ 159,167,139,160,163, 0, 0,116,158, 0,150,165, 0, 0, 0,142,
+ 157, 0,114,166,168, 0, 0, 0,155, 0, 98,113, 0,148, 0,138,
+ 0, 0, 0, 0, 0, 0,153,140, 0,255, 96, 0, 0, 0,143, 0,
+ 133, 0,116, 0,143, 0,174,133, 0,107, 0,105,102, 0, 0,112,
+ 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119
+};
+
+static unsigned char atkbd_set3_keycode[512] = {
+ 0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60,
+ 131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62,
+ 134, 46, 45, 32, 18, 5, 4, 63,135, 57, 47, 33, 20, 19, 6, 64,
+ 136, 49, 48, 35, 34, 21, 7, 65,137,100, 50, 36, 22, 8, 9, 66,
+ 125, 51, 37, 23, 24, 11, 10, 67,126, 52, 53, 38, 39, 25, 12, 68,
+ 113,114, 40, 84, 26, 13, 87, 99,100, 54, 28, 27, 43, 84, 88, 70,
+ 108,105,119,103,111,107, 14,110, 0, 79,106, 75, 71,109,102,104,
+ 82, 83, 80, 76, 77, 72, 69, 98, 0, 96, 81, 0, 78, 73, 55, 85,
+ 89, 90, 91, 92, 74, 0, 0, 0, 0, 0, 0,125,126,127,112, 0,
+ 0,139,150,163,165,115,152,150,166,140,160,154,113,114,167,168,
+ 148,149,147,140, 0, 0, 0, 0, 0, 0,251, 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,
+ 252,253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255
+};
+
+#define ATKBD_CMD_SETLEDS 0x10ed
+#define ATKBD_CMD_GSCANSET 0x11f0
+#define ATKBD_CMD_SSCANSET 0x10f0
+#define ATKBD_CMD_GETID 0x02f2
+#define ATKBD_CMD_ENABLE 0x00f4
+#define ATKBD_CMD_RESET_DIS 0x00f5
+#define ATKBD_CMD_SETALL_MB 0x00f8
+#define ATKBD_CMD_EX_ENABLE 0x10ea
+#define ATKBD_CMD_EX_SETLEDS 0x20eb
+
+#define ATKBD_RET_ACK 0xfa
+#define ATKBD_RET_NAK 0xfe
+
+#define ATKBD_KEY_UNKNOWN 0
+#define ATKBD_KEY_BAT 251
+#define ATKBD_KEY_EMUL0 252
+#define ATKBD_KEY_EMUL1 253
+#define ATKBD_KEY_RELEASE 254
+#define ATKBD_KEY_NULL 255
+
+/*
+ * The atkbd control structure
+ */
+
+struct atkbd {
+ unsigned char keycode[512];
+ struct input_dev dev;
+ struct serio *serio;
+ char name[64];
+ char phys[32];
+ struct tq_struct tq;
+ unsigned char cmdbuf[4];
+ unsigned char cmdcnt;
+ unsigned char set;
+ char release;
+ char ack;
+ char emul;
+ char error;
+ unsigned short id;
+};
+
+/*
+ * atkbd_interrupt(). Here takes place processing of data received from
+ * the keyboard into events.
+ */
+
+static void atkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+ struct atkbd *atkbd = serio->private;
+ int code = data;
+
+#ifdef ATKBD_DEBUG
+ printk(KERN_DEBUG "atkbd.c: Received %02x\n", data);
+#endif
+
+ switch (code) {
+ case ATKBD_RET_ACK:
+ atkbd->ack = 1;
+ return;
+ case ATKBD_RET_NAK:
+ atkbd->ack = -1;
+ return;
+ }
+
+ if (atkbd->cmdcnt) {
+ atkbd->cmdbuf[--atkbd->cmdcnt] = code;
+ return;
+ }
+
+ switch (atkbd->keycode[code]) {
+ case ATKBD_KEY_BAT:
+ queue_task(&atkbd->tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ return;
+ case ATKBD_KEY_EMUL0:
+ atkbd->emul = 1;
+ return;
+ case ATKBD_KEY_EMUL1:
+ atkbd->emul = 2;
+ return;
+ case ATKBD_KEY_RELEASE:
+ atkbd->release = 1;
+ return;
+ }
+
+ if (atkbd->emul) {
+ if (--atkbd->emul) return;
+ code |= 0x100;
+ }
+
+ switch (atkbd->keycode[code]) {
+ case ATKBD_KEY_NULL:
+ break;
+ case ATKBD_KEY_UNKNOWN:
+ printk(KERN_WARNING "atkbd.c: Unknown key (set %d, scancode %#x, on %s) %s.\n",
+ atkbd->set, code, serio->phys, atkbd->release ? "released" : "pressed");
+ break;
+ default:
+ input_report_key(&atkbd->dev, atkbd->keycode[code], !atkbd->release);
+ }
+
+ atkbd->release = 0;
+}
+
+/*
+ * atkbd_sendbyte() sends a byte to the keyboard, and waits for
+ * acknowledge. It doesn't handle resends according to the keyboard
+ * protocol specs, because if these are needed, the keyboard needs
+ * replacement anyway, and they only make a mess in the protocol.
+ */
+
+static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte)
+{
+ int timeout = 10000; /* 100 msec */
+ atkbd->ack = 0;
+
+#ifdef ATKBD_DEBUG
+ printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte);
+#endif
+ serio_write(atkbd->serio, byte);
+ while (!atkbd->ack && timeout--) udelay(10);
+
+ return -(atkbd->ack <= 0);
+}
+
+/*
+ * atkbd_command() sends a command, and its parameters to the keyboard,
+ * then waits for the response and puts it in the param array.
+ */
+
+static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command)
+{
+ int timeout = 50000; /* 500 msec */
+ int send = (command >> 12) & 0xf;
+ int receive = (command >> 8) & 0xf;
+ int i;
+
+ atkbd->cmdcnt = receive;
+
+ if (command & 0xff)
+ if (atkbd_sendbyte(atkbd, command & 0xff))
+ return (atkbd->cmdcnt = 0) - 1;
+
+ for (i = 0; i < send; i++)
+ if (atkbd_sendbyte(atkbd, param[i]))
+ return (atkbd->cmdcnt = 0) - 1;
+
+ while (atkbd->cmdcnt && timeout--) udelay(10);
+
+ for (i = 0; i < receive; i++)
+ param[i] = atkbd->cmdbuf[(receive - 1) - i];
+
+ if (atkbd->cmdcnt)
+ return (atkbd->cmdcnt = 0) - 1;
+
+ return 0;
+}
+
+/*
+ * Event callback from the input module. Events that change the state of
+ * the hardware are processed here.
+ */
+
+static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+ struct atkbd *atkbd = dev->private;
+ char param[2];
+
+ if (!atkbd->serio->write)
+ return -1;
+
+ switch (type) {
+
+ case EV_LED:
+
+ *param = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
+ | (test_bit(LED_NUML, dev->led) ? 2 : 0)
+ | (test_bit(LED_CAPSL, dev->led) ? 4 : 0);
+ atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS);
+
+ if (atkbd->set == 4) {
+ param[0] = 0;
+ param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)
+ | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0)
+ | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
+ | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0);
+ atkbd_command(atkbd, param, ATKBD_CMD_EX_SETLEDS);
+ }
+
+ return 0;
+ }
+
+ return -1;
+}
+
+/*
+ * atkbd_set_3 checks if a keyboard has a working Set 3 support, and
+ * sets it into that. Unfortunately there are keyboards that can be switched
+ * to Set 3, but don't work well in that (BTC Multimedia ...)
+ */
+
+static int atkbd_set_3(struct atkbd *atkbd)
+{
+ unsigned char param;
+
+/*
+ * For known special keyboards we can go ahead and set the correct set.
+ */
+
+ if (atkbd->id == 0xaca1) {
+ param = 3;
+ atkbd_command(atkbd, &param, ATKBD_CMD_SSCANSET);
+ return 3;
+ }
+
+/*
+ * We check for the extra keys on an some keyboards that need extra
+ * command to get enabled. This shouldn't harm any keyboards not
+ * knowing the command.
+ */
+
+ param = 0x71;
+ if (!atkbd_command(atkbd, &param, ATKBD_CMD_EX_ENABLE))
+ return 4;
+
+/*
+ * Try to set the set we want.
+ */
+
+ param = atkbd_set;
+ if (atkbd_command(atkbd, &param, ATKBD_CMD_SSCANSET))
+ return 2;
+
+/*
+ * Read set number. Beware here. Some keyboards always send '2'
+ * or some other number regardless into what mode they have been
+ * attempted to be set. Other keyboards treat the '0' command as
+ * 'set to set 0', and not 'report current set' as they should.
+ * In that case we time out, and return 2.
+ */
+
+ param = 0;
+ if (atkbd_command(atkbd, &param, ATKBD_CMD_GSCANSET))
+ return 2;
+
+/*
+ * Here we return the set number the keyboard reports about
+ * itself.
+ */
+
+ return (param == 3) ? 3 : 2;
+}
+
+/*
+ * atkbd_probe() probes for an AT keyboard on a serio port.
+ */
+
+static int atkbd_probe(struct atkbd *atkbd)
+{
+ unsigned char param[2];
+
+/*
+ * Full reset with selftest can on some keyboards be annoyingly slow,
+ * so we just do a reset-and-disable on the keyboard, which
+ * is considerably faster, but doesn't have to reset everything.
+ */
+
+ if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_DIS))
+ return -1;
+
+/*
+ * Next, we check if it's a keyboard. It should send 0xab83
+ * (0xab84 on IBM ThinkPad, and 0xaca1 on a NCD Sun layout keyboard,
+ * 0xab02 on unxlated i8042 and 0xab03 on unxlated ThinkPad, 0xab7f
+ * on Fujitsu Lifebook).
+ * If it's a mouse, it'll only send 0x00 (0x03 if it's MS mouse),
+ * and we'll time out here, and report an error.
+ */
+
+ param[0] = param[1] = 0;
+
+ if (atkbd_command(atkbd, param, ATKBD_CMD_GETID))
+ return -1;
+
+ atkbd->id = (param[0] << 8) | param[1];
+
+ if (atkbd->id != 0xab83 && atkbd->id != 0xab84 && atkbd->id != 0xaca1 &&
+ atkbd->id != 0xab7f && atkbd->id != 0xab02 && atkbd->id != 0xab03)
+ printk(KERN_WARNING "atkbd.c: Unusual keyboard ID: %#x on %s\n",
+ atkbd->id, atkbd->serio->phys);
+
+ return 0;
+}
+
+/*
+ * atkbd_initialize() sets the keyboard into a sane state.
+ */
+
+static void atkbd_initialize(struct atkbd *atkbd)
+{
+ unsigned char param;
+
+/*
+ * Disable autorepeat. We don't need it, as we do it in software anyway,
+ * because that way can get faster repeat, and have less system load
+ * (less accesses to the slow ISA hardware). If this fails, we don't care,
+ * and will just ignore the repeated keys.
+ */
+
+ atkbd_command(atkbd, NULL, ATKBD_CMD_SETALL_MB);
+
+/*
+ * We also shut off all the leds. The console code will turn them back on,
+ * if needed.
+ */
+
+ param = 0;
+ atkbd_command(atkbd, &param, ATKBD_CMD_SETLEDS);
+
+/*
+ * Last, we enable the keyboard so that we get keypresses from it.
+ */
+
+ if (atkbd_command(atkbd, NULL, ATKBD_CMD_ENABLE))
+ printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n",
+ atkbd->serio->phys);
+}
+
+/*
+ * atkbd_disconnect() cleans up behind us ...
+ */
+
+static void atkbd_disconnect(struct serio *serio)
+{
+ struct atkbd *atkbd = serio->private;
+ input_unregister_device(&atkbd->dev);
+ serio_close(serio);
+ kfree(atkbd);
+}
+
+/*
+ * atkbd_powerup() is called when the keyboard sends the 0xaa character,
+ * meaning that it was disconnected and reconnected. We close the port
+ * in that case and let the upper layer find an appropriate driver for
+ * the device that was connected. It may be a mouse, or a keyboard, we
+ * don't know yet.
+ */
+
+static void atkbd_powerup(void *data)
+{
+ struct atkbd *atkbd = data;
+ mdelay(40); /* FIXME!!! Wait some nicer way */
+ serio_rescan(atkbd->serio);
+}
+
+/*
+ * atkbd_connect() is called when the serio module finds and interface
+ * that isn't handled yet by an appropriate device driver. We check if
+ * there is an AT keyboard out there and if yes, we register ourselves
+ * to the input module.
+ */
+
+static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
+{
+ struct atkbd *atkbd;
+ int i;
+
+ if ((serio->type & SERIO_TYPE) != SERIO_8042)
+ return;
+
+ if (!(atkbd = kmalloc(sizeof(struct atkbd), GFP_KERNEL)))
+ return;
+
+ memset(atkbd, 0, sizeof(struct atkbd));
+
+ if (serio->write) {
+ atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
+ atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+ } else atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+
+ atkbd->serio = serio;
+
+ atkbd->dev.keycode = atkbd->keycode;
+ atkbd->dev.event = atkbd_event;
+ atkbd->dev.private = atkbd;
+
+ atkbd->tq.routine = atkbd_powerup;
+ atkbd->tq.data = atkbd;
+
+ serio->private = atkbd;
+
+ if (serio_open(serio, dev)) {
+ kfree(atkbd);
+ return;
+ }
+
+ if (serio->write) {
+
+ if (atkbd_probe(atkbd)) {
+ serio_close(serio);
+ kfree(atkbd);
+ return;
+ }
+
+ atkbd->set = atkbd_set_3(atkbd);
+
+ } else {
+ atkbd->set = 2;
+ atkbd->id = 0xab00;
+ }
+
+ if (atkbd->set == 4) {
+ atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE);
+ sprintf(atkbd->name, "AT Set 2 Extended keyboard\n");
+ } else
+ sprintf(atkbd->name, "AT Set %d keyboard", atkbd->set);
+
+ sprintf(atkbd->phys, "%s/input0", serio->phys);
+
+ if (atkbd->set == 3)
+ memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
+ else
+ memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
+
+ atkbd->dev.name = atkbd->name;
+ atkbd->dev.phys = atkbd->phys;
+ atkbd->dev.idbus = BUS_I8042;
+ atkbd->dev.idvendor = 0x0001;
+ atkbd->dev.idproduct = atkbd->set;
+ atkbd->dev.idversion = atkbd->id;
+
+ for (i = 0; i < 512; i++)
+ if (atkbd->keycode[i] && atkbd->keycode[i] <= 250)
+ set_bit(atkbd->keycode[i], atkbd->dev.keybit);
+
+ input_register_device(&atkbd->dev);
+
+ printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys);
+
+ if (serio->write)
+ atkbd_initialize(atkbd);
+}
+
+
+static struct serio_dev atkbd_dev = {
+ interrupt: atkbd_interrupt,
+ connect: atkbd_connect,
+ disconnect: atkbd_disconnect
+};
+
+/*
+ * Module init and exit.
+ */
+
+void __init atkbd_setup(char *str, int *ints)
+{
+ if (!ints[0]) atkbd_set = ints[1];
+}
+
+int __init atkbd_init(void)
+{
+ serio_register_device(&atkbd_dev);
+ return 0;
+}
+
+void __exit atkbd_exit(void)
+{
+ serio_unregister_device(&atkbd_dev);
+}
+
+module_init(atkbd_init);
+module_exit(atkbd_exit);
diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c
new file mode 100644
index 000000000000..feaea91dc8b4
--- /dev/null
+++ b/drivers/input/keyboard/maple_keyb.c
@@ -0,0 +1,190 @@
+/*
+ * $Id: maple_keyb.c,v 1.1 2001/11/02 17:27:32 jsimmons 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");
+
+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, 84, 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, 85, 89, 90, 91, 92, 93, 94, 95,
+ 120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113,
+ 115,114, 0, 0, 0,124, 0,181,182,183,184,185,186,187,188,189,
+ 190,191,192,193,194,195,196,197,198, 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]);
+ }
+ }
+
+ 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);
+
+ 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.idbus = BUS_MAPLE;
+
+ input_register_device(&kbd->dev);
+
+ maple_getcond_callback(dev, dc_kbd_callback, 1, MAPLE_FUNC_KEYBOARD);
+
+ printk(KERN_INFO "input%d: keyboard(0x%lx): %s\n",
+ kbd->dev.number, data, kbd->dev.name);
+
+ MOD_INC_USE_COUNT;
+
+ 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);
+
+ MOD_DEC_USE_COUNT;
+}
+
+
+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:
+ */
diff --git a/drivers/input/keyboard/ps2serkbd.c b/drivers/input/keyboard/ps2serkbd.c
new file mode 100644
index 000000000000..afa4c107ff4e
--- /dev/null
+++ b/drivers/input/keyboard/ps2serkbd.c
@@ -0,0 +1,298 @@
+/*
+ * based on: sunkbd.c and ps2serkbd.c
+ *
+ * $Id: ps2serkbd.c,v 1.5 2001/09/25 10:12:07 vojtech Exp $
+ */
+
+/*
+ * PS/2 keyboard via adapter at serial 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
+ */
+
+#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/tqueue.h>
+
+#define ATKBD_CMD_SETLEDS 0x10ed
+#define ATKBD_CMD_GSCANSET 0x11f0
+#define ATKBD_CMD_SSCANSET 0x10f0
+#define ATKBD_CMD_GETID 0x02f2
+#define ATKBD_CMD_ENABLE 0x00f4
+#define ATKBD_CMD_RESET_DIS 0x00f5
+#define ATKBD_CMD_SETALL_MB 0x00f8
+#define ATKBD_CMD_EX_ENABLE 0x10ea
+#define ATKBD_CMD_EX_SETLEDS 0x20eb
+
+#define ATKBD_RET_ACK 0xfa
+#define ATKBD_RET_NAK 0xfe
+
+#define ATKBD_KEY_UNKNOWN 0
+#define ATKBD_KEY_BAT 251
+#define ATKBD_KEY_EMUL0 252
+#define ATKBD_KEY_EMUL1 253
+#define ATKBD_KEY_RELEASE 254
+#define ATKBD_KEY_NULL 255
+
+static unsigned char ps2serkbd_set2_keycode[512] = {
+ 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41, 85,
+ 0, 56, 42, 0, 29, 16, 2, 89, 0, 0, 44, 31, 30, 17, 3, 90,
+ 0, 46, 45, 32, 18, 5, 4, 91, 0, 57, 47, 33, 20, 19, 6, 0,
+ 0, 49, 48, 35, 34, 21, 7, 0, 0, 0, 50, 36, 22, 8, 9, 0,
+ 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
+ 122, 89, 40,120, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 0,
+ 85, 86, 90, 91, 92, 93, 14, 94, 95, 79, 0, 75, 71,121, 0,123,
+ 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
+ 252, 0, 0, 65, 99, 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,251, 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,
+ 252,253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,
+ 0, 0, 92, 90, 85, 0,137, 0, 0, 0, 0, 91, 89,144,115, 0,
+ 136,100,255, 0, 97,149,164, 0,156, 0, 0,140,115, 0, 0,125,
+ 0,150, 0,154,152,163,151,126,112,166, 0,140, 0,147, 0,127,
+ 159,167,139,160,163, 0, 0,116,158, 0,150,165, 0, 0, 0,142,
+ 157, 0,114,166,168, 0, 0, 0,155, 0, 98,113, 0,148, 0,138,
+ 0, 0, 0, 0, 0, 0,153,140, 0, 0, 96, 0, 0, 0,143, 0,
+ 133, 0,116, 0,143, 0,174,133, 0,107, 0,105,102, 0, 0,112,
+ 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119
+};
+
+/*
+ * Per-keyboard data.
+ */
+
+struct ps2serkbd {
+ unsigned char keycode[512];
+ struct input_dev dev;
+ struct serio *serio;
+ char name[64];
+ char phys[32];
+ struct tq_struct tq;
+ unsigned char cmdbuf[4];
+ unsigned char cmdcnt;
+ unsigned char set;
+ char release;
+ char ack;
+ char emul;
+ char error;
+ unsigned short id;
+};
+
+/*
+ * ps2serkbd_interrupt() is called by the low level driver when a character
+ * is received.
+ */
+
+static void ps2serkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+ static int event_count=0;
+ struct ps2serkbd* ps2serkbd = serio->private;
+ int code=data;
+
+#if 0
+ printk(KERN_WARNING "ps2serkbd.c(%8d): (scancode %#x)\n", event_count, data);
+#endif
+ event_count++;
+
+ switch (code) {
+ case ATKBD_RET_ACK:
+ ps2serkbd->ack = 1;
+ return;
+ case ATKBD_RET_NAK:
+ ps2serkbd->ack = -1;
+ return;
+ }
+
+ if (ps2serkbd->cmdcnt) {
+ ps2serkbd->cmdbuf[--ps2serkbd->cmdcnt] = code;
+ return;
+ }
+
+ switch (ps2serkbd->keycode[code]) {
+ case ATKBD_KEY_BAT:
+ queue_task(&ps2serkbd->tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ return;
+ case ATKBD_KEY_EMUL0:
+ ps2serkbd->emul = 1;
+ return;
+ case ATKBD_KEY_EMUL1:
+ ps2serkbd->emul = 2;
+ return;
+ case ATKBD_KEY_RELEASE:
+ ps2serkbd->release = 1;
+ return;
+ }
+
+ if (ps2serkbd->emul) {
+ if (--ps2serkbd->emul) return;
+ code |= 0x100;
+ }
+
+ switch (ps2serkbd->keycode[code]) {
+ case ATKBD_KEY_NULL:
+ break;
+ case ATKBD_KEY_UNKNOWN:
+ printk(KERN_WARNING "ps2serkbd.c: Unknown key (set %d, scancode %#x) %s.\n",
+ ps2serkbd->set, code, ps2serkbd->release ? "released" : "pressed");
+ break;
+ default:
+ input_report_key(&ps2serkbd->dev, ps2serkbd->keycode[code], !ps2serkbd->release);
+ }
+
+ ps2serkbd->release = 0;
+}
+
+/*
+ * ps2serkbd_event() handles events from the input module.
+ */
+
+static int ps2serkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+ switch (type) {
+
+ case EV_LED:
+
+ return 0;
+ }
+
+ return -1;
+}
+
+static int ps2serkbd_initialize(struct ps2serkbd *ps2serkbd)
+{
+ return 0;
+}
+
+static void ps2serkbd_reinit(void *data)
+{
+}
+
+
+static void ps2serkbd_connect(struct serio *serio, struct serio_dev *dev)
+{
+ struct ps2serkbd *ps2serkbd;
+ int i;
+
+ if ((serio->type & SERIO_TYPE) != SERIO_RS232)
+ return;
+
+ if ((serio->type & SERIO_PROTO) && (serio->type & SERIO_PROTO) != SERIO_PS2SER)
+ return;
+
+
+ if (!(ps2serkbd = kmalloc(sizeof(struct ps2serkbd), GFP_KERNEL)))
+ return;
+
+ memset(ps2serkbd, 0, sizeof(struct ps2serkbd));
+
+ ps2serkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
+ ps2serkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
+
+ ps2serkbd->serio = serio;
+
+ ps2serkbd->dev.keycode = ps2serkbd->keycode;
+ ps2serkbd->dev.event = ps2serkbd_event;
+ ps2serkbd->dev.private = ps2serkbd;
+
+ ps2serkbd->tq.routine = ps2serkbd_reinit;
+ ps2serkbd->tq.data = ps2serkbd;
+
+ serio->private = ps2serkbd;
+
+ if (serio_open(serio, dev)) {
+ kfree(ps2serkbd);
+ return;
+ }
+
+ if (ps2serkbd_initialize(ps2serkbd) < 0) {
+ serio_close(serio);
+ kfree(ps2serkbd);
+ return;
+ }
+
+ ps2serkbd->set = 4;
+
+ if (ps2serkbd->set == 4) {
+ ps2serkbd->dev.ledbit[0] |= 0;
+ sprintf(ps2serkbd->name, "AT Set 2 Extended keyboard\n");
+ }
+ memcpy(ps2serkbd->keycode, ps2serkbd_set2_keycode, sizeof(ps2serkbd->keycode));
+
+ sprintf(ps2serkbd->phys, "%s/input0", serio->phys);
+
+ ps2serkbd->dev.name = ps2serkbd->name;
+ ps2serkbd->dev.phys = ps2serkbd->phys;
+ ps2serkbd->dev.idbus = BUS_RS232;
+ ps2serkbd->dev.idvendor = SERIO_PS2SER;
+ ps2serkbd->dev.idproduct = ps2serkbd->set;
+ ps2serkbd->dev.idversion = ps2serkbd->id;
+
+ for (i = 0; i < 512; i++)
+ if (ps2serkbd->keycode[i] && ps2serkbd->keycode[i] <= 250)
+ set_bit(ps2serkbd->keycode[i], ps2serkbd->dev.keybit);
+
+ input_register_device(&ps2serkbd->dev);
+}
+
+/*
+ * ps2serkbd_disconnect() unregisters and closes behind us.
+ */
+
+static void ps2serkbd_disconnect(struct serio *serio)
+{
+ struct ps2serkbd *ps2serkbd = serio->private;
+ input_unregister_device(&ps2serkbd->dev);
+ serio_close(serio);
+ kfree(ps2serkbd);
+}
+
+static struct serio_dev ps2serkbd_dev = {
+interrupt:
+ ps2serkbd_interrupt,
+connect:
+ ps2serkbd_connect,
+disconnect:
+ ps2serkbd_disconnect
+};
+
+/*
+ * The functions for insering/removing us as a module.
+ */
+
+int __init ps2serkbd_init(void)
+{
+ serio_register_device(&ps2serkbd_dev);
+ return 0;
+}
+
+void __exit ps2serkbd_exit(void)
+{
+ serio_unregister_device(&ps2serkbd_dev);
+}
+
+module_init(ps2serkbd_init);
+module_exit(ps2serkbd_exit);
diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c
new file mode 100644
index 000000000000..901567c2b355
--- /dev/null
+++ b/drivers/input/keyboard/sunkbd.c
@@ -0,0 +1,318 @@
+/*
+ * $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/tqueue.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Sun keyboard driver");
+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 tq_struct tq;
+ char name[64];
+ char phys[32];
+ char type;
+ char reset;
+ char layout;
+};
+
+/*
+ * sunkbd_interrupt() is called by the low level driver when a character
+ * is received.
+ */
+
+static void sunkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+ 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 */
+ return;
+ }
+
+ if (sunkbd->layout == -1) {
+ sunkbd->layout = data;
+ return;
+ }
+
+ switch (data) {
+
+ case SUNKBD_RET_RESET:
+ queue_task(&sunkbd->tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ sunkbd->reset = -1;
+ return;
+
+ case SUNKBD_RET_LAYOUT:
+ sunkbd->layout = -1;
+ return;
+
+ case SUNKBD_RET_ALLUP: /* All keys released */
+ return;
+
+ default:
+ if (sunkbd->keycode[data & SUNKBD_KEY]) {
+ input_report_key(&sunkbd->dev, sunkbd->keycode[data & SUNKBD_KEY], !(data & SUNKBD_RELEASE));
+ } else {
+ printk(KERN_WARNING "sunkbd.c: Unknown key (scancode %#x) %s.\n",
+ data & SUNKBD_KEY, data & SUNKBD_RELEASE ? "released" : "pressed");
+ }
+ }
+}
+
+/*
+ * 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)
+{
+ int t;
+
+ t = 1000;
+ sunkbd->reset = -2;
+ sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_RESET);
+ while (sunkbd->reset < 0 && --t) mdelay(1);
+ if (!t) return -1;
+
+ sunkbd->type = sunkbd->reset;
+
+ if (sunkbd->type == 4) { /* Type 4 keyboard */
+ t = 250;
+ sunkbd->layout = -2;
+ sunkbd->serio->write(sunkbd->serio, SUNKBD_CMD_LAYOUT);
+ while (sunkbd->layout < 0 && --t) mdelay(1);
+ if (!t) 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;
+ int t = 1000;
+
+ while (sunkbd->reset < 0 && --t) mdelay(1);
+
+ 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_dev *dev)
+{
+ 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));
+
+ 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;
+
+ sunkbd->tq.routine = sunkbd_reinit;
+ sunkbd->tq.data = sunkbd;
+
+ sunkbd->dev.keycode = sunkbd->keycode;
+ sunkbd->dev.event = sunkbd_event;
+ sunkbd->dev.private = sunkbd;
+
+ serio->private = sunkbd;
+
+ if (serio_open(serio, dev)) {
+ 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 < 255; i++)
+ set_bit(sunkbd->keycode[i], sunkbd->dev.keybit);
+ clear_bit(0, sunkbd->dev.keybit);
+
+ sprintf(sunkbd->name, "%s/input", serio->phys);
+
+ sunkbd->dev.name = sunkbd->name;
+ sunkbd->dev.phys = sunkbd->phys;
+ sunkbd->dev.idbus = BUS_RS232;
+ sunkbd->dev.idvendor = SERIO_SUNKBD;
+ sunkbd->dev.idproduct = sunkbd->type;
+ sunkbd->dev.idversion = 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_dev sunkbd_dev = {
+ 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_device(&sunkbd_dev);
+ return 0;
+}
+
+void __exit sunkbd_exit(void)
+{
+ serio_unregister_device(&sunkbd_dev);
+}
+
+module_init(sunkbd_init);
+module_exit(sunkbd_exit);
diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c
new file mode 100644
index 000000000000..6f0b2410788a
--- /dev/null
+++ b/drivers/input/keyboard/xtkbd.c
@@ -0,0 +1,157 @@
+/*
+ * $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>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("XT keyboard driver");
+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];
+};
+
+void xtkbd_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+ struct xtkbd *xtkbd = serio->private;
+
+ switch (data) {
+ case XTKBD_EMUL0:
+ case XTKBD_EMUL1:
+ return;
+ default:
+
+ if (xtkbd->keycode[data & XTKBD_KEY]) {
+ input_report_key(&xtkbd->dev, xtkbd->keycode[data & XTKBD_KEY], !(data & XTKBD_RELEASE));
+ } else {
+ printk(KERN_WARNING "xtkbd.c: Unknown key (scancode %#x) %s.\n",
+ data & XTKBD_KEY, data & XTKBD_RELEASE ? "released" : "pressed");
+ }
+ }
+}
+
+void xtkbd_connect(struct serio *serio, struct serio_dev *dev)
+{
+ 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;
+
+ xtkbd->dev.keycode = xtkbd->keycode;
+ xtkbd->dev.private = xtkbd;
+
+ serio->private = xtkbd;
+
+ if (serio_open(serio, dev)) {
+ 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.idbus = BUS_XTKBD;
+ xtkbd->dev.idvendor = 0x0001;
+ xtkbd->dev.idproduct = 0x0001;
+ xtkbd->dev.idversion = 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_dev xtkbd_dev = {
+ interrupt: xtkbd_interrupt,
+ connect: xtkbd_connect,
+ disconnect: xtkbd_disconnect
+};
+
+int __init xtkbd_init(void)
+{
+ serio_register_device(&xtkbd_dev);
+ return 0;
+}
+
+void __exit xtkbd_exit(void)
+{
+ serio_unregister_device(&xtkbd_dev);
+}
+
+module_init(xtkbd_init);
+module_exit(xtkbd_exit);
diff --git a/drivers/input/mouse/Config.help b/drivers/input/mouse/Config.help
new file mode 100644
index 000000000000..c60ae83ff85d
--- /dev/null
+++ b/drivers/input/mouse/Config.help
@@ -0,0 +1,87 @@
+CONFIG_INPUT_MOUSE
+ 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
+ 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.
+
+ If unsure, say Y.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called psmouse.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_MOUSE_SERIAL
+ 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.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called sermouse.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_MOUSE_INPORT
+ Say Y here if you have an InPort, Microsoft or ATI XL busmouse.
+ They are rather rare these days.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called inport.o. If you want to compile it as a
+ module, say M here and read <file.:Documentation/modules.txt>.
+
+CONFIG_MOUSE_ATIXL
+ Say Y here if your mouse is of the ATI XL variety.
+
+CONFIG_MOUSE_LOGIBM
+ Say Y here if you have a Logitech busmouse.
+ They are rather rare these days.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called logibm.o. If you want to compile it as a
+ module, say M here and read <file.:Documentation/modules.txt>.
+
+CONFIG_MOUSE_PC110PAD
+ Say Y if you have the IBM PC-110 micro-notebook and want its
+ touchscreen supported.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called pc110pad.o. If you want to compile it as a
+ module, say M here and read <file.:Documentation/modules.txt>.
+
+CONFIG_MOUSE_MAPLE
+ Say Y if you have a DreamCast console and a mouse attached to
+ its Maple bus.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called maplemouse.o. If you want to compile it as a
+ module, say M here and read <file.:Documentation/modules.txt>.
+
+CONFIG_MOUSE_AMIGA
+ Say Y here if you have an Amiga and want its native mouse
+ supported by the kernel.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called amimouse.o. If you want to compile it as a
+ module, say M here and read <file.:Documentation/modules.txt>.
+
+CONFIG_MOUSE_ACORN
+ Say Y here if you have the Acorn RiscPC computer and want its
+ native mouse supported.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called rpcmouse.o. If you want to compile it as a
+ module, say M here and read <file.:Documentation/modules.txt>.
diff --git a/drivers/input/mouse/Config.in b/drivers/input/mouse/Config.in
new file mode 100644
index 000000000000..d740c4188ebd
--- /dev/null
+++ b/drivers/input/mouse/Config.in
@@ -0,0 +1,24 @@
+#
+# Mouse driver configuration
+#
+
+bool 'Mice' CONFIG_INPUT_MOUSE
+
+dep_tristate ' PS/2 mouse' CONFIG_MOUSE_PS2 $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_SERIO
+dep_tristate ' Serial mouse' CONFIG_MOUSE_SERIAL $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_SERIO
+
+dep_tristate ' InPort/MS/ATIXL busmouse' CONFIG_MOUSE_INPORT $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_ISA
+if [ "$CONFIG_MOUSE_INPORT" != "n" ]; then
+ bool ' ATI XL variant' CONFIG_MOUSE_ATIXL
+fi
+dep_tristate ' Logitech busmouse' CONFIG_MOUSE_LOGIBM $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_ISA
+dep_tristate ' IBM PC110 touchpad' CONFIG_MOUSE_PC110PAD $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_ISA
+if [ "$CONFIG_SH_DREAMCAST" = "y" ]; then
+ dep_tristate ' Maple bus mouse' CONFIG_MOUSE_MAPLE $CONFIG_INPUT $CONFIG_INPUT_MOUSE $CONFIG_MAPLE
+fi
+if [ "$CONFIG_AMIGA" = "y" ]; then
+ dep_tristate ' Amiga mouse' CONFIG_MOUSE_AMIGA $CONFIG_INPUT $CONFIG_INPUT_MOUSE
+fi
+if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+ dep_tristate ' Acorn RiscPC mouse' CONFIG_MOUSE_ACORN $CONFIG_INPUT $CONFIG_INPUT_MOUSE
+fi
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
new file mode 100644
index 000000000000..6ac13c13edcf
--- /dev/null
+++ b/drivers/input/mouse/Makefile
@@ -0,0 +1,18 @@
+#
+# Makefile for the mouse drivers.
+#
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o
+obj-$(CONFIG_MOUSE_ACORN) += 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
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c
new file mode 100644
index 000000000000..819d96827187
--- /dev/null
+++ b/drivers/input/mouse/amimouse.c
@@ -0,0 +1,147 @@
+/*
+ * $Id: amimouse.c,v 1.9 2001/09/25 10:12:07 vojtech Exp $
+ *
+ * Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ * Based on the work of:
+ * Michael Rausch James Banks
+ * Matther Dillon David Giller
+ * Nathan Laredo Linus Torvalds
+ * Johan Myreen Jes Sorensen
+ * Russel King
+ */
+
+/*
+ * Amiga mouse 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 <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 void 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) - lastx;
+ if (dx > 127) dx = (nx - 256) - lastx;
+ if (dy < -127) dy = (256 + ny) - lasty;
+ if (dy > 127) dy = (ny - 256) - lasty;
+
+ amimouse_lastx = nx;
+ amimouse_lasty = ny;
+
+ potgor = custom.potgor;
+
+ 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);
+}
+
+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", NULL)) {
+ amimouse_used--;
+ printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", amimouse_irq);
+ 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.idbus = BUS_AMIGA;
+ amimouse_dev.idvendor = 0x0001;
+ amimouse_dev.idproduct = 0x0002;
+ amimouse_dev.idversion = 0x0100;
+
+ input_register_device(&amimouse_dev);
+
+ printk(KERN_INFO "input: %s at joy0dat\n", amimouse_name);
+}
+
+static void __exit amimouse_exit(void)
+{
+ input_unregister_device(&amimouse_dev);
+}
+
+module_init(amimouse_init);
+module_exit(amimouse_exit);
diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c
new file mode 100644
index 000000000000..9931ff92835e
--- /dev/null
+++ b/drivers/input/mouse/inport.c
@@ -0,0 +1,193 @@
+/*
+ * $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 <asm/io.h>
+#include <asm/irq.h>
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/input.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
+
+MODULE_PARM(inport_irq, "i");
+
+static int inport_irq = INPORT_IRQ;
+static int inport_used = 0;
+
+static void 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",
+ idbus: BUS_ISA,
+ idvendor: INPORT_VENDOR,
+ idproduct: 0x0001,
+ idversion: 0x0100,
+};
+
+static void 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);
+
+ 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);
+}
+
+#ifndef MODULE
+static int __init inport_setup(char *str)
+{
+ int ints[4];
+ str = get_options(str, ARRAY_SIZE(ints), ints);
+ if (ints[0] > 0) inport_irq = ints[1];
+ return 1;
+}
+__setup("inport_irq=", inport_setup);
+#endif
+
+static int __init inport_init(void)
+{
+ unsigned char a,b,c;
+
+ if (check_region(INPORT_BASE, INPORT_EXTENT))
+ return -EBUSY;
+
+ a = inb(INPORT_SIGNATURE_PORT);
+ b = inb(INPORT_SIGNATURE_PORT);
+ c = inb(INPORT_SIGNATURE_PORT);
+ if (( a == b ) || ( a != c ))
+ return -ENODEV;
+
+ outb(INPORT_RESET, INPORT_CONTROL_PORT);
+ outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
+ outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
+
+ request_region(INPORT_BASE, INPORT_EXTENT, "inport");
+
+ 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);
diff --git a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c
new file mode 100644
index 000000000000..f1b34343de90
--- /dev/null
+++ b/drivers/input/mouse/logibm.c
@@ -0,0 +1,182 @@
+/*
+ * $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 <asm/io.h>
+#include <asm/irq.h>
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/input.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
+
+MODULE_PARM(logibm_irq, "i");
+
+static int logibm_irq = LOGIBM_IRQ;
+static int logibm_used = 0;
+
+static void 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",
+ idbus: BUS_ISA,
+ idvendor: 0x0003,
+ idproduct: 0x0001,
+ idversion: 0x0100,
+};
+
+static void 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;
+
+ input_report_rel(&logibm_dev, REL_X, dx);
+ input_report_rel(&logibm_dev, REL_Y, 255 - dy);
+ input_report_key(&logibm_dev, BTN_MIDDLE, buttons & 1);
+ input_report_key(&logibm_dev, BTN_LEFT, buttons & 2);
+ input_report_key(&logibm_dev, BTN_RIGHT, buttons & 4);
+}
+
+#ifndef MODULE
+static int __init logibm_setup(char *str)
+{
+ int ints[4];
+ str = get_options(str, ARRAY_SIZE(ints), ints);
+ if (ints[0] > 0) logibm_irq = ints[1];
+ return 1;
+}
+__setup("logibm_irq=", logibm_setup);
+#endif
+
+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);
diff --git a/drivers/input/mouse/maplemouse.c b/drivers/input/mouse/maplemouse.c
new file mode 100644
index 000000000000..34d90206a5b8
--- /dev/null
+++ b/drivers/input/mouse/maplemouse.c
@@ -0,0 +1,137 @@
+/*
+ * $Id: maplemouse.c,v 1.1 2001/11/02 17:27:32 jsimmons 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);
+}
+
+
+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);
+
+ 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.idbus = BUS_MAPLE;
+
+ input_register_device(&mouse->dev);
+
+ maple_getcond_callback(dev, dc_mouse_callback, 1, MAPLE_FUNC_MOUSE);
+
+ printk(KERN_INFO "input%d: mouse(0x%lx): %s\n",
+ mouse->dev.number, data, mouse->dev.name);
+
+ MOD_INC_USE_COUNT;
+
+ 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);
+
+ MOD_DEC_USE_COUNT;
+}
+
+
+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:
+ */
diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c
new file mode 100644
index 000000000000..61ee96685dcf
--- /dev/null
+++ b/drivers/input/mouse/pc110pad.c
@@ -0,0 +1,163 @@
+/*
+ * $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 <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 void 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;
+
+ 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));
+
+ pc110pad_count = 0;
+}
+
+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)
+{
+ unsigned long flags;
+
+ if (pc110pad_used++)
+ return 0;
+
+ save_flags(flags);
+ cli();
+ pc110pad_interrupt(0,0,0);
+ pc110pad_interrupt(0,0,0);
+ pc110pad_interrupt(0,0,0);
+ outb(PC110PAD_ON, pc110pad_io + 2);
+ pc110pad_count = 0;
+ restore_flags(flags);
+
+ return 0;
+}
+
+static int __init pc110pad_init(void)
+{
+ 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", 0))
+ {
+ 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.idbus = BUS_ISA;
+ pc110pad_dev.idvendor = 0x0003;
+ pc110pad_dev.idproduct = 0x0001;
+ pc110pad_dev.idversion = 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, 0);
+ release_region(pc110pad_io, 4);
+}
+
+module_init(pc110pad_init);
+module_exit(pc110pad_exit);
diff --git a/drivers/input/mouse/psmouse.c b/drivers/input/mouse/psmouse.c
new file mode 100644
index 000000000000..ba846a57caa4
--- /dev/null
+++ b/drivers/input/mouse/psmouse.c
@@ -0,0 +1,652 @@
+/*
+ * $Id: psmouse.c,v 1.18 2002/03/13 10:03:43 vojtech Exp $
+ *
+ * Copyright (c) 1999-2001 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
+ *
+ * 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/serio.h>
+#include <linux/init.h>
+#include <linux/tqueue.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("PS/2 mouse driver");
+MODULE_LICENSE("GPL");
+
+#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 0x01f2
+#define PSMOUSE_CMD_SETRATE 0x10f3
+#define PSMOUSE_CMD_ENABLE 0x00f4
+#define PSMOUSE_CMD_RESET_DIS 0x00f6
+
+#define PSMOUSE_RET_BAT 0xaa
+#define PSMOUSE_RET_ACK 0xfa
+#define PSMOUSE_RET_NAK 0xfe
+
+struct psmouse {
+ struct input_dev dev;
+ struct serio *serio;
+ char *vendor;
+ char *name;
+ struct tq_struct tq;
+ unsigned char cmdbuf[8];
+ unsigned char packet[8];
+ unsigned char cmdcnt;
+ unsigned char pktcnt;
+ unsigned char type;
+ unsigned long last;
+ char acking;
+ char ack;
+ char error;
+ char devname[64];
+ char phys[32];
+};
+
+#define PSMOUSE_PS2 1
+#define PSMOUSE_PS2PP 2
+#define PSMOUSE_PS2TPP 3
+#define PSMOUSE_GENPS 4
+#define PSMOUSE_IMPS 5
+#define PSMOUSE_IMEX 6
+
+static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2" };
+
+/*
+ * psmouse_process_packet() anlyzes the PS/2 mouse packet contents and
+ * reports relevant events to the input module.
+ */
+
+static void psmouse_process_packet(struct psmouse *psmouse)
+{
+ struct input_dev *dev = &psmouse->dev;
+ unsigned char *packet = psmouse->packet;
+
+/*
+ * The PS2++ protocol is a little bit complex
+ */
+
+ if (psmouse->type == PSMOUSE_PS2PP || psmouse->type == PSMOUSE_PS2TPP) {
+
+ if ((packet[0] & 0x40) == 0x40 && (int) packet[1] - (int) ((packet[0] & 0x10) << 4) > 191 ) {
+
+ switch (((packet[1] >> 4) & 0x03) | ((packet[0] >> 2) & 0xc0)) {
+
+ case 1: /* Mouse extra info */
+
+ input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL,
+ (int) (packet[2] & 7) - (int) (packet[2] & 8));
+ input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1);
+ input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1);
+
+ break;
+
+ case 3: /* TouchPad extra info */
+
+ input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL,
+ (int) ((packet[2] >> 4) & 7) - (int) ((packet[2] >> 4) & 8));
+ packet[0] = packet[2] | 0x08;
+
+ break;
+
+ default:
+
+ printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n",
+ ((packet[1] >> 4) & 0x03) | ((packet[0] >> 2) & 0xc0));
+
+ }
+
+ packet[0] &= 0x0f;
+ packet[1] = 0;
+ packet[2] = 0;
+
+ }
+ }
+
+/*
+ * 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] & 7) - (int) (packet[2] & 8));
+ 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);
+
+}
+
+/*
+ * psmouse_interrupt() handles incoming characters, either gathering them into
+ * packets or passing them to the command routine as command output.
+ */
+
+static void psmouse_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+ struct psmouse *psmouse = serio->private;
+
+ if (psmouse->acking) {
+ switch (data) {
+ case PSMOUSE_RET_ACK:
+ psmouse->ack = 1;
+ break;
+ case PSMOUSE_RET_NAK:
+ psmouse->ack = -1;
+ break;
+ default:
+ psmouse->ack = 1; /* Workaround for mice which don't ACK the Get ID command */
+ if (psmouse->cmdcnt)
+ psmouse->cmdbuf[--psmouse->cmdcnt] = data;
+ break;
+ }
+ psmouse->acking = 0;
+ return;
+ }
+
+ if (psmouse->cmdcnt) {
+ psmouse->cmdbuf[--psmouse->cmdcnt] = data;
+ return;
+ }
+
+ if (psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/20)) {
+ printk(KERN_WARNING "psmouse.c: Lost synchronization, throwing %d bytes away.\n", psmouse->pktcnt);
+ psmouse->pktcnt = 0;
+ }
+
+ psmouse->last = jiffies;
+ psmouse->packet[psmouse->pktcnt++] = data;
+
+ if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) {
+ if ((psmouse->packet[0] & 0x08) == 0x08) psmouse_process_packet(psmouse);
+ psmouse->pktcnt = 0;
+ return;
+ }
+
+ if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) {
+ queue_task(&psmouse->tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ return;
+ }
+}
+
+/*
+ * 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.
+ */
+
+static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte)
+{
+ int timeout = 10000; /* 100 msec */
+ psmouse->ack = 0;
+ psmouse->acking = 1;
+
+ serio_write(psmouse->serio, byte);
+ while (!psmouse->ack && timeout--) udelay(10);
+
+ return -(psmouse->ack <= 0);
+}
+
+/*
+ * psmouse_command() sends a command and its parameters to the mouse,
+ * then waits for the response and puts it in the param array.
+ */
+
+static int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
+{
+ int timeout = 500000; /* 500 msec */
+ int send = (command >> 12) & 0xf;
+ int receive = (command >> 8) & 0xf;
+ int i;
+
+ psmouse->cmdcnt = receive;
+
+ if (command & 0xff)
+ if (psmouse_sendbyte(psmouse, command & 0xff))
+ return (psmouse->cmdcnt = 0) - 1;
+
+ for (i = 0; i < send; i++)
+ if (psmouse_sendbyte(psmouse, param[i]))
+ return (psmouse->cmdcnt = 0) - 1;
+
+ while (psmouse->cmdcnt && timeout--) udelay(1);
+
+ for (i = 0; i < receive; i++)
+ param[i] = psmouse->cmdbuf[(receive - 1) - i];
+
+ if (psmouse->cmdcnt)
+ return (psmouse->cmdcnt = 0) - 1;
+
+ return 0;
+}
+
+/*
+ * psmouse_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 psmouse_ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command)
+{
+ unsigned char d;
+ int i;
+
+ if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11))
+ return -1;
+
+ for (i = 6; i >= 0; i -= 2) {
+ d = (command >> i) & 3;
+ if(psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
+ return -1;
+ }
+
+ if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL))
+ return -1;
+
+ return 0;
+}
+
+/*
+ * psmouse_extensions() probes for any extensions to the basic PS/2 protocol
+ * the mouse may have.
+ */
+
+static int psmouse_extensions(struct psmouse *psmouse)
+{
+ unsigned char param[4];
+
+ param[0] = 0;
+ psmouse->vendor = "Generic";
+ psmouse->name = "Mouse";
+
+/*
+ * Try Genius NetMouse magic init.
+ */
+
+ 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);
+
+ if (param[0] == 0x00 && param[1] == 0x33 && param[2] == 0x55) {
+ psmouse->vendor = "Genius";
+ psmouse->name = "Mouse";
+
+ set_bit(BTN_EXTRA, psmouse->dev.keybit);
+ set_bit(BTN_SIDE, psmouse->dev.keybit);
+ set_bit(REL_WHEEL, psmouse->dev.relbit);
+
+ return PSMOUSE_GENPS;
+ }
+
+/*
+ * Try Logitech magic ID.
+ */
+
+ 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);
+ psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
+
+ if (param[1]) {
+
+ int i;
+ static int logitech_4btn[] = { 12, 40, 41, 42, 43, 73, 80, -1 };
+ static int logitech_wheel[] = { 75, 76, 80, 81, 83, 88, -1 };
+ static int logitech_ps2pp[] = { 12, 13, 40, 41, 42, 43, 50, 51, 52, 53, 73, 75,
+ 76, 80, 81, 83, 88, 96, 97, -1 };
+
+ int devicetype = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
+
+ psmouse->vendor = "Logitech";
+ psmouse->name = "Mouse";
+
+ if (param[1] < 3)
+ clear_bit(BTN_MIDDLE, psmouse->dev.keybit);
+ if (param[1] < 2)
+ clear_bit(BTN_RIGHT, psmouse->dev.keybit);
+
+ psmouse->type = PSMOUSE_PS2;
+
+ for (i = 0; logitech_ps2pp[i] != -1; i++)
+ if (logitech_ps2pp[i] == devicetype) psmouse->type = PSMOUSE_PS2PP;
+
+ if (psmouse->type != PSMOUSE_PS2PP) return PSMOUSE_PS2;
+
+ for (i = 0; logitech_4btn[i] != -1; i++)
+ if (logitech_4btn[i] == devicetype) set_bit(BTN_SIDE, psmouse->dev.keybit);
+
+ for (i = 0; logitech_wheel[i] != -1; i++)
+ if (logitech_wheel[i] == devicetype) set_bit(REL_WHEEL, psmouse->dev.relbit);
+
+/*
+ * Do Logitech PS2++ / PS2T++ magic init.
+ */
+
+ if (devicetype == 97) { /* TouchPad 3 */
+
+ set_bit(REL_WHEEL, psmouse->dev.relbit);
+ set_bit(REL_HWHEEL, psmouse->dev.relbit);
+
+ param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; /* Unprotect RAM */
+ psmouse_command(psmouse, param, 0x30d1);
+ param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; /* Enable features */
+ psmouse_command(psmouse, param, 0x30d1);
+ param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; /* Enable PS2++ */
+ psmouse_command(psmouse, param, 0x30d1);
+
+ param[0] = 0;
+ if (!psmouse_command(psmouse, param, 0x13d1) &&
+ param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14)
+ return PSMOUSE_PS2TPP;
+
+ } else {
+ psmouse_ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */
+ psmouse_ps2pp_cmd(psmouse, param, 0xDB);
+
+ if ((param[0] & 0x78) == 0x48 && (param[1] & 0xf3) == 0xc2 &&
+ (param[2] & 3) == ((param[1] >> 2) & 3))
+ return PSMOUSE_PS2PP;
+ }
+
+ }
+
+/*
+ * Try IntelliMouse magic init.
+ */
+
+ 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);
+
+ if (param[0] == 3) {
+
+ set_bit(REL_WHEEL, psmouse->dev.relbit);
+
+/*
+ * Try IntelliMouse Explorer magic init.
+ */
+
+ 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);
+
+ if (param[0] == 4) {
+
+ psmouse->vendor = "Microsoft";
+ psmouse->name = "IntelliMouse Explorer";
+
+ set_bit(BTN_SIDE, psmouse->dev.keybit);
+ set_bit(BTN_EXTRA, psmouse->dev.keybit);
+
+ return PSMOUSE_IMEX;
+ }
+
+ psmouse->vendor = "Microsoft";
+ psmouse->name = "IntelliMouse";
+
+ return PSMOUSE_IMPS;
+ }
+
+/*
+ * Okay, all failed, we have a standard mouse here. The number of the buttons is
+ * still a question, though.
+ */
+
+ psmouse->vendor = "Generic";
+ psmouse->name = "Mouse";
+
+ return PSMOUSE_PS2;
+}
+
+/*
+ * psmouse_probe() probes for a PS/2 mouse.
+ */
+
+static int psmouse_probe(struct psmouse *psmouse)
+{
+ unsigned char param[2];
+
+/*
+ * First we reset and disable the mouse.
+ */
+
+ if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS))
+ return -1;
+
+/*
+ * Next, 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] = param[1] = 0xa5;
+
+ if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETID))
+ return -1;
+
+ if (param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04)
+ return -1;
+
+/*
+ * And here we try to determine if it has any extensions over the
+ * basic PS/2 3-button mouse.
+ */
+
+ return psmouse->type = psmouse_extensions(psmouse);
+}
+
+/*
+ * 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 to a highest possible value.
+ * We try 100 first in case mouse fails to set 200.
+ */
+
+ param[0] = 100;
+ psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+
+ param[0] = 200;
+ psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+
+/*
+ * We also set the resolution and scaling.
+ */
+
+ param[0] = 3;
+ psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+ psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
+
+/*
+ * We set the mouse into streaming mode.
+ */
+
+ psmouse_command(psmouse, param, PSMOUSE_CMD_SETSTREAM);
+
+/*
+ * Last, we enable the mouse so that we get reports from it.
+ */
+
+ if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE)) {
+ printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", psmouse->serio->phys);
+ }
+
+}
+
+/*
+ * psmouse_disconnect() cleans up after we don't want talk
+ * to the mouse anymore.
+ */
+
+static void psmouse_disconnect(struct serio *serio)
+{
+ struct psmouse *psmouse = serio->private;
+ input_unregister_device(&psmouse->dev);
+ serio_close(serio);
+ kfree(psmouse);
+}
+
+/*
+ * psmouse_powerup() is called when we get the powerup
+ * sequence - 0xaa [0x00], so that the mouse/kbd is re-probed.
+ */
+
+static void psmouse_powerup(void *data)
+{
+ struct psmouse *psmouse = data;
+
+ if (psmouse->packet[0] == PSMOUSE_RET_BAT && (psmouse->pktcnt == 1 ||
+ (psmouse->pktcnt == 2 && psmouse->packet[1] == 0x00))) {
+ mdelay(40); /* FIXME!!! Wait some nicer way */
+ serio_rescan(psmouse->serio);
+ }
+}
+
+/*
+ * psmouse_connect() is a callback form the serio module when
+ * an unhandled serio port is found.
+ */
+
+static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
+{
+ struct psmouse *psmouse;
+
+ if ((serio->type & SERIO_TYPE) != SERIO_8042)
+ return;
+
+ if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL)))
+ return;
+
+ memset(psmouse, 0, sizeof(struct psmouse));
+
+ 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->tq.routine = psmouse_powerup;
+ psmouse->tq.data = psmouse;
+
+ serio->private = psmouse;
+
+ if (serio_open(serio, dev)) {
+ kfree(psmouse);
+ return;
+ }
+
+ if (psmouse_probe(psmouse) <= 0) {
+ serio_close(serio);
+ kfree(psmouse);
+ return;
+ }
+
+ 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.idbus = BUS_I8042;
+ psmouse->dev.idvendor = psmouse->type;
+ psmouse->dev.idproduct = 0x0002;
+ psmouse->dev.idversion = 0x0100;
+
+ input_register_device(&psmouse->dev);
+
+ printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
+
+ psmouse_initialize(psmouse);
+}
+
+static struct serio_dev psmouse_dev = {
+ interrupt: psmouse_interrupt,
+ connect: psmouse_connect,
+ disconnect: psmouse_disconnect
+};
+
+int __init psmouse_init(void)
+{
+ serio_register_device(&psmouse_dev);
+ return 0;
+}
+
+void __exit psmouse_exit(void)
+{
+ serio_unregister_device(&psmouse_dev);
+}
+
+module_init(psmouse_init);
+module_exit(psmouse_exit);
diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
new file mode 100644
index 000000000000..04d16de5defc
--- /dev/null
+++ b/drivers/input/mouse/rpcmouse.c
@@ -0,0 +1,111 @@
+/*
+ * $Id: rpcmouse.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $
+ *
+ * Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ * Based on the work of:
+ * Russel King
+ */
+
+/*
+ * Acorn RiscPC mouse driver for Linux/ARM
+ */
+
+/*
+ * 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/sched.h>
+#include <linux/ptrace.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/iomd.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Acorn RiscPC mouse driver");
+MODULE_LICENSE("GPL");
+
+#define IOMD_MOUSEBTN 0x800C4000
+
+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",
+ idbus: BUS_ISA,
+ idvendor: 0x0005,
+ idproduct: 0x0001,
+ idversion: 0x0100,
+};
+
+static void rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ short x, y, dx, dy, b;
+
+ x = (short) inl(IOMD_MOUSEX);
+ y = (short) inl(IOMD_MOUSEY);
+ b = (short) inl(IOMD_MOUSEBTN);
+
+ dx = x - rpcmouse_lastx;
+ dy = y - rpcmouse_lasty;
+
+ rpcmouse_lastx = x;
+ rpcmouse_lasty = y;
+
+ input_report_rel(&rpcmouse_dev, REL_X, dx);
+ input_report_rel(&rpcmouse_dev, REL_Y, dy);
+
+ input_report_key(&amimouse_dev, BTN_LEFT, buttons & 0x10);
+ input_report_key(&amimouse_dev, BTN_MIDDLE, buttons & 0x20);
+ input_report_key(&amimouse_dev, BTN_RIGHT, buttons & 0x40);
+}
+
+static int __init rpcmouse_init(void)
+{
+ rpcmouse_lastx = (short) inl(IOMD_MOUSEX);
+ rpcmouse_lasty = (short) inl(IOMD_MOUSEY);
+
+ if (request_irq(IRQ_VSYNCPULSE, rpcmouse_irq, SA_SHIRQ, "rpcmouse", NULL)) {
+ printk(KERN_ERR "rpcmouse: unable to allocate VSYNC interrupt\n");
+ return -1;
+ }
+
+ input_register_device(&rpcmouse_dev);
+ printk(KERN_INFO "input%d: Acorn RiscPC mouse irq %d", IRQ_VSYNCPULSE);
+
+ return 0;
+}
+
+static void __exit rpcmouse_exit(void)
+{
+ input_unregister_device(&rpcmouse_dev);
+ free_irq(IRQ_VSYNCPULSE, NULL);
+}
+
+module_init(rpcmouse_init);
+module_exit(rpcmouse_exit);
diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c
new file mode 100644
index 000000000000..4dd1a4e9033c
--- /dev/null
+++ b/drivers/input/mouse/sermouse.c
@@ -0,0 +1,299 @@
+/*
+ * $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>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Serial mouse driver");
+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 input_dev *dev = &sermouse->dev;
+ signed char *buf = sermouse->buf;
+
+ 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;
+ }
+
+ 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 input_dev *dev = &sermouse->dev;
+ signed char *buf = sermouse->buf;
+
+ if (data & 0x40) sermouse->count = 0;
+
+ 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 & 7) - (data & 8));
+ 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;
+ }
+
+ sermouse->count++;
+}
+
+/*
+ * sermouse_interrupt() handles incoming characters, either gathering them into
+ * packets or passing them to the command routine as command output.
+ */
+
+static void sermouse_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+ struct sermouse *sermouse = serio->private;
+
+ if (time_after(jiffies, sermouse->last + HZ/20)) sermouse->count = 0;
+ sermouse->last = jiffies;
+
+ if (sermouse->type > SERIO_SUN)
+ sermouse_process_ms(sermouse, data);
+ else
+ sermouse_process_msc(sermouse, data);
+}
+
+/*
+ * 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_dev *dev)
+{
+ 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));
+
+ 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.idbus = BUS_RS232;
+ sermouse->dev.idvendor = sermouse->type;
+ sermouse->dev.idproduct = c;
+ sermouse->dev.idversion = 0x0100;
+
+ if (serio_open(serio, dev)) {
+ 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_dev sermouse_dev = {
+ interrupt: sermouse_interrupt,
+ connect: sermouse_connect,
+ disconnect: sermouse_disconnect
+};
+
+int __init sermouse_init(void)
+{
+ serio_register_device(&sermouse_dev);
+ return 0;
+}
+
+void __exit sermouse_exit(void)
+{
+ serio_unregister_device(&sermouse_dev);
+}
+
+module_init(sermouse_init);
+module_exit(sermouse_exit);
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 01fb98c7f30f..a5b4152e2c97 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -1,5 +1,5 @@
/*
- * $Id: mousedev.c,v 1.38 2001/12/26 21:08:33 jsimmons Exp $
+ * $Id: mousedev.c,v 1.42 2002/04/09 20:51:26 jdeneux Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*
@@ -38,6 +38,10 @@
#include <linux/config.h>
#include <linux/smp_lock.h>
#include <linux/random.h>
+#include <linux/major.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");
@@ -225,7 +229,14 @@ static int mousedev_release(struct inode * inode, struct file * file)
static int mousedev_open(struct inode * inode, struct file * file)
{
struct mousedev_list *list;
- int i = minor(inode->i_rdev) - MOUSEDEV_MINOR_BASE;
+ int i;
+
+#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
+ if (major(inode->i_rdev) == MISC_MAJOR)
+ i = MOUSEDEV_MIX;
+ else
+#endif
+ i = minor(inode->i_rdev) - MOUSEDEV_MINOR_BASE;
if (i >= MOUSEDEV_MINORS || !mousedev_table[i])
return -ENODEV;
@@ -494,6 +505,12 @@ static struct input_handler mousedev_handler = {
id_table: mousedev_ids,
};
+#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
+static struct miscdevice psaux_mouse = {
+ PSMOUSE_MINOR, "psaux", &mousedev_fops
+};
+#endif
+
static int __init mousedev_init(void)
{
input_register_handler(&mousedev_handler);
@@ -504,6 +521,9 @@ static int __init mousedev_init(void)
mousedev_mix.exist = 1;
mousedev_mix.minor = MOUSEDEV_MIX;
mousedev_mix.devfs = input_register_minor("mice", MOUSEDEV_MIX, MOUSEDEV_MINOR_BASE);
+#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
+ misc_register(&psaux_mouse);
+#endif
printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n");
@@ -512,6 +532,9 @@ static int __init mousedev_init(void)
static void __exit mousedev_exit(void)
{
+#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
+ misc_deregister(&psaux_mouse);
+#endif
input_unregister_minor(mousedev_mix.devfs);
input_unregister_handler(&mousedev_handler);
}
diff --git a/drivers/input/power.c b/drivers/input/power.c
new file mode 100644
index 000000000000..84af6b392dd5
--- /dev/null
+++ b/drivers/input/power.c
@@ -0,0 +1,180 @@
+/*
+ * $Id: power.c,v 1.10 2001/09/25 09:17:15 vojtech Exp $
+ *
+ * Copyright (c) 2001 "Crazy" James Simmons
+ *
+ * Input driver Power Management.
+ *
+ * Sponsored by Transvirtual Technology.
+ */
+
+/*
+ * 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 <jsimmons@transvirtual.com>.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+
+static struct input_handler power_handler;
+
+/*
+ * Power management can't be done in a interrupt context. So we have to
+ * use keventd.
+ */
+static int suspend_button_pushed = 0;
+static void suspend_button_task_handler(void *data)
+{
+ //extern void pm_do_suspend(void);
+ udelay(200); /* debounce */
+ //pm_do_suspend();
+ suspend_button_pushed = 0;
+}
+
+static struct tq_struct suspend_button_task = {
+ routine: suspend_button_task_handler
+};
+
+static void power_event(struct input_handle *handle, unsigned int type,
+ unsigned int code, int down)
+{
+ struct input_dev *dev = handle->dev;
+
+ printk("Entering power_event\n");
+
+ if (type != EV_KEY || type != EV_PWR) return;
+
+ if (type == EV_PWR) {
+ switch (code) {
+ case KEY_SUSPEND:
+ printk("Powering down entire device\n");
+
+ //pm_send_all(PM_SUSPEND, dev);
+
+ if (!suspend_button_pushed) {
+ suspend_button_pushed = 1;
+ schedule_task(&suspend_button_task);
+ }
+ break;
+ case KEY_POWER:
+ /* Hum power down the machine. */
+ break;
+ default:
+ return;
+ }
+ } else {
+ switch (code) {
+ case KEY_SUSPEND:
+ printk("Powering down input device\n");
+ /* This is risky. See pm.h for details. */
+ if (dev->state != PM_RESUME)
+ dev->state = PM_RESUME;
+ else
+ dev->state = PM_SUSPEND;
+ pm_send(dev->pm_dev, dev->state, dev);
+ break;
+ case KEY_POWER:
+ /* Turn the input device off completely ? */
+ break;
+ default:
+ return;
+ }
+ }
+ return;
+}
+
+static struct input_handle *power_connect(struct input_handler *handler,
+ struct input_dev *dev,
+ struct input_device_id *id)
+{
+ struct input_handle *handle;
+
+ if (!test_bit(EV_KEY, dev->evbit) || !test_bit(EV_PWR, dev->evbit))
+ return NULL;
+
+ if (!test_bit(KEY_SUSPEND, dev->keybit) || (!test_bit(KEY_POWER, dev->keybit)))
+ return NULL;
+
+ if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
+ return NULL;
+ memset(handle, 0, sizeof(struct input_handle));
+
+ handle->dev = dev;
+ handle->handler = handler;
+
+ input_open_device(handle);
+
+ printk(KERN_INFO "power.c: Adding power management to input layer\n");
+ return handle;
+}
+
+static void power_disconnect(struct input_handle *handle)
+{
+ input_close_device(handle);
+ kfree(handle);
+}
+
+static struct input_device_id power_ids[] = {
+ {
+ flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
+ evbit: { BIT(EV_KEY) },
+ keybit: { [LONG(KEY_SUSPEND)] = BIT(KEY_SUSPEND) }
+ },
+ {
+ flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
+ evbit: { BIT(EV_KEY) },
+ keybit: { [LONG(KEY_POWER)] = BIT(KEY_POWER) }
+ },
+ {
+ flags: INPUT_DEVICE_ID_MATCH_EVBIT,
+ evbit: { BIT(EV_PWR) },
+ },
+ { }, /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(input, power_ids);
+
+static struct input_handler power_handler = {
+ event: power_event,
+ connect: power_connect,
+ disconnect: power_disconnect,
+ name: "power",
+ id_table: power_ids,
+};
+
+static int __init power_init(void)
+{
+ input_register_handler(&power_handler);
+ return 0;
+}
+
+static void __exit power_exit(void)
+{
+ input_unregister_handler(&power_handler);
+}
+
+module_init(power_init);
+module_exit(power_exit);
+
+MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
+MODULE_DESCRIPTION("Input Power Management driver");
diff --git a/drivers/input/serio/Config.help b/drivers/input/serio/Config.help
index a82785414452..ae97e4223fc0 100644
--- a/drivers/input/serio/Config.help
+++ b/drivers/input/serio/Config.help
@@ -12,6 +12,18 @@ CONFIG_SERIO
The module will be called serio.o. If you want to compile it
as a module, say M here and read <file:Documentation/modules.txt>.
+CONFIG_SERIO_I8042
+ i8042 is the chip over which the standard AT keyboard and PS/2
+ mouse are connected to the computer. If you use these devices,
+ you'll need to say Y here.
+
+ If unsure, say Y.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called i8042.o. If you want to compile it
+ as a module, say M here and read <file:Documentation/modules.txt>.
+
CONFIG_SERIO_SERPORT
Say Y here if you plan to use an input device (mouse, joystick,
tablet, 6dof) that communicates over the RS232 serial (COM) port.
@@ -24,3 +36,38 @@ CONFIG_SERIO_SERPORT
inserted in and removed from the running kernel whenever you want).
The module will be called serport.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SERIO_CT82C710
+ Say Y here if you have a Texas Instruments TravelMate notebook
+ equipped with the ct82c710 chip and want to use a mouse connected
+ to the "QuickPort".
+
+ If unsure, say N.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called ct82c710.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SERIO_PARKBD
+ Say Y here if you built a simple parallel port adapter to attach
+ an additional AT keyboard, XT keyboard or PS/2 mouse.
+
+ More information is available: <file:Documentation/input/input.txt>
+
+ If unsure, say N.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called parkbd.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SERIO_ACORN
+ Say Y here if you have the Acorn RiscPC and want to use an AT
+ keyboard connected to its keyboard controller.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called rpckbd.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
diff --git a/drivers/input/serio/Config.in b/drivers/input/serio/Config.in
index cc566ad20586..e378e810c18e 100644
--- a/drivers/input/serio/Config.in
+++ b/drivers/input/serio/Config.in
@@ -4,4 +4,16 @@
tristate 'Serial i/o support' CONFIG_SERIO
+dep_tristate ' i8042 PC Keyboard controller' CONFIG_SERIO_I8042 $CONFIG_SERIO $CONFIG_ISA
+if [ "$CONFIG_SERIO_I8042" != "n" ]; then
+ hex ' Register Base Address' CONFIG_I8042_REG_BASE 60
+ int ' PS/2 Keyboard IRQ' CONFIG_I8042_KBD_IRQ 1
+ int ' PS/2 AUX IRQ' CONFIG_I8042_AUX_IRQ 12
+fi
dep_tristate ' Serial port line discipline' CONFIG_SERIO_SERPORT $CONFIG_SERIO
+dep_tristate ' ct82c710 Aux port controller' CONFIG_SERIO_CT82C710 $CONFIG_SERIO $CONFIG_ISA
+dep_tristate ' Parallel port keyboard adapter' CONFIG_SERIO_PARKBD $CONFIG_SERIO $CONFIG_PARPORT
+
+if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+ dep_tristate ' Acorn RiscPC keyboard controller' CONFIG_SERIO_ACORN $CONFIG_SERIO
+fi
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
index 5865d9be9059..8e8e036a0e17 100644
--- a/drivers/input/serio/Makefile
+++ b/drivers/input/serio/Makefile
@@ -9,7 +9,11 @@ export-objs := serio.o
# Each configuration option enables a list of files.
obj-$(CONFIG_SERIO) += serio.o
+obj-$(CONFIG_SERIO_I8042) += i8042.o
+obj-$(CONFIG_SERIO_PARKBD) += parkbd.o
obj-$(CONFIG_SERIO_SERPORT) += serport.o
+obj-$(CONFIG_SERIO_CT82C710) += ct82c710.o
+obj-$(CONFIG_SERIO_RPCKBD) += rpckbd.o
# The global Rules.make.
diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c
new file mode 100644
index 000000000000..8202a64606bb
--- /dev/null
+++ b/drivers/input/serio/ct82c710.c
@@ -0,0 +1,212 @@
+/*
+ * $Id: ct82c710.c,v 1.11 2001/09/25 10:12:07 vojtech Exp $
+ *
+ * Copyright (c) 1999-2001 Vojtech Pavlik
+ */
+
+/*
+ * 82C710 C&T mouse port chip 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/module.h>
+#include <linux/ioport.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/serio.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("82C710 C&T mouse port chip driver");
+MODULE_LICENSE("GPL");
+
+static char ct82c710_name[] = "C&T 82c710 mouse port";
+static char ct82c710_phys[16];
+
+/*
+ * ct82c710 interface
+ */
+
+#define CT82C710_DEV_IDLE 0x01 /* Device Idle */
+#define CT82C710_RX_FULL 0x02 /* Device Char received */
+#define CT82C710_TX_IDLE 0x04 /* Device XMIT Idle */
+#define CT82C710_RESET 0x08 /* Device Reset */
+#define CT82C710_INTS_ON 0x10 /* Device Interrupt On */
+#define CT82C710_ERROR_FLAG 0x20 /* Device Error */
+#define CT82C710_CLEAR 0x40 /* Device Clear */
+#define CT82C710_ENABLE 0x80 /* Device Enable */
+
+#define CT82C710_IRQ 12
+
+static int ct82c710_data = 0;
+static int ct82c710_status = 0;
+
+static void ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs);
+
+/*
+ * Wait for device to send output char and flush any input char.
+ */
+
+static int ct82c170_wait(void)
+{
+ int timeout = 60000;
+
+ while ((inb(ct82c710_status) & (CT82C710_RX_FULL | CT82C710_TX_IDLE | CT82C710_DEV_IDLE))
+ != (CT82C710_DEV_IDLE | CT82C710_TX_IDLE) && timeout) {
+
+ if (inb_p(ct82c710_status) & CT82C710_RX_FULL) inb_p(ct82c710_data);
+
+ udelay(1);
+ timeout--;
+ }
+
+ return !timeout;
+}
+
+static void ct82c710_close(struct serio *serio)
+{
+ if (ct82c170_wait())
+ printk(KERN_WARNING "ct82c710.c: Device busy in close()\n");
+
+ outb_p(inb_p(ct82c710_status) & ~(CT82C710_ENABLE | CT82C710_INTS_ON), ct82c710_status);
+
+ if (ct82c170_wait())
+ printk(KERN_WARNING "ct82c710.c: Device busy in close()\n");
+
+ free_irq(CT82C710_IRQ, NULL);
+}
+
+static int ct82c710_open(struct serio *serio)
+{
+ unsigned char status;
+
+ if (request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL))
+ return -1;
+
+ status = inb_p(ct82c710_status);
+
+ status |= (CT82C710_ENABLE | CT82C710_RESET);
+ outb_p(status, ct82c710_status);
+
+ status &= ~(CT82C710_RESET);
+ outb_p(status, ct82c710_status);
+
+ status |= CT82C710_INTS_ON;
+ outb_p(status, ct82c710_status); /* Enable interrupts */
+
+ while (ct82c170_wait()) {
+ printk(KERN_ERR "ct82c710: Device busy in open()\n");
+ status &= ~(CT82C710_ENABLE | CT82C710_INTS_ON);
+ outb_p(status, ct82c710_status);
+ free_irq(CT82C710_IRQ, NULL);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Write to the 82C710 mouse device.
+ */
+
+static int ct82c710_write(struct serio *port, unsigned char c)
+{
+ if (ct82c170_wait()) return -1;
+ outb_p(c, ct82c710_data);
+ return 0;
+}
+
+static struct serio ct82c710_port =
+{
+ type: SERIO_8042,
+ name: ct82c710_name,
+ phys: ct82c710_phys,
+ write: ct82c710_write,
+ open: ct82c710_open,
+ close: ct82c710_close,
+};
+
+/*
+ * Interrupt handler for the 82C710 mouse port. A character
+ * is waiting in the 82C710.
+ */
+
+static void ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
+{
+ if (ct82c710_port.dev)
+ ct82c710_port.dev->interrupt(&ct82c710_port, inb(ct82c710_data), 0);
+}
+
+/*
+ * See if we can find a 82C710 device. Read mouse address.
+ */
+
+static int __init ct82c710_probe(void)
+{
+ outb_p(0x55, 0x2fa); /* Any value except 9, ff or 36 */
+ outb_p(0xaa, 0x3fa); /* Inverse of 55 */
+ outb_p(0x36, 0x3fa); /* Address the chip */
+ outb_p(0xe4, 0x3fa); /* 390/4; 390 = config address */
+ outb_p(0x1b, 0x2fa); /* Inverse of e4 */
+ outb_p(0x0f, 0x390); /* Write index */
+ if (inb_p(0x391) != 0xe4) /* Config address found? */
+ return -1; /* No: no 82C710 here */
+
+ outb_p(0x0d, 0x390); /* Write index */
+ ct82c710_data = inb_p(0x391) << 2; /* Get mouse I/O address */
+ ct82c710_status = ct82c710_data + 1;
+ outb_p(0x0f, 0x390);
+ outb_p(0x0f, 0x391); /* Close config mode */
+
+ return 0;
+}
+
+int __init ct82c710_init(void)
+{
+ if (ct82c710_probe())
+ return -ENODEV;
+
+ if (request_region(ct82c710_data, 2, "ct82c710"))
+ return -EBUSY;
+
+ sprintf(ct82c710_phys, "isa%04x/serio0", ct82c710_data);
+
+ serio_register_port(&ct82c710_port);
+
+ printk(KERN_INFO "serio: C&T 82c710 mouse port at %#x irq %d\n",
+ ct82c710_data, CT82C710_IRQ);
+
+ return 0;
+}
+
+void __exit ct82c710_exit(void)
+{
+ serio_unregister_port(&ct82c710_port);
+ release_region(ct82c710_data, 2);
+}
+
+module_init(ct82c710_init);
+module_exit(ct82c710_exit);
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
new file mode 100644
index 000000000000..5e222b2f2e31
--- /dev/null
+++ b/drivers/input/serio/i8042.c
@@ -0,0 +1,717 @@
+/*
+ * $Id: i8042.c,v 1.21 2002/03/01 22:09:27 jsimmons Exp $
+ *
+ * Copyright (c) 1999-2001 Vojtech Pavlik
+ */
+
+/*
+ * i8042 keyboard and mouse 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 <asm/io.h>
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/config.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/serio.h>
+#include <linux/sched.h> /* request/free_irq */
+
+#include "i8042.h"
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("i8042 keyboard and mouse controller driver");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(i8042_noaux, "1i");
+MODULE_PARM(i8042_unlock, "1i");
+MODULE_PARM(i8042_reset, "1i");
+MODULE_PARM(i8042_direct, "1i");
+
+static int i8042_noaux;
+static int i8042_unlock;
+static int i8042_reset;
+static int i8042_direct;
+
+spinlock_t i8042_lock = SPIN_LOCK_UNLOCKED;
+
+struct i8042_values {
+ int irq;
+ unsigned char disable;
+ unsigned char irqen;
+ unsigned char exists;
+ unsigned char *name;
+ unsigned char *phys;
+};
+
+static struct serio i8042_kbd_port;
+static struct serio i8042_aux_port;
+static unsigned char i8042_initial_ctr;
+static unsigned char i8042_ctr;
+
+#ifdef I8042_DEBUG_IO
+static unsigned long i8042_start;
+#endif
+
+static unsigned long i8042_unxlate_seen[128 / BITS_PER_LONG];
+static unsigned char i8042_unxlate_table[128] = {
+ 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
+ 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
+ 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
+ 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
+ 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
+ 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
+ 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
+ 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
+};
+
+static void i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+/*
+ * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
+ * be ready for reading values from it / writing values to it.
+ */
+
+static int i8042_wait_read(void)
+{
+ int i = 0;
+ while ((~inb(I8042_STATUS_REG) & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) {
+ udelay(50);
+ i++;
+ }
+ return -(i == I8042_CTL_TIMEOUT);
+}
+
+static int i8042_wait_write(void)
+{
+ int i = 0;
+ while ((inb(I8042_STATUS_REG) & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) {
+ udelay(50);
+ i++;
+ }
+ return -(i == I8042_CTL_TIMEOUT);
+}
+
+/*
+ * i8042_flush() flushes all data that may be in the keyboard and mouse buffers
+ * of the i8042 down the toilet.
+ */
+
+static int i8042_flush(void)
+{
+ unsigned long flags;
+ int i = 0;
+
+ spin_lock_irqsave(&i8042_lock, flags);
+
+ while ((inb(I8042_STATUS_REG) & I8042_STR_OBF) && (i++ < I8042_BUFFER_SIZE))
+#ifdef I8042_DEBUG_IO
+ printk(KERN_DEBUG "i8042.c: %02x <- i8042 (flush) [%d]\n",
+ inb(I8042_DATA_REG), (int) (jiffies - i8042_start));
+#else
+ inb(I8042_DATA_REG);
+#endif
+
+ spin_unlock_irqrestore(&i8042_lock, flags);
+
+ return i;
+}
+
+/*
+ * i8042_command() executes a command on the i8042. It also sends the input parameter(s)
+ * of the commands to it, and receives the output value(s). The parameters are to be
+ * stored in the param array, and the output is placed into the same array. The number
+ * of the parameters and output values is encoded in bits 8-11 of the command
+ * number.
+ */
+
+static int i8042_command(unsigned char *param, int command)
+{
+ unsigned long flags;
+ int retval = 0, i = 0;
+
+ spin_lock_irqsave(&i8042_lock, flags);
+
+ retval = i8042_wait_write();
+ if (!retval) {
+#ifdef I8042_DEBUG_IO
+ printk(KERN_DEBUG "i8042.c: %02x -> i8042 (command) [%d]\n",
+ command & 0xff, (int) (jiffies - i8042_start));
+#endif
+ outb(command & 0xff, I8042_COMMAND_REG);
+ }
+
+ if (!retval)
+ for (i = 0; i < ((command >> 12) & 0xf); i++) {
+ if ((retval = i8042_wait_write())) break;
+#ifdef I8042_DEBUG_IO
+ printk(KERN_DEBUG "i8042.c: %02x -> i8042 (parameter) [%d]\n",
+ param[i], (int) (jiffies - i8042_start));
+#endif
+ outb(param[i], I8042_DATA_REG);
+ }
+
+ if (!retval)
+ for (i = 0; i < ((command >> 8) & 0xf); i++) {
+ if ((retval = i8042_wait_read())) break;
+ if (inb(I8042_STATUS_REG) & I8042_STR_AUXDATA)
+ param[i] = ~inb(I8042_DATA_REG);
+ else
+ param[i] = inb(I8042_DATA_REG);
+#ifdef I8042_DEBUG_IO
+ printk(KERN_DEBUG "i8042.c: %02x <- i8042 (return) [%d]\n",
+ param[i], (int) (jiffies - i8042_start));
+#endif
+ }
+
+ spin_unlock_irqrestore(&i8042_lock, flags);
+
+#ifdef I8042_DEBUG_IO
+ if (retval)
+ printk(KERN_DEBUG "i8042.c: -- i8042 (timeout) [%d]\n",
+ (int) (jiffies - i8042_start));
+#endif
+
+ return retval;
+}
+
+/*
+ * i8042_kbd_write() sends a byte out through the keyboard interface.
+ * It also automatically refreshes the CTR value, since some i8042's
+ * trash their CTR after attempting to send data to an nonexistent
+ * device.
+ */
+
+static int i8042_kbd_write(struct serio *port, unsigned char c)
+{
+ unsigned long flags;
+ int retval = 0;
+
+ spin_lock_irqsave(&i8042_lock, flags);
+
+ if(!(retval = i8042_wait_write())) {
+#ifdef I8042_DEBUG_IO
+ printk(KERN_DEBUG "i8042.c: %02x -> i8042 (kbd-data) [%d]\n",
+ c, (int) (jiffies - i8042_start));
+#endif
+ outb(c, I8042_DATA_REG);
+ }
+
+ spin_unlock_irqrestore(&i8042_lock, flags);
+
+ return retval;
+}
+
+/*
+ * i8042_aux_write() sends a byte out through the aux interface.
+ */
+
+static int i8042_aux_write(struct serio *port, unsigned char c)
+{
+ int retval;
+
+/*
+ * Send the byte out.
+ */
+
+ retval = i8042_command(&c, I8042_CMD_AUX_SEND);
+
+/*
+ * Here we restore the CTR value. I don't know why, but i8042's in half-AT
+ * mode tend to trash their CTR when doing the AUX_SEND command.
+ */
+
+ retval += i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR);
+
+/*
+ * Make sure the interrupt happens and the character is received even
+ * in the case the IRQ isn't wired, so that we can receive further
+ * characters later.
+ */
+
+ i8042_interrupt(0, port, NULL);
+ return retval;
+}
+
+/*
+ * i8042_open() is called when a port is open by the higher layer.
+ * It allocates an interrupt and enables the port.
+ */
+
+static int i8042_open(struct serio *port)
+{
+ struct i8042_values *values = port->driver;
+
+/*
+ * Allocate the interrupt
+ */
+
+ if (request_irq(values->irq, i8042_interrupt, 0, "i8042", NULL)) {
+ printk(KERN_ERR "i8042.c: Can't get irq %d for %s\n", values->irq, values->name);
+ return -1;
+ }
+
+/*
+ * Enable the device and its interrupt.
+ */
+
+ i8042_ctr |= values->irqen;
+ i8042_ctr &= ~values->disable;
+
+ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+ printk(KERN_ERR "i8042.c: Can't write CTR while opening %s.\n", values->name);
+ return -1;
+ }
+
+/*
+ * Flush buffers
+ */
+
+ i8042_flush();
+
+ return 0;
+}
+
+/*
+ * i8042_close() frees the interrupt, and disables the interface when the
+ * upper layer doesn't need it anymore.
+ */
+
+static void i8042_close(struct serio *port)
+{
+ struct i8042_values *values = port->driver;
+
+/*
+ * Disable the device and its interrupt.
+ */
+
+ i8042_ctr &= ~values->irqen;
+ i8042_ctr |= values->disable;
+
+ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+ printk(KERN_ERR "i8042.c: Can't write CTR while closing %s.\n", values->name);
+ return;
+ }
+
+/*
+ * Free the interrupt
+ */
+
+ free_irq(values->irq, NULL);
+}
+
+/*
+ * Structures for registering the devices in the serio.c module.
+ */
+
+static struct i8042_values i8042_kbd_values = {
+ irq: I8042_KBD_IRQ,
+ irqen: I8042_CTR_KBDINT,
+ disable: I8042_CTR_KBDDIS,
+ name: "KBD",
+ exists: 0,
+};
+
+static struct serio i8042_kbd_port =
+{
+ type: SERIO_8042,
+ write: i8042_kbd_write,
+ open: i8042_open,
+ close: i8042_close,
+ driver: &i8042_kbd_values,
+ name: "i8042 Kbd Port",
+ phys: "isa0060/serio0",
+};
+
+static struct i8042_values i8042_aux_values = {
+ irq: I8042_AUX_IRQ,
+ irqen: I8042_CTR_AUXINT,
+ disable: I8042_CTR_AUXDIS,
+ name: "AUX",
+ exists: 0,
+};
+
+static struct serio i8042_aux_port =
+{
+ type: SERIO_8042,
+ write: i8042_aux_write,
+ open: i8042_open,
+ close: i8042_close,
+ driver: &i8042_aux_values,
+ name: "i8042 Aux Port",
+ phys: "isa0060/serio1",
+};
+
+/*
+ * i8042_interrupt() is the most important function in this driver -
+ * it handles the interrupts from the i8042, and sends incoming bytes
+ * to the upper layers.
+ */
+
+static void i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned long flags;
+ unsigned char str, data;
+
+ spin_lock_irqsave(&i8042_lock, flags);
+
+ while ((str = inb(I8042_STATUS_REG)) & I8042_STR_OBF) {
+
+ data = inb(I8042_DATA_REG);
+
+#ifdef I8042_DEBUG_IO
+ printk(KERN_DEBUG "i8042.c: %02x <- i8042 (interrupt-%s) [%d]\n",
+ data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", (int) (jiffies - i8042_start));
+#endif
+
+ if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) {
+ if (i8042_aux_port.dev)
+ i8042_aux_port.dev->interrupt(&i8042_aux_port, data, 0);
+ } else {
+ if (i8042_kbd_values.exists && i8042_kbd_port.dev) {
+ if (!i8042_direct) {
+ if (data > 0x7f) {
+ if (test_and_clear_bit(data & 0x7f, i8042_unxlate_seen)) {
+ i8042_kbd_port.dev->interrupt(&i8042_kbd_port, 0xf0, 0);
+ data = i8042_unxlate_table[data & 0x7f];
+ }
+ } else {
+ set_bit(data, i8042_unxlate_seen);
+ data = i8042_unxlate_table[data];
+ }
+ }
+ i8042_kbd_port.dev->interrupt(&i8042_kbd_port, data, 0);
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&i8042_lock, flags);
+}
+
+/*
+ * i8042_controller init initializes the i8042 controller, and,
+ * most importantly, sets it into non-xlated mode.
+ */
+
+static int __init i8042_controller_init(void)
+{
+
+/*
+ * Check the i/o region before we touch it.
+ */
+#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__)
+ if (check_region(I8042_DATA_REG, 16)) {
+ printk(KERN_ERR "i8042.c: %#x port already in use!\n", I8042_DATA_REG);
+ return -1;
+ }
+#endif
+
+/*
+ * Test the i8042. We need to know if it thinks it's working correctly
+ * before doing anything else.
+ */
+
+ i8042_flush();
+
+ if (i8042_reset) {
+
+ unsigned char param;
+
+ if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
+ printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n");
+ return -1;
+ }
+
+ if (param != I8042_RET_CTL_TEST) {
+ printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n",
+ param, I8042_RET_CTL_TEST);
+ return -1;
+ }
+ }
+
+/*
+ * Read the CTR.
+ */
+
+ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) {
+ printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n");
+ return -1;
+ }
+
+/*
+ * Save the CTR for restoral on unload / reboot.
+ */
+
+ i8042_initial_ctr = i8042_ctr;
+
+/*
+ * Disable both interfaces and their interrupts.
+ */
+
+ i8042_ctr |= I8042_CTR_KBDDIS;
+ i8042_ctr &= ~I8042_CTR_KBDINT;
+
+/*
+ * Handle keylock.
+ */
+
+ if (~inb(I8042_STATUS_REG) & I8042_STR_KEYLOCK) {
+
+ if (i8042_unlock) {
+ i8042_ctr |= I8042_CTR_IGNKEYLOCK;
+ } else {
+ printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n");
+ }
+ }
+
+/*
+ * If the chip is configured into nontranslated mode by the BIOS, don't
+ * bother enabling translating and just use that happily.
+ */
+
+ if (~i8042_ctr & I8042_CTR_XLATE)
+ i8042_direct = 1;
+
+/*
+ * Set nontranslated mode for the kbd interface if requested by an option.
+ * This is vital for a working scancode set 3 support. After this the kbd
+ * interface becomes a simple serial in/out, like the aux interface is. If
+ * the user doesn't wish this, the driver tries to untranslate the values
+ * after the i8042 translates them.
+ */
+
+ if (i8042_direct)
+ i8042_ctr &= ~I8042_CTR_XLATE;
+
+/*
+ * Write CTR back.
+ */
+
+ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+ printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Here we try to reset everything back to a state in which the BIOS will be
+ * able to talk to the hardware when rebooting.
+ */
+
+void i8042_controller_cleanup(void)
+{
+
+/*
+ * Reset the controller.
+ */
+
+ if (i8042_reset) {
+ unsigned char param;
+
+ if (i8042_command(&param, I8042_CMD_CTL_TEST))
+ printk(KERN_ERR "i8042.c: i8042 controller reset timeout.\n");
+ }
+
+/*
+ * Restore the original control register setting.
+ */
+
+ i8042_ctr = i8042_initial_ctr;
+
+ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
+ printk(KERN_WARNING "i8042.c: Can't restore CTR.\n");
+
+/*
+ * Reset anything that is connected to the ports if the ports
+ * are enabled in the original config.
+ */
+
+ if (i8042_kbd_values.exists)
+ i8042_kbd_write(&i8042_kbd_port, 0xff);
+
+ if (i8042_aux_values.exists)
+ i8042_aux_write(&i8042_aux_port, 0xff);
+}
+
+/*
+ * i8042_check_aux() applies as much paranoia as it can at detecting
+ * the presence of an AUX interface.
+ */
+
+static int __init i8042_check_aux(struct i8042_values *values, struct serio *port)
+{
+ unsigned char param;
+
+ i8042_flush();
+
+/*
+ * Internal loopback test - filters out AT-type i8042's
+ */
+
+ param = 0x5a;
+
+ if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xa5)
+ return -1;
+
+/*
+ * External connection test - filters out AT-soldered PS/2 i8042's
+ */
+
+ if (i8042_command(&param, I8042_CMD_AUX_TEST) || param)
+ return -1;
+
+/*
+ * Bit assignment test - filters out PS/2 i8042's in AT mode
+ */
+
+ if (i8042_command(&param, I8042_CMD_AUX_DISABLE))
+ return -1;
+
+ if (i8042_command(&param, I8042_CMD_CTL_RCTR) || (~param & I8042_CTR_AUXDIS))
+ return -1;
+
+ if (i8042_command(&param, I8042_CMD_AUX_TEST) || param) {
+
+/*
+ * We've got an old AMI i8042 with 'Bad Cache' commands.
+ */
+
+ i8042_command(&param, I8042_CMD_AUX_ENABLE);
+ return -1;
+ }
+
+ if (i8042_command(&param, I8042_CMD_AUX_ENABLE))
+ return -1;
+
+ if (i8042_command(&param, I8042_CMD_CTL_RCTR) || (param & I8042_CTR_AUXDIS))
+ return -1;
+
+/*
+ * Disable the interface.
+ */
+
+ i8042_ctr |= I8042_CTR_AUXDIS;
+ i8042_ctr &= ~I8042_CTR_AUXINT;
+
+ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
+ return -1;
+
+ return 0;
+}
+
+/*
+ * i8042_port_register() marks the device as existing,
+ * registers it, and reports to the user.
+ */
+
+static int __init i8042_port_register(struct i8042_values *values, struct serio *port)
+{
+ values->exists = 1;
+ serio_register_port(port);
+ printk(KERN_INFO "serio: i8042 %s port at %#x,%#x irq %d\n",
+ values->name, I8042_DATA_REG, I8042_COMMAND_REG, values->irq);
+
+ return 0;
+}
+
+/*
+ * Module init and cleanup functions.
+ */
+
+void __init i8042_setup(char *str, int *ints)
+{
+ if (!strcmp(str, "i8042_reset=1"))
+ i8042_reset = 1;
+ if (!strcmp(str, "i8042_noaux=1"))
+ i8042_noaux = 1;
+ if (!strcmp(str, "i8042_unlock=1"))
+ i8042_unlock = 1;
+ if (!strcmp(str, "i8042_direct=1"))
+ i8042_direct = 1;
+}
+
+/*
+ * Reset the 8042 back to original mode.
+ */
+static int i8042_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ if (code==SYS_DOWN || code==SYS_HALT)
+ i8042_controller_cleanup();
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block i8042_notifier=
+{
+ i8042_notify_sys,
+ NULL,
+ 0
+};
+
+int __init i8042_init(void)
+{
+#ifdef I8042_DEBUG_IO
+ i8042_start = jiffies;
+#endif
+
+ if (i8042_controller_init())
+ return -ENODEV;
+
+ i8042_port_register(&i8042_kbd_values, &i8042_kbd_port);
+
+ if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values, &i8042_aux_port))
+ i8042_port_register(&i8042_aux_values, &i8042_aux_port);
+
+/*
+ * On ix86 platforms touching the i8042 data register region can do really
+ * bad things. Because of this the region is always reserved on ix86 boxes.
+ */
+#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__)
+ request_region(I8042_DATA_REG, 16, "i8042");
+#endif
+ register_reboot_notifier(&i8042_notifier);
+ return 0;
+}
+
+void __exit i8042_exit(void)
+{
+ unregister_reboot_notifier(&i8042_notifier);
+
+ if (i8042_kbd_values.exists)
+ serio_unregister_port(&i8042_kbd_port);
+
+ if (i8042_aux_values.exists)
+ serio_unregister_port(&i8042_aux_port);
+
+ i8042_controller_cleanup();
+#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__)
+ release_region(I8042_DATA_REG, 16);
+#endif
+}
+
+module_init(i8042_init);
+module_exit(i8042_exit);
diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h
new file mode 100644
index 000000000000..569f81942f50
--- /dev/null
+++ b/drivers/input/serio/i8042.h
@@ -0,0 +1,128 @@
+#ifndef _I8042_H
+#define _I8042_H
+
+/*
+ * $Id: i8042.h,v 1.6 2001/10/05 22:48:09 vojtech Exp $
+ *
+ * Copyright (c) 1999-2001 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
+ *
+ * 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
+ */
+
+/*
+ * If you want to reset your i8042 upon boot, define this.
+ */
+
+#undef I8042_RESET
+
+/*
+ * If you want to trace all the i/o the i8042 module does for
+ * debugging purposes, define this.
+ */
+
+#undef I8042_DEBUG_IO
+
+/*
+ * On most PC based systems the keyboard IRQ is 1.
+ */
+
+#define I8042_KBD_IRQ CONFIG_I8042_KBD_IRQ
+
+/*
+ * On most PC based systems the aux port IRQ is 12. There are exceptions,
+ * though. Unfortunately IRQ probing is not possible without touching
+ * the device attached to the port.
+ */
+
+#define I8042_AUX_IRQ CONFIG_I8042_AUX_IRQ
+
+/*
+ * This is in 50us units, the time we wait for the i8042 to react. This
+ * has to be long enough for the i8042 itself to timeout on sending a byte
+ * to a non-existent mouse.
+ */
+
+#define I8042_CTL_TIMEOUT 10000
+
+/*
+ * Register numbers.
+ */
+
+#define I8042_COMMAND_REG CONFIG_I8042_REG_BASE + 4
+#define I8042_STATUS_REG CONFIG_I8042_REG_BASE + 4
+#define I8042_DATA_REG CONFIG_I8042_REG_BASE
+
+/*
+ * Status register bits.
+ */
+
+#define I8042_STR_PARITY 0x80
+#define I8042_STR_TIMEOUT 0x40
+#define I8042_STR_AUXDATA 0x20
+#define I8042_STR_KEYLOCK 0x10
+#define I8042_STR_CMDDAT 0x08
+#define I8042_STR_IBF 0x02
+#define I8042_STR_OBF 0x01
+
+/*
+ * Control register bits.
+ */
+
+#define I8042_CTR_KBDINT 0x01
+#define I8042_CTR_AUXINT 0x02
+#define I8042_CTR_IGNKEYLOCK 0x08
+#define I8042_CTR_KBDDIS 0x10
+#define I8042_CTR_AUXDIS 0x20
+#define I8042_CTR_XLATE 0x40
+
+/*
+ * Commands.
+ */
+
+#define I8042_CMD_CTL_RCTR 0x0120
+#define I8042_CMD_CTL_WCTR 0x1060
+#define I8042_CMD_CTL_TEST 0x01aa
+
+#define I8042_CMD_KBD_DISABLE 0x00ad
+#define I8042_CMD_KBD_ENABLE 0x00ae
+#define I8042_CMD_KBD_TEST 0x01ab
+#define I8042_CMD_KBD_LOOP 0x11d2
+
+#define I8042_CMD_AUX_DISABLE 0x00a7
+#define I8042_CMD_AUX_ENABLE 0x00a8
+#define I8042_CMD_AUX_TEST 0x01a9
+#define I8042_CMD_AUX_SEND 0x10d4
+#define I8042_CMD_AUX_LOOP 0x11d3
+
+/*
+ * Return codes.
+ */
+
+#define I8042_RET_CTL_TEST 0x55
+
+/*
+ * Expected maximum internal i8042 buffer size. This is used for flushing
+ * the i8042 buffers. 32 should be more than enough.
+ */
+
+#define I8042_BUFFER_SIZE 32
+
+#endif /* _I8042_H */
diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c
new file mode 100644
index 000000000000..18e8c51256f4
--- /dev/null
+++ b/drivers/input/serio/parkbd.c
@@ -0,0 +1,203 @@
+/*
+ * $Id: parkbd.c,v 1.10 2002/03/13 10:09:20 vojtech Exp $
+ *
+ * Copyright (c) 1999-2001 Vojtech Pavlik
+ */
+
+/*
+ * Parallel port to Keyboard port adapter 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/parport.h>
+#include <linux/init.h>
+#include <linux/serio.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Parallel port to Keyboard port adapter driver");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(parkbd, "1i");
+MODULE_PARM(parkbd_mode, "1i");
+
+#define PARKBD_CLOCK 0x01 /* Strobe & Ack */
+#define PARKBD_DATA 0x02 /* AutoFd & Busy */
+
+static int parkbd = 0;
+static int parkbd_mode = SERIO_8042;
+
+static int parkbd_buffer = 0;
+static int parkbd_counter = 0;
+static int parkbd_last = 0;
+static int parkbd_writing = 0;
+static unsigned long parkbd_start = 0;
+
+static struct pardevice *parkbd_dev;
+
+static char parkbd_name[] = "PARKBD AT/XT keyboard adapter";
+static char parkbd_phys[32];
+
+static int parkbd_readlines(void)
+{
+ return (parport_read_status(parkbd_dev->port) >> 6) ^ 2;
+}
+
+static void parkbd_writelines(int data)
+{
+ parport_write_control(parkbd_dev->port, (~data & 3) | 0x10);
+}
+
+static int parkbd_write(struct serio *port, unsigned char c)
+{
+ unsigned char p;
+
+ if (!parkbd_mode) return -1;
+
+ p = c ^ (c >> 4);
+ p = p ^ (p >> 2);
+ p = p ^ (p >> 1);
+
+ parkbd_counter = 0;
+ parkbd_writing = 1;
+ parkbd_buffer = c | (((int) (~p & 1)) << 8) | 0x600;
+
+ parkbd_writelines(2);
+
+ return 0;
+}
+
+static int parkbd_open(struct serio *port)
+{
+ return 0;
+}
+
+static void parkbd_close(struct serio *port)
+{
+}
+
+static struct serio parkbd_port =
+{
+ write: parkbd_write,
+ open: parkbd_open,
+ close: parkbd_close,
+ name: parkbd_name,
+ phys: parkbd_phys,
+};
+
+static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+
+ if (parkbd_writing) {
+
+ if (parkbd_counter && ((parkbd_counter == 11) || time_after(jiffies, parkbd_last + HZ/100))) {
+ parkbd_counter = 0;
+ parkbd_buffer = 0;
+ parkbd_writing = 0;
+ parkbd_writelines(3);
+ return;
+ }
+
+ parkbd_writelines(((parkbd_buffer >> parkbd_counter++) & 1) | 2);
+
+ if (parkbd_counter == 11) {
+ parkbd_counter = 0;
+ parkbd_buffer = 0;
+ parkbd_writing = 0;
+ parkbd_writelines(3);
+ }
+
+ } else {
+
+ if ((parkbd_counter == parkbd_mode + 10) || time_after(jiffies, parkbd_last + HZ/100)) {
+ parkbd_counter = 0;
+ parkbd_buffer = 0;
+ }
+
+ parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++;
+
+ if (parkbd_counter == parkbd_mode + 10) {
+ if (parkbd_port.dev)
+ parkbd_port.dev->interrupt(&parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0);
+ }
+ }
+
+ parkbd_last = jiffies;
+}
+
+static int parkbd_getport(void)
+{
+ struct parport *pp;
+
+ if (parkbd < 0) {
+ printk(KERN_ERR "parkbd: no port specified\n");
+ return -ENODEV;
+ }
+
+ for (pp = parport_enumerate(); pp != NULL && (parkbd > 0); pp = pp->next) parkbd--;
+
+ if (pp == NULL) {
+ printk(KERN_ERR "parkbd: no such parport\n");
+ return -ENODEV;
+ }
+
+ parkbd_dev = parport_register_device(pp, "parkbd", NULL, NULL, parkbd_interrupt, PARPORT_DEV_EXCL, NULL);
+
+ if (!parkbd_dev)
+ return -ENODEV;
+
+ if (parport_claim(parkbd_dev)) {
+ parport_unregister_device(parkbd_dev);
+ return -EBUSY;
+ }
+
+ parkbd_start = jiffies;
+
+ return 0;
+}
+
+
+int __init parkbd_init(void)
+{
+ if (parkbd_getport()) return -1;
+ parkbd_writelines(3);
+ parkbd_port.type = parkbd_mode;
+
+ sprintf(parkbd_phys, "%s/serio0", parkbd_dev->port->name);
+
+ serio_register_port(&parkbd_port);
+
+ printk(KERN_INFO "serio: PARKBD %s adapter on %s\n",
+ parkbd_mode ? "AT" : "XT", parkbd_dev->port->name);
+
+ return 0;
+}
+
+void __exit parkbd_exit(void)
+{
+ parport_release(parkbd_dev);
+ serio_unregister_port(&parkbd_port);
+ parport_unregister_device(parkbd_dev);
+}
+
+module_init(parkbd_init);
+module_exit(parkbd_exit);
diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c
new file mode 100644
index 000000000000..a90879b13047
--- /dev/null
+++ b/drivers/input/serio/rpckbd.c
@@ -0,0 +1,117 @@
+/*
+ * $Id: rpckbd.c,v 1.7 2001/09/25 10:12:07 vojtech Exp $
+ *
+ * Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ * Based on the work of:
+ * unknown author
+ */
+
+/*
+ * Acorn RiscPC PS/2 keyboard controller driver for Linux/ARM
+ */
+
+/*
+ * 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/serio.h>
+
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/iomd.h>
+#include <asm/system.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver");
+MODULE_LICENSE("GPL");
+
+static inline void rpckbd_write(unsigned char val)
+{
+ while(!(inb(IOMD_KCTRL) & (1 << 7)));
+ outb(val, IOMD_KARTTX);
+}
+
+static struct serio rpckbd_port =
+{
+ type: SERIO_8042,
+ write: rpckbd_write,
+ name: "RiscPC PS/2 kbd port",
+ phys: "rpckbd/serio0",
+};
+
+static void rpckbd_rx(int irq, void *dev_id, struct pt_regs *regs)
+{
+ kbd_pt_regs = regs;
+
+ while (inb(IOMD_KCTRL) & (1 << 5))
+ if (rpckbd_port.dev)
+ rpckbd_port.dev->interrupt(&rpckbd_port, inb(IOMD_KARTRX), 0);
+
+}
+
+static void rpckbd_tx(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+static int __init rpckbd_init(void)
+{
+ unsigned long flags;
+
+ /* Reset the keyboard state machine. */
+ outb(0, IOMD_KCTRL);
+ outb(8, IOMD_KCTRL);
+
+ save_flags_cli(flags);
+
+ if (request_irq(IRQ_KEYBOARDRX, rpckbd_rx, 0, "rpckbd", NULL) != 0) {
+ printk(KERN_ERR "rpckbd.c: Could not allocate keyboard receive IRQ!\n")
+ return -EBUSY;
+ }
+
+ if (request_irq(IRQ_KEYBOARDTX, rpckbd_tx, 0, "rpckbd", NULL) != 0) {
+ printk(KERN_ERR "rpckbd.c: Could not allocate keyboard transmit IRQ!\n")
+ free_irq(IRQ_KEYBOARDRX, NULL);
+ return -EBUSY;
+ }
+
+ disable_irq(IRQ_KEYBOARDTX);
+ (void)IOMD_KARTRX;
+
+ restore_flags(flags);
+
+ register_serio_port(&rpckbd_port);
+ printk(KERN_INFO "serio: RiscPC PS/2 kbd port irq %d %d\n", IRQ_KEYBOARDRX, IRQ_KEYBOARDTX);
+
+ return 0;
+}
+
+static void __exit rpckbd_exit(void)
+{
+ free_irq(IRQ_KEYBOARDRX, NULL);
+ free_irq(IRQ_KEYBOARDTX, NULL);
+
+ unregister_serio_port(&rpckbd_port);
+}
+
+module_init(rpckbd_init);
+module_exit(rpckbd_exit);
diff --git a/drivers/input/touchscreen/Config.help b/drivers/input/touchscreen/Config.help
new file mode 100644
index 000000000000..d31ba3326e0a
--- /dev/null
+++ b/drivers/input/touchscreen/Config.help
@@ -0,0 +1,16 @@
+CONFIG_INPUT_TOUCHSCREEN
+ Say Y here, and a list of supported touchscreens will be displayed.
+ This option doesn't affect the kernel.
+
+ If unsure, say Y.
+
+CONFIG_TOUCHSCREEN_GUNZE
+ Say Y here if you have the Gunze AHL-51 touchscreen connected to
+ your system.
+
+ If unsure, say N.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called gunze.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
diff --git a/drivers/input/touchscreen/Config.in b/drivers/input/touchscreen/Config.in
new file mode 100644
index 000000000000..f48cbd5e2371
--- /dev/null
+++ b/drivers/input/touchscreen/Config.in
@@ -0,0 +1,7 @@
+#
+# Mouse driver configuration
+#
+
+bool 'Touchscreens' CONFIG_INPUT_TOUCHSCREEN
+
+dep_tristate ' Gunze AHL-51S touchscreen' CONFIG_TOUCHSCREEN_GUNZE $CONFIG_INPUT $CONFIG_INPUT_TOUCHSCREEN $CONFIG_SERIO
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
new file mode 100644
index 000000000000..d36ec4de1b15
--- /dev/null
+++ b/drivers/input/touchscreen/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the mouse drivers.
+#
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c
new file mode 100644
index 000000000000..8ea3050692e9
--- /dev/null
+++ b/drivers/input/touchscreen/gunze.c
@@ -0,0 +1,178 @@
+/*
+ * $Id: gunze.c,v 1.12 2001/09/25 10:12:07 vojtech Exp $
+ *
+ * Copyright (c) 2000-2001 Vojtech Pavlik
+ */
+
+/*
+ * Gunze AHL-51S touchscreen 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/errno.h>
+#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_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_DESCRIPTION("Gunze AHL-51S touchscreen driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define GUNZE_MAX_LENGTH 10
+
+static char *gunze_name = "Gunze AHL-51S TouchScreen";
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct gunze {
+ struct input_dev dev;
+ struct serio *serio;
+ int idx;
+ unsigned char data[GUNZE_MAX_LENGTH];
+ char phys[32];
+};
+
+static void gunze_process_packet(struct gunze* gunze)
+{
+ struct input_dev *dev = &gunze->dev;
+
+ if (gunze->idx != GUNZE_MAX_LENGTH || gunze->data[5] != ',' ||
+ (gunze->data[0] != 'T' && gunze->data[0] != 'R')) {
+ gunze->data[10] = 0;
+ printk(KERN_WARNING "gunze.c: bad packet: >%s<\n", gunze->data);
+ return;
+ }
+
+ input_report_abs(dev, ABS_X, simple_strtoul(gunze->data + 1, NULL, 10) * 4);
+ input_report_abs(dev, ABS_Y, 3072 - simple_strtoul(gunze->data + 6, NULL, 10) * 3);
+ input_report_key(dev, BTN_TOUCH, gunze->data[0] == 'T');
+}
+
+static void gunze_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+ struct gunze* gunze = serio->private;
+
+ if (data == '\r') {
+ gunze_process_packet(gunze);
+ gunze->idx = 0;
+ } else {
+ if (gunze->idx < GUNZE_MAX_LENGTH)
+ gunze->data[gunze->idx++] = data;
+ }
+}
+
+/*
+ * gunze_disconnect() is the opposite of gunze_connect()
+ */
+
+static void gunze_disconnect(struct serio *serio)
+{
+ struct gunze* gunze = serio->private;
+ input_unregister_device(&gunze->dev);
+ serio_close(serio);
+ kfree(gunze);
+}
+
+/*
+ * gunze_connect() is the routine that is called when someone adds a
+ * new serio device. It looks whether it was registered as a Gunze touchscreen
+ * and if yes, registers it as an input device.
+ */
+
+static void gunze_connect(struct serio *serio, struct serio_dev *dev)
+{
+ struct gunze *gunze;
+
+ if (serio->type != (SERIO_RS232 | SERIO_GUNZE))
+ return;
+
+ if (!(gunze = kmalloc(sizeof(struct gunze), GFP_KERNEL)))
+ return;
+
+ memset(gunze, 0, sizeof(struct gunze));
+
+ gunze->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ gunze->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+ gunze->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
+ gunze->dev.absmin[ABS_X] = 96; gunze->dev.absmin[ABS_Y] = 72;
+ gunze->dev.absmax[ABS_X] = 4000; gunze->dev.absmax[ABS_Y] = 3000;
+
+ gunze->serio = serio;
+ serio->private = gunze;
+
+ sprintf(gunze->phys, "%s/input0", serio->phys);
+
+ gunze->dev.private = gunze;
+ gunze->dev.name = gunze_name;
+ gunze->dev.phys = gunze->phys;
+ gunze->dev.idbus = BUS_RS232;
+ gunze->dev.idvendor = SERIO_GUNZE;
+ gunze->dev.idproduct = 0x0051;
+ gunze->dev.idversion = 0x0100;
+
+ if (serio_open(serio, dev)) {
+ kfree(gunze);
+ return;
+ }
+
+ input_register_device(&gunze->dev);
+
+ printk(KERN_INFO "input: %s on %s\n", gunze_name, serio->phys);
+}
+
+/*
+ * The serio device structure.
+ */
+
+static struct serio_dev gunze_dev = {
+ interrupt: gunze_interrupt,
+ connect: gunze_connect,
+ disconnect: gunze_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+int __init gunze_init(void)
+{
+ serio_register_device(&gunze_dev);
+ return 0;
+}
+
+void __exit gunze_exit(void)
+{
+ serio_unregister_device(&gunze_dev);
+}
+
+module_init(gunze_init);
+module_exit(gunze_exit);
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c
new file mode 100644
index 000000000000..50d238711aab
--- /dev/null
+++ b/drivers/input/tsdev.c
@@ -0,0 +1,443 @@
+/*
+ * $Id: tsdev.c,v 1.15 2002/04/10 16:50:19 jsimmons Exp $
+ *
+ * Copyright (c) 2001 "Crazy" james Simmons
+ *
+ * Input driver to Touchscreen device driver module.
+ *
+ * Sponsored by Transvirtual Technology
+ */
+
+/*
+ * 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 <jsimmons@transvirtual.com>.
+ */
+
+#define TSDEV_MINOR_BASE 128
+#define TSDEV_MINORS 32
+#define TSDEV_BUFFER_SIZE 64
+
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/config.h>
+#include <linux/smp_lock.h>
+#include <linux/random.h>
+#include <linux/time.h>
+
+#ifndef CONFIG_INPUT_TSDEV_SCREEN_X
+#define CONFIG_INPUT_TSDEV_SCREEN_X 240
+#endif
+#ifndef CONFIG_INPUT_TSDEV_SCREEN_Y
+#define CONFIG_INPUT_TSDEV_SCREEN_Y 320
+#endif
+
+struct tsdev {
+ int exist;
+ int open;
+ int minor;
+ char name[16];
+ wait_queue_head_t wait;
+ struct tsdev_list *list;
+ struct input_handle handle;
+ devfs_handle_t devfs;
+};
+
+/* From Compaq's Touch Screen Specification version 0.2 (draft) */
+typedef struct {
+ short pressure;
+ short x;
+ short y;
+ short millisecs;
+} TS_EVENT;
+
+struct tsdev_list {
+ struct fasync_struct *fasync;
+ struct tsdev_list *next;
+ struct tsdev *tsdev;
+ int head, tail;
+ int oldx, oldy, pendown;
+ TS_EVENT event[TSDEV_BUFFER_SIZE];
+};
+
+static struct input_handler tsdev_handler;
+
+static struct tsdev *tsdev_table[TSDEV_MINORS];
+
+static int xres = CONFIG_INPUT_TSDEV_SCREEN_X;
+static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y;
+
+static int tsdev_fasync(int fd, struct file *file, int on)
+{
+ struct tsdev_list *list = file->private_data;
+ int retval;
+
+ retval = fasync_helper(fd, file, on, &list->fasync);
+ return retval < 0 ? retval : 0;
+}
+
+static int tsdev_open(struct inode *inode, struct file *file)
+{
+ int i = minor(inode->i_rdev) - TSDEV_MINOR_BASE;
+ struct tsdev_list *list;
+
+ if (i >= TSDEV_MINORS || !tsdev_table[i])
+ return -ENODEV;
+
+ if (!(list = kmalloc(sizeof(struct tsdev_list), GFP_KERNEL)))
+ return -ENOMEM;
+ memset(list, 0, sizeof(struct tsdev_list));
+
+ list->tsdev = tsdev_table[i];
+ list->next = tsdev_table[i]->list;
+ tsdev_table[i]->list = list;
+ file->private_data = list;
+
+ if (!list->tsdev->open++)
+ if (list->tsdev->exist)
+ input_open_device(&list->tsdev->handle);
+ return 0;
+}
+
+static int tsdev_release(struct inode *inode, struct file *file)
+{
+ struct tsdev_list *list = file->private_data;
+ struct tsdev_list **listptr;
+
+ listptr = &list->tsdev->list;
+ tsdev_fasync(-1, file, 0);
+
+ while (*listptr && (*listptr != list))
+ listptr = &((*listptr)->next);
+ *listptr = (*listptr)->next;
+
+ if (!--list->tsdev->open) {
+ if (list->tsdev->exist) {
+ input_close_device(&list->tsdev->handle);
+ } else {
+ input_unregister_minor(list->tsdev->devfs);
+ tsdev_table[list->tsdev->minor] = NULL;
+ kfree(list->tsdev);
+ }
+ }
+ kfree(list);
+ return 0;
+}
+
+static ssize_t tsdev_read(struct file *file, char *buffer, size_t count,
+ loff_t * ppos)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct tsdev_list *list = file->private_data;
+ int retval = 0;
+
+ if (list->head == list->tail) {
+ add_wait_queue(&list->tsdev->wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ while (list->head == list->tail) {
+ if (!list->tsdev->exist) {
+ retval = -ENODEV;
+ break;
+ }
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ break;
+ }
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&list->tsdev->wait, &wait);
+ }
+
+ if (retval)
+ return retval;
+
+ while (list->head != list->tail
+ && retval + sizeof(TS_EVENT) <= count) {
+ if (copy_to_user
+ (buffer + retval, list->event + list->tail,
+ sizeof(TS_EVENT)))
+ return -EFAULT;
+ list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
+ retval += sizeof(TS_EVENT);
+ }
+ return retval;
+}
+
+/* No kernel lock - fine */
+static unsigned int tsdev_poll(struct file *file, poll_table * wait)
+{
+ struct tsdev_list *list = file->private_data;
+
+ poll_wait(file, &list->tsdev->wait, wait);
+ if (list->head != list->tail)
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+static int tsdev_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+/*
+ struct tsdev_list *list = file->private_data;
+ struct tsdev *evdev = list->tsdev;
+ struct input_dev *dev = tsdev->handle.dev;
+ int retval;
+
+ switch (cmd) {
+ case HHEHE:
+ return 0;
+ case hjff:
+ return 0;
+ default:
+ return 0;
+ }
+*/
+ return -EINVAL;
+}
+
+struct file_operations tsdev_fops = {
+ owner: THIS_MODULE,
+ open: tsdev_open,
+ release: tsdev_release,
+ read: tsdev_read,
+ poll: tsdev_poll,
+ fasync: tsdev_fasync,
+ ioctl: tsdev_ioctl,
+};
+
+static void tsdev_event(struct input_handle *handle, unsigned int type,
+ unsigned int code, int value)
+{
+ struct tsdev *tsdev = handle->private;
+ struct tsdev_list *list = tsdev->list;
+ struct timeval time;
+ int size;
+
+ while (list) {
+ switch (type) {
+ case EV_ABS:
+ switch (code) {
+ case ABS_X:
+ if (!list->pendown)
+ return;
+
+ size =
+ handle->dev->absmax[ABS_X] -
+ handle->dev->absmin[ABS_X];
+ if (size > 0)
+ list->oldx =
+ ((value -
+ handle->dev->absmin[ABS_X]) *
+ xres / size);
+ else
+ list->oldx =
+ ((value -
+ handle->dev->absmin[ABS_X]));
+ break;
+ case ABS_Y:
+ if (!list->pendown)
+ return;
+
+ size =
+ handle->dev->absmax[ABS_Y] -
+ handle->dev->absmin[ABS_Y];
+ if (size > 0)
+ list->oldy =
+ ((value -
+ handle->dev->absmin[ABS_Y]) *
+ yres / size);
+ else
+ list->oldy =
+ ((value -
+ handle->dev->absmin[ABS_Y]));
+ break;
+ case ABS_PRESSURE:
+ list->pendown =
+ ((value >
+ handle->dev->
+ absmin[ABS_PRESSURE])) ? value -
+ handle->dev->absmin[ABS_PRESSURE] : 0;
+ break;
+ }
+ break;
+
+ case EV_REL:
+ switch (code) {
+ case REL_X:
+ if (!list->pendown)
+ return;
+
+ list->oldx += value;
+ if (list->oldx < 0)
+ list->oldx = 0;
+ else if (list->oldx > xres)
+ list->oldx = xres;
+ break;
+ case REL_Y:
+ if (!list->pendown)
+ return;
+
+ list->oldy += value;
+ if (list->oldy < 0)
+ list->oldy = 0;
+ else if (list->oldy > xres)
+ list->oldy = xres;
+ break;
+ }
+ break;
+
+ case EV_KEY:
+ if (code == BTN_TOUCH || code == BTN_MOUSE) {
+ switch (value) {
+ case 0:
+ list->pendown = 0;
+ break;
+ case 1:
+ if (!list->pendown)
+ list->pendown = 1;
+ break;
+ case 2:
+ return;
+ }
+ } else
+ return;
+ break;
+ }
+ do_gettimeofday(&time);
+ list->event[list->head].millisecs = time.tv_usec / 100;
+ list->event[list->head].pressure = list->pendown;
+ list->event[list->head].x = list->oldx;
+ list->event[list->head].y = list->oldy;
+ list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1);
+ kill_fasync(&list->fasync, SIGIO, POLL_IN);
+ list = list->next;
+ }
+ wake_up_interruptible(&tsdev->wait);
+}
+
+static struct input_handle *tsdev_connect(struct input_handler *handler,
+ struct input_dev *dev,
+ struct input_device_id *id)
+{
+ struct tsdev *tsdev;
+ int minor;
+
+ for (minor = 0; minor < TSDEV_MINORS && tsdev_table[minor];
+ minor++);
+ if (minor == TSDEV_MINORS) {
+ printk(KERN_ERR
+ "tsdev: You have way too many touchscreens\n");
+ return NULL;
+ }
+
+ if (!(tsdev = kmalloc(sizeof(struct tsdev), GFP_KERNEL)))
+ return NULL;
+ memset(tsdev, 0, sizeof(struct tsdev));
+ init_waitqueue_head(&tsdev->wait);
+
+ tsdev->minor = minor;
+ tsdev_table[minor] = tsdev;
+ sprintf(tsdev->name, "ts%d", minor);
+
+ tsdev->handle.dev = dev;
+ tsdev->handle.name = tsdev->name;
+ tsdev->handle.handler = handler;
+ tsdev->handle.private = tsdev;
+
+ tsdev->devfs =
+ input_register_minor("ts%d", minor, TSDEV_MINOR_BASE);
+
+ tsdev->exist = 1;
+
+ return &tsdev->handle;
+}
+
+static void tsdev_disconnect(struct input_handle *handle)
+{
+ struct tsdev *tsdev = handle->private;
+
+ tsdev->exist = 0;
+
+ if (tsdev->open) {
+ input_close_device(handle);
+ wake_up_interruptible(&tsdev->wait);
+ } else {
+ input_unregister_minor(tsdev->devfs);
+ tsdev_table[tsdev->minor] = NULL;
+ kfree(tsdev);
+ }
+}
+
+static struct input_device_id tsdev_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_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 */
+
+ {},/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(input, tsdev_ids);
+
+static struct input_handler tsdev_handler = {
+ event: tsdev_event,
+ connect: tsdev_connect,
+ disconnect: tsdev_disconnect,
+ fops: &tsdev_fops,
+ minor: TSDEV_MINOR_BASE,
+ name: "tsdev",
+ id_table: tsdev_ids,
+};
+
+static int __init tsdev_init(void)
+{
+ input_register_handler(&tsdev_handler);
+ printk(KERN_INFO "ts: Compaq touchscreen protocol output\n");
+ return 0;
+}
+
+static void __exit tsdev_exit(void)
+{
+ input_unregister_handler(&tsdev_handler);
+}
+
+module_init(tsdev_init);
+module_exit(tsdev_exit);
+
+MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
+MODULE_DESCRIPTION("Input driver to touchscreen converter");
+MODULE_PARM(xres, "i");
+MODULE_PARM_DESC(xres, "Horizontal screen resolution");
+MODULE_PARM(yres, "i");
+MODULE_PARM_DESC(yres, "Vertical screen resolution");
diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c
index 5021b597997d..baf4b52dfe61 100644
--- a/drivers/isdn/capi/capifs.c
+++ b/drivers/isdn/capi/capifs.c
@@ -221,11 +221,9 @@ static void capifs_put_super(struct super_block *sb)
kfree(sbi);
}
-static int capifs_statfs(struct super_block *sb, struct statfs *buf);
-
static struct super_operations capifs_sops = {
put_super: capifs_put_super,
- statfs: capifs_statfs,
+ statfs: simple_statfs,
};
static int capifs_parse_options(char *options, struct capifs_sb_info *sbi)
@@ -354,19 +352,6 @@ fail:
return -EINVAL;
}
-static int capifs_statfs(struct super_block *sb, struct statfs *buf)
-{
- buf->f_type = CAPIFS_SUPER_MAGIC;
- buf->f_bsize = 1024;
- buf->f_blocks = 0;
- buf->f_bfree = 0;
- buf->f_bavail = 0;
- buf->f_files = 0;
- buf->f_ffree = 0;
- buf->f_namelen = NAME_MAX;
- return 0;
-}
-
static struct inode *capifs_new_inode(struct super_block *sb)
{
struct inode *inode = new_inode(sb);
diff --git a/drivers/message/fusion/Makefile b/drivers/message/fusion/Makefile
index c5298d750522..538032badea0 100644
--- a/drivers/message/fusion/Makefile
+++ b/drivers/message/fusion/Makefile
@@ -51,9 +51,3 @@ obj-$(CONFIG_FUSION_CTL) += mptctl.o
obj-$(CONFIG_FUSION_LAN) += mptlan.o
include $(TOPDIR)/Rules.make
-
-
-# EXP...
-## Fusion MPT extra's...
-##mptscsih.o: $(mptscsih-objs)
-## $(LD) -r -o $@ $(mptscsih-objs)
diff --git a/drivers/net/hamradio/soundmodem/Makefile b/drivers/net/hamradio/soundmodem/Makefile
index 4698281fdeb3..a3fe3f4e61cd 100644
--- a/drivers/net/hamradio/soundmodem/Makefile
+++ b/drivers/net/hamradio/soundmodem/Makefile
@@ -32,5 +32,5 @@ $(obj)/sm_hapn4800.o: $(obj)/sm_tbl_hapn4800.h
$(obj)/sm_fsk9600.o: $(obj)/sm_tbl_fsk9600.h
$(obj)/sm_tbl_%: $(obj)/gentbl
- $<
+ $(obj)/gentbl
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index ad14e1ba25f7..be8f9cee7e88 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -596,6 +596,7 @@ ips_setup(char *ips_str, int *dummy) {
}
return (1);
+}
__setup("ips=", ips_setup);
@@ -632,11 +633,10 @@ __setup("ips=", ips_setup);
}
}
}
+}
#endif
-}
-
/****************************************************************************/
/* */
/* Routine Name: ips_detect */
diff --git a/drivers/tc/Makefile b/drivers/tc/Makefile
index 9ba601d0984b..c7f242db75cc 100644
--- a/drivers/tc/Makefile
+++ b/drivers/tc/Makefile
@@ -15,5 +15,16 @@ obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o
include $(TOPDIR)/Rules.make
-$(obj)/lk201-map.c: $(src)/lk201-map.map
+$(obj)/lk201-map.o: $(obj)/lk201-map.c
+
+# Uncomment if you're changing the keymap and have an appropriate
+# loadkeys version for the map. By default, we'll use the shipped
+# versions.
+# GENERATE_KEYMAP := 1
+
+ifdef GENERATE_KEYMAP
+
+$(obj)/lk201-map.c: $(obj)/%.c: $(src)/%.map
loadkeys --mktable $< > $@
+
+endif
diff --git a/drivers/tc/lk201-map.c_shipped b/drivers/tc/lk201-map.c_shipped
new file mode 100644
index 000000000000..a9df8f5bf62b
--- /dev/null
+++ b/drivers/tc/lk201-map.c_shipped
@@ -0,0 +1,265 @@
+
+/* Do not edit this file! It was automatically generated by */
+/* loadkeys --mktable defkeymap.map > defkeymap.c */
+
+#include <linux/types.h>
+#include <linux/keyboard.h>
+#include <linux/kd.h>
+
+u_short plain_map[NR_KEYS] = {
+ 0xf200, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106,
+ 0xf107, 0xf108, 0xf109, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf11b,
+ 0xf11c, 0xf110, 0xf111, 0xf112, 0xf113, 0xf060, 0xf031, 0xf032,
+ 0xf033, 0xf034, 0xf035, 0xf036, 0xf037, 0xf038, 0xf039, 0xf030,
+ 0xf02d, 0xf03d, 0xf07f, 0xf114, 0xf115, 0xf116, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf009, 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74,
+ 0xfb79, 0xfb75, 0xfb69, 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201,
+ 0xf117, 0xf118, 0xf119, 0xf307, 0xf308, 0xf309, 0xf30b, 0xf702,
+ 0xf207, 0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a,
+ 0xfb6b, 0xfb6c, 0xf03b, 0xf027, 0xf05c, 0xf603, 0xf304, 0xf305,
+ 0xf306, 0xf200, 0xf700, 0xf03e, 0xfb7a, 0xfb78, 0xfb63, 0xfb76,
+ 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf200, 0xf601,
+ 0xf600, 0xf602, 0xf301, 0xf302, 0xf303, 0xf30e, 0xf200, 0xf703,
+ 0xf020, 0xf200, 0xf200, 0xf300, 0xf310, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+static u_short shift_map[NR_KEYS] = {
+ 0xf200, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106,
+ 0xf107, 0xf108, 0xf109, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf203,
+ 0xf11c, 0xf110, 0xf111, 0xf112, 0xf113, 0xf07e, 0xf021, 0xf040,
+ 0xf023, 0xf024, 0xf025, 0xf05e, 0xf026, 0xf02a, 0xf028, 0xf029,
+ 0xf05f, 0xf02b, 0xf07f, 0xf114, 0xf115, 0xf116, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf009, 0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54,
+ 0xfb59, 0xfb55, 0xfb49, 0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf201,
+ 0xf117, 0xf20b, 0xf20a, 0xf307, 0xf308, 0xf309, 0xf30b, 0xf702,
+ 0xf207, 0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a,
+ 0xfb4b, 0xfb4c, 0xf03a, 0xf022, 0xf07c, 0xf603, 0xf304, 0xf305,
+ 0xf306, 0xf200, 0xf700, 0xf03c, 0xfb5a, 0xfb58, 0xfb43, 0xfb56,
+ 0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, 0xf200, 0xf601,
+ 0xf600, 0xf602, 0xf301, 0xf302, 0xf303, 0xf30e, 0xf200, 0xf703,
+ 0xf020, 0xf200, 0xf200, 0xf300, 0xf310, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+static u_short altgr_map[NR_KEYS] = {
+ 0xf200, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106,
+ 0xf107, 0xf108, 0xf109, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf202,
+ 0xf11c, 0xf110, 0xf111, 0xf112, 0xf113, 0xf200, 0xf200, 0xf040,
+ 0xf200, 0xf024, 0xf200, 0xf200, 0xf07b, 0xf05b, 0xf05d, 0xf07d,
+ 0xf05c, 0xf200, 0xf200, 0xf114, 0xf115, 0xf116, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xfb71, 0xfb77, 0xf918, 0xfb72, 0xfb74,
+ 0xfb79, 0xfb75, 0xfb69, 0xfb6f, 0xfb70, 0xf200, 0xf07e, 0xf201,
+ 0xf117, 0xf118, 0xf119, 0xf911, 0xf912, 0xf913, 0xf30b, 0xf702,
+ 0xf207, 0xf914, 0xfb73, 0xf917, 0xf919, 0xfb67, 0xfb68, 0xfb6a,
+ 0xfb6b, 0xfb6c, 0xf200, 0xf200, 0xf200, 0xf603, 0xf90e, 0xf90f,
+ 0xf910, 0xf200, 0xf700, 0xf200, 0xfb7a, 0xfb78, 0xf916, 0xfb76,
+ 0xf915, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200, 0xf200, 0xf601,
+ 0xf600, 0xf602, 0xf90b, 0xf90c, 0xf90d, 0xf30e, 0xf200, 0xf703,
+ 0xf200, 0xf200, 0xf200, 0xf90a, 0xf310, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+static u_short ctrl_map[NR_KEYS] = {
+ 0xf200, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106,
+ 0xf107, 0xf108, 0xf109, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf204,
+ 0xf11c, 0xf110, 0xf111, 0xf112, 0xf113, 0xf81b, 0xf200, 0xf000,
+ 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f, 0xf07f, 0xf200, 0xf200,
+ 0xf01f, 0xf200, 0xf008, 0xf114, 0xf115, 0xf116, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf011, 0xf017, 0xf005, 0xf012, 0xf014,
+ 0xf019, 0xf015, 0xf009, 0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf201,
+ 0xf117, 0xf118, 0xf119, 0xf307, 0xf308, 0xf309, 0xf30b, 0xf702,
+ 0xf207, 0xf001, 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a,
+ 0xf00b, 0xf00c, 0xf200, 0xf007, 0xf01c, 0xf603, 0xf304, 0xf305,
+ 0xf306, 0xf200, 0xf700, 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016,
+ 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf20e, 0xf07f, 0xf200, 0xf601,
+ 0xf600, 0xf602, 0xf301, 0xf302, 0xf303, 0xf30e, 0xf200, 0xf703,
+ 0xf000, 0xf200, 0xf200, 0xf300, 0xf310, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+static u_short shift_ctrl_map[NR_KEYS] = {
+ 0xf200, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106,
+ 0xf107, 0xf108, 0xf109, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf200,
+ 0xf11c, 0xf110, 0xf111, 0xf112, 0xf113, 0xf200, 0xf200, 0xf000,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf01f, 0xf200, 0xf200, 0xf114, 0xf115, 0xf116, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf011, 0xf017, 0xf005, 0xf012, 0xf014,
+ 0xf019, 0xf015, 0xf009, 0xf00f, 0xf010, 0xf200, 0xf200, 0xf201,
+ 0xf117, 0xf118, 0xf119, 0xf307, 0xf308, 0xf309, 0xf30b, 0xf702,
+ 0xf207, 0xf001, 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a,
+ 0xf00b, 0xf00c, 0xf200, 0xf200, 0xf200, 0xf603, 0xf304, 0xf305,
+ 0xf306, 0xf200, 0xf700, 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016,
+ 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, 0xf200, 0xf601,
+ 0xf600, 0xf602, 0xf301, 0xf302, 0xf303, 0xf30e, 0xf200, 0xf703,
+ 0xf200, 0xf200, 0xf200, 0xf300, 0xf310, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+static u_short alt_map[NR_KEYS] = {
+ 0xf200, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506,
+ 0xf507, 0xf508, 0xf509, 0xf50a, 0xf50b, 0xf50c, 0xf50d, 0xf200,
+ 0xf11c, 0xf510, 0xf511, 0xf512, 0xf513, 0xf01b, 0xf831, 0xf832,
+ 0xf833, 0xf834, 0xf835, 0xf836, 0xf837, 0xf838, 0xf839, 0xf830,
+ 0xf82d, 0xf83d, 0xf87f, 0xf114, 0xf115, 0xf116, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf809, 0xf871, 0xf877, 0xf865, 0xf872, 0xf874,
+ 0xf879, 0xf875, 0xf869, 0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf80d,
+ 0xf117, 0xf118, 0xf119, 0xf907, 0xf908, 0xf909, 0xf30b, 0xf702,
+ 0xf207, 0xf861, 0xf873, 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a,
+ 0xf86b, 0xf86c, 0xf83b, 0xf827, 0xf85c, 0xf603, 0xf904, 0xf905,
+ 0xf906, 0xf200, 0xf700, 0xf200, 0xf87a, 0xf878, 0xf863, 0xf876,
+ 0xf862, 0xf86e, 0xf86d, 0xf82c, 0xf82e, 0xf82f, 0xf200, 0xf210,
+ 0xf600, 0xf211, 0xf901, 0xf902, 0xf903, 0xf30e, 0xf200, 0xf703,
+ 0xf820, 0xf200, 0xf200, 0xf900, 0xf310, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+static u_short ctrl_alt_map[NR_KEYS] = {
+ 0xf200, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506,
+ 0xf507, 0xf508, 0xf509, 0xf50a, 0xf50b, 0xf50c, 0xf50d, 0xf200,
+ 0xf11c, 0xf510, 0xf511, 0xf512, 0xf513, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf114, 0xf115, 0xf20c, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf811, 0xf817, 0xf805, 0xf812, 0xf814,
+ 0xf819, 0xf815, 0xf809, 0xf80f, 0xf810, 0xf200, 0xf200, 0xf201,
+ 0xf117, 0xf118, 0xf119, 0xf307, 0xf308, 0xf309, 0xf30b, 0xf702,
+ 0xf207, 0xf801, 0xf813, 0xf804, 0xf806, 0xf807, 0xf808, 0xf80a,
+ 0xf80b, 0xf80c, 0xf200, 0xf200, 0xf200, 0xf603, 0xf304, 0xf305,
+ 0xf306, 0xf200, 0xf700, 0xf200, 0xf81a, 0xf818, 0xf803, 0xf816,
+ 0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, 0xf200, 0xf601,
+ 0xf600, 0xf602, 0xf301, 0xf302, 0xf303, 0xf30e, 0xf200, 0xf703,
+ 0xf200, 0xf200, 0xf200, 0xf300, 0xf20c, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+ushort *key_maps[MAX_NR_KEYMAPS] = {
+ plain_map, shift_map, altgr_map, 0,
+ ctrl_map, shift_ctrl_map, 0, 0,
+ alt_map, 0, 0, 0,
+ ctrl_alt_map, 0
+};
+
+unsigned int keymap_count = 7;
+
+
+/*
+ * Philosophy: most people do not define more strings, but they who do
+ * often want quite a lot of string space. So, we statically allocate
+ * the default and allocate dynamically in chunks of 512 bytes.
+ */
+
+char func_buf[] = {
+ '\033', '[', '[', 'A', 0,
+ '\033', '[', '[', 'B', 0,
+ '\033', '[', '[', 'C', 0,
+ '\033', '[', '[', 'D', 0,
+ '\033', '[', '[', 'E', 0,
+ '\033', '[', '1', '7', '~', 0,
+ '\033', '[', '1', '8', '~', 0,
+ '\033', '[', '1', '9', '~', 0,
+ '\033', '[', '2', '0', '~', 0,
+ '\033', '[', '2', '1', '~', 0,
+ '\033', '[', '2', '3', '~', 0,
+ '\033', '[', '2', '4', '~', 0,
+ '\033', '[', '2', '5', '~', 0,
+ '\033', '[', '2', '6', '~', 0,
+ '\033', '[', '2', '8', '~', 0,
+ '\033', '[', '2', '9', '~', 0,
+ '\033', '[', '3', '1', '~', 0,
+ '\033', '[', '3', '2', '~', 0,
+ '\033', '[', '3', '3', '~', 0,
+ '\033', '[', '3', '4', '~', 0,
+ '\033', '[', '1', '~', 0,
+ '\033', '[', '2', '~', 0,
+ '\033', '[', '3', '~', 0,
+ '\033', '[', '4', '~', 0,
+ '\033', '[', '5', '~', 0,
+ '\033', '[', '6', '~', 0,
+ '\033', '[', 'M', 0,
+ '\033', '[', 'P', 0,
+};
+
+
+char *funcbufptr = func_buf;
+int funcbufsize = sizeof(func_buf);
+int funcbufleft = 0; /* space left */
+
+char *func_table[MAX_NR_FUNC] = {
+ func_buf + 0,
+ func_buf + 5,
+ func_buf + 10,
+ func_buf + 15,
+ func_buf + 20,
+ func_buf + 25,
+ func_buf + 31,
+ func_buf + 37,
+ func_buf + 43,
+ func_buf + 49,
+ func_buf + 55,
+ func_buf + 61,
+ func_buf + 67,
+ func_buf + 73,
+ func_buf + 79,
+ func_buf + 85,
+ func_buf + 91,
+ func_buf + 97,
+ func_buf + 103,
+ func_buf + 109,
+ func_buf + 115,
+ func_buf + 120,
+ func_buf + 125,
+ func_buf + 130,
+ func_buf + 135,
+ func_buf + 140,
+ func_buf + 145,
+ 0,
+ 0,
+ func_buf + 149,
+ 0,
+};
+
+struct kbdiacr accent_table[MAX_DIACR] = {
+ {'`', 'A', 'À'}, {'`', 'a', 'à'},
+ {'\'', 'A', 'Á'}, {'\'', 'a', 'á'},
+ {'^', 'A', 'Â'}, {'^', 'a', 'â'},
+ {'~', 'A', 'Ã'}, {'~', 'a', 'ã'},
+ {'"', 'A', 'Ä'}, {'"', 'a', 'ä'},
+ {'O', 'A', 'Å'}, {'o', 'a', 'å'},
+ {'0', 'A', 'Å'}, {'0', 'a', 'å'},
+ {'A', 'A', 'Å'}, {'a', 'a', 'å'},
+ {'A', 'E', 'Æ'}, {'a', 'e', 'æ'},
+ {',', 'C', 'Ç'}, {',', 'c', 'ç'},
+ {'`', 'E', 'È'}, {'`', 'e', 'è'},
+ {'\'', 'E', 'É'}, {'\'', 'e', 'é'},
+ {'^', 'E', 'Ê'}, {'^', 'e', 'ê'},
+ {'"', 'E', 'Ë'}, {'"', 'e', 'ë'},
+ {'`', 'I', 'Ì'}, {'`', 'i', 'ì'},
+ {'\'', 'I', 'Í'}, {'\'', 'i', 'í'},
+ {'^', 'I', 'Î'}, {'^', 'i', 'î'},
+ {'"', 'I', 'Ï'}, {'"', 'i', 'ï'},
+ {'-', 'D', 'Ð'}, {'-', 'd', 'ð'},
+ {'~', 'N', 'Ñ'}, {'~', 'n', 'ñ'},
+ {'`', 'O', 'Ò'}, {'`', 'o', 'ò'},
+ {'\'', 'O', 'Ó'}, {'\'', 'o', 'ó'},
+ {'^', 'O', 'Ô'}, {'^', 'o', 'ô'},
+ {'~', 'O', 'Õ'}, {'~', 'o', 'õ'},
+ {'"', 'O', 'Ö'}, {'"', 'o', 'ö'},
+ {'/', 'O', 'Ø'}, {'/', 'o', 'ø'},
+ {'`', 'U', 'Ù'}, {'`', 'u', 'ù'},
+ {'\'', 'U', 'Ú'}, {'\'', 'u', 'ú'},
+ {'^', 'U', 'Û'}, {'^', 'u', 'û'},
+ {'"', 'U', 'Ü'}, {'"', 'u', 'ü'},
+ {'\'', 'Y', 'Ý'}, {'\'', 'y', 'ý'},
+ {'T', 'H', 'Þ'}, {'t', 'h', 'þ'},
+ {'s', 's', 'ß'}, {'"', 'y', 'ÿ'},
+ {'s', 'z', 'ß'}, {'i', 'j', 'ÿ'},
+};
+
+unsigned int accent_table_size = 68;
diff --git a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c
index b0a4836a4f9b..db068168efe2 100644
--- a/drivers/usb/class/bluetty.c
+++ b/drivers/usb/class/bluetty.c
@@ -1151,7 +1151,8 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum,
endpoint = bulk_out_endpoint[0];
bluetooth->bulk_out_endpointAddress = endpoint->bEndpointAddress;
-
+ bluetooth->bulk_out_buffer_size = endpoint->wMaxPacketSize * 2;
+
/* create our write urb pool */
for (i = 0; i < NUM_BULK_URBS; ++i) {
struct urb *urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -1166,8 +1167,6 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum,
}
bluetooth->write_urb_pool[i] = urb;
}
-
- bluetooth->bulk_out_buffer_size = endpoint->wMaxPacketSize * 2;
endpoint = interrupt_in_endpoint[0];
bluetooth->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
diff --git a/drivers/usb/class/printer.c b/drivers/usb/class/printer.c
index 7689c3e9caed..cd9b52896fa5 100644
--- a/drivers/usb/class/printer.c
+++ b/drivers/usb/class/printer.c
@@ -372,7 +372,7 @@ static void usblp_cleanup (struct usblp *usblp)
{
devfs_unregister (usblp->devfs);
usblp_table [usblp->minor] = NULL;
- usb_deregister_dev (&usblp_driver, 1, usblp->minor);
+ usb_deregister_dev (1, usblp->minor);
info("usblp%d: removed", usblp->minor);
kfree (usblp->writeurb->transfer_buffer);
@@ -812,20 +812,10 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
init_waitqueue_head(&usblp->wait);
usblp->ifnum = ifnum;
- retval = usb_register_dev(&usblp_driver, 1, &usblp->minor);
+ retval = usb_register_dev(&usblp_fops, USBLP_MINOR_BASE, 1, &usblp->minor);
if (retval) {
- if (retval != -ENODEV) {
- err("Not able to get a minor for this device.");
- goto abort;
- }
- /* Look for a free usblp_table entry on our own. */
- while (usblp_table[usblp->minor]) {
- usblp->minor++;
- if (usblp->minor >= USBLP_MINORS) {
- err("no more free usblp devices");
- goto abort;
- }
- }
+ err("Not able to get a minor for this device.");
+ goto abort;
}
usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL);
@@ -901,7 +891,7 @@ static void *usblp_probe(struct usb_device *dev, unsigned int ifnum,
return usblp;
abort_minor:
- usb_deregister_dev (&usblp_driver, 1, usblp->minor);
+ usb_deregister_dev (1, usblp->minor);
abort:
if (usblp) {
usb_free_urb(usblp->writeurb);
@@ -1111,9 +1101,6 @@ static struct usb_driver usblp_driver = {
name: "usblp",
probe: usblp_probe,
disconnect: usblp_disconnect,
- fops: &usblp_fops,
- minor: USBLP_MINOR_BASE,
- num_minors: USBLP_MINORS,
id_table: usblp_ids,
};
diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
index 506dfecc19d2..11a56285c9ee 100644
--- a/drivers/usb/core/Makefile
+++ b/drivers/usb/core/Makefile
@@ -2,17 +2,17 @@
# Makefile for USB Core files and filesystem
#
-export-objs := usb.o hcd.o hcd-pci.o urb.o message.o config.o
+export-objs := usb.o hcd.o hcd-pci.o urb.o message.o config.o file.o
usbcore-objs := usb.o usb-debug.o hub.o hcd.o urb.o message.o \
- config.o
+ config.o file.o
ifeq ($(CONFIG_PCI),y)
usbcore-objs += hcd-pci.o
endif
ifeq ($(CONFIG_USB_DEVICEFS),y)
- usbcore-objs += devio.o inode.o drivers.o devices.o
+ usbcore-objs += devio.o inode.o devices.o
endif
obj-$(CONFIG_USB) += usbcore.o
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
new file mode 100644
index 000000000000..eba43f1d84e5
--- /dev/null
+++ b/drivers/usb/core/file.c
@@ -0,0 +1,182 @@
+/*
+ * drivers/usb/file.c
+ *
+ * (C) Copyright Linus Torvalds 1999
+ * (C) Copyright Johannes Erdfelt 1999-2001
+ * (C) Copyright Andreas Gal 1999
+ * (C) Copyright Gregory P. Smith 1999
+ * (C) Copyright Deti Fliegl 1999 (new USB architecture)
+ * (C) Copyright Randy Dunlap 2000
+ * (C) Copyright David Brownell 2000-2001 (kernel hotplug, usb_device_id,
+ more docs, etc)
+ * (C) Copyright Yggdrasil Computing, Inc. 2000
+ * (usb_device_id matching changes by Adam J. Richter)
+ * (C) Copyright Greg Kroah-Hartman 2002
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+
+#ifdef CONFIG_USB_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
+#include <linux/usb.h>
+
+devfs_handle_t usb_devfs_handle; /* /dev/usb dir. */
+EXPORT_SYMBOL(usb_devfs_handle);
+
+#define MAX_USB_MINORS 256
+static struct file_operations *usb_minors[MAX_USB_MINORS];
+static spinlock_t minor_lock = SPIN_LOCK_UNLOCKED;
+
+static int usb_open(struct inode * inode, struct file * file)
+{
+ int minor = minor(inode->i_rdev);
+ struct file_operations *c;
+ int err = -ENODEV;
+ struct file_operations *old_fops, *new_fops = NULL;
+
+ spin_lock (&minor_lock);
+ c = usb_minors[minor];
+ spin_unlock (&minor_lock);
+
+ if (!c || !(new_fops = fops_get(c)))
+ return err;
+ old_fops = file->f_op;
+ file->f_op = new_fops;
+ /* Curiouser and curiouser... NULL ->open() as "no device" ? */
+ if (file->f_op->open)
+ err = file->f_op->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 usb_fops = {
+ owner: THIS_MODULE,
+ open: usb_open,
+};
+
+int usb_major_init(void)
+{
+ if (devfs_register_chrdev(USB_MAJOR, "usb", &usb_fops)) {
+ err("unable to get major %d for usb devices", USB_MAJOR);
+ return -EBUSY;
+ }
+
+ usb_devfs_handle = devfs_mk_dir(NULL, "usb", NULL);
+
+ return 0;
+}
+
+void usb_major_cleanup(void)
+{
+ devfs_unregister(usb_devfs_handle);
+ devfs_unregister_chrdev(USB_MAJOR, "usb");
+}
+
+/**
+ * usb_register_dev - register a USB device, and ask for a minor number
+ * @fops: the file operations for this USB device
+ * @minor: the requested starting minor for this device.
+ * @num_minors: number of minor numbers requested for this device
+ * @start_minor: place to put the new starting minor number
+ *
+ * This should be called by all USB drivers that use the USB major number.
+ * If CONFIG_USB_DYNAMIC_MINORS is enabled, the minor number will be
+ * dynamically allocated out of the list of available ones. If it is not
+ * enabled, the minor number will be based on the next available free minor,
+ * starting at the requested @minor.
+ *
+ * usb_deregister_dev() must be called when the driver is done with
+ * the minor numbers given out by this function.
+ *
+ * Returns -EINVAL if something bad happens with trying to register a
+ * device, and 0 on success, alone with a value that the driver should
+ * use in start_minor.
+ */
+int usb_register_dev (struct file_operations *fops, int minor, int num_minors, int *start_minor)
+{
+ int i;
+ int j;
+ int good_spot;
+ int retval = -EINVAL;
+
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+ /*
+ * We don't care what the device tries to start at, we want to start
+ * at zero to pack the devices into the smallest available space with
+ * no holes in the minor range.
+ */
+ minor = 0;
+#endif
+
+ dbg ("asking for %d minors, starting at %d", num_minors, minor);
+
+ if (fops == NULL)
+ goto exit;
+
+ *start_minor = 0;
+ spin_lock (&minor_lock);
+ for (i = minor; i < MAX_USB_MINORS; ++i) {
+ if (usb_minors[i])
+ continue;
+
+ good_spot = 1;
+ for (j = 1; j <= num_minors-1; ++j)
+ if (usb_minors[i+j]) {
+ good_spot = 0;
+ break;
+ }
+ if (good_spot == 0)
+ continue;
+
+ *start_minor = i;
+ dbg("found a minor chunk free, starting at %d", i);
+ for (i = *start_minor; i < (*start_minor + num_minors); ++i)
+ usb_minors[i] = fops;
+
+ retval = 0;
+ goto exit;
+ }
+exit:
+ spin_unlock (&minor_lock);
+ return retval;
+}
+EXPORT_SYMBOL(usb_register_dev);
+
+/**
+ * usb_deregister_dev - deregister a USB device's dynamic minor.
+ * @num_minors: number of minor numbers to put back.
+ * @start_minor: the starting minor number
+ *
+ * Used in conjunction with usb_register_dev(). This function is called
+ * when the USB driver is finished with the minor numbers gotten from a
+ * call to usb_register_dev() (usually when the device is disconnected
+ * from the system.)
+ *
+ * This should be called by all drivers that use the USB major number.
+ */
+void usb_deregister_dev (int num_minors, int start_minor)
+{
+ int i;
+
+ dbg ("removing %d minors starting at %d", num_minors, start_minor);
+
+ spin_lock (&minor_lock);
+ for (i = start_minor; i < (start_minor + num_minors); ++i)
+ usb_minors[i] = NULL;
+ spin_unlock (&minor_lock);
+}
+EXPORT_SYMBOL(usb_deregister_dev);
+
+
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index 8d31640ff966..c637805a4705 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -48,7 +48,6 @@ static spinlock_t mount_lock = SPIN_LOCK_UNLOCKED;
static int mount_count; /* = 0 */
static struct dentry *devices_dentry;
-static struct dentry *drivers_dentry;
static int num_buses; /* = 0 */
static uid_t devuid; /* = 0 */
@@ -548,16 +547,6 @@ static int create_special_files (void)
return -ENODEV;
}
- drivers_dentry = fs_create_file ("drivers",
- listmode | S_IFREG,
- NULL, NULL,
- &usbdevfs_drivers_fops,
- listuid, listgid);
- if (drivers_dentry == NULL) {
- err ("Unable to create drivers usbfs file");
- return -ENODEV;
- }
-
return 0;
}
@@ -565,10 +554,7 @@ static void remove_special_files (void)
{
if (devices_dentry)
fs_remove_file (devices_dentry);
- if (drivers_dentry)
- fs_remove_file (drivers_dentry);
devices_dentry = NULL;
- drivers_dentry = NULL;
remove_mount();
}
@@ -581,11 +567,6 @@ void usbfs_update_special (void)
if (inode)
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
}
- if (drivers_dentry) {
- inode = devices_dentry->d_inode;
- if (inode)
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- }
}
void usbfs_add_bus(struct usb_bus *bus)
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 4842fbf06737..10591d54aebb 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -30,7 +30,6 @@
#include <linux/interrupt.h> /* for in_interrupt() */
#include <linux/kmod.h>
#include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
@@ -45,6 +44,8 @@
extern int usb_hub_init(void);
extern void usb_hub_cleanup(void);
+extern int usb_major_init(void);
+extern void usb_major_cleanup(void);
/*
* Prototypes for the device driver probing/loading functions
@@ -58,75 +59,23 @@ static void usb_check_support(struct usb_device *);
*/
LIST_HEAD(usb_driver_list);
-devfs_handle_t usb_devfs_handle; /* /dev/usb dir. */
-
-#define MAX_USB_MINORS 256
-static struct usb_driver *usb_minors[MAX_USB_MINORS];
-static spinlock_t minor_lock = SPIN_LOCK_UNLOCKED;
-
-static int usb_register_minors (struct usb_driver *driver, int num_minors, int start_minor)
-{
- int i;
-
- dbg("registering %d minors, starting at %d", num_minors, start_minor);
-
- if (start_minor + num_minors >= MAX_USB_MINORS)
- return -EINVAL;
-
- spin_lock (&minor_lock);
- for (i = start_minor; i < (start_minor + num_minors); ++i)
- if (usb_minors[i]) {
- spin_unlock (&minor_lock);
- err("minor %d is already in use, error registering %s driver",
- i, driver->name);
- return -EINVAL;
- }
-
- for (i = start_minor; i < (start_minor + num_minors); ++i)
- usb_minors[i] = driver;
-
- spin_unlock (&minor_lock);
- return 0;
-}
-
-static void usb_deregister_minors (struct usb_driver *driver, int num_minors, int start_minor)
-{
- int i;
-
- dbg ("%s is removing %d minors starting at %d", driver->name,
- num_minors, start_minor);
-
- spin_lock (&minor_lock);
- for (i = start_minor; i < (start_minor + num_minors); ++i)
- usb_minors[i] = NULL;
- spin_unlock (&minor_lock);
-}
/**
- * usb_register - register a USB driver
- * @new_driver: USB operations for the driver
+ * usb_register - register a USB driver
+ * @new_driver: USB operations for the driver
*
- * Registers a USB driver with the USB core. The list of unattached
- * interfaces will be rescanned whenever a new driver is added, allowing
- * the new driver to attach to any recognized devices.
- * Returns a negative error code on failure and 0 on success.
+ * Registers a USB driver with the USB core. The list of unattached
+ * interfaces will be rescanned whenever a new driver is added, allowing
+ * the new driver to attach to any recognized devices.
+ * Returns a negative error code on failure and 0 on success.
+ *
+ * NOTE: if you want your driver to use the USB major number, you must call
+ * usb_register_dev() to enable that functionality. This function no longer
+ * takes care of that.
*/
int usb_register(struct usb_driver *new_driver)
{
int retval = 0;
-
- if ((new_driver->fops) && (new_driver->num_minors == 0)) {
- err ("%s driver must specify num_minors", new_driver->name);
- return -EINVAL;
- }
-
-#ifndef CONFIG_USB_DYNAMIC_MINORS
- if (new_driver->fops != NULL) {
- retval = usb_register_minors (new_driver, new_driver->num_minors, new_driver->minor);
- if (retval)
- return retval;
- }
-#endif
info("registered new driver %s", new_driver->name);
@@ -144,92 +93,6 @@ int usb_register(struct usb_driver *new_driver)
/**
- * usb_register_dev - register a USB device, and ask for a minor number
- * @new_driver: USB operations for the driver
- * @num_minors: number of minor numbers requested for this device
- * @start_minor: place to put the new starting minor number
- *
- * Used to ask the USB core for a new minor number for a device that has
- * just showed up. This is used to dynamically allocate minor numbers
- * from the pool of USB reserved minor numbers.
- *
- * This should be called by all drivers that use the USB major number.
- * This only returns a good value of CONFIG_USB_DYNAMIC_MINORS is
- * selected by the user.
- *
- * usb_deregister_dev() should be called when the driver is done with
- * the minor numbers given out by this function.
- *
- * Returns -ENODEV if CONFIG_USB_DYNAMIC_MINORS is not enabled in this
- * kernel, -EINVAL if something bad happens with trying to register a
- * device, and 0 on success, alone with a value that the driver should
- * use in start_minor.
- */
-#ifdef CONFIG_USB_DYNAMIC_MINORS
-int usb_register_dev (struct usb_driver *new_driver, int num_minors, int *start_minor)
-{
- int i;
- int j;
- int good_spot;
- int retval = -EINVAL;
-
- dbg ("%s is asking for %d minors", new_driver->name, num_minors);
-
- if (new_driver->fops == NULL)
- goto exit;
-
- *start_minor = 0;
- spin_lock (&minor_lock);
- for (i = 0; i < MAX_USB_MINORS; ++i) {
- if (usb_minors[i])
- continue;
-
- good_spot = 1;
- for (j = 1; j <= num_minors-1; ++j)
- if (usb_minors[i+j]) {
- good_spot = 0;
- break;
- }
- if (good_spot == 0)
- continue;
-
- *start_minor = i;
- spin_unlock (&minor_lock);
- retval = usb_register_minors (new_driver, num_minors, *start_minor);
- if (retval) {
- /* someone snuck in here, so let's start looking all over again */
- spin_lock (&minor_lock);
- i = 0;
- continue;
- }
- goto exit;
- }
- spin_unlock (&minor_lock);
-exit:
- return retval;
-}
-
-/**
- * usb_deregister_dev - deregister a USB device's dynamic minor.
- * @driver: USB operations for the driver
- * @num_minors: number of minor numbers to put back.
- * @start_minor: the starting minor number
- *
- * Used in conjunction with usb_register_dev(). This function is called
- * when the USB driver is finished with the minor numbers gotten from a
- * call to usb_register_dev() (usually when the device is disconnected
- * from the system.)
- *
- * This should be called by all drivers that use the USB major number.
- */
-void usb_deregister_dev (struct usb_driver *driver, int num_minors, int start_minor)
-{
- usb_deregister_minors (driver, num_minors, start_minor);
-}
-#endif /* CONFIG_USB_DYNAMIC_MINORS */
-
-
-/**
* usb_scan_devices - scans all unclaimed USB interfaces
* Context: !in_interrupt ()
*
@@ -298,11 +161,15 @@ static void usb_drivers_purge(struct usb_driver *driver,struct usb_device *dev)
}
/**
- * usb_deregister - unregister a USB driver
- * @driver: USB operations of the driver to unregister
- * Context: !in_interrupt ()
+ * usb_deregister - unregister a USB driver
+ * @driver: USB operations of the driver to unregister
+ * Context: !in_interrupt ()
*
- * Unlinks the specified driver from the internal USB driver list.
+ * Unlinks the specified driver from the internal USB driver list.
+ *
+ * NOTE: If you called usb_register_dev(), you still need to call
+ * usb_deregister_dev() to clean up your driver's allocated minor numbers,
+ * this * call will no longer do it for you.
*/
void usb_deregister(struct usb_driver *driver)
{
@@ -310,11 +177,6 @@ void usb_deregister(struct usb_driver *driver)
info("deregistering driver %s", driver->name);
-#ifndef CONFIG_USB_DYNAMIC_MINORS
- if (driver->fops != NULL)
- usb_deregister_minors (driver, driver->num_minors, driver->minor);
-#endif
-
/*
* first we remove the driver, to be sure it doesn't get used by
* another thread while we are stepping through removing entries
@@ -1357,55 +1219,6 @@ int usb_new_device(struct usb_device *dev)
return 0;
}
-static int usb_open(struct inode * inode, struct file * file)
-{
- int minor = minor(inode->i_rdev);
- struct usb_driver *c;
- int err = -ENODEV;
- struct file_operations *old_fops, *new_fops = NULL;
-
- spin_lock (&minor_lock);
- c = usb_minors[minor];
- spin_unlock (&minor_lock);
-
- if (!c || !(new_fops = fops_get(c->fops)))
- return err;
- old_fops = file->f_op;
- file->f_op = new_fops;
- /* Curiouser and curiouser... NULL ->open() as "no device" ? */
- if (file->f_op->open)
- err = file->f_op->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 usb_fops = {
- owner: THIS_MODULE,
- open: usb_open,
-};
-
-int usb_major_init(void)
-{
- if (devfs_register_chrdev(USB_MAJOR, "usb", &usb_fops)) {
- err("unable to get major %d for usb devices", USB_MAJOR);
- return -EBUSY;
- }
-
- usb_devfs_handle = devfs_mk_dir(NULL, "usb", NULL);
-
- return 0;
-}
-
-void usb_major_cleanup(void)
-{
- devfs_unregister(usb_devfs_handle);
- devfs_unregister_chrdev(USB_MAJOR, "usb");
-}
-
#ifdef CONFIG_PROC_FS
struct list_head *usb_driver_get_list(void)
@@ -1463,11 +1276,6 @@ EXPORT_SYMBOL(usb_register);
EXPORT_SYMBOL(usb_deregister);
EXPORT_SYMBOL(usb_scan_devices);
-#ifdef CONFIG_USB_DYNAMIC_MINORS
-EXPORT_SYMBOL(usb_register_dev);
-EXPORT_SYMBOL(usb_deregister_dev);
-#endif
-
EXPORT_SYMBOL(usb_alloc_dev);
EXPORT_SYMBOL(usb_free_dev);
EXPORT_SYMBOL(usb_get_dev);
@@ -1489,5 +1297,4 @@ EXPORT_SYMBOL(__usb_get_extra_descriptor);
EXPORT_SYMBOL(usb_get_current_frame_number);
-EXPORT_SYMBOL(usb_devfs_handle);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/Config.help b/drivers/usb/host/Config.help
index 2456b823e269..7cfd9ff8e5aa 100644
--- a/drivers/usb/host/Config.help
+++ b/drivers/usb/host/Config.help
@@ -36,26 +36,7 @@ CONFIG_USB_OHCI_HCD
The module will be called ohci-hcd.o. If you want to compile it
as a module, say M here and read <file:Documentation/modules.txt>.
-CONFIG_USB_UHCI
- The Universal Host Controller Interface is a standard by Intel for
- accessing the USB hardware in the PC (which is also called the USB
- host controller). If your USB host controller conforms to this
- standard, you may want to say Y, but see below. All recent boards
- with Intel PCI chipsets (like intel 430TX, 440FX, 440LX, 440BX,
- i810, i820) conform to this standard. Also all VIA PCI chipsets
- (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro
- 133).
-
- Currently there exist two drivers for UHCI host controllers: this
- one and the so-called JE driver, which you can get from
- "UHCI alternate (JE) support", below. You need only one.
-
- This code is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called usb-uhci.o. If you want to compile it as a
- module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_USB_UHCI_ALT
+CONFIG_USB_UHCI_HCD_ALT
The Universal Host Controller Interface is a standard by Intel for
accessing the USB hardware in the PC (which is also called the USB
host controller). If your USB host controller conforms to this
@@ -65,31 +46,11 @@ CONFIG_USB_UHCI_ALT
(like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro
133). If unsure, say Y.
- Currently there exist two drivers for UHCI host controllers: this
- so-called JE driver, and the one you get from "UHCI support", above.
- You need only one.
-
This code is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
- The module will be called uhci.o. If you want to compile it as a
+ The module will be called uhci-hcd.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
-CONFIG_USB_OHCI
- The Open Host Controller Interface is a standard by
- Compaq/Microsoft/National for accessing the USB PC hardware (also
- called USB host controller). If your USB host controller conforms to
- this standard, say Y. The USB host controllers on most non-Intel
- architectures and on several x86 compatibles with non-Intel chipsets
- -- like SiS (aktual 610, 610 and so on) or ALi (ALi IV, ALi V,
- Aladdin Pro..) -- conform to this standard.
-
- You may want to read <file:Documentation/usb/ohci.txt>.
-
- This code is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called usb-ohci.o. If you want to compile it
- as a module, say M here and read <file:Documentation/modules.txt>.
-
CONFIG_USB_SL811HS
Say Y here if you have a SL811HS USB host controller in your system.
diff --git a/drivers/usb/host/Config.in b/drivers/usb/host/Config.in
index 806495da5726..dbfb819f8d33 100644
--- a/drivers/usb/host/Config.in
+++ b/drivers/usb/host/Config.in
@@ -2,23 +2,9 @@
# USB Host Controller Drivers
#
comment 'USB Host Controller Drivers'
-dep_tristate ' EHCI HCD (USB 2.0) support (EXPERIMENTAL)' CONFIG_USB_EHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
-dep_tristate ' OHCI HCD support (EXPERIMENTAL)' CONFIG_USB_OHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
-if [ "$CONFIG_USB_UHCI_HCD_ALT" != "y" ]; then
- dep_tristate ' UHCI HCD (most Intel and VIA) support (EXPERIMENTAL)' CONFIG_USB_UHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
-fi
-if [ "$CONFIG_USB_UHCI_HCD" != "y" ]; then
- dep_tristate ' UHCI HCD Alternate (most Intel and VIA) support (EXPERIMENTAL)' CONFIG_USB_UHCI_HCD_ALT $CONFIG_USB $CONFIG_EXPERIMENTAL
-fi
-#if [ "$CONFIG_USB_UHCI_ALT" != "y" ]; then
-# dep_tristate ' UHCI (Intel PIIX4, VIA, ...) support' CONFIG_USB_UHCI $CONFIG_USB
-#fi
-#if [ "$CONFIG_USB_UHCI" != "y" ]; then
-# dep_tristate ' UHCI Alternate Driver (JE) support' CONFIG_USB_UHCI_ALT $CONFIG_USB
-#else
-# define_bool CONFIG_USB_UHCI_ALT n
-#fi
-#dep_tristate ' OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
+dep_tristate ' EHCI HCD (USB 2.0) support' CONFIG_USB_EHCI_HCD $CONFIG_USB
+dep_tristate ' OHCI HCD support' CONFIG_USB_OHCI_HCD $CONFIG_USB
+dep_tristate ' UHCI HCD (most Intel and VIA) support' CONFIG_USB_UHCI_HCD_ALT $CONFIG_USB
if [ "$CONFIG_ARM" = "y" ]; then
dep_tristate ' SA1111 OHCI-compatible host interface support' CONFIG_USB_OHCI_SA1111 $CONFIG_USB
dep_tristate ' SL811HS support' CONFIG_USB_SL811HS $CONFIG_USB
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index b6aba6fb9c49..1d9bd9c37300 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -190,6 +190,8 @@ static void ohci_dump_roothub (struct ohci_hcd *controller, int verbose)
__u32 temp, ndp, i;
temp = roothub_a (controller);
+ if (temp == ~(u32)0)
+ return;
ndp = (temp & RH_A_NDP);
if (verbose) {
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index bfd4bc4315d6..db4276ead92c 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -502,11 +502,19 @@ static void ohci_irq (struct usb_hcd *hcd)
if ((ohci->hcca->done_head != 0)
&& ! (le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {
ints = OHCI_INTR_WDH;
- } else if ((ints = (readl (&regs->intrstatus)
- & readl (&regs->intrenable))) == 0) {
+
+ /* cardbus/... hardware gone before remove() */
+ } else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
+ ohci->disabled++;
+ err ("%s device removed!", hcd->self.bus_name);
+ return;
+
+ /* interrupt for some other device? */
+ } else if ((ints &= readl (&regs->intrenable)) == 0) {
return;
}
+
// dbg ("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no));
if (ints & OHCI_INTR_UE) {
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 23919dfb7c84..33279c5cc906 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -1665,37 +1665,15 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
uhci_unlink_generic(uhci, urb);
- if (urb->transfer_flags & USB_ASYNC_UNLINK) {
- urbp->status = urb->status = -ECONNABORTED;
+ spin_lock(&uhci->urb_remove_list_lock);
- spin_lock(&uhci->urb_remove_list_lock);
-
- /* If we're the first, set the next interrupt bit */
- if (list_empty(&uhci->urb_remove_list))
- uhci_set_next_interrupt(uhci);
-
- list_add(&urbp->urb_list, &uhci->urb_remove_list);
-
- spin_unlock(&uhci->urb_remove_list_lock);
-
- spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
- } else {
- urb->status = -ENOENT;
-
- spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
- if (in_interrupt()) { /* wait at least 1 frame */
- static int errorcount = 10;
-
- if (errorcount--)
- dbg("uhci_urb_dequeue called from interrupt for urb %p", urb);
- udelay(1000);
- } else
- schedule_timeout(1+1*HZ/1000);
-
- uhci_finish_urb(hcd, urb);
- }
+ /* If we're the first, set the next interrupt bit */
+ if (list_empty(&uhci->urb_remove_list))
+ uhci_set_next_interrupt(uhci);
+ list_add(&urbp->urb_list, &uhci->urb_remove_list);
+ spin_unlock(&uhci->urb_remove_list_lock);
+ spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
return 0;
}
@@ -1788,7 +1766,7 @@ static void stall_callback(unsigned long ptr)
tmp = tmp->next;
- u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED;
+ u->transfer_flags |= USB_TIMEOUT_KILLED;
uhci_urb_dequeue(hcd, u);
}
diff --git a/drivers/usb/host/usb-uhci-hcd.c b/drivers/usb/host/usb-uhci-hcd.c
index f7979e431024..1c476e00c633 100644
--- a/drivers/usb/host/usb-uhci-hcd.c
+++ b/drivers/usb/host/usb-uhci-hcd.c
@@ -271,21 +271,15 @@ static int uhci_urb_enqueue (struct usb_hcd *hcd, struct urb *urb, int mem_flags
static int uhci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
{
unsigned long flags=0;
- struct uhci_hcd *uhci;
+ struct uhci_hcd *uhci = hcd_to_uhci (hcd);
+ int ret;
dbg("uhci_urb_dequeue called for %p",urb);
- uhci = hcd_to_uhci (hcd);
-
- if (urb->transfer_flags & USB_ASYNC_UNLINK) {
- int ret;
- spin_lock_irqsave (&uhci->urb_list_lock, flags);
- ret = uhci_unlink_urb_async(uhci, urb, UNLINK_ASYNC_STORE_URB);
- spin_unlock_irqrestore (&uhci->urb_list_lock, flags);
- return ret;
- }
- else
- return uhci_unlink_urb_sync(uhci, urb);
+ spin_lock_irqsave (&uhci->urb_list_lock, flags);
+ ret = uhci_unlink_urb_async(uhci, urb, UNLINK_ASYNC_STORE_URB);
+ spin_unlock_irqrestore (&uhci->urb_list_lock, flags);
+ return ret;
}
/*--------------------------------------------------------------------------*/
static int uhci_get_frame (struct usb_hcd *hcd)
diff --git a/drivers/usb/host/usb-uhci-q.c b/drivers/usb/host/usb-uhci-q.c
index 0ac0d798ab76..da8b67787b46 100644
--- a/drivers/usb/host/usb-uhci-q.c
+++ b/drivers/usb/host/usb-uhci-q.c
@@ -541,22 +541,6 @@ static void uhci_clean_iso_step1(struct uhci_hcd *uhci, urb_priv_t *urb_priv)
}
}
/*-------------------------------------------------------------------*/
-static void uhci_clean_iso_step2(struct uhci_hcd *uhci, urb_priv_t *urb_priv)
-{
- struct list_head *p;
- uhci_desc_t *td;
- int now=UHCI_GET_CURRENT_FRAME(uhci);
-
- dbg("uhci_clean_iso_step2");
- while ((p = urb_priv->desc_list.next) != &urb_priv->desc_list) {
- td = list_entry (p, uhci_desc_t, desc_list);
- list_del (p);
- INIT_LIST_HEAD(&td->horizontal);
- list_add_tail (&td->horizontal, &uhci->free_desc_td);
- td->last_used=now;
- }
-}
-/*-------------------------------------------------------------------*/
/* mode: CLEAN_TRANSFER_NO_DELETION: unlink but no deletion mark (step 1 of async_unlink)
CLEAN_TRANSFER_REGULAR: regular (unlink/delete-mark)
CLEAN_TRANSFER_DELETION_MARK: deletion mark for QH (step 2 of async_unlink)
@@ -759,44 +743,6 @@ static int uhci_unlink_urb_async (struct uhci_hcd *uhci, struct urb *urb, int mo
return 0; // completion will follow
}
/*-------------------------------------------------------------------*/
-// kills an urb by unlinking descriptors and waiting for at least one frame
-static int uhci_unlink_urb_sync (struct uhci_hcd *uhci, struct urb *urb)
-{
- uhci_desc_t *qh;
- urb_priv_t *urb_priv;
- unsigned long flags=0;
-
- spin_lock_irqsave (&uhci->urb_list_lock, flags);
-// err("uhci_unlink_urb_sync %p, %i",urb,urb->status);
-
- // move descriptors out the the running chains, dequeue urb
- uhci_unlink_urb_async(uhci, urb, UNLINK_ASYNC_DONT_STORE);
-
- urb_priv = urb->hcpriv;
-
- spin_unlock_irqrestore (&uhci->urb_list_lock, flags);
-
- // cleanup the rest
- switch (usb_pipetype (urb->pipe)) {
- case PIPE_INTERRUPT:
- case PIPE_ISOCHRONOUS:
- uhci_wait_ms(1);
- uhci_clean_iso_step2(uhci, urb_priv);
- break;
-
- case PIPE_BULK:
- case PIPE_CONTROL:
- qh = list_entry (urb_priv->desc_list.next, uhci_desc_t, desc_list);
- uhci_clean_transfer(uhci, urb, qh, CLEAN_TRANSFER_DELETION_MARK);
- uhci_wait_ms(1);
- }
- urb->status = -ENOENT; // mark urb as killed
-
- finish_urb(uhci,urb);
-
- return 0;
-}
-/*-------------------------------------------------------------------*/
// unlink urbs for specific device or all devices
static void uhci_unlink_urbs(struct uhci_hcd *uhci, struct usb_device *usb_dev, int remove_all)
{
@@ -816,8 +762,6 @@ static void uhci_unlink_urbs(struct uhci_hcd *uhci, struct usb_device *usb_dev,
// err("unlink urb: %p, dev %p, ud %p", urb, usb_dev,urb->dev);
- //urb->transfer_flags |=USB_ASYNC_UNLINK;
-
if (remove_all || (usb_dev == urb->dev)) {
spin_unlock_irqrestore (&uhci->urb_list_lock, flags);
err("forced removing of queued URB %p due to disconnect",urb);
@@ -850,7 +794,7 @@ static void uhci_check_timeouts(struct uhci_hcd *uhci)
type = usb_pipetype (urb->pipe);
if ( urb->timeout && time_after(jiffies, hcpriv->started + urb->timeout)) {
- urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;
+ urb->transfer_flags |= USB_TIMEOUT_KILLED;
async_dbg("uhci_check_timeout: timeout for %p",urb);
uhci_unlink_urb_async(uhci, urb, UNLINK_ASYNC_STORE_URB);
}
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index a4cccb7e4df7..6514054a8813 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -401,6 +401,7 @@ static void mdc800_usb_download_notify (struct urb *urb)
***************************************************************************/
static struct usb_driver mdc800_usb_driver;
+static struct file_operations mdc800_device_ops;
/*
* Callback to search the Mustek MDC800 on the USB Bus
@@ -476,7 +477,7 @@ static void* mdc800_usb_probe (struct usb_device *dev ,unsigned int ifnum,
down (&mdc800->io_lock);
- retval = usb_register_dev (&mdc800_usb_driver, 1, &mdc800->minor);
+ retval = usb_register_dev (&mdc800_device_ops, MDC800_DEVICE_MINOR_BASE, 1, &mdc800->minor);
if (retval && (retval != -ENODEV)) {
err ("Not able to get a minor for this device.");
return 0;
@@ -537,7 +538,7 @@ static void mdc800_usb_disconnect (struct usb_device *dev,void* ptr)
if (mdc800->state == NOT_CONNECTED)
return;
- usb_deregister_dev (&mdc800_usb_driver, 1, mdc800->minor);
+ usb_deregister_dev (1, mdc800->minor);
mdc800->state=NOT_CONNECTED;
@@ -942,12 +943,10 @@ MODULE_DEVICE_TABLE (usb, mdc800_table);
*/
static struct usb_driver mdc800_usb_driver =
{
+ owner: THIS_MODULE,
name: "mdc800",
probe: mdc800_usb_probe,
disconnect: mdc800_usb_disconnect,
- fops: &mdc800_device_ops,
- minor: MDC800_DEVICE_MINOR_BASE,
- num_minors: 1,
id_table: mdc800_table
};
diff --git a/drivers/usb/image/scanner.c b/drivers/usb/image/scanner.c
index 54e181fdb695..2bb1de40e3c0 100644
--- a/drivers/usb/image/scanner.c
+++ b/drivers/usb/image/scanner.c
@@ -971,17 +971,11 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum,
down(&scn_mutex);
- retval = usb_register_dev(&scanner_driver, 1, &scn_minor);
+ retval = usb_register_dev(&usb_scanner_fops, SCN_BASE_MNR, 1, &scn_minor);
if (retval) {
- if (retval != -ENODEV) {
- err ("Not able to get a minor for this device.");
- up(&scn_mutex);
- return NULL;
- }
- for (scn_minor = 0; scn_minor < SCN_MAX_MNR; scn_minor++) {
- if (!p_scn_table[scn_minor])
- break;
- }
+ err ("Not able to get a minor for this device.");
+ up(&scn_mutex);
+ return NULL;
}
/* Check to make sure that the last slot isn't already taken */
@@ -1112,7 +1106,7 @@ disconnect_scanner(struct usb_device *dev, void *ptr)
dbg("disconnect_scanner: De-allocating minor:%d", scn->scn_minor);
devfs_unregister(scn->devfs);
- usb_deregister_dev(&scanner_driver, 1, scn->scn_minor);
+ usb_deregister_dev(1, scn->scn_minor);
p_scn_table[scn->scn_minor] = NULL;
usb_free_urb(scn->scn_irq);
up (&(scn->sem));
@@ -1125,9 +1119,6 @@ usb_driver scanner_driver = {
name: "usbscanner",
probe: probe_scanner,
disconnect: disconnect_scanner,
- fops: &usb_scanner_fops,
- minor: SCN_BASE_MNR,
- num_minors: SCN_MAX_MNR,
id_table: NULL, /* This would be scanner_device_ids, but we
need to check every USB device, in case
we match a user defined vendor/product ID. */
diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c
index 2d7478dcf7c7..cbed3efbb7c4 100644
--- a/drivers/usb/input/aiptek.c
+++ b/drivers/usb/input/aiptek.c
@@ -296,9 +296,8 @@ aiptek_probe(struct usb_device *dev, unsigned int ifnum,
input_register_device(&aiptek->dev);
- printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n",
- aiptek->dev.number, aiptek->features->name, dev->bus->busnum,
- dev->devnum, ifnum);
+ printk(KERN_INFO "input: %s on usb%d:%d.%d\n",
+ aiptek->features->name, dev->bus->busnum, dev->devnum, ifnum);
return aiptek;
}
diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
index 0e4347fa11e1..51b7808d7472 100644
--- a/drivers/usb/input/hiddev.c
+++ b/drivers/usb/input/hiddev.c
@@ -193,7 +193,7 @@ static int hiddev_fasync(int fd, struct file *file, int on)
static void hiddev_cleanup(struct hiddev *hiddev)
{
devfs_unregister(hiddev->devfs);
- usb_deregister_dev(&hiddev_driver, 1, hiddev->minor);
+ usb_deregister_dev(1, hiddev->minor);
hiddev_table[hiddev->minor] = NULL;
kfree(hiddev);
}
@@ -626,21 +626,16 @@ int hiddev_connect(struct hid_device *hid)
if (i == hid->maxapplication)
return -1;
- retval = usb_register_dev (&hiddev_driver, 1, &minor);
+ retval = usb_register_dev (&hiddev_fops, HIDDEV_MINOR_BASE, 1, &minor);
if (retval) {
- if (retval != -ENODEV) {
- err ("Not able to get a minor for this device.");
- return -1;
- }
- for (minor = 0; minor < HIDDEV_MINORS && hiddev_table[minor]; minor++);
- if (minor == HIDDEV_MINORS) {
- printk(KERN_ERR "hiddev: no more free hiddev devices\n");
- return -1;
- }
+ err ("Not able to get a minor for this device.");
+ return -1;
}
- if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL)))
+ if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL))) {
+ usb_deregister_dev (1, minor);
return -1;
+ }
memset(hiddev, 0, sizeof(struct hiddev));
init_waitqueue_head(&hiddev->wait);
@@ -708,9 +703,6 @@ static void *hiddev_usbd_probe(struct usb_device *dev, unsigned int ifnum,
static /* const */ struct usb_driver hiddev_driver = {
name: "hiddev",
probe: hiddev_usbd_probe,
- fops: &hiddev_fops,
- minor: HIDDEV_MINOR_BASE,
- num_minors: HIDDEV_MINORS,
};
int __init hiddev_init(void)
diff --git a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c
index 7df4e9eaba47..3658e693484f 100644
--- a/drivers/usb/media/dabusb.c
+++ b/drivers/usb/media/dabusb.c
@@ -742,14 +742,9 @@ static void *dabusb_probe (struct usb_device *usbdev, unsigned int ifnum,
if (ifnum != _DABUSB_IF && usbdev->descriptor.idProduct == 0x9999)
return NULL;
- retval = usb_register_dev (&dabusb_driver, 1, &devnum);
- if (retval) {
- if (retval != -ENODEV)
- return NULL;
- devnum = dabusb_find_struct ();
- if (devnum == -1)
- return NULL;
- }
+ retval = usb_register_dev (&dabusb_fops, DABUSB_MINOR, 1, &devnum);
+ if (retval)
+ return NULL;
s = &dabusb[devnum];
@@ -791,7 +786,7 @@ static void dabusb_disconnect (struct usb_device *usbdev, void *ptr)
dbg("dabusb_disconnect");
- usb_deregister_dev (&dabusb_driver, 1, s->devnum);
+ usb_deregister_dev (1, s->devnum);
s->remove_pending = 1;
wake_up (&s->wait);
if (s->state == _started)
@@ -814,9 +809,6 @@ static struct usb_driver dabusb_driver =
name: "dabusb",
probe: dabusb_probe,
disconnect: dabusb_disconnect,
- fops: &dabusb_fops,
- minor: DABUSB_MINOR,
- num_minors: NRDABUSB,
id_table: dabusb_ids,
};
diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
index a77c19622b53..0d55087b038b 100644
--- a/drivers/usb/misc/auerswald.c
+++ b/drivers/usb/misc/auerswald.c
@@ -1948,23 +1948,11 @@ static void *auerswald_probe (struct usb_device *usbdev, unsigned int ifnum,
init_waitqueue_head (&cp->bufferwait);
down (&dev_table_mutex);
- ret = usb_register_dev (&auerswald_driver, 1, &dtindex);
+ ret = usb_register_dev (&auerswald_fops, AUER_MINOR_BASE, 1, &dtindex);
if (ret) {
- if (ret != -ENODEV) {
- err ("Not able to get a minor for this device.");
- up (&dev_table_mutex);
- goto pfail;
- }
- /* find a free slot in the device table */
- for (dtindex = 0; dtindex < AUER_MAX_DEVICES; ++dtindex) {
- if (dev_table[dtindex] == NULL)
- break;
- }
- if ( dtindex >= AUER_MAX_DEVICES) {
- err ("more than %d devices plugged in, can not handle this device", AUER_MAX_DEVICES);
- up (&dev_table_mutex);
- goto pfail;
- }
+ err ("Not able to get a minor for this device.");
+ up (&dev_table_mutex);
+ goto pfail;
}
/* Give the device a name */
@@ -2096,7 +2084,7 @@ static void auerswald_disconnect (struct usb_device *usbdev, void *driver_contex
devfs_unregister (cp->devfs);
/* give back our USB minor number */
- usb_deregister_dev (&auerswald_driver, 1, cp->dtindex);
+ usb_deregister_dev (1, cp->dtindex);
/* Stop the interrupt endpoint */
auerswald_int_release (cp);
@@ -2153,9 +2141,6 @@ static struct usb_driver auerswald_driver = {
name: "auerswald",
probe: auerswald_probe,
disconnect: auerswald_disconnect,
- fops: &auerswald_fops,
- minor: AUER_MINOR_BASE,
- num_minors: AUER_MAX_DEVICES,
id_table: auerswald_ids,
};
diff --git a/drivers/usb/misc/brlvger.c b/drivers/usb/misc/brlvger.c
index 7792f1c86ec5..52b815eb57a3 100644
--- a/drivers/usb/misc/brlvger.c
+++ b/drivers/usb/misc/brlvger.c
@@ -246,9 +246,6 @@ static struct usb_driver brlvger_driver =
name: "brlvger",
probe: brlvger_probe,
disconnect: brlvger_disconnect,
- fops: &brlvger_fops,
- minor: BRLVGER_MINOR,
- num_minors: MAX_NR_BRLVGER_DEVS,
id_table: brlvger_ids,
};
@@ -316,21 +313,10 @@ brlvger_probe (struct usb_device *dev, unsigned ifnum,
down(&reserve_sem);
- retval = usb_register_dev(&brlvger_driver, 1, &i);
+ retval = usb_register_dev(&brlvger_fops, BRLVGER_MINOR, 1, &i);
if (retval) {
- if (retval != -ENODEV) {
- err("Not able to get a minor for this device.");
- goto error;
- }
- for( i = 0; i < MAX_NR_BRLVGER_DEVS; i++ )
- if( display_table[i] == NULL )
- break;
-
- if( i == MAX_NR_BRLVGER_DEVS ) {
- err( "This driver cannot handle more than %d "
- "braille displays", MAX_NR_BRLVGER_DEVS);
- goto error;
- }
+ err("Not able to get a minor for this device.");
+ goto error;
}
if( !(priv = kmalloc (sizeof *priv, GFP_KERNEL)) ){
@@ -431,7 +417,7 @@ brlvger_disconnect(struct usb_device *dev, void *ptr)
info("Display %d disconnecting", priv->subminor);
devfs_unregister(priv->devfs);
- usb_deregister_dev(&brlvger_driver, 1, priv->subminor);
+ usb_deregister_dev(1, priv->subminor);
down(&disconnect_sem);
display_table[priv->subminor] = NULL;
diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
index b3f5d0b7bf7f..705f753b8ed2 100644
--- a/drivers/usb/misc/rio500.c
+++ b/drivers/usb/misc/rio500.c
@@ -49,7 +49,11 @@
#define DRIVER_AUTHOR "Cesar Miquel <miquel@df.uba.ar>"
#define DRIVER_DESC "USB Rio 500 driver"
-#define RIO_MINOR 64
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+ #define RIO_MINOR 0
+#else
+ #define RIO_MINOR 64
+#endif
/* stall/wait timeout for rio */
#define NAK_TIMEOUT (HZ)
@@ -65,6 +69,7 @@ struct rio_usb_data {
unsigned int ifnum; /* Interface number of the USB device */
int isopen; /* nz if open */
int present; /* Device is present on the bus */
+ int minor; /* minor number assigned to us */
char *obuf, *ibuf; /* transfer buffers */
char bulk_in_ep, bulk_out_ep; /* Endpoint assignments */
wait_queue_head_t wait_q; /* for timeouts */
@@ -449,9 +454,16 @@ static void *probe_rio(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id)
{
struct rio_usb_data *rio = &rio_instance;
+ int retval;
info("USB Rio found at address %d", dev->devnum);
+ retval = usb_register_dev(&usb_rio_fops, RIO_MINOR, 1, &rio->minor);
+ if (retval) {
+ err("Not able to get a minor for this device.");
+ return NULL;
+ }
+
rio->present = 1;
rio->rio_dev = dev;
@@ -486,6 +498,7 @@ static void disconnect_rio(struct usb_device *dev, void *ptr)
struct rio_usb_data *rio = (struct rio_usb_data *) ptr;
devfs_unregister(rio->devfs);
+ usb_deregister_dev(1, rio->minor);
down(&(rio->lock));
if (rio->isopen) {
@@ -515,9 +528,6 @@ static struct usb_driver rio_driver = {
name: "rio500",
probe: probe_rio,
disconnect: disconnect_rio,
- fops: &usb_rio_fops,
- minor: RIO_MINOR,
- num_minors: 1,
id_table: rio_table,
};
diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c
index 11e3f6bb4d5e..a7d9c72cdbcc 100644
--- a/drivers/usb/net/pegasus.c
+++ b/drivers/usb/net/pegasus.c
@@ -1,46 +1,34 @@
/*
-** Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller
-**
-** Copyright (c) 1999-2002 Petko Manolov (petkan@users.sourceforge.net)
-**
-**
-** ChangeLog:
-** .... Most of the time spend reading sources & docs.
-** v0.2.x First official release for the Linux kernel.
-** v0.3.0 Beutified and structured, some bugs fixed.
-** v0.3.x URBifying bulk requests and bugfixing. First relatively
-** stable release. Still can touch device's registers only
-** from top-halves.
-** v0.4.0 Control messages remained unurbified are now URBs.
-** Now we can touch the HW at any time.
-** v0.4.9 Control urbs again use process context to wait. Argh...
-** Some long standing bugs (enable_net_traffic) fixed.
-** Also nasty trick about resubmiting control urb from
-** interrupt context used. Please let me know how it
-** behaves. Pegasus II support added since this version.
-** TODO: suppressing HCD warnings spewage on disconnect.
-** v0.4.13 Ethernet address is now set at probe(), not at open()
-** time as this seems to break dhcpd.
-** v0.5.0 branch to 2.5.x kernels
-** v0.5.1 ethtool support added
-*/
-
-/*
- * 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.
+ * Copyright (c) 1999-2002 Petko Manolov (petkan@users.sourceforge.net)
*
- * 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.
+ * 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.
*
- * 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
+ * ChangeLog:
+ * .... Most of the time spent on reading sources & docs.
+ * v0.2.x First official release for the Linux kernel.
+ * v0.3.0 Beutified and structured, some bugs fixed.
+ * v0.3.x URBifying bulk requests and bugfixing. First relatively
+ * stable release. Still can touch device's registers only
+ * from top-halves.
+ * v0.4.0 Control messages remained unurbified are now URBs.
+ * Now we can touch the HW at any time.
+ * v0.4.9 Control urbs again use process context to wait. Argh...
+ * Some long standing bugs (enable_net_traffic) fixed.
+ * Also nasty trick about resubmiting control urb from
+ * interrupt context used. Please let me know how it
+ * behaves. Pegasus II support added since this version.
+ * TODO: suppressing HCD warnings spewage on disconnect.
+ * v0.4.13 Ethernet address is now set at probe(), not at open()
+ * time as this seems to break dhcpd.
+ * v0.5.0 branch to 2.5.x kernels
+ * v0.5.1 ethtool support added
+ * v0.5.5 rx socket buffers are in a pool and the their allocation
+ * is out of the interrupt routine.
*/
+
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/init.h>
@@ -58,14 +46,13 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v0.5.4 (2002/04/11)"
+#define DRIVER_VERSION "v0.5.6 (2002/06/23)"
#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
static const char driver_name[] = "pegasus";
-#define PEGASUS_USE_INTR
-#define PEGASUS_WRITE_EEPROM
+#undef PEGASUS_WRITE_EEPROM
#define BMSR_MEDIA (BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | \
BMSR_100FULL | BMSR_ANEGCAPABLE)
@@ -499,13 +486,57 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb)
return 0;
}
+static void fill_skb_pool(pegasus_t *pegasus)
+{
+ int i;
+
+ for (i=0; i < RX_SKBS; i++) {
+ if (pegasus->rx_pool[i])
+ continue;
+ pegasus->rx_pool[i] = dev_alloc_skb(PEGASUS_MTU + 2);
+ /*
+ ** we give up if the allocation fail. the tasklet will be
+ ** rescheduled again anyway...
+ */
+ if (pegasus->rx_pool[i] == NULL)
+ return;
+ pegasus->rx_pool[i]->dev = pegasus->net;
+ skb_reserve(pegasus->rx_pool[i], 2);
+ }
+}
+
+static void free_skb_pool(pegasus_t *pegasus)
+{
+ int i;
+
+ for (i=0; i < RX_SKBS; i++) {
+ if (pegasus->rx_pool[i]) {
+ dev_kfree_skb(pegasus->rx_pool[i]);
+ pegasus->rx_pool[i] = NULL;
+ }
+ }
+}
+
+static inline struct sk_buff *pull_skb(pegasus_t *pegasus)
+{
+ int i;
+ struct sk_buff *skb;
+
+ for (i=0; i < RX_SKBS; i++) {
+ if (likely(pegasus->rx_pool[i] != NULL)) {
+ skb = pegasus->rx_pool[i];
+ pegasus->rx_pool[i] = NULL;
+ return skb;
+ }
+ }
+ return NULL;
+}
+
static void read_bulk_callback(struct urb *urb)
{
pegasus_t *pegasus = urb->context;
struct net_device *net;
- int count = urb->actual_length;
- int rx_status;
- struct sk_buff *skb;
+ int rx_status, count = urb->actual_length;
__u16 pkt_len;
if (!pegasus || !(pegasus->flags & PEGASUS_RUNNING))
@@ -519,7 +550,7 @@ static void read_bulk_callback(struct urb *urb)
case 0:
break;
case -ETIMEDOUT:
- dbg("reset MAC");
+ dbg("%s: reset MAC", net->name);
pegasus->flags &= ~PEGASUS_RX_BUSY;
break;
case -ENOENT:
@@ -546,23 +577,24 @@ static void read_bulk_callback(struct urb *urb)
}
pkt_len = (rx_status & 0xfff) - 8;
- if (!pegasus->rx_skb)
- goto tl_sched;
-
+ if (pegasus->rx_skb == NULL)
+ printk("%s: rx_skb == NULL\n", __FUNCTION__);
+ /*
+ ** we are sure at this point pegasus->rx_skb != NULL
+ ** so we go ahead and pass up the packet.
+ */
skb_put(pegasus->rx_skb, pkt_len);
pegasus->rx_skb->protocol = eth_type_trans(pegasus->rx_skb, net);
netif_rx(pegasus->rx_skb);
-
- if (!(skb = dev_alloc_skb(PEGASUS_MTU + 2))) {
- pegasus->rx_skb = NULL;
- goto tl_sched;
- }
-
- skb->dev = net;
- skb_reserve(skb, 2);
- pegasus->rx_skb = skb;
pegasus->stats.rx_packets++;
pegasus->stats.rx_bytes += pkt_len;
+
+ spin_lock(&pegasus->rx_pool_lock);
+ pegasus->rx_skb = pull_skb(pegasus);
+ spin_unlock(&pegasus->rx_pool_lock);
+
+ if (pegasus->rx_skb == NULL)
+ goto tl_sched;
goon:
FILL_BULK_URB(pegasus->rx_urb, pegasus->usb,
usb_rcvbulkpipe(pegasus->usb, 1),
@@ -587,11 +619,19 @@ static void rx_fixup(unsigned long data)
pegasus = (pegasus_t *)data;
+ spin_lock_irq(&pegasus->rx_pool_lock);
+ fill_skb_pool(pegasus);
+ spin_unlock_irq(&pegasus->rx_pool_lock);
if (pegasus->flags & PEGASUS_RX_URB_FAIL)
if (pegasus->rx_skb)
goto try_again;
-
- if (!(pegasus->rx_skb = dev_alloc_skb(PEGASUS_MTU + 2))) {
+ if (pegasus->rx_skb == NULL) {
+ spin_lock_irq(&pegasus->rx_pool_lock);
+ pegasus->rx_skb = pull_skb(pegasus);
+ spin_unlock_irq(&pegasus->rx_pool_lock);
+ }
+ if (pegasus->rx_skb == NULL) {
+ warn("wow, low on memory");
tasklet_schedule(&pegasus->rx_tl);
return;
}
@@ -625,7 +665,6 @@ static void write_bulk_callback(struct urb *urb)
netif_wake_queue(pegasus->net);
}
-#ifdef PEGASUS_USE_INTR
static void intr_callback(struct urb *urb)
{
pegasus_t *pegasus = urb->context;
@@ -662,7 +701,6 @@ static void intr_callback(struct urb *urb)
}
}
}
-#endif
static void pegasus_tx_timeout(struct net_device *net)
{
@@ -748,15 +786,62 @@ static void set_carrier(struct net_device *net)
}
+static void free_all_urbs(pegasus_t *pegasus)
+{
+ usb_free_urb(pegasus->intr_urb);
+ usb_free_urb(pegasus->tx_urb);
+ usb_free_urb(pegasus->rx_urb);
+ usb_free_urb(pegasus->ctrl_urb);
+}
+
+static void unlink_all_urbs(pegasus_t *pegasus)
+{
+ usb_unlink_urb(pegasus->intr_urb);
+ usb_unlink_urb(pegasus->tx_urb);
+ usb_unlink_urb(pegasus->rx_urb);
+ usb_unlink_urb(pegasus->ctrl_urb);
+}
+
+static int alloc_urbs(pegasus_t *pegasus)
+{
+ pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!pegasus->ctrl_urb) {
+ return 0;
+ }
+ pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!pegasus->rx_urb) {
+ usb_free_urb(pegasus->ctrl_urb);
+ return 0;
+ }
+ pegasus->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!pegasus->tx_urb) {
+ usb_free_urb(pegasus->rx_urb);
+ usb_free_urb(pegasus->ctrl_urb);
+ return 0;
+ }
+ pegasus->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!pegasus->intr_urb) {
+ usb_free_urb(pegasus->tx_urb);
+ usb_free_urb(pegasus->rx_urb);
+ usb_free_urb(pegasus->ctrl_urb);
+ return 0;
+ }
+
+ return 1;
+}
+
static int pegasus_open(struct net_device *net)
{
pegasus_t *pegasus = (pegasus_t *) net->priv;
int res;
- if (!(pegasus->rx_skb = dev_alloc_skb(PEGASUS_MTU + 2)))
+ if (pegasus->rx_skb == NULL)
+ pegasus->rx_skb = pull_skb(pegasus);
+ /*
+ ** Note: no point to free the pool. it is empty :-)
+ */
+ if (!pegasus->rx_skb)
return -ENOMEM;
- pegasus->rx_skb->dev = net;
- skb_reserve(pegasus->rx_skb, 2);
down(&pegasus->sem);
FILL_BULK_URB(pegasus->rx_urb, pegasus->usb,
@@ -765,19 +850,20 @@ static int pegasus_open(struct net_device *net)
read_bulk_callback, pegasus);
if ((res = usb_submit_urb(pegasus->rx_urb, GFP_KERNEL)))
warn("%s: failed rx_urb %d", __FUNCTION__, res);
-#ifdef PEGASUS_USE_INTR
FILL_INT_URB(pegasus->intr_urb, pegasus->usb,
usb_rcvintpipe(pegasus->usb, 3),
pegasus->intr_buff, sizeof(pegasus->intr_buff),
intr_callback, pegasus, pegasus->intr_interval);
if ((res = usb_submit_urb(pegasus->intr_urb, GFP_KERNEL)))
warn("%s: failed intr_urb %d", __FUNCTION__, res);
-#endif
netif_start_queue(net);
pegasus->flags |= PEGASUS_RUNNING;
if ((res = enable_net_traffic(net, pegasus->usb))) {
err("can't enable_net_traffic() - %d", res);
res = -EIO;
+ usb_unlink_urb(pegasus->rx_urb);
+ usb_unlink_urb(pegasus->intr_urb);
+ free_skb_pool(pegasus);
goto exit;
}
set_carrier(net);
@@ -797,13 +883,7 @@ static int pegasus_close(struct net_device *net)
netif_stop_queue(net);
if (!(pegasus->flags & PEGASUS_UNPLUG))
disable_net_traffic(pegasus);
-
- usb_unlink_urb(pegasus->rx_urb);
- usb_unlink_urb(pegasus->tx_urb);
- usb_unlink_urb(pegasus->ctrl_urb);
-#ifdef PEGASUS_USE_INTR
- usb_unlink_urb(pegasus->intr_urb);
-#endif
+ unlink_all_urbs(pegasus);
up(&pegasus->sem);
return 0;
@@ -986,38 +1066,14 @@ static void *pegasus_probe(struct usb_device *dev, unsigned int ifnum,
pegasus->dev_index = dev_index;
init_waitqueue_head(&pegasus->ctrl_wait);
- pegasus->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!pegasus->ctrl_urb) {
- kfree(pegasus);
- return NULL;
- }
- pegasus->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!pegasus->rx_urb) {
- usb_free_urb(pegasus->ctrl_urb);
- kfree(pegasus);
- return NULL;
- }
- pegasus->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!pegasus->tx_urb) {
- usb_free_urb(pegasus->rx_urb);
- usb_free_urb(pegasus->ctrl_urb);
- kfree(pegasus);
- return NULL;
- }
- pegasus->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!pegasus->intr_urb) {
- usb_free_urb(pegasus->tx_urb);
- usb_free_urb(pegasus->rx_urb);
- usb_free_urb(pegasus->ctrl_urb);
+ if (!alloc_urbs(pegasus)) {
kfree(pegasus);
return NULL;
}
net = init_etherdev(NULL, 0);
if (!net) {
- usb_free_urb(pegasus->tx_urb);
- usb_free_urb(pegasus->rx_urb);
- usb_free_urb(pegasus->ctrl_urb);
+ free_all_urbs(pegasus);
kfree(pegasus);
return NULL;
}
@@ -1039,32 +1095,26 @@ static void *pegasus_probe(struct usb_device *dev, unsigned int ifnum,
net->set_multicast_list = pegasus_set_multicast;
net->get_stats = pegasus_netdev_stats;
net->mtu = PEGASUS_MTU;
+ spin_lock_init(&pegasus->rx_pool_lock);
pegasus->features = usb_dev_id[dev_index].private;
-#ifdef PEGASUS_USE_INTR
get_interrupt_interval(pegasus);
-#endif
if (reset_mac(pegasus)) {
err("can't reset MAC");
unregister_netdev(pegasus->net);
- usb_free_urb(pegasus->tx_urb);
- usb_free_urb(pegasus->rx_urb);
- usb_free_urb(pegasus->ctrl_urb);
+ free_all_urbs(pegasus);
kfree(pegasus->net);
kfree(pegasus);
pegasus = NULL;
goto exit;
}
-
- info("%s: %s", net->name, usb_dev_id[dev_index].name);
-
set_ethernet_addr(pegasus);
-
+ fill_skb_pool(pegasus);
+ printk("%s: %s\n", net->name, usb_dev_id[dev_index].name);
if (pegasus->features & PEGASUS_II) {
info("setup Pegasus II specific registers");
setup_pegasus_II(pegasus);
}
-
pegasus->phy = mii_phy_probe(pegasus);
if (pegasus->phy == 0xff) {
warn("can't locate MII phy, using default");
@@ -1087,14 +1137,9 @@ static void pegasus_disconnect(struct usb_device *dev, void *ptr)
pegasus->flags |= PEGASUS_UNPLUG;
unregister_netdev(pegasus->net);
usb_put_dev(dev);
- usb_unlink_urb(pegasus->intr_urb);
- usb_unlink_urb(pegasus->tx_urb);
- usb_unlink_urb(pegasus->rx_urb);
- usb_unlink_urb(pegasus->ctrl_urb);
- usb_free_urb(pegasus->intr_urb);
- usb_free_urb(pegasus->tx_urb);
- usb_free_urb(pegasus->rx_urb);
- usb_free_urb(pegasus->ctrl_urb);
+ unlink_all_urbs(pegasus);
+ free_all_urbs(pegasus);
+ free_skb_pool(pegasus);
if (pegasus->rx_skb)
dev_kfree_skb(pegasus->rx_skb);
kfree(pegasus->net);
diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h
index 6e25d3efd5e1..d231998a4698 100644
--- a/drivers/usb/net/pegasus.h
+++ b/drivers/usb/net/pegasus.h
@@ -2,18 +2,8 @@
* Copyright (c) 1999-2002 Petko Manolov - Petkan (petkan@users.sourceforge.net)
*
* 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
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
*/
@@ -23,6 +13,7 @@
#define HAS_HOME_PNA 0x40000000
#define PEGASUS_MTU 1536
+#define RX_SKBS 4
#define EPROM_WRITE 0x01
#define EPROM_READ 0x02
@@ -100,10 +91,12 @@ typedef struct pegasus {
int intr_interval;
struct tasklet_struct rx_tl;
struct urb *ctrl_urb, *rx_urb, *tx_urb, *intr_urb;
+ struct sk_buff *rx_pool[RX_SKBS];
struct sk_buff *rx_skb;
struct usb_ctrlrequest dr;
wait_queue_head_t ctrl_wait;
struct semaphore sem;
+ spinlock_t rx_pool_lock;
unsigned char intr_buff[8];
__u8 tx_buff[PEGASUS_MTU];
__u8 eth_regs[4];
diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
index 3934c4dd5069..ffd2737fee5b 100644
--- a/drivers/usb/net/rtl8150.c
+++ b/drivers/usb/net/rtl8150.c
@@ -1,15 +1,14 @@
/*
- * Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.net)
- *
- * 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.
+ * Copyright (c) 2002 Petko Manolov (petkan@users.sourceforge.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/config.h>
#include <linux/sched.h>
+#include <linux/init.h>
#include <linux/signal.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -19,7 +18,6 @@
#include <linux/ethtool.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/usb.h>
-#include <linux/init.h>
#include <asm/uaccess.h>
/* Version Information */
@@ -106,7 +104,7 @@ unsigned long multicast_filter_limit = 32;
static void fill_skb_pool(rtl8150_t *);
static void free_skb_pool(rtl8150_t *);
-static struct sk_buff *pull_skb(rtl8150_t *);
+static inline struct sk_buff *pull_skb(rtl8150_t *);
static void rtl8150_disconnect(struct usb_device *dev, void *ptr);
static void *rtl8150_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id);
@@ -312,7 +310,7 @@ static void read_bulk_callback(struct urb *urb)
case -ENOENT:
return; /* the urb is in unlink state */
case -ETIMEDOUT:
- warn("reset needed may be?..");
+ warn("may be reset is needed?..");
goto goon;
default:
warn("Rx status %d", urb->status);
@@ -331,13 +329,13 @@ static void read_bulk_callback(struct urb *urb)
netif_rx(dev->rx_skb);
dev->stats.rx_packets++;
dev->stats.rx_bytes += pkt_len;
-
+
+ spin_lock(&dev->rx_pool_lock);
skb = pull_skb(dev);
+ spin_unlock(&dev->rx_pool_lock);
if (!skb)
goto resched;
- skb->dev = netdev;
- skb_reserve(skb, 2);
dev->rx_skb = skb;
goon:
FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
@@ -361,11 +359,16 @@ static void rx_fixup(unsigned long data)
dev = (rtl8150_t *)data;
+ spin_lock_irq(&dev->rx_pool_lock);
fill_skb_pool(dev);
+ spin_unlock_irq(&dev->rx_pool_lock);
if (test_bit(RX_URB_FAIL, &dev->flags))
if (dev->rx_skb)
goto try_again;
- if (!(skb = pull_skb(dev)))
+ spin_lock_irq(&dev->rx_pool_lock);
+ skb = pull_skb(dev);
+ spin_unlock_irq(&dev->rx_pool_lock);
+ if (skb == NULL)
goto tlsched;
dev->rx_skb = skb;
FILL_BULK_URB(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
@@ -426,51 +429,41 @@ static void fill_skb_pool(rtl8150_t *dev)
{
struct sk_buff *skb;
int i;
- unsigned long flags;
- spin_lock_irqsave(&dev->rx_pool_lock, flags);
for (i = 0; i < RX_SKB_POOL_SIZE; i++) {
if (dev->rx_skb_pool[i])
continue;
skb = dev_alloc_skb(RTL8150_MTU + 2);
if (!skb) {
- spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
return;
}
skb->dev = dev->netdev;
skb_reserve(skb, 2);
dev->rx_skb_pool[i] = skb;
}
- spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
}
static void free_skb_pool(rtl8150_t *dev)
{
int i;
- spin_lock_irq(&dev->rx_pool_lock);
for (i = 0; i < RX_SKB_POOL_SIZE; i++)
if (dev->rx_skb_pool[i])
dev_kfree_skb(dev->rx_skb_pool[i]);
- spin_unlock_irq(&dev->rx_pool_lock);
}
-static struct sk_buff *pull_skb(rtl8150_t *dev)
+static inline struct sk_buff *pull_skb(rtl8150_t *dev)
{
struct sk_buff *skb;
int i;
- unsigned long flags;
- spin_lock_irqsave(&dev->rx_pool_lock, flags);
for (i = 0; i < RX_SKB_POOL_SIZE; i++) {
if (dev->rx_skb_pool[i]) {
skb = dev->rx_skb_pool[i];
dev->rx_skb_pool[i] = NULL;
- spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
return skb;
}
}
- spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
return NULL;
}
@@ -578,8 +571,8 @@ static int rtl8150_open(struct net_device *netdev)
if (dev == NULL) {
return -ENODEV;
}
-
- dev->rx_skb = pull_skb(dev);
+ if (dev->rx_skb == NULL)
+ dev->rx_skb = pull_skb(dev);
if (!dev->rx_skb)
return -ENOMEM;
@@ -816,13 +809,13 @@ static void rtl8150_disconnect(struct usb_device *udev, void *ptr)
dev = NULL;
}
-static int __init usb_rtl8150_init(void)
+int __init usb_rtl8150_init(void)
{
info(DRIVER_DESC " " DRIVER_VERSION);
return usb_register(&rtl8150_driver);
}
-static void __exit usb_rtl8150_exit(void)
+void __exit usb_rtl8150_exit(void)
{
usb_deregister(&rtl8150_driver);
}
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index bcf22f6c2d9f..b7b61cf82d58 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -428,18 +428,13 @@ int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
void *data, u16 size)
{
int status;
- struct usb_ctrlrequest *dr;
-
- dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
- if (!dr)
- return -ENOMEM;
/* fill in the devrequest structure */
- dr->bRequestType = requesttype;
- dr->bRequest = request;
- dr->wValue = cpu_to_le16(value);
- dr->wIndex = cpu_to_le16(index);
- dr->wLength = cpu_to_le16(size);
+ us->dr->bRequestType = requesttype;
+ us->dr->bRequest = request;
+ us->dr->wValue = cpu_to_le16(value);
+ us->dr->wIndex = cpu_to_le16(index);
+ us->dr->wLength = cpu_to_le16(size);
/* lock the URB */
down(&(us->current_urb_sem));
@@ -452,7 +447,7 @@ int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
/* fill the URB */
FILL_CONTROL_URB(us->current_urb, us->pusb_dev, pipe,
- (unsigned char*) dr, data, size,
+ (unsigned char*) us->dr, data, size,
usb_stor_blocking_completion, NULL);
/* submit the URB */
@@ -1162,7 +1157,7 @@ int usb_stor_Bulk_max_lun(struct us_data *us)
int pipe;
/* issue the command -- use usb_control_msg() because
- * the state machine is not yet alive */
+ * this is not a scsi queued-command */
pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
result = usb_control_msg(us->pusb_dev, pipe,
US_BULK_GET_MAX_LUN,
@@ -1181,8 +1176,8 @@ int usb_stor_Bulk_max_lun(struct us_data *us)
if (result == -EPIPE) {
US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
- /* Use usb_clear_halt() because the state machine
- * is not yet alive */
+ /* Use usb_clear_halt() because this is not a
+ * scsi queued-command */
usb_clear_halt(us->pusb_dev, pipe);
}
@@ -1356,27 +1351,6 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
* Reset routines
***********************************************************************/
-struct us_timeout {
- struct us_data *us;
- spinlock_t timer_lock;
-};
-
-/* The timeout event handler
- */
-static void usb_stor_timeout_handler(unsigned long to__)
-{
- struct us_timeout *to = (struct us_timeout *) to__;
- struct us_data *us = to->us;
-
- US_DEBUGP("Timeout occurred\n");
-
- /* abort the current request */
- usb_stor_abort_transport(us);
-
- /* let the reset routine know we have finished */
- spin_unlock(&to->timer_lock);
-}
-
/* This is the common part of the device reset code.
*
* It's handy that every transport mechanism uses the control endpoint for
@@ -1385,28 +1359,20 @@ static void usb_stor_timeout_handler(unsigned long to__)
* Basically, we send a reset with a 20-second timeout, so we don't get
* jammed attempting to do the reset.
*/
-void usb_stor_reset_common(struct us_data *us, u8 request, u8 requesttype,
+static int usb_stor_reset_common(struct us_data *us,
+ u8 request, u8 requesttype,
u16 value, u16 index, void *data, u16 size)
{
int result;
- struct us_timeout timeout_data = {us, SPIN_LOCK_UNLOCKED};
- struct timer_list timeout_list;
-
- /* prepare the timeout handler */
- spin_lock(&timeout_data.timer_lock);
- init_timer(&timeout_list);
/* A 20-second timeout may seem rather long, but a LaCie
* StudioDrive USB2 device takes 16+ seconds to get going
* following a powerup or USB attach event. */
- timeout_list.expires = jiffies + 20 * HZ;
- timeout_list.data = (unsigned long) &timeout_data;
- timeout_list.function = usb_stor_timeout_handler;
- add_timer(&timeout_list);
-
- result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0),
- request, requesttype, value, index, data, size);
+ /* Use usb_control_msg() because this is not a queued-command */
+ result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
+ request, requesttype, value, index, data, size,
+ 20*HZ);
if (result < 0)
goto Done;
@@ -1415,41 +1381,30 @@ void usb_stor_reset_common(struct us_data *us, u8 request, u8 requesttype,
schedule_timeout(HZ*6);
set_current_state(TASK_RUNNING);
+ /* Use usb_clear_halt() because this is not a queued-command */
US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n");
- result = usb_stor_clear_halt(us,
+ result = usb_clear_halt(us->pusb_dev,
usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
if (result < 0)
goto Done;
US_DEBUGP("Soft reset: clearing bulk-out endpoint halt\n");
- result = usb_stor_clear_halt(us,
+ result = usb_clear_halt(us->pusb_dev,
usb_sndbulkpipe(us->pusb_dev, us->ep_out));
Done:
- /* prevent the timer from coming back to haunt us */
- if (!del_timer(&timeout_list)) {
- /* the handler has already started; wait for it to finish */
- spin_lock(&timeout_data.timer_lock);
- /* change the abort into a timeout */
- if (result == -ENOENT)
- result = -ETIMEDOUT;
- }
-
/* return a result code based on the result of the control message */
- if (result >= 0)
- US_DEBUGP("Soft reset done\n");
- else
+ if (result < 0) {
US_DEBUGP("Soft reset failed: %d\n", result);
-
- if (result == -ETIMEDOUT)
- us->srb->result = DID_TIME_OUT << 16;
- else if (result == -ENOENT)
- us->srb->result = DID_ABORT << 16;
- else if (result < 0)
us->srb->result = DID_ERROR << 16;
- else
+ result = FAILED;
+ } else {
+ US_DEBUGP("Soft reset done\n");
us->srb->result = GOOD << 1;
+ result = SUCCESS;
+ }
+ return result;
}
/* This issues a CB[I] Reset to the device in question
@@ -1463,10 +1418,9 @@ int usb_stor_CB_reset(struct us_data *us)
memset(cmd, 0xFF, sizeof(cmd));
cmd[0] = SEND_DIAGNOSTIC;
cmd[1] = 4;
- usb_stor_reset_common(us, US_CBI_ADSC,
+ return usb_stor_reset_common(us, US_CBI_ADSC,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, us->ifnum, cmd, sizeof(cmd));
- return (us->srb->result == GOOD << 1 ? SUCCESS : FAILED);
}
/* This issues a Bulk-only Reset to the device in question, including
@@ -1476,8 +1430,7 @@ int usb_stor_Bulk_reset(struct us_data *us)
{
US_DEBUGP("Bulk reset requested\n");
- usb_stor_reset_common(us, US_BULK_RESET_REQUEST,
+ return usb_stor_reset_common(us, US_BULK_RESET_REQUEST,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, us->ifnum, NULL, 0);
- return (us->srb->result == GOOD << 1 ? SUCCESS : FAILED);
}
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 76d70eb5a9bf..a065df6da68d 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -361,65 +361,42 @@ static int usb_stor_control_thread(void * __us)
BUG_ON(action != US_ACT_COMMAND);
+ /* lock the device pointers */
+ down(&(us->dev_semaphore));
+
/* reject the command if the direction indicator
* is UNKNOWN
*/
if (us->srb->sc_data_direction == SCSI_DATA_UNKNOWN) {
US_DEBUGP("UNKNOWN data direction\n");
us->srb->result = DID_ERROR << 16;
- scsi_lock(host);
- us->srb->scsi_done(us->srb);
- us->srb = NULL;
- scsi_unlock(host);
- continue;
}
/* reject if target != 0 or if LUN is higher than
* the maximum known LUN
*/
- if (us->srb->target &&
+ else if (us->srb->target &&
!(us->flags & US_FL_SCM_MULT_TARG)) {
US_DEBUGP("Bad target number (%d/%d)\n",
us->srb->target, us->srb->lun);
us->srb->result = DID_BAD_TARGET << 16;
-
- scsi_lock(host);
- us->srb->scsi_done(us->srb);
- us->srb = NULL;
- scsi_unlock(host);
- continue;
}
- if (us->srb->lun > us->max_lun) {
+ else if (us->srb->lun > us->max_lun) {
US_DEBUGP("Bad LUN (%d/%d)\n",
us->srb->target, us->srb->lun);
us->srb->result = DID_BAD_TARGET << 16;
-
- scsi_lock(host);
- us->srb->scsi_done(us->srb);
- us->srb = NULL;
- scsi_unlock(host);
- continue;
}
/* handle those devices which can't do a START_STOP */
- if ((us->srb->cmnd[0] == START_STOP) &&
+ else if ((us->srb->cmnd[0] == START_STOP) &&
(us->flags & US_FL_START_STOP)) {
US_DEBUGP("Skipping START_STOP command\n");
us->srb->result = GOOD << 1;
-
- scsi_lock(host);
- us->srb->scsi_done(us->srb);
- us->srb = NULL;
- scsi_unlock(host);
- continue;
}
- /* lock the device pointers */
- down(&(us->dev_semaphore));
-
/* our device has gone - pretend not ready */
- if (!test_bit(DEV_ATTACHED, &us->bitflags)) {
+ else if (!test_bit(DEV_ATTACHED, &us->bitflags)) {
US_DEBUGP("Request is for removed device\n");
/* For REQUEST_SENSE, it's the data. But
* for anything else, it should look like
@@ -443,24 +420,25 @@ static int usb_stor_control_thread(void * __us)
sizeof(usb_stor_sense_notready));
us->srb->result = CHECK_CONDITION << 1;
}
- } else { /* test_bit(DEV_ATTACHED, &us->bitflags) */
+ } /* test_bit(DEV_ATTACHED, &us->bitflags) */
- /* Handle those devices which need us to fake
- * their inquiry data */
- if ((us->srb->cmnd[0] == INQUIRY) &&
+ /* Handle those devices which need us to fake
+ * their inquiry data */
+ else if ((us->srb->cmnd[0] == INQUIRY) &&
(us->flags & US_FL_FIX_INQUIRY)) {
- unsigned char data_ptr[36] = {
- 0x00, 0x80, 0x02, 0x02,
- 0x1F, 0x00, 0x00, 0x00};
+ unsigned char data_ptr[36] = {
+ 0x00, 0x80, 0x02, 0x02,
+ 0x1F, 0x00, 0x00, 0x00};
- US_DEBUGP("Faking INQUIRY command\n");
- fill_inquiry_response(us, data_ptr, 36);
- us->srb->result = GOOD << 1;
- } else {
- /* we've got a command, let's do it! */
- US_DEBUG(usb_stor_show_command(us->srb));
- us->proto_handler(us->srb, us);
- }
+ US_DEBUGP("Faking INQUIRY command\n");
+ fill_inquiry_response(us, data_ptr, 36);
+ us->srb->result = GOOD << 1;
+ }
+
+ /* we've got a command, let's do it! */
+ else {
+ US_DEBUG(usb_stor_show_command(us->srb));
+ us->proto_handler(us->srb, us);
}
/* unlock the device pointers */
@@ -487,54 +465,114 @@ static int usb_stor_control_thread(void * __us)
return 0;
}
-/* Set up the IRQ pipe and handler
+/* Set up the URB, the usb_ctrlrequest, and the IRQ pipe and handler.
+ * ss->dev_semaphore should already be locked.
* Note that this function assumes that all the data in the us_data
* strucuture is current. This includes the ep_int field, which gives us
* the endpoint for the interrupt.
* Returns non-zero on failure, zero on success
*/
-static int usb_stor_allocate_irq(struct us_data *ss)
+static int usb_stor_allocate_urbs(struct us_data *ss)
{
unsigned int pipe;
int maxp;
int result;
- US_DEBUGP("Allocating IRQ for CBI transport\n");
-
- /* lock access to the data structure */
- down(&(ss->irq_urb_sem));
-
- /* allocate the URB */
- ss->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!ss->irq_urb) {
- up(&(ss->irq_urb_sem));
- US_DEBUGP("couldn't allocate interrupt URB");
+ /* allocate the URB we're going to use */
+ US_DEBUGP("Allocating URB\n");
+ ss->current_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!ss->current_urb) {
+ US_DEBUGP("allocation failed\n");
return 1;
}
- /* calculate the pipe and max packet size */
- pipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int->bEndpointAddress &
- USB_ENDPOINT_NUMBER_MASK);
- maxp = usb_maxpacket(ss->pusb_dev, pipe, usb_pipeout(pipe));
- if (maxp > sizeof(ss->irqbuf))
- maxp = sizeof(ss->irqbuf);
-
- /* fill in the URB with our data */
- FILL_INT_URB(ss->irq_urb, ss->pusb_dev, pipe, ss->irqbuf, maxp,
- usb_stor_CBI_irq, ss, ss->ep_int->bInterval);
-
- /* submit the URB for processing */
- result = usb_submit_urb(ss->irq_urb, GFP_KERNEL);
- US_DEBUGP("usb_submit_urb() returns %d\n", result);
- if (result) {
- usb_free_urb(ss->irq_urb);
- up(&(ss->irq_urb_sem));
+ /* allocate the usb_ctrlrequest for control packets */
+ US_DEBUGP("Allocating usb_ctrlrequest\n");
+ ss->dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
+ if (!ss->dr) {
+ US_DEBUGP("allocation failed\n");
return 2;
}
- /* unlock the data structure and return success */
+ /* allocate the IRQ URB, if it is needed */
+ if (ss->protocol == US_PR_CBI) {
+ US_DEBUGP("Allocating IRQ for CBI transport\n");
+
+ /* lock access to the data structure */
+ down(&(ss->irq_urb_sem));
+
+ /* allocate the URB */
+ ss->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!ss->irq_urb) {
+ up(&(ss->irq_urb_sem));
+ US_DEBUGP("couldn't allocate interrupt URB");
+ return 3;
+ }
+
+ /* calculate the pipe and max packet size */
+ pipe = usb_rcvintpipe(ss->pusb_dev,
+ ss->ep_int->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ maxp = usb_maxpacket(ss->pusb_dev, pipe, usb_pipeout(pipe));
+ if (maxp > sizeof(ss->irqbuf))
+ maxp = sizeof(ss->irqbuf);
+
+ /* fill in the URB with our data */
+ FILL_INT_URB(ss->irq_urb, ss->pusb_dev, pipe, ss->irqbuf,
+ maxp, usb_stor_CBI_irq, ss, ss->ep_int->bInterval);
+
+ /* submit the URB for processing */
+ result = usb_submit_urb(ss->irq_urb, GFP_KERNEL);
+ US_DEBUGP("usb_submit_urb() returns %d\n", result);
+ if (result) {
+ up(&(ss->irq_urb_sem));
+ return 4;
+ }
+
+ /* unlock the data structure */
+ up(&(ss->irq_urb_sem));
+
+ } /* ss->protocol == US_PR_CBI */
+
+ return 0; /* success */
+}
+
+/* Deallocate the URB, the usb_ctrlrequest, and the IRQ pipe.
+ * ss->dev_semaphore must already be locked.
+ */
+static void usb_stor_deallocate_urbs(struct us_data *ss)
+{
+ int result;
+
+ /* release the IRQ, if we have one */
+ down(&(ss->irq_urb_sem));
+ if (ss->irq_urb) {
+ US_DEBUGP("-- releasing irq URB\n");
+ result = usb_unlink_urb(ss->irq_urb);
+ US_DEBUGP("-- usb_unlink_urb() returned %d\n", result);
+ usb_free_urb(ss->irq_urb);
+ ss->irq_urb = NULL;
+ }
up(&(ss->irq_urb_sem));
- return 0;
+
+ /* free the usb_ctrlrequest buffer */
+ if (ss->dr) {
+ kfree(ss->dr);
+ ss->dr = NULL;
+ }
+
+ /* free up the main URB for this device */
+ if (ss->current_urb) {
+ US_DEBUGP("-- releasing main URB\n");
+ result = usb_unlink_urb(ss->current_urb);
+ US_DEBUGP("-- usb_unlink_urb() returned %d\n", result);
+ usb_free_urb(ss->current_urb);
+ ss->current_urb = NULL;
+ }
+
+ /* mark the device as gone */
+ clear_bit(DEV_ATTACHED, &ss->bitflags);
+ usb_put_dev(ss->pusb_dev);
+ ss->pusb_dev = NULL;
}
/* Probe to see if a new device is actually a SCSI device */
@@ -712,13 +750,8 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
USB_ENDPOINT_NUMBER_MASK;
ss->ep_int = ep_int;
- /* allocate an IRQ callback if one is needed */
- if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss))
- goto BadDevice;
-
- /* allocate the URB we're going to use */
- ss->current_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!ss->current_urb)
+ /* allocate the URB, the usb_ctrlrequest, and the IRQ URB */
+ if (usb_stor_allocate_urbs(ss))
goto BadDevice;
/* Re-Initialize the device if it needs it */
@@ -741,11 +774,6 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
memset(ss, 0, sizeof(struct us_data));
new_device = 1;
- /* allocate the URB we're going to use */
- ss->current_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!ss->current_urb)
- goto BadDevice;
-
/* Initialize the mutexes only when the struct is new */
init_completion(&(ss->notify));
init_MUTEX_LOCKED(&(ss->ip_waitq));
@@ -943,8 +971,8 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
}
US_DEBUGP("Protocol: %s\n", ss->protocol_name);
- /* allocate an IRQ callback if one is needed */
- if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss))
+ /* allocate the URB, the usb_ctrlrequest, and the IRQ URB */
+ if (usb_stor_allocate_urbs(ss))
goto BadDevice;
/*
@@ -1020,26 +1048,11 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
/* we come here if there are any problems */
BadDevice:
US_DEBUGP("storage_probe() failed\n");
- down(&ss->irq_urb_sem);
- if (ss->irq_urb) {
- usb_unlink_urb(ss->irq_urb);
- usb_free_urb(ss->irq_urb);
- ss->irq_urb = NULL;
- }
- up(&ss->irq_urb_sem);
- if (ss->current_urb) {
- usb_unlink_urb(ss->current_urb);
- usb_free_urb(ss->current_urb);
- ss->current_urb = NULL;
- }
-
- clear_bit(DEV_ATTACHED, &ss->bitflags);
- ss->pusb_dev = NULL;
+ usb_stor_deallocate_urbs(ss);
if (new_device)
kfree(ss);
else
up(&ss->dev_semaphore);
- usb_put_dev(dev);
return NULL;
}
@@ -1047,7 +1060,6 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
static void storage_disconnect(struct usb_device *dev, void *ptr)
{
struct us_data *ss = ptr;
- int result;
US_DEBUGP("storage_disconnect() called\n");
@@ -1057,33 +1069,8 @@ static void storage_disconnect(struct usb_device *dev, void *ptr)
return;
}
- /* lock access to the device data structure */
down(&(ss->dev_semaphore));
-
- /* release the IRQ, if we have one */
- down(&(ss->irq_urb_sem));
- if (ss->irq_urb) {
- US_DEBUGP("-- releasing irq URB\n");
- result = usb_unlink_urb(ss->irq_urb);
- US_DEBUGP("-- usb_unlink_urb() returned %d\n", result);
- usb_free_urb(ss->irq_urb);
- ss->irq_urb = NULL;
- }
- up(&(ss->irq_urb_sem));
-
- /* free up the main URB for this device */
- US_DEBUGP("-- releasing main URB\n");
- result = usb_unlink_urb(ss->current_urb);
- US_DEBUGP("-- usb_unlink_urb() returned %d\n", result);
- usb_free_urb(ss->current_urb);
- ss->current_urb = NULL;
-
- /* mark the device as gone */
- usb_put_dev(ss->pusb_dev);
- ss->pusb_dev = NULL;
- clear_bit(DEV_ATTACHED, &ss->bitflags);
-
- /* unlock access to the device data structure */
+ usb_stor_deallocate_urbs(ss);
up(&(ss->dev_semaphore));
}
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index d0f1f24ded28..57f175ec2866 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -185,6 +185,7 @@ struct us_data {
/* control and bulk communications data */
struct semaphore current_urb_sem; /* to protect irq_urb */
struct urb *current_urb; /* non-int USB requests */
+ struct usb_ctrlrequest *dr; /* control requests */
/* the semaphore for sleeping the control thread */
struct semaphore sema; /* to sleep thread on */
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index ae15d461fd9e..64fb0078a6cc 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -189,9 +189,6 @@ static struct usb_driver skel_driver = {
name: "skeleton",
probe: skel_probe,
disconnect: skel_disconnect,
- fops: &skel_fops,
- minor: USB_SKEL_MINOR_BASE,
- num_minors: MAX_DEVICES,
id_table: skel_table,
};
@@ -532,29 +529,18 @@ static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const stru
}
down (&minor_table_mutex);
- retval = usb_register_dev (&skel_driver, 1, &minor);
+ retval = usb_register_dev (&skel_fops, USB_SKEL_MINOR_BASE, 1, &minor);
if (retval) {
- if (retval != -ENODEV) {
- /* something prevented us from registering this driver */
- err ("Not able to get a minor for this device.");
- goto exit;
- }
- /* we could not get a dynamic minor, so lets find one of our own */
- for (minor = 0; minor < MAX_DEVICES; ++minor) {
- if (minor_table[minor] == NULL)
- break;
- }
- if (minor >= MAX_DEVICES) {
- err ("Too many devices plugged in, can not handle this device.");
- goto exit;
- }
+ /* something prevented us from registering this driver */
+ err ("Not able to get a minor for this device.");
+ goto exit;
}
/* allocate memory for our device state and intialize it */
dev = kmalloc (sizeof(struct usb_skel), GFP_KERNEL);
if (dev == NULL) {
err ("Out of memory");
- goto exit;
+ goto exit_minor;
}
memset (dev, 0x00, sizeof (*dev));
minor_table[minor] = dev;
@@ -628,6 +614,9 @@ error:
skel_delete (dev);
dev = NULL;
+exit_minor:
+ usb_deregister_dev (1, minor);
+
exit:
up (&minor_table_mutex);
return dev;
@@ -655,7 +644,7 @@ static void skel_disconnect(struct usb_device *udev, void *ptr)
devfs_unregister (dev->devfs);
/* give back our dynamic minor */
- usb_deregister_dev (&skel_driver, 1, minor);
+ usb_deregister_dev (1, minor);
/* if the device is not opened, then we clean up right now */
if (!dev->open_count) {
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 43c5d84eb1ca..7fcb72dc8e03 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -954,7 +954,7 @@ static int notesize(struct memelfnote *en)
int sz;
sz = sizeof(struct elf_note);
- sz += roundup(strlen(en->name), 4);
+ sz += roundup(strlen(en->name) + 1, 4);
sz += roundup(en->datasz, 4);
return sz;
@@ -989,7 +989,7 @@ static int writenote(struct memelfnote *men, struct file *file)
{
struct elf_note en;
- en.n_namesz = strlen(men->name);
+ en.n_namesz = strlen(men->name) + 1;
en.n_descsz = men->datasz;
en.n_type = men->type;
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index a354c9fd4574..a5d332064abe 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -281,9 +281,13 @@ struct inode_operations coda_file_inode_operations = {
static int coda_statfs(struct super_block *sb, struct statfs *buf)
{
int error;
+
+ lock_kernel();
error = venus_statfs(sb, buf);
+ unlock_kernel();
+
if (error) {
/* fake something like AFS does */
buf->f_blocks = 9000000;
diff --git a/fs/driverfs/inode.c b/fs/driverfs/inode.c
index 2fd9126199b2..e6a098cdd04b 100644
--- a/fs/driverfs/inode.c
+++ b/fs/driverfs/inode.c
@@ -119,6 +119,9 @@ struct inode *driverfs_get_inode(struct super_block *sb, int mode, int dev)
case S_IFDIR:
inode->i_op = &driverfs_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
+
+ /* directory inodes start off with i_nlink == 2 (for "." entry) */
+ inode->i_nlink++;
break;
case S_IFLNK:
inode->i_op = &page_symlink_inode_operations;
@@ -149,10 +152,8 @@ static int driverfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
lock_kernel();
dentry->d_op = &driverfs_dentry_dir_ops;
res = driverfs_mknod(dir, dentry, mode | S_IFDIR, 0);
- if (!res) {
+ if (!res)
dir->i_nlink++;
- dentry->d_inode->i_nlink++;
- }
unlock_kernel();
return res;
}
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index f08897e90ad2..2e650dcb8b3a 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -500,7 +500,7 @@ static struct super_operations ext3_sops = {
write_super: ext3_write_super, /* BKL not held. We take it. Needed? */
write_super_lockfs: ext3_write_super_lockfs, /* BKL not held. Take it */
unlockfs: ext3_unlockfs, /* BKL not held. We take it */
- statfs: ext3_statfs, /* BKL held */
+ statfs: ext3_statfs, /* BKL not held. */
remount_fs: ext3_remount, /* BKL held */
};
diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c
index d937b64926e3..45886178fda3 100644
--- a/fs/freevxfs/vxfs_super.c
+++ b/fs/freevxfs/vxfs_super.c
@@ -98,7 +98,7 @@ vxfs_put_super(struct super_block *sbp)
* Zero.
*
* Locking:
- * We are under bkl and @sbp->s_lock.
+ * No locks held.
*
* Notes:
* This is everything but complete...
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index 1d906d3535bb..b8306f5f5db9 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -134,6 +134,8 @@ static unsigned count_bitmaps(struct super_block *s)
int hpfs_statfs(struct super_block *s, struct statfs *buf)
{
+ lock_kernel();
+
/*if (s->s_hpfs_n_free == -1) {*/
s->s_hpfs_n_free = count_bitmaps(s);
s->s_hpfs_n_free_dnodes = hpfs_count_one_bitmap(s, s->s_hpfs_dmap);
@@ -146,6 +148,9 @@ int hpfs_statfs(struct super_block *s, struct statfs *buf)
buf->f_files = s->s_hpfs_dirband_size / 4;
buf->f_ffree = s->s_hpfs_n_free_dnodes;
buf->f_namelen = 254;
+
+ unlock_kernel();
+
return 0;
}
diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c
index e71bcbfc3caa..ad179ff4bbdc 100644
--- a/fs/jffs/inode-v23.c
+++ b/fs/jffs/inode-v23.c
@@ -383,7 +383,11 @@ int
jffs_statfs(struct super_block *sb, struct statfs *buf)
{
struct jffs_control *c = (struct jffs_control *) sb->u.generic_sbp;
- struct jffs_fmcontrol *fmc = c->fmc;
+ struct jffs_fmcontrol *fmc;
+
+ lock_kernel();
+
+ fmc = c->fmc;
D2(printk("jffs_statfs()\n"));
@@ -401,6 +405,9 @@ jffs_statfs(struct super_block *sb, struct statfs *buf)
buf->f_ffree = buf->f_bfree;
/* buf->f_fsid = 0; */
buf->f_namelen = JFFS_MAX_NAME_LEN;
+
+ unlock_kernel();
+
return 0;
}
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 211f62a027a1..d643d9540177 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -474,6 +474,8 @@ nfs_statfs(struct super_block *sb, struct statfs *buf)
struct nfs_fsinfo res;
int error;
+ lock_kernel();
+
error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root->d_inode), &res);
buf->f_type = NFS_SUPER_MAGIC;
if (error < 0)
@@ -491,11 +493,17 @@ nfs_statfs(struct super_block *sb, struct statfs *buf)
if (res.namelen == 0 || res.namelen > server->namelen)
res.namelen = server->namelen;
buf->f_namelen = res.namelen;
+
+ out:
+ unlock_kernel();
+
return 0;
+
out_err:
- printk("nfs_statfs: statfs error = %d\n", -error);
+ printk(KERN_WARNING "nfs_statfs: statfs error = %d\n", -error);
buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1;
- return 0;
+ goto out;
+
}
static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog
index e921ef9d19ff..9bd1acc0a5c2 100644
--- a/fs/ntfs/ChangeLog
+++ b/fs/ntfs/ChangeLog
@@ -28,6 +28,17 @@ ToDo:
- Enable NFS exporting of NTFS.
- Use fake inodes for address space i/o.
+2.0.14 - Run list merging code cleanup, minor locking changes, typo fixes.
+
+ - Change fs/ntfs/super.c::ntfs_statfs() to not rely on BKL by moving
+ the locking out of super.c::get_nr_free_mft_records() and taking and
+ dropping the mftbmp_lock rw_semaphore in ntfs_statfs() itself.
+ - Bring attribute run list merging code (fs/ntfs/attrib.c) in sync with
+ current userspace ntfs library code. This means that if a merge
+ fails the original run lists are always left unmodified instead of
+ being silently corrupted.
+ - Misc typo fixes.
+
2.0.13 - Use iget5_locked() in preparation for fake inodes and small cleanups.
- Remove nr_mft_bits and the now superfluous union with nr_mft_records
diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile
index e6fe82353289..208c46697eb9 100644
--- a/fs/ntfs/Makefile
+++ b/fs/ntfs/Makefile
@@ -5,7 +5,7 @@ obj-$(CONFIG_NTFS_FS) += ntfs.o
ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o \
mst.o namei.o super.o sysctl.o time.o unistr.o upcase.o
-EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.13\"
+EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.14\"
ifeq ($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
index c0033a70b8b9..09c9683474cd 100644
--- a/fs/ntfs/attrib.c
+++ b/fs/ntfs/attrib.c
@@ -27,338 +27,433 @@
/* Temporary helper functions -- might become macros */
/**
- * rl_mm - run_list memmove
+ * ntfs_rl_mm - run_list memmove
*
* It is up to the caller to serialize access to the run list @base.
*/
-static inline void rl_mm(run_list_element *base, int dst, int src, int size)
+static inline void ntfs_rl_mm(run_list_element *base, int dst, int src,
+ int size)
{
- if ((dst != src) && (size > 0))
- memmove (base + dst, base + src, size * sizeof (*base));
+ if (likely((dst != src) && (size > 0)))
+ memmove(base + dst, base + src, size * sizeof (*base));
}
/**
- * rl_mc - run_list memory copy
+ * ntfs_rl_mc - run_list memory copy
*
* It is up to the caller to serialize access to the run lists @dstbase and
* @srcbase.
*/
-static inline void rl_mc(run_list_element *dstbase, int dst,
+static inline void ntfs_rl_mc(run_list_element *dstbase, int dst,
run_list_element *srcbase, int src, int size)
{
- if (size > 0)
- memcpy (dstbase+dst, srcbase+src, size * sizeof (*dstbase));
+ if (likely(size > 0))
+ memcpy(dstbase + dst, srcbase + src, size * sizeof(*dstbase));
}
/**
* ntfs_rl_realloc - Reallocate memory for run_lists
- * @orig: The original memory allocation
- * @old: The number of run_lists in the original
- * @new: The number of run_lists we need space for
+ * @rl: original run list
+ * @old_size: number of run list elements in the original run list @rl
+ * @new_size: number of run list elements we need space for
*
* As the run_lists grow, more memory will be required. To prevent the
* kernel having to allocate and reallocate large numbers of small bits of
* memory, this function returns and entire page of memory.
*
- * It is up to the caller to serialize access to the run list @orig.
+ * It is up to the caller to serialize access to the run list @rl.
*
* N.B. If the new allocation doesn't require a different number of pages in
* memory, the function will return the original pointer.
*
- * Return: Pointer The newly allocated, or recycled, memory.
- *
- * Errors: -ENOMEM, Not enough memory to allocate run list array.
- * -EINVAL, Invalid parameters were passed in.
+ * On success, return a pointer to the newly allocated, or recycled, memory.
+ * On error, return -errno. The following error codes are defined:
+ * -ENOMEM - Not enough memory to allocate run list array.
+ * -EINVAL - Invalid parameters were passed in.
*/
-static inline run_list_element *ntfs_rl_realloc(run_list_element *orig,
- int old, int new)
+static inline run_list_element *ntfs_rl_realloc(run_list_element *rl,
+ int old_size, int new_size)
{
- run_list_element *nrl;
+ run_list_element *new_rl;
- old = PAGE_ALIGN (old * sizeof (*orig));
- new = PAGE_ALIGN (new * sizeof (*orig));
- if (old == new)
- return orig;
+ old_size = PAGE_ALIGN(old_size * sizeof(*rl));
+ new_size = PAGE_ALIGN(new_size * sizeof(*rl));
+ if (old_size == new_size)
+ return rl;
- nrl = ntfs_malloc_nofs (new);
- if (!nrl)
- return ERR_PTR (-ENOMEM);
+ new_rl = ntfs_malloc_nofs(new_size);
+ if (unlikely(!new_rl))
+ return ERR_PTR(-ENOMEM);
- if (orig) {
- memcpy (nrl, orig, min (old, new));
- ntfs_free (orig);
+ if (likely(rl != NULL)) {
+ if (unlikely(old_size > new_size))
+ old_size = new_size;
+ memcpy(new_rl, rl, old_size);
+ ntfs_free(rl);
}
- return nrl;
+ return new_rl;
}
/**
- * ntfs_rl_merge - Join together two run_lists
- * @one: The first run_list and destination
- * @two: The second run_list
+ * ntfs_are_rl_mergeable - test if two run lists can be joined together
+ * @dst: original run list
+ * @src: new run list to test for mergeability with @dst
*
- * If possible merge together two run_lists. For this, their VCNs and LCNs
+ * Test if two run lists can be joined together. For this, their VCNs and LCNs
* must be adjacent.
*
- * It is up to the caller to serialize access to the run lists @one and @two.
+ * It is up to the caller to serialize access to the run lists @dst and @src.
*
- * Return: TRUE Success, the run_lists were merged
- * FALSE Failure, the run_lists were not merged
+ * Return: TRUE Success, the run lists can be merged.
+ * FALSE Failure, the run lists cannot be merged.
*/
-static inline BOOL ntfs_rl_merge(run_list_element *one, run_list_element *two)
+static inline BOOL ntfs_are_rl_mergeable(run_list_element *dst,
+ run_list_element *src)
{
- BUG_ON (!one || !two);
+ BUG_ON(!dst || !src);
- if ((one->lcn < 0) || (two->lcn < 0)) /* Are we merging holes? */
+ if ((dst->lcn < 0) || (src->lcn < 0)) /* Are we merging holes? */
return FALSE;
- if ((one->lcn + one->length) != two->lcn) /* Are the runs contiguous? */
+ if ((dst->lcn + dst->length) != src->lcn) /* Are the runs contiguous? */
return FALSE;
- if ((one->vcn + one->length) != two->vcn) /* Are the runs misaligned? */
+ if ((dst->vcn + dst->length) != src->vcn) /* Are the runs misaligned? */
return FALSE;
- one->length += two->length;
return TRUE;
}
/**
- * ntfs_rl_append - Append a run_list after the given element
- * @orig: The original run_list to be worked on.
- * @osize: The number of elements in @orig (including end marker).
- * @new: The run_list to be inserted.
- * @nsize: The number of elements in @new (excluding end marker).
- * @loc: Append the new run_list after this element in @orig.
+ * __ntfs_rl_merge - merge two run lists without testing if they can be merged
+ * @dst: original, destination run list
+ * @src: new run list to merge with @dst
*
- * Append a run_list after element @loc in @orig. Merge the right end of
- * the new run_list, if necessary. Adjust the size of the hole before the
- * appended run_list.
+ * Merge the two run lists, writing into the destination run list @dst. The
+ * caller must make sure the run lists can be merged or this will corrupt the
+ * destination run list.
*
- * It is up to the caller to serialize access to the run lists @orig and @new.
+ * It is up to the caller to serialize access to the run lists @dst and @src.
+ */
+static inline void __ntfs_rl_merge(run_list_element *dst, run_list_element *src)
+{
+ dst->length += src->length;
+}
+
+/**
+ * ntfs_rl_merge - test if two run lists can be joined together and merge them
+ * @dst: original, destination run list
+ * @src: new run list to merge with @dst
*
- * Return: Pointer, The new, combined, run_list
+ * Test if two run lists can be joined together. For this, their VCNs and LCNs
+ * must be adjacent. If they can be merged, perform the merge, writing into
+ * the destination run list @dst.
*
- * Errors: -ENOMEM, Not enough memory to allocate run list array.
- * -EINVAL, Invalid parameters were passed in.
+ * It is up to the caller to serialize access to the run lists @dst and @src.
+ *
+ * Return: TRUE Success, the run lists have been merged.
+ * FALSE Failure, the run lists cannot be merged and have not been
+ * modified.
*/
-static inline run_list_element *ntfs_rl_append(run_list_element *orig,
- int osize, run_list_element *new, int nsize, int loc)
+static inline BOOL ntfs_rl_merge(run_list_element *dst, run_list_element *src)
+{
+ BOOL merge = ntfs_are_rl_mergeable(dst, src);
+
+ if (merge)
+ __ntfs_rl_merge(dst, src);
+ return merge;
+}
+
+/**
+ * ntfs_rl_append - append a run list after a given element
+ * @dst: original run list to be worked on
+ * @dsize: number of elements in @dst (including end marker)
+ * @src: run list to be inserted into @dst
+ * @ssize: number of elements in @src (excluding end marker)
+ * @loc: append the new run list @src after this element in @dst
+ *
+ * Append the run list @src after element @loc in @dst. Merge the right end of
+ * the new run list, if necessary. Adjust the size of the hole before the
+ * appended run list.
+ *
+ * It is up to the caller to serialize access to the run lists @dst and @src.
+ *
+ * On success, return a pointer to the new, combined, run list. Note, both
+ * run lists @dst and @src are deallocated before returning so you cannot use
+ * the pointers for anything any more. (Strictly speaking the returned run list
+ * may be the same as @dst but this is irrelevant.)
+ *
+ * On error, return -errno. Both run lists are left unmodified. The following
+ * error codes are defined:
+ * -ENOMEM - Not enough memory to allocate run list array.
+ * -EINVAL - Invalid parameters were passed in.
+ */
+static inline run_list_element *ntfs_rl_append(run_list_element *dst,
+ int dsize, run_list_element *src, int ssize, int loc)
{
- run_list_element *res;
BOOL right;
+ int magic;
- BUG_ON (!orig || !new);
+ BUG_ON(!dst || !src);
+
+ /* First, check if the right hand end needs merging. */
+ right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1);
+
+ /* Space required: @dst size + @src size, less one if we merged. */
+ dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - right);
+ if (IS_ERR(dst))
+ return dst;
+ /*
+ * We are guaranteed to succeed from here so can start modifying the
+ * original run lists.
+ */
/* First, merge the right hand end, if necessary. */
- right = ntfs_rl_merge (new + nsize - 1, orig + loc + 1);
+ if (right)
+ __ntfs_rl_merge(src + ssize - 1, dst + loc + 1);
- /* Space required: Orig size + New size, less one if we merged. */
- res = ntfs_rl_realloc (orig, osize, osize + nsize - right);
- if (IS_ERR (res))
- return res;
+ magic = loc + ssize;
- /* Move the tail of Orig out of the way, then copy in New. */
- rl_mm (res, loc + 1 + nsize, loc + 1 + right, osize - loc - 1 - right);
- rl_mc (res, loc + 1, new, 0, nsize);
+ /* Move the tail of @dst out of the way, then copy in @src. */
+ ntfs_rl_mm(dst, magic + 1, loc + 1 + right, dsize - loc - 1 - right);
+ ntfs_rl_mc(dst, loc + 1, src, 0, ssize);
/* Adjust the size of the preceding hole. */
- res[loc].length = res[loc+1].vcn - res[loc].vcn;
+ dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn;
/* We may have changed the length of the file, so fix the end marker */
- if (res[loc+nsize+1].lcn == LCN_ENOENT)
- res[loc+nsize+1].vcn = res[loc+nsize].vcn + res[loc+nsize].length;
+ if (dst[magic + 1].lcn == LCN_ENOENT)
+ dst[magic + 1].vcn = dst[magic].vcn + dst[magic].length;
- return res;
+ return dst;
}
/**
- * ntfs_rl_insert - Insert a run_list into another
- * @orig: The original run_list to be worked on.
- * @osize: The number of elements in @orig (including end marker).
- * @new: The run_list to be inserted.
- * @nsize: The number of elements in @new (excluding end marker).
- * @loc: Insert the new run_list before this element in @orig.
- *
- * Insert a run_list before element @loc in @orig. Merge the left end of
- * the new run_list, if necessary. Adjust the size of the hole after the
- * inserted run_list.
- *
- * It is up to the caller to serialize access to the run lists @orig and @new.
- *
- * Return: Pointer, The new, combined, run_list
- *
- * Errors: -ENOMEM, Not enough memory to allocate run list array.
- * -EINVAL, Invalid parameters were passed in.
+ * ntfs_rl_insert - insert a run list into another
+ * @dst: original run list to be worked on
+ * @dsize: number of elements in @dst (including end marker)
+ * @src: new run list to be inserted
+ * @ssize: number of elements in @src (excluding end marker)
+ * @loc: insert the new run list @src before this element in @dst
+ *
+ * Insert the run list @src before element @loc in the run list @dst. Merge the
+ * left end of the new run list, if necessary. Adjust the size of the hole
+ * after the inserted run list.
+ *
+ * It is up to the caller to serialize access to the run lists @dst and @src.
+ *
+ * On success, return a pointer to the new, combined, run list. Note, both
+ * run lists @dst and @src are deallocated before returning so you cannot use
+ * the pointers for anything any more. (Strictly speaking the returned run list
+ * may be the same as @dst but this is irrelevant.)
+ *
+ * On error, return -errno. Both run lists are left unmodified. The following
+ * error codes are defined:
+ * -ENOMEM - Not enough memory to allocate run list array.
+ * -EINVAL - Invalid parameters were passed in.
*/
-static inline run_list_element *ntfs_rl_insert(run_list_element *orig,
- int osize, run_list_element *new, int nsize, int loc)
+static inline run_list_element *ntfs_rl_insert(run_list_element *dst,
+ int dsize, run_list_element *src, int ssize, int loc)
{
- run_list_element *res;
BOOL left = FALSE;
BOOL disc = FALSE; /* Discontinuity */
BOOL hole = FALSE; /* Following a hole */
+ int magic;
- BUG_ON (!orig || !new);
+ BUG_ON(!dst || !src);
- /* disc => Discontinuity between the end of Orig and the start of New.
+ /* disc => Discontinuity between the end of @dst and the start of @src.
* This means we might need to insert a hole.
- * hole => Orig ends with a hole or an unmapped region which we can
+ * hole => @dst ends with a hole or an unmapped region which we can
* extend to match the discontinuity. */
- if (loc == 0) {
- disc = (new[0].vcn > 0);
- } else {
- left = ntfs_rl_merge (orig + loc - 1, new);
+ if (loc == 0)
+ disc = (src[0].vcn > 0);
+ else {
+ s64 merged_length;
+
+ left = ntfs_are_rl_mergeable(dst + loc - 1, src);
+
+ merged_length = dst[loc - 1].length;
+ if (left)
+ merged_length += src->length;
- disc = (new[0].vcn > (orig[loc-1].vcn + orig[loc-1].length));
+ disc = (src[0].vcn > dst[loc - 1].vcn + merged_length);
if (disc)
- hole = (orig[loc-1].lcn == LCN_HOLE);
+ hole = (dst[loc - 1].lcn == LCN_HOLE);
}
- /* Space required: Orig size + New size, less one if we merged,
- * plus one if there was a discontinuity, less one for a trailing hole */
- res = ntfs_rl_realloc (orig, osize, osize + nsize - left + disc - hole);
- if (IS_ERR (res))
- return res;
+ /* Space required: @dst size + @src size, less one if we merged, plus
+ * one if there was a discontinuity, less one for a trailing hole. */
+ dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left + disc - hole);
+ if (IS_ERR(dst))
+ return dst;
+ /*
+ * We are guaranteed to succeed from here so can start modifying the
+ * original run list.
+ */
+
+ if (left)
+ __ntfs_rl_merge(dst + loc - 1, src);
- /* Move the tail of Orig out of the way, then copy in New. */
- rl_mm (res, loc + nsize - left + disc - hole, loc, osize - loc);
- rl_mc (res, loc + disc - hole, new, left, nsize - left);
+ magic = loc + ssize - left + disc - hole;
+
+ /* Move the tail of @dst out of the way, then copy in @src. */
+ ntfs_rl_mm(dst, magic, loc, dsize - loc);
+ ntfs_rl_mc(dst, loc + disc - hole, src, left, ssize - left);
/* Adjust the VCN of the last run ... */
- if (res[loc+nsize-left+disc-hole].lcn <= LCN_HOLE) {
- res[loc+nsize-left+disc-hole].vcn =
- res[loc+nsize-left+disc-hole-1].vcn +
- res[loc+nsize-left+disc-hole-1].length;
- }
+ if (dst[magic].lcn <= LCN_HOLE)
+ dst[magic].vcn = dst[magic - 1].vcn + dst[magic - 1].length;
/* ... and the length. */
- if ((res[loc+nsize-left+disc-hole].lcn == LCN_HOLE) ||
- (res[loc+nsize-left+disc-hole].lcn == LCN_RL_NOT_MAPPED)) {
- res[loc+nsize-left+disc-hole].length =
- res[loc+nsize-left+disc-hole+1].vcn -
- res[loc+nsize-left+disc-hole].vcn;
- }
+ if (dst[magic].lcn == LCN_HOLE || dst[magic].lcn == LCN_RL_NOT_MAPPED)
+ dst[magic].length = dst[magic + 1].vcn - dst[magic].vcn;
/* Writing beyond the end of the file and there's a discontinuity. */
if (disc) {
- if (hole) {
- res[loc-1].length = res[loc].vcn - res[loc-1].vcn;
- } else {
+ if (hole)
+ dst[loc - 1].length = dst[loc].vcn - dst[loc - 1].vcn;
+ else {
if (loc > 0) {
- res[loc].vcn = res[loc-1].vcn +
- res[loc-1].length;
- res[loc].length = res[loc+1].vcn - res[loc].vcn;
+ dst[loc].vcn = dst[loc - 1].vcn +
+ dst[loc - 1].length;
+ dst[loc].length = dst[loc + 1].vcn -
+ dst[loc].vcn;
} else {
- res[loc].vcn = 0;
- res[loc].length = res[loc+1].vcn;
+ dst[loc].vcn = 0;
+ dst[loc].length = dst[loc + 1].vcn;
}
- res[loc].lcn = LCN_RL_NOT_MAPPED;
+ dst[loc].lcn = LCN_RL_NOT_MAPPED;
}
- if (res[loc+nsize-left+disc].lcn == LCN_ENOENT)
- res[loc+nsize-left+disc].vcn = res[loc+nsize-left+disc-1].vcn +
- res[loc+nsize-left+disc-1].length;
- }
+ magic += hole;
- return res;
+ if (dst[magic].lcn == LCN_ENOENT)
+ dst[magic].vcn = dst[magic - 1].vcn +
+ dst[magic - 1].length;
+ }
+ return dst;
}
/**
- * ntfs_rl_replace - Overwrite a run_list element with another run_list
- * @orig: The original run_list to be worked on.
- * @osize: The number of elements in @orig (including end marker).
- * @new: The run_list to be inserted.
- * @nsize: The number of elements in @new (excluding end marker).
- * @loc: Index of run_list @orig to overwrite with @new.
- *
- * Replace the run_list at @loc with @new. Merge the left and right ends of
- * the inserted run_list, if necessary.
- *
- * It is up to the caller to serialize access to the run lists @orig and @new.
- *
- * Return: Pointer, The new, combined, run_list
- *
- * Errors: -ENOMEM, Not enough memory to allocate run list array.
- * -EINVAL, Invalid parameters were passed in.
+ * ntfs_rl_replace - overwrite a run_list element with another run list
+ * @dst: original run list to be worked on
+ * @dsize: number of elements in @dst (including end marker)
+ * @src: new run list to be inserted
+ * @ssize: number of elements in @src (excluding end marker)
+ * @loc: index in run list @dst to overwrite with @src
+ *
+ * Replace the run list element @dst at @loc with @src. Merge the left and
+ * right ends of the inserted run list, if necessary.
+ *
+ * It is up to the caller to serialize access to the run lists @dst and @src.
+ *
+ * On success, return a pointer to the new, combined, run list. Note, both
+ * run lists @dst and @src are deallocated before returning so you cannot use
+ * the pointers for anything any more. (Strictly speaking the returned run list
+ * may be the same as @dst but this is irrelevant.)
+ *
+ * On error, return -errno. Both run lists are left unmodified. The following
+ * error codes are defined:
+ * -ENOMEM - Not enough memory to allocate run list array.
+ * -EINVAL - Invalid parameters were passed in.
*/
-static inline run_list_element *ntfs_rl_replace(run_list_element *orig,
- int osize, run_list_element *new, int nsize, int loc)
+static inline run_list_element *ntfs_rl_replace(run_list_element *dst,
+ int dsize, run_list_element *src, int ssize, int loc)
{
- run_list_element *res;
BOOL left = FALSE;
BOOL right;
+ int magic;
- BUG_ON (!orig || !new);
+ BUG_ON(!dst || !src);
/* First, merge the left and right ends, if necessary. */
- right = ntfs_rl_merge (new + nsize - 1, orig + loc + 1);
+ right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1);
if (loc > 0)
- left = ntfs_rl_merge (orig + loc - 1, new);
+ left = ntfs_are_rl_mergeable(dst + loc - 1, src);
+
+ /* Allocate some space. We'll need less if the left, right, or both
+ * ends were merged. */
+ dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left - right);
+ if (IS_ERR(dst))
+ return dst;
+ /*
+ * We are guaranteed to succeed from here so can start modifying the
+ * original run lists.
+ */
+ if (right)
+ __ntfs_rl_merge(src + ssize - 1, dst + loc + 1);
+ if (left)
+ __ntfs_rl_merge(dst + loc - 1, src);
- /* Allocate some space. We'll need less if the left, right
- * or both ends were merged. */
- res = ntfs_rl_realloc (orig, osize, osize + nsize - left - right);
- if (IS_ERR (res))
- return res;
+ /* FIXME: What does this mean? (AIA) */
+ magic = loc + ssize - left;
- /* Move the tail of Orig out of the way, then copy in New. */
- rl_mm (res, loc + nsize - left, loc + right + 1,
- osize - loc - right - 1);
- rl_mc (res, loc, new, left, nsize - left);
+ /* Move the tail of @dst out of the way, then copy in @src. */
+ ntfs_rl_mm(dst, magic, loc + right + 1, dsize - loc - right - 1);
+ ntfs_rl_mc(dst, loc, src, left, ssize - left);
/* We may have changed the length of the file, so fix the end marker */
- if (res[loc+nsize-left].lcn == LCN_ENOENT)
- res[loc+nsize-left].vcn = res[loc+nsize-left-1].vcn +
- res[loc+nsize-left-1].length;
- return res;
+ if (dst[magic].lcn == LCN_ENOENT)
+ dst[magic].vcn = dst[magic - 1].vcn + dst[magic - 1].length;
+ return dst;
}
/**
- * ntfs_rl_split - Insert a run_list into the centre of a hole
- * @orig: The original run_list to be worked on.
- * @osize: The number of elements in @orig (including end marker).
- * @new: The run_list to be inserted.
- * @nsize: The number of elements in @new (excluding end marker).
- * @loc: Index of run_list in @orig to split with @new.
- *
- * Split the run_list at @loc into two and insert @new. No merging of
- * run_lists is necessary. Adjust the size of the holes either side.
- *
- * It is up to the caller to serialize access to the run lists @orig and @new.
- *
- * Return: Pointer, The new, combined, run_list
- *
- * Errors: -ENOMEM, Not enough memory to allocate run list array.
- * -EINVAL, Invalid parameters were passed in.
+ * ntfs_rl_split - insert a run list into the centre of a hole
+ * @dst: original run list to be worked on
+ * @dsize: number of elements in @dst (including end marker)
+ * @src: new run list to be inserted
+ * @ssize: number of elements in @src (excluding end marker)
+ * @loc: index in run list @dst at which to split and insert @src
+ *
+ * Split the run list @dst at @loc into two and insert @new in between the two
+ * fragments. No merging of run lists is necessary. Adjust the size of the
+ * holes either side.
+ *
+ * It is up to the caller to serialize access to the run lists @dst and @src.
+ *
+ * On success, return a pointer to the new, combined, run list. Note, both
+ * run lists @dst and @src are deallocated before returning so you cannot use
+ * the pointers for anything any more. (Strictly speaking the returned run list
+ * may be the same as @dst but this is irrelevant.)
+ *
+ * On error, return -errno. Both run lists are left unmodified. The following
+ * error codes are defined:
+ * -ENOMEM - Not enough memory to allocate run list array.
+ * -EINVAL - Invalid parameters were passed in.
*/
-static inline run_list_element *ntfs_rl_split(run_list_element *orig, int osize,
- run_list_element *new, int nsize, int loc)
+static inline run_list_element *ntfs_rl_split(run_list_element *dst, int dsize,
+ run_list_element *src, int ssize, int loc)
{
- run_list_element *res;
-
- BUG_ON (!orig || !new);
+ BUG_ON(!dst || !src);
- /* Space required: Orig size + New size + One new hole. */
- res = ntfs_rl_realloc (orig, osize, osize + nsize + 1);
- if (IS_ERR (res))
- return res;
+ /* Space required: @dst size + @src size + one new hole. */
+ dst = ntfs_rl_realloc(dst, dsize, dsize + ssize + 1);
+ if (IS_ERR(dst))
+ return dst;
+ /*
+ * We are guaranteed to succeed from here so can start modifying the
+ * original run lists.
+ */
- /* Move the tail of Orig out of the way, then copy in New. */
- rl_mm (res, loc + 1 + nsize, loc, osize - loc);
- rl_mc (res, loc + 1, new, 0, nsize);
+ /* Move the tail of @dst out of the way, then copy in @src. */
+ ntfs_rl_mm(dst, loc + 1 + ssize, loc, dsize - loc);
+ ntfs_rl_mc(dst, loc + 1, src, 0, ssize);
- /* Adjust the size of the holes either size of New. */
- res[loc].length = res[loc+1].vcn - res[loc].vcn;
- res[loc+nsize+1].vcn = res[loc+nsize].vcn + res[loc+nsize].length;
- res[loc+nsize+1].length = res[loc+nsize+2].vcn - res[loc+nsize+1].vcn;
+ /* Adjust the size of the holes either size of @src. */
+ dst[loc].length = dst[loc+1].vcn - dst[loc].vcn;
+ dst[loc+ssize+1].vcn = dst[loc+ssize].vcn + dst[loc+ssize].length;
+ dst[loc+ssize+1].length = dst[loc+ssize+2].vcn - dst[loc+ssize+1].vcn;
- return res;
+ return dst;
}
/**
- * merge_run_lists - merge two run_lists into one
- * @drl: The original run_list.
- * @srl: The new run_list to be merge into @drl.
+ * ntfs_merge_run_lists - merge two run_lists into one
+ * @drl: original run list to be worked on
+ * @srl: new run list to be merged into @drl
*
- * First we sanity check the two run_lists to make sure that they are sensible
- * and can be merged. The @srl run_list must be either after the @drl run_list
- * or completely within a hole in @drl.
+ * First we sanity check the two run lists @srl and @drl to make sure that they
+ * are sensible and can be merged. The run list @srl must be either after the
+ * run list @drl or completely within a hole (or unmapped region) in @drl.
*
* It is up to the caller to serialize access to the run lists @drl and @srl.
*
@@ -366,25 +461,28 @@ static inline run_list_element *ntfs_rl_split(run_list_element *orig, int osize,
* 1. When attribute lists are used and a further extent is being mapped.
* 2. When new clusters are allocated to fill a hole or extend a file.
*
- * There are four possible ways @srl can be merged. It can be inserted at
- * the beginning of a hole; split the hole in two; appended at the end of
- * a hole; replace the whole hole. It can also be appended to the end of
- * the run_list, which is just a variant of the insert case.
- *
- * N.B. Either, or both, of the input pointers may be freed if the function
- * is successful. Only the returned pointer may be used.
- *
- * If the function fails, neither of the input run_lists may be safe.
- *
- * Return: Pointer, The resultant merged run_list.
- *
- * Errors: -ENOMEM, Not enough memory to allocate run list array.
- * -EINVAL, Invalid parameters were passed in.
- * -ERANGE, The run_lists overlap and cannot be merged.
+ * There are four possible ways @srl can be merged. It can:
+ * - be inserted at the beginning of a hole,
+ * - split the hole in two and be inserted between the two fragments,
+ * - be appended at the end of a hole, or it can
+ * - replace the whole hole.
+ * It can also be appended to the end of the run list, which is just a variant
+ * of the insert case.
+ *
+ * On success, return a pointer to the new, combined, run list. Note, both
+ * run lists @drl and @srl are deallocated before returning so you cannot use
+ * the pointers for anything any more. (Strictly speaking the returned run list
+ * may be the same as @dst but this is irrelevant.)
+ *
+ * On error, return -errno. Both run lists are left unmodified. The following
+ * error codes are defined:
+ * -ENOMEM - Not enough memory to allocate run list array.
+ * -EINVAL - Invalid parameters were passed in.
+ * -ERANGE - The run lists overlap and cannot be merged.
*/
-run_list_element *merge_run_lists(run_list_element *drl, run_list_element *srl)
+run_list_element *ntfs_merge_run_lists(run_list_element *drl,
+ run_list_element *srl)
{
- run_list_element *nrl; /* New run list. */
int di, si; /* Current index into @[ds]rl. */
int sstart; /* First index with lcn > LCN_RL_NOT_MAPPED. */
int dins; /* Index into @drl at which to insert @srl. */
@@ -392,49 +490,49 @@ run_list_element *merge_run_lists(run_list_element *drl, run_list_element *srl)
int dfinal, sfinal; /* The last index into @[ds]rl with
lcn >= LCN_HOLE. */
int marker = 0;
+ VCN marker_vcn = 0;
-#if 1
- ntfs_debug ("dst:");
- ntfs_debug_dump_runlist (drl);
- ntfs_debug ("src:");
- ntfs_debug_dump_runlist (srl);
+#ifdef DEBUG
+ ntfs_debug("dst:");
+ ntfs_debug_dump_runlist(drl);
+ ntfs_debug("src:");
+ ntfs_debug_dump_runlist(srl);
#endif
/* Check for silly calling... */
- if (unlikely (!srl))
+ if (unlikely(!srl))
return drl;
- if (unlikely (IS_ERR (srl) || IS_ERR (drl)))
- return ERR_PTR (-EINVAL);
+ if (unlikely(IS_ERR(srl) || IS_ERR(drl)))
+ return ERR_PTR(-EINVAL);
/* Check for the case where the first mapping is being done now. */
- if (unlikely (!drl)) {
- nrl = srl;
-
+ if (unlikely(!drl)) {
+ drl = srl;
/* Complete the source run list if necessary. */
- if (unlikely (srl[0].vcn)) {
+ if (unlikely(drl[0].vcn)) {
/* Scan to the end of the source run list. */
- for (send = 0; likely (srl[send].length); send++)
+ for (dend = 0; likely(drl[dend].length); dend++)
;
- nrl = ntfs_rl_realloc (srl, send, send + 1);
- if (!nrl)
- return ERR_PTR (-ENOMEM);
-
- rl_mm (nrl, 1, 0, send);
- nrl[0].vcn = 0; /* Add start element. */
- nrl[0].lcn = LCN_RL_NOT_MAPPED;
- nrl[0].length = nrl[1].vcn;
+ drl = ntfs_rl_realloc(drl, dend, dend + 1);
+ if (IS_ERR(drl))
+ return drl;
+ /* Insert start element at the front of the run list. */
+ ntfs_rl_mm(drl, 1, 0, dend);
+ drl[0].vcn = 0;
+ drl[0].lcn = LCN_RL_NOT_MAPPED;
+ drl[0].length = drl[1].vcn;
}
goto finished;
}
si = di = 0;
- /* Skip the unmapped start element(s) in each run_list if present. */
+ /* Skip any unmapped start element(s) in the source run_list. */
while (srl[si].length && srl[si].lcn < (LCN)LCN_HOLE)
si++;
- /* Can't have an entirely unmapped srl run_list. */
- BUG_ON (!srl[si].length);
+ /* Can't have an entirely unmapped source run list. */
+ BUG_ON(!srl[si].length);
/* Record the starting points. */
sstart = si;
@@ -445,19 +543,16 @@ run_list_element *merge_run_lists(run_list_element *drl, run_list_element *srl)
* appended to @drl.
*/
for (; drl[di].length; di++) {
- if ((drl[di].vcn + drl[di].length) > srl[sstart].vcn)
+ if (drl[di].vcn + drl[di].length > srl[sstart].vcn)
break;
}
dins = di;
/* Sanity check for illegal overlaps. */
- if ((drl[di].vcn == srl[si].vcn) &&
- (drl[di].lcn >= 0) &&
- (srl[si].lcn >= 0)) {
- ntfs_error (NULL, "Run lists overlap. Cannot merge! Returning "
- "ERANGE.");
- nrl = ERR_PTR (-ERANGE);
- goto exit;
+ if ((drl[di].vcn == srl[si].vcn) && (drl[di].lcn >= 0) &&
+ (srl[si].lcn >= 0)) {
+ ntfs_error(NULL, "Run lists overlap. Cannot merge!");
+ return ERR_PTR(-ERANGE);
}
/* Scan to the end of both run lists in order to know their sizes. */
@@ -466,9 +561,8 @@ run_list_element *merge_run_lists(run_list_element *drl, run_list_element *srl)
for (dend = di; drl[dend].length; dend++)
;
- if (srl[send].lcn == LCN_ENOENT) {
- marker = send;
- }
+ if (srl[send].lcn == (LCN)LCN_ENOENT)
+ marker_vcn = srl[marker = send].vcn;
/* Scan to the last element with lcn >= LCN_HOLE. */
for (sfinal = send; sfinal >= 0 && srl[sfinal].lcn < LCN_HOLE; sfinal--)
@@ -479,96 +573,142 @@ run_list_element *merge_run_lists(run_list_element *drl, run_list_element *srl)
{
BOOL start;
BOOL finish;
- int ds = dend + 1; /* Number of elements in drl & srl */
+ int ds = dend + 1; /* Number of elements in drl & srl */
int ss = sfinal - sstart + 1;
start = ((drl[dins].lcn < LCN_RL_NOT_MAPPED) || /* End of file */
(drl[dins].vcn == srl[sstart].vcn)); /* Start of hole */
finish = ((drl[dins].lcn >= LCN_RL_NOT_MAPPED) && /* End of file */
((drl[dins].vcn + drl[dins].length) <= /* End of hole */
- (srl[send-1].vcn + srl[send-1].length)));
+ (srl[send - 1].vcn + srl[send - 1].length)));
/* Or we'll lose an end marker */
if (start && finish && (drl[dins].length == 0))
ss++;
- if (marker && (drl[dins].vcn + drl[dins].length > srl[send-1].vcn))
+ if (marker && (drl[dins].vcn + drl[dins].length > srl[send - 1].vcn))
finish = FALSE;
-
#if 0
ntfs_debug("dfinal = %i, dend = %i", dfinal, dend);
ntfs_debug("sstart = %i, sfinal = %i, send = %i", sstart, sfinal, send);
ntfs_debug("start = %i, finish = %i", start, finish);
ntfs_debug("ds = %i, ss = %i, dins = %i", ds, ss, dins);
#endif
- if (start)
+ if (start) {
if (finish)
- nrl = ntfs_rl_replace (drl, ds, srl + sstart, ss, dins);
+ drl = ntfs_rl_replace(drl, ds, srl + sstart, ss, dins);
else
- nrl = ntfs_rl_insert (drl, ds, srl + sstart, ss, dins);
- else
+ drl = ntfs_rl_insert(drl, ds, srl + sstart, ss, dins);
+ } else {
if (finish)
- nrl = ntfs_rl_append (drl, ds, srl + sstart, ss, dins);
+ drl = ntfs_rl_append(drl, ds, srl + sstart, ss, dins);
else
- nrl = ntfs_rl_split (drl, ds, srl + sstart, ss, dins);
-
- if (marker && !IS_ERR(nrl)) {
- for (ds = 0; nrl[ds].length; ds++)
+ drl = ntfs_rl_split(drl, ds, srl + sstart, ss, dins);
+ }
+ if (IS_ERR(drl)) {
+ ntfs_error(NULL, "Merge failed.");
+ return drl;
+ }
+ ntfs_free(srl);
+ if (marker) {
+ ntfs_debug("Triggering marker code.");
+ for (ds = dend; drl[ds].length; ds++)
;
- nrl = ntfs_rl_insert(nrl, ds + 1, srl + marker, 1, ds);
+ /* We only need to care if @srl ended after @drl. */
+ if (drl[ds].vcn <= marker_vcn) {
+ int slots = 0;
+
+ if (drl[ds].vcn == marker_vcn) {
+ ntfs_debug("Old marker = 0x%Lx, replacing with "
+ "LCN_ENOENT.\n",
+ (unsigned long long)
+ drl[ds].lcn);
+ drl[ds].lcn = (LCN)LCN_ENOENT;
+ goto finished;
+ }
+ /*
+ * We need to create an unmapped run list element in
+ * @drl or extend an existing one before adding the
+ * ENOENT terminator.
+ */
+ if (drl[ds].lcn == (LCN)LCN_ENOENT) {
+ ds--;
+ slots = 1;
+ }
+ if (drl[ds].lcn != (LCN)LCN_RL_NOT_MAPPED) {
+ /* Add an unmapped run list element. */
+ if (!slots) {
+ /* FIXME/TODO: We need to have the
+ * extra memory already! (AIA) */
+ drl = ntfs_rl_realloc(drl, ds, ds + 2);
+ if (!drl)
+ goto critical_error;
+ slots = 2;
+ }
+ ds++;
+ /* Need to set vcn if it isn't set already. */
+ if (slots != 1)
+ drl[ds].vcn = drl[ds - 1].vcn +
+ drl[ds - 1].length;
+ drl[ds].lcn = (LCN)LCN_RL_NOT_MAPPED;
+ /* We now used up a slot. */
+ slots--;
+ }
+ drl[ds].length = marker_vcn - drl[ds].vcn;
+ /* Finally add the ENOENT terminator. */
+ ds++;
+ if (!slots) {
+ /* FIXME/TODO: We need to have the extra
+ * memory already! (AIA) */
+ drl = ntfs_rl_realloc(drl, ds, ds + 1);
+ if (!drl)
+ goto critical_error;
+ }
+ drl[ds].vcn = marker_vcn;
+ drl[ds].lcn = (LCN)LCN_ENOENT;
+ drl[ds].length = (s64)0;
+ }
}
}
- if (likely (!IS_ERR (nrl))) {
- /* The merge was completed successfully. */
finished:
- if (nrl != srl)
- ntfs_free (srl);
- /*ntfs_debug ("Done.");*/
- /*ntfs_debug ("Merged run list:");*/
-
-#if 1
- ntfs_debug ("res:");
- ntfs_debug_dump_runlist (nrl);
-#endif
- } else {
- ntfs_error (NULL, "Merge failed, returning error code %ld.",
- -PTR_ERR (nrl));
- }
-exit:
- return nrl;
+ /* The merge was completed successfully. */
+ ntfs_debug("Merged run list:");
+ ntfs_debug_dump_runlist(drl);
+ return drl;
+
+critical_error:
+ /* Critical error! We cannot afford to fail here. */
+ ntfs_error(NULL, "Critical error! Not enough memory.");
+ panic("NTFS: Cannot continue.");
}
/**
* decompress_mapping_pairs - convert mapping pairs array to run list
* @vol: ntfs volume on which the attribute resides
* @attr: attribute record whose mapping pairs array to decompress
- * @run_list: optional run list in which to insert @attr's run list
- *
- * Decompress the attribute @attr's mapping pairs array into a run_list and
- * return the run list or -errno on error. If @run_list is not NULL then
- * the mapping pairs array of @attr is decompressed and the run list inserted
- * into the appropriate place in @run_list. If this is the case and the
- * function returns success, the original pointer passed into @run_list is no
- * longer valid.
+ * @old_rl: optional run list in which to insert @attr's run list
*
* It is up to the caller to serialize access to the run list @old_rl.
*
- * Check the return value for error with IS_ERR(ret_val). If this is FALSE,
- * the function was successful, the return value is the new run list, and if
- * an existing run list pointer was passed in, this is no longer valid.
- * If IS_ERR(ret_val) returns true, there was an error, the return value is not
- * a run_list pointer and the existing run list pointer if one was passed in
- * has not been touched. In this case use PTR_ERR(ret_val) to obtain the error
- * code. Following error codes are defined:
- * -ENOMEM Not enough memory to allocate run list array.
- * -EIO Corrupt run list.
- * -EINVAL Invalid parameters were passed in.
- * -ERANGE The two run lists overlap.
+ * Decompress the attribute @attr's mapping pairs array into a run list. On
+ * success, return the decompressed run list.
+ *
+ * If @old_rl is not NULL, decompressed run list is inserted into the
+ * appropriate place in @old_rl and the resultant, combined run list is
+ * returned. The original @old_rl is deallocated.
+ *
+ * On error, return -errno. @old_rl is left unmodified in that case.
+ *
+ * The following error codes are defined:
+ * -ENOMEM - Not enough memory to allocate run list array.
+ * -EIO - Corrupt run list.
+ * -EINVAL - Invalid parameters were passed in.
+ * -ERANGE - The two run lists overlap.
*
* FIXME: For now we take the conceptionally simplest approach of creating the
* new run list disregarding the already existing one and then splicing the
- * two into one if that is possible (we check for overlap and discard the new
- * run list if overlap present and return error).
+ * two into one, if that is possible (we check for overlap and discard the new
+ * run list if overlap present before returning ERR_PTR(-ERANGE)).
*/
run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
const ATTR_RECORD *attr, run_list_element *old_rl)
@@ -576,12 +716,12 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
VCN vcn; /* Current vcn. */
LCN lcn; /* Current lcn. */
s64 deltaxcn; /* Change in [vl]cn. */
- run_list_element *rl = NULL; /* The output run_list. */
- run_list_element *rl2; /* Temporary run_list. */
+ run_list_element *rl; /* The output run list. */
u8 *buf; /* Current position in mapping pairs array. */
u8 *attr_end; /* End of attribute. */
- int rlsize; /* Size of run_list buffer. */
- int rlpos; /* Current run_list position. */
+ int rlsize; /* Size of run list buffer. */
+ u16 rlpos; /* Current run list position in units of
+ run_list_elements. */
u8 b; /* Current byte offset in buf. */
#ifdef DEBUG
@@ -602,14 +742,12 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
ntfs_error(vol->sb, "Corrupt attribute.");
return ERR_PTR(-EIO);
}
- /* Current position in run_list array. */
+ /* Current position in run list array. */
rlpos = 0;
- /* Allocate first page. */
- rl = ntfs_malloc_nofs(PAGE_SIZE);
+ /* Allocate first page and set current run list size to one page. */
+ rl = ntfs_malloc_nofs(rlsize = PAGE_SIZE);
if (unlikely(!rl))
return ERR_PTR(-ENOMEM);
- /* Current run_list buffer size in bytes. */
- rlsize = PAGE_SIZE;
/* Insert unmapped starting element if necessary. */
if (vcn) {
rl->vcn = (VCN)0;
@@ -624,18 +762,20 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
* operates on whole pages only.
*/
if (((rlpos + 3) * sizeof(*old_rl)) > rlsize) {
+ run_list_element *rl2;
+
rl2 = ntfs_malloc_nofs(rlsize + (int)PAGE_SIZE);
if (unlikely(!rl2)) {
ntfs_free(rl);
return ERR_PTR(-ENOMEM);
}
- memmove(rl2, rl, rlsize);
+ memcpy(rl2, rl, rlsize);
ntfs_free(rl);
rl = rl2;
rlsize += PAGE_SIZE;
}
/* Enter the current vcn into the current run_list element. */
- (rl + rlpos)->vcn = vcn;
+ rl[rlpos].vcn = vcn;
/*
* Get the change in vcn, i.e. the run length in clusters.
* Doing it this way ensures that we signextend negative values.
@@ -664,10 +804,10 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
goto err_out;
}
/*
- * Enter the current run length into the current run_list
+ * Enter the current run length into the current run list
* element.
*/
- (rl + rlpos)->length = deltaxcn;
+ rl[rlpos].length = deltaxcn;
/* Increment the current vcn by the current run length. */
vcn += deltaxcn;
/*
@@ -676,7 +816,7 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
* to LCN_HOLE.
*/
if (!(*buf & 0xf0))
- (rl + rlpos)->lcn = (LCN)LCN_HOLE;
+ rl[rlpos].lcn = (LCN)LCN_HOLE;
else {
/* Get the lcn change which really can be negative. */
u8 b2 = *buf & 0xf;
@@ -709,7 +849,7 @@ run_list_element *decompress_mapping_pairs(const ntfs_volume *vol,
goto err_out;
}
/* Enter the current lcn into the run_list element. */
- (rl + rlpos)->lcn = lcn;
+ rl[rlpos].lcn = lcn;
}
/* Get to the next run_list element. */
rlpos++;
@@ -729,7 +869,7 @@ mpa_err:
"non-resident attribute.");
goto err_out;
}
- /* Setup not mapped run_list element if this is the base extent. */
+ /* Setup not mapped run list element if this is the base extent. */
if (!attr->_ANR(lowest_vcn)) {
VCN max_cluster;
@@ -742,13 +882,13 @@ mpa_err:
* likely, there are more extents following this one.
*/
if (deltaxcn < --max_cluster) {
- //RAR ntfs_debug("More extents to follow; deltaxcn = 0x%Lx, "
- //RAR "max_cluster = 0x%Lx",
- //RAR (long long)deltaxcn,
- //RAR (long long)max_cluster);
- (rl + rlpos)->vcn = vcn;
- vcn += (rl + rlpos)->length = max_cluster - deltaxcn;
- (rl + rlpos)->lcn = (LCN)LCN_RL_NOT_MAPPED;
+ ntfs_debug("More extents to follow; deltaxcn = 0x%Lx, "
+ "max_cluster = 0x%Lx",
+ (long long)deltaxcn,
+ (long long)max_cluster);
+ rl[rlpos].vcn = vcn;
+ vcn += rl[rlpos].length = max_cluster - deltaxcn;
+ rl[rlpos].lcn = (LCN)LCN_RL_NOT_MAPPED;
rlpos++;
} else if (unlikely(deltaxcn > max_cluster)) {
ntfs_error(vol->sb, "Corrupt attribute. deltaxcn = "
@@ -757,25 +897,26 @@ mpa_err:
(long long)max_cluster);
goto mpa_err;
}
- (rl + rlpos)->lcn = (LCN)LCN_ENOENT;
+ rl[rlpos].lcn = (LCN)LCN_ENOENT;
} else /* Not the base extent. There may be more extents to follow. */
- (rl + rlpos)->lcn = (LCN)LCN_RL_NOT_MAPPED;
+ rl[rlpos].lcn = (LCN)LCN_RL_NOT_MAPPED;
/* Setup terminating run_list element. */
- (rl + rlpos)->vcn = vcn;
- (rl + rlpos)->length = (s64)0;
- //RAR ntfs_debug("Mapping pairs array successfully decompressed.");
- //RAR ntfs_debug_dump_runlist(rl);
+ rl[rlpos].vcn = vcn;
+ rl[rlpos].length = (s64)0;
/* If no existing run list was specified, we are done. */
- if (!old_rl)
+ if (!old_rl) {
+ ntfs_debug("Mapping pairs array successfully decompressed:");
+ ntfs_debug_dump_runlist(rl);
return rl;
+ }
/* Now combine the new and old run lists checking for overlaps. */
- rl2 = merge_run_lists(old_rl, rl);
- if (likely(!IS_ERR(rl2)))
- return rl2;
+ old_rl = ntfs_merge_run_lists(old_rl, rl);
+ if (likely(!IS_ERR(old_rl)))
+ return old_rl;
ntfs_free(rl);
ntfs_error(vol->sb, "Failed to merge run lists.");
- return rl2;
+ return old_rl;
io_error:
ntfs_error(vol->sb, "Corrupt attribute.");
err_out:
diff --git a/fs/ntfs/mst.c b/fs/ntfs/mst.c
index 9b502299788a..5a1477db2712 100644
--- a/fs/ntfs/mst.c
+++ b/fs/ntfs/mst.c
@@ -48,7 +48,7 @@ int post_read_mst_fixup(NTFS_RECORD *b, const u32 size)
usa_ofs = le16_to_cpu(b->usa_ofs);
/* Decrement usa_count to get number of fixups. */
usa_count = le16_to_cpu(b->usa_count) - 1;
- /* Size and alignement checks. */
+ /* Size and alignment checks. */
if ( size & (NTFS_BLOCK_SIZE - 1) ||
usa_ofs & 1 ||
usa_ofs + (usa_count * 2) > size ||
@@ -132,7 +132,7 @@ int pre_write_mst_fixup(NTFS_RECORD *b, const u32 size)
usa_ofs = le16_to_cpu(b->usa_ofs);
/* Decrement usa_count to get number of fixups. */
usa_count = le16_to_cpu(b->usa_count) - 1;
- /* Size and alignement checks. */
+ /* Size and alignment checks. */
if ( size & (NTFS_BLOCK_SIZE - 1) ||
usa_ofs & 1 ||
usa_ofs + (usa_count * 2) > size ||
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index 94cc54668d87..68f7589e6987 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -1077,7 +1077,7 @@ iput_mirr_err_out:
* releases all inodes and memory belonging to the NTFS specific part of the
* super block.
*/
-void ntfs_put_super(struct super_block *vfs_sb)
+static void ntfs_put_super(struct super_block *vfs_sb)
{
ntfs_volume *vol = NTFS_SB(vfs_sb);
@@ -1155,7 +1155,7 @@ void ntfs_put_super(struct super_block *vfs_sb)
* Errors are ignored and we just return the number of free clusters we have
* found. This means we return an underestimate on error.
*/
-s64 get_nr_free_clusters(ntfs_volume *vol)
+static s64 get_nr_free_clusters(ntfs_volume *vol)
{
struct address_space *mapping = vol->lcnbmp_ino->i_mapping;
filler_t *readpage = (filler_t*)mapping->a_ops->readpage;
@@ -1227,7 +1227,7 @@ handle_partial_page:
}
/**
- * get_nr_free_mft_records - return the number of free inodes on a volume
+ * __get_nr_free_mft_records - return the number of free inodes on a volume
* @vol: ntfs volume for which to obtain free inode count
*
* Calculate the number of free mft records (inodes) on the mounted NTFS
@@ -1235,8 +1235,10 @@ handle_partial_page:
*
* Errors are ignored and we just return the number of free inodes we have
* found. This means we return an underestimate on error.
+ *
+ * NOTE: Caller must hold mftbmp_lock rw_semaphore for reading or writing.
*/
-unsigned long get_nr_free_mft_records(ntfs_volume *vol)
+static unsigned long __get_nr_free_mft_records(ntfs_volume *vol)
{
struct address_space *mapping;
filler_t *readpage;
@@ -1247,7 +1249,6 @@ unsigned long get_nr_free_mft_records(ntfs_volume *vol)
ntfs_debug("Entering.");
/* Serialize accesses to the inode bitmap. */
- down_read(&vol->mftbmp_lock);
mapping = &vol->mftbmp_mapping;
readpage = (filler_t*)mapping->a_ops->readpage;
/*
@@ -1307,7 +1308,6 @@ handle_partial_page:
}
ntfs_debug("Finished reading $MFT/$BITMAP, last index = 0x%lx",
index - 1);
- up_read(&vol->mftbmp_lock);
ntfs_debug("Exiting.");
return nr_free;
}
@@ -1330,7 +1330,7 @@ handle_partial_page:
*
* Return 0 on success or -errno on error.
*/
-int ntfs_statfs(struct super_block *sb, struct statfs *sfs)
+static int ntfs_statfs(struct super_block *sb, struct statfs *sfs)
{
ntfs_volume *vol = NTFS_SB(sb);
s64 size;
@@ -1354,10 +1354,12 @@ int ntfs_statfs(struct super_block *sb, struct statfs *sfs)
size = 0LL;
/* Free blocks avail to non-superuser, same as above on NTFS. */
sfs->f_bavail = sfs->f_bfree = size;
+ down_read(&vol->mftbmp_lock);
/* Total file nodes in file system (at this moment in time). */
sfs->f_files = vol->mft_ino->i_size >> vol->mft_record_size_bits;
/* Free file nodes in fs (based on current total count). */
- sfs->f_ffree = get_nr_free_mft_records(vol);
+ sfs->f_ffree = __get_nr_free_mft_records(vol);
+ up_read(&vol->mftbmp_lock);
/*
* File system id. This is extremely *nix flavour dependent and even
* within Linux itself all fs do their own thing. I interpret this to
diff --git a/fs/open.c b/fs/open.c
index eec397a0efc2..3742bc8a28d4 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -30,9 +30,7 @@ int vfs_statfs(struct super_block *sb, struct statfs *buf)
retval = -ENOSYS;
if (sb->s_op && sb->s_op->statfs) {
memset(buf, 0, sizeof(struct statfs));
- lock_kernel();
retval = sb->s_op->statfs(sb, buf);
- unlock_kernel();
}
}
return retval;
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index 407948c4ad5b..f69f312c8afb 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -281,6 +281,8 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock )
static int qnx4_statfs(struct super_block *sb, struct statfs *buf)
{
+ lock_kernel();
+
buf->f_type = sb->s_magic;
buf->f_bsize = sb->s_blocksize;
buf->f_blocks = le32_to_cpu(qnx4_sb(sb)->BitMap->di_size) * 8;
@@ -288,6 +290,8 @@ static int qnx4_statfs(struct super_block *sb, struct statfs *buf)
buf->f_bavail = buf->f_bfree;
buf->f_namelen = QNX4_NAME_MAX;
+ unlock_kernel();
+
return 0;
}
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index 7d41fc6389f2..1ed057e963f2 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -102,6 +102,9 @@ struct inode *ramfs_get_inode(struct super_block *sb, int mode, int dev)
case S_IFDIR:
inode->i_op = &ramfs_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
+
+ /* directory inodes start off with i_nlink == 2 (for "." entry) */
+ inode->i_nlink++;
break;
case S_IFLNK:
inode->i_op = &page_symlink_inode_operations;
@@ -131,10 +134,8 @@ static int ramfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int d
static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
{
int retval = ramfs_mknod(dir, dentry, mode | S_IFDIR, 0);
- if (!retval) {
+ if (!retval)
dir->i_nlink++;
- dentry->d_inode->i_nlink++;
- }
return retval;
}
diff --git a/fs/reiserfs/buffer2.c b/fs/reiserfs/buffer2.c
index a078187b1922..a08c2a01d256 100644
--- a/fs/reiserfs/buffer2.c
+++ b/fs/reiserfs/buffer2.c
@@ -25,6 +25,13 @@ void wait_buffer_until_released (const struct buffer_head * bh)
{
int repeat_counter = 0;
+ /*
+ * FIXME! Temporary cludge until ReiserFS people tell what they
+ * actually are trying to protect against!
+ */
+ if (1)
+ return;
+
while (atomic_read (&(bh->b_count)) > 1) {
if ( !(++repeat_counter % 30000000) ) {
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 0d439b0b1508..2acd8dfe1c2a 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -602,7 +602,13 @@ out_no_server:
static int
smb_statfs(struct super_block *sb, struct statfs *buf)
{
- int result = smb_proc_dskattr(sb, buf);
+ int result;
+
+ lock_kernel();
+
+ result = smb_proc_dskattr(sb, buf);
+
+ unlock_kernel();
buf->f_type = SMB_SUPER_MAGIC;
buf->f_namelen = SMB_MAXPATHLEN;
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 1b1680ecfa03..783890fffe9b 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -1726,6 +1726,8 @@ udf_put_super(struct super_block *sb)
static int
udf_statfs(struct super_block *sb, struct statfs *buf)
{
+ lock_kernel();
+
buf->f_type = UDF_SUPER_MAGIC;
buf->f_bsize = sb->s_blocksize;
buf->f_blocks = UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb));
@@ -1738,6 +1740,8 @@ udf_statfs(struct super_block *sb, struct statfs *buf)
/* __kernel_fsid_t f_fsid */
buf->f_namelen = UDF_NAME_LEN;
+ unlock_kernel();
+
return 0;
}
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 7a19f2c4fbf3..a046374ab085 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -959,6 +959,8 @@ int ufs_statfs (struct super_block * sb, struct statfs * buf)
struct ufs_sb_private_info * uspi;
struct ufs_super_block_first * usb1;
+ lock_kernel();
+
uspi = sb->u.ufs_sb.s_uspi;
usb1 = ubh_get_usb_first (USPI_UBH);
@@ -972,6 +974,9 @@ int ufs_statfs (struct super_block * sb, struct statfs * buf)
buf->f_files = uspi->s_ncg * uspi->s_ipg;
buf->f_ffree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree);
buf->f_namelen = UFS_MAXNAMLEN;
+
+ unlock_kernel();
+
return 0;
}
diff --git a/include/linux/input.h b/include/linux/input.h
index aa5e80d60330..76130b47a59a 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -2,7 +2,7 @@
#define _INPUT_H
/*
- * $Id: input.h,v 1.57 2002/01/02 11:59:56 vojtech Exp $
+ * $Id: input.h,v 1.68 2002/05/31 10:35:49 fsirl Exp $
*
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
@@ -322,12 +322,13 @@ struct input_event {
#define KEY_FINANCE 219
#define KEY_SPORT 220
#define KEY_SHOP 221
-
-#define KEY_UNKNOWN 240
-
+#define KEY_ALTERASE 222
+#define KEY_CANCEL 223
#define KEY_BRIGHTNESSDOWN 224
#define KEY_BRIGHTNESSUP 225
+#define KEY_UNKNOWN 240
+
#define BTN_MISC 0x100
#define BTN_0 0x100
#define BTN_1 0x101
@@ -394,6 +395,10 @@ struct input_event {
#define BTN_STYLUS 0x14b
#define BTN_STYLUS2 0x14c
+#define BTN_WHEEL 0x150
+#define BTN_GEAR_DOWN 0x150
+#define BTN_GEAR_UP 0x151
+
#define KEY_MAX 0x1ff
/*
@@ -514,23 +519,19 @@ struct input_event {
* Structures used in ioctls to upload effects to a device
* The first structures are not passed directly by using ioctls.
* They are sub-structures of the actually sent structure (called ff_effect)
- *
- * Ranges:
- * 0 <= __u16 <= 65535
- * -32767 <= __s16 <= +32767 ! Not -32768 for lower bound !
*/
struct ff_replay {
- __u16 length; /* Duration of an effect in ms. All other times are also expressed in ms */
- __u16 delay; /* Time to wait before to start playing an effect */
+ __u16 length; /* Duration of an effect in ms. All other times are also expressed in ms */
+ __u16 delay; /* Time to wait before to start playing an effect */
};
struct ff_trigger {
- __u16 button; /* Number of button triggering an effect */
- __u16 interval; /* Time to wait before an effect can be re-triggered (ms) */
+ __u16 button; /* Number of button triggering an effect */
+ __u16 interval; /* Time to wait before an effect can be re-triggered (ms) */
};
-struct ff_shape {
+struct ff_envelope {
__u16 attack_length; /* Duration of attack (ms) */
__u16 attack_level; /* Level at beginning of attack */
__u16 fade_length; /* Duration of fade (ms) */
@@ -539,41 +540,56 @@ struct ff_shape {
/* FF_CONSTANT */
struct ff_constant_effect {
- __s16 level; /* Strength of effect. Negative values are OK */
- struct ff_shape shape;
+ __s16 level; /* Strength of effect. Negative values are OK */
+ struct ff_envelope envelope;
};
-/* FF_SPRING of FF_FRICTION */
-struct ff_interactive_effect {
-/* Axis along which effect must be created. If null, the field named direction
- * is used
- * It is a bit array (ie to enable axes X and Y, use BIT(ABS_X) | BIT(ABS_Y)
- * It overrides the value of ff_effect::direction, which is used only if
- * axis == 0
- */
- __u16 axis;
+/* FF_RAMP */
+struct ff_ramp_effect {
+ __s16 start_level;
+ __s16 end_level;
+ struct ff_envelope envelope;
+};
+/* FF_SPRING of FF_FRICTION */
+struct ff_condition_effect {
__u16 right_saturation; /* Max level when joystick is on the right */
- __u16 left_saturation; /* Max level when joystick in on the left */
+ __u16 left_saturation; /* Max level when joystick in on the left */
__s16 right_coeff; /* Indicates how fast the force grows when the
joystick moves to the right */
__s16 left_coeff; /* Same for left side */
- __u16 deadband; /* Size of area where no force is produced */
- __s16 center; /* Position of dead dead zone */
+ __u16 deadband; /* Size of area where no force is produced */
+ __s16 center; /* Position of dead zone */
};
/* FF_PERIODIC */
struct ff_periodic_effect {
- __u16 waveform; /* Kind of wave (sine, square...) */
- __u16 period; /* in ms */
+ __u16 waveform; /* Kind of wave (sine, square...) */
+ __u16 period; /* in ms */
__s16 magnitude; /* Peak value */
- __s16 offset; /* Mean value of wave (roughly) */
+ __s16 offset; /* Mean value of wave (roughly) */
__u16 phase; /* 'Horizontal' shift */
- struct ff_shape shape;
+ struct ff_envelope envelope;
+
+/* Only used if waveform == FF_CUSTOM */
+ __u32 custom_len; /* Number of samples */
+ __s16 *custom_data; /* Buffer of samples */
+/* Note: the data pointed by custom_data is copied by the driver. You can
+ * therefore dispose of the memory after the upload/update */
+};
+
+/* FF_RUMBLE */
+/* Some rumble pads have two motors of different weight.
+ strong_magnitude represents the magnitude of the vibration generated
+ by the heavy motor.
+*/
+struct ff_rumble_effect {
+ __u16 strong_magnitude; /* Magnitude of the heavy motor */
+ __u16 weak_magnitude; /* Magnitude of the light one */
};
/*
@@ -598,27 +614,14 @@ struct ff_effect {
union {
struct ff_constant_effect constant;
+ struct ff_ramp_effect ramp;
struct ff_periodic_effect periodic;
- struct ff_interactive_effect interactive;
+ struct ff_condition_effect condition[2]; /* One for each axis */
+ struct ff_rumble_effect rumble;
} u;
};
/*
- * Buttons that can trigger effects. Use for example FF_BTN(BTN_TRIGGER) to
- * access the bitmap.
- */
-
-#define FF_BTN(x) ((x) - BTN_MISC + FF_BTN_OFFSET)
-#define FF_BTN_OFFSET 0x00
-
-/*
- * Force feedback axis mappings. Use FF_ABS() to access the bitmap.
- */
-
-#define FF_ABS(x) ((x) + FF_ABS_OFFSET)
-#define FF_ABS_OFFSET 0x40
-
-/*
* Force feedback effect types
*/
@@ -627,6 +630,9 @@ struct ff_effect {
#define FF_CONSTANT 0x52
#define FF_SPRING 0x53
#define FF_FRICTION 0x54
+#define FF_DAMPER 0x55
+#define FF_INERTIA 0x56
+#define FF_RAMP 0x57
/*
* Force feedback periodic effect types
@@ -668,8 +674,6 @@ struct input_dev {
char *name;
char *phys;
char *uniq;
- int number;
-
unsigned short idbus;
unsigned short idvendor;
unsigned short idproduct;
@@ -707,8 +711,6 @@ struct input_dev {
int absfuzz[ABS_MAX + 1];
int absflat[ABS_MAX + 1];
- int only_one_writer;
-
int (*open)(struct input_dev *dev);
void (*close)(struct input_dev *dev);
int (*accept)(struct input_dev *dev, struct file *file);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index d31eb7e942b3..b1c39c99e75f 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -104,6 +104,7 @@
#include <linux/interrupt.h> /* for in_interrupt() */
#include <linux/list.h> /* for struct list_head */
#include <linux/device.h> /* for struct device */
+#include <linux/fs.h> /* for struct file_operations */
static __inline__ void wait_ms(unsigned int ms)
@@ -648,14 +649,6 @@ struct usb_device_id {
* because its device has been (or is being) disconnected. The
* handle passed is what was returned by probe(), or was provided
* to usb_driver_claim_interface().
- * @fops: USB drivers can reuse some character device framework in
- * the USB subsystem by providing a file operations vector and
- * a minor number.
- * @minor: Used with fops to simplify creating USB character devices.
- * Such drivers have sixteen character devices, using the USB
- * major number and starting with this minor number.
- * @num_minors: Used with minor to specify how many minors are used by
- * this driver.
* @ioctl: Used for drivers that want to talk to userspace through
* the "usbfs" filesystem. This lets devices provide ways to
* expose information to user space regardless of where they
@@ -694,11 +687,6 @@ struct usb_driver {
);
struct list_head driver_list;
-
- struct file_operations *fops;
- int minor;
- int num_minors;
-
struct semaphore serialize;
/* ioctl -- userspace apps can talk to drivers through usbfs */
@@ -722,13 +710,8 @@ extern struct bus_type usb_bus_type;
extern int usb_register(struct usb_driver *);
extern void usb_deregister(struct usb_driver *);
-#ifndef CONFIG_USB_DYNAMIC_MINORS
-static inline int usb_register_dev(struct usb_driver *new_driver, int num_minors, int *start_minor) { return -ENODEV; }
-static inline void usb_deregister_dev(struct usb_driver *driver, int num_minors, int start_minor) {}
-#else
-extern int usb_register_dev(struct usb_driver *new_driver, int num_minors, int *start_minor);
-extern void usb_deregister_dev(struct usb_driver *driver, int num_minors, int start_minor);
-#endif
+extern int usb_register_dev(struct file_operations *fops, int minor, int num_minors, int *start_minor);
+extern void usb_deregister_dev(int num_minors, int start_minor);
/* -------------------------------------------------------------------------- */
diff --git a/mm/mmap.c b/mm/mmap.c
index 7c1badcd5155..384d1ff87f87 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1121,7 +1121,6 @@ void exit_mmap(struct mm_struct * mm)
unsigned long end = mpnt->vm_end;
mm->map_count--;
- remove_shared_vm_struct(mpnt);
unmap_page_range(tlb, mpnt, start, end);
mpnt = mpnt->vm_next;
}
@@ -1148,6 +1147,7 @@ void exit_mmap(struct mm_struct * mm)
*/
while (mpnt) {
struct vm_area_struct * next = mpnt->vm_next;
+ remove_shared_vm_struct(mpnt);
if (mpnt->vm_ops) {
if (mpnt->vm_ops->close)
mpnt->vm_ops->close(mpnt);
diff --git a/net/khttpd/Makefile b/net/khttpd/Makefile
index 0de4262de3e5..5eebd65c3b01 100644
--- a/net/khttpd/Makefile
+++ b/net/khttpd/Makefile
@@ -19,4 +19,4 @@ $(obj)/rfc_time.o: $(obj)/times.h
# Generated files
$(obj)/times.h: $(obj)/make_times_h
- $< >$@
+ $(obj)/make_times_h >$@