码迷,mamicode.com
首页 > 系统相关 > 详细

【转】linux设备驱动之MMC SD卡——核心层简单分析

时间:2015-03-14 00:54:50      阅读:3432      评论:0      收藏:0      [点我收藏+]

标签:

原文网址:http://blog.chinaunix.net/uid-28685940-id-3889878.html

/*************************************************************************************************************************************/
/* bus.c */

/*
 *  linux/drivers/mmc/core/bus.c
 *
 *  Copyright (C) 2003 Russell King, All Rights Reserved.
 *  Copyright (C) 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.
 *
 *  MMC card bus driver model
 */

#include <linux/device.h>
#include <linux/err.h>

#include <linux/mmc/card.h>
#include <linux/mmc/host.h>

#include "core.h"
#include "sdio_cis.h"
#include "bus.h"

#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev)
#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)

/*显示mmc类型 */
static ssize_t mmc_type_show(struct device *dev,
 struct device_attribute *attr, char *buf)
{
 struct mmc_card *card = dev_to_mmc_card(dev);

 switch (card->type) {
 case MMC_TYPE_MMC:
  return sprintf(buf, "MMC\n");
 case MMC_TYPE_SD:
  return sprintf(buf, "SD\n");
 case MMC_TYPE_SDIO:
  return sprintf(buf, "SDIO\n");
 default:
  return -EFAULT;
 }
}

static struct device_attribute mmc_dev_attrs[] = {  /* 设备属性文件 */
 __ATTR(type, S_IRUGO, mmc_type_show, NULL),
 __ATTR_NULL,
};

/*
 * This currently matches any MMC driver to any MMC card - drivers
 * themselves make the decision whether to drive this card in their
 * probe method.
 */
 /* 匹配函数 */
static int mmc_bus_match(struct device *dev, struct device_driver *drv)
{
 return 1;
}

/* 热插拔事件处理函数 */
static int
mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
 struct mmc_card *card = dev_to_mmc_card(dev);
 const char *type;
 int retval = 0;

 switch (card->type) {
 case MMC_TYPE_MMC:
  type = "MMC";
  break;
 case MMC_TYPE_SD:
  type = "SD";
  break;
 case MMC_TYPE_SDIO:
  type = "SDIO";
  break;
 default:
  type = NULL;
 }

 if (type) {
  retval = add_uevent_var(env, "MMC_TYPE=%s", type);  /* 添加ueven环境变量 */
  if (retval)
   return retval;
 }

 retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card));
 if (retval)
  return retval;

 /*
  * Request the mmc_block device.  Note: that this is a direct request
  * for the module it carries no information as to what is inserted.
  */
 retval = add_uevent_var(env, "MODALIAS=mmc:block");

 return retval;
}

/* 探测函数 */
static int mmc_bus_probe(struct device *dev)
{
 struct mmc_driver *drv = to_mmc_driver(dev->driver);
 struct mmc_card *card = dev_to_mmc_card(dev);

 return drv->probe(card); /* 调用struct mmc_driver 的probe函数来挂起设备----由此可见probe函数必须提供 */
}

/* 移除函数 */
static int mmc_bus_remove(struct device *dev)
{
 struct mmc_driver *drv = to_mmc_driver(dev->driver);
 struct mmc_card *card = dev_to_mmc_card(dev);

 drv->remove(card); /* 调用struct mmc_driver 的remove函数来挂起设备----由此可见remove函数必须提供 */

 return 0;
}

 /* 挂起函数 */
static int mmc_bus_suspend(struct device *dev, pm_message_t state)
{
 struct mmc_driver *drv = to_mmc_driver(dev->driver);
 struct mmc_card *card = dev_to_mmc_card(dev);
 int ret = 0;

 if (dev->driver && drv->suspend)
  ret = drv->suspend(card, state);  /* 调用struct mmc_driver 的suspend函数来挂起设备 */
 return ret;
}

/* 恢复函数 */
static int mmc_bus_resume(struct device *dev)
{
 struct mmc_driver *drv = to_mmc_driver(dev->driver);
 struct mmc_card *card = dev_to_mmc_card(dev);
 int ret = 0;

 if (dev->driver && drv->resume)
  ret = drv->resume(card);  /* 调用struct mmc_driver 的resume函数来恢复设备 */
 return ret;
}

static struct bus_type mmc_bus_type = {  /* 总线类型 */
 .name  = "mmc",     /* 总线类型为mmc,会在/sys/bus目录下创建一个mmc目录 */
 .dev_attrs = mmc_dev_attrs,    /* 设备属性 */
 .match  = mmc_bus_match, /* 匹配函数 */
 .uevent  = mmc_bus_uevent, /* 热插拔事件处理函数 */
 .probe  = mmc_bus_probe,  /* 探测函数 */
 .remove  = mmc_bus_remove, /* 移除函数 */
 .suspend = mmc_bus_suspend,      /* 挂起函数 */
 .resume  = mmc_bus_resume, /* 恢复函数 */
};

int mmc_register_bus(void)
{
 return bus_register(&mmc_bus_type);  /* 向设备模型核心注册一条总线 */
}

void mmc_unregister_bus(void)
{
 bus_unregister(&mmc_bus_type);  /* 注销总线 */
}

/**
 * mmc_register_driver - register a media driver
 * @drv: MMC media driver
 */
 /* 注册mmc驱动 */
int mmc_register_driver(struct mmc_driver *drv)
{
 drv->drv.bus = &mmc_bus_type; 
 return driver_register(&drv->drv); /* 向驱动模型核心注册驱动 */
}

EXPORT_SYMBOL(mmc_register_driver);

/**
 * mmc_unregister_driver - unregister a media driver
 * @drv: MMC media driver
 */
 /* 注销mmc驱动 */
void mmc_unregister_driver(struct mmc_driver *drv)
{
 drv->drv.bus = &mmc_bus_type;
 driver_unregister(&drv->drv);
}

EXPORT_SYMBOL(mmc_unregister_driver);

/* 释放SD卡描述结构体----struct mmc_card */
static void mmc_release_card(struct device *dev)
{
 struct mmc_card *card = dev_to_mmc_card(dev);

 sdio_free_common_cis(card);

 if (card->info)
  kfree(card->info);

 kfree(card);
}

/*
 * Allocate and initialise a new MMC card structure.
 */
 /* 分配并初始化一个SD卡描述结构体--struct mmc_card- */
struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type)
{
 struct mmc_card *card;

 card = kzalloc(sizeof(struct mmc_card), GFP_KERNEL);  /* 分配一个struct mmc_card结构体 */
 if (!card)
  return ERR_PTR(-ENOMEM);
       /* 初始化其成员 */
 card->host = host;

 device_initialize(&card->dev);  /* 初始化设备 */

 card->dev.parent = mmc_classdev(host);
 card->dev.bus = &mmc_bus_type;
 card->dev.release = mmc_release_card;
 card->dev.type = type;

 return card;
}

/*
 * Register a new MMC card with the driver model.
 */
 /* 注册一个MMC卡到驱动模型 */
int mmc_add_card(struct mmc_card *card)
{
 int ret;
 const char *type;

 dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), card->rca);  /* 设置设备的名字 */

 switch (card->type) {
 case MMC_TYPE_MMC:
  type = "MMC";
  break;
 case MMC_TYPE_SD:
  type = "SD";
  if (mmc_card_blockaddr(card))
   type = "SDHC";
  break;
 case MMC_TYPE_SDIO:
  type = "SDIO";
  break;
 default:
  type = "?";
  break;
 }

 if (mmc_host_is_spi(card->host)) {  /* 如果mmc主机控制器使用的是SPI总线 */
  printk(KERN_INFO "%s: new %s%s card on SPI\n",
   mmc_hostname(card->host),
   mmc_card_highspeed(card) ? "high speed " : "",
   type);
 } else {
  printk(KERN_INFO "%s: new %s%s card at address %04x\n",
   mmc_hostname(card->host),
   mmc_card_highspeed(card) ? "high speed " : "",
   type, card->rca);
 }

 ret = device_add(&card->dev);  /* 向设备驱动模型核心添加一个设备 */
 if (ret)
  return ret;

#ifdef CONFIG_DEBUG_FS
 mmc_add_card_debugfs(card);
#endif

 mmc_card_set_present(card);

 return 0;
}

/*
 * Unregister a new MMC card with the driver model, and
 * (eventually) free it.
 */
 /*注销一个MMC卡从驱动模型 */
void mmc_remove_card(struct mmc_card *card)
{
#ifdef CONFIG_DEBUG_FS
 mmc_remove_card_debugfs(card);
#endif

 if (mmc_card_present(card)) {
  if (mmc_host_is_spi(card->host)) {
   printk(KERN_INFO "%s: SPI card removed\n",
    mmc_hostname(card->host));
  } else {
   printk(KERN_INFO "%s: card %04x removed\n",
    mmc_hostname(card->host), card->rca);
  }
  device_del(&card->dev);  /* 从设备驱动模型核心删除 */
 }

 put_device(&card->dev); /* 减小设备的引用计数 */
}

 /*************************************************************************************************************************************/
/* core.h */

/*
 *  linux/drivers/mmc/core/core.h
 *
 *  Copyright (C) 2003 Russell King, All Rights Reserved.
 *  Copyright 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.
 */

/*
      SD卡内部结构:
         ______________________________________________________________________________
       /              --         --           --          --          --          --          --         --                                   |
     /   --         ||          ||           ||          ||         ||          ||          ||          ||                                   |
   /     ||         ||          ||           ||          ||         ||          ||          ||          ||                                   |
 /       ||         --          --           --          --         --          --          --          --                                    |
|        --          |            |            |            |           |            |           |            |                                |
|        ↓       ↓        ↓         ↓        ↓       ↓        ↓        ↓        ↓                                 |
|   DATA2   CD/DATA3 CMD       GND       VDD       CLK      GND       DATA0     DATA1                        |
|                                                                                                                                                 |
|             ----------                         -------------------------------------                                                    |
|            |OCR[31:0]|<---->|                                                    |                                                    |
|             ----------              |                                                     |                                                   |
|             ----------              |                                                     |                                                   |
|            |CID[127:0]|<--> |                                                     |                                                    |
|             ----------              |                                                     |                                                    |
|            -----------             |                        Card                       |                                                    |
|            |RCA[15:0]|<--->|                      interface                    |                                                    |
|            -----------             |                      controller                  |                                                    |
|            -----------             |                                                     |                                                    |
|            |DSR[15:0]|<--->|                                                     |            ------                                  |
|            -----------             |                                                     |           |  P    |                                |
|            -----------             |                                                     |           |  o    |                                |
|            |CSD[127:0]|<-->|                                                    |<-----    |  w    |                               |
|            -----------             |                                                     |           |  e    |                                |
|            -----------             |                                                     |           |  r     |                                |
|            |SCR[63:0] |<--> |                                                     |           |        |                                |
|                                            --------------------------------------                |  o     |                                |
|                                                                                                         |  n    |                                |
|                                                                                                          |        |                               |
|     ---------------------------------------------------------------       |  d    |                                                    |
|    |                                  Memory core interface                      reset|<--|  e    |                                |
|     ---------------------------------------------------------------       |   t    |                                                    |
|                                                         ↑                                                 |   e    |                             |
|                                                          |                                                |   c    |                              |
|                                                          |                                                 |   t     |                             |
|                                                          |                                                 |   i     |                              |
|                                                          |                                                 |   o    |                              |
|                                                         ↓                                                  |   n    |                              |
|  -----------------------------------------------------------------       ------                        |
| |                                                                                                               |                                    |
| |                                                                                                               |                                    |
| |                                                                                                               |                                    |
| |                                                                                                               |                                    |
| |                                            Memory   core                                              |                                     |
| |                                                                                                               |                                    
| |                                                                                                               |                                    |
| |                                                                                                               |                                    |
| |                                                                                                               |                                    |
|  ----------------------------------------------------------------                                                                          |
_______________________________________________________________________________________


OCR寄存器:操作条件寄存器
SCR寄存器:SD配置寄存器----保存卡的特殊功能信息
CSD寄存器:卡的特殊数据寄存器----卡的操作条件信息
DSR寄存器:驱动配置寄存器----用来配置卡的输出驱动
RCA寄存器:卡的相对地址----本地系统中卡的地址,动态变化,在主机初始化的时候确定
CID寄存器:卡的识别序列号
*/
#ifndef _MMC_CORE_CORE_H
#define _MMC_CORE_CORE_H

#include <linux/delay.h>

#define MMC_CMD_RETRIES        3

struct mmc_bus_ops {  /* mmc总线操作函数集 */
 void (*remove)(struct mmc_host *);  /* 移除 */
 void (*detect)(struct mmc_host *);   /* 探测 */
 void (*suspend)(struct mmc_host *); /* 挂起 */
 void (*resume)(struct mmc_host *);  /* 恢复 */
};

void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
void mmc_detach_bus(struct mmc_host *host);

void mmc_set_chip_select(struct mmc_host *host, int mode);
void mmc_set_clock(struct mmc_host *host, unsigned int hz);
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
void mmc_set_timing(struct mmc_host *host, unsigned int timing);

/* 延时ms毫秒 */
static inline void mmc_delay(unsigned int ms)
{
 if (ms < 1000 / HZ) {
  cond_resched();
  mdelay(ms);
 } else {
  msleep(ms);
 }
}

void mmc_rescan(struct work_struct *work);
void mmc_start_host(struct mmc_host *host);
void mmc_stop_host(struct mmc_host *host);

