epoll 字符设备驱动 使用iic通信驱动代码
时间: 2023-10-30 08:06:12 浏览: 120
字符设备驱动代码
以下是一个使用 epoll 和 I2C 总线进行通信的字符设备驱动代码示例:
```c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/i2c.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/semaphore.h>
#include <linux/wait.h>
#include <linux/epoll.h>
#define DEVICE_NAME "i2c_char_device"
#define CLASS_NAME "i2c_char_class"
#define I2C_BUS_ID 1
#define I2C_SLAVE_ADDRESS 0x50
static struct i2c_client *client;
static struct class *i2c_char_class = NULL;
static struct device *i2c_char_device = NULL;
static struct cdev i2c_char_cdev;
static dev_t i2c_char_dev;
static struct semaphore sem;
static DECLARE_WAIT_QUEUE_HEAD(waitq);
static struct epoll_event event;
static int epoll_fd;
static int i2c_char_open(struct inode *inode, struct file *filp)
{
if (down_interruptible(&sem))
return -ERESTARTSYS;
return 0;
}
static int i2c_char_release(struct inode *inode, struct file *filp)
{
up(&sem);
return 0;
}
static ssize_t i2c_char_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
ssize_t retval = 0;
char *data = kzalloc(count, GFP_KERNEL);
if (!data)
return -ENOMEM;
if (down_interruptible(&sem))
return -ERESTARTSYS;
if (i2c_master_recv(client, data, count) != count) {
retval = -EIO;
goto out;
}
if (copy_to_user(buf, data, count)) {
retval = -EFAULT;
goto out;
}
retval = count;
out:
kfree(data);
up(&sem);
return retval;
}
static ssize_t i2c_char_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
ssize_t retval = 0;
char *data = kzalloc(count, GFP_KERNEL);
if (!data)
return -ENOMEM;
if (copy_from_user(data, buf, count)) {
retval = -EFAULT;
goto out;
}
if (down_interruptible(&sem))
return -ERESTARTSYS;
if (i2c_master_send(client, data, count) != count) {
retval = -EIO;
goto out;
}
retval = count;
out:
kfree(data);
up(&sem);
return retval;
}
static struct file_operations i2c_char_fops = {
.owner = THIS_MODULE,
.open = i2c_char_open,
.release = i2c_char_release,
.read = i2c_char_read,
.write = i2c_char_write,
};
static int i2c_char_probe(struct i2c_client *cl, const struct i2c_device_id *id)
{
int ret = 0;
client = cl;
if (alloc_chrdev_region(&i2c_char_dev, 0, 1, DEVICE_NAME) < 0) {
ret = -1;
goto out;
}
cdev_init(&i2c_char_cdev, &i2c_char_fops);
i2c_char_cdev.owner = THIS_MODULE;
if (cdev_add(&i2c_char_cdev, i2c_char_dev, 1) < 0) {
ret = -1;
goto out_unregister;
}
i2c_char_class = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(i2c_char_class)) {
ret = PTR_ERR(i2c_char_class);
goto out_cdev_del;
}
i2c_char_device = device_create(i2c_char_class, NULL, i2c_char_dev, NULL, DEVICE_NAME);
if (IS_ERR(i2c_char_device)) {
ret = PTR_ERR(i2c_char_device);
goto out_class_destroy;
}
epoll_fd = epoll_create(1);
if (epoll_fd == -1) {
ret = -1;
goto out_device_destroy;
}
event.events = EPOLLIN | EPOLLRDHUP;
event.data.fd = i2c_char_dev;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, i2c_char_dev, &event) == -1) {
ret = -1;
goto out_epoll_create;
}
sema_init(&sem, 1);
return 0;
out_epoll_create:
close(epoll_fd);
out_device_destroy:
device_destroy(i2c_char_class, i2c_char_dev);
out_class_destroy:
class_destroy(i2c_char_class);
out_cdev_del:
cdev_del(&i2c_char_cdev);
out_unregister:
unregister_chrdev_region(i2c_char_dev, 1);
out:
return ret;
}
static int i2c_char_remove(struct i2c_client *cl)
{
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, i2c_char_dev, &event);
close(epoll_fd);
device_destroy(i2c_char_class, i2c_char_dev);
class_destroy(i2c_char_class);
cdev_del(&i2c_char_cdev);
unregister_chrdev_region(i2c_char_dev, 1);
return 0;
}
static const struct i2c_device_id i2c_char_id[] = {
{ "i2c_char_device", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, i2c_char_id);
static struct i2c_driver i2c_char_driver = {
.driver = {
.name = DEVICE_NAME,
.owner = THIS_MODULE,
},
.probe = i2c_char_probe,
.remove = i2c_char_remove,
.id_table = i2c_char_id,
};
static int __init i2c_char_init(void)
{
return i2c_add_driver(&i2c_char_driver);
}
static void __exit i2c_char_exit(void)
{
i2c_del_driver(&i2c_char_driver);
}
module_init(i2c_char_init);
module_exit(i2c_char_exit);
MODULE_LICENSE("GPL");
```
在该示例中,使用了 I2C 总线驱动来进行数据传输,同时使用了 epoll 来实现异步读取。该驱动支持以下操作:
- 打开设备文件时会获取一个信号量。
- 读取设备文件时会等待数据的到达,然后从 I2C 总线上读取数据并返回给用户空间。
- 写入设备文件时会将数据写入到 I2C 总线上。
- 关闭设备文件时会释放信号量。
在驱动的 probe 函数中,还创建了一个 epoll 实例,并将设备文件添加到 epoll 实例中进行监听。这样,在用户空间中就可以使用 epoll 等待设备文件中的数据到达,从而实现异步读取。
阅读全文