1.MMC/SD的热插拔原理:
1)法1: 设置一个定时器去检查
2)法2: 设置拔插中断检测2.
//fs2410 sd卡驱动初始化步骤:
pxamci_init()
-> platform_device_register()
-> driver_register()
-> pxamci_probe()
-> // card detect, GPG10 eint18 and enable pull-up => S3C2410_GPGCON
S3C2410_GPGUP
// enable eint18 filter and both edge int => S3C2410_EXTINT2
// set SDCLK,SDCMD,SDDAT0~SDDAT3 => S3C2410_GPECON
// Enable SDI Clock => S3C2410_CLKCON 1
// Set INIT clock, about 400KHz => S3C2410_SDIPRE 1
// Type B, FIFO reset, clk enable => S3C2410_SDICON 1
// Wait 74SDCLK for MMC card => udelay(200)
// mask all sdi irq => S3C2410_SDIIMSK
//clear all status => S3C2410_SDICSTA
-> INIT_WORK(&card_hotplug_task, card_hotplug, dev)
-> request_irq(IRQ_EINT18, cd_isr)
-> cd_start()
->如果当前没插上卡,则每250ms检测一次是否有插卡动作
如果当前插上sd卡,则每1s去检测一下是否有拔卡动作
8.65.fs2410检测sd卡拔插的原理:
1)硬件上:
GPG10(EINT18)用于SD卡检测:
GPG10=1 //没插入sd卡
GPG10=0 //插入了sd卡2)软件上:
a)EINT18用于检测sd卡的拔插动作,当有sd卡拔插动作时会产生一个EINT18中断
(both edge int)而EINT18中断服务程序开始启动sd卡拔插检测定时器cd_func()
b)定时器检测sd卡的插拔动作的过程 : cd_func()
=>当检测到有sd卡插拔动作就唤醒任务 : card_hotplug() 进行插卡初始化处理 或者
拔卡注销处理 过程=> 具体代码实现如下:
static void cd_func(unsigned long data)
{
u16 r, i; r = readl(S3C2410_GPGDAT) & (1 << 10);/*检测出sd卡的当前状态 : 假设为插入*/
for (i = 0; i < 5; i++) /*为了防抖动,因此重试5次连续检查
是否真的为插入动作*/
if (r != (readl(S3C2410_GPGDAT) & (1 << 10)))
{
// 在这瞬间发生了sd相反的插拔事件
cd_lst = -1;
mod_timer(&cd_timer, jiffies + HZ / 100); /*10ms后再次检查*/
return;
} //前面5次检测sd卡拔插状态都一致,则继续往下运行
r = r ? 0 : 1;
cd_cnt++;
if (r != cd_lst)
{
cd_lst = r; /*保存好当前的sd卡拔插状态:假设为插入, cd_lst=1*/
cd_cnt = 0; /*sd卡新状态的第一次检测, 为了防抖动,后面每隔10ms连续检测
20次以确认真的是插卡动作*/
} if (cd_cnt < 20)
{
mod_timer(&cd_timer, jiffies + HZ / 100); /*在200ms内检测了20次*/
}
else
{ /*每隔10ms连续检测20次状态都一致,确实是插卡动作,因此停止掉定时器,唤醒
任务开始sd卡初始化动作并再次使能sd卡检测中断EINT18*/
del_timer_sync(&cd_timer);
if (cd_sta != r)
{
cd_sta = r;
schedule_work(&card_hotplug_task);
}
enable_irq(IRQ_EINT18);
}
}
c)
static u8 cd_sta; // 1:插入sd卡, 0:拔下sd卡
static u8 cd_lst; // 保存前一次的sd卡插入状态
static u16 cd_cnt;cd_sta的改变位置和条件:
cd_sta仅在函数cd_func()里改变状态d)card_hotplug()被唤醒后,其初始化过程如下:
//fs2410插入sd卡的初始化过程:
card_hotplug()
-> card_insert()
-> to_platform_device() // 获得平台相关的sd卡控制器资源(IO/IRQ资源)
-> platform_device_resource() // 获得IO资源
-> platform_device_irq() // 获得IRQ资源
-> mmc_alloc_host()
-> //初始化结构pxamci_host
-> INIT_WORK(&host->detect, mmc_rescan, host);
-> pxamci_stop_clock() // 停止sd卡时钟
-> request_irq(IRQ_SDI, pxamci_irq)
-> request_irq(IRQ_DMA0, pxamci_dma_irq)
-> dev_set_drvdata()
-> mmc_add_host()
-> mmc_power_off()
-> mmc_detect_change()
-> 唤醒挂在任务队列host->detect 上的任务mmc_rescan()
schedule_work(&host->detect) mmc_alloc_host()
-> INIT_WORK(&host->detect, mmc_rescan, host);
-> mmc_add_host()/schedule_work(&host->detect)
-> kthread()
-> worker_thread()
-> mmc_rescan()
-> mmc_rescan()
-> mmc_claim_host()
-> mmc_setup()
-> mmc_power_up() // 这里讨论第一次初始化刚插入sd卡的流程
-> host->ops->set_ios()
pxamci_set_ios() // 设置bus_mode = MMC_BUSMODE_OPENDRAIN,
// power_mode = MMC_POWER_UP
-> mmc_delay(1);
clock = host->f_min
power_mode = MMC_POWER_ON
-> mmc_delay(2)
-> mmc_send_op_cond()
-> mmc_select_voltage()
-> mmc_send_op_cond()
-> mmc_discover_cards()
-> mmc_decode_cid()
-> mmc_read_csds()
-> mmc_decode_csd()
-> list_empty()
-> mmc_release_host(host)
-> list_for_each_safe()
-> mmc_list_to_card()
-> mmc_card_present() & mmc_card_dead()
-> mmc_register_card()
-> device_add()
-> bus_add_device()
-> device_attach()
-> bus_match()
-> mmc_drv_probe()
-> drv->probe()
mmc_blk_probe()
-> add_disk()
-> register_disk()
-> check_partition()
-> blk_register_queue()
-> device_create_file()
kthread()
-> worker_thread()
-> mmc_rescan()
-> mmc_register_card()
-> device_add()
-> bus_add_device()
-> device_attach()
-> bus_match()
-> mmc_blk_probe()pxamci_request()
-> pxamci_setup_data()
-> pxamci_start_cmd() static struct resource s3c2410_sdi_resources[] =
{
[0] =
{
.start = S3C2410_VA_SDI,
.end = S3C2410_VA_SDI + 0x100 - 1,
.flags = IORESOURCE_MEM,
},
[1] =
{
.start = IRQ_SDI,
.end = IRQ_SDI,
.flags = IORESOURCE_IRQ,
},
};3.Linux 块设备io请求的处理步骤:
1.每个块驱动程序至少拥有一个 I/O 请求队列。在任意给定时刻,该队列包含了内核
想在该驱动程序的设备上完成的所有 I/0 操作。
1)每个设备有一个默认使用的请求队列
2)块驱动程序中最重要的函数就是request 函数,该函数执行数据读写相关的底层操作
1.1
而每一个MMC卡是看作几个分区来使用的,表征一张MMC卡设备的一个分区的信息放在
结构:hd_struct
2.关于MMC卡块设备的请求队列:
1)请求队列初始化在 : mmc_media.c/mmc_media_init()/
//blk_init_queue(BLK_DEFAULT_QUEUE(mmc_major), DEVICE_REQUEST); Line487
#define DEVICE_REQUEST mmc_media_request
故MMC卡的请求队列处理函数为:mmc_media_request()
4.fs2410mmc卡驱动注册为块设备的步骤/初始化IO请求队列的步骤/io请求的处理步骤:
当要读取块设备(这里以sd卡为例)上的数据时,会调用到__bread()函数, 然后linux内核
会向sd卡设备产生一个io请求.因此块设备操作函数__generic_unplug_device()就调用到
sd卡驱动提供的io请求处理函数mmc_request(),mmc_request()唤醒等在等待队列
md->thread_wq 上的任务 -> mmc_queue_thread(),而mmc_queue_thread()会调用
mq->issue_fn()即mmc_blk_issue_rq(),从而开始一整个io请求的处理过程
mmc_blk_issue_rq(),如下所示:
=>如下所示:
mmc_request()
-> req = elv_next_request(q)
mmc_blk_issue_rq()
-> mmc_card_claim_host()
->
DECLARE_WAITQUEUE(wait, current);
add_wait_queue(&host->wq, &wait);
-> mmc_wait_for_cmd()
-> MMC_BLK_RQ_LED_START() // for test
-> mmc_wait_for_req()
-> mmc_start_request()
-> .request()
pxamci_request()
-> pxamci_stop_clock() // why? /*clock type is MMC type?*/
-> pxamci_start_cmd()
-> writel(0x1e00, S3C2410_SDICSTA) //clear cmd status
-> writel(host->clkrt, S3C2410_SDIPRE) //set clock rate
-> writel(FIFO_TYPE | 1, S3C2410_SDICON); //Type A, enable clock
-> pxamci_enable_irq()
-> MMC_BLK_RQ_LED_STOP() // for test
-> mmc_card_release_host() // Release a MMC host, allowing others to claim the
// host for their operations.
-> host->card_busy = NULL
-> wake_up(&host->wq) mmc_blk_init()
-> register_blkdev()
-> devfs_mk_dir()
-> mmc_register_driver(&mmc_driver)
-> mmc_blk_probe()
-> mmc_blk_alloc()
-> find_first_zero_bit()
-> kmalloc(sizeof(struct mmc_blk_data))
-> alloc_disk()
-> mmc_init_queue()
-> blk_init_queue(mmc_request)
-> blk_queue_prep_rq(mmc_prep_request)
-> blk_queue_bounce_limit()
-> init_waitqueue_head(&mq->thread_wq)
-> kernel_thread(mmc_queue_thread)
-> init_completion()
-> blk_queue_max_sectors()
-> blk_queue_hardsect_size()
-> set_capacity()
-> mmc_blk_set_blksize()
-> mmc_set_drvdata()
-> add_disk(md->disk) 5.MMC卡的存储介质组织:
寻址的单位为字节
每512字节组成一个块,称为扇区。每个扇区可以独立的读取,写入,和擦除。6 SD/mmc卡的挂载.
mount -t vfat /dev/mmcblk0 /tmp // ok
mount -t vfat -o codepage=936,iocharset=cp936 /dev/mmcblk0 /tmp // ok,支持简体中文
Android sim卡热插拔拔掉事件
转载本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。
上一篇:MySQL显示标题列
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
Android热插拔事件处理流程
一、Android热插拔事件处理流程图Android热插拔事件处理流程如下图所示: 二、组成1. NetlinkManager: 全称是NetlinkManag
android vold mountservice storagemanager sd -
android sim卡插拔监听
package com.water.activity; import java.util.List; import android.app.Activity; import android.os.Bundle; import android.telephony.CellLocation; import android.telephony.NeighboringCe
android sim卡插拔监听 android监控sim卡有没有服务示例 android 数据连接 移动终端 -
Debezium从mysql到pg
操作数据表6.1 创建数据表创建数据表使用 CREATE TABLE
Debezium从mysql到pg 创建数据表 修改表结构 查看表结构 字段