现在的位置: 首页 > 综合 > 正文

marvell mmp3 pxa2128 sd8787 bluetooth code analysis

2018年08月25日 ⁄ 综合 ⁄ 共 50230字 ⁄ 字号 评论关闭

本文单板mmp3 pxa2128 

我们先看下probe过程吧,然后再一个一个展开讲解

  1. /**  
  2.  *  @brief This function probe the card 
  3.  *   
  4.  *  @param func    A pointer to sdio_func structure. 
  5.  *  @param id      A pointer to structure sd_device_id   
  6.  *  @return        BT_STATUS_SUCCESS/BT_STATUS_FAILURE or other error no. 
  7.  */  
  8. static int  
  9. sd_probe_card(struct sdio_func *func, const struct sdio_device_id *id)  
  10. {  
  11.     int ret = BT_STATUS_SUCCESS;  
  12.     bt_private *priv = NULL;  
  13.     struct sdio_mmc_card *card = NULL;  
  14.   
  15.     ENTER();  
  16.   
  17.     PRINTM(INFO, "BT: vendor=0x%x,device=0x%x,class=%d,fn=%d\n", id->vendor,  
  18.            id->device, id->class, func->num);  
  19.     card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL);  
  20.     if (!card) {  
  21.         ret = -ENOMEM;  
  22.         goto done;  
  23.     }  
  24.     card->func = func;  
  25. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
      
  26.     /* wait for chip fully wake up */  
  27.     if (!func->enable_timeout)  
  28.         func->enable_timeout = 200;  
  29. #endif   
  30. /* 
  31.        驱动中使用mmc_claim_host(host);来得知,当前mmc控制器是否被占用, 
  32.        当前mmc控制器如果被占用,那么 host->claimed = 1;否则为0,如果为1, 
  33.        那么会在for(;;)循环中调用schedule切换出自己,当占用mmc控制器的 
  34.        操作完成之后,执行 mmc_release_host()的时候,会激活登记到等待队 
  35.        列&host->wq中的其他程序获得mmc主控制器的物理使用权*/  
  36.     sdio_claim_host(func);  
  37. /*  mmc_io_rw_direct()把所有参数直接传递给mmc_io_rw_direct_host() 
  38. SDIO功能部分简单了解下就可*/  
  39. /*使能sdio功能设备*/  
  40.     ret = sdio_enable_func(func);  
  41.     if (ret) {  
  42.         sdio_disable_func(func);  
  43.         sdio_release_host(func);  
  44.         PRINTM(FATAL, "BT: sdio_enable_func() failed: ret=%d\n", ret);  
  45.         kfree(card);  
  46.         LEAVE();  
  47.         return -EIO;  
  48.     }  
  49.     /* 释放mmc控制器 */  
  50.     sdio_release_host(func);  
  51.     priv = bt_add_card(card);  
  52.     if (!priv) {  
  53.         sdio_claim_host(func);  
  54.         sdio_disable_func(func);  
  55.         sdio_release_host(func);  
  56.         ret = BT_STATUS_FAILURE;  
  57.         kfree(card);  
  58.     }  
  59.   done:  
  60.     LEAVE();  
  61.     return ret;  
  62. }  

这里主要讲解download firmware

再看bt_add_card(card)函数实现:

  1. /** 
  2.  *  @brief This function adds the card. it will probe the 
  3.  *  card, allocate the bt_priv and initialize the device.  
  4.  *   
  5.  *  @param card    A pointer to card 
  6.  *  @return        A pointer to bt_private structure 
  7.  */  
  8.   
  9. bt_private *  
  10. bt_add_card(void *card)  
  11. {  
  12.     struct hci_dev *hdev = NULL;  
  13.     bt_private *priv = NULL;  
  14.   
  15.     ENTER();  
  16.   
  17.     priv = kzalloc(sizeof(bt_private), GFP_KERNEL);  
  18.     if (!priv) {  
  19.         PRINTM(FATAL, "Can not allocate priv\n");  
  20.         LEAVE();  
  21.         return NULL;  
  22.     }  
  23.     /* allocate buffer for bt_adapter */  
  24.     if (!(priv->adapter = kzalloc(sizeof(bt_adapter), GFP_KERNEL))) {  
  25.         PRINTM(FATAL, "Allocate buffer for bt_adapter failed!\n");  
  26.         goto err_kmalloc;  
  27.     }  
  28. /* 初始化发送队列,挂起队列及command队列的头*/  
  29.     bt_init_adapter(priv);  
  30.   
  31.     /* Register to HCI Core */  
  32.     hdev = hci_alloc_dev();  
  33.     if (!hdev) {  
  34.         PRINTM(FATAL, "Can not allocate HCI device\n");  
  35.         goto err_kmalloc;  
  36.     }  
  37.   
  38.     PRINTM(INFO, "Starting kthread...\n");  
  39.     priv->MainThread.priv = priv;  
  40.     spin_lock_init(&priv->driver_lock);  
  41. /* 通过固件产生收发事件,从固件接受数据包,并 
  42. 将接受的数据包发送给kernel */  
  43.     bt_create_thread(bt_service_main_thread, &priv->MainThread,  
  44.                      "bt_main_service");  
  45.   
  46.     /* wait for mainthread to up */  
  47.     while (!priv->MainThread.pid) {  
  48.         os_sched_timeout(1);  
  49.     }  
  50.     priv->bt_dev.hcidev = hdev;  
  51.     priv->bt_dev.card = card;  
  52.     hdev->driver_data = priv;  
  53.     ((struct sdio_mmc_card *) card)->priv = priv;  
  54.     priv->adapter->sd_ireg = 0;  
  55.     /*  
  56.      * Register the device. Fillup the private data structure with 
  57.      * relevant information from the card and request for the required 
  58.      * IRQ.  
  59.      */  
  60.     if (sbi_register_dev(priv) < 0) {  
  61.         PRINTM(FATAL, "Failed to register bt device!\n");  
  62.         goto err_registerdev;  
  63.     }  
  64.     if (bt_init_fw(priv)) {  
  65.         PRINTM(FATAL, "BT Firmware Init Failed\n");  
  66.         goto err_init_fw;  
  67.     }  
  68.     LEAVE();  
  69.     return priv;  
  70.   
  71.   err_init_fw:  
  72.     PRINTM(INFO, "unregister device\n");  
  73.     sbi_unregister_dev(priv);  
  74.   err_registerdev:  
  75.     ((struct sdio_mmc_card *) card)->priv = NULL;  
  76.     /* Stop the thread servicing the interrupts */  
  77.     priv->adapter->SurpriseRemoved = TRUE;  
  78.     wake_up_interruptible(&priv->MainThread.waitQ);  
  79.     while (priv->MainThread.pid) {  
  80.         os_sched_timeout(1);  
  81.     }  
  82.   err_kmalloc:  
  83.     if (hdev)  
  84.         kfree(hdev);  
  85.     if (priv->adapter)  
  86.         bt_free_adapter(priv);  
  87.     kfree(priv);  
  88.     LEAVE();  
  89.     return NULL;  
  90. }  

