字符设备例子
嵌入式平台采用RK的,交叉编译工具链采用官方提供的交叉编译工具链。
1.驱动代码dummy_char.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/version.h>
#include <linux/device.h>
#include <linux/cdev.h>
static unsigned int major; /* major number for device */
static struct class *dummy_class;
static struct cdev dummy_cdev;
int dummy_open(struct inode * inode, struct file * filp)
{
pr_info("Someone tried to open me\n");
return 0;
}
int dummy_release(struct inode * inode, struct file * filp)
{
pr_info("Someone closed me\n");
return 0;
}
ssize_t dummy_read (struct file *filp, char __user * buf, size_t count,
loff_t * offset)
{
pr_info("Nothing to read guy\n");
return 0;
}
ssize_t dummy_write(struct file * filp, const char __user * buf, size_t count,
loff_t * offset)
{
pr_info("Can't accept any data guy\n");
return count;
}
struct file_operations dummy_fops = {
open: dummy_open,
release: dummy_release,
read: dummy_read,
write: dummy_write,
};
static int __init dummy_char_init_module(void)
{
struct device *dummy_device;
int error;
dev_t devt = 0;
/* Get a range of minor numbers (starting with 0) to work with */
error = alloc_chrdev_region(&devt, 0, 1, "dummy_char");
if (error < 0) {
pr_err("Can't get major number\n");
return error;
}
major = MAJOR(devt);
pr_info("dummy_char major number = %d\n",major);
/* Create device class, visible in /sys/class */
dummy_class = class_create(THIS_MODULE, "dummy_char_class");
if (IS_ERR(dummy_class)) {
pr_err("Error creating dummy char class.\n");
unregister_chrdev_region(MKDEV(major, 0), 1);
return PTR_ERR(dummy_class);
}
/* Initialize the char device and tie a file_operations to it */
cdev_init(&dummy_cdev, &dummy_fops);
dummy_cdev.owner = THIS_MODULE;
/* Now make the device live for the users to access */
cdev_add(&dummy_cdev, devt, 1);
dummy_device = device_create(dummy_class,
NULL, /* no parent device */
devt, /* associated dev_t */
NULL, /* no additional data */
"dummy_char"); /* device name */
if (IS_ERR(dummy_device)) {
pr_err("Error creating dummy char device.\n");
class_destroy(dummy_class);
unregister_chrdev_region(devt, 1);
return -1;
}
pr_info("dummy char module loaded\n");
return 0;
}
static void __exit dummy_char_cleanup_module(void)
{
unregister_chrdev_region(MKDEV(major, 0), 1);
device_destroy(dummy_class, MKDEV(major, 0));
cdev_del(&dummy_cdev);
class_destroy(dummy_class);
pr_info("dummy char module Unloaded\n");
}
module_init(dummy_char_init_module);
module_exit(dummy_char_cleanup_module);
MODULE_AUTHOR("John Madieu <john.madieu@gmail.com>");
MODULE_DESCRIPTION("Dummy character driver");
MODULE_LICENSE("GPL");
2. Makefile
KERN_DIR = /opt/RV1126/kernel
all:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -C $(KERN_DIR) M=$(shell pwd) modules
cp -rf ./dummy_char.ko
clean:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -C $(KERN_DIR) M=$(shell pwd) clean
rm -rf modules.order ./*.ko ./*.o
obj-m += dummy_char.o
3. 挂载和测试
root# mkdir /lib/modules/$(uname -r)
root# insmod dummy_char.ko
dummy_char major number = 240
dummy char module loaded
root# echo 'test' > /dev/dummy_char
Someone tried to open me
Can't accept any data guy
Someone closed me
root# cat /dev/dummy_char
Someone tried to open me
Nothing to read guy
Someone closed me
root# rmmod dummy_char.ko
dummy char module Unloaded