int mmc_attach_mmc(struct mmc_host *host, u32 ocr);
int mmc_attach_sd(struct mmc_host *host, u32 ocr);
int mmc_attach_sdio(struct mmc_host *host, u32 ocr);

extern int use_spi_crc;

/* Debugfs information for hosts and cards */
void mmc_add_host_debugfs(struct mmc_host *host);
void mmc_remove_host_debugfs(struct mmc_host *host);

void mmc_add_card_debugfs(struct mmc_card *card);
void mmc_remove_card_debugfs(struct mmc_card *card);

#endif
/*************************************************************************************************************************************/
/* core.c */

/*
 *  linux/drivers/mmc/core/core.c
 *
 *  Copyright (C) 2003-2004 Russell King, All Rights Reserved.
 *  SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
 *  Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
 *  MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved.
 *
 * 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 <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/pagemap.h>
#include <linux/err.h>
#include <linux/leds.h>
#include <linux/scatterlist.h>
#include <linux/log2.h>
#include <linux/regulator/consumer.h>

#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>

#include "core.h"
#include "bus.h"
#include "host.h"
#include "sdio_bus.h"

#include "mmc_ops.h"
#include "sd_ops.h"
#include "sdio_ops.h"

static struct workqueue_struct *workqueue;

/*
 * Enabling software CRCs on the data blocks can be a significant (30%)
 * performance cost, and for other reasons may not always be desired.
 * So we allow it it to be disabled.
 */
int use_spi_crc = 1;
module_param(use_spi_crc, bool, 0);

/*
 * Internal function. Schedule delayed work in the MMC work queue.
 */
 /* 调度mmc工作队列上延时工作 */
static int mmc_schedule_delayed_work(struct delayed_work *work,
         unsigned long delay)
{
 return queue_delayed_work(workqueue, work, delay);
}

/*
 * Internal function. Flush all scheduled work from the MMC work queue.
 */
static void mmc_flush_scheduled_work(void)
{
 flush_workqueue(workqueue);
}

/**
 * mmc_request_done - finish processing an MMC request
 * @host: MMC host which completed request
 * @mrq: MMC request which request
 *
 * MMC drivers should call this function when they have completed
 * their processing of a request.
 */
 /* 完成处理一个mmc请求 */
void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
{
 struct mmc_command *cmd = mrq->cmd;
 int err = cmd->error;

 if (err && cmd->retries && mmc_host_is_spi(host)) {
  if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
   cmd->retries = 0;
 }

 if (err && cmd->retries) {
  pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
   mmc_hostname(host), cmd->opcode, err);

  cmd->retries--;
  cmd->error = 0;
  host->ops->request(host, mrq);  /* 如果出现错误并且重复次数不为0则再次调用请求处理函数来处理请求 */
 } else {
  led_trigger_event(host->led, LED_OFF);

  pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n",
   mmc_hostname(host), cmd->opcode, err,
   cmd->resp[0], cmd->resp[1],
   cmd->resp[2], cmd->resp[3]);

  if (mrq->data) {
   pr_debug("%s:     %d bytes transferred: %d\n",
    mmc_hostname(host),
    mrq->data->bytes_xfered, mrq->data->error);
  }

  if (mrq->stop) {
   pr_debug("%s:     (CMD%u): %d: %08x %08x %08x %08x\n",
    mmc_hostname(host), mrq->stop->opcode,
    mrq->stop->error,
    mrq->stop->resp[0], mrq->stop->resp[1],
    mrq->stop->resp[2], mrq->stop->resp[3]);
  }

  if (mrq->done)
   mrq->done(mrq);  /* 如果 struct mmc_request mrq->done有定义则调用该完成回调函数*/
 }
}

EXPORT_SYMBOL(mmc_request_done);

 /* 开始一个请求 */
static void
mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
{
#ifdef CONFIG_MMC_DEBUG
 unsigned int i, sz;
 struct scatterlist *sg;
#endif

 pr_debug("%s: starting CMD%u arg %08x flags %08x\n",
   mmc_hostname(host), mrq->cmd->opcode,
   mrq->cmd->arg, mrq->cmd->flags);

 if (mrq->data) {
  pr_debug("%s:     blksz %d blocks %d flags %08x "
   "tsac %d ms nsac %d\n",
   mmc_hostname(host), mrq->data->blksz,
   mrq->data->blocks, mrq->data->flags,
   mrq->data->timeout_ns / 1000000,
   mrq->data->timeout_clks);
 }

 if (mrq->stop) {
  pr_debug("%s:     CMD%u arg %08x flags %08x\n",
    mmc_hostname(host), mrq->stop->opcode,
    mrq->stop->arg, mrq->stop->flags);
 }

 WARN_ON(!host->claimed);

 led_trigger_event(host->led, LED_FULL);

 mrq->cmd->error = 0;
 mrq->cmd->mrq = mrq;
 if (mrq->data) {
  BUG_ON(mrq->data->blksz > host->max_blk_size);
  BUG_ON(mrq->data->blocks > host->max_blk_count);
  BUG_ON(mrq->data->blocks * mrq->data->blksz >
   host->max_req_size);

#ifdef CONFIG_MMC_DEBUG
  sz = 0;
  for_each_sg(mrq->data->sg, sg, mrq->data->sg_len, i)
   sz += sg->length;
  BUG_ON(sz != mrq->data->blocks * mrq->data->blksz);
#endif

  mrq->cmd->data = mrq->data;
  mrq->data->error = 0;
  mrq->data->mrq = mrq;
  if (mrq->stop) {
   mrq->data->stop = mrq->stop;
   mrq->stop->error = 0;
   mrq->stop->mrq = mrq;
  }
 }
 host->ops->request(host, mrq);  /* 调用host->ops->request请求处理函数来完成mmc协议的命令处理 */
}

/* 请求完成回调函数 */
static void mmc_wait_done(struct mmc_request *mrq)
{
 complete(mrq->done_data);  /* 唤醒等待队列中睡眠进程 */
}

/**
 * mmc_wait_for_req - start a request and wait for completion
 * @host: MMC host to start command
 * @mrq: MMC request to start
 *
 * Start a new MMC custom command request for a host, and wait
 * for the command to complete. Does not attempt to parse the
 * response.
 */
 /* 开始一个 请求并等待它完成 */
void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
{
 DECLARE_COMPLETION_ONSTACK(complete);

 mrq->done_data = &complete;
 mrq->done = mmc_wait_done;  /* 设置请求完成回调函数 */

 mmc_start_request(host, mrq);  /* 开始一个请求 */

 wait_for_completion(&complete); /* 等待请求完成 */
}

EXPORT_SYMBOL(mmc_wait_for_req);

/**
 * mmc_wait_for_cmd - start a command and wait for completion
 * @host: MMC host to start command
 * @cmd: MMC command to start
 * @retries: maximum number of retries
 *
 * Start a new MMC command for a host, and wait for the command
 * to complete.  Return any error that occurred while the command
 * was executing.  Do not attempt to parse the response.
 */
 /* 发送一个命令并等待它完成 */
int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
{
 struct mmc_request mrq;

 WARN_ON(!host->claimed);

 memset(&mrq, 0, sizeof(struct mmc_request));

 memset(cmd->resp, 0, sizeof(cmd->resp));
 cmd->retries = retries;

 mrq.cmd = cmd;  /* 指向命令 */
 cmd->data = NULL;  /* 没有数据 */

 mmc_wait_for_req(host, &mrq);  /* 开始一个请求并等待它完成 */

 return cmd->error;
}

EXPORT_SYMBOL(mmc_wait_for_cmd);

/**
 * mmc_set_data_timeout - set the timeout for a data command
 * @data: data phase for command
 * @card: the MMC card associated with the data transfer
 *
 * Computes the data timeout parameters according to the
 * correct algorithm given the card type.
 */
 /* 设置一个数据命令的超时时间 */
void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
{
 unsigned int mult;

 /*
  * SDIO cards only define an upper 1 s limit on access.
  */
 if (mmc_card_sdio(card)) {  /* 如果是SDIO卡 */
  data->timeout_ns = 1000000000;
  data->timeout_clks = 0;
  return;
 }

 /*
  * SD cards use a 100 multiplier rather than 10
  */
 mult = mmc_card_sd(card) ? 100 : 10;

 /*
  * Scale up the multiplier (and therefore the timeout) by
  * the r2w factor for writes.
  */
 if (data->flags & MMC_DATA_WRITE)
  mult <<= card->csd.r2w_factor;

 data->timeout_ns = card->csd.tacc_ns * mult;
 data->timeout_clks = card->csd.tacc_clks * mult;

 /*
  * SD cards also have an upper limit on the timeout.
  */
 if (mmc_card_sd(card)) {
  unsigned int timeout_us, limit_us;

  timeout_us = data->timeout_ns / 1000;
  timeout_us += data->timeout_clks * 1000 /
   (card->host->ios.clock / 1000);

  if (data->flags & MMC_DATA_WRITE)
   /*
    * The limit is really 250 ms, but that is
    * insufficient for some crappy cards.
    */
   limit_us = 300000;
  else
   limit_us = 100000;

  /*
   * SDHC cards always use these fixed values.
   */
  if (timeout_us > limit_us || mmc_card_blockaddr(card)) {
   data->timeout_ns = limit_us * 1000;
   data->timeout_clks = 0;
  }
 }
 /*
  * Some cards need very high timeouts if driven in SPI mode.
  * The worst observed timeout was 900ms after writing a
  * continuous stream of data until the internal logic
  * overflowed.
  */
 if (mmc_host_is_spi(card->host)) {
  if (data->flags & MMC_DATA_WRITE) {
   if (data->timeout_ns < 1000000000)
    data->timeout_ns = 1000000000; /* 1s */
  } else {
   if (data->timeout_ns < 100000000)
    data->timeout_ns =  100000000; /* 100ms */
  }
 }
}
EXPORT_SYMBOL(mmc_set_data_timeout);

/**
 * mmc_align_data_size - pads a transfer size to a more optimal value
 * @card: the MMC card associated with the data transfer
 * @sz: original transfer size
 *
 * Pads the original data size with a number of extra bytes in
 * order to avoid controller bugs and/or performance hits
 * (e.g. some controllers revert to PIO for certain sizes).
 *
 * Returns the improved size, which might be unmodified.
 *
 * Note that this function is only relevant when issuing a
 * single scatter gather entry.
 */
unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz)
{
 /*
  * FIXME: We don‘t have a system for the controller to tell
  * the core about its problems yet, so for now we just 32-bit
  * align the size.
  */
 sz = ((sz + 3) / 4) * 4;

 return sz;
}
EXPORT_SYMBOL(mmc_align_data_size);

/**
 * __mmc_claim_host - exclusively claim a host
 * @host: mmc host to claim
 * @abort: whether or not the operation should be aborted
 *
 * Claim a host for a set of operations.  If @abort is non null and
 * dereference a non-zero value then this will return prematurely with
 * that non-zero value without acquiring the lock.  Returns zero
 * with the lock held otherwise.
 */
 /* 声明主机控制器 */
int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
{
 DECLARE_WAITQUEUE(wait, current);  /* 定义并初始化一个等待队列 wait*/
 unsigned long flags;
 int stop;

 might_sleep();

 add_wait_queue(&host->wq, &wait);  /* 将 host->wq添加到等待队列wait*/
 spin_lock_irqsave(&host->lock, flags);
 while (1) {
  set_current_state(TASK_UNINTERRUPTIBLE);  /* 设置当前进程的状态为TASK_UNINTERRUPTIBLE */
  stop = abort ? atomic_read(abort) : 0;  /* stop= abort? abort->counter:0?*/
  if (stop || !host->claimed)  /* 当stop=1或者 host->claimed=0时则继续循环*/
   break;
  spin_unlock_irqrestore(&host->lock, flags);
  schedule();  /* 将进程调度处CPU----进程进入休眠 */
  spin_lock_irqsave(&host->lock, flags);
 }
 set_current_state(TASK_RUNNING);  /* 设置当前进程状态为TASK_RUNNING----CPU会调度该进程运行 */
 if (!stop)  /* 如果stop=0则设置 host->claimed = 1,否则*/
  host->claimed = 1;
 else
  wake_up(&host->wq);  /* 唤醒等待队列 host->wq上的进程*/
 spin_unlock_irqrestore(&host->lock, flags);
 remove_wait_queue(&host->wq, &wait);  /* 将host->wq从wait中移除 */
 return stop;
}

EXPORT_SYMBOL(__mmc_claim_host);

/**
 * mmc_release_host - release a host
 * @host: mmc host to release
 *
 * Release a MMC host, allowing others to claim the host
 * for their operations.
 */
 /* 释放主机 */
void mmc_release_host(struct mmc_host *host)
{
 unsigned long flags;

 WARN_ON(!host->claimed);

 spin_lock_irqsave(&host->lock, flags);
 host->claimed = 0;
 spin_unlock_irqrestore(&host->lock, flags);

 wake_up(&host->wq);  /*  唤醒host->wq上的进程*/
}

EXPORT_SYMBOL(mmc_release_host);

/*
 * Internal function that does the actual ios call to the host driver,
 * optionally printing some debug output.
 */
 /* 设置卡的I/O状态 */
static inline void mmc_set_ios(struct mmc_host *host)
{
 struct mmc_ios *ios = &host->ios;

 pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u "
  "width %u timing %u\n",
   mmc_hostname(host), ios->clock, ios->bus_mode,
   ios->power_mode, ios->chip_select, ios->vdd,
   ios->bus_width, ios->timing);

 host->ops->set_ios(host, ios);  /* 调用 struct mmc_host *host->ops->set_ios函数来对卡的I/O状态的进行设置*/
}

