1/** 2 * \file 3 * \brief Basic PS/2 mouse protocol driver 4 */ 5 6/* 7 * Copyright (c) 2011, ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <stdio.h> 16#include <barrelfish/barrelfish.h> 17 18#include "lpc_kbd.h" 19 20#if 0 21#define DEBUG(x...) debug_printf(x) 22#else 23#define DEBUG(x...) (void)0 24#endif 25 26// subset of commands 27#define CMD_ACK 0xfa ///< ACK *from the mouse* in response to a command 28#define CMD_RESET 0xff ///< Reset the mouse 29#define CMD_SETDEFAULTS 0xf6 ///< Apply default values 30#define CMD_DISABLE 0xf5 ///< Disable data reporting 31#define CMD_ENABLE 0xf4 ///< Enable data reporting 32#define CMD_GETDEVID 0xf2 ///< Get device ID 33 34// when the mouse is plugged in or resets itself, it sends these in sequence 35#define RESET0 0xaa 36#define RESET1 0x00 37 38// state of data reception path 39static enum { 40 STATE_IDLE, ///< Nothing doing 41 STATE_PKT1, ///< We saw the first byte of a 3- or 4-byte packet 42 STATE_PKT2, ///< We saw the first two bytes of a 3- or 4-byte packet 43 STATE_PKT3, ///< We saw the first three bytes of a 4-byte packet 44 STATE_SEND_CMD, ///< We sent a command, and we're waiting for the ack 45} data_state; 46 47// state of initialisation path (next level up) 48static enum { 49 INIT_STATE_STARTUP, ///< Just started... 50 INIT_STATE_SENT_RESET, ///< Sent reset command 51 INIT_STATE_SENT_DEFAULTS, ///< Sent set defaults command 52 INIT_STATE_SENT_ENABLE, ///< Sent enable commant 53 INIT_STATE_COMPLETE, ///< Up and running 54 INIT_STATE_SAW_RESET, ///< Saw a reset packet 55} init_state; 56 57static bool sending_command; 58 59static void init_data(uint8_t val); 60 61static void handle_packet(uint8_t *buf, size_t len) 62{ 63 assert(len == 3); 64 65 // unpack packet (TODO: use Mackerel?) 66 bool yoverflow = (buf[0] & 0x80) != 0; 67 bool xoverflow = (buf[0] & 0x40) != 0; 68 bool ysign = (buf[0] & 0x20) != 0; 69 bool xsign = (buf[0] & 0x10) != 0; 70 bool always1 = (buf[0] & 0x08) != 0; 71 bool buttonm = (buf[0] & 0x04) != 0; 72 bool buttonr = (buf[0] & 0x02) != 0; 73 bool buttonl = (buf[0] & 0x01) != 0; 74 uint8_t uxdelta = buf[1]; 75 uint8_t uydelta = buf[2]; 76 77 if (!always1) { 78 DEBUG("invalid packet, discarded\n"); 79 return; 80 } 81 82 if (yoverflow || xoverflow) { 83 DEBUG("X or Y overflow set: probably bogus?\n"); 84 return; 85 } 86 87 int xdelta, ydelta; 88 89 if (ysign) { 90 ydelta = uydelta | (-1 & ~0xff); 91 } else { 92 ydelta = uydelta; 93 } 94 95 if (xsign) { 96 xdelta = uxdelta | (-1 & ~0xff); 97 } else { 98 xdelta = uxdelta; 99 } 100 101 DEBUG("%dx%d L%u M%u R%u\n", xdelta, ydelta, buttonl, buttonm, buttonr); 102 mouse_event(xdelta, ydelta, buttonl, buttonm, buttonr); 103} 104 105// this is called when we receive a byte from the mouse 106void mouse_data(uint8_t val) 107{ 108 static uint8_t buf[3]; 109 110 if (sending_command) { 111 DEBUG("ignored 0x%x while sending command\n", val); 112 return; 113 } 114 115 DEBUG("got 0x%x in state %d:%d\n", val, data_state, init_state); 116 117 switch (data_state) { 118 case STATE_IDLE: 119 if (init_state == INIT_STATE_COMPLETE) { 120 buf[0] = val; 121 data_state++; 122 } 123 break; 124 125 case STATE_PKT1: 126 buf[1] = val; 127 if (buf[0] == RESET0 && buf[1] == RESET1) { 128 init_state = INIT_STATE_SAW_RESET; 129 data_state = STATE_IDLE; 130 init_data(0); 131 } else { 132 data_state++; 133 } 134 break; 135 136 case STATE_PKT2: 137 buf[2] = val; 138 handle_packet(buf, sizeof(buf)); 139 data_state = STATE_IDLE; 140 break; 141 142 case STATE_SEND_CMD: 143 if (val == CMD_ACK) { 144 data_state = STATE_IDLE; 145 init_data(val); 146 } else { 147 DEBUG("unexpected data %x while waiting for command ACK\n", val); 148 } 149 break; 150 151 default: 152 USER_PANIC("unhandled state %d\n", data_state); 153 } 154} 155 156static void send_cmd(uint8_t cmd) 157{ 158 DEBUG("sending 0x%x in state %d:%d\n", cmd, data_state, init_state); 159 160 assert(data_state == STATE_IDLE); 161 data_state = STATE_SEND_CMD; 162 sending_command = true; 163 send_mouse_cmd(cmd); 164 sending_command = false; 165} 166 167static void init_data(uint8_t val) 168{ 169 switch (init_state) { 170 case INIT_STATE_STARTUP: 171 send_cmd(CMD_RESET); 172 init_state = INIT_STATE_SENT_RESET; 173 break; 174 175 case INIT_STATE_SENT_RESET: 176 assert(val == CMD_ACK); 177 case INIT_STATE_SAW_RESET: 178 send_cmd(CMD_SETDEFAULTS); 179 init_state = INIT_STATE_SENT_DEFAULTS; 180 break; 181 182 case INIT_STATE_SENT_DEFAULTS: 183 assert(val == CMD_ACK); 184 send_cmd(CMD_ENABLE); 185 init_state = INIT_STATE_SENT_ENABLE; 186 break; 187 188 case INIT_STATE_SENT_ENABLE: 189 assert(val == CMD_ACK); 190 init_state = INIT_STATE_COMPLETE; 191 break; 192 193 case INIT_STATE_COMPLETE: 194 USER_PANIC("unexpected data 0x%x in complete init state\n", val); 195 break; 196 } 197} 198 199// this is called when we initialise 200void mouse_init(void) 201{ 202 init_state = INIT_STATE_STARTUP; 203 init_data(0); 204} 205