一步步写驱动--设备号

接触过linux的人都知道linux下有七类文件分别是”bcd-lsp”,即b:块设备文件、c:字符设备文件、d:目录、-:普通文件、l:符号链接文件、s:socket文件、p:管道文件。在这些文件里面有连个文件和我们驱动是息息相关的,它们就是字符设备文件和块设备文件。不同于其他文件块设备文件和字符设备文件一般都统一放在/dev目录下。

首先我们看看这类文件是如何得到的,在linux下有个命令mknod,这个命令就是创建设备文件的,命令执行示例:

mknod /dev/console  c  5  1

mknod /dev/sda1     b 8  1

         上面命令执行的时候有四个参数,第一个是我们创建设备文件的名字,第二个参数c(character)表示创建的是字符设备文件,b(block)表示创建的块设备文件,第三个参数表示主设备号,第四个参数表示此设备号。

         Linux下一切皆文件,也就是说可以按照文件的方式访问设备,即访问/dev/下的这些设备文件就能访问到我们的设备。可是这个文件是我们创建出来的,为什么它就是一个设备了呢。其实设备文件本省并不重要,除了一些标准的设备有自己固定的名字外,其他的设备名字是什么并不重要,只要应用程序知道这个设备节点对应哪个设备就可以了,那么怎么样让设备文件和设备对应呢,那么这就是设备号的作用了。

         我们在写设备驱动的时候会为每个设备分配一个设备号,而设备号有分为两部分,一部分是主设备号,一部分是次设备好,主设备好表示是类型的设备,次设备号表示是第几个这类设备。

         前面我们介绍了模块的组成,这里就按部就班的把模块变成驱动,这里先写字符驱动,那么第一步也就是为我们的驱动分配设备号:

         首先我们要构建一个设备号,在内核里有如下定义:

#define MINORBITS         20

#define MINORMASK       ((1U << MINORBITS) - 1)

 

#define MAJOR(dev)        ((unsigned int) ((dev) >>MINORBITS))

#define MINOR(dev)        ((unsigned int) ((dev) & MINORMASK))

#define MKDEV(ma,mi)   (((ma) << MINORBITS) | (mi))

         MKDEV就是构建设备号的一个宏,这个宏有两个参数分别对应的是主设备号和此设备号。从宏的定义我们能够看出一个设备号是一个无符号长整型的数,且主设备号和次设备号分别占12位和20位。另外两个宏MAJOR和MINOR是从一个设备号中取出主次设备号。

         接着我们要做的工作是向操作系统申请这个号,在内核里有如下函数:

int register_chrdev_region(dev_tfrom, unsigned count, const char *name)

{

         ……

}

         我们使用上面这个函数来申请设备号我们先了解下他的参数和返回值:

         参数 from:我们要申请的第一个设备号

                    count:我们要申请从from开始连续的多少个设备号

                    name:内核用来记录这段设备设备号被那个驱动申请走了

         返回值 0 :表示成功

                      负数:表示errno即什么原因导致的我们的失败,errno可以参考include/asm-generic/errno.h和include/asm-generic/errno-base.h

         有申请就有释放,释放设备号使用如下函数:

void unregister_chrdev_region(dev_tfrom, unsigned count)

{

         ……

}

         参数 from:我们要申请的第一个设备号

                    count:我们要申请从from开始连续的多少个设备号

         返回值:这个函数是linux里为数不多的没有返回值的函数

         接着我们要做的工作就是把这些内容添加到我们的模块中:

 #include <linux/module.h>

#include<linux/kernel.h>

#include<linux/init.h>

 

#include<linux/fs.h>

 

MODULE_LICENSE("GPL");

 

int hello_major = 250;

int hello_minor = 0;

int number_of_devices =1;

 

static int __inithello_2_init (void)

{

  int result;

  dev_t dev = 0;

 

  dev = MKDEV (hello_major, hello_minor);

  result = register_chrdev_region (dev,number_of_devices, "hello");

  if (result<0) {

    printk (KERN_WARNING "hello: can't getmajor number %d\n", hello_major);

    return result;

  }

 

  printk (KERN_INFO "Registered characterdriver\n");

  return 0;

}

 

static void __exithello_2_exit (void)

{

  dev_t devno = MKDEV (hello_major,hello_minor);

 

  unregister_chrdev_region (devno,number_of_devices);

 

  printk (KERN_INFO "Char driver cleanedup\n");

}

 

module_init(hello_2_init);

module_exit(hello_2_exit);

         重新编译模块插入内核后我们可以通过cat /proc/devices查看我们的设备号是否申请成功如果是如下现象就OK了:

root@ubuntu:# cat /proc/devices

Character devices:

  1 mem

  4 /dev/vc/0

  4 tty

  4 ttyS

  5 /dev/tty

  5 /dev/console

  5 /dev/ptmx

  6 lp

  7 vcs

 10 misc

 13 input

 21 sg

 29 fb

 99 ppdev

108 ppp

116 alsa

128 ptm

136 pts

180 usb

189 usb_device

250 hello  //这个名字和我们申请设备号函数传递的名字必须相同

251 vmci

252 usbmon

253 bsg

254 rtc

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值