Linux设备驱动子系统第二弹- SD卡 - 图文(10)

2019-08-31 13:59

int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock) {

struct mmc_host *host = card->host; mq->card = card;

mq->queue = blk_init_queue(mmc_request, lock); mq->queue->queuedata = mq; mq->req = NULL;

blk_queue_prep_rq(mq->queue, mmc_prep_request); // 注册mmc_prep_request算法 blk_queue_ordered(mq->queue, QUEUE_ORDERED_DRAIN, NULL); //注册ordered算法

mq->thread = kthread_run(mmc_queue_thread, mq, \ ... ... }

1) mmc_request

它是处理SD卡通用的申请请求的回调函数,或者说是SD卡申请请求的算法。当CPU处于not busy状态,会寻找一个请求,并试图执行它。 /* /drivers/mmc/card/queue.c */ /*

* 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. */

static void mmc_request(struct request_queue *q) {

struct mmc_queue *mq = q->queuedata; struct request *req; if (!mq) {

while ((req = blk_fetch_request(q)) != NULL) { // 寻找来自请求队列的一个请求req req->cmd_flags |= REQ_QUIET;

__blk_end_request_all(req, -EIO); } return; }

if (!mq->req)

wake_up_process(mq->thread); // 如果队列里没有请求req,唤醒守护进程 }

这里我们需要关注这个处理该SD卡请求队列的算法是何时申请的,也就是何时会去申请请求,何时会去唤醒内核线程。 用到回调函数q->request_fn有三处

? ? ?

块设备驱动注册请求队列blk_register_queue() 驱动程序出错,清空请求队列mmc_cleanup_queue() 实现请求队列机制的blk_fetch_request内部本身

blk_fetch_request()->blk_peek_request()->__elv_next_request()->blk_do_ordered()->...->q->request_fn

我们不必深究所谓的电梯算法,只要知道,它是使数据得以高效通信的一种算法,算法自身决定何时去唤醒守护进程处理请求。 2) blk_init_queue()

如果一个块设备希望使用一个标准的请求处理步骤,那就必须使用blk_init_queue()。这个函数注册了q->request_fn(这里就是mmc_request),并初始化请求队列的数据结构struct request_queue。 /*

* call blk_init_queue(). The function @rfn will be called when there * are requests on the queue that need to be processed. If the device * supports plugging, then @rfn may not be called immediately when requests * are available on the queue, but may be called at some time later instead. */

struct request_queue *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock) {

return blk_init_queue_node(rfn, lock, -1); }

其中的rfn就是请求队列的一个算法,即这里的mmc_request。

struct request_queue *blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id) {

struct request_queue *q = blk_alloc_queue_node(GFP_KERNEL, node_id); q->request_fn = rfn; q->prep_rq_fn = NULL;

q->unplug_fn = generic_unplug_device; q->queue_flags = QUEUE_FLAG_DEFAULT; q->queue_lock = lock;

blk_queue_make_request(q, __make_request); if (!elevator_init(q, NULL)) {

blk_queue_congestion_threshold(q); return q; } ... ... }

3) kthead_run()

注意到mmc_init_queue这个函数的最后,创建并运行一个名为mmcqd的线程,顾名思意,mmc queue deamon它是一个SD卡的处理请求队列的守护进程,或者说内核线程,当系统注册SD卡块设备驱动时,就通过mmc_init_queue()开启了这个内核线程。 4) mmc_queue_thread 看看这个内核线程做了些什么,

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); if (!blk_queue_plugged(q)) req = blk_fetch_request(q); mq->req = req;

spin_unlock_irq(q->queue_lock); if (!req) {

if (kthread_should_stop()) {

set_current_state(TASK_RUNNING); break; }

up(&mq->thread_sem); schedule();

down(&mq->thread_sem); continue; }

set_current_state(TASK_RUNNING); mq->issue_fn(mq, req); } while (1);

up(&mq->thread_sem);

return 0; }

首先,这个守护进程是一个while(1)死循环,如果没有特殊要求,即kthread_should_stop()指定要把这个内核线程终止掉,那么它将从系统启动开始一直负责处理SD卡的请求队列。 在循环内部,内核线程首先通过set_current_state(TASK_INTERRUPTIBLE);设置当前线程为可打断的等待线程,进入睡眠状态,等待其他线程唤醒它,这里唤醒它的就是处理SD卡请求的mmc_request,当mq->req为空,即当前没有请求正在处理,则通

过 wake_up_process(mq->thread);唤醒内核线程,接着该线程尝试从请求队列里得到一个请求req,

-> 如果没有请求,则调用schedule()交出cpu的使用权让其自由调度,等到系统空闲时,再次得到cpu控制权,并且执行continue;退出当前循环,重新开始新的循环。

-> 如果得到了一个请求,则通过set_current_state(TASK_RUNNING);将该内核线程设置为当前正在运行的进程,并调用issue_fn(),即mmc_blk_issue_rq,处理这个请求,实现主控制器与SD卡的数据传输。 5) issue_fn

驱动初始化函数probe()里的mmc_blk_alloc()里注册了这个回调函数,md->queue.issue_fn = mmc_blk_issue_rq;

这个函数将req里的成员解析成为mmc_blk_request里的指令和数据,即mmc_command和mmc_data,然后通过mmc_wait_for_req()最终实现主控制器与SD卡间的通信。 struct mmc_blk_request { struct mmc_request mrq; struct mmc_command cmd; struct mmc_command stop; struct mmc_data data; };

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;


Linux设备驱动子系统第二弹- SD卡 - 图文(10).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:太阳能热水器控制仪使用说明书资料

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: