Delete old c files.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@41130 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1,314 +0,0 @@
|
||||
#include "movement_maker.h"
|
||||
|
||||
#include <Debug.h>
|
||||
#if 1
|
||||
# define INFO(x...) dprintf(x)
|
||||
#else
|
||||
# define INFO(x...)
|
||||
#endif
|
||||
|
||||
typedef union {
|
||||
float value;
|
||||
/* FIXME: Assumes 32 bit int. */
|
||||
unsigned int word;
|
||||
} ieee_float_shape_type;
|
||||
|
||||
/* Get a 32 bit int from a float. */
|
||||
|
||||
#define GET_FLOAT_WORD(i,d) \
|
||||
do { \
|
||||
ieee_float_shape_type gf_u; \
|
||||
gf_u.value = (d); \
|
||||
(i) = gf_u.word; \
|
||||
} while (0)
|
||||
|
||||
/* Set a float from a 32 bit int. */
|
||||
|
||||
#define SET_FLOAT_WORD(d,i) \
|
||||
do { \
|
||||
ieee_float_shape_type sf_u; \
|
||||
sf_u.word = (i); \
|
||||
(d) = sf_u.value; \
|
||||
} while (0)
|
||||
|
||||
static const float huge = 1.0e30;
|
||||
|
||||
float
|
||||
floorf(float x)
|
||||
{
|
||||
int32 i0,j0;
|
||||
uint32 i;
|
||||
GET_FLOAT_WORD(i0,x);
|
||||
j0 = ((i0>>23)&0xff)-0x7f;
|
||||
if (j0<23) {
|
||||
if (j0<0) { /* raise inexact if x != 0 */
|
||||
if (huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */
|
||||
if (i0>=0) {i0=0;}
|
||||
else if ((i0&0x7fffffff)!=0)
|
||||
{ i0=0xbf800000;}
|
||||
}
|
||||
} else {
|
||||
i = (0x007fffff)>>j0;
|
||||
if ((i0&i)==0) return x; /* x is integral */
|
||||
if (huge+x>(float)0.0) { /* raise inexact flag */
|
||||
if (i0<0) i0 += (0x00800000)>>j0;
|
||||
i0 &= (~i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (j0==0x80) return x+x; /* inf or NaN */
|
||||
else return x; /* x is integral */
|
||||
}
|
||||
SET_FLOAT_WORD(x,i0);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
ceilf(float x)
|
||||
{
|
||||
int32 i0,j0;
|
||||
uint32 i;
|
||||
|
||||
GET_FLOAT_WORD(i0,x);
|
||||
j0 = ((i0>>23)&0xff)-0x7f;
|
||||
if (j0<23) {
|
||||
if (j0<0) { /* raise inexact if x != 0 */
|
||||
if (huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */
|
||||
if (i0<0) {i0=0x80000000;}
|
||||
else if (i0!=0) { i0=0x3f800000;}
|
||||
}
|
||||
} else {
|
||||
i = (0x007fffff)>>j0;
|
||||
if ((i0&i)==0) return x; /* x is integral */
|
||||
if (huge+x>(float)0.0) { /* raise inexact flag */
|
||||
if (i0>0) i0 += (0x00800000)>>j0;
|
||||
i0 &= (~i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (j0==0x80) return x+x; /* inf or NaN */
|
||||
else return x; /* x is integral */
|
||||
}
|
||||
SET_FLOAT_WORD(x,i0);
|
||||
return x;
|
||||
}
|
||||
|
||||
static const float one = 1.0, tiny=1.0e-30;
|
||||
|
||||
float
|
||||
sqrtf(float x)
|
||||
{
|
||||
float z;
|
||||
int32 sign = (int)0x80000000;
|
||||
int32 ix,s,q,m,t,i;
|
||||
uint32 r;
|
||||
|
||||
GET_FLOAT_WORD(ix,x);
|
||||
|
||||
/* take care of Inf and NaN */
|
||||
if ((ix&0x7f800000)==0x7f800000) {
|
||||
return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf
|
||||
sqrt(-inf)=sNaN */
|
||||
}
|
||||
/* take care of zero */
|
||||
if (ix<=0) {
|
||||
if ((ix&(~sign))==0) return x;/* sqrt(+-0) = +-0 */
|
||||
else if (ix<0)
|
||||
return (x-x)/(x-x); /* sqrt(-ve) = sNaN */
|
||||
}
|
||||
/* normalize x */
|
||||
m = (ix>>23);
|
||||
if (m==0) { /* subnormal x */
|
||||
for(i=0;(ix&0x00800000)==0;i++) ix<<=1;
|
||||
m -= i-1;
|
||||
}
|
||||
m -= 127; /* unbias exponent */
|
||||
ix = (ix&0x007fffff)|0x00800000;
|
||||
if (m&1) /* odd m, double x to make it even */
|
||||
ix += ix;
|
||||
m >>= 1; /* m = [m/2] */
|
||||
|
||||
/* generate sqrt(x) bit by bit */
|
||||
ix += ix;
|
||||
q = s = 0; /* q = sqrt(x) */
|
||||
r = 0x01000000; /* r = moving bit from right to left */
|
||||
|
||||
while(r!=0) {
|
||||
t = s+r;
|
||||
if (t<=ix) {
|
||||
s = t+r;
|
||||
ix -= t;
|
||||
q += r;
|
||||
}
|
||||
ix += ix;
|
||||
r>>=1;
|
||||
}
|
||||
|
||||
/* use floating add to find out rounding direction */
|
||||
if (ix!=0) {
|
||||
z = one-tiny; /* trigger inexact flag */
|
||||
if (z>=one) {
|
||||
z = one+tiny;
|
||||
if (z>one)
|
||||
q += 2;
|
||||
else
|
||||
q += (q&1);
|
||||
}
|
||||
}
|
||||
ix = (q>>1)+0x3f000000;
|
||||
ix += (m <<23);
|
||||
SET_FLOAT_WORD(z,ix);
|
||||
return z;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
make_small(float value)
|
||||
{
|
||||
if (value > 0)
|
||||
return floorf(value);
|
||||
else
|
||||
return ceilf(value);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
get_raw_movement(movement_maker *move, uint32 posX, uint32 posY)
|
||||
{
|
||||
const float acceleration = 0.8;
|
||||
const float translation = 12.0;
|
||||
|
||||
int diff;
|
||||
float xDelta, yDelta;
|
||||
|
||||
if (move->movementStarted) {
|
||||
move->movementStarted = false;
|
||||
// init delta tracking
|
||||
move->previousX = posX;
|
||||
move->previousY = posY;
|
||||
// deltas are automatically reset
|
||||
}
|
||||
|
||||
// accumulate delta and store current pos, reset if pos did not change
|
||||
diff = posX - move->previousX;
|
||||
// lessen the effect of small diffs
|
||||
if ((diff > -3 && diff < -1) || (diff > 1 && diff < 3))
|
||||
diff /= 2;
|
||||
if (diff == 0)
|
||||
move->deltaSumX = 0.0;
|
||||
else
|
||||
move->deltaSumX += diff;
|
||||
|
||||
diff = posY - move->previousY;
|
||||
// lessen the effect of small diffs
|
||||
if ((diff > -3 && diff < -1) || (diff > 1 && diff < 3))
|
||||
diff /= 2;
|
||||
if (diff == 0)
|
||||
move->deltaSumY = 0.0;
|
||||
else
|
||||
move->deltaSumY += diff;
|
||||
|
||||
move->previousX = posX;
|
||||
move->previousY = posY;
|
||||
|
||||
// compute current delta and reset accumulated delta if
|
||||
// abs() is greater than 1
|
||||
xDelta = move->deltaSumX / translation;
|
||||
yDelta = move->deltaSumY / translation;
|
||||
if (xDelta > 1.0) {
|
||||
move->deltaSumX = 0.0;
|
||||
xDelta = 1.0 + (xDelta - 1.0) * acceleration;
|
||||
} else if (xDelta < -1.0) {
|
||||
move->deltaSumX = 0.0;
|
||||
xDelta = -1.0 + (xDelta + 1.0) * acceleration;
|
||||
}
|
||||
|
||||
if (yDelta > 1.0) {
|
||||
move->deltaSumY = 0.0;
|
||||
yDelta = 1.0 + (yDelta - 1.0) * acceleration;
|
||||
} else if (yDelta < -1.0) {
|
||||
move->deltaSumY = 0.0;
|
||||
yDelta = -1.0 + (yDelta + 1.0) * acceleration;
|
||||
}
|
||||
|
||||
move->xDelta = make_small(xDelta);
|
||||
move->yDelta = make_small(yDelta);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
compute_acceleration(movement_maker *move, int8 accel_factor)
|
||||
{
|
||||
// acceleration
|
||||
float acceleration = 1;
|
||||
if (accel_factor != 0) {
|
||||
acceleration = 1 + sqrtf(move->xDelta * move->xDelta
|
||||
+ move->yDelta * move->yDelta) * accel_factor / 50.0;
|
||||
}
|
||||
|
||||
move->xDelta = make_small(move->xDelta * acceleration);
|
||||
move->yDelta = make_small(move->yDelta * acceleration);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
get_movement(movement_maker *move, uint32 posX, uint32 posY)
|
||||
{
|
||||
get_raw_movement(move, posX, posY);
|
||||
|
||||
// INFO("SYN: pos: %lu x %lu, delta: %ld x %ld, sums: %ld x %ld\n",
|
||||
// posX, posY, move->xDelta, move->yDelta,
|
||||
// move->deltaSumX, move->deltaSumY);
|
||||
|
||||
move->xDelta = move->xDelta * move->speed;
|
||||
move->yDelta = move->yDelta * move->speed;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
get_scrolling(movement_maker *move, uint32 posX, uint32 posY)
|
||||
{
|
||||
int32 stepsX = 0, stepsY = 0;
|
||||
|
||||
get_raw_movement(move, posX, posY);
|
||||
compute_acceleration(move, move->scroll_acceleration);
|
||||
|
||||
if (move->scrolling_xStep > 0) {
|
||||
move->scrolling_x += move->xDelta;
|
||||
|
||||
stepsX = make_small(move->scrolling_x / move->scrolling_xStep);
|
||||
|
||||
move->scrolling_x -= stepsX * move->scrolling_xStep;
|
||||
move->xDelta = stepsX;
|
||||
} else {
|
||||
move->scrolling_x = 0;
|
||||
move->xDelta = 0;
|
||||
}
|
||||
if (move->scrolling_yStep > 0) {
|
||||
move->scrolling_y += move->yDelta;
|
||||
|
||||
stepsY = make_small(move->scrolling_y / move->scrolling_yStep);
|
||||
|
||||
move->scrolling_y -= stepsY * move->scrolling_yStep;
|
||||
move->yDelta = -1 * stepsY;
|
||||
} else {
|
||||
move->scrolling_y = 0;
|
||||
move->yDelta = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
start_new_movment(movement_maker *move)
|
||||
{
|
||||
if (move->scrolling_xStep <= 0)
|
||||
move->scrolling_xStep = 1;
|
||||
if (move->scrolling_yStep <= 0)
|
||||
move->scrolling_yStep = 1;
|
||||
|
||||
move->movementStarted = true;
|
||||
move->scrolling_x = 0;
|
||||
move->scrolling_y = 0;
|
||||
}
|
||||
|
||||
@@ -1,836 +0,0 @@
|
||||
/*
|
||||
* 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 ([email protected])
|
||||
*/
|
||||
|
||||
|
||||
#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,
|
||||
};
|
||||
|
||||
@@ -1,418 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-2009 Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors (in chronological order):
|
||||
* Stefano Ceccherini ([email protected])
|
||||
* Axel Dörfler, [email protected]
|
||||
* Marcus Overhagen <[email protected]>
|
||||
*/
|
||||
|
||||
/*! PS/2 bus manager */
|
||||
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "ps2_common.h"
|
||||
#include "ps2_service.h"
|
||||
#include "ps2_dev.h"
|
||||
|
||||
|
||||
isa_module_info *gIsa = NULL;
|
||||
bool gActiveMultiplexingEnabled = false;
|
||||
sem_id gControllerSem;
|
||||
|
||||
static int32 sIgnoreInterrupts = 0;
|
||||
|
||||
|
||||
uint8
|
||||
ps2_read_ctrl(void)
|
||||
{
|
||||
return gIsa->read_io_8(PS2_PORT_CTRL);
|
||||
}
|
||||
|
||||
|
||||
uint8
|
||||
ps2_read_data(void)
|
||||
{
|
||||
return gIsa->read_io_8(PS2_PORT_DATA);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ps2_write_ctrl(uint8 ctrl)
|
||||
{
|
||||
TRACE("ps2: ps2_write_ctrl 0x%02x\n", ctrl);
|
||||
|
||||
gIsa->write_io_8(PS2_PORT_CTRL, ctrl);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ps2_write_data(uint8 data)
|
||||
{
|
||||
TRACE("ps2: ps2_write_data 0x%02x\n", data);
|
||||
|
||||
gIsa->write_io_8(PS2_PORT_DATA, data);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ps2_wait_read(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < PS2_CTRL_WAIT_TIMEOUT / 50; i++) {
|
||||
if (ps2_read_ctrl() & PS2_STATUS_OUTPUT_BUFFER_FULL)
|
||||
return B_OK;
|
||||
snooze(50);
|
||||
}
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ps2_wait_write(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < PS2_CTRL_WAIT_TIMEOUT / 50; i++) {
|
||||
if (!(ps2_read_ctrl() & PS2_STATUS_INPUT_BUFFER_FULL))
|
||||
return B_OK;
|
||||
snooze(50);
|
||||
}
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
void
|
||||
ps2_flush(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
acquire_sem(gControllerSem);
|
||||
atomic_add(&sIgnoreInterrupts, 1);
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
uint8 ctrl;
|
||||
uint8 data;
|
||||
ctrl = ps2_read_ctrl();
|
||||
if (!(ctrl & PS2_STATUS_OUTPUT_BUFFER_FULL))
|
||||
break;
|
||||
data = ps2_read_data();
|
||||
TRACE("ps2: ps2_flush: ctrl 0x%02x, data 0x%02x (%s)\n", ctrl, data, (ctrl & PS2_STATUS_AUX_DATA) ? "aux" : "keyb");
|
||||
snooze(100);
|
||||
}
|
||||
|
||||
atomic_add(&sIgnoreInterrupts, -1);
|
||||
release_sem(gControllerSem);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
ps2_selftest()
|
||||
{
|
||||
status_t res;
|
||||
uint8 in;
|
||||
res = ps2_command(PS2_CTRL_SELF_TEST, NULL, 0, &in, 1);
|
||||
if (res != B_OK || in != 0x55) {
|
||||
INFO("ps2: controller self test failed, status 0x%08lx, data 0x%02x\n", res, in);
|
||||
return B_ERROR;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
ps2_setup_command_byte()
|
||||
{
|
||||
status_t res;
|
||||
uint8 cmdbyte;
|
||||
|
||||
res = ps2_command(PS2_CTRL_READ_CMD, NULL, 0, &cmdbyte, 1);
|
||||
TRACE("ps2: get command byte: res 0x%08lx, cmdbyte 0x%02x\n", res, cmdbyte);
|
||||
if (res != B_OK)
|
||||
cmdbyte = 0x47;
|
||||
|
||||
cmdbyte |= PS2_BITS_TRANSLATE_SCANCODES | PS2_BITS_KEYBOARD_INTERRUPT
|
||||
| PS2_BITS_AUX_INTERRUPT;
|
||||
cmdbyte &= ~(PS2_BITS_KEYBOARD_DISABLED | PS2_BITS_MOUSE_DISABLED);
|
||||
|
||||
res = ps2_command(PS2_CTRL_WRITE_CMD, &cmdbyte, 1, NULL, 0);
|
||||
TRACE("ps2: set command byte: res 0x%08lx, cmdbyte 0x%02x\n", res, cmdbyte);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
ps2_setup_active_multiplexing(bool *enabled)
|
||||
{
|
||||
status_t res;
|
||||
uint8 in, out;
|
||||
|
||||
out = 0xf0;
|
||||
res = ps2_command(0xd3, &out, 1, &in, 1);
|
||||
if (res)
|
||||
goto fail;
|
||||
// Step 1, if controller is good, in does match out.
|
||||
// This test failes with MS Virtual PC.
|
||||
if (in != out)
|
||||
goto no_support;
|
||||
|
||||
out = 0x56;
|
||||
res = ps2_command(0xd3, &out, 1, &in, 1);
|
||||
if (res)
|
||||
goto fail;
|
||||
// Step 2, if controller is good, in does match out.
|
||||
if (in != out)
|
||||
goto no_support;
|
||||
|
||||
out = 0xa4;
|
||||
res = ps2_command(0xd3, &out, 1, &in, 1);
|
||||
if (res)
|
||||
goto fail;
|
||||
// Step 3, if the controller doesn't support active multiplexing,
|
||||
// then in data does match out data (0xa4), else it's version number.
|
||||
if (in == out)
|
||||
goto no_support;
|
||||
|
||||
// With some broken USB legacy emulation, it's 0xac, and with
|
||||
// MS Virtual PC, it's 0xa6. Since current active multiplexing
|
||||
// specification version is 1.1 (0x11), we validate the data.
|
||||
if (in > 0x9f) {
|
||||
TRACE("ps2: active multiplexing v%d.%d detected, but ignored!\n", (in >> 4), in & 0xf);
|
||||
goto no_support;
|
||||
}
|
||||
|
||||
INFO("ps2: active multiplexing v%d.%d enabled\n", (in >> 4), in & 0xf);
|
||||
*enabled = true;
|
||||
goto done;
|
||||
|
||||
no_support:
|
||||
TRACE("ps2: active multiplexing not supported\n");
|
||||
*enabled = false;
|
||||
|
||||
done:
|
||||
// Some controllers get upset by the d3 command and will continue data
|
||||
// loopback, thus we need to send a harmless command (enable keyboard
|
||||
// interface) next.
|
||||
// This fixes bug report #1175
|
||||
res = ps2_command(0xae, NULL, 0, NULL, 0);
|
||||
if (res != B_OK) {
|
||||
INFO("ps2: active multiplexing d3 workaround failed, status 0x%08lx\n", res);
|
||||
}
|
||||
return B_OK;
|
||||
|
||||
fail:
|
||||
TRACE("ps2: testing for active multiplexing failed\n");
|
||||
*enabled = false;
|
||||
// this should revert the controller into legacy mode,
|
||||
// just in case it has switched to multiplexed mode
|
||||
return ps2_selftest();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ps2_command(uint8 cmd, const uint8 *out, int outCount, uint8 *in, int inCount)
|
||||
{
|
||||
status_t res;
|
||||
int i;
|
||||
|
||||
acquire_sem(gControllerSem);
|
||||
atomic_add(&sIgnoreInterrupts, 1);
|
||||
|
||||
#ifdef TRACE_PS2
|
||||
TRACE("ps2: ps2_command cmd 0x%02x, out %d, in %d\n", cmd, outCount, inCount);
|
||||
for (i = 0; i < outCount; i++)
|
||||
TRACE("ps2: ps2_command out 0x%02x\n", out[i]);
|
||||
#endif
|
||||
|
||||
res = ps2_wait_write();
|
||||
if (res == B_OK)
|
||||
ps2_write_ctrl(cmd);
|
||||
|
||||
for (i = 0; res == B_OK && i < outCount; i++) {
|
||||
res = ps2_wait_write();
|
||||
if (res == B_OK)
|
||||
ps2_write_data(out[i]);
|
||||
else
|
||||
TRACE("ps2: ps2_command out byte %d failed\n", i);
|
||||
}
|
||||
|
||||
for (i = 0; res == B_OK && i < inCount; i++) {
|
||||
res = ps2_wait_read();
|
||||
if (res == B_OK)
|
||||
in[i] = ps2_read_data();
|
||||
else
|
||||
TRACE("ps2: ps2_command in byte %d failed\n", i);
|
||||
}
|
||||
|
||||
#ifdef TRACE_PS2
|
||||
for (i = 0; i < inCount; i++)
|
||||
TRACE("ps2: ps2_command in 0x%02x\n", in[i]);
|
||||
TRACE("ps2: ps2_command result 0x%08lx\n", res);
|
||||
#endif
|
||||
|
||||
atomic_add(&sIgnoreInterrupts, -1);
|
||||
release_sem(gControllerSem);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
static int32
|
||||
ps2_interrupt(void* cookie)
|
||||
{
|
||||
uint8 ctrl;
|
||||
uint8 data;
|
||||
bool error;
|
||||
ps2_dev *dev;
|
||||
|
||||
ctrl = ps2_read_ctrl();
|
||||
if (!(ctrl & PS2_STATUS_OUTPUT_BUFFER_FULL))
|
||||
return B_UNHANDLED_INTERRUPT;
|
||||
|
||||
if (atomic_get(&sIgnoreInterrupts)) {
|
||||
TRACE("ps2: ps2_interrupt ignoring, ctrl 0x%02x (%s)\n", ctrl,
|
||||
(ctrl & PS2_STATUS_AUX_DATA) ? "aux" : "keyb");
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}
|
||||
|
||||
data = ps2_read_data();
|
||||
|
||||
if ((ctrl & PS2_STATUS_AUX_DATA) != 0) {
|
||||
uint8 idx;
|
||||
if (gActiveMultiplexingEnabled) {
|
||||
idx = ctrl >> 6;
|
||||
error = (ctrl & 0x04) != 0;
|
||||
TRACE("ps2: ps2_interrupt ctrl 0x%02x, data 0x%02x (mouse %d)\n",
|
||||
ctrl, data, idx);
|
||||
} else {
|
||||
idx = 0;
|
||||
error = (ctrl & 0xC0) != 0;
|
||||
TRACE("ps2: ps2_interrupt ctrl 0x%02x, data 0x%02x (aux)\n", ctrl,
|
||||
data);
|
||||
}
|
||||
dev = &ps2_device[PS2_DEVICE_MOUSE + idx];
|
||||
} else {
|
||||
TRACE("ps2: ps2_interrupt ctrl 0x%02x, data 0x%02x (keyb)\n", ctrl,
|
||||
data);
|
||||
|
||||
dev = &ps2_device[PS2_DEVICE_KEYB];
|
||||
error = (ctrl & 0xC0) != 0;
|
||||
}
|
||||
|
||||
dev->history[1] = dev->history[0];
|
||||
dev->history[0].time = system_time();
|
||||
dev->history[0].data = data;
|
||||
dev->history[0].error = error;
|
||||
|
||||
return ps2_dev_handle_int(dev);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - driver interface
|
||||
|
||||
|
||||
status_t
|
||||
ps2_init(void)
|
||||
{
|
||||
status_t status;
|
||||
|
||||
TRACE("ps2: init\n");
|
||||
|
||||
status = get_module(B_ISA_MODULE_NAME, (module_info **)&gIsa);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
gControllerSem = create_sem(1, "ps/2 keyb ctrl");
|
||||
|
||||
ps2_flush();
|
||||
|
||||
status = ps2_dev_init();
|
||||
if (status < B_OK)
|
||||
goto err1;
|
||||
|
||||
status = ps2_service_init();
|
||||
if (status < B_OK)
|
||||
goto err2;
|
||||
|
||||
status = install_io_interrupt_handler(INT_PS2_KEYBOARD, &ps2_interrupt,
|
||||
NULL, 0);
|
||||
if (status)
|
||||
goto err3;
|
||||
|
||||
status = install_io_interrupt_handler(INT_PS2_MOUSE, &ps2_interrupt, NULL,
|
||||
0);
|
||||
if (status)
|
||||
goto err4;
|
||||
|
||||
// While this might have fixed bug #1185, we can't do this unconditionally
|
||||
// as it obviously messes up many controllers which couldn't reboot anymore
|
||||
// after that
|
||||
//ps2_selftest();
|
||||
|
||||
status = ps2_setup_command_byte();
|
||||
if (status) {
|
||||
INFO("ps2: setting up command byte failed\n");
|
||||
goto err5;
|
||||
}
|
||||
|
||||
ps2_flush();
|
||||
status = ps2_setup_active_multiplexing(&gActiveMultiplexingEnabled);
|
||||
if (status) {
|
||||
INFO("ps2: setting up active multiplexing failed\n");
|
||||
goto err5;
|
||||
}
|
||||
|
||||
if (gActiveMultiplexingEnabled) {
|
||||
if (ps2_dev_command_timeout(&ps2_device[PS2_DEVICE_MOUSE], 0xe6,
|
||||
NULL, 0, NULL, 0, 100000) == B_TIMED_OUT) {
|
||||
INFO("ps2: accessing multiplexed mouse port 0 timed out, ignoring it!\n");
|
||||
} else {
|
||||
ps2_service_notify_device_added(&ps2_device[PS2_DEVICE_MOUSE]);
|
||||
}
|
||||
ps2_service_notify_device_added(&ps2_device[PS2_DEVICE_MOUSE + 1]);
|
||||
ps2_service_notify_device_added(&ps2_device[PS2_DEVICE_MOUSE + 2]);
|
||||
ps2_service_notify_device_added(&ps2_device[PS2_DEVICE_MOUSE + 3]);
|
||||
ps2_service_notify_device_added(&ps2_device[PS2_DEVICE_KEYB]);
|
||||
} else {
|
||||
ps2_service_notify_device_added(&ps2_device[PS2_DEVICE_MOUSE]);
|
||||
ps2_service_notify_device_added(&ps2_device[PS2_DEVICE_KEYB]);
|
||||
}
|
||||
|
||||
TRACE("ps2: init done!\n");
|
||||
return B_OK;
|
||||
|
||||
err5:
|
||||
remove_io_interrupt_handler(INT_PS2_MOUSE, &ps2_interrupt, NULL);
|
||||
err4:
|
||||
remove_io_interrupt_handler(INT_PS2_KEYBOARD, &ps2_interrupt, NULL);
|
||||
err3:
|
||||
ps2_service_exit();
|
||||
err2:
|
||||
ps2_dev_exit();
|
||||
err1:
|
||||
delete_sem(gControllerSem);
|
||||
put_module(B_ISA_MODULE_NAME);
|
||||
TRACE("ps2: init failed!\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ps2_uninit(void)
|
||||
{
|
||||
TRACE("ps2: uninit\n");
|
||||
remove_io_interrupt_handler(INT_PS2_MOUSE, &ps2_interrupt, NULL);
|
||||
remove_io_interrupt_handler(INT_PS2_KEYBOARD, &ps2_interrupt, NULL);
|
||||
ps2_service_exit();
|
||||
ps2_dev_exit();
|
||||
delete_sem(gControllerSem);
|
||||
put_module(B_ISA_MODULE_NAME);
|
||||
}
|
||||
@@ -1,525 +0,0 @@
|
||||
/*
|
||||
* Copyright 2001-2010 Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors (in chronological order):
|
||||
* Elad Lahav ([email protected])
|
||||
* Stefano Ceccherini ([email protected])
|
||||
* Axel Dörfler, [email protected]
|
||||
* Marcus Overhagen <[email protected]>
|
||||
* Clemens Zeidler <[email protected]>
|
||||
*/
|
||||
|
||||
|
||||
/*! PS/2 mouse device driver
|
||||
|
||||
A PS/2 mouse is connected to the IBM 8042 controller, and gets its
|
||||
name from the IBM PS/2 personal computer, which was the first to
|
||||
use this device. All resources are shared between the keyboard, and
|
||||
the mouse, referred to as the "Auxiliary Device".
|
||||
|
||||
I/O:
|
||||
~~~
|
||||
The controller has 3 I/O registers:
|
||||
1. Status (input), mapped to port 64h
|
||||
2. Control (output), mapped to port 64h
|
||||
3. Data (input/output), mapped to port 60h
|
||||
|
||||
Data:
|
||||
~~~~
|
||||
A packet read from the mouse data port is composed of
|
||||
three bytes:
|
||||
byte 0: status byte, where
|
||||
- bit 7: Y overflow (1 = true)
|
||||
- bit 6: X overflow (1 = true)
|
||||
- bit 5: MSB of Y offset
|
||||
- bit 4: MSB of X offset
|
||||
- bit 3: Syncronization bit (always 1)
|
||||
- bit 2: Middle button (1 = down)
|
||||
- bit 1: Right button (1 = down)
|
||||
- bit 0: Left button (1 = down)
|
||||
byte 1: X position change, since last probed (-127 to +127)
|
||||
byte 2: Y position change, since last probed (-127 to +127)
|
||||
|
||||
Intellimouse mice send a four byte packet, where the first three
|
||||
bytes are the same as standard mice, and the last one reports the
|
||||
Z position, which is, usually, the wheel movement.
|
||||
|
||||
Interrupts:
|
||||
~~~~~~~~~~
|
||||
The PS/2 mouse device is connected to interrupt 12.
|
||||
The controller uses 3 consecutive interrupts to inform the computer
|
||||
that it has new data. On the first the data register holds the status
|
||||
byte, on the second the X offset, and on the 3rd the Y offset.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <keyboard_mouse_driver.h>
|
||||
|
||||
#include "ps2_service.h"
|
||||
#include "ps2_standard_mouse.h"
|
||||
|
||||
|
||||
const char* kStandardMousePath[4] = {
|
||||
"input/mouse/ps2/standard_0",
|
||||
"input/mouse/ps2/standard_1",
|
||||
"input/mouse/ps2/standard_2",
|
||||
"input/mouse/ps2/standard_3"
|
||||
};
|
||||
const char* kIntelliMousePath[4] = {
|
||||
"input/mouse/ps2/intelli_0",
|
||||
"input/mouse/ps2/intelli_1",
|
||||
"input/mouse/ps2/intelli_2",
|
||||
"input/mouse/ps2/intelli_3"
|
||||
};
|
||||
|
||||
|
||||
/*! Set sampling rate of the ps2 port.
|
||||
*/
|
||||
static inline status_t
|
||||
ps2_set_sample_rate(ps2_dev *dev, uint8 rate)
|
||||
{
|
||||
return ps2_dev_command(dev, PS2_CMD_SET_SAMPLE_RATE, &rate, 1, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
/*! Converts a packet received by the mouse to a "movement".
|
||||
*/
|
||||
static void
|
||||
ps2_packet_to_movement(standard_mouse_cookie *cookie, uint8 packet[],
|
||||
mouse_movement *pos)
|
||||
{
|
||||
int buttons = packet[0] & 7;
|
||||
int xDelta = ((packet[0] & 0x10) ? ~0xff : 0) | packet[1];
|
||||
int yDelta = ((packet[0] & 0x20) ? ~0xff : 0) | packet[2];
|
||||
int xDeltaWheel = 0;
|
||||
int yDeltaWheel = 0;
|
||||
bigtime_t currentTime = system_time();
|
||||
|
||||
if (buttons != 0 && cookie->buttons_state == 0) {
|
||||
if (cookie->click_last_time + cookie->click_speed > currentTime)
|
||||
cookie->click_count++;
|
||||
else
|
||||
cookie->click_count = 1;
|
||||
|
||||
cookie->click_last_time = currentTime;
|
||||
}
|
||||
|
||||
cookie->buttons_state = buttons;
|
||||
|
||||
if (cookie->flags & F_MOUSE_TYPE_INTELLIMOUSE) {
|
||||
yDeltaWheel = packet[3] & 0x07;
|
||||
if (packet[3] & 0x08)
|
||||
yDeltaWheel |= ~0x07;
|
||||
}
|
||||
/*
|
||||
if (cookie->flags & F_MOUSE_TYPE_2WHEELS) {
|
||||
switch (packet[3] & 0x0F) {
|
||||
case 0x01: yDeltaWheel = +1; break; // wheel 1 down
|
||||
case 0x0F: yDeltaWheel = -1; break; // wheel 1 up
|
||||
case 0x02: xDeltaWheel = +1; break; // wheel 2 down
|
||||
case 0x0E: xDeltaWheel = -1; break; // wheel 2 up
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// TRACE("packet: %02x %02x %02x %02x: xd %d, yd %d, 0x%x (%d), w-xd %d, "
|
||||
// "w-yd %d\n", packet[0], packet[1], packet[2], packet[3],
|
||||
// xDelta, yDelta, buttons, cookie->click_count, xDeltaWheel,
|
||||
// yDeltaWheel);
|
||||
|
||||
if (pos) {
|
||||
pos->xdelta = xDelta;
|
||||
pos->ydelta = yDelta;
|
||||
pos->buttons = buttons;
|
||||
pos->clicks = cookie->click_count;
|
||||
pos->modifiers = 0;
|
||||
pos->timestamp = currentTime;
|
||||
pos->wheel_ydelta = yDeltaWheel;
|
||||
pos->wheel_xdelta = xDeltaWheel;
|
||||
|
||||
TRACE("ps2: ps2_packet_to_movement xdelta: %d, ydelta: %d, buttons %x, "
|
||||
"clicks: %d, timestamp %Ld\n",
|
||||
xDelta, yDelta, buttons, cookie->click_count, currentTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! Read a mouse event from the mouse events chain buffer.
|
||||
*/
|
||||
static status_t
|
||||
standard_mouse_read_event(standard_mouse_cookie *cookie,
|
||||
mouse_movement *movement)
|
||||
{
|
||||
uint8 packet[PS2_MAX_PACKET_SIZE];
|
||||
status_t status;
|
||||
|
||||
TRACE("ps2: standard_mouse_read_event\n");
|
||||
|
||||
status = acquire_sem_etc(cookie->standard_mouse_sem, 1, B_CAN_INTERRUPT, 0);
|
||||
TRACE("ps2: standard_mouse_read_event acquired\n");
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
if (!cookie->dev->active) {
|
||||
TRACE("ps2: standard_mouse_read_event: Error device no longer "
|
||||
"active\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (packet_buffer_read(cookie->standard_mouse_buffer, packet,
|
||||
cookie->dev->packet_size) != cookie->dev->packet_size) {
|
||||
TRACE("ps2: error copying buffer\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (!(packet[0] & 8))
|
||||
panic("ps2: got broken data from packet_buffer_read\n");
|
||||
|
||||
ps2_packet_to_movement(cookie, packet, movement);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
void
|
||||
standard_mouse_disconnect(ps2_dev *dev)
|
||||
{
|
||||
// the mouse device might not be opened at this point
|
||||
INFO("ps2: ps2_standard_mouse_disconnect %s\n", dev->name);
|
||||
if (dev->flags & PS2_FLAG_OPEN)
|
||||
release_sem(((standard_mouse_cookie *)dev->cookie)->standard_mouse_sem);
|
||||
}
|
||||
|
||||
|
||||
/*! Interrupt handler for the mouse device. Called whenever the I/O
|
||||
controller generates an interrupt for the PS/2 mouse. Reads mouse
|
||||
information from the data port, and stores it, so it can be accessed
|
||||
by read() operations. The full data is obtained using 3 consecutive
|
||||
calls to the handler, each holds a different byte on the data port.
|
||||
*/
|
||||
int32
|
||||
standard_mouse_handle_int(ps2_dev *dev)
|
||||
{
|
||||
standard_mouse_cookie *cookie = (standard_mouse_cookie*)dev->cookie;
|
||||
const uint8 data = dev->history[0].data;
|
||||
|
||||
TRACE("ps2: standard mouse: %1x\t%1x\t%1x\t%1x\t%1x\t%1x\t%1x\t%1x\n",
|
||||
data >> 7 & 1, data >> 6 & 1, data >> 5 & 1,
|
||||
data >> 4 & 1, data >> 3 & 1, data >> 2 & 1,
|
||||
data >> 1 & 1, data >> 0 & 1);
|
||||
|
||||
if (cookie->packet_index == 0 && !(data & 8)) {
|
||||
INFO("ps2: bad mouse data, trying resync\n");
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}
|
||||
|
||||
// Workarounds for active multiplexing keyboard controllers
|
||||
// that lose data or send them to the wrong port.
|
||||
if (cookie->packet_index == 0 && (data & 0xc0)) {
|
||||
INFO("ps2: strange mouse data, x/y overflow, trying resync\n");
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}
|
||||
if (cookie->packet_index == 1) {
|
||||
int xDelta
|
||||
= ((cookie->packet_buffer[0] & 0x10) ? 0xFFFFFF00 : 0) | data;
|
||||
if (xDelta < -100 || xDelta > 100) {
|
||||
INFO("ps2: strange mouse data, x-delta %d, trying resync\n",
|
||||
xDelta);
|
||||
cookie->packet_index = 0;
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}
|
||||
}
|
||||
if (cookie->packet_index == 2) {
|
||||
int yDelta
|
||||
= ((cookie->packet_buffer[0] & 0x20) ? 0xFFFFFF00 : 0) | data;
|
||||
if (yDelta < -100 || yDelta > 100) {
|
||||
INFO("ps2: strange mouse data, y-delta %d, trying resync\n",
|
||||
yDelta);
|
||||
cookie->packet_index = 0;
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}
|
||||
}
|
||||
|
||||
cookie->packet_buffer[cookie->packet_index++] = data;
|
||||
|
||||
if (cookie->packet_index != dev->packet_size) {
|
||||
// packet not yet complete
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}
|
||||
|
||||
// complete packet is assembled
|
||||
|
||||
cookie->packet_index = 0;
|
||||
if (packet_buffer_write(cookie->standard_mouse_buffer,
|
||||
cookie->packet_buffer, dev->packet_size) != dev->packet_size) {
|
||||
// buffer is full, drop new data
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}
|
||||
|
||||
release_sem_etc(cookie->standard_mouse_sem, 1, B_DO_NOT_RESCHEDULE);
|
||||
return B_INVOKE_SCHEDULER;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
status_t
|
||||
probe_standard_mouse(ps2_dev * dev)
|
||||
{
|
||||
status_t status;
|
||||
uint8 deviceId = 0;
|
||||
|
||||
// get device id
|
||||
status = ps2_dev_command(dev, PS2_CMD_GET_DEVICE_ID, NULL, 0,
|
||||
&deviceId, 1);
|
||||
if (status != B_OK) {
|
||||
INFO("ps2: probe_mouse get device id failed\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
TRACE("ps2: probe_mouse device id: %2x\n", deviceId);
|
||||
|
||||
// check for MS Intellimouse
|
||||
if (deviceId == 0) {
|
||||
uint8 alternate_device_id;
|
||||
status = ps2_set_sample_rate(dev, 200);
|
||||
status |= ps2_set_sample_rate(dev, 100);
|
||||
status |= ps2_set_sample_rate(dev, 80);
|
||||
status |= ps2_dev_command(dev, PS2_CMD_GET_DEVICE_ID, NULL, 0,
|
||||
&alternate_device_id, 1);
|
||||
if (status == 0) {
|
||||
TRACE("ps2: probe_mouse alternate device id: %2x\n",
|
||||
alternate_device_id);
|
||||
deviceId = alternate_device_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (deviceId == PS2_DEV_ID_STANDARD
|
||||
|| deviceId == PS2_DEV_ID_TOUCHPAD_RICATECH) {
|
||||
INFO("ps2: probe_mouse Standard PS/2 mouse found\n");
|
||||
dev->name = kStandardMousePath[dev->idx];
|
||||
dev->packet_size = PS2_PACKET_STANDARD;
|
||||
} else if (deviceId == PS2_DEV_ID_INTELLIMOUSE) {
|
||||
dev->name = kIntelliMousePath[dev->idx];
|
||||
dev->packet_size = PS2_PACKET_INTELLIMOUSE;
|
||||
INFO("ps2: probe_mouse Extended PS/2 mouse found\n");
|
||||
} else {
|
||||
INFO("ps2: probe_mouse Error unknown device id.\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Device functions
|
||||
|
||||
|
||||
status_t
|
||||
standard_mouse_open(const char *name, uint32 flags, void **_cookie)
|
||||
{
|
||||
standard_mouse_cookie *cookie;
|
||||
status_t status;
|
||||
ps2_dev *dev = NULL;
|
||||
int i;
|
||||
|
||||
TRACE("ps2: standard_mouse_open %s\n", name);
|
||||
|
||||
for (dev = NULL, i = 0; i < PS2_DEVICE_COUNT; i++) {
|
||||
if (0 == strcmp(ps2_device[i].name, name)) {
|
||||
dev = &ps2_device[i];
|
||||
break;
|
||||
}
|
||||
/*if (0 == strcmp(g_passthrough_dev.name, name)) {
|
||||
dev = &g_passthrough_dev;
|
||||
isSynapticsPTDevice = true;
|
||||
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 = malloc(sizeof(standard_mouse_cookie));
|
||||
if (cookie == NULL)
|
||||
goto err1;
|
||||
|
||||
*_cookie = cookie;
|
||||
memset(cookie, 0, sizeof(*cookie));
|
||||
|
||||
cookie->dev = dev;
|
||||
dev->cookie = cookie;
|
||||
dev->disconnect = &standard_mouse_disconnect;
|
||||
dev->handle_int = &standard_mouse_handle_int;
|
||||
|
||||
if (strstr(dev->name, "standard") != NULL)
|
||||
cookie->flags = F_MOUSE_TYPE_STANDARD;
|
||||
|
||||
if (strstr(dev->name, "intelli") != NULL)
|
||||
cookie->flags = F_MOUSE_TYPE_INTELLIMOUSE;
|
||||
|
||||
cookie->standard_mouse_buffer
|
||||
= create_packet_buffer(MOUSE_HISTORY_SIZE * dev->packet_size);
|
||||
if (cookie->standard_mouse_buffer == NULL) {
|
||||
TRACE("ps2: 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->standard_mouse_sem = create_sem(0, "ps2_standard_mouse_sem");
|
||||
if (cookie->standard_mouse_sem < 0) {
|
||||
TRACE("ps2: failed creating PS/2 mouse semaphore!\n");
|
||||
goto err3;
|
||||
}
|
||||
|
||||
status = ps2_dev_command(dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0);
|
||||
if (status < B_OK) {
|
||||
INFO("ps2: cannot enable mouse %s\n", name);
|
||||
goto err4;
|
||||
}
|
||||
|
||||
atomic_or(&dev->flags, PS2_FLAG_ENABLED);
|
||||
|
||||
|
||||
TRACE("ps2: standard_mouse_open %s success\n", name);
|
||||
return B_OK;
|
||||
|
||||
err4:
|
||||
delete_sem(cookie->standard_mouse_sem);
|
||||
err3:
|
||||
delete_packet_buffer(cookie->standard_mouse_buffer);
|
||||
err2:
|
||||
free(cookie);
|
||||
err1:
|
||||
atomic_and(&dev->flags, ~PS2_FLAG_OPEN);
|
||||
|
||||
TRACE("ps2: standard_mouse_open %s failed\n", name);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
standard_mouse_close(void *_cookie)
|
||||
{
|
||||
standard_mouse_cookie *cookie = (standard_mouse_cookie*)_cookie;
|
||||
|
||||
TRACE("ps2: standard_mouse_close %s enter\n", cookie->dev->name);
|
||||
|
||||
ps2_dev_command_timeout(cookie->dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0,
|
||||
150000);
|
||||
|
||||
delete_packet_buffer(cookie->standard_mouse_buffer);
|
||||
delete_sem(cookie->standard_mouse_sem);
|
||||
|
||||
atomic_and(&cookie->dev->flags, ~PS2_FLAG_OPEN);
|
||||
atomic_and(&cookie->dev->flags, ~PS2_FLAG_ENABLED);
|
||||
|
||||
TRACE("ps2: standard_mouse_close %s done\n", cookie->dev->name);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
standard_mouse_freecookie(void *_cookie)
|
||||
{
|
||||
standard_mouse_cookie *cookie = (standard_mouse_cookie*)_cookie;
|
||||
free(cookie);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
standard_mouse_read(void *cookie, off_t pos, void *buffer, size_t *_length)
|
||||
{
|
||||
*_length = 0;
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
standard_mouse_write(void *cookie, off_t pos, const void *buffer,
|
||||
size_t *_length)
|
||||
{
|
||||
*_length = 0;
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
standard_mouse_ioctl(void *_cookie, uint32 op, void *buffer, size_t length)
|
||||
{
|
||||
standard_mouse_cookie *cookie = (standard_mouse_cookie*)_cookie;
|
||||
|
||||
switch (op) {
|
||||
case MS_NUM_EVENTS:
|
||||
{
|
||||
int32 count;
|
||||
TRACE("ps2: ioctl MS_NUM_EVENTS\n");
|
||||
get_sem_count(cookie->standard_mouse_sem, &count);
|
||||
return count;
|
||||
}
|
||||
|
||||
case MS_READ:
|
||||
{
|
||||
mouse_movement movement;
|
||||
status_t status;
|
||||
TRACE("ps2: ioctl MS_READ\n");
|
||||
if ((status = standard_mouse_read_event(cookie, &movement)) < B_OK)
|
||||
return status;
|
||||
// TRACE("%s %d %d %d %d\n", cookie->dev->name,
|
||||
// movement.xdelta, movement.ydelta, movement.buttons,
|
||||
// movement.clicks);
|
||||
return user_memcpy(buffer, &movement, sizeof(movement));
|
||||
}
|
||||
|
||||
case MS_SET_TYPE:
|
||||
TRACE("ps2: ioctl MS_SET_TYPE not implemented\n");
|
||||
return B_BAD_VALUE;
|
||||
|
||||
case MS_SET_MAP:
|
||||
TRACE("ps2: ioctl MS_SET_MAP (set mouse mapping) not "
|
||||
"implemented\n");
|
||||
return B_BAD_VALUE;
|
||||
|
||||
case MS_GET_ACCEL:
|
||||
TRACE("ps2: ioctl MS_GET_ACCEL (get mouse acceleration) not "
|
||||
"implemented\n");
|
||||
return B_BAD_VALUE;
|
||||
|
||||
case MS_SET_ACCEL:
|
||||
TRACE("ps2: ioctl MS_SET_ACCEL (set mouse acceleration) not "
|
||||
"implemented\n");
|
||||
return B_BAD_VALUE;
|
||||
|
||||
case MS_SET_CLICKSPEED:
|
||||
TRACE("ps2: ioctl MS_SETCLICK (set click speed)\n");
|
||||
return user_memcpy(&cookie->click_speed, buffer, sizeof(bigtime_t));
|
||||
|
||||
default:
|
||||
TRACE("ps2: ioctl unknown mouse opcode: %ld\n", op);
|
||||
return B_DEV_INVALID_IOCTL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
device_hooks gStandardMouseDeviceHooks = {
|
||||
standard_mouse_open,
|
||||
standard_mouse_close,
|
||||
standard_mouse_freecookie,
|
||||
standard_mouse_ioctl,
|
||||
standard_mouse_read,
|
||||
standard_mouse_write,
|
||||
};
|
||||
@@ -1,858 +0,0 @@
|
||||
/*
|
||||
* Copyright 2008-2010, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors (in chronological order):
|
||||
* Clemens Zeidler ([email protected])
|
||||
* Axel Dörfler, [email protected]
|
||||
*/
|
||||
|
||||
|
||||
//! PS/2 synaptics touchpad
|
||||
|
||||
|
||||
#include "ps2_synaptics.h"
|
||||
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <keyboard_mouse_driver.h>
|
||||
|
||||
#include "ps2_service.h"
|
||||
|
||||
|
||||
const char* kSynapticsPath[4] = {
|
||||
"input/touchpad/ps2/synaptics_0",
|
||||
"input/touchpad/ps2/synaptics_1",
|
||||
"input/touchpad/ps2/synaptics_2",
|
||||
"input/touchpad/ps2/synaptics_3"
|
||||
};
|
||||
|
||||
|
||||
static touchpad_info sTouchpadInfo;
|
||||
static ps2_dev *sPassthroughDevice = &ps2_device[PS2_DEVICE_SYN_PASSTHROUGH];
|
||||
|
||||
|
||||
static void
|
||||
default_settings(touchpad_settings *set)
|
||||
{
|
||||
memcpy(set, &kDefaultTouchpadSettings, sizeof(touchpad_settings));
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
send_touchpad_arg_timeout(ps2_dev *dev, uint8 arg, bigtime_t timeout)
|
||||
{
|
||||
int8 i;
|
||||
uint8 val[8];
|
||||
for (i = 0; i < 4; i++) {
|
||||
val[2 * i] = (arg >> (6 - 2 * i)) & 3;
|
||||
val[2 * i + 1] = 0xE8;
|
||||
}
|
||||
return ps2_dev_command_timeout(dev, 0xE8, val, 7, NULL, 0, timeout);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
send_touchpad_arg(ps2_dev *dev, uint8 arg)
|
||||
{
|
||||
return send_touchpad_arg_timeout(dev, arg, 4000000);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
set_touchpad_mode(ps2_dev *dev, uint8 mode)
|
||||
{
|
||||
uint8 sample_rate = SYN_CHANGE_MODE;
|
||||
send_touchpad_arg(dev, mode);
|
||||
return ps2_dev_command(dev, PS2_CMD_SET_SAMPLE_RATE, &sample_rate, 1,
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
edge_motion(mouse_movement *movement, touch_event *event, bool validStart)
|
||||
{
|
||||
int32 xdelta = 0;
|
||||
int32 ydelta = 0;
|
||||
|
||||
if (event->xPosition < SYN_AREA_START_X + SYN_EDGE_MOTION_WIDTH)
|
||||
xdelta = -SYN_EDGE_MOTION_SPEED;
|
||||
else if (event->xPosition > SYN_AREA_END_X - SYN_EDGE_MOTION_WIDTH)
|
||||
xdelta = SYN_EDGE_MOTION_SPEED;
|
||||
|
||||
if (event->yPosition < SYN_AREA_START_Y + SYN_EDGE_MOTION_WIDTH)
|
||||
ydelta = -SYN_EDGE_MOTION_SPEED;
|
||||
else if (event->yPosition > SYN_AREA_END_Y - SYN_EDGE_MOTION_WIDTH)
|
||||
ydelta = SYN_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(synaptics_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(synaptics_cookie *cookie, touch_event *event,
|
||||
mouse_movement *movement)
|
||||
{
|
||||
uint32 buttons = event->buttons;
|
||||
|
||||
TRACE("SYNAPTICS: no touch event\n");
|
||||
|
||||
cookie->scrolling_started = false;
|
||||
cookie->movement_started = false;
|
||||
|
||||
if (cookie->tapdrag_started
|
||||
&& (movement->timestamp - cookie->tap_time) < SYN_TAP_TIMEOUT) {
|
||||
buttons = 0x01;
|
||||
}
|
||||
|
||||
// if the movement stopped switch off the tap drag when timeout is expired
|
||||
if ((movement->timestamp - cookie->tap_time) > SYN_TAP_TIMEOUT) {
|
||||
cookie->tapdrag_started = false;
|
||||
cookie->valid_edge_motion = false;
|
||||
TRACE("SYNAPTICS: 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("SYNAPTICS: tap gesture\n");
|
||||
cookie->tap_clicks++;
|
||||
|
||||
if (cookie->tap_clicks > 1) {
|
||||
TRACE("SYNAPTICS: 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(synaptics_cookie *cookie, touch_event *event,
|
||||
mouse_movement *movement)
|
||||
{
|
||||
touchpad_settings *settings = &cookie->settings;
|
||||
bool isStartOfMovement = false;
|
||||
float pressure = 0;
|
||||
|
||||
TRACE("SYNAPTICS: 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("SYNAPTICS: tap drag\n");
|
||||
} else {
|
||||
TRACE("SYNAPTICS: 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 - 100);
|
||||
if (!cookie->tap_started
|
||||
&& isStartOfMovement
|
||||
&& settings->tapgesture_sensibility > 0.
|
||||
&& settings->tapgesture_sensibility > (20 - pressure)) {
|
||||
TRACE("SYNAPTICS: 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(synaptics_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 ((SYN_AREA_END_X - SYN_AREA_WIDTH_X * settings->scroll_rightrange
|
||||
< event->xPosition && !cookie->movement_started
|
||||
&& settings->scroll_rightrange > 0.000001)
|
||||
|| settings->scroll_rightrange > 0.999999) {
|
||||
isSideScrollingV = true;
|
||||
}
|
||||
if ((SYN_AREA_START_Y + SYN_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("SYNAPTICS: 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(synaptics_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) > SYN_TAP_TIMEOUT) {
|
||||
TRACE("SYNAPTICS: tap gesture timed out\n");
|
||||
cookie->tap_started = false;
|
||||
if (!cookie->double_click
|
||||
|| (movement->timestamp - cookie->tap_time) > 2 * SYN_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;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
get_synaptics_movment(synaptics_cookie *cookie, mouse_movement *movement)
|
||||
{
|
||||
status_t status;
|
||||
touch_event event;
|
||||
uint8 event_buffer[PS2_MAX_PACKET_SIZE];
|
||||
uint8 wValue0, wValue1, wValue2, wValue3, wValue;
|
||||
uint32 val32;
|
||||
uint32 xTwelfBit, yTwelfBit;
|
||||
|
||||
status = acquire_sem_etc(cookie->synaptics_sem, 1, B_CAN_INTERRUPT, 0);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
if (!cookie->dev->active) {
|
||||
TRACE("SYNAPTICS: read_event: Error device no longer active\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (packet_buffer_read(cookie->synaptics_ring_buffer, event_buffer,
|
||||
cookie->dev->packet_size) != cookie->dev->packet_size) {
|
||||
TRACE("SYNAPTICS: error copying buffer\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
event.buttons = event_buffer[0] & 3;
|
||||
event.zPressure = event_buffer[2];
|
||||
|
||||
if (sTouchpadInfo.capExtended) {
|
||||
wValue0 = event_buffer[3] >> 2 & 1;
|
||||
wValue1 = event_buffer[0] >> 2 & 1;
|
||||
wValue2 = event_buffer[0] >> 4 & 1;
|
||||
wValue3 = event_buffer[0] >> 5 & 1;
|
||||
|
||||
wValue = wValue0;
|
||||
wValue = wValue | (wValue1 << 1);
|
||||
wValue = wValue | (wValue2 << 2);
|
||||
wValue = wValue | (wValue3 << 3);
|
||||
|
||||
event.wValue = wValue;
|
||||
event.gesture = false;
|
||||
} else {
|
||||
bool finger = event_buffer[0] >> 5 & 1;
|
||||
if (finger) {
|
||||
// finger with normal width
|
||||
event.wValue = 4;
|
||||
}
|
||||
event.gesture = event_buffer[0] >> 2 & 1;
|
||||
}
|
||||
|
||||
event.xPosition = event_buffer[4];
|
||||
event.yPosition = event_buffer[5];
|
||||
|
||||
val32 = event_buffer[1] & 0x0F;
|
||||
event.xPosition += val32 << 8;
|
||||
val32 = event_buffer[1] >> 4 & 0x0F;
|
||||
event.yPosition += val32 << 8;
|
||||
|
||||
xTwelfBit = event_buffer[3] >> 4 & 1;
|
||||
event.xPosition += xTwelfBit << 12;
|
||||
yTwelfBit = event_buffer[3] >> 5 & 1;
|
||||
event.yPosition += yTwelfBit << 12;
|
||||
|
||||
status = event_to_movement(cookie, &event, movement);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
query_capability(ps2_dev *dev)
|
||||
{
|
||||
uint8 val[3];
|
||||
send_touchpad_arg(dev, 0x02);
|
||||
ps2_dev_command(dev, 0xE9, NULL, 0, val, 3);
|
||||
|
||||
sTouchpadInfo.capExtended = val[0] >> 7 & 1;
|
||||
TRACE("SYNAPTICS: extended mode %2x\n", val[0] >> 7 & 1);
|
||||
TRACE("SYNAPTICS: sleep mode %2x\n", val[2] >> 4 & 1);
|
||||
sTouchpadInfo.capSleep = val[2] >> 4 & 1;
|
||||
TRACE("SYNAPTICS: four buttons %2x\n", val[2] >> 3 & 1);
|
||||
sTouchpadInfo.capFourButtons = val[2] >> 3 & 1;
|
||||
TRACE("SYNAPTICS: multi finger %2x\n", val[2] >> 1 & 1);
|
||||
sTouchpadInfo.capMultiFinger = val[2] >> 1 & 1;
|
||||
TRACE("SYNAPTICS: palm detection %2x\n", val[2] & 1);
|
||||
sTouchpadInfo.capPalmDetection = val[2] & 1;
|
||||
TRACE("SYNAPTICS: pass through %2x\n", val[2] >> 7 & 1);
|
||||
sTouchpadInfo.capPassThrough = val[2] >> 7 & 1;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - exported functions
|
||||
|
||||
|
||||
status_t
|
||||
synaptics_pass_through_set_packet_size(ps2_dev *dev, uint8 size)
|
||||
{
|
||||
synaptics_cookie *synapticsCookie = dev->parent_dev->cookie;
|
||||
|
||||
status_t status = ps2_dev_command(dev->parent_dev, PS2_CMD_DISABLE, NULL,
|
||||
0, NULL, 0);
|
||||
if (status < B_OK) {
|
||||
INFO("SYNAPTICS: cannot disable touchpad %s\n", dev->parent_dev->name);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
synapticsCookie->packet_index = 0;
|
||||
|
||||
if (size == 4)
|
||||
synapticsCookie->mode |= SYN_FOUR_BYTE_CHILD;
|
||||
else
|
||||
synapticsCookie->mode &= ~SYN_FOUR_BYTE_CHILD;
|
||||
|
||||
set_touchpad_mode(dev->parent_dev, synapticsCookie->mode);
|
||||
|
||||
status = ps2_dev_command(dev->parent_dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0);
|
||||
if (status < B_OK) {
|
||||
INFO("SYNAPTICS: cannot enable touchpad %s\n", dev->parent_dev->name);
|
||||
return B_ERROR;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
passthrough_command(ps2_dev *dev, uint8 cmd, const uint8 *out, int outCount,
|
||||
uint8 *in, int inCount, bigtime_t timeout)
|
||||
{
|
||||
status_t status;
|
||||
uint8 passThroughCmd = SYN_PASSTHROUGH_CMD;
|
||||
uint8 val;
|
||||
uint32 passThroughInCount = (inCount + 1) * 6;
|
||||
uint8 passThroughIn[passThroughInCount];
|
||||
int8 i;
|
||||
|
||||
TRACE("SYNAPTICS: passthrough command 0x%x\n", cmd);
|
||||
|
||||
status = ps2_dev_command(dev->parent_dev, PS2_CMD_DISABLE, NULL, 0,
|
||||
NULL, 0);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
for (i = -1; i < outCount; i++) {
|
||||
if (i == -1)
|
||||
val = cmd;
|
||||
else
|
||||
val = out[i];
|
||||
status = send_touchpad_arg_timeout(dev->parent_dev, val, timeout);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
if (i != outCount -1) {
|
||||
status = ps2_dev_command_timeout(dev->parent_dev,
|
||||
PS2_CMD_SET_SAMPLE_RATE, &passThroughCmd, 1, NULL, 0, timeout);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
}
|
||||
}
|
||||
status = ps2_dev_command_timeout(dev->parent_dev, PS2_CMD_SET_SAMPLE_RATE,
|
||||
&passThroughCmd, 1, passThroughIn, passThroughInCount, timeout);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
for (i = 0; i < inCount + 1; i++) {
|
||||
uint8 *inPointer = &passThroughIn[i * 6];
|
||||
if (!IS_SYN_PT_PACKAGE(inPointer)) {
|
||||
TRACE("SYNAPTICS: not a pass throught package\n");
|
||||
return B_OK;
|
||||
}
|
||||
if (i == 0)
|
||||
continue;
|
||||
|
||||
in[i - 1] = passThroughIn[i * 6 + 1];
|
||||
}
|
||||
|
||||
status = ps2_dev_command(dev->parent_dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
probe_synaptics(ps2_dev *dev)
|
||||
{
|
||||
uint8 val[3];
|
||||
uint8 deviceId;
|
||||
status_t status;
|
||||
TRACE("SYNAPTICS: probe\n");
|
||||
|
||||
status = send_touchpad_arg(dev, 0x00);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
status = ps2_dev_command(dev, 0xE9, NULL, 0, val, 3);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
sTouchpadInfo.minorVersion = val[0];
|
||||
deviceId = val[1];
|
||||
if (deviceId != SYN_TOUCHPAD) {
|
||||
TRACE("SYNAPTICS: not found\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
TRACE("SYNAPTICS: Touchpad found id:l %2x\n", deviceId);
|
||||
sTouchpadInfo.majorVersion = val[2] & 0x0F;
|
||||
TRACE("SYNAPTICS: version %d.%d\n", sTouchpadInfo.majorVersion,
|
||||
sTouchpadInfo.minorVersion);
|
||||
// version >= 4.0?
|
||||
if (sTouchpadInfo.minorVersion <= 2
|
||||
&& sTouchpadInfo.majorVersion <= 3) {
|
||||
TRACE("SYNAPTICS: too old touchpad not supported\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
dev->name = kSynapticsPath[dev->idx];
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Device functions
|
||||
|
||||
|
||||
status_t
|
||||
synaptics_open(const char *name, uint32 flags, void **_cookie)
|
||||
{
|
||||
status_t status;
|
||||
synaptics_cookie *cookie;
|
||||
ps2_dev *dev;
|
||||
int i;
|
||||
|
||||
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 = (synaptics_cookie*)malloc(sizeof(synaptics_cookie));
|
||||
if (cookie == NULL)
|
||||
goto err1;
|
||||
|
||||
*_cookie = cookie;
|
||||
memset(cookie, 0, sizeof(synaptics_cookie));
|
||||
|
||||
cookie->dev = dev;
|
||||
dev->cookie = cookie;
|
||||
dev->disconnect = &synaptics_disconnect;
|
||||
dev->handle_int = &synaptics_handle_int;
|
||||
|
||||
default_settings(&cookie->settings);
|
||||
|
||||
cookie->movement_maker.speed = 1;
|
||||
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_SYNAPTICS;
|
||||
|
||||
cookie->synaptics_ring_buffer
|
||||
= create_packet_buffer(SYNAPTICS_HISTORY_SIZE * dev->packet_size);
|
||||
if (cookie->synaptics_ring_buffer == NULL) {
|
||||
TRACE("ps2: 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->synaptics_sem = create_sem(0, "ps2_synaptics_sem");
|
||||
if (cookie->synaptics_sem < 0) {
|
||||
TRACE("SYNAPTICS: failed creating semaphore!\n");
|
||||
goto err3;
|
||||
}
|
||||
query_capability(dev);
|
||||
|
||||
// create pass through dev
|
||||
if (sTouchpadInfo.capPassThrough) {
|
||||
TRACE("SYNAPTICS: pass through detected\n");
|
||||
sPassthroughDevice->parent_dev = dev;
|
||||
sPassthroughDevice->idx = dev->idx;
|
||||
ps2_service_notify_device_added(sPassthroughDevice);
|
||||
}
|
||||
|
||||
// Set Mode
|
||||
if (sTouchpadInfo.capExtended)
|
||||
cookie->mode = SYN_ABSOLUTE_W_MODE;
|
||||
else
|
||||
cookie->mode = SYN_ABSOLUTE_MODE;
|
||||
|
||||
status = set_touchpad_mode(dev, cookie->mode);
|
||||
if (status < B_OK) {
|
||||
INFO("SYNAPTICS: cannot set mode %s\n", name);
|
||||
goto err4;
|
||||
}
|
||||
|
||||
status = ps2_dev_command(dev, PS2_CMD_ENABLE, NULL, 0, NULL, 0);
|
||||
if (status < B_OK) {
|
||||
INFO("SYNAPTICS: cannot enable touchpad %s\n", name);
|
||||
goto err4;
|
||||
}
|
||||
|
||||
atomic_or(&dev->flags, PS2_FLAG_ENABLED);
|
||||
|
||||
TRACE("SYNAPTICS: open %s success\n", name);
|
||||
return B_OK;
|
||||
|
||||
err4:
|
||||
delete_sem(cookie->synaptics_sem);
|
||||
err3:
|
||||
delete_packet_buffer(cookie->synaptics_ring_buffer);
|
||||
err2:
|
||||
free(cookie);
|
||||
err1:
|
||||
atomic_and(&dev->flags, ~PS2_FLAG_OPEN);
|
||||
|
||||
TRACE("SYNAPTICS: synaptics_open %s failed\n", name);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
synaptics_close(void *_cookie)
|
||||
{
|
||||
status_t status;
|
||||
synaptics_cookie *cookie = _cookie;
|
||||
|
||||
ps2_dev_command_timeout(cookie->dev, PS2_CMD_DISABLE, NULL, 0, NULL, 0,
|
||||
150000);
|
||||
|
||||
delete_packet_buffer(cookie->synaptics_ring_buffer);
|
||||
delete_sem(cookie->synaptics_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;
|
||||
}
|
||||
|
||||
if (sTouchpadInfo.capPassThrough)
|
||||
ps2_service_notify_device_removed(sPassthroughDevice);
|
||||
|
||||
TRACE("SYNAPTICS: close %s done\n", cookie->dev->name);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
synaptics_freecookie(void *_cookie)
|
||||
{
|
||||
free(_cookie);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
synaptics_read(void *cookie, off_t pos, void *buffer, size_t *_length)
|
||||
{
|
||||
*_length = 0;
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
synaptics_write(void *cookie, off_t pos, const void *buffer, size_t *_length)
|
||||
{
|
||||
*_length = 0;
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
synaptics_ioctl(void *_cookie, uint32 op, void *buffer, size_t length)
|
||||
{
|
||||
synaptics_cookie *cookie = _cookie;
|
||||
mouse_movement movement;
|
||||
status_t status;
|
||||
|
||||
switch (op) {
|
||||
case MS_READ:
|
||||
TRACE("SYNAPTICS: MS_READ get event\n");
|
||||
if ((status = get_synaptics_movment(cookie, &movement)) != B_OK)
|
||||
return status;
|
||||
return user_memcpy(buffer, &movement, sizeof(movement));
|
||||
|
||||
case MS_IS_TOUCHPAD:
|
||||
TRACE("SYNAPTICS: MS_IS_TOUCHPAD\n");
|
||||
return B_OK;
|
||||
|
||||
case MS_SET_TOUCHPAD_SETTINGS:
|
||||
TRACE("SYNAPTICS: 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("SYNAPTICS: ioctl MS_SETCLICK (set click speed)\n");
|
||||
return user_memcpy(&cookie->click_speed, buffer, sizeof(bigtime_t));
|
||||
|
||||
default:
|
||||
TRACE("SYNAPTICS: unknown opcode: %ld\n", op);
|
||||
return B_DEV_INVALID_IOCTL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
synaptics_handle_int(ps2_dev *dev)
|
||||
{
|
||||
synaptics_cookie *cookie = dev->cookie;
|
||||
uint8 val;
|
||||
|
||||
val = cookie->dev->history[0].data;
|
||||
|
||||
if ((cookie->packet_index == 0 || cookie->packet_index == 3)
|
||||
&& (val & 8) != 0) {
|
||||
INFO("SYNAPTICS: bad mouse data, trying resync\n");
|
||||
cookie->packet_index = 0;
|
||||
return B_UNHANDLED_INTERRUPT;
|
||||
}
|
||||
if (cookie->packet_index == 0 && val >> 6 != 0x02) {
|
||||
TRACE("SYNAPTICS: first package begins not with bit 1, 0\n");
|
||||
return B_UNHANDLED_INTERRUPT;
|
||||
}
|
||||
if (cookie->packet_index == 3 && val >> 6 != 0x03) {
|
||||
TRACE("SYNAPTICS: third package begins not with bit 1, 1\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;
|
||||
|
||||
// check if package is a pass through package if true pass it
|
||||
// too the pass through interrupt handle
|
||||
if (sPassthroughDevice->active
|
||||
&& sPassthroughDevice->handle_int != NULL
|
||||
&& IS_SYN_PT_PACKAGE(cookie->packet_buffer)) {
|
||||
status_t status;
|
||||
|
||||
sPassthroughDevice->history[0].data = cookie->packet_buffer[1];
|
||||
sPassthroughDevice->handle_int(sPassthroughDevice);
|
||||
sPassthroughDevice->history[0].data = cookie->packet_buffer[4];
|
||||
sPassthroughDevice->handle_int(sPassthroughDevice);
|
||||
sPassthroughDevice->history[0].data = cookie->packet_buffer[5];
|
||||
status = sPassthroughDevice->handle_int(sPassthroughDevice);
|
||||
|
||||
if (cookie->dev->packet_size == 4) {
|
||||
sPassthroughDevice->history[0].data = cookie->packet_buffer[2];
|
||||
status = sPassthroughDevice->handle_int(sPassthroughDevice);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
if (packet_buffer_write(cookie->synaptics_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->synaptics_sem, 1, B_DO_NOT_RESCHEDULE);
|
||||
|
||||
return B_INVOKE_SCHEDULER;
|
||||
}
|
||||
|
||||
return B_HANDLED_INTERRUPT;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
synaptics_disconnect(ps2_dev *dev)
|
||||
{
|
||||
synaptics_cookie *cookie = dev->cookie;
|
||||
// the mouse device might not be opened at this point
|
||||
INFO("SYNAPTICS: synaptics_disconnect %s\n", dev->name);
|
||||
if ((dev->flags & PS2_FLAG_OPEN) != 0)
|
||||
release_sem(cookie->synaptics_sem);
|
||||
}
|
||||
|
||||
|
||||
device_hooks gSynapticsDeviceHooks = {
|
||||
synaptics_open,
|
||||
synaptics_close,
|
||||
synaptics_freecookie,
|
||||
synaptics_ioctl,
|
||||
synaptics_read,
|
||||
synaptics_write,
|
||||
};
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2009-2010, Haiku, Inc.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Clemens Zeidler (haiku@Clemens-Zeidler.de)
|
||||
*/
|
||||
|
||||
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <keyboard_mouse_driver.h>
|
||||
|
||||
#include "ps2_trackpoint.h"
|
||||
|
||||
|
||||
const char* kTrackpointPath[4] = {
|
||||
"input/mouse/ps2/ibm_trackpoint_0",
|
||||
"input/mouse/ps2/ibm_trackpoint_1",
|
||||
"input/mouse/ps2/ibm_trackpoint_2",
|
||||
"input/mouse/ps2/ibm_trackpoint_3"
|
||||
};
|
||||
|
||||
|
||||
status_t
|
||||
probe_trackpoint(ps2_dev* dev)
|
||||
{
|
||||
uint8 val[2];
|
||||
|
||||
TRACE("TRACKPOINT: probe\n");
|
||||
ps2_dev_command(dev, 0xE1, NULL, 0, val, 2);
|
||||
|
||||
if (val[0] != 0x01) {
|
||||
TRACE("TRACKPOINT: not found\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
dev->name = kTrackpointPath[dev->idx];
|
||||
dev->packet_size = 3;
|
||||
TRACE("TRACKPOINT: version 0x%x found\n", val[1]);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
Reference in New Issue
Block a user