天天看點

LDD3學習筆記(5):字元驅動3

1、字元裝置注冊

在運作時獲得一個獨立的cdev結構的代碼:

Struct cdev* my_cdev=cdev_alloc();

My_codev->ops=&my_fops;

将cdev結構嵌入自己裝置特定的結構:

Void cdev_init(struct cdev* cdev , struct file_operations* fops);

Cdev結建構立後,告訴核心:

Int cdev_add(struct cdev*dev ,dev_t num,unsigned int count);

在驅動完全準備好處理裝置上的操作後再調用cdev_add。

為系統去除一個字元裝置,調用:

Void cdev_del(struct cdev*dev);

1.1、scull中的裝置注冊

Scull的結構struct scull_dev:

struct scull_dev { 

 struct scull_qset *data;  /* Pointer to first quantum set */ 

 int quantum;  /* the current quantum size */ 

 int qset;  /* the current array size */ 

 unsigned long size;  /* amount of data stored here */ 

 unsigned int access_key;  /* used by sculluid and scullpriv */ 

 struct semaphore sem;  /* mutual exclusion semaphore  */ 

 struct cdev cdev; /* Char device structure */

};

裝置與核心接口的struct cdev這個結構必須初始化,并添加到系統中,scull處理這個任務的代碼是:

static void scull_setup_cdev(struct scull_dev *dev, int index)

{

 int err, devno = MKDEV(scull_major, scull_minor + index);

 cdev_init(&dev->cdev, &scull_fops);

 dev->cdev.owner = THIS_MODULE;

 dev->cdev.ops = &scull_fops;

 err = cdev_add (&dev->cdev, devno, 1);

 /* Fail gracefully if need be */

 if (err)

 printk(KERN_NOTICE "Error %d adding scull%d", err, index);

}

2、open和release

至此已經快速浏覽了這些成員,并在以後scull的函數中使用它們。

2.1、open方法

Open應當做的工作:

●     檢查裝置特定的錯誤(例如裝置沒準備好, 或者類似的硬體錯誤)

●     如果它第一次打開, 初始化裝置

●     如果需要, 更新 f_op 指針.

●     配置設定并填充要放進 filp->private_data 的任何資料結構

Open的原型

Int (*open)(struct inode* inode, struct file*filp);

container_of(pointer, container_type, container_field); 

這個宏使用一個指向 container_field 類型的成員的指針, 它在一個 container_type 類型的結構中, 并

且傳回一個指針指向包含結構. 在 scull_open, 這個宏用來找到适當的裝置結構:

struct scull_dev *dev; /* device information */ 

dev = container_of(inode->i_cdev, struct scull_dev, c

filp->private_data = dev; /* for other methods */

2.2、release方法

應該實作的任務:

●     釋放 open 配置設定在 filp->private_data 中的任何東西

在最後的 close 關閉裝置

3、scull的記憶體使用

scull 驅動引入 2 個核心函數來管理 Linux 核心中的記憶體. 這些函數, 定義在 <linux/slab.h>, 是:

void *kmalloc(size_t size, int flags); 

void kfree(void *ptr);

4、讀和寫

scull 中的讀寫代碼需要拷貝一整段資料到或者從使用者位址空間. 這個能力由下列核心函數提供, 它

們拷貝一個任意的位元組數組, 并且位于大部分讀寫實作的核心中.

unsigned long copy_to_user(void __user *to,const void *from,unsigned long count); 

unsigned long copy_from_user(void *to,const void __user *from,unsigned long count); 

繼續閱讀