/*
 * Control chip select pin on a host.
 */
 /* 设置芯片片选 */
void mmc_set_chip_select(struct mmc_host *host, int mode)
{
 host->ios.chip_select = mode;
 mmc_set_ios(host);
}

/*
 * Sets the host clock to the highest possible frequency that
 * is below "hz".
 */
 /* 设置主机控制器时钟 */
void mmc_set_clock(struct mmc_host *host, unsigned int hz)
{
 WARN_ON(hz < host->f_min);

 if (hz > host->f_max)
  hz = host->f_max;

 host->ios.clock = hz;
 mmc_set_ios(host);
}

/*
 * Change the bus mode (open drain/push-pull) of a host.
 */
 /* 设置总线模式 */
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
{
 host->ios.bus_mode = mode;
 mmc_set_ios(host);
}

/*
 * Change data bus width of a host.
 */
 /* 设置总线宽度 */
void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
{
 host->ios.bus_width = width;
 mmc_set_ios(host);
}

/**
 * mmc_vdd_to_ocrbitnum - Convert a voltage to the OCR bit number
 * @vdd: voltage (mV)
 * @low_bits: prefer low bits in boundary cases
 *
 * This function returns the OCR bit number according to the provided @vdd
 * value. If conversion is not possible a negative errno value returned.
 *
 * Depending on the @low_bits flag the function prefers low or high OCR bits
 * on boundary voltages. For example,
 * with @low_bits = true, 3300 mV translates to ilog2(MMC_VDD_32_33);
 * with @low_bits = false, 3300 mV translates to ilog2(MMC_VDD_33_34);
 *
 * Any value in the [1951:1999] range translates to the ilog2(MMC_VDD_20_21).
 */
 /* 将一个电压值转换为OCR寄存器的比特编号 */
static int mmc_vdd_to_ocrbitnum(int vdd, bool low_bits)
{
 const int max_bit = ilog2(MMC_VDD_35_36);
 int bit;

 if (vdd < 1650 || vdd > 3600)
  return -EINVAL;

 if (vdd >= 1650 && vdd <= 1950)
  return ilog2(MMC_VDD_165_195);

 if (low_bits)
  vdd -= 1;

 /* Base 2000 mV, step 100 mV, bit‘s base 8. */
 bit = (vdd - 2000) / 100 + 8;
 if (bit > max_bit)
  return max_bit;
 return bit;
}

/**
 * mmc_vddrange_to_ocrmask - Convert a voltage range to the OCR mask
 * @vdd_min: minimum voltage value (mV)
 * @vdd_max: maximum voltage value (mV)
 *
 * This function returns the OCR mask bits according to the provided @vdd_min
 * and @vdd_max values. If conversion is not possible the function returns 0.
 *
 * Notes wrt boundary cases:
 * This function sets the OCR bits for all boundary voltages, for example
 * [3300:3400] range is translated to MMC_VDD_32_33 | MMC_VDD_33_34 |
 * MMC_VDD_34_35 mask.
 */
 /* 将一个电压等级转换为寄存器OCR的掩码 */
u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max)
{
 u32 mask = 0;

 if (vdd_max < vdd_min)
  return 0;

 /* Prefer high bits for the boundary vdd_max values. */
 vdd_max = mmc_vdd_to_ocrbitnum(vdd_max, false);
 if (vdd_max < 0)
  return 0;

 /* Prefer low bits for the boundary vdd_min values. */
 vdd_min = mmc_vdd_to_ocrbitnum(vdd_min, true);
 if (vdd_min < 0)
  return 0;

 /* Fill the mask, from max bit to min bit. */
 while (vdd_max >= vdd_min)
  mask |= 1 << vdd_max--;

 return mask;
}
EXPORT_SYMBOL(mmc_vddrange_to_ocrmask);

#ifdef CONFIG_REGULATOR

/**
 * mmc_regulator_get_ocrmask - return mask of supported voltages
 * @supply: regulator to use
 *
 * This returns either a negative errno, or a mask of voltages that
 * can be provided to MMC/SD/SDIO devices using the specified voltage
 * regulator.  This would normally be called before registering the
 * MMC host adapter.
 */
 /*返回支持的电压的掩码 */
int mmc_regulator_get_ocrmask(struct regulator *supply)
{
 int   result = 0;
 int   count;
 int   i;

 count = regulator_count_voltages(supply);
 if (count < 0)
  return count;

 for (i = 0; i < count; i++) {
  int  vdd_uV;
  int  vdd_mV;

  vdd_uV = regulator_list_voltage(supply, i);
  if (vdd_uV <= 0)
   continue;

  vdd_mV = vdd_uV / 1000;
  result |= mmc_vddrange_to_ocrmask(vdd_mV, vdd_mV);
 }

 return result;
}
EXPORT_SYMBOL(mmc_regulator_get_ocrmask);

/**
 * mmc_regulator_set_ocr - set regulator to match host->ios voltage
 * @vdd_bit: zero for power off, else a bit number (host->ios.vdd)
 * @supply: regulator to use
 *
 * Returns zero on success, else negative errno.
 *
 * MMC host drivers may use this to enable or disable a regulator using
 * a particular supply voltage.  This would normally be called from the
 * set_ios() method.
 */
 /* 设置调节器使得其能够匹配 host->ios voltage*/
int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit)
{
 int   result = 0;
 int   min_uV, max_uV;
 int   enabled;

 enabled = regulator_is_enabled(supply);
 if (enabled < 0)
  return enabled;

 if (vdd_bit) {
  int  tmp;
  int  voltage;

  /* REVISIT mmc_vddrange_to_ocrmask() may have set some
   * bits this regulator doesn‘t quite support ... don‘t
   * be too picky, most cards and regulators are OK with
   * a 0.1V range goof (it‘s a small error percentage).
   */
  tmp = vdd_bit - ilog2(MMC_VDD_165_195);
  if (tmp == 0) {
   min_uV = 1650 * 1000;
   max_uV = 1950 * 1000;
  } else {
   min_uV = 1900 * 1000 + tmp * 100 * 1000;
   max_uV = min_uV + 100 * 1000;
  }

  /* avoid needless changes to this voltage; the regulator
   * might not allow this operation
   */
  voltage = regulator_get_voltage(supply);
  if (voltage < 0)
   result = voltage;
  else if (voltage < min_uV || voltage > max_uV)
   result = regulator_set_voltage(supply, min_uV, max_uV);
  else
   result = 0;

  if (result == 0 && !enabled)
   result = regulator_enable(supply);
 } else if (enabled) {
  result = regulator_disable(supply);
 }

 return result;
}
EXPORT_SYMBOL(mmc_regulator_set_ocr);

#endif

/*
 * Mask off any voltages we don‘t support and select
 * the lowest voltage
 */
 /* 选择电压 
    屏蔽不支持的电压并且选择最低的工作电压 */
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
{
 int bit;

 ocr &= host->ocr_avail;

 bit = ffs(ocr);
 if (bit) {
  bit -= 1;

  ocr &= 3 << bit;

  host->ios.vdd = bit;
  mmc_set_ios(host);
 } else {
  pr_warning("%s: host doesn‘t support card‘s voltages\n",
    mmc_hostname(host));
  ocr = 0;
 }

 return ocr;
}

/*
 * Select timing parameters for host.
 */
 /* 为主机控制器选择时序参数 */
void mmc_set_timing(struct mmc_host *host, unsigned int timing)
{
 host->ios.timing = timing;
 mmc_set_ios(host);
}

/*
 * Apply power to the MMC stack.  This is a two-stage process.
 * First, we enable power to the card without the clock running.
 * We then wait a bit for the power to stabilise.  Finally,
 * enable the bus drivers and clock to the card.
 *
 * We must _NOT_ enable the clock prior to power stablising.
 *
 * If a host does all the power sequencing itself, ignore the
 * initial MMC_POWER_UP stage.
 */
 /* 上电 */
static void mmc_power_up(struct mmc_host *host)
{
 int bit = fls(host->ocr_avail) - 1;

 host->ios.vdd = bit;
 if (mmc_host_is_spi(host)) {
  host->ios.chip_select = MMC_CS_HIGH;
  host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
 } else {
  host->ios.chip_select = MMC_CS_DONTCARE;
  host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
 }
 host->ios.power_mode = MMC_POWER_UP;
 host->ios.bus_width = MMC_BUS_WIDTH_1;
 host->ios.timing = MMC_TIMING_LEGACY;
 mmc_set_ios(host);

 /*
  * This delay should be sufficient to allow the power supply
  * to reach the minimum voltage.
  */
 mmc_delay(10);

 host->ios.clock = host->f_min;
 host->ios.power_mode = MMC_POWER_ON;
 mmc_set_ios(host);

 /*
  * This delay must be at least 74 clock sizes, or 1 ms, or the
  * time required to reach a stable voltage.
  */
 mmc_delay(10);
}

/* 关闭电源 */
static void mmc_power_off(struct mmc_host *host)
{
 host->ios.clock = 0;
 host->ios.vdd = 0;
 if (!mmc_host_is_spi(host)) {
  host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
  host->ios.chip_select = MMC_CS_DONTCARE;
 }
 host->ios.power_mode = MMC_POWER_OFF;
 host->ios.bus_width = MMC_BUS_WIDTH_1;
 host->ios.timing = MMC_TIMING_LEGACY;
 mmc_set_ios(host);
}

/*
 * Cleanup when the last reference to the bus operator is dropped.
 */
 /* 释放总线操作函数 */
static void __mmc_release_bus(struct mmc_host *host)
{
 BUG_ON(!host);
 BUG_ON(host->bus_refs);
 BUG_ON(!host->bus_dead);

 host->bus_ops = NULL;
}

/*
 * Increase reference count of bus operator
 */
 /* 增加 总线引用计数*/
static inline void mmc_bus_get(struct mmc_host *host)
{
 unsigned long flags;

 spin_lock_irqsave(&host->lock, flags);
 host->bus_refs++;
 spin_unlock_irqrestore(&host->lock, flags);
}

/*
 * Decrease reference count of bus operator and free it if
 * it is the last reference.
 */
 /* 减小总线引用计数 */
static inline void mmc_bus_put(struct mmc_host *host)
{
 unsigned long flags;

 spin_lock_irqsave(&host->lock, flags);
 host->bus_refs--;
 if ((host->bus_refs == 0) && host->bus_ops)
  __mmc_release_bus(host);  /* 如果总线计数器为0并且总线操作函数集有定义则释放它 */
 spin_unlock_irqrestore(&host->lock, flags);
}

/*
 * Assign a mmc bus handler to a host. Only one bus handler may control a
 * host at any given time.
 */
 /* 将主机控制器和总线操作函数绑定 */
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
{
 unsigned long flags;

 BUG_ON(!host);
 BUG_ON(!ops);

 WARN_ON(!host->claimed);

 spin_lock_irqsave(&host->lock, flags);

 BUG_ON(host->bus_ops);
 BUG_ON(host->bus_refs);

 host->bus_ops = ops;
 host->bus_refs = 1;
 host->bus_dead = 0;

 spin_unlock_irqrestore(&host->lock, flags);
}

/*
 * Remove the current bus handler from a host. Assumes that there are
 * no interesting cards left, so the bus is powered down.
 */
 /* 将总线和主机控制器分离 */
void mmc_detach_bus(struct mmc_host *host)
{
 unsigned long flags;

 BUG_ON(!host);

 WARN_ON(!host->claimed);
 WARN_ON(!host->bus_ops);

 spin_lock_irqsave(&host->lock, flags);

 host->bus_dead = 1;  /* 标记总线已经释放 */

 spin_unlock_irqrestore(&host->lock, flags);

 mmc_power_off(host);  /* 关闭电源 */

 mmc_bus_put(host);
}

/**
 * mmc_detect_change - process change of state on a MMC socket
 * @host: host which changed state.
 * @delay: optional delay to wait before detection (jiffies)
 *
 * MMC drivers should call this when they detect a card has been
 * inserted or removed. The MMC layer will confirm that any
 * present card is still functional, and initialize any newly
 * inserted.
 */
 /* 处理mmc插槽变化的状态 */
void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{
#ifdef CONFIG_MMC_DEBUG
 unsigned long flags;
 spin_lock_irqsave(&host->lock, flags);
 WARN_ON(host->removed);
 spin_unlock_irqrestore(&host->lock, flags);
#endif

 mmc_schedule_delayed_work(&host->detect, delay);
}

EXPORT_SYMBOL(mmc_detect_change);

/* 重新扫描 */
void mmc_rescan(struct work_struct *work)
{
 struct mmc_host *host =
  container_of(work, struct mmc_host, detect.work);
 u32 ocr;
 int err;

 mmc_bus_get(host);  /* 增加总线引用计数 */

 if (host->bus_ops == NULL) {  /* 如果总线操作函数集没有定义 */
  /*
   * Only we can add a new handler, so it‘s safe to
   * release the lock here.
   */
  mmc_bus_put(host); /* 减小总线引用计数 */

  if (host->ops->get_cd && host->ops->get_cd(host) == 0)  /* 如果 host->ops->get_cd函数有定义则调用它,如果该函数返回0则表示没有卡插入则退出*/
   goto out;

  mmc_claim_host(host);  /* 声明一个主机控制器 */

  mmc_power_up(host);  /* 上电 */
  mmc_go_idle(host);  /* 进入idle邋状态 */

  mmc_send_if_cond(host, host->ocr_avail);

  /*
   * First we search for SDIO...
   */
  err = mmc_send_io_op_cond(host, 0, &ocr);
  if (!err) {
   if (mmc_attach_sdio(host, ocr))
    mmc_power_off(host);
   goto out;
  }

  /*
   * ...then normal SD...
   */
  err = mmc_send_app_op_cond(host, 0, &ocr);
  if (!err) {
   if (mmc_attach_sd(host, ocr))
    mmc_power_off(host);
   goto out;
  }

  /*
   * ...and finally MMC.
   */
  err = mmc_send_op_cond(host, 0, &ocr);
  if (!err) {
   if (mmc_attach_mmc(host, ocr))
    mmc_power_off(host);
   goto out;
  }

  mmc_release_host(host);
  mmc_power_off(host);
 } else {
  if (host->bus_ops->detect && !host->bus_dead)
   host->bus_ops->detect(host);  /* 探测卡 */

  mmc_bus_put(host);
 }
out:
 if (host->caps & MMC_CAP_NEEDS_POLL)
  mmc_schedule_delayed_work(&host->detect, HZ);
}