这段代码在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这个函数注册

函数实现:

  1. /**  
  2.  *  @brief This function initializes firmware 
  3.  *   
  4.  *  @param priv    A pointer to bt_private structure 
  5.  *  @return        BT_STATUS_SUCCESS or BT_STATUS_FAILURE 
  6.  */  
  7. static int  
  8. bt_init_fw(bt_private * priv)  
  9. {  
  10.     int ret = BT_STATUS_SUCCESS;  
  11.     ENTER();  
  12.     if (fw == 0) { //fw这是个全局变量,当firmware已经初始化时将不再初始化,使能host后直接返回OK,假设尚未初始化的话,那么就执行sbi_disable_host_int函数
      
  13.         sbi_enable_host_int(priv);  
  14.         goto done;  
  15.     }  
  16.     sbi_disable_host_int(priv);  
  17.     priv->fw_crc_check = fw_crc_check; //为1,进行CRC校验
      
  18.     if (sbi_download_fw(priv)) {  //这里就开始download firmware了!!下面着重讲解download
      
  19.         PRINTM(ERROR, "BT FW failed to be download!\n");  
  20.         ret = BT_STATUS_FAILURE;  
  21.         goto done;  
  22.     }  
  23.   done:  
  24.     LEAVE();  
  25.     return ret;  
  26. }  

download firmware过程代码蛮复杂,我们慢慢分析!

  1. sdio_claim_host(card->func);  
  2. if (BT_STATUS_SUCCESS == sd_verify_fw_download(priv, 1)) { //<SPAN style="FONT-SIZE: 24px">第一大事情是确实固件是否准备好接受cmd</SPAN>
      
  3.     PRINTM(MSG, "BT: FW already downloaded!\n");  
  4.     sdio_release_host(card->func);  
  5.     sbi_enable_host_int(priv);  
  6.     if (BT_STATUS_FAILURE == sd_register_conf_dpc(priv)) { // 注册hci_dev需要的几大函数指针,上文已经提到
      
  7.         PRINTM(ERROR,  
  8.                "BT: sd_register_conf_dpc failed. Terminating download\n");  
  9.         ret = BT_STATUS_FAILURE;  
  10.     }  
  11.     goto exit;  
  12. }  

如何确认固件是否已经好的话,调用sd_read_firmware_status此函数,如下所示:

  1. /**  
  2.  *  @brief This function reads fwstatus registers 
  3.  *   
  4.  *  @param priv    A pointer to bt_private structure 
  5.  *  @param dat     A pointer to keep returned data 
  6.  *  @return        BT_STATUS_SUCCESS or BT_STATUS_FAILURE 
  7.  */  
  8. static int  //此函数实际被sd_verify_fw_download他调用
      
  9. sd_read_firmware_status(bt_private * priv, u16 * dat)  
  10. {  
  11.     int ret = BT_STATUS_SUCCESS;  
  12.     u8 fws0;  
  13.     u8 fws1;  
  14.     struct sdio_mmc_card *card = (struct sdio_mmc_card *) priv->bt_dev.card;  
  15.     ENTER();<SPAN style="WHITE-SPACE: pre"> </SPAN> // 调试信息
      
  16.     fws0 = sdio_readb(card->func, CARD_FW_STATUS0_REG, &ret); //读reg FW_STATUS0
      
  17.     if (ret < 0) {  
  18.         LEAVE();  
  19.         return BT_STATUS_FAILURE;  
  20.     }  
  21.     fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret); //读reg FW_STATUS1
      
  22.     if (ret < 0) {  
  23.         LEAVE();  
  24.         return BT_STATUS_FAILURE;  
  25.     }  
  26.     *dat = (((u16) fws1) << 8) | fws0;  
  27.     LEAVE();  
  28.     return BT_STATUS_SUCCESS; //我们都假设成功正常返回
      
  29. }  

