mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-10 06:09:23 -04:00
synaptics_mmi: multiple instances of rmidev
RMI device is utilized to connect to Design Studio tool. Original rmidev code did not support multiple instances running concurrently. This commit adds this feature Change-Id: Iaada97a065b4516bc40240f3d1bf2faadec673cd Signed-off-by: Konstantin Makariev <hcv867@motorola.com> Reviewed-on: https://gerrit.mot.com/1283410 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Reviewed-by: Konstantin Makariev <kmakariev@motorola.com> Submit-Approved: Jira Key
This commit is contained in:
parent
7b676b371b
commit
9b30ff54ec
4 changed files with 212 additions and 123 deletions
|
|
@ -13,11 +13,11 @@ LOCAL_MODULE_TAGS := optional
|
|||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
||||
|
||||
#include $(CLEAR_VARS)
|
||||
#LOCAL_MODULE := synaptics_dsx_rmi_dev.ko
|
||||
#LOCAL_MODULE_TAGS := optional
|
||||
#LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
#include $(DLKM_DIR)/AndroidKernelModule.mk
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := synaptics_dsx_rmi_dev.ko
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
||||
|
||||
#This requires F54 support, thus disable it for now
|
||||
#include $(CLEAR_VARS)
|
||||
|
|
|
|||
|
|
@ -11,5 +11,6 @@ endif
|
|||
|
||||
obj-m += synaptics_mmi.o
|
||||
obj-m += synaptics_dsx_fw_update.o
|
||||
obj-m += synaptics_dsx_rmi_dev.o
|
||||
#obj-m += synaptics_dsx_rmi_dev.o
|
||||
#obj-m += synaptics_dsx_test_reporting.o
|
||||
|
|
|
|||
|
|
@ -585,6 +585,7 @@ struct synaptics_rmi4_data {
|
|||
char *reset_name;
|
||||
|
||||
void *fwu_data;
|
||||
void *rmidev_data;
|
||||
};
|
||||
|
||||
struct pdt_properties {
|
||||
|
|
|
|||
|
|
@ -32,8 +32,24 @@
|
|||
#define CHAR_DEVICE_NAME "rmi"
|
||||
#define DEVICE_CLASS_NAME "rmidev"
|
||||
#define DEV_NUMBER 1
|
||||
#define MAX_INSTANCE 5
|
||||
#define REG_ADDR_LIMIT 0xFFFF
|
||||
|
||||
static char *rmi_cdev_node(struct device *dev, umode_t *mode)
|
||||
{
|
||||
if (mode)
|
||||
*mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
|
||||
return kasprintf(GFP_KERNEL, "rmi/%s", dev_name(dev));
|
||||
}
|
||||
|
||||
static struct class rmi_device_class = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DEVICE_CLASS_NAME,
|
||||
.devnode = rmi_cdev_node,
|
||||
};
|
||||
|
||||
static int rmidev_major_num;
|
||||
|
||||
static ssize_t rmidev_sysfs_data_show(struct file *data_file,
|
||||
struct kobject *kobj, struct bin_attribute *attributes,
|
||||
char *buf, loff_t pos, size_t count);
|
||||
|
|
@ -64,7 +80,7 @@ struct rmidev_handle {
|
|||
struct device dev;
|
||||
struct synaptics_rmi4_data *rmi4_data;
|
||||
struct synaptics_rmi4_exp_fn_ptr *fn_ptr;
|
||||
struct kobject *sysfs_dir;
|
||||
struct completion remove_complete;
|
||||
void *data;
|
||||
};
|
||||
|
||||
|
|
@ -77,7 +93,7 @@ struct rmidev_data {
|
|||
struct temp_buffer data_buf;
|
||||
};
|
||||
|
||||
static struct bin_attribute attr_data = {
|
||||
static const struct bin_attribute attr_data = {
|
||||
.attr = {
|
||||
.name = "data",
|
||||
.mode = (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
|
|
@ -87,7 +103,7 @@ static struct bin_attribute attr_data = {
|
|||
.write = rmidev_sysfs_data_store,
|
||||
};
|
||||
|
||||
static struct device_attribute attrs[] = {
|
||||
static const struct device_attribute attrs[] = {
|
||||
__ATTR(open, S_IWUSR | S_IWGRP,
|
||||
NULL,
|
||||
rmidev_sysfs_open_store),
|
||||
|
|
@ -105,38 +121,37 @@ static struct device_attribute attrs[] = {
|
|||
NULL),
|
||||
};
|
||||
|
||||
static int rmidev_major_num;
|
||||
|
||||
static struct class *rmidev_device_class;
|
||||
|
||||
static struct rmidev_handle *rmidev;
|
||||
|
||||
static struct completion remove_complete;
|
||||
|
||||
static ssize_t rmidev_sysfs_data_show(struct file *data_file,
|
||||
struct kobject *kobj, struct bin_attribute *attributes,
|
||||
char *buf, loff_t pos, size_t count)
|
||||
{
|
||||
struct rmidev_data *dev_data = data_file->private_data;
|
||||
struct rmidev_handle *rmidev = dev_data->rmi_dev;
|
||||
struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
|
||||
int retval;
|
||||
unsigned int data_length = rmidev->length;
|
||||
|
||||
dev_dbg(&rmi4_data->i2c_client->dev,
|
||||
"%s: dev_data %p, rmidev %p, rmi4_data %p\n",
|
||||
__func__, dev_data, rmidev, rmi4_data);
|
||||
|
||||
if (data_length > (REG_ADDR_LIMIT - rmidev->address))
|
||||
data_length = REG_ADDR_LIMIT - rmidev->address;
|
||||
|
||||
if (count < data_length) {
|
||||
dev_err(&rmidev->rmi4_data->i2c_client->dev,
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s: Not enough space (%zu bytes) in buffer\n",
|
||||
__func__, count);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (data_length) {
|
||||
retval = rmidev->fn_ptr->read(rmidev->rmi4_data,
|
||||
retval = rmidev->fn_ptr->read(rmi4_data,
|
||||
rmidev->address,
|
||||
(unsigned char *)buf,
|
||||
data_length);
|
||||
if (retval < 0) {
|
||||
dev_err(&rmidev->rmi4_data->i2c_client->dev,
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to read data\n",
|
||||
__func__);
|
||||
return retval;
|
||||
|
|
@ -152,9 +167,16 @@ static ssize_t rmidev_sysfs_data_store(struct file *data_file,
|
|||
struct kobject *kobj, struct bin_attribute *attributes,
|
||||
char *buf, loff_t pos, size_t count)
|
||||
{
|
||||
struct rmidev_data *dev_data = data_file->private_data;
|
||||
struct rmidev_handle *rmidev = dev_data->rmi_dev;
|
||||
struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
|
||||
int retval;
|
||||
unsigned int data_length = rmidev->length;
|
||||
|
||||
dev_dbg(&rmi4_data->i2c_client->dev,
|
||||
"%s: dev_data %p, rmidev %p, rmi4_data %p\n",
|
||||
__func__, dev_data, rmidev, rmi4_data);
|
||||
|
||||
if (data_length > (REG_ADDR_LIMIT - rmidev->address))
|
||||
data_length = REG_ADDR_LIMIT - rmidev->address;
|
||||
|
||||
|
|
@ -179,16 +201,24 @@ static ssize_t rmidev_sysfs_data_store(struct file *data_file,
|
|||
static ssize_t rmidev_sysfs_open_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct rmidev_data *dev_data =
|
||||
dev_get_drvdata(dev);
|
||||
struct rmidev_handle *rmidev = dev_data->rmi_dev;
|
||||
struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
|
||||
unsigned int input;
|
||||
|
||||
dev_dbg(&rmi4_data->i2c_client->dev,
|
||||
"%s: dev_data %p, rmidev %p, rmi4_data %p\n",
|
||||
__func__, dev_data, rmidev, rmi4_data);
|
||||
|
||||
if (sscanf(buf, "%u", &input) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (input != 1)
|
||||
return -EINVAL;
|
||||
|
||||
rmidev->fn_ptr->enable(rmidev->rmi4_data, false);
|
||||
dev_dbg(&rmidev->rmi4_data->i2c_client->dev,
|
||||
rmidev->fn_ptr->enable(rmi4_data, false);
|
||||
dev_dbg(&rmi4_data->i2c_client->dev,
|
||||
"%s: Attention interrupt disabled\n",
|
||||
__func__);
|
||||
|
||||
|
|
@ -198,16 +228,24 @@ static ssize_t rmidev_sysfs_open_store(struct device *dev,
|
|||
static ssize_t rmidev_sysfs_release_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct rmidev_data *dev_data =
|
||||
dev_get_drvdata(dev);
|
||||
struct rmidev_handle *rmidev = dev_data->rmi_dev;
|
||||
struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
|
||||
unsigned int input;
|
||||
|
||||
dev_dbg(&rmi4_data->i2c_client->dev,
|
||||
"%s: dev_data %p, rmidev %p, rmi4_data %p\n",
|
||||
__func__, dev_data, rmidev, rmi4_data);
|
||||
|
||||
if (sscanf(buf, "%u", &input) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (input != 1)
|
||||
return -EINVAL;
|
||||
|
||||
rmidev->fn_ptr->enable(rmidev->rmi4_data, true);
|
||||
dev_dbg(&rmidev->rmi4_data->i2c_client->dev,
|
||||
rmidev->fn_ptr->enable(rmi4_data, true);
|
||||
dev_dbg(&rmi4_data->i2c_client->dev,
|
||||
"%s: Attention interrupt enabled\n",
|
||||
__func__);
|
||||
|
||||
|
|
@ -217,8 +255,16 @@ static ssize_t rmidev_sysfs_release_store(struct device *dev,
|
|||
static ssize_t rmidev_sysfs_address_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct rmidev_data *dev_data =
|
||||
dev_get_drvdata(dev);
|
||||
struct rmidev_handle *rmidev = dev_data->rmi_dev;
|
||||
struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
|
||||
unsigned int input;
|
||||
|
||||
dev_dbg(&rmi4_data->i2c_client->dev,
|
||||
"%s: dev_data %p, rmidev %p, rmi4_data %p\n",
|
||||
__func__, dev_data, rmidev, rmi4_data);
|
||||
|
||||
if (sscanf(buf, "%u", &input) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -233,8 +279,16 @@ static ssize_t rmidev_sysfs_address_store(struct device *dev,
|
|||
static ssize_t rmidev_sysfs_length_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct rmidev_data *dev_data =
|
||||
dev_get_drvdata(dev);
|
||||
struct rmidev_handle *rmidev = dev_data->rmi_dev;
|
||||
struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
|
||||
unsigned int input;
|
||||
|
||||
dev_dbg(&rmi4_data->i2c_client->dev,
|
||||
"%s: dev_data %p, rmidev %p, rmi4_data %p\n",
|
||||
__func__, dev_data, rmidev, rmi4_data);
|
||||
|
||||
if (sscanf(buf, "%u", &input) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -249,9 +303,17 @@ static ssize_t rmidev_sysfs_length_store(struct device *dev,
|
|||
static ssize_t rmidev_sysfs_attn_state_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct rmidev_data *dev_data =
|
||||
dev_get_drvdata(dev);
|
||||
struct rmidev_handle *rmidev = dev_data->rmi_dev;
|
||||
struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data;
|
||||
int attn_state;
|
||||
const struct synaptics_dsx_platform_data *platform_data =
|
||||
rmidev->rmi4_data->board;
|
||||
&rmi4_data->board;
|
||||
|
||||
dev_dbg(&rmi4_data->i2c_client->dev,
|
||||
"%s: dev_data %p, rmidev %p, rmi4_data %p\n",
|
||||
__func__, dev_data, rmidev, rmi4_data);
|
||||
|
||||
attn_state = gpio_get_value(platform_data->irq_gpio);
|
||||
|
||||
|
|
@ -276,12 +338,16 @@ static loff_t rmidev_llseek(struct file *filp, loff_t off, int whence)
|
|||
{
|
||||
loff_t newpos;
|
||||
struct rmidev_data *dev_data = filp->private_data;
|
||||
struct rmidev_handle *rmidev;
|
||||
struct synaptics_rmi4_data *rmi4_data;
|
||||
|
||||
if (IS_ERR(dev_data)) {
|
||||
pr_err("%s: Pointer of char device data is invalid", __func__);
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
rmidev = dev_data->rmi_dev;
|
||||
rmi4_data = rmidev->rmi4_data;
|
||||
mutex_lock(&(dev_data->file_mutex));
|
||||
|
||||
switch (whence) {
|
||||
|
|
@ -308,7 +374,9 @@ static loff_t rmidev_llseek(struct file *filp, loff_t off, int whence)
|
|||
}
|
||||
|
||||
filp->f_pos = newpos;
|
||||
|
||||
dev_dbg(&rmi4_data->i2c_client->dev,
|
||||
"%s: current position set %lld\n",
|
||||
__func__, newpos);
|
||||
clean_up:
|
||||
mutex_unlock(&(dev_data->file_mutex));
|
||||
|
||||
|
|
@ -329,15 +397,18 @@ static ssize_t rmidev_read(struct file *filp, char __user *buf,
|
|||
ssize_t retval;
|
||||
struct rmidev_data *dev_data = filp->private_data;
|
||||
struct temp_buffer *tb;
|
||||
struct rmidev_handle *rmidev;
|
||||
struct synaptics_rmi4_data *rmi4_data;
|
||||
|
||||
if (IS_ERR(dev_data)) {
|
||||
pr_err("%s: Pointer of char device data is invalid", __func__);
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
rmidev = dev_data->rmi_dev;
|
||||
rmi4_data = rmidev->rmi4_data;
|
||||
mutex_lock(&(dev_data->file_mutex));
|
||||
|
||||
|
||||
if (count > (REG_ADDR_LIMIT - *f_pos))
|
||||
count = REG_ADDR_LIMIT - *f_pos;
|
||||
|
||||
|
|
@ -365,6 +436,10 @@ static ssize_t rmidev_read(struct file *filp, char __user *buf,
|
|||
if (retval < 0)
|
||||
goto clean_up;
|
||||
|
||||
dev_dbg(&rmi4_data->i2c_client->dev,
|
||||
"%s: read %zu bytes at offset %lld\n",
|
||||
__func__, count, *f_pos);
|
||||
|
||||
if (copy_to_user(buf, tb->buf, count))
|
||||
retval = -EFAULT;
|
||||
else
|
||||
|
|
@ -390,12 +465,16 @@ static ssize_t rmidev_write(struct file *filp, const char __user *buf,
|
|||
ssize_t retval;
|
||||
struct rmidev_data *dev_data = filp->private_data;
|
||||
struct temp_buffer *tb;
|
||||
struct rmidev_handle *rmidev;
|
||||
struct synaptics_rmi4_data *rmi4_data;
|
||||
|
||||
if (IS_ERR(dev_data)) {
|
||||
pr_err("%s: Pointer of char device data is invalid", __func__);
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
rmidev = dev_data->rmi_dev;
|
||||
rmi4_data = rmidev->rmi4_data;
|
||||
mutex_lock(&(dev_data->file_mutex));
|
||||
|
||||
if (*f_pos > REG_ADDR_LIMIT) {
|
||||
|
|
@ -423,6 +502,10 @@ static ssize_t rmidev_write(struct file *filp, const char __user *buf,
|
|||
goto clean_up;
|
||||
}
|
||||
|
||||
dev_dbg(&rmi4_data->i2c_client->dev,
|
||||
"%s: write %zu bytes at offset %lld\n",
|
||||
__func__, count, *f_pos);
|
||||
|
||||
retval = rmidev->fn_ptr->write(rmidev->rmi4_data,
|
||||
*f_pos,
|
||||
tb->buf,
|
||||
|
|
@ -446,12 +529,17 @@ static int rmidev_open(struct inode *inp, struct file *filp)
|
|||
int retval = 0;
|
||||
struct rmidev_data *dev_data =
|
||||
container_of(inp->i_cdev, struct rmidev_data, main_dev);
|
||||
struct rmidev_handle *rmidev;
|
||||
|
||||
if (!dev_data)
|
||||
return -EACCES;
|
||||
|
||||
filp->private_data = dev_data;
|
||||
rmidev = dev_data->rmi_dev;
|
||||
dev_dbg(&rmidev->rmi4_data->i2c_client->dev,
|
||||
"%s: device data %p\n",
|
||||
__func__, dev_data);
|
||||
|
||||
filp->private_data = dev_data;
|
||||
mutex_lock(&(dev_data->file_mutex));
|
||||
|
||||
rmidev->fn_ptr->enable(rmidev->rmi4_data, false);
|
||||
|
|
@ -478,10 +566,13 @@ static int rmidev_release(struct inode *inp, struct file *filp)
|
|||
{
|
||||
struct rmidev_data *dev_data =
|
||||
container_of(inp->i_cdev, struct rmidev_data, main_dev);
|
||||
struct rmidev_handle *rmidev;
|
||||
|
||||
if (!dev_data)
|
||||
return -EACCES;
|
||||
|
||||
rmidev = dev_data->rmi_dev;
|
||||
|
||||
mutex_lock(&(dev_data->file_mutex));
|
||||
|
||||
dev_data->ref_count--;
|
||||
|
|
@ -509,9 +600,10 @@ static const struct file_operations rmidev_fops = {
|
|||
|
||||
static void rmidev_device_cleanup(struct rmidev_data *dev_data)
|
||||
{
|
||||
dev_t devno;
|
||||
|
||||
if (dev_data) {
|
||||
dev_t devno;
|
||||
struct rmidev_handle *rmidev = dev_data->rmi_dev;
|
||||
|
||||
devno = dev_data->main_dev.dev;
|
||||
|
||||
if (dev_data->device_class)
|
||||
|
|
@ -519,7 +611,7 @@ static void rmidev_device_cleanup(struct rmidev_data *dev_data)
|
|||
|
||||
cdev_del(&dev_data->main_dev);
|
||||
|
||||
unregister_chrdev_region(devno, 1);
|
||||
unregister_chrdev_region(devno, MAX_INSTANCE);
|
||||
|
||||
dev_dbg(&rmidev->rmi4_data->i2c_client->dev,
|
||||
"%s: rmidev device removed\n",
|
||||
|
|
@ -529,47 +621,17 @@ static void rmidev_device_cleanup(struct rmidev_data *dev_data)
|
|||
return;
|
||||
}
|
||||
|
||||
static char *rmi_char_devnode(struct device *dev, umode_t *mode)
|
||||
{
|
||||
if (!mode)
|
||||
return NULL;
|
||||
|
||||
*mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
|
||||
|
||||
return kasprintf(GFP_KERNEL, "rmi/%s", dev_name(dev));
|
||||
}
|
||||
|
||||
static int rmidev_create_device_class(void)
|
||||
{
|
||||
rmidev_device_class = class_create(THIS_MODULE, DEVICE_CLASS_NAME);
|
||||
|
||||
if (IS_ERR(rmidev_device_class)) {
|
||||
pr_err("%s: Failed to create /dev/%s\n",
|
||||
__func__, CHAR_DEVICE_NAME);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rmidev_device_class->devnode = rmi_char_devnode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmidev_init_device(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
struct rmidev_handle *rmidev =
|
||||
(struct rmidev_handle *)rmi4_data->rmidev_data;
|
||||
int retval;
|
||||
dev_t dev_no;
|
||||
unsigned char attr_count;
|
||||
struct rmidev_data *dev_data;
|
||||
struct device *device_ptr;
|
||||
|
||||
rmidev = kzalloc(sizeof(*rmidev), GFP_KERNEL);
|
||||
if (!rmidev) {
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to alloc mem for rmidev\n",
|
||||
__func__);
|
||||
retval = -ENOMEM;
|
||||
goto err_rmidev;
|
||||
}
|
||||
pr_debug("%s: enter rmi4_data %p\n", __func__, rmi4_data);
|
||||
|
||||
rmidev->fn_ptr = kzalloc(sizeof(*(rmidev->fn_ptr)), GFP_KERNEL);
|
||||
if (!rmidev) {
|
||||
|
|
@ -585,31 +647,22 @@ static int rmidev_init_device(struct synaptics_rmi4_data *rmi4_data)
|
|||
rmidev->fn_ptr->enable = rmi4_data->irq_enable;
|
||||
rmidev->rmi4_data = rmi4_data;
|
||||
|
||||
retval = rmidev_create_device_class();
|
||||
if (retval < 0) {
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to create device class\n",
|
||||
__func__);
|
||||
goto err_device_class;
|
||||
}
|
||||
|
||||
if (rmidev_major_num) {
|
||||
dev_no = MKDEV(rmidev_major_num, DEV_NUMBER);
|
||||
retval = register_chrdev_region(dev_no, 1, CHAR_DEVICE_NAME);
|
||||
} else {
|
||||
retval = alloc_chrdev_region(&dev_no, 0, 1, CHAR_DEVICE_NAME);
|
||||
if (!rmidev_major_num) {
|
||||
retval = alloc_chrdev_region(&dev_no, rmi4_data->instance,
|
||||
MAX_INSTANCE, CHAR_DEVICE_NAME);
|
||||
if (retval < 0) {
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to allocate char device region\n",
|
||||
__func__);
|
||||
"%s: Failed to allocate char device region %d\n",
|
||||
__func__, retval);
|
||||
goto err_device_region;
|
||||
}
|
||||
|
||||
rmidev_major_num = MAJOR(dev_no);
|
||||
dev_dbg(&rmi4_data->i2c_client->dev,
|
||||
"%s: Major number of rmidev = %d\n",
|
||||
__func__, rmidev_major_num);
|
||||
}
|
||||
"%s: Major number of rmidev = %d\n",
|
||||
__func__, rmidev_major_num);
|
||||
} else
|
||||
dev_no = MKDEV(rmidev_major_num, rmi4_data->instance);
|
||||
|
||||
dev_data = kzalloc(sizeof(*dev_data), GFP_KERNEL);
|
||||
if (!dev_data) {
|
||||
|
|
@ -622,6 +675,9 @@ static int rmidev_init_device(struct synaptics_rmi4_data *rmi4_data)
|
|||
|
||||
mutex_init(&dev_data->file_mutex);
|
||||
dev_data->rmi_dev = rmidev;
|
||||
dev_data->device_class = &rmi_device_class;
|
||||
dev_dbg(&rmi4_data->i2c_client->dev,
|
||||
"%s: Device data %p\n", __func__, dev_data);
|
||||
rmidev->data = dev_data;
|
||||
|
||||
cdev_init(&dev_data->main_dev, &rmidev_fops);
|
||||
|
|
@ -634,9 +690,6 @@ static int rmidev_init_device(struct synaptics_rmi4_data *rmi4_data)
|
|||
goto err_char_device;
|
||||
}
|
||||
|
||||
dev_set_name(&rmidev->dev, "rmidev%d", MINOR(dev_no));
|
||||
dev_data->device_class = rmidev_device_class;
|
||||
|
||||
device_ptr = device_create(dev_data->device_class, NULL, dev_no,
|
||||
NULL, CHAR_DEVICE_NAME"%d", MINOR(dev_no));
|
||||
if (IS_ERR(device_ptr)) {
|
||||
|
|
@ -647,14 +700,14 @@ static int rmidev_init_device(struct synaptics_rmi4_data *rmi4_data)
|
|||
goto err_char_device;
|
||||
}
|
||||
|
||||
retval = gpio_export(rmi4_data->board->irq_gpio, false);
|
||||
retval = gpio_export(rmi4_data->board.irq_gpio, false);
|
||||
if (retval < 0) {
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to export attention gpio\n",
|
||||
__func__);
|
||||
} else {
|
||||
retval = gpio_export_link(&(rmi4_data->i2c_client->dev),
|
||||
"attn", rmi4_data->board->irq_gpio);
|
||||
"attn", rmi4_data->board.irq_gpio);
|
||||
if (retval < 0) {
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s Failed to create gpio symlink\n",
|
||||
|
|
@ -662,21 +715,25 @@ static int rmidev_init_device(struct synaptics_rmi4_data *rmi4_data)
|
|||
} else {
|
||||
dev_dbg(&rmi4_data->i2c_client->dev,
|
||||
"%s: Exported attention gpio %d\n",
|
||||
__func__, rmi4_data->board->irq_gpio);
|
||||
__func__, rmi4_data->board.irq_gpio);
|
||||
}
|
||||
}
|
||||
|
||||
rmidev->sysfs_dir = kobject_create_and_add("rmidev",
|
||||
&rmi4_data->i2c_client->dev.kobj);
|
||||
if (!rmidev->sysfs_dir) {
|
||||
rmidev->dev.class = &rmi_device_class;
|
||||
rmidev->dev.parent = &rmi4_data->i2c_client->dev;
|
||||
|
||||
dev_set_name(&rmidev->dev, DEVICE_CLASS_NAME "%d", rmi4_data->instance);
|
||||
dev_set_drvdata(&rmidev->dev, dev_data);
|
||||
|
||||
retval = device_register(&rmidev->dev);
|
||||
if (retval) {
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to create sysfs directory\n",
|
||||
"%s: Failed to register device\n",
|
||||
__func__);
|
||||
goto err_sysfs_dir;
|
||||
}
|
||||
|
||||
retval = sysfs_create_bin_file(rmidev->sysfs_dir,
|
||||
&attr_data);
|
||||
retval = device_create_bin_file(&rmidev->dev, &attr_data);
|
||||
if (retval < 0) {
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to create sysfs bin file\n",
|
||||
|
|
@ -685,8 +742,7 @@ static int rmidev_init_device(struct synaptics_rmi4_data *rmi4_data)
|
|||
}
|
||||
|
||||
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
|
||||
retval = sysfs_create_file(rmidev->sysfs_dir,
|
||||
&attrs[attr_count].attr);
|
||||
retval = device_create_file(&rmidev->dev, &attrs[attr_count]);
|
||||
if (retval < 0) {
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to create sysfs attributes\n",
|
||||
|
|
@ -700,12 +756,12 @@ static int rmidev_init_device(struct synaptics_rmi4_data *rmi4_data)
|
|||
|
||||
err_sysfs_attrs:
|
||||
for (attr_count--; attr_count >= 0; attr_count--)
|
||||
sysfs_remove_file(rmidev->sysfs_dir, &attrs[attr_count].attr);
|
||||
device_remove_file(&rmidev->dev, &attrs[attr_count]);
|
||||
|
||||
sysfs_remove_bin_file(rmidev->sysfs_dir, &attr_data);
|
||||
device_remove_bin_file(&rmidev->dev, &attr_data);
|
||||
|
||||
err_sysfs_bin:
|
||||
kobject_put(rmidev->sysfs_dir);
|
||||
device_unregister(&rmidev->dev);
|
||||
|
||||
err_sysfs_dir:
|
||||
err_char_device:
|
||||
|
|
@ -713,39 +769,37 @@ err_char_device:
|
|||
kfree(dev_data);
|
||||
|
||||
err_dev_data:
|
||||
unregister_chrdev_region(dev_no, 1);
|
||||
unregister_chrdev_region(dev_no, MAX_INSTANCE);
|
||||
|
||||
err_device_region:
|
||||
class_destroy(rmidev_device_class);
|
||||
|
||||
err_device_class:
|
||||
kfree(rmidev->fn_ptr);
|
||||
|
||||
err_fn_ptr:
|
||||
kfree(rmidev);
|
||||
|
||||
err_rmidev:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void rmidev_remove_device(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
struct rmidev_handle *rmidev =
|
||||
(struct rmidev_handle *)rmi4_data->rmidev_data;
|
||||
unsigned char attr_count;
|
||||
struct rmidev_data *dev_data;
|
||||
|
||||
pr_debug("%s: rmi4_data %p\n", __func__, rmi4_data);
|
||||
|
||||
if (!rmidev)
|
||||
return;
|
||||
|
||||
gpio_unexport(rmi4_data->board->irq_gpio);
|
||||
gpio_unexport(rmi4_data->board.irq_gpio);
|
||||
|
||||
sysfs_remove_link(&rmi4_data->i2c_client->dev.kobj, "attn");
|
||||
|
||||
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++)
|
||||
sysfs_remove_file(rmidev->sysfs_dir, &attrs[attr_count].attr);
|
||||
device_remove_file(&rmidev->dev, &attrs[attr_count]);
|
||||
|
||||
sysfs_remove_bin_file(rmidev->sysfs_dir, &attr_data);
|
||||
device_remove_bin_file(&rmidev->dev, &attr_data);
|
||||
|
||||
kobject_put(rmidev->sysfs_dir);
|
||||
device_unregister(&rmidev->dev);
|
||||
|
||||
dev_data = rmidev->data;
|
||||
if (dev_data) {
|
||||
|
|
@ -755,33 +809,66 @@ static void rmidev_remove_device(struct synaptics_rmi4_data *rmi4_data)
|
|||
|
||||
unregister_chrdev_region(rmidev->dev_no, 1);
|
||||
|
||||
class_destroy(rmidev_device_class);
|
||||
|
||||
kfree(rmidev->fn_ptr);
|
||||
kfree(rmidev);
|
||||
|
||||
complete(&remove_complete);
|
||||
complete(&rmidev->remove_complete);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int __init rmidev_module_init(void)
|
||||
{
|
||||
synaptics_rmi4_new_function(RMI_DEV, true,
|
||||
rmidev_init_device,
|
||||
rmidev_remove_device,
|
||||
NULL, NULL, IC_MODE_ANY);
|
||||
int err;
|
||||
struct rmidev_handle *rmidev;
|
||||
struct synaptics_rmi4_data *next = NULL;
|
||||
|
||||
err = class_register(&rmi_device_class);
|
||||
if (err) {
|
||||
pr_err("%s: couldn't register rmi device class\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
while ((next = synaptics_driver_getdata(next)) != NULL) {
|
||||
rmidev = kzalloc(sizeof(*rmidev), GFP_KERNEL);
|
||||
if (!rmidev) {
|
||||
dev_err(&next->i2c_client->dev,
|
||||
"%s: cannot allocate rmidev for rmi4_data %p\n",
|
||||
__func__, next);
|
||||
continue;
|
||||
}
|
||||
dev_dbg(&next->i2c_client->dev,
|
||||
"%s: new rmidev %p\n", __func__, rmidev);
|
||||
next->rmidev_data = (void *)rmidev;
|
||||
synaptics_rmi4_new_function(next, RMI_DEV, true,
|
||||
rmidev_init_device,
|
||||
rmidev_remove_device,
|
||||
NULL, NULL, IC_MODE_ANY);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit rmidev_module_exit(void)
|
||||
{
|
||||
init_completion(&remove_complete);
|
||||
synaptics_rmi4_new_function(RMI_DEV, false,
|
||||
rmidev_init_device,
|
||||
rmidev_remove_device,
|
||||
NULL, NULL, IC_MODE_ANY);
|
||||
wait_for_completion(&remove_complete);
|
||||
struct rmidev_handle *rmidev;
|
||||
struct synaptics_rmi4_data *next = NULL;
|
||||
|
||||
while ((next = synaptics_driver_getdata(next)) != NULL) {
|
||||
rmidev = (struct rmidev_handle *)next->rmidev_data;
|
||||
dev_dbg(&next->i2c_client->dev,
|
||||
"%s: removing rmidev %p\n", __func__, rmidev);
|
||||
init_completion(&rmidev->remove_complete);
|
||||
synaptics_rmi4_new_function(next, RMI_DEV, false,
|
||||
rmidev_init_device,
|
||||
rmidev_remove_device,
|
||||
NULL, NULL, IC_MODE_ANY);
|
||||
wait_for_completion(&rmidev->remove_complete);
|
||||
kfree(rmidev);
|
||||
next->rmidev_data = NULL;
|
||||
}
|
||||
|
||||
class_unregister(&rmi_device_class);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue