我们已经知道在insmod 8812.ko的时候,已经注册了一个usb驱动usb_drv->usbdrv, 其中的成员probe是最关键的,接下来我们来详细看一下probe的过程。
.usbdrv.probe = rtw_drv_init,
第一步:
static int rtw_drv_init(struct usb_interface *pusb_intf, const struct usb_device_id *did)
{
int i;
uint status = _FAIL;
_adapter *if1 = NULL, *if2 = NULL;
struct dvobj_priv *dvobj = NULL;
RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_init\n"));
//step 0.
process_spec_devid(did);
从函数名可以知道这是为了处理一些特别的设备,识别这些特殊设备也是通过PIDVID信息来的。
static void process_spec_devid(const struct usb_device_id *pdid)
{
u16 vid, pid;
u32 flags;
int i;
int num = sizeof(specific_device_id_tbl)/sizeof(struct specific_device_id);
for(i=0; i<num; i++)
{
vid = specific_device_id_tbl[i].idVendor;
pid = specific_device_id_tbl[i].idProduct;
flags = specific_device_id_tbl[i].flags;
#ifdef CONFIG_80211N_HT
if((pdid->idVendor==vid) && (pdid->idProduct==pid) && (flags&SPEC_DEV_ID_DISABLE_HT))
{
rtw_ht_enable = 0;
rtw_cbw40_enable = 0;
rtw_ampdu_enable = 0;
}
#endif
#ifdef RTK_DMP_PLATFORM
// Change the ifname to wlan10 when PC side WFD dongle plugin on DMP platform.
// It is used to distinguish between normal and PC-side wifi dongle/module.
if((pdid->idVendor==vid) && (pdid->idProduct==pid) && (flags&SPEC_DEV_ID_ASSIGN_IFNAME))
{
extern char* ifname;
strncpy(ifname, "wlan10", 6);
//DBG_871X("%s()-%d: ifname=%s, vid=%04X, pid=%04X\n", __FUNCTION__, __LINE__, ifname, vid, pid);
}
#endif /* RTK_DMP_PLATFORM */
}
}
specific_device_id_tbl是一张特殊设备列表,rtw_ht_enable、rtw_cbw40_enable、rtw_ampdu_enable这三个标志暂时不知道是用来做什么,后续分析。
第二步:
/* Initialize dvobj_priv */
if ((dvobj = usb_dvobj_init(pusb_intf)) == NULL) {
RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("initialize device object priv Failed!\n"));
goto exit;
}
初始化dvobj_priv结构体,结构体中存放了设备的接口信息、端点信息。
第三步:
/* Initialize if1 */
if ((if1 = rtw_usb_if1_init(dvobj, pusb_intf, did)) == NULL) {
DBG_871X("rtw_usb_if1_init Failed!\n");
goto free_dvobj;
}
初始化wlan0的无线网络节点:
- 识别芯片的型号和硬件型号并记录在wlan0的接口描述结构体中;
- 根据芯片型号将一些处理函数的地址赋给wlan0的描述结构体;
- 为结构体的intf_start和intf_stop两个成员赋值,这两个函数会在ifconfig wlan0 up和down的时候被调用;
- 将一些直接操作结构体的函数地址赋值到结构体中;
- 获取芯片的版本信息,并从芯片的eeprom中读取芯片的mac地址等信息,赋值到结构体中;
- 初始化一些software资源,这里需要进一步分析;
- 设置mac地址。
//dev_alloc_name && register_netdev
if((status = rtw_drv_register_netdev(if1)) != _SUCCESS) {
goto free_if1;
}
完成wlan0的注册。
#ifdef CONFIG_HOSTAPD_MLME
hostapd_mode_init(if1);
#endif
这张网卡是支持AP和STA两种模式的,因此这里也需要初始化AP模式下的一些资源。
probe的主体流程就结束了,这时候有关wlan0这块无线网卡的信息就记录下来了,相关的处理函数接口也都有了,网络设备节点也注册完成了,ifconfig -a就可以看到wlan0的信息了。
下一步是ifconfig wlan0 up,也就是上文中的usb_intf_start函数,了解网卡的启动过程。