假设这个函数成功了,那么将进行sd_register_conf_dpc(前面两个函数不说了,大家应该都比较清楚了!),这个函数的注释说用来:第一,模块组态;第二注册设备。

在把hci_dev的函数指针都填充后调用bt_send_module_cfg_cmd

  1. hdev->open = bt_open;  
  2. hdev->close = bt_close;  
  3. hdev->flush = bt_flush;  
  4. hdev->send = bt_send_frame;  
  5. hdev->destruct = bt_destruct;  
  6. hdev->ioctl = bt_ioctl;  

这个函数涉及到了sk_buff这个网络里面常用的结构体,同时注释里面说明了发送module cfg cmd到firmware的格式

  1. /**  
  2.  *  @brief This function send module cfg cmd to firmware 
  3.  * 
  4.  *  Command format: 
  5.  *  +--------+--------+--------+--------+--------+--------+--------+ 
  6.  *  |     OCF OGF     | Length |                Data               | 
  7.  *  +--------+--------+--------+--------+--------+--------+--------+ 
  8.  *  |     2-byte      | 1-byte |               4-byte              | 
  9.  *  +--------+--------+--------+--------+--------+--------+--------+ 
  10.  *   
  11.  *  @param priv    A pointer to bt_private structure 
  12.  *  @param subcmd  sub command  
  13.  *  @return        BT_STATUS_SUCCESS or BT_STATUS_FAILURE 
  14.  */  
  1. int  
  2. bt_send_module_cfg_cmd(bt_private * priv, int subcmd)  
  3. {  
  4.     struct sk_buff *skb = NULL;  
  5.     u8 ret = BT_STATUS_SUCCESS;  
  6.     BT_CMD *pCmd;  
  7.     ENTER();  
  8.     skb = bt_skb_alloc(sizeof(BT_CMD), GFP_ATOMIC);  
  9.     if (skb == NULL) {  
  10.         PRINTM(WARN, "BT: No free skb\n");  
  11.         ret = BT_STATUS_FAILURE;  
  12.         goto exit;  
  13.     }  
  14.     pCmd = (BT_CMD *) skb->tail;  //填充sk_buff
      
  15.     pCmd->ocf_ogf = (OGF << 10) | BT_CMD_MODULE_CFG_REQ;  //(0x3f << 10 | 0x5b)
      
  16.     pCmd->length = 1;  
  17.     pCmd->data[0] = subcmd;  //MODULE_BRINGUP_REQ   0xf1
      
  18.     bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;  // 0xfe
      
  19.     skb_put(skb, sizeof(BT_CMD));  
  20.     skb->dev = (void *) priv->bt_dev.hcidev;  
  21.     skb_queue_head(&priv->adapter->tx_queue, skb); //吧skb插入tx_queue链表中
      
  22.     priv->bt_dev.sendcmdflag = TRUE;  
  23.     priv->bt_dev.send_cmd_ocf = BT_CMD_MODULE_CFG_REQ; //0x5b
      
  24.     priv->adapter->cmd_complete = FALSE;  
  25.     PRINTM(CMD, "Queue module cfg Command(0x%x)\n", pCmd->ocf_ogf);  
  26.     wake_up_interruptible(&priv->MainThread.waitQ);//唤醒在probe时创建的线程来处理这个skb
      
  27.     /*  
  28.        On some Android platforms certain delay is needed for HCI daemon to 
  29.        remove this module and close itself gracefully. Otherwise it hangs. This  
  30.        10ms delay is a workaround for such platforms as the root cause has not 
  31.        been found yet. */  
  32.     mdelay(10);  
  33.     if (!os_wait_interruptible_timeout  
  34.         (priv->adapter->cmd_wait_q, priv->adapter->cmd_complete,  
  35.          WAIT_UNTIL_CMD_RESP)) {  
  36.         ret = BT_STATUS_FAILURE;  
  37.         PRINTM(MSG, "BT: module_cfg_cmd (0x%x): timeout sendcmdflag=%d\n",  
  38.                subcmd, priv->bt_dev.sendcmdflag);  
  39.     } else {  
  40.         PRINTM(CMD, "BT: module cfg Command done\n");  
  41.     }  
  42.   exit:  
  43.     LEAVE();  
  44.     return ret;  
  45. }  

下面返回后到电源管理部分,主要是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

  1. /**  
  2.  *  @brief This function downloads firmware image to the card. 
  3.  *   
  4.  *  @param priv     A pointer to bt_private structure 
  5.  *  @return         BT_STATUS_SUCCESS/BT_STATUS_FAILURE or other error no. 
  6.  */  
  7. int  
  8. sd_download_firmware_w_helper(bt_private * priv)  
  9. {  
  10.     int ret = BT_STATUS_SUCCESS;  
  11.     int err;  
  12.     char *cur_fw_name = NULL;  
  13.     ENTER();  
  14.     cur_fw_name = fw_name;  
  15.     if (req_fw_nowait) {  
  16. #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32)
      
  17.         if ((ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,  
  18.                                            cur_fw_name, priv->hotplug_device,  
  19.                                            GFP_KERNEL, priv,  
  20.                                            sd_request_fw_callback)) < 0)  
  1. //实际上下载过程就是最后一个回调函数sd_request_fw_callback了,有兴趣可仔细阅读下。
      
  2. #else   
  3.         if ((ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,  
  4.                                            cur_fw_name, priv->hotplug_device,  
  5.                                            priv, sd_request_fw_callback)) < 0)  
  6. #endif   
  7.             PRINTM(FATAL,  
  8.                    "BT: request_firmware_nowait() failed, error code = %#x\n",  
  9.                    ret);  
  10.     } else {  
  11.         if ((err =  
  12.              request_firmware(&priv->firmware, cur_fw_name,  
  13.                               priv->hotplug_device)) < 0) {  
  14.             PRINTM(FATAL, "BT: request_firmware() failed, error code = %#x\n",  
  15.                    err);  
  16.             ret = BT_STATUS_FAILURE;  
  17.         } else  
  18.             ret = sd_request_fw_dpc(priv->firmware, priv);  
  19.     }  
  20.   
  21.     LEAVE();  
  22.     return ret;  
  23. }  

