|
|
|
@ -2,7 +2,7 @@ |
|
|
|
|
* Finger Sensing Pad PS/2 mouse driver. |
|
|
|
|
* |
|
|
|
|
* Copyright (C) 2005-2007 Asia Vital Components Co., Ltd. |
|
|
|
|
* Copyright (C) 2005-2011 Tai-hwa Liang, Sentelic Corporation. |
|
|
|
|
* Copyright (C) 2005-2012 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 |
|
|
|
@ -21,6 +21,7 @@ |
|
|
|
|
|
|
|
|
|
#include <linux/module.h> |
|
|
|
|
#include <linux/input.h> |
|
|
|
|
#include <linux/input/mt.h> |
|
|
|
|
#include <linux/ctype.h> |
|
|
|
|
#include <linux/libps2.h> |
|
|
|
|
#include <linux/serio.h> |
|
|
|
@ -36,6 +37,9 @@ |
|
|
|
|
#define FSP_CMD_TIMEOUT 200 |
|
|
|
|
#define FSP_CMD_TIMEOUT2 30 |
|
|
|
|
|
|
|
|
|
#define GET_ABS_X(packet) ((packet[1] << 2) | ((packet[3] >> 2) & 0x03)) |
|
|
|
|
#define GET_ABS_Y(packet) ((packet[2] << 2) | (packet[3] & 0x03)) |
|
|
|
|
|
|
|
|
|
/** Driver version. */ |
|
|
|
|
static const char fsp_drv_ver[] = "1.0.0-K"; |
|
|
|
|
|
|
|
|
@ -128,8 +132,9 @@ static int fsp_reg_read(struct psmouse *psmouse, int reg_addr, int *reg_val) |
|
|
|
|
out: |
|
|
|
|
ps2_end_command(ps2dev); |
|
|
|
|
psmouse_activate(psmouse); |
|
|
|
|
dev_dbg(&ps2dev->serio->dev, "READ REG: 0x%02x is 0x%02x (rc = %d)\n", |
|
|
|
|
reg_addr, *reg_val, rc); |
|
|
|
|
psmouse_dbg(psmouse, |
|
|
|
|
"READ REG: 0x%02x is 0x%02x (rc = %d)\n", |
|
|
|
|
reg_addr, *reg_val, rc); |
|
|
|
|
return rc; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -179,8 +184,9 @@ static int fsp_reg_write(struct psmouse *psmouse, int reg_addr, int reg_val) |
|
|
|
|
|
|
|
|
|
out: |
|
|
|
|
ps2_end_command(ps2dev); |
|
|
|
|
dev_dbg(&ps2dev->serio->dev, "WRITE REG: 0x%02x to 0x%02x (rc = %d)\n", |
|
|
|
|
reg_addr, reg_val, rc); |
|
|
|
|
psmouse_dbg(psmouse, |
|
|
|
|
"WRITE REG: 0x%02x to 0x%02x (rc = %d)\n", |
|
|
|
|
reg_addr, reg_val, rc); |
|
|
|
|
return rc; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -237,8 +243,9 @@ static int fsp_page_reg_read(struct psmouse *psmouse, int *reg_val) |
|
|
|
|
out: |
|
|
|
|
ps2_end_command(ps2dev); |
|
|
|
|
psmouse_activate(psmouse); |
|
|
|
|
dev_dbg(&ps2dev->serio->dev, "READ PAGE REG: 0x%02x (rc = %d)\n", |
|
|
|
|
*reg_val, rc); |
|
|
|
|
psmouse_dbg(psmouse, |
|
|
|
|
"READ PAGE REG: 0x%02x (rc = %d)\n", |
|
|
|
|
*reg_val, rc); |
|
|
|
|
return rc; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -274,8 +281,9 @@ static int fsp_page_reg_write(struct psmouse *psmouse, int reg_val) |
|
|
|
|
|
|
|
|
|
out: |
|
|
|
|
ps2_end_command(ps2dev); |
|
|
|
|
dev_dbg(&ps2dev->serio->dev, "WRITE PAGE REG: to 0x%02x (rc = %d)\n", |
|
|
|
|
reg_val, rc); |
|
|
|
|
psmouse_dbg(psmouse, |
|
|
|
|
"WRITE PAGE REG: to 0x%02x (rc = %d)\n", |
|
|
|
|
reg_val, rc); |
|
|
|
|
return rc; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -319,7 +327,7 @@ static int fsp_opc_tag_enable(struct psmouse *psmouse, bool enable) |
|
|
|
|
int res = 0; |
|
|
|
|
|
|
|
|
|
if (fsp_reg_read(psmouse, FSP_REG_OPC_QDOWN, &v) == -1) { |
|
|
|
|
dev_err(&psmouse->ps2dev.serio->dev, "Unable get OPC state.\n"); |
|
|
|
|
psmouse_err(psmouse, "Unable get OPC state.\n"); |
|
|
|
|
return -EIO; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -336,8 +344,7 @@ static int fsp_opc_tag_enable(struct psmouse *psmouse, bool enable) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (res != 0) { |
|
|
|
|
dev_err(&psmouse->ps2dev.serio->dev, |
|
|
|
|
"Unable to enable OPC tag.\n"); |
|
|
|
|
psmouse_err(psmouse, "Unable to enable OPC tag.\n"); |
|
|
|
|
res = -EIO; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -615,18 +622,40 @@ static struct attribute_group fsp_attribute_group = { |
|
|
|
|
.attrs = fsp_attributes, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
#ifdef FSP_DEBUG |
|
|
|
|
static void fsp_packet_debug(unsigned char packet[]) |
|
|
|
|
#ifdef FSP_DEBUG |
|
|
|
|
static void fsp_packet_debug(struct psmouse *psmouse, unsigned char packet[]) |
|
|
|
|
{ |
|
|
|
|
static unsigned int ps2_packet_cnt; |
|
|
|
|
static unsigned int ps2_last_second; |
|
|
|
|
unsigned int jiffies_msec; |
|
|
|
|
const char *packet_type = "UNKNOWN"; |
|
|
|
|
unsigned short abs_x = 0, abs_y = 0; |
|
|
|
|
|
|
|
|
|
/* Interpret & dump the packet data. */ |
|
|
|
|
switch (packet[0] >> FSP_PKT_TYPE_SHIFT) { |
|
|
|
|
case FSP_PKT_TYPE_ABS: |
|
|
|
|
packet_type = "Absolute"; |
|
|
|
|
abs_x = GET_ABS_X(packet); |
|
|
|
|
abs_y = GET_ABS_Y(packet); |
|
|
|
|
break; |
|
|
|
|
case FSP_PKT_TYPE_NORMAL: |
|
|
|
|
packet_type = "Normal"; |
|
|
|
|
break; |
|
|
|
|
case FSP_PKT_TYPE_NOTIFY: |
|
|
|
|
packet_type = "Notify"; |
|
|
|
|
break; |
|
|
|
|
case FSP_PKT_TYPE_NORMAL_OPC: |
|
|
|
|
packet_type = "Normal-OPC"; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ps2_packet_cnt++; |
|
|
|
|
jiffies_msec = jiffies_to_msecs(jiffies); |
|
|
|
|
psmouse_dbg(psmouse, |
|
|
|
|
"%08dms PS/2 packets: %02x, %02x, %02x, %02x\n", |
|
|
|
|
jiffies_msec, packet[0], packet[1], packet[2], packet[3]); |
|
|
|
|
"%08dms %s packets: %02x, %02x, %02x, %02x; " |
|
|
|
|
"abs_x: %d, abs_y: %d\n", |
|
|
|
|
jiffies_msec, packet_type, |
|
|
|
|
packet[0], packet[1], packet[2], packet[3], abs_x, abs_y); |
|
|
|
|
|
|
|
|
|
if (jiffies_msec - ps2_last_second > 1000) { |
|
|
|
|
psmouse_dbg(psmouse, "PS/2 packets/sec = %d\n", ps2_packet_cnt); |
|
|
|
@ -635,17 +664,29 @@ static void fsp_packet_debug(unsigned char packet[]) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#else |
|
|
|
|
static void fsp_packet_debug(unsigned char packet[]) |
|
|
|
|
static void fsp_packet_debug(struct psmouse *psmouse, unsigned char packet[]) |
|
|
|
|
{ |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
static void fsp_set_slot(struct input_dev *dev, int slot, bool active, |
|
|
|
|
unsigned int x, unsigned int y) |
|
|
|
|
{ |
|
|
|
|
input_mt_slot(dev, slot); |
|
|
|
|
input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); |
|
|
|
|
if (active) { |
|
|
|
|
input_report_abs(dev, ABS_MT_POSITION_X, x); |
|
|
|
|
input_report_abs(dev, ABS_MT_POSITION_Y, y); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse) |
|
|
|
|
{ |
|
|
|
|
struct input_dev *dev = psmouse->dev; |
|
|
|
|
struct fsp_data *ad = psmouse->private; |
|
|
|
|
unsigned char *packet = psmouse->packet; |
|
|
|
|
unsigned char button_status = 0, lscroll = 0, rscroll = 0; |
|
|
|
|
unsigned short abs_x, abs_y, fgrs = 0; |
|
|
|
|
int rel_x, rel_y; |
|
|
|
|
|
|
|
|
|
if (psmouse->pktcnt < 4) |
|
|
|
@ -655,16 +696,76 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse) |
|
|
|
|
* Full packet accumulated, process it |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
fsp_packet_debug(psmouse, packet); |
|
|
|
|
|
|
|
|
|
switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) { |
|
|
|
|
case FSP_PKT_TYPE_ABS: |
|
|
|
|
dev_warn(&psmouse->ps2dev.serio->dev, |
|
|
|
|
"Unexpected absolute mode packet, ignored.\n"); |
|
|
|
|
abs_x = GET_ABS_X(packet); |
|
|
|
|
abs_y = GET_ABS_Y(packet); |
|
|
|
|
|
|
|
|
|
if (packet[0] & FSP_PB0_MFMC) { |
|
|
|
|
/*
|
|
|
|
|
* MFMC packet: assume that there are two fingers on |
|
|
|
|
* pad |
|
|
|
|
*/ |
|
|
|
|
fgrs = 2; |
|
|
|
|
|
|
|
|
|
/* MFMC packet */ |
|
|
|
|
if (packet[0] & FSP_PB0_MFMC_FGR2) { |
|
|
|
|
/* 2nd finger */ |
|
|
|
|
if (ad->last_mt_fgr == 2) { |
|
|
|
|
/*
|
|
|
|
|
* workaround for buggy firmware |
|
|
|
|
* which doesn't clear MFMC bit if |
|
|
|
|
* the 1st finger is up |
|
|
|
|
*/ |
|
|
|
|
fgrs = 1; |
|
|
|
|
fsp_set_slot(dev, 0, false, 0, 0); |
|
|
|
|
} |
|
|
|
|
ad->last_mt_fgr = 2; |
|
|
|
|
|
|
|
|
|
fsp_set_slot(dev, 1, fgrs == 2, abs_x, abs_y); |
|
|
|
|
} else { |
|
|
|
|
/* 1st finger */ |
|
|
|
|
if (ad->last_mt_fgr == 1) { |
|
|
|
|
/*
|
|
|
|
|
* workaround for buggy firmware |
|
|
|
|
* which doesn't clear MFMC bit if |
|
|
|
|
* the 2nd finger is up |
|
|
|
|
*/ |
|
|
|
|
fgrs = 1; |
|
|
|
|
fsp_set_slot(dev, 1, false, 0, 0); |
|
|
|
|
} |
|
|
|
|
ad->last_mt_fgr = 1; |
|
|
|
|
fsp_set_slot(dev, 0, fgrs != 0, abs_x, abs_y); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
/* SFAC packet */ |
|
|
|
|
|
|
|
|
|
/* no multi-finger information */ |
|
|
|
|
ad->last_mt_fgr = 0; |
|
|
|
|
|
|
|
|
|
if (abs_x != 0 && abs_y != 0) |
|
|
|
|
fgrs = 1; |
|
|
|
|
|
|
|
|
|
fsp_set_slot(dev, 0, fgrs > 0, abs_x, abs_y); |
|
|
|
|
fsp_set_slot(dev, 1, false, 0, 0); |
|
|
|
|
} |
|
|
|
|
if (fgrs > 0) { |
|
|
|
|
input_report_abs(dev, ABS_X, abs_x); |
|
|
|
|
input_report_abs(dev, ABS_Y, abs_y); |
|
|
|
|
} |
|
|
|
|
input_report_key(dev, BTN_LEFT, packet[0] & 0x01); |
|
|
|
|
input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); |
|
|
|
|
input_report_key(dev, BTN_TOUCH, fgrs); |
|
|
|
|
input_report_key(dev, BTN_TOOL_FINGER, fgrs == 1); |
|
|
|
|
input_report_key(dev, BTN_TOOL_DOUBLETAP, fgrs == 2); |
|
|
|
|
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); |
|
|
|
|
packet[0] &= ~FSP_PB0_LBTN; |
|
|
|
|
/* fall through */ |
|
|
|
|
|
|
|
|
|
case FSP_PKT_TYPE_NORMAL: |
|
|
|
@ -711,8 +812,6 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse) |
|
|
|
|
|
|
|
|
|
input_sync(dev); |
|
|
|
|
|
|
|
|
|
fsp_packet_debug(packet); |
|
|
|
|
|
|
|
|
|
return PSMOUSE_FULL_PACKET; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -736,42 +835,106 @@ static int fsp_activate_protocol(struct psmouse *psmouse) |
|
|
|
|
|
|
|
|
|
ps2_command(ps2dev, param, PSMOUSE_CMD_GETID); |
|
|
|
|
if (param[0] != 0x04) { |
|
|
|
|
dev_err(&psmouse->ps2dev.serio->dev, |
|
|
|
|
"Unable to enable 4 bytes packet format.\n"); |
|
|
|
|
psmouse_err(psmouse, |
|
|
|
|
"Unable to enable 4 bytes packet format.\n"); |
|
|
|
|
return -EIO; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &val)) { |
|
|
|
|
dev_err(&psmouse->ps2dev.serio->dev, |
|
|
|
|
"Unable to read SYSCTL5 register.\n"); |
|
|
|
|
return -EIO; |
|
|
|
|
} |
|
|
|
|
if (pad->ver < FSP_VER_STL3888_C0) { |
|
|
|
|
/* Preparing relative coordinates output for older hardware */ |
|
|
|
|
if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &val)) { |
|
|
|
|
psmouse_err(psmouse, |
|
|
|
|
"Unable to read SYSCTL5 register.\n"); |
|
|
|
|
return -EIO; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
val &= ~(FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8 | FSP_BIT_EN_AUTO_MSID8); |
|
|
|
|
/* Ensure we are not in absolute mode */ |
|
|
|
|
val &= ~FSP_BIT_EN_PKT_G0; |
|
|
|
|
if (pad->buttons == 0x06) { |
|
|
|
|
/* Left/Middle/Right & Scroll Up/Down/Right/Left */ |
|
|
|
|
val |= FSP_BIT_EN_MSID6; |
|
|
|
|
} |
|
|
|
|
if (fsp_get_buttons(psmouse, &pad->buttons)) { |
|
|
|
|
psmouse_err(psmouse, |
|
|
|
|
"Unable to retrieve number of buttons.\n"); |
|
|
|
|
return -EIO; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, val)) { |
|
|
|
|
dev_err(&psmouse->ps2dev.serio->dev, |
|
|
|
|
"Unable to set up required mode bits.\n"); |
|
|
|
|
return -EIO; |
|
|
|
|
val &= ~(FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8 | FSP_BIT_EN_AUTO_MSID8); |
|
|
|
|
/* Ensure we are not in absolute mode */ |
|
|
|
|
val &= ~FSP_BIT_EN_PKT_G0; |
|
|
|
|
if (pad->buttons == 0x06) { |
|
|
|
|
/* Left/Middle/Right & Scroll Up/Down/Right/Left */ |
|
|
|
|
val |= FSP_BIT_EN_MSID6; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, val)) { |
|
|
|
|
psmouse_err(psmouse, |
|
|
|
|
"Unable to set up required mode bits.\n"); |
|
|
|
|
return -EIO; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Enable OPC tags such that driver can tell the difference |
|
|
|
|
* between on-pad and real button click |
|
|
|
|
*/ |
|
|
|
|
if (fsp_opc_tag_enable(psmouse, true)) |
|
|
|
|
psmouse_warn(psmouse, |
|
|
|
|
"Failed to enable OPC tag mode.\n"); |
|
|
|
|
/* enable on-pad click by default */ |
|
|
|
|
pad->flags |= FSPDRV_FLAG_EN_OPC; |
|
|
|
|
|
|
|
|
|
/* Enable on-pad vertical and horizontal scrolling */ |
|
|
|
|
fsp_onpad_vscr(psmouse, true); |
|
|
|
|
fsp_onpad_hscr(psmouse, true); |
|
|
|
|
} else { |
|
|
|
|
/* Enable absolute coordinates output for Cx/Dx hardware */ |
|
|
|
|
if (fsp_reg_write(psmouse, FSP_REG_SWC1, |
|
|
|
|
FSP_BIT_SWC1_EN_ABS_1F | |
|
|
|
|
FSP_BIT_SWC1_EN_ABS_2F | |
|
|
|
|
FSP_BIT_SWC1_EN_FUP_OUT | |
|
|
|
|
FSP_BIT_SWC1_EN_ABS_CON)) { |
|
|
|
|
psmouse_err(psmouse, |
|
|
|
|
"Unable to enable absolute coordinates output.\n"); |
|
|
|
|
return -EIO; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Enable OPC tags such that driver can tell the difference between |
|
|
|
|
* on-pad and real button click |
|
|
|
|
*/ |
|
|
|
|
if (fsp_opc_tag_enable(psmouse, true)) |
|
|
|
|
dev_warn(&psmouse->ps2dev.serio->dev, |
|
|
|
|
"Failed to enable OPC tag mode.\n"); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Enable on-pad vertical and horizontal scrolling */ |
|
|
|
|
fsp_onpad_vscr(psmouse, true); |
|
|
|
|
fsp_onpad_hscr(psmouse, true); |
|
|
|
|
static int fsp_set_input_params(struct psmouse *psmouse) |
|
|
|
|
{ |
|
|
|
|
struct input_dev *dev = psmouse->dev; |
|
|
|
|
struct fsp_data *pad = psmouse->private; |
|
|
|
|
|
|
|
|
|
if (pad->ver < FSP_VER_STL3888_C0) { |
|
|
|
|
__set_bit(BTN_MIDDLE, dev->keybit); |
|
|
|
|
__set_bit(BTN_BACK, dev->keybit); |
|
|
|
|
__set_bit(BTN_FORWARD, dev->keybit); |
|
|
|
|
__set_bit(REL_WHEEL, dev->relbit); |
|
|
|
|
__set_bit(REL_HWHEEL, dev->relbit); |
|
|
|
|
} else { |
|
|
|
|
/*
|
|
|
|
|
* Hardware prior to Cx performs much better in relative mode; |
|
|
|
|
* hence, only enable absolute coordinates output as well as |
|
|
|
|
* multi-touch output for the newer hardware. |
|
|
|
|
* |
|
|
|
|
* Maximum coordinates can be computed as: |
|
|
|
|
* |
|
|
|
|
* number of scanlines * 64 - 57 |
|
|
|
|
* |
|
|
|
|
* where number of X/Y scanline lines are 16/12. |
|
|
|
|
*/ |
|
|
|
|
int abs_x = 967, abs_y = 711; |
|
|
|
|
|
|
|
|
|
__set_bit(EV_ABS, dev->evbit); |
|
|
|
|
__clear_bit(EV_REL, dev->evbit); |
|
|
|
|
__set_bit(BTN_TOUCH, dev->keybit); |
|
|
|
|
__set_bit(BTN_TOOL_FINGER, dev->keybit); |
|
|
|
|
__set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); |
|
|
|
|
__set_bit(INPUT_PROP_SEMI_MT, dev->propbit); |
|
|
|
|
|
|
|
|
|
input_set_abs_params(dev, ABS_X, 0, abs_x, 0, 0); |
|
|
|
|
input_set_abs_params(dev, ABS_Y, 0, abs_y, 0, 0); |
|
|
|
|
input_mt_init_slots(dev, 2); |
|
|
|
|
input_set_abs_params(dev, ABS_MT_POSITION_X, 0, abs_x, 0, 0); |
|
|
|
|
input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, abs_y, 0, 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
@ -829,18 +992,16 @@ static int fsp_reconnect(struct psmouse *psmouse) |
|
|
|
|
int fsp_init(struct psmouse *psmouse) |
|
|
|
|
{ |
|
|
|
|
struct fsp_data *priv; |
|
|
|
|
int ver, rev, buttons; |
|
|
|
|
int ver, rev; |
|
|
|
|
int error; |
|
|
|
|
|
|
|
|
|
if (fsp_get_version(psmouse, &ver) || |
|
|
|
|
fsp_get_revision(psmouse, &rev) || |
|
|
|
|
fsp_get_buttons(psmouse, &buttons)) { |
|
|
|
|
fsp_get_revision(psmouse, &rev)) { |
|
|
|
|
return -ENODEV; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
psmouse_info(psmouse, |
|
|
|
|
"Finger Sensing Pad, hw: %d.%d.%d, sw: %s, buttons: %d\n", |
|
|
|
|
ver >> 4, ver & 0x0F, rev, fsp_drv_ver, buttons & 7); |
|
|
|
|
psmouse_info(psmouse, "Finger Sensing Pad, hw: %d.%d.%d, sw: %s\n", |
|
|
|
|
ver >> 4, ver & 0x0F, rev, fsp_drv_ver); |
|
|
|
|
|
|
|
|
|
psmouse->private = priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL); |
|
|
|
|
if (!priv) |
|
|
|
@ -848,17 +1009,6 @@ int fsp_init(struct psmouse *psmouse) |
|
|
|
|
|
|
|
|
|
priv->ver = ver; |
|
|
|
|
priv->rev = rev; |
|
|
|
|
priv->buttons = buttons; |
|
|
|
|
|
|
|
|
|
/* enable on-pad click by default */ |
|
|
|
|
priv->flags |= FSPDRV_FLAG_EN_OPC; |
|
|
|
|
|
|
|
|
|
/* Set up various supported input event bits */ |
|
|
|
|
__set_bit(BTN_MIDDLE, psmouse->dev->keybit); |
|
|
|
|
__set_bit(BTN_BACK, psmouse->dev->keybit); |
|
|
|
|
__set_bit(BTN_FORWARD, psmouse->dev->keybit); |
|
|
|
|
__set_bit(REL_WHEEL, psmouse->dev->relbit); |
|
|
|
|
__set_bit(REL_HWHEEL, psmouse->dev->relbit); |
|
|
|
|
|
|
|
|
|
psmouse->protocol_handler = fsp_process_byte; |
|
|
|
|
psmouse->disconnect = fsp_disconnect; |
|
|
|
@ -866,16 +1016,20 @@ int fsp_init(struct psmouse *psmouse) |
|
|
|
|
psmouse->cleanup = fsp_reset; |
|
|
|
|
psmouse->pktsize = 4; |
|
|
|
|
|
|
|
|
|
/* set default packet output based on number of buttons we found */ |
|
|
|
|
error = fsp_activate_protocol(psmouse); |
|
|
|
|
if (error) |
|
|
|
|
goto err_out; |
|
|
|
|
|
|
|
|
|
/* Set up various supported input event bits */ |
|
|
|
|
error = fsp_set_input_params(psmouse); |
|
|
|
|
if (error) |
|
|
|
|
goto err_out; |
|
|
|
|
|
|
|
|
|
error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj, |
|
|
|
|
&fsp_attribute_group); |
|
|
|
|
if (error) { |
|
|
|
|
dev_err(&psmouse->ps2dev.serio->dev, |
|
|
|
|
"Failed to create sysfs attributes (%d)", error); |
|
|
|
|
psmouse_err(psmouse, |
|
|
|
|
"Failed to create sysfs attributes (%d)", error); |
|
|
|
|
goto err_out; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|