天天看點

字元裝置的讀寫

在應用程式看來,字元裝置隻是一個裝置檔案,應用程式可以像操作普通檔案一樣對硬體裝置進行操作。應用層對裝置的操作都在裝置驅動程式的file_operations結構中有對應的接口,比如應用層的read函數對應驅動層的file_operations-> read,而應用層的write函數對應驅動層的file_operations-> write。本節介紹字元裝置核心空間與使用者空間資料互動的方法。

先看file_operations中的讀寫接口:

  1. ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);  
  2. ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); 

它們的第二個參數實際上是使用者空間的資料位址。由于核心态和使用者态使用不同的記憶體定義,是以二者之間不能直接通路對方的記憶體,而應該使用Linux中的使用者和核心态記憶體互動函數,這些函數在include/asm/uaccess.h中聲明。

從核心空間複制資料到使用者空間使用copy_to_user函數:

  1. unsigned long copy_to_user (void __user * to, const void * from, unsigned long n); 

而要從使用者空間複制資料到核心空間可以用copy_from_user函數:

  1. unsigned long copy_from_user (void * to, const void* from, unsigned long n); 

此外核心空間和使用者空間之間也可進行單值互動(如char、int、long類型):

  1. int  put_user(dataum,ptr);  //向使用者空間傳單值  
  2. int  get_user(local,ptr);   //向核心空間傳單值 

當一個指針指向使用者空間時,必須確定指向的使用者位址是合法的,而且對應的頁面也已經映射,這一點可以使用access_ok函數檢測。access_ok函數的type參數有兩個選項:VERIFY_READ、VERIFY_ WRITE,分别對應記憶體讀、寫。

  1. int access_ok(int type, const void *addr, unsigned long size); 

在通路使用者空間的記憶體時,可以使用下面的方法先檢查使用者空間的指針是否合法:

  1. char kernelbuffer[100];  
  2. static ssize_t demo_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)  
  3. {  
  4.     if (!access_ok(VERIFY_WRITE, buffer, count))  
  5.         return -EFAULT;  
  6.     if (copy_to_user(buffer, kernelbuffer, count))  
  7.             return -EFAULT;  
  8.     return count;  
  9. }