设备驱动分层:设备节点,设备驱动相关 用了半个月来看字符设备中的错综复杂的结构体,以后要达到的标准是从一个Hello World模板直接写出一个字符设备驱动程序。
设备节点相关:
freg_init()
{
err = alloc_chrdev_region(&dev, 0, 1 , FREG_DEVNODE_NAME);
freg_major = MAJOR(dev);
freg_minor = MINOR(dev);
..........
}
freg_exit()
{
unregister_chrdev_region(MKDEV(freg_major, freg_minor), 0, 1 , FREG_DEVNODE_NAME);
..........
}
字符设备驱动层:static struct file_operations freg_fops = {
.owner = THIS_MODULE,
.open = freg_open,
.release = freg_release,
.read = freg_read,
.write = freg_write,
};
freg_init()
{
cdev_init(&(dev->dev), &freg_fops);dev->dev.owner = THIS_MODULE;
dev->dev.ops = &freg_fops; //cdev_init会将freg_fops赋值给dev.ops所以不用再赋值 可以省略。
err = cdev_add(&(dev->dev),devno, 1);
..........
}
freg_exit()
{
cdev_del(&(freg_dev->dev));
..........
}
完整代码:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
static struct cdev *freg_cdev; //An instance of a character device
static dev_t ndev; //The node of the device
/* "freg"设备的全局变量 */
static int freg_var = 0;
//static int freg_major = 250;
static int freg_major = 0;
static int freg_minor = 0;
static ssize_t freg_read(struct file *filp, char __user *buf, size_t sz, loff_t *off)
{
printk("In the freg_read() function!\n");
/* 将freg_var从内核空间复制到用户空间 */
if (copy_to_user(buf, &freg_var, sizeof(int))) {
return - EFAULT;
}
printk("freg_read enter ,the data is %d\n",freg_var);
return sizeof(int);
}
static ssize_t freg_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos)
{
printk("In the freg_write() function!\n");
/* 将用户空间的数据复制到内核空间的freg_var */
if (copy_from_user(&freg_var, buf, sizeof(int))) {
return -EFAULT;
}
printk("freg_write enter ,the data is %d\n",freg_var);
return sizeof(int);
}
// file_operations is a very important data struct in character type device
struct file_operations freg_ops = {
.owner = THIS_MODULE,
.read = freg_read,
.write = freg_write,
};
// initialization function of the module
static int __init freg_init(void)
{
int err;
printk(KERN_ALERT"Initializing freg device.\n");
// -----------------------设备号相关--------------------------
err = alloc_chrdev_region(&ndev, 0, 1, "freg"); //allocate the device node number dynamically
if(err < 0)
return err;
freg_major = MAJOR(ndev);
freg_minor = MINOR(ndev);
printk("freg_init():major=%d, minor=%d\n", MAJOR(ndev), MINOR(ndev));
// -------------------------完------------------------------
// ----------------------设备驱动相关--------------------------
freg_cdev = cdev_alloc();
cdev_init(freg_cdev, &freg_ops); //initialize the device instance
freg_cdev->owner = THIS_MODULE;
//freg_cdev->ops = &freg_ops; //可以不做,因为cdev_init会将freg_ops赋值
err = cdev_add(freg_cdev, ndev, 1);//register the char_dev into the system
if(err < 0)
return err;
// -------------------------完--------------------------------
printk(KERN_ALERT"Succedded to initialize freg device.\n");
return 0;
}
static void __exit freg_exit(void)
{
ndev = MKDEV(freg_major, freg_minor);
printk(KERN_ALERT"Destroy freg device.\n");
cdev_del(freg_cdev); //unregister the char_dev from the system
unregister_chrdev_region(ndev, 1);//free the device node number
}
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Fake Register Driver");
module_init(freg_init);
module_exit(freg_exit);
编译好后,insmod freg.ko加载驱动。
# cat /proc/devices | grep freg
通过以上命令来查找freg的主设备号
# mknod /dev/freg c 250 0
创建设备节点
应用程序测试:
测试结果: