s3c6410 的SDIO驱动分析

正在研究mw8686 的Linux SDIO驱动,编译好后在s3c6410运行,发现未能出现网络接口设备。一查之下,它使用sdio总线进行操作驱动和设备,但是在 /sys/bus/sdio/devices 没有看到任何设备。因此推理是这个导致WiFi无法使用SDIO的原因。因为sdio驱动的初始化是放在probe当中,而probe是在sdio设备与sdio driver的match的过程中执行中。没有设备,意味着无法进行SDIO初始化。


我用的是Linux 2.6.28的版本,在网络上找到几个其它版本,主要Linux 2.6.21的,利用下午上课时间,进行一下课堂实验。发现这两个版本的实现差别很大,实际上两个分水岭。刚开始没明白这个道理,被两个版本的的源码搞得很混乱,因此为了解决问题,对这个两版本的SDIO实现进行分析


  关于mw8686的模块分析,参见我的博文

  

<<S3C6410硬件模块分析 -- SDIO WiFi模块分析>>



  首先根据档和源码来看三星发了几个关健的BSP,一个是针对linux 2.6.21.另外一个针对 linux 2.6.28的。这两个对SDIO的驱动采用不同的实际,有一篇官方文档可以看看,里面对Linux 2.6.21 SDIO实现分析得详细。

  

  <<SMDK6400 6410 HS MMC porting Guide v1.0 >>,但是网上只能找到这一个

 如果你对Linux 2.6的驱动模型相当了解,实际也能很快分析清楚。


SDIO总线


   首先mw8686的if_sdio.c直接使用了sdio 总线。这个虚拟总线是由 driver/mmc/core/sdio_bus.c实现,在两个版本,这个基本是变化不大的地方。要注意,这里的SDIO和MMC是两个兼容的接口,因此在源码中两个术语经常互换.

    sdio bus是一个标准的Linux 的总线,因此它需要有标准 bus device 和标准bus driver来注册到系统中。

   

  这是 sdio_bus.c的总线定义

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,
};

int sdio_register_bus(void)
{
 return bus_register(&sdio_bus_type);
}

void sdio_unregister_bus(void)
{
 bus_unregister(&sdio_bus_type);
}

 


而对应总线驱动struct device_driver 是 struct sdio_driver

/*
 * SDIO function device driver
 */
struct sdio_driver {
 char *name;
 const struct sdio_device_id *id_table;

int (*probe)(struct sdio_func *, const struct sdio_device_id *);
 void (*remove)(struct sdio_func *);

struct device_driver drv;
};

 

它使用 如下两个函数来注册和销毁sdio_driver.

extern int sdio_register_driver(struct sdio_driver *);
extern void sdio_unregister_driver(struct sdio_driver *);

 

   而对应总线设备的就是 struct device  是 struct sdio_func,这个名字与device差别太大了,因此我一开没有太在意。

   

/*
 * SDIO function devices
 */
struct sdio_func {
 struct mmc_card  *card;  /* the card this device belongs to */
 struct device  dev;  /* the device */
 sdio_irq_handler_t *irq_handler; /* IRQ callback */
 unsigned int  num;  /* function number */

unsigned char  class;  /* standard interface class */
 unsigned short  vendor;  /* vendor id */
 unsigned short  device;  /* device id */

unsigned  max_blksize; /* maximum block size */
 unsigned  cur_blksize; /* current block size */

unsigned  enable_timeout; /* max enable timeout in msec */

unsigned int  state;  /* function state */
#define SDIO_STATE_PRESENT (1<<0)  /* present in sysfs */

u8   tmpbuf[4]; /* DMA:able scratch buffer */

unsigned  num_info; /* number of info strings */
 const char  **info;  /* info strings */

struct sdio_func_tuple *tuples;
};

 

  

对于sdio_func操作

  int sdio_add_func(struct sdio_func *func);
  void sdio_remove_func(struct sdio_func *func);

 

在drivers/net/wireless/libertas/if_sdio.c

 它定义了如下的 sdio_driver

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwfggy.html