1 /*
\r * Copyright (C) 2012 Spreadtrum Communications Inc.
\r *
\r * This software is licensed under the terms of the GNU General Public
\r * License version 2, as published by the Free Software Foundation, and
\r * may be copied, distributed, and modified under those terms.
\r *
\r * This program is distributed in the hope that it will be useful,
\r * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r * GNU General Public License for more details.
\r */
\r#include <linux/compat.h>
\r#include <linux/fs.h>
\r#include <linux/uaccess.h>
\r#include <video/sensor_drv_k.h>
\r#include "compat_sensor_drv_k.h"
\r//#define DEBUG_COMPAT_SENSOR_DRV
\r#ifdef DEBUG_COMPAT_SENSOR_DRV
\r#define COMPAT_SENSOR_PRINT printk
\r#else
\r#define COMPAT_SENSOR_PRINT(...)
\r#endif
\rstruct compat_sensor_reg_tab_tag {
\r compat_caddr_t sensor_reg_tab_ptr;
\r uint32_t reg_count;
\r uint32_t reg_bits;
\r uint32_t burst_mode;
\r};
\rstruct compat_sensor_i2c_tag {
\r compat_caddr_t i2c_data;
\r uint16_t i2c_count;
\r uint16_t slave_addr;
\r};
\r\rstruct compat_sensor_otp_data_info_tag {
\r uint32_t size;
\r compat_caddr_t data_ptr;
\r};
\rstruct compat_sensor_otp_param_tag {
\r uint32_t start_addr;
\r uint32_t len;
\r compat_caddr_t buff;
\r struct compat_sensor_otp_data_info_tag golden;
\r struct compat_sensor_otp_data_info_tag awb;
\r struct compat_sensor_otp_data_info_tag lsc;
\r uint32_t type;
\r};
\r\r#define COMPAT_SENSOR_IO_I2C_WRITE_REGS _IOW(SENSOR_IOC_MAGIC, 14, struct compat_sensor_reg_tab_tag)
\r#define COMPAT_SENSOR_IO_I2C_WRITE_EXT _IOW(SENSOR_IOC_MAGIC, 17, struct compat_sensor_i2c_tag)
\r#define COMPAT_SENSOR_IO_I2C_READ_EXT _IOWR(SENSOR_IOC_MAGIC, 20, struct compat_sensor_i2c_tag)
\r#define COMPAT_SENSOR_IO_READ_OTPDATA _IOWR(SENSOR_IOC_MAGIC, 254,struct compat_sensor_otp_param_tag)
\r\rstatic long compat_get_sensor_reg_tab_tag(
\r struct compat_sensor_reg_tab_tag __user *data32,
\r struct sensor_reg_tab_tag __user *data)
\r{
\r compat_caddr_t c;
\r uint32_t i;
\r int err;
\r err = get_user(c, &data32->sensor_reg_tab_ptr);
\r err |= put_user(c, &data->sensor_reg_tab_ptr);
\r err |= get_user(i, &data32->reg_count);
\r err |= put_user(i, &data->reg_count);
\r err |= get_user(i, &data32->reg_bits);
\r err |= put_user(i, &data->reg_bits);
\r err |= get_user(i, &data32->burst_mode);
\r err |= put_user(i, &data->burst_mode);
\r COMPAT_SENSOR_PRINT("sensor_reg_tab_ptr: %p reg_count: %d reg_bits: %d burst_mode: %d\n",
\r data->sensor_reg_tab_ptr, data->reg_count, data->reg_bits, data->burst_mode);
\r return err;
\r}
\r\rstatic long compat_get_sensor_i2c_tag(
\r struct compat_sensor_i2c_tag __user *data32,
\r struct sensor_i2c_tag __user *data)
\r{
\r compat_caddr_t c;
\r uint16_t i;
\r int err;
\r err = get_user(c, &data32->i2c_data);
\r err |= put_user(c, &data->i2c_data);
\r err |= get_user(i, &data32->i2c_count);
\r err |= put_user(i, &data->i2c_count);
\r err |= get_user(i, &data32->slave_addr);
\r err |= put_user(i, &data->slave_addr);
\r COMPAT_SENSOR_PRINT("i2c_data: %p i2c_count: %d slave_addr: %d\n",
\r data->i2c_data, data->i2c_count, data->slave_addr);
\r return err;
\r}
\r\rstatic long compat_get_otp_param_tag(
\r struct compat_sensor_otp_param_tag __user *data32,
\r struct _sensor_otp_param_tag __user *data)
\r{
\r compat_caddr_t c;
\r uint32_t i;
\r int err;
\r\r err = get_user(i, &data32->start_addr);
\r err |= put_user(i, &data->start_addr);
\r err |= get_user(i, &data32->len);
\r err |= put_user(i, &data->len);
\r err |= get_user(c, &data32->buff);
\r err |= put_user(c, &data->buff);
\r\r err |= get_user(c, &data32->awb.data_ptr);
\r err |= put_user(c, &data->awb.data_ptr);
\r err |= get_user(i, &data32->awb.size);
\r err |= put_user(i, &data->awb.size);
\r\r err |= get_user(c, &data32->lsc.data_ptr);
\r err |= put_user(c, &data->lsc.data_ptr);
\r err |= get_user(i, &data32->lsc.size);
\r err |= put_user(i, &data->lsc.size);
\r return err;
\r}
\rlong compat_sensor_k_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
\r{
\r int compatible_arg = 1;
\r long err = 0;
\r if (!filp->f_op || !filp->f_op->unlocked_ioctl)
\r return -ENOTTY;
\r switch (cmd) {
\r case COMPAT_SENSOR_IO_I2C_WRITE_REGS:
\r {
\r struct compat_sensor_reg_tab_tag __user *data32;
\r struct sensor_reg_tab_tag __user *data;
\r data32 = compat_ptr(arg);
\r data = compat_alloc_user_space(sizeof(*data));
\r if (NULL == data)
\r return -EFAULT;
\r err = compat_get_sensor_reg_tab_tag(data32, data);
\r if (err)
\r return err;
\r return filp->f_op->unlocked_ioctl(filp, SENSOR_IO_I2C_WRITE_REGS,
\r (unsigned long)data);
\r }
\r case COMPAT_SENSOR_IO_I2C_WRITE_EXT:
\r {
\r struct compat_sensor_i2c_tag __user *data32;
\r struct sensor_i2c_tag __user *data;
\r data32 = compat_ptr(arg);
\r data = compat_alloc_user_space(sizeof(*data));
\r if (NULL == data)
\r return -EFAULT;
\r err = compat_get_sensor_i2c_tag(data32, data);
\r if (err)
\r return err;
\r return filp->f_op->unlocked_ioctl(filp, SENSOR_IO_I2C_WRITE_EXT,
\r (unsigned long)data);
\r }
\r case COMPAT_SENSOR_IO_I2C_READ_EXT:
\r {
\r struct compat_sensor_i2c_tag __user *data32;
\r struct sensor_i2c_tag __user *data;
\r data32 = compat_ptr(arg);
\r data = compat_alloc_user_space(sizeof(*data));
\r if (NULL == data)
\r return -EFAULT;
\r err = compat_get_sensor_i2c_tag(data32, data);
\r if (err)
\r return err;
\r return filp->f_op->unlocked_ioctl(filp, SENSOR_IO_I2C_READ_EXT,
\r (unsigned long)data);
\r }
\r\r case COMPAT_SENSOR_IO_READ_OTPDATA:
\r {
\r struct compat_sensor_otp_param_tag __user *data32;
\r SENSOR_OTP_PARAM_T __user *data;
\r\r printk("SENSOR: ioctl COMPAT_SENSOR_IO_READ_OTPDATA \n");
\r data32 = compat_ptr(arg);
\r data = compat_alloc_user_space(sizeof(*data));
\r if (NULL == data)
\r return -EFAULT;
\r\r err = compat_get_otp_param_tag(data32, data);
\r if (err)
\r return err;
\r return filp->f_op->unlocked_ioctl(filp, SENSOR_IO_READ_OTPDATA,
\r (unsigned long)data);
\r }
\r break;
\r\r default:
\r return filp->f_op->unlocked_ioctl(filp, cmd,
\r (unsigned long)compat_ptr(arg));
\r }
\r}
\r