/* 启动主机控制器 */
void mmc_start_host(struct mmc_host *host)
{
 mmc_power_off(host);  /* 打开电源 */
 mmc_detect_change(host, 0);  /* 探测 插槽是否发生变化*/
}

/* 停止主机控制器 */
void mmc_stop_host(struct mmc_host *host)
{
#ifdef CONFIG_MMC_DEBUG
 unsigned long flags;
 spin_lock_irqsave(&host->lock, flags);
 host->removed = 1;  /* 标记主机被移除 */
 spin_unlock_irqrestore(&host->lock, flags);
#endif

 cancel_delayed_work(&host->detect);
 mmc_flush_scheduled_work();

 mmc_bus_get(host);
 if (host->bus_ops && !host->bus_dead) {
  if (host->bus_ops->remove)
   host->bus_ops->remove(host);  /* 调用总线操作函数的移除函数 */

  mmc_claim_host(host); /* 声明一个主机控制器 */
  mmc_detach_bus(host); /* 将总线和主机控制器分离 */
  mmc_release_host(host); /* 释放主机控制器 */
 }
 mmc_bus_put(host);  /* 减小总线引用计数 */

 BUG_ON(host->card);

 mmc_power_off(host);  /* 关闭电源 */
}

#ifdef CONFIG_PM

/**
 * mmc_suspend_host - suspend a host
 * @host: mmc host
 * @state: suspend mode (PM_SUSPEND_xxx)
 */
 /* 挂起主机控制器 */
int mmc_suspend_host(struct mmc_host *host, pm_message_t state)
{
 cancel_delayed_work(&host->detect);
 mmc_flush_scheduled_work();

 mmc_bus_get(host);  /* 增加总线引用计数 */
 if (host->bus_ops && !host->bus_dead) {
  if (host->bus_ops->suspend)
   host->bus_ops->suspend(host);    /* 如果总线操作函数集的挂起函数有定义则调用它 */
  if (!host->bus_ops->resume) {
   if (host->bus_ops->remove)
    host->bus_ops->remove(host); /* 如果总线操作函数集的移除函数有定义则调用它 */

   mmc_claim_host(host); /* 声明一个主机控制器 */
   mmc_detach_bus(host);  /* 将总线和主机控制器分离 */
   mmc_release_host(host); /* 释放主机控制器 */
  }
 }
 mmc_bus_put(host);  /* 减小总线计数 */

 mmc_power_off(host);  /* 关闭电源 */

 return 0;
}

EXPORT_SYMBOL(mmc_suspend_host);

/**
 * mmc_resume_host - resume a previously suspended host
 * @host: mmc host
 */
 /* 恢复主机控制器 */
int mmc_resume_host(struct mmc_host *host)
{
 mmc_bus_get(host);  /* 增加引用计数 */
 if (host->bus_ops && !host->bus_dead) {
  mmc_power_up(host);  /* 上电 */
  mmc_select_voltage(host, host->ocr);  /* 选择工作电压 */
  BUG_ON(!host->bus_ops->resume);
  host->bus_ops->resume(host);  /* 调用 */
 }
 mmc_bus_put(host);

 /*
  * We add a slight delay here so that resume can progress
  * in parallel.
  */
 mmc_detect_change(host, 1);

 return 0;
}

EXPORT_SYMBOL(mmc_resume_host);

#endif

static int __init mmc_init(void)
{
 int ret;

 workqueue = create_singlethread_workqueue("kmmcd");  /* 创建工作队列 */
 if (!workqueue)
  return -ENOMEM;

 ret = mmc_register_bus();  /* 注册mmc总线 */
 if (ret)
  goto destroy_workqueue;

 ret = mmc_register_host_class();  /* 注册主机类 */
 if (ret)
  goto unregister_bus;

 ret = sdio_register_bus();  /* 注册SDIO总线 */
 if (ret)
  goto unregister_host_class;

 return 0;

unregister_host_class:
 mmc_unregister_host_class();
unregister_bus:
 mmc_unregister_bus();
destroy_workqueue:
 destroy_workqueue(workqueue);

 return ret;
}

static void __exit mmc_exit(void)
{
 sdio_unregister_bus();
 mmc_unregister_host_class();
 mmc_unregister_bus();
 destroy_workqueue(workqueue);
}

subsys_initcall(mmc_init);
module_exit(mmc_exit);

MODULE_LICENSE("GPL");

/*************************************************************************************************************************************/
/*  host.c*/

/*
 *  linux/drivers/mmc/core/host.c
 *
 *  Copyright (C) 2003 Russell King, All Rights Reserved.
 *  Copyright (C) 2007-2008 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.
 *
 *  MMC host class device management
 */

#include <linux/device.h>
#include <linux/err.h>
#include <linux/idr.h>
#include <linux/pagemap.h>
#include <linux/leds.h>

#include <linux/mmc/host.h>

#include "core.h"
#include "host.h"

#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)

/* 释放主机 */
static void mmc_host_classdev_release(struct device *dev)
{
 struct mmc_host *host = cls_dev_to_mmc_host(dev);
 kfree(host);
}

static struct class mmc_host_class = {  /* 主机类 */
 .name  = "mmc_host",   /* 类的名字为mmc_host */
 .dev_release = mmc_host_classdev_release,
};

/* 注册一个主机类 */
int mmc_register_host_class(void)
{
 return class_register(&mmc_host_class); /* 注册mmc_host_class类 */
}
/* 注销主机类 */
void mmc_unregister_host_class(void)
{
 class_unregister(&mmc_host_class);
}

static DEFINE_IDR(mmc_host_idr);
static DEFINE_SPINLOCK(mmc_host_lock);

/**
 * mmc_alloc_host - initialise the per-host structure.
 * @extra: sizeof private data structure
 * @dev: pointer to host device model structure
 *
 * Initialise the per-host structure.
 */
 /* 分配一个struct mmc_host结构
     参数extra为要分配的额外的内存*/
struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
{
 int err;
 struct mmc_host *host;

 if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL))
  return NULL;

 host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL); /* 分配内存 */
 if (!host)
  return NULL;

 spin_lock(&mmc_host_lock);
 err = idr_get_new(&mmc_host_idr, host, &host->index);
 spin_unlock(&mmc_host_lock);
 if (err)
  goto free;
       /* 初始化struct mmc_host名字 */
 dev_set_name(&host->class_dev, "mmc%d", host->index);

 host->parent = dev;
 host->class_dev.parent = dev;
 host->class_dev.class = &mmc_host_class;
 device_initialize(&host->class_dev);  /* 初始化设备 */

 spin_lock_init(&host->lock);
 init_waitqueue_head(&host->wq); /*  初始化等待队列 */
 INIT_DELAYED_WORK(&host->detect, mmc_rescan); /* 初始化延时工作结构 */

 /*
  * By default, hosts do not support SGIO or large requests.
  * They have to set these according to their abilities.
  */
 /* 设置它的成员 */
 host->max_hw_segs = 1;
 host->max_phys_segs = 1;
 host->max_seg_size = PAGE_CACHE_SIZE;

 host->max_req_size = PAGE_CACHE_SIZE;
 host->max_blk_size = 512;
 host->max_blk_count = PAGE_CACHE_SIZE / 512;

 return host;

free:
 kfree(host);
 return NULL;
}

EXPORT_SYMBOL(mmc_alloc_host);

/**
 * mmc_add_host - initialise host hardware
 * @host: mmc host
 *
 * Register the host with the driver model. The host must be
 * prepared to start servicing requests before this function
 * completes.
 */
 /* 添加一个mmc主机 */
int mmc_add_host(struct mmc_host *host)
{
 int err;

 WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
  !host->ops->enable_sdio_irq);

 led_trigger_register_simple(dev_name(&host->class_dev), &host->led);

 err = device_add(&host->class_dev);  /* 向驱动模型核心添加一个设备 */
 if (err)
  return err;

#ifdef CONFIG_DEBUG_FS
 mmc_add_host_debugfs(host);
#endif

 mmc_start_host(host);  /* 启动主机控制器 */

 return 0;
}

EXPORT_SYMBOL(mmc_add_host);

/**
 * mmc_remove_host - remove host hardware
 * @host: mmc host
 *
 * Unregister and remove all cards associated with this host,
 * and power down the MMC bus. No new requests will be issued
 * after this function has returned.
 */
 /* 移除一个mmc主机控制器 */
void mmc_remove_host(struct mmc_host *host)
{
 mmc_stop_host(host);

#ifdef CONFIG_DEBUG_FS
 mmc_remove_host_debugfs(host);
#endif

 device_del(&host->class_dev); /* 从设备驱动模型核心删除一个设备 */

 led_trigger_unregister_simple(host->led);
}

EXPORT_SYMBOL(mmc_remove_host);

/**
 * mmc_free_host - free the host structure
 * @host: mmc host
 *
 * Free the host once all references to it have been dropped.
 */
 /* 释放主机控制器结构 */
void mmc_free_host(struct mmc_host *host)
{
 spin_lock(&mmc_host_lock);
 idr_remove(&mmc_host_idr, host->index);
 spin_unlock(&mmc_host_lock);

 put_device(&host->class_dev);
}

EXPORT_SYMBOL(mmc_free_host);

 /*************************************************************************************************************************************/
/* mmc.c */

/*
 *  linux/drivers/mmc/core/mmc.c
 *
 *  Copyright (C) 2003-2004 Russell King, All Rights Reserved.
 *  Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
 *  MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved.
 *
 * 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 <linux/err.h>

#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>

#include "core.h"
#include "bus.h"
#include "mmc_ops.h"

static const unsigned int tran_exp[] = {
 10000,  100000,  1000000, 10000000,
 0,  0,  0,  0
};

static const unsigned char tran_mant[] = {
 0, 10, 12, 13, 15, 20, 25, 30,
 35, 40, 45, 50, 55, 60, 70, 80,
};

static const unsigned int tacc_exp[] = {
 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
};

static const unsigned int tacc_mant[] = {
 0, 10, 12, 13, 15, 20, 25, 30,
 35, 40, 45, 50, 55, 60, 70, 80,
};

#define UNSTUFF_BITS(resp,start,size)     \
 ({        \
  const int __size = size;    \
  const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \
  const int __off = 3 - ((start) / 32);   \
  const int __shft = (start) & 31;   \
  u32 __res;      \
         \
  __res = resp[__off] >> __shft;    \
  if (__size + __shft > 32)    \
   __res |= resp[__off-1] << ((32 - __shft) % 32); \
  __res & __mask;      \
 })

/*
 * Given the decoded CSD structure, decode the raw CID to our CID structure.
 */
 /* 解码CID寄存器 */
static int mmc_decode_cid(struct mmc_card *card)
{
 u32 *resp = card->raw_cid;

 /*
  * The selection of the format here is based upon published
  * specs from sandisk and from what people have reported.
  */
 switch (card->csd.mmca_vsn) {
 case 0: /* MMC v1.0 - v1.2 */
 case 1: /* MMC v1.4 */
  card->cid.manfid = UNSTUFF_BITS(resp, 104, 24);
  card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
  card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
  card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
  card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
  card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
  card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8);
  card->cid.prod_name[6] = UNSTUFF_BITS(resp, 48, 8);
  card->cid.hwrev  = UNSTUFF_BITS(resp, 44, 4);
  card->cid.fwrev  = UNSTUFF_BITS(resp, 40, 4);
  card->cid.serial = UNSTUFF_BITS(resp, 16, 24);
  card->cid.month  = UNSTUFF_BITS(resp, 12, 4);
  card->cid.year  = UNSTUFF_BITS(resp, 8, 4) + 1997;
  break;

 case 2: /* MMC v2.0 - v2.2 */
 case 3: /* MMC v3.1 - v3.3 */
 case 4: /* MMC v4 */
  card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
  card->cid.oemid  = UNSTUFF_BITS(resp, 104, 16);
  card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
  card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
  card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
  card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
  card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
  card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8);
  card->cid.serial = UNSTUFF_BITS(resp, 16, 32);
  card->cid.month  = UNSTUFF_BITS(resp, 12, 4);
  card->cid.year  = UNSTUFF_BITS(resp, 8, 4) + 1997;
  break;

 default:
  printk(KERN_ERR "%s: card has unknown MMCA version %d\n",
   mmc_hostname(card->host), card->csd.mmca_vsn);
  return -EINVAL;
 }

 return 0;
}

/*
 * Given a 128-bit response, decode to our card CSD structure.
 */
 /* 解码CSD寄存器 */
