正在研究mw8686 的Linux SDIO驱动,编译好后在s3c6410运行,发现未能出现网络接口设备。一查之下,它使用sdio总线进行操作驱动和设备,但是在 /sys/bus/sdio/devices 没有看到任何设备。因此推理是这个导致WiFi无法使用SDIO的原因。因为sdio驱动的初始化是放在probe当中,而probe是在sdio设备与sdio driver的match的过程中执行中。没有设备,意味着无法进行SDIO初始化。 static struct bus_type sdio_bus_type = { int sdio_register_bus(void) void sdio_unregister_bus(void) 而对应总线驱动struct device_driver 是 struct sdio_driver /* int (*probe)(struct sdio_func *, const struct sdio_device_id *); struct device_driver drv; 它使用 如下两个函数来注册和销毁sdio_driver.extern int sdio_register_driver(struct sdio_driver *); /* unsigned char class; /* standard interface class */ unsigned max_blksize; /* maximum block size */ unsigned enable_timeout; /* max enable timeout in msec */ unsigned int state; /* function state */ u8 tmpbuf[4]; /* DMA:able scratch buffer */ unsigned num_info; /* number of info strings */ struct sdio_func_tuple *tuples; 对于sdio_func操作 int sdio_add_func(struct sdio_func *func); static struct sdio_driver if_sdio_driver = { static int __init if_sdio_init_module(void) SDIO采用的与MMC兼容的命令接口,因此对于mmc的操作,LINUX又封装一层,使用数据结构 mmc_host struct mmc_host { /* private data */ struct mmc_ios ios; /* current io bus settings */ /* group bitfields together to minimize padding */ struct mmc_card *card; /* device attached to this host */ wait_queue_head_t wq; struct delayed_work detect; const struct mmc_bus_ops *bus_ops; /* current bus driver */ unsigned int sdio_irqs; #ifdef CONFIG_LEDS_TRIGGERS struct dentry *debugfs_root; unsigned long private[0] ____cacheline_aligned; 而mmc_host是一个特殊内核类 mmc_host,它会在 /sys/class/ 建立一个mmc_host类. //drivers/mmc/core/host.c static struct class mmc_host_class = { int mmc_register_host_class(void) void mmc_unregister_host_class(void) mmc_host用于描述MMC接口 CPU一侧的设备,它可以看成是class device的特例,而插入的SDIO设备,如SD卡则封装成数据结构,如果mmc_host发送命令和数据是通过 struct mmc_host_ops 操作 如果SDIO设备操作,直接采用如下定义 mmc_card /mmc_bus如果SD卡的之存储设备进行块设备操作,则需要另一个额外的mmc bus总线,并且需要定义mmc_card结构,对应(device).并且进行存储的块设备操作定义在mmc_driver类。 如果SDIO设备本身不需要这个总线 在mmc又单独定义一个 mmc总线,
我用的是Linux 2.6.28的版本,在网络上找到几个其它版本,主要Linux 2.6.21的,利用下午上课时间,进行一下课堂实验。发现这两个版本的实现差别很大,实际上两个分水岭。刚开始没明白这个道理,被两个版本的的源码搞得很混乱,因此为了解决问题,对这个两版本的SDIO实现进行分析
关于mw8686的模块分析,参见我的博文 <
.name = 'sdio',
.dev_attrs = sdio_dev_attrs,
.match = sdio_bus_match,
.uevent = sdio_bus_uevent,
.probe = sdio_bus_probe,
.remove = sdio_bus_remove,
};
{
return bus_register(&sdio_bus_type);
}
{
bus_unregister(&sdio_bus_type);
}
* SDIO function device driver
*/
struct sdio_driver {
char *name;
const struct sdio_device_id *id_table;
void (*remove)(struct sdio_func *);
};
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 short vendor; /* vendor id */
unsigned short device; /* device id */
unsigned cur_blksize; /* current block size */
#define SDIO_STATE_PRESENT (1<<0) /* present in sysfs */
const char **info; /* info strings */
};
void sdio_remove_func(struct sdio_func *func); 在drivers/net/wireless/libertas/if_sdio.c 它定义了如下的 sdio_driver
.name = 'libertas_sdio',
.id_table = if_sdio_ids,
.probe = if_sdio_probe,
.remove = if_sdio_remove,
};
{
int ret = 0;
ret = sdio_register_driver(&if_sdio_driver);
return ret;
}
static void __exit if_sdio_exit_module(void)
{
sdio_unregister_driver(&if_sdio_driver);
}
struct device *parent;
struct device class_dev;
int index;
const struct mmc_host_ops *ops;
unsigned int f_min;
unsigned int f_max;
u32 ocr_avail;
unsigned long caps; /* Host capabilities */
/* host specific block data */
unsigned int max_seg_size; /* see blk_queue_max_segment_size */
unsigned short max_hw_segs; /* see blk_queue_max_hw_segments */
unsigned short max_phys_segs; /* see blk_queue_max_phys_segments */
unsigned short unused;
unsigned int max_req_size; /* maximum number of bytes in one req */
unsigned int max_blk_size; /* maximum size of one mmc block */
unsigned int max_blk_count; /* maximum number of blocks in one req */
spinlock_t lock; /* lock for claim and bus ops */
u32 ocr; /* the current OCR setting */
unsigned int use_spi_crc:1;
unsigned int claimed:1; /* host exclusively claimed */
unsigned int bus_dead:1; /* bus has been released */
#ifdef CONFIG_MMC_DEBUG
unsigned int removed:1; /* host is being removed */
#endif
unsigned int bus_refs; /* reference counter */
struct task_struct *sdio_irq_thread;
atomic_t sdio_irq_thread_abort;
struct led_trigger *led; /* activity led */
#endif
};
.name = 'mmc_host',
.dev_release = mmc_host_classdev_release,
};
{
return class_register(&mmc_host_class);
}
{
class_unregister(&mmc_host_class);
}struct mmc_host_ops {
void (*request)(struct mmc_host *host, struct mmc_request *req);
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);
};static struct mmc_host_ops s3c_hsmmc_ops = {
.request = s3c_hsmmc_request,
.set_ios = s3c_hsmmc_set_ios,
};
上一篇:s3c6410 TVout 测试
下一篇:gsm库(libgsm)在ARM-Linux下的移植
推荐阅读最新更新时间:2024-11-13 10:26
设计资源 培训 开发板 精华推荐
- NOIX4SN5000BLFB-GEVB:XGS 5000,单声道 FBD HB
- 物联网点阵时钟
- LTC3859IFE 三路输出降压-升压型同步控制器的典型应用电路
- 超小型usb转uart(ttl) 改
- NCS21911SN2GEVB:NCS21911SN 评估板
- AL5809 60V 两端恒流 LED 驱动器 PowerDI 与高端 LED 串的典型应用
- DC209A,用于 LTC1404CS8 12 位高速 600ksps 模数转换器的演示板,具有停机功能
- TA8215L 18W BTL x 2ch 音频功率放大器典型应用
- LD29150PT50R 1.5A超低压降稳压器典型应用电路
- NCP139AFCT110T2GEVB:NCP139 WLCSP-6 评估板 1V1