diff --git a/drivers/input/touchscreen/synaptics_mmi/Android.mk b/drivers/input/touchscreen/synaptics_mmi/Android.mk index 33f40482a21c..2d487aa4f8c5 100644 --- a/drivers/input/touchscreen/synaptics_mmi/Android.mk +++ b/drivers/input/touchscreen/synaptics_mmi/Android.mk @@ -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) diff --git a/drivers/input/touchscreen/synaptics_mmi/Kbuild b/drivers/input/touchscreen/synaptics_mmi/Kbuild index ca0ed9353b9f..8f566f9824fd 100644 --- a/drivers/input/touchscreen/synaptics_mmi/Kbuild +++ b/drivers/input/touchscreen/synaptics_mmi/Kbuild @@ -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 diff --git a/drivers/input/touchscreen/synaptics_mmi/synaptics_dsx_i2c.h b/drivers/input/touchscreen/synaptics_mmi/synaptics_dsx_i2c.h index 2f716fdc977f..6ac6789c2977 100644 --- a/drivers/input/touchscreen/synaptics_mmi/synaptics_dsx_i2c.h +++ b/drivers/input/touchscreen/synaptics_mmi/synaptics_dsx_i2c.h @@ -585,6 +585,7 @@ struct synaptics_rmi4_data { char *reset_name; void *fwu_data; + void *rmidev_data; }; struct pdt_properties { diff --git a/drivers/input/touchscreen/synaptics_mmi/synaptics_dsx_rmi_dev.c b/drivers/input/touchscreen/synaptics_mmi/synaptics_dsx_rmi_dev.c index 4be4b5da8403..c5b44b1b2c92 100644 --- a/drivers/input/touchscreen/synaptics_mmi/synaptics_dsx_rmi_dev.c +++ b/drivers/input/touchscreen/synaptics_mmi/synaptics_dsx_rmi_dev.c @@ -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; }