[haiku-commits] r41124 - haiku/trunk/src/add-ons/kernel/bus_managers/ps2

  • From: clemens.zeidler@xxxxxxxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sun, 27 Mar 2011 10:53:57 +0200 (CEST)

Author: czeidler
Date: 2011-03-27 10:53:57 +0200 (Sun, 27 Mar 2011)
New Revision: 41124
Changeset: https://dev.haiku-os.org/changeset/41124

Added:
   haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_alps.c
   haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_alps.h
Modified:
   haiku/trunk/src/add-ons/kernel/bus_managers/ps2/Jamfile
   haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_defs.h
   haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_dev.c
   haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.h
Log:
Work in progress on a ALPS touchpad driver. The driver is roughly working but 
disabled at the moment. Its 
more or less a copy of the synaptics driver. Next step is to refactor the 
movement generation and share the 
code with the synaptics driver.



Modified: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/Jamfile
===================================================================
--- haiku/trunk/src/add-ons/kernel/bus_managers/ps2/Jamfile     2011-03-27 
06:12:47 UTC (rev 41123)
+++ haiku/trunk/src/add-ons/kernel/bus_managers/ps2/Jamfile     2011-03-27 
08:53:57 UTC (rev 41124)
@@ -5,6 +5,7 @@
 
 KernelAddon ps2 :
        packet_buffer.cpp
+       ps2_alps.c
        ps2_common.c
        ps2_dev.c
        ps2_keyboard.cpp

Added: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_alps.c
===================================================================
--- haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_alps.c                  
        (rev 0)
+++ haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_alps.c  2011-03-27 
08:53:57 UTC (rev 41124)
@@ -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           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,
+};
+

Added: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_alps.h
===================================================================
--- haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_alps.h                  
        (rev 0)
+++ haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_alps.h  2011-03-27 
08:53:57 UTC (rev 41124)
@@ -0,0 +1,56 @@
+#ifndef ALPS_H
+#define ALPS_H
+
+#include <KernelExport.h>
+
+#include <touchpad_settings.h>
+
+#include "movement_maker.h"
+#include "packet_buffer.h"
+#include "ps2_dev.h"
+
+
+typedef struct {
+       ps2_dev*                        dev;
+
+       sem_id                          sem;
+       packet_buffer*          ring_buffer;
+       size_t                          packet_index;
+       uint8                           packet_buffer[PS2_PACKET_ALPS];
+       uint8                           mode;
+
+       movement_maker          movement_maker;
+       bool                            movement_started;
+       bool                            scrolling_started;
+       bool                            tap_started;
+       bigtime_t                       tap_time;
+       int32                           tap_delta_x;
+       int32                           tap_delta_y;
+       int32                           tap_clicks;
+       bool                            tapdrag_started;
+       bool                            valid_edge_motion;
+       bool                            double_click;
+
+       bigtime_t                       click_last_time;
+       bigtime_t                       click_speed;
+       int32                           click_count;
+       uint32                          buttons_state;
+
+       touchpad_settings       settings;
+} alps_cookie;
+
+
+status_t probe_alps(ps2_dev *dev);
+
+status_t alps_open(const char *name, uint32 flags, void **_cookie);
+status_t alps_close(void *_cookie);
+status_t alps_freecookie(void *_cookie);
+status_t alps_ioctl(void *_cookie, uint32 op, void *buffer, size_t length);
+
+int32 alps_handle_int(ps2_dev *dev);
+void alps_disconnect(ps2_dev *dev);
+
+device_hooks gALPSDeviceHooks;
+
+
+#endif /* ALPS_H */

Modified: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_defs.h
===================================================================
--- haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_defs.h  2011-03-27 
06:12:47 UTC (rev 41123)
+++ haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_defs.h  2011-03-27 
08:53:57 UTC (rev 41124)
@@ -77,6 +77,7 @@
 #define PS2_PACKET_STANDARD                            3
 #define PS2_PACKET_INTELLIMOUSE                        4
 #define PS2_PACKET_SYNAPTICS                   6
+#define PS2_PACKET_ALPS                                        6
 #define PS2_MAX_PACKET_SIZE                            6
        // Should be equal to the biggest packet size
 

Modified: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_dev.c
===================================================================
--- haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_dev.c   2011-03-27 
06:12:47 UTC (rev 41123)
+++ haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_dev.c   2011-03-27 
08:53:57 UTC (rev 41124)
@@ -13,6 +13,7 @@
 #include "ps2_dev.h"
 #include "ps2_service.h"
 
+#include "ps2_alps.h"
 #include "ps2_standard_mouse.h"
 #include "ps2_synaptics.h"
 #include "ps2_trackpoint.h"
@@ -115,6 +116,12 @@
                goto dev_found;
        }
 
+       status = probe_alps(dev);
+       if (status == B_OK) {
+               *hooks = &gALPSDeviceHooks;
+               goto dev_found;
+       }
+
        // reset the mouse for the case that the previous probes leaf the mouse 
in
        // a undefined state
        status = ps2_reset_mouse(dev);

Modified: haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.h
===================================================================
--- haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.h     
2011-03-27 06:12:47 UTC (rev 41123)
+++ haiku/trunk/src/add-ons/kernel/bus_managers/ps2/ps2_synaptics.h     
2011-03-27 08:53:57 UTC (rev 41124)
@@ -11,7 +11,6 @@
 
 #include <KernelExport.h>
 
-#include <keyboard_mouse_driver.h>
 #include <touchpad_settings.h>
 
 #include "movement_maker.h"


Other related posts:

  • » [haiku-commits] r41124 - haiku/trunk/src/add-ons/kernel/bus_managers/ps2 - clemens . zeidler