Linux SD卡驱动开发(六) —— SD卡启动过程总体分析

一、工作流程

mmc驱动主要文件包括

drivers/mmc/card/block.c
drivers/mmc/card/queue.c
drivers/mmc/core/core.c
drivers/mmc/core/host.c
drivers/mmc/core/

内核启动时,首先执行core/core.c的mmc_init,注册mmc、sd总线,以及一个host class设备。接着执行card/block.c中,申请一个块设备

二、数据结构:

这里涉及三种总线

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. 1. platform bus //MMC host controller 作为一种 platform device, 它是需要注册到 platform bus上 的    
  2. driver/base/platform.c    
  3. struct bus_type platform_bus_type = {    
  4.     .name        = "platform",    
  5.     .dev_attrs    = platform_dev_attrs,    
  6.     .match        = platform_match,    
  7.     .uevent        = platform_uevent,    
  8.     .pm        = &platform_dev_pm_ops,    
  9. };    
  10.     
  11. 2. mmc bus type  //在mmc_init()中被创建的.通过调用 mmc_register_bus() 来注册 MMC 总线    
  12. drivers\mmc\core\bus.c    
  13. static struct bus_type mmc_bus_type = {    
  14.     .name        = "mmc",    
  15.     .dev_attrs    = mmc_dev_attrs,    
  16.     .match        = mmc_bus_match,    
  17.     .uevent        = mmc_bus_uevent,    
  18.     .probe        = mmc_bus_probe,    
  19.     .remove        = mmc_bus_remove,    
  20.     .shutdown        = mmc_bus_shutdown,    
  21.     .pm        = &mmc_bus_pm_ops,    
  22. };    
  23.     
  24. 3. sdio bus type    //在mmc_init()中被创建的.通过调用sdio_register_bus() 来注册 SDIO 总线    
  25. drivers\mmc\core\sdio_bus.c    
  26. static struct bus_type sdio_bus_type = {    
  27.     .name        = "sdio",    
  28.     .dev_attrs    = sdio_dev_attrs,    
  29.     .match        = sdio_bus_match,    
  30.     .uevent        = sdio_bus_uevent,    
  31.     .probe        = sdio_bus_probe,    
  32.     .remove        = sdio_bus_remove,    
  33.     .pm        = SDIO_PM_OPS_PTR,    
  34. };    
     其中mmc总线操作相关函数,由于mmc卡支持多种总数据线,如SPI、SDIO、8LineMMC而不同的总线的操作控制方式不尽相同,所以通过此结构与相应的总线回调函数相关联。
[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. //总线操作结构  
  2. struct mmc_bus_ops {  
  3.     void (*remove)(struct mmc_host *);  
  4.     void (*detect)(struct mmc_host *);  
  5.     int (*sysfs_add)(struct mmc_host *, struct mmc_card *card);  
  6.     void (*sysfs_remove)(struct mmc_host *, struct mmc_card *card);  
  7.     void (*suspend)(struct mmc_host *);  
  8.     void (*resume)(struct mmc_host *);  
  9. };  
  10. //  mmc卡的总线操作 core/mmc.c  
  11. static const struct mmc_bus_ops mmc_ops = {  
  12.     .remove = mmc_remove,  
  13.     .detect = mmc_detect,  
  14.     .sysfs_add = mmc_sysfs_add,  
  15.     .sysfs_remove = mmc_sysfs_remove,  
  16.     .suspend = mmc_suspend,  
  17.     .resume = mmc_resume,  
  18. };  
  19. // sd卡的总线操作 core/sd.c  
  20. static const struct mmc_bus_ops mmc_sd_ops = {  
  21.     .remove = mmc_sd_remove,  
  22.     .detect = mmc_sd_detect,  
  23.     .sysfs_add = mmc_sd_sysfs_add,  
  24.     .sysfs_remove = mmc_sd_sysfs_remove,  
  25.     .suspend = mmc_sd_suspend,  
  26.     .resume = mmc_sd_resume,  
  27. };  
  28. // sdio的总线操作 core/sdio.c  
  29. static const struct mmc_bus_ops mmc_sdio_ops = {  
  30.     .remove = mmc_sdio_remove,  
  31.     .detect = mmc_sdio_detect,  
  32. };  

关于总线操作的函数:

.detect,驱动程序经常需要调用此函数去检测mmc卡的状态,具体实现是发送CMD13命令,并读回响应,如果响应错误,则依次调用.remove、detach_bus来移除卡及释放总线。


三、总体架构

1、kernel启动时,先后执行mmc_init()及mmc_blk_init(),以对mmc设备及mmc块模块进行初始化

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. mmc/core/core.c    
  2. static int __init mmc_init(void)    
  3.     workqueue = alloc_ordered_workqueue("kmmcd", 0);//建立了一个工作队列workqueue,这个工作队列的作用主要是用来支持热插拔    
  4.     ret = mmc_register_bus();//注册一个mmc总线    
  5.     ret = mmc_register_host_class();//注册了一个 mmc_host 类    
  6.     ret = sdio_register_bus();//注册了一个 sdio_bus_type    
  7.         
  8. *******     
  9. mmc/card/block.c    
  10. static int __init mmc_blk_init(void)    
  11.     res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");//注册一个块设备    
  12.     res = mmc_register_driver(&mmc_driver);//注册一个mmc设备驱动    
  13.     
  14. static struct mmc_driver mmc_driver =    
  15.     .probe      = mmc_blk_probe,    
  16.         
  17. static int mmc_blk_probe(struct mmc_card *card)    
  18.     mmc_set_bus_resume_policy(card->host, 1);//*host 该指针指向一个mmc主机实例,块设备中的读写操作就是调用这个mmc主机的操作函数host->ops->request来实现对实际硬件的操作。    

2、core部分会做两件事

a -- 取得总线

b -- 检查总线操作结构指针bus_ops,如果为空,则重新利用各总线对端口进行扫描,检测顺序依次为:SDIO、Normal SD、MMC。当检测到相应的卡类型后,就使用mmc_attach_bus()把相对应的总线操作与host连接起来

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)  
  2. {  
  3.     ...  
  4.     host->bus_ops = ops;  
  5.     ...  
  6. }  

