您的位置:首页 > 其它

wifi driver 学习笔记 - gangyanliang的专栏 - 博客频道 - CSDN.NET

2013-08-08 07:55 525 查看
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 span style='font-size:14px;font-style:normal;font-weight:bold;color:rgb(51, 51, 51);' >MAX_MLAN_ADAPTER默认值为2</span>

m_handle[index] = NULL;

}

/* Replace default fw image name for specific drv_mode */ 把默认的固件镜像替换为指定的 drv_mode

if (fw_name) {

for (i = 0; i < sizeofdrv mode_tbl sizeofdrv_mode_tbl i br style='font-size:14px;font-style:normal;font-weight:normal;color:rgb(51, 51, 51);' /> 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 br style='font-size:14px;font-style:normal;font-weight:normal;color:rgb(51, 51, 51);' /> if (m_handle[index] == NULL)

break;

}

if (index < MAX MLAN_ADAPTER br style='font-size:14px;font-style:normal;font-weight:normal;color:rgb(51, 51, 51);' /> 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 br style='font-size:14px;font-style:normal;font-weight:normal;color:rgb(51, 51, 51);' /> 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 VERSIONbr style='font-size:14px;font-style:normal;font-weight:normal;color:rgb(51, 51, 51);' /> handle-<nl_sk =

netlink_kernel_create(netlink_num, NL_MULTICAST_GROUP, NULL,

THIS_MODULE);

#else

#if LINUX_VERSION_CODE < KERNEL VERSIONbr style='font-size:14px;font-style:normal;font-weight:normal;color:rgb(51, 51, 51);' /> 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 br style='font-size:14px;font-style:normal;font-weight:normal;color:rgb(51, 51, 51);' /> m_handle[index] = NULL;

}

((struct sdio_mmc_card *) card)-<handle = NULL;

err_handle:

MOAL_REL_SEMAPHORE(&AddRemoveCardSem);

exit_sem_err:

LEAVE();

return NULL;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