当前位置:   article > 正文

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

hci_dev没有voice_setting 成员

2enableNative的分析

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

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

  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. // Try for 10 seconds, this can only succeed once hciattach has sent the
  24. // firmware and then turned on hci device via HCIUARTSETPROTO ioctl
  25. //这里其实有一个小的bug,注释是10s的尝试时间,事实上每次等待的时间是100ms,总共时间就已经到100s了,不过也无伤大雅了。
  26. //这里就是通过ioctl去进行hcidev的up,我们可以理解只有hciattach把芯片全部初始化完成,这里才能够成功up,否则就会出错,我们就需要去不停的进行尝试。
  27. //你肯定会有疑问,hciattach那边是如何控制这边的出错的啊?其实很简单,在hciattach初始化要结束的时候才会去创建hcidev,若是连hcidev都没有,up必然会出错了,呵呵,具体的细节下面再详细分析了
  28. //hciattach对hcidev的影响见2.1
  29. //hcidev up的详细分析见2.2
  30. for (attempt = 1000; attempt > 0; attempt--) {
  31. //创建socket,没什么好说的
  32. hci_sock = create_hci_sock();
  33. if (hci_sock < 0) goto out;
  34. //通过ioctl来进行up
  35. ret = ioctl(hci_sock, HCIDEVUP, HCI_DEV_ID);
  36. LOGI("bt_enable: ret: %d, errno: %d", ret, errno);
  37. if (!ret) {
  38. break;
  39. } else if (errno == EALREADY) {
  40. LOGW("Bluetoothd already started, unexpectedly!");
  41. break;
  42. }
  43. close(hci_sock);
  44. usleep(100000); // 100 ms retry delay
  45. }
  46. if (attempt == 0) {
  47. LOGE("%s: Timeout waiting for HCI device to come up, error- %d, ",
  48. __FUNCTION__, ret);
  49. //若出错,停止hciattach service
  50. if (property_set("ctl.stop", "hciattach") < 0) {
  51. LOGE("Error stopping hciattach");
  52. }
  53. //把芯片的电压关闭掉
  54. set_bluetooth_power(0);
  55. goto out;
  56. }
  57. LOGI("Starting bluetoothd deamon");
  58. //启动bluetoothd service,详细的分析见2.2
  59. if (property_set("ctl.start", "bluetoothd") < 0) {
  60. LOGE("Failed to start bluetoothd");
  61. set_bluetooth_power(0);
  62. goto out;
  63. }
  64. ret = 0;
  65. out:
  66. if (hci_sock >= 0) close(hci_sock);
  67. return ret;
  68. }

2.1hciattach中的hci dev的注册。

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

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

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

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

  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. err = p->open(hu);
  27. if (err)
  28. return err;
  29. hu->proto = p;
  30. //重点关注一下dev的register
  31. err = hci_uart_register_dev(hu);
  32. ……
  33. return 0;
  34. }
  35. static int hci_uart_register_dev(struct hci_uart *hu)
  36. {
  37. struct hci_dev *hdev;
  38. BT_DBG("");
  39. //申请hci dev的结构体空间
  40. /* Initialize and register HCI device */
  41. hdev = hci_alloc_dev();
  42. if (!hdev) {
  43. BT_ERR("Can't allocate HCI device");
  44. return -ENOMEM;
  45. }
  46. //初始化hdev的一些成员
  47. hu->hdev = hdev;
  48. hdev->bus = HCI_UART;
  49. hdev->driver_data = hu;
  50. hdev->open = hci_uart_open;
  51. hdev->close = hci_uart_close;
  52. hdev->flush = hci_uart_flush;
  53. hdev->send = hci_uart_send_frame;
  54. hdev->destruct = hci_uart_destruct;
  55. hdev->parent = hu->tty->dev;
  56. hdev->owner = THIS_MODULE;
  57. //reset默认为0,就是设置为HCI_QUIRK_NO_RESET
  58. if (!reset)
  59. set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
  60. //这里根据各家的方案会有所不同,一般是没有设置的
  61. if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags))
  62. set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
  63. //把这个device注册到hci,见2.1.1
  64. if (hci_register_dev(hdev) < 0) {
  65. BT_ERR("Can't register HCI device");
  66. hci_free_dev(hdev);
  67. return -ENODEV;
  68. }
  69. return 0;
  70. }

2.1.1hci device的注册

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

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

2.2hci dev up的流程分析

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

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

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

若您觉得该文章对您有帮助,请在下面用鼠标轻轻按一下“顶”,哈哈~~·

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号