Many changes, it now does work okay on Haiku (tested with consoled only (both,
keyboard and mouse part), since for some reason, the app_server refuses to work with the input_server for me now): - keyboards are now actually detected, the keyboard device is only published if there actually is a keyboard - keyboard_close() no longer calls put_module() for the ISA bus manager; it's sharing that resource with the mouse driver. - rewrote the keyboard command handshake; now, the acknowledge byte is always considered, and it's now also safe to call keyboard commands with the interrupt handler installed (bytes read are now safely routed through the handler). - keyboard_open() now also sets the PS/2 command byte to enable keyboard interrupts (this may actually have been the source of all evil - ie. keyboard not working after having touched the mouse) - many commands now try again several times if they failed - ps2_get_command_byte() is now safe to be called when the keyboard driver is up and running, too (it's now locally buffered) - more and better error checks - possibly more I forgot about... - general cleanup. Note, there is still some functionality missing from the keyboard driver: - ctrl/alt/del handling - key repeat (delay, time, non-repeating) Repeat stuff might better be moved to the input_server add-on, anyway, for more flexibility and better performance. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@12498 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
b9cc06b57c
commit
80bd55147b
@ -6,6 +6,7 @@
|
||||
* PS/2 hid device driver
|
||||
* Authors (in chronological order):
|
||||
* Stefano Ceccherini (burton666@libero.it)
|
||||
* Axel Dörfler, axeld@pinc-software.de
|
||||
*/
|
||||
|
||||
|
||||
@ -19,10 +20,8 @@
|
||||
#define DEVICE_KEYBOARD_NAME "input/keyboard/at/0"
|
||||
|
||||
int32 api_version = B_CUR_DRIVER_API_VERSION;
|
||||
isa_module_info *gIsa = NULL;
|
||||
|
||||
device_hooks
|
||||
keyboard_hooks = {
|
||||
static device_hooks sKeyboardDeviceHooks = {
|
||||
keyboard_open,
|
||||
keyboard_close,
|
||||
keyboard_freecookie,
|
||||
@ -35,9 +34,7 @@ keyboard_hooks = {
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
device_hooks
|
||||
mouse_hooks = {
|
||||
static device_hooks sMouseDeviceHooks = {
|
||||
mouse_open,
|
||||
mouse_close,
|
||||
mouse_freecookie,
|
||||
@ -51,6 +48,79 @@ mouse_hooks = {
|
||||
};
|
||||
|
||||
|
||||
isa_module_info *gIsa = NULL;
|
||||
sem_id gDeviceOpenSemaphore;
|
||||
|
||||
static int32 sInitialized = 0;
|
||||
static uint8 sCommandByte = 0;
|
||||
static bool sKeyboardDetected = false;
|
||||
|
||||
static sem_id sResultSemaphore;
|
||||
static sem_id sResultOwnerSemaphore;
|
||||
static uint8 *sResultBuffer;
|
||||
static int32 sResultBytes;
|
||||
|
||||
|
||||
/** Wait until the specified status bits are cleared or set, depending on the
|
||||
* second parameter.
|
||||
* This currently busy waits, but should nonetheless be avoided in interrupt
|
||||
* handlers.
|
||||
*/
|
||||
|
||||
static status_t
|
||||
wait_for_status(int32 bits, bool set)
|
||||
{
|
||||
int8 read;
|
||||
int32 tries = 100;
|
||||
|
||||
TRACE(("wait_write_ctrl(bits = %lx, %s)\n", bits, set ? "set" : "cleared"));
|
||||
|
||||
while (tries-- > 0) {
|
||||
read = gIsa->read_io_8(PS2_PORT_CTRL);
|
||||
if (((read & bits) != 0) == set)
|
||||
return B_OK;
|
||||
|
||||
spin(100);
|
||||
}
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static inline status_t
|
||||
wait_for_bits_cleared(int32 bits)
|
||||
{
|
||||
return wait_for_status(bits, false);
|
||||
}
|
||||
|
||||
|
||||
static inline status_t
|
||||
wait_for_bits_set(int32 bits)
|
||||
{
|
||||
return wait_for_status(bits, true);
|
||||
}
|
||||
|
||||
|
||||
/** Reads the command byte from the 8042 controller.
|
||||
* Since the read goes through the data port, this function must not be
|
||||
* called when the keyboard driver is up and running.
|
||||
*/
|
||||
|
||||
static status_t
|
||||
get_command_byte(uint8 *data)
|
||||
{
|
||||
TRACE(("get_command_byte()\n"));
|
||||
|
||||
if (ps2_write_ctrl(PS2_CTRL_READ_CMD) == B_OK)
|
||||
return ps2_read_data(data);
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
/** Wait until the control port is ready to be written. This requires that
|
||||
* the "Input buffer full" and "Output buffer full" bits will both be set
|
||||
* to 0. Returns true if the control port is ready to be written, false
|
||||
@ -58,131 +128,159 @@ mouse_hooks = {
|
||||
* port is still busy.
|
||||
*/
|
||||
|
||||
bool
|
||||
wait_write_ctrl(void)
|
||||
status_t
|
||||
ps2_write_ctrl(uint8 data)
|
||||
{
|
||||
int8 read;
|
||||
int32 tries = 100;
|
||||
TRACE(("wait_write_ctrl()\n"));
|
||||
do {
|
||||
read = gIsa->read_io_8(PS2_PORT_CTRL);
|
||||
spin(100);
|
||||
} while ((read & (PS2_IBUF_FULL | PS2_OBUF_FULL)) && tries-- > 0);
|
||||
if (wait_for_bits_cleared(PS2_STATUS_INPUT_BUFFER_FULL | PS2_STATUS_OUTPUT_BUFFER_FULL) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
return tries > 0;
|
||||
gIsa->write_io_8(PS2_PORT_CTRL, data);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/** Wait until the data port is ready to be written. This requires that
|
||||
* the "Input buffer full" bit will be set to 0.
|
||||
/** Wait until the data port is ready to be written, and then writes \a data to it.
|
||||
*/
|
||||
|
||||
bool
|
||||
wait_write_data(void)
|
||||
status_t
|
||||
ps2_write_data(uint8 data)
|
||||
{
|
||||
int8 read;
|
||||
int32 tries = 100;
|
||||
TRACE(("wait_write_data()\n"));
|
||||
do {
|
||||
read = gIsa->read_io_8(PS2_PORT_CTRL);
|
||||
spin(100);
|
||||
} while ((read & PS2_IBUF_FULL) && tries-- > 0);
|
||||
if (wait_for_bits_cleared(PS2_STATUS_INPUT_BUFFER_FULL) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
return tries > 0;
|
||||
gIsa->write_io_8(PS2_PORT_DATA, data);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/** Wait until the data port can be read from. This requires that the
|
||||
* "Output buffer full" bit will be set to 1.
|
||||
/** Wait until the data port can be read from, and then transfers the byte read
|
||||
* to /a data.
|
||||
*/
|
||||
|
||||
bool
|
||||
wait_read_data(void)
|
||||
status_t
|
||||
ps2_read_data(uint8 *data)
|
||||
{
|
||||
int8 read;
|
||||
int32 tries = 100;
|
||||
TRACE(("wait_read_data()\n"));
|
||||
do {
|
||||
read = gIsa->read_io_8(PS2_PORT_CTRL);
|
||||
spin(100);
|
||||
} while (!(read & PS2_OBUF_FULL) && tries-- > 0);
|
||||
if (wait_for_bits_set(PS2_STATUS_OUTPUT_BUFFER_FULL) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
return tries > 0;
|
||||
*data = gIsa->read_io_8(PS2_PORT_DATA);
|
||||
TRACE(("ps2_read_data(): read %u\n", *data));
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/** Get the ps2 command byte.
|
||||
|
||||
/** Get the PS/2 command byte. This cannot fail, since we're using our buffered
|
||||
* data, read out in init_driver().
|
||||
*/
|
||||
|
||||
int8
|
||||
get_command_byte(void)
|
||||
uint8
|
||||
ps2_get_command_byte(void)
|
||||
{
|
||||
int8 read = 0;
|
||||
TRACE(("ps2_get_command_byte(): command byte = %x\n", sCommandByte));
|
||||
|
||||
TRACE(("set_command_byte()\n"));
|
||||
if (wait_write_ctrl()) {
|
||||
gIsa->write_io_8(PS2_PORT_CTRL, PS2_CTRL_READ_CMD);
|
||||
if (wait_read_data())
|
||||
read = gIsa->read_io_8(PS2_PORT_DATA);
|
||||
}
|
||||
|
||||
return read;
|
||||
return sCommandByte;
|
||||
}
|
||||
|
||||
|
||||
/** Set the ps2 command byte.
|
||||
* Parameters:
|
||||
* unsigned char, byte to write
|
||||
*/
|
||||
|
||||
void
|
||||
set_command_byte(unsigned char cmd)
|
||||
status_t
|
||||
ps2_set_command_byte(uint8 command)
|
||||
{
|
||||
TRACE(("set_command_byte()\n"));
|
||||
if (wait_write_ctrl()) {
|
||||
gIsa->write_io_8(PS2_PORT_CTRL, PS2_CTRL_WRITE_CMD);
|
||||
if (wait_write_data())
|
||||
gIsa->write_io_8(PS2_PORT_DATA, cmd);
|
||||
TRACE(("set_command_byte(command = %x)\n", command));
|
||||
|
||||
if (ps2_write_ctrl(PS2_CTRL_WRITE_CMD) == B_OK
|
||||
&& ps2_write_data(command) == B_OK) {
|
||||
sCommandByte = command;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/** Reads a single byte from the data port.
|
||||
* Return value:
|
||||
* unsigned char, byte read
|
||||
*/
|
||||
|
||||
uint8
|
||||
read_data_byte(void)
|
||||
bool
|
||||
ps2_handle_result(uint8 data)
|
||||
{
|
||||
TRACE(("read_data_byte()\n"));
|
||||
if (wait_read_data()) {
|
||||
TRACE(("read_data_byte(): ok\n"));
|
||||
return gIsa->read_io_8(PS2_PORT_DATA);
|
||||
}
|
||||
|
||||
TRACE(("read_data_byte(): timeout\n"));
|
||||
|
||||
return PS2_ERROR;
|
||||
int32 bytesLeft;
|
||||
|
||||
if (sResultBuffer == NULL
|
||||
|| (bytesLeft = atomic_add(&sResultBytes, -1)) <= 0)
|
||||
return false;
|
||||
|
||||
*(sResultBuffer++) = data;
|
||||
if (bytesLeft == 1)
|
||||
release_sem_etc(sResultSemaphore, 1, B_DO_NOT_RESCHEDULE);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** Writes a byte to the mouse device. Uses the control port to indicate
|
||||
* that the byte is sent to the auxiliary device (mouse), instead of the
|
||||
* keyboard.
|
||||
* Parameters:
|
||||
* unsigned char, byte to write
|
||||
*/
|
||||
void
|
||||
ps2_claim_result(uint8 *buffer, size_t bytes)
|
||||
{
|
||||
acquire_sem(sResultOwnerSemaphore);
|
||||
|
||||
sResultBuffer = buffer;
|
||||
sResultBytes = bytes;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
write_aux_byte(unsigned char cmd)
|
||||
ps2_unclaim_result(void)
|
||||
{
|
||||
TRACE(("write_aux_byte()\n"));
|
||||
if (wait_write_ctrl()) {
|
||||
gIsa->write_io_8(PS2_PORT_CTRL, PS2_CTRL_WRITE_AUX);
|
||||
sResultBytes = 0;
|
||||
sResultBuffer = NULL;
|
||||
|
||||
if (wait_write_data())
|
||||
gIsa->write_io_8(PS2_PORT_DATA, cmd);
|
||||
release_sem(sResultOwnerSemaphore);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ps2_wait_for_result(void)
|
||||
{
|
||||
status_t status = acquire_sem_etc(sResultSemaphore, 1, B_RELATIVE_TIMEOUT, 100000);
|
||||
// 0.1 secs for now
|
||||
|
||||
ps2_unclaim_result();
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ps2_common_uninitialize(void)
|
||||
{
|
||||
// do we still need the resources?
|
||||
if (atomic_add(&sInitialized, -1) > 1)
|
||||
return;
|
||||
|
||||
delete_sem(sResultSemaphore);
|
||||
delete_sem(sResultOwnerSemaphore);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ps2_common_initialize(void)
|
||||
{
|
||||
if (atomic_add(&sInitialized, 1) > 0) {
|
||||
// we're already initialized
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
sResultSemaphore = create_sem(0, "ps/2 result");
|
||||
if (sResultSemaphore < B_OK)
|
||||
return sResultSemaphore;
|
||||
|
||||
sResultOwnerSemaphore = create_sem(1, "ps/2 result owner");
|
||||
if (sResultOwnerSemaphore < B_OK) {
|
||||
delete_sem(sResultSemaphore);
|
||||
return sResultOwnerSemaphore;
|
||||
}
|
||||
|
||||
sResultBytes = 0;
|
||||
sResultBuffer = NULL;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -197,18 +295,20 @@ init_hardware(void)
|
||||
}
|
||||
|
||||
|
||||
static const char *
|
||||
kDevices[] = {
|
||||
DEVICE_KEYBOARD_NAME,
|
||||
DEVICE_MOUSE_NAME,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
const char **
|
||||
publish_devices(void)
|
||||
{
|
||||
return kDevices;
|
||||
static char *kDevices[3];
|
||||
|
||||
kDevices[0] = DEVICE_MOUSE_NAME;
|
||||
|
||||
if (sKeyboardDetected) {
|
||||
kDevices[1] = DEVICE_KEYBOARD_NAME;
|
||||
kDevices[2] = NULL;
|
||||
} else
|
||||
kDevices[1] = NULL;
|
||||
|
||||
return (const char **)kDevices;
|
||||
}
|
||||
|
||||
|
||||
@ -216,9 +316,9 @@ device_hooks *
|
||||
find_device(const char *name)
|
||||
{
|
||||
if (!strcmp(name, DEVICE_MOUSE_NAME))
|
||||
return &mouse_hooks;
|
||||
return &sMouseDeviceHooks;
|
||||
else if (!strcmp(name, DEVICE_KEYBOARD_NAME))
|
||||
return &keyboard_hooks;
|
||||
return &sKeyboardDeviceHooks;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -235,12 +335,31 @@ init_driver(void)
|
||||
return status;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
// If there is no keyboard or mouse, we don't need to publish ourselves
|
||||
|
||||
if (probe_keyboard() == B_OK)
|
||||
sKeyboardDetected = true;
|
||||
else
|
||||
dprintf("ps2_hid: no keyboard detected!\n");
|
||||
|
||||
if (!sKeyboardDetected && probe_mouse() != B_OK) {
|
||||
put_module(B_ISA_MODULE_NAME);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// A semaphore to synchronize open keyboard and mouse devices
|
||||
|
||||
gDeviceOpenSemaphore = create_sem(1, "ps/2 open");
|
||||
if (gDeviceOpenSemaphore < B_OK)
|
||||
return gDeviceOpenSemaphore;
|
||||
|
||||
return get_command_byte(&sCommandByte);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
uninit_driver(void)
|
||||
{
|
||||
delete_sem(gDeviceOpenSemaphore);
|
||||
put_module(B_ISA_MODULE_NAME);
|
||||
}
|
||||
|
@ -19,59 +19,67 @@
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// definitions
|
||||
// Interface definitions for the Intel 8042, 8741, or 8742 (PS/2)
|
||||
|
||||
// I/O addresses
|
||||
#define PS2_PORT_DATA 0x60
|
||||
#define PS2_PORT_CTRL 0x64
|
||||
#define PS2_PORT_DATA 0x60
|
||||
#define PS2_PORT_CTRL 0x64
|
||||
|
||||
// data port bits
|
||||
#define PS2_OBUF_FULL 0x01
|
||||
#define PS2_IBUF_FULL 0x02
|
||||
#define PS2_MOUSE_OBUF_FULL 0x20
|
||||
#define PS2_TIMEOUT 0x40
|
||||
#define PS2_STATUS_OUTPUT_BUFFER_FULL 0x01
|
||||
#define PS2_STATUS_INPUT_BUFFER_FULL 0x02
|
||||
#define PS2_STATUS_MOUSE_DATA 0x20
|
||||
#define PS2_STATUS_TIMEOUT 0x40
|
||||
|
||||
// control words
|
||||
#define PS2_CTRL_READ_CMD 0x20
|
||||
#define PS2_CTRL_WRITE_CMD 0x60
|
||||
#define PS2_CTRL_WRITE_AUX 0xD4
|
||||
#define PS2_CTRL_MOUSE_DISABLE 0xA7
|
||||
#define PS2_CTRL_MOUSE_ENABLE 0xA8
|
||||
#define PS2_CTRL_MOUSE_TEST 0xA9
|
||||
#define PS2_CTRL_READ_CMD 0x20
|
||||
#define PS2_CTRL_WRITE_CMD 0x60
|
||||
#define PS2_CTRL_WRITE_AUX 0xd4
|
||||
#define PS2_CTRL_MOUSE_DISABLE 0xa7
|
||||
#define PS2_CTRL_MOUSE_ENABLE 0xa8
|
||||
#define PS2_CTRL_MOUSE_TEST 0xa9
|
||||
#define PS2_CTRL_KEYBOARD_SELF_TEST 0xaa
|
||||
#define PS2_CTRL_KEYBOARD_ACTIVATE 0xae
|
||||
#define PS2_CTRL_KEYBOARD_DEACTIVATE 0xad
|
||||
|
||||
// command bytes
|
||||
#define PS2_CMD_DEV_INIT 0x43
|
||||
#define PS2_CMD_DEV_INIT 0x43
|
||||
|
||||
// command bits
|
||||
#define PS2_BITS_AUX_INTERRUPT 0x02
|
||||
#define PS2_BITS_MOUSE_DISABLED 0x20
|
||||
#define PS2_BITS_KEYBOARD_INTERRUPT 0x01
|
||||
#define PS2_BITS_AUX_INTERRUPT 0x02
|
||||
#define PS2_BITS_KEYBOARD_DISABLED 0x10
|
||||
#define PS2_BITS_MOUSE_DISABLED 0x20
|
||||
#define PS2_BITS_TRANSLATE_SCANCODES 0x40
|
||||
|
||||
// data words
|
||||
#define PS2_CMD_TEST_PASSED 0xAA
|
||||
#define PS2_CMD_GET_DEVICE_ID 0xF2
|
||||
#define PS2_CMD_SET_SAMPLE_RATE 0xF3
|
||||
#define PS2_CMD_ENABLE_MOUSE 0xF4
|
||||
#define PS2_CMD_DISABLE_MOUSE 0xF5
|
||||
#define PS2_CMD_RESET_MOUSE 0xFF
|
||||
#define PS2_CMD_TEST_PASSED 0xaa
|
||||
#define PS2_CMD_GET_DEVICE_ID 0xf2
|
||||
#define PS2_CMD_SET_SAMPLE_RATE 0xf3
|
||||
#define PS2_CMD_ENABLE_MOUSE 0xf4
|
||||
#define PS2_CMD_DISABLE_MOUSE 0xf5
|
||||
#define PS2_CMD_RESET_MOUSE 0xff
|
||||
|
||||
// reply codes
|
||||
#define PS2_RES_TEST_PASSED 0x55
|
||||
#define PS2_RES_ACK 0xFA
|
||||
#define PS2_RES_RESEND 0xFE
|
||||
#define PS2_ERROR 0xFC
|
||||
#define PS2_REPLY_TEST_PASSED 0x55
|
||||
#define PS2_REPLY_ACK 0xfa
|
||||
#define PS2_REPLY_RESEND 0xfe
|
||||
#define PS2_REPLY_ERROR 0xfc
|
||||
|
||||
// interrupts
|
||||
#define INT_PS2_MOUSE 0x0C
|
||||
#define INT_PS2_KEYBOARD 0x01
|
||||
#define INT_PS2_MOUSE 0x0c
|
||||
#define INT_PS2_KEYBOARD 0x01
|
||||
|
||||
// mouse device IDs
|
||||
#define PS2_DEV_ID_STANDARD 0
|
||||
#define PS2_DEV_ID_INTELLIMOUSE 3
|
||||
#define PS2_DEV_ID_STANDARD 0
|
||||
#define PS2_DEV_ID_INTELLIMOUSE 3
|
||||
|
||||
// packet sizes
|
||||
#define PS2_PACKET_STANDARD 3
|
||||
#define PS2_PACKET_INTELLIMOUSE 4
|
||||
#define PS2_MAX_PACKET_SIZE 4 // Should be equal to the biggest packet size
|
||||
#define PS2_PACKET_STANDARD 3
|
||||
#define PS2_PACKET_INTELLIMOUSE 4
|
||||
#define PS2_MAX_PACKET_SIZE 4
|
||||
// Should be equal to the biggest packet size
|
||||
|
||||
|
||||
// debug defines
|
||||
#ifdef DEBUG
|
||||
@ -82,16 +90,28 @@
|
||||
|
||||
// global variables
|
||||
extern isa_module_info *gIsa;
|
||||
extern sem_id gDeviceOpenSemaphore;
|
||||
|
||||
// prototypes
|
||||
bool wait_write_ctrl(void);
|
||||
bool wait_write_data(void);
|
||||
bool wait_read_data(void);
|
||||
void write_aux_byte(unsigned char cmd);
|
||||
uint8 read_data_byte(void);
|
||||
// prototypes from common.c
|
||||
extern status_t ps2_write_ctrl(uint8 data);
|
||||
extern status_t ps2_write_data(uint8 data);
|
||||
extern status_t ps2_read_data(uint8 *data);
|
||||
|
||||
int8 get_command_byte(void);
|
||||
void set_command_byte(unsigned char cmd);
|
||||
extern status_t ps2_write_aux_byte(uint8 data);
|
||||
extern uint8 ps2_get_command_byte(void);
|
||||
extern status_t ps2_set_command_byte(uint8 command);
|
||||
|
||||
extern void ps2_claim_result(uint8 *buffer, size_t bytes);
|
||||
extern void ps2_unclaim_result(void);
|
||||
extern status_t ps2_wait_for_result(void);
|
||||
extern bool ps2_handle_result(uint8 data);
|
||||
|
||||
extern void ps2_common_uninitialize(void);
|
||||
extern status_t ps2_common_initialize(void);
|
||||
|
||||
// prototypes from keyboard.c & mouse.c
|
||||
extern status_t probe_keyboard(void);
|
||||
extern status_t probe_mouse(void);
|
||||
|
||||
extern status_t keyboard_open(const char *name, uint32 flags, void **cookie);
|
||||
extern status_t keyboard_close(void *cookie);
|
||||
|
@ -27,20 +27,113 @@ enum {
|
||||
} leds_status;
|
||||
|
||||
enum {
|
||||
PS2_SET_LEDS = 0xed
|
||||
} commands;
|
||||
PS2_DATA_SET_LEDS = 0xed,
|
||||
PS2_ENABLE_KEYBOARD = 0xf4,
|
||||
|
||||
EXTENDED_KEY = 0xe0,
|
||||
};
|
||||
|
||||
|
||||
static int32 sKeyboardOpenMask;
|
||||
static sem_id sKeyboardSem;
|
||||
static struct packet_buffer *sKeyBuffer;
|
||||
static bool sIsExtended = false;
|
||||
static bool sInterruptHandlerInstalled = false;
|
||||
|
||||
|
||||
static void
|
||||
static status_t
|
||||
keyboard_write_byte(uint8 byte)
|
||||
{
|
||||
uint8 acknowledged = 0;
|
||||
|
||||
TRACE(("keyboard_write_byte(byte = %u)\n", byte));
|
||||
|
||||
if (sInterruptHandlerInstalled) {
|
||||
ps2_claim_result(&acknowledged, 1);
|
||||
|
||||
if (ps2_write_data(byte) != B_OK) {
|
||||
ps2_unclaim_result();
|
||||
return B_TIMED_OUT;
|
||||
}
|
||||
|
||||
ps2_wait_for_result();
|
||||
} else {
|
||||
status_t status = ps2_write_data(byte);
|
||||
if (status == B_OK)
|
||||
status = ps2_read_data(&acknowledged);
|
||||
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
}
|
||||
|
||||
return acknowledged == PS2_REPLY_ACK ? B_OK : B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
keyboard_read_bytes(uint8 *buffer, size_t bufferSize)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
TRACE(("keyboard_read_bytes(bufferSize = %lu)\n", bufferSize));
|
||||
|
||||
if (sInterruptHandlerInstalled) {
|
||||
ps2_claim_result(buffer, bufferSize);
|
||||
return ps2_wait_for_result();
|
||||
}
|
||||
|
||||
for (i = 0; i < bufferSize; i++) {
|
||||
status_t status = ps2_read_data(&buffer[i]);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
keyboard_empty_data(void)
|
||||
{
|
||||
uint8 data;
|
||||
|
||||
TRACE(("keyboard_empty_data()\n"));
|
||||
|
||||
while (ps2_read_data(&data) == B_OK) {
|
||||
// empty keyboard output buffer
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
keyboard_command(uint8 command, uint8 *buffer, size_t bufferSize)
|
||||
{
|
||||
status_t status;
|
||||
uint32 i;
|
||||
|
||||
TRACE(("keyboard_command(command = %u, bufferSize = %lu)\n", command, bufferSize));
|
||||
|
||||
status = keyboard_write_byte(command);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
for (i = 0; i < bufferSize; i++) {
|
||||
status = keyboard_write_byte(buffer[i]);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
set_leds(led_info *ledInfo)
|
||||
{
|
||||
int leds = 0;
|
||||
uint8 leds = 0;
|
||||
|
||||
TRACE(("ps2_hid: set keyboard LEDs\n"));
|
||||
|
||||
if (ledInfo->scroll_lock)
|
||||
leds |= LED_SCROLL;
|
||||
if (ledInfo->num_lock)
|
||||
@ -48,59 +141,69 @@ set_leds(led_info *ledInfo)
|
||||
if (ledInfo->caps_lock)
|
||||
leds |= LED_CAPS;
|
||||
|
||||
wait_write_data();
|
||||
gIsa->write_io_8(PS2_PORT_DATA, PS2_SET_LEDS);
|
||||
wait_write_data();
|
||||
gIsa->write_io_8(PS2_PORT_DATA, leds);
|
||||
return keyboard_command(PS2_DATA_SET_LEDS, &leds, sizeof(leds));
|
||||
}
|
||||
|
||||
|
||||
static int32
|
||||
static int32
|
||||
handle_keyboard_interrupt(void *data)
|
||||
{
|
||||
// TODO: Handle braindead "pause" key special case
|
||||
at_kbd_io keyInfo;
|
||||
unsigned char read, scancode;
|
||||
|
||||
read = gIsa->read_io_8(PS2_PORT_DATA);
|
||||
uint8 read = gIsa->read_io_8(PS2_PORT_CTRL);
|
||||
TRACE(("handle_keyboard_interrupt: read = 0x%x\n", read));
|
||||
|
||||
if (read == 0xE0) {
|
||||
sIsExtended = true;
|
||||
TRACE(("Extended key\n"));
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}
|
||||
if (read & PS2_STATUS_OUTPUT_BUFFER_FULL) {
|
||||
at_kbd_io keyInfo;
|
||||
uint8 scancode;
|
||||
|
||||
scancode = read;
|
||||
read = gIsa->read_io_8(PS2_PORT_DATA);
|
||||
|
||||
TRACE(("scancode: %x\n", scancode));
|
||||
// someone else might wait for a result from the keyboard controller
|
||||
if (ps2_handle_result(read))
|
||||
return B_INVOKE_SCHEDULER;
|
||||
|
||||
// For now, F12 enters the kernel debugger
|
||||
// ToDo: remove me later :-)
|
||||
if (scancode == 88)
|
||||
panic("keyboard requested halt.\n");
|
||||
// TODO: Handle braindead "pause" key special case
|
||||
|
||||
if (scancode & 0x80) {
|
||||
keyInfo.is_keydown = false;
|
||||
scancode -= 0x80;
|
||||
} else
|
||||
keyInfo.is_keydown = true;
|
||||
if (read == EXTENDED_KEY) {
|
||||
sIsExtended = true;
|
||||
TRACE(("Extended key\n"));
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}
|
||||
|
||||
if (sIsExtended) {
|
||||
scancode |= 0x80;
|
||||
sIsExtended = false;
|
||||
scancode = read;
|
||||
|
||||
TRACE(("scancode: %x\n", scancode));
|
||||
|
||||
// For now, F12 enters the kernel debugger
|
||||
// ToDo: remove me later :-)
|
||||
if (scancode == 88)
|
||||
panic("keyboard requested halt.\n");
|
||||
|
||||
if (scancode & 0x80) {
|
||||
keyInfo.is_keydown = false;
|
||||
scancode -= 0x80;
|
||||
} else
|
||||
keyInfo.is_keydown = true;
|
||||
|
||||
if (sIsExtended) {
|
||||
scancode |= 0x80;
|
||||
sIsExtended = false;
|
||||
}
|
||||
|
||||
keyInfo.timestamp = system_time();
|
||||
keyInfo.scancode = scancode;
|
||||
|
||||
while (packet_buffer_write(sKeyBuffer, (uint8 *)&keyInfo, sizeof(keyInfo)) == 0) {
|
||||
// if there is no space left in the buffer, we start dropping old key strokes
|
||||
packet_buffer_flush(sKeyBuffer, sizeof(keyInfo));
|
||||
}
|
||||
|
||||
release_sem_etc(sKeyboardSem, 1, B_DO_NOT_RESCHEDULE);
|
||||
} else {
|
||||
// ToDo: the buffer is not yet available, we should come back soon...
|
||||
// (depending on how often we see the message below... :-)
|
||||
dprintf("ps2_hid: keyboard: buffer not available!\n");
|
||||
}
|
||||
|
||||
keyInfo.timestamp = system_time();
|
||||
keyInfo.scancode = scancode;
|
||||
|
||||
while (packet_buffer_write(sKeyBuffer, (uint8 *)&keyInfo, sizeof(keyInfo)) == 0) {
|
||||
// if there is no space left in the buffer, we start dropping old key strokes
|
||||
packet_buffer_flush(sKeyBuffer, sizeof(keyInfo));
|
||||
}
|
||||
|
||||
release_sem_etc(sKeyboardSem, 1, B_DO_NOT_RESCHEDULE);
|
||||
|
||||
return B_INVOKE_SCHEDULER;
|
||||
}
|
||||
|
||||
@ -109,8 +212,11 @@ static status_t
|
||||
read_keyboard_packet(at_kbd_io *userBuffer)
|
||||
{
|
||||
at_kbd_io packet;
|
||||
status_t status;
|
||||
|
||||
status_t status = acquire_sem_etc(sKeyboardSem, 1, B_CAN_INTERRUPT, 0);
|
||||
TRACE(("read_keyboard_packet()\n"));
|
||||
|
||||
status = acquire_sem_etc(sKeyboardSem, 1, B_CAN_INTERRUPT, 0);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
@ -125,58 +231,156 @@ read_keyboard_packet(at_kbd_io *userBuffer)
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
enable_keyboard(void)
|
||||
{
|
||||
uint32 tries = 3;
|
||||
|
||||
keyboard_empty_data();
|
||||
|
||||
while (tries-- > 0) {
|
||||
if (keyboard_command(PS2_ENABLE_KEYBOARD, NULL, 0) == B_OK)
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
status_t
|
||||
status_t
|
||||
probe_keyboard(void)
|
||||
{
|
||||
uint32 tries;
|
||||
|
||||
// ToDo: for now there just is a keyboard ready to be used...
|
||||
|
||||
keyboard_empty_data();
|
||||
|
||||
// Keyboard self-test
|
||||
|
||||
if (ps2_write_ctrl(PS2_CTRL_KEYBOARD_SELF_TEST) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
tries = 3;
|
||||
while (tries-- > 0) {
|
||||
uint8 acknowledged;
|
||||
if (ps2_read_data(&acknowledged) == B_OK && acknowledged == PS2_REPLY_ACK)
|
||||
break;
|
||||
}
|
||||
if (tries < 0)
|
||||
return B_ERROR;
|
||||
|
||||
// Activate keyboard
|
||||
|
||||
if (ps2_write_ctrl(PS2_CTRL_KEYBOARD_ACTIVATE) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
// Enable keyboard
|
||||
|
||||
return enable_keyboard();
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
status_t
|
||||
keyboard_open(const char *name, uint32 flags, void **_cookie)
|
||||
{
|
||||
uint8 commandByte;
|
||||
status_t status;
|
||||
|
||||
TRACE(("keyboard open()\n"));
|
||||
|
||||
if (atomic_or(&sKeyboardOpenMask, 1) != 0)
|
||||
return B_BUSY;
|
||||
|
||||
acquire_sem(gDeviceOpenSemaphore);
|
||||
|
||||
status = ps2_common_initialize();
|
||||
if (status != B_OK)
|
||||
goto err1;
|
||||
|
||||
sKeyboardSem = create_sem(0, "keyboard_sem");
|
||||
if (sKeyboardSem < 0) {
|
||||
atomic_and(&sKeyboardOpenMask, 0);
|
||||
return sKeyboardSem;
|
||||
status = sKeyboardSem;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
sKeyBuffer = create_packet_buffer(KEY_BUFFER_SIZE * sizeof(at_kbd_io));
|
||||
if (sKeyBuffer == NULL) {
|
||||
panic("could not create keyboard packet buffer!\n");
|
||||
atomic_and(&sKeyboardOpenMask, 0);
|
||||
return B_NO_MEMORY;
|
||||
status = B_NO_MEMORY;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
keyboard_empty_data();
|
||||
|
||||
commandByte = ps2_get_command_byte()
|
||||
| PS2_BITS_KEYBOARD_INTERRUPT | PS2_BITS_TRANSLATE_SCANCODES;
|
||||
commandByte &= ~PS2_BITS_KEYBOARD_DISABLED;
|
||||
|
||||
status = ps2_set_command_byte(commandByte);
|
||||
if (status < B_OK) {
|
||||
TRACE(("keyboard_open(): cannot set command byte\n"));
|
||||
goto err4;
|
||||
}
|
||||
|
||||
status = install_io_interrupt_handler(INT_PS2_KEYBOARD,
|
||||
&handle_keyboard_interrupt, NULL, 0);
|
||||
if (status < B_OK)
|
||||
goto err4;
|
||||
|
||||
sInterruptHandlerInstalled = true;
|
||||
release_sem(gDeviceOpenSemaphore);
|
||||
|
||||
*_cookie = NULL;
|
||||
|
||||
return install_io_interrupt_handler(INT_PS2_KEYBOARD, &handle_keyboard_interrupt, NULL, 0);
|
||||
TRACE(("keyboard_open(): done.\n"));
|
||||
return B_OK;
|
||||
|
||||
err4:
|
||||
delete_packet_buffer(sKeyBuffer);
|
||||
err3:
|
||||
delete_sem(sKeyboardSem);
|
||||
err2:
|
||||
ps2_common_uninitialize();
|
||||
err1:
|
||||
atomic_and(&sKeyboardOpenMask, 0);
|
||||
release_sem(gDeviceOpenSemaphore);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
status_t
|
||||
keyboard_close(void *cookie)
|
||||
{
|
||||
TRACE(("keyboard_close()\n"));
|
||||
|
||||
remove_io_interrupt_handler(INT_PS2_KEYBOARD, &handle_keyboard_interrupt, NULL);
|
||||
sInterruptHandlerInstalled = false;
|
||||
|
||||
delete_packet_buffer(sKeyBuffer);
|
||||
delete_sem(sKeyboardSem);
|
||||
|
||||
ps2_common_uninitialize();
|
||||
atomic_and(&sKeyboardOpenMask, 0);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
status_t
|
||||
keyboard_freecookie(void *cookie)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
status_t
|
||||
keyboard_read(void *cookie, off_t pos, void *buffer, size_t *_length)
|
||||
{
|
||||
TRACE(("keyboard read()\n"));
|
||||
@ -185,7 +389,7 @@ keyboard_read(void *cookie, off_t pos, void *buffer, size_t *_length)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
status_t
|
||||
keyboard_write(void *cookie, off_t pos, const void *buffer, size_t *_length)
|
||||
{
|
||||
TRACE(("keyboard write()\n"));
|
||||
@ -194,7 +398,7 @@ keyboard_write(void *cookie, off_t pos, const void *buffer, size_t *_length)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
status_t
|
||||
keyboard_ioctl(void *cookie, uint32 op, void *buffer, size_t length)
|
||||
{
|
||||
TRACE(("keyboard ioctl()\n"));
|
||||
@ -210,17 +414,16 @@ keyboard_ioctl(void *cookie, uint32 op, void *buffer, size_t length)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
TRACE(("KB_SET_LEDS\n"));
|
||||
set_leds(&info);
|
||||
return B_OK;
|
||||
return set_leds(&info);
|
||||
}
|
||||
|
||||
case KB_SET_KEY_REPEATING:
|
||||
case KB_SET_KEY_NONREPEATING:
|
||||
TRACE(("ioctl 0x%x not implemented yet, returning B_OK\n", op));
|
||||
TRACE(("ps2_hid: ioctl 0x%lx not implemented yet, returning B_OK\n", op));
|
||||
return B_OK;
|
||||
|
||||
default:
|
||||
TRACE(("invalid ioctl 0x%x\n", op));
|
||||
TRACE(("ps2_hid: invalid ioctl 0x%lx\n", op));
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
@ -82,8 +82,24 @@ static int sButtonsState;
|
||||
static int32 sPacketSize;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// mouse functions
|
||||
/** Writes a byte to the mouse device. Uses the control port to indicate
|
||||
* that the byte is sent to the auxiliary device (mouse), instead of the
|
||||
* keyboard.
|
||||
*/
|
||||
|
||||
status_t
|
||||
ps2_write_aux_byte(uint8 data)
|
||||
{
|
||||
TRACE(("ps2_write_aux_byte(data = %u)\n", data));
|
||||
|
||||
if (ps2_write_ctrl(PS2_CTRL_WRITE_AUX) == B_OK
|
||||
&& ps2_write_data(data) == B_OK
|
||||
&& ps2_read_data(&data) == B_OK)
|
||||
return data == PS2_REPLY_ACK ? B_OK : B_TIMED_OUT;
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
static status_t
|
||||
@ -102,46 +118,24 @@ ps2_reset_mouse()
|
||||
*/
|
||||
|
||||
|
||||
/** Enables or disables mouse reporting for the ps2 port.
|
||||
*/
|
||||
|
||||
static status_t
|
||||
ps2_enable_mouse(bool enable)
|
||||
{
|
||||
int32 tries = 2;
|
||||
uint8 read;
|
||||
|
||||
do {
|
||||
write_aux_byte(enable ? PS2_CMD_ENABLE_MOUSE : PS2_CMD_DISABLE_MOUSE);
|
||||
read = read_data_byte();
|
||||
if (read == PS2_RES_ACK)
|
||||
break;
|
||||
spin(100);
|
||||
} while (read == PS2_RES_RESEND && tries-- > 0);
|
||||
|
||||
if (read != PS2_RES_ACK)
|
||||
return B_ERROR;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/** Set sampling rate of the ps2 port.
|
||||
*/
|
||||
|
||||
static status_t
|
||||
ps2_set_sample_rate(uint32 rate)
|
||||
{
|
||||
status_t status = B_ERROR;
|
||||
int32 tries = 5;
|
||||
|
||||
write_aux_byte(PS2_CMD_SET_SAMPLE_RATE);
|
||||
if (read_data_byte() == PS2_RES_ACK) {
|
||||
write_aux_byte(rate);
|
||||
if (read_data_byte() == PS2_RES_ACK)
|
||||
status = B_OK;
|
||||
while (--tries > 0) {
|
||||
status_t status = ps2_write_aux_byte(PS2_CMD_SET_SAMPLE_RATE);
|
||||
if (status == B_OK)
|
||||
status = ps2_write_aux_byte(rate);
|
||||
|
||||
if (status == B_OK)
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
return status;
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
@ -187,7 +181,7 @@ ps2_packet_to_movement(uint8 packet[], mouse_movement *pos)
|
||||
pos->wheel_ydelta = (int)wheel_ydelta;
|
||||
pos->wheel_xdelta = (int)wheel_xdelta;
|
||||
|
||||
TRACE(("xdelta: %d, ydelta: %d, buttons %x, clicks: %d, timestamp %Ld\n",
|
||||
TRACE(("xdelta: %d, ydelta: %d, buttons %x, clicks: %ld, timestamp %Ld\n",
|
||||
xDelta, yDelta, buttons, sClickCount, currentTime));
|
||||
}
|
||||
}
|
||||
@ -219,8 +213,25 @@ ps2_mouse_read(mouse_movement *userMovement)
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// interrupt
|
||||
/** Enables or disables mouse reporting for the PS/2 port.
|
||||
*/
|
||||
|
||||
static status_t
|
||||
set_mouse_enabled(bool enable)
|
||||
{
|
||||
int32 tries = 5;
|
||||
|
||||
while (true) {
|
||||
if (ps2_write_aux_byte(enable ?
|
||||
PS2_CMD_ENABLE_MOUSE : PS2_CMD_DISABLE_MOUSE) == B_OK)
|
||||
return B_OK;
|
||||
|
||||
if (--tries <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/** Interrupt handler for the mouse device. Called whenever the I/O
|
||||
@ -239,7 +250,8 @@ handle_mouse_interrupt(void* data)
|
||||
return B_UNHANDLED_INTERRUPT;
|
||||
}
|
||||
|
||||
read = read_data_byte();
|
||||
read = gIsa->read_io_8(PS2_PORT_DATA);
|
||||
|
||||
TRACE(("mouse interrupt : byte %x\n", read));
|
||||
while (packet_buffer_write(sMouseBuffer, &read, sizeof(read)) == 0) {
|
||||
// we start dropping packets when the buffer is full
|
||||
@ -263,6 +275,52 @@ handle_mouse_interrupt(void* data)
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
status_t
|
||||
probe_mouse(void)
|
||||
{
|
||||
int8 deviceId = -1;
|
||||
|
||||
// get device id
|
||||
if (ps2_write_aux_byte(PS2_CMD_GET_DEVICE_ID) == B_OK)
|
||||
ps2_read_data(&deviceId);
|
||||
|
||||
TRACE(("probe_mouse(): device id: %2x\n", deviceId));
|
||||
|
||||
if (deviceId == 0) {
|
||||
int32 tries = 5;
|
||||
|
||||
while (--tries > 0) {
|
||||
// try to switch to intellimouse mode
|
||||
if (ps2_set_sample_rate(200) == B_OK
|
||||
&& ps2_set_sample_rate(100) == B_OK
|
||||
&& ps2_set_sample_rate(80) == B_OK) {
|
||||
// get device id, again
|
||||
if (ps2_write_aux_byte(PS2_CMD_GET_DEVICE_ID) == B_OK)
|
||||
ps2_read_data(&deviceId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (deviceId == PS2_DEV_ID_STANDARD) {
|
||||
sPacketSize = PS2_PACKET_STANDARD;
|
||||
TRACE(("Standard PS/2 mouse found\n"));
|
||||
} else if (deviceId == PS2_DEV_ID_INTELLIMOUSE) {
|
||||
sPacketSize = PS2_PACKET_INTELLIMOUSE;
|
||||
TRACE(("Extended PS/2 mouse found\n"));
|
||||
} else {
|
||||
// Something's wrong. Better quit
|
||||
dprintf("ps2_hid: No mouse found\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// Device functions
|
||||
|
||||
@ -272,48 +330,27 @@ mouse_open(const char *name, uint32 flags, void **_cookie)
|
||||
{
|
||||
status_t status;
|
||||
int8 commandByte;
|
||||
int8 deviceId = -1;
|
||||
|
||||
TRACE(("mouse_open()\n"));
|
||||
|
||||
if (atomic_or(&sOpenMask, 1) != 0)
|
||||
return B_BUSY;
|
||||
|
||||
// get device id
|
||||
write_aux_byte(PS2_CMD_GET_DEVICE_ID);
|
||||
if (read_data_byte() == PS2_RES_ACK)
|
||||
deviceId = read_data_byte();
|
||||
acquire_sem(gDeviceOpenSemaphore);
|
||||
|
||||
TRACE(("init_driver: device id: %2x\n", deviceId));
|
||||
if (deviceId == 0) {
|
||||
// try to switch to intellimouse mode
|
||||
ps2_set_sample_rate(200);
|
||||
ps2_set_sample_rate(100);
|
||||
ps2_set_sample_rate(80);
|
||||
}
|
||||
status = probe_mouse();
|
||||
if (status != B_OK)
|
||||
goto err1;
|
||||
|
||||
// get device id, again
|
||||
write_aux_byte(PS2_CMD_GET_DEVICE_ID);
|
||||
if (read_data_byte() == PS2_RES_ACK)
|
||||
deviceId = read_data_byte();
|
||||
|
||||
if (deviceId == PS2_DEV_ID_STANDARD) {
|
||||
sPacketSize = PS2_PACKET_STANDARD;
|
||||
TRACE(("Standard ps2 mouse found\n"));
|
||||
} else if (deviceId == PS2_DEV_ID_INTELLIMOUSE) {
|
||||
sPacketSize = PS2_PACKET_INTELLIMOUSE;
|
||||
TRACE(("Extended ps2 mouse found\n"));
|
||||
} else {
|
||||
TRACE(("No mouse found\n"));
|
||||
put_module(B_ISA_MODULE_NAME);
|
||||
return B_ERROR; // Something's wrong. Better quit
|
||||
}
|
||||
status = ps2_common_initialize();
|
||||
if (status != B_OK)
|
||||
goto err1;
|
||||
|
||||
sMouseBuffer = create_packet_buffer(MOUSE_HISTORY_SIZE * sPacketSize);
|
||||
if (sMouseBuffer == NULL) {
|
||||
TRACE(("can't allocate mouse actions buffer\n"));
|
||||
put_module(B_ISA_MODULE_NAME);
|
||||
return B_ERROR;
|
||||
status = B_NO_MEMORY;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
// create the mouse semaphore, used for synchronization between
|
||||
@ -321,30 +358,50 @@ mouse_open(const char *name, uint32 flags, void **_cookie)
|
||||
sMouseSem = create_sem(0, "ps2_mouse_sem");
|
||||
if (sMouseSem < 0) {
|
||||
TRACE(("failed creating PS/2 mouse semaphore!\n"));
|
||||
delete_packet_buffer(sMouseBuffer);
|
||||
put_module(B_ISA_MODULE_NAME);
|
||||
return sMouseSem;
|
||||
status = sMouseSem;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
set_sem_owner(sMouseSem, B_SYSTEM_TEAM);
|
||||
|
||||
*_cookie = NULL;
|
||||
|
||||
commandByte = get_command_byte();
|
||||
commandByte |= PS2_BITS_AUX_INTERRUPT;
|
||||
commandByte = ps2_get_command_byte() | PS2_BITS_AUX_INTERRUPT;
|
||||
commandByte &= ~PS2_BITS_MOUSE_DISABLED;
|
||||
set_command_byte(commandByte);
|
||||
|
||||
status = ps2_enable_mouse(true);
|
||||
status = ps2_set_command_byte(commandByte);
|
||||
if (status < B_OK) {
|
||||
TRACE(("mouse_open(): cannot enable PS/2 mouse\n"));
|
||||
return B_ERROR;
|
||||
TRACE(("mouse_open(): sending command byte failed\n"));
|
||||
goto err4;
|
||||
}
|
||||
|
||||
TRACE(("mouse_open(): mouse succesfully enabled\n"));
|
||||
status = set_mouse_enabled(true);
|
||||
if (status < B_OK) {
|
||||
TRACE(("mouse_open(): cannot enable PS/2 mouse\n"));
|
||||
goto err4;
|
||||
}
|
||||
|
||||
// register interrupt handler
|
||||
return install_io_interrupt_handler(INT_PS2_MOUSE, handle_mouse_interrupt, NULL, 0);
|
||||
status = install_io_interrupt_handler(INT_PS2_MOUSE,
|
||||
handle_mouse_interrupt, NULL, 0);
|
||||
if (status < B_OK) {
|
||||
TRACE(("mouse_open(): cannot install interrupt handler\n"));
|
||||
goto err4;
|
||||
}
|
||||
|
||||
release_sem(gDeviceOpenSemaphore);
|
||||
|
||||
TRACE(("mouse_open(): mouse succesfully enabled\n"));
|
||||
return B_OK;
|
||||
|
||||
err4:
|
||||
delete_sem(sMouseSem);
|
||||
err3:
|
||||
delete_packet_buffer(sMouseBuffer);
|
||||
err2:
|
||||
ps2_common_uninitialize();
|
||||
err1:
|
||||
atomic_and(&sOpenMask, 0);
|
||||
release_sem(gDeviceOpenSemaphore);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@ -352,13 +409,15 @@ status_t
|
||||
mouse_close(void *cookie)
|
||||
{
|
||||
TRACE(("mouse_close()\n"));
|
||||
ps2_enable_mouse(false);
|
||||
|
||||
set_mouse_enabled(false);
|
||||
|
||||
delete_packet_buffer(sMouseBuffer);
|
||||
delete_sem(sMouseSem);
|
||||
|
||||
remove_io_interrupt_handler(INT_PS2_MOUSE, handle_mouse_interrupt, NULL);
|
||||
|
||||
ps2_common_uninitialize();
|
||||
atomic_and(&sOpenMask, 0);
|
||||
|
||||
return B_OK;
|
||||
|
Loading…
Reference in New Issue
Block a user