linux系统中实现字符设备及其驱动程序

实验编号

2

题目

字符设备

实验目的

了解Linux设备管理原理,。

实验内容

实现一个虚拟的字符设备及其相关的驱动程序,支持以下功能:

用户可以向设备写入字符串,并覆盖设备中原有的字符串;

用户可以从设备读出写入的字符串;

用户通过系统调用ioctl清除设备中写入的字符串;

设备关闭前,只能被打开一次.

参见ppt中的rwbuff设备及其驱动程序

报告内容要求

(1) 程序实现方法和思路

(2) 测试及结果

     

一、            实现思路

         Linux将硬件设备看做一类特殊的文件(/dev/*),设备驱动程序被组织为一组完成不同任务的函数的集合,通过这些函数使得linux的设备操作犹如文件一般。在应用程序看来,硬件设备只是一个设备文件,应用程序可以象操作普通文件一样对硬件设备进行操作,如open()close()read()write() 等。

    所以,一个字符( char ) 设备也就是一种可以当作一个字节流来存取的设备( 如同一个文件 ),可以通过一系列的文件操作实现字符设备驱动程序。

 

二、            实验步骤

(1)   设置内核支持模块(make menuconfig),如图2.1所示:

 

                                        2.1 模块支持的设置

不过,这一步可以省略,因为所使用的linux系统――linux-up内核,默认支持模块的。

(2)   所需头文件及宏定义

#include  <linux/kernel.h>        // for kernel programming

#include <linux/module.h>       //  for kernel module struct.

#include <linux/fs.h>             //  struct file_operations

 

#define   RWBUF_NAME  “rwbuf”           // 设备文件 /dev/rwbuf

#define   RWBUF_DEV    “/dev/rwbuf”    // device path

#define  RWBUF_MAJOR  60               // 主设备号

#define  RWBUF_CLEAR   0x909090       // IO Ctrl Command

(3)   重要的数据结构:file_operationsfileinode

<linux/fs.h>中定义了这三个结构.
struct file_operations {
         struct module *owner;
         loff_t (*llseek) (struct file *, loff_t, int);
         ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
         ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
         ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
         ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);
         int (*readdir) (struct file *, void *, filldir_t);
         unsigned int (*poll) (struct file *, struct poll_table_struct *);
         int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
         int (*mmap) (struct file *, struct vm_area_struct *);
         int (*open) (struct inode *, struct file *);
         int (*flush) (struct file *);
         int (*release) (struct inode *, struct file *);
         int (*fsync) (struct file *, struct dentry *, int datasync);
         int (*aio_fsync) (struct kiocb *, int datasync);
         int (*fasync) (int, struct file *, int);
         int (*lock) (struct file *, int, struct file_lock *);
         ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
         ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
         ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
         ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
         unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
         int (*check_flags)(int);
         int (*dir_notify)(struct file *filp, unsigned long arg);
}
file_operations
结构定义了一组函数指针,每一个打开的文件(struct file表示)和它自己的一组函数(包含在一个叫f_op的域中,它指向一个 struct file_operations结构)相联系.这些操作都是来实现系统调用的,所以才被命名为open,read,等等.对于那些不需要的 功能(比如你的设备不需要write功能,即不需要向设备写数据),可以给write指针付
NULL.

struct file

 {
         struct list_head         f_list;
         struct dentry            *f_dentry;
         struct vfsmount          *f_vfsmnt;
         struct file_operations   *f_op;
         atomic_t                 f_count;
         unsigned int             f_flags;
         mode_t                   f_mode;
         int                      f_error;
         loff_t                   f_pos;
         struct fown_struct       f_owner;
         unsigned int             f_uid, f_gid;
         struct file_ra_state     f_ra;

         unsigned long            f_version;
         void                     *f_security;

         /* needed for tty driver, and maybe others */
         void                     *private_data;

#ifdef CONFIG_EPOLL
         /* Used by fs/eventpoll.c to link all the hooks to this file */
         struct list_head         f_ep_links;
         spinlock_t               f_ep_lock;
#endif /* #ifdef CONFIG_EPOLL */
         struct address_space     *f_mapping;
};
每个打开的文件对应一个struct file.它在被打开时由内核创建,并传给它所有可以操作该文件的函数,到文件被关闭时才被删除
.

The inode Structure.
Inode
结构是用来在内核内部表示文件的.同一个文件可以被打开好多次,所以可以对应很多struct file,但是只对应一个struct inode.该结构里面包含了很多信息,但是,驱动开发者只关心里面两个重要的域
:
dev_t i_rdev;//
含有真正的设备号

struct cdev *i_cdev;//struct cdev
是内核内部表示字符设备的结构.

(4)   注册设备号

定义好majorminor number 后就可以在内核中注册一个设备了.注册一个字符设备需要用到下面几个函数:
int register_chrdev_region(dev_t first,unsigned int count,char *name);
first
是要注册的设备号范围的开始(其中minor号一般设置为0),count是所申请的连续设备号的总数.name是设备的名称.它会在/proc/devices中出现
.
int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name);
这个函数是用来动态分配设备号的.有余开发者不知道所要用的major号是多少,便让内核动态分配一个.参数dev是个output-only参数
.
void unregister_chrdev_region(dev_t first,unsigned int count);
一般在模块清除函数中调用.

(5)   用户接口实现

定义操作集合:

static struct file_operations rwbuf_fops =

{

   open:     rwbuf_open,

   release:  rwbuf_close,

   read:     rwbuf_read,

   write:     rwbuf_write,

   ioctl:      rwbuf_ioctl,

};

然后分别实现各个操作,详见代码。

(6)   编译及加载设备模块

编译:

gcc -c rwbuf.c -D__KERNEL__ -DMODULE -DMODVERSIONS -Wall -include /usr/src/linux/include/linux/modversions.h -I/usr/src/linux/include

安装与卸载

  mknod  /dev/rwbuf  c  60  0    创建设备文件

/sbin/insmod    rwbuf.o              安装设备驱动

/sbin/rmmod    rwbuf                   卸载设备驱动

(7)   测试驱动程序

      void writer()

           {

             char yourmsg[1000]="Hello OYZ!";

             char c;

             int i = 0, h = 0, n = 0 ;

   h=open(RWBUF_DEV,O_WRONLY);

   n = write(h, yourmsg, sizeof(yourmsg)+1);

   close(h);

   printf("write OK!/n");

}

 

void reader()

{

   char yourmsg[1000];

   int h=open(RWBUF_DEV,O_RDONLY);

   int n=read(h,yourmsg,sizeof(yourmsg));

   close(h);

   printf("read OK!/n");

}

 

void cleaner()

{

   char yourmsg[1000];

   int h=open(RWBUF_DEV,O_RDWR);

   int n=ioctl(h,RWBUF_CLEAR,0);

   close(h);

   printf("rwbuf successfully removed!/n");

}

 

三、            实验结果   

 

 

     

           

                  图2.2 字符设备测试结果

   

    测试结果如上图2所示,可以说明字符驱动设备添加成功。

如果将rwbuf模块卸载,则测试程序将不能输入写入的字符串,如下图所示:

 

 

 

                      图2.3 卸载先前已装入的字符设备

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值