File: sqUnixFBDevMousePS2.c

package info (click to toggle)
squeak-vm 1%3A4.10.2.2614-4.1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 13,284 kB
  • ctags: 15,344
  • sloc: ansic: 75,096; cs: 11,191; objc: 5,494; sh: 3,170; asm: 1,533; cpp: 449; pascal: 372; makefile: 366; awk: 103
file content (208 lines) | stat: -rw-r--r-- 5,866 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/* sqUnixFBDevMousePS2.c -- weirdness unique to PS/2 mice
 * 
 * Author: Ian.Piumarta@INRIA.Fr
 * 
 * Last edited: 2009-08-19 04:35:03 by piumarta on emilia-2.local
 */

/* The framebuffer display driver was donated to the Squeak community by:
 * 
 *	Weather Dimensions, Inc.
 *	13271 Skislope Way, Truckee, CA 96161
 *	http://www.weatherdimensions.com
 *
 * Copyright (C) 2003 Ian Piumarta
 * All Rights Reserved.
 * 
 * This file is part of Unix Squeak.
 * 
 *   Permission is hereby granted, free of charge, to any person obtaining a copy
 *   of this software and associated documentation files (the "Software"), to deal
 *   in the Software without restriction, including without limitation the rights
 *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *   copies of the Software, and to permit persons to whom the Software is
 *   furnished to do so, subject to the following conditions:
 * 
 *   The above copyright notice and this permission notice shall be included in
 *   all copies or substantial portions of the Software.
 * 
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *   SOFTWARE.
 */

#define PS2_DISABLE_DELAY   100*1000
#define PS2_RESET_DELAY	   1500*1000
#define PS2_FLUSH_DELAY	    100*1000
#define PS2_READ_DELAY	    100*1000
#define PS2_SEND_DELAY	    100*1000

#define	PS2_RESET		0xff
#define	PS2_RESEND		0xfe
#define	PS2_ERROR		0xfc
#define	PS2_OK			0xfa
#define	PS2_SET_DEFAULTS	0xf6
#define	PS2_DISABLE		0xf5
#define	PS2_ENABLE		0xf4
#define	PS2_SET_SAMPLE_RATE	0xf3
#define	PS2_GET_ID		0xf2
#define	PS2_SET_REMOTE_MODE	0xf0
#define	PS2_SET_WRAP_MODE	0xee
#define	PS2_RESET_WRAP_MODE	0xec
#define	PS2_READ_DATA		0xeb
#define	PS2_SET_STREAM_MODE	0xea
#define	PS2_STATUS_REQUEST	0xe9
#define	PS2_SELFTEST_OK		0xaa


static void ms_ps2_flush(_self)
{
  unsigned char buf[32];
  debugf("%s: flush\n", self->msName);
  while (ms_read(self, buf, sizeof(buf), 1, PS2_FLUSH_DELAY))
    ;
}


static void ms_ps2_handleEvents(_self)
{
  unsigned char buf[3*8];
  int		n;
  
  if ((n= ms_read(self, buf, sizeof(buf), 3, PS2_READ_DELAY)) >= 3)
    {
      unsigned char *cmd= buf;
      while (n >= 3)
	{
	  int b= 0, dx, dy;
	  // The protocol requires the top 2 bits clear and bit 3 set.
	  // Some Micro$oft mice violate this, but any luser stupid
	  // enough to buy a M$ mouse deserves what they get.
	  if (0x08 != (cmd[0] & 0xc8))
	    {
	      fprintf(stderr, "%s: illegal command: %02x %02x %02x\n", self->msName,
		      cmd[0], cmd[1], cmd[2]);
	      ms_ps2_flush(self);	// resync the stream
	      return;
	    }
	  if (cmd[0] & 1) b |= RedButtonBit;
	  if (cmd[0] & 2) b |= BlueButtonBit;
	  if (cmd[0] & 4) b |= YellowButtonBit;
	  dx= cmd[1];  if (cmd[0] & 0x10) dx -= 256;
	  dy= cmd[2];  if (cmd[0] & 0x20) dy -= 256;
	  dy= -dy;
	  self->callback(b, dx, dy);
	  n -= 3;  cmd += 3;
	}
    }
}


static int ms_ps2_send(_self, unsigned char *command, int len)
{
  unsigned char buf[1];
  int i;
  debugf("%s: send\n", self->msName);
  for (i= 0;  i < len;  ++i)
    {
    resend:
      if (1 != write(self->fd, command + i, 1))
	{
	  debugf("%s: send failed during write\n", self->msName);
	  return 0;
	}
      debugf(">%02x\n", command[i]);
      if (1 != ms_read(self, buf, 1, 1, PS2_SEND_DELAY))
	{
	  debugf("%s: send failed during read\n", self->msName);
	  return 0;
	}
      switch (buf[0])
	{
	case PS2_OK:
	case PS2_SELFTEST_OK:	/* /dev/input/mice emulation is broken */
	  break;
	case PS2_ERROR:
	  fprintf(stderr, "%s: error response in send\n", self->msName);
	  return 0;
	case PS2_RESEND:
	  debugf("%s: resend\n", self->msName);
	  goto resend;
	default:
	  fprintf(stderr, "%s: illegal response %02x in send\n", self->msName, buf[0]);
	  break;
	}
    }
  return 1;
}


static void ms_ps2_disable(_self)
{
  unsigned char command[]= { PS2_DISABLE };
  debugf("%s: disable\n", self->msName);
  if (1 != write(self->fd, command, 1))
    {
      debugf("%s: disable failed during write\n", self->msName);
      return;
    }
  debugf(">%02x\n", command[0]);
  while (1 == ms_read(self, command, 1, 1, PS2_DISABLE_DELAY))
    if (PS2_OK == command[0])
      break;
}


static int ms_ps2_enable(_self)
{
  unsigned char command[]= { PS2_ENABLE };
  debugf("%s: enable\n", self->msName);
  return ms_ps2_send(self, command, sizeof(command));
}


static int ms_ps2_reset(_self)
{
  unsigned char command[]= { PS2_RESET }, buf[2];
  debugf("%s: reset\n", self->msName);
  if (!ms_ps2_send(self, command, sizeof(command)))
    return -1;
  if (2 == ms_read(self, buf, 2, 2, PS2_RESET_DELAY))
    {
      debugf("%s: response %02x %02x\n", self->msName, buf[0], buf[1]);
      switch (buf[0])
	{
	case PS2_SELFTEST_OK:
	  return buf[1];	// mouse device id
	  break;
	case PS2_ERROR:
	  fprintf(stderr, "%s: self-test failed\n", self->msName);
	  break;
	default:
	  debugf("%s: bad response\n", self->msName);
	  break;
	}
    }
  /* /dev/input/mice emulation returns PS2_SELFTEST_OK where send()
     expects PS2_OK, causing control to fall through to here.  we pick
     up the mouse id immediately in the flush(), so the only harm done
     is a misleading "reset failed" message while debugging.  */
  ms_ps2_flush(self);
  debugf("%s: reset failed\n", self->msName);
  return -1;
}


static void ms_ps2_init(_self)
{
  int id;
  ms_ps2_disable(self);
  id= ms_ps2_reset(self);
  debugf("%s: mouse id %02x\n", self->msName, id);
  ms_ps2_enable(self);
}