分类: LINUX
2014-09-12 14:56:54
#ifndef MMC_QUEUE_H
#define MMC_QUEUE_H
struct request;
struct task_struct;
struct mmc_queue { /* mmc请求队列 -----对MMC卡的操作是通过该结构的传递来完成的*/
struct mmc_card *card; /* 指向卡 */
struct task_struct *thread; /* 执行处理请求的线程 */
struct semaphore thread_sem; /* 线程使用的信号量 */
unsigned int flags; /* 标志位*/
struct request *req; /* 通用的请求 */
int (*issue_fn)(struct mmc_queue *, struct request *); /* 发出请求让设备开始处理函数 */
void *data; /* 指向私有数据 */
struct request_queue *queue; /* 指向块层请求队列 */
struct scatterlist *sg;
char *bounce_buf; /* 弹性缓冲区 */
struct scatterlist *bounce_sg; /* 碎片链表 */
unsigned int bounce_sg_len; /* 碎片长度 */
};
extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *);
extern void mmc_cleanup_queue(struct mmc_queue *);
extern void mmc_queue_suspend(struct mmc_queue *);
extern void mmc_queue_resume(struct mmc_queue *);
extern unsigned int mmc_queue_map_sg(struct mmc_queue *);
extern void mmc_queue_bounce_pre(struct mmc_queue *);
extern void mmc_queue_bounce_post(struct mmc_queue *);
#endif
/*************************************************************************************************************************************/
/* queue.c */
/*
* linux/drivers/mmc/card/queue.c
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
* Copyright 2006-2007 Pierre Ossman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include
#include
#include
#include
#include
#include
#include
#include "queue.h"
#define MMC_QUEUE_BOUNCESZ 65536
#define MMC_QUEUE_SUSPENDED (1 << 0)
/*
* Prepare a MMC request. This just filters out odd stuff.
*/
/* 命令预处理函数 */
static int mmc_prep_request(struct request_queue *q, struct request *req)
{
/*
* We only like normal block requests.
*/
if (!blk_fs_request(req)) { /*如果不是文件系统请求 */
blk_dump_rq_flags(req, "MMC bad request"); /* 无效请求 */
return BLKPREP_KILL;
}
req->cmd_flags |= REQ_DONTPREP;
return BLKPREP_OK;
}
/* 请求队列处理线程 */
static int mmc_queue_thread(void *d)
{
struct mmc_queue *mq = d;
struct request_queue *q = mq->queue;
current->flags |= PF_MEMALLOC;
down(&mq->thread_sem);
do {
struct request *req = NULL;
spin_lock_irq(q->queue_lock);
set_current_state(TASK_INTERRUPTIBLE); /* 设置当前进程状态为TASK_INTERRUPTIBLE */
if (!blk_queue_plugged(q)) /* 如果队列是非阻塞状态,得到下一个请求 */
req = elv_next_request(q); /* 获取第一个未完成的请求 */
mq->req = req;
spin_unlock_irq(q->queue_lock);
if (!req) { /* 如果请求为空 */
if (kthread_should_stop()) { /* 线程是否应该返回 */
set_current_state(TASK_RUNNING); /* 如果是则设置当前进程状态为TASK_RUNNING*/
break;
}
up(&mq->thread_sem);
schedule(); /* 调度出进程----进程进入睡眠 */
down(&mq->thread_sem);
continue;
}
set_current_state(TASK_RUNNING); /* 设置当前进程为TASK_RUNNING */
mq->issue_fn(mq, req); /* 调用mmc请求队列的issue_fn函数发出请求让设备处理请求 */
} while (1);
up(&mq->thread_sem);
return 0;
}
/*
* Generic MMC request handler. This is called for any queue on a
* particular host. When the host is not busy, we look for a request
* on any queue on this host, and attempt to issue it. This may
* not be the queue we were asked to process.
*/
/* mmc请求处理函数 ,它唤醒请求队列处理线程*/
static void mmc_request(struct request_queue *q)
{
struct mmc_queue *mq = q->queuedata; /* 在 mmc_init_queue函数中将struct mmc_queue 结构体地址保存到了mq->queue->queuedata*/
struct request *req;
int ret;
if (!mq) { /* 如果mq为空则 没有创建mmc请求队列*/
printk(KERN_ERR "MMC: killing requests for dead queue\n");
while ((req = elv_next_request(q)) != NULL) { /* 获取请求队列中下一个要传输的请求 */
do {
ret = __blk_end_request(req, -EIO,
blk_rq_cur_bytes(req));
} while (ret);
}
return;
}
if (!mq->req)
wake_up_process(mq->thread); /* 如果有请求则唤醒请求队列处理线程 */
}
/**
* mmc_init_queue - initialise a queue structure.
* @mq: mmc queue
* @card: mmc card to attach this queue
* @lock: queue lock
*
* Initialise a MMC card request queue.
*/
/* 初始化mmc 请求队列*/
int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock)
{
struct mmc_host *host = card->host;
u64 limit = BLK_BOUNCE_HIGH;
int ret;
if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
limit = *mmc_dev(host)->dma_mask;
mq->card = card;
mq->queue = blk_init_queue(mmc_request, lock); /* 初始化请求队列,mmc_request为请求处理函数 */
if (!mq->queue)
return -ENOMEM;
mq->queue->queuedata = mq; /* 将mq保存起来方便以后使用*/
mq->req = NULL;
blk_queue_prep_rq(mq->queue, mmc_prep_request); /* 绑定命令预处理函数----把这个处理请求的命令发送给硬件设备 */
blk_queue_ordered(mq->queue, QUEUE_ORDERED_DRAIN, NULL);
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
#ifdef CONFIG_MMC_BLOCK_BOUNCE
if (host->max_hw_segs == 1) {
unsigned int bouncesz;
bouncesz = MMC_QUEUE_BOUNCESZ;
if (bouncesz > host->max_req_size)
bouncesz = host->max_req_size;
if (bouncesz > host->max_seg_size)
bouncesz = host->max_seg_size;
if (bouncesz > (host->max_blk_count * 512))
bouncesz = host->max_blk_count * 512;
if (bouncesz > 512) {
mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
if (!mq->bounce_buf) {
printk(KERN_WARNING "%s: unable to "
"allocate bounce buffer\n",
mmc_card_name(card));
}
}
if (mq->bounce_buf) {
blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
blk_queue_max_sectors(mq->queue, bouncesz / 512);
blk_queue_max_phys_segments(mq->queue, bouncesz / 512);
blk_queue_max_hw_segments(mq->queue, bouncesz / 512);
blk_queue_max_segment_size(mq->queue, bouncesz);
mq->sg = kmalloc(sizeof(struct scatterlist),
GFP_KERNEL);
if (!mq->sg) {
ret = -ENOMEM;
goto cleanup_queue;
}
sg_init_table(mq->sg, 1);
mq->bounce_sg = kmalloc(sizeof(struct scatterlist) *
bouncesz / 512, GFP_KERNEL);
if (!mq->bounce_sg) {
ret = -ENOMEM;
goto cleanup_queue;
}
sg_init_table(mq->bounce_sg, bouncesz / 512);
}
}
#endif
/* 初始化请求队列的扇区及片段限制 */
if (!mq->bounce_buf) {
blk_queue_bounce_limit(mq->queue, limit);
blk_queue_max_sectors(mq->queue,
min(host->max_blk_count, host->max_req_size / 512));
blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);
blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
blk_queue_max_segment_size(mq->queue, host->max_seg_size);
mq->sg = kmalloc(sizeof(struct scatterlist) *
host->max_phys_segs, GFP_KERNEL);
if (!mq->sg) {
ret = -ENOMEM;
goto cleanup_queue;
}
sg_init_table(mq->sg, host->max_phys_segs);
}
init_MUTEX(&mq->thread_sem);
mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd"); /* 创建一个内核线程来处理请求 队列*/
if (IS_ERR(mq->thread)) {
ret = PTR_ERR(mq->thread);
goto free_bounce_sg;
}
return 0;
free_bounce_sg:
if (mq->bounce_sg)
kfree(mq->bounce_sg);
mq->bounce_sg = NULL;
cleanup_queue:
if (mq->sg)
kfree(mq->sg);
mq->sg = NULL;
if (mq->bounce_buf)
kfree(mq->bounce_buf);
mq->bounce_buf = NULL;
blk_cleanup_queue(mq->queue);
return ret;
}
/*释放请求队列 */
void mmc_cleanup_queue(struct mmc_queue *mq)
{
struct request_queue *q = mq->queue;
unsigned long flags;
/* Mark that we should start throwing out stragglers */
spin_lock_irqsave(q->queue_lock, flags);
q->queuedata = NULL;
spin_unlock_irqrestore(q->queue_lock, flags);
/* Make sure the queue isn't suspended, as that will deadlock */
mmc_queue_resume(mq); /*恢复请求队列 */
/* Then terminate our worker thread */
kthread_stop(mq->thread); /* 停止请求处理线程 */
if (mq->bounce_sg)
kfree(mq->bounce_sg); /* */
mq->bounce_sg = NULL;
kfree(mq->sg);
mq->sg = NULL;
if (mq->bounce_buf)
kfree(mq->bounce_buf);
mq->bounce_buf = NULL;
blk_cleanup_queue(mq->queue); /* 释放请求队列 */
mq->card = NULL;
}
EXPORT_SYMBOL(mmc_cleanup_queue);
/**
* mmc_queue_suspend - suspend a MMC request queue
* @mq: MMC queue to suspend
*
* Stop the block request queue, and wait for our thread to
* complete any outstanding requests. This ensures that we
* won't suspend while a request is being processed.
*/
/* 挂起mmc请求队列 */
void mmc_queue_suspend(struct mmc_queue *mq)
{
struct request_queue *q = mq->queue;
unsigned long flags;
if (!(mq->flags & MMC_QUEUE_SUSPENDED)) {
mq->flags |= MMC_QUEUE_SUSPENDED;
spin_lock_irqsave(q->queue_lock, flags);
blk_stop_queue(q); /* 停止请求队列 */
spin_unlock_irqrestore(q->queue_lock, flags);
down(&mq->thread_sem);
}
}
/**
* mmc_queue_resume - resume a previously suspended MMC request queue
* @mq: MMC queue to resume
*/
/*恢复请求队列 */
void mmc_queue_resume(struct mmc_queue *mq)
{
struct request_queue *q = mq->queue;
unsigned long flags;
if (mq->flags & MMC_QUEUE_SUSPENDED) {
mq->flags &= ~MMC_QUEUE_SUSPENDED;
up(&mq->thread_sem);
spin_lock_irqsave(q->queue_lock, flags);
blk_start_queue(q); /* 启动请求队列 */
spin_unlock_irqrestore(q->queue_lock, flags);
}
}
/*
* Prepare the sg list(s) to be handed of to the host driver
*/
/*为主机驱动 准备一个 struct scatterlist*/
unsigned int mmc_queue_map_sg(struct mmc_queue *mq)
{
unsigned int sg_len;
size_t buflen;
struct scatterlist *sg;
int i;
if (!mq->bounce_buf)
return blk_rq_map_sg(mq->queue, mq->req, mq->sg);
BUG_ON(!mq->bounce_sg);
sg_len = blk_rq_map_sg(mq->queue, mq->req, mq->bounce_sg);
mq->bounce_sg_len = sg_len;
buflen = 0;
for_each_sg(mq->bounce_sg, sg, sg_len, i)
buflen += sg->length;
sg_init_one(mq->sg, mq->bounce_buf, buflen);
return 1;
}
/*
* If writing, bounce the data to the buffer before the request
* is sent to the host driver
*/
/* 如果是写,则在请求被发送到主机驱动前弹出数据到buffer */
void mmc_queue_bounce_pre(struct mmc_queue *mq)
{
unsigned long flags;
if (!mq->bounce_buf)
return;
if (rq_data_dir(mq->req) != WRITE)
return;
local_irq_save(flags);
sg_copy_to_buffer(mq->bounce_sg, mq->bounce_sg_len,
mq->bounce_buf, mq->sg[0].length);
local_irq_restore(flags);
}
/*
* If reading, bounce the data from the buffer after the request
* has been handled by the host driver
*/
/* 如果是读,则在请求被主机驱动处理后弹出数据到buffer */
void mmc_queue_bounce_post(struct mmc_queue *mq)
{
unsigned long flags;
if (!mq->bounce_buf)
return;
if (rq_data_dir(mq->req) != READ)
return;
local_irq_save(flags);
sg_copy_from_buffer(mq->bounce_sg, mq->bounce_sg_len,
mq->bounce_buf, mq->sg[0].length);
local_irq_restore(flags);
}
/*************************************************************************************************************************************/
/* block.c */
/*
* Block driver for media (i.e., flash cards)
*
* Copyright 2002 Hewlett-Packard Company
* Copyright 2005-2008 Pierre Ossman
*
* Use consistent with the GNU GPL is permitted,
* provided that this copyright notice is
* preserved in its entirety in all copies and derived works.
*
* HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
* AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
* FITNESS FOR ANY PARTICULAR PURPOSE.
*
* Many thanks to Alessandro Rubini and Jonathan Corbet!
*
* Author: Andrew Christian
* 28 May 2002
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "queue.h"
MODULE_ALIAS("mmc:block");
/*
* max 8 partitions per card
*/
/* 最大支持8个mmc主机控制器,每个控制器可控制4个卡,每个卡最大可有8个分区 */
#define MMC_SHIFT 3 /* 表示最大支持8个分区(1<< MMC_SHIFT) */
#define MMC_NUM_MINORS (256 >> MMC_SHIFT) /*次设备号数 MMC_NUM_MINORS=32 */
static DECLARE_BITMAP(dev_use, MMC_NUM_MINORS); /* 一个控制器用32位表示使用情况 */
/* 定义位图
#define BITS_PER_BYTE 8
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) 将一个bit转换为long
#define DECLARE_BITMAP(name,bits) unsigned long name[BITS_TO_LONGS(bits)]---->定义位映射
static DECLARE_BITMAP(dev_use, MMC_NUM_MINORS)= unsigned long dev_use[BITS_TO_LONGS(32)]=unsigned long dev_use[DIV_ROUND_UP(32, 8 * 4) ]===>
=unsigned long dev_use[ (((32) + (32) - 1) / (32))]=unsigned long dev_use[ (((32) + (32) - 1) / (32))]=unsigned long dev_use[1]
即tatic DECLARE_BITMAP(dev_use, MMC_NUM_MINORS)=unsigned long dev_use[1]
*/
/*
* There is one mmc_blk_data per slot.
*/
struct mmc_blk_data { /* mmc卡插槽对应的一个块的数据结构*/
spinlock_t lock;
struct gendisk *disk; /* 通用磁盘指针 */
struct mmc_queue queue; /* mmc请求队列 */
unsigned int usage; /* 使用计数 */
unsigned int read_only; /* 只读标志 */
};
static DEFINE_MUTEX(open_lock);
/* 通过gendisk结构体获取 struct mmc_blk_data指针*/
static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
{
struct mmc_blk_data *md;
mutex_lock(&open_lock);
md = disk->private_data;
if (md && md->usage == 0)
md = NULL;
if (md)
md->usage++; /* 增加使用计数*/
mutex_unlock(&open_lock);
return md;
}
/* 释放struct mmc_blk_data结构 */
static void mmc_blk_put(struct mmc_blk_data *md)
{
mutex_lock(&open_lock);
md->usage--;
if (md->usage == 0) {
int devidx = MINOR(disk_devt(md->disk)) >> MMC_SHIFT;
__clear_bit(devidx, dev_use); /* dev_use[devidx]=0 */
put_disk(md->disk);
kfree(md);
}
mutex_unlock(&open_lock);
}
/* 打开设备 */
static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
{
struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
int ret = -ENXIO;
if (md) {
if (md->usage == 2)
check_disk_change(bdev); /* 检查磁盘介质释放改变 */
ret = 0;
if ((mode & FMODE_WRITE) && md->read_only) {
mmc_blk_put(md);
ret = -EROFS;
}
}
return ret;
}
/* 关闭设备 */
static int mmc_blk_release(struct gendisk *disk, fmode_t mode)
{
struct mmc_blk_data *md = disk->private_data;
mmc_blk_put(md);
return 0;
}
/* 获取驱动器信息 */
static int
mmc_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{
geo->cylinders = get_capacity(bdev->bd_disk) / (4 * 16); /* 柱面数 */
geo->heads = 4; /* 磁头数 */
geo->sectors = 16; /* 扇区数 */
return 0;
}
static struct block_device_operations mmc_bdops = { /* 块设备操作函数 */
.open = mmc_blk_open,
.release = mmc_blk_release,
.getgeo = mmc_blk_getgeo,
.owner = THIS_MODULE,
};
struct mmc_blk_request { /* mmc块设备请求描述结构体 */
struct mmc_request mrq; /* mmc卡的请求 */
struct mmc_command cmd; /* mmc命令 */
struct mmc_command stop; /* mmc停止命令 */
struct mmc_data data; /* mmc卡读写的数据相关信息 */
};
/* mmc SD卡读写多个块 */
static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
{
int err;
__be32 blocks;
struct mmc_request mrq;
struct mmc_command cmd;
struct mmc_data data;
unsigned int timeout_us;
struct scatterlist sg;
memset(&cmd, 0, sizeof(struct mmc_command));
/* 设置命令 */
cmd.opcode = MMC_APP_CMD;
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 0); /* 发送命令并等待它完成 */
if (err)
return (u32)-1;
if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD))
return (u32)-1;
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = SD_APP_SEND_NUM_WR_BLKS;
cmd.arg = 0;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
memset(&data, 0, sizeof(struct mmc_data));
data.timeout_ns = card->csd.tacc_ns * 100;
data.timeout_clks = card->csd.tacc_clks * 100;
timeout_us = data.timeout_ns / 1000;
timeout_us += data.timeout_clks * 1000 /
(card->host->ios.clock / 1000);
if (timeout_us > 100000) {
data.timeout_ns = 100000000;
data.timeout_clks = 0;
}
data.blksz = 4;
data.blocks = 1;
data.flags = MMC_DATA_READ;
data.sg = &sg;
data.sg_len = 1;
memset(&mrq, 0, sizeof(struct mmc_request));
mrq.cmd = &cmd;
mrq.data = &data;
sg_init_one(&sg, &blocks, 4);
mmc_wait_for_req(card->host, &mrq);
if (cmd.error || data.error)
return (u32)-1;
return ntohl(blocks);
}
/* 获取卡的状态 */
static u32 get_card_status(struct mmc_card *card, struct request *req)
{
struct mmc_command cmd;
int err;
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_SEND_STATUS;
if (!mmc_host_is_spi(card->host))
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 0); /* 发送一个命令并等待它完成 */
if (err)
printk(KERN_ERR "%s: error %d sending status comand",
req->rq_disk->disk_name, err);
return cmd.resp[0];
}
/* 发出读写请求的函数----初始化块请求结构后,向卡发送请求命令,并等待请求完成 */
static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
{
struct mmc_blk_data *md = mq->data;
struct mmc_card *card = md->queue.card;
struct mmc_blk_request brq; /* 定义一个struct mmc_blk_request结构体类型变量 */
int ret = 1, disable_multi = 0;
mmc_claim_host(card->host); /* 声明一个主机来进行一系列的操作 ----认领控制器,发送命令到卡设置卡的选中状态*/
do {
struct mmc_command cmd;
u32 readcmd, writecmd, status = 0;
/* 设置 struct mmc_blk_request的成员*/
memset(&brq, 0, sizeof(struct mmc_blk_request));
brq.mrq.cmd = &brq.cmd;
brq.mrq.data = &brq.data;
brq.cmd.arg = req->sector;
if (!mmc_card_blockaddr(card)) /* struct mmc_card *card->state & MMC_STATE_BLOCKADDR */
brq.cmd.arg <<= 9;
brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
brq.data.blksz = 512;
brq.stop.opcode = MMC_STOP_TRANSMISSION;
brq.stop.arg = 0;
brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
brq.data.blocks = req->nr_sectors;
/*
* The block layer doesn't support all sector count
* restrictions, so we need to be prepared for too big
* requests.
*/
/* 检查请求中 数据*/
if (brq.data.blocks > card->host->max_blk_count)
brq.data.blocks = card->host->max_blk_count;
/*
* After a read error, we redo the request one sector at a time
* in order to accurately determine which sectors can be read
* successfully.
*/
if (disable_multi && brq.data.blocks > 1)
brq.data.blocks = 1;
if (brq.data.blocks > 1) { /* 多块读写 */
/* SPI multiblock writes terminate using a special
* token, not a STOP_TRANSMISSION request.
*/
if (!mmc_host_is_spi(card->host)
|| rq_data_dir(req) == READ) /* 如果mmc主机控制器不是SPI模式或者是读取数据 */
brq.mrq.stop = &brq.stop;
readcmd = MMC_READ_MULTIPLE_BLOCK;
writecmd = MMC_WRITE_MULTIPLE_BLOCK;
} else { /* 单块读写 */
brq.mrq.stop = NULL;
readcmd = MMC_READ_SINGLE_BLOCK;
writecmd = MMC_WRITE_BLOCK;
}
if (rq_data_dir(req) == READ) { /* 读 */
brq.cmd.opcode = readcmd;
brq.data.flags |= MMC_DATA_READ;
} else { /* 写 */
brq.cmd.opcode = writecmd;
brq.data.flags |= MMC_DATA_WRITE;
}
mmc_set_data_timeout(&brq.data, card); /* 设置一个数据命令的超时时间 */
brq.data.sg = mq->sg;
brq.data.sg_len = mmc_queue_map_sg(mq); /* 为主机驱动准备一个struct scatterlist */
/*
* Adjust the sg list so it is the same size as the
* request.
*/
if (brq.data.blocks != req->nr_sectors) {
int i, data_size = brq.data.blocks << 9;
struct scatterlist *sg;
for_each_sg(brq.data.sg, sg, brq.data.sg_len, i) {
data_size -= sg->length;
if (data_size <= 0) {
sg->length += data_size;
i++;
break;
}
}
brq.data.sg_len = i;
}
mmc_queue_bounce_pre(mq); /* 如果是写,则在请求被发送到主机驱动前弹出数据到buffer */
mmc_wait_for_req(card->host, &brq.mrq); /* 开始一个 请求并等待它完成 */
mmc_queue_bounce_post(mq); /* 如果是读,则在请求被主机驱动处理后弹出数据到buffer */
/*
* Check for errors here, but don't jump to cmd_err
* until later as we need to wait for the card to leave
* programming mode even when things go wrong.
*/
if (brq.cmd.error || brq.data.error || brq.stop.error) {
if (brq.data.blocks > 1 && rq_data_dir(req) == READ) {
/* Redo read one sector at a time */
printk(KERN_WARNING "%s: retrying using single "
"block read\n", req->rq_disk->disk_name);
disable_multi = 1;
continue;
}
status = get_card_status(card, req); /* 获取卡的状态 */
}
if (brq.cmd.error) {
printk(KERN_ERR "%s: error %d sending read/write "
"command, response %#x, card status %#x\n",
req->rq_disk->disk_name, brq.cmd.error,
brq.cmd.resp[0], status);
}
if (brq.data.error) {
if (brq.data.error == -ETIMEDOUT && brq.mrq.stop)
/* 'Stop' response contains card status */
status = brq.mrq.stop->resp[0];
printk(KERN_ERR "%s: error %d transferring data,"
" sector %u, nr %u, card status %#x\n",
req->rq_disk->disk_name, brq.data.error,
(unsigned)req->sector,
(unsigned)req->nr_sectors, status);
}
if (brq.stop.error) {
printk(KERN_ERR "%s: error %d sending stop command, "
"response %#x, card status %#x\n",
req->rq_disk->disk_name, brq.stop.error,
brq.stop.resp[0], status);
}
if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
do {
int err;
cmd.opcode = MMC_SEND_STATUS;
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 5);
if (err) {
printk(KERN_ERR "%s: error %d requesting status\n",
req->rq_disk->disk_name, err);
goto cmd_err;
}
/*
* Some cards mishandle the status bits,
* so make sure to check both the busy
* indication and the card state.
*/
} while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
(R1_CURRENT_STATE(cmd.resp[0]) == 7));
#if 0
if (cmd.resp[0] & ~0x00000900)
printk(KERN_ERR "%s: status = %08x\n",
req->rq_disk->disk_name, cmd.resp[0]);
if (mmc_decode_status(cmd.resp))
goto cmd_err;
#endif
}
if (brq.cmd.error || brq.stop.error || brq.data.error) {
if (rq_data_dir(req) == READ) {
/*
* After an error, we redo I/O one sector at a
* time, so we only reach here after trying to
* read a single sector.
*/
spin_lock_irq(&md->lock);
ret = __blk_end_request(req, -EIO, brq.data.blksz);
spin_unlock_irq(&md->lock);
continue;
}
goto cmd_err;
}
/*
* A block was successfully transferred.
*/
spin_lock_irq(&md->lock);
ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
spin_unlock_irq(&md->lock);
} while (ret);
mmc_release_host(card->host); /* 释放主机 */
return 1;
cmd_err:
/*
* If this is an SD card and we're writing, we can first
* mark the known good sectors as ok.
*
* If the card is not SD, we can still ok written sectors
* as reported by the controller (which might be less than
* the real number of written sectors, but never more).
*/
if (mmc_card_sd(card)) {
u32 blocks;
blocks = mmc_sd_num_wr_blocks(card);
if (blocks != (u32)-1) {
spin_lock_irq(&md->lock);
ret = __blk_end_request(req, 0, blocks << 9);
spin_unlock_irq(&md->lock);
}
} else {
spin_lock_irq(&md->lock);
ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
spin_unlock_irq(&md->lock);
}
mmc_release_host(card->host);
spin_lock_irq(&md->lock);
while (ret)
ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
spin_unlock_irq(&md->lock);
return 0;
}
static inline int mmc_blk_readonly(struct mmc_card *card)
{
return mmc_card_readonly(card) ||
!(card->csd.cmdclass & CCC_BLOCK_WRITE);
}
/* 分配一个MMC块设备----分配并初始化一个struct mmc_blk_data结构体,初始化通用磁盘及请求队列 */
static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
{
struct mmc_blk_data *md;
int devidx, ret;
devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS); /* 在 dev_use数组中找到第一个0位*/
if (devidx >= MMC_NUM_MINORS)
return ERR_PTR(-ENOSPC);
__set_bit(devidx, dev_use); /* 设置数组 dev_use的第devidx位的值为1--->表示使用*/
md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL); /* 分配一个struct mmc_blk_data结构体 */
if (!md) {
ret = -ENOMEM;
goto out;
}
/*
* Set the read-only status based on the supported commands
* and the write protect switch.
*/
md->read_only = mmc_blk_readonly(card);
md->disk = alloc_disk(1 << MMC_SHIFT); /* 分配一个struct gendisk结构体 ,次设备号(分区数)为8*/
if (md->disk == NULL) {
ret = -ENOMEM;
goto err_kfree;
}
spin_lock_init(&md->lock);
md->usage = 1;
ret = mmc_init_queue(&md->queue, card, &md->lock); /* 初始化mmc 请求队列*/
if (ret)
goto err_putdisk;
md->queue.issue_fn = mmc_blk_issue_rq; /* 绑定发出读写请求的函数 */
md->queue.data = md; /*struct mmc_blk_data结构体的地址保存起来方便以后使用 */
/* 初始化分配的gendisk的成员 */
md->disk->major = MMC_BLOCK_MAJOR;
md->disk->first_minor = devidx << MMC_SHIFT;
md->disk->fops = &mmc_bdops; /* 设置操作函数 */
md->disk->private_data = md; /*struct mmc_blk_data结构体的地址保存起来方便以后使用 */
md->disk->queue = md->queue.queue;
md->disk->driverfs_dev = &card->dev;
/*
* As discussed on lkml, GENHD_FL_REMOVABLE should:
*
* - be set for removable media with permanent block devices
* - be unset for removable block devices with permanent media
*
* Since MMC block devices clearly fall under the second
* case, we do not set GENHD_FL_REMOVABLE. Userspace
* should use the block device creation/destruction hotplug
* messages to tell when the card is present.
*/
sprintf(md->disk->disk_name, "mmcblk%d", devidx);
blk_queue_hardsect_size(md->queue.queue, 512); /* 设置硬件能处理的最小的扇区大小为512字节 */
if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) { /* 如果卡不是SD卡并且 卡使用块地址 */
/*
* The EXT_CSD sector count is in number or 512 byte
* sectors.
*/
set_capacity(md->disk, card->ext_csd.sectors); /* 设置容量(单位为扇区) 即md->disk->part0.nr_sects = card->ext_csd.sectors*/
} else { /* SD卡 */
/*
* 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)); /* 设置容量(单位为扇区) 即md->disk->part0.nr_sects =card->csd.capacity << (card->csd.read_blkbits - 9)*/
}
return md;
err_putdisk:
put_disk(md->disk);
err_kfree:
kfree(md);
out:
return ERR_PTR(ret);
}
/* 设置卡大小,发送命令设置卡为选中状态 */
static int
mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
{
struct mmc_command cmd;
int err;
/* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
if (mmc_card_blockaddr(card)) /* 如果卡使用块地址则返回*/
return 0;
mmc_claim_host(card->host); /* 声明一个主机 */
cmd.opcode = MMC_SET_BLOCKLEN;
cmd.arg = 512;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 5); /* 发送命令并等待它完成 */
mmc_release_host(card->host); /* 释放主机 */
if (err) {
printk(KERN_ERR "%s: unable to set block size to %d: %d\n",
md->disk->disk_name, cmd.arg, err);
return -EINVAL;
}
return 0;
}
/* 探测函数----它探测MMC控制器释否存在,并初始化控制器的结构以及探测MMC卡的状态并初始化 */
static int mmc_blk_probe(struct mmc_card *card)
{
struct mmc_blk_data *md;
int err;
char cap_str[10];
/*
* Check that the card supports the command class(es) we need.
*/
if (!(card->csd.cmdclass & CCC_BLOCK_READ)) /* 如果 卡不支持块读命令则返回错误*/
return -ENODEV;
md = mmc_blk_alloc(card); /* 分配一个MMC块设备----分配并初始化一个struct mmc_blk_data结构体 */
if (IS_ERR(md))
return PTR_ERR(md);
err = mmc_blk_set_blksize(md, card); /* 设置卡大小,发送命令设置卡为选中状态 */
if (err)
goto out;
string_get_size((u64)get_capacity(md->disk) << 9, STRING_UNITS_2,
cap_str, sizeof(cap_str));
printk(KERN_INFO "%s: %s %s %s %s\n",
md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
cap_str, md->read_only ? "(ro)" : "");
mmc_set_drvdata(card, md); /* 将md保存起来即card->dev->driver_data=md */
add_disk(md->disk); /* 添加 一个磁盘*/
return 0;
out:
mmc_blk_put(md);
return err;
}
/* 移除函数 */
static void mmc_blk_remove(struct mmc_card *card)
{
struct mmc_blk_data *md = mmc_get_drvdata(card);
if (md) {
/* Stop new requests from getting into the queue */
del_gendisk(md->disk); /* 注销磁盘 */
/* Then flush out any already in there */
mmc_cleanup_queue(&md->queue); /* 释放请求队列 */
mmc_blk_put(md); /* 释放struct mmc_blk_data结构体 */
}
mmc_set_drvdata(card, NULL); /*card->dev->driver_data=NULL */
}
#ifdef CONFIG_PM
/* 挂起设备函数 */
static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
{
struct mmc_blk_data *md = mmc_get_drvdata(card);
if (md) {
mmc_queue_suspend(&md->queue); /* 挂起请求队列 */
}
return 0;
}
/* 恢复设备函数 */
static int mmc_blk_resume(struct mmc_card *card)
{
struct mmc_blk_data *md = mmc_get_drvdata(card);
if (md) {
mmc_blk_set_blksize(md, card); /* 设置卡的大小,发送命令设置卡为选中状态 */
mmc_queue_resume(&md->queue); /* 恢复请求队列 */
}
return 0;
}
#else
#define mmc_blk_suspend NULL
#define mmc_blk_resume NULL
#endif
static struct mmc_driver mmc_driver = {
.drv = {
.name = "mmcblk", /* 驱动名字为mmcblk */
},
.probe = mmc_blk_probe, /* 探测函数 */
.remove = mmc_blk_remove, /* 移除函数 */
.suspend = mmc_blk_suspend, /* 挂起设备函数 */
.resume = mmc_blk_resume, /* 恢复设备函数 */
};
static int __init mmc_blk_init(void)
{
int res;
res = register_blkdev(MMC_BLOCK_MAJOR, "mmc"); /* 注册块设备,设备名为mmc */
if (res)
goto out;
res = mmc_register_driver(&mmc_driver); /* 注册MMC设备驱动 */
if (res)
goto out2;
return 0;
out2:
unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
out:
return res;
}
static void __exit mmc_blk_exit(void)
{
mmc_unregister_driver(&mmc_driver);
unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
}
module_init(mmc_blk_init);
module_exit(mmc_blk_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver");