常见存储介质
NAND Flash
NOR Flash
HDD 机械硬盘
SSD 固态硬盘(包含NAND Flash)
UFS(包含NAND Flash)
eMMC(Embedded Multi Media Card) eMMC接口+NAND Flash(
DSC:discrete 离散物料
MCP:一体式集成物料。若内部为emmc,叫做eMCP,。若内部为uMCP,叫做uMCP(eMCP&uMCP_CHHDWarrior的博客-CSDN博客)
先看下硬件连接(除电源)
Linux下的eMMC架构
eMMC的注册过程,先注册host(eMMC通信的接口),然后注册块设备,在add_disk的过程中会扫描分区,添加分区,Android通过vold挂载各分区,流程如下
注册平台的mmc控制器驱动
mmc_alloc_host--->INIT_DELAYED_WORK(&host->detect, mmc_rescan);
mmc_add_host
mmc_start_host
void mmc_start_host(struct mmc_host *host)
{
mmc_gpiod_request_cd_irq(host);--->ctx->cd_gpio_isr = mmc_gpio_cd_irqt;-->mmc_schedule_delayed_work(&host->detect, delay);
_mmc_detect_change(host, 0, false);--->_mmc_detect_change-->mmc_schedule_delayed_work(&host->detect, delay);
}
扫瞄并注册设备
mmc_rescan
mmc_rescan_try_freq
mmc_power_up
mmc_attach_mmc(mmc_attach_sd/mmc_attach_sdio)
mmc_init_card mmc_alloc_card-->card->dev.bus = &mmc_bus_type;
mmc_add_card device_add bus_probe_device device_initial_probe __device_attach __device_attach_driver really_probe dev->bus->probe
内核默认注册了驱动
static int mmc_bus_probe(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
return drv->probe(card);
}
static int mmc_bus_match(struct device *dev, struct device_driver *drv)
{
return 1;
}
static struct bus_type mmc_bus_type = {
.match = mmc_bus_match,
.probe = mmc_bus_probe,
};
kernel/driver/mmc/card.c
int mmc_register_driver(struct mmc_driver *drv)
{
drv->drv.bus = &mmc_bus_type;
return driver_register(&drv->drv);
}
static struct mmc_driver mmc_driver = {
.drv = {
.name = "mmcblk",
.pm = &mmc_blk_pm_ops,
},
.probe = mmc_blk_probe,
.remove = mmc_blk_remove,
.shutdown = mmc_blk_shutdown,
};
static int __init mmc_blk_init(void)
{
mmc_register_driver(&mmc_driver);
}
static int mmc_blk_probe(struct mmc_card *card)
{
struct mmc_blk_data *md;
md=mmc_blk_alloc(card);
mmc_add_disk(md)
}
static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
{
mmc_blk_alloc_req(card, &card->dev, size, false, NULL,MMC_BLK_DATA_AREA_MAIN);
}
static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,struct device *parent,sector_t size,bool default_ro,const char *subname,int area_type)
{
alloc_disk();
mmc_init_queue-->blk_init_queue(mmc_request_fn, lock);
}
static int mmc_add_disk(struct mmc_blk_data *md)
{
add_disk(md->disk);-->register_disk(disk);-->blkdev_get-->__blkdev_get-->rescan_partitions-->check_partition-->check_part-->efi_partition-->put_partition
add_partition
}
虚拟内存块设备driver,用于理解块设备的运行。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SECTOR_SIZE (512)
static int BLK_SIZE=10*1024*512;
struct vmem_device *vdev=NULL;
static int vmem_major;
struct vmem_device {
struct gendisk *disk;
struct request_queue *que;
void *buf;
spinlock_t lock;
ssize_t size;
};
static int vmem_open(struct block_device *bdev, fmode_t mode)
{
pr_info("vmem_open\n");
return 0;
}
static void vmem_release(struct gendisk *disk, fmode_t mode)
{
pr_info("vmem_release\n");
}
static int vmem_ioctl(struct block_device *bdev, fmode_t mode,unsigned command, unsigned long argument)
{
pr_info("vmem_ioctl\n");
return 0;
}
static int vmem_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{
geo->cylinders=1;
geo->heads=1;
geo->sectors=BLK_SIZE/SECTOR_SIZE;
pr_info("vmem_getgeo\n");
return 0;
}
static struct block_device_operations vmem_fops={
.owner=THIS_MODULE,
.getgeo=vmem_getgeo,
.ioctl=vmem_ioctl,
.open=vmem_open,
.release=vmem_release,
};
static int vmem_transfer(struct vmem_device *vdev, uint64_t pos, ssize_t size, void *buffer, int write)
{
if(write)
memcpy(vdev->buf+pos, buffer, size);
else
memcpy(buffer, vdev->buf+pos, size);
return 0;
}
static void vmem_request(struct request_queue *q){
struct request *req;
uint64_t pos=0;
ssize_t size=0;
struct bio_vec bvec;
int rv=0;
struct req_iterator iter;
void *kaddr=NULL;
while((req=blk_fetch_request(q)) != NULL){
spin_unlock_irq(q->queue_lock);
pos=blk_rq_pos(req)*SECTOR_SIZE;
size=blk_rq_bytes(req);
if(pos+size>vdev->size){
printk(KERN_WARNING "beyond addr\n");
rv=-EIO;
goto skip;
}
rq_for_each_segment(bvec, req, iter){
kaddr=kmap(bvec.bv_page);
rv=vmem_transfer(vdev, pos, bvec.bv_len, kaddr+bvec.bv_offset, rq_data_dir(req));
if(rv<0)
goto skip;
pos+=bvec.bv_len;
kunmap(bvec.bv_page);
}
skip:
blk_end_request_all(req, rv);
spin_lock_irq(q->queue_lock);
}
}
static int __init vmem_init(void)
{
struct gendisk *disk;
vmem_major=register_blkdev(0, "VMEM");
vdev=kzalloc(sizeof(struct vmem_device), GFP_KERNEL);
if(!vdev){
printk(KERN_WARNING "vmem_device: unable to allocate mem\n");
goto out;
}
vdev->size=BLK_SIZE;
vdev->buf=vmalloc(vdev->size);
if(vdev->buf==NULL){
printk(KERN_WARNING "failed to vmalloc vdev->buf\n");
goto out_dev;
}
spin_lock_init(&vdev->lock);
vdev->que=blk_init_queue(vmem_request, &vdev->lock);
if(vdev->que==NULL){
printk(KERN_WARNING "failed to init queue\n");
goto out_buf;
}
disk=alloc_disk(1);
if(disk==NULL){
printk(KERN_WARNING "failed to alloc disk\n");
goto out_que;
}
vdev->disk=disk;
disk->major=vmem_major;
disk->first_minor=1;
disk->fops=&vmem_fops;
disk->queue=vdev->que;
disk->private_data=vdev;
sprintf(disk->disk_name, "VMEM");
set_capacity(disk, BLK_SIZE/SECTOR_SIZE);
add_disk(disk);
printk(KERN_INFO "succeed to init\n");
return 0;
out_que:
blk_cleanup_queue(vdev->que);
out_buf:
vfree(vdev->buf);
out_dev:
kfree(vdev);
out:
unregister_blkdev(vmem_major, "VMEM");
return -1;
}
static void __exit vmem_exit(void)
{
del_gendisk(vdev->disk);
blk_cleanup_queue(vdev->que);
put_disk(vdev->disk);
vfree(vdev->buf);
kfree(vdev);
unregister_blkdev(vmem_major, "VMEM");
printk(KERN_INFO "module exit\n");
}
module_init(vmem_init);
module_exit(vmem_exit);
MODULE_AUTHOR("Pingbo An");
MODULE_LICENSE("GPL v2");
mkdir /home/w/disk
mkfs.ext4 /dev/VMEM
mount /dev/VMEM /home/w/disk
mkfs.ext4格式硬盘为ext4格式,linux下还有很多格式硬件的命令,如mkfs.ext3,mkfs.msdos.mkfs.vfat等