]> xenbits.xensource.com Git - xenclient/ioemu-pq.git/commitdiff
Code improvements, along with better code commentary.
authorMark Hemment <markhem@isildur.uk.xensource.com>
Thu, 11 Jun 2009 11:31:18 +0000 (12:31 +0100)
committerMark Hemment <markhem@isildur.uk.xensource.com>
Thu, 11 Jun 2009 11:31:18 +0000 (12:31 +0100)
  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

index 83f48b73cb0d8fba80b34d04f40b2e80d58cf9f9..5fa186fb5cfb0526d04ba7415e643b9243c72b33 100644 (file)
@@ -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 <linux/input.h>
@@ -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