module_init(woal_init_module);
初始化wifi模块
module_exit(woal_cleanup_module);
卸载wifi模块
module_param(fw_name, charp, 0);
参数固件的名称。
MODULE_PARM_DESC(fw_name, "Firmware name");
对fw_name进行描述
module_param(fw_crc_check, int, 1);
MODULE_PARM_DESC(fw_crc_check,
"1: Enable FW download CRC check (default); 0: Disable FW download CRC check");
如果fw_crc_check的值为1,则固件下载进行循环冗余校验(默认);如果为0则不进行虚幻冗余校验
module_param(mac_addr, charp, 0);
MODULE_PARM_DESC(mac_addr, "MAC address");
mac_addr 为 物理地址
#ifdef MFG_CMD_SUPPORT
module_param(mfg_mode, int, 0);
MODULE_PARM_DESC(mfg_mode,
"0: Download normal firmware; 1: Download MFG firmware");
如果mfg_mode的值为0则下载普通版的firmware,如果值为1则下载MFGfirmware
#endif /* MFG_CMD_SUPPORT */
module_param(drv_mode, int, 0);
MODULE_PARM_DESC(drv_mode, "1: STA; 2: UAP; 3: STA+UAP");
驱动类型drv_mode=1为STA,drv_mode=2为UAP,drv_mode=3为STA和UAP综合。
#ifdef DEBUG_LEVEL1
module_param(drvdbg, ulong, 0);
MODULE_PARM_DESC(drvdbg, "Driver debug");
drvdbg为 驱动调试
#endif /* DEBUG_LEVEL1 */
module_param(auto_ds, int, 0);
MODULE_PARM_DESC(auto_ds,
"0: MLAN default; 1: Enable auto deep sleep; 2: Disable auto deep sleep");
auto_ds=0就是MLAN默认的模式,auto_ds=1可进入深度睡眠模式, auto_ds=2禁止进入深度睡眠模式。
module_param(ps_mode, int, 0);
MODULE_PARM_DESC(ps_mode,
"0: MLAN default; 1: Enable IEEE PS mode; 2: Disable IEEE PS mode");
ps_mode=0为MALN的默认模式ps_mode=1打开IEEE PS ps_mode =2为关闭IEEE PS(PS 可能代表的是物理时隙)
module_param(max_tx_buf, int, 0);
MODULE_PARM_DESC(max_tx_buf, "Maximum Tx buffer size (2048/4096/8192)");
发送最大缓冲区间大小max_tx_buf的值可以是2048或4096或8192
#ifdef SDIO_SUSPEND_RESUME
module_param(pm_keep_power, int, 1);
MODULE_PARM_DESC(pm_keep_power, "1: PM keep power (default);
0: PM no power");电源管理pm_keep_power=1能管理,0失去管理能力
#endif
#if defined(STA_SUPPORT)
module_param(cfg_11d, int, 0);
MODULE_PARM_DESC(cfg_11d,
"0: MLAN default; 1: Enable 802.11d; 2: Disable 802.11d");
cfg_11d=0代表MLAN默认的模式,cfg_11d=1代表打开802.11d,cfg_11d=2代表关闭802.11b
#endif
初始化MLAN模块,返回值为 MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
static int
woal_init_module(void)
{
int ret = (int) MLAN_STATUS_SUCCESS;
unsigned int i = 0;
int index = 0;
ENTER();
/* Init the wlan_private pointer array first */
首先初始化WLAN自身的指针数组 m_handle
for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
MAX_MLAN_ADAPTER默认值为2
m_handle[index] = NULL;
}
/* Replace default fw image name for specific drv_mode */
把默认的固件镜像替换为指定的 drv_mode
if (fw_name) {
for (i = 0; i < (sizeof(drv_mode_tbl) / sizeof(drv_mode_tbl[0])); i++) {
if (drv_mode_tbl[i].drv_mode == drv_mode) {
drv_mode_tbl[i].fw_name = fw_name;
break;
}
}
}
/* Init mutex */
MOAL_INIT_SEMAPHORE(&AddRemoveCardSem);
初始化一个信号量作为互斥信号
/* Register with bus */
ret = woal_bus_register();
把模块注册到总线上
LEAVE();
return ret;
}
/**
* @brief This function registers the IF module in bus driver
把IF(不知道什么意思)注册到总线驱动上
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status
woal_bus_register(void)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
ENTER();
/* SDIO Driver Registration */
if (sdio_register_driver(&wlan_sdio)) {
把WLAN的sdio驱动结构链接到sdio驱动上。
PRINTM(MFATAL, "SDIO Driver Registration Failed \n");
LEAVE();
return MLAN_STATUS_FAILURE;
}
LEAVE();
return ret;
}
在这分支:
一、wlan_sdio结构体分支下
static struct sdio_driver wlan_sdio = {
.name = "wlan_sdio",
.id_table = wlan_ids,
.probe = woal_sdio_probe,
.remove = woal_sdio_remove,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
.drv = {
.owner = THIS_MODULE,
#ifdef SDIO_SUSPEND_RESUME
#ifdef MMC_PM_KEEP_POWER
.pm = &wlan_sdio_pm_ops,
#endif
#endif
}
#else
#ifdef SDIO_SUSPEND_RESUME
#ifdef MMC_PM_KEEP_POWER
.drv = {
.pm = &wlan_sdio_pm_ops,
}
#endif
#endif
#endif
};
注册一个sdio_driver类型的wlan_sdio设备
这里初始化的并不是全部的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;
};
这里有一个 device_driver类型的drv 结构体
struct device_driver {
const char *name;
struct bus_type *bus;
struct module *owner;
const char *mod_name; /* used for built-in modules */
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
#if defined(CONFIG_OF)
const struct of_device_id *of_match_table;
#endif
int (*probe) (struct device *dev);
int (*remove) (struct device *dev);
void (*shutdown) (struct device *dev);
int (*suspend) (struct device *dev, pm_message_t state);
int (*resume) (struct device *dev);
const struct attribute_group **groups;
const struct dev_pm_ops *pm;
struct driver_private *p;
};
二、sdio_register_driver函数分支下
int sdio_register_driver(struct sdio_driver *drv)
{
drv->drv.name = drv->name;
drv->drv.name指的是sdio_driver下的drv结构体(也就是device_driver结构体)下的*name,而drv->name指的是wlan_sdio下的 .name="wlan_sdio"
drv->drv.bus = &sdio_bus_type;
drv->drv.bus指的是sdio_driver下的drv结构体(也就是device_driver结构体)下的*bus,因为挂载在sdio总线上,所以类型直接赋值为 sdio_bus_type 。
return driver_register(&drv->drv);
注册设备wlan_sdio设备对应的设备驱动,并且寻找对应的设备并与之关联。
}
.id_table = wlan_ids ---------> const struct sdio_device_id *id_table; ------------->
struct sdio_device_id {
__u8 class; /* Standard interface or SDIO_ANY_ID */
__u16 vendor; /* Vendor or SDIO_ANY_ID */
__u16 device; /* Device ID or SDIO_ANY_ID */
kernel_ulong_t driver_data /* Data private to the driver */
__attribute__((aligned(sizeof(kernel_ulong_t))));
};
一个 sdio_driver 会把它的这张id 表去和每一个sdio 设备的实际情况进行比较,如果该设备的实际情况和这张表里的某一个id 相同,准确地说,只有这许多特征都吻合,才能够把一个sdio device 和这个sdio driver 进行绑定,这些特征哪怕差一点也不行.就像我们每个人都是一道弧,都在不停寻找能让彼此嵌成完整的圆的另一道弧,事实却是,每个人对PI的理解不尽相同, 而圆心能否重合,或许只有痛过才知道.差之毫厘,失之交臂.
/** @brief This function handles client driver probe.
*
* @param func A pointer to sdio_func structure.
* @param id A pointer to sdio_device_id structure.
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
static int
woal_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) 将驱动程序和设备进行绑定
{
int ret = MLAN_STATUS_SUCCESS;
struct sdio_mmc_card *card = NULL;
moal_handle *handle;
ENTER();
PRINTM(MINFO, "vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n",
func->vendor, func->device, func->class, func->num);
card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL);
if (!card) {
PRINTM(MFATAL, "Failed to allocate memory in probe function!\n");
LEAVE();
return -ENOMEM;
}
card->func = func;
#ifdef MMC_QUIRK_BLKSZ_FOR_BYTE_MODE
/* The byte mode patch is available in kernel MMC driver which fixes one
issue in MP-A transfer. bit1: use func->cur_blksize for byte mode */
func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
/* wait for chip fully wake up */
if (!func->enable_timeout)
func->enable_timeout = 200;
#endif
sdio_claim_host(func);
/*
调用的是mmc_claim_host(func->card->host);后面注释。
*/
ret = sdio_enable_func(func);
if (ret) {
sdio_disable_func(func);
sdio_release_host(func);
kfree(card);
PRINTM(MFATAL, "sdio_enable_func() failed: ret=%d\n", ret);
LEAVE();
return -EIO;
}
sdio_release_host(func);
if (NULL == (handle = woal_add_card(card))) {
PRINTM(MERROR, "woal_add_card failed\n");
kfree(card);
sdio_claim_host(func);
sdio_disable_func(func);
sdio_release_host(func);
ret = MLAN_STATUS_FAILURE;
}
LEAVE();
return ret;
}
/** Structure: SDIO MMC card */
struct sdio_mmc_card
{
/** sdio_func structure pointer */
struct sdio_func *func;
/** moal_handle structure pointer */
moal_handle *handle;
/** saved host clock value */
unsigned int host_clock;
};
/**
* sdio_claim_host - exclusively claim a bus for a certain SDIO function
* @func: SDIO function that will be accessed
*
* Claim a bus for a set of operations. The SDIO function given
* is used to figure out which bus is relevant.
*/
void sdio_claim_host(struct sdio_func *func)
{
BUG_ON(!func);
BUG_ON(!func->card);
mmc_claim_host(func->card->host);
}
EXPORT_SYMBOL_GPL(sdio_claim_host);
/*
驱动中使用mmc_claim_host(host);来得知,当前mmc控制器是否被占用,当前mmc控制器如果被占用,那么 host->claimed = 1;否则为0,如果为1,那么会在for(;;)循环中调用schedule切换出自己,当占用mmc控制器的操作完成之后,执行 mmc_release_host()的时候,会激活登记到等待队列&host->wq中的其他程序获得mmc主控制器的物理使用权
*/
/**
* sdio_enable_func - enables a SDIO function for usage
* @func: SDIO function to enable
*
* Powers up and activates a SDIO function so that register
* access is possible.
*/
int sdio_enable_func(struct sdio_func *func)
{
int ret;
unsigned char reg;
unsigned long timeout;
BUG_ON(!func);
BUG_ON(!func->card);
pr_debug("SDIO: Enabling device %s...\n", sdio_func_id(func));
ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IOEx, 0, ®);
if (ret)
goto err;
reg |= 1 << func->num;
ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IOEx, reg, NULL);
if (ret)
goto err;
timeout = jiffies + msecs_to_jiffies(func->enable_timeout);
while (1) {
ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IORx, 0, ®);
if (ret)
goto err;
if (reg & (1 << func->num))
break;
ret = -ETIME;
if (time_after(jiffies, timeout))
goto err;
}
pr_debug("SDIO: Enabled device %s\n", sdio_func_id(func));
return 0;
err:
pr_debug("SDIO: Failed to enable device %s\n", sdio_func_id(func));
return ret;
}
mmc_io_rw_direct()把所有参数直接传递给mmc_io_rw_direct_host()SDIO功能部分简单了解下就可以,一般HOST部分芯片厂商都会做好。
/**
* @brief This function adds the card. it will probe the
* card, allocate the mlan_private and initialize the device.
*
* @param card A pointer to card
*
* @return A pointer to moal_handle structure
*/
moal_handle *
woal_add_card(void *card)
{
moal_handle *handle = NULL;
mlan_status status = MLAN_STATUS_SUCCESS;
int i;
int netlink_num = NETLINK_MARVELL;
int index = 0;
ENTER();
if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem))
goto exit_sem_err;
/* Allocate buffer for moal_handle */
if (!(handle = kmalloc(sizeof(moal_handle), GFP_ATOMIC))) {
PRINTM(MERROR, "Allocate buffer for moal_handle failed!\n");
goto err_handle;
}
/* Init moal_handle */
memset(handle, 0, sizeof(moal_handle));
handle->card = card;
/* Save the handle */
for (index = 0; index < MAX_MLAN_ADAPTER; index++) {
if (m_handle[index] == NULL)
break;
}
if (index < MAX_MLAN_ADAPTER) {
m_handle[index] = handle;
handle->handle_idx = index;
} else {
PRINTM(MERROR, "Exceeded maximum cards supported!\n");
goto err_kmalloc;
}
if (mac_addr) {
t_u8 temp[20];
t_u8 len = strlen(mac_addr) + 1;
if (len < sizeof(temp)) {
memcpy(temp, mac_addr, len);
handle->set_mac_addr = 1;
/* note: the following function overwrites the temp buffer */
woal_mac2u8(handle->mac_addr, temp);
}
}
((struct sdio_mmc_card *) card)->handle = handle;
/* Init SW */
if (MLAN_STATUS_SUCCESS != woal_init_sw(handle)) {
PRINTM(MFATAL, "Software Init Failed\n");
goto err_kmalloc;
}
do {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
handle->nl_sk =
netlink_kernel_create(netlink_num, NL_MULTICAST_GROUP, NULL,
THIS_MODULE);
#else
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
handle->nl_sk =
netlink_kernel_create(netlink_num, NL_MULTICAST_GROUP, NULL, NULL,
THIS_MODULE);
#else
handle->nl_sk =
netlink_kernel_create(&init_net, netlink_num, NL_MULTICAST_GROUP,
NULL, NULL, THIS_MODULE);
#endif
#endif
if (handle->nl_sk) {
PRINTM(MINFO, "Netlink number = %d\n", netlink_num);
handle->netlink_num = netlink_num;
break;
}
netlink_num--;
} while (netlink_num > 0);
if (handle->nl_sk == NULL) {
PRINTM(MERROR,
"Could not initialize netlink event passing mechanism!\n");
goto err_kmalloc;
}
/** Create workqueue */
handle->workqueue = create_workqueue("MOAL_WORK_QUEUE");
if (!handle->workqueue)
goto err_kmalloc;
MLAN_INIT_WORK(&handle->main_work, woal_main_work_queue);
#ifdef REASSOCIATION
PRINTM(MINFO, "Starting re-association thread...\n");
handle->reassoc_thread.handle = handle;
woal_create_thread(woal_reassociation_thread,
&handle->reassoc_thread, "woal_reassoc_service");
while (!handle->reassoc_thread.pid) {
woal_sched_timeout(2);
}
#endif /* REASSOCIATION */
/* Register the device. Fill up the private data structure with relevant
information from the card and request for the required IRQ. */
if (woal_register_dev(handle) != MLAN_STATUS_SUCCESS) {
PRINTM(MFATAL, "Failed to register wlan device!\n");
goto err_registerdev;
}
/* Since settling time after runtime resume is huge (~10s) we
can't really use runtime PM. Fortunatelly the firmware is quite
good at conserving power when the device is not used. */
pm_runtime_forbid(&((struct sdio_mmc_card *)card)->func->dev);
/* Init FW and HW */
if (MLAN_STATUS_SUCCESS != woal_init_fw(handle)) {
PRINTM(MFATAL, "Firmware Init Failed\n");
goto err_init_fw;
}
#ifdef CONFIG_PROC_FS
/* Initialize proc fs */
woal_proc_init(handle);
#endif /* CONFIG_PROC_FS */
/* Add interfaces */
for (i = 0; i < handle->drv_mode->intf_num; i++) {
if (!woal_add_interface
(handle, handle->priv_num,
handle->drv_mode->bss_attr[i].bss_type)) {
status = MLAN_STATUS_FAILURE;
break;
}
handle->priv_num++;
}
if (status != MLAN_STATUS_SUCCESS)
goto err_add_intf;
MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
LEAVE();
return handle;
err_add_intf:
for (i = 0; i < handle->priv_num; i++)
woal_remove_interface(handle, i);
#ifdef CONFIG_PROC_FS
woal_proc_exit(handle);
#endif
err_init_fw:
pm_runtime_allow(&((struct sdio_mmc_card *)card)->func->dev);
/* Unregister device */
PRINTM(MINFO, "unregister device\n");
woal_unregister_dev(handle);
err_registerdev:
handle->surprise_removed = MTRUE;
woal_terminate_workqueue(handle);
#ifdef REASSOCIATION
if (handle->reassoc_thread.pid) {
wake_up_interruptible(&handle->reassoc_thread.wait_q);
}
/* waiting for main thread quit */
while (handle->reassoc_thread.pid) {
woal_sched_timeout(2);
}
#endif /* REASSOCIATION */
err_kmalloc:
if ((handle->hardware_status == HardwareStatusFwReady) ||
(handle->hardware_status == HardwareStatusReady)) {
PRINTM(MINFO, "shutdown mlan\n");
handle->init_wait_q_woken = MFALSE;
status = mlan_shutdown_fw(handle->pmlan_adapter);
if (status == MLAN_STATUS_PENDING)
wait_event_interruptible(handle->init_wait_q,
handle->init_wait_q_woken);
}
woal_free_moal_handle(handle);
if (index < MAX_MLAN_ADAPTER) {
m_handle[index] = NULL;
}
((struct sdio_mmc_card *) card)->handle = NULL;
err_handle:
MOAL_REL_SEMAPHORE(&AddRemoveCardSem);
exit_sem_err:
LEAVE();
return NULL;
}