Description: Upstream changes introduced in version 3.1.3-13
This patch has been created by dpkg-source during the package build.
Here's the last changelog entry, hopefully it gives details on why
those changes were made:
.
tpconfig (3.1.3-13) unstable; urgency=low
.
* Adopt tpconfig. Thanks to Osamu Aoki for his previous work.
Closes: #479218.
* Bump Standards Version to 3.9.0. (No changes needed).
* Correct debian/watch to state that no upstream is available.
* Update README.Debian to remove outdated information.
* Remove empty debian/prerm.
* Rewrite debian/rules to take advantage of debhelper 7.
* Depends on autotools-dev.
* Switch to 3.0 (quilt) format.
* Add a lintian override for sourcing /etc/default/tpconfig: the
existence of the file is tested in a way that lintian does not detect.
.
The person named in the Author field signed this changelog entry.
Author: Vincent Bernat <bernat@debian.org>
Bug-Debian: http://bugs.debian.org/479218
---
The information above should follow the Patch Tagging Guidelines, please
checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here
are templates for supplementary fields that you might want to add:
Origin: <vendor|upstream|other>, <url of original patch>
Bug: <url in upstream bugtracker>
Bug-Debian: http://bugs.debian.org/<bugnumber>
Bug-Ubuntu: https://launchpad.net/bugs/<bugnumber>
Forwarded: <no|not-needed|url proving that it has been forwarded>
Reviewed-By: <name and email of someone who approved the patch>
Last-Update: <YYYY-MM-DD>
--- tpconfig-3.1.3.orig/tpconfig.h
+++ tpconfig-3.1.3/tpconfig.h
@@ -73,6 +73,7 @@
typedef unsigned char byte;
extern int DEBUG_LEVEL;
+extern int ignore_selected_assertions;
extern int silent;
extern float firmware_rev;
extern char single_mode_byte;
--- tpconfig-3.1.3.orig/synaptics.c
+++ tpconfig-3.1.3/synaptics.c
@@ -185,12 +185,10 @@ static unsigned int model_id;
#define QUAD_MODE_BYTE 0x0302
void
-synaptics_usage (char *progname)
+synaptics_usage (void)
{
- copyright ();
- printf ("Usage: %s [OPTION]...\n", progname);
printf
- ("Configure a Synaptics TouchPad.\n"
+ ("Options for a Synaptics TouchPad:\n"
"\n"
" -i, --info display current TouchPad configuration\n"
" -x, --reset perform a software reset on the TouchPad\n"
@@ -241,11 +239,11 @@ synaptics_usage (char *progname)
}
printf
("\n"
- " --help display this help and exit\n"
- " --version output version information\n"
- "\n"
- "Report bugs to <kall@compass.com>\n");
- exit(1);
+ " -h, --help display this help and exit\n"
+ " -v, --version output version information\n"
+ " -D, --debug=[0-3] generate debug output\n"
+ " -d, --device=DEVICE use alternate device file\n"
+ "\n");
}
@@ -282,7 +280,7 @@ status_rqst (int fd, byte cmd, byte *byt
static void
set_modes (int fd, unsigned int modes)
{
- if (DEBUG_LEVEL)
+ if (DEBUG_LEVEL > DEBUG_LOW)
fprintf (stderr, "[set modes: %#02x]\n", modes);
if (single_mode_byte)
{
@@ -318,7 +316,9 @@ query_identify (int fd,
{
byte b1, b2, b3;
status_rqst (fd, STP_QRY_IDENTIFY, &b1, &b2, &b3);
- assert (b2 == 0x47);
+ if (!ignore_selected_assertions)
+ /* Recent 2.6 kernels return 0x03 instead. */
+ assert (b2 == 0x47 || b2 == 0x03);
if (version_major) (*version_major) = (b3 & 0x0F);
if (version_minor) (*version_minor) = b1;
if (model_code) (*model_code) = ((b3 & 0xF0) >> 4);
@@ -330,10 +330,13 @@ query_modes (int fd)
byte b1, b2, b3;
byte b4, b5, b6;
status_rqst (fd, STP_QRY_READ_MODES, &b1, &b2, &b3);
- assert (b2 == 0x47);
+ if (!ignore_selected_assertions)
+ /* Recent 2.6 kernels return 0x03 instead. */
+ assert (b2 == 0x47 || b2 == 0x03);
if (single_mode_byte)
{
- assert (b1 == 0x3B);
+ if (!ignore_selected_assertions)
+ assert (b1 == 0x3B);
return b3;
}
else
@@ -342,7 +345,9 @@ query_modes (int fd)
if (fw_version < QUAD_MODE_BYTE)
{
status_rqst (fd, STP_QRY_READ_CAPS, &b4, &b5, &b6);
- assert (b5 == 0x47);
+ if (!ignore_selected_assertions)
+ /* Recent 2.6 kernels return 0x03 instead. */
+ assert (b5 == 0x47 || b5 == 0x03);
return ((unsigned int) b1 << 24) | ((unsigned int) b3 << 16) |
((unsigned int) b4 << 8) | (unsigned int) b6;
}
@@ -392,7 +397,8 @@ query_resolutions (int fd, unsigned int
{
byte b1, b2, b3;
status_rqst (fd, STP_QRY_READ_RES, &b1, &b2, &b3);
- assert ((b2 & 0x80) != 0);
+ if (!ignore_selected_assertions)
+ assert ((b2 & 0x80) != 0);
(*xres) = b1;
(*yres) = b3;
}
@@ -413,7 +419,8 @@ is_Synaptics (int fd)
b3 = getbyte (fd);
}
#endif
- retval = (b2 == 0x47);
+ /* Recent 2.6 kernels return 0x03 instead. */
+ retval = (b2 == 0x47 || b2 == 0x03);
if (retval)
{
fw_version_major = (b3 & 0x0F);
@@ -426,11 +433,12 @@ is_Synaptics (int fd)
void
reset_synaptics (int fd)
{
- fprintf (stderr,"Performing software reset on TouchPad.\n");
+ fprintf (stdout,"Performing software reset on TouchPad.\n");
putbyte (fd, AUX_RESET);
getbyte_expected (fd, AUX_RESET_ACK1, "software reset ACK 1");
getbyte_expected (fd, AUX_RESET_ACK2, "software reset ACK 2");
- fprintf (stderr, "Software reset of TouchPad complete.\n");
+ putbyte (fd, AUX_ENABLE_DEV);
+ fprintf (stdout, "Software reset of TouchPad complete.\n");
}
void
@@ -572,6 +580,8 @@ set_z_threshold (int fd)
if (optarg)
{
int a = get_argument (7);
+ if (DEBUG_LEVEL)
+ fprintf (stderr, "Z threshold set as \"%s\".\n", optarg);
if (a < 0)
{
fprintf (stderr, "Invalid Z threshold \"%s\" [use 0-7].\n", optarg);
@@ -580,7 +590,7 @@ set_z_threshold (int fd)
set_modes (fd, STP_SET_OMODE_Z_THRESH (query_modes (fd), a));
}
if (!silent)
- show_z_threshold (query_modes (fd), stderr);
+ show_z_threshold (query_modes (fd), stdout);
}
static void
@@ -590,6 +600,8 @@ set_tap_mode (int fd)
if (optarg)
{
int a = get_argument (limit);
+ if (DEBUG_LEVEL)
+ fprintf (stderr, "Tap mode set as \"%s\".\n", optarg);
if (a < 0)
{
fprintf (stderr, "Invalid tap mode \"%s\" [use 0-%d].\n",
@@ -602,7 +614,7 @@ set_tap_mode (int fd)
set_modes (fd, STP_SET_OMODE_TAP_MODE (query_modes (fd), a));
}
if (!silent)
- show_tap_mode (query_modes (fd), stderr);
+ show_tap_mode (query_modes (fd), stdout);
}
static void
@@ -616,6 +628,8 @@ set_edge_motion (int fd)
if (optarg)
{
int a = get_argument (3);
+ if (DEBUG_LEVEL)
+ fprintf (stderr, "Edge motion set as \"%s\".\n", optarg);
if (a < 0 || a == 2)
{
fprintf (stderr, "Invalid edge motion \"%s\" [use 0, 1, 3].\n",
@@ -625,7 +639,7 @@ set_edge_motion (int fd)
set_modes (fd, STP_SET_OMODE_EDGE_MOTN (query_modes (fd), a));
}
if (!silent)
- show_edge_motion (query_modes (fd), stderr);
+ show_edge_motion (query_modes (fd), stdout);
}
static void
@@ -639,6 +653,8 @@ set_corner_mode (int fd)
if (optarg)
{
int a = get_argument (1);
+ if (DEBUG_LEVEL)
+ fprintf (stderr, "Corner mode set as \"%s\".\n", optarg);
if (a < 0)
{
fprintf (stderr, "Invalid corner mode \"%s\" [use 0-1].\n", optarg);
@@ -647,7 +663,7 @@ set_corner_mode (int fd)
set_modes (fd, STP_SET_OMODE_CORNER (query_modes (fd), a));
}
if (!silent)
- show_tap_mode (query_modes (fd), stderr);
+ show_tap_mode (query_modes (fd), stdout);
}
static void
@@ -658,7 +674,7 @@ set_packet_mode (int fd, int absolute)
else
set_modes (fd, STP_SET_OMODE_ABSOLUTE (query_modes (fd), absolute));
if (!silent)
- show_packet_mode (query_modes (fd), stderr);
+ show_packet_mode (query_modes (fd), stdout);
}
static void
@@ -667,6 +683,8 @@ set_rate (int fd)
if (optarg)
{
int a = get_argument (1);
+ if (DEBUG_LEVEL)
+ fprintf (stderr, "Rate set as \"%s\".\n", optarg);
if (a < 0)
{
fprintf (stderr, "Invalid rate \"%s\" [use 0-%c].\n",
@@ -679,7 +697,7 @@ set_rate (int fd)
set_modes (fd, STP_SET_OMODE_RATE (query_modes (fd), a));
}
if (!silent)
- show_packet_mode (query_modes (fd), stderr);
+ show_packet_mode (query_modes (fd), stdout);
}
static void
@@ -692,7 +710,7 @@ set_button_mode (int fd, int three)
}
set_modes (fd, STP_SET_OMODE_3_BUTTON (query_modes (fd), three));
if (!silent)
- show_button_mode (query_modes (fd), stderr);
+ show_button_mode (query_modes (fd), stdout);
}
static void
@@ -705,7 +723,7 @@ set_corner_click (int fd, int middle)
}
set_modes (fd, STP_SET_OMODE_MIDDLE (query_modes (fd), middle));
if (!silent)
- show_button_mode (query_modes (fd), stderr);
+ show_button_mode (query_modes (fd), stdout);
}
static void
@@ -719,6 +737,8 @@ set_sleep_mode (int fd)
if (optarg)
{
int a = get_argument (1);
+ if (DEBUG_LEVEL)
+ fprintf (stderr, "Sleep mode set as \"%s\".\n", optarg);
if (a < 0)
{
fprintf (stderr, "Invalid sleep mode \"%s\" [use 0-1].\n", optarg);
@@ -727,7 +747,7 @@ set_sleep_mode (int fd)
set_modes (fd, STP_SET_MODE_SLEEP (query_modes (fd), a));
}
if (!silent)
- show_sleep_mode (query_modes (fd), stderr);
+ show_sleep_mode (query_modes (fd), stdout);
}
static void
@@ -741,6 +761,8 @@ set_right_margin (int fd)
if (optarg)
{
int a = get_argument (15);
+ if (DEBUG_LEVEL)
+ fprintf (stderr, "Right margin set as \"%s\".\n", optarg);
if (a < 0)
{
fprintf (stderr, "Invalid right margin \"%s\" [use 0-15].\n", optarg);
@@ -749,7 +771,7 @@ set_right_margin (int fd)
set_modes (fd, STP_SET_OMODE_RIGHT_MGN (query_modes (fd), a));
}
if (!silent)
- show_margins (query_modes (fd), stderr);
+ show_margins (query_modes (fd), stdout);
}
static void
@@ -763,6 +785,8 @@ set_left_margin (int fd)
if (optarg)
{
int a = get_argument (15);
+ if (DEBUG_LEVEL)
+ fprintf (stderr, "Left margin set as \"%s\".\n", optarg);
if (a < 0)
{
fprintf (stderr, "Invalid left margin \"%s\" [use 0-15].\n", optarg);
@@ -771,7 +795,7 @@ set_left_margin (int fd)
set_modes (fd, STP_SET_OMODE_LEFT_MGN (query_modes (fd), a));
}
if (!silent)
- show_margins (query_modes (fd), stderr);
+ show_margins (query_modes (fd), stdout);
}
static void
@@ -785,6 +809,8 @@ set_top_margin (int fd)
if (optarg)
{
int a = get_argument (15);
+ if (DEBUG_LEVEL)
+ fprintf (stderr, "Top margin set as \"%s\".\n", optarg);
if (a < 0)
{
fprintf (stderr, "Invalid top margin \"%s\" [use 0-15].\n", optarg);
@@ -793,7 +819,7 @@ set_top_margin (int fd)
set_modes (fd, STP_SET_OMODE_TOP_MGN (query_modes (fd), a));
}
if (!silent)
- show_margins (query_modes (fd), stderr);
+ show_margins (query_modes (fd), stdout);
}
static void
@@ -807,6 +833,8 @@ set_bottom_margin (int fd)
if (optarg)
{
int a = get_argument (15);
+ if (DEBUG_LEVEL)
+ fprintf (stderr, "Bottom margin set as \"%s\".\n", optarg);
if (a < 0)
{
fprintf (stderr, "Invalid bottom margin \"%s\" [use 0-15].\n", optarg);
@@ -815,7 +843,7 @@ set_bottom_margin (int fd)
set_modes (fd, STP_SET_OMODE_BOTTOM_MGN (query_modes (fd), a));
}
if (!silent)
- show_margins (query_modes (fd), stderr);
+ show_margins (query_modes (fd), stdout);
}
static void
@@ -901,7 +929,9 @@ synaptics_functions (int c, int fd, char
switch (c)
{
case 'h': /* --help */
- synaptics_usage (argv[0]);
+ printf ("Usage: %s [OPTION]...\n", (argv[0]));
+ synaptics_usage ();
+ printf ("Report bugs to <kall@compass.com>\n");
break;
case 'q': /* --quiet */
silent = 1;
@@ -909,12 +939,9 @@ synaptics_functions (int c, int fd, char
case 'x': /* --reset */
reset_synaptics (fd);
break;
- case 'v': /* --version */
- version_info ();
- break;
case 'i': /* --info */
if (!silent)
- synaptics_info (fd, stderr);
+ synaptics_info (fd, stdout);
break;
case 'z': /* --zthreshold */
set_z_threshold (fd);
@@ -945,7 +972,7 @@ synaptics_functions (int c, int fd, char
set_packet_mode (fd, a);
}
else if (!silent)
- show_tap_mode (query_modes (fd), stderr);
+ show_tap_mode (query_modes (fd), stdout);
break;
case 'r': /* --rate */
set_rate (fd);
@@ -975,7 +1002,7 @@ synaptics_functions (int c, int fd, char
set_corner_click (fd, a);
}
else if (!silent)
- show_button_mode (query_modes (fd), stderr);
+ show_button_mode (query_modes (fd), stdout);
break;
case 's': /* --sleep */
set_sleep_mode (fd);
@@ -985,7 +1012,7 @@ synaptics_functions (int c, int fd, char
fprintf (stderr, "Adjustable margins not supported on this TouchPad.\n");
else if (!silent)
/* Firmware prior to version 3.2 has four mode bytes */
- show_margins (query_modes (fd), stderr);
+ show_margins (query_modes (fd), stdout);
break;
case '4': /* --right-margin */
set_right_margin (fd);
--- tpconfig-3.1.3.orig/tpconfig.c
+++ tpconfig-3.1.3/tpconfig.c
@@ -106,15 +106,17 @@ static char rcsid[]="$Id: tpconfig.c,v 2
#include "tpconfig.h"
-extern void synaptics_usage(char *progname);
+extern void synaptics_usage(void);
extern void set_firmware_options(int fd, FILE *out);
-extern void ALPS_usage(char *progname);
+extern void ALPS_usage(void);
extern void synaptics_functions(int c,int fd,char **argv);
extern void alps_functions(int c,int fd,char **argv);
extern int is_ALPS(int fd);
extern int is_Synaptics(int fd);
int DEBUG_LEVEL;
+int ignore_selected_assertions;
+char mousedev[128] = "/dev/psaux";
int silent;
float firmware_rev;
char single_mode_byte;
@@ -126,10 +128,17 @@ void init_fd(int *fd)
int status;
if (*fd<0)
{
- *fd = open("/dev/psaux", O_RDWR|O_NDELAY);
+ if (DEBUG_LEVEL)
+ fprintf (stderr, "Probing mouse port [%s].\n", mousedev);
+ *fd = open(mousedev, O_RDWR|O_NDELAY);
if (*fd < 0)
- fatal("Could not open PS/2 Port [/dev/psaux]");
+ {
+ fprintf(stderr, "Could not open PS/2 Port [%s].\n", mousedev);
+ exit (0);
+ }
#ifdef __linux
+ if (DEBUG_LEVEL)
+ fprintf (stderr, "Grabbing mouse port [%s].\n", mousedev);
/* If AUX_GRAB kernel patch present, use it. */
while (ioctl (*fd, AUX_GRAB, 0) < 0)
{
@@ -137,15 +146,19 @@ if (*fd<0)
break;
if (errno != EAGAIN)
{
- perror ("/dev/psaux");
+ perror (mousedev);
fatal ("Unable to get exclusive access to PS/2 Port.");
exit (1);
}
}
#endif
tcflush(*fd,TCIOFLUSH);
+ if (DEBUG_LEVEL)
+ fprintf (stderr, "Trying Synaptics detection.\n");
if (!is_Synaptics(*fd))
{
+ if (DEBUG_LEVEL)
+ fprintf (stderr, "Trying Alps detection.\n");
status = is_ALPS(*fd);
if(status == 0)
{
@@ -191,7 +204,97 @@ DEBUG_LEVEL = DEBUG_NONE;
DEBUG_LEVEL = DEBUG_LOW;
#endif
-copyright();
+static struct option synaptics_long_options[] =
+ {
+ {"help", no_argument, NULL, 'h'}, /* -h */
+ {"version", no_argument, NULL, 'v'}, /* -v */
+ {"debug", optional_argument, NULL, 'D'}, /* -D */
+ {"device", required_argument, NULL, 'd'}, /* -d */
+ {"silent", no_argument, NULL, 'q'}, /* -q */
+ {"quiet", no_argument, NULL, 'q'}, /* -q */
+ {"info", no_argument, NULL, 'i'}, /* -i */
+ {"reset", no_argument, NULL, 'x'}, /* -x */
+ /* Mode 1 options */
+ {"zthreshold", optional_argument, NULL, 'z'}, /* -z */
+ {"threshold", optional_argument, NULL, 'z'}, /* -z */
+ {"corner", optional_argument, NULL, 'c'}, /* -c */
+ {"tapmode", optional_argument, NULL, 't'}, /* -t */
+ {"edgemode", optional_argument, NULL, 'e'}, /* -e */
+ /* Mode 2 options */
+ {"absolute", no_argument, NULL, 'A'}, /* similar to -a */
+ {"relative", no_argument, NULL, 'R'}, /* similar to -a */
+ {"rate", optional_argument, NULL, 'r'}, /* -r */
+ {"two-button", no_argument, NULL, '2'}, /* -2 */
+ {"three-button", no_argument, NULL, '3'}, /* -3 */
+ {"middle-button", no_argument, NULL, '<'}, /* similar to -m */
+ {"right-button", no_argument, NULL, '>'}, /* similar to -m */
+ {"sleep", optional_argument, NULL, 's'}, /* -s */
+ /* Mode 3 options */
+ {"right-margin", optional_argument, NULL, '4'}, /* similar to -M */
+ {"left-margin", optional_argument, NULL, '5'}, /* similar to -M */
+ /* Mode 4 options */
+ {"top-margin", optional_argument, NULL, '6'}, /* similar to -M */
+ {"bottom-margin", optional_argument, NULL, '7'}, /* similar to -M */
+ {NULL, no_argument, NULL, 0}
+ };
+const char * synaptics_short_options = "hvD::d:qiz::x::c::t::e::a::r::23m::s::M";
+
+static struct option ALPS_long_options[] =
+ {
+ {"help", no_argument, NULL, 'h'}, /* -h */
+ {"version", no_argument, NULL, 'v'}, /* -v */
+ {"debug", optional_argument, NULL, 'D'}, /* -D */
+ {"device", required_argument, NULL, 'd'}, /* -d */
+ {"info", no_argument, NULL, 'i'}, /* -i */
+ {"reset", no_argument, NULL, 'x'}, /* -x */
+ {"tapmode", optional_argument, NULL, 't'}, /* -t */
+ {NULL, no_argument, NULL, 0}
+ };
+const char * ALPS_short_options = "hvD::d:irt::";
+
+/* Initial option processing to handle special options. */
+optind = 1;
+while (1)
+ {
+ switch (getopt_long (argc, argv, synaptics_short_options,
+ synaptics_long_options, &option_index))
+ {
+ case 'h':
+ printf ("Usage: %s [OPTION]...\n", (argv[0]));
+ synaptics_usage ();
+ ALPS_usage ();
+ printf ("Report bugs to <kall@compass.com>\n");
+ return (0);
+
+ case 'v':
+ copyright ();
+ return (0);
+
+ case 'D':
+ if (optarg == 0)
+ DEBUG_LEVEL = DEBUG_LOW;
+ else if ((strcmp (optarg, "0")) == 0)
+ DEBUG_LEVEL = DEBUG_NONE;
+ else if ((strcmp (optarg, "1")) == 0)
+ DEBUG_LEVEL = DEBUG_LOW;
+ else if ((strcmp (optarg, "2")) == 0)
+ DEBUG_LEVEL = DEBUG_MEDIUM;
+ else
+ DEBUG_LEVEL = DEBUG_HIGH;
+ break;
+
+ case 'd':
+ strncpy (mousedev, optarg, ((sizeof (mousedev)) - 1));
+ break;
+
+ case -1:
+ goto initial_options_done;
+
+ default:
+ break;
+ }
+ }
+initial_options_done:
/* Open file descriptor and determine if we are connected to a touchpad */
@@ -200,72 +303,37 @@ init_fd(&fd);
if(touchpad_type == SYNAPTICS_TOUCHPAD)
set_firmware_options(fd,stdout);
-if((argc < 2) && (touchpad_type == SYNAPTICS_TOUCHPAD))
- synaptics_usage(argv[0]); /* no command line options */
-else if((argc < 2) &&
- ((touchpad_type == ALPS_GLIDEPAD) || (touchpad_type == ALPS_STICKPOINTER_AND_GLIDEPOINT)))
- ALPS_usage(argv[0]);
-
+optind = 1;
opterr=1;
while (1)
{
- static struct option synaptics_long_options[] =
- {
- {"help", no_argument, NULL, 'h'},
- {"silent", no_argument, NULL, 'q'}, /* -q */
- {"quiet", no_argument, NULL, 'q'}, /* -q */
- {"info", no_argument, NULL, 'i'}, /* -i */
- {"version", no_argument, NULL, 'v'}, /* -v */
- {"reset", no_argument, NULL, 'x'}, /* -x */
- /* Mode 1 options */
- {"zthreshold", optional_argument, NULL, 'z'}, /* -z */
- {"threshold", optional_argument, NULL, 'z'}, /* -z */
- {"corner", optional_argument, NULL, 'c'}, /* -c */
- {"tapmode", optional_argument, NULL, 't'}, /* -t */
- {"edgemode", optional_argument, NULL, 'e'}, /* -e */
- /* Mode 2 options */
- {"absolute", no_argument, NULL, 'A'}, /* similar to -a */
- {"relative", no_argument, NULL, 'R'}, /* similar to -a */
- {"rate", optional_argument, NULL, 'r'}, /* -r */
- {"two-button", no_argument, NULL, '2'}, /* -2 */
- {"three-button", no_argument, NULL, '3'}, /* -3 */
- {"middle-button", no_argument, NULL, '<'}, /* similar to -m */
- {"right-button", no_argument, NULL, '>'}, /* similar to -m */
- {"sleep", optional_argument, NULL, 's'}, /* -s */
- /* Mode 3 options */
- {"right-margin", optional_argument, NULL, '4'}, /* similar to -M */
- {"left-margin", optional_argument, NULL, '5'}, /* similar to -M */
- /* Mode 4 options */
- {"top-margin", optional_argument, NULL, '6'}, /* similar to -M */
- {"bottom-margin", optional_argument, NULL, '7'}, /* similar to -M */
- {NULL, no_argument, NULL, 0}
- };
-
- static struct option ALPS_long_options[] =
- {
- {"help", no_argument, NULL, 'h'},
- {"info", no_argument, NULL, 'i'}, /* -i */
- {"reset", no_argument, NULL, 'x'}, /* -x */
- {"tapmode", optional_argument, NULL, 't'}, /* -t */
- {"version", no_argument, NULL, 'v'}, /* -v */
- {NULL, no_argument, NULL, 0}
- };
-
if(touchpad_type == SYNAPTICS_TOUCHPAD)
- c = getopt_long (argc, argv, "qivzx::c::t::e::a::r::23m::s::M",
+ c = getopt_long (argc, argv, synaptics_short_options,
synaptics_long_options, &option_index);
else if((touchpad_type == ALPS_STICKPOINTER_AND_GLIDEPOINT) || (touchpad_type == ALPS_GLIDEPAD))
- c = getopt_long (argc, argv, "hirtv",
+ c = getopt_long (argc, argv, ALPS_short_options,
ALPS_long_options, &option_index);
- if (c == -1)
- break;
-
- if(touchpad_type == SYNAPTICS_TOUCHPAD)
- synaptics_functions(c,fd,argv);
- else if((touchpad_type == ALPS_STICKPOINTER_AND_GLIDEPOINT) || (touchpad_type == ALPS_GLIDEPAD))
- alps_functions(c,fd,argv);
+ switch (c)
+ {
+ case 'h':
+ case 'v':
+ case 'D':
+ case 'd':
+ break;
+
+ case -1:
+ goto options_done;
+
+ default:
+ if (touchpad_type == SYNAPTICS_TOUCHPAD)
+ synaptics_functions (c, fd, argv);
+ else if ((touchpad_type == ALPS_STICKPOINTER_AND_GLIDEPOINT)
+ || (touchpad_type == ALPS_GLIDEPAD))
+ alps_functions (c, fd, argv);
+ }
}
+options_done:
if (optind < argc)
{
fprintf(stderr, "Extra options: ");
--- /dev/null
+++ tpconfig-3.1.3/psaux-2.4.12-combined.diff
@@ -0,0 +1,409 @@
+diff -ruN linux-2.4.12-orig/drivers/char/pc_keyb.c linux-2.4.12/drivers/char/pc_keyb.c
+--- linux-2.4.12-orig/drivers/char/pc_keyb.c Tue Sep 18 01:52:35 2001
++++ linux-2.4.12/drivers/char/pc_keyb.c Thu Oct 11 13:10:03 2001
+@@ -13,6 +13,15 @@
+ * Code fixes to handle mouse ACKs properly.
+ * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29.
+ *
++ * More work to handle mouse ACKs properly. (Modified version of
++ * patch by Julian Bradfield <jcb@dcs.ed.ac.uk>.)
++ * Chris Hanson <cph@zurich.ai.mit.edu> 2000-12-11.
++ *
++ * Implement exclusive access mechanism for aux device.
++ * This permits grabbing the mouse away from the X server,
++ * which is needed by fancy mice that have configurable features.
++ * Chris Hanson <cph@zurich.ai.mit.edu> 2000-10-30.
++ *
+ */
+
+ #include <linux/config.h>
+@@ -66,6 +75,8 @@
+ static void aux_write_ack(int val);
+ static void __aux_write_ack(int val);
+ static int aux_reconnect = 0;
++static void aux_kill_fasync(struct fasync_struct **fasync, int sig, int band);
++static int aux_release_ioctl(struct file *file);
+ #endif
+
+ static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
+@@ -89,13 +100,30 @@
+
+ static struct aux_queue *queue; /* Mouse data buffer. */
+ static int aux_count;
+-/* used when we send commands to the mouse that expect an ACK. */
++/* Used when we (as opposed to user programs using the aux device)
++ send commands to the mouse. */
+ static unsigned char mouse_reply_expected;
+
++/* Used to make sure we have received an ACK from the byte last
++ written to the mouse before writing another. */
++static unsigned long mouse_ack_pending;
++static wait_queue_head_t mouse_ack_wait;
++/* How many jiffies to wait for the mouse to respond to a command with
++ an ACK. 25 msec is the maximum allowed delay for the hardware to
++ respond. We round that up to the nearest jiffy. */
++#define MOUSE_ACK_TIMEOUT ((25 * HZ + 999) / 1000)
++
+ #define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT)
+ #define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT)
+
+ #define MAX_RETRIES 60 /* some aux operations take long time*/
++
++/* Support for exclusive access to the AUX device. */
++static struct file *aux_exclusive;
++static wait_queue_head_t aux_exclusive_wait;
++static unsigned long aux_last_write;
++#define AUX_GRAB _IO('M', 1)
++#define AUX_RELEASE _IO('M', 2)
+ #endif /* CONFIG_PSMOUSE */
+
+ /*
+@@ -427,6 +455,13 @@
+ {
+ #ifdef CONFIG_PSMOUSE
+ static unsigned char prev_code;
++ if (mouse_ack_pending) {
++ /* It needn't actually be an ack, it could be an echo;
++ but every byte sent to the mouse results in a byte
++ back. */
++ wake_up_interruptible(&mouse_ack_wait);
++ mouse_ack_pending = 0;
++ }
+ if (mouse_reply_expected) {
+ if (scancode == AUX_ACK) {
+ mouse_reply_expected--;
+@@ -451,7 +486,7 @@
+ head = (head + 1) & (AUX_BUF_SIZE-1);
+ if (head != queue->tail) {
+ queue->head = head;
+- kill_fasync(&queue->fasync, SIGIO, POLL_IN);
++ aux_kill_fasync(&queue->fasync, SIGIO, POLL_IN);
+ wake_up_interruptible(&queue->proc_list);
+ }
+ }
+@@ -968,19 +1003,75 @@
+ return retval;
+ }
+
++static void mouse_ack_timeout(unsigned long data)
++{
++ wake_up_interruptible(&mouse_ack_wait);
++}
++
+ /*
+ * Send a byte to the mouse.
+ */
+-static void aux_write_dev(int val)
++static int aux_write_dev(int val, int dont_block, int handle_ack)
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&kbd_controller_lock, flags);
+ kb_wait();
++ /* If we haven't yet received the ACK from the previous write,
++ we must wait for it. */
++ if (mouse_ack_pending) {
++ unsigned long expires;
++ struct timer_list timer;
++ DECLARE_WAITQUEUE(wait, current);
++
++ if (dont_block) {
++ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++ return -EAGAIN;
++ }
++ expires = mouse_ack_pending + MOUSE_ACK_TIMEOUT;
++ if (jiffies >= expires)
++ goto timed_out;
++
++ add_wait_queue(&mouse_ack_wait, &wait);
++ init_timer (&timer);
++ timer.expires = expires;
++ timer.data = 0;
++ timer.function = mouse_ack_timeout;
++ add_timer(&timer);
++
++ do {
++ current->state = TASK_INTERRUPTIBLE;
++ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++ schedule();
++ spin_lock_irqsave(&kbd_controller_lock, flags);
++ } while (mouse_ack_pending
++ && jiffies < expires
++ && !signal_pending(current));
++
++ del_timer(&timer);
++ remove_wait_queue(&mouse_ack_wait, &wait);
++
++ if (mouse_ack_pending && jiffies >= expires) {
++ timed_out:
++ printk(KERN_WARNING "mouse ack timeout\n");
++ mouse_ack_pending = 0;
++ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++ return -EIO;
++ }
++ if (signal_pending(current)) {
++ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++ return -ERESTARTSYS;
++ }
++ }
+ kbd_write_command(KBD_CCMD_WRITE_MOUSE);
+ kb_wait();
+ kbd_write_output(val);
++ mouse_ack_pending = jiffies;
++ if (handle_ack)
++ /* We will deal with the ACK ourselves. */
++ mouse_reply_expected++;
+ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++ return 0;
+ }
+
+ /*
+@@ -992,11 +1083,13 @@
+ kbd_write_command(KBD_CCMD_WRITE_MOUSE);
+ kb_wait();
+ kbd_write_output(val);
+- /* we expect an ACK in response. */
++ mouse_ack_pending = jiffies;
++ /* We will deal with the ACK ourselves. */
+ mouse_reply_expected++;
+ kb_wait();
+ }
+
++#ifdef INITIALIZE_MOUSE
+ static void aux_write_ack(int val)
+ {
+ unsigned long flags;
+@@ -1005,6 +1098,33 @@
+ __aux_write_ack(val);
+ spin_unlock_irqrestore(&kbd_controller_lock, flags);
+ }
++#endif /* INITIALIZE_MOUSE */
++
++static void aux_kill_fasync(struct fasync_struct **fasync, int sig, int band)
++{
++ struct fasync_struct * fp;
++ struct fasync_struct fa;
++
++ fp = *fasync;
++ /* If someone has grabbed the AUX device, send signal only to
++ them and not to other processes. We could do this directly
++ if send_sigio was exported, but since it isn't we must
++ synthesize a "struct fasync_struct" to pass to
++ kill_fasync. */
++ if (aux_exclusive) {
++ while (1) {
++ if (!fp)
++ return;
++ if (fp->fa_file == aux_exclusive)
++ break;
++ fp = fp->fa_next;
++ }
++ fa = (*fp);
++ fa.fa_next = NULL;
++ fp = &fa;
++ }
++ kill_fasync(&fp, sig, band);
++}
+
+ static unsigned char get_from_queue(void)
+ {
+@@ -1044,6 +1164,8 @@
+ {
+ lock_kernel();
+ fasync_aux(-1, file, 0);
++ if (aux_exclusive == file)
++ aux_release_ioctl(file);
+ if (--aux_count) {
+ unlock_kernel();
+ return 0;
+@@ -1073,7 +1195,7 @@
+ kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable the
+ auxiliary port on
+ controller. */
+- aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */
++ aux_write_dev(AUX_ENABLE_DEV, 0, 1); /* Enable aux device */
+ kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */
+
+ mdelay(2); /* Ensure we follow the kbc access delay rules.. */
+@@ -1084,6 +1206,33 @@
+ }
+
+ /*
++ * Implement exclusive access mechanism.
++ */
++
++#define AUX_ACCESS_ALLOWED(file) (!aux_exclusive || aux_exclusive == (file))
++
++static ssize_t aux_wait_for_access(struct file * file)
++{
++ DECLARE_WAITQUEUE(wait, current);
++
++ if (!AUX_ACCESS_ALLOWED(file)) {
++ if (file->f_flags & O_NONBLOCK)
++ return -EAGAIN;
++ add_wait_queue(&aux_exclusive_wait, &wait);
++ do {
++ current->state = TASK_INTERRUPTIBLE;
++ schedule();
++ }
++ while (!AUX_ACCESS_ALLOWED(file)
++ && !signal_pending(current));
++ remove_wait_queue(&aux_exclusive_wait, &wait);
++ }
++ if (!AUX_ACCESS_ALLOWED(file))
++ return -ERESTARTSYS;
++ return 0;
++}
++
++/*
+ * Put bytes from input queue to buffer.
+ */
+
+@@ -1093,7 +1242,11 @@
+ DECLARE_WAITQUEUE(wait, current);
+ ssize_t i = count;
+ unsigned char c;
++ ssize_t retval;
+
++ retval = aux_wait_for_access(file);
++ if (retval < 0)
++ return retval;
+ if (queue_empty()) {
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+@@ -1128,23 +1281,32 @@
+ static ssize_t write_aux(struct file * file, const char * buffer,
+ size_t count, loff_t *ppos)
+ {
+- ssize_t retval = 0;
++ ssize_t retval;
+
++ retval = aux_wait_for_access(file);
++ if (retval < 0)
++ return retval;
+ if (count) {
+ ssize_t written = 0;
+
++ retval = -EIO;
+ if (count > 32)
+ count = 32; /* Limit to 32 bytes. */
+ do {
+ char c;
++ int write_result;
+ get_user(c, buffer++);
+- aux_write_dev(c);
++ write_result = aux_write_dev(c, file->f_flags & O_NONBLOCK, 0);
++ if (write_result) {
++ retval = write_result;
++ break;
++ }
+ written++;
+ } while (--count);
+- retval = -EIO;
+ if (written) {
+ retval = written;
+ file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
++ aux_last_write = jiffies;
+ }
+ }
+
+@@ -1155,15 +1317,80 @@
+ static unsigned int aux_poll(struct file *file, poll_table * wait)
+ {
+ poll_wait(file, &queue->proc_list, wait);
+- if (!queue_empty())
++ if (AUX_ACCESS_ALLOWED(file) && !queue_empty())
+ return POLLIN | POLLRDNORM;
+ return 0;
+ }
+
++/* Wait this long after last write to mouse before allowing AUX_GRAB
++ to happen. This ensures that any outstanding mouse command is
++ completed. The ACK from the command is supposed to arrive in 25
++ msec, and each subsequent status bytes are supposed to arrive
++ within 20 msec, so a command with 5 status bytes (I don't know any
++ this long) might take 125 msec. Fudge this up a bit to account for
++ additional delay introduced by bus locking. */
++#define AUX_GRAB_MIN_TIME (aux_last_write + (((200 * HZ) + 500) / 1000))
++#define AUX_GRAB_ALLOWED (aux_exclusive == 0 && (jiffies >= AUX_GRAB_MIN_TIME))
++
++static void aux_grab_timeout(unsigned long data)
++{
++ wake_up_interruptible(&aux_exclusive_wait);
++}
++
++static int aux_grab_ioctl(struct file *file)
++{
++ DECLARE_WAITQUEUE(wait, current);
++ struct timer_list timer;
++
++ if (aux_exclusive == file)
++ return -EINVAL;
++ if (!AUX_GRAB_ALLOWED) {
++ if (file->f_flags & O_NONBLOCK)
++ return -EAGAIN;
++ init_timer (&timer);
++ timer.expires = AUX_GRAB_MIN_TIME;
++ timer.data = 0;
++ timer.function = aux_grab_timeout;
++ add_wait_queue(&aux_exclusive_wait, &wait);
++ add_timer(&timer);
++ do {
++ current->state = TASK_INTERRUPTIBLE;
++ schedule();
++ }
++ while (!AUX_GRAB_ALLOWED && !signal_pending(current));
++ del_timer(&timer);
++ remove_wait_queue(&aux_exclusive_wait, &wait);
++ }
++ if (!AUX_GRAB_ALLOWED)
++ return -ERESTARTSYS;
++ aux_exclusive = file;
++ return 0;
++}
++
++static int aux_release_ioctl(struct file *file)
++{
++ if (aux_exclusive != file)
++ return -ENOENT;
++ aux_exclusive = 0;
++ wake_up_interruptible(&aux_exclusive_wait);
++ return 0;
++}
++
++static int aux_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ switch (cmd) {
++ case AUX_GRAB: return aux_grab_ioctl(file);
++ case AUX_RELEASE: return aux_release_ioctl(file);
++ default: return -EINVAL;
++ }
++}
++
+ struct file_operations psaux_fops = {
+ read: read_aux,
+ write: write_aux,
+ poll: aux_poll,
++ ioctl: aux_ioctl,
+ open: open_aux,
+ release: release_aux,
+ fasync: fasync_aux,
+@@ -1195,6 +1422,8 @@
+ memset(queue, 0, sizeof(*queue));
+ queue->head = queue->tail = 0;
+ init_waitqueue_head(&queue->proc_list);
++ init_waitqueue_head(&mouse_ack_wait);
++ init_waitqueue_head(&aux_exclusive_wait);
+
+ #ifdef INITIALIZE_MOUSE
+ kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */
+@@ -1206,6 +1435,8 @@
+ #endif /* INITIALIZE_MOUSE */
+ kbd_write_command(KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */
+ kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */
++
++ aux_last_write = jiffies;
+
+ return 0;
+ }
--- /dev/null
+++ tpconfig-3.1.3/psaux-2.4.9-combined.diff
@@ -0,0 +1,408 @@
+--- linux-2.4.9/drivers/char/pc_keyb.c.orig Tue Aug 14 18:49:50 2001
++++ linux-2.4.9/drivers/char/pc_keyb.c Thu Aug 16 22:29:33 2001
+@@ -13,6 +13,15 @@
+ * Code fixes to handle mouse ACKs properly.
+ * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29.
+ *
++ * More work to handle mouse ACKs properly. (Modified version of
++ * patch by Julian Bradfield <jcb@dcs.ed.ac.uk>.)
++ * Chris Hanson <cph@zurich.ai.mit.edu> 2000-12-11.
++ *
++ * Implement exclusive access mechanism for aux device.
++ * This permits grabbing the mouse away from the X server,
++ * which is needed by fancy mice that have configurable features.
++ * Chris Hanson <cph@zurich.ai.mit.edu> 2000-10-30.
++ *
+ */
+
+ #include <linux/config.h>
+@@ -64,6 +73,8 @@
+ static void aux_write_ack(int val);
+ static void __aux_write_ack(int val);
+ static int aux_reconnect = 0;
++static void aux_kill_fasync(struct fasync_struct **fasync, int sig, int band);
++static int aux_release_ioctl(struct file *file);
+ #endif
+
+ static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
+@@ -87,13 +98,30 @@
+
+ static struct aux_queue *queue; /* Mouse data buffer. */
+ static int aux_count;
+-/* used when we send commands to the mouse that expect an ACK. */
++/* Used when we (as opposed to user programs using the aux device)
++ send commands to the mouse. */
+ static unsigned char mouse_reply_expected;
+
++/* Used to make sure we have received an ACK from the byte last
++ written to the mouse before writing another. */
++static unsigned long mouse_ack_pending;
++static wait_queue_head_t mouse_ack_wait;
++/* How many jiffies to wait for the mouse to respond to a command with
++ an ACK. 25 msec is the maximum allowed delay for the hardware to
++ respond. We round that up to the nearest jiffy. */
++#define MOUSE_ACK_TIMEOUT ((25 * HZ + 999) / 1000)
++
+ #define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT)
+ #define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT)
+
+ #define MAX_RETRIES 60 /* some aux operations take long time*/
++
++/* Support for exclusive access to the AUX device. */
++static struct file *aux_exclusive;
++static wait_queue_head_t aux_exclusive_wait;
++static unsigned long aux_last_write;
++#define AUX_GRAB _IO('M', 1)
++#define AUX_RELEASE _IO('M', 2)
+ #endif /* CONFIG_PSMOUSE */
+
+ /*
+@@ -399,6 +427,13 @@
+ {
+ #ifdef CONFIG_PSMOUSE
+ static unsigned char prev_code;
++ if (mouse_ack_pending) {
++ /* It needn't actually be an ack, it could be an echo;
++ but every byte sent to the mouse results in a byte
++ back. */
++ wake_up_interruptible(&mouse_ack_wait);
++ mouse_ack_pending = 0;
++ }
+ if (mouse_reply_expected) {
+ if (scancode == AUX_ACK) {
+ mouse_reply_expected--;
+@@ -423,7 +458,7 @@
+ head = (head + 1) & (AUX_BUF_SIZE-1);
+ if (head != queue->tail) {
+ queue->head = head;
+- kill_fasync(&queue->fasync, SIGIO, POLL_IN);
++ aux_kill_fasync(&queue->fasync, SIGIO, POLL_IN);
+ wake_up_interruptible(&queue->proc_list);
+ }
+ }
+@@ -895,19 +930,75 @@
+ return retval;
+ }
+
++static void mouse_ack_timeout(unsigned long data)
++{
++ wake_up_interruptible(&mouse_ack_wait);
++}
++
+ /*
+ * Send a byte to the mouse.
+ */
+-static void aux_write_dev(int val)
++static int aux_write_dev(int val, int dont_block, int handle_ack)
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&kbd_controller_lock, flags);
+ kb_wait();
++ /* If we haven't yet received the ACK from the previous write,
++ we must wait for it. */
++ if (mouse_ack_pending) {
++ unsigned long expires;
++ struct timer_list timer;
++ DECLARE_WAITQUEUE(wait, current);
++
++ if (dont_block) {
++ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++ return -EAGAIN;
++ }
++ expires = mouse_ack_pending + MOUSE_ACK_TIMEOUT;
++ if (jiffies >= expires)
++ goto timed_out;
++
++ add_wait_queue(&mouse_ack_wait, &wait);
++ init_timer (&timer);
++ timer.expires = expires;
++ timer.data = 0;
++ timer.function = mouse_ack_timeout;
++ add_timer(&timer);
++
++ do {
++ current->state = TASK_INTERRUPTIBLE;
++ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++ schedule();
++ spin_lock_irqsave(&kbd_controller_lock, flags);
++ } while (mouse_ack_pending
++ && jiffies < expires
++ && !signal_pending(current));
++
++ del_timer(&timer);
++ remove_wait_queue(&mouse_ack_wait, &wait);
++
++ if (mouse_ack_pending && jiffies >= expires) {
++ timed_out:
++ printk(KERN_WARNING "mouse ack timeout\n");
++ mouse_ack_pending = 0;
++ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++ return -EIO;
++ }
++ if (signal_pending(current)) {
++ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++ return -ERESTARTSYS;
++ }
++ }
+ kbd_write_command(KBD_CCMD_WRITE_MOUSE);
+ kb_wait();
+ kbd_write_output(val);
++ mouse_ack_pending = jiffies;
++ if (handle_ack)
++ /* We will deal with the ACK ourselves. */
++ mouse_reply_expected++;
+ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++ return 0;
+ }
+
+ /*
+@@ -919,11 +1010,13 @@
+ kbd_write_command(KBD_CCMD_WRITE_MOUSE);
+ kb_wait();
+ kbd_write_output(val);
+- /* we expect an ACK in response. */
++ mouse_ack_pending = jiffies;
++ /* We will deal with the ACK ourselves. */
+ mouse_reply_expected++;
+ kb_wait();
+ }
+
++#ifdef INITIALIZE_MOUSE
+ static void aux_write_ack(int val)
+ {
+ unsigned long flags;
+@@ -932,6 +1025,33 @@
+ __aux_write_ack(val);
+ spin_unlock_irqrestore(&kbd_controller_lock, flags);
+ }
++#endif /* INITIALIZE_MOUSE */
++
++static void aux_kill_fasync(struct fasync_struct **fasync, int sig, int band)
++{
++ struct fasync_struct * fp;
++ struct fasync_struct fa;
++
++ fp = *fasync;
++ /* If someone has grabbed the AUX device, send signal only to
++ them and not to other processes. We could do this directly
++ if send_sigio was exported, but since it isn't we must
++ synthesize a "struct fasync_struct" to pass to
++ kill_fasync. */
++ if (aux_exclusive) {
++ while (1) {
++ if (!fp)
++ return;
++ if (fp->fa_file == aux_exclusive)
++ break;
++ fp = fp->fa_next;
++ }
++ fa = (*fp);
++ fa.fa_next = NULL;
++ fp = &fa;
++ }
++ kill_fasync(&fp, sig, band);
++}
+
+ static unsigned char get_from_queue(void)
+ {
+@@ -971,6 +1091,8 @@
+ {
+ lock_kernel();
+ fasync_aux(-1, file, 0);
++ if (aux_exclusive == file)
++ aux_release_ioctl(file);
+ if (--aux_count) {
+ unlock_kernel();
+ return 0;
+@@ -1000,7 +1122,7 @@
+ kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable the
+ auxiliary port on
+ controller. */
+- aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */
++ aux_write_dev(AUX_ENABLE_DEV, 0, 1); /* Enable aux device */
+ kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */
+
+ mdelay(2); /* Ensure we follow the kbc access delay rules.. */
+@@ -1011,6 +1133,33 @@
+ }
+
+ /*
++ * Implement exclusive access mechanism.
++ */
++
++#define AUX_ACCESS_ALLOWED(file) (!aux_exclusive || aux_exclusive == (file))
++
++static ssize_t aux_wait_for_access(struct file * file)
++{
++ DECLARE_WAITQUEUE(wait, current);
++
++ if (!AUX_ACCESS_ALLOWED(file)) {
++ if (file->f_flags & O_NONBLOCK)
++ return -EAGAIN;
++ add_wait_queue(&aux_exclusive_wait, &wait);
++ do {
++ current->state = TASK_INTERRUPTIBLE;
++ schedule();
++ }
++ while (!AUX_ACCESS_ALLOWED(file)
++ && !signal_pending(current));
++ remove_wait_queue(&aux_exclusive_wait, &wait);
++ }
++ if (!AUX_ACCESS_ALLOWED(file))
++ return -ERESTARTSYS;
++ return 0;
++}
++
++/*
+ * Put bytes from input queue to buffer.
+ */
+
+@@ -1020,7 +1169,11 @@
+ DECLARE_WAITQUEUE(wait, current);
+ ssize_t i = count;
+ unsigned char c;
++ ssize_t retval;
+
++ retval = aux_wait_for_access(file);
++ if (retval < 0)
++ return retval;
+ if (queue_empty()) {
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+@@ -1055,23 +1208,32 @@
+ static ssize_t write_aux(struct file * file, const char * buffer,
+ size_t count, loff_t *ppos)
+ {
+- ssize_t retval = 0;
++ ssize_t retval;
+
++ retval = aux_wait_for_access(file);
++ if (retval < 0)
++ return retval;
+ if (count) {
+ ssize_t written = 0;
+
++ retval = -EIO;
+ if (count > 32)
+ count = 32; /* Limit to 32 bytes. */
+ do {
+ char c;
++ int write_result;
+ get_user(c, buffer++);
+- aux_write_dev(c);
++ write_result = aux_write_dev(c, file->f_flags & O_NONBLOCK, 0);
++ if (write_result) {
++ retval = write_result;
++ break;
++ }
+ written++;
+ } while (--count);
+- retval = -EIO;
+ if (written) {
+ retval = written;
+ file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
++ aux_last_write = jiffies;
+ }
+ }
+
+@@ -1082,15 +1244,80 @@
+ static unsigned int aux_poll(struct file *file, poll_table * wait)
+ {
+ poll_wait(file, &queue->proc_list, wait);
+- if (!queue_empty())
++ if (AUX_ACCESS_ALLOWED(file) && !queue_empty())
+ return POLLIN | POLLRDNORM;
+ return 0;
+ }
+
++/* Wait this long after last write to mouse before allowing AUX_GRAB
++ to happen. This ensures that any outstanding mouse command is
++ completed. The ACK from the command is supposed to arrive in 25
++ msec, and each subsequent status bytes are supposed to arrive
++ within 20 msec, so a command with 5 status bytes (I don't know any
++ this long) might take 125 msec. Fudge this up a bit to account for
++ additional delay introduced by bus locking. */
++#define AUX_GRAB_MIN_TIME (aux_last_write + (((200 * HZ) + 500) / 1000))
++#define AUX_GRAB_ALLOWED (aux_exclusive == 0 && (jiffies >= AUX_GRAB_MIN_TIME))
++
++static void aux_grab_timeout(unsigned long data)
++{
++ wake_up_interruptible(&aux_exclusive_wait);
++}
++
++static int aux_grab_ioctl(struct file *file)
++{
++ DECLARE_WAITQUEUE(wait, current);
++ struct timer_list timer;
++
++ if (aux_exclusive == file)
++ return -EINVAL;
++ if (!AUX_GRAB_ALLOWED) {
++ if (file->f_flags & O_NONBLOCK)
++ return -EAGAIN;
++ init_timer (&timer);
++ timer.expires = AUX_GRAB_MIN_TIME;
++ timer.data = 0;
++ timer.function = aux_grab_timeout;
++ add_wait_queue(&aux_exclusive_wait, &wait);
++ add_timer(&timer);
++ do {
++ current->state = TASK_INTERRUPTIBLE;
++ schedule();
++ }
++ while (!AUX_GRAB_ALLOWED && !signal_pending(current));
++ del_timer(&timer);
++ remove_wait_queue(&aux_exclusive_wait, &wait);
++ }
++ if (!AUX_GRAB_ALLOWED)
++ return -ERESTARTSYS;
++ aux_exclusive = file;
++ return 0;
++}
++
++static int aux_release_ioctl(struct file *file)
++{
++ if (aux_exclusive != file)
++ return -ENOENT;
++ aux_exclusive = 0;
++ wake_up_interruptible(&aux_exclusive_wait);
++ return 0;
++}
++
++static int aux_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ switch (cmd) {
++ case AUX_GRAB: return aux_grab_ioctl(file);
++ case AUX_RELEASE: return aux_release_ioctl(file);
++ default: return -EINVAL;
++ }
++}
++
+ struct file_operations psaux_fops = {
+ read: read_aux,
+ write: write_aux,
+ poll: aux_poll,
++ ioctl: aux_ioctl,
+ open: open_aux,
+ release: release_aux,
+ fasync: fasync_aux,
+@@ -1115,6 +1342,8 @@
+ memset(queue, 0, sizeof(*queue));
+ queue->head = queue->tail = 0;
+ init_waitqueue_head(&queue->proc_list);
++ init_waitqueue_head(&mouse_ack_wait);
++ init_waitqueue_head(&aux_exclusive_wait);
+
+ #ifdef INITIALIZE_MOUSE
+ kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */
+@@ -1126,6 +1355,8 @@
+ #endif /* INITIALIZE_MOUSE */
+ kbd_write_command(KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */
+ kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */
++
++ aux_last_write = jiffies;
+
+ return 0;
+ }
--- tpconfig-3.1.3.orig/utils.c
+++ tpconfig-3.1.3/utils.c
@@ -89,17 +89,17 @@ int left;
int i;
if (DEBUG_LEVEL == DEBUG_HIGH)
- printf ("PS2_write: %d bytes\n", num_bytes);
+ fprintf (stderr, "PS2_write: %d bytes\n", num_bytes);
/* Use the temporary buffer to store the data as it arrives */
gettimeofday(&start, 0);
at = 0;
left = num_bytes;
if (DEBUG_LEVEL == DEBUG_HIGH)
{
- printf ("PS2_write:");
+ fprintf (stderr, "PS2_write:");
for (i = 0; i < num_bytes; i++)
- printf(" %#2x", *(buffer + i));
- printf("\n");
+ fprintf (stderr, " %#02x", *(buffer + i));
+ fprintf (stderr, "\n");
}
do
@@ -116,14 +116,14 @@ do
/ 1000000.0)
> TIMEOUT)
{
- printf ("\nTimed out waiting to write to device.\n");
+ fprintf (stderr, "\nTimed out waiting to write to device.\n");
exit (-1);
}
}
while(left > 0);
if (DEBUG_LEVEL == DEBUG_HIGH)
- printf ("PS2_write: done\n");
+ fprintf (stderr, "PS2_write: done\n");
return(at);
} /* ps2_write */
@@ -138,7 +138,7 @@ int left;
int i;
if (DEBUG_LEVEL == DEBUG_HIGH)
- printf ("PS2_read: %d bytes\n", num_bytes);
+ fprintf (stderr, "PS2_read: %d bytes\n", num_bytes);
/* Use the temporary buffer to store the data as it arrives */
gettimeofday(&start, 0);
at = 0;
@@ -157,55 +157,44 @@ do
/ 1000000.0)
> TIMEOUT)
{
- printf("\nTimed out waiting to read from device (is pc_keyb.c kernel patch installed?)\n");
- exit(-1);
+ fprintf (stderr, "\nTimed out waiting to read from device (is pc_keyb.c kernel patch installed?)\n");
+ exit (-1);
}
}
while(left > 0);
if (DEBUG_LEVEL == DEBUG_HIGH)
{
- printf("PS2_read:");
+ fprintf (stderr, "PS2_read:");
for (i = 0; i < at; i++)
- printf (" %#2x", *(buffer + i));
- printf ("\n");
- printf ("PS2_read: read %d\n", at);
+ fprintf (stderr, " %#2x", *(buffer + i));
+ fprintf (stderr, "\n");
+ fprintf (stderr, "PS2_read: read %d\n", at);
}
return(at);
} /* ps2_read */
-
-
-
-void version_info(void)
-{ /* version_info */
-printf( "\nSynaptics Touchpad and ALPS GlidePad/Glidepoint configuration tool\n");
-printf(" version: " VERSION "\n\n");
-} /* version_info */
-
void copyright(void)
-{ /* copyright */
- printf("\n========================================================================\n");
- printf("= =\n");
- printf("= tpconfig version: %-9s =\n", VERSION);
- printf("= =\n");
- printf("= Synaptics Touchpad and ALPS GlidePad/Stickpointer configuration tool =\n");
- printf("= =\n");
- printf("= Copyright (C) 1997 C. Scott Ananian<cananian@alumni.princeton.edu> =\n");
- printf("= Copyright (C) 1998-2001 Bruce Kall <kall@compass.com> =\n");
- printf("= Last Modified (Version 3.1.3) by Bruce Kall, 2/22/2002 =\n");
- printf("= =\n");
- printf("= tpconfig comes with ABSOLUTELY NO WARRANTY. This is free software, =\n");
- printf("= and you are welcome to redistribute it under the terms of the GPL. =\n");
- printf("= =\n");
- printf("========================================================================\n\n");
-} /* copyright */
+{
+ printf("\n");
+ printf(" tpconfig version: %s\n", VERSION);
+ printf("\n");
+ printf(" Synaptics Touchpad and ALPS GlidePad/Stickpointer configuration tool\n");
+ printf("\n");
+ printf(" Copyright (C) 1997 C. Scott Ananian <cananian@alumni.princeton.edu>\n");
+ printf(" Copyright (C) 1998-2001 Bruce Kall <kall@compass.com>\n");
+ printf(" Last Modified (Version 3.1.3) by Bruce Kall, 2/22/2002\n");
+ printf("\n");
+ printf(" tpconfig comes with ABSOLUTELY NO WARRANTY. This is free software,\n");
+ printf(" and you are welcome to redistribute it under the terms of the GPL.\n");
+ printf("\n");
+}
/* write a byte to the ps/2 port, handling ACK */
void
putbyte (int fd, byte b)
{
if (DEBUG_LEVEL > DEBUG_LOW)
- printf ("putbyte: write %#02x\n", b);
+ fprintf (stderr, "putbyte: write %#02x\n", b);
ps2_write (fd, &b, 1);
getbyte_expected (fd, AUX_ACK, "putbyte");
}
@@ -217,7 +206,7 @@ getbyte (int fd)
byte b;
ps2_read (fd, &b, 1);
if (DEBUG_LEVEL > DEBUG_LOW)
- printf ("ps2_read_byte: read %#02x\n", b);
+ fprintf (stderr, "ps2_read_byte: read %#02x\n", b);
return b;
}
@@ -226,6 +215,10 @@ getbyte_expected (int fd, byte expected,
{
byte b = getbyte (fd);
if (DEBUG_LEVEL && b != expected)
- printf ("Read %#02x, expected %#02x in %s.\n", b, expected, what);
- assert (b == expected);
+ fprintf (stderr, "Read %#02x, expected %#02x in %s.\n", b, expected, what);
+#if 0
+ /* Upstream recommends commenting this out for 2.6 kernels. */
+ if (!ignore_selected_assertions)
+ assert (b == expected);
+#endif
}
--- tpconfig-3.1.3.orig/ALPS.c
+++ tpconfig-3.1.3/ALPS.c
@@ -62,7 +62,6 @@ static char rcsid[]="$Header: /home/bruc
extern int ps2_write(int fd,char *buffer,int num_bytes);
extern int ps2_read(int fd,char *buffer,int num_bytes);
-extern void version_info(void);
extern void putbyte(int fd, byte b);
extern byte getbyte(int fd);
@@ -81,8 +80,8 @@ for(i = 0;i < 3;i++)
putbyte(fd,c);
}
c = 0xe9;
-if(DEBUG_LEVEL)
- printf("Writing [%x]\n",c);
+if(DEBUG_LEVEL > DEBUG_LOW)
+ printf("Writing [%#04x]\n",c);
num_written = ps2_write(fd,&c,1);
if(num_written != 1)
{
@@ -98,10 +97,10 @@ if(num_read != 4)
/* resend enable command for xmission of external mouse data */
c = 0xf4;
-if(DEBUG_LEVEL)
+if(DEBUG_LEVEL > DEBUG_LOW)
{
printf("Resending Enable command\n");
- printf("Writing [%x]\n",c);
+ printf("Writing [%#04x]\n",c);
}
num_written = ps2_write(fd,&c,1);
if(num_written != 1)
@@ -109,12 +108,12 @@ if(num_written != 1)
fprintf(stderr,"Error writing byte\n");
return(0);
}
-if(DEBUG_LEVEL)
+if(DEBUG_LEVEL > DEBUG_LOW)
{
- printf("Response 0 [%x]\n",status[0]);
- printf("Response 1 [%x]\n",status[1]);
- printf("Response 2 [%x]\n",status[2]);
- printf("Response 3 [%x]\n",status[3]);
+ printf("Response 0 [%#04x]\n",status[0]);
+ printf("Response 1 [%#04x]\n",status[1]);
+ printf("Response 2 [%#04x]\n",status[2]);
+ printf("Response 3 [%#04x]\n",status[3]);
}
return(!ERROR);
} /* ALPS_status */
@@ -125,7 +124,7 @@ byte response[4];
int tap_on = TRUE;
int error;
-if(DEBUG_LEVEL)
+if(DEBUG_LEVEL > DEBUG_LOW)
printf("\n\nChecking Whether ALPS Tap status is enabled or disabled\n");
@@ -149,7 +148,7 @@ else if(touchpad_type == ALPS_GLIDEPAD)
}
-if(DEBUG_LEVEL)
+if(DEBUG_LEVEL > DEBUG_LOW)
{
if(tap_on)
printf("Done Checking Status of Tap Enabled/Disable, Tap is ON \n");
@@ -166,8 +165,8 @@ byte c;
int num_written;
c = 0xff;
-if(DEBUG_LEVEL)
- printf("\nWriting Reset [%x], Reading Nothing\n",(int)c);
+if(DEBUG_LEVEL > DEBUG_LOW)
+ printf("\nWriting Reset [%#04x], Reading Nothing\n",(int)c);
num_written = ps2_write(fd,&c,1);
if(num_written != 1)
{
@@ -183,7 +182,7 @@ int ALPS_SP_tap(int fd,char enable)
{ /* ALPS_SP_tap */
byte c;
int i;
-if(DEBUG_LEVEL)
+if(DEBUG_LEVEL > DEBUG_LOW)
{
if(enable)
printf("\n\nEnabling SP tap\n");
@@ -204,7 +203,7 @@ else
c = 0x0a;
putbyte(fd,c);
-if(DEBUG_LEVEL)
+if(DEBUG_LEVEL > DEBUG_LOW)
printf("Done Enabling/Disabling SP tap\n");
return(!ERROR);
} /* ALPS_SP_tap */
@@ -214,7 +213,7 @@ int ALPS_through_mode(int fd,char set)
{ /* ALPS_through_mode */
byte c;
int i;
-if(DEBUG_LEVEL)
+if(DEBUG_LEVEL > DEBUG_LOW)
{
if(set)
printf("\n\nEnabling ALPS_through_mode\n");
@@ -236,7 +235,7 @@ putbyte(fd,c);
/* We may receive 3 more bytes, ignore them */
tcflush(fd,TCIOFLUSH);
-if(DEBUG_LEVEL)
+if(DEBUG_LEVEL > DEBUG_LOW)
{
if(set)
printf("Done Enabling ALPS_through_mode\n\n\n");
@@ -256,7 +255,7 @@ int num_read;
int num_written;
int error;
-if(DEBUG_LEVEL)
+if(DEBUG_LEVEL > DEBUG_LOW)
{
if(enable)
printf("\n\nEnabling GP tap\n");
@@ -275,22 +274,22 @@ if(touchpad_type == ALPS_STICKPOINTER_AN
}
c = 0xE9;
-if(DEBUG_LEVEL)
- printf("Writing Initial [%x]\n",(int)c);
+if(DEBUG_LEVEL > DEBUG_LOW)
+ printf("Writing Initial [%#04x]\n",(int)c);
num_written = ps2_write(fd,&c,1);
num_read = ps2_read(fd,response,4);
-if(DEBUG_LEVEL)
+if(DEBUG_LEVEL > DEBUG_LOW)
{
printf("Just Read num = [%d] bytes",num_read);
printf("\n");
}
if((num_read != 4) || (response[0] != AUX_ACK))
{
- printf("-----> Invalid response from Alps Glidepad/Glidepoint [%x] \n",(int)response[0]);
+ printf("-----> Invalid response from Alps Glidepad/Glidepoint [%#04x] \n",(int)response[0]);
return(ERROR);
}
-if(DEBUG_LEVEL)
- printf("Current Settings [%x] [%x] [%x]\n",response[1],response[2],response[3]);
+if(DEBUG_LEVEL > DEBUG_LOW)
+ printf("Current Settings [%#04x] [%#04x] [%#04x]\n",response[1],response[2],response[3]);
for(i = 0;i < 2;i++)
{
@@ -300,13 +299,13 @@ for(i = 0;i < 2;i++)
if(enable)
{
- if(DEBUG_LEVEL)
+ if(DEBUG_LEVEL > DEBUG_LOW)
printf("Enabling Tap\n");
c = 0xF3;
}
else
{
- if(DEBUG_LEVEL)
+ if(DEBUG_LEVEL > DEBUG_LOW)
printf("Disabling Tap\n");
c = 0xE8;
}
@@ -373,8 +372,8 @@ for(i = 0;i < 3;i++)
putbyte(fd,c);
}
c = 0xe9;
-if(DEBUG_LEVEL)
- printf("Writing Initial [%x] in is_ALPS\n",(int)c);
+if(DEBUG_LEVEL > DEBUG_LOW)
+ printf("Writing Initial [%#04x] in is_ALPS\n",(int)c);
num_written = ps2_write(fd,&c,1);
if(num_written != 1)
{
@@ -388,8 +387,8 @@ if(num_read != 4)
return(0);
}
-if(DEBUG_LEVEL)
- printf("ALPS Configuration Info [%2x][%2x][%2x]\n",response[1],response[2],response[3]);
+if(DEBUG_LEVEL > DEBUG_LOW)
+ printf("ALPS Configuration Info [%#04x][%#04x][%#04x]\n",response[1],response[2],response[3]);
return_value = 0;
for(i = 0;i < NUM_SINGLES;i++)
@@ -427,7 +426,7 @@ if(return_value)
{
if(!tap_on)
{ /* reset tap_on to off since we just had to do a reset */
- if(DEBUG_LEVEL)
+ if(DEBUG_LEVEL > DEBUG_LOW)
printf("Turning ALPS Tap Back OFF\n");
if(touchpad_type == ALPS_STICKPOINTER_AND_GLIDEPOINT)
{
@@ -445,22 +444,20 @@ return(return_value);
-void ALPS_usage(char *progname)
+void ALPS_usage(void)
{
- copyright ();
- printf ("Usage: %s [OPTION]...\n", progname);
- printf ("Configure an ALPS GlidePad/GlidePoint.\n"
+ printf ("Options for an ALPS GlidePad/GlidePoint:\n"
"\n"
" -i, --info display current TouchPad configuration\n"
" -t, --tapmode=[0-1] display/set tapping mode:\n"
" 0 = tapping off\n"
" 1 = tapping on\n"
" -r, --reset reset ALPS device\n"
- " --help display this help and exit\n"
- " --version output version information\n"
- "\n"
- "Report bugs to <kall@compass.com\n");
- exit(0);
+ " -h, --help display this help and exit\n"
+ " -v, --version output version information\n"
+ " -D, --debug=[0-3] generate debug output\n"
+ " -d, --device=DEVICE use alternate device file\n"
+ "\n");
}
@@ -471,7 +468,9 @@ void alps_functions(int c,int fd,char **
int mode;
switch (c)
{
- case 'h': ALPS_usage(argv[0]);
+ case 'h': printf ("Usage: %s [OPTION]...\n", (argv[0]));
+ ALPS_usage();
+ printf ("Report bugs to <kall@compass.com>\n");
break;
case 'i': if(touchpad_type == ALPS_GLIDEPAD)
printf("\nFound ALPS GlidePad\n\n");
@@ -497,11 +496,11 @@ void alps_functions(int c,int fd,char **
else
{
mode = optarg[0]-'0';
- if(DEBUG_LEVEL)
+ if(DEBUG_LEVEL > DEBUG_LOW)
printf("User Asked to set Tap mode to [%d]\n",mode);
if(mode > 0)
{
- if(DEBUG_LEVEL)
+ if(DEBUG_LEVEL > DEBUG_LOW)
printf("Turning ALPS Tap ON\n");
if(touchpad_type == ALPS_STICKPOINTER_AND_GLIDEPOINT)
{
@@ -513,7 +512,7 @@ void alps_functions(int c,int fd,char **
}
else
{ /* disable tap mode */
- if(DEBUG_LEVEL)
+ if(DEBUG_LEVEL > DEBUG_LOW)
printf("Turning ALPS Tap OFF\n");
if(touchpad_type == ALPS_STICKPOINTER_AND_GLIDEPOINT)
{
@@ -531,9 +530,6 @@ void alps_functions(int c,int fd,char **
}
}
break;
- case 'v': /* --version */
- version_info();
- break;
default:
fprintf(stderr, "Unknown option %c.\n", (char)c);
--- /dev/null
+++ tpconfig-3.1.3/psaux-2.4.15-combined.diff
@@ -0,0 +1,1630 @@
+diff -ruN linux-2.4.15-orig/drivers/char/pc_keyb.c linux-2.4.15/drivers/char/pc_keyb.c
+--- linux-2.4.15-orig/drivers/char/pc_keyb.c Fri Nov 9 17:01:21 2001
++++ linux-2.4.15/drivers/char/pc_keyb.c Sat Nov 24 20:45:47 2001
+@@ -13,6 +13,15 @@
+ * Code fixes to handle mouse ACKs properly.
+ * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29.
+ *
++ * More work to handle mouse ACKs properly. (Modified version of
++ * patch by Julian Bradfield <jcb@dcs.ed.ac.uk>.)
++ * Chris Hanson <cph@zurich.ai.mit.edu> 2000-12-11.
++ *
++ * Implement exclusive access mechanism for aux device.
++ * This permits grabbing the mouse away from the X server,
++ * which is needed by fancy mice that have configurable features.
++ * Chris Hanson <cph@zurich.ai.mit.edu> 2000-10-30.
++ *
+ */
+
+ #include <linux/config.h>
+@@ -67,6 +76,8 @@
+ static void aux_write_ack(int val);
+ static void __aux_write_ack(int val);
+ static int aux_reconnect = 0;
++static void aux_kill_fasync(struct fasync_struct **fasync, int sig, int band);
++static int aux_release_ioctl(struct file *file);
+ #endif
+
+ static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
+@@ -90,13 +101,30 @@
+
+ static struct aux_queue *queue; /* Mouse data buffer. */
+ static int aux_count;
+-/* used when we send commands to the mouse that expect an ACK. */
++/* Used when we (as opposed to user programs using the aux device)
++ send commands to the mouse. */
+ static unsigned char mouse_reply_expected;
+
++/* Used to make sure we have received an ACK from the byte last
++ written to the mouse before writing another. */
++static unsigned long mouse_ack_pending;
++static wait_queue_head_t mouse_ack_wait;
++/* How many jiffies to wait for the mouse to respond to a command with
++ an ACK. 25 msec is the maximum allowed delay for the hardware to
++ respond. We round that up to the nearest jiffy. */
++#define MOUSE_ACK_TIMEOUT ((25 * HZ + 999) / 1000)
++
+ #define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT)
+ #define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT)
+
+ #define MAX_RETRIES 60 /* some aux operations take long time*/
++
++/* Support for exclusive access to the AUX device. */
++static struct file *aux_exclusive;
++static wait_queue_head_t aux_exclusive_wait;
++static unsigned long aux_last_write;
++#define AUX_GRAB _IO('M', 1)
++#define AUX_RELEASE _IO('M', 2)
+ #endif /* CONFIG_PSMOUSE */
+
+ /*
+@@ -431,6 +459,13 @@
+ {
+ #ifdef CONFIG_PSMOUSE
+ static unsigned char prev_code;
++ if (mouse_ack_pending) {
++ /* It needn't actually be an ack, it could be an echo;
++ but every byte sent to the mouse results in a byte
++ back. */
++ wake_up_interruptible(&mouse_ack_wait);
++ mouse_ack_pending = 0;
++ }
+ if (mouse_reply_expected) {
+ if (scancode == AUX_ACK) {
+ mouse_reply_expected--;
+@@ -455,7 +490,7 @@
+ head = (head + 1) & (AUX_BUF_SIZE-1);
+ if (head != queue->tail) {
+ queue->head = head;
+- kill_fasync(&queue->fasync, SIGIO, POLL_IN);
++ aux_kill_fasync(&queue->fasync, SIGIO, POLL_IN);
+ wake_up_interruptible(&queue->proc_list);
+ }
+ }
+@@ -972,19 +1007,75 @@
+ return retval;
+ }
+
++static void mouse_ack_timeout(unsigned long data)
++{
++ wake_up_interruptible(&mouse_ack_wait);
++}
++
+ /*
+ * Send a byte to the mouse.
+ */
+-static void aux_write_dev(int val)
++static int aux_write_dev(int val, int dont_block, int handle_ack)
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&kbd_controller_lock, flags);
+ kb_wait();
++ /* If we haven't yet received the ACK from the previous write,
++ we must wait for it. */
++ if (mouse_ack_pending) {
++ unsigned long expires;
++ struct timer_list timer;
++ DECLARE_WAITQUEUE(wait, current);
++
++ if (dont_block) {
++ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++ return -EAGAIN;
++ }
++ expires = mouse_ack_pending + MOUSE_ACK_TIMEOUT;
++ if (jiffies >= expires)
++ goto timed_out;
++
++ add_wait_queue(&mouse_ack_wait, &wait);
++ init_timer (&timer);
++ timer.expires = expires;
++ timer.data = 0;
++ timer.function = mouse_ack_timeout;
++ add_timer(&timer);
++
++ do {
++ current->state = TASK_INTERRUPTIBLE;
++ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++ schedule();
++ spin_lock_irqsave(&kbd_controller_lock, flags);
++ } while (mouse_ack_pending
++ && jiffies < expires
++ && !signal_pending(current));
++
++ del_timer(&timer);
++ remove_wait_queue(&mouse_ack_wait, &wait);
++
++ if (mouse_ack_pending && jiffies >= expires) {
++ timed_out:
++ printk(KERN_WARNING "mouse ack timeout\n");
++ mouse_ack_pending = 0;
++ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++ return -EIO;
++ }
++ if (signal_pending(current)) {
++ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++ return -ERESTARTSYS;
++ }
++ }
+ kbd_write_command(KBD_CCMD_WRITE_MOUSE);
+ kb_wait();
+ kbd_write_output(val);
++ mouse_ack_pending = jiffies;
++ if (handle_ack)
++ /* We will deal with the ACK ourselves. */
++ mouse_reply_expected++;
+ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++ return 0;
+ }
+
+ /*
+@@ -996,11 +1087,13 @@
+ kbd_write_command(KBD_CCMD_WRITE_MOUSE);
+ kb_wait();
+ kbd_write_output(val);
+- /* we expect an ACK in response. */
++ mouse_ack_pending = jiffies;
++ /* We will deal with the ACK ourselves. */
+ mouse_reply_expected++;
+ kb_wait();
+ }
+
++#ifdef INITIALIZE_MOUSE
+ static void aux_write_ack(int val)
+ {
+ unsigned long flags;
+@@ -1009,6 +1102,33 @@
+ __aux_write_ack(val);
+ spin_unlock_irqrestore(&kbd_controller_lock, flags);
+ }
++#endif /* INITIALIZE_MOUSE */
++
++static void aux_kill_fasync(struct fasync_struct **fasync, int sig, int band)
++{
++ struct fasync_struct * fp;
++ struct fasync_struct fa;
++
++ fp = *fasync;
++ /* If someone has grabbed the AUX device, send signal only to
++ them and not to other processes. We could do this directly
++ if send_sigio was exported, but since it isn't we must
++ synthesize a "struct fasync_struct" to pass to
++ kill_fasync. */
++ if (aux_exclusive) {
++ while (1) {
++ if (!fp)
++ return;
++ if (fp->fa_file == aux_exclusive)
++ break;
++ fp = fp->fa_next;
++ }
++ fa = (*fp);
++ fa.fa_next = NULL;
++ fp = &fa;
++ }
++ kill_fasync(&fp, sig, band);
++}
+
+ static unsigned char get_from_queue(void)
+ {
+@@ -1048,6 +1168,8 @@
+ {
+ lock_kernel();
+ fasync_aux(-1, file, 0);
++ if (aux_exclusive == file)
++ aux_release_ioctl(file);
+ if (--aux_count) {
+ unlock_kernel();
+ return 0;
+@@ -1077,7 +1199,7 @@
+ kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable the
+ auxiliary port on
+ controller. */
+- aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */
++ aux_write_dev(AUX_ENABLE_DEV, 0, 1); /* Enable aux device */
+ kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */
+
+ mdelay(2); /* Ensure we follow the kbc access delay rules.. */
+@@ -1088,6 +1210,33 @@
+ }
+
+ /*
++ * Implement exclusive access mechanism.
++ */
++
++#define AUX_ACCESS_ALLOWED(file) (!aux_exclusive || aux_exclusive == (file))
++
++static ssize_t aux_wait_for_access(struct file * file)
++{
++ DECLARE_WAITQUEUE(wait, current);
++
++ if (!AUX_ACCESS_ALLOWED(file)) {
++ if (file->f_flags & O_NONBLOCK)
++ return -EAGAIN;
++ add_wait_queue(&aux_exclusive_wait, &wait);
++ do {
++ current->state = TASK_INTERRUPTIBLE;
++ schedule();
++ }
++ while (!AUX_ACCESS_ALLOWED(file)
++ && !signal_pending(current));
++ remove_wait_queue(&aux_exclusive_wait, &wait);
++ }
++ if (!AUX_ACCESS_ALLOWED(file))
++ return -ERESTARTSYS;
++ return 0;
++}
++
++/*
+ * Put bytes from input queue to buffer.
+ */
+
+@@ -1097,7 +1246,11 @@
+ DECLARE_WAITQUEUE(wait, current);
+ ssize_t i = count;
+ unsigned char c;
++ ssize_t retval;
+
++ retval = aux_wait_for_access(file);
++ if (retval < 0)
++ return retval;
+ if (queue_empty()) {
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+@@ -1132,23 +1285,32 @@
+ static ssize_t write_aux(struct file * file, const char * buffer,
+ size_t count, loff_t *ppos)
+ {
+- ssize_t retval = 0;
++ ssize_t retval;
+
++ retval = aux_wait_for_access(file);
++ if (retval < 0)
++ return retval;
+ if (count) {
+ ssize_t written = 0;
+
++ retval = -EIO;
+ if (count > 32)
+ count = 32; /* Limit to 32 bytes. */
+ do {
+ char c;
++ int write_result;
+ get_user(c, buffer++);
+- aux_write_dev(c);
++ write_result = aux_write_dev(c, file->f_flags & O_NONBLOCK, 0);
++ if (write_result) {
++ retval = write_result;
++ break;
++ }
+ written++;
+ } while (--count);
+- retval = -EIO;
+ if (written) {
+ retval = written;
+ file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
++ aux_last_write = jiffies;
+ }
+ }
+
+@@ -1159,15 +1321,80 @@
+ static unsigned int aux_poll(struct file *file, poll_table * wait)
+ {
+ poll_wait(file, &queue->proc_list, wait);
+- if (!queue_empty())
++ if (AUX_ACCESS_ALLOWED(file) && !queue_empty())
+ return POLLIN | POLLRDNORM;
+ return 0;
+ }
+
++/* Wait this long after last write to mouse before allowing AUX_GRAB
++ to happen. This ensures that any outstanding mouse command is
++ completed. The ACK from the command is supposed to arrive in 25
++ msec, and each subsequent status bytes are supposed to arrive
++ within 20 msec, so a command with 5 status bytes (I don't know any
++ this long) might take 125 msec. Fudge this up a bit to account for
++ additional delay introduced by bus locking. */
++#define AUX_GRAB_MIN_TIME (aux_last_write + (((200 * HZ) + 500) / 1000))
++#define AUX_GRAB_ALLOWED (aux_exclusive == 0 && (jiffies >= AUX_GRAB_MIN_TIME))
++
++static void aux_grab_timeout(unsigned long data)
++{
++ wake_up_interruptible(&aux_exclusive_wait);
++}
++
++static int aux_grab_ioctl(struct file *file)
++{
++ DECLARE_WAITQUEUE(wait, current);
++ struct timer_list timer;
++
++ if (aux_exclusive == file)
++ return -EINVAL;
++ if (!AUX_GRAB_ALLOWED) {
++ if (file->f_flags & O_NONBLOCK)
++ return -EAGAIN;
++ init_timer (&timer);
++ timer.expires = AUX_GRAB_MIN_TIME;
++ timer.data = 0;
++ timer.function = aux_grab_timeout;
++ add_wait_queue(&aux_exclusive_wait, &wait);
++ add_timer(&timer);
++ do {
++ current->state = TASK_INTERRUPTIBLE;
++ schedule();
++ }
++ while (!AUX_GRAB_ALLOWED && !signal_pending(current));
++ del_timer(&timer);
++ remove_wait_queue(&aux_exclusive_wait, &wait);
++ }
++ if (!AUX_GRAB_ALLOWED)
++ return -ERESTARTSYS;
++ aux_exclusive = file;
++ return 0;
++}
++
++static int aux_release_ioctl(struct file *file)
++{
++ if (aux_exclusive != file)
++ return -ENOENT;
++ aux_exclusive = 0;
++ wake_up_interruptible(&aux_exclusive_wait);
++ return 0;
++}
++
++static int aux_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ switch (cmd) {
++ case AUX_GRAB: return aux_grab_ioctl(file);
++ case AUX_RELEASE: return aux_release_ioctl(file);
++ default: return -EINVAL;
++ }
++}
++
+ struct file_operations psaux_fops = {
+ read: read_aux,
+ write: write_aux,
+ poll: aux_poll,
++ ioctl: aux_ioctl,
+ open: open_aux,
+ release: release_aux,
+ fasync: fasync_aux,
+@@ -1199,6 +1426,8 @@
+ memset(queue, 0, sizeof(*queue));
+ queue->head = queue->tail = 0;
+ init_waitqueue_head(&queue->proc_list);
++ init_waitqueue_head(&mouse_ack_wait);
++ init_waitqueue_head(&aux_exclusive_wait);
+
+ #ifdef INITIALIZE_MOUSE
+ kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */
+@@ -1210,6 +1439,8 @@
+ #endif /* INITIALIZE_MOUSE */
+ kbd_write_command(KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */
+ kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */
++
++ aux_last_write = jiffies;
+
+ return 0;
+ }
+diff -ruN linux-2.4.15-orig/drivers/char/pc_keyb.c.orig linux-2.4.15/drivers/char/pc_keyb.c.orig
+--- linux-2.4.15-orig/drivers/char/pc_keyb.c.orig Wed Dec 31 19:00:00 1969
++++ linux-2.4.15/drivers/char/pc_keyb.c.orig Fri Nov 9 17:01:21 2001
+@@ -0,0 +1,1217 @@
++/*
++ * linux/drivers/char/pc_keyb.c
++ *
++ * Separation of the PC low-level part by Geert Uytterhoeven, May 1997
++ * See keyboard.c for the whole history.
++ *
++ * Major cleanup by Martin Mares, May 1997
++ *
++ * Combined the keyboard and PS/2 mouse handling into one file,
++ * because they share the same hardware.
++ * Johan Myreen <jem@iki.fi> 1998-10-08.
++ *
++ * Code fixes to handle mouse ACKs properly.
++ * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29.
++ *
++ */
++
++#include <linux/config.h>
++
++#include <linux/spinlock.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/mm.h>
++#include <linux/signal.h>
++#include <linux/init.h>
++#include <linux/kbd_ll.h>
++#include <linux/delay.h>
++#include <linux/random.h>
++#include <linux/poll.h>
++#include <linux/miscdevice.h>
++#include <linux/slab.h>
++#include <linux/kbd_kern.h>
++#include <linux/vt_kern.h>
++#include <linux/smp_lock.h>
++#include <linux/kd.h>
++#include <linux/pm.h>
++
++#include <asm/keyboard.h>
++#include <asm/bitops.h>
++#include <asm/uaccess.h>
++#include <asm/irq.h>
++#include <asm/system.h>
++
++#include <asm/io.h>
++
++/* Some configuration switches are present in the include file... */
++
++#include <linux/pc_keyb.h>
++
++/* Simple translation table for the SysRq keys */
++
++#ifdef CONFIG_MAGIC_SYSRQ
++unsigned char pckbd_sysrq_xlate[128] =
++ "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */
++ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */
++ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */
++ "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */
++ "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */
++ "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
++ "\r\000/"; /* 0x60 - 0x6f */
++#endif
++
++static void kbd_write_command_w(int data);
++static void kbd_write_output_w(int data);
++#ifdef CONFIG_PSMOUSE
++static void aux_write_ack(int val);
++static void __aux_write_ack(int val);
++static int aux_reconnect = 0;
++#endif
++
++static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
++static unsigned char handle_kbd_event(void);
++
++/* used only by send_data - set by keyboard_interrupt */
++static volatile unsigned char reply_expected;
++static volatile unsigned char acknowledge;
++static volatile unsigned char resend;
++
++
++#if defined CONFIG_PSMOUSE
++/*
++ * PS/2 Auxiliary Device
++ */
++
++static int __init psaux_init(void);
++
++#define AUX_RECONNECT1 0xaa /* scancode1 when ps2 device is plugged (back) in */
++#define AUX_RECONNECT2 0x00 /* scancode2 when ps2 device is plugged (back) in */
++
++static struct aux_queue *queue; /* Mouse data buffer. */
++static int aux_count;
++/* used when we send commands to the mouse that expect an ACK. */
++static unsigned char mouse_reply_expected;
++
++#define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT)
++#define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT)
++
++#define MAX_RETRIES 60 /* some aux operations take long time*/
++#endif /* CONFIG_PSMOUSE */
++
++/*
++ * Wait for keyboard controller input buffer to drain.
++ *
++ * Don't use 'jiffies' so that we don't depend on
++ * interrupts..
++ *
++ * Quote from PS/2 System Reference Manual:
++ *
++ * "Address hex 0060 and address hex 0064 should be written only when
++ * the input-buffer-full bit and output-buffer-full bit in the
++ * Controller Status register are set 0."
++ */
++
++static void kb_wait(void)
++{
++ unsigned long timeout = KBC_TIMEOUT;
++
++ do {
++ /*
++ * "handle_kbd_event()" will handle any incoming events
++ * while we wait - keypresses or mouse movement.
++ */
++ unsigned char status = handle_kbd_event();
++
++ if (! (status & KBD_STAT_IBF))
++ return;
++ mdelay(1);
++ timeout--;
++ } while (timeout);
++#ifdef KBD_REPORT_TIMEOUTS
++ printk(KERN_WARNING "Keyboard timed out[1]\n");
++#endif
++}
++
++/*
++ * Translation of escaped scancodes to keycodes.
++ * This is now user-settable.
++ * The keycodes 1-88,96-111,119 are fairly standard, and
++ * should probably not be changed - changing might confuse X.
++ * X also interprets scancode 0x5d (KEY_Begin).
++ *
++ * For 1-88 keycode equals scancode.
++ */
++
++#define E0_KPENTER 96
++#define E0_RCTRL 97
++#define E0_KPSLASH 98
++#define E0_PRSCR 99
++#define E0_RALT 100
++#define E0_BREAK 101 /* (control-pause) */
++#define E0_HOME 102
++#define E0_UP 103
++#define E0_PGUP 104
++#define E0_LEFT 105
++#define E0_RIGHT 106
++#define E0_END 107
++#define E0_DOWN 108
++#define E0_PGDN 109
++#define E0_INS 110
++#define E0_DEL 111
++
++#define E1_PAUSE 119
++
++/*
++ * The keycodes below are randomly located in 89-95,112-118,120-127.
++ * They could be thrown away (and all occurrences below replaced by 0),
++ * but that would force many users to use the `setkeycodes' utility, where
++ * they needed not before. It does not matter that there are duplicates, as
++ * long as no duplication occurs for any single keyboard.
++ */
++#define SC_LIM 89
++
++#define FOCUS_PF1 85 /* actual code! */
++#define FOCUS_PF2 89
++#define FOCUS_PF3 90
++#define FOCUS_PF4 91
++#define FOCUS_PF5 92
++#define FOCUS_PF6 93
++#define FOCUS_PF7 94
++#define FOCUS_PF8 95
++#define FOCUS_PF9 120
++#define FOCUS_PF10 121
++#define FOCUS_PF11 122
++#define FOCUS_PF12 123
++
++#define JAP_86 124
++/* tfj@olivia.ping.dk:
++ * The four keys are located over the numeric keypad, and are
++ * labelled A1-A4. It's an rc930 keyboard, from
++ * Regnecentralen/RC International, Now ICL.
++ * Scancodes: 59, 5a, 5b, 5c.
++ */
++#define RGN1 124
++#define RGN2 125
++#define RGN3 126
++#define RGN4 127
++
++static unsigned char high_keys[128 - SC_LIM] = {
++ RGN1, RGN2, RGN3, RGN4, 0, 0, 0, /* 0x59-0x5f */
++ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */
++ 0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12, /* 0x68-0x6f */
++ 0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3, /* 0x70-0x77 */
++ FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7, /* 0x78-0x7b */
++ FOCUS_PF8, JAP_86, FOCUS_PF10, 0 /* 0x7c-0x7f */
++};
++
++/* BTC */
++#define E0_MACRO 112
++/* LK450 */
++#define E0_F13 113
++#define E0_F14 114
++#define E0_HELP 115
++#define E0_DO 116
++#define E0_F17 117
++#define E0_KPMINPLUS 118
++/*
++ * My OmniKey generates e0 4c for the "OMNI" key and the
++ * right alt key does nada. [kkoller@nyx10.cs.du.edu]
++ */
++#define E0_OK 124
++/*
++ * New microsoft keyboard is rumoured to have
++ * e0 5b (left window button), e0 5c (right window button),
++ * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU]
++ * [or: Windows_L, Windows_R, TaskMan]
++ */
++#define E0_MSLW 125
++#define E0_MSRW 126
++#define E0_MSTM 127
++
++static unsigned char e0_keys[128] = {
++ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */
++ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */
++ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */
++ 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */
++ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */
++ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */
++ 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */
++ E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */
++ E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */
++ E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */
++ E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */
++ 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* 0x58-0x5f */
++ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */
++ 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */
++ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */
++ 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */
++};
++
++int pckbd_setkeycode(unsigned int scancode, unsigned int keycode)
++{
++ if (scancode < SC_LIM || scancode > 255 || keycode > 127)
++ return -EINVAL;
++ if (scancode < 128)
++ high_keys[scancode - SC_LIM] = keycode;
++ else
++ e0_keys[scancode - 128] = keycode;
++ return 0;
++}
++
++int pckbd_getkeycode(unsigned int scancode)
++{
++ return
++ (scancode < SC_LIM || scancode > 255) ? -EINVAL :
++ (scancode < 128) ? high_keys[scancode - SC_LIM] :
++ e0_keys[scancode - 128];
++}
++
++static int do_acknowledge(unsigned char scancode)
++{
++ if (reply_expected) {
++ /* Unfortunately, we must recognise these codes only if we know they
++ * are known to be valid (i.e., after sending a command), because there
++ * are some brain-damaged keyboards (yes, FOCUS 9000 again) which have
++ * keys with such codes :(
++ */
++ if (scancode == KBD_REPLY_ACK) {
++ acknowledge = 1;
++ reply_expected = 0;
++ return 0;
++ } else if (scancode == KBD_REPLY_RESEND) {
++ resend = 1;
++ reply_expected = 0;
++ return 0;
++ }
++ /* Should not happen... */
++#if 0
++ printk(KERN_DEBUG "keyboard reply expected - got %02x\n",
++ scancode);
++#endif
++ }
++ return 1;
++}
++
++int pckbd_translate(unsigned char scancode, unsigned char *keycode,
++ char raw_mode)
++{
++ static int prev_scancode;
++
++ /* special prefix scancodes.. */
++ if (scancode == 0xe0 || scancode == 0xe1) {
++ prev_scancode = scancode;
++ return 0;
++ }
++
++ /* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */
++ if (scancode == 0x00 || scancode == 0xff) {
++ prev_scancode = 0;
++ return 0;
++ }
++
++ scancode &= 0x7f;
++
++ if (prev_scancode) {
++ /*
++ * usually it will be 0xe0, but a Pause key generates
++ * e1 1d 45 e1 9d c5 when pressed, and nothing when released
++ */
++ if (prev_scancode != 0xe0) {
++ if (prev_scancode == 0xe1 && scancode == 0x1d) {
++ prev_scancode = 0x100;
++ return 0;
++ } else if (prev_scancode == 0x100 && scancode == 0x45) {
++ *keycode = E1_PAUSE;
++ prev_scancode = 0;
++ } else {
++#ifdef KBD_REPORT_UNKN
++ if (!raw_mode)
++ printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
++#endif
++ prev_scancode = 0;
++ return 0;
++ }
++ } else {
++ prev_scancode = 0;
++ /*
++ * The keyboard maintains its own internal caps lock and
++ * num lock statuses. In caps lock mode E0 AA precedes make
++ * code and E0 2A follows break code. In num lock mode,
++ * E0 2A precedes make code and E0 AA follows break code.
++ * We do our own book-keeping, so we will just ignore these.
++ */
++ /*
++ * For my keyboard there is no caps lock mode, but there are
++ * both Shift-L and Shift-R modes. The former mode generates
++ * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs.
++ * So, we should also ignore the latter. - aeb@cwi.nl
++ */
++ if (scancode == 0x2a || scancode == 0x36)
++ return 0;
++
++ if (e0_keys[scancode])
++ *keycode = e0_keys[scancode];
++ else {
++#ifdef KBD_REPORT_UNKN
++ if (!raw_mode)
++ printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
++ scancode);
++#endif
++ return 0;
++ }
++ }
++ } else if (scancode >= SC_LIM) {
++ /* This happens with the FOCUS 9000 keyboard
++ Its keys PF1..PF12 are reported to generate
++ 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f
++ Moreover, unless repeated, they do not generate
++ key-down events, so we have to zero up_flag below */
++ /* Also, Japanese 86/106 keyboards are reported to
++ generate 0x73 and 0x7d for \ - and \ | respectively. */
++ /* Also, some Brazilian keyboard is reported to produce
++ 0x73 and 0x7e for \ ? and KP-dot, respectively. */
++
++ *keycode = high_keys[scancode - SC_LIM];
++
++ if (!*keycode) {
++ if (!raw_mode) {
++#ifdef KBD_REPORT_UNKN
++ printk(KERN_INFO "keyboard: unrecognized scancode (%02x)"
++ " - ignored\n", scancode);
++#endif
++ }
++ return 0;
++ }
++ } else
++ *keycode = scancode;
++ return 1;
++}
++
++char pckbd_unexpected_up(unsigned char keycode)
++{
++ /* unexpected, but this can happen: maybe this was a key release for a
++ FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */
++ if (keycode >= SC_LIM || keycode == 85)
++ return 0;
++ else
++ return 0200;
++}
++
++int pckbd_pm_resume(struct pm_dev *dev, pm_request_t rqst, void *data)
++{
++#if defined CONFIG_PSMOUSE
++ unsigned long flags;
++
++ if (rqst == PM_RESUME) {
++ if (queue) { /* Aux port detected */
++ if (aux_count == 0) { /* Mouse not in use */
++ spin_lock_irqsave(&kbd_controller_lock, flags);
++ /*
++ * Dell Lat. C600 A06 enables mouse after resume.
++ * When user touches the pad, it posts IRQ 12
++ * (which we do not process), thus holding keyboard.
++ */
++ kbd_write_command(KBD_CCMD_MOUSE_DISABLE);
++ /* kbd_write_cmd(AUX_INTS_OFF); */ /* Config & lock */
++ kb_wait();
++ kbd_write_command(KBD_CCMD_WRITE_MODE);
++ kb_wait();
++ kbd_write_output(AUX_INTS_OFF);
++ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++ }
++ }
++ }
++#endif
++ return 0;
++}
++
++
++static inline void handle_mouse_event(unsigned char scancode)
++{
++#ifdef CONFIG_PSMOUSE
++ static unsigned char prev_code;
++ if (mouse_reply_expected) {
++ if (scancode == AUX_ACK) {
++ mouse_reply_expected--;
++ return;
++ }
++ mouse_reply_expected = 0;
++ }
++ else if(scancode == AUX_RECONNECT2 && prev_code == AUX_RECONNECT1
++ && aux_reconnect) {
++ printk (KERN_INFO "PS/2 mouse reconnect detected\n");
++ queue->head = queue->tail = 0; /* Flush input queue */
++ __aux_write_ack(AUX_ENABLE_DEV); /* ping the mouse :) */
++ return;
++ }
++
++ prev_code = scancode;
++ add_mouse_randomness(scancode);
++ if (aux_count) {
++ int head = queue->head;
++
++ queue->buf[head] = scancode;
++ head = (head + 1) & (AUX_BUF_SIZE-1);
++ if (head != queue->tail) {
++ queue->head = head;
++ kill_fasync(&queue->fasync, SIGIO, POLL_IN);
++ wake_up_interruptible(&queue->proc_list);
++ }
++ }
++#endif
++}
++
++static unsigned char kbd_exists = 1;
++
++static inline void handle_keyboard_event(unsigned char scancode)
++{
++#ifdef CONFIG_VT
++ kbd_exists = 1;
++ if (do_acknowledge(scancode))
++ handle_scancode(scancode, !(scancode & 0x80));
++#endif
++ tasklet_schedule(&keyboard_tasklet);
++}
++
++/*
++ * This reads the keyboard status port, and does the
++ * appropriate action.
++ *
++ * It requires that we hold the keyboard controller
++ * spinlock.
++ */
++static unsigned char handle_kbd_event(void)
++{
++ unsigned char status = kbd_read_status();
++ unsigned int work = 10000;
++
++ while ((--work > 0) && (status & KBD_STAT_OBF)) {
++ unsigned char scancode;
++
++ scancode = kbd_read_input();
++
++ /* Error bytes must be ignored to make the
++ Synaptics touchpads compaq use work */
++#if 1
++ /* Ignore error bytes */
++ if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR)))
++#endif
++ {
++ if (status & KBD_STAT_MOUSE_OBF)
++ handle_mouse_event(scancode);
++ else
++ handle_keyboard_event(scancode);
++ }
++
++ status = kbd_read_status();
++ }
++
++ if (!work)
++ printk(KERN_ERR "pc_keyb: controller jammed (0x%02X).\n", status);
++
++ return status;
++}
++
++
++static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++#ifdef CONFIG_VT
++ kbd_pt_regs = regs;
++#endif
++
++ spin_lock_irq(&kbd_controller_lock);
++ handle_kbd_event();
++ spin_unlock_irq(&kbd_controller_lock);
++}
++
++/*
++ * send_data sends a character to the keyboard and waits
++ * for an acknowledge, possibly retrying if asked to. Returns
++ * the success status.
++ *
++ * Don't use 'jiffies', so that we don't depend on interrupts
++ */
++static int send_data(unsigned char data)
++{
++ int retries = 3;
++
++ do {
++ unsigned long timeout = KBD_TIMEOUT;
++
++ acknowledge = 0; /* Set by interrupt routine on receipt of ACK. */
++ resend = 0;
++ reply_expected = 1;
++ kbd_write_output_w(data);
++ for (;;) {
++ if (acknowledge)
++ return 1;
++ if (resend)
++ break;
++ mdelay(1);
++ if (!--timeout) {
++#ifdef KBD_REPORT_TIMEOUTS
++ printk(KERN_WARNING "keyboard: Timeout - AT keyboard not present?(%02x)\n", data);
++#endif
++ return 0;
++ }
++ }
++ } while (retries-- > 0);
++#ifdef KBD_REPORT_TIMEOUTS
++ printk(KERN_WARNING "keyboard: Too many NACKs -- noisy kbd cable?\n");
++#endif
++ return 0;
++}
++
++void pckbd_leds(unsigned char leds)
++{
++ if (kbd_exists && (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds))) {
++ send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */
++ kbd_exists = 0;
++ }
++}
++
++#define DEFAULT_KEYB_REP_DELAY 250
++#define DEFAULT_KEYB_REP_RATE 30 /* cps */
++
++static struct kbd_repeat kbdrate={
++ DEFAULT_KEYB_REP_DELAY,
++ DEFAULT_KEYB_REP_RATE
++};
++
++static unsigned char parse_kbd_rate(struct kbd_repeat *r)
++{
++ static struct r2v{
++ int rate;
++ unsigned char val;
++ } kbd_rates[]={ {5,0x14},
++ {7,0x10},
++ {10,0x0c},
++ {15,0x08},
++ {20,0x04},
++ {25,0x02},
++ {30,0x00}
++ };
++ static struct d2v{
++ int delay;
++ unsigned char val;
++ } kbd_delays[]={{250,0},
++ {500,1},
++ {750,2},
++ {1000,3}
++ };
++ int rate=0,delay=0;
++ if (r != NULL){
++ int i,new_rate=30,new_delay=250;
++ if (r->rate <= 0)
++ r->rate=kbdrate.rate;
++ if (r->delay <= 0)
++ r->delay=kbdrate.delay;
++ for (i=0; i < sizeof(kbd_rates)/sizeof(struct r2v); i++)
++ if (kbd_rates[i].rate == r->rate){
++ new_rate=kbd_rates[i].rate;
++ rate=kbd_rates[i].val;
++ break;
++ }
++ for (i=0; i < sizeof(kbd_delays)/sizeof(struct d2v); i++)
++ if (kbd_delays[i].delay == r->delay){
++ new_delay=kbd_delays[i].delay;
++ delay=kbd_delays[i].val;
++ break;
++ }
++ r->rate=new_rate;
++ r->delay=new_delay;
++ }
++ return (delay << 5) | rate;
++}
++
++static int write_kbd_rate(unsigned char r)
++{
++ if (!send_data(KBD_CMD_SET_RATE) || !send_data(r)){
++ send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */
++ return 0;
++ }else
++ return 1;
++}
++
++static int pckbd_rate(struct kbd_repeat *rep)
++{
++ if (rep == NULL)
++ return -EINVAL;
++ else{
++ unsigned char r=parse_kbd_rate(rep);
++ struct kbd_repeat old_rep;
++ memcpy(&old_rep,&kbdrate,sizeof(struct kbd_repeat));
++ if (write_kbd_rate(r)){
++ memcpy(&kbdrate,rep,sizeof(struct kbd_repeat));
++ memcpy(rep,&old_rep,sizeof(struct kbd_repeat));
++ return 0;
++ }
++ }
++ return -EIO;
++}
++
++/*
++ * In case we run on a non-x86 hardware we need to initialize both the
++ * keyboard controller and the keyboard. On a x86, the BIOS will
++ * already have initialized them.
++ *
++ * Some x86 BIOSes do not correctly initialize the keyboard, so the
++ * "kbd-reset" command line options can be given to force a reset.
++ * [Ranger]
++ */
++#ifdef __i386__
++ int kbd_startup_reset __initdata = 0;
++#else
++ int kbd_startup_reset __initdata = 1;
++#endif
++
++/* for "kbd-reset" cmdline param */
++static int __init kbd_reset_setup(char *str)
++{
++ kbd_startup_reset = 1;
++ return 1;
++}
++
++__setup("kbd-reset", kbd_reset_setup);
++
++#define KBD_NO_DATA (-1) /* No data */
++#define KBD_BAD_DATA (-2) /* Parity or other error */
++
++static int __init kbd_read_data(void)
++{
++ int retval = KBD_NO_DATA;
++ unsigned char status;
++
++ status = kbd_read_status();
++ if (status & KBD_STAT_OBF) {
++ unsigned char data = kbd_read_input();
++
++ retval = data;
++ if (status & (KBD_STAT_GTO | KBD_STAT_PERR))
++ retval = KBD_BAD_DATA;
++ }
++ return retval;
++}
++
++static void __init kbd_clear_input(void)
++{
++ int maxread = 100; /* Random number */
++
++ do {
++ if (kbd_read_data() == KBD_NO_DATA)
++ break;
++ } while (--maxread);
++}
++
++static int __init kbd_wait_for_input(void)
++{
++ long timeout = KBD_INIT_TIMEOUT;
++
++ do {
++ int retval = kbd_read_data();
++ if (retval >= 0)
++ return retval;
++ mdelay(1);
++ } while (--timeout);
++ return -1;
++}
++
++static void kbd_write_command_w(int data)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&kbd_controller_lock, flags);
++ kb_wait();
++ kbd_write_command(data);
++ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++}
++
++static void kbd_write_output_w(int data)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&kbd_controller_lock, flags);
++ kb_wait();
++ kbd_write_output(data);
++ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++}
++
++#if defined(__alpha__)
++/*
++ * Some Alphas cannot mask some/all interrupts, so we have to
++ * make sure not to allow interrupts AT ALL when polling for
++ * specific return values from the keyboard.
++ *
++ * I think this should work on any architecture, but for now, only Alpha.
++ */
++static int kbd_write_command_w_and_wait(int data)
++{
++ unsigned long flags;
++ int input;
++
++ spin_lock_irqsave(&kbd_controller_lock, flags);
++ kb_wait();
++ kbd_write_command(data);
++ input = kbd_wait_for_input();
++ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++ return input;
++}
++
++static int kbd_write_output_w_and_wait(int data)
++{
++ unsigned long flags;
++ int input;
++
++ spin_lock_irqsave(&kbd_controller_lock, flags);
++ kb_wait();
++ kbd_write_output(data);
++ input = kbd_wait_for_input();
++ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++ return input;
++}
++#else
++static int kbd_write_command_w_and_wait(int data)
++{
++ kbd_write_command_w(data);
++ return kbd_wait_for_input();
++}
++
++static int kbd_write_output_w_and_wait(int data)
++{
++ kbd_write_output_w(data);
++ return kbd_wait_for_input();
++}
++#endif /* __alpha__ */
++
++#if defined CONFIG_PSMOUSE
++static void kbd_write_cmd(int cmd)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&kbd_controller_lock, flags);
++ kb_wait();
++ kbd_write_command(KBD_CCMD_WRITE_MODE);
++ kb_wait();
++ kbd_write_output(cmd);
++ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++}
++#endif /* CONFIG_PSMOUSE */
++
++static char * __init initialize_kbd(void)
++{
++ int status;
++
++ /*
++ * Test the keyboard interface.
++ * This seems to be the only way to get it going.
++ * If the test is successful a x55 is placed in the input buffer.
++ */
++ kbd_write_command_w(KBD_CCMD_SELF_TEST);
++ if (kbd_wait_for_input() != 0x55)
++ return "Keyboard failed self test";
++
++ /*
++ * Perform a keyboard interface test. This causes the controller
++ * to test the keyboard clock and data lines. The results of the
++ * test are placed in the input buffer.
++ */
++ kbd_write_command_w(KBD_CCMD_KBD_TEST);
++ if (kbd_wait_for_input() != 0x00)
++ return "Keyboard interface failed self test";
++
++ /*
++ * Enable the keyboard by allowing the keyboard clock to run.
++ */
++ kbd_write_command_w(KBD_CCMD_KBD_ENABLE);
++
++ /*
++ * Reset keyboard. If the read times out
++ * then the assumption is that no keyboard is
++ * plugged into the machine.
++ * This defaults the keyboard to scan-code set 2.
++ *
++ * Set up to try again if the keyboard asks for RESEND.
++ */
++ do {
++ kbd_write_output_w(KBD_CMD_RESET);
++ status = kbd_wait_for_input();
++ if (status == KBD_REPLY_ACK)
++ break;
++ if (status != KBD_REPLY_RESEND)
++ return "Keyboard reset failed, no ACK";
++ } while (1);
++
++ if (kbd_wait_for_input() != KBD_REPLY_POR)
++ return "Keyboard reset failed, no POR";
++
++ /*
++ * Set keyboard controller mode. During this, the keyboard should be
++ * in the disabled state.
++ *
++ * Set up to try again if the keyboard asks for RESEND.
++ */
++ do {
++ kbd_write_output_w(KBD_CMD_DISABLE);
++ status = kbd_wait_for_input();
++ if (status == KBD_REPLY_ACK)
++ break;
++ if (status != KBD_REPLY_RESEND)
++ return "Disable keyboard: no ACK";
++ } while (1);
++
++ kbd_write_command_w(KBD_CCMD_WRITE_MODE);
++ kbd_write_output_w(KBD_MODE_KBD_INT
++ | KBD_MODE_SYS
++ | KBD_MODE_DISABLE_MOUSE
++ | KBD_MODE_KCC);
++
++ /* ibm powerpc portables need this to use scan-code set 1 -- Cort */
++ if (!(kbd_write_command_w_and_wait(KBD_CCMD_READ_MODE) & KBD_MODE_KCC))
++ {
++ /*
++ * If the controller does not support conversion,
++ * Set the keyboard to scan-code set 1.
++ */
++ kbd_write_output_w(0xF0);
++ kbd_wait_for_input();
++ kbd_write_output_w(0x01);
++ kbd_wait_for_input();
++ }
++
++ if (kbd_write_output_w_and_wait(KBD_CMD_ENABLE) != KBD_REPLY_ACK)
++ return "Enable keyboard: no ACK";
++
++ /*
++ * Finally, set the typematic rate to maximum.
++ */
++ if (kbd_write_output_w_and_wait(KBD_CMD_SET_RATE) != KBD_REPLY_ACK)
++ return "Set rate: no ACK";
++ if (kbd_write_output_w_and_wait(0x00) != KBD_REPLY_ACK)
++ return "Set rate: no 2nd ACK";
++
++ return NULL;
++}
++
++void __init pckbd_init_hw(void)
++{
++ kbd_request_region();
++
++ /* Flush any pending input. */
++ kbd_clear_input();
++
++ if (kbd_startup_reset) {
++ char *msg = initialize_kbd();
++ if (msg)
++ printk(KERN_WARNING "initialize_kbd: %s\n", msg);
++ }
++
++#if defined CONFIG_PSMOUSE
++ psaux_init();
++#endif
++
++ kbd_rate = pckbd_rate;
++
++ /* Ok, finally allocate the IRQ, and off we go.. */
++ kbd_request_irq(keyboard_interrupt);
++}
++
++#if defined CONFIG_PSMOUSE
++
++static int __init aux_reconnect_setup (char *str)
++{
++ aux_reconnect = 1;
++ return 1;
++}
++
++__setup("psaux-reconnect", aux_reconnect_setup);
++
++/*
++ * Check if this is a dual port controller.
++ */
++static int __init detect_auxiliary_port(void)
++{
++ unsigned long flags;
++ int loops = 10;
++ int retval = 0;
++
++ /* Check if the BIOS detected a device on the auxiliary port. */
++ if (aux_device_present == 0xaa)
++ return 1;
++
++ spin_lock_irqsave(&kbd_controller_lock, flags);
++
++ /* Put the value 0x5A in the output buffer using the "Write
++ * Auxiliary Device Output Buffer" command (0xD3). Poll the
++ * Status Register for a while to see if the value really
++ * turns up in the Data Register. If the KBD_STAT_MOUSE_OBF
++ * bit is also set to 1 in the Status Register, we assume this
++ * controller has an Auxiliary Port (a.k.a. Mouse Port).
++ */
++ kb_wait();
++ kbd_write_command(KBD_CCMD_WRITE_AUX_OBUF);
++
++ kb_wait();
++ kbd_write_output(0x5a); /* 0x5a is a random dummy value. */
++
++ do {
++ unsigned char status = kbd_read_status();
++
++ if (status & KBD_STAT_OBF) {
++ (void) kbd_read_input();
++ if (status & KBD_STAT_MOUSE_OBF) {
++ printk(KERN_INFO "Detected PS/2 Mouse Port.\n");
++ retval = 1;
++ }
++ break;
++ }
++ mdelay(1);
++ } while (--loops);
++ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++
++ return retval;
++}
++
++/*
++ * Send a byte to the mouse.
++ */
++static void aux_write_dev(int val)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&kbd_controller_lock, flags);
++ kb_wait();
++ kbd_write_command(KBD_CCMD_WRITE_MOUSE);
++ kb_wait();
++ kbd_write_output(val);
++ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++}
++
++/*
++ * Send a byte to the mouse & handle returned ack
++ */
++static void __aux_write_ack(int val)
++{
++ kb_wait();
++ kbd_write_command(KBD_CCMD_WRITE_MOUSE);
++ kb_wait();
++ kbd_write_output(val);
++ /* we expect an ACK in response. */
++ mouse_reply_expected++;
++ kb_wait();
++}
++
++static void aux_write_ack(int val)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&kbd_controller_lock, flags);
++ __aux_write_ack(val);
++ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++}
++
++static unsigned char get_from_queue(void)
++{
++ unsigned char result;
++ unsigned long flags;
++
++ spin_lock_irqsave(&kbd_controller_lock, flags);
++ result = queue->buf[queue->tail];
++ queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
++ spin_unlock_irqrestore(&kbd_controller_lock, flags);
++ return result;
++}
++
++
++static inline int queue_empty(void)
++{
++ return queue->head == queue->tail;
++}
++
++static int fasync_aux(int fd, struct file *filp, int on)
++{
++ int retval;
++
++ retval = fasync_helper(fd, filp, on, &queue->fasync);
++ if (retval < 0)
++ return retval;
++ return 0;
++}
++
++
++/*
++ * Random magic cookie for the aux device
++ */
++#define AUX_DEV ((void *)queue)
++
++static int release_aux(struct inode * inode, struct file * file)
++{
++ lock_kernel();
++ fasync_aux(-1, file, 0);
++ if (--aux_count) {
++ unlock_kernel();
++ return 0;
++ }
++ kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints */
++ kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE);
++ aux_free_irq(AUX_DEV);
++ unlock_kernel();
++ return 0;
++}
++
++/*
++ * Install interrupt handler.
++ * Enable auxiliary device.
++ */
++
++static int open_aux(struct inode * inode, struct file * file)
++{
++ if (aux_count++) {
++ return 0;
++ }
++ queue->head = queue->tail = 0; /* Flush input queue */
++ if (aux_request_irq(keyboard_interrupt, AUX_DEV)) {
++ aux_count--;
++ return -EBUSY;
++ }
++ kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable the
++ auxiliary port on
++ controller. */
++ aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */
++ kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */
++
++ mdelay(2); /* Ensure we follow the kbc access delay rules.. */
++
++ send_data(KBD_CMD_ENABLE); /* try to workaround toshiba4030cdt problem */
++
++ return 0;
++}
++
++/*
++ * Put bytes from input queue to buffer.
++ */
++
++static ssize_t read_aux(struct file * file, char * buffer,
++ size_t count, loff_t *ppos)
++{
++ DECLARE_WAITQUEUE(wait, current);
++ ssize_t i = count;
++ unsigned char c;
++
++ if (queue_empty()) {
++ if (file->f_flags & O_NONBLOCK)
++ return -EAGAIN;
++ add_wait_queue(&queue->proc_list, &wait);
++repeat:
++ set_current_state(TASK_INTERRUPTIBLE);
++ if (queue_empty() && !signal_pending(current)) {
++ schedule();
++ goto repeat;
++ }
++ current->state = TASK_RUNNING;
++ remove_wait_queue(&queue->proc_list, &wait);
++ }
++ while (i > 0 && !queue_empty()) {
++ c = get_from_queue();
++ put_user(c, buffer++);
++ i--;
++ }
++ if (count-i) {
++ file->f_dentry->d_inode->i_atime = CURRENT_TIME;
++ return count-i;
++ }
++ if (signal_pending(current))
++ return -ERESTARTSYS;
++ return 0;
++}
++
++/*
++ * Write to the aux device.
++ */
++
++static ssize_t write_aux(struct file * file, const char * buffer,
++ size_t count, loff_t *ppos)
++{
++ ssize_t retval = 0;
++
++ if (count) {
++ ssize_t written = 0;
++
++ if (count > 32)
++ count = 32; /* Limit to 32 bytes. */
++ do {
++ char c;
++ get_user(c, buffer++);
++ aux_write_dev(c);
++ written++;
++ } while (--count);
++ retval = -EIO;
++ if (written) {
++ retval = written;
++ file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
++ }
++ }
++
++ return retval;
++}
++
++/* No kernel lock held - fine */
++static unsigned int aux_poll(struct file *file, poll_table * wait)
++{
++ poll_wait(file, &queue->proc_list, wait);
++ if (!queue_empty())
++ return POLLIN | POLLRDNORM;
++ return 0;
++}
++
++struct file_operations psaux_fops = {
++ read: read_aux,
++ write: write_aux,
++ poll: aux_poll,
++ open: open_aux,
++ release: release_aux,
++ fasync: fasync_aux,
++};
++
++/*
++ * Initialize driver.
++ */
++static struct miscdevice psaux_mouse = {
++ PSMOUSE_MINOR, "psaux", &psaux_fops
++};
++
++static int __init psaux_init(void)
++{
++ int retval;
++
++ if (!detect_auxiliary_port())
++ return -EIO;
++
++ if ((retval = misc_register(&psaux_mouse)))
++ return retval;
++
++ queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
++ if (queue == NULL) {
++ printk(KERN_ERR "psaux_init(): out of memory\n");
++ misc_deregister(&psaux_mouse);
++ return -ENOMEM;
++ }
++ memset(queue, 0, sizeof(*queue));
++ queue->head = queue->tail = 0;
++ init_waitqueue_head(&queue->proc_list);
++
++#ifdef INITIALIZE_MOUSE
++ kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */
++ aux_write_ack(AUX_SET_SAMPLE);
++ aux_write_ack(100); /* 100 samples/sec */
++ aux_write_ack(AUX_SET_RES);
++ aux_write_ack(3); /* 8 counts per mm */
++ aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */
++#endif /* INITIALIZE_MOUSE */
++ kbd_write_command(KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */
++ kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */
++
++ return 0;
++}
++
++#endif /* CONFIG_PSMOUSE */