s5p4418
sdio接口的wifi模块驱动:If_sdio.c (drivers\net\wireless\libertas)
linux 版本:3.4.29
在博客:http://blog.csdn.net/eliot_shao/article/details/50178475 中通过跟踪代码的方式,大概了解了mmc控制器HOST的驱动:建立host mmc设备,等待卡的插入,如果有卡插入,卡的类型包括SDIO接口wifi模块,emmc,tf,sd卡等,则控制器驱动判断设备类型是SDIO,MMC还是SD,如下:
/* Order's important: probe SDIO, then SD, then MMC */
if (!mmc_attach_sdio(host))
return 0;
if (!mmc_attach_sd(host))
return 0;
if (!mmc_attach_mmc(host))
return 0;
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,
.pm = SDIO_PM_OPS_PTR,
};
---------
sdio_match_device(func, drv);
----------------
if (ids) {
while (ids->class || ids->vendor || ids->device) {
if (sdio_match_one(func, ids))
return ids;
ids++;
}
}-----------------------
static const struct sdio_device_id *sdio_match_one(struct sdio_func *func,
const struct sdio_device_id *id)
{
if (id->class != (__u8)SDIO_ANY_ID && id->class != func->class)
return NULL;
if (id->vendor != (__u16)SDIO_ANY_ID && id->vendor != func->vendor)
return NULL;
if (id->device != (__u16)SDIO_ANY_ID && id->device != func->device)
return NULL;
return id;
}-------------
最终通过驱动和设备struct sdio_device_id进行匹配!如果找到驱动,则会执行驱动的probe,进行一系列设备的初始化。
SDIO接口的wifi的通信接口也是mmc系统,所以wifi驱动也要加上一层mmc驱动的外衣。
这里主要分析:If_sdio.c (drivers\net\wireless\libertas)
首先是sdio注册驱动:
sdio_register_driver(&if_sdio_driver);
假设现在总线已经找到了设备对应的驱动,先面就是执行static int if_sdio_probe
probe关于wifi模块的操作主要是:
1、调用函数alloc_netdev()函数分配网络设备。
2、对网络设备dev进行初始化,操作函数绑定之后,接着调用了register_netdev(dev)函数,将网络设备注入到内核。
到这里可以在系统跑起来后用ifconfig命令来查看这个网络设备,还可以设置这个网络设备的ip地址,网关,子网掩码等。
在这个probe函数中还创建了一个内核线程,用来管理这个网络设备的数据发送、事件的处理(卡的拔出)和一些命令的处理。还申请了一个接收数据中断,只要这个wifi模块接收到数据,就会发送一个中断,告诉sdi host我接收到了数据,然后,host就会发送读取命令,对其进行读取,将读取到的数据放到skbuf中递交给ip层。
数据接收:
if_sdio_probe函数中我们已经申请了一个接收数据的中断
if_sdio_interrupt(),当接收到数据,wifi模块通过产生中断来提醒host去读取数据,host通过发送cmd53命令将数据接收后放到skbuf中,然后调用ip层提供的接口(netif_rx())函数将数据递交到ip层。
具体源码跟踪:
priv = lbs_add_card(card, &func->dev);-->
/* Allocate an Ethernet device and register it */
wdev = lbs_cfg_alloc(dmdev);if (lbs_init_adapter(priv)) {
pr_err("failed to initialize adapter structure\n");
goto err_wdev;
}
dev = alloc_netdev(0, "wlan%d", ether_setup);
register_netdev(dev);
ret = if_sdio_power_on(card);-->
ret = sdio_claim_irq(func, if_sdio_interrupt);
if (cause & IF_SDIO_H_INT_UPLD) {
ret = if_sdio_card_to_host(card);
if (ret)
goto out;
}
case MVMS_DAT:
ret = if_sdio_handle_data(card, card->buffer + 4, chunk - 4);
if (ret)
goto out;
break;
skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + NET_IP_ALIGN);
lbs_process_rxed_packet(card->priv, skb);
if (in_interrupt())
netif_rx(skb);
发送数据的过程:
ip层通过接口(dev_queue_xmit())将数据递交给网络设备协议接口层,网络设备借口层利用netdevice中的注册函数的数据发送函数(.ndo_start_xmit = lbs_hard_start_xmit,),唤醒主线程priv->main_thread,在主线程中回调(priv->hw_host_to_card = if_sdio_host_to_card;)if_sdio_host_to_card()函数。紧接着唤醒packet_work(包处理队列),最后通过sdio协议将数据发送到wifi模块的sram中,wifi模块会自动的将对数据进行处理(例如DA转换等)同无线电波的形式将数据发送到无线路由器。