这个结束了,probe也就结束了。

刚才好几个地方调用了wakeup一个waitQ,这个实际上也是probe时创建的一个线程,然后sk_buff都是通过这个线程来执行的,这个函数为:

  1. /**  
  2.  *  @brief This function handles the major job in bluetooth driver. 
  3.  *  it handles the event generated by firmware, rx data received 
  4.  *  from firmware and tx data sent from kernel. 
  5.  *   
  6.  *  @param data    A pointer to bt_thread structure 
  7.  *  @return        BT_STATUS_SUCCESS 
  8.  */  
  9. static int  
  10. bt_service_main_thread(void *data)  
  11. {  
  12.     bt_thread *thread = data;  
  13.     bt_private *priv = thread->priv;  
  14.     bt_adapter *Adapter = priv->adapter;  
  15.     wait_queue_t wait;  
  16.     u8 ireg = 0;  
  17.     struct sk_buff *skb;  
  18.     ENTER();  
  19.     bt_activate_thread(thread);    // set field pid
      
  20.     init_waitqueue_entry(&wait, current);  // 初始化要等待的队列wait
      
  21.     current->flags |= PF_NOFREEZE;  
  22.   
  23.     for (;;) {  
  24.         add_wait_queue(&thread->waitQ, &wait);   // 添加wait到等待队列waitQ中
      
  25.         OS_SET_THREAD_STATE(TASK_INTERRUPTIBLE);  
  26.         if (priv->adapter->WakeupTries ||  
  27.             ((!priv->adapter->IntCounter) &&  
  28.              (!priv->bt_dev.tx_dnld_rdy ||  
  29.               skb_queue_empty(&priv->adapter->tx_queue)))) {  
  30.             PRINTM(INFO, "Main: Thread sleeping...\n");  
  31.             schedule();            // 睡眠,代码中wake_up_interruptable()函数来唤醒,这是才会继续向下执行
      
  32.         }  
  33.         OS_SET_THREAD_STATE(TASK_RUNNING);  // 设置任务已经运行标志
      
  34.         remove_wait_queue(&thread->waitQ, &wait);  // 清楚等待队列链表节点
      
  35.         if (kthread_should_stop() || Adapter->SurpriseRemoved) {  
  36.             PRINTM(INFO, "main-thread: break from main thread: "  
  37.                    "SurpriseRemoved=0x%x\n", Adapter->SurpriseRemoved);  
  38.             break;  
  39.         }  
  40.   
  41.         PRINTM(INFO, "Main: Thread waking up...\n");  // 下面就开始处理数据发送了
      
  42.         if (priv->adapter->IntCounter) {  
  43.             OS_INT_DISABLE;  
  44.             Adapter->IntCounter = 0;  
  45.             OS_INT_RESTORE;  
  46.             sbi_get_int_status(priv, &ireg);  
  47.         } else if ((priv->adapter->ps_state == PS_SLEEP) &&  
  48.                    !skb_queue_empty(&priv->adapter->tx_queue)) {  
  49.             priv->adapter->WakeupTries++;  
  50.             sbi_wakeup_firmware(priv);  
  51.             continue;  
  52.         }  
  53.         if (priv->adapter->ps_state == PS_SLEEP)  
  54.             continue;  
  55.         if (priv->bt_dev.tx_dnld_rdy == TRUE) {  
  56.             if (!skb_queue_empty(&priv->adapter->tx_queue)) {  
  57.                 skb = skb_dequeue(&priv->adapter->tx_queue); // 摘出要处理的数据
      
  58.                 if (skb) {  
  59.                     if (SendSinglePacket(priv, skb)) //这个函数就是发送数据了。
      
  60.                         priv->bt_dev.hcidev->stat.err_tx++;  
  61.                     else  
  62.                         priv->bt_dev.hcidev->stat.byte_tx += skb->len;  
  63.                     kfree_skb(skb);  
  64.                 }  
  65.             }  
  66.         }  
  67.     }  
  68.     bt_deactivate_thread(thread);  
  69.     LEAVE();  
  70.     return BT_STATUS_SUCCESS;  
  71. }  

