From e26ca8052024c344d68e13f0bf5538eac6dde10c Mon Sep 17 00:00:00 2001 From: Mark Hemment Date: Thu, 11 Jun 2009 12:31:18 +0100 Subject: [PATCH] Code improvements, along with better code commentary. Start of Active PS/2 Multiplexing support for multiple AUX devices, and code comments has to where the pass2 driver needs enhancements to complete the multiplexing support. --- master/ps2-passthrough | 2449 +++++++++++++++++++++++++++------------- 1 file changed, 1649 insertions(+), 800 deletions(-) diff --git a/master/ps2-passthrough b/master/ps2-passthrough index 83f48b7..5fa186f 100644 --- a/master/ps2-passthrough +++ b/master/ps2-passthrough @@ -101,30 +101,30 @@ index 2e3cade..d0e0957 100644 typedef struct RTCState RTCState; diff --git a/pass2.c b/pass2.c new file mode 100644 -index 0000000..9fa8baf +index 0000000..978a565 --- /dev/null +++ b/pass2.c -@@ -0,0 +1,11180 @@ +@@ -0,0 +1,12029 @@ +/* + * PS/2 Pass-through driver. Version: 0.9 -+ * A host which has focus to a device (KBD or AUX) talks directly to the h/w ++ * A guest which has focus to a device (KBD or AUX) talks directly to the h/w + * while this driver "monitors" the conversation. -+ * For a host which does not have focus to a device this driver is able to -+ * hold the 'expected' conversation to keep the host happy. When a host -+ * obtains focus to a device, it is programmed to behave as the host expects. ++ * For a guest which does not have focus to a device this driver is able to ++ * hold the 'expected' conversation to keep the guest happy. When a guest ++ * obtains focus to a device, it is set to behave as the guest expects. + * This works for vanilla PS/2 devices (KBD and AUX), and also for the + * Synaptics touchpad. + * Currently, there are a number of limitations; + * o switching focus part way through a cmd works only for a number + * of cmds. should wait until the PVM is up (login screen) before + * switching to a SVM, and that SVM should be up too. This avoids -+ * interrupting the initialization conversations between the hosts ++ * interrupting the initialization conversations between the guests + * and h/w. + * o switching VMs takes around a second. this will be reduced in + * later versions. + * o tested with Vista and Ubuntu as primary VM's, but only with + * Vista with secondary VMs present. -+ * o not yet tested with AppServer....XXXX ++ * o tested with AppServer; switching only KBD works. + */ + +#include @@ -139,8 +139,9 @@ index 0000000..9fa8baf + * Ugh; u32 and u8 aren't part of IOEMU. This will go away... + */ + -+typedef uint32_t u32; /* XXX */ ++typedef uint32_t u32; +typedef unsigned char u8; ++ +#include "pass2.h" +#include "qemu-common.h" +#include "console.h" @@ -166,8 +167,13 @@ index 0000000..9fa8baf + * Keyboard Controller Commands + */ + ++#define PA2_CTL_CMD_NULL 0x00 /* no command (rouge value) */ +#define PA2_CTL_CMD_MODE_READ 0x20 /* read mode bits */ +#define PA2_CTL_CMD_MODE_WRITE 0x60 /* write mode bits */ ++#define PA2_CTL_CMD_ROUTE_AUX0 0x90 /* multi; route to aux0 */ ++#define PA2_CTL_CMD_ROUTE_AUX1 0x91 /* multi; route to aux0 */ ++#define PA2_CTL_CMD_ROUTE_AUX2 0x92 /* multi; route to aux0 */ ++#define PA2_CTL_CMD_ROUTE_AUX3 0x93 /* multi; route to aux0 */ +#define PA2_CTL_CMD_VERSION_GET 0xA1 /* get controller version */ +#define PA2_CTL_CMD_AUX_DISABLE 0xA7 /* disable AUX interface */ +#define PA2_CTL_CMD_AUX_ENABLE 0xA8 /* enable AUX interface */ @@ -197,8 +203,8 @@ index 0000000..9fa8baf + +/* + * Keyboard Commands -+ * Typematic cmds are accepted by this driver, and (if focused) passed -+ * through to the h/w, but are not restored when focus is switched. ++ * Typemantic commands, and make/break setting commands, are not support by ++ * this driver. + */ + +#define PA2_KBD_CMD_LEDS_SET 0xED /* Set keyboard leds */ @@ -209,14 +215,14 @@ index 0000000..9fa8baf +#define PA2_KBD_CMD_ENABLE 0xF4 /* Enable scanning */ +#define PA2_KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ +#define PA2_KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ -+#define PA2_KBD_CMD_RESET_TYPEMATIC 0xF7 /* ignored XXX */ -+#define PA2_KBD_CMD_ALL_BREAK 0xF8 -+#define PA2_KBD_CMD_ALL_MAKE 0xF9 -+#define PA2_KBD_CMD_ALL_TYPE_MAKE 0xFA -+#define PA2_KBD_CMD_SET_KEY_TYPE 0xFB -+#define PA2_KBD_CMD_SET_KEY_BREAK 0xFC -+#define PA2_KBD_CMD_SET_KEY_MAKE 0xFD -+#define PA2_KBD_CMD_RESEND 0xFE ++#define PA2_KBD_CMD_RESET_TYPEMATIC 0xF7 /* not implemented */ ++#define PA2_KBD_CMD_ALL_BREAK 0xF8 /* not implemented */ ++#define PA2_KBD_CMD_ALL_MAKE 0xF9 /* not implemented */ ++#define PA2_KBD_CMD_ALL_TYPE_MAKE 0xFA /* not implemented */ ++#define PA2_KBD_CMD_SET_KEY_TYPE 0xFB /* not implemented */ ++#define PA2_KBD_CMD_SET_KEY_BREAK 0xFC /* not implemented */ ++#define PA2_KBD_CMD_SET_KEY_MAKE 0xFD /* not implemented */ ++#define PA2_KBD_CMD_RESEND 0xFE /* not implemented */ +#define PA2_KBD_CMD_RESET 0xFF /* Reset */ + +/* @@ -298,6 +304,21 @@ index 0000000..9fa8baf +/* + * AUX Commands + * AUX_SYNAP_E1 and AUX_SYNAP_E2 are Synaptic cmds. Not 100% what they do... ++ * Update: These are not Synatpic cmds! They are commands for the 'nipple' ++ * pointing device (IBM trackpoint). ++ * 0xE1 - read secondary ID ++ * 0xE2 - trackpoint ctrl cmd ++ * These commands are passed-through the the trackpoint ctrl when the ++ * Synaptic's mode byte has bit PA2_SYNAP_BIT_TRANSPARENT set. ++ * For 0xE1, the device will return two bytes; first is always 0x01, and the ++ * second debotes a set of functional specifications. In this driver, should ++ * issues 0xE1 during once-init and record the result for later response to ++ * guests. ++ * For 0xE2, the following byte/bytes contain a command. Most of these ++ * commands are writes into the trackpoint's "RAM" which control its behaviour. ++ * In this driver, need to code for what writes to different addresses do. ++ * From a quick investigation, only a handful of addresses are used by Vista's ++ * driver so this should not be a huge task to support. + */ + +#define PA2_AUX_CMD_SYNAP_E1 0xE1 /* XXX */ @@ -343,7 +364,12 @@ index 0000000..9fa8baf +#define PA2_OUTPORT_KBDO 0x80 + +/* -+ * Synaptics "special" get request arguments. ++ * Synaptics Informational queries. ++ * These 'tables' are read from the touchpad, using Synaptics special command ++ * sequence. Each table has three 8-bit entries. ++ * Three of the tables are undocumented in the lastest Synaptics interfacing ++ * guide, but has these are treated as 'pass-through' can function without ++ * undestanding their contents. + */ + +#define PA2_SYNAP_GET_IDENTIFY 0x00 @@ -371,8 +397,11 @@ index 0000000..9fa8baf + +/* + * Format of a AUX data reporting. Current does not support Synaptic's -+ * historical mode. XXX ++ * Support normal PS/2 data format, and two Synaptic data formats (absolute and ++ * wide modes). ++ * Does not support Synaptic's 'historical' format. + */ ++ +enum pa2_aux_fmt_e { PA2_AUX_FMT_DEFAULT, PA2_AUX_FMT_ABS, + PA2_AUX_FMT_ABS_WMODE }; +typedef enum pa2_aux_fmt_e pa2_aux_fmt_t; @@ -448,8 +477,8 @@ index 0000000..9fa8baf + * through cmd). + */ + -+struct pa2_s; /* XXX */ -+struct pa2_cmd_s; /* XXX */ ++struct pa2_s; ++struct pa2_cmd_s; +typedef int (pa2_fcmd_t)(struct pa2_s *, struct pa2_cmd_s *); +typedef void (pa2_fdone_t)(struct pa2_s *, struct pa2_cmd_s *); +typedef int (pa2_fwrite_t)(struct pa2_s *, struct pa2_cmd_s *, uint8_t); @@ -479,13 +508,21 @@ index 0000000..9fa8baf + * + * pcc_cmd - command code + * pcc_name - name given to the command -+ * pcc_bytes_in - number of bytes we expect from the h/w, -+ * excluding ACK (if XXX set in pp_flags). ++ * pcc_bytes_in - number of bytes we expect from the h/w, excluding ACK + * pcc_bytes_out - number of bytes we'll be sending to the h/w for -+ * the cmd. -+ * pcc_output_dest - specifices where the output goes; kbd or aux. ++ * the command. + * pcc_seq - for aux cmds only; specifies how many argument bytes + * the aux cmd has. Such as SET_RES and SET_SAMPLE. ++ * pcc_output_dest - specifices where the any output goes; KBD or AUX. ++ * pcc_flags - pc_flags ++ * pcc_func_write - function called when guest performs a write to an ++ * ioport ++ * pcc_func_read - function called when data is received from the h/w ++ * pcc_func_cmd - function called when command starts ++ * pcc_func_done - function called when command completes (all input/ ++ * output received) ++ * pcc_func_redo - function called if device gains focus during command ++ * execution. + */ + +typedef struct pa2_cmd_des_s { @@ -495,7 +532,7 @@ index 0000000..9fa8baf + const uint8_t pcc_bytes_out; + const uint8_t pcc_seq; + pa2_dest_t pcc_output_dest; -+ const uint32_t pcc_flags; /* combine with pc_flags */ ++ const uint32_t pcc_flags; + pa2_fwrite_t *pcc_func_write; + pa2_fread_t *pcc_func_read; + pa2_fcmd_t *pcc_func_cmd; @@ -504,20 +541,54 @@ index 0000000..9fa8baf +} pa2_cmd_des_t; + +/* -+ * pp_cmd - controller cmd being processed -+ * pp_irqbuf - status and data received from kernel, trigger by -+ * a h/w interrupt. -+ * pp_start - first empty position in pp_irqbuf[]. -+ * pp_end - first populated position in pp_irqbuf[]. ++ * Command execution. ++ * This is build from the command descriptor (pa2_cmd_des_t) above when a ++ * command starts. It contains both static and dynamic data used to execute ++ * the command. ++ * pp_cmd - cmd being processed ++ * pp_active - set if device has focus, and command can communicate ++ * with the h/w. That is, read/write to ioports. ++ * pp_bytes_in - number of bytes we expect from the h/w, excluding ACK ++ * pp_bytes_out - number of bytes we'll be sending to the h/w for ++ * the command. ++ * pc_counter - counter, incremented on each in/out byte. Used to ++ * drive command's state machine. + * pp_expected_input - expected response from device. This is the next + * byte expected, and is used when switching focus + * between guests when a cmd is active. -+ * pc_aux_res_set_seq - consective number of PA2_AUX_CMD_RES_SET seen -+ * pc_aux_special_byte - special command byte encoded in four -+ * args to PA2_AUX_CMD_RES_SET ++ * pc_tmp_buf - working buffer for command's state machine. ++ * pc_flags - flags. see below ++ * pc_cmd_desp - back pointer to command descriptor in a table. ++ * ++ * pc_func_write - function called when guest performs a write to an ++ * ioport. From command descriptor. ++ * pc_func_read - function called when data is received from the h/w. ++ * From command descriptor. ++ * pc_func_cmd - function called when command starts. From cmd desc. ++ * pc_func_done - function called when command completes (all input/ ++ * output received). From command descriptor. ++ * pc_func_redo - function called if device gains focus during command ++ * execution. From command descriptor. ++ * ++ * AUX commands, which take arguments, are formed from mulitple ++ * ctrl commands (PA2_CTL_CMD_OBUF_WRITE). The pc_aux_* members are used to ++ * remember the AUX state across the sequence of OBUF_WRITE cmds. ++ * pc_aux_cmd - the AUX command (start of sequence). ++ * pc_aux_seq - sequence counter for AUX comds that take arguments. ++ * pc_aux_cmd_desp - back pointer to AUX command descriptor in a table. ++ * pc_aux_func_done - function called when AUX comamnd completes. ++ * pc_aux_func_write - function called when guest does a write for to the ++ * AUX. ++ * pc_aux_func_read - function called when data is recieved from the AUX h/w ++ * pc_aux_res_set_seq - consective number of PA2_AUX_CMD_RES_SET seen. Used ++ * in detecting Synaptic special command sequences. ++ * pc_aux_special_byte - special command byte encoded in four args to ++ * PA2_AUX_CMD_RES_SET (the Synaptic special cmd seq). ++ * ++ * pc_aux_p28 - Synaptic specific. + */ + -+struct pa_syp_0x28_s; /* XXX */ ++struct pa_syp_0x28_s; +typedef struct pa2_cmd_s { + uint8_t pc_cmd; + uint8_t pc_active; @@ -527,11 +598,8 @@ index 0000000..9fa8baf + uint8_t pc_expected_input; + uint8_t pc_tmp_buf[16]; + uint16_t pc_flags; -+ -+ + pa2_cmd_des_t *pc_cmd_desp; + -+ /* should ref these straight from the table - no need to copy XXX */ + pa2_fwrite_t *pc_func_write; + pa2_fread_t *pc_func_read; + pa2_fcmd_t *pc_func_cmd; @@ -554,13 +622,13 @@ index 0000000..9fa8baf + * pc_flags. + */ + -+#define PA2_CMD_FLG_INPUT 0x0001 /* expect bytes from h/w (true? XXX */ -+#define PA2_CMD_FLG_OUTPUT 0x0002 /* expects bytes to send to h/w XXX */ ++#define PA2_CMD_FLG_INPUT 0x0001 /* expect bytes from h/w */ ++#define PA2_CMD_FLG_OUTPUT 0x0002 /* expect bytes from guest */ +#define PA2_CMD_FLG_ACK 0x0004 /* expect ACK from h/w */ +#define PA2_CMD_FLG_CTRL 0x0008 /* ctl cmd */ +#define PA2_CMD_FLG_KBD 0x0010 /* KBD cmd */ +#define PA2_CMD_FLG_AUX 0x0020 /* AUX cmd */ -+#define PA2_CMD_FLG_AUX_BYTE 0x0040 /* AUX cmd */ ++#define PA2_CMD_FLG_AUX_BYTE 0x0040 /* AUX argument for AUX cmd sequence */ +#define PA2_CMD_FLG_WR_ACTIVE 0x0080 /* cmd in write progress */ +#define PA2_CMD_FLG_SHORT 0x0100 /* short form cmd - presently, only + used for PA2_AUX_CMD_STATUS_GET */ @@ -569,21 +637,14 @@ index 0000000..9fa8baf +#define PA2_CMD_FLG_SPECIAL 0x1000 /* synaptic special cmd seq */ + +/* -+ * Global data (constant). -+ * pg_ctl_test_result_kbd result of PA2_CTL_CMD_KBD_TEST -+ * pg_ctl_test_result_aux result of PA2_CTL_CMD_AUX_TEST -+ * pg_kbd_id result of PA2_KBD_CMD_GET_ID -+ */ -+ -+/* + * When the pointing device is a Synaptic touchpad, this structure contains + * the variable state associated with the touchpad. + * ps_mode_byte - the touchpad mode bytes, whose bits are defined + * by PA2_SYNAP_BIT_* -+ * ps_e1_byte1 -+ * ps_e1_byte2 ++ * ps_e1_byte1 - first byte associated with E1 cmd ++ * ps_e1_byte2 - second byte associated with E2 cmd + * ps_hv_flgs - flags describing the state of the members of this -+ * structure. ++ * structure. (see below) + */ + +typedef struct pa2_syp_state_s { @@ -594,13 +655,6 @@ index 0000000..9fa8baf +} pa2_syp_state_t; + +/* -+ * No idea about the E1's. -+ * On first access, from a power-cycled system, they have; -+ * 0x01 (ps_e1_byte1) -+ * 0x0e (ps_e1_byte2) -+ */ -+ -+/* + * ps_hv_flgs + */ + @@ -628,7 +682,7 @@ index 0000000..9fa8baf +#define PA2_SYNAP_BIT_ABS 0x80 /* absolute */ + +/* -+ * Seeing undocumented Synaptic extended cmd sequence; ++ * Seeing undocumented Synaptic special cmd sequence; + * RES_SET * 4 + SAMPLE_SET 0x28 + * (0x14 is documented, 0x28 isn't). During initialization (on the PVM) + * this driver was capturing the output of different 0x28 cmds and storing @@ -636,12 +690,21 @@ index 0000000..9fa8baf + * coded in pa2_aux_once_init() as the returned values are mostly the same. + * Need to invesigate this deeper (ie. talk to Synaptic), but for now + * blindly continue with the dumb method as it appears to keep the Windows -+ * Synaptic driver happy. Note; ubuntu uses different 0x028 cmds than ++ * Synaptic driver happy. Note; ubuntu uses different 0x28 cmds than + * Windows (Vista). Currently, this means ubuntu is not supported as a + * SVM. XXX + * p28_status - set if p28_bytes[] is populated for this entry + * p28_special - the 'special' cmd byte encoded in the RES_SET * 4 + * p28_bytes - the response. usually 5 bytes, but can be 11. ++ * ++ * OK, made new progress on this. ++ * The above special command sequence forms a Synatpic pass-through operation, ++ * and is used to "pass-through" commands to the controller of the 'nipple' ++ * pointing device - which on Lenovo laptops is an IBM trackpoint. The ++ * spec for this device can be donwloaded from here; ++ * http://wwwcssrv.almaden.ibm.com/trackpoint/download.html ++ * Programming the trackpoint appears to consist of writes into memory ++ * locations. + */ + +typedef struct pa_syp_0x28_s { @@ -722,100 +785,152 @@ index 0000000..9fa8baf + uint8_t pcy_initial_e1_byte2; + + /* values in undefined fields */ -+ uint8_t pcy_nibble1; /* read serial num XXX */ -+ uint8_t pcy_byte1; /* read serial num XXX */ -+ uint8_t pcy_resol; /* read resolutions XXX */ ++ uint8_t pcy_nibble1; /* read serial num */ ++ uint8_t pcy_byte1; /* read serial num */ ++ uint8_t pcy_resol; /* read resolutions */ + uint32_t pcy_hv_flgs; + + pa_syp_0x28_t pcy_28_resp[20]; +} pa2_syp_const_t; + -+#define PA2_HV_SYNAP_INFO_MIN 0x00001 /* info_minor */ -+#define PA2_HV_SYNAP_INFO_MAJ 0x00002 /* info_major */ -+#define PA2_HV_SYNAP_MODEL_CD 0x00004 /* model_code */ -+#define PA2_HV_SYNAP_XUPMM 0x00008 /* info_xupmm */ -+#define PA2_HV_SYNAP_YUPMM 0x00010 /* info_yupmm */ ++#define PA2_HV_SYNAP_INFO_MIN 0x00001 /* info_minor */ ++#define PA2_HV_SYNAP_INFO_MAJ 0x00002 /* info_major */ ++#define PA2_HV_SYNAP_MODEL_CD 0x00004 /* model_code */ ++#define PA2_HV_SYNAP_XUPMM 0x00008 /* info_xupmm */ ++#define PA2_HV_SYNAP_YUPMM 0x00010 /* info_yupmm */ +#define PA2_HV_SYNAP_CAPS_FIRST_BYTE 0x00020 +#define PA2_HV_SYNAP_CAPS_THIRD_BYTE 0x00040 -+#define PA2_HV_SYNAP_MODEL_00 0x00080 /* model; 0-7 */ -+#define PA2_HV_SYNAP_MODEL_08 0x00100 /* model; 8-15 */ -+#define PA2_HV_SYNAP_MODEL_16 0x00200 /* model; 16-23 */ -+#define PA2_HV_SYNAP_SER_00 0x00400 /* serial; 0-7 */ -+#define PA2_HV_SYNAP_SER_08 0x00800 /* serial; 8-15 */ -+#define PA2_HV_SYNAP_SER_16 0x01000 /* serial; 16-23 */ -+#define PA2_HV_SYNAP_SER_24 0x02000 /* serial; 24-31 */ -+#define PA2_HV_SYNAP_SER_32 0x04000 /* serial; 32-35 */ -+ -+#define PA2_HV_SYNAP_SER_NB 0x08000 /* pcy_nibble1 */ -+#define PA2_HW_SYNAP_SER_BYTE 0x10000 /* pcy_byte1 */ -+#define PA2_HW_SYNAP_RESOL 0x20000 /* pcy_hv_flgs */ -+ -+#define PA2_HV_SYNAP_UNKNOWN1 0x0100000 -+#define PA2_HV_SYNAP_EXT_MODEL 0x0200000 -+#define PA2_HV_SYNAP_UNKNOWN3 0x0400000 -+#define PA2_HV_SYNAP_UNKNOWN4 0x0800000 ++#define PA2_HV_SYNAP_MODEL_00 0x00080 /* model; 0-7 */ ++#define PA2_HV_SYNAP_MODEL_08 0x00100 /* model; 8-15 */ ++#define PA2_HV_SYNAP_MODEL_16 0x00200 /* model; 16-23 */ ++#define PA2_HV_SYNAP_SER_00 0x00400 /* serial; 0-7 */ ++#define PA2_HV_SYNAP_SER_08 0x00800 /* serial; 8-15 */ ++#define PA2_HV_SYNAP_SER_16 0x01000 /* serial; 16-23 */ ++#define PA2_HV_SYNAP_SER_24 0x02000 /* serial; 24-31 */ ++#define PA2_HV_SYNAP_SER_32 0x04000 /* serial; 32-35 */ ++ ++#define PA2_HV_SYNAP_SER_NB 0x08000 /* pcy_nibble1 */ ++#define PA2_HW_SYNAP_SER_BYTE 0x10000 /* pcy_byte1 */ ++#define PA2_HW_SYNAP_RESOL 0x20000 /* pcy_hv_flgs */ ++ ++#define PA2_HV_SYNAP_UNKNOWN1 0x0100000 ++#define PA2_HV_SYNAP_EXT_MODEL 0x0200000 ++#define PA2_HV_SYNAP_UNKNOWN3 0x0400000 ++#define PA2_HV_SYNAP_UNKNOWN4 0x0800000 + +#define PA2_HV_SYNAP_CONST_E1_BYTE1 0x1000000 +#define PA2_HV_SYNAP_CONST_E1_BYTE2 0x2000000 + -+#define PA2_HV_SYNAP_MODES_B1 0x4000000 ++#define PA2_HV_SYNAP_MODES_B1 0x4000000 ++ ++/* ++ * AUX state. ++ * This is the dynamic state of an AUX device. ++ * pas_aux_status - values for remote, enable and scale. ++ * pas_aux_res - resolution setting ++ * pas_aux_sample - sample rate setting ++ * pas_aux_wrap_mode - state of wrap mode ++ * pas_hv_flgs - indicates which of the above values the s/w state ++ * (held in this struct) are valid. ++ */ ++ ++typedef struct pa2_aux_state_s { ++ uint8_t pas_aux_status; ++ uint8_t pas_aux_res; ++ uint8_t pas_aux_sample; ++ uint8_t pas_aux_wrap_mode; /* no have flag */ ++ uint8_t pas_hv_flgs; ++} pa2_aux_state_t; + ++/* ++ * pas_hv_flgs ++ */ ++ ++#define PA2_HV_AUX_STATE_REMOTE 0x0001 /* aux_status */ ++#define PA2_HV_AUX_STATE_ENABLE 0x0002 /* aux_status */ ++#define PA2_HV_AUX_STATE_SCALE 0x0004 /* aux_status */ ++#define PA2_HV_AUX_STATE_RES 0x0008 /* aux_res */ ++#define PA2_HV_AUX_STATE_SAMP 0x0010 /* aux_samp */ ++ ++/* ++ * Maximum number of AUX devices support by this driver. ++ * Limit comes from Active PS/2 Multiplexing. ++ */ ++ ++#define PA2_MAX_NUM_AUX 4 + +/* + * KBD and AUX state. -+ * This is the non-constant state. If a Synaptic touchpad is identified, then -+ * pss_synaptic will also be populated (and PA2_CONST_SYNAP_YES set in -+ * corrsponding pa2_const_t's psc_flgs). ++ * This is the dynamic state of the devices attached to a controller. ++ * If a Synaptic touchpad is identified, then pss_synaptic will also be ++ * populated (and PA2_CONST_SYNAP_YES set in corrsponding pa2_const_t's ++ * psc_flgs). + * -+ * These are actually synaptic state ++ * pss_status_last - last status reported to guest ++ * pss_status - s/w calculated status ++ * pss_mode - s/w calculated mode byte ++ * pss_kbd_rate - current KBD rate ++ * pss_kbd_leds - current settings of LEDs ++ * pss_outport - s/w calculated outport + * pss_setscale_last - 0 if setscale11, 1 if setscale12 ++ * pss_aux - dynamic state of AUX devices ++ * pss_aux_index - selected (routed) AUX device for multiplexing ++ * pss_flags - see below ++ * pss_hv_flgs - indicates which values are valid ++ * pss_synaptic - Synaptic touchpad dynamic state. + */ + +typedef struct pa2_state_s { -+ uint8_t pss_status_last; /* status given to guest */ -+ uint8_t pss_status; /* s/w calculate */ ++ uint8_t pss_status_last; ++ uint8_t pss_status; + uint8_t pss_mode; + uint8_t pss_kbd_rate; + uint8_t pss_kbd_leds; + uint8_t pss_outport; -+ uint8_t pss_aux_status; -+ uint8_t pss_aux_res; -+ uint8_t pss_aux_sample; -+ uint8_t pss_aux_wrap_mode; /* no have flag */ + uint8_t pss_setscale_last; -+ uint16_t pss_hv_flgs; ++ pa2_aux_state_t pss_aux[PA2_MAX_NUM_AUX]; ++ uint8_t pss_aux_index; ++ uint8_t pss_flags; ++ uint8_t pss_hv_flgs; + pa2_syp_state_t pss_synaptic; +} pa2_state_t; + +/* ++ * pss_flags ++ */ ++ ++#define PA2_STATE_AUX_MULTI 0x01 /* in ps/2 multiplex mode */ ++#define PA2_STATE_AUX_ROUTE 0x02 /* route to aux active */ ++ ++/* + * pss_hv_flgs ++ * Indicates where the s/w state (pa2_state_t) is in sync with h/w. + */ + -+#define PA2_HV_STATE_AUX_REMOTE 0x0001 /* aux_status */ -+#define PA2_HV_STATE_AUX_ENABLE 0x0002 /* aux_status */ -+#define PA2_HV_STATE_AUX_SCALE 0x0004 /* aux_status */ -+#define PA2_HV_STATE_MODE 0x0008 /* mode bits are in sync */ -+#define PA2_HV_STATE_OUTPORT 0x0010 /* outport */ -+#define PA2_HV_STATE_AUX_RES 0x0020 /* aux_res */ -+#define PA2_HV_STATE_AUX_SAMP 0x0080 /* aux_samp */ -+#define PA2_HV_STATE_KBD_RATE 0x0100 /* kbd_rate */ -+#define PA2_HV_STATE_KBD_LEDS 0x0200 /* kbd_leds */ ++#define PA2_HV_STATE_MODE 0x01 /* mode bits */ ++#define PA2_HV_STATE_OUTPORT 0x02 /* outport */ ++#define PA2_HV_STATE_KBD_RATE 0x04 /* kbd_rate */ ++#define PA2_HV_STATE_KBD_LEDS 0x08 /* kbd_leds */ + +/* + * Once known, these are constants. + * psc_inport - value from inport (PA2_CTL_CMD_INPORT_READ) + * psc_kbd_id - KBD ID (PA2_KBD_CMD_GET_ID). -+ * psc_aux_type - AUX type (PA2_AUX_CMD_TYPE_GET). ++ * psc_aux_type - AUX type (PA2_AUX_CMD_TYPE_GET). This needs ++ * expanding to support AUX multiplexing. + * psc_ctl_test - result of CTL test (PA2_CTL_CMD_SELF_TEST) + * psc_ctl_version - result of CTL version cmd (PA2_CTL_CMD_VERSION_GET) + * psc_ctl_kbd_test - result of CTL KBD test (PA2_CTL_CMD_KBD_TEST) + * psc_ctl_aux_test - result of CTL AUX test (PA2_CTL_CMD_AUX_TEST) + * psc_hv_flgs - have flags (fields that are populated) -+ * psc_flgs - other flags ++ * psc_flgs - other flags. see below. ++ * psc_multi_version - version of Active PS/2 multiplexing, if supported ++ * (PA2_CONST_MULTIPLEXING). ++ * psc_synap - Synaptic's constant state (when h/w present). + * + * On Lenovo T400, a PA2_CTL_CMD_VERSION_GET isn't responded to by the h/w. + * If this occurs, PA2_CONST_NO_CTL_VERSION is set so hosts without focus -+ * can not reply inkind. ++ * can reply inkind. + */ + +typedef struct pa2_const_s { @@ -826,12 +941,18 @@ index 0000000..9fa8baf + uint8_t psc_ctl_version; + uint8_t psc_ctl_kbd_test; + uint8_t psc_ctl_aux_test; -+ uint16_t psc_hv_flgs; /* have flags */ ++ uint16_t psc_hv_flgs; + uint8_t psc_flgs; ++ uint8_t psc_multi_version; + pa2_syp_const_t psc_synap; +} pa2_const_t; + -+/* psc_hv_flgs */ ++/* ++ * psc_hv_flgs ++ * "Have flags". For this structure, primary use is debugging (as should ++ * contain all these values during the 'once init' the the ctrl and devices). ++ */ ++ +#define PA2_HV_CONST_INPORT 0x0001 /* psc_kbd_id */ +#define PA2_HV_CONST_KBD_ID 0x0002 /* psc_kbd_id */ +#define PA2_HV_CONST_AUX_TYPE 0x0004 /* psc_aux_type */ @@ -840,25 +961,47 @@ index 0000000..9fa8baf +#define PA2_HV_CONST_CTL_KBD_TEST 0x0040 /* psc_ctl_aux_test */ +#define PA2_HV_CONST_CTL_AUX_TEST 0x0080 /* psc_ctl_aux_test */ + -+/* psc_flgs */ ++/* ++ * psc_flgs ++ */ ++ +#define PA2_CONST_SYNAP_PROBED 0x0001 /* have probe for synaptic? */ +#define PA2_CONST_SYNAP_YES 0x0002 /* synaptic present */ -+#define PA2_CONST_NO_CTL_VERSION 0x0004 ++#define PA2_CONST_NO_CTL_VERSION 0x0004 /* set if CTL_CMD_VERSION_GET ++ * is not supported by h/w */ ++#define PA2_CONST_MULTIPLEXING 0x0008 /* supports multiplexing */ + +/* + * One structure to bind them all together... -+ * pp_fd[] - file descriptors to communicate with kernel driver -+ * pp_active[] - has focus (KBD/AUX) -+ * pp_grabbing[] - device being grabbed or dropped (KBD/AUX). -+ * pp_init - set when performing first time initializing. -+ * pp_limit - timeout limit waiting for response...more work needed -+ * here XXX -+ * pp_aux_data - AUX data (last reported abs/rel position) -+ * pp_data_last - last data reported to host (should be split between ++ * This pulls together dynamic and constant state, along with queues, focus ++ * (active) state, etc. That is, it is the parent structure. ++ * pp_fd[] - file descriptors to communicate with kernel driver ++ * pp_active[] - indicates if device has focus (KBD/AUX) ++ * pp_grabbing[] - device being grabbed or dropped (KBD/AUX). ++ * pp_losing_focus[] - was used when dom0_driver could tell an pass2 ++ * instance that it was gaining focus while another ++ * instance had focus - pass2 would first request ++ * instance with focus to drop before before allow the ++ * other to grab. This behaviour from dom0_driver is ++ * no longer seen, and the code that supports this hasn't ++ * been maintained. Should be removed. ++ * pp_state_cur - current, dynamic, state ++ * pp_state_const - constant state ++ * pp_cmds - commands (in-progress state). ++ * pp_irqbuf - data received from h/w (KBD and AUX). ++ * pp_init - set when performing first time initializing. ++ * pp_limit - timeout limit waiting for response from a command. ++ * Used for internally generated commands (from grabbing, ++ * dropping device, and during initialization). Not for ++ * comamnds from guests. ++ * pp_aux_data - AUX data (last reported abs/rel position) ++ * pp_data_last - last data reported to host (should be split between + * KBD/AUX XXX) -+ * pp_byte_write_last - last byte written by host (should be split between ++ * pp_byte_write_last - last byte written by host (should be split between + * KBD/AUX XXX) -+ * pp_keystate - status of keys. This is incomplete...XXX ++ * pp_keystate - status of KBD keys. Two dimensions, to support ++ * scancodes with escape sequences. ++ * pp_key_esc - set if scancode escape sequence seen. + */ + +typedef struct pa2_s { @@ -866,23 +1009,18 @@ index 0000000..9fa8baf + uint pp_active[2]; + uint pp_grabbing[2]; + uint pp_losing_focus[2]; -+ + pa2_state_t pp_state_cur; + pa2_const_t pp_state_const; + pa2_cmd_t pp_cmds[PA2_OUTPUT_MAX]; + pa2_hdata_t pp_irqbuf[2]; -+ + uint pp_init; + uint pp_limit; -+ + pa2_aux_data_t pp_aux_data; -+ + uint32_t pp_flags; + uint8_t pp_data_last; + uint8_t pp_byte_write_last; -+ + uint8_t pp_keystate[2][128]; -+ uint8_t pp_key_esc; /* escape seq */ ++ uint8_t pp_key_esc; + + /* + * Integration with rest of io-emu. @@ -899,21 +1037,18 @@ index 0000000..9fa8baf + +/* + * pp_flags -+ * PA2_FLG_KBD_IRQ KBD interrupt raised -+ * PA2_FLG_AUX_IRQ AUX interrupt raised -+ * PA2_FLG_UNREP_STATUS haven't reported the last status read. used -+ * by DEBUG only -+ * PA2_FLG_SYNAPTIC_PROBE seen synaptic probe (GET_IDENTITY) from this -+ * guest + */ + -+#define PA2_FLG_KBD_IRQ 0x0001 -+#define PA2_FLG_AUX_IRQ 0x0002 -+#define PA2_FLG_UNREP_STATUS 0x0004 -+#define PA2_FLG_SYNAPTIC_PROBE 0x0010 ++#define PA2_FLG_KBD_IRQ 0x0001 /* KBD interrupt raised */ ++#define PA2_FLG_AUX_IRQ 0x0002 /* AUX interrupt raised */ ++#define PA2_FLG_UNREP_STATUS 0x0004 /* set if the last status read hasn't ++ * been recored to log. Debug only. */ ++#define PA2_FLG_SYNAPTIC_PROBE 0x0010 /* set if Synaptic probe (GET_IDENTITY) ++ * has been seen from guest */ + +/* + * THE global! ++ * This holds the state, etc, from this instance of pass2. + */ + +static pa2_t pa2_state; @@ -1090,6 +1225,8 @@ index 0000000..9fa8baf +/* + * Output error message to stderr (which can be re-directed by qemu to a log + * file), and (if enabled) to our debug log file. ++ * The ASSERT() is there so that a call to pa2_error() always generates a ++ * BUG: entry in the log file when compiled DEBUG. + */ + +static __attribute__ ((format (printf, 1, 2))) void @@ -1120,13 +1257,16 @@ index 0000000..9fa8baf + +/* + * Lower a raised interrupt. ++ * Can be called when no interrupt is raised. ++ * Note, interrupts are mutually exclusive; cannot have both KBD and AUX ++ * raised at the same time. + */ + +static void +pa2_irq_lower( + pa2_t *fp) +{ -+ /* mutually excluisve */ ++ + if (fp->pp_flags & PA2_FLG_KBD_IRQ) { + ASSERT((fp->pp_flags & PA2_FLG_AUX_IRQ) == 0); + PRINT_DEBUG(PA2_DBG_MID, "pa2_irq_lower: lowering kbd\n"); @@ -1142,6 +1282,7 @@ index 0000000..9fa8baf +} + +/* ++ * Raise an interrupt. + * Examine next input record, and decide if need to raise an interrupt, and + * if so which one. + */ @@ -1154,18 +1295,20 @@ index 0000000..9fa8baf + pa2_entry_t *pdp; + uint i; + ++ /* ++ * Fast track; if an interrupt already raised cannot raise a new one. ++ */ ++ + if (fp->pp_flags & (PA2_FLG_KBD_IRQ | PA2_FLG_AUX_IRQ)) { + goto out; + } + + /* + * If data is pending for a device, check mode bit to see if interrupts -+ * are enabled. Only one raised interrupt. ++ * are enabled. Only one interrupt can be raised. + * KBD comes first (PA2_KBD_INDEX < PA2_INDEX_AUX) so its interrupts + * take priority. Needed as the AUX can spam a large number of + * interrupts. -+ * What if a bad keyboard spamming interrupts? Not much can be done, -+ * but could have a round-robin... XXX + */ + + for (i = 0; i < 2; i++) { @@ -1219,20 +1362,21 @@ index 0000000..9fa8baf + ** Queue handling functions. + **/ + ++static int pa2_cmd_process(pa2_t *, pa2_cmd_t *, uint8_t, uint8_t); ++static uint32_t pa2_status_read(pa2_t *, int); ++ +/* + * Place a record into the input queue. -+ * The status register's output buffer bits (PA2_CTL_STAT_OBF, PA2_CTL_STAT_AUX_OBF) -+ * are maintained here. Other bits are the responsibility of the caller. ++ * The status register's output buffer bits (PA2_CTL_STAT_OBF, ++ * PA2_CTL_STAT_AUX_OBF) are maintained here. Other bits are the ++ * responsibility of the caller. + */ + -+/* XXX fwd XXX */ -+static int pa2_cmd_process(pa2_t *, pa2_cmd_t *, uint8_t, uint8_t); -+static uint32_t pa2_status_read(pa2_t *, int); -+ +/* + * Queue data at end of KBD input. If there is a cmd assocaited with the + * KBD, then run the data through it. -+ * This is used when the KBD is non-active. ++ * This is used when the KBD does not have focus (non-active), and the state ++ * machine is generating the data (command response) for the guest. + */ + +static int @@ -1267,19 +1411,30 @@ index 0000000..9fa8baf + pa2_error("Overflow!!!\n"); + php->ph_overflow++; + ret = 1; -+ /* send a RESEND to the guest? XXX */ + } + return ret; +} + ++/* ++ * Queue a KBD AUX at end of input. ++ */ ++ +static int +pa2_kbd_ack( + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ + return pa2_kbd_append(fp, cmdp, PA2_KBD_REPLY_ACK); +} + ++/* ++ * Queue data at end of AUX input. If there is a cmd assocaited with the ++ * AUX, then run the data through it. ++ * This is used when the KBD does not have focus (non-active), and the state ++ * machine is generating the data (command response) for the guest. ++ */ ++ +static int +pa2_aux_append( + pa2_t *fp, @@ -1312,16 +1467,20 @@ index 0000000..9fa8baf + pa2_error("Overflow!!!\n"); + php->ph_overflow++; + ret = 1; -+ /* send a RESEND to the guest? XXX */ + } + return ret; +} + ++/* ++ * Queue an AUX AUX at end of input. ++ */ ++ +static int +pa2_aux_ack( + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ + return pa2_aux_append(fp, cmdp, PA2_AUX_REPLY_ACK); +} + @@ -1340,6 +1499,12 @@ index 0000000..9fa8baf +static pa2_binding_t *pa2_binding; +static uint8_t pa2_binding_bitmap[256 / 8]; + ++/* ++ * Eject a scancode into a guest. ++ * Used when removing key presses during a VM switch (as the guest will not ++ * see a key break if it has lost KBD focus). ++ */ ++ +static void +pa2_key_inject( + pa2_t *fp, @@ -1347,13 +1512,18 @@ index 0000000..9fa8baf + uint escape, + uint make) +{ ++ + ASSERT(make == 0 || make == 1); + ASSERT(escape == 0 || escape == 1); -+ + PRINT_DEBUG(PA2_DBG_HIGH, "key_inject: 0x%X 0x%X 0x%X\n", + keycode, escape, make); + if (escape == 1) { -+ pa2_kbd_append(fp, NULL, 0xE0); /* magic XXX */ ++ ++ /* ++ * An escape scancode sequence. Generate the escape code. ++ */ ++ ++ pa2_kbd_append(fp, NULL, 0xE0); + } + if (make == 0) { + pa2_kbd_append(fp, NULL, keycode | 0x80); @@ -1363,6 +1533,11 @@ index 0000000..9fa8baf + return; +} + ++/* ++ * Search the registered key bindings to see if the made key triggers a match. ++ * If a match is found, the callback is called and this function returns ++ * non-zero - indicating the caller should not pass this key press to the guest. */ ++ +static int +pa2_binding_search( + pa2_t *fp, @@ -1418,9 +1593,10 @@ index 0000000..9fa8baf +} + +/* -+ * Here, the keys we are passed are Linux input keys (as in -+ * ./include/linux/input.h), but we are talking directly to the keyboard -+ * and so are dealing in scancodes. ++ * Generate a registered key binding. Called during initilization from the ++ * dom0_driver for the 'hot keys' it is interested in (eg. for VM switching). ++ * Here, the keys passed are Linux input keys (as in ./include/linux/input.h), ++ * but we are talking directly to the keyboard and so are dealing in scancodes. + * Currently, the keys being passed in match the scancodes but will need + * to add conversion table in the future. XXX + */ @@ -1466,8 +1642,16 @@ index 0000000..9fa8baf + return ret; +} + ++/** ++ ** Functions for communicating with the h/w. ++ ** Communication is via file descriptors into the pass2 kernel driver. ++ **/ ++ +/* + * Write to data port. ++ * 'index' indicates if this write is for the KBD or AUX device. This is ++ * only used by the pass2 kernel driver to assert that the ioemu instance ++ * has focus for the device it is writing to. + * Unlike the below cmd write, a data write (to the data port) doesn't clear + * any queued data from the device. + */ @@ -1492,12 +1676,15 @@ index 0000000..9fa8baf + pa2_error("error writing data\n"); + ret = 1; + } -+ fp->pp_byte_write_last = byte; /* only on success? XXX */ ++ if (ret == 0) { ++ fp->pp_byte_write_last = byte; ++ } + return ret; +} + +/* + * Write cmd to data port. ++ * See pa2_reg_data_write() above for 'index'. + * A cmd clears any queued data (while the above data write, doesn't). + */ + @@ -1525,13 +1712,14 @@ index 0000000..9fa8baf + pa2_error("error writing data\n"); + ret = 1; + } -+ fp->pp_byte_write_last = cmd; /* only on success? XXX */ ++ if (ret == 0) { ++ fp->pp_byte_write_last = cmd; ++ } + return ret; +} + +/* -+ * Write to cmd port. -+ * This should abort any current cmd....XXX ++ * Write to command byte to command port. + */ + +static int @@ -1551,7 +1739,12 @@ index 0000000..9fa8baf + return ret; +} + -+/* fwd XXX */ ++/** ++ ** Cmd/Done functions for controller commands. ++ ** These are the state machines for controller commands. ++ **/ ++ ++/* fwd references */ +static int pa2_ctl_mode_write_do(pa2_t *, uint8_t); +static int pa2_ctl_aux_enable_do(pa2_t *); +static int pa2_ctl_kbd_enable_do(pa2_t *); @@ -1559,10 +1752,6 @@ index 0000000..9fa8baf +static int pa2_ctl_outport_write_do(pa2_t *, uint8_t); +static int pa2_ctl_aux_disable_do(pa2_t *); + -+/** -+ ** Cmd/Done functions for controller commands. -+ **/ -+ +/* --------------------------------------------------------------------- */ + +/* @@ -1642,6 +1831,7 @@ index 0000000..9fa8baf +pa2_ctl_mode_read_redo( + pa2_t *fp) +{ ++ + /* + * Returned the mode, as we know it, to the caller so nothing + * to be done here. @@ -1657,6 +1847,11 @@ index 0000000..9fa8baf + * Write to Keyboard Controller's Command Byte (aka mode). + * The next byte written to the data port is placed in the controller's command + * byte. ++ * The mode byte controls behaviour of both KBD and AUX devices. When KBD and ++ * AUX have focus to different guests (as with AppServer) how to handle a ++ * guest writing to the mode byte? Suspect it does not happen, so no attempt ++ * is made to handle this case; provided the guest has focus on either the ++ * KBD or AUX, the write is allowed. + */ + +static void @@ -1671,7 +1866,6 @@ index 0000000..9fa8baf + ssp = &fp->pp_state_cur; + ASSERT(ssp->pss_hv_flgs & PA2_HV_STATE_MODE); + PRINT_DEBUG(PA2_DBG_MID, "ctl_mode_write_done: 0x%X\n", ssp->pss_mode); -+ /* why raise ints? XXX */ + pa2_irq_raise(fp); + return; +} @@ -1689,8 +1883,8 @@ index 0000000..9fa8baf + ssp = &fp->pp_state_cur; + PRINT_DEBUG(PA2_DBG_LOW, "ctl_mode_write_cmd\n"); + ret = 0; -+ /* should depend on what mode bits are being changed... XXX */ -+ if (fp->pp_active[0] == 1 || fp->pp_active[1] == 1) { ++ if (fp->pp_active[PA2_INDEX_KBD] == 1 || ++ fp->pp_active[PA2_INDEX_AUX] == 1) { + ret = pa2_reg_cmd_write(fp, cmdp->pc_cmd); + } + return ret; @@ -1714,11 +1908,6 @@ index 0000000..9fa8baf + fp->pp_active[PA2_INDEX_AUX] == 1) { + ret = pa2_reg_data_write(fp, PA2_INDEX_KBD, byte); + } else { -+ /* -+ * Need to lock XXXX -+ */ -+ -+ /* should depend on what mode bits are being changed... XXX */ + if (fp->pp_active[PA2_INDEX_KBD] == 1) { + ret = pa2_reg_data_write(fp, PA2_INDEX_KBD, byte); + } else if (fp->pp_active[PA2_INDEX_AUX] == 1) { @@ -1746,6 +1935,213 @@ index 0000000..9fa8baf + +/* --------------------------------------------------------------------- */ + ++/* ++ * For active PS/2 multiplexing. ++ * Route a command to AUX #0. ++ */ ++ ++static void ++pa2_ctl_route_aux0_done( ++ pa2_t *fp, ++ pa2_cmd_t *cmdp) ++{ ++ ++ PRINT_DEBUG(PA2_DBG_MID, "ctl_route_aux0_done\n"); ++ return; ++} ++ ++static int ++pa2_ctl_route_aux0_cmd( ++ pa2_t *fp, ++ pa2_cmd_t *cmdp) ++{ ++ pa2_state_t *ssp; ++ int ret; ++ ++ ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_ROUTE_AUX0); ++ ASSERT(cmdp->pc_counter == 0); ++ PRINT_DEBUG(PA2_DBG_LOW, "ctl_route_aux0_cmd\n"); ++ ++ /* ++ * If not in multiplex mode, ignore. ++ */ ++ ++ ret = 0; ++ ssp = &fp->pp_state_cur; ++ if (!(ssp->pss_flags & PA2_STATE_AUX_MULTI)) { ++ goto out; ++ } ++ if (fp->pp_active[0] == 1 || fp->pp_active[1] == 1) { ++ ret = pa2_reg_cmd_write(fp, cmdp->pc_cmd); ++ if (ret == 0) { ++ ssp->pss_flags |= PA2_STATE_AUX_ROUTE; ++ ssp->pss_aux_index = 0; ++ } ++ } ++ ++out: ++ return ret; ++} ++ ++/* --------------------------------------------------------------------- */ ++ ++/* ++ * For active PS/2 multiplexing. ++ * Route a command to AUX #1. ++ */ ++ ++static void ++pa2_ctl_route_aux1_done( ++ pa2_t *fp, ++ pa2_cmd_t *cmdp) ++{ ++ ++ PRINT_DEBUG(PA2_DBG_MID, "ctl_route_aux1_done\n"); ++ return; ++} ++ ++static int ++pa2_ctl_route_aux1_cmd( ++ pa2_t *fp, ++ pa2_cmd_t *cmdp) ++{ ++ pa2_state_t *ssp; ++ int ret; ++ ++ ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_ROUTE_AUX1); ++ ASSERT(cmdp->pc_counter == 0); ++ PRINT_DEBUG(PA2_DBG_LOW, "ctl_route_aux1_cmd\n"); ++ ++ /* ++ * If not in multiplex mode, then ignore. ++ */ ++ ++ ret = 0; ++ ssp = &fp->pp_state_cur; ++ if (ssp->pss_flags & PA2_STATE_AUX_MULTI) { ++ goto out; ++ } ++ if (fp->pp_active[0] == 1 || fp->pp_active[1] == 1) { ++ ret = pa2_reg_cmd_write(fp, cmdp->pc_cmd); ++ if (ret == 0) { ++ ssp->pss_flags |= PA2_STATE_AUX_ROUTE; ++ ssp->pss_aux_index = 1; ++ } ++ } ++ ++out: ++ return ret; ++} ++ ++/* --------------------------------------------------------------------- */ ++ ++/* ++ * For active PS/2 multiplexing. ++ * Route a command to AUX #2. ++ */ ++ ++static void ++pa2_ctl_route_aux2_done( ++ pa2_t *fp, ++ pa2_cmd_t *cmdp) ++{ ++ ++ PRINT_DEBUG(PA2_DBG_MID, "ctl_route_aux2_done\n"); ++ return; ++} ++ ++static int ++pa2_ctl_route_aux2_cmd( ++ pa2_t *fp, ++ pa2_cmd_t *cmdp) ++{ ++ pa2_state_t *ssp; ++ int ret; ++ ++ ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_ROUTE_AUX2); ++ ASSERT(cmdp->pc_counter == 0); ++ PRINT_DEBUG(PA2_DBG_LOW, "ctl_route_aux2_cmd\n"); ++ ++ /* ++ * If not in multiplex mode, then ignore. ++ */ ++ ++ ret = 0; ++ ssp = &fp->pp_state_cur; ++ if (!(ssp->pss_flags & PA2_STATE_AUX_MULTI)) { ++ goto out; ++ } ++ if (fp->pp_active[0] == 1 || fp->pp_active[1] == 1) { ++ ret = pa2_reg_cmd_write(fp, cmdp->pc_cmd); ++ if (ret == 0) { ++ ssp->pss_flags |= PA2_STATE_AUX_ROUTE; ++ ssp->pss_aux_index = 2; ++ } ++ } ++ ++out: ++ return ret; ++} ++ ++/* --------------------------------------------------------------------- */ ++ ++/* ++ * For active PS/2 multiplexing. ++ * Route a command to AUX #3. ++ */ ++ ++static void ++pa2_ctl_route_aux3_done( ++ pa2_t *fp, ++ pa2_cmd_t *cmdp) ++{ ++ ++ PRINT_DEBUG(PA2_DBG_MID, "ctl_route_aux3_done\n"); ++ return; ++} ++ ++static int ++pa2_ctl_route_aux3_cmd( ++ pa2_t *fp, ++ pa2_cmd_t *cmdp) ++{ ++ pa2_state_t *ssp; ++ int ret; ++ ++ ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_ROUTE_AUX3); ++ ASSERT(cmdp->pc_counter == 0); ++ PRINT_DEBUG(PA2_DBG_LOW, "ctl_route_aux3_cmd\n"); ++ ++ /* ++ * If not in multiplex mode, then ignore. ++ */ ++ ++ ret = 0; ++ ssp = &fp->pp_state_cur; ++ if (!(ssp->pss_flags & PA2_STATE_AUX_MULTI)) { ++ goto out; ++ } ++ if (fp->pp_active[0] == 1 || fp->pp_active[1] == 1) { ++ ret = pa2_reg_cmd_write(fp, cmdp->pc_cmd); ++ if (ret == 0) { ++ ssp->pss_flags |= PA2_STATE_AUX_ROUTE; ++ ssp->pss_aux_index = 3; ++ } ++ } ++ ++out: ++ return ret; ++} ++ ++/* --------------------------------------------------------------------- */ ++ ++/* ++ * The the controller (firmware) version. ++ * This is only done during 'once init' phase, and the stored value returned ++ * to guests. Note, most controllers do not appear to support this command, ++ * but most guest drivers appear to issue it. ++ */ ++ +static void +pa2_ctl_version_get_done( + pa2_t *fp, @@ -1780,7 +2176,6 @@ index 0000000..9fa8baf + ret = pa2_reg_cmd_write(fp, cmdp->pc_cmd); + } else if (scp->psc_flgs & PA2_CONST_NO_CTL_VERSION) { + ASSERT(!(scp->psc_hv_flgs & PA2_HV_CONST_CTL_VERSION)); -+ /* adjust length.... XXX */ + } else { + ASSERT(scp->psc_hv_flgs & PA2_HV_CONST_CTL_VERSION); + ret = pa2_kbd_append(fp, cmdp, scp->psc_ctl_version); @@ -1810,6 +2205,7 @@ index 0000000..9fa8baf +pa2_ctl_version_get_redo( + pa2_t *fp) +{ ++ + PRINT_DEBUG(PA2_DBG_MID, "ctl_version_get_redo\n"); + return 0; +} @@ -1821,6 +2217,7 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ + ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_AUX_DISABLE); + ASSERT(fp->pp_state_cur.pss_mode & PA2_CTL_MODE_DISABLE_AUX); + PRINT_DEBUG(PA2_DBG_MID, "ctl_aux_disable_done\n"); @@ -1862,6 +2259,7 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ + ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_AUX_ENABLE); + ASSERT(!(fp->pp_state_cur.pss_mode & PA2_CTL_MODE_DISABLE_AUX)); + PRINT_DEBUG(PA2_DBG_MID, "ctl_aux_enable_done\n"); @@ -1874,6 +2272,7 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ pa2_state_t *ssp; + int ret; + + ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_AUX_ENABLE); @@ -1882,6 +2281,20 @@ index 0000000..9fa8baf + if (fp->pp_active[PA2_INDEX_AUX] == 1) { + ret = pa2_reg_cmd_write(fp, cmdp->pc_cmd); + } ++ ++ /* ++ * If in multiplex mode, and there is a route cmd active, then ++ * mark selected AUX device as enabled. ++ */ ++ ++ ssp = &fp->pp_state_cur; ++ if ((ssp->pss_flags & PA2_STATE_AUX_MULTI) && ++ (ssp->pss_flags & PA2_STATE_AUX_ROUTE)) { ++ /* ++ * Need to implement support for AUX multiplexing. XXX ++ */ ++ ; ++ } + fp->pp_state_cur.pss_mode &= ~PA2_CTL_MODE_DISABLE_AUX; + return ret; +} @@ -1908,6 +2321,8 @@ index 0000000..9fa8baf + * 03 - data line low + * 04 - data line high + * FF - no AUX device ++ * The AUX test is only done during 'once init', and the stored value is ++ * returned to guests. + */ + +static void @@ -1969,6 +2384,7 @@ index 0000000..9fa8baf +pa2_ctl_aux_test_redo( + pa2_t *fp) +{ ++ + PRINT_DEBUG(PA2_DBG_MID, "ctl_aux_test_redo\n"); + return 0; +} @@ -1978,7 +2394,7 @@ index 0000000..9fa8baf +/* + * Controller self-test. + * Return 0x55 (PA2_CTL_REPLY_SELF) if no errors. -+ * Only done during our init. ++ * Only done during our 'once init', with stored result returned to clients. + */ + +static void @@ -2045,7 +2461,7 @@ index 0000000..9fa8baf + ssp = &fp->pp_state_cur; + ssp->pss_mode &= ~PA2_CTL_MODE_INT_KBD; + ssp->pss_mode &= ~PA2_CTL_MODE_INT_AUX; -+ ssp->pss_mode &= ~PA2_CTL_MODE_KCC; /* not sure XXX */ ++ ssp->pss_mode &= ~PA2_CTL_MODE_KCC; + ssp->pss_mode |= PA2_CTL_MODE_DISABLE_KBD; + ssp->pss_mode |= PA2_CTL_MODE_DISABLE_AUX; + cmdp->pc_counter++; @@ -2056,6 +2472,7 @@ index 0000000..9fa8baf +pa2_ctl_self_test_redo( + pa2_t *fp) +{ ++ + PRINT_DEBUG(PA2_DBG_MID, "ctl_self_test_redo\n"); + return 0; +} @@ -2129,6 +2546,7 @@ index 0000000..9fa8baf +pa2_ctl_kbd_test_redo( + pa2_t *fp) +{ ++ + PRINT_DEBUG(PA2_DBG_MID, "ctl_kbd_test_redo\n"); + return 0; +} @@ -2140,6 +2558,7 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ + ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_KBD_ENABLE); + ASSERT(!(fp->pp_state_cur.pss_mode & PA2_CTL_MODE_DISABLE_KBD)); + PRINT_DEBUG(PA2_DBG_MID, "ctl_kbd_enable_done\n"); @@ -2160,7 +2579,6 @@ index 0000000..9fa8baf + ret = pa2_reg_cmd_write(fp, cmdp->pc_cmd); + } + fp->pp_state_cur.pss_mode &= ~PA2_CTL_MODE_DISABLE_KBD; -+ /* pa2_irq_raise(fp); no longer required? XXXX */ + return ret; +} + @@ -2182,6 +2600,7 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ + ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_KBD_DISABLE); + ASSERT(fp->pp_state_cur.pss_mode & PA2_CTL_MODE_DISABLE_KBD); + PRINT_DEBUG(PA2_DBG_MID, "ctl_kbd_disable_done\n"); @@ -2276,6 +2695,7 @@ index 0000000..9fa8baf +pa2_ctl_inport_read_redo( + pa2_t *fp) +{ ++ + PRINT_DEBUG(PA2_DBG_MID, "ctl_inport_read_redo\n"); + return 0; +} @@ -2343,12 +2763,21 @@ index 0000000..9fa8baf +pa2_ctl_outport_read_redo( + pa2_t *fp) +{ ++ + PRINT_DEBUG(PA2_DBG_MID, "ctl_outport_read_redo\n"); + return 0; +} + +/*****************************************************************/ + ++/* ++ * The Outport byte controls behaviour of both KBD and AUX devices. When KBD ++ * and AUX have focus to different guests (as with AppServer) how to handle a ++ * guest writing to the outport? Suspect it does not happen, so no attempt ++ * is made to handle this case; provided the guest has focus on either the ++ * KBD or AUX, the write is allowed. ++ */ ++ +static void +pa2_ctl_outport_write_done( + pa2_t *fp, @@ -2376,9 +2805,7 @@ index 0000000..9fa8baf + ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_OUTPORT_WRITE); + ASSERT(cmdp->pc_counter == 0); + PRINT_DEBUG(PA2_DBG_LOW, "ctl_outport_write_cmd\n"); -+ /* lets never write to this port for now XXX */ + ret = 0; -+ /* should depend on what bits are being modified XXX */ + if (fp->pp_active[PA2_INDEX_KBD] == 1 || + fp->pp_active[PA2_INDEX_AUX] == 1) { + ret = pa2_reg_cmd_write(fp, cmdp->pc_cmd); @@ -2399,10 +2826,8 @@ index 0000000..9fa8baf + ASSERT(cmdp->pc_counter == 0); + PRINT_DEBUG(PA2_DBG_HIGH, "ctl_outport_write_write: 0x%X\n", byte); + ret = 0; -+ /* should depend on what bits are being modified XXX */ + if (fp->pp_active[PA2_INDEX_KBD] == 1 || + fp->pp_active[PA2_INDEX_AUX] == 1) { -+ PRINT_DEBUG(PA2_DBG_HIGH, "Here1\n"); + ret = pa2_reg_data_write(fp, PA2_INDEX_KBD, byte); + } else { + ioport_set_a20(!!(byte & PA2_OUTPORT_GA20)); @@ -2434,9 +2859,9 @@ index 0000000..9fa8baf +/*****************************************************************/ + +/* -+ * Write Keyboard Output Register: on PS/2 systems the next data byte written -+ * to port 60h input register is written to port 60h output register as if -+ * initiated by a device; invokes interrupt if enabled. ++ * Write Keyboard Output Register: the next data byte written to port 60h ++ * input register is written to port 60h output register as if initiated by a ++ * device; invokes interrupt if enabled. + */ + +static void @@ -2495,6 +2920,7 @@ index 0000000..9fa8baf +pa2_ctl_obuf_write_redo( + pa2_t *fp) +{ ++ + PRINT_DEBUG(PA2_DBG_MID, "ctl_obuf_write_redo\n"); + return 0; +} @@ -2502,9 +2928,9 @@ index 0000000..9fa8baf +/*****************************************************************/ + +/* -+ * Write Auxiliary Output Register: on PS/2 systems the next data byte -+ * written to port 60h input register is written to port 60h output -+ * register as if initiated by a device; invokes interrupt if enabled ++ * Write Auxiliary Output Register: the next data byte written to port 60h ++ * input register is written to port 60h output register as if initiated by ++ * a device; invokes interrupt if enabled + */ + +static void @@ -2512,6 +2938,7 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ + ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_WRITE_AUX_OBUF); + ASSERT(cmdp->pc_counter == 2); + PRINT_DEBUG(PA2_DBG_MID, "write_aux_obuf_done\n"); @@ -2545,6 +2972,7 @@ index 0000000..9fa8baf + pa2_cmd_t *cmdp, + uint8_t byte) +{ ++ + ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_WRITE_AUX_OBUF); + ASSERT(cmdp->pc_counter == 1); + PRINT_DEBUG(PA2_DBG_LOW, "ctl_write_aux_obuf_read\n"); @@ -2576,6 +3004,7 @@ index 0000000..9fa8baf +pa2_ctl_write_aux_obuf_redo( + pa2_t *fp) +{ ++ + PRINT_DEBUG(PA2_DBG_MID, "ctl_write_aux_obuf_redo\n"); + return 0; +} @@ -2583,8 +3012,10 @@ index 0000000..9fa8baf +/*****************************************************************/ + +/* -+ * The PA2_CTL_CMD_WRITE_AUX command is always delayed, until we know what -+ * the following AUX cmd is. ++ * The PA2_CTL_CMD_WRITE_AUX command is always delayed, until the following ++ * AUX cmd is known. When the AUX command is received from the guest, its ++ * handler calls pa2_ctl_write_aux_pending() to write the CTL_CMD_WRITE_AUX ++ * command before sending its AUX cmd. + */ + +static int @@ -2607,7 +3038,12 @@ index 0000000..9fa8baf + cmdp->pc_flags &= ~PA2_CMD_FLG_PENDING_AUX; + ret = pa2_reg_cmd_write(fp, PA2_CTL_CMD_WRITE_AUX); + if (ret == 0) { -+ /* wait for input buffer to become empty */ ++ ++ /* ++ * Wait for input buffer to become empty, before returning. ++ * This ensures the ctrl has consumed/processed the cmd. ++ */ ++ + ret = 1; + for (i = 0; i < 100; i++) { + status = pa2_status_read(fp, PA2_INDEX_RAW); @@ -2630,12 +3066,8 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ -+ /* -+ * pc_cmd will have been overwritten with command that followed. -+ */ + + ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_WRITE_AUX); -+ /* ASSERT(cmdp->pc_counter == 1); XXX */ + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX)); + PRINT_DEBUG(PA2_DBG_MID, "ctl_write_aux_done\n"); + return; @@ -2646,6 +3078,7 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ + ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_WRITE_AUX); + ASSERT(cmdp->pc_counter == 0); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX)); @@ -2662,7 +3095,6 @@ index 0000000..9fa8baf +{ + int ret; + -+ /* should never be called XXXX */ + ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_WRITE_AUX); + ASSERT(cmdp->pc_counter == 0); + PRINT_DEBUG(PA2_DBG_LOW, "ctl_write_aux_write\n"); @@ -2679,20 +3111,27 @@ index 0000000..9fa8baf +pa2_ctl_write_aux_redo( + pa2_t *fp) +{ ++ + PRINT_DEBUG(PA2_DBG_MID, "ctl_write_aux_redo\n"); + return 0; +} + +/*****************************************************************/ + ++/* ++ * CTL_CMD_DISABLE_A20 command is currently being ignored by this driver. ++ * That is, not sent through the h/w. This is not causing any issues, but ++ * should be re-visited if MS-DOS guests are to be supported... ++ */ ++ +static void +pa2_ctl_disable_a20_done( + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ + ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_DISABLE_A20); + PRINT_DEBUG(PA2_DBG_MID, "ctl_disable_a20_done\n"); -+ /* XXX */ + return; +} + @@ -2701,10 +3140,9 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ + ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_DISABLE_A20); + PRINT_DEBUG(PA2_DBG_LOW, "ctl_disable_a20_cmd\n"); -+ /* just ignore this for now XXX */ -+ /* fp->pp_state_cur.pss_mode XXX */ + return 0; +} + @@ -2712,20 +3150,27 @@ index 0000000..9fa8baf +pa2_ctl_disable_a20_redo( + pa2_t *fp) +{ ++ + PRINT_DEBUG(PA2_DBG_MID, "ctl_disable_a20_redo\n"); + return 0; +} + +/*****************************************************************/ + ++/* ++ * CTL_CMD_ENABLE_A20 command is currently being ignored by this driver. ++ * That is, not sent through the h/w. This is not causing any issues, but ++ * should be re-visited if MS-DOS guests are to be supported... ++ */ ++ +static void +pa2_ctl_enable_a20_done( + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ + ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_ENABLE_A20); + PRINT_DEBUG(PA2_DBG_MID, "pa2_ctl_enable_a20_done\n"); -+ /* XXX */ + return; +} + @@ -2734,10 +3179,9 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ + ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_ENABLE_A20); + PRINT_DEBUG(PA2_DBG_LOW, "pa2_ctl_enable_a20_cmd\n"); -+ /* just ignore this for now XXX */ -+ /* fp->pp_state_cur.pss_mode XXX */ + return 0; +} + @@ -2745,6 +3189,7 @@ index 0000000..9fa8baf +pa2_ctl_enable_a20_redo( + pa2_t *fp) +{ ++ + PRINT_DEBUG(PA2_DBG_MID, "ctl_enable_a20_redo\n"); + return 0; +} @@ -2752,7 +3197,9 @@ index 0000000..9fa8baf +/*****************************************************************/ + +/* -+ * I think this is a keyboard command - not a keyboard controller cmd XXXX ++ * Resend last byte. ++ * Not sure about this. Currently not implemented, as has not been seen ++ * but would only expect this for a (h/w or f/w) error. + */ + +static void @@ -2760,6 +3207,7 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ + ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_RESEND); + PRINT_DEBUG(PA2_DBG_MID, "ctl_resend_done\n"); + return; @@ -2792,6 +3240,7 @@ index 0000000..9fa8baf + pa2_cmd_t *cmdp, + uint8_t byte) +{ ++ + ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_RESEND); + PRINT_DEBUG(PA2_DBG_LOW, "ctl_resend_read\n"); + ASSERT(fp->pp_byte_write_last == byte); @@ -2802,20 +3251,30 @@ index 0000000..9fa8baf +pa2_ctl_resend_redo( + pa2_t *fp) +{ ++ + PRINT_DEBUG(PA2_DBG_MID, "ctl_resend_redo\n"); + return 0; +} + -+/* --------------------------------- */ ++/*****************************************************************/ ++ ++/* ++ * Perform a ctrl reset. ++ * When KBD and AUX have focus to different guests (as with AppServer) how to ++ * handle a ctrl reset? As with CTL_CMD_MODE_WRITE, I suspect it does not ++ * happen so no attempt is made to handle this case; provided the guest has ++ * focus on either the KBD or AUX, the reset is allowed. ++ */ + +static void +pa2_ctl_reset_done( + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ + ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_RESET); + ASSERT(cmdp->pc_counter == 0); -+ PRINT_DEBUG(PA2_DBG_LOW, "ctl_reset_done\n"); ++ PRINT_DEBUG(PA2_DBG_MID, "ctl_reset_done\n"); + return; +} + @@ -2830,8 +3289,8 @@ index 0000000..9fa8baf + ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_RESET); + PRINT_DEBUG(PA2_DBG_LOW, "ctl_reset_cmd\n"); + ret = 0; -+ /* should be both XXX */ -+ if (fp->pp_active[PA2_INDEX_KBD] == 1 || fp->pp_active[PA2_INDEX_AUX] == 1) { ++ if (fp->pp_active[PA2_INDEX_KBD] == 1 || ++ fp->pp_active[PA2_INDEX_AUX] == 1) { + ret = pa2_reg_cmd_write(fp, cmdp->pc_cmd); + } + return ret; @@ -2841,14 +3300,18 @@ index 0000000..9fa8baf +pa2_ctl_reset_redo( + pa2_t *fp) +{ ++ + PRINT_DEBUG(PA2_DBG_MID, "ctl_reset_redo\n"); + return 0; +} + +/*****************************************************************/ -+/* --------------------------------- */ + -+static /* const XXX */ pa2_cmd_des_t pa2_ctl_cmd[] = { ++/* ++ * Command descriptor table for ctrl commands. ++ */ ++ ++static pa2_cmd_des_t pa2_ctl_cmd[] = { +/* 0x20 */ { PA2_CTL_CMD_MODE_READ, "CTL_CMD_MODE_READ", + 1, 0, 0, PA2_OUTPUT_KBD, + PA2_CMD_FLG_CTRL, @@ -2864,6 +3327,34 @@ index 0000000..9fa8baf + pa2_ctl_mode_write_cmd, pa2_ctl_mode_write_done, + pa2_ctl_mode_write_redo + }, ++/* 0x90 */ { PA2_CTL_CMD_ROUTE_AUX0, "CTL_CMD_ROUTE_AUX0", ++ 0, 0, 0, PA2_OUTPUT_KBD, ++ 0, ++ NULL, NULL, ++ pa2_ctl_route_aux0_cmd, pa2_ctl_route_aux0_done, ++ NULL, ++ }, ++/* 0x91 */ { PA2_CTL_CMD_ROUTE_AUX1, "CTL_CMD_ROUTE_AUX1", ++ 0, 0, 0, PA2_OUTPUT_KBD, ++ 0, ++ NULL, NULL, ++ pa2_ctl_route_aux1_cmd, pa2_ctl_route_aux1_done, ++ NULL, ++ }, ++/* 0x92 */ { PA2_CTL_CMD_ROUTE_AUX2, "CTL_CMD_ROUTE_AUX2", ++ 0, 0, 0, PA2_OUTPUT_KBD, ++ 0, ++ NULL, NULL, ++ pa2_ctl_route_aux2_cmd, pa2_ctl_route_aux2_done, ++ NULL, ++ }, ++/* 0x93 */ { PA2_CTL_CMD_ROUTE_AUX3, "CTL_CMD_ROUTE_AUX3", ++ 0, 0, 0, PA2_OUTPUT_NONE, ++ 0, ++ NULL, NULL, ++ pa2_ctl_route_aux3_cmd, pa2_ctl_route_aux3_done, ++ NULL, ++ }, +/* 0xA1 */ { PA2_CTL_CMD_VERSION_GET, "CTL_CMD_GET_VERSION", + 1, 1, 0, PA2_OUTPUT_KBD, + PA2_CMD_FLG_CTRL, @@ -2992,7 +3483,11 @@ index 0000000..9fa8baf + }, +}; + -+/* fwd XXX */ ++/** ++ ** Keyboard cmd done functions. ++ **/ ++ ++/* fwd declarations */ +static int pa2_kbd_leds_set_do(pa2_t *, uint8_t); +static int pa2_kbd_rate_set_do(pa2_t *, uint8_t); +static int pa2_kbd_enable_do(pa2_t *); @@ -3000,9 +3495,7 @@ index 0000000..9fa8baf +static int pa2_kbd_reset_disable_do(pa2_t *); +static int pa2_kbd_reset_do(pa2_t *); + -+/** -+ ** Keyboard cmd done functions. -+ **/ ++/*****************************************************************/ + +static void +pa2_kbd_leds_set_done( @@ -3101,11 +3594,11 @@ index 0000000..9fa8baf + return ret; +} + -+/************************************************************/ ++/*****************************************************************/ + +/* -+ * 0xEE - Diagnostic Echo, keyboard echoes the EE byte back to the system -+ * without an acknowledgement. ++ * Diagnostic Echo, keyboard echoes the EE byte back to the system without an ++ * acknowledgement. + */ + +static void @@ -3113,6 +3606,7 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ + ASSERT(cmdp->pc_cmd == PA2_KBD_CMD_ECHO); + ASSERT(cmdp->pc_counter == 1); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED)); @@ -3148,6 +3642,7 @@ index 0000000..9fa8baf + pa2_cmd_t *cmdp, + uint8_t byte) +{ ++ + ASSERT(cmdp->pc_cmd == PA2_KBD_CMD_ECHO); + ASSERT(cmdp->pc_counter == 0); + ASSERT(byte == PA2_KBD_REPLY_ECHO_RESP); @@ -3163,15 +3658,18 @@ index 0000000..9fa8baf +pa2_kbd_echo_redo( + pa2_t *fp) +{ ++ + PRINT_DEBUG(PA2_DBG_MID, "kbd_echo_redo\n"); + return 0; +} + -+/************************************************************/ ++/*****************************************************************/ + +/* -+ * 0xF2 - PS/2 Read Keyboard ID, keyboard responds with an ACK and a two -+ * byte keyboard ID of 83AB. ++ * Read Keyboard ID, keyboard responds with an ACK and a two byte keyboard ID ++ * of 83AB. ++ * This KBD cmd is only performed during 'once init', with the stored result ++ * returned to guests. + */ + +static void @@ -3198,7 +3696,6 @@ index 0000000..9fa8baf + pa2_const_t *scp; + int ret; + -+ /* causes scanning to be resumed if previously disabled XXX */ + ASSERT(cmdp->pc_cmd == PA2_KBD_CMD_GET_ID); + ASSERT(cmdp->pc_counter == 0); + PRINT_DEBUG(PA2_DBG_LOW, "kbd_get_id_cmd\n"); @@ -3283,6 +3780,7 @@ index 0000000..9fa8baf +pa2_kbd_get_id_redo( + pa2_t *fp) +{ ++ + PRINT_DEBUG(PA2_DBG_MID, "kbd_get_id_redo\n"); + return 0; +} @@ -3389,9 +3887,10 @@ index 0000000..9fa8baf + +/************************************************************/ + -+/* 0xF4 - Enable Keyboard, cause the keyboard to clear its output buffer -+ * and last typematic key and then respond with an ACK. The -+ * keyboard then begins scanning. ++/* ++ * Enable Keyboard, cause the keyboard to clear its output buffer and last ++ * typematic key and then respond with an ACK. The keyboard then begins ++ * scanning. + */ + +static void @@ -3399,6 +3898,7 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ + ASSERT(cmdp->pc_cmd == PA2_KBD_CMD_ENABLE); + ASSERT(cmdp->pc_counter == 1); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED)); @@ -3420,7 +3920,6 @@ index 0000000..9fa8baf + cmdp->pc_expected_input = PA2_KBD_REPLY_ACK; + cmdp->pc_flags |= PA2_CMD_FLG_EXPECTED; + -+ /* clear the keyboard's output buffer XXX */ + if (cmdp->pc_active == 1) { + ret = pa2_reg_cmd_data_write(fp, PA2_INDEX_KBD, cmdp->pc_cmd); + } else { @@ -3435,6 +3934,7 @@ index 0000000..9fa8baf + pa2_cmd_t *cmdp, + uint8_t byte) +{ ++ + ASSERT(cmdp->pc_cmd == PA2_KBD_CMD_ENABLE); + ASSERT(cmdp->pc_counter == 0); + ASSERT(byte == PA2_KBD_REPLY_ACK); @@ -3492,7 +3992,6 @@ index 0000000..9fa8baf + + ASSERT(cmdp->pc_cmd == PA2_KBD_CMD_RESET_DISABLE); + PRINT_DEBUG(PA2_DBG_LOW, "kbd_reset_disable_cmd\n"); -+ /* clear the input buffer XXX */ + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED)); + cmdp->pc_expected_input = PA2_KBD_REPLY_ACK; + cmdp->pc_flags |= PA2_CMD_FLG_EXPECTED; @@ -3539,9 +4038,10 @@ index 0000000..9fa8baf + +/************************************************************/ + -+/* F6 Set Default, resets to power-on condition by clearing the output buffer, -+ * resetting typematic rate/delay and last typematic key and sets default -+ * key types. The keyboard responds with an ACK and continues scanning. ++/* ++ * Set Default, resets to power-on condition by clearing the output buffer, ++ * resetting typematic rate/delay and last typematic key and sets default key ++ * types. The keyboard responds with an ACK and continues scanning. + */ + +static void @@ -3549,10 +4049,10 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ + ASSERT(cmdp->pc_cmd == PA2_KBD_CMD_RESET_ENABLE); + ASSERT(!(fp->pp_state_cur.pss_status & PA2_CTL_STAT_UNLOCKED)); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED)); -+ /* XXX more asserting XXX */ + PRINT_DEBUG(PA2_DBG_MID, "kbd_reset_enable_done\n"); + return; +} @@ -3611,9 +4111,10 @@ index 0000000..9fa8baf + +/************************************************************/ + -+/* FF Reset, Keyboard sends ACK and waits for system to receive it then -+ * begins a program reset and Basic Assurance Test (BAT). Keyboard -+ * returns a one byte completion code then sets default Scan Code Set 2. ++/* ++ * Reset, Keyboard sends ACK and waits for system to receive it then begins a ++ * program reset and Basic Assurance Test (BAT). Keyboard returns a one byte ++ * completion code then sets default Scan Code Set 2. + */ + +static void @@ -3621,6 +4122,7 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ + ASSERT(cmdp->pc_cmd == PA2_KBD_CMD_RESET); + ASSERT(cmdp->pc_counter == 2); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED)); @@ -3658,7 +4160,7 @@ index 0000000..9fa8baf + int ret; + + ASSERT(cmdp->pc_cmd == PA2_KBD_CMD_RESET); -+ PRINT_DEBUG(PA2_DBG_LOW, "kbd_reset_read\n"); ++ PRINT_DEBUG(PA2_DBG_LOW, "kbd_reset_read: 0x%X\n", byte); + ASSERT(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED); + cmdp->pc_flags &= ~PA2_CMD_FLG_EXPECTED; + ret = 0; @@ -3703,6 +4205,10 @@ index 0000000..9fa8baf + +/************************************************************/ + ++/* ++ * Command descriptor table for keyboard commands. ++ */ ++ +static pa2_cmd_des_t pa2_kbd_cmd[] = { +/* 0xED */ { PA2_KBD_CMD_LEDS_SET, "KBD_CMD_LEDS_SET", + 0, 2, 0, PA2_OUTPUT_KBD, @@ -3762,7 +4268,13 @@ index 0000000..9fa8baf + }, +}; + -+/* fwd XX */ ++/** ++ ** Aux cmd done functions. ++ **/ ++ ++/**********************************************************************/ ++ ++/* fwd declatations */ +static int pa2_aux_scale11_set_do(pa2_t *); +static int pa2_aux_scale21_set_do(pa2_t *); +static int pa2_aux_res_set_do(pa2_t *, uint8_t); @@ -3775,11 +4287,6 @@ index 0000000..9fa8baf +static int pa2_aux_default_set_do(pa2_t *); +static int pa2_aux_reset_do(pa2_t *); + -+ -+/** -+ ** Aux cmd done functions. -+ **/ -+ +/**********************************************************************/ + +/* @@ -3889,7 +4396,7 @@ index 0000000..9fa8baf + ret = pa2_aux_append(fp, cmdp, sp->ps_e1_byte1); + break; + -+ case 1: ++ case 1: /* first response byte */ + sp->ps_e1_byte1 = byte; + sp->ps_hv_flgs |= PA2_HV_SYNAP_STATE_E1_BYTE1; + @@ -3912,7 +4419,7 @@ index 0000000..9fa8baf + ret = pa2_aux_append(fp, cmdp, sp->ps_e1_byte2); + break; + -+ case 2: ++ case 2: /* second response byte */ + sp->ps_e1_byte2 = byte; + sp->ps_hv_flgs |= PA2_HV_SYNAP_STATE_E1_BYTE2; + if (cmdp->pc_active == 1) { @@ -3936,6 +4443,7 @@ index 0000000..9fa8baf +pa2_aux_synap_e1_redo( + pa2_t *fp) +{ ++ + PRINT_DEBUG(PA2_DBG_MID, "aux_synap_e1_redo\n"); + return 0; +} @@ -3947,6 +4455,7 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_SYNAP_E2); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED)); + PRINT_DEBUG(PA2_DBG_HIGH, "aux_synap_e2_done\n"); @@ -4060,7 +4569,8 @@ index 0000000..9fa8baf + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_SYNAP_E2); + ASSERT(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED)); -+ PRINT_DEBUG(PA2_DBG_HIGH, "aux_synap_e2_write: 0x%X (%d)\n", byte, cmdp->pc_counter); ++ PRINT_DEBUG(PA2_DBG_HIGH, "aux_synap_e2_write: 0x%X (%d)\n", ++ byte, cmdp->pc_counter); + ret = pa2_ctl_write_aux_pending(fp, cmdp); + if (ret != 0) { + goto out; @@ -4088,7 +4598,7 @@ index 0000000..9fa8baf + break; + + default: -+ pa2_error("XXXXX"); ++ pa2_error("Extra write byte for 0xE2: 0x%X\n", byte); + ret = 1; + break; + } @@ -4109,31 +4619,30 @@ index 0000000..9fa8baf + return ret; +} + ++/**********************************************************************/ ++ +/* -+ * This clears the PS2 scaling bit. ++ * This clears the PS/2 scaling bit. + * Synaptics doesn't honour this bit (for data reporting), but will correctly + * reflect its value for a PA2_AUX_CMD_STATUS_GET. So, if we have the status, + * clear this bit. + */ + -+/* -+ * Note: pp_outbuf_pos is reset for each cmd. As arguments to AUX cmds are -+ * sent via a CCMD_WRITE_AUX, this resets pp_outbuf_pos (and pp_inbuf_pos). -+ * As AUX cmds are counted as output, pp_outbuf_pos will be 1 for AUX cmds -+ * that take no arguments, and one for those that do take arguements (or, -+ * rather, argument as no AUX cmds take more than one input). -+ */ -+ +static void +pa2_aux_scale11_set_done( + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ pa2_state_t *ssp; ++ pa2_aux_state_t *pap; ++ + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_SCALE11_SET); + ASSERT(cmdp->pc_counter == 1); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX)); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED)); -+ ASSERT(!(fp->pp_state_cur.pss_aux_status & PA2_AUX_STAT_SCALING)); ++ ssp = &fp->pp_state_cur; ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; ++ ASSERT(!(pap->pas_aux_status & PA2_AUX_STAT_SCALING)); + PRINT_DEBUG(PA2_DBG_MID, "aux_scale11_set_done\n"); + return; +} @@ -4174,6 +4683,7 @@ index 0000000..9fa8baf + uint8_t byte) +{ + pa2_state_t *ssp; ++ pa2_aux_state_t *pap; + + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_SCALE11_SET); + ASSERT(cmdp->pc_counter == 0); @@ -4184,9 +4694,12 @@ index 0000000..9fa8baf + cmdp->pc_flags &= ~PA2_CMD_FLG_EXPECTED; + ssp = &fp->pp_state_cur; + if (byte == PA2_AUX_REPLY_ACK) { -+ ssp->pss_hv_flgs |= PA2_HV_STATE_AUX_SCALE; -+ ssp->pss_setscale_last = 0; -+ ssp->pss_aux_status &= ~PA2_AUX_STAT_SCALING; ++ if (ssp->pss_aux_index == 0) { ++ ssp->pss_setscale_last = 0; ++ } ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; ++ pap->pas_hv_flgs |= PA2_HV_AUX_STATE_SCALE; ++ pap->pas_aux_status &= ~PA2_AUX_STAT_SCALING; + } + cmdp->pc_counter++; + return 0; @@ -4210,10 +4723,15 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ pa2_state_t *ssp; ++ pa2_aux_state_t *pap; ++ + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_SCALE21_SET); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX)); + ASSERT(cmdp->pc_counter == 1); -+ ASSERT(fp->pp_state_cur.pss_aux_status & PA2_AUX_STAT_SCALING); ++ ssp = &fp->pp_state_cur; ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; ++ ASSERT(pap->pas_aux_status & PA2_AUX_STAT_SCALING); + PRINT_DEBUG(PA2_DBG_MID, "aux_scale21_set_done\n"); + return; +} @@ -4251,6 +4769,7 @@ index 0000000..9fa8baf + uint8_t byte) +{ + pa2_state_t *ssp; ++ pa2_aux_state_t *pap; + + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_SCALE21_SET); + ASSERT(cmdp->pc_counter == 0); @@ -4261,9 +4780,12 @@ index 0000000..9fa8baf + cmdp->pc_flags &= ~PA2_CMD_FLG_EXPECTED; + ssp = &fp->pp_state_cur; + if (byte == PA2_AUX_REPLY_ACK) { -+ ssp->pss_hv_flgs |= PA2_HV_STATE_AUX_SCALE; -+ ssp->pss_setscale_last = 1; -+ ssp->pss_aux_status |= PA2_AUX_STAT_SCALING; ++ if (ssp->pss_aux_index == 0) { ++ ssp->pss_setscale_last = 1; ++ } ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; ++ pap->pas_hv_flgs |= PA2_HV_AUX_STATE_SCALE; ++ pap->pas_aux_status |= PA2_AUX_STAT_SCALING; + } + cmdp->pc_counter++; + return 0; @@ -4288,14 +4810,16 @@ index 0000000..9fa8baf + pa2_cmd_t *cmdp) +{ + pa2_state_t *ssp; ++ pa2_aux_state_t *pap; + + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_RES_SET); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX)); + ASSERT(cmdp->pc_counter == 2); + ssp = &fp->pp_state_cur; -+ ASSERT(ssp->pss_hv_flgs & PA2_HV_STATE_AUX_RES); ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; ++ ASSERT(pap->pas_hv_flgs & PA2_HV_AUX_STATE_RES); + PRINT_DEBUG(PA2_DBG_MID, "aux_res_set_done: 0x%X (%u)\n", -+ ssp->pss_aux_res, cmdp->pc_aux_res_set_seq); ++ pap->pas_aux_res, cmdp->pc_aux_res_set_seq); + return; +} + @@ -4347,6 +4871,7 @@ index 0000000..9fa8baf + uint8_t byte) +{ + pa2_state_t *ssp; ++ pa2_aux_state_t *pap; + int ret; + + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_RES_SET); @@ -4358,18 +4883,17 @@ index 0000000..9fa8baf + + /* + * Might not actually be setting the res, but the preamble for a -+ * synaptic special cmd. Store a copy of the current res -+ * to restore. ++ * Synaptic special command sequcen. + */ + + ssp = &fp->pp_state_cur; -+ ssp->pss_aux_res = byte & 0x3; -+ ssp->pss_hv_flgs |= PA2_HV_STATE_AUX_RES; ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; ++ pap->pas_aux_res = byte & 0x3; ++ pap->pas_hv_flgs |= PA2_HV_AUX_STATE_RES; + cmdp->pc_aux_special_byte <<= 2; + cmdp->pc_aux_special_byte |= (byte & 0x3); + cmdp->pc_aux_res_set_seq++; -+ if (cmdp->pc_aux_res_set_seq > 4) { -+ /* correct? XXX */ ++ if (ssp->pss_aux_index == 0 && cmdp->pc_aux_res_set_seq > 4) { + cmdp->pc_aux_res_set_seq = 4; + } + ret = 0; @@ -4390,17 +4914,23 @@ index 0000000..9fa8baf + pa2_t *fp) +{ + pa2_state_t *ssp; ++ pa2_aux_state_t *pap; + int ret; + + PRINT_DEBUG(PA2_DBG_MID, "aux_res_set_redo\n"); + ssp = &fp->pp_state_cur; -+ ret = pa2_aux_res_set_do(fp, ssp->pss_aux_res); ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; ++ ret = pa2_aux_res_set_do(fp, pap->pas_aux_res); + return ret; +} + +/*******************************************************************/ + -+/* should be moved to a synaptic area XXX */ ++/* ++ * For a Synaptic special command sequence that is reading an information ++ * table, display the name of the command when DEBUG. ++ */ ++ +static void +pa2_synaptic_print_cmd( + pa2_t *fp, @@ -4408,7 +4938,6 @@ index 0000000..9fa8baf +{ + pa2_state_t *ssp; + -+ /* special byte should be inside synaptic area XXX */ + ssp = &fp->pp_state_cur; + switch (cmdp->pc_aux_special_byte) { + case PA2_SYNAP_GET_IDENTIFY: @@ -4469,18 +4998,23 @@ index 0000000..9fa8baf + pa2_cmd_t *cmdp) +{ + pa2_state_t *ssp; ++ pa2_aux_state_t *pap; + pa2_syp_state_t *sp; + + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_STATUS_GET); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX)); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED)); ++ ++ /* ++ * Is this a Synaptic special command sequence? ++ */ ++ + ssp = &fp->pp_state_cur; + if (cmdp->pc_flags & PA2_CMD_FLG_SPECIAL) { + ASSERT(cmdp->pc_aux_res_set_seq == 4); + cmdp->pc_flags &= ~PA2_CMD_FLG_SPECIAL; + cmdp->pc_aux_res_set_seq = 0; + cmdp->pc_aux_special_byte = 0; -+ /* more debug XXX */ + PRINT_DEBUG(PA2_DBG_MID, "aux_get_status_done: for " + "special\n"); + } else { @@ -4491,9 +5025,10 @@ index 0000000..9fa8baf + "aux_get_status_done: mode_byte 0x%X\n", sp->ps_mode_byte); + cmdp->pc_flags &= ~PA2_CMD_FLG_SHORT; + } else { ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; + PRINT_DEBUG(PA2_DBG_MID, + "aux_get_status_done: 0x%X 0x%X 0x%X \n", -+ ssp->pss_aux_status, ssp->pss_aux_res, ssp->pss_aux_sample); ++ pap->pas_aux_status, pap->pas_aux_res, pap->pas_aux_sample); + } + } + return; @@ -4527,21 +5062,20 @@ index 0000000..9fa8baf + if (scp->psc_flgs & + (PA2_CONST_SYNAP_YES | PA2_CONST_SYNAP_PROBED)) { + sp = &ssp->pss_synaptic; -+ PRINT_DEBUG(PA2_DBG_MID, "STATUS: 0x%X 0x%X\n", scp->psc_flgs, sp->ps_mode_byte); + foo = 0; + if (cmdp->pc_aux_res_set_seq == 4) { + foo = 1; + if (!(sp->ps_mode_byte & PA2_SYNAP_BIT_TRANSPARENT)) { -+ PRINT_DEBUG(PA2_DBG_MID, -+ "Setting PA2_CMD_FLG_SPECIAL (0x%X)\n", -+ sp->ps_mode_byte); ++ PRINT_DEBUG(PA2_DBG_MID, ++ "Setting PA2_CMD_FLG_SPECIAL (0x%X)\n", ++ sp->ps_mode_byte); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_SPECIAL)); + cmdp->pc_flags |= PA2_CMD_FLG_SPECIAL; + } + } + + /* -+ * shorter reply XXX ++ * shorter reply? + */ + +#if 1 @@ -4578,6 +5112,7 @@ index 0000000..9fa8baf + pa2_const_t *scp; + pa2_syp_const_t *syp; + pa2_syp_state_t *sp; ++ pa2_aux_state_t *pap; + uint8_t data; + uint8_t counter; + int ret; @@ -4591,92 +5126,100 @@ index 0000000..9fa8baf + cmdp->pc_flags &= ~PA2_CMD_FLG_EXPECTED; + ssp = &fp->pp_state_cur; + syp = &fp->pp_state_const.psc_synap; ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; + sp = &ssp->pss_synaptic; + if (!(cmdp->pc_flags & PA2_CMD_FLG_SPECIAL)) { + switch (counter) { + case 0: /* ACK */ + ASSERT(byte == PA2_AUX_REPLY_ACK); -+ cmdp->pc_expected_input = ssp->pss_aux_status; ++ cmdp->pc_expected_input = pap->pas_aux_status; + cmdp->pc_flags |= PA2_CMD_FLG_EXPECTED; + if (cmdp->pc_active == 0) { -+ ASSERT(ssp->pss_hv_flgs & -+ PA2_HV_STATE_AUX_RES); ++ ASSERT(pap->pas_hv_flgs & ++ PA2_HV_AUX_STATE_RES); + /* if short, then no XXX */ + ret = pa2_aux_append(fp, cmdp, -+ ssp->pss_aux_status); ++ pap->pas_aux_status); + } + break; + + case 1: /* aux status */ + if (cmdp->pc_flags & PA2_CMD_FLG_SHORT) { -+ if (ssp->pss_hv_flgs & PA2_HV_STATE_AUX_SAMP) { -+ ASSERT(ssp->pss_aux_sample == byte); ++ if (pap->pas_hv_flgs & PA2_HV_AUX_STATE_SAMP) { ++ ASSERT(pap->pas_aux_sample == byte); + } -+ ssp->pss_hv_flgs |= PA2_HV_STATE_AUX_SAMP; -+ ssp->pss_aux_sample = byte; ++ pap->pas_hv_flgs |= PA2_HV_AUX_STATE_SAMP; ++ pap->pas_aux_sample = byte; + break; + } + -+ if (ssp->pss_hv_flgs & PA2_HV_STATE_AUX_REMOTE) { ++ if (pap->pas_hv_flgs & PA2_HV_AUX_STATE_REMOTE) { + ASSERT((byte & PA2_AUX_STAT_REMOTE) == -+ (ssp->pss_aux_status & PA2_AUX_STAT_REMOTE)); ++ (pap->pas_aux_status & PA2_AUX_STAT_REMOTE)); + } -+ if (ssp->pss_hv_flgs & PA2_HV_STATE_AUX_ENABLE) { ++ if (pap->pas_hv_flgs & PA2_HV_AUX_STATE_ENABLE) { + ASSERT((byte & PA2_AUX_STAT_ENABLE) == -+ (ssp->pss_aux_status & PA2_AUX_STAT_ENABLE)); ++ (pap->pas_aux_status & PA2_AUX_STAT_ENABLE)); + } -+ if (ssp->pss_hv_flgs & PA2_HV_STATE_AUX_SCALE) { ++ if (pap->pas_hv_flgs & PA2_HV_AUX_STATE_SCALE) { + ASSERT((byte & PA2_AUX_STAT_SCALING) == -+ (ssp->pss_aux_status & PA2_AUX_STAT_SCALING)); ++ (pap->pas_aux_status & PA2_AUX_STAT_SCALING)); + } -+ /* should use pp_tmp_buf here XXX */ -+ ssp->pss_aux_status = byte; -+ ssp->pss_hv_flgs |= PA2_HV_STATE_AUX_REMOTE;; -+ ssp->pss_hv_flgs |= PA2_HV_STATE_AUX_ENABLE;; -+ ssp->pss_hv_flgs |= PA2_HV_STATE_AUX_SCALE;; ++ /* should use pc_tmp_buf here to hold value, only ++ * setting it in our s/w when the cmd completes ++ * successfully. ++ */ ++ pap->pas_aux_status = byte; ++ pap->pas_hv_flgs |= PA2_HV_AUX_STATE_REMOTE;; ++ pap->pas_hv_flgs |= PA2_HV_AUX_STATE_ENABLE;; ++ pap->pas_hv_flgs |= PA2_HV_AUX_STATE_SCALE;; + -+ cmdp->pc_expected_input = ssp->pss_aux_res; ++ cmdp->pc_expected_input = pap->pas_aux_res; + cmdp->pc_flags |= PA2_CMD_FLG_EXPECTED; + + if (cmdp->pc_active == 1) { + break; + } -+ ASSERT(ssp->pss_hv_flgs & PA2_HV_STATE_AUX_RES); -+ ret = pa2_aux_append(fp, cmdp, ssp->pss_aux_res); ++ ASSERT(pap->pas_hv_flgs & PA2_HV_AUX_STATE_RES); ++ ret = pa2_aux_append(fp, cmdp, pap->pas_aux_res); + break; + + case 2: /* resolution */ + if (cmdp->pc_flags & PA2_CMD_FLG_SHORT) { -+ PRINT_DEBUG(PA2_DBG_HIGH, "unknown1: 0x%X\n", byte); ++ PRINT_DEBUG(PA2_DBG_HIGH, "aux_status_read: " ++ "unknown1: 0x%X\n", byte); + break; + } -+ if (ssp->pss_hv_flgs & PA2_HV_STATE_AUX_RES) { -+ ASSERT(ssp->pss_aux_res == byte); ++ if (pap->pas_hv_flgs & PA2_HV_AUX_STATE_RES) { ++ ASSERT(pap->pas_aux_res == byte); + } -+ ssp->pss_hv_flgs |= PA2_HV_STATE_AUX_RES; -+ ssp->pss_aux_res = byte; ++ pap->pas_hv_flgs |= PA2_HV_AUX_STATE_RES; ++ pap->pas_aux_res = byte; + -+ cmdp->pc_expected_input = ssp->pss_aux_sample; ++ cmdp->pc_expected_input = pap->pas_aux_sample; + cmdp->pc_flags |= PA2_CMD_FLG_EXPECTED; + + if (cmdp->pc_active == 1) { + break; + } -+ ASSERT(ssp->pss_hv_flgs & PA2_HV_STATE_AUX_SAMP); -+ ret = pa2_aux_append(fp, cmdp, ssp->pss_aux_sample); ++ ASSERT(pap->pas_hv_flgs & PA2_HV_AUX_STATE_SAMP); ++ ret = pa2_aux_append(fp, cmdp, pap->pas_aux_sample); + break; + -+ case 3: ++ case 3: /* sample */ + if (cmdp->pc_flags & PA2_CMD_FLG_SHORT) { -+ PRINT_DEBUG(PA2_DBG_HIGH, "unknown2: 0x%X\n", byte); ++ PRINT_DEBUG(PA2_DBG_HIGH, "aux_status_read: " ++ "unknown2: 0x%X\n", byte); + break; + } -+ if (ssp->pss_hv_flgs & PA2_HV_STATE_AUX_SAMP) { -+ ASSERT(ssp->pss_aux_sample == byte); -+ PRINT_DEBUG(PA2_DBG_HIGH, "sample: 0x%X 0x%X\n", ssp->pss_aux_sample, byte); ++ if (pap->pas_hv_flgs & PA2_HV_AUX_STATE_SAMP) { ++ ASSERT(pap->pas_aux_sample == byte); ++ PRINT_DEBUG(PA2_DBG_HIGH, "aux_status_read: " ++ "sample: 0x%X 0x%X\n", ++ pap->pas_aux_sample, byte); + } -+ ssp->pss_hv_flgs |= PA2_HV_STATE_AUX_SAMP; -+ ssp->pss_aux_sample = byte; ++ pap->pas_hv_flgs |= PA2_HV_AUX_STATE_SAMP; ++ pap->pas_aux_sample = byte; + break; + + case 4: @@ -4836,6 +5379,15 @@ index 0000000..9fa8baf + break; + + case PA2_SYNAP_GET_MODES: ++ ++ /* ++ * This is documented as always have value 0x3B, but ++ * with later Synaptic h/w this is not always the case. ++ * Leave the ASSERT() against 0x3B only, for now. ++ * Will confirm with Synaptic what the legal values ++ * are... ++ */ ++ + ASSERT(byte == 0x3B); + if (byte != 0x3B) { + PRINT_DEBUG(PA2_DBG_MID, "\t0x3B = 0x%X\n", @@ -4880,7 +5432,6 @@ index 0000000..9fa8baf + + case PA2_SYNAP_GET_UNKNOWN_XXX1: + syp->pcy_unknown11 = byte; -+ /* XXXX have flag for this? XXX */ + cmdp->pc_expected_input = syp->pcy_unknown12; + cmdp->pc_flags |= PA2_CMD_FLG_EXPECTED; + if (cmdp->pc_active == 1) { @@ -4903,7 +5454,6 @@ index 0000000..9fa8baf + } + ASSERT(syp->pcy_hv_flgs & PA2_HV_SYNAP_SER_32); + ASSERT(syp->pcy_hv_flgs & PA2_HV_SYNAP_SER_NB); -+ /* store undeinfed bits somehere XXXX */ + ret = pa2_aux_append(fp, cmdp, data); + break; + @@ -4977,7 +5527,7 @@ index 0000000..9fa8baf + */ + + ASSERT(byte == 0x47 || byte == 0); -+ if (byte == 0x47) { /* magic XXX */ ++ if (byte == 0x47) { + if (fp->pp_init == 1) { + scp = &fp->pp_state_const; + scp->psc_flgs |= PA2_CONST_SYNAP_YES; @@ -5135,7 +5685,6 @@ index 0000000..9fa8baf + case PA2_SYNAP_GET_MODES: + sp->ps_hv_flgs |= PA2_HV_SYNAP_STATE_MODE_BYTE; + sp->ps_mode_byte = byte; -+ PRINT_DEBUG(PA2_DBG_HIGH, "sp->ps_mode_byte = 0x%X\n", sp->ps_mode_byte); + + /* + * If the absolute bit is set, this makes each @@ -5145,7 +5694,8 @@ index 0000000..9fa8baf + if (sp->ps_mode_byte & PA2_SYNAP_BIT_ABS) { + fp->pp_aux_data.pad_format = PA2_AUX_FMT_ABS; + if (sp->ps_mode_byte & PA2_SYNAP_BIT_WMODE) { -+ fp->pp_aux_data.pad_format = PA2_AUX_FMT_ABS_WMODE; ++ fp->pp_aux_data.pad_format = ++ PA2_AUX_FMT_ABS_WMODE; + } + } + break; @@ -5213,6 +5763,7 @@ index 0000000..9fa8baf +pa2_aux_get_status_redo( + pa2_t *fp) +{ ++ + PRINT_DEBUG(PA2_DBG_MID, "aux_get_status_redo\n"); + return 0; +} @@ -5224,12 +5775,16 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ pa2_state_t *ssp; ++ pa2_aux_state_t *pap; ++ + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_STREAM_SET); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX)); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED)); + ASSERT(cmdp->pc_counter == 1); -+ ASSERT(!(fp->pp_state_cur.pss_aux_status & PA2_AUX_STAT_REMOTE)); -+ /* need to assert have remote XXX */ ++ ssp = &fp->pp_state_cur; ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; ++ ASSERT(!(pap->pas_aux_status & PA2_AUX_STAT_REMOTE)); + PRINT_DEBUG(PA2_DBG_MID, "aux_stream_set_done\n"); + return; +} @@ -5245,7 +5800,7 @@ index 0000000..9fa8baf + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_STREAM_SET); + ASSERT(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED)); -+ PRINT_DEBUG(PA2_DBG_MID, "aux_stream_set_cmd\n"); ++ PRINT_DEBUG(PA2_DBG_LOW, "aux_stream_set_cmd\n"); + ret = pa2_ctl_write_aux_pending(fp, cmdp); + if (cmdp->pc_active == 1) { + ret = pa2_reg_cmd_data_write(fp, PA2_INDEX_AUX, @@ -5262,6 +5817,9 @@ index 0000000..9fa8baf + pa2_cmd_t *cmdp, + uint8_t byte) +{ ++ pa2_state_t *ssp; ++ pa2_aux_state_t *pap; ++ + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_STREAM_SET); + ASSERT(cmdp->pc_counter == 0); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX)); @@ -5269,8 +5827,10 @@ index 0000000..9fa8baf + PRINT_DEBUG(PA2_DBG_LOW, "aux_stream_set_read\n"); + ASSERT(byte == PA2_AUX_REPLY_ACK); + cmdp->pc_flags &= ~PA2_CMD_FLG_EXPECTED; -+ fp->pp_state_cur.pss_hv_flgs |= PA2_HV_STATE_AUX_REMOTE;; -+ fp->pp_state_cur.pss_aux_status &= ~PA2_AUX_STAT_REMOTE; ++ ssp = &fp->pp_state_cur; ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; ++ pap->pas_hv_flgs |= PA2_HV_AUX_STATE_REMOTE;; ++ pap->pas_aux_status &= ~PA2_AUX_STAT_REMOTE; + cmdp->pc_counter++; + return 0; +} @@ -5293,6 +5853,7 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_POLL); + ASSERT(cmdp->pc_counter == 1); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX)); @@ -5330,6 +5891,7 @@ index 0000000..9fa8baf + pa2_cmd_t *cmdp, + uint8_t byte) +{ ++ + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_POLL); + ASSERT(cmdp->pc_counter == 0); + ASSERT(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED); @@ -5345,6 +5907,7 @@ index 0000000..9fa8baf +pa2_aux_poll_redo( + pa2_t *fp) +{ ++ + PRINT_DEBUG(PA2_DBG_MID, "aux_poll_redo\n"); + return 0; +} @@ -5356,11 +5919,16 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ pa2_state_t *ssp; ++ pa2_aux_state_t *pap; ++ + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_WRAP_RESET); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX)); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED)); + ASSERT(cmdp->pc_counter == 1); -+ ASSERT(fp->pp_state_cur.pss_aux_wrap_mode == 0); ++ ssp = &fp->pp_state_cur; ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; ++ ASSERT(pap->pas_aux_wrap_mode == 0); + PRINT_DEBUG(PA2_DBG_MID, "aux_wrap_reset_done\n"); + return; +} @@ -5380,7 +5948,8 @@ index 0000000..9fa8baf + cmdp->pc_flags |= PA2_CMD_FLG_EXPECTED; + ret = pa2_ctl_write_aux_pending(fp, cmdp); + if (cmdp->pc_active == 1) { -+ ret = pa2_reg_cmd_data_write(fp, PA2_INDEX_AUX, cmdp->pc_aux_cmd); ++ ret = pa2_reg_cmd_data_write(fp, PA2_INDEX_AUX, ++ cmdp->pc_aux_cmd); + } else { + ret = pa2_aux_ack(fp, cmdp); + } @@ -5393,13 +5962,18 @@ index 0000000..9fa8baf + pa2_cmd_t *cmdp, + uint8_t byte) +{ ++ pa2_state_t *ssp; ++ pa2_aux_state_t *pap; ++ + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_WRAP_RESET); + ASSERT(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED); + ASSERT(cmdp->pc_counter == 0); + PRINT_DEBUG(PA2_DBG_LOW, "aux_wrap_reset_read\n"); + ASSERT(byte == PA2_AUX_REPLY_ACK); + cmdp->pc_flags &= ~PA2_CMD_FLG_EXPECTED; -+ fp->pp_state_cur.pss_aux_wrap_mode = 0; ++ ssp = &fp->pp_state_cur; ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; ++ pap->pas_aux_wrap_mode = 0; + cmdp->pc_counter++; + return 0; +} @@ -5423,7 +5997,6 @@ index 0000000..9fa8baf + * guest. There are two exceptions to this: the "Reset" command and "Reset + * Wrap Mode" command. The mouse treats these as valid commands and does not + * echo them back to the guest. -+ * Credit the above. XXX + * Currently, wrap mode cmds accepted but wrap not supported. XXX + */ + @@ -5432,10 +6005,15 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ pa2_state_t *ssp; ++ pa2_aux_state_t *pap; ++ + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_WRAP_SET); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX)); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED)); -+ ASSERT(fp->pp_state_cur.pss_aux_wrap_mode == 1); ++ ssp = &fp->pp_state_cur; ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; ++ ASSERT(pap->pas_aux_wrap_mode == 1); + PRINT_DEBUG(PA2_DBG_LOW, "aux_wrap_set_done\n"); + return; +} @@ -5455,7 +6033,8 @@ index 0000000..9fa8baf + cmdp->pc_flags |= PA2_CMD_FLG_EXPECTED; + ret = pa2_ctl_write_aux_pending(fp, cmdp); + if (cmdp->pc_active == 1) { -+ ret = pa2_reg_cmd_data_write(fp, PA2_INDEX_AUX, cmdp->pc_aux_cmd); ++ ret = pa2_reg_cmd_data_write(fp, PA2_INDEX_AUX, ++ cmdp->pc_aux_cmd); + } else { + ret = pa2_aux_ack(fp, cmdp); + } @@ -5468,6 +6047,9 @@ index 0000000..9fa8baf + pa2_cmd_t *cmdp, + uint8_t byte) +{ ++ pa2_state_t *ssp; ++ pa2_aux_state_t *pap; ++ + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_WRAP_SET); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX)); + ASSERT(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED); @@ -5475,7 +6057,9 @@ index 0000000..9fa8baf + PRINT_DEBUG(PA2_DBG_LOW, "aux_wrap_set_read\n"); + ASSERT(byte == PA2_AUX_REPLY_ACK); + cmdp->pc_flags &= ~PA2_CMD_FLG_EXPECTED; -+ fp->pp_state_cur.pss_aux_wrap_mode = 1; ++ ssp = &fp->pp_state_cur; ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; ++ pap->pas_aux_wrap_mode = 1; + cmdp->pc_counter++; + return 0; +} @@ -5498,11 +6082,16 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ pa2_state_t *ssp; ++ pa2_aux_state_t *pap; ++ + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_REMOTE_SET); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX)); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED)); + ASSERT(cmdp->pc_counter == 1); -+ ASSERT(fp->pp_state_cur.pss_aux_status & PA2_AUX_STAT_REMOTE); ++ ssp = &fp->pp_state_cur; ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; ++ ASSERT(pap->pas_aux_status & PA2_AUX_STAT_REMOTE); + PRINT_DEBUG(PA2_DBG_MID, "aux_remote_set_done\n"); + return; +} @@ -5517,12 +6106,13 @@ index 0000000..9fa8baf + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_REMOTE_SET); + ASSERT(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED)); -+ PRINT_DEBUG(PA2_DBG_MID, "aux_remote_set_cmd\n"); ++ PRINT_DEBUG(PA2_DBG_LOW, "aux_remote_set_cmd\n"); + cmdp->pc_expected_input = PA2_AUX_REPLY_ACK; + cmdp->pc_flags |= PA2_CMD_FLG_EXPECTED; + ret = pa2_ctl_write_aux_pending(fp, cmdp); + if (cmdp->pc_active == 1) { -+ ret = pa2_reg_cmd_data_write(fp, PA2_INDEX_AUX, cmdp->pc_aux_cmd); ++ ret = pa2_reg_cmd_data_write(fp, PA2_INDEX_AUX, ++ cmdp->pc_aux_cmd); + } else { + ret = pa2_aux_ack(fp, cmdp); + } @@ -5535,6 +6125,9 @@ index 0000000..9fa8baf + pa2_cmd_t *cmdp, + uint8_t byte) +{ ++ pa2_state_t *ssp; ++ pa2_aux_state_t *pap; ++ + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_REMOTE_SET); + ASSERT(cmdp->pc_counter == 0); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX)); @@ -5542,7 +6135,9 @@ index 0000000..9fa8baf + PRINT_DEBUG(PA2_DBG_LOW, "aux_remote_set_read\n"); + ASSERT(byte == PA2_AUX_REPLY_ACK); + cmdp->pc_flags &= ~PA2_CMD_FLG_EXPECTED; -+ fp->pp_state_cur.pss_aux_status |= PA2_AUX_STAT_REMOTE; ++ ssp = &fp->pp_state_cur; ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; ++ pap->pas_aux_status |= PA2_AUX_STAT_REMOTE; + cmdp->pc_counter++; + return 0; +} @@ -5592,7 +6187,8 @@ index 0000000..9fa8baf + cmdp->pc_flags |= PA2_CMD_FLG_EXPECTED; + ret = pa2_ctl_write_aux_pending(fp, cmdp); + if (cmdp->pc_active == 1) { -+ ret = pa2_reg_cmd_data_write(fp, PA2_INDEX_AUX, cmdp->pc_aux_cmd); ++ ret = pa2_reg_cmd_data_write(fp, PA2_INDEX_AUX, ++ cmdp->pc_aux_cmd); + } else { + ret = pa2_aux_ack(fp, cmdp); + } @@ -5627,7 +6223,7 @@ index 0000000..9fa8baf + } + break; + -+ case 1: ++ case 1: /* AUX type */ + if (scp->psc_hv_flgs & PA2_HV_CONST_AUX_TYPE) { + ASSERT(scp->psc_aux_type == byte); + } @@ -5647,6 +6243,7 @@ index 0000000..9fa8baf +pa2_aux_type_get_redo( + pa2_t *fp) +{ ++ + PRINT_DEBUG(PA2_DBG_MID, "aux_type_get_redo\n"); + return 0; +} @@ -5668,6 +6265,7 @@ index 0000000..9fa8baf + pa2_cmd_t *cmdp) +{ + pa2_state_t *ssp; ++ pa2_aux_state_t *pap; + pa2_syp_state_t *sp; + + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_SAMPLE_SET); @@ -5684,9 +6282,10 @@ index 0000000..9fa8baf + PRINT_DEBUG(PA2_DBG_MID, "aux_sample_set_done (special): " + "0x%X\n", sp->ps_mode_byte); + } else { -+ ASSERT(ssp->pss_hv_flgs & PA2_HV_STATE_AUX_SAMP); ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; ++ ASSERT(pap->pas_hv_flgs & PA2_HV_AUX_STATE_SAMP); + PRINT_DEBUG(PA2_DBG_MID, "aux_sample_set_done: 0x%X\n", -+ ssp->pss_aux_sample); ++ pap->pas_aux_sample); + } + return; +} @@ -5712,7 +6311,8 @@ index 0000000..9fa8baf + cmdp->pc_flags |= PA2_CMD_FLG_EXPECTED; + ret = pa2_ctl_write_aux_pending(fp, cmdp); + if (cmdp->pc_active == 1) { -+ ret = pa2_reg_cmd_data_write(fp, PA2_INDEX_AUX, cmdp->pc_aux_cmd); ++ ret = pa2_reg_cmd_data_write(fp, PA2_INDEX_AUX, ++ cmdp->pc_aux_cmd); + } else { + ret = pa2_aux_ack(fp, cmdp); + } @@ -5726,6 +6326,7 @@ index 0000000..9fa8baf + uint8_t byte) +{ + pa2_state_t *ssp; ++ pa2_aux_state_t *pap; + pa2_syp_state_t *sp; + pa2_syp_const_t *syp; + pa_syp_0x28_t *p28p; @@ -5741,6 +6342,7 @@ index 0000000..9fa8baf + ret = 0; + cmdp->pc_flags &= ~PA2_CMD_FLG_EXPECTED; + ssp = &fp->pp_state_cur; ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; + counter = cmdp->pc_counter++; + switch(counter) { + case 0: /* ACK of cmd */ @@ -5765,8 +6367,8 @@ index 0000000..9fa8baf + sp = &fp->pp_state_cur.pss_synaptic; + if (!(cmdp->pc_flags & PA2_CMD_FLG_SPECIAL) || + (sp->ps_mode_byte & PA2_SYNAP_BIT_TRANSPARENT)) { -+ ssp->pss_aux_sample = cmdp->pc_tmp_buf[0]; -+ ssp->pss_hv_flgs |= PA2_HV_STATE_AUX_SAMP; ++ pap->pas_aux_sample = cmdp->pc_tmp_buf[0]; ++ pap->pas_hv_flgs |= PA2_HV_AUX_STATE_SAMP; + } + if (!(cmdp->pc_flags & PA2_CMD_FLG_SPECIAL)) { + break; @@ -5786,7 +6388,8 @@ index 0000000..9fa8baf + if (sp->ps_mode_byte & PA2_SYNAP_BIT_ABS) { + fp->pp_aux_data.pad_format = PA2_AUX_FMT_ABS; + if (sp->ps_mode_byte & PA2_SYNAP_BIT_WMODE) { -+ fp->pp_aux_data.pad_format = PA2_AUX_FMT_ABS_WMODE; ++ fp->pp_aux_data.pad_format = ++ PA2_AUX_FMT_ABS_WMODE; + } + } + break; @@ -5919,6 +6522,7 @@ index 0000000..9fa8baf +pa2_aux_sample_set_redo( + pa2_t *fp) +{ ++ + PRINT_DEBUG(PA2_DBG_MID, "aux_sample_set_redo\n"); + return -1; /* XXXXXXXXXXXXXXXXXXXXX */ +} @@ -5931,13 +6535,15 @@ index 0000000..9fa8baf + pa2_cmd_t *cmdp) +{ + pa2_state_t *ssp; ++ pa2_aux_state_t *pap; + + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_DEV_ENABLE); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX)); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED)); + ASSERT(cmdp->pc_counter == 1); + ssp = &fp->pp_state_cur; -+ ASSERT(ssp->pss_aux_status & PA2_AUX_STAT_ENABLE); ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; ++ ASSERT(pap->pas_aux_status & PA2_AUX_STAT_ENABLE); + PRINT_DEBUG(PA2_DBG_MID, "aux_dev_enable_done\n"); + return; +} @@ -5957,7 +6563,8 @@ index 0000000..9fa8baf + cmdp->pc_flags |= PA2_CMD_FLG_EXPECTED; + ret = pa2_ctl_write_aux_pending(fp, cmdp); + if (cmdp->pc_active == 1) { -+ ret = pa2_reg_cmd_data_write(fp, PA2_INDEX_AUX, cmdp->pc_aux_cmd); ++ ret = pa2_reg_cmd_data_write(fp, PA2_INDEX_AUX, ++ cmdp->pc_aux_cmd); + } else { + ret = pa2_aux_ack(fp, cmdp); + } @@ -5971,6 +6578,7 @@ index 0000000..9fa8baf + uint8_t byte) +{ + pa2_state_t *ssp; ++ pa2_aux_state_t *pap; + + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_DEV_ENABLE); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX)); @@ -5982,8 +6590,9 @@ index 0000000..9fa8baf + cmdp->pc_counter++; + if (byte == PA2_AUX_REPLY_ACK) { + ssp = &fp->pp_state_cur; -+ ssp->pss_hv_flgs |= PA2_HV_STATE_AUX_SCALE; -+ ssp->pss_aux_status |= PA2_AUX_STAT_ENABLE; ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; ++ pap->pas_hv_flgs |= PA2_HV_AUX_STATE_SCALE; ++ pap->pas_aux_status |= PA2_AUX_STAT_ENABLE; + } + return 0; +} @@ -6007,12 +6616,14 @@ index 0000000..9fa8baf + pa2_cmd_t *cmdp) +{ + pa2_state_t *ssp; ++ pa2_aux_state_t *pap; + + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_DEV_DISABLE); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX)); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED)); + ssp = &fp->pp_state_cur; -+ ASSERT(!(ssp->pss_aux_status & PA2_AUX_STAT_ENABLE)); ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; ++ ASSERT(!(pap->pas_aux_status & PA2_AUX_STAT_ENABLE)); + PRINT_DEBUG(PA2_DBG_MID, "aux_dev_disable_done\n"); + return; +} @@ -6032,7 +6643,8 @@ index 0000000..9fa8baf + cmdp->pc_flags |= PA2_CMD_FLG_EXPECTED; + ret = pa2_ctl_write_aux_pending(fp, cmdp); + if (cmdp->pc_active == 1) { -+ ret = pa2_reg_cmd_data_write(fp, PA2_INDEX_AUX, cmdp->pc_aux_cmd); ++ ret = pa2_reg_cmd_data_write(fp, PA2_INDEX_AUX, ++ cmdp->pc_aux_cmd); + } else { + ret = pa2_aux_ack(fp, cmdp); + } @@ -6046,6 +6658,7 @@ index 0000000..9fa8baf + uint8_t byte) +{ + pa2_state_t *ssp; ++ pa2_aux_state_t *pap; + + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_DEV_DISABLE); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX)); @@ -6057,8 +6670,9 @@ index 0000000..9fa8baf + cmdp->pc_counter++; + if (byte == PA2_AUX_REPLY_ACK) { + ssp = &fp->pp_state_cur; -+ ssp->pss_hv_flgs |= PA2_HV_STATE_AUX_SCALE; -+ ssp->pss_aux_status &= ~PA2_AUX_STAT_ENABLE; ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; ++ pap->pas_hv_flgs |= PA2_HV_AUX_STATE_SCALE; ++ pap->pas_aux_status &= ~PA2_AUX_STAT_ENABLE; + } + return 0; +} @@ -6086,23 +6700,24 @@ index 0000000..9fa8baf + int full_reset) +{ + pa2_state_t *ssp; ++ pa2_aux_state_t *pap; + pa2_const_t *scp; + pa2_syp_state_t *sp; + + PRINT_DEBUG_ENTER("\n"); + ssp = &fp->pp_state_cur; -+ ssp->pss_aux_sample = 100; -+ ssp->pss_hv_flgs |= PA2_HV_STATE_AUX_SAMP; -+ ssp->pss_aux_res = 0x02; -+ ssp->pss_hv_flgs |= PA2_HV_STATE_AUX_RES; -+ ssp->pss_aux_status &= ~PA2_AUX_STAT_SCALING; -+ ssp->pss_aux_status &= ~PA2_AUX_STAT_REMOTE; -+ ssp->pss_aux_status &= ~PA2_AUX_STAT_ENABLE; -+ ssp->pss_aux_wrap_mode = 0; -+ /* only if not s/w initial XXX */ -+ ssp->pss_hv_flgs |= PA2_HV_STATE_AUX_REMOTE;; -+ ssp->pss_hv_flgs |= PA2_HV_STATE_AUX_ENABLE;; -+ ssp->pss_hv_flgs |= PA2_HV_STATE_AUX_SCALE;; ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; ++ pap->pas_aux_sample = 100; ++ pap->pas_hv_flgs |= PA2_HV_AUX_STATE_SAMP; ++ pap->pas_aux_res = 0x02; ++ pap->pas_hv_flgs |= PA2_HV_AUX_STATE_RES; ++ pap->pas_aux_status &= ~PA2_AUX_STAT_SCALING; ++ pap->pas_aux_status &= ~PA2_AUX_STAT_REMOTE; ++ pap->pas_aux_status &= ~PA2_AUX_STAT_ENABLE; ++ pap->pas_aux_wrap_mode = 0; ++ pap->pas_hv_flgs |= PA2_HV_AUX_STATE_REMOTE;; ++ pap->pas_hv_flgs |= PA2_HV_AUX_STATE_ENABLE;; ++ pap->pas_hv_flgs |= PA2_HV_AUX_STATE_SCALE;; + + /* + * It is not clear if synatic clears the ABS bit during a reset or @@ -6110,7 +6725,7 @@ index 0000000..9fa8baf + */ + + scp = &fp->pp_state_const; -+ if (scp->psc_flgs & PA2_CONST_SYNAP_YES) { ++ if ((scp->psc_flgs & PA2_CONST_SYNAP_YES) && ssp->pss_aux_index == 0) { + /* + * If last setscale was setscale21, then do not clear bits. + * Discovered via investigation... @@ -6123,7 +6738,8 @@ index 0000000..9fa8baf + sp = &ssp->pss_synaptic; + if (sp->ps_hv_flgs & PA2_HV_SYNAP_STATE_MODE_BYTE) { + sp->ps_mode_byte &= ~PA2_SYNAP_BIT_ABS; -+ fp->pp_aux_data.pad_format = PA2_AUX_FMT_DEFAULT; ++ fp->pp_aux_data.pad_format = ++ PA2_AUX_FMT_DEFAULT; + } + } + } @@ -6133,7 +6749,9 @@ index 0000000..9fa8baf + * reset. + */ + -+ ssp->pss_setscale_last = 0; ++ if (ssp->pss_aux_index == 0) { ++ ssp->pss_setscale_last = 0; ++ } + return; +} + @@ -6142,6 +6760,7 @@ index 0000000..9fa8baf + pa2_t *fp, + pa2_cmd_t *cmdp) +{ ++ + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_DEFAULT_SET); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX)); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED)); @@ -6165,7 +6784,8 @@ index 0000000..9fa8baf + cmdp->pc_flags |= PA2_CMD_FLG_EXPECTED; + ret = pa2_ctl_write_aux_pending(fp, cmdp); + if (cmdp->pc_active == 1) { -+ ret = pa2_reg_cmd_data_write(fp, PA2_INDEX_AUX, cmdp->pc_aux_cmd); ++ ret = pa2_reg_cmd_data_write(fp, PA2_INDEX_AUX, ++ cmdp->pc_aux_cmd); + } else { + ret = pa2_aux_ack(fp, cmdp); + } @@ -6178,6 +6798,7 @@ index 0000000..9fa8baf + pa2_cmd_t *cmdp, + uint8_t byte) +{ ++ + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_DEFAULT_SET); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX)); + ASSERT(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED); @@ -6233,7 +6854,8 @@ index 0000000..9fa8baf + cmdp->pc_flags |= PA2_CMD_FLG_EXPECTED; + ret = pa2_ctl_write_aux_pending(fp, cmdp); + if (cmdp->pc_active == 1) { -+ ret = pa2_reg_cmd_data_write(fp, PA2_INDEX_AUX, cmdp->pc_aux_cmd); ++ ret = pa2_reg_cmd_data_write(fp, PA2_INDEX_AUX, ++ cmdp->pc_aux_cmd); + } else { + ret = pa2_aux_ack(fp, cmdp); + } @@ -6261,6 +6883,7 @@ index 0000000..9fa8baf +pa2_aux_ack_redo( + pa2_t *fp) +{ ++ + PRINT_DEBUG(PA2_DBG_MID, "aux_ack_redo\n"); + return 0; +} @@ -6276,8 +6899,6 @@ index 0000000..9fa8baf + * scaling is 1:1 + * stream mode is selected + * data reporting is disabled -+ * We only peform a reset when initializing the device. XXX -+ * No delay when a non-active guest requests a reset. XXX + */ + +static void @@ -6286,18 +6907,19 @@ index 0000000..9fa8baf + pa2_cmd_t *cmdp) +{ + pa2_state_t *ssp; ++ pa2_aux_state_t *pap; + + ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_RESET); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_PENDING_AUX)); + ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_EXPECTED)); + ASSERT(cmdp->pc_counter == 3); + ssp = &fp->pp_state_cur; -+ ASSERT(ssp->pss_aux_sample == 100); -+ ASSERT(ssp->pss_aux_res == 0x02); -+ ASSERT(!(ssp->pss_aux_status & PA2_AUX_STAT_SCALING)); -+ ASSERT(!(ssp->pss_aux_status & PA2_AUX_STAT_REMOTE)); -+ ASSERT(!(ssp->pss_aux_status & PA2_AUX_STAT_ENABLE)); -+ /* abs mode disabled XXX */ ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; ++ ASSERT(pap->pas_aux_sample == 100); ++ ASSERT(pap->pas_aux_res == 0x02); ++ ASSERT(!(pap->pas_aux_status & PA2_AUX_STAT_SCALING)); ++ ASSERT(!(pap->pas_aux_status & PA2_AUX_STAT_REMOTE)); ++ ASSERT(!(pap->pas_aux_status & PA2_AUX_STAT_ENABLE)); + PRINT_DEBUG(PA2_DBG_MID, "aux_reset_done\n"); + return; +} @@ -6318,7 +6940,8 @@ index 0000000..9fa8baf + cmdp->pc_flags |= PA2_CMD_FLG_EXPECTED; + ret = pa2_ctl_write_aux_pending(fp, cmdp); + if (cmdp->pc_active == 1) { -+ ret = pa2_reg_cmd_data_write(fp, PA2_INDEX_AUX, cmdp->pc_aux_cmd); ++ ret = pa2_reg_cmd_data_write(fp, PA2_INDEX_AUX, ++ cmdp->pc_aux_cmd); + } else { + ret = pa2_aux_ack(fp, cmdp); + } @@ -6360,13 +6983,12 @@ index 0000000..9fa8baf + break; + + case 2: /* device index */ -+ + ASSERT(byte == 0); + pa2_aux_set_state_default(fp, 1); + break; + + default: -+ /* pa2_error() XXX */ ++ ASSERT(0); + ret = 1; + } + return ret; @@ -6385,6 +7007,10 @@ index 0000000..9fa8baf + +/*******************************************************************/ + ++/* ++ * Command descriptor table for AUX commands. ++ */ ++ +static pa2_cmd_des_t pa2_aux_cmd[] = { +/* 0xE1 */ { PA2_AUX_CMD_SYNAP_E1, "AUX_CMD_SYNAP_E1", + 2, 0, 1, PA2_OUTPUT_AUX, @@ -6514,32 +7140,9 @@ index 0000000..9fa8baf + }, +}; + -+#if 0 -+/* -+ * New cmd started before old one finished. This function aborts the "inflight" -+ * cmd state. -+ */ -+ -+static void -+pa2_cmd_abort( -+ pa2_t *fp, -+ pa2_cmd_t *cmdp) -+{ -+ pa2_state_t *ssp; -+ -+ ssp = &fp->pp_state_cur; -+ if (cmdp->pc_flags & PA2_CMD_FLG_KBD) { -+ ssp->pss_mode &= ~PA2_CTL_MODE_DISABLE_KBD; -+ } -+ if (cmdp->pc_flags & PA2_CMD_FLG_AUX) { -+ ssp->pss_mode &= ~PA2_CTL_MODE_DISABLE_AUX; -+ } -+ return; -+} -+#endif -+ +/* -+ * All input/output from cmd has been received/sent, so process its completion. ++ * Called for command completion, for all commands. ++ * All input/output for cmd has been received/sent. Process its completion. + */ + +static void @@ -6557,21 +7160,24 @@ index 0000000..9fa8baf + ASSERT(cmdp->pc_cmd != 0); + ASSERT(cmdp->pc_bytes_in == 0); + ASSERT(cmdp->pc_bytes_out == 0); -+ /* some of the flg bits are cleared by the done routiens - should assert afterwards XXX */ ++ ++ /* ++ * Some of these flag bits are cleared by the done rountes - should ++ * assert afterwards too (missing!). ++ */ ++ + ASSERT((cmdp->pc_flags & ~(PA2_CMD_FLG_CTRL | PA2_CMD_FLG_AUX | + PA2_CMD_FLG_AUX_BYTE | + PA2_CMD_FLG_KBD | + PA2_CMD_FLG_SHORT | + PA2_CMD_FLG_SPECIAL | + PA2_CMD_FLG_WR_ACTIVE)) == 0); -+ PRINT_DEBUG(PA2_DBG_MID, "pa2_cmd_done: %s - 0x%X 0x%X\n", ++ PRINT_DEBUG(PA2_DBG_HIGH, "pa2_cmd_done: %s - 0x%X 0x%X\n", + cmdp->pc_cmd_desp->pcc_name, cmdp->pc_flags, fp->pp_flags); + + /* -+ * An AUX cmd enables a disabled AUX interface, and a KBD cmd -+ * (at least, may be ctl cmds? XXX) enables the KBD interface. -+ * When does this enable actually happen? Start or end of the cmd? -+ * Lets assume end, as that makes more sense. ++ * An AUX cmd re-enables a disabled AUX interface, and a KBD cmd ++ * re-enables the KBD interface. + */ + + ssp = &fp->pp_state_cur; @@ -6600,22 +7206,22 @@ index 0000000..9fa8baf + } + + /* -+ * Either the AUX cmd, or an argument byte. ++ * For an AUX cmd, either completed the cmd byte or an argument byte. + */ + + ASSERT(cmdp->pc_flags & (PA2_CMD_FLG_AUX | PA2_CMD_FLG_AUX_BYTE)); -+ /* assert only one set XXX */ + cmdp->pc_flags &= ~(PA2_CMD_FLG_AUX | PA2_CMD_FLG_AUX_BYTE); + + /* -+ * Aux cmd processing could be done in PA2_CTL_CMD_WRITE_AUX XXX ++ * Aux cmd processing. If no more cmds in the AUX sequence, then ++ * the command is completed. + */ + + ASSERT(cmdp->pc_aux_seq > 0); + if (cmdp->pc_aux_seq > 0) { + cmdp->pc_aux_seq--; + } else { -+ pa2_error("XXXX\n"); ++ pa2_error("pa2_cmd_done: Unexpected zero pc_aux_seq\n"); + } + if (cmdp->pc_aux_seq == 0) { + ASSERT(cmdp->pc_aux_func_done != NULL); @@ -6628,12 +7234,30 @@ index 0000000..9fa8baf + cmdp->pc_aux_cmd = 0; + ASSERT(cmdp->pc_flags == 0); + } else { ++ ++ /* ++ * More byte(s) expected for AUX command sequence. Mark this ++ * in the flags. ++ */ ++ + cmdp->pc_flags |= PA2_CMD_FLG_AUX_BYTE; + } + goto clean1; + +clean: + cmdp->pc_flags = 0; ++ ++ /* ++ * If it is other than a 're-direct' command, then clear the index. ++ */ ++ ++ if (cmdp->pc_cmd != 0x90 && cmdp->pc_cmd != 0x91 && ++ cmdp->pc_cmd != 0x92 && cmdp->pc_cmd != 0x93) { ++ PRINT_DEBUG(PA2_DBG_HIGH, "pa2_cmd_done: Clearing index: %d\n", ++ ssp->pss_aux_index); ++ ssp->pss_aux_index = 0; ++ } ++ +clean1: + ASSERT(cmdp->pc_cmd_desp != NULL); + cmdp->pc_cmd = 0; @@ -6649,16 +7273,11 @@ index 0000000..9fa8baf + cmdp->pc_func_redo = NULL; + + /* -+ * Keyboard completion separated out? XXX -+ */ -+ -+ -+ /* + * If cmd started inactive, but device is now active, then need + * to redo. + */ + -+ if (cmdp->pc_flags == 0) { /* XXXX nasty XXX */ ++ if (cmdp->pc_flags == 0) { + index = cmdp - &fp->pp_cmds[0]; + if (active == 0 && fp->pp_active[index] == 1) { + ASSERT(redo != NULL); @@ -6670,12 +7289,22 @@ index 0000000..9fa8baf + return; +} + ++/* ++ * Abort a command. ++ * This occurs when a guest starts a new command without waiting for the ++ * current one to complete. This can be because of a bug in the guest driver, ++ * a bug in this driver, or the guest timed out waiting for a reponse and so ++ * starts a new command. ++ * Aborting a command is clearing its state. No interaction with the underlying ++ * h/w - when it sees a new command, it will abort any in progress. ++ */ ++ +static void +pa2_cmd_abort( + pa2_t *fp, + pa2_cmd_t *cmdp) +{ -+ cmdp->pc_cmd = 0; /* PA2_CTL_CMD_NULL XXX */ ++ cmdp->pc_cmd = PA2_CTL_CMD_NULL; + cmdp->pc_active = 0; + cmdp->pc_bytes_in = 0; + cmdp->pc_bytes_out = 0; @@ -6704,7 +7333,12 @@ index 0000000..9fa8baf +} + +/* -+ * Taken given KBD cmd and prepare to run. ++ * Called when a KBD cmd is issued. ++ * A KBD command is detected when there is a write to the data port, and no ++ * controller/AUX command in progress (that is, there is no in progress cmd ++ * that is expecting data). ++ * Load the KBD command from the command descriptor table, and return to the ++ * caller. + */ + +static pa2_cmd_t * @@ -6750,7 +7384,12 @@ index 0000000..9fa8baf + ASSERT(cmdp->pc_aux_cmd == 0); + ASSERT(cmdp->pc_aux_p28 == NULL); + -+ if (cmdp->pc_cmd != 0) { /* no-op XXX */ ++ /* ++ * If there is a current command in this slot, then abort it - we're ++ * starting a new one. ++ */ ++ ++ if (cmdp->pc_cmd != 0) { + pa2_cmd_abort(fp, cmdp); + } + @@ -6758,15 +7397,9 @@ index 0000000..9fa8baf + cmdp->pc_cmd_desp = ccp; + cmdp->pc_counter = 0; + cmdp->pc_active = fp->pp_active[PA2_INDEX_KBD]; -+ + cmdp->pc_aux_cmd = 0; + cmdp->pc_aux_p28 = NULL; + -+ /* -+ * Clear any bad state that may be present due to a bug in this file, -+ * or a bad guest. -+ */ -+ + cmdp->pc_func_done = ccp->pcc_func_done; + cmdp->pc_func_cmd = ccp->pcc_func_cmd; + cmdp->pc_func_write = ccp->pcc_func_write; @@ -6783,7 +7416,7 @@ index 0000000..9fa8baf + cmdp->pc_flags |= PA2_CMD_FLG_INPUT; + + /* -+ * No ack for an echo. ++ * KBD cmds are ACK'ed, but there is no ack for an echo. Assert this. + */ + + ASSERT(cmdp->pc_cmd != PA2_KBD_CMD_ECHO || @@ -6797,7 +7430,12 @@ index 0000000..9fa8baf +} + +/* -+ * Taken given KBD cmd and prepare to run. ++ * Called when a AUX cmd is issued. ++ * An AUX command is detected when there is a write to the data port, and a ++ * PA2_CTL_CMD_WRITE_AUX is in progress. That is, expecting cmd/data for ++ * the AUX due to a preceeding ctrl command. ++ * Load the AUX command from the command descriptor table, and return to the ++ * caller. + */ + +static pa2_cmd_t * @@ -6837,7 +7475,6 @@ index 0000000..9fa8baf + ~(PA2_CMD_FLG_OUTPUT | PA2_CMD_FLG_PENDING_AUX))); + ASSERT(cmdp->pc_bytes_in == 0); + ASSERT(cmdp->pc_func_done != NULL); -+ /*ASSERT(!(cmdp->pc_flags & PA2_CMD_FLG_ACK)); XXX */ + ASSERT(cmdp->pc_aux_seq == 0); + ASSERT(cmdp->pc_func_read == NULL); + ASSERT(cmdp->pc_aux_func_done == NULL); @@ -6902,7 +7539,10 @@ index 0000000..9fa8baf +} + +/* -+ * Load a cmd directed at the controller. ++ * Called when a CTRL cmd is issued. ++ * A CTRL command is detected when there is a write to the command port. ++ * Load the CTRL command from the command descriptor table, and return to the ++ * caller. + */ + +static pa2_cmd_t * @@ -6916,7 +7556,7 @@ index 0000000..9fa8baf + uint i; + + /* -+ * For now, dumb linear search. Will speed up later. XXX ++ * For now, a linear search. Can speed up later, but is not critical. + */ + + ccp = NULL; @@ -6930,7 +7570,6 @@ index 0000000..9fa8baf + } + if (ccp == NULL) { + pa2_error("ctl_cmd_load: bad cmd: 0x%X\n", cmd); -+ /* abort any current cmds? XXX */ + cmdp = NULL; + goto out; + } @@ -6950,7 +7589,8 @@ index 0000000..9fa8baf + if (ccp->pcc_cmd != PA2_CTL_CMD_WRITE_AUX) { + ASSERT(cmdp->pc_flags == 0); + if (cmdp->pc_flags != 0) { -+ PRINT_DEBUG(PA2_DBG_HIGH, "pc_flags: 0x%X\n", cmdp->pc_flags); ++ PRINT_DEBUG(PA2_DBG_HIGH, "pc_flags: 0x%X\n", ++ cmdp->pc_flags); + } + } + ASSERT(cmdp->pc_func_done == NULL); @@ -6984,7 +7624,9 @@ index 0000000..9fa8baf + cmdp->pc_counter = 0; + + /* -+ * May be part of a sequence, so ensure only unwanted flags are cleared. ++ * May be part of a sequence (either AUX cmd sequence, or a Synaptic ++ * special cmd seq), so ensure only unwanted flags are cleared for ++ * a write to the AUX. + */ + + if (cmdp->pc_cmd == PA2_CTL_CMD_WRITE_AUX) { @@ -7001,11 +7643,7 @@ index 0000000..9fa8baf + cmdp->pc_func_read = ccp->pcc_func_read; + cmdp->pc_aux_p28 = NULL; + -+ /* -+ * It is incorrect to set pc_active, but leave for now. XXX -+ */ -+ -+ cmdp->pc_active = 1; /* XXX */ ++ cmdp->pc_active = 1; + if (fp->pp_active[PA2_INDEX_AUX] == 0 && + fp->pp_active[PA2_INDEX_KBD] == 0) { + cmdp->pc_active = 0; @@ -7037,9 +7675,9 @@ index 0000000..9fa8baf +} + +/* -+ * Run input through current command. -+ * Consume any expected ACK/input, and complete cmd if no more input/output -+ * expected. ++ * Called when data is received from the h/w. ++ * The caller identifies the command the data is for, and this function runs the ++ * data through the state machine for the given command. + */ + +int @@ -7052,7 +7690,8 @@ index 0000000..9fa8baf + int ret; + + /* -+ * Expecting ack? ++ * If marked as expecting an ACK, then the data received should be an ++ * ACK. Otherwise, should be expecting input. + */ + + PRINT_DEBUG_ENTER(": 0x%X 0x%X\n", status, data); @@ -7065,11 +7704,6 @@ index 0000000..9fa8baf + pa2_error("cmd_process: didn't receive expected ack: 0x%X\n", + data); + } else if (cmdp->pc_flags & PA2_CMD_FLG_INPUT) { -+ /* -+ * Should sort this out; ACK isn't countered as an input -+ * byte. XXXX This makes the code uglier than it needs to be. -+ */ -+ + ASSERT(cmdp->pc_bytes_in != 0); + ASSERT(cmdp->pc_cmd != 0); + if (cmdp->pc_bytes_in == 0) { @@ -7080,7 +7714,9 @@ index 0000000..9fa8baf + } + + /* -+ * Notify of the read. ++ * Run data through cmd's read function. ++ * If the command is running against the AUX port, then pass the ++ * byte to the AUX read function. + */ + + ret = 1; @@ -7129,14 +7765,29 @@ index 0000000..9fa8baf +} + +/* -+ * Read interrupt records, returning the number read. -+ * Can be called from our interrupt handler, or when out of records reading -+ * the status or data ports. -+ * "num" is the number of records to read - 0 means all. -+ */ -+ -+/* -+ * Only needed for debug. XXX ++ * AUX data received from the h/w, and there is no AUX cmd in progress. ++ * This means the data is a positional report. This function validates ++ * the input, but has no other action. It should be changed to be a no-op ++ * for non-DEBUG. ++ * When a new AUX device is attached it performs a self-test and the transmits ++ * the announcment sequence of 2 bytes; 0xAA 0x00 Some controllers see these ++ * two bytes, followed by silence, and conclude an AUX device has been attached ++ * and proceed to initialize it. This initialization causes other attached AUX ++ * devices to be reset and re-initialized by the ctrl. As the ctrl does not ++ * know about advanced h/w, this initialization causes extended features to be ++ * disabled (ie. not re-enabled). It is believed this is what happens with ++ * Dell and a port replicator; when a PS/2 mouse is attached to the replicator ++ * the touchpad loses its 'special' features. With the ctrl trapping the ++ * announcment seq, and initializing and merging the AUX devices, allows legacy ++ * software to support hot-plug multiple AUX devices. ++ * If the ctrl is not trapping the 0xAA 0x00 sequence, and passing on to ++ * OS, then the AUX driver can use it to detected hot-plug PS/2 AUX device and ++ * perform initialization. As this is handled in the OS, AUX drivers should ++ * know extended features of devcies (eg. absolute mode of touchpads) and ++ * continue to support them in the presence of new h/w. Detection code for ++ * the announce sequence should be placed in this function (beaware, 0xAA 0x00 ++ * is a valid start of a positional data report, so extra checks would be ++ * needed - such as a delay). + */ + +static void @@ -7149,7 +7800,6 @@ index 0000000..9fa8baf + pa2_aux_data_t *ap; + + PRINT_DEBUG(PA2_DBG_MID, "pa2_aux_data: 0x%X\n", data); -+ + ssp = &fp->pp_state_cur; + sp = &ssp->pss_synaptic; + ap = &fp->pp_aux_data; @@ -7283,8 +7933,10 @@ index 0000000..9fa8baf +} + +/* -+ * Data from KBD; key makes and breaks. -+ * Returns whether to pass the make/break to the guest. 1 = yes, 0 = no ++ * KBD data received from the h/w, and there is no KBD cmd in progress. ++ * This means the data is a key make/break report. This function updates ++ * the key state as tracked by this driver, and checks if a key make ++ * triggers a key binding match. + */ + +static uint @@ -7301,8 +7953,6 @@ index 0000000..9fa8baf + fp->pp_key_esc = 1; + break; + -+ /* need to handle E1, etc XXX */ -+ + default: + esc = fp->pp_key_esc; + if (fp->pp_key_esc) { @@ -7333,7 +7983,7 @@ index 0000000..9fa8baf + * If num is zero, reads all available records from kernel, otherwise reads + * up to 'num' records. + * Returns the number of records read, not including any 'forced' record (a -+ * forced recored being one with status only - no data available for given ++ * forced record being one with status only - no data available for given + * device). + */ + @@ -7365,6 +8015,11 @@ index 0000000..9fa8baf + num = UINT_MAX; + } + ++ /* ++ * Read records from kernel in batches that fit into the ++ * prec[] array. ++ */ ++ + count = 0; + phd.ph_records = &prec[0]; + do { @@ -7384,8 +8039,9 @@ index 0000000..9fa8baf + } + + /* -+ * Is the kernel driver telling us to lose -+ * focus? ++ * Is the kernel driver telling us to lose focus? ++ * This is old code that is likely not needed, and hasn't ++ * been maintained. Should be removed. + */ + + if (phd.ph_focus != 0 && fp->pp_losing_focus[index] == 0) { @@ -7476,7 +8132,7 @@ index 0000000..9fa8baf + + /* + * If the record returned was a "forced" record (no data -+ * indicated in the status) then we're emptied the kernel's ++ * indicated in the status) then we've emptied the kernel's + * buffer and should read no more. + */ + @@ -7497,14 +8153,15 @@ index 0000000..9fa8baf + * lose focus, then do it. + */ + -+ if (fp->pp_losing_focus[index] == 1 && /* XXX */ ++ if (fp->pp_losing_focus[index] == 1 && + fp->pp_cmds[index].pc_cmd == 0 && + !(fp->pp_flags & PA2_FLG_KBD_IRQ) && + !(fp->pp_flags & PA2_FLG_AUX_IRQ)) { + PRINT_DEBUG(PA2_DBG_HIGH, "Telling kernel we're " + "giving up focus\n"); + byte = 0; -+ if (ioctl(fp->pp_fd[PA2_INDEX_CTL], PA2_IOCTL_GRAB, &byte) == -1) { ++ if (ioctl(fp->pp_fd[PA2_INDEX_CTL], PA2_IOCTL_GRAB, ++ &byte) == -1) { + PRINT_DEBUG(PA2_DBG_HIGH, "ioctl error\n"); + } + qemu_set_fd_handler(fp->pp_fd[0], NULL, NULL, fp); @@ -7519,10 +8176,10 @@ index 0000000..9fa8baf +} + +/* -+ * Report the last unreported status read. ++ * Report the last unreported status read to the log. + * This is used to reduce the large number of status reads from a guest + * (often, polling for data or waiting for input buf bit to clear). Only -+ * used/needed when compiled debug. ++ * of meaning when compiled DEBUG. + */ + +static void @@ -7554,12 +8211,20 @@ index 0000000..9fa8baf + } + +out: -+ return; -+#else -+ return; +#endif /* PA2_DEBUG */ ++ return; +} + ++/* ++ * Read the status register. ++ * If the index specifies KBD or AUX, then only return a status register ++ * related to the given device. ++ * If WILD, then report any available status register (from either device). ++ * IF RAW, then access underlying h/w for status register (needed for ++ * 'internal' (ie. _do() cmds) that need to poll checking for input buffer ++ * empty bit, etc). ++ */ ++ +static uint32_t +pa2_status_read( + pa2_t *fp, @@ -7600,13 +8265,11 @@ index 0000000..9fa8baf + (fp->pp_flags & PA2_FLG_KBD_IRQ)) { + php = &fp->pp_irqbuf[PA2_INDEX_KBD]; + ASSERT(php->ph_start != php->ph_end); -+ /* ASSERT(fp->pp_active[PA2_INDEX_KBD] == 1); */ + } + if (index != PA2_INDEX_KBD && + (fp->pp_flags & PA2_FLG_AUX_IRQ)) { + php = &fp->pp_irqbuf[PA2_INDEX_AUX]; + ASSERT(php->ph_start != php->ph_end); -+ /* ASSERT(fp->pp_active[PA2_INDEX_AUX] == 1); */ + } + if (php != NULL && php->ph_start != php->ph_end) { + break; @@ -7680,7 +8343,6 @@ index 0000000..9fa8baf + goto out; + } + -+ +out: +#if defined(PA2_DEBUG) + /* @@ -7721,6 +8383,8 @@ index 0000000..9fa8baf + +/* + * Function called when guest reads the status register. ++ * As do not know what device they are interested in, pass WILD to our ++ * generic status reg read function. + */ + +static uint32_t @@ -7735,6 +8399,13 @@ index 0000000..9fa8baf + return pa2_status_read(fp, PA2_INDEX_WILD); +} + ++/* ++ * Read any availble data. ++ * If the index specifies KBD or AUX, then only return data related to the ++ * given device. ++ * If WILD, then report any available data (from either device). ++ */ ++ +static uint32_t +pa2_data_read( + pa2_t *fp, @@ -7832,16 +8503,9 @@ index 0000000..9fa8baf + * Currently, the above always succeeds. When it can fail, + * (no data, as indicated by status register bits) we'll + * return the last data. -+ * Should return our calcualted data. XXXX + */ + + data = fp->pp_data_last; -+ -+ /* -+ * Should only be updating this for a guest call, not an -+ * internal one. XXXX -+ */ -+ + status = ssp->pss_status_last; /* ->pp_status? XXX */ + break; + } while (1); @@ -7873,7 +8537,7 @@ index 0000000..9fa8baf + pa2_irq_lower(fp); + + /* -+ * Raise an interrupt associated with the next interrupt. ++ * Raise an interrupt if required. + */ + + pa2_irq_raise(fp); @@ -7881,6 +8545,12 @@ index 0000000..9fa8baf + return data; +} + ++/* ++ * Function called when guest reads the data register. ++ * As do not know what device they are interested in, pass WILD to our ++ * generic data reg read function. ++ */ ++ +static uint32_t +pa2_guest_data_read( + void *opq, @@ -7893,6 +8563,12 @@ index 0000000..9fa8baf + return pa2_data_read(fp, PA2_INDEX_WILD); +} + ++/* ++ * Write data to output register. ++ * This function examines the in progress commands to determine the type of ++ * write for our state machine. ++ */ ++ +static void +pa2_data_write( + pa2_t *fp, @@ -7919,6 +8595,7 @@ index 0000000..9fa8baf + * (really, the same case as the first). + */ + ++ ret = 0; + cmdp = NULL; + for (index = 0; index < PA2_OUTPUT_MAX; index++) { + if (fp->pp_cmds[index].pc_cmd == 0) { @@ -7935,7 +8612,9 @@ index 0000000..9fa8baf + + /* + * If no command expecting bytes, then this is a KBD cmd. -+ * Currently, an unknown cmd is ignored. It should be NAK'ed. XXX ++ * Currently, an unknown cmd is ignored. It probably should first be ++ * errored with PA2_KBD_REPLY_RESEND, and if the client resends the ++ * same cmd then return PA2_KBD_REPLY_OVERUN2 (0xFF). + */ + + byte = data; @@ -7958,8 +8637,8 @@ index 0000000..9fa8baf + ASSERT(cmdp == &fp->pp_cmds[PA2_OUTPUT_AUX]); + + /* -+ * Currently, an unknown cmd is ignored. It should be -+ * NAK'ed. XXX ++ * Currently, an unknown cmd is ignored. It probably should ++ * be errored with PA2_AUX_REPLY_RESEND. + */ + + if (cmdp->pc_aux_cmd == 0) { @@ -7976,10 +8655,9 @@ index 0000000..9fa8baf + } + + /* -+ * If this is not a requested write to the AUX, then is -+ * an argumemnt to a previous AUX cmd. -+ * This looks ugly. XXX -+ * This is where the func's data write should be called. XXX ++ * If this is not a requested write to the AUX, then it is ++ * an argumemnt to a previous AUX cmd (ie. an argument to ++ * an AUX command). + */ + + ASSERT(cmdp->pc_flags & PA2_CMD_FLG_AUX_BYTE); @@ -8016,6 +8694,10 @@ index 0000000..9fa8baf + } + } + ++ /* ++ * Has all the expected output been seen? ++ */ ++ + if ((cmdp->pc_flags & PA2_CMD_FLG_OUTPUT) && + cmdp->pc_bytes_out == 0) { + cmdp->pc_flags &= ~PA2_CMD_FLG_OUTPUT; @@ -8023,7 +8705,7 @@ index 0000000..9fa8baf + "write_data: Out phase completed\n"); + + /* -+ * If no input need, then completed. ++ * If no input expected for this, then completed. + */ + + if (!(cmdp->pc_flags & (PA2_CMD_FLG_INPUT | @@ -8041,6 +8723,10 @@ index 0000000..9fa8baf + return; +} + ++/* ++ * Function called when guest writes to the data register. ++ */ ++ +static void +pa2_guest_data_write( + void *opq, @@ -8064,6 +8750,7 @@ index 0000000..9fa8baf + pa2_t *fp, + uint32_t cmd) +{ ++ pa2_state_t *ssp; + pa2_cmd_t *cmdp; + int ret; + uint8_t byte; @@ -8072,16 +8759,17 @@ index 0000000..9fa8baf + pa2_report_last_status(fp); + + /* -+ * Found a matching command? -+ * If not, write the byte to the command register - if we're active, -+ * that way something right might happen... -+ * Hmm, probably should NACK it. XXX ++ * This should be a new ctrl command. Search the ctrl command table, ++ * and load the cmd returning ptr to the cmd structure. ++ * If no matching command found, then ignore command. As ctrl ++ * commands are not ACKed, cannot generate an error. + */ + + ASSERT(cmd <= 0xFF); + byte = cmd; + cmdp = pa2_ctl_cmd_load(fp, byte); + ASSERT(cmdp != NULL); ++ ssp = &fp->pp_state_cur; + if (cmdp == NULL) { + if (fp->pp_active[PA2_INDEX_KBD] == 1 || + fp->pp_active[PA2_INDEX_AUX] == 1) { @@ -8094,13 +8782,14 @@ index 0000000..9fa8baf + } + + /* -+ * Before calling func, mark cmd as write active. If we're -+ * not active (pp_active) then cmd could complete in a -+ * simulated read and cmd completion would run before this -+ * returned - not what is wanted/required. ++ * Before calling func, mark cmd as write active. If we're not active ++ * (pp_active == 0 - ie. do not have focus) then cmd could complete in a ++ * simulated read and cmd completion would run before this returned - ++ * not what is wanted/required. PA2_CMD_FLG_WR_ACTIVE protects ++ * against this. + */ + -+ fp->pp_state_cur.pss_status |= PA2_STAT_CMD; ++ ssp->pss_status |= PA2_STAT_CMD; + ASSERT(cmdp->pc_func_cmd != NULL); + cmdp->pc_flags |= PA2_CMD_FLG_WR_ACTIVE; + ret = cmdp->pc_func_cmd(fp, cmdp); @@ -8137,6 +8826,10 @@ index 0000000..9fa8baf + return; +} + ++/* ++ * Function called when guest writes to the command register. ++ */ ++ +static void +pa2_guest_cmd_write( + void *opq, @@ -8153,6 +8846,8 @@ index 0000000..9fa8baf + +/* + * Interrupt from i8042. ++ * Called from the qemu_set_fd_handler() when there is data available in ++ * the kernel to read. + */ + +static void @@ -8164,7 +8859,6 @@ index 0000000..9fa8baf + + /* + * Read interrupt records. If none found, then nothing else to do. -+ * Remember first free record, so can examine it later. + */ + + PRINT_DEBUG_ENTER("\n"); @@ -8177,7 +8871,9 @@ index 0000000..9fa8baf + +/* + * Wait for input buffer to become empty. -+ * Need to check timeouts...XXX ++ * This is used internally to test when the h/w has consumed the given ++ * input (cannot write until this is clear). ++ * Do not wait forever; return non-zero if timeout. + */ + +static int @@ -8202,6 +8898,12 @@ index 0000000..9fa8baf + return ret; +} + ++/* ++ * Wait for output buffer to become full (for non-AUX data). ++ * This is used internally to test when the h/w has data available to read. ++ * Do not wait forever; return non-zero if timeout. ++ */ ++ +static int +pa2_wait_on_output_buf( + pa2_t *fp) @@ -8225,6 +8927,12 @@ index 0000000..9fa8baf + return ret; +} + ++/* ++ * Wait for output buffer to become full (for AUX data). ++ * This is used internally to test when the h/w has data available to read. ++ * Do not wait forever; return non-zero if timeout. ++ */ ++ +static int +pa2_wait_on_aux_output_buf( + pa2_t *fp) @@ -8248,6 +8956,14 @@ index 0000000..9fa8baf + return ret; +} + ++/* ++ * Write given command byte to command register. ++ * This is used internally to send commands to the cmd reg. ++ * Before writing, wait for the inoput buffer to be marked as empty, but ++ * even if that times out send the command anyway. Writing can help get the ++ * h/w out of a bad state. ++ */ ++ +static int +pa2_cmd_write_do( + pa2_t *fp, @@ -8263,12 +8979,19 @@ index 0000000..9fa8baf + ret = pa2_wait_on_input_buffer(fp); + ASSERT(ret == 0); + pa2_cmd_write(fp, cmd); -+#if 0 -+ ret |= pa2_wait_on_input_buffer(fp); -+#endif + return ret; +} + ++/* ++ * Write to data port, waiting for the input buffer flag to become clear ++ * before doing so. ++ * But send away, even if input buffer flag doesn't clear, as sending can help ++ * to get the h/w out of a bad state. ++ * It is paraniod to wait on the input buffer after the write (as the next ++ * write should wait before writing), and should be removed after testing withn ++ * it gone. ++ */ ++ +static int +pa2_data_write_do( + pa2_t *fp, @@ -8276,19 +8999,18 @@ index 0000000..9fa8baf +{ + int ret; + -+ /* -+ * Send away, even if input buffer flag doesn't clear. -+ * Sending can help to get the h/w out of a bad state. -+ */ -+ + ret = pa2_wait_on_input_buffer(fp); + pa2_data_write(fp, data); -+ /* EXPLAIN XXXXXX */ + ret |= pa2_wait_on_input_buffer(fp); + ASSERT(ret == 0); + return ret; +} + ++/* ++ * Read from output port, returning result in buffer byte. ++ * Return non-zero on error. ++ */ ++ +static int +pa2_output_read_do( + pa2_t *fp, @@ -8304,6 +9026,11 @@ index 0000000..9fa8baf + return ret; +} + ++/* ++ * Read from AUX output port, returning result in buffer byte. ++ * Return non-zero on error. ++ */ ++ +static int +pa2_output_aux_read_do( + pa2_t *fp, @@ -8321,7 +9048,7 @@ index 0000000..9fa8baf + +/* + * Send an AUX cmd, and consume the reply ACK. -+ * Returns 0 on success, and 1 on failure. ++ * Returns 0 on success, and non-zero on failure. + */ + +static int @@ -8443,7 +9170,7 @@ index 0000000..9fa8baf + ASSERT(!(scp->psc_hv_flgs & PA2_HV_CONST_CTL_VERSION)); + ASSERT(!(scp->psc_flgs & PA2_CONST_NO_CTL_VERSION)); + scp->psc_flgs |= PA2_CONST_NO_CTL_VERSION; -+ ret = 0; /* XXX */ ++ ret = 0; + } + } + return ret; @@ -8629,10 +9356,6 @@ index 0000000..9fa8baf +} + +/* -+ * Test the controller can talk to the keyboard. -+ */ -+ -+/* + * Set LEDS to given state. + */ + @@ -9003,6 +9726,7 @@ index 0000000..9fa8baf + pa2_t *fp) +{ + pa2_state_t *ssp; ++ pa2_aux_state_t *pap; + pa2_cmd_t *cmdp; + pa2_const_t *scp; + pa2_syp_state_t *sp; @@ -9019,6 +9743,7 @@ index 0000000..9fa8baf + special = 0; + ssp = &fp->pp_state_cur; + sp = &ssp->pss_synaptic; ++ pap = &ssp->pss_aux[ssp->pss_aux_index]; + scp = &fp->pp_state_const; + if (scp->psc_flgs & (PA2_CONST_SYNAP_YES | PA2_CONST_SYNAP_PROBED)) { + cmdp = &fp->pp_cmds[PA2_OUTPUT_AUX]; @@ -9063,34 +9788,37 @@ index 0000000..9fa8baf + if (ret != 0) { + break; + } -+ flags = ssp->pss_hv_flgs; ++ flags = pap->pas_hv_flgs; + switch (state) { + /* handle when special cmds XXX */ + + case 2: -+ ASSERT(special || (flags & PA2_HV_STATE_AUX_SAMP)); ++ ASSERT(special || (flags & PA2_HV_AUX_STATE_SAMP)); + /* FALLTRHOUGH */ + + case 1: + if (short_form) { + /* unknown XXX */ + } else { -+ ASSERT(special || (flags & PA2_HV_STATE_AUX_RES)); ++ ASSERT(special || (flags & PA2_HV_AUX_STATE_RES)); + } + /* FALLTRHOUGH */ + + case 0: + if (short_form) { -+ /*ASSERT(flags & PA2_HV_STATE_AUX_SAMP); mode_byte XXX */ ++#if 0 ++ ASSERT(flags & PA2_HV_AUX_STATE_SAMP); ++#endif + break; + } -+ ASSERT(special || (flags & PA2_HV_STATE_AUX_REMOTE)); -+ ASSERT(special || (flags & PA2_HV_STATE_AUX_ENABLE)); -+ ASSERT(special || (flags & PA2_HV_STATE_AUX_SCALE)); ++ ASSERT(special || (flags & PA2_HV_AUX_STATE_REMOTE)); ++ ASSERT(special || (flags & PA2_HV_AUX_STATE_ENABLE)); ++ ASSERT(special || (flags & PA2_HV_AUX_STATE_SCALE)); + break; + } + state++; + } ++ +out: + return ret; +} @@ -9110,6 +9838,20 @@ index 0000000..9fa8baf + return ret; +} + ++static int ++pa2_ctl_cmd_write_aux_obuf_do( ++ pa2_t *fp, ++ uint8_t byte) ++{ ++ int ret; ++ ++ ret = pa2_cmd_write_do(fp, PA2_CTL_CMD_WRITE_AUX_OBUF); ++ if (ret == 0) { ++ ret = pa2_data_write_do(fp, byte); ++ } ++ return ret; ++} ++ +/** + ** Synaptic special cmd sequence functions. + **/ @@ -9129,21 +9871,19 @@ index 0000000..9fa8baf + uint i; + uint8_t data; + -+ /* -+ * Should always have RES when we reach here. -+ */ -+ -+ ASSERT(fp->pp_state_cur.pss_hv_flgs & PA2_HV_STATE_AUX_RES); -+ -+ /* caller? XXX */ + (void) pa2_ctl_aux_disable_do(fp); + + ret = pa2_aux_cmd_do(fp, PA2_AUX_CMD_SCALE11_SET); -+ ret = pa2_aux_cmd_do(fp, PA2_AUX_CMD_SCALE11_SET); ++ if (ret != 0) { ++ goto out; ++ } ++ ret = pa2_aux_cmd_do(fp, PA2_AUX_CMD_SCALE11_SET); + for (i = 0; i < 4 && ret == 0; i++) { + data = (byte >> ((3 - i) * 2)) & 0x3; + ret = pa2_aux_res_set_do(fp, data); + } ++ ++out: + ASSERT(ret == 0); + return ret; +} @@ -9154,33 +9894,12 @@ index 0000000..9fa8baf + uint8_t byte) +{ + pa2_state_t *ssp; -+ uint8_t res; + int ret; + -+ ssp = &fp->pp_state_cur; -+ ASSERT(ssp->pss_hv_flgs & PA2_HV_STATE_AUX_RES); -+ res = ssp->pss_aux_res; -+ ret = pa2_synaptic_cmd_preamble(fp, byte); -+ if (ret == 0) { -+#if 0 -+ (void) pa2_ctl_kbd_disable_do(fp); -+#endif -+ ret = pa2_aux_status_get_do(fp); -+ } -+ -+ /* -+ * Not sure about this... -+ * If the series of set resolutions (acutally, its the final one) -+ * would have changed the resolution, then restore the original value. -+ * I think the transparent bit, in the synaptic mode-byte, can change -+ * this behaviour... XXX -+ */ -+#if 0 -+ if (ssp->pss_aux_res != res) { -+ ret = pa2_aux_res_set_do(fp, res); -+ ASSERT(ssp->pss_aux_res == res); ++ ret = pa2_synaptic_cmd_preamble(fp, byte); ++ if (ret == 0) { ++ ret = pa2_aux_status_get_do(fp); + } -+#endif + return ret; +} + @@ -9189,28 +9908,12 @@ index 0000000..9fa8baf + pa2_t *fp, + uint8_t byte) +{ -+ pa2_state_t *ssp; -+ uint8_t res; + int ret; + -+ ssp = &fp->pp_state_cur; -+ ASSERT(ssp->pss_hv_flgs & PA2_HV_STATE_AUX_RES); -+ res = ssp->pss_aux_res; + ret = pa2_synaptic_cmd_preamble(fp, byte); + if (ret == 0) { + ret = pa2_aux_sample_set_do(fp, 0x14); + } -+ -+#if 0 -+ /* -+ * See comment in func above. -+ */ -+ -+ if (ssp->pss_aux_res != res) { -+ ret = pa2_aux_res_set_do(fp, res); -+ ASSERT(ssp->pss_aux_res == res); -+ } -+#endif + return ret; +} + @@ -9219,16 +9922,11 @@ index 0000000..9fa8baf + pa2_t *fp, + uint8_t byte) +{ -+ pa2_state_t *ssp; -+ uint8_t res; + uint8_t data; + uint len; + uint i; + int ret; + -+ ssp = &fp->pp_state_cur; -+ ASSERT(ssp->pss_hv_flgs & PA2_HV_STATE_AUX_RES); -+ res = ssp->pss_aux_res; + ret = pa2_synaptic_cmd_preamble(fp, byte); + if (ret == 0) { + ret = pa2_aux_sample_set_do(fp, 0x28); /* XXX */ @@ -9244,16 +9942,6 @@ index 0000000..9fa8baf + break; + } + } -+#if 0 -+ /* -+ * See comment in func above. -+ */ -+ -+ if (ssp->pss_aux_res != res) { -+ ret = pa2_aux_res_set_do(fp, res); -+ ASSERT(ssp->pss_aux_res == res); -+ } -+#endif + return ret; +} + @@ -9273,7 +9961,7 @@ index 0000000..9fa8baf +} + +/* -+ * Probe for synaptic touchpad. ++ * Probe for Synaptic touchpad. + * This sends special cmd sequence for the identify. The state machine + * check for the middle byte of the response to be $0x47. If it is, then + * the AUX device is marked as a synaptic touchpad. @@ -9355,7 +10043,7 @@ index 0000000..9fa8baf + if (!(mode_byte & PA2_SYNAP_BIT_TRANSPARENT)) { + ret = pa2_synaptic_mode_byte(fp, mode_byte | + PA2_SYNAP_BIT_TRANSPARENT); -+ /* XXXX */ ++ /* error handling XXXX */ + } + + PRINT_DEBUG(PA2_DBG_HIGH, "pa2_synaptic_e1_get()\n"); @@ -9406,6 +10094,114 @@ index 0000000..9fa8baf + return ret; +} + ++/* ++ * Exit multiplexed mode of Active PS/2 Multiplexing, into legacy mode. ++ */ ++ ++static void ++pa2_aux_multiplexing_exit( ++ pa2_t *fp) ++{ ++ static const uint8_t pa2_multi_send[] = {0xF0, 0x56, 0xA5}; ++ pa2_const_t *scp; ++ pa2_state_t *ssp; ++ uint8_t inbyte; ++ uint8_t outbyte; ++ int state; ++ int ret; ++ ++ PRINT_DEBUG(PA2_DBG_HIGH, "Multiplexing exiting...\n"); ++ scp = &fp->pp_state_const; ++ ssp = &fp->pp_state_cur; ++ ASSERT(scp->psc_flgs & PA2_CONST_MULTIPLEXING); ++ ASSERT(ssp->pss_flags & PA2_STATE_AUX_MULTI); ++ for (state = 0; state < 3; state++) { ++ outbyte = pa2_multi_send[state]; ++ ret = pa2_ctl_cmd_write_aux_obuf_do(fp, outbyte); ++ if (ret != 0) { ++ break; ++ } ++ ret = pa2_output_aux_read_do(fp, &inbyte); ++ if (ret != 0) { ++ break; ++ } ++ if (state == 0 || state == 1) { ++ if (inbyte == outbyte) { ++ continue; ++ } ++ ASSERT(0); ++ break; ++ } ++ if (inbyte == outbyte) { ++ break; ++ } ++ ASSERT(inbyte == scp->psc_multi_version); ++ ssp->pss_flags &= ~PA2_STATE_AUX_MULTI; ++ } ++ return; ++} ++ ++/* ++ * Testing if active ps/2 multiplexing is supported. ++ * Return true if supported, false if not. ++ */ ++ ++static int ++pa2_aux_multiplexing_probe( ++ pa2_t *fp) ++{ ++ static const uint8_t pa2_multi_send[] = {0xF0, 0x56, 0xA4}; ++ pa2_const_t *scp; ++ pa2_state_t *ssp; ++ uint8_t inbyte; ++ uint8_t outbyte; ++ int state; ++ int ret; ++ int supported; ++ ++ PRINT_DEBUG(PA2_DBG_HIGH, "Probing multiplexing...\n"); ++ ASSERT(fp->pp_init == 1); ++ scp = &fp->pp_state_const; ++ ASSERT(!(scp->psc_flgs & PA2_CONST_MULTIPLEXING)); ++ ssp = &fp->pp_state_cur; ++ ASSERT(!(ssp->pss_flags & PA2_STATE_AUX_MULTI)); ++ supported = 0; ++ for (state = 0; state < 3; state++) { ++ outbyte = pa2_multi_send[state]; ++ ret = pa2_ctl_cmd_write_aux_obuf_do(fp, outbyte); ++ if (ret != 0) { ++ break; ++ } ++ ret = pa2_output_aux_read_do(fp, &inbyte); ++ if (ret != 0) { ++ break; ++ } ++ if (state == 0 || state == 1) { ++ if (inbyte == outbyte) { ++ continue; ++ } ++ ASSERT(0); ++ break; ++ } ++ if (inbyte == outbyte) { ++ break; ++ } ++ scp->psc_multi_version |= inbyte; ++ scp->psc_flgs |= PA2_CONST_MULTIPLEXING; ++ ssp->pss_flags |= PA2_STATE_AUX_MULTI; ++ PRINT_DEBUG(PA2_DBG_HIGH, "Multiplexing support. " ++ "Version: 0x%X\n", scp->psc_multi_version); ++ supported = 1; ++ } ++ return supported; ++} ++ ++/* ++ * Read Synaptic's tables of constant data. ++ * This is called during the AUX one-off init, as (being constant) the data ++ * in these tables (that gives h/w capabilities, etc) never changes. ++ */ ++ +static int +pa2_synaptic_const_load( + pa2_t *fp) @@ -9526,6 +10322,10 @@ index 0000000..9fa8baf + } + ASSERT(syp->pcy_hv_flgs & PA2_HV_SYNAP_UNKNOWN1); + ++ /* ++ * pcy_capQueries tells us how many additional tables the h/w has. ++ */ ++ + if (syp->pcy_capExtended && syp->pcy_capQueries >= 1) { + if (!(syp->pcy_hv_flgs & PA2_HV_SYNAP_EXT_MODEL)) { + ret = pa2_synaptic_cmd_get(fp, @@ -9539,7 +10339,8 @@ index 0000000..9fa8baf + + if (syp->pcy_capExtended && syp->pcy_capQueries >= 4) { + if (!(syp->pcy_hv_flgs & PA2_HV_SYNAP_UNKNOWN3)) { -+ ret = pa2_synaptic_cmd_get(fp, PA2_SYNAP_GET_UNKNOWN_XXX3); ++ ret = pa2_synaptic_cmd_get(fp, ++ PA2_SYNAP_GET_UNKNOWN_XXX3); + if (ret != 0) { + goto out; + } @@ -9549,7 +10350,8 @@ index 0000000..9fa8baf + + if (syp->pcy_capExtended && syp->pcy_capQueries >= 4) { + if (!(syp->pcy_hv_flgs & PA2_HV_SYNAP_UNKNOWN4)) { -+ ret = pa2_synaptic_cmd_get(fp, PA2_SYNAP_GET_UNKNOWN_XXX4); ++ ret = pa2_synaptic_cmd_get(fp, ++ PA2_SYNAP_GET_UNKNOWN_XXX4); + if (ret != 0) { + goto out; + } @@ -9613,6 +10415,13 @@ index 0000000..9fa8baf + return; +} + ++/* ++ * Nasty function that drains 8042 output buffer, and disables devices. ++ * It was (once) called during KBD and AUX init, but now is only called ++ * for the one-off CTRL init. This needs revisiting to see if it really is ++ * needed. Certainly, as it is now only called for ctrl init the tests to ++ * see if a device has focus can be removed. ++ */ + +static int +pa2_i8042_sane_init( @@ -9639,40 +10448,42 @@ index 0000000..9fa8baf + while (done == 0) { + for (i = 0; i < 10; i++) { + status = pa2_status_read(fp, PA2_INDEX_WILD); -+ if ((status & (PA2_CTL_STAT_OBF | PA2_CTL_STAT_AUX_OBF)) == ++ if ((status & ++ (PA2_CTL_STAT_OBF | PA2_CTL_STAT_AUX_OBF)) == + (PA2_CTL_STAT_OBF | PA2_CTL_STAT_AUX_OBF)) { -+ if (fp->pp_active[PA2_INDEX_AUX] == 1) { -+ (void) pa2_output_aux_read_do(fp, &byte); -+ } else { -+ usleep(10); -+ /* after certain amount of time, what to do? XXX */ -+ (void) pa2_output_aux_read_do(fp, &byte); ++ /* ++ * If there is AUX data preventing us from ++ * proceeding, then clear it by reading. ++ * If we do not have focus, then allow someone ++ * else to read, but we do need this data ++ * to be moved so read anyway. Is this right? ++ */ ++ ++ if (fp->pp_active[PA2_INDEX_AUX] == 0) { ++ usleep(50); + } ++ (void) pa2_output_aux_read_do(fp, &byte); + limit = 4; + continue; + } + if (status & PA2_CTL_STAT_OBF) { -+ if (fp->pp_active[PA2_INDEX_KBD] == 1) { -+ (void) pa2_output_read_do(fp, &byte); -+ } else { -+ usleep(10); -+ (void) pa2_output_read_do(fp, &byte); ++ /* ++ * Same as AUX case above. Force read even ++ * if do not have focus... ++ */ ++ ++ if (fp->pp_active[PA2_INDEX_KBD] == 0) { ++ usleep(50); + } ++ (void) pa2_output_read_do(fp, &byte); + limit = 4; + continue; + } + break; + } + ret = 0; -+#if 0 -+ if (fp->pp_active[PA2_INDEX_KBD] == 1) { -+ ret |= pa2_ctl_kbd_disable_do(fp); -+ } -+ if (fp->pp_active[PA2_INDEX_AUX] == 1) { -+ ret |= pa2_ctl_aux_disable_do(fp); -+ } -+#endif + /* drain */ ++ status = 0; + for (i = 0; i < limit; i++) { + status = pa2_status_read(fp, PA2_INDEX_WILD); + if (!(status & PA2_CTL_STAT_OBF)) { @@ -9681,7 +10492,6 @@ index 0000000..9fa8baf + } + break; + } -+ /* select based upon pp_active[] XXX */ + if ((status & (PA2_CTL_STAT_OBF | PA2_CTL_STAT_AUX_OBF)) == + (PA2_CTL_STAT_OBF | PA2_CTL_STAT_AUX_OBF)) { + if (fp->pp_active[PA2_INDEX_AUX] == 1) { @@ -9712,6 +10522,11 @@ index 0000000..9fa8baf + return ret; +} + ++/* ++ * Initialize the AUX device to the saved state. ++ * Called when guest is obtaining focus on the AUX device. ++ */ ++ +static int +pa2_aux_init( + pa2_t *fp) @@ -9719,6 +10534,7 @@ index 0000000..9fa8baf + pa2_state_t saved; + pa2_const_t *scp; + pa2_state_t *ssp; ++ pa2_aux_state_t *pap; + pa2_syp_state_t *sp; + pa2_syp_const_t *syp; + pa2_cmd_t cmd; @@ -9739,6 +10555,7 @@ index 0000000..9fa8baf + fail_count = 0; + scp = &fp->pp_state_const; + ssp = &fp->pp_state_cur; ++ pap = &ssp->pss_aux[0]; + + cmdp = &fp->pp_cmds[PA2_OUTPUT_AUX]; + cmd = *cmdp; @@ -9752,11 +10569,25 @@ index 0000000..9fa8baf + goto out; + } + ++ /* ++ * Save dynamic state of AUX device. ++ * Setting up the device changes the saved state, so take a copy ++ * before starting work. ++ */ ++ + memcpy(&saved, ssp, sizeof (saved)); + sp = &ssp->pss_synaptic; + mode = ssp->pss_mode; + PRINT_DEBUG(PA2_DBG_MID, "Aux_init: mode_byte 0x%X\n", mode); -+ aux_dev_enabled = ssp->pss_aux_status & PA2_AUX_STAT_ENABLE; ++ aux_dev_enabled = pap->pas_aux_status & PA2_AUX_STAT_ENABLE; ++ ++ /* ++ * Take the initialization lock. While we're 'playing' with the AUX ++ * device, another ioemu instance could be dropping the KBD. If these ++ * are allowed to race, can get the s/w into a deadlock state (waiting ++ * for a command that has been abort by another thread issuing a ++ * command). ++ */ + + fd = fp->pp_fd[PA2_INDEX_CTL]; + lock = 1; @@ -9770,7 +10601,6 @@ index 0000000..9fa8baf + ret = 0; + PRINT_DEBUG(PA2_DBG_HIGH, "aux_init: %u\n", step); + switch (step) { -+ + case 0: + /* + * Clear Synaptic mode_byte. This puts us in @@ -9812,33 +10642,36 @@ index 0000000..9fa8baf + * avoid unnecessary actions. + */ + -+ ASSERT(ssp->pss_hv_flgs & PA2_HV_STATE_AUX_REMOTE); -+ ASSERT(ssp->pss_hv_flgs & PA2_HV_STATE_AUX_SCALE); -+ if ((ssp->pss_aux_status & PA2_AUX_STAT_REMOTE) == -+ (saved.pss_aux_status & PA2_AUX_STAT_REMOTE)) { -+ saved.pss_hv_flgs |= PA2_HV_STATE_AUX_REMOTE; ++ ASSERT(pap->pas_hv_flgs & PA2_HV_AUX_STATE_REMOTE); ++ ASSERT(pap->pas_hv_flgs & PA2_HV_AUX_STATE_SCALE); ++ if ((pap->pas_aux_status & PA2_AUX_STAT_REMOTE) == ++ (saved.pss_aux[0].pas_aux_status & ++ PA2_AUX_STAT_REMOTE)) { ++ saved.pss_aux[0].pas_hv_flgs |= ++ PA2_HV_AUX_STATE_REMOTE; + } -+ if ((ssp->pss_aux_status & PA2_AUX_STAT_SCALING) == -+ (saved.pss_aux_status & PA2_AUX_STAT_SCALING)) { -+ saved.pss_hv_flgs |= PA2_HV_STATE_AUX_SCALE; ++ if ((pap->pas_aux_status & PA2_AUX_STAT_SCALING) == ++ (saved.pss_aux[0].pas_aux_status & ++ PA2_AUX_STAT_SCALING)) { ++ saved.pss_aux[0].pas_hv_flgs |= ++ PA2_HV_AUX_STATE_SCALE; + } + memcpy(ssp, &saved, sizeof(saved)); + break; + + case 7: -+ /* only AUX XXX */ + (void) pa2_ctl_aux_disable_do(fp); + ret = pa2_ctl_mode_write_do(fp, ssp->pss_mode); + break; + + case 8: + (void) pa2_ctl_aux_disable_do(fp); -+ ret = pa2_aux_res_set_do(fp, ssp->pss_aux_res); ++ ret = pa2_aux_res_set_do(fp, pap->pas_aux_res); + break; + + case 9: + (void) pa2_ctl_aux_disable_do(fp); -+ ret = pa2_aux_sample_set_do(fp, ssp->pss_aux_sample); ++ ret = pa2_aux_sample_set_do(fp, pap->pas_aux_sample); + break; + + case 10: @@ -9848,15 +10681,15 @@ index 0000000..9fa8baf + * so only need this step if the status is REMOTE. + */ + -+ ASSERT(ssp->pss_hv_flgs & PA2_HV_STATE_AUX_REMOTE); -+ if (ssp->pss_aux_status & PA2_AUX_STAT_REMOTE) { ++ ASSERT(pap->pas_hv_flgs & PA2_HV_AUX_STATE_REMOTE); ++ if (pap->pas_aux_status & PA2_AUX_STAT_REMOTE) { + (void) pa2_ctl_aux_disable_do(fp); + ret = pa2_aux_remote_set_do(fp); + } + break; + + case 12: -+ if (ssp->pss_aux_wrap_mode == 1) { ++ if (pap->pas_aux_wrap_mode == 1) { + (void) pa2_ctl_aux_disable_do(fp); + ret = pa2_aux_wrap_set_do(fp); + } else { @@ -9871,14 +10704,13 @@ index 0000000..9fa8baf + * so only need this step if scaling is 21. + */ + -+ ASSERT(ssp->pss_hv_flgs & PA2_HV_STATE_AUX_SCALE); -+ if (ssp->pss_aux_status & PA2_AUX_STAT_SCALING) { ++ ASSERT(pap->pas_hv_flgs & PA2_HV_AUX_STATE_SCALE); ++ if (pap->pas_aux_status & PA2_AUX_STAT_SCALING) { + (void) pa2_ctl_aux_disable_do(fp); + ret = pa2_aux_scale21_set_do(fp); + break; + } + ASSERT(ssp->pss_setscale_last == 0); -+ /* clear the buttons XXX */ + break; + + case 18: @@ -9906,19 +10738,13 @@ index 0000000..9fa8baf + ret = pa2_synaptic_mode_byte(fp, sp->ps_mode_byte); + break; + -+ case 20: -+ /* -+ * Value written via E2. XXX -+ */ -+ -+ break; -+ + case 22: + if (aux_dev_enabled) { + (void) pa2_ctl_kbd_disable_do(fp); + ret = pa2_aux_dev_enable_do(fp); + } else { -+ ASSERT(!(ssp->pss_aux_status & PA2_AUX_STAT_ENABLE)); ++ ASSERT(!(pap->pas_aux_status & ++ PA2_AUX_STAT_ENABLE)); + } + break; + @@ -9971,6 +10797,12 @@ index 0000000..9fa8baf + return ret; +} + ++/* ++ * One-off initialization of AUX. ++ * Peformed by primarty VM to get h/w into known state and to extract AUX ++ * constant data from device. ++ */ ++ +static int +pa2_aux_once_init( + pa2_t *fp) @@ -9998,10 +10830,16 @@ index 0000000..9fa8baf + ssp = &fp->pp_state_cur; + sp = &ssp->pss_synaptic; + syp = &fp->pp_state_const.psc_synap; -+ + ASSERT(fp->pp_init == 1); + -+ /* should retry on failure...have kernel interruptible XXX */ ++ /* ++ * Take the init lock. Is not needed here (as cannot be racing ++ * with others in acessing the h/w - see pa2_dev_disable()), but ++ * kernel pass2 driver asserts this is held and it does no harm to ++ * hold it here. ++ * This ioctl() is interruptible, should retry on a signal. XXX ++ */ ++ + lock = 1; + fd = fp->pp_fd[PA2_INDEX_CTL]; + if (ioctl(fd, PA2_IOCTL_INIT_CMD, &lock) == -1) { @@ -10013,15 +10851,8 @@ index 0000000..9fa8baf + while (done == 0) { + uint8_t status; + ret = 0; -+ pa2_outport_read_do(fp); -+ PRINT_DEBUG(PA2_DBG_HIGH, "aux_once_init: %u 0x%X 0x%X\n", step, -+ ssp->pss_mode, ssp->pss_outport); -+ ret = pa2_ctl_mode_read_do(fp); -+ ret = pa2_outport_read_do(fp); -+ status = pa2_status_read(fp, PA2_INDEX_RAW); -+ PRINT_DEBUG(PA2_DBG_MID, "aux_once_init-mode: 0x%X 0x%X 0x%X\n", ssp->pss_mode, ssp->pss_outport, status); ++ PRINT_DEBUG(PA2_DBG_HIGH, "aux_once_init: %u\n", step); + switch (step) { -+ + case 0: + /* + * Clear Synaptic mode_byte. This puts us in @@ -10066,7 +10897,6 @@ index 0000000..9fa8baf + break; + + case 7: -+ /* only AUX XXX */ + (void) pa2_ctl_aux_disable_do(fp); + ret = pa2_ctl_mode_write_do(fp, ssp->pss_mode); + break; @@ -10085,51 +10915,6 @@ index 0000000..9fa8baf + ret = pa2_synaptic_const_load(fp); + break; + -+#if 0 -+ case 11: -+ if (!(scp->psc_flgs & PA2_CONST_SYNAP_YES)) { -+ break; -+ } -+ sp->ps_mode_byte = PA2_SYNAP_BIT_ABS | PA2_SYNAP_BIT_WMODE | PA2_SYNAP_BIT_RATE; -+ PRINT_DEBUG(PA2_DBG_HIGH, "Setting1 mode_byte to 0x%X\n", -+ sp->ps_mode_byte); -+ ret = pa2_synaptic_mode_byte(fp, -+ sp->ps_mode_byte); -+ -+ ret = pa2_aux_dev_enable_do(fp); -+ ret = pa2_aux_dev_disable_do(fp); -+ ret = pa2_synaptic_cmd_get(fp, PA2_SYNAP_GET_MODES); -+ -+ sp->ps_mode_byte = PA2_SYNAP_BIT_TRANSPARENT | PA2_SYNAP_BIT_ABS | PA2_SYNAP_BIT_WMODE | PA2_SYNAP_BIT_RATE; -+ PRINT_DEBUG(PA2_DBG_HIGH, "Setting2 mode_byte to 0x%X\n", -+ sp->ps_mode_byte); -+ ret = pa2_synaptic_mode_byte(fp, -+ sp->ps_mode_byte); -+ -+ ret = pa2_aux_scale21_set_do(fp); -+ ret = pa2_aux_reset_do(fp); -+ -+ ret = pa2_synaptic_cmd_get(fp, PA2_SYNAP_GET_IDENTIFY); -+ ret = pa2_synaptic_e1_do(fp); -+ ret = pa2_aux_sample_set_do(fp, 0x28); -+ -+ ret = pa2_aux_synap_e2_do(fp); -+ ret = pa2_aux_res_set_do(fp, 0x3); -+ -+ -+ ret = pa2_aux_scale21_set_do(fp); -+ ret = pa2_aux_scale11_set_do(fp); -+ ret = pa2_aux_dev_disable_do(fp); -+ -+ for (i = 0; i < sizeof (pa2_28_queries); i++) { -+ PRINT_DEBUG(PA2_DBG_HIGH, "Quering: 0x%x\n", pa2_28_queries[i]); -+ pa2_synaptic_ext_cmd_set(fp, pa2_28_queries[i]); -+ } -+ ret = pa2_synaptic_mode_byte(fp, -+ sp->ps_mode_byte & -+ ~PA2_SYNAP_BIT_TRANSPARENT); -+ break; -+#else + case 11: + if (!(scp->psc_flgs & PA2_CONST_SYNAP_YES)) { + break; @@ -10171,11 +10956,10 @@ index 0000000..9fa8baf + p28p->p28_bytes[10] = 0x00; + } + break; -+#endif + + case 12: + /* -+ * Reset. ++ * Set the scaling. + */ + + (void) pa2_ctl_aux_disable_do(fp); @@ -10184,7 +10968,7 @@ index 0000000..9fa8baf + + case 14: + /* -+ * Reset. ++ * Ensure disabled. + */ + + (void) pa2_ctl_aux_disable_do(fp); @@ -10192,6 +10976,11 @@ index 0000000..9fa8baf + break; + + case 15: ++ ++ /* ++ * Empty AUX input. ++ */ ++ + pa2_drain(fp, PA2_INDEX_AUX); + break; + @@ -10229,10 +11018,6 @@ index 0000000..9fa8baf +} + + -+/* -+ * Intialize the KBD. -+ */ -+ +static int +pa2_kbd_init( + pa2_t *fp) @@ -10275,8 +11060,11 @@ index 0000000..9fa8baf + ret = 0; + PRINT_DEBUG(PA2_DBG_HIGH, "kbd_init: %u\n", step); + switch (step) { -+ + case 0: ++ /* ++ * Reset to get into known state. ++ */ ++ + (void) pa2_ctl_kbd_disable_do(fp); + ret = pa2_kbd_reset_disable_do(fp); + break; @@ -10296,7 +11084,6 @@ index 0000000..9fa8baf + break; + + case 4: -+ /* only KBD XXX */ + (void) pa2_ctl_kbd_disable_do(fp); + ret = pa2_ctl_mode_write_do(fp, ssp->pss_mode); + break; @@ -10350,6 +11137,11 @@ index 0000000..9fa8baf + return ret; +} + ++/* ++ * One-off initialization of KBD. ++ * Peformed by primarty VM to get h/w into known state. ++ */ ++ +static int +pa2_kbd_once_init( + pa2_t *fp) @@ -10380,6 +11172,13 @@ index 0000000..9fa8baf + kbd_rate = ssp->pss_kbd_rate; + kbd_leds = ssp->pss_kbd_leds; + ++ /* ++ * Take the init lock. Is not needed here (as cannot be racing ++ * with others in acessing the h/w - see pa2_dev_disable()), but ++ * kernel pass2 driver asserts this is held and it does no harm to ++ * hold it here. ++ */ ++ + fd = fp->pp_fd[PA2_INDEX_CTL]; + lock = 1; + PRINT_DEBUG(PA2_DBG_HIGH, "Taking cmd lock: %u\n", step); @@ -10394,26 +11193,38 @@ index 0000000..9fa8baf + PRINT_DEBUG(PA2_DBG_HIGH, "kbd_once_init: %u 0x%X 0x%X\n", step, + ssp->pss_mode, ssp->pss_outport); + switch (step) { -+ + case 0: ++ /* ++ * Reset to get into known state. ++ */ ++ + (void) pa2_ctl_kbd_disable_do(fp); + ret = pa2_kbd_reset_disable_do(fp); + break; + + case 1: ++ /* ++ * Drain any queue data. ++ */ ++ + pa2_drain(fp, PA2_INDEX_KBD); + break; + + case 4: -+ /* only KBD XXX */ ++ /* ++ * Ensure the Mode is set such that KBD can generate ++ * interrupts when enabled. ++ */ ++ + (void) pa2_ctl_kbd_disable_do(fp); -+ ret = pa2_ctl_mode_write_do(fp, ssp->pss_mode | PA2_CTL_MODE_INT_KBD); ++ ret = pa2_ctl_mode_write_do(fp, ++ ssp->pss_mode | PA2_CTL_MODE_INT_KBD); + break; + + case 5: + + /* -+ * Enable scanning. Should be part of our status. XXX ++ * Enable scanning. + */ + + (void) pa2_ctl_kbd_disable_do(fp); @@ -10489,13 +11300,7 @@ index 0000000..9fa8baf + ssp = &fp->pp_state_cur; + mode = ssp->pss_mode; + while (done == 0) { -+ if (step != 0) { -+ pa2_ctl_mode_read_do(fp); -+ } -+ if (step > 11) { -+ pa2_outport_read_do(fp); -+ } -+ PRINT_DEBUG(PA2_DBG_MID, "ctl_init: %u 0x%X 0x%X\n", step, ssp->pss_mode, ssp->pss_outport); ++ PRINT_DEBUG(PA2_DBG_MID, "ctl_init: %u\n", step); + ret = 0; + switch (step) { + case 0: @@ -10509,33 +11314,33 @@ index 0000000..9fa8baf + * Lets be paraniod, and reset the controller twice. + */ + -+ ret = pa2_ctl_mode_read_do(fp); -+ PRINT_DEBUG(PA2_DBG_MID, "ctl_reset1: 0x%X\n", ssp->pss_mode); + ret = pa2_ctl_reset_do(fp); -+ ret = pa2_ctl_mode_read_do(fp); -+ PRINT_DEBUG(PA2_DBG_MID, "ctl_reset2: 0x%X\n", ssp->pss_mode); + break; + + case 4: ++ /* ++ * Get KBD into sane state. ++ */ ++ + ret = pa2_i8042_sane_init(fp); -+#if 1 + ret |= pa2_kbd_reset_disable_do(fp); -+#else -+ ret = pa2_ctl_mode_read_do(fp); -+ PRINT_DEBUG(PA2_DBG_MID, "kbd_reset1: 0x%X\n", ssp->pss_mode); -+ ret |= pa2_kbd_reset_do(fp); -+ ret = pa2_ctl_mode_read_do(fp); -+ PRINT_DEBUG(PA2_DBG_MID, "kbd_reset2: 0x%X\n", ssp->pss_mode); -+#endif + break; + + case 5: ++ /* ++ * Get AUX into sane state. ++ */ ++ + ret = pa2_i8042_sane_init(fp); ++#if 0 + ret = pa2_ctl_mode_read_do(fp); + PRINT_DEBUG(PA2_DBG_MID, "aux_reset1: 0x%X\n", ssp->pss_mode); ++#endif + ret |= pa2_aux_dev_disable_do(fp); ++#if 0 + ret = pa2_ctl_mode_read_do(fp); + PRINT_DEBUG(PA2_DBG_MID, "aux_reset2: 0x%X\n", ssp->pss_mode); ++#endif + break; + + case 6: @@ -10551,18 +11356,30 @@ index 0000000..9fa8baf + break; + + case 9: -+ ret = pa2_ctl_version_get_do(fp); ++ /* ++ * Probe if AUX muliplexing is support by this ++ * h/w. ++ */ ++ ++ ret = pa2_aux_multiplexing_probe(fp); ++ if (ret == 1) { ++ pa2_aux_multiplexing_exit(fp); ++ } + break; + + case 10: -+ ret = pa2_ctl_outport_write_do(fp, ssp->pss_outport); ++ ret = pa2_ctl_version_get_do(fp); + break; + + case 11: -+ ret = pa2_ctl_mode_write_do(fp, mode); ++ ret = pa2_ctl_outport_write_do(fp, ssp->pss_outport); + break; + + case 12: ++ ret = pa2_ctl_mode_write_do(fp, mode); ++ break; ++ ++ case 13: + /* leave with devices disabled */ + done = 1; + break; @@ -10586,7 +11403,7 @@ index 0000000..9fa8baf +} + +/* -+ * Before releasing a device, disable it and interrupts. ++ * This function is called before releasing a device; disable it and interrupts. + */ + +static int @@ -10607,9 +11424,24 @@ index 0000000..9fa8baf + ASSERT(index == PA2_INDEX_KBD || index == PA2_INDEX_AUX); + ASSERT(fp->pp_active[index] == 1); + ASSERT(fp->pp_grabbing[index] == 0); ++ ++ /* ++ * Save the current dynamic state, as disabling the device can ++ * mess with this. ++ */ ++ + ssp = &fp->pp_state_cur; + memcpy(&saved, ssp, sizeof (saved)); + ++ /* ++ * Take the initialization lock. While we're 'playing' with one ++ * device (eg. dropping AUX), another ioemu instance could be ++ * grabbing the KBD. If these are allowed to race, can get the ++ * s/w into a deadlock state (waiting for a command that has been ++ * abort by another thread issuing a command). ++ * This ioctl() is interruptible, should retry on a signal. XXX ++ */ ++ + ret = 0; + lock = 1; + fd = fp->pp_fd[PA2_INDEX_CTL]; @@ -10626,9 +11458,16 @@ index 0000000..9fa8baf + PRINT_DEBUG(PA2_DBG_HIGH, "dev_disable: %u\n", step); + ret = 0; + switch(step) { -+ + case 0: + case 1: ++ /* ++ * Disable the device. Be paraniod, and do this ++ * twice...it does not take long, and the first ++ * may be discarded if it causes an in progress cmd ++ * to abort (may be, think I've seen it a couple of ++ * times). ++ */ ++ + if (index == PA2_INDEX_KBD) { + (void) pa2_ctl_kbd_disable_do(fp); + (void) pa2_kbd_reset_disable_do(fp); @@ -10639,29 +11478,11 @@ index 0000000..9fa8baf + break; + + case 2: -+ /* drain */ ++ /* drain all queued data */ + pa2_drain(fp, PA2_INDEX_KBD); + break; + -+#if 0 -+ case 6: -+ /* -+ * Disable interrupts. -+ * Combine this with above? XXX -+ */ -+ -+ if (ssp->pss_hv_flgs & PA2_HV_STATE_MODE) { -+ mode = ssp->pss_mode; -+ if (index == PA2_INDEX_KBD) { -+ mode &= ~PA2_CTL_MODE_INT_KBD; -+ } else { -+ mode &= ~PA2_CTL_MODE_INT_AUX; -+ } -+ ret = pa2_ctl_mode_write_do(fp, mode); -+ } -+ break; -+#endif -+ case 8: ++ case 3: + done = 1; + break; + } @@ -10693,7 +11514,9 @@ index 0000000..9fa8baf +} + +/* -+ * Should be able to return failure.. XXX ++ * Called to initialize this driver. ++ * Load default values into AUX and KBD state, and register with the ports ++ * were interested in for reads/writes from guests. + */ + +void @@ -10704,15 +11527,16 @@ index 0000000..9fa8baf +{ + pa2_t *fp; + pa2_state_t *ssp; ++ pa2_aux_state_t *pap; + pa2_syp_state_t *sp; + pa2_const_t *scp; + char buffer[1024]; ++ int i; + int ret; + +#if defined(PA2_DEBUG) + fprintf(stderr, "pa2: i8042_init()\n"); +#endif -+ + fp = &pa2_state; + fp->pp_kbd_irq = kbd_irq; + fp->pp_aux_irq = aux_irq; @@ -10729,25 +11553,25 @@ index 0000000..9fa8baf + ssp = &fp->pp_state_cur; + scp = &fp->pp_state_const; + sp = &ssp->pss_synaptic; -+ fp->pp_state_cur.pss_mode = PA2_CTL_MODE_DISABLE_AUX; -+ fp->pp_state_cur.pss_status = PA2_CTL_STAT_UNLOCKED; -+ -+ fp->pp_limit = 50; /* XXX */ -+ ++ fp->pp_limit = 50; ++ ssp->pss_mode = PA2_CTL_MODE_DISABLE_AUX; ++ ssp->pss_status = PA2_CTL_STAT_UNLOCKED; + ssp->pss_outport = PA2_OUTPORT_SYSR | PA2_OUTPORT_AXDO | + PA2_OUTPORT_ACLK | PA2_OUTPORT_OUTB | + PA2_OUTPORT_AUXB | PA2_OUTPORT_KCLK | + PA2_OUTPORT_KBDO; + ssp->pss_kbd_rate = PA2_KBD_DEFAULT_RATE; -+ ssp->pss_kbd_leds = 0x0; /* XXX */ -+ ssp->pss_aux_status = 0; -+ ssp->pss_aux_wrap_mode = 0; -+ ssp->pss_aux_sample = 100; -+ ssp->pss_aux_res = 0x02; ++ ssp->pss_kbd_leds = 0x0; ++ for (i = 0; i < PA2_MAX_NUM_AUX; i++) { ++ pap = &ssp->pss_aux[i]; ++ pap->pas_aux_status = 0; ++ pap->pas_aux_wrap_mode = 0; ++ pap->pas_aux_sample = 100; ++ pap->pas_aux_res = 0x02; ++ } + + scp->psc_ctl_test = PA2_CTL_REPLY_SELF; -+ -+ scp->psc_kbd_id = 0x83 || (0xAB << 8); /* magic XXX */ ++ scp->psc_kbd_id = 0x83 || (0xAB << 8); + + sp->ps_e1_byte1 = PA2_SYNAP_E1_DEFAULT1; + sp->ps_e1_byte2 = PA2_SYNAP_E1_DEFAULT2; @@ -10804,7 +11628,8 @@ index 0000000..9fa8baf + **/ + +/* -+ * Add key combination into our trap table. ++ * Add key combination into our trap table of key bindings. ++ * Called from dom0_driver. + */ + +void @@ -10821,17 +11646,14 @@ index 0000000..9fa8baf + fp = &pa2_state; + ret = pa2_binding_insert(fp, keys, callback, payload); + ASSERT(ret == 0); -+ -+ /* need to be able to return an error XXX */ + return; +} + +/* + * Reset KBD keys. -+ * This empties the kbd input stream (need to call into kernel to complete -+ * this XXX), and then clears any made keys by sending their break sequence -+ * to the guest. -+ * While injecting keyboard could be sending new make/break keys, but as ++ * This empties the KBD input stream, and then clears any made keys by sending ++ * their break sequence to the guest. ++ * While injecting keys could be sending new make/break keys, but as + * we're single threaded there, no danger of racing... + */ + @@ -10871,6 +11693,10 @@ index 0000000..9fa8baf + return; +} + ++/* ++ * A no-op for us? ++ */ ++ +void +pa2_kbd_secure( + void (*ugh)(int)) @@ -10882,6 +11708,11 @@ index 0000000..9fa8baf + return; +} + ++/* ++ * Called from dom0_driver to grab the AUX (grab == 1), or to release the ++ * AUX (grab == 0). ++ */ ++ +int +pa2_aux_grab( + int grab) @@ -10929,7 +11760,6 @@ index 0000000..9fa8baf + if (cmdp->pc_cmd != 0) { + ASSERT(cmdp->pc_active == 1); + cmd = *cmdp; -+ /* should abort cmd XXX */ + saved_cmd = 1; + } + @@ -10947,8 +11777,9 @@ index 0000000..9fa8baf + *cmdp = cmd; + cmdp->pc_active = 0; + if (cmdp->pc_flags & PA2_CMD_FLG_EXPECTED) { -+ PRINT_DEBUG(PA2_DBG_HIGH, "Completing aux cmd %s\n", -+ cmdp->pc_cmd_desp->pcc_name); ++ PRINT_DEBUG(PA2_DBG_HIGH, "Completing aux " ++ "cmd %s\n", ++ cmdp->pc_cmd_desp->pcc_name); + cmdp->pc_flags &= ~PA2_CMD_FLG_EXPECTED; + pa2_aux_append(fp, cmdp, + cmdp->pc_expected_input); @@ -10963,11 +11794,7 @@ index 0000000..9fa8baf + pa2_error("Cannot grab!\n"); + } + PRINT_DEBUG(PA2_DBG_HIGH, "Grab ioctl done\n"); -+ /* -+ * Window XXX -+ */ + -+ /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ + if (byte == 1) { + PRINT_DEBUG(PA2_DBG_HIGH, "Initializing AUX\n"); + pa2_aux_init(fp); @@ -10984,6 +11811,11 @@ index 0000000..9fa8baf + return 1; +} + ++/* ++ * Called from dom0_driver to grab the KBD (grab == 1), or to release the ++ * KBD (grab == 0). ++ */ ++ +int +pa2_kbd_grab( + int grab) @@ -10992,6 +11824,7 @@ index 0000000..9fa8baf + pa2_t *fp; + pa2_state_t *ssp; + pa2_syp_state_t *sp; ++ pa2_aux_state_t *pap; + pa2_cmd_t cmd; + pa2_cmd_t *cmdp; + pa2_hdata_t *php; @@ -11012,8 +11845,6 @@ index 0000000..9fa8baf + + /* + * Releasing KBD? -+ * First, complete any outstanding KBD cmd. -+ * What about ctl cmds? + */ + + memset(&gp, 0, sizeof (gp)); @@ -11022,7 +11853,7 @@ index 0000000..9fa8baf + pa2_state_dump(fp); + + /* -+ * Drop all queued input. ++ * Drop all queued input and ensure the irq is not raised. + */ + + php = &fp->pp_irqbuf[PA2_INDEX_KBD]; @@ -11033,9 +11864,10 @@ index 0000000..9fa8baf + } + ssp = &fp->pp_state_cur; + sp = &ssp->pss_synaptic; ++ pap = &ssp->pss_aux[0]; + gp.pg_grab = 0; -+ gp.pg_aux_sample = ssp->pss_aux_sample; -+ gp.pg_aux_res = ssp->pss_aux_res; ++ gp.pg_aux_sample = pap->pas_aux_sample; ++ gp.pg_aux_res = pap->pas_aux_res; + + /* + * If we've seen the synaptic probe from the guest's driver @@ -11062,6 +11894,13 @@ index 0000000..9fa8baf + saved_cmd = 1; + } + ++ /* ++ * Disable the device, this will prevent it generating ++ * interrupts and any new data. ++ * Can then mark the KBD as inactive (non-focus) for this ++ * guest, and disable our polling for h/w for data. ++ */ ++ + pa2_dev_disable(fp, PA2_INDEX_KBD); + fp->pp_active[PA2_INDEX_KBD] = 0; + qemu_set_fd_handler(fp->pp_fd[PA2_INDEX_KBD], NULL, NULL, @@ -11076,8 +11915,9 @@ index 0000000..9fa8baf + *cmdp = cmd; + cmdp->pc_active = 0; + if (cmdp->pc_flags & PA2_CMD_FLG_EXPECTED) { -+ PRINT_DEBUG(PA2_DBG_HIGH, "Completing kbd cmd %s\n", -+ cmdp->pc_cmd_desp->pcc_name); ++ PRINT_DEBUG(PA2_DBG_HIGH, "Completing kbd " ++ "cmd %s\n", ++ cmdp->pc_cmd_desp->pcc_name); + cmdp->pc_flags &= ~PA2_CMD_FLG_EXPECTED; + pa2_kbd_append(fp, cmdp, + cmdp->pc_expected_input); @@ -11094,6 +11934,12 @@ index 0000000..9fa8baf + } + PRINT_DEBUG(PA2_DBG_HIGH, "Grab ioctl done\n"); + ++ /* ++ * If grabbing KBD, mark it as active and install our 'irq' ++ * handler. Then call pa2_kbd_init() to place KBD into the state ++ * when it was dropped. Discard all queued data (ph_start = ph_end). ++ */ ++ + if (byte == 1) { + fp->pp_active[PA2_INDEX_KBD] = 1; + fp->pp_grabbing[PA2_INDEX_KBD] = 1; @@ -11113,6 +11959,11 @@ index 0000000..9fa8baf + return 1; +} + ++/* ++ * Probe is no-op for PS/2. ++ * PS/2 hotplug for AUX devices should do something here. ++ */ ++ +void +pa2_probe( + int grab) @@ -11133,7 +11984,7 @@ index 0000000..9fa8baf + * next first open will need to before the initilization again. + * + * Note, this init function needs to be able to return failure. Currently, -+ * the API doesn't allow this. XXX markhe ++ * the API doesn't allow this. + */ + +void @@ -11183,7 +12034,7 @@ index 0000000..9fa8baf + /* + * First take the initialization lock. This is allowed, even if + * someone else has grabbed the devices. If someone else has -+ * grabbed, then they must have the initialization earlier. ++ * grabbed, then they must have initialized earlier. + */ + + byte = 1; @@ -11195,7 +12046,7 @@ index 0000000..9fa8baf + } + + /* -+ * Query the driver for cached results ++ * Query the driver for cached results. + * If there is no cached result, then the length is 0 and we need to + * perform first time initialization. + * As all copies of ioemu running should be from the same binary, @@ -11245,7 +12096,6 @@ index 0000000..9fa8baf + fp->pp_grabbing[PA2_INDEX_AUX] = 0; + + PRINT_DEBUG(PA2_DBG_HIGH, "Saving constants\n"); -+ /* double-check size - buffer overrun XXX */ + buf.di_len = sizeof (pa2_const_t); + memset(&buf.di_data[0], 0, PA2_DATA_INIT_MAX); + memcpy(&buf.di_data[0], &fp->pp_state_const, sizeof (pa2_const_t)); @@ -11257,7 +12107,7 @@ index 0000000..9fa8baf + +unlock: + /* -+ * Unlock. ++ * Drop the initialization lock. + */ + + byte = 0; @@ -11282,7 +12132,6 @@ index 0000000..9fa8baf + } + } + PRINT_DEBUG_EXIT("\n"); -+ /* should be able to return an error XXX */ + return; +} diff --git a/pass2.h b/pass2.h -- 2.39.5