1. 驱动框架
1.1 驱动文件: my_cdev.c
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/slab.h>
#define MAX_DEV_CNT 65535
struct my_cdev {
int len;
unsigned char buf[100];
struct cdev cdev;
};
struct my_cdev *my_cdev;
static dev_t dev_num;
struct class *my_cdev_class;
static ssize_t my_cdev_read(struct file *file, char __user *buffer, size_t count,
loff_t *ppos)
{
struct my_cdev *dev = file->private_data;
if (copy_to_user(buffer, &dev->buf, count))
printk("read failed.\n");
return sizeof(int);
}
static ssize_t my_cdev_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
struct my_cdev *dev = file->private_data;
int i;
if (copy_from_user(&dev->buf, buffer, count))
printk("write failed.\n");
for (i = 0; i < count; i++)
printk("dev->buf[%d] = %c\n", i, dev->buf[i]);
return sizeof(int);
}
static int my_cdev_open(struct inode *inode, struct file *file)
{
struct my_cdev *mycd;
mycd = container_of(inode->i_cdev, struct my_cdev, cdev);
file->private_data = mycd;
printk("my char device is opened.\n");
return 0;
}
static int my_cdev_release(struct inode *inode, struct file *filp)
{
printk("my char device is closed.\n");
return 0;
}
static const struct file_operations my_cdev_fops = {
.owner = THIS_MODULE,
.read = my_cdev_read,
.write = my_cdev_write,
.open = my_cdev_open,
.release = my_cdev_release,
};
int __init my_cdev_init(void)
{
int ret = 0;
my_cdev = kzalloc(sizeof(struct my_cdev), GFP_KERNEL);
if (!my_cdev) {
printk("can't alloc memory for this device.\n");
goto err;
ret = -ENOMEM;
}
ret = alloc_chrdev_region(&dev_num, 0, MAX_DEV_CNT, "my_cdev");
if (ret < 0) {
printk("register the device number failed.\n");
goto err;
}
cdev_init(&my_cdev->cdev, &my_cdev_fops);
ret = cdev_add(&my_cdev->cdev, dev_num, MAX_DEV_CNT);
if (ret < 0){
printk("add the device failed.\n");
goto cdev_add_failed;
}
my_cdev_class = class_create(THIS_MODULE, "mycdev");
if (IS_ERR(my_cdev_class)) {
printk(KERN_ERR "Error creating mycdev class.\n");
cdev_del(&my_cdev->cdev);
goto cdev_add_failed;
}
device_create(my_cdev_class, NULL, dev_num, NULL, "my_cdev");
printk("my chardev initialized.\n");
return ret;
cdev_add_failed:
unregister_chrdev_region(dev_num, MAX_DEV_CNT);
err:
kfree(my_cdev);
return ret;
}
void __exit my_cdev_exit(void)
{
device_destroy(my_cdev_class, dev_num);
class_destroy(my_cdev_class);
cdev_del(&my_cdev->cdev);
unregister_chrdev_region(dev_num, MAX_DEV_CNT);
printk("my chardev removed.\n");
}
module_init(my_cdev_init);
module_exit(my_cdev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("2247720389@qq.com");
MODULE_DESCRIPTION("A char device driver frame");
1.2 Makefile
obj-m += my_cdev.o
KERN_DIR := /lib/modules/$(shell uname -r)/build
all:
$(MAKE) -C $(KERN_DIR) M=`pwd` modules
.PHONY: clean
clean:
make -C $(KERN_DIR) M=`pwd` clean
2. 驱动测试程序
2.1 测试文件: my_cdev_test.c
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#define W_SIZE 10
#define R_SIZE 8
int main(int argc, char **argv)
{
int fd;
unsigned char w_buffer[100] = {'h','e','l','l','o','w','o','r','l','d'};
unsigned char r_buffer[100] = {0};
int i;
int ret;
fd = open("/dev/my_cdev", O_RDWR);
if (fd < 0)
printf("can't open the device!\n");
printf("***hello world*** fd = %d\n", fd);
ret = write(fd, w_buffer, W_SIZE);
if (ret == -1)
printf("sorry, write failed.\n");
ret = read(fd, r_buffer, R_SIZE);
if (ret == -1)
printf("sorry, read failed.\n");
for (i = 0; i < R_SIZE; i++)
printf("r_buffer[%d] = %c\n", i, r_buffer[i]);
close(fd);
return 0;
}
2.2 Makefile
all:
gcc -o my_cdev_test my_cdev_test.c
clean:
rm -rf *.o
rm -rf my_cdev_test
3. 测试结果(全程打开dmesg)
3.0 全程打开dmesg
3.1 加载driver
3.2 运行test程序
3.3 卸载driver
driver卸载后,再次查看/proc/devices和/sys/class,则无my_cdev信息。
4. 附dmesg