[android源码分析]enable_native中的hci dev注册和up

来源:互联网 发布:阿里云不能开启gpu 编辑:程序博客网 时间:2024/06/16 19:38

2enableNative的分析

         enable Native是真正的蓝牙使能的函数,蓝牙打开的一系列操作都是通过他来真正实现的。可以认为,这个函数蓝牙使能的主干,其余几个方面都可以认为是旁枝末节而已,因此,无论如何,我们必须了解到这个函数真正的精髓所在。

         先来看jni层究竟是如何实现这个函数的:

[cpp] view plaincopy
  1. static jint enableNative(JNIEnv *env, jobject object) {  
  2. #ifdef HAVE_BLUETOOTH  
  3. LOGV("%s", __FUNCTION__);  
  4. //可以看到其实很简单,就是调用bt_enable函数  
  5.     return bt_enable();  
  6. #endif  
  7.     return -1;  
  8. }  
  9.     bt_enable是libbluedroid.so这个动态库中的一个函数,所以,很容易就可以找到对应的源码:system/bluetooth/bluedroid/bluetooth.c  
  10. int bt_enable() {  
  11. ……  
  12. //这里是通过rfkill来设置蓝牙芯片的电压,也就是通常所说的上电  
  13. //这里是通过向对应的rfkill的state文件置1,各家的方案都有各家的做法,但实现的接口是统一的  
  14.     if (set_bluetooth_power(1) < 0) goto out;  
  15.     //启动hciattach service,这个是在init.rc中定义的service,在前面的文章中我已经有说明过。  
  16.     //hciattach的作用是用来初始化蓝牙芯片,他包含了串口的波特率的初始化,fw的download等一系列的操作,各家的方案又会有所差异,所以,我就不详细分析了,大家知道这个是做些什么操作的即可  
  17.     LOGI("Starting hciattach daemon");  
  18.     if (property_set("ctl.start""hciattach") < 0) {  
  19.         LOGE("Failed to start hciattach");  
  20.         set_bluetooth_power(0);  
  21.         goto out;  
  22.     }  
  23.   
  24.     // Try for 10 seconds, this can only succeed once hciattach has sent the  
  25. // firmware and then turned on hci device via HCIUARTSETPROTO ioctl  
  26. //这里其实有一个小的bug,注释是10s的尝试时间,事实上每次等待的时间是100ms,总共时间就已经到100s了,不过也无伤大雅了。  
  27. //这里就是通过ioctl去进行hcidev的up,我们可以理解只有hciattach把芯片全部初始化完成,这里才能够成功up,否则就会出错,我们就需要去不停的进行尝试。  
  28. //你肯定会有疑问,hciattach那边是如何控制这边的出错的啊?其实很简单,在hciattach初始化要结束的时候才会去创建hcidev,若是连hcidev都没有,up必然会出错了,呵呵,具体的细节下面再详细分析了  
  29. //hciattach对hcidev的影响见2.1  
  30. //hcidev up的详细分析见2.2  
  31. for (attempt = 1000; attempt > 0;  attempt--) {  
  32.     //创建socket,没什么好说的  
  33.         hci_sock = create_hci_sock();  
  34.         if (hci_sock < 0) goto out;  
  35.         //通过ioctl来进行up  
  36.         ret = ioctl(hci_sock, HCIDEVUP, HCI_DEV_ID);  
  37.   
  38.         LOGI("bt_enable: ret: %d, errno: %d", ret, errno);  
  39.         if (!ret) {  
  40.             break;  
  41.         } else if (errno == EALREADY) {  
  42.             LOGW("Bluetoothd already started, unexpectedly!");  
  43.             break;  
  44.         }  
  45.   
  46.         close(hci_sock);  
  47.         usleep(100000);  // 100 ms retry delay  
  48.     }  
  49.     if (attempt == 0) {  
  50.         LOGE("%s: Timeout waiting for HCI device to come up, error- %d, ",  
  51.             __FUNCTION__, ret);  
  52. //若出错,停止hciattach service  
  53.         if (property_set("ctl.stop""hciattach") < 0) {  
  54.             LOGE("Error stopping hciattach");  
  55.         }  
  56. //把芯片的电压关闭掉  
  57.         set_bluetooth_power(0);  
  58.         goto out;  
  59.     }  
  60.   
  61. LOGI("Starting bluetoothd deamon");  
  62. //启动bluetoothd service,详细的分析见2.2  
  63.     if (property_set("ctl.start""bluetoothd") < 0) {  
  64.         LOGE("Failed to start bluetoothd");  
  65.         set_bluetooth_power(0);  
  66.         goto out;  
  67.     }  
  68.   
  69.     ret = 0;  
  70.   
  71. out:  
  72.     if (hci_sock >= 0) close(hci_sock);  
  73.     return ret;  
  74. }  

