歡迎您光臨本站 註冊首頁

Linux字元驅動總結

←手機掃碼閱讀     火星人 @ 2014-03-09 , reply:0
1、主設備號和此設備號 主編號標識設備相連的驅動,次編號被內核用來決定引用哪個設備. 在內核中, dev_t 類型(<linux/types.h>中定義)用來持有設備編號.對於 2.6.0 內核, dev_t 32 位的量, 12 位用作主編號, 20 位用作次編號. 應當利用在 <linux/kdev_t.h>中的一套宏定義. 為獲得一個 dev_t 的主或者次編號, 使用:

(dev_t)-->主設備號、次設備號

MAJOR(dev_t dev)
MINOR(dev_t dev)

主設備號、次設備號-->(dev_t)

MKDEV(int major,int minor)

在建立一個字元驅動時你的驅動需要做的第一件事是獲取一個或多個設備編號來使用.並且應當在不再使用它們時釋放它.

int register_chrdev_region(dev_t first, unsigned int count,char *name); //指定設備編號

int alloc_chrdev_region(dev_t *dev, unsigned int firstminor,
unsigned int count, char *name); //
動態生成設備編號

void unregister_chrdev_region(dev_t first, unsigned int count); //
釋放設備編號

安排主編號最好的方式, 我們認為, 是預設使用動態分配, 而留給自己在載入時或者甚至在編譯時指定主編號的選項權.

以下是在scull.c中用來獲取主設備好的代碼:

if (scull_major) {
dev
= MKDEV(scull_major, scull_minor);
result
= register_chrdev_region(dev, scull_nr_devs, "scull");
} else {
result
= alloc_chrdev_region(&dev, scull_minor, scull_nr_devs,"scull");
scull_major = MAJOR
(dev);
}
if (result < 0) {
printk
(KERN_WARNING "scull: can't get major %dn", scull_major);
return result
;
}

動態分配的缺點是你無法提前創建設備節點, 因為分配給你的模塊的主編號會變化. 對於驅動的正常使用, 這不是問題, 因為一旦編號分配了, 你可從 /proc/devices 中讀取它.

2、一些重要數據結構

大部分的基礎性的驅動操作包括 4 個重要的內核數據結構cdev,file_operations, file inode.

file_operations結構定義在 <linux/fs.h>

struct file_operations scull_fops = {
.owner = THIS_MODULE,
.llseek = scull_llseek,
.read = scull_read,
.write = scull_write,
.ioctl = scull_ioctl,
.open = scull_open,
.release = scull_release,
};

struct file,

定義於 <linux/fs.h>與用戶空間程序的 FILE 指針沒有任何關係.文件結構代表一個打開的文件.它由內核在 open 時創建, 並傳遞給在文件上操作的任何函數, 直到的關閉. 在文件的所有實例都關閉后, 內核釋放這個數據結構.

struct inode ,是在內核內部用來表示文件的.因此, 它和代表打開文件描述符的文件結構是不同的. 可能有代表單個文件的多個打開描述符的許多文件結構, 但是它們都指向一個單個 inode 結構.

struct cdev ,Linux2.6內核與2.4內核不同2.6內核採用了.cdev結構體來描述管理字元設備

struct cdev {
struct kobject kobj; //嵌在cdev結構中的kobject對象
struct module *owner;
struct file_operations *ops;/*file_operation 結構體,最終與硬體打交道的函數都註冊在這裡*/
struct list_head list;
dev_t dev;
unsigned int count;
}; 與其相關的操作函數有:
    1. struct cdev 分配空間(

      如果已經將struct cdev 嵌入到自己的設備的特定結構體中,並分配了空間,這步略過!)

struct cdev *my_cdev = cdev_alloc();

    1. 初始化struct cdev

void cdev_init(struct cdev *cdev, const struct file_operations *fops)

    1. 初始化cdev.owner

cdev.owner = THIS_MODULE;

    1. cdev設置完成,通知內核struct cdev的信息(在執行這步之前必須確定你對

      struct cdev
      的以上設置已經完成!

int cdev_add(struct cdev *p, dev_t dev, unsigned count)

從系統中移除一個字元設備:void cdev_del(struct cdev *p)

以下是scull中的初始化代碼(之前已經為struct scull_dev 分配了空間):

/*
* Set up the char_dev structure for this device.
*/

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; //
這句可以省略,在cdev_init中已經做過
err
= cdev_add (&dev->cdev, devno, 1);
/* Fail gracefully if need be
這步值得注意*/
if (err)
printk
(KERN_NOTICE "Error %d adding scull%d", err, index);
}

open 方法

open 方法提供給驅動來做任何的初始化來準備後續的操作. 在大部分驅動中, open 應當進行下面的工作:

●檢查設備特定的錯誤(例如設備沒準備好, 或者類似的硬體錯誤)
如果它第一次打開, 初始化設備
如果需要, 更新 f_op 指針.
分配並填充要放進 filp->private_data 的任何數據結構

但是, 事情的第一步常常是確定打開哪個設備. 記住 open 方法的原型是:

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

inode 參數有我們需要的信息

,以它的 i_cdev 成員的形式, 裡面包含我們之前建立的 cdev 結構.

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, cdev);
filp->private_data = dev; /* for other methods */

識別打開的設備的另外的方法是查看51CTO提醒您,請勿濫發廣告!存儲在 inode 結構的次編號. 如果你使用 register_chrdev 註冊你的設備, 你必須使用這個技術. 確認使用

iminor inode 結構中獲取次編號, 並且確定它對應一個你的驅動真正準備好處理的設備.

int scull_open(struct inode *inode, struct file *filp)
{
struct scull_dev *dev; /* device information */
dev = container_of(inode->i_cdev, struct scull_dev, cdev);
filp->private_data = dev; /* for other methods */
/* now trim to 0 the length of the device if open was write-only */
if ( (filp->f_flags & O_ACCMODE) = = O_WRONLY) {
scull_trim(dev); /* ignore errors */
}
return 0; /* success */
}

release 方法

●釋放 open 分配在 filp->private_data

中的任何東西
close 關閉設備

scull 的基本形式沒有硬體去關閉, 因此需要的代碼是最少的:

int scull_release(struct inode *inode, struct file *filp)
{
return 0;
}

scull模型的內存使用

本文出自 「sh411yy」 博客,請務必保留此出處http://sh411yy.blog.51cto.com/2993620/548496


[火星人 ] Linux字元驅動總結已經有560次圍觀

http://coctec.com/docs/linux/show-post-48967.html