天天看點

linux 字元裝置驅動模闆

學習Linux裝置驅動已經有一段時間了,但是發現學習後很多的知識點記憶模糊了,是以對學習過的知識進行了梳理和總結。

1.一般的驅動都是以子產品的形式存在的,那麼在字元裝置的子產品加載函數中要完成裝置号的申請(靜态、動态兩種方法)和cdev的注冊,而在解除安裝函數中實作裝置号的釋放和cdev的登出。

2. 驅動編寫模闆:

/*
這個裝置結構體是自己定義的結構體,包含字元裝置結構體和自己定義的其他的成員。
*/
// 裝置結構體
struct xxx_dev_t{

    struct cdev cdev;
    ...
}xxx_dev;

// 裝置驅動子產品加載函數

static int __init xxx_init(void)
{
    ...
    cdev_init(&xxx_dev.cdev,&xxx_fops);// 這個字元裝置初始化函數是最關鍵的裝置和驅動的綁定,這樣才能使用驅動函數來操作字元裝置。
    xxx_dev.cdev.owner=THIS_MODULE;
    // 擷取字元裝置号
    if(xxx_major){
        register_chrdev_region(xxx_dev_no,1,DEV_NAME); // 先是知道裝置号靜态的申請,不成功則動态的配置設定申請。
        }else{
           alloc_chrdev_region(&xxx_dev_no,0,1,DEV_NAME);
        }
}
// 注冊裝置
ret=cdev_add(&xxx_dev_cdev,xxx_dev_no,1);
}

// 裝置驅動子產品解除安裝函數
static void __exit xxx_exit(void)
{
    // 釋放占用的裝置号
    unregister_chrdev_region(xxx_dev_no,1);
       //    登出裝置
     cdev_del(&xxx_dev.cdev);
....
}

           

3.驅動操作成員函數的編寫,例如,open(),close(),read(),write(),release()等函數,先單獨的編寫在檔案中,再賦給struct file_operations xxx_fops 結構體成員中。

// 讀裝置
ssize_t xxx_read(strcut file *filp,char __user *buf,size_t count,loff_t *f_pos)
{
    ...

    copy_to_user(buf,...,..);
}

ssize_t xxx_write(struct file *filp, const char __user *buf, size_t count,
loff_t *f_pos)
{
     ...
    copy_from_user(..., buf, ...);
     ...
}
/*
long xxx_ioctl() 函數等,根據自己的裝置操作需求編寫函數;

**/
// 關鍵的驅動檔案操作結構體

struct file_operations xxx_fops = {
    .owner = THIS_MODULE,
    .read = xxx_read,
    .write = xxx_write,
    .unlocked_ioctl= xxx_ioctl,

};
           

注意:(1)檔案操作函數中從讀函數是從從核心空間讀到使用者空間讀資料,是以使用copy_to_user()函數,to 到使用者空間。

           (2)copy_from_user() 是把使用者空間的資料複制到核心空間,from。

            ( 3 ) 下面是字元裝置的示意圖。

linux 字元裝置驅動模闆

      (4)這個字元裝置的模闆是基本的字元裝置、驅動的模闆。一般的裝置和驅動是以總線的形式來編寫的,例如虛拟總線,這個我們在下一次筆記中記錄學習。