| /** |
| * |
| * 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; |
| } |