2、enableNative的分析
enable Native是真正的蓝牙使能的函数,蓝牙打开的一系列操作都是通过他来真正实现的。可以认为,这个函数蓝牙使能的主干,其余几个方面都可以认为是旁枝末节而已,因此,无论如何,我们必须了解到这个函数真正的精髓所在。
先来看jni层究竟是如何实现这个函数的:
static jint enableNative(JNIEnv *env, jobject object) { #ifdef HAVE_BLUETOOTH LOGV("%s", __FUNCTION__); //可以看到其实很简单,就是调用bt_enable函数 return bt_enable(); #endif return -1; } bt_enable是libbluedroid.so这个动态库中的一个函数,所以,很容易就可以找到对应的源码:system/bluetooth/bluedroid/bluetooth.c int bt_enable() { …… //这里是通过rfkill来设置蓝牙芯片的电压,也就是通常所说的上电 //这里是通过向对应的rfkill的state文件置1,各家的方案都有各家的做法,但实现的接口是统一的 if (set_bluetooth_power(1) < 0) goto out; //启动hciattach service,这个是在init.rc中定义的service,在前面的文章中我已经有说明过。 //hciattach的作用是用来初始化蓝牙芯片,他包含了串口的波特率的初始化,fw的download等一系列的操作,各家的方案又会有所差异,所以,我就不详细分析了,大家知道这个是做些什么操作的即可 LOGI("Starting hciattach daemon"); if (property_set("ctl.start", "hciattach") < 0) { LOGE("Failed to start hciattach"); set_bluetooth_power(0); goto out; } // Try for 10 seconds, this can only succeed once hciattach has sent the // firmware and then turned on hci device via HCIUARTSETPROTO ioctl //这里其实有一个小的bug,注释是10s的尝试时间,事实上每次等待的时间是100ms,总共时间就已经到100s了,不过也无伤大雅了。 //这里就是通过ioctl去进行hcidev的up,我们可以理解只有hciattach把芯片全部初始化完成,这里才能够成功up,否则就会出错,我们就需要去不停的进行尝试。 //你肯定会有疑问,hciattach那边是如何控制这边的出错的啊?其实很简单,在hciattach初始化要结束的时候才会去创建hcidev,若是连hcidev都没有,up必然会出错了,呵呵,具体的细节下面再详细分析了 //hciattach对hcidev的影响见2.1 //hcidev up的详细分析见2.2 for (attempt = 1000; attempt > 0; attempt--) { //创建socket,没什么好说的 hci_sock = create_hci_sock(); if (hci_sock < 0) goto out; //通过ioctl来进行up ret = ioctl(hci_sock, HCIDEVUP, HCI_DEV_ID); LOGI("bt_enable: ret: %d, errno: %d", ret, errno); if (!ret) { break; } else if (errno == EALREADY) { LOGW("Bluetoothd already started, unexpectedly!"); break; } close(hci_sock); usleep(100000); // 100 ms retry delay } if (attempt == 0) { LOGE("%s: Timeout waiting for HCI device to come up, error- %d, ", __FUNCTION__, ret); //若出错,停止hciattach service if (property_set("ctl.stop", "hciattach") < 0) { LOGE("Error stopping hciattach"); } //把芯片的电压关闭掉 set_bluetooth_power(0); goto out; } LOGI("Starting bluetoothd deamon"); //启动bluetoothd service,详细的分析见2.2 if (property_set("ctl.start", "bluetoothd") < 0) { LOGE("Failed to start bluetoothd"); set_bluetooth_power(0); goto out; } ret = 0; out: if (hci_sock >= 0) close(hci_sock); return ret; }
2.1、hciattach中的hci dev的注册。
我们已经说了hciattach每一家的方案都是不同的,其中涉及到各家的代码实现就不详细分析了,这里我们为了使下面的hci dev up的流程分析得更加清楚,会说明一下在每家蓝牙初始化结束之后都会进行的hci device的注册流程。
在verdor蓝牙初始化结束之后会调用如下函数,这个函数就是对hci dev的注册,proto就是各家的方案不同了,比如h4,h5之类的
if (ioctl(fd, HCIUARTSETPROTO, u->proto) < 0) { perror("Can't set device"); return -1; }
我们来看HCIUARTSETPROTO最终会调用什么:
static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) {…… case HCIUARTSETPROTO: //检测hu->flags是否设置HCI_UART_PROTO_SET是否置位,没有就会进入到if内,并置位。显然,开始我们是没有的 if (!test_and_set_bit(HCI_UART_PROTO_SET, &hu->flags)) { //重要的就是这个函数了 err = hci_uart_set_proto(hu, arg); if (err) { //有erro,把这个标志位清空 clear_bit(HCI_UART_PROTO_SET, &hu->flags); return err; } } else return -EBUSY; break; ……} static int hci_uart_set_proto(struct hci_uart *hu, int id) { struct hci_uart_proto *p; int err; //首先是proto的一些初始化,各家都不相同,我们就不分析了 p = hci_uart_get_proto(id); if (!p) return -EPROTONOSUPPORT; err = p->open(hu); if (err) return err; hu->proto = p; //重点关注一下dev的register err = hci_uart_register_dev(hu); …… return 0; } static int hci_uart_register_dev(struct hci_uart *hu) { struct hci_dev *hdev; BT_DBG(""); //申请hci dev的结构体空间 /* Initialize and register HCI device */ hdev = hci_alloc_dev(); if (!hdev) { BT_ERR("Can't allocate HCI device"); return -ENOMEM; } //初始化hdev的一些成员 hu->hdev = hdev; hdev->bus = HCI_UART; hdev->driver_data = hu; hdev->open = hci_uart_open; hdev->close = hci_uart_close; hdev->flush = hci_uart_flush; hdev->send = hci_uart_send_frame; hdev->destruct = hci_uart_destruct; hdev->parent = hu->tty->dev; hdev->owner = THIS_MODULE; //reset默认为0,就是设置为HCI_QUIRK_NO_RESET if (!reset) set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); //这里根据各家的方案会有所不同,一般是没有设置的 if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags)) set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); //把这个device注册到hci,见2.1.1 if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); hci_free_dev(hdev); return -ENODEV; } return 0; }
2.1.1hci device的注册
/* Register HCI device */ int hci_register_dev(struct hci_dev *hdev) { struct list_head *head = &hci_dev_list, *p; int i, id = 0; BT_DBG("%p name %s bus %d owner %p", hdev, hdev->name, hdev->bus, hdev->owner); //首先要保证这个device已经初始化了一些必要的内容,比如open,close和destruct函数 if (!hdev->open || !hdev->close || !hdev->destruct) return -EINVAL; //抓住写的锁 write_lock_bh(&hci_dev_list_lock); //在hci_dev_list中找第一个可用的device id /* Find first available device id */ list_for_each(p, &hci_dev_list) { if (list_entry(p, struct hci_dev, list)->id != id) break; head = p; id++; } //一般而言,我们都是第一个,也就是hci0了 sprintf(hdev->name, "hci%d", id); hdev->id = id; //把hdev->list插入到hci_dev_list这个双向链表中 list_add(&hdev->list, head); //hdev的ref cnt +1 atomic_set(&hdev->refcnt, 1); //初始化一个锁 spin_lock_init(&hdev->lock); hdev->flags = 0; //packet type hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1); hdev->esco_type = (ESCO_HV1); hdev->link_mode = (HCI_LM_ACCEPT); //iocapability初始化为no input no output //很显然,这些初始化的内容都比较保守,所以,我们可以期待在不久的将来,他们会全部或者部分被修改掉 hdev->io_capability = 0x03; /* No Input No Output */ //idle和sniff mode相关的参数设置 hdev->idle_timeout = 0; hdev->sniff_max_interval = 800; hdev->sniff_min_interval = 80; //初始化了3个队列和task,分别是cmd,tx,rx 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); skb_queue_head_init(&hdev->rx_q); skb_queue_head_init(&hdev->cmd_q); skb_queue_head_init(&hdev->raw_q); //初始化一个cmd的timer setup_timer(&hdev->cmd_timer, hci_cmd_timer, (unsigned long) hdev); for (i = 0; i < NUM_REASSEMBLY; i++) hdev->reassembly[i] = NULL; //初始化一个wait 队列 init_waitqueue_head(&hdev->req_wait_q); mutex_init(&hdev->req_lock); //初始化inquiry,connect的cache inquiry_cache_init(hdev); hci_conn_hash_init(hdev); //初始化几个list INIT_LIST_HEAD(&hdev->blacklist); INIT_LIST_HEAD(&hdev->uuids); INIT_LIST_HEAD(&hdev->link_keys); INIT_LIST_HEAD(&hdev->remote_oob_data); INIT_LIST_HEAD(&hdev->adv_entries); //在启动一个adv的timer setup_timer(&hdev->adv_timer, hci_clear_adv_cache, (unsigned long) hdev); memset(&hdev->stat, 0, sizeof(struct hci_dev_stats)); atomic_set(&hdev->promisc, 0); //释放锁 write_unlock_bh(&hci_dev_list_lock); //创建一个单任务的工作队列 hdev->workqueue = create_singlethread_workqueue(hdev->name); if (!hdev->workqueue) goto nomem; hdev->tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(hdev->tfm)) BT_INFO("Failed to load transform for ecb(aes): %ld", PTR_ERR(hdev->tfm)); hci_register_sysfs(hdev); //申请rfkill hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev, RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, hdev); if (hdev->rfkill) { if (rfkill_register(hdev->rfkill) < 0) { rfkill_destroy(hdev->rfkill); hdev->rfkill = NULL; } } //会发送一个DEV_REG出去,若是有监听的,那么就会做相应的处理,kernel中是没有啦,但是在bluez中是有的,等bluez分析完成,我们再来分析这里 hci_notify(hdev, HCI_DEV_REG); …… }
至此,hci device的注册流程就已经完全ok了。
2.2、hci dev up的流程分析
hci device的up是通过HCIDEVUP这个ioctl来实现的,他实现的代码在kernel/net/bluetooth/hci_sock.c中:
static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { …… case HCIDEVUP: //主要就是这个open函数 return hci_dev_open(arg); ……} int hci_dev_open(__u16 dev) { …… //在hciattach没有完成的时候,我们基本都是在这里直接return hdev = hci_dev_get(dev); if (!hdev) return -ENODEV; BT_DBG("%s %p", hdev->name, hdev); //抓住锁 hci_req_lock(hdev); //看rfkill是否正常,这里是在hci dev注册的时候就会申请的 if (hdev->rfkill && rfkill_blocked(hdev->rfkill)) { ret = -ERFKILL; goto done; } //检查是否已经up了,若已经up了,当然就不需要做什么了 if (test_bit(HCI_UP, &hdev->flags)) { ret = -EALREADY; goto done; } //这个就没有设置了 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) set_bit(HCI_RAW, &hdev->flags); //目前把非BR/EDR的控制器都设置HCI_RAW /* Treat all non BR/EDR controllers as raw devices for now */ if (hdev->dev_type != HCI_BREDR) set_bit(HCI_RAW, &hdev->flags); //调用dev的open函数 //在hci_uart_register_dev函数中,我们有初始化hdev->open = hci_uart_open //所以直接去看hci_uart_open函数即可,其实很简单,就是hdev->flags的HCI_RUNNING位置1 if (hdev->open(hdev)) { ret = -EIO; goto done; } //若不是HCI_RAW if (!test_bit(HCI_RAW, &hdev->flags)) { //设置cmd的count为1 atomic_set(&hdev->cmd_cnt, 1); //为flags的HCI_INIT置位 set_bit(HCI_INIT, &hdev->flags); //初始好的最后一个cmd置为0 hdev->init_last_cmd = 0; //hci的初始化,timeout是10s //这里是一些hci cmd和response的交互,我们会在2.1.1中进行详细分析 ret = __hci_request(hdev, hci_init_req, 0, msecs_to_jiffies(HCI_INIT_TIMEOUT)); //若是支援le,则需要继续le的一些初始化,这里就暂不分析了 if (lmp_host_le_capable(hdev)) ret = __hci_request(hdev, hci_le_init_req, 0, msecs_to_jiffies(HCI_INIT_TIMEOUT)); //把HCI_INIT标志位清除 clear_bit(HCI_INIT, &hdev->flags); } if (!ret) { //若是初始化成功,hdev的ref+1 hci_dev_hold(hdev); //设置hdev的HCI_UP位 set_bit(HCI_UP, &hdev->flags); //通知HCI_DEV_UP,若是有人需要监测dev的up,则这里就会得到通知,从而进行下一步的操作,和dev_reg是一样的,在kernel中是没有,但是在bluez中仍然是有的。 hci_notify(hdev, HCI_DEV_UP); //看flags中的HCI_SETUP位是否被置位,若是没有,则调用mgmt_powered函数通知bluez去做一些处理,这个在register dev的时候就会置位,所以,这里我们不会再调用了 if (!test_bit(HCI_SETUP, &hdev->flags)) mgmt_powered(hdev->id, 1); } else { /* Init failed, cleanup */ //一些错误的处理,不详细分析了,和register是对应的 …… }
至此,整个这个流程中的hci device的注册和up就已经全部分析完成了,细心的童鞋会发现其实这之中的cmd和event的交互我们并没有详细分析,而这恰恰是一个很重要的过程,晓东将会在另一篇文章中和大家详细分析,若是想学习的童鞋最好先去把bluetooth的spec学习一下,否则估计你是很难看懂了哦~~
若您觉得该文章对您有帮助,请在下面用鼠标轻轻按一下“顶”,哈哈~~·