linux 内核驱动一 字符驱动

linux 字符驱动是最基本的设备驱动程序,接下来的所有内容都会基于这个Demo,当然也会不断的修改其中的BUG。(早晨逛超市突然想出一句话,“看别人吃肉,自己在流口水的同时,也需要想想他是怎么捕猎的”)。开个玩笑。

进入正题:

#include <linux/module.h> /* 最基本的文件,支持动态添加和卸载模块 */
#include <linux/fs.h> /* 包含了文件操作相关struct的定义,例如大名鼎鼎的struct file_operations; 同时包含了定义struct inode结构体、MINOR、MAJOR的头文件 */
#include <linux/slab.h> /* 定义了kmalloc相关的函数,要用到kmalloc 时需要include此头文件 */
#include <linux/errno.h> /* 包含了对返回值的宏定义,这样用户程序可以用perror输出错误信息 */
#include <linux/types.h> /* 对一些特殊类型的定义,例如dev_t, off_t, pid_t */
#include <linux/cdev.h> /* cdev 结构及相关函数的定义 */
#include <linux/wait.h> /* 等代队列相关头文件,同时它包含了自旋锁的头文件 */
#include <linux/init.h> /* 初始化头文件 */
#include <linux/kernel.h> /* 驱动要写入内核,与内核相关的头文件 */
#include <linux/uaccess.h> /* 包含了copy_to_user、copy_from_user等内核访问用户进程内存地址的函数定义 */
#include <linux/device.h> /* 包含了device、class 等结构的定义 */
#include <linux/io.h> /* 包含了ioremap、iowrite等内核访问IO内存等函数的定义 */
#include <linux/ioctl.h> /* _IO(type, nr)等定义 */
#include <linux/semaphore.h> /* 使用信号量必须的头文件 */
#include <asm/delay.h> /* delay */

//#define TEST_QUEUE_DEBUD/*日志控制定义 */

#ifdef TEST_QUEUE_DEBUD
    #define LOG(fmt,args...) printk(fmt,##args)
#else
    #define LOG(fmt,args...)
#endif

#define DEVICE_NAME		"test_wait_queue"   /*设备名字*/
#define FILE_NAME		"test_wait_queue0"


static int test_open(struct inode *inode, struct file* filp);
static int test_close(struct inode *inode, struct file *filp);
static ssize_t test_read(struct file *file_p, char __user * buf, size_t len, loff_t * ppos);
static ssize_t test_write(struct file *file_p, char __user * buf, size_t len, loff_t * ppos);

static char *g_buf;

static struct test_wait_queue_t
{
    struct cdev cdev;             /*字符设备结构体*/
    struct class *queue_class;    /*创建设备文件 */
    struct device *queue_device;  /*创建设备文件 */
};

static struct file_operations fops={
    .owner		= THIS_MODULE,
    .open       = test_open,
    .release    = test_close,
    .read       = test_read,
    .write      = test_write,
};
static struct test_wait_queue_t test_wait_queue; /* 设备相关结构体实例 */


static int test_open(struct inode *inode, struct file* filp)   /*打开设备 */
{
    LOG("Enter %s",__FUNCTION__);
    return 0;
}
static int test_close(struct inode *inode, struct file *filp)    /*关闭设备 */
{

    LOG("Enter %s",__FUNCTION__);
    return 0;
}
static ssize_t test_read(struct file *file_p, char __user * buf, size_t len , loff_t * ppos)
{
    int ret;
    static int num = 0;
    int length=0;
    LOG("Enter %s",__FUNCTION__);

    LOG(g_buf);
    length=strlen(g_buf)+1;

    copy_to_user(buf,g_buf,length);
    memset(g_buf,0, 100);
    return length;
 

}
static ssize_t test_write(struct file *file_p, char __user * buf, size_t len, loff_t * ppos)
{
    static int num = 0;
    LOG("Enter %s",__FUNCTION__);
    memset(g_buf,0, 100);
    copy_from_user(g_buf,buf,len);
    LOG(g_buf);
    return len; 
}

static int test_queue_init(void)
{
    int ret;
    LOG("Enter %s\n",__FUNCTION__);
    
    cdev_init(&test_wait_queue.cdev,&fops);       /*注册字符设备*/
    alloc_chrdev_region(&test_wait_queue.cdev.dev, 0, 1, DEVICE_NAME);  
    cdev_add(&test_wait_queue.cdev, test_wait_queue.cdev.dev, 1);
	/* 自动创建设备节点 */
	test_wait_queue.queue_class = class_create(THIS_MODULE, DEVICE_NAME);
	test_wait_queue.queue_device= device_create(test_wait_queue.queue_class, NULL, test_wait_queue.cdev.dev, NULL, FILE_NAME);

    g_buf = (char *)kmalloc(100,GFP_KERNEL); 

    return 0;

}
static void test_queue_exit(void)
{
    device_unregister(test_wait_queue.queue_device);
	class_destroy(test_wait_queue.queue_class);
	/* 注销字符设备 */
	cdev_del(&test_wait_queue.cdev);
	/* 释放设备号 */
	unregister_chrdev_region(test_wait_queue.cdev.dev, 1);
    LOG("Exit %s\n",__FUNCTION__);
    kfree(g_buf);
}
module_init(test_queue_init);
module_exit(test_queue_exit);

MODULE_AUTHOR("yhl");
MODULE_DESCRIPTION("test_queue_exit");
MODULE_LICENSE("GPL");

总结一下下,编写一个最简单的字符驱动设备,有以下几个必须的步骤:

1. 通过module_init()来创建自己的入口函数;

2. 填充file_op结构体,创建字符设备;

3. 创建设备文件   即 /dev下的文件;

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值