这里最重要的函数就是SendSinglePacket了

  1. /** @brief This function processes a single packet  
  2.  *   
  3.  *  @param priv    A pointer to bt_private structure 
  4.  *  @param skb     A pointer to skb which includes TX packet 
  5.  *  @return        BT_STATUS_SUCCESS or BT_STATUS_FAILURE 
  6.  */  
  7. static int  
  8. SendSinglePacket(bt_private * priv, struct sk_buff *skb)  
  9. {  
  10.     int ret;  
  11.     ENTER();  
  12.     if (!skb || !skb->data)  
  13.         return BT_STATUS_FAILURE;  
  14.     if (!skb->len || ((skb->len + BT_HEADER_LEN) > BT_UPLD_SIZE)) {  
  15.         PRINTM(ERROR, "Tx Error: Bad skb length %d : %d\n", skb->len,  
  16.                BT_UPLD_SIZE);  
  17.         return BT_STATUS_FAILURE;  
  18.     }  
  19.     /* This is SDIO specific header length: byte[3][2][1], type: byte[0] 
  20.        (HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor) */  
  21.     skb_push(skb, BT_HEADER_LEN);  
  22.     skb->data[0] = (skb->len & 0x0000ff);  
  23.     skb->data[1] = (skb->len & 0x00ff00) >> 8;  
  24.     skb->data[2] = (skb->len & 0xff0000) >> 16;  
  25.     skb->data[3] = bt_cb(skb)->pkt_type;  
  26.     if (bt_cb(skb)->pkt_type == MRVL_VENDOR_PKT)  
  27.         PRINTM(CMD, "DNLD_CMD: ocf_ogf=0x%x len=%d\n",  
  28.                *((u16 *) & skb->data[4]), skb->len);  
  29.     ret = sbi_host_to_card(priv, skb->data, skb->len);  
  30.     LEAVE();  
  31.     return ret;  
  32. }  

这个函数调用了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(用户接口层)这个重要代码中,如下所示,提供了一系列的接口函数

  1. static const struct proto_ops hci_sock_ops = {  
  2.     .family     = PF_BLUETOOTH,  
  3.     .owner      = THIS_MODULE,  
  4.     .release    = hci_sock_release,  
  5.     .bind       = hci_sock_bind,  
  6.     .getname    = hci_sock_getname,  
  7.     .sendmsg    = hci_sock_sendmsg,  
  8.     .recvmsg    = hci_sock_recvmsg,  
  9.     .ioctl      = hci_sock_ioctl,  
  10.     .poll       = datagram_poll,  
  11.     .listen     = sock_no_listen,  
  12.     .shutdown   = sock_no_shutdown,  
  13.     .setsockopt = hci_sock_setsockopt,  
  14.     .getsockopt = hci_sock_getsockopt,  
  15.     .connect    = sock_no_connect,  
  16.     .socketpair = sock_no_socketpair,  
  17.     .accept     = sock_no_accept,  
  18.     .mmap       = sock_no_mmap  
  19. };  

我们重点关注hci_sock_ioctl这个函数,扫描的CMD上面已经看到是HCIINQUIRY这个参数,代码直接return hci_inquiry(argp);我们继续跟踪,就到了(核心层)hci_core.c代码,如下所示:

  1. int hci_inquiry(void __user *arg)  
  2. {  
  3.     __u8 __user *ptr = arg;  
  4.     struct hci_inquiry_req ir;  
  5.     struct hci_dev *hdev;  
  6.     int err = 0, do_inquiry = 0, max_rsp;  
  7.     long timeo;  
  8.     __u8 *buf;  
  9.   
  10.     if (copy_from_user(&ir, ptr, sizeof(ir)))  
  11.         return -EFAULT;  
  12.   
  13.     hdev = hci_dev_get(ir.dev_id);  
  14.     if (!hdev)  
  15.         return -ENODEV;  
  16.   
  17.     hci_dev_lock_bh(hdev);  
  18.     if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX ||  
  19.                 inquiry_cache_empty(hdev) ||  
  20.                 ir.flags & IREQ_CACHE_FLUSH) {  
  21.         inquiry_cache_flush(hdev);  
  22.         do_inquiry = 1;  
  23.     }  
  24.     hci_dev_unlock_bh(hdev);  
  25.   
  26.     timeo = ir.length * msecs_to_jiffies(2000);  
  27.   
  28.     if (do_inquiry) {  
  29.         err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo);   //这个函数就是重点了!!!!!
      
  30.         if (err < 0)  
  31.             goto done;  
  32.     }  
  33.   
  34.     /* for unlimited number of responses we will use buffer with 255 entries */  
  35.     max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp;  
  36.   
  37.     /* cache_dump can't sleep. Therefore we allocate temp buffer and then 
  38.      * copy it to the user space. 
  39.      */  
  40.     buf = kmalloc(sizeof(struct inquiry_info) * max_rsp, GFP_KERNEL);  
  41.     if (!buf) {  
  42.         err = -ENOMEM;  
  43.         goto done;  
  44.     }  
  45.   
  46.     hci_dev_lock_bh(hdev);  
  47.     ir.num_rsp = inquiry_cache_dump(hdev, max_rsp, buf);  
  48.     hci_dev_unlock_bh(hdev);  
  49.   
  50.     BT_DBG("num_rsp %d", ir.num_rsp);  
  51.   
  52.     if (!copy_to_user(ptr, &ir, sizeof(ir))) {  
  53.         ptr += sizeof(ir);  
  54.         if (copy_to_user(ptr, buf, sizeof(struct inquiry_info) *  
  55.                     ir.num_rsp))  
  56.             err = -EFAULT;  
  57.     } else  
  58.         err = -EFAULT;  
  59.   
  60.     kfree(buf);  
  61.   
  62. done:  
  63.     hci_dev_put(hdev);  
  64.     return err;  
  65. }  

