hello_world-3.0之简单字符设备

                      hello_world-3.0之简单字符设备


1.helloworldmem.c

#include<linux/module.h>
#include<linux/init.h>
#include<linux/cdev.h>
#include<linux/fs.h>

#define HELLOWORLDMEM_SIZE 0x1000
#define HELLOWORLDMEM_MAJOR 250

static int helloworldmem_major = HELLOWORLDMEM_MAJOR;

struct helloworldmem_dev {
   struct cdev cdev;
   unsigned char mem[HELLOWORLDMEM_SIZE];
};

struct helloworldmem_dev dev;
static const struct file_operations helloworldmem_fops = {
   .owner = THIS_MODULE,
};

static void helloworldmem_setup_cdev()
{
   int err,devno = MKDEV(helloworldmem_major,0);
   cdev_init(&dev.cdev,&helloworldmem_fops);
   dev.cdev.owner = THIS_MODULE;
   err = cdev_add(&dev.cdev,devno,1);
   if(err)
      printk(KERN_NOTICE "Error %d adding helloworldmem",err);
}

int __init helloworldmem_init(void)
{
   int result;
   dev_t devno = MKDEV(helloworldmem_major,0);
   if(helloworldmem_major)
      result = register_chrdev_region(devno,1,"helloworldmem");
   else
   {
      result = alloc_chrdev_region(&devno,0,1,"helloworldmem");
      helloworldmem_major = MAJOR(devno);
      
   
   }
   if(result < 0)
      return result;
   helloworldmem_setup_cdev();
   return 0;


}

void __exit helloworldmem_exit(void)
{
   cdev_del(&dev.cdev);
   unregister_chrdev_region(MKDEV(helloworldmem_major,0),1);
}
module_init(helloworldmem_init);
module_exit(helloworldmem_exit);
MODULE_LICENSE("GPL");

2.分析以及写一个最简单的字符设备的步骤


2.1  首先是定义一个自己的结构helloworldmem_dev

这个结构呢,内嵌一个cdev;其实,我们想想前面的设备驱动模型,那个是设备中内嵌一个kobject,这里内嵌一个cdev,是想加入到字符驱动核心系统中,让他成为字符

驱动,这样编写驱动来讲更方便,而且,可以应用字符核心系统中提供的函数接口,轻易的实现在内核中创建并且注册。


2.2 关于设备号dev_t 以及注册字符设备驱动

系统中每一个设备在/dev/下都有一个设备号。其中设备的主设备号是12位,次设备号是20位

可以通过MAJOR(dev_t dev)来获取主设备号。


其实,设备号的获得有两种方法,一种是静态的:写死主设备号,然后通过MKDEV(major,mirror)来制作一个设备号,然后通过register_chrdev_region(devno,1,"helloworldmem")来注册一个字符设备驱动,

一种是动态的,这种方法比较常见:alloc_chrdev_region(&devno,0,1,"helloworldmem");这样一步将动态的分配了字符设备号,而且还注册了字符设备驱动

221 /**
222  * alloc_chrdev_region() - register a range of char device numbers
223  * @dev: output parameter for first assigned number
224  * @baseminor: first of the requested range of minor numbers
225  * @count: the number of minor numbers required
226  * @name: the name of the associated device or driver
227  *
228  * Allocates a range of char device numbers.  The major number will be
229  * chosen dynamically, and returned (along with the first minor number)
230  * in @dev.  Returns zero or a negative error code.
231  */
232 int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
233                         const char *name)
234 {
235         struct char_device_struct *cd;
236         cd = __register_chrdev_region(0, baseminor, count, name);
237         if (IS_ERR(cd))
238                 return PTR_ERR(cd);
239         *dev = MKDEV(cd->major, cd->baseminor);
240         return 0;
241 }
这个是注册一系列的连续的次设备和一个主设备的设备,dev_t *dev,将要传给的那个设备号,basemirror 开始的次设备号,count,次设备号数量,name,名字

其中已经包含了register_chrdev_region了。

2.3 初始化并注册字符设备


cdev_init(&dev.cdev,&helloworld_fops);这一步是初始化字符设备,dev.cdev.owner貌似这个是必须的,但是不清楚原因,添加上就是

cdev_add(&dev.cdev,devno,1)这一步正式的注册设备到系统中

2.4 卸载字符设备与字符设备驱动


cdev_del(&dev.cdev)  这个是卸载字符设备
unregister_chrdev_region(MKDEV(helloworld_major,0),1)
这个是卸载字符设备驱动


总结:我是根据前面简单设备模型中的内容来理解字符设备驱动,首先,我们定义了一个设备,那么他需要有设备的注册和设备驱动的注册,以及bus,那么

字符设备的bus,我们不必讨论了,这个是字符设备核心系统干的事,那么字符设备的设备注册,分为两步:一,字符设备初始化:cdev_init;二。字符设备注册到

系统中cdev_add;那么字符设备驱动的注册呢,其实就一个register_chrdev_region,这样一个设备就注册到字符设备核心子系统中了。其他的事是子系统操心的。这也就是

为什么linux中出现很多的子系统,这样很方便我们开发驱动了。

相对应的卸载设备是cdev_del,卸载驱动是unregister_chrdev_region.了

对于#include<linux/fs.h>,需要他是因为alloc_chrdev_region 和unregister_chrdev_region都在这里声明了,我本来以为需要他是因为fs_operations哈哈





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值