M7350/kernel/drivers/input/touchscreen/synaptics/rmi_f11.c

914 lines
32 KiB
C
Raw Normal View History

2024-09-09 08:52:07 +00:00
/**
*
* Synaptics Register Mapped Interface (RMI4) Function $11 support for 2D.
* Copyright (c) 2007 - 2011, Synaptics Incorporated
*
*/
/*
* This file is licensed under the GPL2 license.
*
*#############################################################################
* GPL
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* 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.
*
*#############################################################################
*/
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/input/rmi_platformdata.h>
#include <linux/module.h>
#include "rmi.h"
#include "rmi_drvr.h"
#include "rmi_bus.h"
#include "rmi_sensor.h"
#include "rmi_function.h"
#include "rmi_f11.h"
static int sensorMaxX;
static int sensorMaxY;
struct f11_instance_data {
struct rmi_F11_device_query *deviceInfo;
struct rmi_F11_sensor_query *sensorInfo;
struct rmi_F11_control *controlRegisters;
int button_height;
unsigned char fingerDataBufferSize;
unsigned char absDataOffset;
unsigned char absDataSize;
unsigned char relDataOffset;
unsigned char gestureDataOffset;
unsigned char *fingerDataBuffer;
/* Last X & Y seen, needed at finger lift. Was down indicates at least one finger was here. */
/* TODO: Eventually we'll need to track this info on a per finger basis. */
bool wasdown;
unsigned int oldX;
unsigned int oldY;
/* Transformations to be applied to coordinates before reporting. */
bool flipX;
bool flipY;
int offsetX;
int offsetY;
int clipXLow;
int clipXHigh;
int clipYLow;
int clipYHigh;
bool swap_axes;
bool relReport;
};
enum f11_finger_state {
F11_NO_FINGER = 0,
F11_PRESENT = 1,
F11_INACCURATE = 2,
F11_RESERVED = 3
};
static ssize_t rmi_fn_11_flip_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t rmi_fn_11_flip_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
DEVICE_ATTR(flip, 0664, rmi_fn_11_flip_show, rmi_fn_11_flip_store); /* RW attr */
static ssize_t rmi_fn_11_clip_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t rmi_fn_11_clip_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
DEVICE_ATTR(clip, 0664, rmi_fn_11_clip_show, rmi_fn_11_clip_store); /* RW attr */
static ssize_t rmi_fn_11_offset_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t rmi_fn_11_offset_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
DEVICE_ATTR(offset, 0664, rmi_fn_11_offset_show, rmi_fn_11_offset_store); /* RW attr */
static ssize_t rmi_fn_11_swap_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t rmi_fn_11_swap_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
DEVICE_ATTR(swap, 0664, rmi_fn_11_swap_show, rmi_fn_11_swap_store); /* RW attr */
static ssize_t rmi_fn_11_relreport_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t rmi_fn_11_relreport_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
DEVICE_ATTR(relreport, 0664, rmi_fn_11_relreport_show, rmi_fn_11_relreport_store); /* RW attr */
static ssize_t rmi_fn_11_maxPos_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t rmi_fn_11_maxPos_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
DEVICE_ATTR(maxPos, 0664, rmi_fn_11_maxPos_show, rmi_fn_11_maxPos_store); /* RW attr */
static void FN_11_relreport(struct rmi_function_info *rmifninfo);
/*
* There is no attention function for Fn $11 - it is left NULL
* in the function table so it is not called.
*
*/
/*
* This reads in a sample and reports the function $11 source data to the
* input subsystem. It is used for both polling and interrupt driven
* operation. This is called a lot so don't put in any informational
* printks since they will slow things way down!
*/
void FN_11_inthandler(struct rmi_function_info *rmifninfo,
unsigned int assertedIRQs)
{
/* number of touch points - fingers down in this case */
int fingerDownCount;
int finger;
struct rmi_function_device *function_device;
struct f11_instance_data *instanceData;
instanceData = (struct f11_instance_data *) rmifninfo->fndata;
fingerDownCount = 0;
function_device = rmifninfo->function_device;
/* get 2D sensor finger data */
if (rmi_read_multiple(rmifninfo->sensor, rmifninfo->funcDescriptor.dataBaseAddr,
instanceData->fingerDataBuffer, instanceData->fingerDataBufferSize)) {
printk(KERN_ERR "%s: Failed to read finger data registers.\n", __func__);
return;
}
/* First we need to count the fingers and generate some events related to that. */
for (finger = 0; finger < instanceData->sensorInfo->numberOfFingers; finger++) {
int reg;
int fingerShift;
int fingerStatus;
/* determine which data byte the finger status is in */
reg = finger/4;
/* bit shift to get finger's status */
fingerShift = (finger % 4) * 2;
fingerStatus = (instanceData->fingerDataBuffer[reg] >> fingerShift) & 3;
if (fingerStatus == F11_PRESENT || fingerStatus == F11_INACCURATE) {
fingerDownCount++;
instanceData->wasdown = true;
}
}
input_report_key(function_device->input,
BTN_TOUCH, !!fingerDownCount);
for (finger = 0; finger < instanceData->sensorInfo->numberOfFingers; finger++) {
int reg;
int fingerShift;
int fingerStatus;
int X = 0, Y = 0, Z = 0, Wy = 0, Wx = 0;
/* determine which data byte the finger status is in */
reg = finger/4;
/* bit shift to get finger's status */
fingerShift = (finger % 4) * 2;
fingerStatus = (instanceData->fingerDataBuffer[reg] >> fingerShift) & 3;
/* if finger status indicates a finger is present then
read the finger data and report it */
if (fingerStatus == F11_PRESENT || fingerStatus == F11_INACCURATE) {
if (instanceData->sensorInfo->hasAbs) {
int maxX = instanceData->controlRegisters->sensorMaxXPos;
int maxY = instanceData->controlRegisters->sensorMaxYPos;
reg = instanceData->absDataOffset + (finger * instanceData->absDataSize);
X = (instanceData->fingerDataBuffer[reg] << 4) & 0x0ff0;
X |= (instanceData->fingerDataBuffer[reg+2] & 0x0f);
Y = (instanceData->fingerDataBuffer[reg+1] << 4) & 0x0ff0;
Y |= ((instanceData->fingerDataBuffer[reg+2] & 0xf0) >> 4) & 0x0f;
/* First thing to do is swap axes if needed.
*/
if (instanceData->swap_axes) {
int temp = X;
X = Y;
Y = temp;
maxX = instanceData->controlRegisters->sensorMaxYPos;
maxY = instanceData->controlRegisters->sensorMaxXPos;
}
if (instanceData->flipX)
X = max(maxX-X, 0);
X = X - instanceData->offsetX;
X = min(max(X, instanceData->clipXLow), instanceData->clipXHigh);
if (instanceData->flipY)
Y = max(maxY-Y, 0);
Y = Y - instanceData->offsetY;
Y = min(max(Y, instanceData->clipYLow), instanceData->clipYHigh);
/* upper 4 bits of W are Wy,
lower 4 of W are Wx */
Wy = (instanceData->fingerDataBuffer[reg+3] >> 4) & 0x0f;
Wx = instanceData->fingerDataBuffer[reg+3] & 0x0f;
if (instanceData->swap_axes) {
int temp = Wx;
Wx = Wy;
Wy = temp;
}
Z = instanceData->fingerDataBuffer[reg+4];
/* if this is the first finger report normal
ABS_X, ABS_Y, PRESSURE, TOOL_WIDTH events for
non-MT apps. Apps that support Multi-touch
will ignore these events and use the MT events.
Apps that don't support Multi-touch will still
function.
*/
if (fingerDownCount == 1) {
instanceData->oldX = X;
instanceData->oldY = Y;
input_report_abs(function_device->input, ABS_X, X);
input_report_abs(function_device->input, ABS_Y, Y);
input_report_abs(function_device->input, ABS_PRESSURE, Z);
input_report_abs(function_device->input, ABS_TOOL_WIDTH,
max(Wx, Wy));
} else {
/* TODO generate non MT events for multifinger situation. */
}
#ifdef CONFIG_SYNA_MULTI_TOUCH
/* Report Multi-Touch events for each finger */
input_report_abs(function_device->input,
ABS_MT_PRESSURE, Z);
input_report_abs(function_device->input, ABS_MT_POSITION_X, X);
input_report_abs(function_device->input, ABS_MT_POSITION_Y, Y);
/* TODO: Tracking ID needs to be reported but not used yet. */
/* Could be formed by keeping an id per position and assiging */
/* a new id when fingerStatus changes for that position.*/
input_report_abs(function_device->input, ABS_MT_TRACKING_ID,
finger);
/* MT sync between fingers */
input_mt_sync(function_device->input);
#endif
}
}
}
/* if we had a finger down before and now we don't have any send a button up. */
if ((fingerDownCount == 0) && instanceData->wasdown) {
instanceData->wasdown = false;
#ifdef CONFIG_SYNA_MULTI_TOUCH
input_report_abs(function_device->input, ABS_MT_PRESSURE, 0);
input_report_key(function_device->input, BTN_TOUCH, 0);
input_mt_sync(function_device->input);
#endif
}
FN_11_relreport(rmifninfo);
input_sync(function_device->input); /* sync after groups of events */
}
EXPORT_SYMBOL(FN_11_inthandler);
/* This function reads in relative data for first finger and send to input system */
static void FN_11_relreport(struct rmi_function_info *rmifninfo)
{
struct f11_instance_data *instanceData;
struct rmi_function_device *function_device;
signed char X, Y;
unsigned short fn11DataBaseAddr;
instanceData = (struct f11_instance_data *) rmifninfo->fndata;
if (instanceData->sensorInfo->hasRel && instanceData->relReport) {
int reg = instanceData->relDataOffset;
function_device = rmifninfo->function_device;
fn11DataBaseAddr = rmifninfo->funcDescriptor.dataBaseAddr;
/* Read and report Rel data for primary finger one register for X and one for Y*/
X = instanceData->fingerDataBuffer[reg];
Y = instanceData->fingerDataBuffer[reg+1];
if (instanceData->swap_axes) {
signed char temp = X;
X = Y;
Y = temp;
}
if (instanceData->flipX) {
X = -X;
}
if (instanceData->flipY) {
Y = -Y;
}
X = (signed char) min(127, max(-128, (int) X));
Y = (signed char) min(127, max(-128, (int) Y));
input_report_rel(function_device->input, REL_X, X);
input_report_rel(function_device->input, REL_Y, Y);
}
}
int FN_11_config(struct rmi_function_info *rmifninfo)
{
/* For the data source - print info and do any
source specific configuration. */
unsigned char data[14];
int retval = 0;
pr_debug("%s: RMI4 function $11 config\n", __func__);
/* Get and print some info about the data source... */
/* To Query 2D devices we need to read from the address obtained
* from the function descriptor stored in the RMI function info.
*/
retval = rmi_read_multiple(rmifninfo->sensor, rmifninfo->funcDescriptor.queryBaseAddr,
data, 9);
if (retval) {
printk(KERN_ERR "%s: RMI4 function $11 config:"
"Could not read function query registers 0x%x\n",
__func__, rmifninfo->funcDescriptor.queryBaseAddr);
} else {
pr_debug("%s: Number of Fingers: %d\n",
__func__, data[1] & 7);
pr_debug("%s: Is Configurable: %d\n",
__func__, data[1] & (1 << 7) ? 1 : 0);
pr_debug("%s: Has Gestures: %d\n",
__func__, data[1] & (1 << 5) ? 1 : 0);
pr_debug("%s: Has Absolute: %d\n",
__func__, data[1] & (1 << 4) ? 1 : 0);
pr_debug("%s: Has Relative: %d\n",
__func__, data[1] & (1 << 3) ? 1 : 0);
pr_debug("%s: Number X Electrodes: %d\n",
__func__, data[2] & 0x1f);
pr_debug("%s: Number Y Electrodes: %d\n",
__func__, data[3] & 0x1f);
pr_debug("%s: Maximum Electrodes: %d\n",
__func__, data[4] & 0x1f);
pr_debug("%s: Absolute Data Size: %d\n",
__func__, data[5] & 3);
pr_debug("%s: Has XY Dist: %d\n",
__func__, data[7] & (1 << 7) ? 1 : 0);
pr_debug("%s: Has Pinch: %d\n",
__func__, data[7] & (1 << 6) ? 1 : 0);
pr_debug("%s: Has Press: %d\n",
__func__, data[7] & (1 << 5) ? 1 : 0);
pr_debug("%s: Has Flick: %d\n",
__func__, data[7] & (1 << 4) ? 1 : 0);
pr_debug("%s: Has Early Tap: %d\n",
__func__, data[7] & (1 << 3) ? 1 : 0);
pr_debug("%s: Has Double Tap: %d\n",
__func__, data[7] & (1 << 2) ? 1 : 0);
pr_debug("%s: Has Tap and Hold: %d\n",
__func__, data[7] & (1 << 1) ? 1 : 0);
pr_debug("%s: Has Tap: %d\n",
__func__, data[7] & 1 ? 1 : 0);
pr_debug("%s: Has Palm Detect: %d\n",
__func__, data[8] & 1 ? 1 : 0);
pr_debug("%s: Has Rotate: %d\n",
__func__, data[8] & (1 << 1) ? 1 : 0);
retval = rmi_read_multiple(rmifninfo->sensor,
rmifninfo->funcDescriptor.controlBaseAddr, data, 14);
if (retval) {
printk(KERN_ERR "%s: RMI4 function $11 config:"
"Could not read control registers 0x%x\n",
__func__, rmifninfo->funcDescriptor.controlBaseAddr);
return retval;
}
/* Store these for use later...*/
sensorMaxX = ((data[6] & 0x1f) << 8) | ((data[7] & 0xff) << 0);
sensorMaxY = ((data[8] & 0x1f) << 8) | ((data[9] & 0xff) << 0);
pr_debug("%s: Sensor Max X: %d\n", __func__, sensorMaxX);
pr_debug("%s: Sensor Max Y: %d\n", __func__, sensorMaxY);
}
return retval;
}
EXPORT_SYMBOL(FN_11_config);
/* This operation is done in a number of places, so we have a handy routine
* for it.
*/
static void f11_set_abs_params(struct rmi_function_device *function_device)
{
struct f11_instance_data *instance_data = function_device->rfi->fndata;
/* Use the max X and max Y read from the device, or the clip values,
* whichever is stricter.
*/
int xMin = instance_data->clipXLow;
int xMax = min((int) instance_data->controlRegisters->sensorMaxXPos, instance_data->clipXHigh);
int yMin = instance_data->clipYLow;
int yMax = min((int) instance_data->controlRegisters->sensorMaxYPos, instance_data->clipYHigh) - instance_data->button_height;
if (instance_data->swap_axes) {
int temp = xMin;
xMin = yMin;
yMin = temp;
temp = xMax;
xMax = yMax;
yMax = temp;
}
printk(KERN_DEBUG "%s: Set ranges X=[%d..%d] Y=[%d..%d].", __func__, xMin, xMax, yMin, yMax);
input_set_abs_params(function_device->input, ABS_X, xMin, xMax,
0, 0);
input_set_abs_params(function_device->input, ABS_Y, yMin, yMax,
0, 0);
input_set_abs_params(function_device->input, ABS_PRESSURE, 0, 255, 0, 0);
input_set_abs_params(function_device->input, ABS_TOOL_WIDTH, 0, 15, 0, 0);
#ifdef CONFIG_SYNA_MULTI_TOUCH
input_set_abs_params(function_device->input, ABS_MT_PRESSURE,
0, 15, 0, 0);
input_set_abs_params(function_device->input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
input_set_abs_params(function_device->input, ABS_MT_TRACKING_ID,
0, 10, 0, 0);
input_set_abs_params(function_device->input, ABS_MT_POSITION_X, xMin, xMax,
0, 0);
input_set_abs_params(function_device->input, ABS_MT_POSITION_Y, yMin, yMax,
0, 0);
#endif
}
/* Initialize any function $11 specific params and settings - input
* settings, device settings, etc.
*/
int FN_11_init(struct rmi_function_device *function_device)
{
struct f11_instance_data *instanceData = function_device->rfi->fndata;
int retval = 0;
struct rmi_f11_functiondata *functiondata = rmi_sensor_get_functiondata(function_device->sensor, RMI_F11_INDEX);
printk(KERN_DEBUG "%s: RMI4 F11 init", __func__);
/* TODO: Initialize these through some normal kernel mechanism.
*/
instanceData->flipX = false;
instanceData->flipY = false;
instanceData->swap_axes = false;
instanceData->relReport = true;
instanceData->offsetX = instanceData->offsetY = 0;
instanceData->clipXLow = instanceData->clipYLow = 0;
/* TODO: 65536 should actually be the largest valid RMI4 position coordinate */
instanceData->clipXHigh = instanceData->clipYHigh = 65536;
/* Load any overrides that were specified via platform data.
*/
if (functiondata) {
printk(KERN_DEBUG "%s: found F11 per function platformdata.", __func__);
instanceData->flipX = functiondata->flipX;
instanceData->flipY = functiondata->flipY;
instanceData->button_height = functiondata->button_height;
instanceData->swap_axes = functiondata->swap_axes;
if (functiondata->offset) {
instanceData->offsetX = functiondata->offset->x;
instanceData->offsetY = functiondata->offset->y;
}
if (functiondata->clipX) {
if (functiondata->clipX->min >= functiondata->clipX->max) {
printk(KERN_WARNING "%s: Clip X min (%d) >= X clip max (%d) - ignored.",
__func__, functiondata->clipX->min, functiondata->clipX->max);
} else {
instanceData->clipXLow = functiondata->clipX->min;
instanceData->clipXHigh = functiondata->clipX->max;
}
}
if (functiondata->clipY) {
if (functiondata->clipY->min >= functiondata->clipY->max) {
printk(KERN_WARNING "%s: Clip Y min (%d) >= Y clip max (%d) - ignored.",
__func__, functiondata->clipY->min, functiondata->clipY->max);
} else {
instanceData->clipYLow = functiondata->clipY->min;
instanceData->clipYHigh = functiondata->clipY->max;
}
}
}
/* need to init the input abs params for the 2D */
set_bit(EV_ABS, function_device->input->evbit);
set_bit(EV_SYN, function_device->input->evbit);
set_bit(EV_KEY, function_device->input->evbit);
set_bit(BTN_TOUCH, function_device->input->keybit);
set_bit(KEY_OK, function_device->input->keybit);
f11_set_abs_params(function_device);
printk(KERN_DEBUG "%s: Creating sysfs files.", __func__);
retval = device_create_file(&function_device->dev, &dev_attr_flip);
if (retval) {
printk(KERN_ERR "%s: Failed to create flip.", __func__);
return retval;
}
retval = device_create_file(&function_device->dev, &dev_attr_clip);
if (retval) {
printk(KERN_ERR "%s: Failed to create clip.", __func__);
return retval;
}
retval = device_create_file(&function_device->dev, &dev_attr_offset);
if (retval) {
printk(KERN_ERR "%s: Failed to create offset.", __func__);
return retval;
}
retval = device_create_file(&function_device->dev, &dev_attr_swap);
if (retval) {
printk(KERN_ERR "%s: Failed to create swap.", __func__);
return retval;
}
retval = device_create_file(&function_device->dev, &dev_attr_relreport);
if (retval) {
printk(KERN_ERR "%s: Failed to create relreport.", __func__);
return retval;
}
retval = device_create_file(&function_device->dev, &dev_attr_maxPos);
if (retval) {
printk(KERN_ERR "%s: Failed to create maxPos.", __func__);
return retval;
}
return 0;
}
EXPORT_SYMBOL(FN_11_init);
int FN_11_detect(struct rmi_function_info *rmifninfo,
struct rmi_function_descriptor *fndescr, unsigned int interruptCount)
{
unsigned char fn11Queries[12]; /* TODO: Compute size correctly. */
unsigned char fn11Control[12]; /* TODO: Compute size correctly. */
int i;
unsigned short fn11InterruptOffset;
unsigned char fn11AbsDataBlockSize;
int fn11HasPinch, fn11HasFlick, fn11HasTap;
int fn11HasTapAndHold, fn11HasDoubleTap;
int fn11HasEarlyTap, fn11HasPress;
int fn11HasPalmDetect, fn11HasRotate;
int fn11HasRel;
unsigned char f11_egr_0, f11_egr_1;
unsigned int fn11AllDataBlockSize;
int retval = 0;
struct f11_instance_data *instanceData;
printk(KERN_DEBUG "%s: RMI4 F11 detect\n", __func__);
instanceData = kzalloc(sizeof(struct f11_instance_data), GFP_KERNEL);
if (!instanceData) {
printk(KERN_ERR "%s: Error allocating F11 instance data.\n", __func__);
return -ENOMEM;
}
instanceData->deviceInfo = kzalloc(sizeof(struct rmi_F11_device_query), GFP_KERNEL);
if (!instanceData->deviceInfo) {
printk(KERN_ERR "%s: Error allocating F11 device query.\n", __func__);
return -ENOMEM;
}
instanceData->sensorInfo = kzalloc(sizeof(struct rmi_F11_sensor_query), GFP_KERNEL);
if (!instanceData->sensorInfo) {
printk(KERN_ERR "%s: Error allocating F11 sensor query.\n", __func__);
return -ENOMEM;
}
rmifninfo->fndata = instanceData;
/* Store addresses - used elsewhere to read data,
* control, query, etc. */
rmifninfo->funcDescriptor.queryBaseAddr = fndescr->queryBaseAddr;
rmifninfo->funcDescriptor.commandBaseAddr = fndescr->commandBaseAddr;
rmifninfo->funcDescriptor.controlBaseAddr = fndescr->controlBaseAddr;
rmifninfo->funcDescriptor.dataBaseAddr = fndescr->dataBaseAddr;
rmifninfo->funcDescriptor.interruptSrcCnt = fndescr->interruptSrcCnt;
rmifninfo->funcDescriptor.functionNum = fndescr->functionNum;
rmifninfo->numSources = fndescr->interruptSrcCnt;
/* need to get number of fingers supported, data size, etc. -
to be used when getting data since the number of registers to
read depends on the number of fingers supported and data size. */
retval = rmi_read_multiple(rmifninfo->sensor, fndescr->queryBaseAddr, fn11Queries,
sizeof(fn11Queries));
if (retval) {
printk(KERN_ERR "%s: RMI4 function $11 detect: "
"Could not read function query registers 0x%x\n",
__func__, rmifninfo->funcDescriptor.queryBaseAddr);
return retval;
}
/* Extract device data. */
instanceData->deviceInfo->hasQuery9 = (fn11Queries[0] & 0x04) != 0;
instanceData->deviceInfo->numberOfSensors = (fn11Queries[0] & 0x07) + 1;
printk(KERN_DEBUG "%s: F11 device - %d sensors. Query 9? %d.", __func__, instanceData->deviceInfo->numberOfSensors, instanceData->deviceInfo->hasQuery9);
/* Extract sensor data. */
/* 2D data sources have only 3 bits for the number of fingers
supported - so the encoding is a bit wierd. */
instanceData->sensorInfo->numberOfFingers = 2; /* default number of fingers supported */
if ((fn11Queries[1] & 0x7) <= 4)
/* add 1 since zero based */
instanceData->sensorInfo->numberOfFingers = (fn11Queries[1] & 0x7) + 1;
else {
/* a value of 5 is up to 10 fingers - 6 and 7 are reserved
(shouldn't get these i int retval;n a normal 2D source). */
if ((fn11Queries[1] & 0x7) == 5)
instanceData->sensorInfo->numberOfFingers = 10;
}
instanceData->sensorInfo->configurable = (fn11Queries[1] & 0x80) != 0;
instanceData->sensorInfo->hasSensitivityAdjust = (fn11Queries[1] & 0x40) != 0;
instanceData->sensorInfo->hasGestures = (fn11Queries[1] & 0x20) != 0;
instanceData->sensorInfo->hasAbs = (fn11Queries[1] & 0x10) != 0;
instanceData->sensorInfo->hasRel = (fn11Queries[1] & 0x08) != 0;
instanceData->sensorInfo->absDataSize = fn11Queries[5] & 0x03;
printk(KERN_DEBUG "%s: Number of fingers: %d.", __func__, instanceData->sensorInfo->numberOfFingers);
/* Need to get interrupt info to be used later when handling
interrupts. */
rmifninfo->interruptRegister = interruptCount/8;
/* loop through interrupts for each source in fn $11 and or in a bit
to the interrupt mask for each. */
fn11InterruptOffset = interruptCount % 8;
for (i = fn11InterruptOffset;
i < ((fndescr->interruptSrcCnt & 0x7) + fn11InterruptOffset);
i++)
rmifninfo->interruptMask |= 1 << i;
/* Figure out just how much data we'll need to read. */
instanceData->fingerDataBufferSize = (instanceData->sensorInfo->numberOfFingers + 3) / 4;
/* One each for X and Y, one for LSB for X & Y, one for W, one for Z */
fn11AbsDataBlockSize = 5;
if (instanceData->sensorInfo->absDataSize != 0)
printk(KERN_WARNING "%s: Unrecognized abs data size %d ignored.", __func__, instanceData->sensorInfo->absDataSize);
if (instanceData->sensorInfo->hasAbs) {
instanceData->absDataSize = fn11AbsDataBlockSize;
instanceData->absDataOffset = instanceData->fingerDataBufferSize;
instanceData->fingerDataBufferSize += instanceData->sensorInfo->numberOfFingers * fn11AbsDataBlockSize;
}
if (instanceData->sensorInfo->hasRel) {
instanceData->relDataOffset = ((instanceData->sensorInfo->numberOfFingers + 3) / 4) +
/* absolute data, per finger times number of fingers */
(fn11AbsDataBlockSize * instanceData->sensorInfo->numberOfFingers);
instanceData->fingerDataBufferSize += instanceData->sensorInfo->numberOfFingers * 2;
}
if (instanceData->sensorInfo->hasGestures) {
instanceData->gestureDataOffset = instanceData->fingerDataBufferSize;
printk(KERN_WARNING "%s: WARNING Need to correctly compute gesture data location.", __func__);
}
/* need to determine the size of data to read - this depends on
conditions such as whether Relative data is reported and if Gesture
data is reported. */
f11_egr_0 = fn11Queries[7];
f11_egr_1 = fn11Queries[8];
/* Get info about what EGR data is supported, whether it has
Relative data supported, etc. */
fn11HasPinch = f11_egr_0 & 0x40;
fn11HasFlick = f11_egr_0 & 0x10;
fn11HasTap = f11_egr_0 & 0x01;
fn11HasTapAndHold = f11_egr_0 & 0x02;
fn11HasDoubleTap = f11_egr_0 & 0x04;
fn11HasEarlyTap = f11_egr_0 & 0x08;
fn11HasPress = f11_egr_0 & 0x20;
fn11HasPalmDetect = f11_egr_1 & 0x01;
fn11HasRotate = f11_egr_1 & 0x02;
fn11HasRel = fn11Queries[1] & 0x08;
/* Size of all data including finger status, absolute data for each
finger, relative data and EGR data */
fn11AllDataBlockSize =
/* finger status, four fingers per register */
((instanceData->sensorInfo->numberOfFingers + 3) / 4) +
/* absolute data, per finger times number of fingers */
(fn11AbsDataBlockSize * instanceData->sensorInfo->numberOfFingers) +
/* two relative registers (if relative is being reported) */
2 * fn11HasRel +
/* F11_2D_Data8 is only present if the egr_0
register is non-zero. */
!!(f11_egr_0) +
/* F11_2D_Data9 is only present if either egr_0 or
egr_1 registers are non-zero. */
(f11_egr_0 || f11_egr_1) +
/* F11_2D_Data10 is only present if EGR_PINCH or EGR_FLICK of
egr_0 reports as 1. */
!!(fn11HasPinch | fn11HasFlick) +
/* F11_2D_Data11 and F11_2D_Data12 are only present if
EGR_FLICK of egr_0 reports as 1. */
2 * !!(fn11HasFlick);
instanceData->fingerDataBuffer = kcalloc(instanceData->fingerDataBufferSize, sizeof(unsigned char), GFP_KERNEL);
if (!instanceData->fingerDataBuffer) {
printk(KERN_ERR "%s: Failed to allocate finger data buffer.", __func__);
return -ENOMEM;
}
/* Grab a copy of the control registers. */
instanceData->controlRegisters = kzalloc(sizeof(struct rmi_F11_control), GFP_KERNEL);
if (!instanceData->controlRegisters) {
printk(KERN_ERR "%s: Error allocating F11 control registers.\n", __func__);
return -ENOMEM;
}
retval = rmi_read_multiple(rmifninfo->sensor, fndescr->controlBaseAddr,
fn11Control, sizeof(fn11Control));
if (retval) {
printk(KERN_ERR "%s: Failed to read F11 control registers.", __func__);
return retval;
}
instanceData->controlRegisters->sensorMaxXPos = (((int) fn11Control[7] & 0x0F) << 8) + fn11Control[6];
instanceData->controlRegisters->sensorMaxYPos = (((int) fn11Control[9] & 0x0F) << 8) + fn11Control[8];
printk(KERN_DEBUG "%s: Max X %d Max Y %d", __func__, instanceData->controlRegisters->sensorMaxXPos, instanceData->controlRegisters->sensorMaxYPos);
return 0;
}
EXPORT_SYMBOL(FN_11_detect);
static ssize_t rmi_fn_11_maxPos_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct rmi_function_device *fn = dev_get_drvdata(dev);
struct f11_instance_data *instance_data = (struct f11_instance_data *)fn->rfi->fndata;
return sprintf(buf, "%u %u\n", instance_data->controlRegisters->sensorMaxXPos, instance_data->controlRegisters->sensorMaxYPos);
}
static ssize_t rmi_fn_11_maxPos_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
return -EPERM;
}
static ssize_t rmi_fn_11_flip_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct rmi_function_device *fn = dev_get_drvdata(dev);
struct f11_instance_data *instance_data = (struct f11_instance_data *)fn->rfi->fndata;
return sprintf(buf, "%u %u\n", instance_data->flipX, instance_data->flipY);
}
static ssize_t rmi_fn_11_flip_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct rmi_function_device *fn = dev_get_drvdata(dev);
struct f11_instance_data *instance_data = (struct f11_instance_data *)fn->rfi->fndata;
unsigned int newX, newY;
printk(KERN_DEBUG "%s: Flip set to %s", __func__, buf);
if (sscanf(buf, "%u %u", &newX, &newY) != 2)
return -EINVAL;
if (newX < 0 || newX > 1 || newY < 0 || newY > 1)
return -EINVAL;
instance_data->flipX = newX;
instance_data->flipY = newY;
return count;
}
static ssize_t rmi_fn_11_swap_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct rmi_function_device *fn = dev_get_drvdata(dev);
struct f11_instance_data *instance_data = (struct f11_instance_data *)fn->rfi->fndata;
return sprintf(buf, "%u\n", instance_data->swap_axes);
}
static ssize_t rmi_fn_11_swap_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct rmi_function_device *fn = dev_get_drvdata(dev);
struct f11_instance_data *instance_data = (struct f11_instance_data *)fn->rfi->fndata;
unsigned int newSwap;
printk(KERN_DEBUG "%s: Swap set to %s", __func__, buf);
if (sscanf(buf, "%u", &newSwap) != 1)
return -EINVAL;
if (newSwap < 0 || newSwap > 1)
return -EINVAL;
instance_data->swap_axes = newSwap;
f11_set_abs_params(fn);
return count;
}
static ssize_t rmi_fn_11_relreport_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct rmi_function_device *fn = dev_get_drvdata(dev);
struct f11_instance_data *instance_data = (struct f11_instance_data *)fn->rfi->fndata;
return sprintf(buf, "%u \n", instance_data->relReport);
}
static ssize_t rmi_fn_11_relreport_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct rmi_function_device *fn = dev_get_drvdata(dev);
struct f11_instance_data *instance_data = (struct f11_instance_data *)fn->rfi->fndata;
unsigned int relRep;
printk(KERN_DEBUG "%s: relReport set to %s", __func__, buf);
if (sscanf(buf, "%u", &relRep) != 1)
return -EINVAL;
if (relRep < 0 || relRep > 1)
return -EINVAL;
instance_data->relReport = relRep;
return count;
}
static ssize_t rmi_fn_11_offset_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct rmi_function_device *fn = dev_get_drvdata(dev);
struct f11_instance_data *instance_data = (struct f11_instance_data *)fn->rfi->fndata;
return sprintf(buf, "%d %d\n", instance_data->offsetX, instance_data->offsetY);
}
static ssize_t rmi_fn_11_offset_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct rmi_function_device *fn = dev_get_drvdata(dev);
struct f11_instance_data *instance_data = (struct f11_instance_data *)fn->rfi->fndata;
int newX, newY;
printk(KERN_DEBUG "%s: Offset set to %s", __func__, buf);
if (sscanf(buf, "%d %d", &newX, &newY) != 2)
return -EINVAL;
instance_data->offsetX = newX;
instance_data->offsetY = newY;
return count;
}
static ssize_t rmi_fn_11_clip_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct rmi_function_device *fn = dev_get_drvdata(dev);
struct f11_instance_data *instance_data = (struct f11_instance_data *)fn->rfi->fndata;
return sprintf(buf, "%u %u %u %u\n",
instance_data->clipXLow, instance_data->clipXHigh,
instance_data->clipYLow, instance_data->clipYHigh);
}
static ssize_t rmi_fn_11_clip_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct rmi_function_device *fn = dev_get_drvdata(dev);
struct f11_instance_data *instance_data = (struct f11_instance_data *)fn->rfi->fndata;
unsigned int newXLow, newXHigh, newYLow, newYHigh;
printk(KERN_DEBUG "%s: Clip set to %s", __func__, buf);
if (sscanf(buf, "%u %u %u %u", &newXLow, &newXHigh, &newYLow, &newYHigh) != 4)
return -EINVAL;
if (newXLow < 0 || newXLow >= newXHigh || newYLow < 0 || newYLow >= newYHigh)
return -EINVAL;
instance_data->clipXLow = newXLow;
instance_data->clipXHigh = newXHigh;
instance_data->clipYLow = newYLow;
instance_data->clipYHigh = newYHigh;
f11_set_abs_params(fn);
return count;
}