上面代码中加了很多“!”的就是真正的扫描函数了hci_request,他实际上注册了一个回调函数hci_inq_req,然后主函数等待这个回调函数返回从而结束请求!

这个回调函数实现如下:

  1. static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)  
  2. {  
  3.     struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt;  
  4.     struct hci_cp_inquiry cp;  
  5.   
  6.     BT_DBG("%s", hdev->name);  
  7.   
  8.     if (test_bit(HCI_INQUIRY, &hdev->flags))  
  9.         return;  
  10.   
  11.     /* Start Inquiry */  
  12.     memcpy(&cp.lap, &ir->lap, 3);  
  13.     cp.length  = ir->length;  
  14.     cp.num_rsp = ir->num_rsp;  
  15.     hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);  
  16. }  

然后就发送command了!

  1. /* Send HCI command */  
  2. int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)  
  3. {  
  4.     int len = HCI_COMMAND_HDR_SIZE + plen;  
  5.     struct hci_command_hdr *hdr;  
  6.     struct sk_buff *skb;  
  7.   
  8.     BT_DBG("%s opcode 0x%x plen %d", hdev->name, opcode, plen);  
  9.   
  10.     skb = bt_skb_alloc(len, GFP_ATOMIC);  
  11.     if (!skb) {  
  12.         BT_ERR("%s no memory for command", hdev->name);  
  13.         return -ENOMEM;  
  14.     }  
  15.   
  16.     hdr = (struct hci_command_hdr *) skb_put(skb, HCI_COMMAND_HDR_SIZE);  
  17.     hdr->opcode = cpu_to_le16(opcode);  
  18.     hdr->plen   = plen;  
  19.   
  20.     if (plen)  
  21.         memcpy(skb_put(skb, plen), param, plen);  
  22.   
  23.     BT_DBG("skb len %d", skb->len);  
  24.   
  25.     bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;  
  26.     skb->dev = (void *) hdev;  
  27.   
  28.     if (test_bit(HCI_INIT, &hdev->flags))  
  29.         hdev->init_last_cmd = opcode;  
  30.   
  31.     skb_queue_tail(&hdev->cmd_q, skb);  
  32.     tasklet_schedule(&hdev->cmd_task);  
  33.   
  34.     return 0;  
  35. }  

这个函数先分配了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时已经注册过了,这里不全截了,如下:

  1. tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev);  
  2. tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);  
  3. tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);  

这里我们暂时关心的是hci_cmd_task函数,如下:

  1. static void hci_cmd_task(unsigned long arg)  
  2. {  
  3.     struct hci_dev *hdev = (struct hci_dev *) arg;  
  4.     struct sk_buff *skb;  
  5.   
  6.     BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));  
  7.   
  8.     /* Send queued commands */  
  9.     if (atomic_read(&hdev->cmd_cnt)) {  
  10.         skb = skb_dequeue(&hdev->cmd_q);  
  11.         if (!skb)  
  12.             return;  
  13.   
  14.         kfree_skb(hdev->sent_cmd);  
  15.   
  16.         hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC);  
  17.         if (hdev->sent_cmd) {  
  18.             atomic_dec(&hdev->cmd_cnt);  
  19.             hci_send_frame(skb);  
  20.             if (test_bit(HCI_RESET, &hdev->flags))  
  21.                 del_timer(&hdev->cmd_timer);  
  22.             else  
  23.                 mod_timer(&hdev->cmd_timer,  
  24.                   jiffies + msecs_to_jiffies(HCI_CMD_TIMEOUT));  
  25.         } else {  
  26.             skb_queue_head(&hdev->cmd_q, skb);  
  27.             tasklet_schedule(&hdev->cmd_task);  
  28.         }  
  29.     }  
  30. }  

