linux系統中實現字符設備及其驅動程序

實驗編號<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

2

題目

字符設備

實驗目的

瞭解Linux設備管理原理,。

實驗內容

實現一個虛擬的字符設備及其相關的驅動程序,支持以下功能:

用戶可以向設備寫入字符串,並覆蓋設備中原有的字符串;

用戶可以從設備讀出寫入的字符串;

用戶通過系統調用ioctl清除設備中寫入的字符串;

設備關閉前,只能被打開一次.

參見ppt中的rwbuff設備及其驅動程序

報告內容要求

(1) 程序實現方法和思路

(2) 測試及結果

     

一、            實現思路

         Linux將硬件設備看做一類特殊的文件(/dev/*),設備驅動程序被組織爲一組完成不同任務的函數的集合,通過這些函數使得linux的設備操作猶如文件一般。在應用程序看來,硬件設備只是一個設備文件,應用程序可以象操作普通文件一樣對硬件設備進行操作,如open()close()read()write() 等。

    所以,一個字符( char ) 設備也就是一種可以當作一個字節流來存取的設備( 如同一個文件 ),可以通過一系列的文件操作實現字符設備驅動程序。

 

二、            實驗步驟

(1)   設置內核支持模塊(make menuconfig),如圖2.1所示:

 

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />

                                        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 卸載先前已裝入的字符設備

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章