2.1hciattach中的hci dev的注册。

我们已经说了hciattach每一家的方案都是不同的,其中涉及到各家的代码实现就不详细分析了,这里我们为了使下面的hci dev up的流程分析得更加清楚,会说明一下在每家蓝牙初始化结束之后都会进行的hci device的注册流程。

verdor蓝牙初始化结束之后会调用如下函数,这个函数就是对hci dev的注册,proto就是各家的方案不同了,比如h4h5之类的

[cpp] view plaincopy
  1. if (ioctl(fd, HCIUARTSETPROTO, u->proto) < 0) {  
  2.     perror("Can't set device");  
  3.     return -1;  
  4. }  

我们来看HCIUARTSETPROTO最终会调用什么:

[cpp] view plaincopy
  1. static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,  
  2.                     unsigned int cmd, unsigned long arg)  
  3. {……  
  4.     case HCIUARTSETPROTO:  
  5.         //检测hu->flags是否设置HCI_UART_PROTO_SET是否置位,没有就会进入到if内,并置位。显然,开始我们是没有的  
  6.         if (!test_and_set_bit(HCI_UART_PROTO_SET, &hu->flags)) {  
  7.             //重要的就是这个函数了  
  8.             err = hci_uart_set_proto(hu, arg);  
  9.             if (err) {    
  10.                 //有erro,把这个标志位清空  
  11.                 clear_bit(HCI_UART_PROTO_SET, &hu->flags);  
  12.                 return err;  
  13.             }  
  14.         } else  
  15.             return -EBUSY;  
  16.         break;  
  17. ……}  
  18. static int hci_uart_set_proto(struct hci_uart *hu, int id)  
  19. {  
  20.     struct hci_uart_proto *p;  
  21.     int err;  
  22.     //首先是proto的一些初始化,各家都不相同,我们就不分析了  
  23.     p = hci_uart_get_proto(id);  
  24.     if (!p)  
  25.         return -EPROTONOSUPPORT;  
  26.   
  27.     err = p->open(hu);  
  28.     if (err)  
  29.         return err;  
  30.   
  31.     hu->proto = p;  
  32.     //重点关注一下dev的register  
  33.     err = hci_uart_register_dev(hu);  
  34. ……  
  35.   
  36.     return 0;  
  37. }  
  38.   
  39. static int hci_uart_register_dev(struct hci_uart *hu)  
  40. {  
  41.     struct hci_dev *hdev;  
  42.   
  43.     BT_DBG("");  
  44.     //申请hci dev的结构体空间  
  45.     /* Initialize and register HCI device */  
  46.     hdev = hci_alloc_dev();  
  47.     if (!hdev) {  
  48.         BT_ERR("Can't allocate HCI device");  
  49.         return -ENOMEM;  
  50.     }  
  51.     //初始化hdev的一些成员  
  52.     hu->hdev = hdev;  
  53.   
  54.     hdev->bus = HCI_UART;  
  55.     hdev->driver_data = hu;  
  56.   
  57.     hdev->open  = hci_uart_open;  
  58.     hdev->close = hci_uart_close;  
  59.     hdev->flush = hci_uart_flush;  
  60.     hdev->send  = hci_uart_send_frame;  
  61.     hdev->destruct = hci_uart_destruct;  
  62.     hdev->parent = hu->tty->dev;  
  63.   
  64.     hdev->owner = THIS_MODULE;  
  65.     //reset默认为0,就是设置为HCI_QUIRK_NO_RESET  
  66.     if (!reset)  
  67.         set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);  
  68.     //这里根据各家的方案会有所不同,一般是没有设置的  
  69.     if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags))  
  70.         set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);  
  71.     //把这个device注册到hci,见2.1.1  
  72.     if (hci_register_dev(hdev) < 0) {  
  73.         BT_ERR("Can't register HCI device");  
  74.         hci_free_dev(hdev);  
  75.         return -ENODEV;  
  76.     }  
  77.   
  78.     return 0;  
  79. }  

2.1.1hci device的注册

