[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Gnewsense-dev] gNewSense-MIPS, Yeelong and SiliconMotion video driv
From: |
Hongbing Hu |
Subject: |
Re: [Gnewsense-dev] gNewSense-MIPS, Yeelong and SiliconMotion video driver |
Date: |
Fri, 12 Mar 2010 11:22:53 +0800 |
User-agent: |
Mozilla-Thunderbird 2.0.0.9 (X11/20080110) |
It gives these error messages:
/usr/lib/pm-utils/sleep.d/99yeelong thaw: system type :
lemote-yeeloong-2f-8.9inches
/usr/lib/pm-utils/sleep.d/99yeelong: line 56:
/sys/class/usb_host/usb_host2/companion: No such file or directory
/usr/lib/pm-utils/sleep.d/99yeelong: line 57:
/sys/class/usb_host/usb_host1/companion: No such file or directory
/usr/lib/pm-utils/sleep.d/99yeelong: line 60:
/sys/class/usb_host/usb_host2/companion: No such file or directory
/usr/lib/pm-utils/sleep.d/99yeelong: line 61:
/sys/class/usb_host/usb_host1/companion: No such file or directory
Ehci driver(drivers/usb/host/ehci-hub.c), which kernel verison is
2.6.27.1, will export these sysfs.
I don't verify another version.
FATAL: Module r8187 not found.
r8187 is wifi module name.
it may be r8187b in your system.
/usr/lib/pm-utils/sleep.d/99yeelong: line 70:
/sys/bus/platform/devices/i8042/serio1/flags: No such file or directory
The sys path is created by sentelic.c (touchpad driver)
Throught it,we can control the touchpad, such as speed, enable or disable.
The standard kernel may be not export these sysfile.
Attachment is the patch about it.
down: error fetching interface information: Device not found
up: error fetching interface information: Device not found
/usr/lib/pm-utils/sleep.d/99yeelong: line 73: echo: write error: Invalid
argument
I'am sorry,it's my fault.
I have mailed an patch to fix it.
Thanks for karl's work.
B.R.
/usr/lib/pm-utils/sleep.d/99yeelong: line 74: /etc/init.d/NetworkManager: No
such file or directory
--
---------------------------------------------------------
HuHongbing (Software Department)
Tel : 0512-52308631
E-mail : address@hidden
MSN : address@hidden
WEB : www.lemote.com
JiangSu Lemote Corp. Ltd.
MengLan, Yushan, Changshu, JiangSu Province, China
---------------------------------------------------------
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index d4d2025..dd73db8 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -18,7 +18,7 @@ obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o
obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o
obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o
-psmouse-objs := psmouse-base.o synaptics.o
+psmouse-objs := psmouse-base.o synaptics.o sentelic.o
psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o
psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) += logips2pp.o
diff --git a/drivers/input/mouse/psmouse-base.c
b/drivers/input/mouse/psmouse-base.c
index f5a6be1..32b26f8 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -28,6 +28,7 @@
#include "lifebook.h"
#include "trackpoint.h"
#include "touchkit_ps2.h"
+#include "sentelic.h"
#define DRIVER_DESC "PS/2 mouse driver"
@@ -630,6 +631,20 @@ static int psmouse_extensions(struct psmouse *psmouse,
}
}
+/*
+ * Try Finger Sensing Pad
+ */
+ if (max_proto > PSMOUSE_IMEX) {
+ if (fsp_detect(psmouse, set_properties) == 0) {
+ if (!set_properties || fsp_init(psmouse) == 0)
+ return PSMOUSE_FSP;
+/*
+ * Init failed, try basic relative protocols
+ */
+ max_proto = PSMOUSE_IMEX;
+ }
+ }
+
if (max_proto > PSMOUSE_IMEX) {
if (genius_detect(psmouse, set_properties) == 0)
@@ -713,6 +728,13 @@ static const struct psmouse_protocol psmouse_protocols[] =
{
.maxproto = 1,
.detect = intellimouse_detect,
},
+ {
+ .type = PSMOUSE_FSP,
+ .name = "FSPPS/2",
+ .alias = "fsp",
+ .detect = fsp_detect,
+ .init = fsp_init,
+ },
{
.type = PSMOUSE_IMEX,
.name = "ImExPS/2",
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 1317bdd..91ec7a5 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -89,6 +89,7 @@ enum psmouse_type {
PSMOUSE_TRACKPOINT,
PSMOUSE_TOUCHKIT_PS2,
PSMOUSE_CORTRON,
+ PSMOUSE_FSP,
PSMOUSE_AUTO /* This one should always be last */
};
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c
new file mode 100644
index 0000000..4101483
--- /dev/null
+++ b/drivers/input/mouse/sentelic.c
@@ -0,0 +1,1453 @@
+/*-
+ * Finger Sensing Pad PS/2 mouse driver.
+ *
+ * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd.
+ * Copyright (C) 2005-2008 Tai-hwa Liang, Sentelic Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: sentelic.c 28732 2008-10-17 07:03:29Z avatar $
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/input.h>
+#include <linux/ctype.h>
+#include <linux/libps2.h>
+#include <linux/serio.h>
+#include <linux/jiffies.h>
+
+#include "psmouse.h"
+#include "sentelic.h"
+
+/**
+ * The timeout for FSP PS/2 command only(in millisecond).
+ */
+#define FSP_CMD_TIMEOUT (30)
+
+/** Driver version. */
+static unsigned int fsp_drv_ver[] = {1, 0, 0};
+
+#ifdef FSP_DEBUG
+static unsigned int ps2_packet_cnt = 0;
+static unsigned int ps2_last_second = 0;
+#endif
+
+/*
+ * A direct copy of ps2_command(), with reduced timeout value as the hardware
+ * will return non-standard response which results in timeout in almost all
+ * commanding sequences.
+ */
+static int
+fsp_ps2_command(struct psmouse *psmouse, unsigned char *param, int command)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ int timeout;
+ int send = (command >> 12) & 0xf;
+ int receive = (command >> 8) & 0xf;
+ int rc = -1;
+ int i;
+
+ if (receive > sizeof(ps2dev->cmdbuf)) {
+ WARN_ON(1);
+ return (-1);
+ }
+
+ if (send && !param) {
+ WARN_ON(1);
+ return (-1);
+ }
+
+ mutex_lock(&ps2dev->cmd_mutex);
+
+ serio_pause_rx(ps2dev->serio);
+ ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0;
+ ps2dev->cmdcnt = receive;
+ if (receive && param)
+ for (i = 0; i < receive; i++)
+ ps2dev->cmdbuf[(receive - 1) - i] = param[i];
+ serio_continue_rx(ps2dev->serio);
+
+ if (ps2_sendbyte(ps2dev, command & 0xff,
+ command == PS2_CMD_RESET_BAT ? 1000 : FSP_CMD_TIMEOUT))
+ goto out;
+
+ for (i = 0; i < send; i++) {
+ if (ps2_sendbyte(ps2dev, param[i], FSP_CMD_TIMEOUT))
+ goto out;
+ }
+
+ /*
+ * The reset command takes a long time to execute.
+ */
+ timeout = msecs_to_jiffies(command == PS2_CMD_RESET_BAT ? 4000 : 500);
+
+ timeout = wait_event_timeout(ps2dev->wait,
+ !(ps2dev->flags & PS2_FLAG_CMD1), timeout);
+
+ if (ps2dev->cmdcnt && timeout > 0) {
+ wait_event_timeout(ps2dev->wait,
+ !(ps2dev->flags & PS2_FLAG_CMD), timeout);
+ }
+
+ if (param) {
+ for (i = 0; i < receive; i++)
+ param[i] = ps2dev->cmdbuf[(receive - 1) - i];
+ }
+
+ if (ps2dev->cmdcnt && (command != PS2_CMD_RESET_BAT || ps2dev->cmdcnt
!= 1))
+ goto out;
+
+ rc = 0;
+out:
+ serio_pause_rx(ps2dev->serio);
+ ps2dev->flags = 0;
+ serio_continue_rx(ps2dev->serio);
+
+ mutex_unlock(&ps2dev->cmd_mutex);
+ return (rc);
+}
+
+/*
+ * Make sure that the value being sent to FSP will not conflict with
+ * possible sample rate values.
+ */
+static unsigned char
+fsp_test_swap_cmd(unsigned char reg_val)
+{
+ switch (reg_val) {
+ case 10: case 20: case 40: case 60: case 80: case 100: case 200:
+ /*
+ * The requested value being sent to FSP matched to possible
+ * sample rates, swap the given value such that the hardware
+ * wouldn't get confused.
+ */
+ return ((reg_val >> 4) | (reg_val << 4));
+ default:
+ return (reg_val); /* swap isn't necessary */
+ }
+}
+
+/*
+ * Make sure that the value being sent to FSP will not conflict with certain
+ * commands.
+ */
+static unsigned char
+fsp_test_invert_cmd(unsigned char reg_val)
+{
+ switch (reg_val) {
+ case 0xe9: case 0xee: case 0xf2: case 0xff:
+ /*
+ * The requested value being sent to FSP matched to certain
+ * commands, inverse the given value such that the hardware
+ * wouldn't get confused.
+ */
+ return ~(reg_val);
+ default:
+ return (reg_val); /* inversion isn't necessary */
+ }
+}
+
+static int
+fsp_reg_read(struct psmouse *psmouse, int reg_addr, int *reg_val)
+{
+ unsigned char param[3];
+ unsigned char addr;
+#ifdef FSP_DEBUG
+ printk(KERN_INFO "fsp_reg_read: READ REG\n");
+#endif
+ if (fsp_ps2_command(psmouse, NULL, 0x00f3) < 0)
+ return (-1);
+
+ /* should return 0xfe(request for resending) */
+ fsp_ps2_command(psmouse, NULL, 0x0066);
+ /* should return 0xfc(failed) */
+ fsp_ps2_command(psmouse, NULL, 0x0088);
+
+ if (fsp_ps2_command(psmouse, NULL, 0x00f3) < 0)
+ return (-1);
+
+ if ((addr = fsp_test_invert_cmd(reg_addr)) != reg_addr) {
+ fsp_ps2_command(psmouse, NULL, 0x0068);
+ } else {
+ if ((addr = fsp_test_swap_cmd(reg_addr)) != reg_addr) {
+ /* swapping is required */
+ fsp_ps2_command(psmouse, NULL, 0x00cc);
+ /* expect 0xfe */
+ } else {
+ /* swapping isn't necessary */
+ fsp_ps2_command(psmouse, NULL, 0x0066);
+ /* expect 0xfe */
+ }
+ }
+ /* should return 0xfc(failed) */
+ fsp_ps2_command(psmouse, NULL, addr);
+
+ if (fsp_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO) < 0)
+ return (-1);
+
+ *reg_val = param[2];
+
+ return (0);
+}
+
+static int
+fsp_reg_write(struct psmouse *psmouse, int reg_addr, int reg_val)
+{
+ unsigned char v;
+#ifdef FSP_DEBUG
+ printk(KERN_INFO "fsp_reg_write: WRITE REG\n");
+#endif
+ if (fsp_ps2_command(psmouse, NULL, 0x00f3) < 0)
+ return (-1);
+
+ if ((v = fsp_test_invert_cmd(reg_addr)) != reg_addr) {
+ /* inversion is required */
+ fsp_ps2_command(psmouse, NULL, 0x0074);
+ } else {
+ if ((v = fsp_test_swap_cmd(reg_addr)) != reg_addr) {
+ /* swapping is required */
+ fsp_ps2_command(psmouse, NULL, 0x0077);
+ } else {
+ /* swapping isn't necessary */
+ fsp_ps2_command(psmouse, NULL, 0x0055);
+ }
+ }
+ /* write the register address in correct order */
+ fsp_ps2_command(psmouse, NULL, v);
+
+ if (fsp_ps2_command(psmouse, NULL, 0x00f3) < 0)
+ return (-1);
+
+ if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) {
+ /* inversion is required */
+ fsp_ps2_command(psmouse, NULL, 0x0047);
+ } else {
+ if ((v = fsp_test_swap_cmd(reg_val)) != reg_val) {
+ /* swapping is required */
+ fsp_ps2_command(psmouse, NULL, 0x0044);
+ } else {
+ /* swapping isn't necessary */
+ fsp_ps2_command(psmouse, NULL, 0x0033);
+ }
+ }
+ /* write the register value in correct order */
+ fsp_ps2_command(psmouse, NULL, v);
+
+ return (0);
+}
+
+/* enable register clock gating for writing certain registers */
+static int
+fsp_reg_write_enable(struct psmouse *psmouse, int en)
+{
+ int v, nv;
+
+ if (fsp_reg_read(psmouse, FSP_REG_SYSCTL1, &v) == -1)
+ return (-1);
+
+ if (en) {
+ nv = v | FSP_BIT_EN_REG_CLK;
+ } else {
+ nv = v & ~(FSP_BIT_EN_REG_CLK);
+ }
+ /* only write if necessary */
+ if (nv != v) {
+ if (fsp_reg_write(psmouse, FSP_REG_SYSCTL1, nv) == -1)
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+fsp_page_reg_read(struct psmouse *psmouse, int *reg_val)
+{
+ unsigned char param[3];
+#ifdef FSP_DEBUG
+ printk(KERN_INFO "fsp_page_reg_read: READ PAGE REG\n");
+#endif
+ if (fsp_ps2_command(psmouse, NULL, 0x00f3) < 0)
+ return (-1);
+
+ fsp_ps2_command(psmouse, NULL, 0x0066);
+ fsp_ps2_command(psmouse, NULL, 0x0088);
+
+ if (fsp_ps2_command(psmouse, NULL, 0x00f3) < 0)
+ return (-1);
+
+ fsp_ps2_command(psmouse, NULL, 0x0083);
+ fsp_ps2_command(psmouse, NULL, 0x0088);
+
+ /* get the returned result */
+ if (fsp_ps2_command(psmouse, param, PSMOUSE_CMD_GETINFO))
+ return (-1);
+
+ *reg_val = param[2];
+
+ return (0);
+}
+
+static int
+fsp_page_reg_write(struct psmouse *psmouse, int reg_val)
+{
+ unsigned char v;
+#ifdef FSP_DEBUG
+ printk(KERN_INFO "fsp_page_reg_write: WRITE PAGE REG\n");
+#endif
+ if (fsp_ps2_command(psmouse, NULL, 0x00f3) < 0)
+ return (-1);
+
+ fsp_ps2_command(psmouse, NULL, 0x0038);
+ fsp_ps2_command(psmouse, NULL, 0x0088);
+
+ if (fsp_ps2_command(psmouse, NULL, 0x00f3) < 0)
+ return (-1);
+
+ if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) {
+ fsp_ps2_command(psmouse, NULL, 0x0047);
+ } else {
+ if ((v = fsp_test_swap_cmd(reg_val)) != reg_val) {
+ /* swapping is required */
+ fsp_ps2_command(psmouse, NULL, 0x0044);
+ } else {
+ /* swapping isn't necessary */
+ fsp_ps2_command(psmouse, NULL, 0x0033);
+ }
+ }
+ fsp_ps2_command(psmouse, NULL, v);
+
+ return (0);
+}
+
+static int
+fsp_batch_write_reg(struct psmouse *psmouse,
+ const unsigned char *params, size_t size)
+{
+ int i, v;
+
+ if (size == 0)
+ return (0);
+
+ /* begin writing: enable register clock gating */
+ fsp_reg_write_enable(psmouse, 1);
+
+ for (i = v = 0; i < size; i += 2) {
+ if (fsp_reg_write(psmouse, params[i], params[i + 1]) != 0)
+ v = -1;
+ }
+
+ /* complete writing: disable register clock gating */
+ fsp_reg_write_enable(psmouse, 0);
+
+ return (v);
+}
+
+static int
+fsp_device_id(struct psmouse *psmouse)
+{
+ int id;
+
+ if (fsp_reg_read(psmouse, FSP_REG_DEVICE_ID, &id))
+ return (-1);
+ else
+ return (id);
+}
+
+static int
+fsp_get_version(struct psmouse *psmouse)
+{
+ int ver;
+
+ if (fsp_reg_read(psmouse, FSP_REG_VERSION, &ver))
+ return (-1);
+ else
+ return (ver);
+}
+
+static int
+fsp_get_revision(struct psmouse *psmouse)
+{
+ int rev;
+
+ if (fsp_reg_read(psmouse, FSP_REG_REVISION, &rev))
+ return (-1);
+ else
+ return (rev);
+}
+
+static int
+fsp_get_buttons(struct psmouse *psmouse)
+{
+ int buttons;
+
+ if (fsp_reg_read(psmouse, FSP_REG_TMOD_STATUS1, &buttons) == -1)
+ return (-1);
+
+ switch (buttons & 0x30) {
+ case 0x30:
+ default:
+ /* Left/Middle/Right */
+ return (0x02);
+
+ case 0x20:
+ /* Left/Middle/Right & Scroll Up/Down */
+ return (0x04);
+
+ case 0x10:
+ /* Left/Middle/Right & Scroll Up/Down/Right/Left */
+ return (0x06);
+
+ case 0x00:
+ /* Left/Middle/Right/Forward/Backward & Scroll Up/Down */
+ return (0x16);
+ }
+}
+
+/** enable on-pad command tag output */
+static int
+fsp_opc_tag_enable(struct psmouse *psmouse, int en)
+{
+ int v, nv, res = 0;
+
+ if (fsp_reg_read(psmouse, FSP_REG_OPC_QDOWN, &v) == -1) {
+ printk(KERN_ERR "Unable get OPC state.\n");
+ return (-1);
+ }
+ if (en) {
+ nv = v | FSP_BIT_EN_OPC_TAG;
+ } else {
+ nv = v & ~(FSP_BIT_EN_OPC_TAG);
+ }
+ /* only write if necessary */
+ if (nv != v) {
+ fsp_reg_write_enable(psmouse, 1);
+ res = fsp_reg_write(psmouse, FSP_REG_OPC_QDOWN, nv);
+ fsp_reg_write_enable(psmouse, 0);
+ }
+ if (res != 0) {
+ printk(KERN_ERR "Unable to enable OPC tag.\n");
+ }
+ return (res);
+}
+
+/**
+ * set packet format based on the number of buttons current device has
+ */
+static int
+fsp_set_packet_format(struct psmouse *psmouse)
+{
+ struct fsp_data *ad = psmouse->private;
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ unsigned char param[2];
+ int val;
+
+ switch (ad->buttons) {
+ case 0x02:
+ /* Left/Middle/Right */
+ case 0x04:
+ /* Left/Middle/Right & Scroll Up/Down */
+ case 0x16:
+ /* Left/Middle/Right/Forward/Backward & Scroll Up/Down */
+
+ /*
+ * standard procedure to enter FSP Intellimouse mode
+ * (scrolling wheel, 4th and 5th buttons)
+ */
+ param[0] = 200;
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+ param[0] = 200;
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+ param[0] = 80;
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
+ if (param[0] != 0x04) {
+ printk(KERN_ERR "Unable to enable 4 bytes packet.\n");
+ psmouse->pktsize = 3;
+ return (-1);
+ }
+ psmouse->pktsize = 4;
+ break;
+ case 0x06:
+ /* Left/Middle/Right & Scroll Up/Down/Right/Left */
+ fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &val);
+ val &= ~(FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8 |
FSP_BIT_EN_AUTO_MSID8);
+ val |= FSP_BIT_EN_MSID6;
+ if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, val)) {
+ printk(KERN_ERR "Unable to enable MSID6 mode.\n");
+ return (-1);
+ }
+ psmouse->pktsize = 4;
+ break;
+ default:
+ printk(KERN_ERR "Unknown number of buttons.\n");
+ break;
+ }
+ /*
+ * enable OPC tags such that driver can tell the difference between
+ * on-pad and real button click
+ */
+ return fsp_opc_tag_enable(psmouse, 1);
+}
+
+/*
+ * return 0 if the pad is placed in 180 degree
+ */
+int
+fsp_get_degree(struct psmouse *psmouse)
+{
+ int degree;
+
+ if (fsp_reg_read(psmouse, FSP_REG_TMOD_STATUS1, °ree))
+ return (-1);
+ else
+ return (degree & FSP_BIT_NO_ROTATION) ? 1 : 0;
+}
+
+static int
+fsp_onpad_vscr(struct psmouse *psmouse, int enable)
+{
+ struct fsp_data *ad = psmouse->private;
+ struct fsp_hw_state *state = &ad->hw_state;
+ int val;
+
+ if (fsp_reg_read(psmouse, FSP_REG_ONPAD_CTL, &val))
+ return (-1);
+
+ state->onpad_vscroll = (enable == 0) ? 0 : 1;
+
+ if (enable)
+ val |= (FSP_BIT_FIX_VSCR | FSP_BIT_ONPAD_ENABLE);
+ else
+ val &= (0xff ^ FSP_BIT_FIX_VSCR);
+
+ if (fsp_reg_write(psmouse, FSP_REG_ONPAD_CTL, val))
+ return (-1);
+
+ return (0);
+}
+
+static int
+fsp_onpad_hscr(struct psmouse *psmouse, int enable)
+{
+ struct fsp_data *ad = psmouse->private;
+ struct fsp_hw_state *state = &ad->hw_state;
+ int val, v2;
+
+ if (fsp_reg_read(psmouse, FSP_REG_ONPAD_CTL, &val))
+ return (-1);
+
+ if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &v2))
+ return (-1);
+
+ state->onpad_hscroll = (enable == 0) ? 0 : 1;
+
+ if (enable) {
+ val |= (FSP_BIT_FIX_HSCR | FSP_BIT_ONPAD_ENABLE);
+ v2 |= FSP_BIT_EN_MSID6;
+ } else {
+ val &= (0xff ^ FSP_BIT_FIX_HSCR);
+ v2 &= ~(FSP_BIT_EN_MSID6 | FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8);
+ }
+
+ if (fsp_reg_write(psmouse, FSP_REG_ONPAD_CTL, val))
+ return (-1);
+
+ /* reconfigure horizontal scrolling packet output */
+ if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, v2))
+ return (-1);
+
+ return (0);
+}
+
+static int
+fsp_onpad_icon(struct psmouse *psmouse, int enable)
+{
+ struct fsp_data *ad = psmouse->private;
+ struct fsp_hw_state *state = &ad->hw_state;
+ int val;
+
+#ifdef notyet
+ /* switch to register page 1, where icon switch button registers are */
+ fsp_reg_read(psmouse, FSP_REG_PAGE_CTRL, &val);
+ val |= 0x01;
+ if (fsp_reg_write(psmouse, FSP_REG_PAGE_CTRL, val))
+ return (-1);
+
+ fsp_reg_write_enable(psmouse, 1);
+ /* set position of icon switch button */
+ /*
+ * XL XH
+ * YL+--------+
+ * | sw_btn | POSITION UNIT IS IN 0.5 SCANLINE
+ * YH+--------+
+ */
+ if (fsp_reg_write(psmouse, FSP_REG_OPTZ_YHI, 0))
+ val = -1;
+ if (fsp_reg_write(psmouse, FSP_REG_OPTZ_YLO, 6))
+ val = -1;
+ if (fsp_reg_write(psmouse, FSP_REG_OPTZ_XHI, 0))
+ val = -1;
+ if (fsp_reg_write(psmouse, FSP_REG_OPTZ_XLO, 6 | 0x80))
+ val = -1;
+ fsp_reg_write_enable(psmouse, 0);
+ if (val == -1)
+ return (-1);
+
+ /* switch back to register page 0 */
+ fsp_reg_read(psmouse, FSP_REG_PAGE_CTRL, &val);
+ val &= ~0x01;
+ if (fsp_reg_write(psmouse, FSP_REG_PAGE_CTRL, val))
+ return (-1);
+#endif
+ /* enable icon switch button and absolute packet */
+ fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &val);
+ val &= ~(FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8 | FSP_BIT_EN_AUTO_MSID8);
+
+ if (enable) {
+ val |= (FSP_BIT_EN_MSID8 | FSP_BIT_EN_PKT_G0);
+ state->onpad_icon = 1;
+ state->abs_pkt = 1;
+ } else {
+ state->onpad_icon = 0;
+ state->abs_pkt = 0;
+ }
+
+ if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, val))
+ return (-1);
+
+ return (0);
+}
+
+/*
+ * It turns out that kernel provided sscanf() was not able to scan numbers
+ * in specified width; therefore, we ended up with rolling our own version
+ * of HEX string to integer helper.
+ */
+static int
+hexstr2int(const char *str, int width)
+{
+ int i, val, res = 0;
+
+ if (width > sizeof(int))
+ return (res);
+
+ for (i = 0; i < width; i++) {
+ const char *ptr = &str[i];
+
+ if (!isxdigit(*ptr))
+ break;
+
+ val = isdigit(*ptr) ? *ptr - '0' : toupper(*ptr)- 'A' + 10;
+ res = res * 16 + val;
+ }
+ return (res);
+}
+
+static ssize_t
+psmouse_attr_show_setreg(struct psmouse *psmouse, void *data, char *buf)
+{
+ /* do nothing */
+ return (0);
+}
+
+/*
+ * Write device specific initial parameters.
+ *
+ * ex: abcdc00d -- write 0xcd to register 0xab and 0x0d to 0xc0
+ */
+static ssize_t
+psmouse_attr_set_setreg(struct psmouse *psmouse, void *data,
+ const char *buf, size_t count)
+{
+ struct fsp_data *ad = psmouse->private;
+ int i, len, val;
+
+ if ((count % 4) != 0)
+ return (-EINVAL);
+
+ if ((len = (count >> 1)) >= sizeof(ad->init_params))
+ return (-ENOMEM);
+
+ for (i = 0; i < len; i += 2) {
+ val = hexstr2int(&buf[i << 1], 4);
+ ad->init_params[i] = (val >> 8) & 0xff;
+ ad->init_params[i + 1] = val & 0xff;
+ }
+ ad->init_params_len = len;
+ fsp_batch_write_reg(psmouse, ad->init_params, len);
+
+ return (count);
+}
+
+PSMOUSE_DEFINE_ATTR(setreg, S_IWUSR | S_IRUGO, NULL,
+ psmouse_attr_show_setreg, psmouse_attr_set_setreg);
+
+static ssize_t
+psmouse_attr_show_getreg(struct psmouse *psmouse, void *data, char *buf)
+{
+ struct fsp_data *ad = psmouse->private;
+
+ buf[0] = 0;
+ return sprintf(buf, "%04x\n", ad->last_reg_val);
+}
+
+/*
+ * Read a register from device.
+ *
+ * ex: ab -- read content from register 0xab
+ */
+static ssize_t
+psmouse_attr_set_getreg(struct psmouse *psmouse, void *data, const char *buf,
+ size_t count)
+{
+ struct fsp_data *ad = psmouse->private;
+ int reg, val;
+
+ if (count != 2)
+ return (-EINVAL);
+
+ reg = hexstr2int(buf, 2);
+
+ if (fsp_reg_read(psmouse, reg, &val))
+ return (-ENODEV);
+
+ ad->last_reg_val = (reg << 8) | val;
+
+ return (count);
+}
+
+PSMOUSE_DEFINE_ATTR(getreg, S_IWUSR | S_IRUGO, NULL,
+ psmouse_attr_show_getreg, psmouse_attr_set_getreg);
+
+static ssize_t
+psmouse_attr_show_pagereg(struct psmouse *psmouse, void *data, char *buf)
+{
+ int val;
+
+ buf[0] = 0;
+
+ if (fsp_page_reg_read(psmouse, &val))
+ return (-ENODEV);
+
+ return sprintf(buf, "%02x\n", val);
+}
+
+static ssize_t
+psmouse_attr_set_pagereg(struct psmouse *psmouse, void *data, const char *buf,
+ size_t count)
+{
+ int val;
+
+ if (count != 2)
+ return (-EINVAL);
+
+ val = hexstr2int(buf, 2);
+
+ if (fsp_page_reg_write(psmouse, val))
+ return (-ENODEV);
+
+ return (count);
+}
+
+PSMOUSE_DEFINE_ATTR(page, S_IWUSR | S_IRUGO, NULL,
+ psmouse_attr_show_pagereg, psmouse_attr_set_pagereg);
+
+static ssize_t
+psmouse_attr_show_ps2(struct psmouse *psmouse, void *data, char *buf)
+{
+ struct fsp_data *ad = psmouse->private;
+ char tmp[2];
+ int i, len;
+
+ for (i = len = 0; i < ad->resp_cnt; i++) {
+ len += sprintf(tmp, "%02x", ad->resp[i]);
+ strcat(buf, tmp);
+ }
+ strcat(buf, "\n");
+ return (len + 1);
+}
+
+static ssize_t
+psmouse_attr_set_ps2(struct psmouse *psmouse, void *data, const char *buf,
+ size_t count)
+{
+ struct fsp_data *ad = psmouse->private;
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ int v;
+
+ if (count != 4)
+ return (-EINVAL);
+
+ v = hexstr2int(buf, 4);
+
+ if (ps2_command(ps2dev, ad->resp, v) != -1) {
+ ad->resp_cnt = (v >> 8) & (FSP_RESP_PKT_MAXLEN - 1);
+ } else {
+ ad->resp_cnt = 0;
+ }
+ return (count);
+}
+
+PSMOUSE_DEFINE_ATTR(ps2, S_IWUSR | S_IRUGO, NULL,
+ psmouse_attr_show_ps2, psmouse_attr_set_ps2);
+
+static ssize_t
+psmouse_attr_show_vscroll(struct psmouse *psmouse, void *data, char *buf)
+{
+ struct fsp_data *ad = psmouse->private;
+
+ return sprintf(buf, "%d\n", ad->hw_state.onpad_vscroll ? 1 : 0);
+}
+
+static ssize_t
+psmouse_attr_set_vscroll(struct psmouse *psmouse, void *data, const char *buf,
+ size_t count)
+{
+ struct fsp_data *ad = psmouse->private;
+ unsigned long val;
+ char *rest;
+
+ val = simple_strtoul(buf, &rest, 10);
+
+ if (*rest || (val > 1))
+ return (-EINVAL);
+
+ ad->hw_state.onpad_vscroll = val;
+ fsp_onpad_vscr(psmouse, val);
+
+ return (count);
+}
+
+PSMOUSE_DEFINE_ATTR(vscroll, S_IWUSR | S_IRUGO | S_IWUGO, NULL,
+ psmouse_attr_show_vscroll, psmouse_attr_set_vscroll);
+
+static ssize_t
+psmouse_attr_show_hscroll(struct psmouse *psmouse, void *data, char *buf)
+{
+ struct fsp_data *ad = psmouse->private;
+
+ return sprintf(buf, "%d\n", ad->hw_state.onpad_hscroll ? 1 : 0);
+}
+
+static ssize_t
+psmouse_attr_set_hscroll(struct psmouse *psmouse, void *data, const char *buf,
+ size_t count)
+{
+ struct fsp_data *ad = psmouse->private;
+ unsigned long val;
+ char *rest;
+
+ val = simple_strtoul(buf, &rest, 10);
+
+ if (*rest || (val > 1))
+ return (-EINVAL);
+
+ ad->hw_state.onpad_hscroll = val;
+ fsp_onpad_hscr(psmouse, val);
+
+ return (count);
+}
+
+PSMOUSE_DEFINE_ATTR(hscroll, S_IWUSR | S_IRUGO | S_IWUGO, NULL,
+ psmouse_attr_show_hscroll, psmouse_attr_set_hscroll);
+
+static ssize_t
+psmouse_attr_show_onpadicon(struct psmouse *psmouse, void *data, char *buf)
+{
+ struct fsp_data *ad = psmouse->private;
+
+ return sprintf(buf, "%d\n", ad->hw_state.onpad_icon ? 1 : 0);
+}
+
+static ssize_t
+psmouse_attr_set_onpadicon(struct psmouse *psmouse, void *data,
+ const char *buf, size_t count)
+{
+ struct fsp_data *ad = psmouse->private;
+ unsigned long val;
+ char *rest;
+
+ val = simple_strtoul(buf, &rest, 10);
+
+ if (*rest || (val > 1))
+ return (-EINVAL);
+
+ ad->hw_state.onpad_icon = val;
+ fsp_onpad_icon(psmouse, val);
+
+ return (count);
+}
+
+PSMOUSE_DEFINE_ATTR(onpadicon, S_IWUSR | S_IRUGO | S_IWUGO, NULL,
+ psmouse_attr_show_onpadicon, psmouse_attr_set_onpadicon);
+
+static ssize_t
+psmouse_attr_show_pktfmt(struct psmouse *psmouse, void *data, char *buf)
+{
+ struct fsp_data *ad = psmouse->private;
+
+ return sprintf(buf, "%d\n", ad->hw_state.pkt_fmt);
+}
+
+static ssize_t
+psmouse_attr_set_pktfmt(struct psmouse *psmouse, void *data,
+ const char *buf, size_t count)
+{
+ struct fsp_data *ad = psmouse->private;
+ unsigned long val;
+ char *rest;
+
+ val = simple_strtoul(buf, &rest, 10);
+
+ if (*rest || (val > 2))
+ return (-EINVAL);
+
+ ad->hw_state.pkt_fmt = val;
+ /* TODO need full G0/A0 abs. packet setup */
+
+ return (count);
+}
+
+PSMOUSE_DEFINE_ATTR(pktfmt, S_IWUSR | S_IRUGO | S_IWUGO, NULL,
+ psmouse_attr_show_pktfmt, psmouse_attr_set_pktfmt);
+
+static ssize_t
+psmouse_attr_show_flags(struct psmouse *psmouse, void *data, char *buf)
+{
+ struct fsp_data *ad = psmouse->private;
+
+ return sprintf(buf, "%c%c%c%c%c%c\n",
+ ad->flags & FSPDRV_FLAG_OPICON_KEY ? 'K' : 'k',
+ ad->flags & FSPDRV_FLAG_OPICON_BTN ? 'B' : 'b',
+ ad->flags & FSPDRV_FLAG_REVERSE_X ? 'X' : 'x',
+ ad->flags & FSPDRV_FLAG_REVERSE_Y ? 'Y' : 'y',
+ ad->flags & FSPDRV_FLAG_AUTO_SWITCH ? 'A' : 'a',
+ ad->flags & FSPDRV_FLAG_EN_OPC ? 'C' : 'c');
+}
+
+static ssize_t
+psmouse_attr_set_flags(struct psmouse *psmouse, void *data,
+ const char *buf, size_t count)
+{
+ struct fsp_data *ad = psmouse->private;
+ size_t i;
+
+ for (i = 0; i < count; i++) {
+ switch (buf[i]) {
+ case 'B':
+ ad->flags |= FSPDRV_FLAG_OPICON_BTN;
+ break;
+ case 'b':
+ ad->flags &= ~FSPDRV_FLAG_OPICON_BTN;
+ break;
+ case 'K':
+ ad->flags |= FSPDRV_FLAG_OPICON_KEY;
+ break;
+ case 'k':
+ ad->flags &= ~FSPDRV_FLAG_OPICON_KEY;
+ break;
+ case 'X':
+ ad->flags |= FSPDRV_FLAG_REVERSE_X;
+ break;
+ case 'x':
+ ad->flags &= ~FSPDRV_FLAG_REVERSE_X;
+ break;
+ case 'Y':
+ ad->flags |= FSPDRV_FLAG_REVERSE_Y;
+ break;
+ case 'y':
+ ad->flags &= ~FSPDRV_FLAG_REVERSE_Y;
+ break;
+ case 'A':
+ ad->flags |= FSPDRV_FLAG_AUTO_SWITCH;
+ break;
+ case 'a':
+ ad->flags &= ~FSPDRV_FLAG_AUTO_SWITCH;
+ break;
+ case 'C':
+ ad->flags |= FSPDRV_FLAG_EN_OPC;
+ break;
+ case 'c':
+ ad->flags &= ~FSPDRV_FLAG_EN_OPC;
+ break;
+ case 'R':
+ case 'r':
+ /* hack: reset pad */
+#ifdef FSP_DEBUG
+ printk(KERN_INFO "Resetting FSP...\n");
+#endif
+ /* disable on-pad vertical scrolling */
+ fsp_onpad_vscr(psmouse, 0);
+ /* disable on-pad horizontal scrolling */
+ fsp_onpad_hscr(psmouse, 0);
+
+ /*
+ * disable on-pad switching icon and absolute packet
+ * mode
+ */
+ fsp_onpad_icon(psmouse, 0);
+ /* reload custom initial parameters */
+ fsp_reset(psmouse);
+ /* re-initialise output packet format */
+ fsp_set_packet_format(psmouse);
+ break;
+ default:
+ return (-EINVAL);
+ }
+ }
+ return (count);
+}
+
+PSMOUSE_DEFINE_ATTR(flags, S_IWUSR | S_IRUGO | S_IWUGO, NULL,
+ psmouse_attr_show_flags, psmouse_attr_set_flags);
+
+static ssize_t
+psmouse_attr_show_ver(struct psmouse *psmouse, void *data, char *buf)
+{
+ return sprintf(buf, "Sentelic FSP kernel module %d.%d.%d\n",
+ fsp_drv_ver[0], fsp_drv_ver[1], fsp_drv_ver[2]);
+}
+
+static ssize_t
+psmouse_attr_set_ver(struct psmouse *psmouse, void *data,
+ const char *buf, size_t count)
+{
+ /* do nothing */
+ return (count);
+}
+
+PSMOUSE_DEFINE_ATTR(ver, S_IRUSR | S_IRUGO, NULL,
+ psmouse_attr_show_ver, psmouse_attr_set_ver);
+
+static ssize_t
+psmouse_attr_show_accel(struct psmouse *psmouse, void *data, char *buf)
+{
+ struct fsp_data *ad = psmouse->private;
+
+ return sprintf(buf, "%d %d %d\n",
+ ad->accel_num, ad->accel_denom, ad->accel_threshold);
+}
+
+static ssize_t
+psmouse_attr_set_accel(struct psmouse *psmouse, void *data,
+ const char *buf, size_t count)
+{
+ struct fsp_data *ad = psmouse->private;
+
+ sscanf(buf, "%d %d %d",
+ &ad->accel_num, &ad->accel_denom, &ad->accel_threshold);
+
+ /* sanity check */
+ if (ad->accel_num <= 0)
+ ad->accel_num = DEFAULT_ACCEL_NUM;
+
+ /* prevent dividing by zero */
+ if (ad->accel_denom <= 0)
+ ad->accel_denom = DEFAULT_ACCEL_DENOM;
+
+ if (ad->accel_threshold <= 0)
+ ad->accel_threshold = DEFAULT_ACCEL_THRESHOLD;
+
+ return (count);
+}
+
+PSMOUSE_DEFINE_ATTR(accel, S_IWUSR | S_IRUGO | S_IWUGO, NULL,
+ psmouse_attr_show_accel, psmouse_attr_set_accel);
+
+int
+fsp_reset(struct psmouse *psmouse)
+{
+ /* TODO: reset initial parameters */
+ return (0);
+}
+
+static int
+fsp_reconnect(struct psmouse *psmouse)
+{
+ int version;
+
+ if (fsp_detect(psmouse, 0) < 0)
+ return (-1);
+
+ if ((version = fsp_get_version(psmouse)) < 0)
+ return (-1);
+
+ fsp_reset(psmouse);
+
+ return (0);
+}
+
+static void
+fsp_remove_sysfs(struct psmouse *psmouse)
+{
+ device_remove_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_setreg.dattr);
+ device_remove_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_getreg.dattr);
+ device_remove_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_page.dattr);
+ device_remove_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_ps2.dattr);
+ device_remove_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_vscroll.dattr);
+ device_remove_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_hscroll.dattr);
+ device_remove_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_onpadicon.dattr);
+ device_remove_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_pktfmt.dattr);
+ device_remove_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_flags.dattr);
+ device_remove_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_ver.dattr);
+ device_remove_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_accel.dattr);
+}
+
+static void
+fsp_disconnect(struct psmouse *psmouse)
+{
+ fsp_remove_sysfs(psmouse);
+ fsp_opc_tag_enable(psmouse, 0);
+ fsp_reset(psmouse);
+ kfree(psmouse->private);
+}
+
+int
+fsp_detect(struct psmouse *psmouse, int set_properties)
+{
+ int rc;
+
+ if (fsp_device_id(psmouse) != 0x01)
+ return (-1);
+
+ if (set_properties) {
+ psmouse->vendor = "Sentelic";
+ psmouse->name = "FingerSensingPad";
+
+ /*
+ * register sysfs callbacks for userland program to set
+ * initial parameters
+ */
+ rc = device_create_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_setreg.dattr);
+ if (rc)
+ goto sysfs_creation_failed;
+
+ rc = device_create_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_getreg.dattr);
+ if (rc)
+ goto sysfs_creation_failed;
+
+ rc = device_create_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_page.dattr);
+ if (rc)
+ goto sysfs_creation_failed;
+
+ rc = device_create_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_ps2.dattr);
+ if (rc)
+ goto sysfs_creation_failed;
+
+ rc = device_create_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_vscroll.dattr);
+ if (rc)
+ goto sysfs_creation_failed;
+
+ rc = device_create_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_hscroll.dattr);
+ if (rc)
+ goto sysfs_creation_failed;
+
+ rc = device_create_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_onpadicon.dattr);
+ if (rc)
+ goto sysfs_creation_failed;
+
+ rc = device_create_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_pktfmt.dattr);
+ if (rc)
+ goto sysfs_creation_failed;
+
+ rc = device_create_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_flags.dattr);
+ if (rc)
+ goto sysfs_creation_failed;
+
+ rc = device_create_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_ver.dattr);
+ if (rc)
+ goto sysfs_creation_failed;
+
+ rc = device_create_file(&psmouse->ps2dev.serio->dev,
+ &psmouse_attr_accel.dattr);
+ if (rc)
+ goto sysfs_creation_failed;
+ }
+ return (0);
+sysfs_creation_failed:
+ fsp_remove_sysfs(psmouse);
+ printk(KERN_ERR "failed to create sysfs node(%d)", rc);
+ return (-1);
+}
+
+static void
+fsp_set_input_params(struct psmouse *psmouse)
+{
+ struct fsp_data *ad = psmouse->private;
+ struct fsp_hw_state *state = &ad->hw_state;
+
+ if (state->abs_pkt == 0) {
+ set_bit(BTN_MIDDLE, psmouse->dev->keybit);
+ set_bit(REL_WHEEL, psmouse->dev->relbit);
+ set_bit(REL_HWHEEL, psmouse->dev->relbit);
+
+ set_bit(EV_REL, psmouse->dev->evbit);
+ set_bit(REL_X, psmouse->dev->relbit);
+ set_bit(REL_Y, psmouse->dev->relbit);
+
+ set_bit(BTN_BACK, psmouse->dev->keybit);
+ set_bit(BTN_FORWARD, psmouse->dev->keybit);
+
+ clear_bit(EV_ABS, psmouse->dev->evbit);
+ clear_bit(BTN_SIDE, psmouse->dev->keybit);
+ clear_bit(BTN_EXTRA, psmouse->dev->keybit);
+ } else {
+ /* enable absolute packet mode */
+ set_bit(EV_ABS, psmouse->dev->evbit);
+
+ input_set_abs_params(psmouse->dev, ABS_X,
+ 0, 1023, 0, 0);
+ input_set_abs_params(psmouse->dev, ABS_Y,
+ 0, 767, 0, 0);
+
+ /* no more relative coordinates */
+ clear_bit(EV_REL, psmouse->dev->evbit);
+ clear_bit(REL_X, psmouse->dev->relbit);
+ clear_bit(REL_Y, psmouse->dev->relbit);
+ }
+}
+
+static psmouse_ret_t
+fsp_process_byte(struct psmouse *psmouse
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
+, struct pt_regs *regs
+#endif
+)
+{
+ struct input_dev *dev = psmouse->dev;
+ struct fsp_data *ad = psmouse->private;
+ unsigned char *packet = psmouse->packet;
+ unsigned char button_status = 0, lscroll, rscroll;
+#ifdef FSP_DEBUG
+ unsigned int jiffies_msec;
+#endif
+ static unsigned short prev_abs_x, prev_abs_y;
+ unsigned short abs_x, abs_y;
+ int rel_x, rel_y;
+
+ if (psmouse->pktcnt < 4)
+ return (PSMOUSE_GOOD_DATA);
+
+ if (psmouse->ps2dev.flags != 0) {
+ /*
+ * XXX need to find the root cause that makes commanding
+ * packet leaking to this function.
+ *
+ * Perhaps our own version of ps2_command() is out of date?
+ */
+ return (PSMOUSE_GOOD_DATA);
+ }
+
+ /*
+ * Full packet accumulated, process it
+ */
+ lscroll = rscroll = 0;
+
+ switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) {
+ case FSP_PKT_TYPE_ABS:
+ abs_x = (packet[1] << 2) | ((packet[3] >> 2) & 0x03);
+ abs_y = (packet[2] << 2) | (packet[3] & 0x03);
+
+ if (abs_x && abs_y) {
+ /* no X/Y directional reversal when finger is up */
+ if (ad->flags & FSPDRV_FLAG_REVERSE_X)
+ abs_x = 1023 - abs_x;
+ if (ad->flags & FSPDRV_FLAG_REVERSE_Y)
+ abs_y = 767 - abs_y;
+ prev_abs_x = abs_x;
+ prev_abs_y = abs_y;
+ }
+ if (ad->flags & (FSPDRV_FLAG_OPICON_BTN |
FSPDRV_FLAG_OPICON_KEY)) {
+ /* do nothing */
+ } else {
+ input_report_key(dev, BTN_LEFT, packet[0] & 1);
+ input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
+ input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1);
+#if 0
+ /* vscroll down */
+ input_report_key(dev, BTN_BACK, (packet[3] >> 5) & 1);
+ /* vscroll up */
+ input_report_key(dev, BTN_FORWARD, (packet[3] >> 4) &
1);
+ /* rscroll */
+ input_report_key(dev, BTN_RIGHT, (packet[3] >> 7) & 1);
+ /* lscroll */
+ input_report_key(dev, BTN_LEFT, (packet[3] >> 6) & 1);
+#endif
+ }
+ input_report_abs(dev, ABS_X, prev_abs_x);
+ input_report_abs(dev, ABS_Y, prev_abs_y);
+ break;
+ case FSP_PKT_TYPE_NORMAL_OPC:
+ /* on-pad click, filter it if necessary */
+ if ((ad->flags & FSPDRV_FLAG_EN_OPC) != FSPDRV_FLAG_EN_OPC) {
+ packet[0] &= ~BIT(0);
+ }
+ /* fall through */
+ case FSP_PKT_TYPE_NORMAL:
+ /* normal packet */
+ /* special packet data translation from on-pad packets */
+ if (packet[3] != 0) {
+ if (packet[3] & BIT(0)) {
+ button_status |= 0x01; /* wheel down */
+ }
+ if (packet[3] & BIT(1)) {
+ button_status |= 0x0f; /* wheel up */
+ }
+ if (packet[3] & BIT(2)) {
+ button_status |= BIT(5);/* horizontal left */
+ }
+ if (packet[3] & BIT(3)) {
+ button_status |= BIT(4);/* horizontal right */
+ }
+ /* push back to packet queue */
+ if (button_status != 0)
+ packet[3] = button_status;
+ rscroll = (packet[3] >> 4) & 1;
+ lscroll = (packet[3] >> 5) & 1;
+ }
+ /*
+ * Processing wheel up/down and extra button events
+ */
+ input_report_rel(dev, REL_WHEEL, (int)(packet[3] & 8) -
(int)(packet[3] & 7));
+ input_report_rel(dev, REL_HWHEEL, lscroll - rscroll);
+ input_report_key(dev, BTN_BACK, lscroll);
+ input_report_key(dev, BTN_FORWARD, rscroll);
+
+ /*
+ * Generic PS/2 Mouse
+ */
+ input_report_key(dev, BTN_LEFT, packet[0] & 1);
+ input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1);
+ input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1);
+
+ /* perform acceleration */
+ rel_x = packet[1] ? (int)packet[1] - (int)((packet[0] << 4) &
0x100) : 0;
+ rel_y = packet[2] ? (int)((packet[0] << 3) & 0x100) -
(int)packet[2] : 0;
+
+ if (abs(rel_x) > ad->accel_threshold) {
+ rel_x = rel_x * ad->accel_num / ad->accel_denom;
+ }
+ if (abs(rel_y) > ad->accel_threshold) {
+ rel_y = rel_y * ad->accel_num / ad->accel_denom;
+ }
+ input_report_rel(dev, REL_X, rel_x);
+ input_report_rel(dev, REL_Y, rel_y);
+ break;
+ }
+
+ input_sync(dev);
+
+#ifdef FSP_DEBUG
+ ps2_packet_cnt++;
+ jiffies_msec = jiffies_to_msecs(jiffies);
+ printk(KERN_INFO "%08dms PS/2 packets: %02x, %02x, %02x, %02x\n",
jiffies_msec, packet[0], packet[1], packet[2], packet[3]);
+
+ if (jiffies_msec - ps2_last_second > 1000) {
+ printk(KERN_INFO "PS/2 packets/sec = %d\n", ps2_packet_cnt);
+ ps2_packet_cnt = 0;
+ ps2_last_second = jiffies_msec;
+ }
+#endif
+ return (PSMOUSE_FULL_PACKET);
+}
+
+int
+fsp_init(struct psmouse *psmouse)
+{
+ struct fsp_data *priv;
+ int ver;
+
+ if ((ver = fsp_get_version(psmouse)) < 0)
+ return (-1);
+
+ if (!(priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL)))
+ return (-ENOMEM);
+
+ psmouse->private = priv;
+
+ priv->ver = ver;
+ priv->rev = fsp_get_revision(psmouse);
+ priv->buttons = fsp_get_buttons(psmouse);
+
+ /* enable on-pad click by default */
+ priv->flags |= FSPDRV_FLAG_EN_OPC;
+
+ switch (priv->buttons) {
+ case 0x06:
+ priv->hw_state.btn_fbbb = 0;
+ priv->hw_state.btn_slsr = 1;
+ break;
+ case 0x16:
+ priv->hw_state.btn_fbbb = 1;
+ priv->hw_state.btn_slsr = 0;
+ break;
+ default:
+ priv->hw_state.btn_fbbb = 0;
+ priv->hw_state.btn_slsr = 0;
+ break;
+ }
+ psmouse->protocol_handler = fsp_process_byte;
+ psmouse->disconnect = fsp_disconnect;
+ psmouse->reconnect = fsp_reconnect;
+
+ /* report hardware information */
+ printk(KERN_INFO "Finger Sensing Pad, hw: %d.%d.%d, sw: %d.%d.%d,
buttons: %d\n",
+ (priv->ver >> 4), (priv->ver & 0x0F), priv->rev,
+ fsp_drv_ver[0], fsp_drv_ver[1], fsp_drv_ver[2],
+ priv->buttons & 7);
+
+ /* set default acceleration parameters */
+ priv->accel_num = DEFAULT_ACCEL_NUM;
+ priv->accel_denom = DEFAULT_ACCEL_DENOM;
+ priv->accel_threshold = DEFAULT_ACCEL_THRESHOLD;
+
+ /* set default packet output based on number of buttons we found */
+ fsp_set_packet_format(psmouse);
+
+ /* disable on-pad vertical scrolling */
+ //fsp_onpad_vscr(psmouse, 0);
+
+ /* disable on-pad horizontal scrolling */
+ fsp_onpad_hscr(psmouse, 0);
+
+ /* disable on-pad switching icon and absolute packet mode */
+ fsp_onpad_icon(psmouse, 0);
+
+ /* set various supported input event bits */
+ fsp_set_input_params(psmouse);
+
+ return (0);
+}
diff --git a/drivers/input/mouse/sentelic.h b/drivers/input/mouse/sentelic.h
new file mode 100644
index 0000000..8fcaa40
--- /dev/null
+++ b/drivers/input/mouse/sentelic.h
@@ -0,0 +1,136 @@
+/*-
+ * Finger Sensing Pad PS/2 mouse driver.
+ *
+ * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd.
+ * Copyright (C) 2005-2008 Tai-hwa Liang, Sentelic Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: sentelic.h 28700 2008-10-16 07:23:43Z avatar $
+ */
+
+#ifndef __SENTELIC_H__
+#define __SENTELIC_H__
+
+#if defined(__KERNEL__)
+extern int fsp_detect(struct psmouse *psmouse, int set_properties);
+extern int fsp_init(struct psmouse *psmouse);
+extern int fsp_reset(struct psmouse *psmouse);
+#endif
+
+/* Finger-sensing Pad information registers */
+#define FSP_REG_DEVICE_ID 0x00
+#define FSP_REG_VERSION 0x01
+#define FSP_REG_REVISION 0x04
+#define FSP_REG_TMOD_STATUS1 0x0B
+#define FSP_BIT_NO_ROTATION BIT(3)
+#define FSP_REG_PAGE_CTRL 0x0F
+
+/* Finger-sensing Pad control registers */
+#define FSP_REG_SYSCTL1 0x10
+#define FSP_BIT_EN_REG_CLK BIT(5)
+#define FSP_REG_OPC_QDOWN 0x31
+#define FSP_BIT_EN_OPC_TAG BIT(7)
+#define FSP_REG_OPTZ_XLO 0x34
+#define FSP_REG_OPTZ_XHI 0x35
+#define FSP_REG_OPTZ_YLO 0x36
+#define FSP_REG_OPTZ_YHI 0x37
+#define FSP_REG_SYSCTL5 0x40
+#define FSP_BIT_90_DEGREE BIT(0)
+#define FSP_BIT_EN_MSID6 BIT(1)
+#define FSP_BIT_EN_MSID7 BIT(2)
+#define FSP_BIT_EN_MSID8 BIT(3)
+#define FSP_BIT_EN_AUTO_MSID8 BIT(5)
+#define FSP_BIT_EN_PKT_G0 BIT(6)
+
+#define FSP_REG_ONPAD_CTL 0x43
+#define FSP_BIT_ONPAD_ENABLE BIT(0)
+#define FSP_BIT_ONPAD_FBBB BIT(1)
+#define FSP_BIT_FIX_VSCR BIT(3)
+#define FSP_BIT_FIX_HSCR BIT(5)
+#define FSP_BIT_DRAG_LOCK BIT(6)
+
+/* Finger-sensing Pad packet formating related definitions */
+
+/* absolute packet type */
+#define FSP_PKT_TYPE_NORMAL (0x00)
+#define FSP_PKT_TYPE_ABS (0x01)
+#define FSP_PKT_TYPE_NOTIFY (0x02)
+#define FSP_PKT_TYPE_NORMAL_OPC (0x03)
+#define FSP_PKT_TYPE_SHIFT (6)
+
+struct fsp_hw_state
+{
+ unsigned char onpad_vscroll:1,/* On-pad vertical scroll zone */
+ onpad_hscroll:1,/* On-pad horizontal scroll zone */
+ onpad_icon:1, /* On-pad icons */
+ btn_fbbb:1, /* Forward/backward button */
+ btn_slsr:1, /* Scroll left/right button */
+ abs_pkt:1, /* absolute packet mode */
+ pkt_fmt:2; /* packet format */
+ unsigned int reg_val; /* used by reg_write sysctl */
+};
+
+struct fsp_data
+{
+ unsigned int flags;
+#define FSPDRV_FLAG_CMD (0x010) /* The command bit of flags
indicates the special FSP PS/2 command is sent. */
+#define FSPDRV_FLAG_RESP (0x020) /* The response bit of flags indicates
the special FSP PS/2 comamnd is sent and response is received. */
+#define FSPDRV_FLAG_OPICON_BTN (0x040) /* Output on-pad icons as BTN events */
+#define FSPDRV_FLAG_OPICON_KEY (0x080) /* Output on-pad icons as KEY events */
+#define FSPDRV_FLAG_REVERSE_X (0x100) /* reverse X direction */
+#define FSPDRV_FLAG_REVERSE_Y (0x200) /* reverse Y direction */
+#define FSPDRV_FLAG_AUTO_SWITCH (0x400) /* software on-pad icon auto
switch */
+#define FSPDRV_FLAG_EN_OPC (0x800) /* enable on-pad clicking */
+#define FSP_RESP_PKT_MAXLEN (8) /* The max response packet size. */
+ unsigned char cmd; /* The buffer used to store the sending
PS/2 command */
+ unsigned char resp[FSP_RESP_PKT_MAXLEN]; /* The buffer used
to store the response of PS/2 command */
+ int resp_cnt; /* The command count in resp
buffer */
+ unsigned char buttons; /* Number of buttons */
+ unsigned char ver; /* hardware version */
+ unsigned char rev; /* hardware revison */
+ unsigned int mode; /* device mode */
+#define FSPDRV_MODE_BTN_RIGHT BIT(0)
+#define FSPDRV_MODE_BTN_MIDDLE BIT(1)
+#define FSPDRV_MODE_BTN_LEFT BIT(2)
+#define FSPDRV_MODE_BTN_SCRD BIT(3)
+#define FSPDRV_MODE_BTN_SCRU BIT(4)
+#define FSPDRV_MODE_BTN_SCRL BIT(5)
+#define FSPDRV_MODE_BTN_SCRR BIT(6)
+#define FSPDRV_MODE_BTN_FB BIT(7)
+#define FSPDRV_MODE_BTN_BB BIT(8)
+ unsigned char button_status;
+ unsigned int last_reg_val;
+
+/** default acceleration numerator */
+#define DEFAULT_ACCEL_NUM (2)
+ /** numerator for the acceleration multiplier */
+ int accel_num;
+/** default acceleration denominator */
+#define DEFAULT_ACCEL_DENOM (1)
+ /** denominator for the acceleration multiplier */
+ int accel_denom;
+/** default acceleration threshold */
+#define DEFAULT_ACCEL_THRESHOLD (4)
+
+ /** acceleration threshold */
+ int accel_threshold;
+#define FSPDRV_SET_REG_BUF_LEN (256)
+ unsigned char init_params[FSPDRV_SET_REG_BUF_LEN];
+ size_t init_params_len;
+ struct fsp_hw_state hw_state;
+};
+
+#endif /* !__SENTELIC_H__ */
--- 99yeeloong 2010-03-10 13:43:02.000000000 +0800
+++ 99yeeloong 2010-03-12 11:18:51.000000000 +0800
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
# This script fix some known issues in yeeloong after resume
# issues after resume:
# 1:when we use the camera, machine can not hibernated
@@ -11,7 +11,7 @@
#Check the system is yeeloong or not
if [ -f /proc/cpuinfo ]
then
- cat /proc/cpuinfo |grep yeeloong
+ grep -c yeeloong /proc/cpuinfo
if [ "$?" -ne "0" ]
then
exit
@@ -19,28 +19,28 @@ then
fi
action=$1
-eth_infterface=`ifconfig -a|grep eth\[0-100\]|cut -d " " -f 1` #eth0....eth100
+eth_interface=`ifconfig -a|grep eth\[0-100\]|cut -d " " -f 1` #eth0....eth100
wlan_interface=`ifconfig -a|grep wlan\[0-100\]|cut -d " " -f 1`
#wlan0....wlan100
swap_part=`swapon -s |awk 'NR==2 {print $1}'` #swap partition
+OLD_GOVERNOR=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor)
do_suspend()
{
if [ x$swap_part = x"" ]
then
- echo "no swap partition"
+ echo "No swap partition"
return 1;
fi
-OLD_GOVERNOR=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor)
-echo performance >/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
+echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
sync
device="/dev/video0"
-if fuser -s $device #kill the process which uses camera
+if fuser -s $device #kill the process which uses camera
then
(fuser -s -k -9 $device 2>/dev/null || sleep 1) \
- && (echo "unable kill \n" || exit -1)
+ && (printf "Unable to kill fuser\n" || exit -1)
fi
-ifconfig $eth_infterface down
-ifconfig $wlan_infterface down
+ifconfig $eth_interface down
+ifconfig $wlan_interface down
modprobe -r r8187
modprobe -r uvcvideo
if [ x$action = x"hibernate" ]
@@ -52,13 +52,13 @@ fi
}
do_resume(){
-echo 0 >/sys/bus/usb/drivers_autoprobe
-echo 4 >/sys/class/usb_host/usb_host2/companion
-echo 1 >/sys/class/usb_host/usb_host1/companion
+echo 0 > /sys/bus/usb/drivers_autoprobe
+echo 4 > /sys/class/usb_host/usb_host2/companion
+echo 1 > /sys/class/usb_host/usb_host1/companion
sleep 1
-echo 1 >/sys/bus/usb/drivers_autoprobe
-echo -4 >/sys/class/usb_host/usb_host2/companion
-echo -1 >/sys/class/usb_host/usb_host1/companion
+echo 1 > /sys/bus/usb/drivers_autoprobe
+echo -4 > /sys/class/usb_host/usb_host2/companion
+echo -1 > /sys/class/usb_host/usb_host1/companion
sleep 1 #wait for some devices stable
if [ x$action = x"thaw" ]
then
- Re: [Gnewsense-dev] gNewSense-MIPS, Yeelong and SiliconMotion video driver, (continued)
- Re: [Gnewsense-dev] gNewSense-MIPS, Yeelong and SiliconMotion video driver, Richard Stallman, 2010/03/11
- Re: [Gnewsense-dev] gNewSense-MIPS, Yeelong and SiliconMotion video driver, Karl Goetz, 2010/03/11
- Re: [Gnewsense-dev] gNewSense-MIPS, Yeelong and SiliconMotion video driver, Hongbing Hu, 2010/03/11
- Re: [Gnewsense-dev] gNewSense-MIPS, Yeelong and SiliconMotion video driver, Richard Stallman, 2010/03/12
- Re: [Gnewsense-dev] gNewSense-MIPS, Yeelong and SiliconMotion video driver, Richard Stallman, 2010/03/12
- Re: [Gnewsense-dev] gNewSense-MIPS, Yeelong and SiliconMotion video driver, Sam Geeraerts, 2010/03/13
- Re: [Gnewsense-dev] gNewSense-MIPS, Yeelong and SiliconMotion video driver, Richard Stallman, 2010/03/13
- Re: [Gnewsense-dev] gNewSense-MIPS, Yeelong and SiliconMotion video driver,
Hongbing Hu <=
- Re: [Gnewsense-dev] gNewSense-MIPS, Yeelong and SiliconMotion video driver, Karl Goetz, 2010/03/10
- Re: [Gnewsense-dev] gNewSense-MIPS, Yeelong and SiliconMotion video driver, Richard Stallman, 2010/03/09
- Re: [Gnewsense-dev] gNewSense-MIPS, Yeelong and SiliconMotion video driver, zhangfx, 2010/03/09