这里面涉及很多链表操作,需要先熟悉下更好,处理前先把这个skb从链表中删除了,然后调用了hci_send_frame这个函数,如下:

  1. static int hci_send_frame(struct sk_buff *skb)  
  2. {  
  3.     struct hci_dev *hdev = (struct hci_dev *) skb->dev;  
  4.   
  5.     if (!hdev) {  
  6.         kfree_skb(skb);  
  7.         return -ENODEV;  
  8.     }  
  9.   
  10.     BT_DBG("%s type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);  
  11.   
  12.     if (atomic_read(&hdev->promisc)) {  
  13.         /* Time stamp */  
  14.         __net_timestamp(skb);  
  15.   
  16.         hci_send_to_sock(hdev, skb, NULL);  
  17.     }  
  18.   
  19.     /* Get rid of skb owner, prior to sending to the driver. */  
  20.     skb_orphan(skb);  
  21.   
  22.     return hdev->send(skb);  
  23. }  

我们看到最后一行是个函数指针,调用了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模块,所以不同芯片都会有差异了,如下:

  1. /** @brief This function processes a single packet  
  2.  *   
  3.  *  @param priv    A pointer to bt_private structure 
  4.  *  @param skb     A pointer to skb which includes TX packet 
  5.  *  @return        BT_STATUS_SUCCESS or BT_STATUS_FAILURE 
  6.  */  
  7. static int  
  8. SendSinglePacket(bt_private * priv, struct sk_buff *skb)  
  9. {  
  10.     int ret;  
  11.     ENTER();  
  12.     if (!skb || !skb->data)  
  13.         return BT_STATUS_FAILURE;  
  14.     if (!skb->len || ((skb->len + BT_HEADER_LEN) > BT_UPLD_SIZE)) {  
  15.         PRINTM(ERROR, "Tx Error: Bad skb length %d : %d\n", skb->len,  
  16.                BT_UPLD_SIZE);  
  17.         return BT_STATUS_FAILURE;  
  18.     }  
  19.     /* This is SDIO specific header length: byte[3][2][1], type: byte[0] 
  20.        (HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor) */  
  21.     skb_push(skb, BT_HEADER_LEN);  
  22.     skb->data[0] = (skb->len & 0x0000ff);  
  23.     skb->data[1] = (skb->len & 0x00ff00) >> 8;  
  24.     skb->data[2] = (skb->len & 0xff0000) >> 16;  
  25.     skb->data[3] = bt_cb(skb)->pkt_type;  
  26.     if (bt_cb(skb)->pkt_type == MRVL_VENDOR_PKT)  
  27.         PRINTM(CMD, "DNLD_CMD: ocf_ogf=0x%x len=%d\n",  
  28.                *((u16 *) & skb->data[4]), skb->len);  
  29.     ret = sbi_host_to_card(priv, skb->data, skb->len);  
  30.     LEAVE();  
  31.     return ret;  
  32. }  

先加sdio头,然后再调用sbi_host_to_card函数,如下:

  1. /**   
  2.  *  @brief This function sends data to the card. 
  3.  *   
  4.  *  @param priv    A pointer to bt_private structure 
  5.  *  @param payload A pointer to the data/cmd buffer 
  6.  *  @param nb      Length of data/cmd 
  7.  *  @return        BT_STATUS_SUCCESS or BT_STATUS_FAILURE 
  8.  */  
  9. int  
  10. sbi_host_to_card(bt_private * priv, u8 * payload, u16 nb)  
  11. {  
  12.     struct sdio_mmc_card *card = priv->bt_dev.card;  
  13.     int ret = BT_STATUS_SUCCESS;  
  14.     int buf_block_len;  
  15.     int blksz;  
  16.     int i = 0;  
  17.     u8 *buf = NULL;  
  18.     struct hci_dev *hdev = priv->bt_dev.hcidev;  
  19.     void *tmpbuf = NULL;  
  20.     int tmpbufsz;  
  21.   
  22.     ENTER();  
  23.   
  24.     if (!card || !card->func) {  
  25.         PRINTM(ERROR, "BT: card or function is NULL!\n");  
  26.         LEAVE();  
  27.         return BT_STATUS_FAILURE;  
  28.     }  
  29.     buf = payload;  
  30.   
  31.     /* Allocate buffer and copy payload */  
  32.     blksz = SD_BLOCK_SIZE;  
  33.     buf_block_len = (nb + blksz - 1) / blksz;  
  34.     if ((u32) payload & (DMA_ALIGNMENT - 1)) {  
  35.         tmpbufsz = buf_block_len * blksz + DMA_ALIGNMENT;  
  36.         tmpbuf = kmalloc(tmpbufsz, GFP_KERNEL);  
  37.         memset(tmpbuf, 0, tmpbufsz);  
  38.         /* Ensure 8-byte aligned CMD buffer */  
  39.         buf = (u8 *) ALIGN_ADDR(tmpbuf, DMA_ALIGNMENT);  
  40.         memcpy(buf, payload, nb);  
  41.     }  
  42.     sdio_claim_host(card->func);  
  43. #define MAX_WRITE_IOMEM_RETRY   2
      
  44.     do {  
  45.         /* Transfer data to card */  
  46.         ret = sdio_writesb(card->func, priv->bt_dev.ioport, buf,  
  47.                            buf_block_len * blksz);  
  48.         if (ret < 0) {  
  49.             i++;  
  50.             PRINTM(ERROR, "BT: host_to_card, write iomem (%d) failed: %d\n", i,  
  51.                    ret);  
  52.             sdio_writeb(card->func, HOST_WO_CMD53_FINISH_HOST,  
  53.                         CONFIGURATION_REG, &ret);  
  54.             udelay(20);  
  55.             ret = BT_STATUS_FAILURE;  
  56.             if (i > MAX_WRITE_IOMEM_RETRY)  
  57.                 goto exit;  
  58.         } else {  
  59.             DBG_HEXDUMP(DAT_D, "BT: SDIO Blk Wr", payload, nb);  
  60.             PRINTM(DATA, "BT: SDIO Blk Wr %s: len=%d\n", hdev->name, nb);  
  61.         }  
  62.     } while (ret == BT_STATUS_FAILURE);  
  63.     priv->bt_dev.tx_dnld_rdy = FALSE; // 此时禁止了再次来数据!这个函数和sbi_get_int_status(priv, &ireg);这个函数呼应
      
  64.   exit:  
  65.     sdio_release_host(card->func);  
  66.     if (tmpbuf)  
  67.         kfree(tmpbuf);  
  68.     LEAVE();  
  69.     return ret;  
  70. }  

前面一直忽略了sbi_get_int_status(priv, &ireg);这个函数,而经过跟踪发现了我一直未找到的一个数据流动问题,只看到了从kernel向card发送数据,却一直没有看到kernel从card读数据!原来如下:

  1. /**  
  2.  *  @brief This function checks the interrupt status and handle it accordingly. 
  3.  *   
  4.  *  @param priv    A pointer to bt_private structure 
  5.  *  @param ireg    A pointer to variable that keeps returned value 
  6.  *  @return        BT_STATUS_SUCCESS  
  7.  */  
  8. int  
  9. sbi_get_int_status(bt_private * priv, u8 * ireg)  
  10. {  
  11.     int ret = BT_STATUS_SUCCESS;  
  12.     u8 sdio_ireg = 0;  
  13.     struct sdio_mmc_card *card = priv->bt_dev.card;  
  14.     struct hci_dev *hdev = priv->bt_dev.hcidev;  
  15.   
  16.     ENTER();  
  17.   
  18.     *ireg = 0;  
  19.     OS_INT_DISABLE;  
  20.     sdio_ireg = priv->adapter->sd_ireg;  
  21.     priv->adapter->sd_ireg = 0;  
  22.     OS_INT_RESTORE;  
  23.     sdio_claim_host(card->func);  
  24.     PRINTM(INTR, "BT: get_int_status %s: sdio_ireg=0x%x\n", hdev->name,  
  25.            sdio_ireg);  
  26.     priv->adapter->irq_done = sdio_ireg;  
  27.     if (sdio_ireg & DN_LD_HOST_INT_STATUS) {    /* tx_done INT 这里判断是否是下载模式 */  
  28.         if (priv->bt_dev.tx_dnld_rdy) { /* tx_done already received */  
  29.             PRINTM(INFO,  
  30.                    "BT: warning: tx_done already received: tx_dnld_rdy=0x%x int status=0x%x\n",  
  31.                    priv->bt_dev.tx_dnld_rdy, sdio_ireg);  
  32.         } else {  
  33.             priv->bt_dev.tx_dnld_rdy = TRUE;  
  34.         }  
  35.     }  
  36.     if (sdio_ireg & UP_LD_HOST_INT_STATUS)  
  37.         sd_card_to_host(priv);  //这里根据中断返回的状态这里判断是否是上传模式!
      
  38.   
  39.     *ireg = sdio_ireg;  
  40.     ret = BT_STATUS_SUCCESS;  
  41.     sdio_release_host(card->func);  
  42.     LEAVE();  
  43.     return ret;  
  44. }  

记住从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要发送数据!

  1. /**  
  2.  *  @brief This function handles the interrupt. 
  3.  *   
  4.  *  @param func  A pointer to sdio_func structure 
  5.  *  @return      N/A 
  6.  */  
  7. static void  
  8. sd_interrupt(struct sdio_func *func)  
  9. {  
  10.     bt_private *priv;  
  11.     struct hci_dev *hcidev;  
  12.     struct sdio_mmc_card *card;  
  13.     int ret = BT_STATUS_SUCCESS;  
  14.     u8 ireg = 0;  
  15.   
  16.     ENTER();  
  17.   
  18.     card = sdio_get_drvdata(func);  
  19.     if (!card || !card->priv) {  
  20.         PRINTM(INFO,  
  21.                "BT: %s: sbi_interrupt(%p) card or priv is NULL, card=%p\n",  
  22.                __FUNCTION__, func, card);  
  23.         LEAVE();  
  24.         return;  
  25.     }  
  26.     priv = card->priv;  
  27.     hcidev = priv->bt_dev.hcidev;  
  28.   
  29.     ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret);  
  30.     if (ret) {  
  31.         PRINTM(WARN, "BT: sdio_read_ioreg: read int status register failed\n");  
  32.         goto done;  
  33.     }  
  34.     if (ireg != 0) {  
  35.         /*  
  36.          * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS 
  37.          * Clear the interrupt status register and re-enable the interrupt 
  38.          */  
  39.         PRINTM(INTR, "BT: INT %s: sdio_ireg = 0x%x\n", hcidev->name, ireg);  
  40.         priv->adapter->irq_recv = ireg;  
  41.     } else {  
  42.         PRINTM(ERROR, "BT: ERR: ireg=0\n");  
  43.     }  
  44.     OS_INT_DISABLE;  
  45.     priv->adapter->sd_ireg |= ireg;  
  46.     OS_INT_RESTORE;  
  47.     bt_interrupt(hcidev); // 这里这个函数调用了wake_up(...)
      
  48.   done:  
  49.     LEAVE();  
  50. }  

