当前位置:首页 > CN2资讯 > 正文内容

linux resolve命令 linux rescan

2天前CN2资讯


废话不多说,直接切进主题:

       Linux在内核源码的drivers/mmc/core文件夹下为我们的提供了一系列SD卡的接口服务函数。可以查看Makefile如下


可见,core文件夹下有针对总线的服务bus.c,针对主控制器的服务host.c,针对SD卡的服务sd.c, sd_ops.c等等。

其中,最为核心的一个函数便是之前提到的位于core.c的mmc_rescan,概括来讲,主要完成两项任务,即

扫描SD总线,插入SD卡
扫描SD总线,拔出SD卡

一、 插入SD卡

        前面HOST篇最后的中断篇中讲到,插入SD卡,主控制器产生中断,进入中断处理函数s3cmci_irq_cd,其中调用的函数 mmc_detect_change,它将最终调用queue_delayed_work执行工作队列里的mmc_rescan函数

下面来看看 mmc_rescan


[cpp]  view plain  copy


 


1. void mmc_rescan(struct work_struct *work) 2. { 3. struct mmc_host *host = 4. struct mmc_host, detect.work); 5. int i; 6. 7. if (host->rescan_disable) 8. return; 9. 10. /* If there is a non-removable card registered, only scan once */ 11. if ((host->caps & MMC_CAP_NONREMOVABLE) && host->rescan_entered) 12. return; 13. host->rescan_entered = 1; 14. 15. mmc_bus_get(host); 16. 17. /* 18. * if there is a _removable_ card registered, check whether it is 19. * still present 20. */ 21. if (host->bus_ops && host->bus_ops->detect && !host->bus_dead 22. && !(host->caps & MMC_CAP_NONREMOVABLE)) 23. host->bus_ops->detect(host); 24. 25. host->detect_change = 0; 26. 27. /* 28. * Let mmc_bus_put() free the bus/bus_ops if we've found that 29. * the card is no longer present. 30. */ 31. mmc_bus_put(host); 32. mmc_bus_get(host); 33. 34. /* if there still is a card present, stop here */ 35. if (host->bus_ops != NULL) { 36. mmc_bus_put(host); 37. goto out; 38. } 39. 40. /* 41. * Only we can add a new handler, so it's safe to 42. * release the lock here. 43. */ 44. mmc_bus_put(host); 45. 46. if (!(host->caps & MMC_CAP_NONREMOVABLE) && host->ops->get_cd && 47. host->ops->get_cd(host) == 0) { 48. mmc_claim_host(host); 49. mmc_power_off(host); 50. mmc_release_host(host); 51. goto out; 52. } 53. 54. mmc_claim_host(host); 55. for (i = 0; i < ARRAY_SIZE(freqs); i++) { 56. if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) 57. break; 58. if (freqs[i] <= host->f_min) 59. break; 60. } 61. mmc_release_host(host); 62. 63. out: 64. if (host->caps & MMC_CAP_NEEDS_POLL) 65. mmc_schedule_delayed_work(&host->detect, HZ); 66. }


具体的实现方法就是通过向SD卡上电,看是否能成功,以普通SD卡为例,为普通SD卡上电的函数mmc_send_app_op_cond(host, 0, &ocr);

执行if()里的mmc_attach_sd()进行总线与SD卡的绑定

如果上电失败,则返回非0值,跳过if(),尝试其他上电的方法。

     那么,上电方法究竟有何不同呢?具体看看mmc_send_app_op_cond()的实现过程


[cpp]  view plain  copy


 

1. int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) 2. { 3. struct mmc_command cmd; 4. /* #define SD_APP_OP_COND 41 */ 5. mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES); 6. 7. ... ... 8. 9. }

