Author: czeidler Date: 2011-03-28 10:18:31 +0200 (Mon, 28 Mar 2011) New Revision: 41134 Changeset: https://dev.haiku-os.org/changeset/41134 Added: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/movement_maker.cpp haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_alps.cpp haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_common.cpp haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_dev.cpp haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_module.cpp haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_standard_mouse.cpp haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.cpp haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_trackpoint.cpp Removed: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/movement_maker.c haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_alps.c haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_common.c haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_dev.c haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_module.c haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_standard_mouse.c haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.c haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_trackpoint.c Modified: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/Jamfile haiku/trunk/src/add-ons/kernel/bus_managers/ps2/movement_maker.h haiku/trunk/src/add-ons/kernel/bus_managers/ps2/packet_buffer.cpp haiku/trunk/src/add-ons/kernel/bus_managers/ps2/packet_buffer.h haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_alps.h haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_standard_mouse.h haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.h Log: Reapply the ps2 cpp patch. Thanks Axel. Modified: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/Jamfile =================================================================== --- haiku/trunk/src/add-ons/kernel/bus_managers/ps2/Jamfile 2011-03-28 08:10:26 UTC (rev 41133) +++ haiku/trunk/src/add-ons/kernel/bus_managers/ps2/Jamfile 2011-03-28 08:18:31 UTC (rev 41134) @@ -5,14 +5,14 @@ KernelAddon ps2 : packet_buffer.cpp - ps2_alps.c - ps2_common.c - ps2_dev.c + ps2_alps.cpp + ps2_common.cpp + ps2_dev.cpp ps2_keyboard.cpp - ps2_module.c - ps2_standard_mouse.c - ps2_synaptics.c - ps2_trackpoint.c + ps2_module.cpp + ps2_standard_mouse.cpp + ps2_synaptics.cpp + ps2_trackpoint.cpp ps2_service.cpp - movement_maker.c + movement_maker.cpp ; Copied: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/movement_maker.cpp (from rev 41133, haiku/trunk/src/add-ons/kernel/bus_managers/ps2/movement_maker.c) =================================================================== --- haiku/trunk/src/add-ons/kernel/bus_managers/ps2/movement_maker.cpp (rev 0) +++ haiku/trunk/src/add-ons/kernel/bus_managers/ps2/movement_maker.cpp 2011-03-28 08:18:31 UTC (rev 41134) @@ -0,0 +1,314 @@ +#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; +} + Modified: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/movement_maker.h =================================================================== --- haiku/trunk/src/add-ons/kernel/bus_managers/ps2/movement_maker.h 2011-03-28 08:10:26 UTC (rev 41133) +++ haiku/trunk/src/add-ons/kernel/bus_managers/ps2/movement_maker.h 2011-03-28 08:18:31 UTC (rev 41134) @@ -30,7 +30,6 @@ } movement_maker; - void get_raw_movement(movement_maker *move, uint32 posX, uint32 posY); void compute_acceleration(movement_maker *move, int8 accel_factor); void get_movement(movement_maker *move, uint32 posX, uint32 posY); Modified: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/packet_buffer.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/bus_managers/ps2/packet_buffer.cpp 2011-03-28 08:10:26 UTC (rev 41133) +++ haiku/trunk/src/add-ons/kernel/bus_managers/ps2/packet_buffer.cpp 2011-03-28 08:18:31 UTC (rev 41134) @@ -6,32 +6,16 @@ #include "packet_buffer.h" -#include <KernelExport.h> #include <util/ring_buffer.h> #include <stdlib.h> #include <string.h> -/** The idea behind this packet buffer is to have multi-threading safe - * implementation that can be used in interrupts on top of the - * ring_buffer implementation provided by the kernel. - * It uses a spinlock for synchronization. - * - * IOW if you don't have such high restrictions in your environment, - * you better don't want to use it at all. - */ - -struct packet_buffer { - struct ring_buffer *buffer; - spinlock lock; -}; - - -struct packet_buffer * +packet_buffer* create_packet_buffer(size_t size) { - struct packet_buffer *buffer + packet_buffer* buffer = (packet_buffer *)malloc(sizeof(packet_buffer)); if (buffer == NULL) return NULL; @@ -48,7 +32,7 @@ void -delete_packet_buffer(struct packet_buffer *buffer) +delete_packet_buffer(packet_buffer* buffer) { delete_ring_buffer(buffer->buffer); free(buffer); @@ -56,7 +40,7 @@ void -packet_buffer_clear(struct packet_buffer *buffer) +packet_buffer_clear(packet_buffer* buffer) { cpu_status state = disable_interrupts(); acquire_spinlock(&buffer->lock); @@ -69,7 +53,7 @@ size_t -packet_buffer_readable(struct packet_buffer *buffer) +packet_buffer_readable(packet_buffer* buffer) { cpu_status state = disable_interrupts(); acquire_spinlock(&buffer->lock); @@ -84,7 +68,7 @@ size_t -packet_buffer_writable(struct packet_buffer *buffer) +packet_buffer_writable(packet_buffer* buffer) { cpu_status state = disable_interrupts(); acquire_spinlock(&buffer->lock); @@ -99,7 +83,7 @@ void -packet_buffer_flush(struct packet_buffer *buffer, size_t length) +packet_buffer_flush(packet_buffer* buffer, size_t length) { cpu_status state = disable_interrupts(); acquire_spinlock(&buffer->lock); @@ -112,7 +96,7 @@ size_t -packet_buffer_read(struct packet_buffer *buffer, uint8 *data, size_t length) +packet_buffer_read(packet_buffer* buffer, uint8 *data, size_t length) { cpu_status state = disable_interrupts(); acquire_spinlock(&buffer->lock); @@ -127,7 +111,7 @@ size_t -packet_buffer_write(struct packet_buffer *buffer, const uint8 *data, +packet_buffer_write(packet_buffer* buffer, const uint8 *data, size_t length) { cpu_status state = disable_interrupts(); Modified: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/packet_buffer.h =================================================================== --- haiku/trunk/src/add-ons/kernel/bus_managers/ps2/packet_buffer.h 2011-03-28 08:10:26 UTC (rev 41133) +++ haiku/trunk/src/add-ons/kernel/bus_managers/ps2/packet_buffer.h 2011-03-28 08:18:31 UTC (rev 41134) @@ -6,30 +6,37 @@ #define PACKET_BUFFER_H +#include <KernelExport.h> #include <OS.h> -struct packet_buffer; -typedef struct packet_buffer packet_buffer; +struct ring_buffer; -#ifdef __cplusplus -extern "C" { -#endif -struct packet_buffer *create_packet_buffer(size_t size); -void delete_packet_buffer(struct packet_buffer *buffer); +/** The idea behind this packet buffer is to have multi-threading safe + * implementation that can be used in interrupts on top of the + * ring_buffer implementation provided by the kernel. + * It uses a spinlock for synchronization. + * + * IOW if you don't have such high restrictions in your environment, + * you better don't want to use it at all. + */ +struct packet_buffer { + struct ring_buffer* buffer; + spinlock lock; +}; -void packet_buffer_clear(struct packet_buffer *buffer); -size_t packet_buffer_readable(struct packet_buffer *buffer); + +struct packet_buffer* create_packet_buffer(size_t size); +void delete_packet_buffer(struct packet_buffer* buffer); + +void packet_buffer_clear(struct packet_buffer* buffer); +size_t packet_buffer_readable(struct packet_buffer* buffer); size_t packet_buffer_writable(struct packet_buffer *buffer); -void packet_buffer_flush(struct packet_buffer *buffer, size_t bytes); -size_t packet_buffer_read(struct packet_buffer *buffer, uint8 *data, size_t +void packet_buffer_flush(struct packet_buffer* buffer, size_t bytes); +size_t packet_buffer_read(struct packet_buffer* buffer, uint8* data, size_t length); -size_t packet_buffer_write(struct packet_buffer *buffer, const uint8 *data, +size_t packet_buffer_write(struct packet_buffer* buffer, const uint8* data, size_t length); -#ifdef __cplusplus -} -#endif - #endif /* PACKET_BUFFER_H */ Copied: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_alps.cpp (from rev 41133, haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_alps.c) =================================================================== --- haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_alps.cpp (rev 0) +++ haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_alps.cpp 2011-03-28 08:18:31 UTC (rev 41134) @@ -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@xxxxxxxxxxxxxxxxxx) + */ + + +#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 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->movementMaker); + } + + get_movement(&cookie->movementMaker, event->xPosition, event->yPosition); + + movement->xdelta = cookie->movementMaker.xDelta; + movement->ydelta = cookie->movementMaker.yDelta; + + // tap gesture + cookie->tap_delta_x += cookie->movementMaker.xDelta; + cookie->tap_delta_y += cookie->movementMaker.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->movementMaker); + } + get_scrolling(&cookie->movementMaker, event->xPosition, + event->yPosition); + movement->wheel_ydelta = cookie->movementMaker.yDelta; + movement->wheel_xdelta = cookie->movementMaker.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 uint32 minX = 50000; +static uint32 minY = 50000; +static uint32 maxX = 0; +static uint32 maxY = 0; +static uint32 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); + [... truncated: 2878 lines follow ...]