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>
+ * 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"
+ * 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 */
+
+/*
+ * 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 */
+#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 */
+
+/*
+/*
+ * 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 */
+#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
+
+/*
+ * 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;
+ * 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);
+ *
+ * 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 {
+ 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;
+} 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;
+ 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;
+ * 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 */
+#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 {
+} 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
+ */
+
+#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
+ * 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 {
+ 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 {
+ 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 */
+#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 {
+ 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.
+
+/*
+ * 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;
+/*
+ * 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
+
+/*
+ * 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");
+}
+
+/*
++ * Raise an interrupt.
+ * Examine next input record, and decide if need to raise an interrupt, and
+ * if so which one.
+ */
+ 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++) {
+ ** 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
+ 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,
+ 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);
+}
+
+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,
+ 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);
+ 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,
+}
+
+/*
-+ * 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
+ */
+ 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.
+ */
+ 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).
+ */
+
+ 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
+ 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 *);
+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.
-+ **/
-+
+/* --------------------------------------------------------------------- */
+
+/*
+pa2_ctl_mode_read_redo(
+ pa2_t *fp)
+{
++
+ /*
+ * Returned the mode, as we know it, to the caller so nothing
+ * to be done here.
+ * 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
+ 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;
+}
+ 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;
+ 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) {
+
+/* --------------------------------------------------------------------- */
+
++/*
++ * 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,
+ 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);
+pa2_ctl_version_get_redo(
+ pa2_t *fp)
+{
++
+ PRINT_DEBUG(PA2_DBG_MID, "ctl_version_get_redo\n");
+ return 0;
+}
+ 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");
+ 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");
+ pa2_t *fp,
+ pa2_cmd_t *cmdp)
+{
++ pa2_state_t *ssp;
+ int ret;
+
+ ASSERT(cmdp->pc_cmd == PA2_CTL_CMD_AUX_ENABLE);
+ 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;
+}
+ * 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
+pa2_ctl_aux_test_redo(
+ pa2_t *fp)
+{
++
+ PRINT_DEBUG(PA2_DBG_MID, "ctl_aux_test_redo\n");
+ return 0;
+}
+/*
+ * 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
+ 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++;
+pa2_ctl_self_test_redo(
+ pa2_t *fp)
+{
++
+ PRINT_DEBUG(PA2_DBG_MID, "ctl_self_test_redo\n");
+ return 0;
+}
+pa2_ctl_kbd_test_redo(
+ pa2_t *fp)
+{
++
+ PRINT_DEBUG(PA2_DBG_MID, "ctl_kbd_test_redo\n");
+ return 0;
+}
+ 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");
+ 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;
+}
+
+ 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");
+pa2_ctl_inport_read_redo(
+ pa2_t *fp)
+{
++
+ PRINT_DEBUG(PA2_DBG_MID, "ctl_inport_read_redo\n");
+ return 0;
+}
+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,
+ 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);
+ 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));
+/*****************************************************************/
+
+/*
-+ * 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
+pa2_ctl_obuf_write_redo(
+ pa2_t *fp)
+{
++
+ PRINT_DEBUG(PA2_DBG_MID, "ctl_obuf_write_redo\n");
+ return 0;
+}
+/*****************************************************************/
+
+/*
-+ * 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
+ 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");
+ 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");
+pa2_ctl_write_aux_obuf_redo(
+ pa2_t *fp)
+{
++
+ PRINT_DEBUG(PA2_DBG_MID, "ctl_write_aux_obuf_redo\n");
+ return 0;
+}
+/*****************************************************************/
+
+/*
-+ * 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
+ 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);
+ 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;
+ 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));
+{
+ 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");
+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;
+}
+
+ 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;
+}
+
+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;
+}
+
+ 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;
+}
+
+pa2_ctl_enable_a20_redo(
+ pa2_t *fp)
+{
++
+ PRINT_DEBUG(PA2_DBG_MID, "ctl_enable_a20_redo\n");
+ return 0;
+}
+/*****************************************************************/
+
+/*
-+ * 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
+ 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;
+ 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);
+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;
+}
+
+ 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;
+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,
+ 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,
+ },
+};
+
-+/* 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 *);
+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(
+ 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
+ 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));
+ 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);
+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
+ 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");
+pa2_kbd_get_id_redo(
+ pa2_t *fp)
+{
++
+ PRINT_DEBUG(PA2_DBG_MID, "kbd_get_id_redo\n");
+ return 0;
+}
+
+/************************************************************/
+
-+/* 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
+ 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));
+ 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 {
+ 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);
+
+ 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;
+
+/************************************************************/
+
-+/* 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
+ 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;
+}
+
+/************************************************************/
+
-+/* 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
+ 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));
+ 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;
+
+/************************************************************/
+
++/*
++ * 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,
+ },
+};
+
-+/* 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);
+static int pa2_aux_default_set_do(pa2_t *);
+static int pa2_aux_reset_do(pa2_t *);
+
-+
-+/**
-+ ** Aux cmd done functions.
-+ **/
-+
+/**********************************************************************/
+
+/*
+ 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;
+
+ 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) {
+pa2_aux_synap_e1_redo(
+ pa2_t *fp)
+{
++
+ PRINT_DEBUG(PA2_DBG_MID, "aux_synap_e1_redo\n");
+ return 0;
+}
+ 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");
+ 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;
+ break;
+
+ default:
-+ pa2_error("XXXXX");
++ pa2_error("Extra write byte for 0xE2: 0x%X\n", byte);
+ ret = 1;
+ break;
+ }
+ 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;
+}
+ 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);
+ 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;
+ 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;
+}
+ 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);
+ 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;
+ 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;
+}
+
+ uint8_t byte)
+{
+ pa2_state_t *ssp;
++ pa2_aux_state_t *pap;
+ int ret;
+
+ ASSERT(cmdp->pc_aux_cmd == PA2_AUX_CMD_RES_SET);
+
+ /*
+ * 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;
+ 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,
+{
+ 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:
+ 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 {
+ "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;
+ 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
+ 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;
+ 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:
+ 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",
+
+ 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) {
+ }
+ 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;
+
+ */
+
+ 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;
+ 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
+ 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;
+pa2_aux_get_status_redo(
+ pa2_t *fp)
+{
++
+ PRINT_DEBUG(PA2_DBG_MID, "aux_get_status_redo\n");
+ return 0;
+}
+ 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;
+}
+ 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,
+ 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));
+ 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;
+}
+ 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));
+ 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);
+pa2_aux_poll_redo(
+ pa2_t *fp)
+{
++
+ PRINT_DEBUG(PA2_DBG_MID, "aux_poll_redo\n");
+ return 0;
+}
+ 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;
+}
+ 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);
+ }
+ 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;
+}
+ * 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
+ */
+
+ 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;
+}
+ 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);
+ }
+ 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);
+ 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;
+}
+ 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;
+}
+ 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);
+ }
+ 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));
+ 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;
+}
+ 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);
+ }
+ }
+ break;
+
-+ case 1:
++ case 1: /* AUX type */
+ if (scp->psc_hv_flgs & PA2_HV_CONST_AUX_TYPE) {
+ ASSERT(scp->psc_aux_type == byte);
+ }
+pa2_aux_type_get_redo(
+ pa2_t *fp)
+{
++
+ PRINT_DEBUG(PA2_DBG_MID, "aux_type_get_redo\n");
+ return 0;
+}
+ 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);
+ 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;
+}
+ 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);
+ }
+ 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;
+ 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 */
+ 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;
+ 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;
+pa2_aux_sample_set_redo(
+ pa2_t *fp)
+{
++
+ PRINT_DEBUG(PA2_DBG_MID, "aux_sample_set_redo\n");
+ return -1; /* XXXXXXXXXXXXXXXXXXXXX */
+}
+ 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;
+}
+ 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);
+ }
+ 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));
+ 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;
+}
+ 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;
+}
+ 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);
+ }
+ 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));
+ 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;
+}
+ 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
+ */
+
+ 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...
+ 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;
+ }
+ }
+ }
+ * reset.
+ */
+
-+ ssp->pss_setscale_last = 0;
++ if (ssp->pss_aux_index == 0) {
++ ssp->pss_setscale_last = 0;
++ }
+ return;
+}
+
+ 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));
+ 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);
+ }
+ 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);
+ 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);
+ }
+pa2_aux_ack_redo(
+ pa2_t *fp)
+{
++
+ PRINT_DEBUG(PA2_DBG_MID, "aux_ack_redo\n");
+ return 0;
+}
+ * 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
+ 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;
+}
+ 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);
+ }
+ 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;
+
+/*******************************************************************/
+
++/*
++ * 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,
+ },
+};
+
-+#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
+ 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;
+ }
+
+ /*
-+ * 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);
+ 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;
+ 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);
+ 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;
+}
+
+/*
-+ * 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 *
+ 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);
+ }
+
+ 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;
+ 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 ||
+}
+
+/*
-+ * 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 *
+ ~(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);
+}
+
+/*
-+ * 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 *
+ 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;
+ }
+ if (ccp == NULL) {
+ pa2_error("ctl_cmd_load: bad cmd: 0x%X\n", cmd);
-+ /* abort any current cmds? XXX */
+ cmdp = NULL;
+ goto out;
+ }
+ 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);
+ 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) {
+ 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;
+}
+
+/*
-+ * 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
+ 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);
+ 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) {
+ }
+
+ /*
-+ * 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;
+}
+
+/*
-+ * 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
+ 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;
+}
+
+/*
-+ * 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
+ fp->pp_key_esc = 1;
+ break;
+
-+ /* need to handle E1, etc XXX */
-+
+ default:
+ esc = fp->pp_key_esc;
+ if (fp->pp_key_esc) {
+ * 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).
+ */
+
+ num = UINT_MAX;
+ }
+
++ /*
++ * Read records from kernel in batches that fit into the
++ * prec[] array.
++ */
++
+ count = 0;
+ phd.ph_records = &prec[0];
+ do {
+ }
+
+ /*
-+ * 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) {
+
+ /*
+ * 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.
+ */
+
+ * 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);
+}
+
+/*
-+ * 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
+ }
+
+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,
+ (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;
+ goto out;
+ }
+
-+
+out:
+#if defined(PA2_DEBUG)
+ /*
+
+/*
+ * 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
+ 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,
+ * 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);
+ pa2_irq_lower(fp);
+
+ /*
-+ * Raise an interrupt associated with the next interrupt.
++ * Raise an interrupt if required.
+ */
+
+ pa2_irq_raise(fp);
+ 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,
+ 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,
+ * (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) {
+
+ /*
+ * 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;
+ 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) {
+ }
+
+ /*
-+ * 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);
+ }
+ }
+
++ /*
++ * 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;
+ "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 |
+ return;
+}
+
++/*
++ * Function called when guest writes to the data register.
++ */
++
+static void
+pa2_guest_data_write(
+ void *opq,
+ pa2_t *fp,
+ uint32_t cmd)
+{
++ pa2_state_t *ssp;
+ pa2_cmd_t *cmdp;
+ int ret;
+ uint8_t byte;
+ 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) {
+ }
+
+ /*
-+ * 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);
+ return;
+}
+
++/*
++ * Function called when guest writes to the command register.
++ */
++
+static void
+pa2_guest_cmd_write(
+ void *opq,
+
+/*
+ * Interrupt from i8042.
++ * Called from the qemu_set_fd_handler() when there is data available in
++ * the kernel to read.
+ */
+
+static void
+
+ /*
+ * Read interrupt records. If none found, then nothing else to do.
-+ * Remember first free record, so can examine it later.
+ */
+
+ PRINT_DEBUG_ENTER("\n");
+
+/*
+ * 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
+ 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)
+ 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)
+ 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,
+ 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,
+{
+ 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,
+ 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,
+
+/*
+ * 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
+ 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;
+}
+
+/*
-+ * Test the controller can talk to the keyboard.
-+ */
-+
-+/*
+ * Set LEDS to given state.
+ */
+
+ 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;
+ 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];
+ 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;
+}
+ 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.
+ **/
+ 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;
+}
+ 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;
+}
+
+ 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;
+}
+
+ 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 */
+ 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;
+}
+
+}
+
+/*
-+ * 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.
+ 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");
+ 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)
+ }
+ 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,
+
+ 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;
+ }
+
+ 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;
+ }
+ 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(
+ 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)) {
+ }
+ 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) {
+ 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)
+ 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;
+ 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;
+ 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;
+ ret = 0;
+ PRINT_DEBUG(PA2_DBG_HIGH, "aux_init: %u\n", step);
+ switch (step) {
-+
+ case 0:
+ /*
+ * Clear Synaptic mode_byte. This puts us in
+ * 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:
+ * 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 {
+ * 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:
+ 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;
+
+ 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)
+ 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) {
+ 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
+ break;
+
+ case 7:
-+ /* only AUX XXX */
+ (void) pa2_ctl_aux_disable_do(fp);
+ ret = pa2_ctl_mode_write_do(fp, ssp->pss_mode);
+ break;
+ 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;
+ p28p->p28_bytes[10] = 0x00;
+ }
+ break;
-+#endif
+
+ case 12:
+ /*
-+ * Reset.
++ * Set the scaling.
+ */
+
+ (void) pa2_ctl_aux_disable_do(fp);
+
+ case 14:
+ /*
-+ * Reset.
++ * Ensure disabled.
+ */
+
+ (void) pa2_ctl_aux_disable_do(fp);
+ break;
+
+ case 15:
++
++ /*
++ * Empty AUX input.
++ */
++
+ pa2_drain(fp, PA2_INDEX_AUX);
+ break;
+
+}
+
+
-+/*
-+ * Intialize the KBD.
-+ */
-+
+static int
+pa2_kbd_init(
+ pa2_t *fp)
+ 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;
+ break;
+
+ case 4:
-+ /* only KBD XXX */
+ (void) pa2_ctl_kbd_disable_do(fp);
+ ret = pa2_ctl_mode_write_do(fp, ssp->pss_mode);
+ break;
+ 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)
+ 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);
+ 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);
+ 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:
+ * 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:
+ 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;
+}
+
+/*
-+ * Before releasing a device, disable it and interrupts.
++ * This function is called before releasing a device; disable it and interrupts.
+ */
+
+static int
+ 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];
+ 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);
+ 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;
+ }
+}
+
+/*
-+ * 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
+{
+ 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;
+ 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;
+ **/
+
+/*
-+ * Add key combination into our trap table.
++ * Add key combination into our trap table of key bindings.
++ * Called from dom0_driver.
+ */
+
+void
+ 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...
+ */
+
+ return;
+}
+
++/*
++ * A no-op for us?
++ */
++
+void
+pa2_kbd_secure(
+ void (*ugh)(int))
+ return;
+}
+
++/*
++ * Called from dom0_driver to grab the AUX (grab == 1), or to release the
++ * AUX (grab == 0).
++ */
++
+int
+pa2_aux_grab(
+ int grab)
+ if (cmdp->pc_cmd != 0) {
+ ASSERT(cmdp->pc_active == 1);
+ cmd = *cmdp;
-+ /* should abort cmd XXX */
+ saved_cmd = 1;
+ }
+
+ *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);
+ 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);
+ 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)
+ 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;
+
+ /*
+ * Releasing KBD?
-+ * First, complete any outstanding KBD cmd.
-+ * What about ctl cmds?
+ */
+
+ memset(&gp, 0, sizeof (gp));
+ 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];
+ }
+ 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
+ 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,
+ *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);
+ }
+ 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;
+ return 1;
+}
+
++/*
++ * Probe is no-op for PS/2.
++ * PS/2 hotplug for AUX devices should do something here.
++ */
++
+void
+pa2_probe(
+ int grab)
+ * 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
+ /*
+ * 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;
+ }
+
+ /*
-+ * 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,
+ 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));
+
+unlock:
+ /*
-+ * Unlock.
++ * Drop the initialization lock.
+ */
+
+ byte = 0;
+ }
+ }
+ PRINT_DEBUG_EXIT("\n");
-+ /* should be able to return an error XXX */
+ return;
+}
diff --git a/pass2.h b/pass2.h