[cpp]  view plain  copy


 


  • 1. int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, struct mmc_command *cmd, int retries) 2. { 3. 4. /* #define MMC_APP_CMD 55 */ 5. mrq.cmd = cmd; 6. cmd->data = NULL; 7. 8. mmc_wait_for_req(host, &mrq); 9. 10. ... ... 11. 12. }


    这里的指令SD_APP_OP_COND只有SD2.0的协议支持,也就是说,只有普通SD卡支持,所以也只有普通SD卡能够成功上电。 

                 

    如果上电成功,就开始进行总线与SD卡的绑定,通过mmc_attach_sd(),绑定过程可分为四步,

    注册SD总线上的操作函数 - struct mmc_bus_ops mmc_sd_ops

    设置主控制器的时钟和总线方式 - 通过回调函数host->ops->set_ios();

    启动SD卡 - 根据协议,完成SD卡启动的各个步骤

    注册SD卡设备驱动


    二、注册总线上的操作函数


    [cpp]  view plain  copy


     

    1. int mmc_attach_sd(struct mmc_host *host, u32 ocr) 2. { 3. mmc_sd_attach_bus_ops(host); 4. 5. ... ... 6. 7. }


    [cpp]  view plain  copy


     

    1. static void mmc_sd_attach_bus_ops(struct mmc_host *host) 2. { 3. const struct mmc_bus_ops *bus_ops; 4. 5. bus_ops = &mmc_sd_ops; 6. mmc_attach_bus(host, bus_ops); 7. }


    [cpp]  view plain  copy


     


  • 1. void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops) 2. { 3. host->bus_ops = ops; 4. host->bus_refs = 1; 5. host->bus_dead = 0; 6. }


    [cpp]  view plain  copy


     


  • 1. static const struct mmc_bus_ops mmc_sd_ops = { 2. // 拔出SD卡的操作函数 3. // 探测SD卡的操作函数 4. .suspend = NULL, 5. .resume = NULL, 6. // 重新启动SD卡的操作函数 7. };


         这里的mmc_sd_detect和mmc_sd_remove就是拔出SD卡所需要用到的函数,下文将详细讨论。这里需要注意的是,插入SD卡的时候,并不执行mmc_sd_detect和mmc_sd_remove这两个函数,但是会注册它们,也就是说,这两个函数的功能已经实现,将来可以使用。

    三、设置时钟和总线


    [cpp]  view plain  copy


     

    1. int mmc_attach_sd(struct mmc_host *host, u32 ocr) 2. { 3. host->ocr = mmc_select_voltage(host, ocr); 4. 5. ... ... 6. 7. } 8. 9. u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) 10. { 11. mmc_set_ios(host); 12. 13. ... ... 14. } 15. 16. static inline void mmc_set_ios(struct mmc_host *host) 17. { 18. struct mmc_ios *ios = &host->ios; 19. 20. // 设置主控制器时钟和总线的回调函数,具体实现由主控制器驱动完成 21. }

        从这里可以体会到回调函数的精髓:协议层里利用回调函数为所有满足该协议的设备提供统一的接口,而具体实现由底层不同的设备驱动各自完成。注意到,之所以要定义一些放之四海而皆准的公用的类,比如struct mmc_host,就是需要通过struct mmc_host *host指针作为形参传到协议层所提供的接口函数中,从而得以调用。


    四、启动SD卡


    [cpp]  view plain  copy


     


    1. int mmc_attach_sd(struct mmc_host *host, u32 ocr) 2. { 3. 4. mmc_sd_init_card(host, host->ocr, NULL); 5. 6. ... ... 7. 8. }


     mmc_sd_init_card主要完成以下任务,

    SD卡的启动过程
    得到寄存器CID, CSD, SCR, RCA的数据
    其他操作比如切换到高速模式,初始化card



    [cpp]  view plain  copy


     

    1. static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, struct mmc_card *oldcard) 2. { 3. 4. /* SD卡的启动过程 */ 5. mmc_go_idle(host); 6. mmc_send_if_cond(host, ocr); 7. mmc_send_app_op_cond(host, ocr, NULL); 8. mmc_all_send_cid(host, cid); 9. mmc_send_relative_addr(host, &card->rca); 10. 11. /* 得到寄存器CID, CSD, SCR的数据 */ 12. mmc_send_csd(card, card->raw_csd); 13. mmc_decode_csd(card); 14. mmc_decode_cid(card); 15. mmc_app_send_scr(card, card->raw_scr); 16. mmc_decode_scr(card); 17. 18. /* 其它操作 */ 19. mmc_alloc_card(host, &sd_type); 20. mmc_select_card(card); 21. mmc_read_switch(card); 22. mmc_switch_hs(card); 23. ... ... 24. 25. }


    1) SD卡的启动过程

        根据SD2.0协议,SD卡的状态可分为两种模式:卡识别模式(card-identification mode)和数据传输模式(data-transfer mode)。这里,我们关注启动SD卡的卡识别模式。


    综合代码:


    [cpp]  view plain  copy


     

    1. mmc_go_idle(host); CMD0 2. Idle State 3. mmc_send_if_cond(host, ocr); CMD8 4. mmc_send_app_op_cond(host, ocr, NULL); ACMD41 5. Ready State 6. mmc_all_send_cid(host, cid); CMD2 7. Identification State 8. mmc_send_relative_addr(host, &card->rca); CMD3 9. Stand-by State


    2) 寄存器CID, CSD, SCR, RCA

    -> 发送指令并得到寄存器的值

       当主控制器向SD卡发送cmd指令,比如mmc_send_cid(card, card->raw_cid),请求得到SD卡CID寄存器的值,当主控制器发送cmd完成后,芯片产生一个内部中断,处理结束cmd的中断函数,之后得到来自SD卡的response,即CID寄存器的值,存放于host->cmd->resp[i]中。关于内部中断处理,参看上文的中断一节里的 mmc_wait_for_cmd()

       mmc_send_cid(card, card->raw_cid);这个函数发送了接收CSD寄存器的请求,并且得到了来自SD卡的CSD寄存器的值。


    [cpp]  view plain  copy


     


    1. int mmc_send_cid(struct mmc_card *card, u32 *cid) 2. { 3. return mmc_send_cxd_native(card->host, card->rca << 16, cid, MMC_SEND_CID); 4. 5. } 6. 7. static int mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode) 8. { 9. cmd.opcode = opcode; 10. cmd.arg = arg; 11. cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; 12. 13. mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); 14. 15. sizeof(u32) * 4); // 得到response赋给cxd,即card->raw_cid 16. 17. ... ... 18. }



    -> 解析寄存器的值

        为什么要解析?先来看看寄存器CID在SD卡协议里的定义,它是一个128位的寄存器,存放了关于这块SD卡的基本信息,就像自己的身份证。通过mmc_send_cid()将这个寄存器的数值赋给了card->raw_cid (定义 u32 raw_cid[4];) ,为了方便得到具体某一个信息,协议层为我们解析了寄存器里的域,并赋给card->cid,比如厂商名称,就可以通过card->cid.manfid直接读取到。



    [cpp]  view plain  copy


     

    1. static int mmc_decode_cid(struct mmc_card *card) 2. { 3. u32 *resp = card->raw_cid; 4. 5. card->cid.manfid = UNSTUFF_BITS(resp, 120, 8); 6. card->cid.oemid = UNSTUFF_BITS(resp, 104, 16); 7. card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8); 8. card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8); 9. card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8); 10. card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); 11. card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); 12. card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8); 13. card->cid.serial = UNSTUFF_BITS(resp, 16, 32); 14. card->cid.month = UNSTUFF_BITS(resp, 12, 4); 15. card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997; 16. return 0; 17. }


    五、 注册SD卡设备驱动


    [cpp]  view plain  copy


     

    1. int mmc_attach_sd(struct mmc_host *host, u32 ocr) 2. 3. 4. /* mmc_alloc_card(host, &sd_type); 在mmc_sd_init_card()已完成 */ 5. 6. mmc_add_card(host->card); 7. 8. ... ...

    上文已经提到,设备驱动程序都会通过alloc_xxx()和add_xxx()两步来注册驱动,其实质是调用/drivers/base/core.c里的device_initialize()和device_add(),device_add()完成建立kobject,sys文件,发送uevent,等工作。

    六、拔出SD卡


    [cpp]  view plain  copy


     


    1. void mmc_rescan(struct work_struct *work) 2. 3. struct mmc_host *host = container_of(work, struct mmc_host, detect.work); 4. mmc_bus_get(host); 5. 6. /* if there is a card registered, check whether it is still present */ 7. if ((host->bus_ops != NULL) && host->bus_ops->detect && !host->bus_dead) 8. host->bus_ops->detect(host); 9. 10. mmc_bus_put(host); 11. 12. ... ...


    这里的mmc_bus_get/put(),为SD总线加上一个自旋锁,规定同时只能有一个线程在SD总线上操作。

    1、 bus_ops->detect()

           mmc_rescan()扫描SD总线,如果发现host->ops上赋了值,即之前已有SD卡注册过,就执行bus_ops->detect()操作去探测SD总线上是否还存在SD卡,如果不存在了,就执行bus_ops->remove()拔出SD卡。之前已经提到,这个bus_ops->detect()已在mmc_attach_sd()注册完成了。


    [cpp]  view plain  copy


     

    1. static void mmc_sd_detect(struct mmc_host *host) 2. { 3. mmc_claim_host(host); 4. 5. /* 6. * Just check if our card has been removed. 7. */ 8. err = mmc_send_status(host->card, NULL); 9. 10. mmc_release_host(host); 11. 12. if (err) { 13. mmc_sd_remove(host); 14. 15. mmc_claim_host(host); 16. mmc_detach_bus(host); 17. mmc_release_host(host); 18. } 19. }


    这里的mmc_claim_host(host)通过set_current_state(TASK_RUNNING);将当前进程设置为正在运行进程。

    mmc_send_status()发送得到SD卡状态的请求,如果未能得到状态数据,则执行mmc_sd_remove(host)拔出SD卡。


    [cpp]  view plain  copy


     


    1. int mmc_send_status(struct mmc_card *card, u32 *status) 2. { 3. struct mmc_command cmd; 4. 5. /* #define MMC_SEND_STATUS 13 */ 6. cmd.arg = card->rca << 16; 7. cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; 8. 9. err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); 10. 11. if (err) 12. return err; // 接收来自SD卡的response失败,即没有发现SD卡 13. if (status) 14. *status = cmd.resp[0]; 15. 16. return 0; 17. 18. }


    2、bus_ops->remove()

          拔出SD卡,其实就是注册SD卡驱动的反操作,实质就是执行device_del()和device_put()


    [cpp]  view plain  copy


     


  • 1. static void mmc_sd_remove(struct mmc_host *host) 2. { 3. mmc_remove_card(host->card); 4. host->card = NULL; 5. } 6. void mmc_remove_card(struct mmc_card *card) 7. { 8. if (mmc_card_present(card)) 9. device_del(&card->dev); 10. 11. put_device(&card->dev); 12. }
      你可能想看:
    • 扫描二维码推送至手机访问。

      版权声明:本文由皇冠云发布,如需转载请注明出处。

      本文链接:https://www.idchg.com/info/25499.html

      分享给朋友:

      “linux resolve命令 linux rescan” 的相关文章

      bbtec:高性能海外VPS的优质选择,适合联通用户的流媒体与在线游戏体验

      bbtec产品介绍 bbtec,这个在中国联通用户中逐渐崭露头角的海外VPS选择,无疑是一条连接世界的优质线路。作为软银线路,它专为追求高性能网络体验的用户设计,尤其适合频繁访问国外网站的朋友。bbtec具备低延迟、大带宽和快速下载速度的显著特点,特别是在流媒体应用的需求日益增长的今天,bbtec显...

      GIA VPS服务器:高速稳定的理想选择及价格性能分析

      GIA VPS服务器概述 在选择服务器时,GIA VPS服务器越来越受到关注。我之前在寻找合适的VPS时,了解到GIA VPS是一个非常不错的选择。它采用了CN2 GIA线路,提供了高效、稳定的网络连接。对我来说,网络的速度和稳定性是使用服务器的关键因素,而GIA VPS服务器在这两个方面表现都很优...

      SpartanHost VPS主机评测:高性能与安全性的理想选择

      在我开始探索VPS主机市场时,SpartanHost引起了我的注意。这个公司成立于2013年,自那时起便在行业中扎根,专注于提供高性能的VPS解决方案。他们使用的是基于KVM架构的主机产品,充分满足用户的需求。从他们的运营历史来看,尽管时间不算很久,但SpartanHost凭借其稳定的服务和灵活的选...

      搬瓦工最新优惠码分享,让你享受更多折扣

      在寻找优质VPS时,搬瓦工(BandwagonHost)绝对是一个热门的选择。为了让用户在购买过程中享受到更多优惠,现在分享一下搬瓦工最新的优惠码。 最新优惠码是BWHCGLUKKB,通过这个优惠码用户可以享受6.78%的循环优惠,这一优惠适用于搬瓦工全场的商品,无论是新购、续费还是升级服务,都能获...

      DC2:动画创作、网络安全与汽车文化的多重魅力探索

      DC2 可谓是一个充满魔力的词汇,它在不同的领域中有着不同的意义。这种多样性让它成为了动画爱好者、汽车迷,甚至网络安全专家的共同话题。我对这些含义的探索,给我带来了许多启发和乐趣,让我对这个小小的组合字母有了更深刻的理解。 首先,提到 DC2,许多人可能会想到 DC2 动画软件。这款软件不仅在手机动...

      探索4837线路:高速度、稳定性与价格优势的网络选择

      在当今网络时代,选择合适的线路对于提高上网体验至关重要。4837线路就是其中一个备受关注的选项。它主要指在回国或出国前,通过一个名为4837的节点进行连接,进行跨国网络传输。这个线路归类为联通线路,其特点在于相对负载较低,使得整体表现更胜一筹。经过近年来的广泛应用,4837线路逐渐成为热门选择。 我...