119370Spst/*
219370Spst * Copyright 2001-2014 Haiku, Inc. All rights reserved.
3130803Smarcel * Distributed under the terms of the MIT License.
4130803Smarcel *
5130803Smarcel * Authors (in chronological order):
6130803Smarcel *		Elad Lahav, elad@eldarshany.com
798944Sobrien *		Stefano Ceccherini, burton666@libero.it
819370Spst *		Axel D��rfler, axeld@pinc-software.de
998944Sobrien *		Marcus Overhagen, marcus@overhagen.de
1098944Sobrien *		Clemens Zeidler, czeidler@gmx.de
1198944Sobrien *		John Scipione, jscipione@gmail.com
1298944Sobrien */
1319370Spst
1498944Sobrien
1598944Sobrien/*!	PS/2 mouse device driver
1698944Sobrien
1798944Sobrien	A PS/2 mouse is connected to the IBM 8042 controller, and gets its
1819370Spst	name from the IBM PS/2 personal computer, which was the first to
1998944Sobrien	use this device. All resources are shared between the keyboard, and
2098944Sobrien	the mouse, referred to as the "Auxiliary Device".
2198944Sobrien
2298944Sobrien	I/O:
2319370Spst	~~~
2419370Spst	The controller has 3 I/O registers:
2519370Spst	1. Status (input), mapped to port 64h
2619370Spst	2. Control (output), mapped to port 64h
2719370Spst	3. Data (input/output), mapped to port 60h
2819370Spst
2919370Spst	Data:
3019370Spst	~~~~
3119370Spst	A packet read from the mouse data port is composed of
3219370Spst	three bytes:
3319370Spst		byte 0: status byte, where
3446283Sdfr			- bit 7: Y overflow (1 = true)
3598944Sobrien			- bit 6: X overflow (1 = true)
3698944Sobrien			- bit 5: MSB of Y offset
3719370Spst			- bit 4: MSB of X offset
3819370Spst			- bit 3: Syncronization bit (always 1)
3919370Spst			- bit 2: Middle button (1 = down)
4019370Spst			- bit 1: Right button (1 = down)
4119370Spst			- bit 0: Left button (1 = down)
4298944Sobrien		byte 1: X position change, since last probed (-127 to +127)
4398944Sobrien		byte 2: Y position change, since last probed (-127 to +127)
4419370Spst
4598944Sobrien	Intellimouse mice send a four byte packet, where the first three
4619370Spst	bytes are the same as standard mice, and the last one reports the
4798944Sobrien	Z position, which is, usually, the wheel movement.
4819370Spst
4998944Sobrien	Interrupts:
5019370Spst	~~~~~~~~~~
5198944Sobrien	The PS/2 mouse device is connected to interrupt 12.
5219370Spst	The controller uses 3 consecutive interrupts to inform the computer
5398944Sobrien	that it has new data. On the first the data register holds the status
5419370Spst	byte, on the second the X offset, and on the 3rd the Y offset.
5598944Sobrien*/
5619370Spst
5798944Sobrien
5819370Spst#include <stdlib.h>
5998944Sobrien#include <string.h>
6046283Sdfr
6198944Sobrien#include <keyboard_mouse_driver.h>
6298944Sobrien
6319370Spst#include "ps2_service.h"
6419370Spst#include "ps2_standard_mouse.h"
6519370Spst
6619370Spst
6719370Spst//#define TRACE_PS2_MOUSE
6819370Spst#ifdef TRACE_PS2_MOUSE
6919370Spst#	define TRACE(x...) dprintf(x)
7019370Spst#else
7119370Spst#	define TRACE(x...)
7219370Spst#endif
7319370Spst
7419370Spst
7519370Spstconst char* kStandardMousePath[4] = {
7619370Spst	"input/mouse/ps2/standard_0",
7719370Spst	"input/mouse/ps2/standard_1",
7819370Spst	"input/mouse/ps2/standard_2",
7919370Spst	"input/mouse/ps2/standard_3"
8019370Spst};
8119370Spst
8219370Spstconst char* kIntelliMousePath[4] = {
8319370Spst	"input/mouse/ps2/intelli_0",
8419370Spst	"input/mouse/ps2/intelli_1",
8519370Spst	"input/mouse/ps2/intelli_2",
8619370Spst	"input/mouse/ps2/intelli_3"
8719370Spst};
8819370Spst
8919370Spst
9019370Spst//!	Set sampling rate of the ps2 port.
9119370Spststatic inline status_t
9219370Spstps2_set_sample_rate(ps2_dev* dev, uint8 rate)
9319370Spst{
9419370Spst	return ps2_dev_command(dev, PS2_CMD_SET_SAMPLE_RATE, &rate, 1, NULL, 0);
9519370Spst}
9619370Spst
9719370Spst
9819370Spst//!	Converts a packet received by the mouse to a "movement".
9919370Spststatic void
10019370Spstps2_packet_to_movement(standard_mouse_cookie* cookie, uint8 packet[],
10119370Spst	mouse_movement* pos)
10219370Spst{
10398944Sobrien	int buttons = packet[0] & 7;
10419370Spst	int xDelta = ((packet[0] & 0x10) ? ~0xff : 0) | packet[1];
10519370Spst	int yDelta = ((packet[0] & 0x20) ? ~0xff : 0) | packet[2];
10619370Spst	int xDeltaWheel = 0;
10719370Spst	int yDeltaWheel = 0;
10819370Spst	bigtime_t currentTime = system_time();
10919370Spst
11019370Spst	if (buttons != 0 && cookie->buttons_state == 0) {
11119370Spst		if (cookie->click_last_time + cookie->click_speed > currentTime)
11219370Spst			cookie->click_count++;
11319370Spst		else
11419370Spst			cookie->click_count = 1;
11519370Spst
11619370Spst		cookie->click_last_time = currentTime;
11719370Spst	}
11819370Spst
11919370Spst	cookie->buttons_state = buttons;
12019370Spst
12119370Spst	if (cookie->flags & F_MOUSE_TYPE_INTELLIMOUSE) {
12219370Spst		yDeltaWheel = packet[3] & 0x07;
12319370Spst 		if (packet[3] & 0x08)
12419370Spst			yDeltaWheel |= ~0x07;
12519370Spst	}
12698944Sobrien#if 0
12798944Sobrien	if (cookie->flags & F_MOUSE_TYPE_2WHEELS) {
12898944Sobrien		switch (packet[3] & 0x0F) {
12919370Spst			case 0x01: yDeltaWheel = +1; break; // wheel 1 down
13019370Spst			case 0x0F: yDeltaWheel = -1; break; // wheel 1 up
13119370Spst			case 0x02: xDeltaWheel = +1; break; // wheel 2 down
13219370Spst			case 0x0E: xDeltaWheel = -1; break; // wheel 2 up
13319370Spst		}
13419370Spst	}
13598944Sobrien#endif
13619370Spst
13719370Spst#if 0
13819370Spst	TRACE("packet: %02x %02x %02x %02x: xd %d, yd %d, 0x%x (%d), w-xd %d, "
13919370Spst		"w-yd %d\n", packet[0], packet[1], packet[2], packet[3],
14019370Spst		xDelta, yDelta, buttons, cookie->click_count, xDeltaWheel,
14119370Spst		yDeltaWheel);
14298944Sobrien#endif
14319370Spst
14419370Spst	if (pos != NULL) {
14519370Spst		pos->xdelta = xDelta;
14619370Spst		pos->ydelta = yDelta;
14719370Spst		pos->buttons = buttons;
14898944Sobrien		pos->clicks = cookie->click_count;
14946283Sdfr		pos->modifiers = 0;
15098944Sobrien		pos->timestamp = currentTime;
15119370Spst		pos->wheel_ydelta = yDeltaWheel;
15219370Spst		pos->wheel_xdelta = xDeltaWheel;
153242936Semaste
154242936Semaste		TRACE("ps2: ps2_packet_to_movement xdelta: %d, ydelta: %d, buttons %x, "
155242936Semaste			"clicks: %d, timestamp %" B_PRIdBIGTIME "\n",
15619370Spst			xDelta, yDelta, buttons, cookie->click_count, currentTime);
157242936Semaste	}
158242936Semaste}
15919370Spst
16019370Spst
16119370Spst//!	Read a mouse event from the mouse events chain buffer.
162242936Semastestatic status_t
16319370Spststandard_mouse_read_event(standard_mouse_cookie* cookie,
16419370Spst	mouse_movement* movement)
165242936Semaste{
16619370Spst	uint8 packet[PS2_MAX_PACKET_SIZE];
16719370Spst	status_t status;
168242936Semaste
16919370Spst	TRACE("ps2: standard_mouse_read_event\n");
17019370Spst
171242936Semaste	status = acquire_sem_etc(cookie->standard_mouse_sem, 1, B_CAN_INTERRUPT, 0);
172242936Semaste	TRACE("ps2: standard_mouse_read_event acquired\n");
173242936Semaste	if (status < B_OK)
174242936Semaste		return status;
175242936Semaste
176242936Semaste	if (!cookie->dev->active) {
177242936Semaste		TRACE("ps2: standard_mouse_read_event: Error device no longer "
178242936Semaste			"active\n");
179242936Semaste		return B_ERROR;
180242936Semaste	}
181242936Semaste
182242936Semaste	if (packet_buffer_read(cookie->standard_mouse_buffer, packet,
183242936Semaste		cookie->dev->packet_size) != cookie->dev->packet_size) {
184242936Semaste		TRACE("ps2: error copying buffer\n");
185242936Semaste		return B_ERROR;
186242936Semaste	}
187242936Semaste
188242936Semaste	if (!(packet[0] & 8))
189242936Semaste		panic("ps2: got broken data from packet_buffer_read\n");
190242936Semaste
191242936Semaste	ps2_packet_to_movement(cookie, packet, movement);
192242936Semaste	return B_OK;
193242936Semaste}
194242936Semaste
195242936Semaste
196242936Semaste//	#pragma mark - Interrupt handler functions
197242936Semaste
198242936Semaste
199242936Semastevoid
200242936Semastestandard_mouse_disconnect(ps2_dev* dev)
201242936Semaste{
202242936Semaste	// the mouse device might not be opened at this point
203242936Semaste	INFO("ps2: ps2_standard_mouse_disconnect %s\n", dev->name);
204242936Semaste	if (dev->flags & PS2_FLAG_OPEN)
205242936Semaste		release_sem(((standard_mouse_cookie*)dev->cookie)->standard_mouse_sem);
206242936Semaste}
207242936Semaste
208242936Semaste
209242936Semaste/*!	Interrupt handler for the mouse device. Called whenever the I/O
210242936Semaste	controller generates an interrupt for the PS/2 mouse. Reads mouse
211242936Semaste	information from the data port, and stores it, so it can be accessed
212242936Semaste	by read() operations. The full data is obtained using 3 consecutive
21319370Spst	calls to the handler, each holds a different byte on the data port.
21419370Spst*/
21519370Spstint32
21619370Spststandard_mouse_handle_int(ps2_dev* dev)
21719370Spst{
21819370Spst	standard_mouse_cookie* cookie = (standard_mouse_cookie*)dev->cookie;
21919370Spst	const uint8 data = dev->history[0].data;
22019370Spst
22198944Sobrien	TRACE("ps2: standard mouse: %1x\t%1x\t%1x\t%1x\t%1x\t%1x\t%1x\t%1x\n",
22298944Sobrien		data >> 7 & 1, data >> 6 & 1, data >> 5 & 1,
22319370Spst		data >> 4 & 1, data >> 3 & 1, data >> 2 & 1,
22419370Spst		data >> 1 & 1, data >> 0 & 1);
22519370Spst
22619370Spst	if (cookie->packet_index == 0 && (data & 8) == 0) {
22719370Spst		INFO("ps2: bad mouse data, trying resync\n");
22819370Spst		return B_HANDLED_INTERRUPT;
22919370Spst	}
23019370Spst
23119370Spst	// Workarounds for active multiplexing keyboard controllers
23219370Spst	// that lose data or send them to the wrong port.
23319370Spst	if (cookie->packet_index == 0 && (data & 0xc0) != 0) {
23419370Spst		INFO("ps2: strange mouse data, x/y overflow, trying resync\n");
23519370Spst		return B_HANDLED_INTERRUPT;
23619370Spst	}
23719370Spst
23819370Spst	cookie->buffer[cookie->packet_index++] = data;
23919370Spst
24019370Spst	if (cookie->packet_index != dev->packet_size) {
24119370Spst		// packet not yet complete
24219370Spst		return B_HANDLED_INTERRUPT;
24319370Spst	}
24419370Spst
24519370Spst	// complete packet is assembled
24619370Spst
24719370Spst	cookie->packet_index = 0;
24819370Spst	if (packet_buffer_write(cookie->standard_mouse_buffer,
24919370Spst		cookie->buffer, dev->packet_size) != dev->packet_size) {
25019370Spst		// buffer is full, drop new data
25119370Spst		return B_HANDLED_INTERRUPT;
25246283Sdfr	}
25346283Sdfr
25446283Sdfr	release_sem_etc(cookie->standard_mouse_sem, 1, B_DO_NOT_RESCHEDULE);
25546283Sdfr
25646283Sdfr	return B_INVOKE_SCHEDULER;
25746283Sdfr}
25819370Spst
25946283Sdfr
26046283Sdfr//	#pragma mark - probe_standard_mouse()
26146283Sdfr
26246283Sdfr
26398944Sobrienstatus_t
26446283Sdfrprobe_standard_mouse(ps2_dev* dev)
26546283Sdfr{
26698944Sobrien	status_t status;
26798944Sobrien	uint8 deviceId = 0;
26846283Sdfr
26998944Sobrien	// get device id
27098944Sobrien	status = ps2_dev_command(dev, PS2_CMD_GET_DEVICE_ID, NULL, 0,
27146283Sdfr		&deviceId, 1);
27246283Sdfr	if (status != B_OK) {
27346283Sdfr		INFO("ps2: probe_mouse get device id failed\n");
27446283Sdfr		return B_ERROR;
27546283Sdfr	}
27646283Sdfr
27746283Sdfr	TRACE("ps2: probe_mouse device id: %2x\n", deviceId);
27846283Sdfr
27946283Sdfr	// check for MS Intellimouse
28046283Sdfr	if (deviceId == 0) {
28146283Sdfr		uint8 alternate_device_id;
28246283Sdfr		status  = ps2_set_sample_rate(dev, 200);
28346283Sdfr		status |= ps2_set_sample_rate(dev, 100);
28446283Sdfr		status |= ps2_set_sample_rate(dev, 80);
28546283Sdfr		status |= ps2_dev_command(dev, PS2_CMD_GET_DEVICE_ID, NULL, 0,
28646283Sdfr			&alternate_device_id, 1);
28746283Sdfr		if (status == 0) {
28846283Sdfr			TRACE("ps2: probe_mouse alternate device id: %2x\n",
28946283Sdfr				alternate_device_id);
29046283Sdfr			deviceId = alternate_device_id;
29146283Sdfr		}
29246283Sdfr	}
29346283Sdfr
29446283Sdfr	if (deviceId == PS2_DEV_ID_STANDARD
29546283Sdfr		|| deviceId == PS2_DEV_ID_TOUCHPAD_RICATECH) {
29698944Sobrien		INFO("ps2: probe_mouse Standard PS/2 mouse found\n");
29746283Sdfr		dev->name = kStandardMousePath[dev->idx];
29846283Sdfr		dev->packet_size = PS2_PACKET_STANDARD;
29946283Sdfr	} else if (deviceId == PS2_DEV_ID_INTELLIMOUSE) {
30046283Sdfr		dev->name = kIntelliMousePath[dev->idx];
30146283Sdfr		dev->packet_size = PS2_PACKET_INTELLIMOUSE;
30219370Spst		INFO("ps2: probe_mouse Extended PS/2 mouse found\n");
30398944Sobrien	} else {
30498944Sobrien		INFO("ps2: probe_mouse Error unknown device id.\n");
30519370Spst		return B_ERROR;
30619370Spst	}
30746283Sdfr
30819370Spst	return B_OK;
30946283Sdfr}
31046283Sdfr
31146283Sdfr
31246283Sdfr//	#pragma mark - Device functions
31346283Sdfr
31446283Sdfr
31546283Sdfrstatus_t
31646283Sdfrstandard_mouse_open(const char* name, uint32 flags, void** _cookie)
31746283Sdfr{
31846283Sdfr	standard_mouse_cookie* cookie;
31946283Sdfr	status_t status;
32046283Sdfr	ps2_dev* dev = NULL;
32146283Sdfr	int i;
32246283Sdfr
32346283Sdfr	TRACE("ps2: standard_mouse_open %s\n", name);
32446283Sdfr
32546283Sdfr	for (dev = NULL, i = 0; i < PS2_DEVICE_COUNT; i++) {
32646283Sdfr		if (0 == strcmp(ps2_device[i].name, name)) {
32746283Sdfr			dev = &ps2_device[i];
32846283Sdfr			break;
32946283Sdfr		}
33046283Sdfr#if 0
33146283Sdfr		if (0 == strcmp(g_passthrough_dev.name, name)) {
33246283Sdfr			dev = &g_passthrough_dev;
33346283Sdfr			isSynapticsPTDevice = true;
33446283Sdfr			break;
33546283Sdfr		}
33646283Sdfr#endif
33746283Sdfr	}
33846283Sdfr
33946283Sdfr	if (dev == NULL) {
34046283Sdfr		TRACE("ps2: dev = NULL\n");
34146283Sdfr		return B_ERROR;
34246283Sdfr	}
34346283Sdfr
34446283Sdfr	if (atomic_or(&dev->flags, PS2_FLAG_OPEN) & PS2_FLAG_OPEN)
34546283Sdfr		return B_BUSY;
34646283Sdfr
34746283Sdfr	cookie = (standard_mouse_cookie*)malloc(sizeof(standard_mouse_cookie));
34846283Sdfr	if (cookie == NULL)
34946283Sdfr		goto err1;
35046283Sdfr
35146283Sdfr	*_cookie = cookie;
35246283Sdfr	memset(cookie, 0, sizeof(*cookie));
35346283Sdfr
35446283Sdfr	cookie->dev = dev;
35546283Sdfr	dev->cookie = cookie;
35646283Sdfr	dev->disconnect = &standard_mouse_disconnect;
35746283Sdfr	dev->handle_int = &standard_mouse_handle_int;
35846283Sdfr
35919370Spst	if (strstr(dev->name, "standard") != NULL)
36019370Spst		cookie->flags = F_MOUSE_TYPE_STANDARD;
36119370Spst
36246283Sdfr	if (strstr(dev->name, "intelli") != NULL)
36319370Spst		cookie->flags = F_MOUSE_TYPE_INTELLIMOUSE;
36419370Spst
36519370Spst	cookie->standard_mouse_buffer
36619370Spst		= create_packet_buffer(MOUSE_HISTORY_SIZE * dev->packet_size);
36719370Spst	if (cookie->standard_mouse_buffer == NULL) {
36898944Sobrien		TRACE("ps2: can't allocate mouse actions buffer\n");
369130803Smarcel		goto err2;
37019370Spst	}
37119370Spst
372130803Smarcel	// create the mouse semaphore, used for synchronization between
37319370Spst	// the interrupt handler and the read operation
37419370Spst	cookie->standard_mouse_sem = create_sem(0, "ps2_standard_mouse_sem");
37519370Spst	if (cookie->standard_mouse_sem < 0) {
37619370Spst		TRACE("ps2: failed creating PS/2 mouse semaphore!\n");
37798944Sobrien		goto err3;
378130803Smarcel	}
37919370Spst
38019370Spst	status = ps2_dev_command(dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0);
38119370Spst	if (status < B_OK) {
38219370Spst		INFO("ps2: cannot enable mouse %s\n", name);
38398944Sobrien		goto err4;
384130803Smarcel	}
38519370Spst
38619370Spst	atomic_or(&dev->flags, PS2_FLAG_ENABLED);
38719370Spst
38819370Spst
38919370Spst	TRACE("ps2: standard_mouse_open %s success\n", name);
39019370Spst	return B_OK;
39119370Spst
39219370Spsterr4:
39319370Spst	delete_sem(cookie->standard_mouse_sem);
39419370Spsterr3:
39519370Spst	delete_packet_buffer(cookie->standard_mouse_buffer);
39619370Spsterr2:
39719370Spst	free(cookie);
39819370Spsterr1:
39998944Sobrien	atomic_and(&dev->flags, ~PS2_FLAG_OPEN);
40019370Spst
40198944Sobrien	TRACE("ps2: standard_mouse_open %s failed\n", name);
40219370Spst	return B_ERROR;
40319370Spst}
40419370Spst
40519370Spst
40619370Spststatus_t
40719370Spststandard_mouse_close(void* _cookie)
40819370Spst{
40919370Spst	standard_mouse_cookie* cookie = (standard_mouse_cookie*)_cookie;
41019370Spst
41198944Sobrien	TRACE("ps2: standard_mouse_close %s enter\n", cookie->dev->name);
41219370Spst
41319370Spst	ps2_dev_command_timeout(cookie->dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0,
41419370Spst		150000);
41519370Spst
41619370Spst	delete_packet_buffer(cookie->standard_mouse_buffer);
41719370Spst	delete_sem(cookie->standard_mouse_sem);
41819370Spst
41919370Spst	atomic_and(&cookie->dev->flags, ~PS2_FLAG_OPEN);
42098944Sobrien	atomic_and(&cookie->dev->flags, ~PS2_FLAG_ENABLED);
42146283Sdfr
42219370Spst	TRACE("ps2: standard_mouse_close %s done\n", cookie->dev->name);
42319370Spst	return B_OK;
42419370Spst}
42519370Spst
42698944Sobrien
42746283Sdfrstatus_t
42819370Spststandard_mouse_freecookie(void* _cookie)
42919370Spst{
43019370Spst	standard_mouse_cookie* cookie = (standard_mouse_cookie*)_cookie;
43146283Sdfr	free(cookie);
43219370Spst	return B_OK;
43319370Spst}
43419370Spst
43546283Sdfr
43619370Spststatic status_t
43719370Spststandard_mouse_read(void* cookie, off_t pos, void* buffer, size_t* _length)
43819370Spst{
43946283Sdfr	*_length = 0;
44019370Spst	return B_NOT_ALLOWED;
44119370Spst}
44219370Spst
44346283Sdfr
44419370Spststatic status_t
44519370Spststandard_mouse_write(void* cookie, off_t pos, const void* buffer,
44698944Sobrien	size_t* _length)
44719370Spst{
44846283Sdfr	*_length = 0;
44946283Sdfr	return B_NOT_ALLOWED;
45046283Sdfr}
45119370Spst
45219370Spst
45319370Spststatus_t
45419370Spststandard_mouse_ioctl(void* _cookie, uint32 op, void* buffer, size_t length)
45519370Spst{
45619370Spst	standard_mouse_cookie* cookie = (standard_mouse_cookie*)_cookie;
45719370Spst
45898944Sobrien	switch (op) {
45919370Spst		case MS_NUM_EVENTS:
46046283Sdfr		{
46146283Sdfr			int32 count;
46219370Spst			TRACE("ps2: ioctl MS_NUM_EVENTS\n");
46346283Sdfr			get_sem_count(cookie->standard_mouse_sem, &count);
46446283Sdfr			return count;
46546283Sdfr		}
46646283Sdfr
46746283Sdfr		case MS_READ:
46846283Sdfr		{
46946283Sdfr			mouse_movement movement;
47046283Sdfr			status_t status;
47146283Sdfr			TRACE("ps2: ioctl MS_READ\n");
47219370Spst			if ((status = standard_mouse_read_event(cookie, &movement)) < B_OK)
47319370Spst				return status;
47498944Sobrien//			TRACE("%s %d %d %d %d\n", cookie->dev->name,
47598944Sobrien//				movement.xdelta, movement.ydelta, movement.buttons,
47619370Spst//				movement.clicks);
47719370Spst			return user_memcpy(buffer, &movement, sizeof(movement));
47898944Sobrien		}
47919370Spst
48019370Spst		case MS_SET_TYPE:
48119370Spst			TRACE("ps2: ioctl MS_SET_TYPE not implemented\n");
48298944Sobrien			return B_BAD_VALUE;
48319370Spst
48419370Spst		case MS_SET_MAP:
48598944Sobrien			TRACE("ps2: ioctl MS_SET_MAP (set mouse mapping) not "
48698944Sobrien				"implemented\n");
48798944Sobrien			return B_BAD_VALUE;
48898944Sobrien
48998944Sobrien		case MS_GET_ACCEL:
49098944Sobrien			TRACE("ps2: ioctl MS_GET_ACCEL (get mouse acceleration) not "
49198944Sobrien				"implemented\n");
49298944Sobrien			return B_BAD_VALUE;
493130803Smarcel
494130803Smarcel		case MS_SET_ACCEL:
495130803Smarcel			TRACE("ps2: ioctl MS_SET_ACCEL (set mouse acceleration) not "
49698944Sobrien				"implemented\n");
49798944Sobrien			return B_BAD_VALUE;
49898944Sobrien
49919370Spst		case MS_SET_CLICKSPEED:
50098944Sobrien			TRACE("ps2: ioctl MS_SETCLICK (set click speed)\n");
50198944Sobrien			return user_memcpy(&cookie->click_speed, buffer, sizeof(bigtime_t));
50298944Sobrien
50398944Sobrien		default:
50498944Sobrien			TRACE("ps2: ioctl unknown mouse opcode: %" B_PRIu32 "\n", op);
50598944Sobrien			return B_DEV_INVALID_IOCTL;
50698944Sobrien	}
50798944Sobrien}
50819370Spst
50919370Spst
51019370Spstdevice_hooks gStandardMouseDeviceHooks = {
51119370Spst	standard_mouse_open,
51219370Spst	standard_mouse_close,
51319370Spst	standard_mouse_freecookie,
51419370Spst	standard_mouse_ioctl,
51519370Spst	standard_mouse_read,
51698944Sobrien	standard_mouse_write,
51798944Sobrien};
51898944Sobrien