在设定各种状态后调用了wake_up来唤醒等待队列,如下:

  1. /**  
  2.  *  @brief This function handles the interrupt. it will change PS 
  3.  *  state if applicable. it will wake up main_thread to handle 
  4.  *  the interrupt event as well. 
  5.  *   
  6.  *  @param hdev    A pointer to hci_dev structure 
  7.  *  @return        N/A 
  8.  */  
  9. void  
  10. bt_interrupt(struct hci_dev *hdev)  
  11. {  
  12.     bt_private *priv = (bt_private *) hdev->driver_data;  
  13.     ENTER();  
  14.     PRINTM(INTR, "****interrupt****\n");  
  15.     priv->adapter->ps_state = PS_AWAKE;  
  16.     if (priv->adapter->hs_state == HS_ACTIVATED) {  
  17.         PRINTM(CMD, "BT: %s: HS DEACTIVATED in ISR!\n", hdev->name);  
  18.         priv->adapter->hs_state = HS_DEACTIVATED;  
  19.     }  
  20.     priv->adapter->WakeupTries = 0;  
  21.     priv->adapter->IntCounter++;  
  22.     wake_up_interruptible(&priv->MainThread.waitQ);  
  23.     LEAVE();  
  24.   
  25. }  

抱歉!评论已关闭.