[cpp] view plaincopy
  1. /* Register HCI device */  
  2. int hci_register_dev(struct hci_dev *hdev)  
  3. {  
  4.     struct list_head *head = &hci_dev_list, *p;  
  5.     int i, id = 0;  
  6.   
  7.     BT_DBG("%p name %s bus %d owner %p", hdev, hdev->name,  
  8.                         hdev->bus, hdev->owner);  
  9.     //首先要保证这个device已经初始化了一些必要的内容,比如open,close和destruct函数  
  10.     if (!hdev->open || !hdev->close || !hdev->destruct)  
  11.         return -EINVAL;  
  12. //抓住写的锁  
  13.     write_lock_bh(&hci_dev_list_lock);  
  14. //在hci_dev_list中找第一个可用的device id  
  15.     /* Find first available device id */  
  16.     list_for_each(p, &hci_dev_list) {  
  17.         if (list_entry(p, struct hci_dev, list)->id != id)  
  18.             break;  
  19.         head = p; id++;  
  20.     }  
  21.     //一般而言,我们都是第一个,也就是hci0了  
  22.     sprintf(hdev->name, "hci%d", id);  
  23.     hdev->id = id;  
  24. //把hdev->list插入到hci_dev_list这个双向链表中  
  25.     list_add(&hdev->list, head);  
  26.     //hdev的ref cnt +1  
  27.     atomic_set(&hdev->refcnt, 1);  
  28.     //初始化一个锁  
  29.     spin_lock_init(&hdev->lock);  
  30.   
  31.     hdev->flags = 0;  
  32.     //packet type  
  33.     hdev->pkt_type  = (HCI_DM1 | HCI_DH1 | HCI_HV1);  
  34.     hdev->esco_type = (ESCO_HV1);  
  35.     hdev->link_mode = (HCI_LM_ACCEPT);  
  36.     //iocapability初始化为no input no output  
  37.     //很显然,这些初始化的内容都比较保守,所以,我们可以期待在不久的将来,他们会全部或者部分被修改掉  
  38.     hdev->io_capability = 0x03; /* No Input No Output */  
  39.     //idle和sniff mode相关的参数设置  
  40.     hdev->idle_timeout = 0;  
  41.     hdev->sniff_max_interval = 800;  
  42.     hdev->sniff_min_interval = 80;  
  43.     //初始化了3个队列和task,分别是cmd,tx,rx   
  44.     tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev);  
  45.     tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);  
  46.     tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);  
  47.   
  48.     skb_queue_head_init(&hdev->rx_q);  
  49.     skb_queue_head_init(&hdev->cmd_q);  
  50.     skb_queue_head_init(&hdev->raw_q);  
  51.     //初始化一个cmd的timer  
  52.     setup_timer(&hdev->cmd_timer, hci_cmd_timer, (unsigned long) hdev);  
  53.   
  54.     for (i = 0; i < NUM_REASSEMBLY; i++)  
  55.         hdev->reassembly[i] = NULL;  
  56.     //初始化一个wait 队列  
  57.     init_waitqueue_head(&hdev->req_wait_q);  
  58.     mutex_init(&hdev->req_lock);  
  59.     //初始化inquiry,connect的cache  
  60.     inquiry_cache_init(hdev);  
  61.   
  62.     hci_conn_hash_init(hdev);  
  63.     //初始化几个list  
  64.     INIT_LIST_HEAD(&hdev->blacklist);  
  65.     INIT_LIST_HEAD(&hdev->uuids);  
  66.     INIT_LIST_HEAD(&hdev->link_keys);  
  67.     INIT_LIST_HEAD(&hdev->remote_oob_data);  
  68.     INIT_LIST_HEAD(&hdev->adv_entries);  
  69.     //在启动一个adv的timer  
  70.     setup_timer(&hdev->adv_timer, hci_clear_adv_cache,  
  71.                         (unsigned long) hdev);  
  72.     memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));  
  73.   
  74.     atomic_set(&hdev->promisc, 0);  
  75.     //释放锁  
  76.     write_unlock_bh(&hci_dev_list_lock);  
  77.     //创建一个单任务的工作队列  
  78.     hdev->workqueue = create_singlethread_workqueue(hdev->name);  
  79.     if (!hdev->workqueue)  
  80.         goto nomem;  
  81.     hdev->tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);  
  82.     if (IS_ERR(hdev->tfm))  
  83.         BT_INFO("Failed to load transform for ecb(aes): %ld",  
  84.                             PTR_ERR(hdev->tfm));  
  85.   
  86.     hci_register_sysfs(hdev);  
  87.     //申请rfkill  
  88.     hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,  
  89.                 RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, hdev);  
  90.     if (hdev->rfkill) {  
  91.         if (rfkill_register(hdev->rfkill) < 0) {  
  92.             rfkill_destroy(hdev->rfkill);  
  93.             hdev->rfkill = NULL;  
  94.         }  
  95.     }  
  96.     //会发送一个DEV_REG出去,若是有监听的,那么就会做相应的处理,kernel中是没有啦,但是在bluez中是有的,等bluez分析完成,我们再来分析这里  
  97.     hci_notify(hdev, HCI_DEV_REG);  
  98. ……  
  99. }  

至此,hci device的注册流程就已经完全ok了。

2.2hci dev up的流程分析

  hci deviceup是通过HCIDEVUP这个ioctl来实现的,他实现的代码在kernel/net/bluetooth/hci_sock.c中:

