裝置節點註冊和操作方法連線
阿新 • • 發佈:2019-01-26
今天把驅動程式亂七八糟的看了一通,簡單總結一下。
一個完整的驅動,需要提供如下的東西,
第一,使用者空間/dev下面的裝置節點。當然,如果該裝置僅僅是核心的使用,例如I2C,則不需要在/dev下面建立裝置節點。
第二,驅動程式,就是能到對映到/dev下面的fopen等系列操作。
中間有些負責,不過這些基本的東西都還是能夠找到,具體細節上的聯絡,還需要後面認真分析。從簡單的sd卡驅動來看這些內容都是可以找到的。
add_disk(md->disk)----》最終會向/dev下面新增節點。
md = mmc_blk_alloc(card); ----》會連線上實際的fopen等系列操作
-----------------------------------------------------華麗的分割線-------------------------------------------------------------------------
SD卡屬於塊裝置,card驅動部分為了將SD卡驅動成為塊裝置。介紹該部分的內容時先介紹驅動結構體和介面函式結構體,然後介紹幾個關鍵的驅動函式。
1.驅動的結構體mmc_driver
該結構體定義驅動的名字,驅動探針函式、驅動移除函式、驅動阻塞和驅動重啟等函式。
static struct mmc_driver mmc_driver = {
.drv = {
.name = "mmcblk",
},
.probe = mmc_blk_probe,
.remove = mmc_blk_remove,
.suspend = mmc_blk_suspend,
.resume = mmc_blk_resume,
};
2.塊裝置操作結構體mmc_bdops
結構體mmc_bdops中定義了塊裝置操作的介面函式。
static struct block_device_operations mmc_bdops = {
.open = mmc_blk_open,
.release = mmc_blk_release,
.getgeo = mmc_blk_getgeo,
.owner = THIS_MODULE,
};
3.塊裝置探針函式mmc_blk_probe()
該函式主要完成檢驗卡支援的命令,分配mmc_blk_data結構體空間,設定塊的大小,最後設定card的driver_data 欄位,並註冊mmc資訊到系統。
static int mmc_blk_probe(struct mmc_card *card)
{
struct mmc_blk_data *md;
int err;
char cap_str[10];
/*檢查卡支援的命令*/
if (!(card->csd.cmdclass & CCC_BLOCK_READ))
return -ENODEV;
/*為card分配mmc_blk_data結構體空間*/
md = mmc_blk_alloc(card);
/*設定塊的大小*/
mmc_blk_set_blksize(md, card);
/*將md設定為card的driver_data 欄位*/
mmc_set_drvdata(card, md);
/*把mmc包含的資訊向系統進行註冊,註冊成功後就可以在文
件系統對應目錄下找到 mmc_card對應的結點裝置*/
add_disk(md->disk);
return 0;
}
4.驅動的入口函式mmc_blk_init()
載入驅動時該函式被呼叫,該函式向核心申請註冊一個塊裝置,然後進入核心層進行註冊。
static int __init mmc_blk_init(void)
{
/*向核心申請註冊一個塊裝置*/
res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
/*進入核心層進行註冊*/
mmc_register_driver(&mmc_driver);
return 0;
}
5.為塊裝置分配空間函式mmc_blk_alloc()
函式mmc_blk_alloc()為塊裝置分配空間,並初始化一個請求佇列,設定裝置佇列的sector大小。
static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
{
struct mmc_blk_data *md;
int devidx, ret;
/*在記憶體中查詢第一個被清理過的bit*/
devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS);
if (devidx >= MMC_NUM_MINORS)
return ERR_PTR(-ENOSPC);
/*從地址 dev_use開始設定bit,設定為devidx*/
__set_bit(devidx, dev_use);
/*分配結構體mmc_blk_data空間並初始化*/
md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
/*設定卡的狀態為只讀*/
md->read_only = mmc_blk_readonly(card);
/*分配裝置的次裝置號為8*/
md->disk = alloc_disk(1 << MMC_SHIFT);
}
spin_lock_init(&md->lock);
md->usage = 1;
/*初始化一個請求佇列,並將該佇列與卡關聯*/
mmc_init_queue(&md->queue, card, &md->lock);
/*註冊 mmc_blk_issue_rq到md->queue,當md->queue上
有request待處理時, mmc_blk_issue_rq就會被呼叫*/
md->queue.issue_fn = mmc_blk_issue_rq;
md->queue.data = md;
/*註冊相關的mmc_blk _data包含的塊裝置區*/
md->disk->major = MMC_BLOCK_MAJOR;
md->disk->first_minor = devidx << MMC_SHIFT;
md->disk->fops = &mmc_bdops;
md->disk->private_data = md;
md->disk->queue = md->queue.queue;
md->disk->driverfs_dev = &card->dev;
sprintf(md->disk->disk_name, "mmcblk%d", devidx);
/*設定傳輸sector大小*/
blk_queue_hardsect_size(md->queue.queue, 512);
/*根據卡的型別設定容量*/
if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
/*
* The EXT_CSD sector count is in number or 512 byte
* sectors.
*/
set_capacity(md->disk, card->ext_csd.sectors);
} else {
/*
* The CSD capacity field is in units of read_blkbits.
* set_capacity takes units of 512 bytes.
*/
set_capacity(md->disk,
card->csd.capacity << (card->csd.read_blkbits - 9));
}
return md;
}
在該驅動部分還包括一些對塊操作的函式,如mmc_blk_open()、mmc_blk_get()、mmc_blk_put()、mmc_blk_release()和mmc_blk_getgeo()
一個完整的驅動,需要提供如下的東西,
第一,使用者空間/dev下面的裝置節點。當然,如果該裝置僅僅是核心的使用,例如I2C,則不需要在/dev下面建立裝置節點。
第二,驅動程式,就是能到對映到/dev下面的fopen等系列操作。
中間有些負責,不過這些基本的東西都還是能夠找到,具體細節上的聯絡,還需要後面認真分析。從簡單的sd卡驅動來看這些內容都是可以找到的。
add_disk(md->disk)----》最終會向/dev下面新增節點。
md = mmc_blk_alloc(card); ----》會連線上實際的fopen等系列操作
-----------------------------------------------------華麗的分割線-------------------------------------------------------------------------
SD卡屬於塊裝置,card驅動部分為了將SD卡驅動成為塊裝置。介紹該部分的內容時先介紹驅動結構體和介面函式結構體,然後介紹幾個關鍵的驅動函式。
1.驅動的結構體mmc_driver
該結構體定義驅動的名字,驅動探針函式、驅動移除函式、驅動阻塞和驅動重啟等函式。
static struct mmc_driver mmc_driver = {
.drv = {
.name = "mmcblk",
},
.probe = mmc_blk_probe,
.remove = mmc_blk_remove,
.suspend = mmc_blk_suspend,
.resume = mmc_blk_resume,
};
2.塊裝置操作結構體mmc_bdops
結構體mmc_bdops中定義了塊裝置操作的介面函式。
static struct block_device_operations mmc_bdops = {
.open = mmc_blk_open,
.release = mmc_blk_release,
.getgeo = mmc_blk_getgeo,
.owner = THIS_MODULE,
};
3.塊裝置探針函式mmc_blk_probe()
該函式主要完成檢驗卡支援的命令,分配mmc_blk_data結構體空間,設定塊的大小,最後設定card的driver_data 欄位,並註冊mmc資訊到系統。
static int mmc_blk_probe(struct mmc_card *card)
{
struct mmc_blk_data *md;
int err;
char cap_str[10];
/*檢查卡支援的命令*/
if (!(card->csd.cmdclass & CCC_BLOCK_READ))
return -ENODEV;
/*為card分配mmc_blk_data結構體空間*/
md = mmc_blk_alloc(card);
/*設定塊的大小*/
mmc_blk_set_blksize(md, card);
/*將md設定為card的driver_data 欄位*/
mmc_set_drvdata(card, md);
/*把mmc包含的資訊向系統進行註冊,註冊成功後就可以在文
件系統對應目錄下找到 mmc_card對應的結點裝置*/
add_disk(md->disk);
return 0;
}
4.驅動的入口函式mmc_blk_init()
載入驅動時該函式被呼叫,該函式向核心申請註冊一個塊裝置,然後進入核心層進行註冊。
static int __init mmc_blk_init(void)
{
/*向核心申請註冊一個塊裝置*/
res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
/*進入核心層進行註冊*/
mmc_register_driver(&mmc_driver);
return 0;
}
5.為塊裝置分配空間函式mmc_blk_alloc()
函式mmc_blk_alloc()為塊裝置分配空間,並初始化一個請求佇列,設定裝置佇列的sector大小。
static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
{
struct mmc_blk_data *md;
int devidx, ret;
/*在記憶體中查詢第一個被清理過的bit*/
devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS);
if (devidx >= MMC_NUM_MINORS)
return ERR_PTR(-ENOSPC);
/*從地址 dev_use開始設定bit,設定為devidx*/
__set_bit(devidx, dev_use);
/*分配結構體mmc_blk_data空間並初始化*/
md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
/*設定卡的狀態為只讀*/
md->read_only = mmc_blk_readonly(card);
/*分配裝置的次裝置號為8*/
md->disk = alloc_disk(1 << MMC_SHIFT);
}
spin_lock_init(&md->lock);
md->usage = 1;
/*初始化一個請求佇列,並將該佇列與卡關聯*/
mmc_init_queue(&md->queue, card, &md->lock);
/*註冊 mmc_blk_issue_rq到md->queue,當md->queue上
有request待處理時, mmc_blk_issue_rq就會被呼叫*/
md->queue.issue_fn = mmc_blk_issue_rq;
md->queue.data = md;
/*註冊相關的mmc_blk _data包含的塊裝置區*/
md->disk->major = MMC_BLOCK_MAJOR;
md->disk->first_minor = devidx << MMC_SHIFT;
md->disk->fops = &mmc_bdops;
md->disk->private_data = md;
md->disk->queue = md->queue.queue;
md->disk->driverfs_dev = &card->dev;
sprintf(md->disk->disk_name, "mmcblk%d", devidx);
/*設定傳輸sector大小*/
blk_queue_hardsect_size(md->queue.queue, 512);
/*根據卡的型別設定容量*/
if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
/*
* The EXT_CSD sector count is in number or 512 byte
* sectors.
*/
set_capacity(md->disk, card->ext_csd.sectors);
} else {
/*
* The CSD capacity field is in units of read_blkbits.
* set_capacity takes units of 512 bytes.
*/
set_capacity(md->disk,
card->csd.capacity << (card->csd.read_blkbits - 9));
}
return md;
}
在該驅動部分還包括一些對塊操作的函式,如mmc_blk_open()、mmc_blk_get()、mmc_blk_put()、mmc_blk_release()和mmc_blk_getgeo()