3、然后在挂载mmc设备驱动时,执行驱动程序中的xx_mmc_probe(),检测host设备中挂载的sd设备

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. kernel\arch\arm\configs\msm9625_defconfig    
  2. CONFIG_MMC_MSM=y    
  3.     
  4. kernel\drivers\mmc\host\Makefile    
  5. obj-$(CONFIG_MMC_MSM)        += msm_sdcc.o        
  6.     
  7. msm_sdcc.c (drivers\mmc\host)    
  8. //系统初始化时扫描 platform 总线上是否有名为该SD主控制器名字"msm_sdcc"的设备,如果有, 驱动程序将主控制器挂载到 platform 总线上,并注册该驱动程序    
  9. static int __init msmsdcc_init(void)    
  10.     platform_driver_register(&msmsdcc_driver);    //注册 platform driver    
  11.         
  12. static struct platform_driver msmsdcc_driver = {    
  13.     .probe        = msmsdcc_probe,    
  14.     .remove        = msmsdcc_remove,    
  15.     .driver        = {    
  16.         .name    = "msm_sdcc",    
  17.         .pm    = &msmsdcc_dev_pm_ops,    
  18.         .of_match_table = msmsdcc_dt_match,    
  19.     },    
  20. };        
  21.         
  22. //整个设备驱动的 probe()函数,其本质就是是为设备建立起数据结构并对其赋初值    
  23. //msmsdcc_probe 所有赋值中,我们重点关注从 platform_device *pdev里得到的数据,即设备树里的数据    
  24. //platform_device *pdev是在系统初始化的时候扫描 platform 总线发现SD主控制器后所得到的数据    
  25. static int msmsdcc_probe(struct platform_device *pdev)        
  26. {        
  27.     //初始化设备的数据结构    
  28.     if (pdev->dev.of_node) {    
  29.     plat = msmsdcc_populate_pdata(&pdev->dev);        //获取设备树信息    
  30.     of_property_read_u32((&pdev->dev)->of_node,"cell-index", &pdev->id);    
  31.     } else {    
  32.         plat = pdev->dev.platform_data;    
  33.     }    
  34.     //为主设备控制器建立数据结构,建立kobject,并初始化等待队列,工作队列,以及一些控制器的配置    
  35.     mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);            ---- 1    
  36.     //实现设备驱动的功能函数,如mmc->ops = &pxamci_ops;    
  37.     mmc->ops = &msmsdcc_ops;    
  38.     //申请中断函数 request_irq()    
  39.     ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,DRIVER_NAME " (cmd)", host);    
  40.     //注册设备,即注册kobject,建立sys文件,发送uevent等    
  41.     mmc_add_host(mmc);                                                        ---- 2    
  42.     //其他需求,如在/proc/driver下建立用户交互文件等    
  43.     ret = device_create_file(&pdev->dev, &host->auto_cmd21_attr);    
  44. }        

4、此时probe函数会创建一个host设备,然后开启一个延时任务mmc_rescan()

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. 1:      
  2. core/host.c     
  3. //重要函数mmc_alloc_host , 用于分配mmc_host结构体指针的内存空间大小    
  4. struct mmc_host *mmc_alloc_host(int extra, struct device *dev)----创建一个 mmc_host 和 mmc_spi_host ,且mmc_host的最后一个成员指针private指向mmc_spi_host    
  5.     //建立数据结构    
  6.     struct mmc_host *host;      
  7.     host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);    
  8.     //建立kobject    
  9.     host->parent = dev;    
  10.     host->class_dev.parent = dev;    
  11.     host->class_dev.class = &mmc_host_class;    
  12.     device_initialize(&host->class_dev);    
  13.     //初始化等待队列,工作队列    
  14.     init_waitqueue_head(&host->wq);    
  15.     INIT_DELAYED_WORK(&host->detect, mmc_rescan);    //建立了一个工作队列任务 structdelayed_work detect。工作队列任务执行的函数为mmc_rescan    
  16.     //配置控制器    
  17.     host->max_segs = 1;    
  18.     host->max_seg_size = PAGE_CACHE_SIZE;    
  19.     return host;    

5、驱动挂载成功后,mmc_rescan()函数被执行,然后对卡进行初始化(步骤后面详细讲述)

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. core/core.c    
  2. //mmc_rescan 函数是需要重点关注的,因为SD卡协议中的检测,以及卡识别等都是在此函数中实现    
  3. void mmc_rescan(struct work_struct *work)    
  4.     if (host->bus_ops && host->bus_ops->detect && !host->bus_dead && !(host->caps & MMC_CAP_NONREMOVABLE))    //存在热插拔卡,不包括emmc,调用探测函数    
  5.     host->bus_ops->detect(host);    
  6.     mmc_bus_put(host);    //减少引用技术,就释放    
  7.     mmc_bus_get(host);    //增加bus引用计数    
  8.     if (host->bus_ops != NULL) {    
  9.         mmc_bus_put(host);    //如果卡仍然存在,减少引用计数,不必探测了    
  10.         goto out;    
  11.     }    
  12.     if (host->ops->get_cd && host->ops->get_cd(host) == 0)  //有卡,退出    
  13.     goto out;    
  14.     mmc_claim_host(host);                   //用于检测host是否被占用,占用则退出,否则标记成占用    
  15.         
  16.     if (!mmc_rescan_try_freq(host, host->f_min))    
初始化卡接以下流程初始化:

a、发送CMD0使卡进入IDLE状态
b、发送CMD8,检查卡是否SD2.0。SD1.1是不支持CMD8的,因此在SD2.0 Spec中提出了先发送CMD8,如响应为无效命令,则卡为SD1.1,否则就是SD2.0(请参考SD2.0 Spec)。
c、发送CMD5读取OCR寄存器。
d、发送ACMD55、CMD41,使卡进入工作状态。MMC卡并不支持ACMD55、CMD41,如果这步通过了,则证明这张卡是SD卡。
e、如果d步骤错误,则发送CMD1判断卡是否为MMC。SD卡不支持CMD1,而MMC卡支持,这就是SD和MMC类型的判断依据。
f、如果ACMD41和CMD1都不能通过,那这张卡恐怕就是无效卡了,初始化失败。

      假如扫描到总线上挂有有效的设备,就调用相对应的函数把设备装到系统中,mmc_attach_sdio()、mmc_attach_sd()、mmc_attach_mmc()这三个函数分别是装载sdio设备,sd卡和mmc卡的。

     在 sd卡中,驱动循环发送ACMD41、CMD55给卡,读取OCR寄存器,成功后,依次发送CMD2(读CID)、CMD3(得到RCA)、CMD9(读 CSD)、CMD7(选择卡)。后面还有几个命令分别是ACMD41&CMD51,使用CMD6切换一些功能,如切换到高速模式。

     经过上述步骤,已经确定当前插入的卡是一张有效、可识别的存储卡。然后调用mmc_add_card()把存储卡加到系统中。正式与系统驱动连接在一起

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)    
  2.     host->f_init = freq;                 //设置某一个时钟频率    
  3.     mmc_power_up(host);                     //与 mmc_power_off 类似,不过设置了启动时需要的 ios    
  4.     mmc_go_idle(host);          ----1a      //CMD0 ,SD卡从 inactive 到 idle            
  5.     mmc_send_if_cond(host, host->ocr_avail);//检测SD卡是否支持SD2.0         
  6.     if (!mmc_attach_sd(host))   ----1b      //然后对mmc或者sd发送一些命令进行探测,这里以 sd 为例    
  7.     
  8. 1a:    
  9. int mmc_go_idle(struct mmc_host *host)      
  10.     struct mmc_command cmd = {0};    
  11.     cmd.opcode = MMC_GO_IDLE_STATE; //即CMD0    
  12.     cmd.arg = 0;                    //此命令无参数    
  13.     err = mmc_wait_for_cmd(host, &cmd, 0)    
  14.         
  15. int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)    
  16.     memset(cmd->resp, 0, sizeof(cmd->resp));  //调用了 mmc_start_request,     
  17.     cmd->retries = retries;    
  18.     mrq.cmd = cmd;                                  
  19.     mmc_wait_for_req(host, &mrq);    
  20.         
  21. void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)   ----重要函数    
  22.     __mmc_start_req(host, mrq);    
  23.     
  24. static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)    
  25.     mmc_start_request(host, mrq);    
  26.             
  27. static void mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)    
  28.     host->ops->request(host, mrq);    //即 msmsdcc_request, MMC 核心与核HOST 层握手了    
  29.     
  30.         
  31. 1b:     
  32. core/mmc.c    
  33. int mmc_attach_sd(struct mmc_host *host)                    //完成匹配,和初始化卡的功能    
  34.     err = mmc_send_app_op_cond(host, 0, &ocr);      ----1b1 //检测是否是支持SD卡    
  35.     host->ocr = mmc_select_voltage(host, ocr);               //设置MMC电压    
  36.     err = mmc_init_card(host, host->ocr, NULL);              //对mmc卡进行初始化,主要是读取mmc卡里的一些寄存器信息,且对这些寄存器的值进行设置    
  37.     err = mmc_sd_init_card(host, host->ocr, NULL);   ----1b2    
  38.     err = mmc_add_card(host->card);                  ----1b3 //调用 mmc_add_card 来把 mmc_card 挂载到 mmc_bus_type 总线去    
  39.         
  40.         
  41. 1b1:    
  42. int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)    
  43.     cmd.opcode = SD_APP_OP_COND;    //ACMD41,获取 SDcard 的允许电压范围值,保存在 ocr 中. 所有发送它之前需要发送 CMD_55 命令。执行完后 card 状态变为 READY    
  44.     
  45.         
  46.         
  47. 1b2:    
  48. static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,struct mmc_card *oldcard)    
  49.     err = mmc_sd_get_cid(host, ocr, cid, &rocr);        //发送 CMD2 ,获取卡的身份信息,进入到身份状态    
  50.     card = mmc_alloc_card(host, &sd_type);              //分配一张 SD 类型的 card 结构    
  51.     err = mmc_send_relative_addr(host, &card->rca);      //获取卡的相对地址,注意一前卡和主机通信都采用默认地址,现在有了自己的地址了,进入到 stand_by 状态    
  52.     err = mmc_sd_get_csd(host, card); ----mmc_send_csd(card, card->raw_csd);//CMD9, 获取 CSD 寄存器的信息,包括 block 长度,卡容量等信息    
  53.     err = mmc_select_card(card);                        //发送 CMD7, 选中目前 RADD 地址上的卡,任何时候总线上只有一张卡被选中,进入了传输状态     
  54.     err = mmc_sd_setup_card(host, card, oldcard != NULL);       
  55.     
  56. int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,bool reinit)    
  57.     mmc_app_send_scr(card, card->raw_scr);   //发送命令 ACMD51 获取 SRC 寄存器的内容,进入到 SENDING-DATA 状态    
  58.     if (host->ops->get_ro(host) > 0 )      // get_ro(host) 即是 msmsdcc_get_ro     
  59.         mmc_card_set_readonly(card);        //是否写保护,如果是的,将 card 状态设置为只读状态    
  60.         
  61. 1b3:    
  62. core/bus.c    
  63. int mmc_add_card(struct mmc_card *card)     //  /sys/devices/msm_sdcc.2/mmc_host/mmc0    
  64.     ret = device_add(&card->dev);    
  65.     
  66. drivers/base/core.c    
  67. int device_add(struct device *dev)    
  68.     dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id); //    
  69.     bus_probe_device(dev);    
  70.     
  71. void bus_probe_device(struct device *dev)    
  72.         if (bus->p->drivers_autoprobe)     
  73.         ret = device_attach(dev);           //这样,在总线 mmc_bus_type 中就有了 mmc 设备 mmc_card 了        
  74.         
  75.         
  76. ***********     
  77. 2:    
  78. //完成kobject的注册,并调用 mmc_rescan,目的在于在系统初始化的时候就扫描SD总线查看是否存在SD卡    
  79. int mmc_add_host(struct mmc_host *host)    
  80.     err = device_add(&host->class_dev);//将设备注册进linux设备模型,最终的结果就是在 sys/bus/platform/devices 目录下能见到 mmc 设备节点    
  81.     mmc_start_host(host);    
  82.         
  83.         
  84. void mmc_start_host(struct mmc_host *host)      
  85.     mmc_power_off(host);                ----2a    
  86.     mmc_detect_change(host, 0);         ----2b    
  87.     
  88. 2a:    
  89. void mmc_power_off(struct mmc_host *host)       
  90.     host->ios.power_mode = MMC_POWER_OFF;    //对 ios 进行了设置    
  91.     ...    
  92.     mmc_set_ios(host);    
  93.     
  94. void mmc_set_ios(struct mmc_host *host)    
  95.     host->ops->set_ios(host, ios);            // set_ios 实际上就是 mmc_host_ops 的 .set_ios  = msmsdcc_set_ios,    
  96.     
  97. 2b:    
  98. void mmc_detect_change(struct mmc_host *host, unsigned long delay)    
  99.         mmc_schedule_delayed_work(&host->detect, delay); //实际上就是调用我们前面说的延时函数 mmc_rescan    

6、卡设备加到系统中后,通知mmc块设备驱动。块设备驱动此时调用probe函数,即mmc_blk_probe()函数,mmc_blk_probe()首 先分配一个新的mmc_blk_data结构变量,然后调用mmc_init_queue,初始化blk队列。然后建立一个线程 mmc_queue_thread()


7、然后就可以进行传输命令和数据了

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. struct mmc_host_ops {           
  2.     //用于SD卡命令的传输,比如发送和接收命令,CMD0,CMD8,ACMD41诸如此类的都是在这个函数去实现    
  3.     void    (*request)(struct mmc_host *host, struct mmc_request *req);    
  4.     
  5. }    
  6.     
  7. static const struct mmc_host_ops msmsdcc_ops = {    
  8.     .enable     = msmsdcc_enable,    
  9.     .disable    = msmsdcc_disable,    
  10.     .pre_req        = msmsdcc_pre_req,    
  11.     .post_req       = msmsdcc_post_req,    
  12.     .request    = msmsdcc_request,    
  13.     .set_ios    = msmsdcc_set_ios,    
  14.     .get_ro     = msmsdcc_get_ro,    
  15.     .enable_sdio_irq = msmsdcc_enable_sdio_irq,    
  16.     .start_signal_voltage_switch = msmsdcc_switch_io_voltage,    
  17.     .execute_tuning = msmsdcc_execute_tuning,    
  18.     .hw_reset = msmsdcc_hw_reset,    
  19.     .stop_request = msmsdcc_stop_request,    
  20.     .get_xfer_remain = msmsdcc_get_xfer_remain,    
  21.     .notify_load = msmsdcc_notify_load,    
  22. };    
  23.     
  24. /*这个函数实现了命令和数据的发送和接收,  
  25. 当 CORE 部分需要发送命令或者传输数据时,都会调用这个函数,并传递 mrq 请求*/    
  26. static void msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)    
  27.     mmc_request_done(mmc, mrq);             // 如果卡不存在,就终止请求    
  28.     msmsdcc_request_start(host, mrq);           
  29.     
  30. static void msmsdcc_request_start (struct msmsdcc_host *host, struct mmc_request *mrq)    
  31.     if ((mrq->data->flags & MMC_DATA_READ) ||host->curr.use_wr_data_pend)      //判断发送数据还是命令    
  32.         msmsdcc_start_data(host, mrq->data,mrq->sbc ? mrq->sbc : mrq->cmd,0);   //发送数据    
  33.     else    
  34.         msmsdcc_start_command(host,mrq->sbc ? mrq->sbc : mrq->cmd,0);          //发送命令    
  35.     
  36.     
  37. static void msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,struct mmc_command *cmd, u32 c)    
  38.     //对某些 寄存器进行设置, 使能某些中断, 如 pio_irqmask    
  39.     ...    
  40.     if (is_dma_mode(host) && (datactrl & MCI_DPSM_DMAENABLE))   //采用 DMA 进行数据传输还是采用 FIFO 进行数据传输    
  41.         msmsdcc_start_command_deferred(host, cmd, &c);          //启动了数据传输模式    
  42.     else        
  43.         msmsdcc_start_command(host, cmd, c)    
  44.     
  45. static void msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)    
  46. {    
  47.     msmsdcc_start_command_deferred(host, cmd, &c);    
  48.     msmsdcc_start_command_exec(host, cmd->arg, c);    
  49. }    
  50.     
  51. static void msmsdcc_start_command_deferred(struct msmsdcc_host *host,struct mmc_command *cmd, u32 *c)    
  52.     cmd->opcode ----对应SD卡命令 ,如 CMD0:复位SD 卡 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/401904.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

svn怎么上传文件 — 百度经验无耻推广

2019独角兽企业重金招聘Python工程师标准>>> svn怎么上传文件 — 欢乐地点进去捧场 PS:觉得笔者太无耻,直接在下方评论抨击 转载于:https://my.oschina.net/cenqingbo/blog/212284

apache 重写和虚拟目录配置

要求:假如我请求一个地址:www.lxy.com/news-sport-id123.html转成:www.lxy.com/show.php?catenews&classsport&id123步骤:①首先我们需要在apache中启用rewrite模块打开apache的httpd.conf文件,找到#LoadModu…

JavaScript代码片段

简介:本文收集了我常用的JavaScript代码片段,欢迎提意见! 大灰狼边敲门边说:“小兔子乖乖,把门儿开开!” 小兔子听到后,连忙去开门:“来喽!” 兔妈妈对小兔子喊道&#x…

路由器开发(一)—— 路由器硬件结构及软件体系

一、路由器的硬件构成 路由器主要由以下几个部分组成:输入/输出接口部分、包转发或交换结构部分(switching fabric)、路由计算或处理部分。如图所示 图1 路由器的基本组成 输入端口是物理链路和输入包的进口处。端口通常由线卡提供&#…

路由器开发(二)—— 路由器工作原理

当信息需要在两个网络之间传输时,常用路由器这种互连设备来负责数据的传输。路由器的主要工作是:路径的决定和数据包的转发(从路由器一个接口输入,然后选择合适接口输出);维护路由表。 路由器工作的方式非常…

Android颜色渐变的分隔线(ListView)

2019独角兽企业重金招聘Python工程师标准>>> shape.xml xx <?xml version"1.0" encoding"utf-8"?><shape xmlns:android"http://schemas.android.com/apk/res/android" > <gradient android:startColor&qu…

项目实践中Linux集群的总结和思考

2019独角兽企业重金招聘Python工程师标准>>> 前言&#xff1a;作为一名Linux/unix系统工程师、项目实施工程师&#xff0c;这几年一直在涉及到对外项目&#xff0c;经手过许多小中型网站的架构&#xff0c;F5、LVS及Nginx接触的都比较多&#xff0c;我想一种比较通俗…

路由器基础知识详解

第一章 网络互联 网络的根本目的非常简单&#xff1a;方便人们交换所获得的信息。但是网络的应用需求非常复杂&#xff1a;有的用户希望高带宽&#xff0c;但并不要求很长的传输距离&#xff1b;有的用户要求很长的距离&#xff0c;但对带宽要求很低&#xff1b;有的对网络的…

事务与锁机制

2019独角兽企业重金招聘Python工程师标准>>> 事务定义&#xff1a; 访问并可能更新数据库&#xff1a;一句或一组SQL&#xff0c;或者是一段程序&#xff0c;反正update了就是事务 ACID的4原则&#xff1a; 原子性&#xff1a; 一致性&#xff1a; 隔离性&#xff1…

路由器 VS OSI七层模型

OSI Open Source Initiative&#xff08;简称OSI&#xff0c;有译作开放源代码促进会、开放原始码组织&#xff09;是一个旨在推动开源软件发展的非盈利组织。OSI参考模型&#xff08;OSI/RM&#xff09;的全称是开放系统互连参考模型&#xff08;Open System Interconnection …

Linux Wireless架构总结

1、无线网络驱动(ath9k_htc) ath9k_htc是一个基于USB接口的SoftMAC无线网络适配器。为了其驱动能正常工作&#xff0c;首先必须调用usb_register来注册驱动定义的usb_driver&#xff0c;以借助USB Core的力量来处理与USB协议相关的事件。其代码如下&#xff1a;[cpp] view plai…

MySQL 日志文件 说明

MySQL 5.5 官方文档上有关日志的分类&#xff1a;By default, nologs are enabled. The following log-specific sections provide information about the server options that enable logging.--默认情况下&#xff0c;没有启动任何log&#xff0c;可以通过如下log 选项来启动…

Linux 下wifi 驱动开发(四)—— USB接口WiFi驱动浅析

前面学习了SDIO接口的WiFi驱动&#xff0c;现在我们来学习一下USB接口的WiFi驱动&#xff0c;二者的区别在于接口不同。而USB接口的设备驱动&#xff0c;我们前面也有学习&#xff0c;比如USB摄像头驱动、USB鼠标驱动&#xff0c;同样都符合LinuxUSB驱动结构&#xff1a; USB设…

Linux 下wifi 驱动开发(三)—— SDIO接口WiFi驱动浅析

SDIO-Wifi模块是基于SDIO接口的符合wifi无线网络标准的嵌入式模块&#xff0c;内置无线网络协议IEEE802.11协议栈以及TCP/IP协议栈&#xff0c;能够实现用户主平台数据通过SDIO口到无线网络之间的转换。SDIO具有传输数据快&#xff0c;兼容SD、MMC接口等特点。 对于SDIO接口的w…

Erlang并发机制 –进程调度

2019独角兽企业重金招聘Python工程师标准>>> Erlang调度器主要完成对Erlang进程的调度&#xff0c;它是Erlang实现软件实时和进程之间公平使用CPU的关键。Erlang运行时&#xff0c;有4种任务需要被调度&#xff1a;进程&#xff0c;Port&#xff0c;Linked-in drive…

Linux 下wifi 驱动开发(二)—— WiFi模块浅析

一、什么是wifi 模块 百度百科上这样定义&#xff1a; Wi-Fi模块又名串口Wi-Fi模块&#xff0c;属于物联网传输层&#xff0c;功能是将串口或TTL电平转为符合Wi-Fi无线网络通信标准的嵌入式模块&#xff0c;内置无线网络协议IEEE802.11b.g.n协议栈以及TCP/IP协议栈。传统的硬件…

Linux 下wifi 驱动开发(一)—— WiFi基础知识解析

一、WiFi相关基础概念 1、什么是wifi 我们看一下百度百科是如何定义的&#xff1a; Wi-Fi是一种可以将个人电脑、手持设备&#xff08;如pad、手机&#xff09;等终端以无线方式互相连接的技术&#xff0c;事实上它是一个高频无线电信号。[1] 无线保真是一个无线网络通信技术…

Linux 网络设备驱动开发(一) —— linux内核网络分层结构

Linux内核对网络驱动程序使用统一的接口&#xff0c;并且对于网络设备采用面向对象的思想设计。 Linux内核采用分层结构处理网络数据包。分层结构与网络协议的结构匹配&#xff0c;既能简化数据包处理流程&#xff0c;又便于扩展和维护。 一、内核网络结构 在Linux内核中&#…

Linux 网络设备驱动开发(二) —— Linux 网络栈剖析

一、协议简介 虽然对于网络的正式介绍一般都参考了 OSI&#xff08;Open Systems Interconnection&#xff09;模型&#xff0c;但是本文对 Linux 中基本网络栈的介绍分为四层的 Internet 模型&#xff08;如图 1 所示&#xff09;。 图 1. 网络栈的 Internet 模型 这个栈的最底…

Linux 网络设备驱动开发(三) —— 网络设备驱动基本原理和框架

一、协议栈层次对比 二、Linux网络子系统 Linux网络子系统的顶部是系统调用接口层。它为用户空间提供的应用程序提供了一种访问内核网络子系统的方法&#xff08;socket&#xff09;。位于其下面是一个协议无关层&#xff0c;它提供一种通用的方法来使用传输层协议。然后是具…