[cpp] view plaincopy
  1. static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)  
  2. {  
  3. ……  
  4.     case HCIDEVUP:  
  5. //主要就是这个open函数  
  6.         return hci_dev_open(arg);  
  7. ……}  
  8.   
  9. int hci_dev_open(__u16 dev)  
  10. {  
  11. ……  
  12. //在hciattach没有完成的时候,我们基本都是在这里直接return  
  13.     hdev = hci_dev_get(dev);  
  14.     if (!hdev)  
  15.         return -ENODEV;  
  16.   
  17.     BT_DBG("%s %p", hdev->name, hdev);  
  18. //抓住锁  
  19.     hci_req_lock(hdev);  
  20. //看rfkill是否正常,这里是在hci dev注册的时候就会申请的   
  21.     if (hdev->rfkill && rfkill_blocked(hdev->rfkill)) {  
  22.         ret = -ERFKILL;  
  23.         goto done;  
  24.     }  
  25. //检查是否已经up了,若已经up了,当然就不需要做什么了  
  26.     if (test_bit(HCI_UP, &hdev->flags)) {  
  27.         ret = -EALREADY;  
  28.         goto done;  
  29.     }  
  30. //这个就没有设置了  
  31.     if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))  
  32.         set_bit(HCI_RAW, &hdev->flags);  
  33. //目前把非BR/EDR的控制器都设置HCI_RAW  
  34.     /* Treat all non BR/EDR controllers as raw devices for now */  
  35.     if (hdev->dev_type != HCI_BREDR)  
  36.         set_bit(HCI_RAW, &hdev->flags);  
  37. //调用dev的open函数  
  38. //在hci_uart_register_dev函数中,我们有初始化hdev->open  = hci_uart_open  
  39. //所以直接去看hci_uart_open函数即可,其实很简单,就是hdev->flags的HCI_RUNNING位置1  
  40.     if (hdev->open(hdev)) {  
  41.         ret = -EIO;  
  42.         goto done;  
  43.     }  
  44. //若不是HCI_RAW  
  45.     if (!test_bit(HCI_RAW, &hdev->flags)) {  
  46.         //设置cmd的count为1  
  47.         atomic_set(&hdev->cmd_cnt, 1);  
  48.         //为flags的HCI_INIT置位  
  49.         set_bit(HCI_INIT, &hdev->flags);  
  50.         //初始好的最后一个cmd置为0  
  51.         hdev->init_last_cmd = 0;  
  52.         //hci的初始化,timeout是10s  
  53.         //这里是一些hci cmd和response的交互,我们会在2.1.1中进行详细分析  
  54.         ret = __hci_request(hdev, hci_init_req, 0,  
  55.                     msecs_to_jiffies(HCI_INIT_TIMEOUT));  
  56.         //若是支援le,则需要继续le的一些初始化,这里就暂不分析了  
  57.         if (lmp_host_le_capable(hdev))  
  58.             ret = __hci_request(hdev, hci_le_init_req, 0,  
  59.                     msecs_to_jiffies(HCI_INIT_TIMEOUT));  
  60.         //把HCI_INIT标志位清除  
  61.         clear_bit(HCI_INIT, &hdev->flags);  
  62.     }  
  63.   
  64.     if (!ret) {  
  65.     //若是初始化成功,hdev的ref+1  
  66.         hci_dev_hold(hdev);  
  67.     //设置hdev的HCI_UP位  
  68.         set_bit(HCI_UP, &hdev->flags);  
  69.     //通知HCI_DEV_UP,若是有人需要监测dev的up,则这里就会得到通知,从而进行下一步的操作,和dev_reg是一样的,在kernel中是没有,但是在bluez中仍然是有的。  
  70.         hci_notify(hdev, HCI_DEV_UP);  
  71.         //看flags中的HCI_SETUP位是否被置位,若是没有,则调用mgmt_powered函数通知bluez去做一些处理,这个在register dev的时候就会置位,所以,这里我们不会再调用了  
  72.         if (!test_bit(HCI_SETUP, &hdev->flags))  
  73.             mgmt_powered(hdev->id, 1);  
  74.     } else {  
  75.         /* Init failed, cleanup */  
  76.         //一些错误的处理,不详细分析了,和register是对应的  
  77. ……  
  78. }  

至此,整个这个流程中的hci device的注册和up就已经全部分析完成了,细心的童鞋会发现其实这之中的cmd和event的交互我们并没有详细分析,而这恰恰是一个很重要的过程,晓东将会在另一篇文章中和大家详细分析,若是想学习的童鞋最好先去把bluetooth的spec学习一下,否则估计你是很难看懂了哦~~

 

0 0