Work in progress on a ALPS touchpad driver. The driver is roughly working but disabled at the moment. Its

more or less a copy of the synaptics driver. Next step is to refactor the movement generation and share the 
code with the synaptics driver.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@41124 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Clemens Zeidler 2011-03-27 08:53:57 +00:00
parent 40c53b443d
commit b78920b3f1
6 changed files with 901 additions and 1 deletions

View File

@ -5,6 +5,7 @@ UsePrivateKernelHeaders ;
KernelAddon ps2 :
packet_buffer.cpp
ps2_alps.c
ps2_common.c
ps2_dev.c
ps2_keyboard.cpp

View File

@ -0,0 +1,836 @@
/*
* Copyright 2011, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* The alps_model_info struct and all the hardware specs are taken from the
* linux driver, thanks a lot!
*
* Authors:
* Clemens Zeidler (haiku@Clemens-Zeidler.de)
*/
#include "ps2_alps.h"
#include <stdlib.h>
#include <string.h>
#include <keyboard_mouse_driver.h>
#include "ps2_service.h"
const char* kALPSPath[4] = {
"input/touchpad/ps2/alps_0",
"input/touchpad/ps2/alps_1",
"input/touchpad/ps2/alps_2",
"input/touchpad/ps2/alps_3"
};
enum button_ids
{
kLeftButton = 0x01,
kRightButton = 0x02
};
typedef struct alps_model_info {
uint8 id[3];
uint8 firstByte;
uint8 maskFirstByte;
uint8 flags;
} alps_model_info;
#define ALPS_OLDPROTO 0x01 // old style input
#define ALPS_DUALPOINT 0x02 // touchpad has trackstick
#define ALPS_PASS 0x04 // device has a pass-through port
#define ALPS_WHEEL 0x08 // hardware wheel present
#define ALPS_FW_BK_1 0x10 // front & back buttons present
#define ALPS_FW_BK_2 0x20 // front & back buttons present
#define ALPS_FOUR_BUTTONS 0x40 // 4 direction button present
#define ALPS_PS2_INTERLEAVED 0x80 // 3-byte PS/2 packet interleaved with
// 6-byte ALPS packet
static const struct alps_model_info gALPSModelInfos[] = {
// {{0x32, 0x02, 0x14}, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT},
// Toshiba Salellite Pro M10
// {{0x33, 0x02, 0x0a}, 0x88, 0xf8, ALPS_OLDPROTO},
// UMAX-530T
{{0x53, 0x02, 0x0a}, 0xf8, 0xf8, 0},
{{0x53, 0x02, 0x14}, 0xf8, 0xf8, 0},
{{0x60, 0x03, 0xc8}, 0xf8, 0xf8, 0},
// HP ze1115
{{0x63, 0x02, 0x0a}, 0xf8, 0xf8, 0},
{{0x63, 0x02, 0x14}, 0xf8, 0xf8, 0},
// {{0x63, 0x02, 0x28}, 0xf8, 0xf8, ALPS_FW_BK_2},
// Fujitsu Siemens S6010
// {{0x63, 0x02, 0x3c}, 0x8f, 0x8f, ALPS_WHEEL},
// Toshiba Satellite S2400-103
// {{0x63, 0x02, 0x50}, 0xef, 0xef, ALPS_FW_BK_1},
// NEC Versa L320
{{0x63, 0x02, 0x64}, 0xf8, 0xf8, 0},
// {{0x63, 0x03, 0xc8}, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT},
// Dell Latitude D800
{{0x73, 0x00, 0x0a}, 0xf8, 0xf8, ALPS_DUALPOINT},
// ThinkPad R61 8918-5QG, x301
{{0x73, 0x02, 0x0a}, 0xf8, 0xf8, 0},
// {{0x73, 0x02, 0x14}, 0xf8, 0xf8, ALPS_FW_BK_2},
// Ahtec Laptop
// {{0x20, 0x02, 0x0e}, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT},
// XXX
// {{0x22, 0x02, 0x0a}, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT},
// {{0x22, 0x02, 0x14}, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT},
// Dell Latitude D600
// {{0x62, 0x02, 0x14}, 0xcf, 0xcf, ALPS_PASS | ALPS_DUALPOINT
// | ALPS_PS2_INTERLEAVED},
// Dell Latitude E5500, E6400, E6500, Precision M4400
// {{0x73, 0x02, 0x50}, 0xcf, 0xcf, ALPS_FOUR_BUTTONS},
// Dell Vostro 1400
// {{0x52, 0x01, 0x14}, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT
// | ALPS_PS2_INTERLEAVED},
// Toshiba Tecra A11-11L
{{0, 0, 0}, 0, 0, 0}
};
static alps_model_info* sFoundModel = NULL;
#define PS2_MOUSE_CMD_SET_SCALE11 0xe6
#define PS2_MOUSE_CMD_SET_SCALE21 0xe7
#define PS2_MOUSE_CMD_SET_RES 0xe8
#define PS2_MOUSE_CMD_GET_INFO 0xe9
#define PS2_MOUSE_CMD_SET_STREAM 0xea
#define PS2_MOUSE_CMD_SET_POLL 0xf0
#define PS2_MOUSE_CMD_SET_RATE 0xf3
// touchpad proportions
#define SPEED_FACTOR 4.5
#define EDGE_MOTION_WIDTH 10
#define EDGE_MOTION_SPEED (5 * SPEED_FACTOR)
// increase the touchpad size a little bit
#define AREA_START_X 50
#define AREA_END_X 985
#define AREA_WIDTH_X (AREA_END_X - AREA_START_X)
#define AREA_START_Y 45
#define AREA_END_Y 735
#define AREA_WIDTH_Y (AREA_END_Y - AREA_START_Y)
#define TAP_TIMEOUT 200000
#define MIN_PRESSURE 15
#define MAX_PRESSURE 115
#define ALPS_HISTORY_SIZE 256
typedef struct {
uint8 buttons;
uint32 xPosition;
uint32 yPosition;
uint8 zPressure;
// absolut mode
bool finger;
// absolut w mode
uint8 wValue;
} touch_event;
static bool
edge_motion(mouse_movement *movement, touch_event *event, bool validStart)
{
int32 xdelta = 0;
int32 ydelta = 0;
if (event->xPosition < AREA_START_X + EDGE_MOTION_WIDTH)
xdelta = -EDGE_MOTION_SPEED;
else if (event->xPosition > AREA_END_X - EDGE_MOTION_WIDTH)
xdelta = EDGE_MOTION_SPEED;
if (event->yPosition < AREA_START_Y + EDGE_MOTION_WIDTH)
ydelta = -EDGE_MOTION_SPEED;
else if (event->yPosition > AREA_END_Y - EDGE_MOTION_WIDTH)
ydelta = EDGE_MOTION_SPEED;
if (xdelta && validStart)
movement->xdelta = xdelta;
if (ydelta && validStart)
movement->ydelta = ydelta;
if ((xdelta || ydelta) && !validStart)
return false;
return true;
}
/*! If a button has been clicked (movement->buttons must be set accordingly),
this function updates the click_count of the \a cookie, as well as the
\a movement's clicks field.
Also, it sets the cookie's button state from movement->buttons.
*/
static inline void
update_buttons(alps_cookie *cookie, mouse_movement *movement)
{
// set click count correctly according to double click timeout
if (movement->buttons != 0 && cookie->buttons_state == 0) {
if (cookie->click_last_time + cookie->click_speed > movement->timestamp)
cookie->click_count++;
else
cookie->click_count = 1;
cookie->click_last_time = movement->timestamp;
}
if (movement->buttons != 0)
movement->clicks = cookie->click_count;
cookie->buttons_state = movement->buttons;
}
static inline void
no_touch_to_movement(alps_cookie *cookie, touch_event *event,
mouse_movement *movement)
{
uint32 buttons = event->buttons;
TRACE("ALPS: no touch event\n");
cookie->scrolling_started = false;
cookie->movement_started = false;
if (cookie->tapdrag_started
&& (movement->timestamp - cookie->tap_time) < TAP_TIMEOUT) {
buttons = 0x01;
}
// if the movement stopped switch off the tap drag when timeout is expired
if ((movement->timestamp - cookie->tap_time) > TAP_TIMEOUT) {
cookie->tapdrag_started = false;
cookie->valid_edge_motion = false;
TRACE("ALPS: tap drag gesture timed out\n");
}
if (abs(cookie->tap_delta_x) > 15 || abs(cookie->tap_delta_y) > 15) {
cookie->tap_started = false;
cookie->tap_clicks = 0;
}
if (cookie->tap_started || cookie->double_click) {
TRACE("ALPS: tap gesture\n");
cookie->tap_clicks++;
if (cookie->tap_clicks > 1) {
TRACE("ALPS: empty click\n");
buttons = 0x00;
cookie->tap_clicks = 0;
cookie->double_click = true;
} else {
buttons = 0x01;
cookie->tap_started = false;
cookie->tapdrag_started = true;
cookie->double_click = false;
}
}
movement->buttons = buttons;
update_buttons(cookie, movement);
}
static inline void
move_to_movement(alps_cookie *cookie, touch_event *event,
mouse_movement *movement)
{
touchpad_settings *settings = &cookie->settings;
bool isStartOfMovement = false;
float pressure = 0;
TRACE("ALPS: movement event\n");
if (!cookie->movement_started) {
isStartOfMovement = true;
cookie->movement_started = true;
start_new_movment(&cookie->movement_maker);
}
get_movement(&cookie->movement_maker, event->xPosition, event->yPosition);
movement->xdelta = cookie->movement_maker.xDelta;
movement->ydelta = cookie->movement_maker.yDelta;
// tap gesture
cookie->tap_delta_x += cookie->movement_maker.xDelta;
cookie->tap_delta_y += cookie->movement_maker.yDelta;
if (cookie->tapdrag_started) {
movement->buttons = kLeftButton;
movement->clicks = 0;
cookie->valid_edge_motion = edge_motion(movement, event,
cookie->valid_edge_motion);
TRACE("ALPS: tap drag\n");
} else {
TRACE("ALPS: movement set buttons\n");
movement->buttons = event->buttons;
}
// use only a fraction of pressure range, the max pressure seems to be
// to high
pressure = 20 * (event->zPressure - MIN_PRESSURE)
/ (MAX_PRESSURE - MIN_PRESSURE - 40);
if (!cookie->tap_started
&& isStartOfMovement
&& settings->tapgesture_sensibility > 0.
&& settings->tapgesture_sensibility > (20 - pressure)) {
TRACE("ALPS: tap started\n");
cookie->tap_started = true;
cookie->tap_time = system_time();
cookie->tap_delta_x = 0;
cookie->tap_delta_y = 0;
}
update_buttons(cookie, movement);
}
/*! Checks if this is a scrolling event or not, and also actually does the
scrolling work if it is.
\return \c true if this was a scrolling event, \c false if not.
*/
static inline bool
check_scrolling_to_movement(alps_cookie *cookie, touch_event *event,
mouse_movement *movement)
{
touchpad_settings *settings = &cookie->settings;
bool isSideScrollingV = false;
bool isSideScrollingH = false;
// if a button is pressed don't allow to scroll, we likely be in a drag
// action
if (cookie->buttons_state != 0)
return false;
if ((AREA_END_X - AREA_WIDTH_X * settings->scroll_rightrange
< event->xPosition && !cookie->movement_started
&& settings->scroll_rightrange > 0.000001)
|| settings->scroll_rightrange > 0.999999) {
isSideScrollingV = true;
}
if ((AREA_START_Y + AREA_WIDTH_Y * settings->scroll_bottomrange
> event->yPosition && !cookie->movement_started
&& settings->scroll_bottomrange > 0.000001)
|| settings->scroll_bottomrange > 0.999999) {
isSideScrollingH = true;
}
if ((event->wValue == 0 || event->wValue == 1)
&& settings->scroll_twofinger) {
// two finger scrolling is enabled
isSideScrollingV = true;
isSideScrollingH = settings->scroll_twofinger_horizontal;
}
if (!isSideScrollingV && !isSideScrollingH) {
cookie->scrolling_started = false;
return false;
}
TRACE("ALPS: scroll event\n");
cookie->tap_started = false;
cookie->tap_clicks = 0;
cookie->tapdrag_started = false;
cookie->valid_edge_motion = false;
if (!cookie->scrolling_started) {
cookie->scrolling_started = true;
start_new_movment(&cookie->movement_maker);
}
get_scrolling(&cookie->movement_maker, event->xPosition,
event->yPosition);
movement->wheel_ydelta = cookie->movement_maker.yDelta;
movement->wheel_xdelta = cookie->movement_maker.xDelta;
if (isSideScrollingV && !isSideScrollingH)
movement->wheel_xdelta = 0;
else if (isSideScrollingH && !isSideScrollingV)
movement->wheel_ydelta = 0;
cookie->buttons_state = movement->buttons;
return true;
}
static status_t
event_to_movement(alps_cookie *cookie, touch_event *event,
mouse_movement *movement)
{
if (!movement)
return B_ERROR;
movement->xdelta = 0;
movement->ydelta = 0;
movement->buttons = 0;
movement->wheel_ydelta = 0;
movement->wheel_xdelta = 0;
movement->modifiers = 0;
movement->clicks = 0;
movement->timestamp = system_time();
if ((movement->timestamp - cookie->tap_time) > TAP_TIMEOUT) {
TRACE("ALPS: tap gesture timed out\n");
cookie->tap_started = false;
if (!cookie->double_click
|| (movement->timestamp - cookie->tap_time) > 2 * TAP_TIMEOUT) {
cookie->tap_clicks = 0;
}
}
if (event->buttons & kLeftButton) {
cookie->tap_clicks = 0;
cookie->tapdrag_started = false;
cookie->tap_started = false;
cookie->valid_edge_motion = false;
}
if (event->zPressure >= MIN_PRESSURE && event->zPressure < MAX_PRESSURE
&& ((event->wValue >=4 && event->wValue <=7)
|| event->wValue == 0 || event->wValue == 1)
&& (event->xPosition != 0 || event->yPosition != 0)) {
// The touch pad is in touch with at least one finger
if (!check_scrolling_to_movement(cookie, event, movement))
move_to_movement(cookie, event, movement);
} else
no_touch_to_movement(cookie, event, movement);
return B_OK;
}
/* Data taken from linux driver:
ALPS absolute Mode - new format
byte 0: 1 ? ? ? 1 ? ? ?
byte 1: 0 x6 x5 x4 x3 x2 x1 x0
byte 2: 0 x10 x9 x8 x7 ? fin ges
byte 3: 0 y9 y8 y7 1 M R L
byte 4: 0 y6 y5 y4 y3 y2 y1 y0
byte 5: 0 z6 z5 z4 z3 z2 z1 z0
*/
// debug
static int minX = 50000;
static int minY = 50000;
static int maxX = 0;
static int maxY = 0;
static int maxZ = 0;
// debug end
static status_t
get_alps_movment(alps_cookie *cookie, mouse_movement *movement)
{
status_t status;
touch_event event;
uint8 event_buffer[PS2_PACKET_ALPS];
status = acquire_sem_etc(cookie->sem, 1, B_CAN_INTERRUPT, 0);
if (status < B_OK)
return status;
if (!cookie->dev->active) {
TRACE("ALPS: read_event: Error device no longer active\n");
return B_ERROR;
}
if (packet_buffer_read(cookie->ring_buffer, event_buffer,
cookie->dev->packet_size) != cookie->dev->packet_size) {
TRACE("ALPS: error copying buffer\n");
return B_ERROR;
}
event.buttons = event_buffer[3] & 3;
event.zPressure = event_buffer[5];
// finger on touchpad
if (event_buffer[2] & 0x2) {
// finger with normal width
event.wValue = 4;
} else {
event.wValue = 3;
}
// tabgesture
if (event_buffer[2] & 0x1) {
event.zPressure = 80;
event.wValue = 4;
}
event.xPosition = event_buffer[1] | ((event_buffer[2] & 0x78) << 4);
event.yPosition = event_buffer[4] | ((event_buffer[3] & 0x70) << 3);
// debug
if (event.xPosition < minX)
minX = event.xPosition;
if (event.yPosition < minY)
minY = event.yPosition;
if (event.xPosition > maxX)
maxX = event.xPosition;
if (event.yPosition > maxY)
maxY = event.yPosition;
if (event.zPressure > maxZ)
maxZ = event.zPressure;
dprintf("x %i %i, y %i %i, z %i %i, fin %i ges %i\n", minX, maxX, minY, maxY,
maxZ, event.zPressure, event_buffer[2] & 0x2, event_buffer[2] & 0x1);
// debug end
event.yPosition = AREA_END_Y - event.yPosition;
status = event_to_movement(cookie, &event, movement);
// check for trackpoint even (z pressure 127)
if (sFoundModel->flags & ALPS_DUALPOINT && event.zPressure == 127) {
movement->xdelta = event.xPosition > 383 ? event.xPosition - 768
: event.xPosition;
event.yPosition = AREA_END_Y - event.yPosition;
movement->ydelta = event.yPosition > 255
? event.yPosition - 512 : event.yPosition;
event.yPosition = AREA_END_Y - event.yPosition;
movement->wheel_xdelta = 0;
movement->wheel_ydelta = 0;
}
return status;
}
static void
default_settings(touchpad_settings *set)
{
memcpy(set, &kDefaultTouchpadSettings, sizeof(touchpad_settings));
}
status_t
probe_alps(ps2_dev* dev)
{
int i;
uint8 val[3];
TRACE("ALPS: probe\n");
return B_ERROR;
val[0] = 0;
if (ps2_dev_command(dev, PS2_MOUSE_CMD_SET_RES, val, 1, NULL, 0) != B_OK
|| ps2_dev_command(dev, PS2_MOUSE_CMD_SET_SCALE11, NULL, 0, NULL, 0)
!= B_OK
|| ps2_dev_command(dev, PS2_MOUSE_CMD_SET_SCALE11, NULL, 0, NULL, 0)
!= B_OK
|| ps2_dev_command(dev, PS2_MOUSE_CMD_SET_SCALE11, NULL, 0, NULL, 0)
!= B_OK)
return B_ERROR;
if (ps2_dev_command(dev, PS2_MOUSE_CMD_GET_INFO, NULL, 0, val, 3)
!= B_OK)
return B_ERROR;
if (val[0] != 0 || val[1] != 0 || (val[2] != 10 && val[2] != 100))
return B_ERROR;
val[0] = 0;
if (ps2_dev_command(dev, PS2_MOUSE_CMD_SET_RES, val, 1, NULL, 0) != B_OK
|| ps2_dev_command(dev, PS2_MOUSE_CMD_SET_SCALE21, NULL, 0, NULL, 0)
!= B_OK
|| ps2_dev_command(dev, PS2_MOUSE_CMD_SET_SCALE21, NULL, 0, NULL, 0)
!= B_OK
|| ps2_dev_command(dev, PS2_MOUSE_CMD_SET_SCALE21, NULL, 0, NULL, 0)
!= B_OK)
return B_ERROR;
if (ps2_dev_command(dev, PS2_MOUSE_CMD_GET_INFO, NULL, 0, val, 3)
!= B_OK)
return B_ERROR;
for (i = 0; ; i++) {
const alps_model_info* info = &gALPSModelInfos[i];
if (info->id[0] == 0) {
INFO("ALPS not supported: %2.2x %2.2x %2.2x\n", val[0], val[1],
val[2]);
return B_ERROR;
}
if (info->id[0] == val[0] && info->id[1] == val[1]
&& info->id[2] == val[2]) {
sFoundModel = (alps_model_info*)info;
INFO("ALPS found: %2.2x %2.2x %2.2x\n", val[0], val[1], val[2]);
break;
}
}
dev->name = kALPSPath[dev->idx];
dev->packet_size = -1;
return B_OK;
}
status_t
alps_open(const char *name, uint32 flags, void **_cookie)
{
alps_cookie *cookie;
ps2_dev *dev;
int i;
uint8 val[3];
uint8 arg;
for (dev = NULL, i = 0; i < PS2_DEVICE_COUNT; i++) {
if (0 == strcmp(ps2_device[i].name, name)) {
dev = &ps2_device[i];
break;
}
}
if (dev == NULL) {
TRACE("ps2: dev = NULL\n");
return B_ERROR;
}
if (atomic_or(&dev->flags, PS2_FLAG_OPEN) & PS2_FLAG_OPEN)
return B_BUSY;
cookie = (alps_cookie*)malloc(sizeof(alps_cookie));
if (cookie == NULL)
goto err1;
*_cookie = cookie;
memset(cookie, 0, sizeof(alps_cookie));
cookie->dev = dev;
dev->cookie = cookie;
dev->disconnect = &alps_disconnect;
dev->handle_int = &alps_handle_int;
default_settings(&cookie->settings);
cookie->movement_maker.speed = 1 * SPEED_FACTOR;
cookie->movement_maker.scrolling_xStep = cookie->settings.scroll_xstepsize;
cookie->movement_maker.scrolling_yStep = cookie->settings.scroll_ystepsize;
cookie->movement_maker.scroll_acceleration
= cookie->settings.scroll_acceleration;
cookie->movement_started = false;
cookie->scrolling_started = false;
cookie->tap_started = false;
cookie->double_click = false;
cookie->valid_edge_motion = false;
dev->packet_size = PS2_PACKET_ALPS;
cookie->ring_buffer
= create_packet_buffer(ALPS_HISTORY_SIZE * dev->packet_size);
if (cookie->ring_buffer == NULL) {
TRACE("ALPS: can't allocate mouse actions buffer\n");
goto err2;
}
// create the mouse semaphore, used for synchronization between
// the interrupt handler and the read operation
cookie->sem = create_sem(0, "ps2_alps_sem");
if (cookie->sem < 0) {
TRACE("ALPS: failed creating semaphore!\n");
goto err3;
}
// switch tap mode off
arg = 0x00;
if (ps2_dev_command(dev, PS2_MOUSE_CMD_GET_INFO, NULL, 0, val, 3) != B_OK
|| ps2_dev_command(dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0) != B_OK
|| ps2_dev_command(dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0) != B_OK
|| ps2_dev_command(dev, PS2_MOUSE_CMD_SET_RES, &arg, 1, NULL, 0) != B_OK)
goto err4;
// init the alps device to absolut mode
if (ps2_dev_command(dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0) != B_OK
|| ps2_dev_command(dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0) != B_OK
|| ps2_dev_command(dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0) != B_OK
|| ps2_dev_command(dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0) != B_OK
|| ps2_dev_command(dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0) != B_OK)
goto err4;
if (ps2_dev_command(dev, PS2_MOUSE_CMD_SET_STREAM, NULL, 0, NULL, 0) != B_OK)
goto err4;
if (ps2_dev_command(dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0) != B_OK)
goto err4;
atomic_or(&dev->flags, PS2_FLAG_ENABLED);
TRACE("ALPS: open %s success\n", name);
return B_OK;
err4:
delete_sem(cookie->sem);
err3:
delete_packet_buffer(cookie->ring_buffer);
err2:
free(cookie);
err1:
atomic_and(&dev->flags, ~PS2_FLAG_OPEN);
TRACE("ALPS: open %s failed\n", name);
return B_ERROR;
}
status_t
alps_close(void *_cookie)
{
status_t status;
alps_cookie *cookie = _cookie;
ps2_dev_command_timeout(cookie->dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0,
150000);
delete_packet_buffer(cookie->ring_buffer);
delete_sem(cookie->sem);
atomic_and(&cookie->dev->flags, ~PS2_FLAG_OPEN);
atomic_and(&cookie->dev->flags, ~PS2_FLAG_ENABLED);
// Reset the touchpad so it generate standard ps2 packets instead of
// extended ones. If not, BeOS is confused with such packets when rebooting
// without a complete shutdown.
status = ps2_reset_mouse(cookie->dev);
if (status != B_OK) {
INFO("ps2: reset failed\n");
return B_ERROR;
}
TRACE("ALPS: close %s done\n", cookie->dev->name);
return B_OK;
}
status_t
alps_freecookie(void *_cookie)
{
free(_cookie);
return B_OK;
}
status_t
alps_ioctl(void *_cookie, uint32 op, void *buffer, size_t length)
{
alps_cookie *cookie = _cookie;
mouse_movement movement;
status_t status;
switch (op) {
case MS_READ:
TRACE("ALPS: MS_READ get event\n");
if ((status = get_alps_movment(cookie, &movement)) != B_OK)
return status;
return user_memcpy(buffer, &movement, sizeof(movement));
case MS_IS_TOUCHPAD:
TRACE("ALPS: MS_IS_TOUCHPAD\n");
return B_OK;
case MS_SET_TOUCHPAD_SETTINGS:
TRACE("ALPS: MS_SET_TOUCHPAD_SETTINGS");
user_memcpy(&cookie->settings, buffer, sizeof(touchpad_settings));
cookie->movement_maker.scrolling_xStep
= cookie->settings.scroll_xstepsize;
cookie->movement_maker.scrolling_yStep
= cookie->settings.scroll_ystepsize;
cookie->movement_maker.scroll_acceleration
= cookie->settings.scroll_acceleration;
return B_OK;
case MS_SET_CLICKSPEED:
TRACE("ALPS: ioctl MS_SETCLICK (set click speed)\n");
return user_memcpy(&cookie->click_speed, buffer, sizeof(bigtime_t));
default:
TRACE("ALPS: unknown opcode: %ld\n", op);
return B_BAD_VALUE;
}
}
static status_t
alps_read(void *cookie, off_t pos, void *buffer, size_t *_length)
{
*_length = 0;
return B_NOT_ALLOWED;
}
static status_t
alps_write(void *cookie, off_t pos, const void *buffer, size_t *_length)
{
*_length = 0;
return B_NOT_ALLOWED;
}
int32
alps_handle_int(ps2_dev *dev)
{
alps_cookie *cookie = dev->cookie;
uint8 val;
val = cookie->dev->history[0].data;
//dprintf("%i %i %i %i %i %i %i %i\n", (val >> 7) & 0x1, (val >> 6) & 0x1, (val >> 5) & 0x1, (val >> 4) & 0x1, (val >> 3) & 0x1,
// (val >> 2) & 0x1, (val >> 1) & 0x1, (val >> 0) & 0x1);
if (cookie->packet_index == 0
&& (val & sFoundModel->maskFirstByte) != sFoundModel->firstByte) {
INFO("ALPS: bad header, trying resync\n");
cookie->packet_index = 0;
return B_UNHANDLED_INTERRUPT;
}
// data packages starting with a 0
if (cookie->packet_index > 1 && (val & 0x80)) {
INFO("ALPS: bad package data, trying resync\n");
cookie->packet_index = 0;
return B_UNHANDLED_INTERRUPT;
}
cookie->packet_buffer[cookie->packet_index] = val;
cookie->packet_index++;
if (cookie->packet_index >= 6) {
cookie->packet_index = 0;
if (packet_buffer_write(cookie->ring_buffer,
cookie->packet_buffer, cookie->dev->packet_size)
!= cookie->dev->packet_size) {
// buffer is full, drop new data
return B_HANDLED_INTERRUPT;
}
release_sem_etc(cookie->sem, 1, B_DO_NOT_RESCHEDULE);
return B_INVOKE_SCHEDULER;
}
return B_HANDLED_INTERRUPT;
}
void
alps_disconnect(ps2_dev *dev)
{
alps_cookie *cookie = dev->cookie;
// the mouse device might not be opened at this point
INFO("ALPS: alps_disconnect %s\n", dev->name);
if ((dev->flags & PS2_FLAG_OPEN) != 0)
release_sem(cookie->sem);
}
device_hooks gALPSDeviceHooks = {
alps_open,
alps_close,
alps_freecookie,
alps_ioctl,
alps_read,
alps_write,
};