static int mmc_decode_csd(struct mmc_card *card)
{
 struct mmc_csd *csd = &card->csd;
 unsigned int e, m, csd_struct;
 u32 *resp = card->raw_csd;

 /*
  * We only understand CSD structure v1.1 and v1.2.
  * v1.2 has extra information in bits 15, 11 and 10.
  */
 csd_struct = UNSTUFF_BITS(resp, 126, 2);
 if (csd_struct != 1 && csd_struct != 2) {
  printk(KERN_ERR "%s: unrecognised CSD structure version %d\n",
   mmc_hostname(card->host), csd_struct);
  return -EINVAL;
 }

 csd->mmca_vsn  = UNSTUFF_BITS(resp, 122, 4);
 m = UNSTUFF_BITS(resp, 115, 4);
 e = UNSTUFF_BITS(resp, 112, 3);
 csd->tacc_ns  = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
 csd->tacc_clks  = UNSTUFF_BITS(resp, 104, 8) * 100;

 m = UNSTUFF_BITS(resp, 99, 4);
 e = UNSTUFF_BITS(resp, 96, 3);
 csd->max_dtr   = tran_exp[e] * tran_mant[m];
 csd->cmdclass   = UNSTUFF_BITS(resp, 84, 12);

 e = UNSTUFF_BITS(resp, 47, 3);
 m = UNSTUFF_BITS(resp, 62, 12);
 csd->capacity   = (1 + m) << (e + 2);

 csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
 csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
 csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
 csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
 csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
 csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
 csd->write_partial = UNSTUFF_BITS(resp, 21, 1);

 return 0;
}

/*
 * Read and decode extended CSD.
 */
 /* 读取并且解码扩展的CSD寄存器 */
static int mmc_read_ext_csd(struct mmc_card *card)
{
 int err;
 u8 *ext_csd;
 unsigned int ext_csd_struct;

 BUG_ON(!card);

 if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
  return 0;

 /*
  * As the ext_csd is so large and mostly unused, we don‘t store the
  * raw block in mmc_card.
  */
 ext_csd = kmalloc(512, GFP_KERNEL);
 if (!ext_csd) {
  printk(KERN_ERR "%s: could not allocate a buffer to "
   "receive the ext_csd.\n", mmc_hostname(card->host));
  return -ENOMEM;
 }

 err = mmc_send_ext_csd(card, ext_csd);
 if (err) {
  /*
   * We all hosts that cannot perform the command
   * to fail more gracefully
   */
  if (err != -EINVAL)
   goto out;

  /*
   * High capacity cards should have this "magic" size
   * stored in their CSD.
   */
  if (card->csd.capacity == (4096 * 512)) {
   printk(KERN_ERR "%s: unable to read EXT_CSD "
    "on a possible high capacity card. "
    "Card will be ignored.\n",
    mmc_hostname(card->host));
  } else {
   printk(KERN_WARNING "%s: unable to read "
    "EXT_CSD, performance might "
    "suffer.\n",
    mmc_hostname(card->host));
   err = 0;
  }

  goto out;
 }

 ext_csd_struct = ext_csd[EXT_CSD_REV];
 if (ext_csd_struct > 3) {
  printk(KERN_ERR "%s: unrecognised EXT_CSD structure "
   "version %d\n", mmc_hostname(card->host),
   ext_csd_struct);
  err = -EINVAL;
  goto out;
 }

 if (ext_csd_struct >= 2) {
  card->ext_csd.sectors =
   ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
   ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
   ext_csd[EXT_CSD_SEC_CNT + 2] << 16 |
   ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
  if (card->ext_csd.sectors)
   mmc_card_set_blockaddr(card);
 }

 switch (ext_csd[EXT_CSD_CARD_TYPE]) {
 case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
  card->ext_csd.hs_max_dtr = 52000000;
  break;
 case EXT_CSD_CARD_TYPE_26:
  card->ext_csd.hs_max_dtr = 26000000;
  break;
 default:
  /* MMC v4 spec says this cannot happen */
  printk(KERN_WARNING "%s: card is mmc v4 but doesn‘t "
   "support any high-speed modes.\n",
   mmc_hostname(card->host));
  goto out;
 }

out:
 kfree(ext_csd);

 return err;
}

MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
 card->raw_cid[2], card->raw_cid[3]);
MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
 card->raw_csd[2], card->raw_csd[3]);
MMC_DEV_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
MMC_DEV_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);

static struct attribute *mmc_std_attrs[] = {
 &dev_attr_cid.attr,
 &dev_attr_csd.attr,
 &dev_attr_date.attr,
 &dev_attr_fwrev.attr,
 &dev_attr_hwrev.attr,
 &dev_attr_manfid.attr,
 &dev_attr_name.attr,
 &dev_attr_oemid.attr,
 &dev_attr_serial.attr,
 NULL,
};

static struct attribute_group mmc_std_attr_group = {
 .attrs = mmc_std_attrs,
};

static struct attribute_group *mmc_attr_groups[] = {
 &mmc_std_attr_group,
 NULL,
};

static struct device_type mmc_type = {
 .groups = mmc_attr_groups,
};

/*
 * Handle the detection and initialisation of a card.
 *
 * In the case of a resume, "oldcard" will contain the card
 * we‘re trying to reinitialise.
 */
 /* 初始化卡 */
static int mmc_init_card(struct mmc_host *host, u32 ocr,
 struct mmc_card *oldcard)
{
 struct mmc_card *card;
 int err;
 u32 cid[4];
 unsigned int max_dtr;

 BUG_ON(!host);
 WARN_ON(!host->claimed);

 /*
  * Since we‘re changing the OCR value, we seem to
  * need to tell some cards to go back to the idle
  * state.  We wait 1ms to give cards time to
  * respond.
  */
 mmc_go_idle(host);  /* 进入空闲模式 */

 /* The extra bit indicates that we support high capacity */
 err = mmc_send_op_cond(host, ocr | (1 << 30), NULL);
 if (err)
  goto err;

 /*
  * For SPI, enable CRC as appropriate.
  */
 if (mmc_host_is_spi(host)) {
  err = mmc_spi_set_crc(host, use_spi_crc);
  if (err)
   goto err;
 }

 /*
  * Fetch CID from card.
  */
 if (mmc_host_is_spi(host))
  err = mmc_send_cid(host, cid);
 else
  err = mmc_all_send_cid(host, cid);
 if (err)
  goto err;

 if (oldcard) {
  if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) {
   err = -ENOENT;
   goto err;
  }

  card = oldcard;
 } else {
  /*
   * Allocate card structure.
   */
  card = mmc_alloc_card(host, &mmc_type);  /*  */
  if (IS_ERR(card)) {
   err = PTR_ERR(card);
   goto err;
  }

  card->type = MMC_TYPE_MMC;
  card->rca = 1;
  memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
 }

 /*
  * For native busses:  set card RCA and quit open drain mode.
  */
 if (!mmc_host_is_spi(host)) {
  err = mmc_set_relative_addr(card);
  if (err)
   goto free_card;

  mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
 }

 if (!oldcard) {
  /*
   * Fetch CSD from card.
   */
  err = mmc_send_csd(card, card->raw_csd);
  if (err)
   goto free_card;

  err = mmc_decode_csd(card);
  if (err)
   goto free_card;
  err = mmc_decode_cid(card);
  if (err)
   goto free_card;
 }

 /*
  * Select card, as all following commands rely on that.
  */
 if (!mmc_host_is_spi(host)) {
  err = mmc_select_card(card);
  if (err)
   goto free_card;
 }

 if (!oldcard) {
  /*
   * Fetch and process extended CSD.
   */
  err = mmc_read_ext_csd(card);
  if (err)
   goto free_card;
 }

 /*
  * Activate high speed (if supported)
  */
 if ((card->ext_csd.hs_max_dtr != 0) &&
  (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
  err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
   EXT_CSD_HS_TIMING, 1);
  if (err)
   goto free_card;

  mmc_card_set_highspeed(card);

  mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
 }

 /*
  * Compute bus speed.
  */
 max_dtr = (unsigned int)-1;

 if (mmc_card_highspeed(card)) {
  if (max_dtr > card->ext_csd.hs_max_dtr)
   max_dtr = card->ext_csd.hs_max_dtr;
 } else if (max_dtr > card->csd.max_dtr) {
  max_dtr = card->csd.max_dtr;
 }

 mmc_set_clock(host, max_dtr);

 /*
  * Activate wide bus (if supported).
  */
 if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
     (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
  unsigned ext_csd_bit, bus_width;

  if (host->caps & MMC_CAP_8_BIT_DATA) {
   ext_csd_bit = EXT_CSD_BUS_WIDTH_8;
   bus_width = MMC_BUS_WIDTH_8;
  } else {
   ext_csd_bit = EXT_CSD_BUS_WIDTH_4;
   bus_width = MMC_BUS_WIDTH_4;
  }

  err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
     EXT_CSD_BUS_WIDTH, ext_csd_bit);

  if (err)
   goto free_card;

  mmc_set_bus_width(card->host, bus_width);
 }

 if (!oldcard)
  host->card = card;

 return 0;

free_card:
 if (!oldcard)
  mmc_remove_card(card);
err:

 return err;
}

/*
 * Host is being removed. Free up the current card.
 */
 /* 移除函数 */
static void mmc_remove(struct mmc_host *host)
{
 BUG_ON(!host);
 BUG_ON(!host->card);

 mmc_remove_card(host->card);  /* 移除卡 */
 host->card = NULL;
}

/*
 * Card detection callback from host.
 */
 /* 探测函数 */
static void mmc_detect(struct mmc_host *host)
{
 int err;

 BUG_ON(!host);
 BUG_ON(!host->card);

 mmc_claim_host(host);  /* 声明一个主机控制器 */

 /*
  * Just check if our card has been removed.
  */
 err = mmc_send_status(host->card, NULL);  /* 发送卡的状态 */

 mmc_release_host(host);  /* 释放主机 */

 if (err) {
  mmc_remove(host);

  mmc_claim_host(host);
  mmc_detach_bus(host);
  mmc_release_host(host);
 }
}

#ifdef CONFIG_MMC_UNSAFE_RESUME

/*
 * Suspend callback from host.
 */
 /* 挂起函数 */
static void mmc_suspend(struct mmc_host *host)
{
 BUG_ON(!host);
 BUG_ON(!host->card);

 mmc_claim_host(host);  /* 声明主机控制器 */
 if (!mmc_host_is_spi(host))
  mmc_deselect_cards(host);
 host->card->state &= ~MMC_STATE_HIGHSPEED;
 mmc_release_host(host);
}

/*
 * Resume callback from host.
 *
 * This function tries to determine if the same card is still present
 * and, if so, restore all state to it.
 */
 /* 恢复函数 */
static void mmc_resume(struct mmc_host *host)
{
 int err;

 BUG_ON(!host);
 BUG_ON(!host->card);

 mmc_claim_host(host);  /* 声明一个主机控制器 */
 err = mmc_init_card(host, host->ocr, host->card);  /* 初始化卡 */
 mmc_release_host(host);  /* 释放主机 */

 if (err) {
  mmc_remove(host);

  mmc_claim_host(host);
  mmc_detach_bus(host);
  mmc_release_host(host);
 }

}

#else

#define mmc_suspend NULL
#define mmc_resume NULL

#endif

static const struct mmc_bus_ops mmc_ops = {  /* 总线操作函数 */
 .remove = mmc_remove,
 .detect = mmc_detect,
 .suspend = mmc_suspend,
 .resume = mmc_resume,
};

/*
 * Starting point for MMC card init.
 */
 /*  */
int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
{
 int err;

 BUG_ON(!host);
 WARN_ON(!host->claimed);

 mmc_attach_bus(host, &mmc_ops);  /* 将主机和总线操作函数绑定 */

 /*
  * We need to get OCR a different way for SPI.
  */
 if (mmc_host_is_spi(host)) {
  err = mmc_spi_read_ocr(host, 1, &ocr);
  if (err)
   goto err;
 }

 /*
  * Sanity check the voltages that the card claims to
  * support.
  */
 if (ocr & 0x7F) {
  printk(KERN_WARNING "%s: card claims to support voltages "
         "below the defined range. These will be ignored.\n",
         mmc_hostname(host));
  ocr &= ~0x7F;
 }

 host->ocr = mmc_select_voltage(host, ocr); /* 选择电压  */

 /*
  * Can we support the voltage of the card?
  */
 if (!host->ocr) {
  err = -EINVAL;
  goto err;
 }

 /*
  * Detect and init the card.
  */
 err = mmc_init_card(host, host->ocr, NULL);  /* 初始化卡 */
 if (err)
  goto err;

 mmc_release_host(host);  /* 释放主机 */

 err = mmc_add_card(host->card);  /* 添加卡 */
 if (err)
  goto remove_card;

 return 0;

remove_card:
 mmc_remove_card(host->card);
 host->card = NULL;
 mmc_claim_host(host);
err:
 mmc_detach_bus(host);
 mmc_release_host(host);

 printk(KERN_ERR "%s: error %d whilst initialising MMC card\n",
  mmc_hostname(host), err);

 return err;
}
/*************************************************************************************************************************************/
/* mmc_ops.c */

/*
 *  linux/drivers/mmc/core/mmc_ops.h
 *
 *  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 as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 */

#include <linux/types.h>
#include <linux/scatterlist.h>

#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>

#include "core.h"
#include "mmc_ops.h"
/* mmc操作函数集 */

 /* 选中卡 */
static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
{
 int err;
 struct mmc_command cmd;

 BUG_ON(!host);

 memset(&cmd, 0, sizeof(struct mmc_command));

 cmd.opcode = MMC_SELECT_CARD;

 if (card) {
  cmd.arg = card->rca << 16;
  cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
 } else {
  cmd.arg = 0;
  cmd.flags = MMC_RSP_NONE | MMC_CMD_AC;
 }

 err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
 if (err)
  return err;

 return 0;
}

