Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1681645
  • 博文数量: 1493
  • 博客积分: 38
  • 博客等级: 民兵
  • 技术积分: 5834
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-19 17:28
文章分类

全部博文(1493)

文章存档

2016年(11)

2015年(38)

2014年(137)

2013年(253)

2012年(1054)

2011年(1)

分类:

2012-07-11 08:28:38

原文地址:Linux字符设备驱动 作者:pingchang2012

    在Linux中有一句哲学“Linux下皆文件”,设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以像操作普通文件一样对硬件设备进行操作。
Linux设备驱动程序的分类:
Linux设备驱动程序分为字符设备驱动(无缓冲且只能顺序存取),块设备驱动程序(有缓冲且可以随机存取)。每个字符设备和块设备都必须有主次设备号,主设备号相同的设备是同类设备(使用同一驱动程序)(1)块设备:系统中能够随机(不需要按顺序)访问固定大小数据片(chunk)的设备被称作块设备;他们都是以安装文件系统的方式使用的(2)字符设备:字符设备按照字符流动的方式被有序访问

在内核中,dev_t类型用来保存设备编号(包括主设备号和次设备号),dev_t是一个32位的数,12位表示主设备号,20为表示次设备号

(1)主设备号 = MAJOR(dev_t dev)

(2)次设备号 = MINOR(dev_t dev)

(3)设备编号 = MKDEV(int major,int minor)

分配和释放设备号:

(1)int register_chrdev_region(dev_t first,unsigned int count,char *name);

(2)int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name);

(3)void unregister_chrdev_region(dev_t first,unsigned int count);

注册字符设备
在获得了设备号范围之后,需要将设备添加到字符设备数据库中,以激活设备。这需要用cdev_init函数初始化一个struct cdev的实例,然后调用cdev_add函数

(1)void cdev_init(struct cdev *cdev,struct file_operation *fops);
函数用于初始化cdev的成员,并建立cdev和file_operations之间的连接

(2)int  cdev_add(struct cdev *dev,dev_t num,unsigned int count)
(3)void  cdev_del(stuct cdev *dev)
cdev_add()函数和cdev_del()函数分别向系统添加和删除一个cdev,完成字符设备的注册和注销。对cdev_add()的调用通常发生在字符设备驱动模块加载函数中,
而对cdev_del()函数的调用则通常发生在字符设备驱动模块卸载函数中

cdev 一般它有两种定义初始化方式:静态的和动态的

1>静态内存定义初始化:

struct cdev my_cdev;

cdev_init(&my_cdev, &fops);

my_cdev.owner = THIS_MODULE;

2>动态内存定义初始化:

struct cdev *my_cdev = cdev_alloc();

my_cdev->ops = &fops;

my_cdev->owner = THIS_MODULE;

实际上Linux内核为我们提供了一组函数,可以用来在模块加载的时候自动在/dev目录下创建相应设备节点,并在卸载模块时删除该节点,class_creat 以及 device_creat 来实现自动在 /dev 下自动创建节点

  1. int __init hello_init (void)
    {
        int result;
        devno = MKDEV(HELLO_MAJOR, HELLO_MINOR);
  2.     if (HELLO_MAJOR)
  3.     {
           result = register_chrdev_region(devno, 2, "memdev");
  4.     }
        else
  5.     {
           result = alloc_chrdev_region(&devno, 0, 2, "memdev");
           HELLO_MAJOR = MAJOR(devno);
        } 
        printk("MAJOR IS %d\n",HELLO_MAJOR);
  6.     my_class = class_create(THIS_MODULE,"hello_char_class");  //类名为
  7.     if(IS_ERR(my_class))
       {
              printk("Err: failed in creating class.\n");
              return -1; 
        }
  8.     device_create(my_class,NULL,devno,NULL,"memdev");      //设备名为memdev
  9.    if (result<0)
        {
               printk (KERN_WARNING "hello: can't get major number %d\n",         HELLO_MAJOR);
               return result;
        }
  10.     cdev_init(&cdev, &hello_fops);
        cdev.owner = THIS_MODULE;
        cdev_add(&cdev, devno, NUMBER_OF_DEVICES);
  11.     printk (KERN_INFO "Character driver Registered\n");
        return 0;
    }
  12. static void __exit hello_exit (void)
  13. {
        cdev_del (&cdev);
  14.     device_destroy(my_class, devno);         //delete device node under /dev//必须先删除设备,再删除class类
        class_destroy(my_class);                 //delete class created by us
  15.     unregister_chrdev_region (devno,NUMBER_OF_DEVICES);
  16.     printk (KERN_INFO "char driver cleaned up\n");
    }
  17. module_init (hello_init);
    module_exit (hello_exit);
阅读(202) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~