View File

@ -0,0 +1,56 @@
#ifndef ALPS_H
#define ALPS_H
#include <KernelExport.h>
#include <touchpad_settings.h>
#include "movement_maker.h"
#include "packet_buffer.h"
#include "ps2_dev.h"
typedef struct {
ps2_dev* dev;
sem_id sem;
packet_buffer* ring_buffer;
size_t packet_index;
uint8 packet_buffer[PS2_PACKET_ALPS];
uint8 mode;
movement_maker movement_maker;
bool movement_started;
bool scrolling_started;
bool tap_started;
bigtime_t tap_time;
int32 tap_delta_x;
int32 tap_delta_y;
int32 tap_clicks;
bool tapdrag_started;
bool valid_edge_motion;
bool double_click;
bigtime_t click_last_time;
bigtime_t click_speed;
int32 click_count;
uint32 buttons_state;
touchpad_settings settings;
} alps_cookie;
status_t probe_alps(ps2_dev *dev);
status_t alps_open(const char *name, uint32 flags, void **_cookie);
status_t alps_close(void *_cookie);
status_t alps_freecookie(void *_cookie);
status_t alps_ioctl(void *_cookie, uint32 op, void *buffer, size_t length);
int32 alps_handle_int(ps2_dev *dev);
void alps_disconnect(ps2_dev *dev);
device_hooks gALPSDeviceHooks;
#endif /* ALPS_H */

View File

@ -77,6 +77,7 @@
#define PS2_PACKET_STANDARD 3
#define PS2_PACKET_INTELLIMOUSE 4
#define PS2_PACKET_SYNAPTICS 6
#define PS2_PACKET_ALPS 6
#define PS2_MAX_PACKET_SIZE 6
// Should be equal to the biggest packet size

View File

@ -13,6 +13,7 @@
#include "ps2_dev.h"
#include "ps2_service.h"
#include "ps2_alps.h"
#include "ps2_standard_mouse.h"
#include "ps2_synaptics.h"
#include "ps2_trackpoint.h"
@ -115,6 +116,12 @@ ps2_dev_detect_pointing(ps2_dev *dev, device_hooks **hooks)
goto dev_found;
}
status = probe_alps(dev);
if (status == B_OK) {
*hooks = &gALPSDeviceHooks;
goto dev_found;
}
// reset the mouse for the case that the previous probes leaf the mouse in
// a undefined state
status = ps2_reset_mouse(dev);

View File

@ -11,7 +11,6 @@
#include <KernelExport.h>
#include <keyboard_mouse_driver.h>
#include <touchpad_settings.h>
#include "movement_maker.h"