/*选中卡 */
int mmc_select_card(struct mmc_card *card)
{
 BUG_ON(!card);

 return _mmc_select_card(card->host, card);
}

/* 取消选中 */
int mmc_deselect_cards(struct mmc_host *host)
{
 return _mmc_select_card(host, NULL);
}

/* 进入空闲模式 */
int mmc_go_idle(struct mmc_host *host)
{
 int err;
 struct mmc_command cmd;

 /*
  * Non-SPI hosts need to prevent chipselect going active during
  * GO_IDLE; that would put chips into SPI mode.  Remind them of
  * that in case of hardware that won‘t pull up DAT3/nCS otherwise.
  *
  * SPI hosts ignore ios.chip_select; it‘s managed according to
  * rules that must accomodate non-MMC slaves which this layer
  * won‘t even know about.
  */
 if (!mmc_host_is_spi(host)) {
  mmc_set_chip_select(host, MMC_CS_HIGH);
  mmc_delay(1);
 }

 memset(&cmd, 0, sizeof(struct mmc_command));

 cmd.opcode = MMC_GO_IDLE_STATE;
 cmd.arg = 0;
 cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;

 err = mmc_wait_for_cmd(host, &cmd, 0);

 mmc_delay(1);

 if (!mmc_host_is_spi(host)) {
  mmc_set_chip_select(host, MMC_CS_DONTCARE);
  mmc_delay(1);
 }

 host->use_spi_crc = 0;

 return err;
}

int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
{
 struct mmc_command cmd;
 int i, err = 0;

 BUG_ON(!host);

 memset(&cmd, 0, sizeof(struct mmc_command));

 cmd.opcode = MMC_SEND_OP_COND;
 cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
 cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;

 for (i = 100; i; i--) {
  err = mmc_wait_for_cmd(host, &cmd, 0);
  if (err)
   break;

  /* if we‘re just probing, do a single pass */
  if (ocr == 0)
   break;

  /* otherwise wait until reset completes */
  if (mmc_host_is_spi(host)) {
   if (!(cmd.resp[0] & R1_SPI_IDLE))
    break;
  } else {
   if (cmd.resp[0] & MMC_CARD_BUSY)
    break;
  }

  err = -ETIMEDOUT;

  mmc_delay(10);
 }

 if (rocr && !mmc_host_is_spi(host))
  *rocr = cmd.resp[0];

 return err;
}

int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
{
 int err;
 struct mmc_command cmd;

 BUG_ON(!host);
 BUG_ON(!cid);

 memset(&cmd, 0, sizeof(struct mmc_command));

 cmd.opcode = MMC_ALL_SEND_CID;
 cmd.arg = 0;
 cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;

 err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);  /* 等待命令发送完成 */
 if (err)
  return err;

 memcpy(cid, cmd.resp, sizeof(u32) * 4);

 return 0;
}

/* 设置相对地址 */
int mmc_set_relative_addr(struct mmc_card *card)
{
 int err;
 struct mmc_command cmd;

 BUG_ON(!card);
 BUG_ON(!card->host);

 memset(&cmd, 0, sizeof(struct mmc_command));

 cmd.opcode = MMC_SET_RELATIVE_ADDR;
 cmd.arg = card->rca << 16;
 cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;

 err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
 if (err)
  return err;

 return 0;
}

static int
mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode)
{
 int err;
 struct mmc_command cmd;

 BUG_ON(!host);
 BUG_ON(!cxd);

 memset(&cmd, 0, sizeof(struct mmc_command));

 cmd.opcode = opcode;
 cmd.arg = arg;
 cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;

 err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
 if (err)
  return err;

 memcpy(cxd, cmd.resp, sizeof(u32) * 4);

 return 0;
}

static int
mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
  u32 opcode, void *buf, unsigned len)
{
 struct mmc_request mrq;
 struct mmc_command cmd;
 struct mmc_data data;
 struct scatterlist sg;
 void *data_buf;

 /* dma onto stack is unsafe/nonportable, but callers to this
  * routine normally provide temporary on-stack buffers ...
  */
 data_buf = kmalloc(len, GFP_KERNEL);
 if (data_buf == NULL)
  return -ENOMEM;

 memset(&mrq, 0, sizeof(struct mmc_request));
 memset(&cmd, 0, sizeof(struct mmc_command));
 memset(&data, 0, sizeof(struct mmc_data));

 mrq.cmd = &cmd;
 mrq.data = &data;

 cmd.opcode = opcode;
 cmd.arg = 0;

 /* NOTE HACK:  the MMC_RSP_SPI_R1 is always correct here, but we
  * rely on callers to never use this with "native" calls for reading
  * CSD or CID.  Native versions of those commands use the R2 type,
  * not R1 plus a data block.
  */
 cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;

 data.blksz = len;
 data.blocks = 1;
 data.flags = MMC_DATA_READ;
 data.sg = &sg;
 data.sg_len = 1;

 sg_init_one(&sg, data_buf, len);

 if (opcode == MMC_SEND_CSD || opcode == MMC_SEND_CID) {
  /*
   * The spec states that CSR and CID accesses have a timeout
   * of 64 clock cycles.
   */
  data.timeout_ns = 0;
  data.timeout_clks = 64;
 } else
  mmc_set_data_timeout(&data, card);

 mmc_wait_for_req(host, &mrq);

 memcpy(buf, data_buf, len);
 kfree(data_buf);

 if (cmd.error)
  return cmd.error;
 if (data.error)
  return data.error;

 return 0;
}

int mmc_send_csd(struct mmc_card *card, u32 *csd)
{
 int ret, i;

 if (!mmc_host_is_spi(card->host))
  return mmc_send_cxd_native(card->host, card->rca << 16,
    csd, MMC_SEND_CSD);

 ret = mmc_send_cxd_data(card, card->host, MMC_SEND_CSD, csd, 16);
 if (ret)
  return ret;

 for (i = 0;i < 4;i++)
  csd[i] = be32_to_cpu(csd[i]);

 return 0;
}

int mmc_send_cid(struct mmc_host *host, u32 *cid)
{
 int ret, i;

 if (!mmc_host_is_spi(host)) {
  if (!host->card)
   return -EINVAL;
  return mmc_send_cxd_native(host, host->card->rca << 16,
    cid, MMC_SEND_CID);
 }

 ret = mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid, 16);
 if (ret)
  return ret;

 for (i = 0;i < 4;i++)
  cid[i] = be32_to_cpu(cid[i]);

 return 0;
}

int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
{
 return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD,
   ext_csd, 512);
}

int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
{
 struct mmc_command cmd;
 int err;

 memset(&cmd, 0, sizeof(struct mmc_command));

 cmd.opcode = MMC_SPI_READ_OCR;
 cmd.arg = highcap ? (1 << 30) : 0;
 cmd.flags = MMC_RSP_SPI_R3;

 err = mmc_wait_for_cmd(host, &cmd, 0);

 *ocrp = cmd.resp[1];
 return err;
}

int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
{
 struct mmc_command cmd;
 int err;

 memset(&cmd, 0, sizeof(struct mmc_command));

 cmd.opcode = MMC_SPI_CRC_ON_OFF;
 cmd.flags = MMC_RSP_SPI_R1;
 cmd.arg = use_crc;

 err = mmc_wait_for_cmd(host, &cmd, 0);
 if (!err)
  host->use_spi_crc = use_crc;
 return err;
}

int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
{
 int err;
 struct mmc_command cmd;

 BUG_ON(!card);
 BUG_ON(!card->host);

 memset(&cmd, 0, sizeof(struct mmc_command));

 cmd.opcode = MMC_SWITCH;
 cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
    (index << 16) |
    (value << 8) |
    set;
 cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;

 err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
 if (err)
  return err;

 return 0;
}

/* 发送卡的状态 */
int mmc_send_status(struct mmc_card *card, u32 *status)
{
 int err;
 struct mmc_command cmd;

 BUG_ON(!card);
 BUG_ON(!card->host);

 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, MMC_CMD_RETRIES);  /* 发送命令并等待它完成 */
 if (err)
  return err;

 /* NOTE: callers are required to understand the difference
  * between "native" and SPI format status words!
  */
 if (status)
  *status = cmd.resp[0];

 return 0;
}

 /*************************************************************************************************************************************/
/* sd.c */

/*
 *  linux/drivers/mmc/core/sd.c
 *
 *  Copyright (C) 2003-2004 Russell King, All Rights Reserved.
 *  SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
 *  Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
 *
 * 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 <linux/err.h>

#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>

#include "core.h"
#include "bus.h"
#include "mmc_ops.h"
#include "sd_ops.h"

static const unsigned int tran_exp[] = {
 10000,  100000,  1000000, 10000000,
 0,  0,  0,  0
};

static const unsigned char tran_mant[] = {
 0, 10, 12, 13, 15, 20, 25, 30,
 35, 40, 45, 50, 55, 60, 70, 80,
};

static const unsigned int tacc_exp[] = {
 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
};

static const unsigned int tacc_mant[] = {
 0, 10, 12, 13, 15, 20, 25, 30,
 35, 40, 45, 50, 55, 60, 70, 80,
};

#define UNSTUFF_BITS(resp,start,size)     \
 ({        \
  const int __size = size;    \
  const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \
  const int __off = 3 - ((start) / 32);   \
  const int __shft = (start) & 31;   \
  u32 __res;      \
         \
  __res = resp[__off] >> __shft;    \
  if (__size + __shft > 32)    \
   __res |= resp[__off-1] << ((32 - __shft) % 32); \
  __res & __mask;      \
 })

/*
 * Given the decoded CSD structure, decode the raw CID to our CID structure.
 */
 /* 解码CID寄存器 */
static void mmc_decode_cid(struct mmc_card *card)
{
 u32 *resp = card->raw_cid;

 memset(&card->cid, 0, sizeof(struct mmc_cid));

 /*
  * SD doesn‘t currently have a version field so we will
  * have to assume we can parse this.
  */
 card->cid.manfid  = UNSTUFF_BITS(resp, 120, 8);
 card->cid.oemid   = UNSTUFF_BITS(resp, 104, 16);
 card->cid.prod_name[0]  = UNSTUFF_BITS(resp, 96, 8);
 card->cid.prod_name[1]  = UNSTUFF_BITS(resp, 88, 8);
 card->cid.prod_name[2]  = UNSTUFF_BITS(resp, 80, 8);
 card->cid.prod_name[3]  = UNSTUFF_BITS(resp, 72, 8);
 card->cid.prod_name[4]  = UNSTUFF_BITS(resp, 64, 8);
 card->cid.hwrev   = UNSTUFF_BITS(resp, 60, 4);
 card->cid.fwrev   = UNSTUFF_BITS(resp, 56, 4);
 card->cid.serial  = UNSTUFF_BITS(resp, 24, 32);
 card->cid.year   = UNSTUFF_BITS(resp, 12, 8);
 card->cid.month   = UNSTUFF_BITS(resp, 8, 4);

 card->cid.year += 2000; /* SD cards year offset */
}

/*
 * Given a 128-bit response, decode to our card CSD structure.
 */
 /* 解码SCD寄存器 */
static int mmc_decode_csd(struct mmc_card *card)
{
 struct mmc_csd *csd = &card->csd;
 unsigned int e, m, csd_struct;
 u32 *resp = card->raw_csd;

 csd_struct = UNSTUFF_BITS(resp, 126, 2);

 switch (csd_struct) {
 case 0:
  m = UNSTUFF_BITS(resp, 115, 4);
  e = UNSTUFF_BITS(resp, 112, 3);
  csd->tacc_ns  = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
  csd->tacc_clks  = UNSTUFF_BITS(resp, 104, 8) * 100;

  m = UNSTUFF_BITS(resp, 99, 4);
  e = UNSTUFF_BITS(resp, 96, 3);
  csd->max_dtr   = tran_exp[e] * tran_mant[m];
  csd->cmdclass   = UNSTUFF_BITS(resp, 84, 12);

  e = UNSTUFF_BITS(resp, 47, 3);
  m = UNSTUFF_BITS(resp, 62, 12);
  csd->capacity   = (1 + m) << (e + 2);

  csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
  csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
  csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
  csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
  csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
  csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
  csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
  break;
 case 1:
  /*
   * This is a block-addressed SDHC card. Most
   * interesting fields are unused and have fixed
   * values. To avoid getting tripped by buggy cards,
   * we assume those fixed values ourselves.
   */
  mmc_card_set_blockaddr(card);

  csd->tacc_ns  = 0; /* Unused */
  csd->tacc_clks  = 0; /* Unused */

  m = UNSTUFF_BITS(resp, 99, 4);
  e = UNSTUFF_BITS(resp, 96, 3);
  csd->max_dtr   = tran_exp[e] * tran_mant[m];
  csd->cmdclass   = UNSTUFF_BITS(resp, 84, 12);

  m = UNSTUFF_BITS(resp, 48, 22);
  csd->capacity     = (1 + m) << 10;

  csd->read_blkbits = 9;
  csd->read_partial = 0;
  csd->write_misalign = 0;
  csd->read_misalign = 0;
  csd->r2w_factor = 4; /* Unused */
  csd->write_blkbits = 9;
  csd->write_partial = 0;
  break;
 default:
  printk(KERN_ERR "%s: unrecognised CSD structure version %d\n",
   mmc_hostname(card->host), csd_struct);
  return -EINVAL;
 }

 return 0;
}

