Linux의 mmc 드라이버 개요
(Kernel 버전은 4.1을 기반으로 작성되었습니다)
소개
mmc 드라이버는 Linux의 저장 장치 드라이버 중 하나입니다.
eMMC나 SD카드등의 디바이스를 Linux로 취급하기 위한 드라이버가 되고 있습니다.
다음과 같은 처리를 담당하고 있습니다.
mmc 드라이버의 구조
mmc 드라이버의 소스는 아래에 저장됩니다.
(Kernelソースディレクトリ)
└ drivers
└ mmc
├ card
├ core
└ host
mmc 드라이버는 아래 그림과 같이 구성되어 있습니다.
mmc 블록 큐 드라이버
이 부분에서는, 상위의 블록 I/O 처리부로부터 받은 요구를, 큐 드라이버가 큐로 관리합니다.
그리고, 블록 드라이버는 큐로부터 픽업 된 요구의 타입 (read,write,erase 등)을 해석해, 한층 더 아래의 mmc 코어부에 건네줍니다.
mmc 코어, SD 카드/eMMC 처리부
mmc 코어부는 상위로부터 받은 요구의 대상이, SD 카드인지 eMMC인지를 판별하고, SD 카드/eMMC 처리부에 요구를 건네줍니다.
SD 카드와 eMMC에서는 카드의 인식이나 스피드 모드의 설정 등, 세세한 부분에서 처리가 다르기 때문에, SD 카드/eMMC 처리부에서, 상위로부터의 요구를 각각에 대응한 처리로 바꾸어, 하위의 SD 호스트 컨트롤러 공통 처리부나 모델 종속부의 구현을 호출하여 호스트 컨트롤러를 제어합니다.
SD 호스트 컨트롤러 공통 처리부/기종 의존부
SD 호스트 컨트롤러의 레지스터를 두드려 조작하고 있는 부분이 여기가 됩니다.
SD 호스트 컨트롤러는 규격화되어 있어 레지스터 구조 등은 기본적으로 동일하게 되어 있으므로, 규격에 따른 기종을 사용하고 있는 경우는 거의 공통 처리부에서 처리할 수 있습니다.
기종 의존부는, 하드의 초기화나, 그 이름대로 기종에 의해 공통 처리부에서는 대응할 수 없는 처리를 담당합니다.
mmc 드라이버에서는, 기종 의존의 처리를 공통부에 건네주기 위해서, 이하의 2개의 구조체가 준비되어 있습니다. 각 멤버에는 공통 처리부에서 구현되는 함수를 사용할지, 모델 종속부에서 구현하는 함수를 사용할지를 선택할 수 있습니다.
include/linux/mmc/host.hstruct mmc_host_ops {
/*
* It is optional for the host to implement pre_req and post_req in
* order to support double buffering of requests (prepare one
* request while another request is active).
* pre_req() must always be followed by a post_req().
* To undo a call made to pre_req(), call post_req() with
* a nonzero err condition.
*/
void (*post_req)(struct mmc_host *host, struct mmc_request *req,
int err);
void (*pre_req)(struct mmc_host *host, struct mmc_request *req,
bool is_first_req);
void (*request)(struct mmc_host *host, struct mmc_request *req);
/*
* Avoid calling these three functions too often or in a "fast path",
* since underlaying controller might implement them in an expensive
* and/or slow way.
*
* Also note that these functions might sleep, so don't call them
* in the atomic contexts!
*
* Return values for the get_ro callback should be:
* 0 for a read/write card
* 1 for a read-only card
* -ENOSYS when not supported (equal to NULL callback)
* or a negative errno value when something bad happened
*
* Return values for the get_cd callback should be:
* 0 for a absent card
* 1 for a present card
* -ENOSYS when not supported (equal to NULL callback)
* or a negative errno value when something bad happened
*/
void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
int (*get_ro)(struct mmc_host *host);
int (*get_cd)(struct mmc_host *host);
void (*enable_sdio_irq)(struct mmc_host *host, int enable);
/* optional callback for HC quirks */
void (*init_card)(struct mmc_host *host, struct mmc_card *card);
int (*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios);
/* Check if the card is pulling dat[0:3] low */
int (*card_busy)(struct mmc_host *host);
/* The tuning command opcode value is different for SD and eMMC cards */
int (*execute_tuning)(struct mmc_host *host, u32 opcode);
/* Prepare HS400 target operating frequency depending host driver */
int (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
int (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
void (*hw_reset)(struct mmc_host *host);
void (*card_event)(struct mmc_host *host);
/*
* Optional callback to support controllers with HW issues for multiple
* I/O. Returns the number of supported blocks for the request.
*/
int (*multi_io_quirk)(struct mmc_card *card,
unsigned int direction, int blk_size);
};
drivers/mmc/host/sdhci.hstruct sdhci_ops {
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
u32 (*read_l)(struct sdhci_host *host, int reg);
u16 (*read_w)(struct sdhci_host *host, int reg);
u8 (*read_b)(struct sdhci_host *host, int reg);
void (*write_l)(struct sdhci_host *host, u32 val, int reg);
void (*write_w)(struct sdhci_host *host, u16 val, int reg);
void (*write_b)(struct sdhci_host *host, u8 val, int reg);
#endif
void (*set_clock)(struct sdhci_host *host, unsigned int clock);
int (*enable_dma)(struct sdhci_host *host);
unsigned int (*get_max_clock)(struct sdhci_host *host);
unsigned int (*get_min_clock)(struct sdhci_host *host);
unsigned int (*get_timeout_clock)(struct sdhci_host *host);
unsigned int (*get_max_timeout_count)(struct sdhci_host *host);
void (*set_timeout)(struct sdhci_host *host,
struct mmc_command *cmd);
void (*set_bus_width)(struct sdhci_host *host, int width);
void (*platform_send_init_74_clocks)(struct sdhci_host *host,
u8 power_mode);
unsigned int (*get_ro)(struct sdhci_host *host);
void (*reset)(struct sdhci_host *host, u8 mask);
int (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode);
void (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
void (*hw_reset)(struct sdhci_host *host);
void (*adma_workaround)(struct sdhci_host *host, u32 intmask);
void (*platform_init)(struct sdhci_host *host);
void (*card_event)(struct sdhci_host *host);
void (*voltage_switch)(struct sdhci_host *host);
};
이러한 구조로 되어 있기 때문에, 드라이버 개발자는 공통부에 손을 넣지 않고, 기종 의존부만을 기술하는 것으로 드라이버의 실장을 할 수 있게 되어 있습니다.
참고 자료
Linux Kernel MMC Storage driver Overview
htps //w w. s에서 멋지다. 네 t / 라 m ぃ 라 j / ぃ ん x 케 r 네 루 m ㎝ s 라 게 d ゔ ぇ r ゔ ぇ r ゔ ぃ
Reference
이 문제에 관하여(Linux의 mmc 드라이버 개요), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/yu_ura/items/1970d8c8f6275cc61ca3
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
(Kernelソースディレクトリ)
└ drivers
└ mmc
├ card
├ core
└ host
struct mmc_host_ops {
/*
* It is optional for the host to implement pre_req and post_req in
* order to support double buffering of requests (prepare one
* request while another request is active).
* pre_req() must always be followed by a post_req().
* To undo a call made to pre_req(), call post_req() with
* a nonzero err condition.
*/
void (*post_req)(struct mmc_host *host, struct mmc_request *req,
int err);
void (*pre_req)(struct mmc_host *host, struct mmc_request *req,
bool is_first_req);
void (*request)(struct mmc_host *host, struct mmc_request *req);
/*
* Avoid calling these three functions too often or in a "fast path",
* since underlaying controller might implement them in an expensive
* and/or slow way.
*
* Also note that these functions might sleep, so don't call them
* in the atomic contexts!
*
* Return values for the get_ro callback should be:
* 0 for a read/write card
* 1 for a read-only card
* -ENOSYS when not supported (equal to NULL callback)
* or a negative errno value when something bad happened
*
* Return values for the get_cd callback should be:
* 0 for a absent card
* 1 for a present card
* -ENOSYS when not supported (equal to NULL callback)
* or a negative errno value when something bad happened
*/
void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
int (*get_ro)(struct mmc_host *host);
int (*get_cd)(struct mmc_host *host);
void (*enable_sdio_irq)(struct mmc_host *host, int enable);
/* optional callback for HC quirks */
void (*init_card)(struct mmc_host *host, struct mmc_card *card);
int (*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios);
/* Check if the card is pulling dat[0:3] low */
int (*card_busy)(struct mmc_host *host);
/* The tuning command opcode value is different for SD and eMMC cards */
int (*execute_tuning)(struct mmc_host *host, u32 opcode);
/* Prepare HS400 target operating frequency depending host driver */
int (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
int (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
void (*hw_reset)(struct mmc_host *host);
void (*card_event)(struct mmc_host *host);
/*
* Optional callback to support controllers with HW issues for multiple
* I/O. Returns the number of supported blocks for the request.
*/
int (*multi_io_quirk)(struct mmc_card *card,
unsigned int direction, int blk_size);
};
struct sdhci_ops {
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
u32 (*read_l)(struct sdhci_host *host, int reg);
u16 (*read_w)(struct sdhci_host *host, int reg);
u8 (*read_b)(struct sdhci_host *host, int reg);
void (*write_l)(struct sdhci_host *host, u32 val, int reg);
void (*write_w)(struct sdhci_host *host, u16 val, int reg);
void (*write_b)(struct sdhci_host *host, u8 val, int reg);
#endif
void (*set_clock)(struct sdhci_host *host, unsigned int clock);
int (*enable_dma)(struct sdhci_host *host);
unsigned int (*get_max_clock)(struct sdhci_host *host);
unsigned int (*get_min_clock)(struct sdhci_host *host);
unsigned int (*get_timeout_clock)(struct sdhci_host *host);
unsigned int (*get_max_timeout_count)(struct sdhci_host *host);
void (*set_timeout)(struct sdhci_host *host,
struct mmc_command *cmd);
void (*set_bus_width)(struct sdhci_host *host, int width);
void (*platform_send_init_74_clocks)(struct sdhci_host *host,
u8 power_mode);
unsigned int (*get_ro)(struct sdhci_host *host);
void (*reset)(struct sdhci_host *host, u8 mask);
int (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode);
void (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
void (*hw_reset)(struct sdhci_host *host);
void (*adma_workaround)(struct sdhci_host *host, u32 intmask);
void (*platform_init)(struct sdhci_host *host);
void (*card_event)(struct sdhci_host *host);
void (*voltage_switch)(struct sdhci_host *host);
};
Linux Kernel MMC Storage driver Overview
htps //w w. s에서 멋지다. 네 t / 라 m ぃ 라 j / ぃ ん x 케 r 네 루 m ㎝ s 라 게 d ゔ ぇ r ゔ ぇ r ゔ ぃ
Reference
이 문제에 관하여(Linux의 mmc 드라이버 개요), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/yu_ura/items/1970d8c8f6275cc61ca3텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)