Linux设备驱动程序学习笔记4——简单的字符设备实现

 
这一节,我将对上一节建立的字符设备框架进行实现。这里只对init,exit,open,release,read和write函数做了实现。
在Linux下用vi建立一DemoCharDev.c文件,其内容书写如下:
 
//DemoCharDev.c start///
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/kernel.h> //for container_of
#include <linux/cdev.h> //与cdev相关
#include “scull.h” //《 Linux 设备驱动程序》自带的例子代码
#define MAJOR_NUM 14 //主设备号
#define MINOR_NUM 3 //次设备号
#define NAME “DemoCharDev” //设备名称
 
MODULE_LECENSE(“Dual BSD/GPL”);
 
static int DemoCharDev_open(struct inode *inode, struct file *filp);
static int DemoCharDev_release(struct inode *inode, struct file *filp);
ssize_t DemoCharDev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
ssize_t DemoCharDev_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);
 
static int major = MAJOR_NUM;
statci struct cdev DemoCharDev;
struct file_operations DemoCharDev_fops = {
.owner = THIS_MODULE,
.open = DemoCharDev_open,
.release = DemoCharDev_release,
.read = DemoCharDev_read,
.write = DemoCharDev_write, //注意此处的逗号
};
 
static int __init DemoCharDev_init(void)
{//__init标记表示该函数只在初始化期间使用
        int ret;
        dev_t dev_id;
 
       printk(“Hello, enter the DemoCharDev_init function!/n”);
       
        //获取主设备号
        if(major)
        {
               //静态分配
               dev_id = MKDEV(major, MINOR_NUM); //将主次设备号转化为dev_t类型
               ret = register_chrdev_region(dev_id, 3, NAME);               
        }
        else
        {
               //动态分配
               ret = alloc_chrdev_region(&dev_id, 0, 3, NAME);
               major = MAJOR(dev_id);
        }
        if(ret < 0)
        {
               printk(“DemoCharDev: can’t get major %d/n”, major);
               return ret;
        }
        printk(“MAJOR: %d/n”,major);
 
        cdev_init(&DemoCharDev, &char_fops); //初始化分配到struct cdev结构
        ret = cdev_add(&DemoCharDev, dev_id, 1); //告诉内核有关struct cdev结构的信息
if(ret < 0)
        {
               printk(“DemoCharDev: can’t add the device! Error no is %d/n”, ret);
               return ret;
        }
 
        printk(“Goodbye, the DemoCharDev_init is over!/n”);
 
       return 0;
}
 
static void __exit DemoCharDev_exit(void)
{//__exit表示该函数只能在模块被卸载或者系统关闭时被调用
        dev_t dev_id;
 
       printk(“Goodbye, cruel world!/n”);
       
        cdev_del(&DemoCharDev); //从系统中移除字符设备
dev_id = MKDEV(major, MINOR_NUM);
        unregister_chrdev_region(dev_id, 3); //释放设备编号
 
printk(“Goodbye, the DemoCharDev_exit function is over!/n”);
}
 
static int DemoCharDev_open(struct inode *inode, struct file *filp)
{
        struct scull_dev *dev;
 
       printk(“Hello, enter the DemoCharDev_open function!/n”);
      
        dev = container_of(inode->i_cdev, struct scull_dev, cdev);
        filp->private_data = dev;
 
        if((filp->f_flags & O_ACCMODE) == O_WRONLY)
        {
               scull_trim(dev);
        }
      
printk(“Goodbye, the DemoCharDev_open function is over!/n”);
 
return 0;
}
 
static int DemoCharDev_release(struct inode *inode, struct file *filp)
{
        //release函数暂不做任何处理
       printk(“Hello, enter the DemoCharDev_release function!/n”);
        printk(“Goodbye, the DemoCharDev_release function is over!/n”);
       return 0;
}
 
ssize_t DemoCharDev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
        struct scull_dev *dev = filp->private_data;
        struct scull_qset *dptr = NULL; //第一个链表项
        int quantum = dev->quantum;
        int qset = dev->qset;
        int itemsize = quantum * qset; //该链表项有多少字节
int item, s_pos, q_pos, rest;
ssize_t retval = 0;
 
       printk(“Hello, enter the DemoCharDev_read function!/n”);
 
        if(down_interruptible(&dev->sem))
        {
               return –ERESTARTSYS;
        }
       
        if(*f_pos >= dev->size)
               goto out;
        if(*f_pos + count > dev->size)
               count = dev->size - *f_pos;
 
        //在量子集中寻找链表项,qset索引及偏移量
        item = (long)*f_pos / itemsize;
        rest = (long)*f_pos % itemsize;
        s_pos = rest / quantum;
        q_pos = rest % quantum;
        //沿该链表前行,直到正确的位置
        dptr = scull_follow(dev, item);
 
        if(NULL == dptr || !dptr->data || !dptr->data[s_pos])
               goto out;
        //读取该量子的数据直到结尾
if(count > quantum – q_pos)
               count = quantum – q_pos;
 
        if(copy_to_user(buf, dptr->data[s_pos] + q_pos, count))
{
       retval = -EFAULT;
       goto out;
}
       *f_pos += count;
        retval = count;
out:
        up(&dev->sem);
printk(“Goodbye, the DemoCharDev_read function is over!/n”);
        return retval;
}
 
ssize_t DemoCharDev_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
        struct scull_dev *dev = filp->private_data;
        struct scull_qset *dptr = NULL;
        int quantum = dev->quantum;
        int qset = dev->qset;
        int itemsize = quantum * qset;
        int item, s_pos, q_pos, rest;
        ssize_t retval = -ENOMEM;
 
       printf(KERN_ALERT “Hello, enter the DemoCharDev_write function!/n”);
 
if(down_interruptible(&dev->sem))
        {
               return –ERESTARTSYS;
        }
        //在量子集中寻找链表项,qset索引及偏移量
        item = (long)*f_pos / itemsize;
        rest = (long)*f_pos % itemsize;
        s_pos = rest / quantum;
        q_pos = rest % quantum;
        //沿该链表前行,直到正确的位置
        dptr = scull_follow(dev, item);
        if(NULL == dptr)
        {
               goto out;
        }
        if(!dptr->data)
        {
               dptr->data = kmalloc(qset*sizeof(char *), GFP_KERNEL);
               if(!dptr->data)
                      goto out;
               memset(dptr->data, 0, qset*sizeof(char*));
        }
        If(!dptr->data[s_pos])
        {
               dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL);
               If(!dptr->data[s_pos])
                      goto out;
        }
        //读取该量子的数据直到结尾
if(count > quantum – q_pos)
               count = quantum – q_pos;
        if(copy_from_user(dptr->data[s_pos]+q_pos,buf,count))
        {
               retval = -EFAULT;
               goto out;
        }
        *f_pos += count;
        retval = count;
 
        if(dev->size < *f_pos)
               dev->size = *f_pos;
out:
        up(&dev->sem);
        printk(“Goodbye, the DemoCharDev_write function is over!/n”);
        return retval;
}
 
module_init(DemoCharDev_init);
module_exit(DemoCharDev_exit);
//DemoCharDev.c end///
其Makefile文件的书写如“ Linux设备驱动程序学习笔记1——模块加载和卸载”中所描述。
 
文中只是一个字符设备驱动的框架的简单实现。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值