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:
parent
40c53b443d
commit
b78920b3f1
@ -5,6 +5,7 @@ UsePrivateKernelHeaders ;
|
||||
|
||||
KernelAddon ps2 :
|
||||
packet_buffer.cpp
|
||||
ps2_alps.c
|
||||
ps2_common.c
|
||||
ps2_dev.c
|
||||
ps2_keyboard.cpp
|
||||
|
836
src/add-ons/kernel/bus_managers/ps2/ps2_alps.c
Normal file
836
src/add-ons/kernel/bus_managers/ps2/ps2_alps.c
Normal 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,
|
||||
};
|
||||
|
56
src/add-ons/kernel/bus_managers/ps2/ps2_alps.h
Normal file
56
src/add-ons/kernel/bus_managers/ps2/ps2_alps.h
Normal 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 */
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include <keyboard_mouse_driver.h>
|
||||
#include <touchpad_settings.h>
|
||||
|
||||
#include "movement_maker.h"
|
||||
|
Loading…
Reference in New Issue
Block a user