register_chrdev()与unregister_chrdev()

Linux下的设备驱动程序被组织为一组完成不同任务的函数的集合,通过这些函数使得Windows的设备操作犹如文件一般。在应用程序看来,硬件设备只 是一个设备文件,应用程序可以象操作普通文件一样对硬件设备进行操作,如open ()、close ()、read ()、write () 等。
Linux主要将设备分为二类:字符设备和块设备。字符设备是指设备发送和接收数据以字符的形式进行;而块设备则以整个数据缓冲区的形式进行。字符设备的驱动相对比较简单。

  下面我们来假设一个非常简单的虚拟字符设备:这个设备中只有一个4个字节的全局变量int global_var,而这个设备的名字叫做"gobalvar"。对"gobalvar"设备的读写等操作即是对其中全局变量global_var的操作。

  驱动程序是内核的一部分,因此我们需要给其添加模块初始化函数,该函数用来完成对所控设备的初始化工作,并调用register_chrdev() 函数注册字符设备:

static int __init gobalvar_init(void)
{
 if (register_chrdev(MAJOR_NUM, " gobalvar ", &gobalvar_fops))
 {
  //…注册失败
 }
 else
 {
  //…注册成功
 }
}

   其中,register_chrdev函数中的参数MAJOR_NUM为主设备号,"gobalvar"为设备名,gobalvar_fops为包含基 本函数入口点的结构体,类型为file_operations。当gobalvar模块被加载时,gobalvar_init被执行,它将调用内核函数 register_chrdev,把驱动程序的基本入口点指针存放在内核的字符设备地址表中,在用户进程对该设备执行系统调用时提供入口地址。

  与模块初始化函数对应的就是模块卸载函数,需要调用register_chrdev()的"反函数" unregister_chrdev():

static void __exit gobalvar_exit(void)
{
 if (unregister_chrdev(MAJOR_NUM, " gobalvar "))
 {
  //…卸载失败
 }
 else
 {
  //…卸载成功
 }
}

   随着内核不断增加新的功能,file_operations结构体已逐渐变得越来越大,但是大多数的驱动程序只是利用了其中的一部分。对于字符设备来 说,要提供的主要入口有:open ()、release ()、read ()、write ()、ioctl ()、llseek()、poll()等



使用register_chrdev注册字符设备

注册字符设备可以使用register_chrdev函数。

 
 
  1. int register_chrdev (unsigned int major, const  char *name, struct file_operations*fops); 

register_chrdev函数的major参数如果等于0,则表示采用系统动态分配的主设备号。

注销字符设备可以使用unregister_chrdev函数。

 
 
  1. int unregister_chrdev(unsigned int major, const char *name); 

例1.3  register_chrdev注册字符设备实例

代码见光盘\src\1drivermodel\1-3register_chrdev。核心代码如下所示:

 
 
  1. static unsigned char simple_inc=0;  
  2. static unsigned char demoBuffer[256];  
  3. int simple_open(struct inode *inode, struct file *filp)  
  4. {  
  5.     if(simple_inc>0)return -ERESTARTSYS;  
  6.     simple_inc++;  
  7.     return 0;  
  8. }  
  9. int simple_release(struct inode *inode, struct file *filp)  
  10. {  
  11.     simple_inc--;  
  12.     return 0;  
  13. }  
  14. ssize_t simple_read(struct file *filp, char __user *buf, size_t count,loff_t *f_pos)  
  15. {  
  16.     /* 把数据复制到应用程序空间 */  
  17.     if (copy_to_user(buf,demoBuffer,count))  
  18.     {  
  19.        count=-EFAULT;   
  20.     }  
  21.     return count;  
  22. }  
  23. ssize_t simple_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)  
  24. {  
  25.     /* 把数据复制到内核空间 */  
  26.     if (copy_from_user(demoBuffer+*f_pos, buf, count))  
  27.     {  
  28.         count = -EFAULT;  
  29.     }  
  30.     return count;  
  31. }  
  32. struct file_operations simple_fops = {  
  33.     .owner =    THIS_MODULE,  
  34.     .read =     simple_read,  
  35.     .write =    simple_write,  
  36.     .open =     simple_open,  
  37.     .release =  simple_release,  
  38. };  
  39. /*******************************************************  
  40.                 MODULE ROUTINE  
  41. *******************************************************/  
  42. void simple_cleanup_module(void)  
  43. {  
  44.     unregister_chrdev(simple_MAJOR,  "simple");   
  45.     printk("simple_cleanup_module!\n");  
  46. }  
  47. int simple_init_module(void)  
  48. {  
  49.     int ret;  
  50.     //根据设备号与设备名注册字符设备  
  51.     ret = register_chrdev(simple_MAJOR, "simple", &simple_fops);   
  52.     if (ret < 0)  
  53.     {  
  54.         printk("Unable to register character device %d!\n",simple_MAJOR);  
  55.         return ret;  
  56.     }  
  57.     return 0;  
  58. }  
  59. module_init(simple_init_module);  
  60. module_exit(simple_cleanup_module);  

应用程序的代码如下:
 
 
  1. void main(void)  
  2. {  
  3.     int fd;  
  4.     int i;  
  5.     char data[256];  
  6.     int retval;  
  7.     fd=open("/dev/fgj",O_RDWR);  
  8.     if(fd==-1)  
  9.     {  
  10.         perror("error open\n");  
  11.         exit(-1);  
  12.     }  
  13.     printf("open /dev/fgj successfully\n");  
  14.     //写数据  
  15.     retval=write(fd,"fgj",3);  
  16.     if(retval==-1)  
  17.     {  
  18.         perror("write error\n");  
  19.         exit(-1);  
  20.     }  
  21.     //读数据  
  22.     retval=read(fd,data,3);  
  23.     if(retval==-1)  
  24.     {  
  25.         perror("read error\n");  
  26.         exit(-1);  
  27.     }  
  28.     data[retval]=0;  
  29.     printf("read successfully:%s\n",data);  
  30.     //关闭设备  
  31.     close(fd);  
  32. }  

字符设备模块使用insmod加载,加载完毕需要在/dev目录下使用mkmod命令建立相应的文件结点,编译生成的应用层可执行程序为test。本例运行结果如下:
 
 
  1. [root@/home]#insmod demo.ko  
  2. [root@urbetter /home]# mknod /dev/fgj c 224 0  
  3. [root@urbetter /home]# ./test   
  4. open /dev/fgj successfully  
  5. read successfully:fgj  

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值