本文单板mmp3 pxa2128
我们先看下probe过程吧,然后再一个一个展开讲解
- /**
- * @brief This function probe the card
- *
- * @param func A pointer to sdio_func structure.
- * @param id A pointer to structure sd_device_id
- * @return BT_STATUS_SUCCESS/BT_STATUS_FAILURE or other error no.
- */
- static int
- sd_probe_card(struct sdio_func *func, const struct sdio_device_id *id)
- {
- int ret = BT_STATUS_SUCCESS;
- bt_private *priv = NULL;
- struct sdio_mmc_card *card = NULL;
- ENTER();
- PRINTM(INFO, "BT: vendor=0x%x,device=0x%x,class=%d,fn=%d\n", id->vendor,
- id->device, id->class, func->num);
- card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL);
- if (!card) {
- ret = -ENOMEM;
- goto done;
- }
- card->func = func;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
- /* wait for chip fully wake up */
- if (!func->enable_timeout)
- func->enable_timeout = 200;
- #endif
- /*
- 驱动中使用mmc_claim_host(host);来得知,当前mmc控制器是否被占用,
- 当前mmc控制器如果被占用,那么 host->claimed = 1;否则为0,如果为1,
- 那么会在for(;;)循环中调用schedule切换出自己,当占用mmc控制器的
- 操作完成之后,执行 mmc_release_host()的时候,会激活登记到等待队
- 列&host->wq中的其他程序获得mmc主控制器的物理使用权*/
- sdio_claim_host(func);
- /* mmc_io_rw_direct()把所有参数直接传递给mmc_io_rw_direct_host()
- SDIO功能部分简单了解下就可*/
- /*使能sdio功能设备*/
- ret = sdio_enable_func(func);
- if (ret) {
- sdio_disable_func(func);
- sdio_release_host(func);
- PRINTM(FATAL, "BT: sdio_enable_func() failed: ret=%d\n", ret);
- kfree(card);
- LEAVE();
- return -EIO;
- }
- /* 释放mmc控制器 */
- sdio_release_host(func);
- priv = bt_add_card(card);
- if (!priv) {
- sdio_claim_host(func);
- sdio_disable_func(func);
- sdio_release_host(func);
- ret = BT_STATUS_FAILURE;
- kfree(card);
- }
- done:
- LEAVE();
- return ret;
- }
/** * @brief This function probe the card * * @param func A pointer to sdio_func structure. * @param id A pointer to structure sd_device_id * @return BT_STATUS_SUCCESS/BT_STATUS_FAILURE or other error no. */ static int sd_probe_card(struct sdio_func *func, const struct sdio_device_id *id) { int ret = BT_STATUS_SUCCESS; bt_private *priv = NULL; struct sdio_mmc_card *card = NULL; ENTER(); PRINTM(INFO, "BT: vendor=0x%x,device=0x%x,class=%d,fn=%d\n", id->vendor, id->device, id->class, func->num); card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL); if (!card) { ret = -ENOMEM; goto done; } card->func = func; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) /* wait for chip fully wake up */ if (!func->enable_timeout) func->enable_timeout = 200; #endif /* 驱动中使用mmc_claim_host(host);来得知,当前mmc控制器是否被占用, 当前mmc控制器如果被占用,那么 host->claimed = 1;否则为0,如果为1, 那么会在for(;;)循环中调用schedule切换出自己,当占用mmc控制器的 操作完成之后,执行 mmc_release_host()的时候,会激活登记到等待队 列&host->wq中的其他程序获得mmc主控制器的物理使用权*/ sdio_claim_host(func); /* mmc_io_rw_direct()把所有参数直接传递给mmc_io_rw_direct_host() SDIO功能部分简单了解下就可*/ /*使能sdio功能设备*/ ret = sdio_enable_func(func); if (ret) { sdio_disable_func(func); sdio_release_host(func); PRINTM(FATAL, "BT: sdio_enable_func() failed: ret=%d\n", ret); kfree(card); LEAVE(); return -EIO; } /* 释放mmc控制器 */ sdio_release_host(func); priv = bt_add_card(card); if (!priv) { sdio_claim_host(func); sdio_disable_func(func); sdio_release_host(func); ret = BT_STATUS_FAILURE; kfree(card); } done: LEAVE(); return ret; }
这里主要讲解download firmware
再看bt_add_card(card)函数实现:
- /**
- * @brief This function adds the card. it will probe the
- * card, allocate the bt_priv and initialize the device.
- *
- * @param card A pointer to card
- * @return A pointer to bt_private structure
- */
- bt_private *
- bt_add_card(void *card)
- {
- struct hci_dev *hdev = NULL;
- bt_private *priv = NULL;
- ENTER();
- priv = kzalloc(sizeof(bt_private), GFP_KERNEL);
- if (!priv) {
- PRINTM(FATAL, "Can not allocate priv\n");
- LEAVE();
- return NULL;
- }
- /* allocate buffer for bt_adapter */
- if (!(priv->adapter = kzalloc(sizeof(bt_adapter), GFP_KERNEL))) {
- PRINTM(FATAL, "Allocate buffer for bt_adapter failed!\n");
- goto err_kmalloc;
- }
- /* 初始化发送队列,挂起队列及command队列的头*/
- bt_init_adapter(priv);
- /* Register to HCI Core */
- hdev = hci_alloc_dev();
- if (!hdev) {
- PRINTM(FATAL, "Can not allocate HCI device\n");
- goto err_kmalloc;
- }
- PRINTM(INFO, "Starting kthread...\n");
- priv->MainThread.priv = priv;
- spin_lock_init(&priv->driver_lock);
- /* 通过固件产生收发事件,从固件接受数据包,并
- 将接受的数据包发送给kernel */
- bt_create_thread(bt_service_main_thread, &priv->MainThread,
- "bt_main_service");
- /* wait for mainthread to up */
- while (!priv->MainThread.pid) {
- os_sched_timeout(1);
- }
- priv->bt_dev.hcidev = hdev;
- priv->bt_dev.card = card;
- hdev->driver_data = priv;
- ((struct sdio_mmc_card *) card)->priv = priv;
- priv->adapter->sd_ireg = 0;
- /*
- * Register the device. Fillup the private data structure with
- * relevant information from the card and request for the required
- * IRQ.
- */
- if (sbi_register_dev(priv) < 0) {
- PRINTM(FATAL, "Failed to register bt device!\n");
- goto err_registerdev;
- }
- if (bt_init_fw(priv)) {
- PRINTM(FATAL, "BT Firmware Init Failed\n");
- goto err_init_fw;
- }
- LEAVE();
- return priv;
- err_init_fw:
- PRINTM(INFO, "unregister device\n");
- sbi_unregister_dev(priv);
- err_registerdev:
- ((struct sdio_mmc_card *) card)->priv = NULL;
- /* Stop the thread servicing the interrupts */
- priv->adapter->SurpriseRemoved = TRUE;
- wake_up_interruptible(&priv->MainThread.waitQ);
- while (priv->MainThread.pid) {
- os_sched_timeout(1);
- }
- err_kmalloc:
- if (hdev)
- kfree(hdev);
- if (priv->adapter)
- bt_free_adapter(priv);
- kfree(priv);
- LEAVE();
- return NULL;
- }
/** * @brief This function adds the card. it will probe the * card, allocate the bt_priv and initialize the device. * * @param card A pointer to card * @return A pointer to bt_private structure */ bt_private * bt_add_card(void *card) { struct hci_dev *hdev = NULL; bt_private *priv = NULL; ENTER(); priv = kzalloc(sizeof(bt_private), GFP_KERNEL); if (!priv) { PRINTM(FATAL, "Can not allocate priv\n"); LEAVE(); return NULL; } /* allocate buffer for bt_adapter */ if (!(priv->adapter = kzalloc(sizeof(bt_adapter), GFP_KERNEL))) { PRINTM(FATAL, "Allocate buffer for bt_adapter failed!\n"); goto err_kmalloc; } /* 初始化发送队列,挂起队列及command队列的头*/ bt_init_adapter(priv); /* Register to HCI Core */ hdev = hci_alloc_dev(); if (!hdev) { PRINTM(FATAL, "Can not allocate HCI device\n"); goto err_kmalloc; } PRINTM(INFO, "Starting kthread...\n"); priv->MainThread.priv = priv; spin_lock_init(&priv->driver_lock); /* 通过固件产生收发事件,从固件接受数据包,并 将接受的数据包发送给kernel */ bt_create_thread(bt_service_main_thread, &priv->MainThread, "bt_main_service"); /* wait for mainthread to up */ while (!priv->MainThread.pid) { os_sched_timeout(1); } priv->bt_dev.hcidev = hdev; priv->bt_dev.card = card; hdev->driver_data = priv; ((struct sdio_mmc_card *) card)->priv = priv; priv->adapter->sd_ireg = 0; /* * Register the device. Fillup the private data structure with * relevant information from the card and request for the required * IRQ. */ if (sbi_register_dev(priv) < 0) { PRINTM(FATAL, "Failed to register bt device!\n"); goto err_registerdev; } if (bt_init_fw(priv)) { PRINTM(FATAL, "BT Firmware Init Failed\n"); goto err_init_fw; } LEAVE(); return priv; err_init_fw: PRINTM(INFO, "unregister device\n"); sbi_unregister_dev(priv); err_registerdev: ((struct sdio_mmc_card *) card)->priv = NULL; /* Stop the thread servicing the interrupts */ priv->adapter->SurpriseRemoved = TRUE; wake_up_interruptible(&priv->MainThread.waitQ); while (priv->MainThread.pid) { os_sched_timeout(1); } err_kmalloc: if (hdev) kfree(hdev); if (priv->adapter) bt_free_adapter(priv); kfree(priv); LEAVE(); return NULL; }
这段代码在sbi_register_dev(priv)后便调用了我们关注的bt_init_fw(priv)函数。
下面我们详解bt_init_fw函数过程
首先要说明下hci_dev中的几个函数指针{open;close;flush;send;destruct;ioctl}由代码bt_main.c中的sd_register_conf_dpc这个函数注册
函数实现:
- /**
- * @brief This function initializes firmware
- *
- * @param priv A pointer to bt_private structure
- * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
- */
- static int
- bt_init_fw(bt_private * priv)
- {
- int ret = BT_STATUS_SUCCESS;
- ENTER();
- if (fw == 0) { //fw这是个全局变量,当firmware已经初始化时将不再初始化,使能host后直接返回OK,假设尚未初始化的话,那么就执行sbi_disable_host_int函数
- sbi_enable_host_int(priv);
- goto done;
- }
- sbi_disable_host_int(priv);
- priv->fw_crc_check = fw_crc_check; //为1,进行CRC校验
- if (sbi_download_fw(priv)) { //这里就开始download firmware了!!下面着重讲解download
- PRINTM(ERROR, "BT FW failed to be download!\n");
- ret = BT_STATUS_FAILURE;
- goto done;
- }
- done:
- LEAVE();
- return ret;
- }
/** * @brief This function initializes firmware * * @param priv A pointer to bt_private structure * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE */ static int bt_init_fw(bt_private * priv) { int ret = BT_STATUS_SUCCESS; ENTER(); if (fw == 0) { //fw这是个全局变量,当firmware已经初始化时将不再初始化,使能host后直接返回OK,假设尚未初始化的话,那么就执行sbi_disable_host_int函数 sbi_enable_host_int(priv); goto done; } sbi_disable_host_int(priv); priv->fw_crc_check = fw_crc_check; //为1,进行CRC校验 if (sbi_download_fw(priv)) { //这里就开始download firmware了!!下面着重讲解download PRINTM(ERROR, "BT FW failed to be download!\n"); ret = BT_STATUS_FAILURE; goto done; } done: LEAVE(); return ret; }
download firmware过程代码蛮复杂,我们慢慢分析!
- sdio_claim_host(card->func);
- if (BT_STATUS_SUCCESS == sd_verify_fw_download(priv, 1)) { //<SPAN style="FONT-SIZE: 24px">第一大事情是确实固件是否准备好接受cmd</SPAN>
- PRINTM(MSG, "BT: FW already downloaded!\n");
- sdio_release_host(card->func);
- sbi_enable_host_int(priv);
- if (BT_STATUS_FAILURE == sd_register_conf_dpc(priv)) { // 注册hci_dev需要的几大函数指针,上文已经提到
- PRINTM(ERROR,
- "BT: sd_register_conf_dpc failed. Terminating download\n");
- ret = BT_STATUS_FAILURE;
- }
- goto exit;
- }
sdio_claim_host(card->func);
if (BT_STATUS_SUCCESS == sd_verify_fw_download(priv, 1)) { //第一大事情是确实固件是否准备好接受cmd
PRINTM(MSG, "BT: FW already downloaded!\n");
sdio_release_host(card->func);
sbi_enable_host_int(priv);
if (BT_STATUS_FAILURE == sd_register_conf_dpc(priv)) { // 注册hci_dev需要的几大函数指针,上文已经提到
PRINTM(ERROR,
"BT: sd_register_conf_dpc failed. Terminating download\n");
ret = BT_STATUS_FAILURE;
}
goto exit;
}
如何确认固件是否已经好的话,调用sd_read_firmware_status此函数,如下所示:
- /**
- * @brief This function reads fwstatus registers
- *
- * @param priv A pointer to bt_private structure
- * @param dat A pointer to keep returned data
- * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
- */
- static int //此函数实际被sd_verify_fw_download他调用
- sd_read_firmware_status(bt_private * priv, u16 * dat)
- {
- int ret = BT_STATUS_SUCCESS;
- u8 fws0;
- u8 fws1;
- struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card;
- ENTER();<SPAN style="WHITE-SPACE: pre"> </SPAN> // 调试信息
- fws0 = sdio_readb(card->func, CARD_FW_STATUS0_REG, &ret); //读reg FW_STATUS0
- if (ret < 0) {
- LEAVE();
- return BT_STATUS_FAILURE;
- }
- fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret); //读reg FW_STATUS1
- if (ret < 0) {
- LEAVE();
- return BT_STATUS_FAILURE;
- }
- *dat = (((u16) fws1) << 8) | fws0;
- LEAVE();
- return BT_STATUS_SUCCESS; //我们都假设成功正常返回
- }
/**
* @brief This function reads fwstatus registers
*
* @param priv A pointer to bt_private structure
* @param dat A pointer to keep returned data
* @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
*/
static int //此函数实际被sd_verify_fw_download他调用
sd_read_firmware_status(bt_private * priv, u16 * dat)
{
int ret = BT_STATUS_SUCCESS;
u8 fws0;
u8 fws1;
struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card;
ENTER(); // 调试信息
fws0 = sdio_readb(card->func, CARD_FW_STATUS0_REG, &ret); //读reg FW_STATUS0
if (ret < 0) {
LEAVE();
return BT_STATUS_FAILURE;
}
fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret); //读reg FW_STATUS1
if (ret < 0) {
LEAVE();
return BT_STATUS_FAILURE;
}
*dat = (((u16) fws1) << 8) | fws0;
LEAVE();
return BT_STATUS_SUCCESS; //我们都假设成功正常返回
}
假设这个函数成功了,那么将进行sd_register_conf_dpc(前面两个函数不说了,大家应该都比较清楚了!),这个函数的注释说用来:第一,模块组态;第二注册设备。
在把hci_dev的函数指针都填充后调用bt_send_module_cfg_cmd
- hdev->open = bt_open;
- hdev->close = bt_close;
- hdev->flush = bt_flush;
- hdev->send = bt_send_frame;
- hdev->destruct = bt_destruct;
- hdev->ioctl = bt_ioctl;
hdev->open = bt_open; hdev->close = bt_close; hdev->flush = bt_flush; hdev->send = bt_send_frame; hdev->destruct = bt_destruct; hdev->ioctl = bt_ioctl;
这个函数涉及到了sk_buff这个网络里面常用的结构体,同时注释里面说明了发送module cfg cmd到firmware的格式
- /**
- * @brief This function send module cfg cmd to firmware
- *
- * Command format:
- * +--------+--------+--------+--------+--------+--------+--------+
- * | OCF OGF | Length | Data |
- * +--------+--------+--------+--------+--------+--------+--------+
- * | 2-byte | 1-byte | 4-byte |
- * +--------+--------+--------+--------+--------+--------+--------+
- *
- * @param priv A pointer to bt_private structure
- * @param subcmd sub command
- * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
- */
/** * @brief This function send module cfg cmd to firmware * * Command format: * +--------+--------+--------+--------+--------+--------+--------+ * | OCF OGF | Length | Data | * +--------+--------+--------+--------+--------+--------+--------+ * | 2-byte | 1-byte | 4-byte | * +--------+--------+--------+--------+--------+--------+--------+ * * @param priv A pointer to bt_private structure * @param subcmd sub command * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE */
- int
- bt_send_module_cfg_cmd(bt_private * priv, int subcmd)
- {
- struct sk_buff *skb = NULL;
- u8 ret = BT_STATUS_SUCCESS;
- BT_CMD *pCmd;
- ENTER();
- skb = bt_skb_alloc(sizeof(BT_CMD), GFP_ATOMIC);
- if (skb == NULL) {
- PRINTM(WARN, "BT: No free skb\n");
- ret = BT_STATUS_FAILURE;
- goto exit;
- }
- pCmd = (BT_CMD *) skb->tail; //填充sk_buff
- pCmd->ocf_ogf = (OGF << 10) | BT_CMD_MODULE_CFG_REQ; //(0x3f << 10 | 0x5b)
- pCmd->length = 1;
- pCmd->data[0] = subcmd; //MODULE_BRINGUP_REQ 0xf1
- bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; // 0xfe
- skb_put(skb, sizeof(BT_CMD));
- skb->dev = (void *) priv->bt_dev.hcidev;
- skb_queue_head(&priv->adapter->tx_queue, skb); //吧skb插入tx_queue链表中
- priv->bt_dev.sendcmdflag = TRUE;
- priv->bt_dev.send_cmd_ocf = BT_CMD_MODULE_CFG_REQ; //0x5b
- priv->adapter->cmd_complete = FALSE;
- PRINTM(CMD, "Queue module cfg Command(0x%x)\n", pCmd->ocf_ogf);
- wake_up_interruptible(&priv->MainThread.waitQ);//唤醒在probe时创建的线程来处理这个skb
- /*
- On some Android platforms certain delay is needed for HCI daemon to
- remove this module and close itself gracefully. Otherwise it hangs. This
- 10ms delay is a workaround for such platforms as the root cause has not
- been found yet. */
- mdelay(10);
- if (!os_wait_interruptible_timeout
- (priv->adapter->cmd_wait_q, priv->adapter->cmd_complete,
- WAIT_UNTIL_CMD_RESP)) {
- ret = BT_STATUS_FAILURE;
- PRINTM(MSG, "BT: module_cfg_cmd (0x%x): timeout sendcmdflag=%d\n",
- subcmd, priv->bt_dev.sendcmdflag);
- } else {
- PRINTM(CMD, "BT: module cfg Command done\n");
- }
- exit:
- LEAVE();
- return ret;
- }
int bt_send_module_cfg_cmd(bt_private * priv, int subcmd) { struct sk_buff *skb = NULL; u8 ret = BT_STATUS_SUCCESS; BT_CMD *pCmd; ENTER(); skb = bt_skb_alloc(sizeof(BT_CMD), GFP_ATOMIC); if (skb == NULL) { PRINTM(WARN, "BT: No free skb\n"); ret = BT_STATUS_FAILURE; goto exit; } pCmd = (BT_CMD *) skb->tail; //填充sk_buff pCmd->ocf_ogf = (OGF << 10) | BT_CMD_MODULE_CFG_REQ; //(0x3f << 10 | 0x5b) pCmd->length = 1; pCmd->data[0] = subcmd; //MODULE_BRINGUP_REQ 0xf1 bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; // 0xfe skb_put(skb, sizeof(BT_CMD)); skb->dev = (void *) priv->bt_dev.hcidev; skb_queue_head(&priv->adapter->tx_queue, skb); //吧skb插入tx_queue链表中 priv->bt_dev.sendcmdflag = TRUE; priv->bt_dev.send_cmd_ocf = BT_CMD_MODULE_CFG_REQ; //0x5b priv->adapter->cmd_complete = FALSE; PRINTM(CMD, "Queue module cfg Command(0x%x)\n", pCmd->ocf_ogf); wake_up_interruptible(&priv->MainThread.waitQ);//唤醒在probe时创建的线程来处理这个skb /* On some Android platforms certain delay is needed for HCI daemon to remove this module and close itself gracefully. Otherwise it hangs. This 10ms delay is a workaround for such platforms as the root cause has not been found yet. */ mdelay(10); if (!os_wait_interruptible_timeout (priv->adapter->cmd_wait_q, priv->adapter->cmd_complete, WAIT_UNTIL_CMD_RESP)) { ret = BT_STATUS_FAILURE; PRINTM(MSG, "BT: module_cfg_cmd (0x%x): timeout sendcmdflag=%d\n", subcmd, priv->bt_dev.sendcmdflag); } else { PRINTM(CMD, "BT: module cfg Command done\n"); } exit: LEAVE(); return ret; }
下面返回后到电源管理部分,主要是powermode以及suspend /resume
调用bt_enable_ps及bt_send_hscfg_cmd最后再
wake_up_interruptible(&priv->MainThread.waitQ);
然后调用ret = hci_register_dev(hdev);这个函数在hci_core.c,三个tasklet分别对应hci_cmd_task,hci_rx_task,hci_tx_task以及一个单线程工作队列。
在这个
然后调用bt_init_config(priv, init_cfg) 在bt_init.c中
调用request_firmware -> bt_process_init_cfg(priv, (u8 *) cfg->data, cfg->size);
->bt_set_mac_address(priv, bt_mac) 在这里设置了mac,这个函数实现在bt_main.c中,这个过程也是通过sk_buff这个结构体。
最后再创建bt_proc_init(priv);用户空间文件,函数sd_register_conf_dpc就执行完毕了。
然后调用sd_download_firmware_w_helper(priv)这个函数下载firmware
- /**
- * @brief This function downloads firmware image to the card.
- *
- * @param priv A pointer to bt_private structure
- * @return BT_STATUS_SUCCESS/BT_STATUS_FAILURE or other error no.
- */
- int
- sd_download_firmware_w_helper(bt_private * priv)
- {
- int ret = BT_STATUS_SUCCESS;
- int err;
- char *cur_fw_name = NULL;
- ENTER();
- cur_fw_name = fw_name;
- if (req_fw_nowait) {
- #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32)
- if ((ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
- cur_fw_name, priv->hotplug_device,
- GFP_KERNEL, priv,
- sd_request_fw_callback)) < 0)
/** * @brief This function downloads firmware image to the card. * * @param priv A pointer to bt_private structure * @return BT_STATUS_SUCCESS/BT_STATUS_FAILURE or other error no. */ int sd_download_firmware_w_helper(bt_private * priv) { int ret = BT_STATUS_SUCCESS; int err; char *cur_fw_name = NULL; ENTER(); cur_fw_name = fw_name; if (req_fw_nowait) { #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32) if ((ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, cur_fw_name, priv->hotplug_device, GFP_KERNEL, priv, sd_request_fw_callback)) < 0)
- //实际上下载过程就是最后一个回调函数sd_request_fw_callback了,有兴趣可仔细阅读下。
- #else
- if ((ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
- cur_fw_name, priv->hotplug_device,
- priv, sd_request_fw_callback)) < 0)
- #endif
- PRINTM(FATAL,
- "BT: request_firmware_nowait() failed, error code = %#x\n",
- ret);
- } else {
- if ((err =
- request_firmware(&priv->firmware, cur_fw_name,
- priv->hotplug_device)) < 0) {
- PRINTM(FATAL, "BT: request_firmware() failed, error code = %#x\n",
- err);
- ret = BT_STATUS_FAILURE;
- } else
- ret = sd_request_fw_dpc(priv->firmware, priv);
- }
- LEAVE();
- return ret;
- }
//实际上下载过程就是最后一个回调函数sd_request_fw_callback了,有兴趣可仔细阅读下。 #else if ((ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, cur_fw_name, priv->hotplug_device, priv, sd_request_fw_callback)) < 0) #endif PRINTM(FATAL, "BT: request_firmware_nowait() failed, error code = %#x\n", ret); } else { if ((err = request_firmware(&priv->firmware, cur_fw_name, priv->hotplug_device)) < 0) { PRINTM(FATAL, "BT: request_firmware() failed, error code = %#x\n", err); ret = BT_STATUS_FAILURE; } else ret = sd_request_fw_dpc(priv->firmware, priv); } LEAVE(); return ret; }
这个结束了,probe也就结束了。
刚才好几个地方调用了wakeup一个waitQ,这个实际上也是probe时创建的一个线程,然后sk_buff都是通过这个线程来执行的,这个函数为:
- /**
- * @brief This function handles the major job in bluetooth driver.
- * it handles the event generated by firmware, rx data received
- * from firmware and tx data sent from kernel.
- *
- * @param data A pointer to bt_thread structure
- * @return BT_STATUS_SUCCESS
- */
- static int
- bt_service_main_thread(void *data)
- {
- bt_thread *thread = data;
- bt_private *priv = thread->priv;
- bt_adapter *Adapter = priv->adapter;
- wait_queue_t wait;
- u8 ireg = 0;
- struct sk_buff *skb;
- ENTER();
- bt_activate_thread(thread); // set field pid
- init_waitqueue_entry(&wait, current); // 初始化要等待的队列wait
- current->flags |= PF_NOFREEZE;
- for (;;) {
- add_wait_queue(&thread->waitQ, &wait); // 添加wait到等待队列waitQ中
- OS_SET_THREAD_STATE(TASK_INTERRUPTIBLE);
- if (priv->adapter->WakeupTries ||
- ((!priv->adapter->IntCounter) &&
- (!priv->bt_dev.tx_dnld_rdy ||
- skb_queue_empty(&priv->adapter->tx_queue)))) {
- PRINTM(INFO, "Main: Thread sleeping...\n");
- schedule(); // 睡眠,代码中wake_up_interruptable()函数来唤醒,这是才会继续向下执行
- }
- OS_SET_THREAD_STATE(TASK_RUNNING); // 设置任务已经运行标志
- remove_wait_queue(&thread->waitQ, &wait); // 清楚等待队列链表节点
- if (kthread_should_stop() || Adapter->SurpriseRemoved) {
- PRINTM(INFO, "main-thread: break from main thread: "
- "SurpriseRemoved=0x%x\n", Adapter->SurpriseRemoved);
- break;
- }
- PRINTM(INFO, "Main: Thread waking up...\n"); // 下面就开始处理数据发送了
- if (priv->adapter->IntCounter) {
- OS_INT_DISABLE;
- Adapter->IntCounter = 0;
- OS_INT_RESTORE;
- sbi_get_int_status(priv, &ireg);
- } else if ((priv->adapter->ps_state == PS_SLEEP) &&
- !skb_queue_empty(&priv->adapter->tx_queue)) {
- priv->adapter->WakeupTries++;
- sbi_wakeup_firmware(priv);
- continue;
- }
- if (priv->adapter->ps_state == PS_SLEEP)
- continue;
- if (priv->bt_dev.tx_dnld_rdy == TRUE) {
- if (!skb_queue_empty(&priv->adapter->tx_queue)) {
- skb = skb_dequeue(&priv->adapter->tx_queue); // 摘出要处理的数据
- if (skb) {
- if (SendSinglePacket(priv, skb)) //这个函数就是发送数据了。
- priv->bt_dev.hcidev->stat.err_tx++;
- else
- priv->bt_dev.hcidev->stat.byte_tx += skb->len;
- kfree_skb(skb);
- }
- }
- }
- }
- bt_deactivate_thread(thread);
- LEAVE();
- return BT_STATUS_SUCCESS;
- }
/** * @brief This function handles the major job in bluetooth driver. * it handles the event generated by firmware, rx data received * from firmware and tx data sent from kernel. * * @param data A pointer to bt_thread structure * @return BT_STATUS_SUCCESS */ static int bt_service_main_thread(void *data) { bt_thread *thread = data; bt_private *priv = thread->priv; bt_adapter *Adapter = priv->adapter; wait_queue_t wait; u8 ireg = 0; struct sk_buff *skb; ENTER(); bt_activate_thread(thread); // set field pid init_waitqueue_entry(&wait, current); // 初始化要等待的队列wait current->flags |= PF_NOFREEZE; for (;;) { add_wait_queue(&thread->waitQ, &wait); // 添加wait到等待队列waitQ中 OS_SET_THREAD_STATE(TASK_INTERRUPTIBLE); if (priv->adapter->WakeupTries || ((!priv->adapter->IntCounter) && (!priv->bt_dev.tx_dnld_rdy || skb_queue_empty(&priv->adapter->tx_queue)))) { PRINTM(INFO, "Main: Thread sleeping...\n"); schedule(); // 睡眠,代码中wake_up_interruptable()函数来唤醒,这是才会继续向下执行 } OS_SET_THREAD_STATE(TASK_RUNNING); // 设置任务已经运行标志 remove_wait_queue(&thread->waitQ, &wait); // 清楚等待队列链表节点 if (kthread_should_stop() || Adapter->SurpriseRemoved) { PRINTM(INFO, "main-thread: break from main thread: " "SurpriseRemoved=0x%x\n", Adapter->SurpriseRemoved); break; } PRINTM(INFO, "Main: Thread waking up...\n"); // 下面就开始处理数据发送了 if (priv->adapter->IntCounter) { OS_INT_DISABLE; Adapter->IntCounter = 0; OS_INT_RESTORE; sbi_get_int_status(priv, &ireg); } else if ((priv->adapter->ps_state == PS_SLEEP) && !skb_queue_empty(&priv->adapter->tx_queue)) { priv->adapter->WakeupTries++; sbi_wakeup_firmware(priv); continue; } if (priv->adapter->ps_state == PS_SLEEP) continue; if (priv->bt_dev.tx_dnld_rdy == TRUE) { if (!skb_queue_empty(&priv->adapter->tx_queue)) { skb = skb_dequeue(&priv->adapter->tx_queue); // 摘出要处理的数据 if (skb) { if (SendSinglePacket(priv, skb)) //这个函数就是发送数据了。 priv->bt_dev.hcidev->stat.err_tx++; else priv->bt_dev.hcidev->stat.byte_tx += skb->len; kfree_skb(skb); } } } } bt_deactivate_thread(thread); LEAVE(); return BT_STATUS_SUCCESS; }
这里最重要的函数就是SendSinglePacket了
- /** @brief This function processes a single packet
- *
- * @param priv A pointer to bt_private structure
- * @param skb A pointer to skb which includes TX packet
- * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
- */
- static int
- SendSinglePacket(bt_private * priv, struct sk_buff *skb)
- {
- int ret;
- ENTER();
- if (!skb || !skb->data)
- return BT_STATUS_FAILURE;
- if (!skb->len || ((skb->len + BT_HEADER_LEN) > BT_UPLD_SIZE)) {
- PRINTM(ERROR, "Tx Error: Bad skb length %d : %d\n", skb->len,
- BT_UPLD_SIZE);
- return BT_STATUS_FAILURE;
- }
- /* This is SDIO specific header length: byte[3][2][1], type: byte[0]
- (HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor) */
- skb_push(skb, BT_HEADER_LEN);
- skb->data[0] = (skb->len & 0x0000ff);
- skb->data[1] = (skb->len & 0x00ff00) >> 8;
- skb->data[2] = (skb->len & 0xff0000) >> 16;
- skb->data[3] = bt_cb(skb)->pkt_type;
- if (bt_cb(skb)->pkt_type == MRVL_VENDOR_PKT)
- PRINTM(CMD, "DNLD_CMD: ocf_ogf=0x%x len=%d\n",
- *((u16 *) & skb->data[4]), skb->len);
- ret = sbi_host_to_card(priv, skb->data, skb->len);
- LEAVE();
- return ret;
- }
/** @brief This function processes a single packet * * @param priv A pointer to bt_private structure * @param skb A pointer to skb which includes TX packet * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE */ static int SendSinglePacket(bt_private * priv, struct sk_buff *skb) { int ret; ENTER(); if (!skb || !skb->data) return BT_STATUS_FAILURE; if (!skb->len || ((skb->len + BT_HEADER_LEN) > BT_UPLD_SIZE)) { PRINTM(ERROR, "Tx Error: Bad skb length %d : %d\n", skb->len, BT_UPLD_SIZE); return BT_STATUS_FAILURE; } /* This is SDIO specific header length: byte[3][2][1], type: byte[0] (HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor) */ skb_push(skb, BT_HEADER_LEN); skb->data[0] = (skb->len & 0x0000ff); skb->data[1] = (skb->len & 0x00ff00) >> 8; skb->data[2] = (skb->len & 0xff0000) >> 16; skb->data[3] = bt_cb(skb)->pkt_type; if (bt_cb(skb)->pkt_type == MRVL_VENDOR_PKT) PRINTM(CMD, "DNLD_CMD: ocf_ogf=0x%x len=%d\n", *((u16 *) & skb->data[4]), skb->len); ret = sbi_host_to_card(priv, skb->data, skb->len); LEAVE(); return ret; }
这个函数调用了skb_push函数,此函数会对data这个字段进行处理,linux里面代码说明为add data to the start of a buffer,它会将data指针前移4个字节,然后len字段增加4。
最后就是调用在bt_sdiommc.c文件中sbi_host_to_card函数了,这个函数会调用linux提供的sdio方面(sdio_io.c)的接口函数sdio_writesb,通过dma的方式真正发送数据。
--------------------------------------------------华丽分割线------------------------------------------------
下面我们讲解一个扫描的例子吧(这个例子虽然简单但是也是花了好几个小时才得以理解):
首先在linux上扫描有哪些蓝牙设备,linux为我们提供了一个命令叫hcitool,我们直接调用
# hcitool scan // 首先得把蓝牙设备up起来,如下:
# hciconfig hci0 up
# hciconfig hci0 piscan //即可发现又可连接
#hciconfig -a //查看是否OK
下面我们看下hcitool执行的大致过程如下:
我们看到了linux用户和内核经常使用的ioctl接口函数,然后跟踪下代码发现此ioctl世纪上是在hci_sock.c(用户接口层)这个重要代码中,如下所示,提供了一系列的接口函数
- static const struct proto_ops hci_sock_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .release = hci_sock_release,
- .bind = hci_sock_bind,
- .getname = hci_sock_getname,
- .sendmsg = hci_sock_sendmsg,
- .recvmsg = hci_sock_recvmsg,
- .ioctl = hci_sock_ioctl,
- .poll = datagram_poll,
- .listen = sock_no_listen,
- .shutdown = sock_no_shutdown,
- .setsockopt = hci_sock_setsockopt,
- .getsockopt = hci_sock_getsockopt,
- .connect = sock_no_connect,
- .socketpair = sock_no_socketpair,
- .accept = sock_no_accept,
- .mmap = sock_no_mmap
- };
static const struct proto_ops hci_sock_ops = { .family = PF_BLUETOOTH, .owner = THIS_MODULE, .release = hci_sock_release, .bind = hci_sock_bind, .getname = hci_sock_getname, .sendmsg = hci_sock_sendmsg, .recvmsg = hci_sock_recvmsg, .ioctl = hci_sock_ioctl, .poll = datagram_poll, .listen = sock_no_listen, .shutdown = sock_no_shutdown, .setsockopt = hci_sock_setsockopt, .getsockopt = hci_sock_getsockopt, .connect = sock_no_connect, .socketpair = sock_no_socketpair, .accept = sock_no_accept, .mmap = sock_no_mmap };
我们重点关注hci_sock_ioctl这个函数,扫描的CMD上面已经看到是HCIINQUIRY这个参数,代码直接return hci_inquiry(argp);我们继续跟踪,就到了(核心层)hci_core.c代码,如下所示:
- int hci_inquiry(void __user *arg)
- {
- __u8 __user *ptr = arg;
- struct hci_inquiry_req ir;
- struct hci_dev *hdev;
- int err = 0, do_inquiry = 0, max_rsp;
- long timeo;
- __u8 *buf;
- if (copy_from_user(&ir, ptr, sizeof(ir)))
- return -EFAULT;
- hdev = hci_dev_get(ir.dev_id);
- if (!hdev)
- return -ENODEV;
- hci_dev_lock_bh(hdev);
- if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX ||
- inquiry_cache_empty(hdev) ||
- ir.flags & IREQ_CACHE_FLUSH) {
- inquiry_cache_flush(hdev);
- do_inquiry = 1;
- }
- hci_dev_unlock_bh(hdev);
- timeo = ir.length * msecs_to_jiffies(2000);
- if (do_inquiry) {
- err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo); //这个函数就是重点了!!!!!
- if (err < 0)
- goto done;
- }
- /* for unlimited number of responses we will use buffer with 255 entries */
- max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp;
- /* cache_dump can't sleep. Therefore we allocate temp buffer and then
- * copy it to the user space.
- */
- buf = kmalloc(sizeof(struct inquiry_info) * max_rsp, GFP_KERNEL);
- if (!buf) {
- err = -ENOMEM;
- goto done;
- }
- hci_dev_lock_bh(hdev);
- ir.num_rsp = inquiry_cache_dump(hdev, max_rsp, buf);
- hci_dev_unlock_bh(hdev);
- BT_DBG("num_rsp %d", ir.num_rsp);
- if (!copy_to_user(ptr, &ir, sizeof(ir))) {
- ptr += sizeof(ir);
- if (copy_to_user(ptr, buf, sizeof(struct inquiry_info) *
- ir.num_rsp))
- err = -EFAULT;
- } else
- err = -EFAULT;
- kfree(buf);
- done:
- hci_dev_put(hdev);
- return err;
- }
int hci_inquiry(void __user *arg) { __u8 __user *ptr = arg; struct hci_inquiry_req ir; struct hci_dev *hdev; int err = 0, do_inquiry = 0, max_rsp; long timeo; __u8 *buf; if (copy_from_user(&ir, ptr, sizeof(ir))) return -EFAULT; hdev = hci_dev_get(ir.dev_id); if (!hdev) return -ENODEV; hci_dev_lock_bh(hdev); if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX || inquiry_cache_empty(hdev) || ir.flags & IREQ_CACHE_FLUSH) { inquiry_cache_flush(hdev); do_inquiry = 1; } hci_dev_unlock_bh(hdev); timeo = ir.length * msecs_to_jiffies(2000); if (do_inquiry) { err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo); //这个函数就是重点了!!!!! if (err < 0) goto done; } /* for unlimited number of responses we will use buffer with 255 entries */ max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp; /* cache_dump can't sleep. Therefore we allocate temp buffer and then * copy it to the user space. */ buf = kmalloc(sizeof(struct inquiry_info) * max_rsp, GFP_KERNEL); if (!buf) { err = -ENOMEM; goto done; } hci_dev_lock_bh(hdev); ir.num_rsp = inquiry_cache_dump(hdev, max_rsp, buf); hci_dev_unlock_bh(hdev); BT_DBG("num_rsp %d", ir.num_rsp); if (!copy_to_user(ptr, &ir, sizeof(ir))) { ptr += sizeof(ir); if (copy_to_user(ptr, buf, sizeof(struct inquiry_info) * ir.num_rsp)) err = -EFAULT; } else err = -EFAULT; kfree(buf); done: hci_dev_put(hdev); return err; }
上面代码中加了很多“!”的就是真正的扫描函数了hci_request,他实际上注册了一个回调函数hci_inq_req,然后主函数等待这个回调函数返回从而结束请求!
这个回调函数实现如下:
- static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
- {
- struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt;
- struct hci_cp_inquiry cp;
- BT_DBG("%s", hdev->name);
- if (test_bit(HCI_INQUIRY, &hdev->flags))
- return;
- /* Start Inquiry */
- memcpy(&cp.lap, &ir->lap, 3);
- cp.length = ir->length;
- cp.num_rsp = ir->num_rsp;
- hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
- }
static void hci_inq_req(struct hci_dev *hdev, unsigned long opt) { struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt; struct hci_cp_inquiry cp; BT_DBG("%s", hdev->name); if (test_bit(HCI_INQUIRY, &hdev->flags)) return; /* Start Inquiry */ memcpy(&cp.lap, &ir->lap, 3); cp.length = ir->length; cp.num_rsp = ir->num_rsp; hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp); }
然后就发送command了!
- /* Send HCI command */
- int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
- {
- int len = HCI_COMMAND_HDR_SIZE + plen;
- struct hci_command_hdr *hdr;
- struct sk_buff *skb;
- BT_DBG("%s opcode 0x%x plen %d", hdev->name, opcode, plen);
- skb = bt_skb_alloc(len, GFP_ATOMIC);
- if (!skb) {
- BT_ERR("%s no memory for command", hdev->name);
- return -ENOMEM;
- }
- hdr = (struct hci_command_hdr *) skb_put(skb, HCI_COMMAND_HDR_SIZE);
- hdr->opcode = cpu_to_le16(opcode);
- hdr->plen = plen;
- if (plen)
- memcpy(skb_put(skb, plen), param, plen);
- BT_DBG("skb len %d", skb->len);
- bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
- skb->dev = (void *) hdev;
- if (test_bit(HCI_INIT, &hdev->flags))
- hdev->init_last_cmd = opcode;
- skb_queue_tail(&hdev->cmd_q, skb);
- tasklet_schedule(&hdev->cmd_task);
- return 0;
- }
/* Send HCI command */ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param) { int len = HCI_COMMAND_HDR_SIZE + plen; struct hci_command_hdr *hdr; struct sk_buff *skb; BT_DBG("%s opcode 0x%x plen %d", hdev->name, opcode, plen); skb = bt_skb_alloc(len, GFP_ATOMIC); if (!skb) { BT_ERR("%s no memory for command", hdev->name); return -ENOMEM; } hdr = (struct hci_command_hdr *) skb_put(skb, HCI_COMMAND_HDR_SIZE); hdr->opcode = cpu_to_le16(opcode); hdr->plen = plen; if (plen) memcpy(skb_put(skb, plen), param, plen); BT_DBG("skb len %d", skb->len); bt_cb(skb)->pkt_type = HCI_COMMAND_PKT; skb->dev = (void *) hdev; if (test_bit(HCI_INIT, &hdev->flags)) hdev->init_last_cmd = opcode; skb_queue_tail(&hdev->cmd_q, skb); tasklet_schedule(&hdev->cmd_task); return 0; }
这个函数先分配了sk_buff结构体的空间,然后检查command的类型,是cmd_taskor rx_taskor tx_task,检查发现这个cmd就是cmd_task,那么就触发tasklet我的数据来临了,请随时准备好要工作了,那么linux就马不停蹄的在最快的时间内来触发他工作,因为tasklet是在linux里面比较优先的了,当然如果想更快还有带优先级的!好了,下面就到tasklet_init注册的函数了,这几个init注册函数在hci_register_dev注册了,这个函数前面在probe
bt device时已经注册过了,这里不全截了,如下:
- tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev);
- tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
- tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev); tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev); tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
这里我们暂时关心的是hci_cmd_task函数,如下:
- static void hci_cmd_task(unsigned long arg)
- {
- struct hci_dev *hdev = (struct hci_dev *) arg;
- struct sk_buff *skb;
- BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
- /* Send queued commands */
- if (atomic_read(&hdev->cmd_cnt)) {
- skb = skb_dequeue(&hdev->cmd_q);
- if (!skb)
- return;
- kfree_skb(hdev->sent_cmd);
- hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC);
- if (hdev->sent_cmd) {
- atomic_dec(&hdev->cmd_cnt);
- hci_send_frame(skb);
- if (test_bit(HCI_RESET, &hdev->flags))
- del_timer(&hdev->cmd_timer);
- else
- mod_timer(&hdev->cmd_timer,
- jiffies + msecs_to_jiffies(HCI_CMD_TIMEOUT));
- } else {
- skb_queue_head(&hdev->cmd_q, skb);
- tasklet_schedule(&hdev->cmd_task);
- }
- }
- }
static void hci_cmd_task(unsigned long arg)
{
struct hci_dev *hdev = (struct hci_dev *) arg;
struct sk_buff *skb;
BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
/* Send queued commands */
if (atomic_read(&hdev->cmd_cnt)) {
skb = skb_dequeue(&hdev->cmd_q);
if (!skb)
return;
kfree_skb(hdev->sent_cmd);
hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC);
if (hdev->sent_cmd) {
atomic_dec(&hdev->cmd_cnt);
hci_send_frame(skb);
if (test_bit(HCI_RESET, &hdev->flags))
del_timer(&hdev->cmd_timer);
else
mod_timer(&hdev->cmd_timer,
jiffies + msecs_to_jiffies(HCI_CMD_TIMEOUT));
} else {
skb_queue_head(&hdev->cmd_q, skb);
tasklet_schedule(&hdev->cmd_task);
}
}
}
这里面涉及很多链表操作,需要先熟悉下更好,处理前先把这个skb从链表中删除了,然后调用了hci_send_frame这个函数,如下:
- static int hci_send_frame(struct sk_buff *skb)
- {
- struct hci_dev *hdev = (struct hci_dev *) skb->dev;
- if (!hdev) {
- kfree_skb(skb);
- return -ENODEV;
- }
- BT_DBG("%s type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
- if (atomic_read(&hdev->promisc)) {
- /* Time stamp */
- __net_timestamp(skb);
- hci_send_to_sock(hdev, skb, NULL);
- }
- /* Get rid of skb owner, prior to sending to the driver. */
- skb_orphan(skb);
- return hdev->send(skb);
- }
static int hci_send_frame(struct sk_buff *skb) { struct hci_dev *hdev = (struct hci_dev *) skb->dev; if (!hdev) { kfree_skb(skb); return -ENODEV; } BT_DBG("%s type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len); if (atomic_read(&hdev->promisc)) { /* Time stamp */ __net_timestamp(skb); hci_send_to_sock(hdev, skb, NULL); } /* Get rid of skb owner, prior to sending to the driver. */ skb_orphan(skb); return hdev->send(skb); }
我们看到最后一行是个函数指针,调用了hci_dev下的send函数指针,到这里代码都在hci_core.c中,所以其实这些都是用户接口与驱动接口打交道的桥梁,也就成为核心层了。然后这个函数指针前面已经写过了,其实就是调用的是bt_main.c的bt_send_frame函数了,这个函数再次判断这个pkt_type是什么,是HCI_COMMAND_PKT还是HCI_ACLDATA_PKT还是HCI_SCODATA_PKT,然后插入链表尾部,再唤醒上文提到的工作队列wake_up_interruptible(&priv->MainThread.waitQ);就这个函数了,经过辗转反侧又回到了这个工作队列,也就是上文中的bt_service_main_thread函数了。
同样在这个函数里面先把这个skb从链表中取出并unlink掉,然后再调用SendSinglePacket,这个函数前面已经提到,我的是sdio模块,所以不同芯片都会有差异了,如下:
- /** @brief This function processes a single packet
- *
- * @param priv A pointer to bt_private structure
- * @param skb A pointer to skb which includes TX packet
- * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
- */
- static int
- SendSinglePacket(bt_private * priv, struct sk_buff *skb)
- {
- int ret;
- ENTER();
- if (!skb || !skb->data)
- return BT_STATUS_FAILURE;
- if (!skb->len || ((skb->len + BT_HEADER_LEN) > BT_UPLD_SIZE)) {
- PRINTM(ERROR, "Tx Error: Bad skb length %d : %d\n", skb->len,
- BT_UPLD_SIZE);
- return BT_STATUS_FAILURE;
- }
- /* This is SDIO specific header length: byte[3][2][1], type: byte[0]
- (HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor) */
- skb_push(skb, BT_HEADER_LEN);
- skb->data[0] = (skb->len & 0x0000ff);
- skb->data[1] = (skb->len & 0x00ff00) >> 8;
- skb->data[2] = (skb->len & 0xff0000) >> 16;
- skb->data[3] = bt_cb(skb)->pkt_type;
- if (bt_cb(skb)->pkt_type == MRVL_VENDOR_PKT)
- PRINTM(CMD, "DNLD_CMD: ocf_ogf=0x%x len=%d\n",
- *((u16 *) & skb->data[4]), skb->len);
- ret = sbi_host_to_card(priv, skb->data, skb->len);
- LEAVE();
- return ret;
- }
/** @brief This function processes a single packet * * @param priv A pointer to bt_private structure * @param skb A pointer to skb which includes TX packet * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE */ static int SendSinglePacket(bt_private * priv, struct sk_buff *skb) { int ret; ENTER(); if (!skb || !skb->data) return BT_STATUS_FAILURE; if (!skb->len || ((skb->len + BT_HEADER_LEN) > BT_UPLD_SIZE)) { PRINTM(ERROR, "Tx Error: Bad skb length %d : %d\n", skb->len, BT_UPLD_SIZE); return BT_STATUS_FAILURE; } /* This is SDIO specific header length: byte[3][2][1], type: byte[0] (HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor) */ skb_push(skb, BT_HEADER_LEN); skb->data[0] = (skb->len & 0x0000ff); skb->data[1] = (skb->len & 0x00ff00) >> 8; skb->data[2] = (skb->len & 0xff0000) >> 16; skb->data[3] = bt_cb(skb)->pkt_type; if (bt_cb(skb)->pkt_type == MRVL_VENDOR_PKT) PRINTM(CMD, "DNLD_CMD: ocf_ogf=0x%x len=%d\n", *((u16 *) & skb->data[4]), skb->len); ret = sbi_host_to_card(priv, skb->data, skb->len); LEAVE(); return ret; }
先加sdio头,然后再调用sbi_host_to_card函数,如下:
- /**
- * @brief This function sends data to the card.
- *
- * @param priv A pointer to bt_private structure
- * @param payload A pointer to the data/cmd buffer
- * @param nb Length of data/cmd
- * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE
- */
- int
- sbi_host_to_card(bt_private * priv, u8 * payload, u16 nb)
- {
- struct sdio_mmc_card *card = priv->bt_dev.card;
- int ret = BT_STATUS_SUCCESS;
- int buf_block_len;
- int blksz;
- int i = 0;
- u8 *buf = NULL;
- struct hci_dev *hdev = priv->bt_dev.hcidev;
- void *tmpbuf = NULL;
- int tmpbufsz;
- ENTER();
- if (!card || !card->func) {
- PRINTM(ERROR, "BT: card or function is NULL!\n");
- LEAVE();
- return BT_STATUS_FAILURE;
- }
- buf = payload;
- /* Allocate buffer and copy payload */
- blksz = SD_BLOCK_SIZE;
- buf_block_len = (nb + blksz - 1) / blksz;
- if ((u32) payload & (DMA_ALIGNMENT - 1)) {
- tmpbufsz = buf_block_len * blksz + DMA_ALIGNMENT;
- tmpbuf = kmalloc(tmpbufsz, GFP_KERNEL);
- memset(tmpbuf, 0, tmpbufsz);
- /* Ensure 8-byte aligned CMD buffer */
- buf = (u8 *) ALIGN_ADDR(tmpbuf, DMA_ALIGNMENT);
- memcpy(buf, payload, nb);
- }
- sdio_claim_host(card->func);
- #define MAX_WRITE_IOMEM_RETRY 2
- do {
- /* Transfer data to card */
- ret = sdio_writesb(card->func, priv->bt_dev.ioport, buf,
- buf_block_len * blksz);
- if (ret < 0) {
- i++;
- PRINTM(ERROR, "BT: host_to_card, write iomem (%d) failed: %d\n", i,
- ret);
- sdio_writeb(card->func, HOST_WO_CMD53_FINISH_HOST,
- CONFIGURATION_REG, &ret);
- udelay(20);
- ret = BT_STATUS_FAILURE;
- if (i > MAX_WRITE_IOMEM_RETRY)
- goto exit;
- } else {
- DBG_HEXDUMP(DAT_D, "BT: SDIO Blk Wr", payload, nb);
- PRINTM(DATA, "BT: SDIO Blk Wr %s: len=%d\n", hdev->name, nb);
- }
- } while (ret == BT_STATUS_FAILURE);
- priv->bt_dev.tx_dnld_rdy = FALSE; // 此时禁止了再次来数据!这个函数和sbi_get_int_status(priv, &ireg);这个函数呼应
- exit:
- sdio_release_host(card->func);
- if (tmpbuf)
- kfree(tmpbuf);
- LEAVE();
- return ret;
- }
/** * @brief This function sends data to the card. * * @param priv A pointer to bt_private structure * @param payload A pointer to the data/cmd buffer * @param nb Length of data/cmd * @return BT_STATUS_SUCCESS or BT_STATUS_FAILURE */ int sbi_host_to_card(bt_private * priv, u8 * payload, u16 nb) { struct sdio_mmc_card *card = priv->bt_dev.card; int ret = BT_STATUS_SUCCESS; int buf_block_len; int blksz; int i = 0; u8 *buf = NULL; struct hci_dev *hdev = priv->bt_dev.hcidev; void *tmpbuf = NULL; int tmpbufsz; ENTER(); if (!card || !card->func) { PRINTM(ERROR, "BT: card or function is NULL!\n"); LEAVE(); return BT_STATUS_FAILURE; } buf = payload; /* Allocate buffer and copy payload */ blksz = SD_BLOCK_SIZE; buf_block_len = (nb + blksz - 1) / blksz; if ((u32) payload & (DMA_ALIGNMENT - 1)) { tmpbufsz = buf_block_len * blksz + DMA_ALIGNMENT; tmpbuf = kmalloc(tmpbufsz, GFP_KERNEL); memset(tmpbuf, 0, tmpbufsz); /* Ensure 8-byte aligned CMD buffer */ buf = (u8 *) ALIGN_ADDR(tmpbuf, DMA_ALIGNMENT); memcpy(buf, payload, nb); } sdio_claim_host(card->func); #define MAX_WRITE_IOMEM_RETRY 2 do { /* Transfer data to card */ ret = sdio_writesb(card->func, priv->bt_dev.ioport, buf, buf_block_len * blksz); if (ret < 0) { i++; PRINTM(ERROR, "BT: host_to_card, write iomem (%d) failed: %d\n", i, ret); sdio_writeb(card->func, HOST_WO_CMD53_FINISH_HOST, CONFIGURATION_REG, &ret); udelay(20); ret = BT_STATUS_FAILURE; if (i > MAX_WRITE_IOMEM_RETRY) goto exit; } else { DBG_HEXDUMP(DAT_D, "BT: SDIO Blk Wr", payload, nb); PRINTM(DATA, "BT: SDIO Blk Wr %s: len=%d\n", hdev->name, nb); } } while (ret == BT_STATUS_FAILURE); priv->bt_dev.tx_dnld_rdy = FALSE; // 此时禁止了再次来数据!这个函数和sbi_get_int_status(priv, &ireg);这个函数呼应 exit: sdio_release_host(card->func); if (tmpbuf) kfree(tmpbuf); LEAVE(); return ret; }
前面一直忽略了sbi_get_int_status(priv, &ireg);这个函数,而经过跟踪发现了我一直未找到的一个数据流动问题,只看到了从kernel向card发送数据,却一直没有看到kernel从card读数据!原来如下:
- /**
- * @brief This function checks the interrupt status and handle it accordingly.
- *
- * @param priv A pointer to bt_private structure
- * @param ireg A pointer to variable that keeps returned value
- * @return BT_STATUS_SUCCESS
- */
- int
- sbi_get_int_status(bt_private * priv, u8 * ireg)
- {
- int ret = BT_STATUS_SUCCESS;
- u8 sdio_ireg = 0;
- struct sdio_mmc_card *card = priv->bt_dev.card;
- struct hci_dev *hdev = priv->bt_dev.hcidev;
- ENTER();
- *ireg = 0;
- OS_INT_DISABLE;
- sdio_ireg = priv->adapter->sd_ireg;
- priv->adapter->sd_ireg = 0;
- OS_INT_RESTORE;
- sdio_claim_host(card->func);
- PRINTM(INTR, "BT: get_int_status %s: sdio_ireg=0x%x\n", hdev->name,
- sdio_ireg);
- priv->adapter->irq_done = sdio_ireg;
- if (sdio_ireg & DN_LD_HOST_INT_STATUS) { /* tx_done INT 这里判断是否是下载模式 */
- if (priv->bt_dev.tx_dnld_rdy) { /* tx_done already received */
- PRINTM(INFO,
- "BT: warning: tx_done already received: tx_dnld_rdy=0x%x int status=0x%x\n",
- priv->bt_dev.tx_dnld_rdy, sdio_ireg);
- } else {
- priv->bt_dev.tx_dnld_rdy = TRUE;
- }
- }
- if (sdio_ireg & UP_LD_HOST_INT_STATUS)
- sd_card_to_host(priv); //这里根据中断返回的状态这里判断是否是上传模式!
- *ireg = sdio_ireg;
- ret = BT_STATUS_SUCCESS;
- sdio_release_host(card->func);
- LEAVE();
- return ret;
- }
/** * @brief This function checks the interrupt status and handle it accordingly. * * @param priv A pointer to bt_private structure * @param ireg A pointer to variable that keeps returned value * @return BT_STATUS_SUCCESS */ int sbi_get_int_status(bt_private * priv, u8 * ireg) { int ret = BT_STATUS_SUCCESS; u8 sdio_ireg = 0; struct sdio_mmc_card *card = priv->bt_dev.card; struct hci_dev *hdev = priv->bt_dev.hcidev; ENTER(); *ireg = 0; OS_INT_DISABLE; sdio_ireg = priv->adapter->sd_ireg; priv->adapter->sd_ireg = 0; OS_INT_RESTORE; sdio_claim_host(card->func); PRINTM(INTR, "BT: get_int_status %s: sdio_ireg=0x%x\n", hdev->name, sdio_ireg); priv->adapter->irq_done = sdio_ireg; if (sdio_ireg & DN_LD_HOST_INT_STATUS) { /* tx_done INT 这里判断是否是下载模式 */ if (priv->bt_dev.tx_dnld_rdy) { /* tx_done already received */ PRINTM(INFO, "BT: warning: tx_done already received: tx_dnld_rdy=0x%x int status=0x%x\n", priv->bt_dev.tx_dnld_rdy, sdio_ireg); } else { priv->bt_dev.tx_dnld_rdy = TRUE; } } if (sdio_ireg & UP_LD_HOST_INT_STATUS) sd_card_to_host(priv); //这里根据中断返回的状态这里判断是否是上传模式! *ireg = sdio_ireg; ret = BT_STATUS_SUCCESS; sdio_release_host(card->func); LEAVE(); return ret; }
记住从kernel发送数据到card为:sbi_host_to_card
而kernel从card读数据为:sd_card_to_host
暂时而言scan过程就结束了,但是还很多具体数据内容未去分析,以及数据的返回过程都没有去分析,下面将着重去根据协议分析数据内容!见谅!
今天再次根据printk信息看到了中断的发生情况,中断处理函数为sd_interrupt,这个函数会读中断状态寄存器HOST_INTSTATUS_REG(0x03)假设这个中断状态寄存器的内容为1的话,sbi_get_int_status这个函数中将进行判断,从而认为card要上传数据,假设内容为2的话,则是kernel要发送数据!
- /**
- * @brief This function handles the interrupt.
- *
- * @param func A pointer to sdio_func structure
- * @return N/A
- */
- static void
- sd_interrupt(struct sdio_func *func)
- {
- bt_private *priv;
- struct hci_dev *hcidev;
- struct sdio_mmc_card *card;
- int ret = BT_STATUS_SUCCESS;
- u8 ireg = 0;
- ENTER();
- card = sdio_get_drvdata(func);
- if (!card || !card->priv) {
- PRINTM(INFO,
- "BT: %s: sbi_interrupt(%p) card or priv is NULL, card=%p\n",
- __FUNCTION__, func, card);
- LEAVE();
- return;
- }
- priv = card->priv;
- hcidev = priv->bt_dev.hcidev;
- ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret);
- if (ret) {
- PRINTM(WARN, "BT: sdio_read_ioreg: read int status register failed\n");
- goto done;
- }
- if (ireg != 0) {
- /*
- * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
- * Clear the interrupt status register and re-enable the interrupt
- */
- PRINTM(INTR, "BT: INT %s: sdio_ireg = 0x%x\n", hcidev->name, ireg);
- priv->adapter->irq_recv = ireg;
- } else {
- PRINTM(ERROR, "BT: ERR: ireg=0\n");
- }
- OS_INT_DISABLE;
- priv->adapter->sd_ireg |= ireg;
- OS_INT_RESTORE;
- bt_interrupt(hcidev); // 这里这个函数调用了wake_up(...)
- done:
- LEAVE();
- }
/** * @brief This function handles the interrupt. * * @param func A pointer to sdio_func structure * @return N/A */ static void sd_interrupt(struct sdio_func *func) { bt_private *priv; struct hci_dev *hcidev; struct sdio_mmc_card *card; int ret = BT_STATUS_SUCCESS; u8 ireg = 0; ENTER(); card = sdio_get_drvdata(func); if (!card || !card->priv) { PRINTM(INFO, "BT: %s: sbi_interrupt(%p) card or priv is NULL, card=%p\n", __FUNCTION__, func, card); LEAVE(); return; } priv = card->priv; hcidev = priv->bt_dev.hcidev; ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret); if (ret) { PRINTM(WARN, "BT: sdio_read_ioreg: read int status register failed\n"); goto done; } if (ireg != 0) { /* * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS * Clear the interrupt status register and re-enable the interrupt */ PRINTM(INTR, "BT: INT %s: sdio_ireg = 0x%x\n", hcidev->name, ireg); priv->adapter->irq_recv = ireg; } else { PRINTM(ERROR, "BT: ERR: ireg=0\n"); } OS_INT_DISABLE; priv->adapter->sd_ireg |= ireg; OS_INT_RESTORE; bt_interrupt(hcidev); // 这里这个函数调用了wake_up(...) done: LEAVE(); }
在设定各种状态后调用了wake_up来唤醒等待队列,如下:
- /**
- * @brief This function handles the interrupt. it will change PS
- * state if applicable. it will wake up main_thread to handle
- * the interrupt event as well.
- *
- * @param hdev A pointer to hci_dev structure
- * @return N/A
- */
- void
- bt_interrupt(struct hci_dev *hdev)
- {
- bt_private *priv = (bt_private *) hdev->driver_data;
- ENTER();
- PRINTM(INTR, "****interrupt****\n");
- priv->adapter->ps_state = PS_AWAKE;
- if (priv->adapter->hs_state == HS_ACTIVATED) {
- PRINTM(CMD, "BT: %s: HS DEACTIVATED in ISR!\n", hdev->name);
- priv->adapter->hs_state = HS_DEACTIVATED;
- }
- priv->adapter->WakeupTries = 0;
- priv->adapter->IntCounter++;
- wake_up_interruptible(&priv->MainThread.waitQ);
- LEAVE();
- }
/** * @brief This function handles the interrupt. it will change PS * state if applicable. it will wake up main_thread to handle * the interrupt event as well. * * @param hdev A pointer to hci_dev structure * @return N/A */ void bt_interrupt(struct hci_dev *hdev) { bt_private *priv = (bt_private *) hdev->driver_data; ENTER(); PRINTM(INTR, "****interrupt****\n"); priv->adapter->ps_state = PS_AWAKE; if (priv->adapter->hs_state == HS_ACTIVATED) { PRINTM(CMD, "BT: %s: HS DEACTIVATED in ISR!\n", hdev->name); priv->adapter->hs_state = HS_DEACTIVATED; } priv->adapter->WakeupTries = 0; priv->adapter->IntCounter++; wake_up_interruptible(&priv->MainThread.waitQ); LEAVE(); }