linux驱动为自定义设备添加poll方法

都是以前写过的代码,现在整理下,怕忘了。
还是mstar安卓电视方案添加的功能,阿三客户要添加一个工厂调试的功能:在电脑上设置类似白平衡参数的一些数值,然后把数值和命令通过红外发射器发出,电视接收到后根据命令和数值自动调节白平衡等参数,红外协议是NEC。
我采用的方法是在红外驱动中添加一个虚拟设备,然后判断红外接收到的数据,如果是工厂调试命令就把数据写到这个虚拟设备中;应用层就启动一个线程一直去读这个设备的数据,根据读到的数据来调用mstar SuperNova的接口去调节白平衡等参数;因为无法用中断做,所以就想到了用poll这个方法做。

首先在红外驱动中添加一个虚拟设备,为这个设备添加open,read,poll文件操作函数:

static int FA_major = 0;
static struct cdev cdev;
//FA_send这个变量用做检测进程唤醒的条件
static volatile int FA_send = 0;
//生成一个等待队列头
static DECLARE_WAIT_QUEUE_HEAD(FA_waitq); 
static int FA_open(struct inode* inode, struct  file* filp);
static ssize_t FA_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos);
static unsigned int FA_poll(struct file * filp, poll_table * wait);

static const struct file_operations FA_fops = {
  .owner = THIS_MODULE,
  .read = FA_read,
  .open = FA_open,
  .poll = FA_poll,
};
//这个结构体用来存储红外命令
struct FA_dev {                                                        
  char type;                      
  char value;       
};
static struct FA_dev* fa_dev = NULL;
static struct class* fa_class = NULL;
static int FA_open(struct inode* inode, struct  file* filp) {
    filp->private_data = fa_dev;
    return 0;
}
static ssize_t FA_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos) {    
    ssize_t err = 0;
    struct FA_dev* dev = filp->private_data;
    if(count < sizeof(struct FA_dev)) {
        goto out;
    }
    //将红外命令写到这个设备中   
    dev->type = fa_dev->type;
    dev->value = fa_dev->value;
    //FA_send由判断红外命令的方法赋值,如果是工厂命令就置为1,
    //否则为0,wait_event_interruptible根据FA_send的值来
    //唤醒进程
    wait_event_interruptible(FA_waitq, FA_send);
    if(copy_to_user(buf, dev, sizeof(struct FA_dev))) {
        err = -EFAULT;
        goto out;
    }
    //读完数据,FA_send 置0
    FA_send = 0;
    err = sizeof(struct FA_dev);
out:
    return err;
}
static unsigned int FA_poll(struct file * filp, poll_table * wait) {
    unsigned int mask = 0;
    //把当前进程添加到FA_waitq等待列表
    poll_wait(filp, &FA_waitq, wait);
    //如果红外接收到工厂命令则返回可读
    if (FA_send)
        mask |= POLLIN | POLLRDNORM;
    return mask;
}

在红外驱动初始化时也初始化这个虚拟设备

dev_t devno = 0;
struct device* temp = NULL;
result = alloc_chrdev_region(&devno, 0, 1, "FA");
if(result < 0) {
    printk("Failed to alloc char dev region.\n");
}
FA_major = MAJOR(devno);
cdev_init(&cdev, &FA_fops);
cdev.owner = THIS_MODULE;
cdev.ops = &FA_fops;
cdev_add(&cdev, MKDEV(FA_major, 0), 1);
fa_dev = kmalloc(sizeof(struct FA_dev), GFP_KERNEL);
if(!fa_dev) {
    printk("Failed to alloc fa_dev.\n");
}
memset(fa_dev, 0, sizeof(struct FA_dev));
fa_dev->type = 0;
fa_dev->value = 0;
fa_class = class_create(THIS_MODULE, "FA");
if(IS_ERR(fa_class)) {
    printk("Failed to create FA class.\n");
}
temp = device_create(fa_class, NULL, devno, "%s", "FA");
if(IS_ERR(temp)) {
     printk("Failed to create FA device.\n");
}
dev_set_drvdata(temp, fa_dev);

在红外数据接收的代码中添加判断工厂命令的代码

//如果数据格式是工厂命令
if(XXXX) {
    //为工厂命令数据的结构体赋值,这个值会被用户层的read函数读到
    fa_dev->type=u8IRSwModeBuf[1];
    fa_dev->value=u8IRSwModeBuf[2];
    //是工厂命令,唤醒条件置1
    FA_send = 1;
    //唤醒注册到FA_waitq等待队列上的进程
    wake_up_interruptible(&FA_waitq);
}

驱动部分的就这些了,最后在用户层用poll和read函数去读数据就行了

const char *name = "/dev/FA";
struct pollfd FAfd;
int FAret;
unsigned char buf[2];

//打开虚拟设备
int fd = open(name, O_RDONLY);
if (fd < 0) {
    printf("---open fail\n");
    return NULL;
}
//设置监视的文件描述符
FAfd.fd = fd;
//设置监视文件描述符的事件掩码
FAfd.events = POLLIN;
while(1) {
    //第三个参数-1代表一直阻塞,0则是立即返回,正数是阻塞的超时时间
    FAret = poll(&FAfd, 1, -1);
    //如果在超时前没有任何事件发生,则返回0,如果成功会返回文件描述符个数
    if (FAret <= 0)
        continue;
    //如果监视文件描述符的事件结果是有数据可读,则执行下一步
    if (FAfd.revents & POLLIN) {
        FAret = read(fd,buf,sizeof(buf));
        if (FAret <= 0)
            continue;
        printf("buf---:0x%2.2X%2.2X.\n", buf[0], buf[1]);
    }
}
close(fd);
return NULL;
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值