diff options
| author | Yuval Adam <_@yuv.al> | 2017-08-30 08:25:59 +0000 |
|---|---|---|
| committer | Yuval Adam <_@yuv.al> | 2017-08-30 08:25:59 +0000 |
| commit | 8e4bff4cab0ddac6060645b0715210484d02ff40 (patch) | |
| tree | 3a5c3024371a04692a3a6d9974d001cdff8ebf84 /drivers/input/touchscreen/focaltech/focaltech_ctl.c | |
Diffstat (limited to 'drivers/input/touchscreen/focaltech/focaltech_ctl.c')
| -rw-r--r-- | drivers/input/touchscreen/focaltech/focaltech_ctl.c | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/focaltech/focaltech_ctl.c b/drivers/input/touchscreen/focaltech/focaltech_ctl.c new file mode 100644 index 00000000..c654da28 --- /dev/null +++ b/drivers/input/touchscreen/focaltech/focaltech_ctl.c @@ -0,0 +1,334 @@ +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/semaphore.h> +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/sched.h> +#include <linux/kthread.h> +#include <linux/kernel.h> +#include <linux/semaphore.h> +#include <linux/proc_fs.h> +#include <asm/uaccess.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/cdev.h> +#include <linux/device.h> + +#include <linux/i2c/focaltech.h> +#include <linux/i2c/focaltech_ex_fun.h> +#include <linux/i2c/focaltech_ctl.h> + +static int ft_rw_iic_drv_major = FT_RW_IIC_DRV_MAJOR; +struct ft_rw_i2c_dev { + struct cdev cdev; + struct semaphore ft_rw_i2c_sem; + struct i2c_client *client; +}; +struct ft_rw_i2c_dev *ft_rw_i2c_dev_tt; +static struct class *fts_class; +#if 0 +int ft5x0x_i2c_Read(struct i2c_client *client, char *writebuf, + int writelen, char *readbuf, int readlen) +{ +int ret; + +if (writelen > 0) { +struct i2c_msg msgs[] = { +{ + .addr = client->addr, + .flags = 0, + .len = writelen, + .buf = writebuf, + }, +{ + .addr = client->addr, + .flags = I2C_M_RD, + .len = readlen, + .buf = readbuf, + }, +}; +ret = i2c_transfer(client->adapter, msgs, 2); +if (ret < 0) +dev_err(&client->dev, "f%s: i2c read error.\n", +__func__); +} else { +struct i2c_msg msgs[] = { +{ + .addr = client->addr, + .flags = I2C_M_RD, + .len = readlen, + .buf = readbuf, + }, +}; +ret = i2c_transfer(client->adapter, msgs, 1); +if (ret < 0) +dev_err(&client->dev, "%s:i2c read error.\n", __func__); +} +return ret; +} + +/*write data by i2c*/ +int ft5x0x_i2c_Write(struct i2c_client *client, char *writebuf, int writelen) +{ +int ret; + +struct i2c_msg msg[] = { +{ + .addr = client->addr, + .flags = 0, + .len = writelen, + .buf = writebuf, + }, +}; + +ret = i2c_transfer(client->adapter, msg, 1); +if (ret < 0) +dev_err(&client->dev, "%s i2c write error.\n", __func__); + +return ret; +} +#endif + +static int ft_rw_iic_drv_myread(struct i2c_client *client, u8 *buf, int length) +{ + int ret = 0; + ret = fts_i2c_Read(client, NULL, 0, buf, length); + + if(ret<0) + dev_err(&client->dev, "%s:IIC Read failed\n", + __func__); + return ret; +} + +static int ft_rw_iic_drv_mywrite(struct i2c_client *client, u8 *buf, int length) +{ + int ret = 0; + ret = fts_i2c_Write(client, buf, length); + if(ret<0) + dev_err(&client->dev, "%s:IIC Write failed\n", + __func__); + return ret; +} + +static int ft_rw_iic_drv_RDWR(struct i2c_client *client, unsigned long arg) +{ + struct ft_rw_i2c_queue i2c_rw_queue; + u8 __user **data_ptrs; + struct ft_rw_i2c * i2c_rw_msg; + int ret = 0; + int i,j; + + if (!access_ok(VERIFY_READ, (struct ft_rw_i2c_queue *)arg, sizeof(struct ft_rw_i2c_queue))) + return -EFAULT; + + if (copy_from_user(&i2c_rw_queue, + (struct ft_rw_i2c_queue *)arg, + sizeof(struct ft_rw_i2c_queue))) + return -EFAULT; + + if (i2c_rw_queue.queuenum > FT_I2C_RDWR_MAX_QUEUE) + return -EINVAL; + + + i2c_rw_msg = (struct ft_rw_i2c*) + kmalloc(i2c_rw_queue.queuenum *sizeof(struct ft_rw_i2c), + GFP_KERNEL); + if (!i2c_rw_msg) + return -ENOMEM; + + if (copy_from_user(i2c_rw_msg, i2c_rw_queue.i2c_queue, + i2c_rw_queue.queuenum*sizeof(struct ft_rw_i2c))) { + kfree(i2c_rw_msg); + i2c_rw_msg = NULL; + return -EFAULT; + } + + data_ptrs = kmalloc(i2c_rw_queue.queuenum * sizeof(u8 __user *), GFP_KERNEL); + if (data_ptrs == NULL) { + kfree(i2c_rw_msg); + i2c_rw_msg = NULL; + return -ENOMEM; + } + + ret = 0; + for (i=0; i< i2c_rw_queue.queuenum; i++) { + if ((i2c_rw_msg[i].length > 8192)|| + (i2c_rw_msg[i].flag & I2C_M_RECV_LEN)) { + ret = -EINVAL; + break; + } + data_ptrs[i] = (u8 __user *)i2c_rw_msg[i].buf; + i2c_rw_msg[i].buf = kmalloc(i2c_rw_msg[i].length, GFP_KERNEL); + if (i2c_rw_msg[i].buf == NULL) { + ret = -ENOMEM; + break; + } + + if (copy_from_user(i2c_rw_msg[i].buf, data_ptrs[i], i2c_rw_msg[i].length)) { + ++i; + ret = -EFAULT; + break; + } + } + + if (ret < 0) { + for (j=0; j<i; ++j) + { + kfree(i2c_rw_msg[j].buf); + i2c_rw_msg[j].buf = NULL; + } + kfree(data_ptrs); + data_ptrs = NULL; + kfree(i2c_rw_msg); + i2c_rw_msg = NULL; + return ret; + } + + for (i=0; i< i2c_rw_queue.queuenum; i++) { + if (i2c_rw_msg[i].flag) { + ret = ft_rw_iic_drv_myread(client, + i2c_rw_msg[i].buf, i2c_rw_msg[i].length); + if (ret>=0) + ret = copy_to_user(data_ptrs[i], i2c_rw_msg[i].buf, i2c_rw_msg[i].length); + } + else + ret = ft_rw_iic_drv_mywrite(client, + i2c_rw_msg[i].buf, i2c_rw_msg[i].length); + } + for (j=0; j<i; ++j) + { + if(i2c_rw_msg[j].buf != NULL) + kfree(i2c_rw_msg[j].buf); + } + if(data_ptrs != NULL) + kfree(data_ptrs); + if(i2c_rw_msg != NULL) + kfree(i2c_rw_msg); + return ret; + +} + +/* +*char device open function interface +*/ +static int ft_rw_iic_drv_open(struct inode *inode, struct file *filp) +{ + filp->private_data = ft_rw_i2c_dev_tt; + return 0; +} + +/* +*char device close function interface +*/ +static int ft_rw_iic_drv_release(struct inode *inode, struct file *filp) +{ + + return 0; +} + +static int ft_rw_iic_drv_ioctl(struct file *filp, unsigned + int cmd, unsigned long arg) +{ + int ret = 0; + struct ft_rw_i2c_dev *ftdev = filp->private_data; + ftdev = filp->private_data; + + //down(&ft_rw_i2c_dev_tt->ft_rw_i2c_sem); + switch (cmd) + { + case FT_I2C_RW: + ret = ft_rw_iic_drv_RDWR(ftdev->client, arg); + break; + default: + ret = -ENOTTY; + break; + } + //up(&ft_rw_i2c_dev_tt->ft_rw_i2c_sem); + return ret; +} + + +/* +*char device file operation which will be put to register the char device +*/ +static const struct file_operations ft_rw_iic_drv_fops = { + .owner = THIS_MODULE, + .open = ft_rw_iic_drv_open, + .release = ft_rw_iic_drv_release, + .unlocked_ioctl = ft_rw_iic_drv_ioctl, +}; + + +static void ft_rw_iic_drv_setup_cdev(struct ft_rw_i2c_dev *dev, int index) +{ + int err, devno = MKDEV(ft_rw_iic_drv_major, index); + + cdev_init(&dev->cdev, &ft_rw_iic_drv_fops); + dev->cdev.owner = THIS_MODULE; + dev->cdev.ops = &ft_rw_iic_drv_fops; + err = cdev_add(&dev->cdev, devno, 1); + if (err) + printk(KERN_NOTICE "Error %d adding LED%d", err, index); +} + +static int ft_rw_iic_drv_myinitdev(struct i2c_client *client) +{ + int err = 0; + dev_t devno = MKDEV(ft_rw_iic_drv_major, 0); + + if (ft_rw_iic_drv_major) + err = register_chrdev_region(devno, 1, FT_RW_IIC_DRV); + else { + err = alloc_chrdev_region(&devno, 0, 1, FT_RW_IIC_DRV); + ft_rw_iic_drv_major = MAJOR(devno); + } + if (err < 0) { + dev_err(&client->dev, "%s:ft_rw_iic_drv failed error code=%d---\n", + __func__, err); + return err; + } + + ft_rw_i2c_dev_tt = kmalloc(sizeof(struct ft_rw_i2c_dev), GFP_KERNEL); + if (!ft_rw_i2c_dev_tt){ + err = -ENOMEM; + unregister_chrdev_region(devno, 1); + dev_err(&client->dev, "%s:ft_rw_iic_drv failed\n", + __func__); + return err; + } + ft_rw_i2c_dev_tt->client = client; + //init_MUTEX(&ft_rw_i2c_dev_tt->ft_rw_i2c_sem); + ft_rw_iic_drv_setup_cdev(ft_rw_i2c_dev_tt, 0); + + fts_class = class_create(THIS_MODULE, "fts_class"); + if (IS_ERR(fts_class)) { + dev_err(&client->dev, "%s:failed in creating class.\n", + __func__); + return -1; + } + /*create device node*/ + device_create(fts_class, NULL, MKDEV(ft_rw_iic_drv_major, 0), + NULL, FT_RW_IIC_DRV); + + return 0; +} + +int ft_rw_iic_drv_init(struct i2c_client *client) +{ + dev_dbg(&client->dev, "[FTS]----ft_rw_iic_drv init ---\n"); + return ft_rw_iic_drv_myinitdev(client); +} + +void ft_rw_iic_drv_exit(void) +{ + device_destroy(fts_class, MKDEV(ft_rw_iic_drv_major, 0)); + /*delete class created by us*/ + class_destroy(fts_class); + /*delet the cdev*/ + cdev_del(&ft_rw_i2c_dev_tt->cdev); + kfree(ft_rw_i2c_dev_tt); + unregister_chrdev_region(MKDEV(ft_rw_iic_drv_major, 0), 1); +} + |
