嵌入式Linux下Nor Flash驅動程式設計
前面已經詳細講述了MTD子系統原理知識,這一節講述嵌入式Linux下對NorFlash的驅動程式設計。在MTD裝置層上有MTD字元裝置和MTD塊裝置。
1、MTD字元裝置層的源碼檔案為/mtd/mtdchar.c。該源碼檔案為MTD原始裝置提供了一個字元裝置提供者,使得上層應用程式可以以字元裝置的方式來訪問MTD原始裝置。mtdchar.c主要定義了一個字元裝置訪問檔案操作函數和向核心註冊了一個字元裝置,MTD字元裝置的主裝置號為90,源碼如下:
#define MTD_CHAR_MAJOR 90
#define MTD_BLOCK_MAJOR 31
static const struct file_operations mtd_fops = {
.owner = THIS_MODULE,
.llseek = mtd_lseek,
.read = mtd_read,
.write = mtd_write,
.ioctl = mtd_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = mtd_compat_ioctl,
#endif
.open = mtd_open,
.release = mtd_close,
.mmap = mtd_mmap,
#ifndef CONFIG_MMU
.get_unmapped_area = mtd_get_unmapped_area,
#endif
};
接著在MTD字元裝置驅動的模組初始化函數中註冊MTD字元裝置,代碼如下:
static int __init init_mtdchar(void)
{
int status;
status = register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops);
if (status < 0) {
printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
MTD_CHAR_MAJOR);
}
return status;
}
2、MTD塊裝置
mtd/mtd_blkdevs.c原始碼檔案提供了MTD 轉換層裝置和塊裝置訪問之間的介面。該檔案定義了塊裝置提供者函數,代碼如下:
static const struct block_device_operations mtd_blktrans_ops = {
.owner = THIS_MODULE,
.open = blktrans_open,
.release = blktrans_release,
.locked_ioctl = blktrans_ioctl,
.getgeo = blktrans_getgeo,
};
add_mtd_blktrans_dev函數用來將一個MTD轉換層裝置註冊到核心中,每一個MTD轉換層裝置都對應一個通用磁碟裝置。add_mtd_blktrans_dev函數針對一個MTD轉換層裝置分配了一個磁碟裝置結構體,並調用函數add_disk註冊磁碟裝置到核心中。
int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
{
struct mtd_blktrans_ops *tr = new->tr;
struct mtd_blktrans_dev *d;
int last_devnum = -1;
struct gendisk *gd;
if (mutex_trylock(&mtd_table_mutex)) {
mutex_unlock(&mtd_table_mutex);
BUG();
}
list_for_each_entry(d, &tr->devs, list) {
if (new->devnum == -1) {
/* Use first free number */
if (d->devnum != last_devnum+1) {
/* Found a free devnum. Plug it in here */
new->devnum = last_devnum+1;
list_add_tail(&new->list, &d->list);
goto added;
}
} else if (d->devnum == new->devnum) {
/* Required number taken */
return -EBUSY;
} else if (d->devnum > new->devnum) {
/* Required number was free */
list_add_tail(&new->list, &d->list);
goto added;
}
last_devnum = d->devnum;
}
if (new->devnum == -1)
new->devnum = last_devnum+1;
if ((new->devnum << tr->part_bits) > 256) {
return -EBUSY;
}
list_add_tail(&new->list, &tr->devs);
added:
mutex_init(&new->lock);
if (!tr->writesect)
new->readonly = 1;
gd = alloc_disk(1 << tr->part_bits);
if (!gd) {
list_del(&new->list);
return -ENOMEM;
}
gd->major = tr->major;
gd->first_minor = (new->devnum) << tr->part_bits;
gd->fops = &mtd_blktrans_ops;
if (tr->part_bits)
if (new->devnum < 26)
snprintf(gd->disk_name, sizeof(gd->disk_name),
"%s%c", tr->name, 'a' + new->devnum);
else
snprintf(gd->disk_name, sizeof(gd->disk_name),
"%s%c%c", tr->name,
'a' - 1 + new->devnum / 26,
'a' + new->devnum % 26);
else
snprintf(gd->disk_name, sizeof(gd->disk_name),
"%s%d", tr->name, new->devnum);
/* 2.5 has capacity in units of 512 bytes while still
having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */
set_capacity(gd, (new->size * tr->blksize) >> 9);
gd->private_data = new;
new->blkcore_priv = gd;
gd->queue = tr->blkcore_priv->rq;
gd->driverfs_dev = &new->mtd->dev;
if (new->readonly)
set_disk_ro(gd, 1);
add_disk(gd);
return 0;
}
MTD原始裝置>>轉換層裝置>>磁碟裝置>>塊裝置(">>"是屬於的意思)。
mtdblock.c源檔案實現了MTD塊裝置層驅動,定義了一個轉換層裝置操作函數介面。
static struct mtd_blktrans_ops mtdblock_tr = {
.name = "mtdblock",
.major = 31,
.part_bits = 0,
.blksize = 512,
.open = mtdblock_open,
.flush = mtdblock_flush,
.release = mtdblock_release,
.readsect = mtdblock_readsect,
.writesect = mtdblock_writesect,
.add_mtd = mtdblock_add_mtd,
.remove_dev = mtdblock_remove_dev,
.owner = THIS_MODULE,
};
然後調用register_mtd_blktrans(&mtdblock_tr)註冊一個轉換層裝置。