实现一个字符设备驱动程序,能对字符设备执行打开、读、写、I/O控制和关闭的基本操作
时间: 2023-11-25 20:08:51 浏览: 127
字符设备驱动相关代码示例
好的,下面是一个实现了打开、读、写、I/O控制和关闭的基本操作的字符设备驱动程序示例代码:
```c
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/cdev.h>
#include <linux/device.h>
#define DEVICE_NAME "my_char_dev"
#define BUFFER_SIZE 1024
static int major;
static struct cdev my_cdev;
static char buffer[BUFFER_SIZE];
static struct class *my_class;
static int my_char_dev_open(struct inode *inode, struct file *filp)
{
filp->private_data = container_of(inode->i_cdev, struct my_cdev_data, cdev);
return 0;
}
static ssize_t my_char_dev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
struct my_cdev_data *dev = filp->private_data;
ssize_t retval = 0;
if (*f_pos >= BUFFER_SIZE) {
goto out;
}
if (*f_pos + count > BUFFER_SIZE) {
count = BUFFER_SIZE - *f_pos;
}
if (copy_to_user(buf, buffer + *f_pos, count)) {
retval = -EFAULT;
goto out;
}
*f_pos += count;
retval = count;
out:
return retval;
}
static ssize_t my_char_dev_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
struct my_cdev_data *dev = filp->private_data;
ssize_t retval = 0;
if (*f_pos >= BUFFER_SIZE) {
goto out;
}
if (*f_pos + count > BUFFER_SIZE) {
count = BUFFER_SIZE - *f_pos;
}
if (copy_from_user(buffer + *f_pos, buf, count)) {
retval = -EFAULT;
goto out;
}
*f_pos += count;
retval = count;
out:
return retval;
}
static long my_char_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct my_cdev_data *dev = filp->private_data;
long retval = 0;
switch (cmd) {
/* I/O control commands */
default:
retval = -ENOTTY;
break;
}
return retval;
}
static int my_char_dev_release(struct inode *inode, struct file *filp)
{
return 0;
}
static struct file_operations my_char_dev_fops = {
.owner = THIS_MODULE,
.open = my_char_dev_open,
.read = my_char_dev_read,
.write = my_char_dev_write,
.unlocked_ioctl = my_char_dev_ioctl,
.release = my_char_dev_release,
};
struct my_cdev_data {
struct cdev cdev;
};
static int __init my_char_dev_init(void)
{
int retval;
dev_t dev;
memset(buffer, 0, BUFFER_SIZE);
/* Allocate dynamic device number */
retval = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME);
if (retval < 0) {
printk(KERN_ERR "Failed to allocate dynamic device number.\n");
return retval;
}
major = MAJOR(dev);
printk(KERN_INFO "Registered char device with major number %d.\n", major);
/* Initialize cdev */
cdev_init(&my_cdev, &my_char_dev_fops);
my_cdev.owner = THIS_MODULE;
/* Add cdev */
retval = cdev_add(&my_cdev, dev, 1);
if (retval < 0) {
printk(KERN_ERR "Failed to add cdev.\n");
unregister_chrdev_region(dev, 1);
return retval;
}
/* Create device file */
my_class = class_create(THIS_MODULE, DEVICE_NAME);
if (IS_ERR(my_class)) {
printk(KERN_ERR "Failed to create class.\n");
cdev_del(&my_cdev);
unregister_chrdev_region(dev, 1);
return PTR_ERR(my_class);
}
device_create(my_class, NULL, dev, NULL, DEVICE_NAME);
return 0;
}
static void __exit my_char_dev_exit(void)
{
dev_t dev = MKDEV(major, 0);
device_destroy(my_class, dev);
class_destroy(my_class);
cdev_del(&my_cdev);
unregister_chrdev_region(dev, 1);
printk(KERN_INFO "Unregistered char device with major number %d.\n", major);
}
module_init(my_char_dev_init);
module_exit(my_char_dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your name");
MODULE_DESCRIPTION("A simple character device driver.");
```
这个驱动程序实现了打开、读、写、I/O控制和关闭的基本操作。
在初始化函数中,它首先使用 `alloc_chrdev_region` 函数分配一个动态设备号,并注册字符设备。然后,它初始化和添加一个 cdev,并创建一个设备文件。在退出函数中,它删除设备文件、cdev,并释放设备号。
在 `my_char_dev_open` 函数中,它将 cdev 的指针存储到文件私有数据中。在 `my_char_dev_read` 和 `my_char_dev_write` 函数中,它使用 `copy_to_user` 和 `copy_from_user` 函数将数据从缓冲区中读取或写入到应用程序的缓冲区。在 `my_char_dev_ioctl` 函数中,它处理 I/O 控制命令。
当你编译并加载这个模块后,在终端中执行命令:
```
$ sudo mknod /dev/my_char_dev c <major number> 0
```
其中,`<major number>` 是上面注册的字符设备的主设备号。
然后,你就可以像操作一个普通的文件一样进行读写操作了,例如:
```
$ echo "Hello, world!" > /dev/my_char_dev
$ cat /dev/my_char_dev
Hello, world!
```
此外,你还可以使用 `ioctl` 命令向设备发送特定的控制命令,例如:
```
$ sudo ioctl /dev/my_char_dev 0
```
这个示例只是一个非常简单的驱动程序,实际的驱动程序可能涉及到更复杂的操作,例如设备的初始化,中断处理等等。
阅读全文