vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / bus_managers / ps2 / ps2_standard_mouse.cpp
blobe9647f9a1de2702014baff58d21bfbcff16732a6
1 /*
2 * Copyright 2001-2014 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors (in chronological order):
6 * Elad Lahav, elad@eldarshany.com
7 * Stefano Ceccherini, burton666@libero.it
8 * Axel Dörfler, axeld@pinc-software.de
9 * Marcus Overhagen, marcus@overhagen.de
10 * Clemens Zeidler, czeidler@gmx.de
11 * John Scipione, jscipione@gmail.com
15 /*! PS/2 mouse device driver
17 A PS/2 mouse is connected to the IBM 8042 controller, and gets its
18 name from the IBM PS/2 personal computer, which was the first to
19 use this device. All resources are shared between the keyboard, and
20 the mouse, referred to as the "Auxiliary Device".
22 I/O:
23 ~~~
24 The controller has 3 I/O registers:
25 1. Status (input), mapped to port 64h
26 2. Control (output), mapped to port 64h
27 3. Data (input/output), mapped to port 60h
29 Data:
30 ~~~~
31 A packet read from the mouse data port is composed of
32 three bytes:
33 byte 0: status byte, where
34 - bit 7: Y overflow (1 = true)
35 - bit 6: X overflow (1 = true)
36 - bit 5: MSB of Y offset
37 - bit 4: MSB of X offset
38 - bit 3: Syncronization bit (always 1)
39 - bit 2: Middle button (1 = down)
40 - bit 1: Right button (1 = down)
41 - bit 0: Left button (1 = down)
42 byte 1: X position change, since last probed (-127 to +127)
43 byte 2: Y position change, since last probed (-127 to +127)
45 Intellimouse mice send a four byte packet, where the first three
46 bytes are the same as standard mice, and the last one reports the
47 Z position, which is, usually, the wheel movement.
49 Interrupts:
50 ~~~~~~~~~~
51 The PS/2 mouse device is connected to interrupt 12.
52 The controller uses 3 consecutive interrupts to inform the computer
53 that it has new data. On the first the data register holds the status
54 byte, on the second the X offset, and on the 3rd the Y offset.
58 #include <stdlib.h>
59 #include <string.h>
61 #include <keyboard_mouse_driver.h>
63 #include "ps2_service.h"
64 #include "ps2_standard_mouse.h"
67 const char* kStandardMousePath[4] = {
68 "input/mouse/ps2/standard_0",
69 "input/mouse/ps2/standard_1",
70 "input/mouse/ps2/standard_2",
71 "input/mouse/ps2/standard_3"
74 const char* kIntelliMousePath[4] = {
75 "input/mouse/ps2/intelli_0",
76 "input/mouse/ps2/intelli_1",
77 "input/mouse/ps2/intelli_2",
78 "input/mouse/ps2/intelli_3"
82 //! Set sampling rate of the ps2 port.
83 static inline status_t
84 ps2_set_sample_rate(ps2_dev* dev, uint8 rate)
86 return ps2_dev_command(dev, PS2_CMD_SET_SAMPLE_RATE, &rate, 1, NULL, 0);
90 //! Converts a packet received by the mouse to a "movement".
91 static void
92 ps2_packet_to_movement(standard_mouse_cookie* cookie, uint8 packet[],
93 mouse_movement* pos)
95 int buttons = packet[0] & 7;
96 int xDelta = ((packet[0] & 0x10) ? ~0xff : 0) | packet[1];
97 int yDelta = ((packet[0] & 0x20) ? ~0xff : 0) | packet[2];
98 int xDeltaWheel = 0;
99 int yDeltaWheel = 0;
100 bigtime_t currentTime = system_time();
102 if (buttons != 0 && cookie->buttons_state == 0) {
103 if (cookie->click_last_time + cookie->click_speed > currentTime)
104 cookie->click_count++;
105 else
106 cookie->click_count = 1;
108 cookie->click_last_time = currentTime;
111 cookie->buttons_state = buttons;
113 if (cookie->flags & F_MOUSE_TYPE_INTELLIMOUSE) {
114 yDeltaWheel = packet[3] & 0x07;
115 if (packet[3] & 0x08)
116 yDeltaWheel |= ~0x07;
118 #if 0
119 if (cookie->flags & F_MOUSE_TYPE_2WHEELS) {
120 switch (packet[3] & 0x0F) {
121 case 0x01: yDeltaWheel = +1; break; // wheel 1 down
122 case 0x0F: yDeltaWheel = -1; break; // wheel 1 up
123 case 0x02: xDeltaWheel = +1; break; // wheel 2 down
124 case 0x0E: xDeltaWheel = -1; break; // wheel 2 up
127 #endif
129 #if 0
130 TRACE("packet: %02x %02x %02x %02x: xd %d, yd %d, 0x%x (%d), w-xd %d, "
131 "w-yd %d\n", packet[0], packet[1], packet[2], packet[3],
132 xDelta, yDelta, buttons, cookie->click_count, xDeltaWheel,
133 yDeltaWheel);
134 #endif
136 if (pos != NULL) {
137 pos->xdelta = xDelta;
138 pos->ydelta = yDelta;
139 pos->buttons = buttons;
140 pos->clicks = cookie->click_count;
141 pos->modifiers = 0;
142 pos->timestamp = currentTime;
143 pos->wheel_ydelta = yDeltaWheel;
144 pos->wheel_xdelta = xDeltaWheel;
146 TRACE("ps2: ps2_packet_to_movement xdelta: %d, ydelta: %d, buttons %x, "
147 "clicks: %d, timestamp %Ld\n",
148 xDelta, yDelta, buttons, cookie->click_count, currentTime);
153 //! Read a mouse event from the mouse events chain buffer.
154 static status_t
155 standard_mouse_read_event(standard_mouse_cookie* cookie,
156 mouse_movement* movement)
158 uint8 packet[PS2_MAX_PACKET_SIZE];
159 status_t status;
161 TRACE("ps2: standard_mouse_read_event\n");
163 status = acquire_sem_etc(cookie->standard_mouse_sem, 1, B_CAN_INTERRUPT, 0);
164 TRACE("ps2: standard_mouse_read_event acquired\n");
165 if (status < B_OK)
166 return status;
168 if (!cookie->dev->active) {
169 TRACE("ps2: standard_mouse_read_event: Error device no longer "
170 "active\n");
171 return B_ERROR;
174 if (packet_buffer_read(cookie->standard_mouse_buffer, packet,
175 cookie->dev->packet_size) != cookie->dev->packet_size) {
176 TRACE("ps2: error copying buffer\n");
177 return B_ERROR;
180 if (!(packet[0] & 8))
181 panic("ps2: got broken data from packet_buffer_read\n");
183 ps2_packet_to_movement(cookie, packet, movement);
184 return B_OK;
188 // #pragma mark - Interrupt handler functions
191 void
192 standard_mouse_disconnect(ps2_dev* dev)
194 // the mouse device might not be opened at this point
195 INFO("ps2: ps2_standard_mouse_disconnect %s\n", dev->name);
196 if (dev->flags & PS2_FLAG_OPEN)
197 release_sem(((standard_mouse_cookie*)dev->cookie)->standard_mouse_sem);
201 /*! Interrupt handler for the mouse device. Called whenever the I/O
202 controller generates an interrupt for the PS/2 mouse. Reads mouse
203 information from the data port, and stores it, so it can be accessed
204 by read() operations. The full data is obtained using 3 consecutive
205 calls to the handler, each holds a different byte on the data port.
207 int32
208 standard_mouse_handle_int(ps2_dev* dev)
210 standard_mouse_cookie* cookie = (standard_mouse_cookie*)dev->cookie;
211 const uint8 data = dev->history[0].data;
213 TRACE("ps2: standard mouse: %1x\t%1x\t%1x\t%1x\t%1x\t%1x\t%1x\t%1x\n",
214 data >> 7 & 1, data >> 6 & 1, data >> 5 & 1,
215 data >> 4 & 1, data >> 3 & 1, data >> 2 & 1,
216 data >> 1 & 1, data >> 0 & 1);
218 if (cookie->packet_index == 0 && (data & 8) == 0) {
219 INFO("ps2: bad mouse data, trying resync\n");
220 return B_HANDLED_INTERRUPT;
223 // Workarounds for active multiplexing keyboard controllers
224 // that lose data or send them to the wrong port.
225 if (cookie->packet_index == 0 && (data & 0xc0) != 0) {
226 INFO("ps2: strange mouse data, x/y overflow, trying resync\n");
227 return B_HANDLED_INTERRUPT;
230 cookie->buffer[cookie->packet_index++] = data;
232 if (cookie->packet_index != dev->packet_size) {
233 // packet not yet complete
234 return B_HANDLED_INTERRUPT;
237 // complete packet is assembled
239 cookie->packet_index = 0;
240 if (packet_buffer_write(cookie->standard_mouse_buffer,
241 cookie->buffer, dev->packet_size) != dev->packet_size) {
242 // buffer is full, drop new data
243 return B_HANDLED_INTERRUPT;
246 release_sem_etc(cookie->standard_mouse_sem, 1, B_DO_NOT_RESCHEDULE);
248 return B_INVOKE_SCHEDULER;
252 // #pragma mark - probe_standard_mouse()
255 status_t
256 probe_standard_mouse(ps2_dev* dev)
258 status_t status;
259 uint8 deviceId = 0;
261 // get device id
262 status = ps2_dev_command(dev, PS2_CMD_GET_DEVICE_ID, NULL, 0,
263 &deviceId, 1);
264 if (status != B_OK) {
265 INFO("ps2: probe_mouse get device id failed\n");
266 return B_ERROR;
269 TRACE("ps2: probe_mouse device id: %2x\n", deviceId);
271 // check for MS Intellimouse
272 if (deviceId == 0) {
273 uint8 alternate_device_id;
274 status = ps2_set_sample_rate(dev, 200);
275 status |= ps2_set_sample_rate(dev, 100);
276 status |= ps2_set_sample_rate(dev, 80);
277 status |= ps2_dev_command(dev, PS2_CMD_GET_DEVICE_ID, NULL, 0,
278 &alternate_device_id, 1);
279 if (status == 0) {
280 TRACE("ps2: probe_mouse alternate device id: %2x\n",
281 alternate_device_id);
282 deviceId = alternate_device_id;
286 if (deviceId == PS2_DEV_ID_STANDARD
287 || deviceId == PS2_DEV_ID_TOUCHPAD_RICATECH) {
288 INFO("ps2: probe_mouse Standard PS/2 mouse found\n");
289 dev->name = kStandardMousePath[dev->idx];
290 dev->packet_size = PS2_PACKET_STANDARD;
291 } else if (deviceId == PS2_DEV_ID_INTELLIMOUSE) {
292 dev->name = kIntelliMousePath[dev->idx];
293 dev->packet_size = PS2_PACKET_INTELLIMOUSE;
294 INFO("ps2: probe_mouse Extended PS/2 mouse found\n");
295 } else {
296 INFO("ps2: probe_mouse Error unknown device id.\n");
297 return B_ERROR;
300 return B_OK;
304 // #pragma mark - Device functions
307 status_t
308 standard_mouse_open(const char* name, uint32 flags, void** _cookie)
310 standard_mouse_cookie* cookie;
311 status_t status;
312 ps2_dev* dev = NULL;
313 int i;
315 TRACE("ps2: standard_mouse_open %s\n", name);
317 for (dev = NULL, i = 0; i < PS2_DEVICE_COUNT; i++) {
318 if (0 == strcmp(ps2_device[i].name, name)) {
319 dev = &ps2_device[i];
320 break;
322 #if 0
323 if (0 == strcmp(g_passthrough_dev.name, name)) {
324 dev = &g_passthrough_dev;
325 isSynapticsPTDevice = true;
326 break;
328 #endif
331 if (dev == NULL) {
332 TRACE("ps2: dev = NULL\n");
333 return B_ERROR;
336 if (atomic_or(&dev->flags, PS2_FLAG_OPEN) & PS2_FLAG_OPEN)
337 return B_BUSY;
339 cookie = (standard_mouse_cookie*)malloc(sizeof(standard_mouse_cookie));
340 if (cookie == NULL)
341 goto err1;
343 *_cookie = cookie;
344 memset(cookie, 0, sizeof(*cookie));
346 cookie->dev = dev;
347 dev->cookie = cookie;
348 dev->disconnect = &standard_mouse_disconnect;
349 dev->handle_int = &standard_mouse_handle_int;
351 if (strstr(dev->name, "standard") != NULL)
352 cookie->flags = F_MOUSE_TYPE_STANDARD;
354 if (strstr(dev->name, "intelli") != NULL)
355 cookie->flags = F_MOUSE_TYPE_INTELLIMOUSE;
357 cookie->standard_mouse_buffer
358 = create_packet_buffer(MOUSE_HISTORY_SIZE * dev->packet_size);
359 if (cookie->standard_mouse_buffer == NULL) {
360 TRACE("ps2: can't allocate mouse actions buffer\n");
361 goto err2;
364 // create the mouse semaphore, used for synchronization between
365 // the interrupt handler and the read operation
366 cookie->standard_mouse_sem = create_sem(0, "ps2_standard_mouse_sem");
367 if (cookie->standard_mouse_sem < 0) {
368 TRACE("ps2: failed creating PS/2 mouse semaphore!\n");
369 goto err3;
372 status = ps2_dev_command(dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0);
373 if (status < B_OK) {
374 INFO("ps2: cannot enable mouse %s\n", name);
375 goto err4;
378 atomic_or(&dev->flags, PS2_FLAG_ENABLED);
381 TRACE("ps2: standard_mouse_open %s success\n", name);
382 return B_OK;
384 err4:
385 delete_sem(cookie->standard_mouse_sem);
386 err3:
387 delete_packet_buffer(cookie->standard_mouse_buffer);
388 err2:
389 free(cookie);
390 err1:
391 atomic_and(&dev->flags, ~PS2_FLAG_OPEN);
393 TRACE("ps2: standard_mouse_open %s failed\n", name);
394 return B_ERROR;
398 status_t
399 standard_mouse_close(void* _cookie)
401 standard_mouse_cookie* cookie = (standard_mouse_cookie*)_cookie;
403 TRACE("ps2: standard_mouse_close %s enter\n", cookie->dev->name);
405 ps2_dev_command_timeout(cookie->dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0,
406 150000);
408 delete_packet_buffer(cookie->standard_mouse_buffer);
409 delete_sem(cookie->standard_mouse_sem);
411 atomic_and(&cookie->dev->flags, ~PS2_FLAG_OPEN);
412 atomic_and(&cookie->dev->flags, ~PS2_FLAG_ENABLED);
414 TRACE("ps2: standard_mouse_close %s done\n", cookie->dev->name);
415 return B_OK;
419 status_t
420 standard_mouse_freecookie(void* _cookie)
422 standard_mouse_cookie* cookie = (standard_mouse_cookie*)_cookie;
423 free(cookie);
424 return B_OK;
428 static status_t
429 standard_mouse_read(void* cookie, off_t pos, void* buffer, size_t* _length)
431 *_length = 0;
432 return B_NOT_ALLOWED;
436 static status_t
437 standard_mouse_write(void* cookie, off_t pos, const void* buffer,
438 size_t* _length)
440 *_length = 0;
441 return B_NOT_ALLOWED;
445 status_t
446 standard_mouse_ioctl(void* _cookie, uint32 op, void* buffer, size_t length)
448 standard_mouse_cookie* cookie = (standard_mouse_cookie*)_cookie;
450 switch (op) {
451 case MS_NUM_EVENTS:
453 int32 count;
454 TRACE("ps2: ioctl MS_NUM_EVENTS\n");
455 get_sem_count(cookie->standard_mouse_sem, &count);
456 return count;
459 case MS_READ:
461 mouse_movement movement;
462 status_t status;
463 TRACE("ps2: ioctl MS_READ\n");
464 if ((status = standard_mouse_read_event(cookie, &movement)) < B_OK)
465 return status;
466 // TRACE("%s %d %d %d %d\n", cookie->dev->name,
467 // movement.xdelta, movement.ydelta, movement.buttons,
468 // movement.clicks);
469 return user_memcpy(buffer, &movement, sizeof(movement));
472 case MS_SET_TYPE:
473 TRACE("ps2: ioctl MS_SET_TYPE not implemented\n");
474 return B_BAD_VALUE;
476 case MS_SET_MAP:
477 TRACE("ps2: ioctl MS_SET_MAP (set mouse mapping) not "
478 "implemented\n");
479 return B_BAD_VALUE;
481 case MS_GET_ACCEL:
482 TRACE("ps2: ioctl MS_GET_ACCEL (get mouse acceleration) not "
483 "implemented\n");
484 return B_BAD_VALUE;
486 case MS_SET_ACCEL:
487 TRACE("ps2: ioctl MS_SET_ACCEL (set mouse acceleration) not "
488 "implemented\n");
489 return B_BAD_VALUE;
491 case MS_SET_CLICKSPEED:
492 TRACE("ps2: ioctl MS_SETCLICK (set click speed)\n");
493 return user_memcpy(&cookie->click_speed, buffer, sizeof(bigtime_t));
495 default:
496 TRACE("ps2: ioctl unknown mouse opcode: %ld\n", op);
497 return B_DEV_INVALID_IOCTL;
502 device_hooks gStandardMouseDeviceHooks = {
503 standard_mouse_open,
504 standard_mouse_close,
505 standard_mouse_freecookie,
506 standard_mouse_ioctl,
507 standard_mouse_read,
508 standard_mouse_write,