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);