/*
 * Given a 64-bit response, decode to our card SCR structure.
 */
 /* 解码SCR寄存器 */
static int mmc_decode_scr(struct mmc_card *card)
{
 struct sd_scr *scr = &card->scr;
 unsigned int scr_struct;
 u32 resp[4];

 resp[3] = card->raw_scr[1];
 resp[2] = card->raw_scr[0];

 scr_struct = UNSTUFF_BITS(resp, 60, 4);
 if (scr_struct != 0) {
  printk(KERN_ERR "%s: unrecognised SCR structure version %d\n",
   mmc_hostname(card->host), scr_struct);
  return -EINVAL;
 }

 scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
 scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);

 return 0;
}

/*
 * Fetches and decodes switch information
 */
 /* 获取总线宽度 */
static int mmc_read_switch(struct mmc_card *card)
{
 int err;
 u8 *status;

 if (card->scr.sda_vsn < SCR_SPEC_VER_1)
  return 0;

 if (!(card->csd.cmdclass & CCC_SWITCH)) {
  printk(KERN_WARNING "%s: card lacks mandatory switch "
   "function, performance might suffer.\n",
   mmc_hostname(card->host));
  return 0;
 }

 err = -EIO;

 status = kmalloc(64, GFP_KERNEL);
 if (!status) {
  printk(KERN_ERR "%s: could not allocate a buffer for "
   "switch capabilities.\n", mmc_hostname(card->host));
  return -ENOMEM;
 }

 err = mmc_sd_switch(card, 0, 0, 1, status);
 if (err) {
  /*
   * We all hosts that cannot perform the command
   * to fail more gracefully
   */
  if (err != -EINVAL)
   goto out;

  printk(KERN_WARNING "%s: problem reading switch "
   "capabilities, performance might suffer.\n",
   mmc_hostname(card->host));
  err = 0;

  goto out;
 }

 if (status[13] & 0x02)
  card->sw_caps.hs_max_dtr = 50000000;

out:
 kfree(status);

 return err;
}

/*
 * Test if the card supports high-speed mode and, if so, switch to it.
 */
 /* 测试卡是否支持高度模式,如果支持则切换到高速模式 */
static int mmc_switch_hs(struct mmc_card *card)
{
 int err;
 u8 *status;

 if (card->scr.sda_vsn < SCR_SPEC_VER_1)
  return 0;

 if (!(card->csd.cmdclass & CCC_SWITCH))
  return 0;

 if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED))
  return 0;

 if (card->sw_caps.hs_max_dtr == 0)
  return 0;

 err = -EIO;

 status = kmalloc(64, GFP_KERNEL);
 if (!status) {
  printk(KERN_ERR "%s: could not allocate a buffer for "
   "switch capabilities.\n", mmc_hostname(card->host));
  return -ENOMEM;
 }

 err = mmc_sd_switch(card, 1, 0, 1, status);
 if (err)
  goto out;

 if ((status[16] & 0xF) != 1) {
  printk(KERN_WARNING "%s: Problem switching card "
   "into high-speed mode!\n",
   mmc_hostname(card->host));
 } else {
  mmc_card_set_highspeed(card);
  mmc_set_timing(card->host, MMC_TIMING_SD_HS);
 }

out:
 kfree(status);

 return err;
}

MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
 card->raw_cid[2], card->raw_cid[3]);
MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
 card->raw_csd[2], card->raw_csd[3]);
MMC_DEV_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]);
MMC_DEV_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
MMC_DEV_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);


static struct attribute *sd_std_attrs[] = {
 &dev_attr_cid.attr,
 &dev_attr_csd.attr,
 &dev_attr_scr.attr,
 &dev_attr_date.attr,
 &dev_attr_fwrev.attr,
 &dev_attr_hwrev.attr,
 &dev_attr_manfid.attr,
 &dev_attr_name.attr,
 &dev_attr_oemid.attr,
 &dev_attr_serial.attr,
 NULL,
};

static struct attribute_group sd_std_attr_group = {
 .attrs = sd_std_attrs,
};

static struct attribute_group *sd_attr_groups[] = {
 &sd_std_attr_group,
 NULL,
};

static struct device_type sd_type = {
 .groups = sd_attr_groups,
};

/*
 * Handle the detection and initialisation of a card.
 *
 * In the case of a resume, "oldcard" will contain the card
 * we‘re trying to reinitialise.
 */
 /* 探测并初始化SD卡 */
static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
 struct mmc_card *oldcard)
{
 struct mmc_card *card;
 int err;
 u32 cid[4];
 unsigned int max_dtr;

 BUG_ON(!host);
 WARN_ON(!host->claimed);

 /*
  * Since we‘re changing the OCR value, we seem to
  * need to tell some cards to go back to the idle
  * state.  We wait 1ms to give cards time to
  * respond.
  */
 mmc_go_idle(host);  /* 进入空闲模式 */

 /*
  * If SD_SEND_IF_COND indicates an SD 2.0
  * compliant card and we should set bit 30
  * of the ocr to indicate that we can handle
  * block-addressed SDHC cards.
  */
 err = mmc_send_if_cond(host, ocr);
 if (!err)
  ocr |= 1 << 30;

 err = mmc_send_app_op_cond(host, ocr, NULL);
 if (err)
  goto err;

 /*
  * Fetch CID from card.
  */
 if (mmc_host_is_spi(host))
  err = mmc_send_cid(host, cid);
 else
  err = mmc_all_send_cid(host, cid);  /* 读取存储卡的CID寄存器 */
 if (err)
  goto err;

 if (oldcard) {
  if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) {
   err = -ENOENT;
   goto err;
  }

  card = oldcard;
 } else {
  /*
   * Allocate card structure.
   */
  card = mmc_alloc_card(host, &sd_type);
  if (IS_ERR(card)) {
   err = PTR_ERR(card);
   goto err;
  }

  card->type = MMC_TYPE_SD;
  memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
 }

 /*
  * For native busses:  get card RCA and quit open drain mode.
  */
 if (!mmc_host_is_spi(host)) {
  err = mmc_send_relative_addr(host, &card->rca);
  if (err)
   goto free_card;

  mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
 }

 if (!oldcard) {
  /*
   * Fetch CSD from card.
   */
  err = mmc_send_csd(card, card->raw_csd);
  if (err)
   goto free_card;

  err = mmc_decode_csd(card);
  if (err)
   goto free_card;

  mmc_decode_cid(card);
 }

 /*
  * Select card, as all following commands rely on that.
  */
 if (!mmc_host_is_spi(host)) {
  err = mmc_select_card(card);
  if (err)
   goto free_card;
 }

 if (!oldcard) {
  /*
   * Fetch SCR from card.
   */
  err = mmc_app_send_scr(card, card->raw_scr);
  if (err)
   goto free_card;

  err = mmc_decode_scr(card);
  if (err < 0)
   goto free_card;

  /*
   * Fetch switch information from card.
   */
  err = mmc_read_switch(card);
  if (err)
   goto free_card;
 }

 /*
  * For SPI, enable CRC as appropriate.
  * This CRC enable is located AFTER the reading of the
  * card registers because some SDHC cards are not able
  * to provide valid CRCs for non-512-byte blocks.
  */
 if (mmc_host_is_spi(host)) {
  err = mmc_spi_set_crc(host, use_spi_crc);
  if (err)
   goto free_card;
 }

 /*
  * Attempt to change to high-speed (if supported)
  */
 err = mmc_switch_hs(card);
 if (err)
  goto free_card;

 /*
  * Compute bus speed.
  */
 max_dtr = (unsigned int)-1;

 if (mmc_card_highspeed(card)) {
  if (max_dtr > card->sw_caps.hs_max_dtr)
   max_dtr = card->sw_caps.hs_max_dtr;
 } else if (max_dtr > card->csd.max_dtr) {
  max_dtr = card->csd.max_dtr;
 }

 mmc_set_clock(host, max_dtr);

 /*
  * Switch to wider bus (if supported).
  */
 if ((host->caps & MMC_CAP_4_BIT_DATA) &&
  (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
  err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
  if (err)
   goto free_card;

  mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
 }

 /*
  * Check if read-only switch is active.
  */
 if (!oldcard) {
  if (!host->ops->get_ro || host->ops->get_ro(host) < 0) {
   printk(KERN_WARNING "%s: host does not "
    "support reading read-only "
    "switch. assuming write-enable.\n",
    mmc_hostname(host));
  } else {
   if (host->ops->get_ro(host) > 0)
    mmc_card_set_readonly(card);
  }
 }

 if (!oldcard)
  host->card = card;

 return 0;

free_card:
 if (!oldcard)
  mmc_remove_card(card);
err:

 return err;
}

/*
 * Host is being removed. Free up the current card.
 */
 /* 移除函数 */
static void mmc_sd_remove(struct mmc_host *host)
{
 BUG_ON(!host);
 BUG_ON(!host->card);

 mmc_remove_card(host->card);  /* 移除卡 */
 host->card = NULL;
}

/*
 * Card detection callback from host.
 */
 /* 探测函数 */
static void mmc_sd_detect(struct mmc_host *host)
{
 int err;

 BUG_ON(!host);
 BUG_ON(!host->card);

 mmc_claim_host(host);

 /*
  * Just check if our card has been removed.
  */
 err = mmc_send_status(host->card, NULL);

 mmc_release_host(host);

 if (err) {
  mmc_sd_remove(host);

  mmc_claim_host(host);
  mmc_detach_bus(host);
  mmc_release_host(host);
 }
}

#ifdef CONFIG_MMC_UNSAFE_RESUME

/*
 * Suspend callback from host.
 */
 /* 挂起函数 */
static void mmc_sd_suspend(struct mmc_host *host)
{
 BUG_ON(!host);
 BUG_ON(!host->card);

 mmc_claim_host(host);
 if (!mmc_host_is_spi(host))
  mmc_deselect_cards(host);
 host->card->state &= ~MMC_STATE_HIGHSPEED;
 mmc_release_host(host);
}

/*
 * Resume callback from host.
 *
 * This function tries to determine if the same card is still present
 * and, if so, restore all state to it.
 */
 /* 恢复函数 */
static void mmc_sd_resume(struct mmc_host *host)
{
 int err;

 BUG_ON(!host);
 BUG_ON(!host->card);

 mmc_claim_host(host); /* 声明一个主机控制器 */
 err = mmc_sd_init_card(host, host->ocr, host->card);/* 探测并初始化SD卡 */
 mmc_release_host(host); /* 释放主机 */

 if (err) {
  mmc_sd_remove(host);

  mmc_claim_host(host);
  mmc_detach_bus(host);
  mmc_release_host(host);
 }

}

#else

#define mmc_sd_suspend NULL
#define mmc_sd_resume NULL

#endif

static const struct mmc_bus_ops mmc_sd_ops = {  /* SD总线操作函数 */
 .remove = mmc_sd_remove,
 .detect = mmc_sd_detect,
 .suspend = mmc_sd_suspend,
 .resume = mmc_sd_resume,
};

/*
 * Starting point for SD card init.
 */
 /* 依附一个SD卡 */
int mmc_attach_sd(struct mmc_host *host, u32 ocr)
{
 int err;

 BUG_ON(!host);
 WARN_ON(!host->claimed);

 mmc_attach_bus(host, &mmc_sd_ops);  /* 将主机和总线绑定 */

 /*
  * We need to get OCR a different way for SPI.
  */
 if (mmc_host_is_spi(host)) {
  mmc_go_idle(host);

  err = mmc_spi_read_ocr(host, 0, &ocr);
  if (err)
   goto err;
 }

 /*
  * Sanity check the voltages that the card claims to
  * support.
  */
 if (ocr & 0x7F) {
  printk(KERN_WARNING "%s: card claims to support voltages "
         "below the defined range. These will be ignored.\n",
         mmc_hostname(host));
  ocr &= ~0x7F;
 }

 if (ocr & MMC_VDD_165_195) {
  printk(KERN_WARNING "%s: SD card claims to support the "
         "incompletely defined ‘low voltage range‘. This "
         "will be ignored.\n", mmc_hostname(host));
  ocr &= ~MMC_VDD_165_195;
 }

 host->ocr = mmc_select_voltage(host, ocr); /* 选择工作电压 */

 /*
  * Can we support the voltage(s) of the card(s)?
  */
 if (!host->ocr) {
  err = -EINVAL;
  goto err;
 }

 /*
  * Detect and init the card.
  */
 err = mmc_sd_init_card(host, host->ocr, NULL);  /* 探测并初始化SD卡 */
 if (err)
  goto err;

 mmc_release_host(host);  /* 释放主机控制器 */

 err = mmc_add_card(host->card);  /* 添加一个SD卡 */
 if (err)
  goto remove_card;

 return 0;

remove_card:
 mmc_remove_card(host->card);
 host->card = NULL;
 mmc_claim_host(host);
err:
 mmc_detach_bus(host);
 mmc_release_host(host);

 printk(KERN_ERR "%s: error %d whilst initialising SD card\n",
  mmc_hostname(host), err);

 return err;
}

 /*************************************************************************************************************************************/
/* sdio_bus.c */

/*
 *  linux/drivers/mmc/core/sdio_bus.c
 *
 *  Copyright 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 as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * SDIO function driver model
 */

#include <linux/device.h>
#include <linux/err.h>

#include <linux/mmc/card.h>
#include <linux/mmc/sdio_func.h>

#include "sdio_cis.h"
#include "sdio_bus.h"

#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev)
#define to_sdio_driver(d)      container_of(d, struct sdio_driver, drv)

