在linux/kernel/drivers/input/sensor目录下的kxjt2.c里增加对重力感应gsensor的属性,用于采用工作队列轮询和中断方式上报数据。具体流程如下
1.先增加一个属性
static DEVICE_ATTR(matt,S_IRUGO | S_IWUSR,kxtj2_matt_show,kxtj2_matt_set);
2.将属性合并到原来的属性集合中
static struct attribute *kxtj2_attributes[] = {
&dev_attr_matt.attr,
&dev_attr_enable.attr,
&dev_attr_rawdata_for_mag.attr,
NULL
};
3.实现show和set函数
static ssize_t kxtj2_matt_set(struct device *dev, struct device_attribute *devattr,char *buf,size_t count)
{
//int err=0;
struct i2c_client *client = to_i2c_client(dev);
struct kxtj2_data *tj2 = i2c_get_clientdata(client);
char reg1;
int val = simple_strtoul(buf, NULL, 10) ? 1 : 0;
atomic_set(&tj2->matt,val); //将shell终端输入的属性值传给matt这个属性
switch(val){
case 0: //Work Queue
matt_list=1;
printk("#matt# Enable Polling Mode(Work Queue)...\n");
i2c_smbus_write_byte_data(client, CTRL_REG1, 0);
tj2->ctrl_reg1 &= 0xDF;//interrupt disable
i2c_smbus_write_byte_data(client, CTRL_REG1, tj2->ctrl_reg1);
tj2->ctrl_reg1 |= PC1_ON;//bit 5 set 0,
i2c_smbus_write_byte_data(client, CTRL_REG1, tj2->ctrl_reg1);
kxtj2_workqueue(client);//
break;
case 1: //Interrupt Mode
matt_list=0;//close list function
printk("#matt# access to interrupt mode\n");
i2c_smbus_write_byte_data(client, CTRL_REG1, 0);
tj2->ctrl_reg1 |= (PC1_ON|DRDYE);
i2c_smbus_write_byte_data(client, CTRL_REG1, tj2->ctrl_reg1);
kxtj2_interrupt(client);//request interrupt
break;
}
return count;
}
static ssize_t kxtj2_matt_show(struct device *dev, struct device_attribute *devattr,char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct kxtj2_data *tj2 = i2c_get_clientdata(client);
return sprintf(buf,"%d",atomic_read(&tj2->matt));
}
4.实现工作队列
static void matt_work_function(struct work_struct *work)
{
// struct kxtj2_data *tj2 = container_of((struct delayed_work *)work,struct kxtj2_data, matt_work.work);//
if(matt_list == 1)
{
kxtj2_report_acceleration_data(tj3);
printk("#matt# list_work_function--2\n");
//queue_delayed_work(tj2->matt_workqueue,&tj2->matt_work,msecs_to_jiffies(100));
queue_delayed_work(matt_workqueue,&matt_work,msecs_to_jiffies(100));
}
if(matt_list == 0 ) return;
}
static int kxtj2_workqueue(struct i2c_client *client)
{
struct kxtj2_data *tj2 = i2c_get_clientdata(client);
matt_workqueue=create_singlethread_workqueue("matt queue");
INIT_DELAYED_WORK(&matt_work,matt_work_function);
queue_delayed_work(matt_workqueue,&matt_work,msecs_to_jiffies(100));
return 0;
}
5.实现中断函数
static irqreturn_t gpio_interrupt_handler(int irq, struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct kxtj2_data *tj2 = i2c_get_clientdata(client);
printk("#matt#interrupt handler -1\n");
kxtj2_report_acceleration_data(tj2);
return IRQ_HANDLED;
}
//Interrupt Mode
static int kxtj2_interrupt(struct i2c_client *client)
{
unsigned int gpio,irq;
int rc;
printk("#matt# go to interrupt request \n");
struct kxtj2_data *tj2 = i2c_get_clientdata(client);
i2c_smbus_write_byte_data(client, CTRL_REG1, 0);
tj2->int_ctrl |= 0x38;
i2c_smbus_write_byte_data(client, INT_CTRL1, tj2->int_ctrl);
tj2->ctrl_reg1 |= PC1_ON;
i2c_smbus_write_byte_data(client, CTRL_REG1, tj2->ctrl_reg1);
gpio=acpi_get_gpio("\\_SB.GPO2",3);
if(!gpio_is_valid(gpio)) return -1;
if(rc=gpio_request(gpio, "matt_inter_gpio"))
{
printk(" #matt# error gpio_request : %d\n",rc);
return rc;
}
if(rc=gpio_direction_input(gpio))
{
gpio_free(gpio);
printk("#matt# error gpio_direction_input: %d\n",rc);
return rc;
}
irq=gpio_to_irq(gpio);
if(rc=request_threaded_irq(irq,
NULL,
gpio_interrupt_handler,
IRQF_ONESHOT|IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING,
"matt_gpio_irq",
&client->dev))
{
gpio_free(gpio);
return rc;
}
printk("#matt# request interrupt success.\n");
return 0;
}
6.在原来的probe函数中获取tj2的指针
tj2 = kzalloc(sizeof(*tj2), GFP_KERNEL);
tj3=tj2;//tj3是全局变量用于队列及其中断处理