友善之臂Mini2440之嵌入式Linux下Nor Flash驱动程序设计

嵌入式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)注册一个转换层设备。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值