编写字符设备驱动实现简单功能,用户层调用ioctl接口,使用动态库测试与驱动通信的代码
时间: 2024-03-18 07:41:50 浏览: 54
以下是一个简单的字符设备驱动程序的示例代码,实现了读取和写入设备数据的功能,以及处理ioctl接口:
```c
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/cdev.h>
#include <linux/ioctl.h>
#define DEVICE_NAME "my_device"
struct my_device_data {
char data[100];
int len;
};
struct my_device {
struct cdev cdev;
struct my_device_data data;
};
static int my_device_open(struct inode *inode, struct file *filp)
{
struct my_device *dev = container_of(inode->i_cdev, struct my_device, cdev);
filp->private_data = dev;
return 0;
}
static int my_device_release(struct inode *inode, struct file *filp)
{
return 0;
}
static ssize_t my_device_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
struct my_device *dev = filp->private_data;
int len = min_t(int, count, dev->data.len - *f_pos);
if (len <= 0)
return 0;
if (copy_to_user(buf, dev->data.data + *f_pos, len))
return -EFAULT;
*f_pos += len;
return len;
}
static ssize_t my_device_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
struct my_device *dev = filp->private_data;
int len = min_t(int, count, sizeof(dev->data.data) - *f_pos);
if (len <= 0)
return 0;
if (copy_from_user(dev->data.data + *f_pos, buf, len))
return -EFAULT;
*f_pos += len;
dev->data.len = *f_pos;
return len;
}
static long my_device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct my_device *dev = filp->private_data;
int err = 0;
switch (cmd) {
case 0:
// do something
break;
case 1:
// do something else
break;
default:
err = -EINVAL;
break;
}
return err;
}
static const struct file_operations my_device_fops = {
.owner = THIS_MODULE,
.open = my_device_open,
.release = my_device_release,
.read = my_device_read,
.write = my_device_write,
.unlocked_ioctl = my_device_ioctl,
};
static struct my_device my_device_data;
static dev_t devno;
static int __init my_device_init(void)
{
int err;
err = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME);
if (err < 0)
return err;
cdev_init(&my_device_data.cdev, &my_device_fops);
my_device_data.cdev.owner = THIS_MODULE;
err = cdev_add(&my_device_data.cdev, devno, 1);
if (err < 0) {
unregister_chrdev_region(devno, 1);
return err;
}
return 0;
}
static void __exit my_device_exit(void)
{
cdev_del(&my_device_data.cdev);
unregister_chrdev_region(devno, 1);
}
module_init(my_device_init);
module_exit(my_device_exit);
MODULE_LICENSE("GPL");
```
以下是一个简单的动态库的示例代码,用于测试与驱动程序的通信,其中包含了测试读取和写入设备数据的函数,以及测试ioctl接口的函数:
```c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define DEVICE_NAME "/dev/my_device"
struct my_device_data {
char data[100];
int len;
};
#define MY_DEVICE_IOCTL_CMD0 _IO('M', 0)
#define MY_DEVICE_IOCTL_CMD1 _IO('M', 1)
int my_device_read(struct my_device_data *data)
{
int fd = open(DEVICE_NAME, O_RDONLY);
if (fd < 0)
return fd;
int ret = read(fd, data->data, sizeof(data->data));
if (ret >= 0)
data->len = ret;
close(fd);
return ret;
}
int my_device_write(struct my_device_data *data)
{
int fd = open(DEVICE_NAME, O_WRONLY);
if (fd < 0)
return fd;
int ret = write(fd, data->data, data->len);
close(fd);
return ret;
}
int my_device_ioctl(int cmd)
{
int fd = open(DEVICE_NAME, O_RDWR);
if (fd < 0)
return fd;
int ret = ioctl(fd, cmd);
close(fd);
return ret;
}
```
最后,以下是一个简单的用户层程序的示例代码,用于调用动态库中的测试函数,测试驱动程序的功能:
```c
#include <stdio.h>
#include "my_device.h"
int main()
{
struct my_device_data data = {{0}, 0};
int ret;
// test read and write
strcpy(data.data, "hello, world!");
data.len = strlen(data.data) + 1;
ret = my_device_write(&data);
if (ret < 0) {
fprintf(stderr, "my_device_write failed: %d\n", ret);
return 1;
}
memset(&data, 0, sizeof(data));
ret = my_device_read(&data);
if (ret < 0) {
fprintf(stderr, "my_device_read failed: %d\n", ret);
return 1;
}
printf("read data: %s\n", data.data);
// test ioctl
ret = my_device_ioctl(MY_DEVICE_IOCTL_CMD0);
if (ret < 0) {
fprintf(stderr, "my_device_ioctl failed: %d\n", ret);
return 1;
}
return 0;
}
```
阅读全文