1e637ccf5SClemens Zeidler /*
2819b4547SJohn Scipione * Copyright 2001-2014 Haiku, Inc. All rights reserved.
3e637ccf5SClemens Zeidler * Distributed under the terms of the MIT License.
4e637ccf5SClemens Zeidler *
5e637ccf5SClemens Zeidler * Authors (in chronological order):
6819b4547SJohn Scipione * Elad Lahav, elad@eldarshany.com
7819b4547SJohn Scipione * Stefano Ceccherini, burton666@libero.it
8e637ccf5SClemens Zeidler * Axel Dörfler, axeld@pinc-software.de
9819b4547SJohn Scipione * Marcus Overhagen, marcus@overhagen.de
10819b4547SJohn Scipione * Clemens Zeidler, czeidler@gmx.de
11819b4547SJohn Scipione * John Scipione, jscipione@gmail.com
12e637ccf5SClemens Zeidler */
13e637ccf5SClemens Zeidler
14e637ccf5SClemens Zeidler
15e637ccf5SClemens Zeidler /*! PS/2 mouse device driver
16e637ccf5SClemens Zeidler
17e637ccf5SClemens Zeidler A PS/2 mouse is connected to the IBM 8042 controller, and gets its
18e637ccf5SClemens Zeidler name from the IBM PS/2 personal computer, which was the first to
19e637ccf5SClemens Zeidler use this device. All resources are shared between the keyboard, and
20e637ccf5SClemens Zeidler the mouse, referred to as the "Auxiliary Device".
21e637ccf5SClemens Zeidler
22e637ccf5SClemens Zeidler I/O:
23e637ccf5SClemens Zeidler ~~~
24e637ccf5SClemens Zeidler The controller has 3 I/O registers:
25e637ccf5SClemens Zeidler 1. Status (input), mapped to port 64h
26e637ccf5SClemens Zeidler 2. Control (output), mapped to port 64h
27e637ccf5SClemens Zeidler 3. Data (input/output), mapped to port 60h
28e637ccf5SClemens Zeidler
29e637ccf5SClemens Zeidler Data:
30e637ccf5SClemens Zeidler ~~~~
31e637ccf5SClemens Zeidler A packet read from the mouse data port is composed of
32e637ccf5SClemens Zeidler three bytes:
33e637ccf5SClemens Zeidler byte 0: status byte, where
34e637ccf5SClemens Zeidler - bit 7: Y overflow (1 = true)
35e637ccf5SClemens Zeidler - bit 6: X overflow (1 = true)
36e637ccf5SClemens Zeidler - bit 5: MSB of Y offset
37e637ccf5SClemens Zeidler - bit 4: MSB of X offset
38e637ccf5SClemens Zeidler - bit 3: Syncronization bit (always 1)
39e637ccf5SClemens Zeidler - bit 2: Middle button (1 = down)
40e637ccf5SClemens Zeidler - bit 1: Right button (1 = down)
41e637ccf5SClemens Zeidler - bit 0: Left button (1 = down)
42e637ccf5SClemens Zeidler byte 1: X position change, since last probed (-127 to +127)
43e637ccf5SClemens Zeidler byte 2: Y position change, since last probed (-127 to +127)
44e637ccf5SClemens Zeidler
45e637ccf5SClemens Zeidler Intellimouse mice send a four byte packet, where the first three
46e637ccf5SClemens Zeidler bytes are the same as standard mice, and the last one reports the
47e637ccf5SClemens Zeidler Z position, which is, usually, the wheel movement.
48e637ccf5SClemens Zeidler
49e637ccf5SClemens Zeidler Interrupts:
50e637ccf5SClemens Zeidler ~~~~~~~~~~
51e637ccf5SClemens Zeidler The PS/2 mouse device is connected to interrupt 12.
52e637ccf5SClemens Zeidler The controller uses 3 consecutive interrupts to inform the computer
53e637ccf5SClemens Zeidler that it has new data. On the first the data register holds the status
54e637ccf5SClemens Zeidler byte, on the second the X offset, and on the 3rd the Y offset.
55e637ccf5SClemens Zeidler */
56e637ccf5SClemens Zeidler
57e637ccf5SClemens Zeidler
58e637ccf5SClemens Zeidler #include <stdlib.h>
59e637ccf5SClemens Zeidler #include <string.h>
60e637ccf5SClemens Zeidler
61e637ccf5SClemens Zeidler #include <keyboard_mouse_driver.h>
62e637ccf5SClemens Zeidler
63e637ccf5SClemens Zeidler #include "ps2_service.h"
64e637ccf5SClemens Zeidler #include "ps2_standard_mouse.h"
65e637ccf5SClemens Zeidler
66e637ccf5SClemens Zeidler
67*fdbbdcccSAdrien Destugues //#define TRACE_PS2_MOUSE
68*fdbbdcccSAdrien Destugues #ifdef TRACE_PS2_MOUSE
69*fdbbdcccSAdrien Destugues # define TRACE(x...) dprintf(x)
70*fdbbdcccSAdrien Destugues #else
71*fdbbdcccSAdrien Destugues # define TRACE(x...)
72*fdbbdcccSAdrien Destugues #endif
73*fdbbdcccSAdrien Destugues
74*fdbbdcccSAdrien Destugues
75e637ccf5SClemens Zeidler const char* kStandardMousePath[4] = {
76e637ccf5SClemens Zeidler "input/mouse/ps2/standard_0",
77e637ccf5SClemens Zeidler "input/mouse/ps2/standard_1",
78e637ccf5SClemens Zeidler "input/mouse/ps2/standard_2",
79e637ccf5SClemens Zeidler "input/mouse/ps2/standard_3"
80e637ccf5SClemens Zeidler };
81819b4547SJohn Scipione
82e637ccf5SClemens Zeidler const char* kIntelliMousePath[4] = {
83e637ccf5SClemens Zeidler "input/mouse/ps2/intelli_0",
84e637ccf5SClemens Zeidler "input/mouse/ps2/intelli_1",
85e637ccf5SClemens Zeidler "input/mouse/ps2/intelli_2",
86e637ccf5SClemens Zeidler "input/mouse/ps2/intelli_3"
87e637ccf5SClemens Zeidler };
88e637ccf5SClemens Zeidler
89e637ccf5SClemens Zeidler
90819b4547SJohn Scipione //! Set sampling rate of the ps2 port.
91e637ccf5SClemens Zeidler static inline status_t
ps2_set_sample_rate(ps2_dev * dev,uint8 rate)92e637ccf5SClemens Zeidler ps2_set_sample_rate(ps2_dev* dev, uint8 rate)
93e637ccf5SClemens Zeidler {
94e637ccf5SClemens Zeidler return ps2_dev_command(dev, PS2_CMD_SET_SAMPLE_RATE, &rate, 1, NULL, 0);
95e637ccf5SClemens Zeidler }
96e637ccf5SClemens Zeidler
97e637ccf5SClemens Zeidler
98819b4547SJohn Scipione //! Converts a packet received by the mouse to a "movement".
99e637ccf5SClemens Zeidler static void
ps2_packet_to_movement(standard_mouse_cookie * cookie,uint8 packet[],mouse_movement * pos)100e637ccf5SClemens Zeidler ps2_packet_to_movement(standard_mouse_cookie* cookie, uint8 packet[],
101e637ccf5SClemens Zeidler mouse_movement* pos)
102e637ccf5SClemens Zeidler {
103e637ccf5SClemens Zeidler int buttons = packet[0] & 7;
104e637ccf5SClemens Zeidler int xDelta = ((packet[0] & 0x10) ? ~0xff : 0) | packet[1];
105e637ccf5SClemens Zeidler int yDelta = ((packet[0] & 0x20) ? ~0xff : 0) | packet[2];
106e637ccf5SClemens Zeidler int xDeltaWheel = 0;
107e637ccf5SClemens Zeidler int yDeltaWheel = 0;
108e637ccf5SClemens Zeidler bigtime_t currentTime = system_time();
109e637ccf5SClemens Zeidler
110e637ccf5SClemens Zeidler if (buttons != 0 && cookie->buttons_state == 0) {
111e637ccf5SClemens Zeidler if (cookie->click_last_time + cookie->click_speed > currentTime)
112e637ccf5SClemens Zeidler cookie->click_count++;
113e637ccf5SClemens Zeidler else
114e637ccf5SClemens Zeidler cookie->click_count = 1;
115e637ccf5SClemens Zeidler
116e637ccf5SClemens Zeidler cookie->click_last_time = currentTime;
117e637ccf5SClemens Zeidler }
118e637ccf5SClemens Zeidler
119e637ccf5SClemens Zeidler cookie->buttons_state = buttons;
120e637ccf5SClemens Zeidler
121e637ccf5SClemens Zeidler if (cookie->flags & F_MOUSE_TYPE_INTELLIMOUSE) {
122e637ccf5SClemens Zeidler yDeltaWheel = packet[3] & 0x07;
123e637ccf5SClemens Zeidler if (packet[3] & 0x08)
124e637ccf5SClemens Zeidler yDeltaWheel |= ~0x07;
125e637ccf5SClemens Zeidler }
126819b4547SJohn Scipione #if 0
127e637ccf5SClemens Zeidler if (cookie->flags & F_MOUSE_TYPE_2WHEELS) {
128e637ccf5SClemens Zeidler switch (packet[3] & 0x0F) {
129e637ccf5SClemens Zeidler case 0x01: yDeltaWheel = +1; break; // wheel 1 down
130e637ccf5SClemens Zeidler case 0x0F: yDeltaWheel = -1; break; // wheel 1 up
131e637ccf5SClemens Zeidler case 0x02: xDeltaWheel = +1; break; // wheel 2 down
132e637ccf5SClemens Zeidler case 0x0E: xDeltaWheel = -1; break; // wheel 2 up
133e637ccf5SClemens Zeidler }
134e637ccf5SClemens Zeidler }
135819b4547SJohn Scipione #endif
136e637ccf5SClemens Zeidler
137819b4547SJohn Scipione #if 0
138819b4547SJohn Scipione TRACE("packet: %02x %02x %02x %02x: xd %d, yd %d, 0x%x (%d), w-xd %d, "
139819b4547SJohn Scipione "w-yd %d\n", packet[0], packet[1], packet[2], packet[3],
140819b4547SJohn Scipione xDelta, yDelta, buttons, cookie->click_count, xDeltaWheel,
141819b4547SJohn Scipione yDeltaWheel);
142819b4547SJohn Scipione #endif
143e637ccf5SClemens Zeidler
144819b4547SJohn Scipione if (pos != NULL) {
145e637ccf5SClemens Zeidler pos->xdelta = xDelta;
146e637ccf5SClemens Zeidler pos->ydelta = yDelta;
147e637ccf5SClemens Zeidler pos->buttons = buttons;
148e637ccf5SClemens Zeidler pos->clicks = cookie->click_count;
149e637ccf5SClemens Zeidler pos->modifiers = 0;
150e637ccf5SClemens Zeidler pos->timestamp = currentTime;
151e637ccf5SClemens Zeidler pos->wheel_ydelta = yDeltaWheel;
152e637ccf5SClemens Zeidler pos->wheel_xdelta = xDeltaWheel;
153e637ccf5SClemens Zeidler
154e637ccf5SClemens Zeidler TRACE("ps2: ps2_packet_to_movement xdelta: %d, ydelta: %d, buttons %x, "
155ebdb22deSZoltán Mizsei "clicks: %d, timestamp %" B_PRIdBIGTIME "\n",
156e637ccf5SClemens Zeidler xDelta, yDelta, buttons, cookie->click_count, currentTime);
157e637ccf5SClemens Zeidler }
158e637ccf5SClemens Zeidler }
159e637ccf5SClemens Zeidler
160e637ccf5SClemens Zeidler
161819b4547SJohn Scipione //! Read a mouse event from the mouse events chain buffer.
162e637ccf5SClemens Zeidler static status_t
standard_mouse_read_event(standard_mouse_cookie * cookie,mouse_movement * movement)163e637ccf5SClemens Zeidler standard_mouse_read_event(standard_mouse_cookie* cookie,
164e637ccf5SClemens Zeidler mouse_movement* movement)
165e637ccf5SClemens Zeidler {
166e637ccf5SClemens Zeidler uint8 packet[PS2_MAX_PACKET_SIZE];
167e637ccf5SClemens Zeidler status_t status;
168e637ccf5SClemens Zeidler
169e637ccf5SClemens Zeidler TRACE("ps2: standard_mouse_read_event\n");
170e637ccf5SClemens Zeidler
171e637ccf5SClemens Zeidler status = acquire_sem_etc(cookie->standard_mouse_sem, 1, B_CAN_INTERRUPT, 0);
172e637ccf5SClemens Zeidler TRACE("ps2: standard_mouse_read_event acquired\n");
173e637ccf5SClemens Zeidler if (status < B_OK)
174e637ccf5SClemens Zeidler return status;
175e637ccf5SClemens Zeidler
176e637ccf5SClemens Zeidler if (!cookie->dev->active) {
177e637ccf5SClemens Zeidler TRACE("ps2: standard_mouse_read_event: Error device no longer "
178e637ccf5SClemens Zeidler "active\n");
179e637ccf5SClemens Zeidler return B_ERROR;
180e637ccf5SClemens Zeidler }
181e637ccf5SClemens Zeidler
182e637ccf5SClemens Zeidler if (packet_buffer_read(cookie->standard_mouse_buffer, packet,
183e637ccf5SClemens Zeidler cookie->dev->packet_size) != cookie->dev->packet_size) {
184e637ccf5SClemens Zeidler TRACE("ps2: error copying buffer\n");
185e637ccf5SClemens Zeidler return B_ERROR;
186e637ccf5SClemens Zeidler }
187e637ccf5SClemens Zeidler
188e637ccf5SClemens Zeidler if (!(packet[0] & 8))
189e637ccf5SClemens Zeidler panic("ps2: got broken data from packet_buffer_read\n");
190e637ccf5SClemens Zeidler
191e637ccf5SClemens Zeidler ps2_packet_to_movement(cookie, packet, movement);
192e637ccf5SClemens Zeidler return B_OK;
193e637ccf5SClemens Zeidler }
194e637ccf5SClemens Zeidler
195e637ccf5SClemens Zeidler
196819b4547SJohn Scipione // #pragma mark - Interrupt handler functions
197e637ccf5SClemens Zeidler
198e637ccf5SClemens Zeidler
199e637ccf5SClemens Zeidler void
standard_mouse_disconnect(ps2_dev * dev)200e637ccf5SClemens Zeidler standard_mouse_disconnect(ps2_dev* dev)
201e637ccf5SClemens Zeidler {
202e637ccf5SClemens Zeidler // the mouse device might not be opened at this point
203e637ccf5SClemens Zeidler INFO("ps2: ps2_standard_mouse_disconnect %s\n", dev->name);
204e637ccf5SClemens Zeidler if (dev->flags & PS2_FLAG_OPEN)
205e637ccf5SClemens Zeidler release_sem(((standard_mouse_cookie*)dev->cookie)->standard_mouse_sem);
206e637ccf5SClemens Zeidler }
207e637ccf5SClemens Zeidler
208e637ccf5SClemens Zeidler
209e637ccf5SClemens Zeidler /*! Interrupt handler for the mouse device. Called whenever the I/O
210e637ccf5SClemens Zeidler controller generates an interrupt for the PS/2 mouse. Reads mouse
211e637ccf5SClemens Zeidler information from the data port, and stores it, so it can be accessed
212e637ccf5SClemens Zeidler by read() operations. The full data is obtained using 3 consecutive
213e637ccf5SClemens Zeidler calls to the handler, each holds a different byte on the data port.
214e637ccf5SClemens Zeidler */
215e637ccf5SClemens Zeidler int32
standard_mouse_handle_int(ps2_dev * dev)216e637ccf5SClemens Zeidler standard_mouse_handle_int(ps2_dev* dev)
217e637ccf5SClemens Zeidler {
218e637ccf5SClemens Zeidler standard_mouse_cookie* cookie = (standard_mouse_cookie*)dev->cookie;
219e637ccf5SClemens Zeidler const uint8 data = dev->history[0].data;
220e637ccf5SClemens Zeidler
221e637ccf5SClemens Zeidler TRACE("ps2: standard mouse: %1x\t%1x\t%1x\t%1x\t%1x\t%1x\t%1x\t%1x\n",
222e637ccf5SClemens Zeidler data >> 7 & 1, data >> 6 & 1, data >> 5 & 1,
223e637ccf5SClemens Zeidler data >> 4 & 1, data >> 3 & 1, data >> 2 & 1,
224e637ccf5SClemens Zeidler data >> 1 & 1, data >> 0 & 1);
225e637ccf5SClemens Zeidler
226819b4547SJohn Scipione if (cookie->packet_index == 0 && (data & 8) == 0) {
227e637ccf5SClemens Zeidler INFO("ps2: bad mouse data, trying resync\n");
228e637ccf5SClemens Zeidler return B_HANDLED_INTERRUPT;
229e637ccf5SClemens Zeidler }
230e637ccf5SClemens Zeidler
231e637ccf5SClemens Zeidler // Workarounds for active multiplexing keyboard controllers
232e637ccf5SClemens Zeidler // that lose data or send them to the wrong port.
233819b4547SJohn Scipione if (cookie->packet_index == 0 && (data & 0xc0) != 0) {
234e637ccf5SClemens Zeidler INFO("ps2: strange mouse data, x/y overflow, trying resync\n");
235e637ccf5SClemens Zeidler return B_HANDLED_INTERRUPT;
236e637ccf5SClemens Zeidler }
237819b4547SJohn Scipione
238e637ccf5SClemens Zeidler cookie->buffer[cookie->packet_index++] = data;
239e637ccf5SClemens Zeidler
240e637ccf5SClemens Zeidler if (cookie->packet_index != dev->packet_size) {
241e637ccf5SClemens Zeidler // packet not yet complete
242e637ccf5SClemens Zeidler return B_HANDLED_INTERRUPT;
243e637ccf5SClemens Zeidler }
244e637ccf5SClemens Zeidler
245e637ccf5SClemens Zeidler // complete packet is assembled
246e637ccf5SClemens Zeidler
247e637ccf5SClemens Zeidler cookie->packet_index = 0;
248e637ccf5SClemens Zeidler if (packet_buffer_write(cookie->standard_mouse_buffer,
249e637ccf5SClemens Zeidler cookie->buffer, dev->packet_size) != dev->packet_size) {
250e637ccf5SClemens Zeidler // buffer is full, drop new data
251e637ccf5SClemens Zeidler return B_HANDLED_INTERRUPT;
252e637ccf5SClemens Zeidler }
253e637ccf5SClemens Zeidler
254e637ccf5SClemens Zeidler release_sem_etc(cookie->standard_mouse_sem, 1, B_DO_NOT_RESCHEDULE);
255819b4547SJohn Scipione
256e637ccf5SClemens Zeidler return B_INVOKE_SCHEDULER;
257e637ccf5SClemens Zeidler }
258e637ccf5SClemens Zeidler
259e637ccf5SClemens Zeidler
260819b4547SJohn Scipione // #pragma mark - probe_standard_mouse()
261e637ccf5SClemens Zeidler
262e637ccf5SClemens Zeidler
263e637ccf5SClemens Zeidler status_t
probe_standard_mouse(ps2_dev * dev)264e637ccf5SClemens Zeidler probe_standard_mouse(ps2_dev* dev)
265e637ccf5SClemens Zeidler {
266e637ccf5SClemens Zeidler status_t status;
267e637ccf5SClemens Zeidler uint8 deviceId = 0;
268e637ccf5SClemens Zeidler
269e637ccf5SClemens Zeidler // get device id
270e637ccf5SClemens Zeidler status = ps2_dev_command(dev, PS2_CMD_GET_DEVICE_ID, NULL, 0,
271e637ccf5SClemens Zeidler &deviceId, 1);
272e637ccf5SClemens Zeidler if (status != B_OK) {
273e637ccf5SClemens Zeidler INFO("ps2: probe_mouse get device id failed\n");
274e637ccf5SClemens Zeidler return B_ERROR;
275e637ccf5SClemens Zeidler }
276e637ccf5SClemens Zeidler
277e637ccf5SClemens Zeidler TRACE("ps2: probe_mouse device id: %2x\n", deviceId);
278e637ccf5SClemens Zeidler
279e637ccf5SClemens Zeidler // check for MS Intellimouse
280e637ccf5SClemens Zeidler if (deviceId == 0) {
281e637ccf5SClemens Zeidler uint8 alternate_device_id;
282e637ccf5SClemens Zeidler status = ps2_set_sample_rate(dev, 200);
283e637ccf5SClemens Zeidler status |= ps2_set_sample_rate(dev, 100);
284e637ccf5SClemens Zeidler status |= ps2_set_sample_rate(dev, 80);
285e637ccf5SClemens Zeidler status |= ps2_dev_command(dev, PS2_CMD_GET_DEVICE_ID, NULL, 0,
286e637ccf5SClemens Zeidler &alternate_device_id, 1);
287e637ccf5SClemens Zeidler if (status == 0) {
288e637ccf5SClemens Zeidler TRACE("ps2: probe_mouse alternate device id: %2x\n",
289e637ccf5SClemens Zeidler alternate_device_id);
290e637ccf5SClemens Zeidler deviceId = alternate_device_id;
291e637ccf5SClemens Zeidler }
292e637ccf5SClemens Zeidler }
293e637ccf5SClemens Zeidler
294e637ccf5SClemens Zeidler if (deviceId == PS2_DEV_ID_STANDARD
295e637ccf5SClemens Zeidler || deviceId == PS2_DEV_ID_TOUCHPAD_RICATECH) {
296e637ccf5SClemens Zeidler INFO("ps2: probe_mouse Standard PS/2 mouse found\n");
297e637ccf5SClemens Zeidler dev->name = kStandardMousePath[dev->idx];
298e637ccf5SClemens Zeidler dev->packet_size = PS2_PACKET_STANDARD;
299e637ccf5SClemens Zeidler } else if (deviceId == PS2_DEV_ID_INTELLIMOUSE) {
300e637ccf5SClemens Zeidler dev->name = kIntelliMousePath[dev->idx];
301e637ccf5SClemens Zeidler dev->packet_size = PS2_PACKET_INTELLIMOUSE;
302e637ccf5SClemens Zeidler INFO("ps2: probe_mouse Extended PS/2 mouse found\n");
303e637ccf5SClemens Zeidler } else {
304e637ccf5SClemens Zeidler INFO("ps2: probe_mouse Error unknown device id.\n");
305e637ccf5SClemens Zeidler return B_ERROR;
306e637ccf5SClemens Zeidler }
307e637ccf5SClemens Zeidler
308e637ccf5SClemens Zeidler return B_OK;
309e637ccf5SClemens Zeidler }
310e637ccf5SClemens Zeidler
311e637ccf5SClemens Zeidler
312e637ccf5SClemens Zeidler // #pragma mark - Device functions
313e637ccf5SClemens Zeidler
314e637ccf5SClemens Zeidler
315e637ccf5SClemens Zeidler status_t
standard_mouse_open(const char * name,uint32 flags,void ** _cookie)316e637ccf5SClemens Zeidler standard_mouse_open(const char* name, uint32 flags, void** _cookie)
317e637ccf5SClemens Zeidler {
318e637ccf5SClemens Zeidler standard_mouse_cookie* cookie;
319e637ccf5SClemens Zeidler status_t status;
320e637ccf5SClemens Zeidler ps2_dev* dev = NULL;
321e637ccf5SClemens Zeidler int i;
322e637ccf5SClemens Zeidler
323e637ccf5SClemens Zeidler TRACE("ps2: standard_mouse_open %s\n", name);
324e637ccf5SClemens Zeidler
325e637ccf5SClemens Zeidler for (dev = NULL, i = 0; i < PS2_DEVICE_COUNT; i++) {
326e637ccf5SClemens Zeidler if (0 == strcmp(ps2_device[i].name, name)) {
327e637ccf5SClemens Zeidler dev = &ps2_device[i];
328e637ccf5SClemens Zeidler break;
329e637ccf5SClemens Zeidler }
330819b4547SJohn Scipione #if 0
331819b4547SJohn Scipione if (0 == strcmp(g_passthrough_dev.name, name)) {
332e637ccf5SClemens Zeidler dev = &g_passthrough_dev;
333e637ccf5SClemens Zeidler isSynapticsPTDevice = true;
334e637ccf5SClemens Zeidler break;
335819b4547SJohn Scipione }
336819b4547SJohn Scipione #endif
337e637ccf5SClemens Zeidler }
338e637ccf5SClemens Zeidler
339e637ccf5SClemens Zeidler if (dev == NULL) {
340e637ccf5SClemens Zeidler TRACE("ps2: dev = NULL\n");
341e637ccf5SClemens Zeidler return B_ERROR;
342e637ccf5SClemens Zeidler }
343e637ccf5SClemens Zeidler
344e637ccf5SClemens Zeidler if (atomic_or(&dev->flags, PS2_FLAG_OPEN) & PS2_FLAG_OPEN)
345e637ccf5SClemens Zeidler return B_BUSY;
346e637ccf5SClemens Zeidler
347e637ccf5SClemens Zeidler cookie = (standard_mouse_cookie*)malloc(sizeof(standard_mouse_cookie));
348e637ccf5SClemens Zeidler if (cookie == NULL)
349e637ccf5SClemens Zeidler goto err1;
350e637ccf5SClemens Zeidler
351e637ccf5SClemens Zeidler *_cookie = cookie;
352e637ccf5SClemens Zeidler memset(cookie, 0, sizeof(*cookie));
353e637ccf5SClemens Zeidler
354e637ccf5SClemens Zeidler cookie->dev = dev;
355e637ccf5SClemens Zeidler dev->cookie = cookie;
356e637ccf5SClemens Zeidler dev->disconnect = &standard_mouse_disconnect;
357e637ccf5SClemens Zeidler dev->handle_int = &standard_mouse_handle_int;
358e637ccf5SClemens Zeidler
359e637ccf5SClemens Zeidler if (strstr(dev->name, "standard") != NULL)
360e637ccf5SClemens Zeidler cookie->flags = F_MOUSE_TYPE_STANDARD;
361e637ccf5SClemens Zeidler
362e637ccf5SClemens Zeidler if (strstr(dev->name, "intelli") != NULL)
363e637ccf5SClemens Zeidler cookie->flags = F_MOUSE_TYPE_INTELLIMOUSE;
364e637ccf5SClemens Zeidler
365e637ccf5SClemens Zeidler cookie->standard_mouse_buffer
366e637ccf5SClemens Zeidler = create_packet_buffer(MOUSE_HISTORY_SIZE * dev->packet_size);
367e637ccf5SClemens Zeidler if (cookie->standard_mouse_buffer == NULL) {
368e637ccf5SClemens Zeidler TRACE("ps2: can't allocate mouse actions buffer\n");
369e637ccf5SClemens Zeidler goto err2;
370e637ccf5SClemens Zeidler }
371e637ccf5SClemens Zeidler
372e637ccf5SClemens Zeidler // create the mouse semaphore, used for synchronization between
373e637ccf5SClemens Zeidler // the interrupt handler and the read operation
374e637ccf5SClemens Zeidler cookie->standard_mouse_sem = create_sem(0, "ps2_standard_mouse_sem");
375e637ccf5SClemens Zeidler if (cookie->standard_mouse_sem < 0) {
376e637ccf5SClemens Zeidler TRACE("ps2: failed creating PS/2 mouse semaphore!\n");
377e637ccf5SClemens Zeidler goto err3;
378e637ccf5SClemens Zeidler }
379e637ccf5SClemens Zeidler
380e637ccf5SClemens Zeidler status = ps2_dev_command(dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0);
381e637ccf5SClemens Zeidler if (status < B_OK) {
382e637ccf5SClemens Zeidler INFO("ps2: cannot enable mouse %s\n", name);
383e637ccf5SClemens Zeidler goto err4;
384e637ccf5SClemens Zeidler }
385e637ccf5SClemens Zeidler
386e637ccf5SClemens Zeidler atomic_or(&dev->flags, PS2_FLAG_ENABLED);
387e637ccf5SClemens Zeidler
388e637ccf5SClemens Zeidler
389e637ccf5SClemens Zeidler TRACE("ps2: standard_mouse_open %s success\n", name);
390e637ccf5SClemens Zeidler return B_OK;
391e637ccf5SClemens Zeidler
392e637ccf5SClemens Zeidler err4:
393e637ccf5SClemens Zeidler delete_sem(cookie->standard_mouse_sem);
394e637ccf5SClemens Zeidler err3:
395e637ccf5SClemens Zeidler delete_packet_buffer(cookie->standard_mouse_buffer);
396e637ccf5SClemens Zeidler err2:
397e637ccf5SClemens Zeidler free(cookie);
398e637ccf5SClemens Zeidler err1:
399e637ccf5SClemens Zeidler atomic_and(&dev->flags, ~PS2_FLAG_OPEN);
400e637ccf5SClemens Zeidler
401e637ccf5SClemens Zeidler TRACE("ps2: standard_mouse_open %s failed\n", name);
402e637ccf5SClemens Zeidler return B_ERROR;
403e637ccf5SClemens Zeidler }
404e637ccf5SClemens Zeidler
405e637ccf5SClemens Zeidler
406e637ccf5SClemens Zeidler status_t
standard_mouse_close(void * _cookie)407e637ccf5SClemens Zeidler standard_mouse_close(void* _cookie)
408e637ccf5SClemens Zeidler {
409e637ccf5SClemens Zeidler standard_mouse_cookie* cookie = (standard_mouse_cookie*)_cookie;
410e637ccf5SClemens Zeidler
411e637ccf5SClemens Zeidler TRACE("ps2: standard_mouse_close %s enter\n", cookie->dev->name);
412e637ccf5SClemens Zeidler
413e637ccf5SClemens Zeidler ps2_dev_command_timeout(cookie->dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0,
414e637ccf5SClemens Zeidler 150000);
415e637ccf5SClemens Zeidler
416e637ccf5SClemens Zeidler delete_packet_buffer(cookie->standard_mouse_buffer);
417e637ccf5SClemens Zeidler delete_sem(cookie->standard_mouse_sem);
418e637ccf5SClemens Zeidler
419e637ccf5SClemens Zeidler atomic_and(&cookie->dev->flags, ~PS2_FLAG_OPEN);
420e637ccf5SClemens Zeidler atomic_and(&cookie->dev->flags, ~PS2_FLAG_ENABLED);
421e637ccf5SClemens Zeidler
422e637ccf5SClemens Zeidler TRACE("ps2: standard_mouse_close %s done\n", cookie->dev->name);
423e637ccf5SClemens Zeidler return B_OK;
424e637ccf5SClemens Zeidler }
425e637ccf5SClemens Zeidler
426e637ccf5SClemens Zeidler
427e637ccf5SClemens Zeidler status_t
standard_mouse_freecookie(void * _cookie)428e637ccf5SClemens Zeidler standard_mouse_freecookie(void* _cookie)
429e637ccf5SClemens Zeidler {
430e637ccf5SClemens Zeidler standard_mouse_cookie* cookie = (standard_mouse_cookie*)_cookie;
431e637ccf5SClemens Zeidler free(cookie);
432e637ccf5SClemens Zeidler return B_OK;
433e637ccf5SClemens Zeidler }
434e637ccf5SClemens Zeidler
435e637ccf5SClemens Zeidler
436e637ccf5SClemens Zeidler static status_t
standard_mouse_read(void * cookie,off_t pos,void * buffer,size_t * _length)437e637ccf5SClemens Zeidler standard_mouse_read(void* cookie, off_t pos, void* buffer, size_t* _length)
438e637ccf5SClemens Zeidler {
439e637ccf5SClemens Zeidler *_length = 0;
440e637ccf5SClemens Zeidler return B_NOT_ALLOWED;
441e637ccf5SClemens Zeidler }
442e637ccf5SClemens Zeidler
443e637ccf5SClemens Zeidler
444e637ccf5SClemens Zeidler static status_t
standard_mouse_write(void * cookie,off_t pos,const void * buffer,size_t * _length)445e637ccf5SClemens Zeidler standard_mouse_write(void* cookie, off_t pos, const void* buffer,
446e637ccf5SClemens Zeidler size_t* _length)
447e637ccf5SClemens Zeidler {
448e637ccf5SClemens Zeidler *_length = 0;
449e637ccf5SClemens Zeidler return B_NOT_ALLOWED;
450e637ccf5SClemens Zeidler }
451e637ccf5SClemens Zeidler
452e637ccf5SClemens Zeidler
453e637ccf5SClemens Zeidler status_t
standard_mouse_ioctl(void * _cookie,uint32 op,void * buffer,size_t length)454e637ccf5SClemens Zeidler standard_mouse_ioctl(void* _cookie, uint32 op, void* buffer, size_t length)
455e637ccf5SClemens Zeidler {
456e637ccf5SClemens Zeidler standard_mouse_cookie* cookie = (standard_mouse_cookie*)_cookie;
457e637ccf5SClemens Zeidler
458e637ccf5SClemens Zeidler switch (op) {
459e637ccf5SClemens Zeidler case MS_NUM_EVENTS:
460e637ccf5SClemens Zeidler {
461e637ccf5SClemens Zeidler int32 count;
462e637ccf5SClemens Zeidler TRACE("ps2: ioctl MS_NUM_EVENTS\n");
463e637ccf5SClemens Zeidler get_sem_count(cookie->standard_mouse_sem, &count);
464e637ccf5SClemens Zeidler return count;
465e637ccf5SClemens Zeidler }
466e637ccf5SClemens Zeidler
467e637ccf5SClemens Zeidler case MS_READ:
468e637ccf5SClemens Zeidler {
469e637ccf5SClemens Zeidler mouse_movement movement;
470e637ccf5SClemens Zeidler status_t status;
471e637ccf5SClemens Zeidler TRACE("ps2: ioctl MS_READ\n");
472e637ccf5SClemens Zeidler if ((status = standard_mouse_read_event(cookie, &movement)) < B_OK)
473e637ccf5SClemens Zeidler return status;
474e637ccf5SClemens Zeidler // TRACE("%s %d %d %d %d\n", cookie->dev->name,
475e637ccf5SClemens Zeidler // movement.xdelta, movement.ydelta, movement.buttons,
476e637ccf5SClemens Zeidler // movement.clicks);
477e637ccf5SClemens Zeidler return user_memcpy(buffer, &movement, sizeof(movement));
478e637ccf5SClemens Zeidler }
479e637ccf5SClemens Zeidler
480e637ccf5SClemens Zeidler case MS_SET_TYPE:
481e637ccf5SClemens Zeidler TRACE("ps2: ioctl MS_SET_TYPE not implemented\n");
482e637ccf5SClemens Zeidler return B_BAD_VALUE;
483e637ccf5SClemens Zeidler
484e637ccf5SClemens Zeidler case MS_SET_MAP:
485e637ccf5SClemens Zeidler TRACE("ps2: ioctl MS_SET_MAP (set mouse mapping) not "
486e637ccf5SClemens Zeidler "implemented\n");
487e637ccf5SClemens Zeidler return B_BAD_VALUE;
488e637ccf5SClemens Zeidler
489e637ccf5SClemens Zeidler case MS_GET_ACCEL:
490e637ccf5SClemens Zeidler TRACE("ps2: ioctl MS_GET_ACCEL (get mouse acceleration) not "
491e637ccf5SClemens Zeidler "implemented\n");
492e637ccf5SClemens Zeidler return B_BAD_VALUE;
493e637ccf5SClemens Zeidler
494e637ccf5SClemens Zeidler case MS_SET_ACCEL:
495e637ccf5SClemens Zeidler TRACE("ps2: ioctl MS_SET_ACCEL (set mouse acceleration) not "
496e637ccf5SClemens Zeidler "implemented\n");
497e637ccf5SClemens Zeidler return B_BAD_VALUE;
498e637ccf5SClemens Zeidler
499e637ccf5SClemens Zeidler case MS_SET_CLICKSPEED:
500e637ccf5SClemens Zeidler TRACE("ps2: ioctl MS_SETCLICK (set click speed)\n");
501e637ccf5SClemens Zeidler return user_memcpy(&cookie->click_speed, buffer, sizeof(bigtime_t));
502e637ccf5SClemens Zeidler
503e637ccf5SClemens Zeidler default:
504ebdb22deSZoltán Mizsei TRACE("ps2: ioctl unknown mouse opcode: %" B_PRIu32 "\n", op);
505e637ccf5SClemens Zeidler return B_DEV_INVALID_IOCTL;
506e637ccf5SClemens Zeidler }
507e637ccf5SClemens Zeidler }
508e637ccf5SClemens Zeidler
509e637ccf5SClemens Zeidler
510e637ccf5SClemens Zeidler device_hooks gStandardMouseDeviceHooks = {
511e637ccf5SClemens Zeidler standard_mouse_open,
512e637ccf5SClemens Zeidler standard_mouse_close,
513e637ccf5SClemens Zeidler standard_mouse_freecookie,
514e637ccf5SClemens Zeidler standard_mouse_ioctl,
515e637ccf5SClemens Zeidler standard_mouse_read,
516e637ccf5SClemens Zeidler standard_mouse_write,
517e637ccf5SClemens Zeidler };
518