/* show configuration fields */
#define sdio_config_attr(field, format_string)    \
static ssize_t        \
field##_show(struct device *dev, struct device_attribute *attr, char *buf)    \
{         \
 struct sdio_func *func;      \
         \
 func = dev_to_sdio_func (dev);     \
 return sprintf (buf, format_string, func->field);  \
}

sdio_config_attr(class, "0x%02x\n");
sdio_config_attr(vendor, "0x%04x\n");
sdio_config_attr(device, "0x%04x\n");

static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
{
 struct sdio_func *func = dev_to_sdio_func (dev);

 return sprintf(buf, "sdio:c%02Xv%04Xd%04X\n",
   func->class, func->vendor, func->device);
}

static struct device_attribute sdio_dev_attrs[] = {
 __ATTR_RO(class),
 __ATTR_RO(vendor),
 __ATTR_RO(device),
 __ATTR_RO(modalias),
 __ATTR_NULL,
};

static const struct sdio_device_id *sdio_match_one(struct sdio_func *func,
 const struct sdio_device_id *id)
{
 if (id->class != (__u8)SDIO_ANY_ID && id->class != func->class)
  return NULL;
 if (id->vendor != (__u16)SDIO_ANY_ID && id->vendor != func->vendor)
  return NULL;
 if (id->device != (__u16)SDIO_ANY_ID && id->device != func->device)
  return NULL;
 return id;
}

static const struct sdio_device_id *sdio_match_device(struct sdio_func *func,
 struct sdio_driver *sdrv)
{
 const struct sdio_device_id *ids;

 ids = sdrv->id_table;

 if (ids) {
  while (ids->class || ids->vendor || ids->device) {
   if (sdio_match_one(func, ids))
    return ids;
   ids++;
  }
 }

 return NULL;
}

static int sdio_bus_match(struct device *dev, struct device_driver *drv)
{
 struct sdio_func *func = dev_to_sdio_func(dev);
 struct sdio_driver *sdrv = to_sdio_driver(drv);

 if (sdio_match_device(func, sdrv))
  return 1;

 return 0;
}

static int
sdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
 struct sdio_func *func = dev_to_sdio_func(dev);

 if (add_uevent_var(env,
   "SDIO_CLASS=%02X", func->class))
  return -ENOMEM;

 if (add_uevent_var(env, 
   "SDIO_ID=%04X:%04X", func->vendor, func->device))
  return -ENOMEM;

 if (add_uevent_var(env,
   "MODALIAS=sdio:c%02Xv%04Xd%04X",
   func->class, func->vendor, func->device))
  return -ENOMEM;

 return 0;
}

static int sdio_bus_probe(struct device *dev)
{
 struct sdio_driver *drv = to_sdio_driver(dev->driver);
 struct sdio_func *func = dev_to_sdio_func(dev);
 const struct sdio_device_id *id;
 int ret;

 id = sdio_match_device(func, drv);
 if (!id)
  return -ENODEV;

 /* Set the default block size so the driver is sure it‘s something
  * sensible. */
 sdio_claim_host(func);
 ret = sdio_set_block_size(func, 0);
 sdio_release_host(func);
 if (ret)
  return ret;

 return drv->probe(func, id);
}

static int sdio_bus_remove(struct device *dev)
{
 struct sdio_driver *drv = to_sdio_driver(dev->driver);
 struct sdio_func *func = dev_to_sdio_func(dev);

 drv->remove(func);

 if (func->irq_handler) {
  printk(KERN_WARNING "WARNING: driver %s did not remove "
   "its interrupt handler!\n", drv->name);
  sdio_claim_host(func);
  sdio_release_irq(func);
  sdio_release_host(func);
 }

 return 0;
}

static struct bus_type sdio_bus_type = { /*定义总线类型 */
 .name  = "sdio",
 .dev_attrs = sdio_dev_attrs,
 .match  = sdio_bus_match,
 .uevent  = sdio_bus_uevent,
 .probe  = sdio_bus_probe,
 .remove  = sdio_bus_remove,
};

/* 注册SDIO总线 */
int sdio_register_bus(void)
{
 return bus_register(&sdio_bus_type);  /* 注册总线 */
}

/* 注销SDIO总线 */
void sdio_unregister_bus(void)
{
 bus_unregister(&sdio_bus_type);
}

/**
 * sdio_register_driver - register a function driver
 * @drv: SDIO function driver
 */
int sdio_register_driver(struct sdio_driver *drv)  /* 注册SDIO总线驱动 */
{
 drv->drv.name = drv->name;
 drv->drv.bus = &sdio_bus_type;
 return driver_register(&drv->drv);
}
EXPORT_SYMBOL_GPL(sdio_register_driver);

/**
 * sdio_unregister_driver - unregister a function driver
 * @drv: SDIO function driver
 */
void sdio_unregister_driver(struct sdio_driver *drv) /* 注销SDIO总线驱动 */
{
 drv->drv.bus = &sdio_bus_type;
 driver_unregister(&drv->drv);
}
EXPORT_SYMBOL_GPL(sdio_unregister_driver);

static void sdio_release_func(struct device *dev)
{
 struct sdio_func *func = dev_to_sdio_func(dev);

 sdio_free_func_cis(func);

 if (func->info)
  kfree(func->info);

 kfree(func);
}

/*
 * Allocate and initialise a new SDIO function structure.
 */
struct sdio_func *sdio_alloc_func(struct mmc_card *card)
{
 struct sdio_func *func;

 func = kzalloc(sizeof(struct sdio_func), GFP_KERNEL);
 if (!func)
  return ERR_PTR(-ENOMEM);

 func->card = card;

 device_initialize(&func->dev);

 func->dev.parent = &card->dev;
 func->dev.bus = &sdio_bus_type;
 func->dev.release = sdio_release_func;

 return func;
}

/*
 * Register a new SDIO function with the driver model.
 */
int sdio_add_func(struct sdio_func *func)
{
 int ret;

 dev_set_name(&func->dev, "%s:%d", mmc_card_id(func->card), func->num);

 ret = device_add(&func->dev);
 if (ret == 0)
  sdio_func_set_present(func);

 return ret;
}

/*
 * Unregister a SDIO function with the driver model, and
 * (eventually) free it.
 */
void sdio_remove_func(struct sdio_func *func)
{
 if (sdio_func_present(func))
  device_del(&func->dev);

 put_device(&func->dev);
}

 /*************************************************************************************************************************************/
/* sdio_irq.c */

/*
 * linux/drivers/mmc/core/sdio_irq.c
 *
 * Author:      Nicolas Pitre
 * Created:     June 18, 2007
 * Copyright:   MontaVista Software Inc.
 *
 * Copyright 2008 Pierre Ossman
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 */

#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/delay.h>

#include <linux/mmc/core.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sdio_func.h>

#include "sdio_ops.h"

/* 处理SDIO挂起中断 */
static int process_sdio_pending_irqs(struct mmc_card *card)
{
 int i, ret, count;
 unsigned char pending;

 ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending);
 if (ret) {
  printk(KERN_DEBUG "%s: error %d reading SDIO_CCCR_INTx\n",
         mmc_card_id(card), ret);
  return ret;
 }

 count = 0;
 for (i = 1; i <= 7; i++) {
  if (pending & (1 << i)) {
   struct sdio_func *func = card->sdio_func[i - 1];
   if (!func) {
    printk(KERN_WARNING "%s: pending IRQ for "
     "non-existant function\n",
     mmc_card_id(card));
    ret = -EINVAL;
   } else if (func->irq_handler) {
    func->irq_handler(func);
    count++;
   } else {
    printk(KERN_WARNING "%s: pending IRQ with no handler\n",
           sdio_func_id(func));
    ret = -EINVAL;
   }
  }
 }

 if (count)
  return count;

 return ret;
}

/* SDIO中断处理线程 */
static int sdio_irq_thread(void *_host)
{
 struct mmc_host *host = _host;
 struct sched_param param = { .sched_priority = 1 };
 unsigned long period, idle_period;
 int ret;

 sched_setscheduler(current, SCHED_FIFO, &param);

 /*
  * We want to allow for SDIO cards to work even on non SDIO
  * aware hosts.  One thing that non SDIO host cannot do is
  * asynchronous notification of pending SDIO card interrupts
  * hence we poll for them in that case.
  */
 idle_period = msecs_to_jiffies(10);
 period = (host->caps & MMC_CAP_SDIO_IRQ) ?
  MAX_SCHEDULE_TIMEOUT : idle_period;

 pr_debug("%s: IRQ thread started (poll period = %lu jiffies)\n",
   mmc_hostname(host), period);

 do {
  /*
   * We claim the host here on drivers behalf for a couple
   * reasons:
   *
   * 1) it is already needed to retrieve the CCCR_INTx;
   * 2) we want the driver(s) to clear the IRQ condition ASAP;
   * 3) we need to control the abort condition locally.
   *
   * Just like traditional hard IRQ handlers, we expect SDIO
   * IRQ handlers to be quick and to the point, so that the
   * holding of the host lock does not cover too much work
   * that doesn‘t require that lock to be held.
   */
  ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort);
  if (ret)
   break;
  ret = process_sdio_pending_irqs(host->card);
  mmc_release_host(host);

  /*
   * Give other threads a chance to run in the presence of
   * errors.
   */
  if (ret < 0) {
   set_current_state(TASK_INTERRUPTIBLE);
   if (!kthread_should_stop())
    schedule_timeout(HZ);
   set_current_state(TASK_RUNNING);
  }

  /*
   * Adaptive polling frequency based on the assumption
   * that an interrupt will be closely followed by more.
   * This has a substantial benefit for network devices.
   */
  if (!(host->caps & MMC_CAP_SDIO_IRQ)) {
   if (ret > 0)
    period /= 2;
   else {
    period++;
    if (period > idle_period)
     period = idle_period;
   }
  }

  set_current_state(TASK_INTERRUPTIBLE);
  if (host->caps & MMC_CAP_SDIO_IRQ)
   host->ops->enable_sdio_irq(host, 1);
  if (!kthread_should_stop())
   schedule_timeout(period);
  set_current_state(TASK_RUNNING);
 } while (!kthread_should_stop());

 if (host->caps & MMC_CAP_SDIO_IRQ)
  host->ops->enable_sdio_irq(host, 0);

 pr_debug("%s: IRQ thread exiting with code %d\n",
   mmc_hostname(host), ret);

 return ret;
}


static int sdio_card_irq_get(struct mmc_card *card)
{
 struct mmc_host *host = card->host;

 WARN_ON(!host->claimed);

 if (!host->sdio_irqs++) {
  atomic_set(&host->sdio_irq_thread_abort, 0);
  host->sdio_irq_thread =
   kthread_run(sdio_irq_thread, host, "ksdioirqd/%s",
    mmc_hostname(host));
  if (IS_ERR(host->sdio_irq_thread)) {
   int err = PTR_ERR(host->sdio_irq_thread);
   host->sdio_irqs--;
   return err;
  }
 }

 return 0;
}

static int sdio_card_irq_put(struct mmc_card *card)
{
 struct mmc_host *host = card->host;

 WARN_ON(!host->claimed);
 BUG_ON(host->sdio_irqs < 1);

 if (!--host->sdio_irqs) {
  atomic_set(&host->sdio_irq_thread_abort, 1);
  kthread_stop(host->sdio_irq_thread);
 }

 return 0;
}

/**
 * sdio_claim_irq - claim the IRQ for a SDIO function
 * @func: SDIO function
 * @handler: IRQ handler callback
 *
 * Claim and activate the IRQ for the given SDIO function. The provided
 * handler will be called when that IRQ is asserted.  The host is always
 * claimed already when the handler is called so the handler must not
 * call sdio_claim_host() nor sdio_release_host().
 */
 /* 声明中断 */
int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler)
{
 int ret;
 unsigned char reg;

 BUG_ON(!func);
 BUG_ON(!func->card);

 pr_debug("SDIO: Enabling IRQ for %s...\n", sdio_func_id(func));

 if (func->irq_handler) {
  pr_debug("SDIO: IRQ for %s already in use.\n", sdio_func_id(func));
  return -EBUSY;
 }

 ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, &reg);
 if (ret)
  return ret;

 reg |= 1 << func->num;

 reg |= 1; /* Master interrupt enable */

 ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL);
 if (ret)
  return ret;

 func->irq_handler = handler;
 ret = sdio_card_irq_get(func->card);
 if (ret)
  func->irq_handler = NULL;

 return ret;
}
EXPORT_SYMBOL_GPL(sdio_claim_irq);

/**
 * sdio_release_irq - release the IRQ for a SDIO function
 * @func: SDIO function
 *
 * Disable and release the IRQ for the given SDIO function.
 */
 /* 释放中断 */
int sdio_release_irq(struct sdio_func *func)
{
 int ret;
 unsigned char reg;

 BUG_ON(!func);
 BUG_ON(!func->card);

 pr_debug("SDIO: Disabling IRQ for %s...\n", sdio_func_id(func));

 if (func->irq_handler) {
  func->irq_handler = NULL;
  sdio_card_irq_put(func->card);
 }

 ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, &reg);
 if (ret)
  return ret;

 reg &= ~(1 << func->num);

 /* Disable master interrupt with the last function interrupt */
 if (!(reg & 0xFE))
  reg = 0;

 ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL);
 if (ret)
  return ret;

 return 0;
}
EXPORT_SYMBOL_GPL(sdio_release_irq);

【转】linux设备驱动之MMC SD卡——核心层简单分析

标签:

原文地址:http://www.cnblogs.com/wi100sh/p/4336247.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!