作为一个程序员,咋废话就不多说了,直接看代码吧,哈哈~~
2)adapter的初始化
gboolean adapter_init(struct btd_adapter *adapter)
{
int err;
/* adapter_ops makes sure that newly registered adapters always
* start off as powered */
//置up位,为什么不放到最后在置位啊
adapter->up = TRUE;
//读bdaddr,这个就是得到dev的bdaddr到adapter->bdaddr
adapter_ops->read_bdaddr(adapter->dev_id, &adapter->bdaddr);
//和BDADDR_ANY比较一下,若是一样就是有问题啦。
if (bacmp(&adapter->bdaddr, BDADDR_ANY) == 0) {
error("No address available for hci%d", adapter->dev_id);
return FALSE;
}
//同样的时候拷贝dev的features到adapter的features中
err = adapter_ops->read_local_features(adapter->dev_id,
adapter->features);
if (err < 0) {
error("Can't read features for hci%d: %s (%d)",
adapter->dev_id, strerror(-err), -err);
return FALSE;
}
//对应的config文件下,看是否有name,显然是没有的,所以会进入if中
if (read_local_name(&adapter->bdaddr, adapter->name) < 0)
//adapter->name应该是null了,main_opts.name就是main.conf中的内容了,是%m。这里就是初始化adapter->name的值了。读取的是ro.product.model的值,他在buildinfo.sh定义为PRODUCT_MODEL,而PRODUCT_MODEL就是对应的base.mk中定义的,所以,我们可以在这里改变名字。就是我们见到的8825gc,具体见2-1.
expand_name(adapter->name, MAX_NAME_LENGTH, main_opts.name,
adapter->dev_id);
//是否支持gatt,显然目前我们并不支持
if (main_opts.attrib_server)
attrib_gap_set(GATT_CHARAC_DEVICE_NAME,
(const uint8_t *) adapter->name, strlen(adapter->name));
//初始化service list,就是把开始的那些service record和adapter这边关联起来。见2-2
sdp_init_services_list(&adapter->bdaddr);
//就是加载那些plugin的adpater driver,见2-3分析
load_drivers(adapter);
//清除block列表
clear_blocked(adapter);
//加载device,就是创建一系列的文件,见2-4分析
load_devices(adapter);
/* Set pairable mode */
//读config文件下的pairable的值,若是没有读到就设为true,否则就是读到的值
if (read_device_pairable(&adapter->bdaddr, &adapter->pairable) < 0)
adapter->pairable = TRUE;
/* retrieve the active connections: address the scenario where
* the are active connections before the daemon've started */
//得到active的connection
load_connections(adapter);
//initialized设为true
adapter->initialized = TRUE;
return TRUE;
}
2-1 expand_name分析
expand_name就是扩展名字了。这里ANDROID_EXPAND_NAME是必然会定义了的
static char *expand_name(char *dst, int size, char *str, int dev_id)
{
register int sp, np, olen;
char *opt, buf[10];
#ifdef ANDROID_EXPAND_NAME
char value[PROPERTY_VALUE_MAX];
#endif
//这里当然不是null了
if (!str || !dst)
return NULL;
sp = np = 0;
while (np < size - 1 && str[sp]) {
switch (str[sp]) {
case '%':
opt = NULL;
switch (str[sp+1]) {
case 'd':
……
//我们是%m,所以会走到这里
#ifdef ANDROID_EXPAND_NAME
case 'b':
property_get("ro.product.brand", value, "");
opt = value;
break;
//得到ro.product.model的值
case 'm':
property_get("ro.product.model", value, "");
opt = value;
break;
……
#endif
case '%':
dst[np++] = str[sp++];
/* fall through */
default:
sp++;
continue;
}
if (opt) {
/* substitute */
//保存到adapter.name中
olen = strlen(opt);
if (np + olen < size - 1)
memcpy(dst + np, opt, olen);
np += olen;
}
sp += 2;
continue;
case '\\':
sp++;
/* fall through */
default:
dst[np++] = str[sp++];
break;
}
}
dst[np] = '\0';
return dst;
}
2-2 sdp_init_services_list
这个函数主要就是把开始的service record和对应的adapter关联起来
void sdp_init_services_list(bdaddr_t *device)
{
sdp_list_t *p;
DBG("");
//access_db就是开始那边sdp record会加入的
for (p = access_db; p != NULL; p = p->next) {
sdp_access_t *access = p->data;
sdp_record_t *rec;
if (bacmp(BDADDR_ANY, &access->device))
continue;
//得到对应的sdp record
rec = sdp_record_find(access->handle);
if (rec == NULL)
continue;
SDPDBG("adding record with handle %x", access->handle);
//加入到每一个adapter中,这里其实也就是一个了
//这里其实就是会调用adapter_service_insert函数
manager_foreach_adapter(adapter_service_insert, rec);
}
}
void adapter_service_insert(struct btd_adapter *adapter, void *r)
{
sdp_record_t *rec = r;
gboolean new_uuid;
//看adapter services中是否已经有了该uuid
if (sdp_list_find(adapter->services, &rec->svclass, uuid_cmp) == NULL)
new_uuid = TRUE;
else
new_uuid = FALSE;
//把这个rec加入到adapter services中
adapter->services = sdp_list_insert_sorted(adapter->services, rec,
record_sort);
if (new_uuid) {
//add uuid,新的uuid,则需要调用hciops中的add uuid
uint8_t svc_hint = get_uuid_mask(&rec->svclass);
//调用hciops对应的add_uuid,就是下面的hciops_add_uuid
adapter_ops->add_uuid(adapter->dev_id, &rec->svclass, svc_hint);
}
//因为adapter还没有初始化完成,所以这个不会做什么,直接return而已
adapter_emit_uuids_updated(adapter);
}
static int hciops_add_uuid(int index, uuid_t *uuid, uint8_t svc_hint)
{
struct dev_info *dev = &devs[index];
struct uuid_info *info;
DBG("hci%d", index);
//新建一个uuid info用来保存这个新的uuid
info = g_new0(struct uuid_info, 1);
memcpy(&info->uuid, uuid, sizeof(*uuid));
info->svc_hint = svc_hint;
//加入到dev->uuids列表中
dev->uuids = g_slist_append(dev->uuids, info);
return update_service_classes(index);
}
static int update_service_classes(int index)
{
struct dev_info *dev = &devs[index];
uint8_t value;
int err;
//uuid对应的service class集合
value = generate_service_class(index);
DBG("hci%d value %u", index, value);
/* Update only the service class, keep the limited bit,
* major/minor class bits intact */
dev->wanted_cod &= 0x00ffff;
dev->wanted_cod |= (value << 16);
/* If the cache is enabled or an existing CoD write is in progress
* just bail out */
//我们这边的cached_enable是置为true的,所以,暂时就直接return了,后面等到了再分析吧
if (dev->cache_enable || dev->pending_cod)
return 0;
……
}
2-3 plugin的adapter driver的加载
在2.2.7中,我们详细分析了各个plugin的初始化,他们最后也注册了一系列的adapter_driver,这里我们就是把这些driver进行初始化。
//其实就是遍历adapter_drivers列表,然后probe driver
static void load_drivers(struct btd_adapter *adapter)
{
GSList *l;
for (l = adapter_drivers; l; l = l->next)
probe_driver(adapter, l->data);
}
static void probe_driver(struct btd_adapter *adapter, gpointer user_data)
{
struct btd_adapter_driver *driver = user_data;
int err;
//检查是否已经up
if (!adapter->up)
return;
//检查是否有probe函数
if (driver->probe == NULL)
return;
//调用对应的probe
err = driver->probe(adapter);
if (err < 0) {
error("%s: %s (%d)", driver->name, strerror(-err), -err);
return;
}
//加入到loaded_drivers列表中
adapter->loaded_drivers = g_slist_prepend(adapter->loaded_drivers,
driver);
}
从2.3.7的最后,我们发现最终注册到adapter_driver列表中的有:a2dp_server_driver,avrcp_server_driver,input_server_driver,network_server_driver,hdp_adapter_driver。所以,下面我们就这些进行一下分析。我们以a2dp_server_driver为例进行分析,其它的就比较类似了,不多做解释。
a2dp_server_driver的probe函数分析
static int a2dp_server_probe(struct btd_adapter *adapter)
{
struct audio_adapter *adp;
//得到adapter的path
const gchar *path = adapter_get_path(adapter);
bdaddr_t src;
int err;
DBG("path %s", path);
//创建一个audio adapter,开始肯定没有啦
adp = audio_adapter_get(adapter);
if (!adp)
return -EINVAL;
//得到对应的address
adapter_get_address(adapter, &src);
//a2dp的注册,很大程度上需要根据config做一些不同的操作
err = a2dp_register(connection, &src, config);
if (err < 0)
audio_adapter_unref(adp);
return err;
}
int a2dp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config)
{
int sbc_srcs = 1, sbc_sinks = 1;
int mpeg12_srcs = 0, mpeg12_sinks = 0;
gboolean source = TRUE, sink = FALSE, socket = TRUE;
gboolean delay_reporting = FALSE;
char *str;
GError *err = NULL;
int i;
struct a2dp_server *server;
if (!config)
goto proceed;
//关于config,配置如下:
/*
Enable=Sink,Control
Disable=Headset,Gateway,Source
Master=false
FastConnectable=false
[A2DP]
SBCSources=1
MPEG12Sources=0
*/
str = g_key_file_get_string(config, "General", "Enable", &err);
if (err) {
DBG("audio.conf: %s", err->message);
g_clear_error(&err);
} else {
if (strstr(str, "Sink"))
source = TRUE; //source是true,是反的啊~~
if (strstr(str, "Source"))
sink = TRUE;
g_free(str);
}
str = g_key_file_get_string(config, "General", "Disable", &err);
if (err) {
DBG("audio.conf: %s", err->message);
g_clear_error(&err);
} else {
if (strstr(str, "Sink"))
source = FALSE;
if (strstr(str, "Source"))
sink = FALSE; //这个是false
if (strstr(str, "Socket"))
socket = FALSE; //socket没有,所以它还是true
g_free(str);
}
/* Don't register any local sep if Socket is disabled */
//socket肯定是会支持的,所以这里不会走到
if (socket == FALSE) {
sbc_srcs = 0;
sbc_sinks = 0;
mpeg12_srcs = 0;
mpeg12_sinks = 0;
goto proceed;
}
str = g_key_file_get_string(config, "A2DP", "SBCSources", &err);
if (err) {
DBG("audio.conf: %s", err->message);
g_clear_error(&err);
} else {
sbc_srcs = atoi(str); //sbc_srcs=1
g_free(str);
}
str = g_key_file_get_string(config, "A2DP", "MPEG12Sources", &err);
if (err) {
DBG("audio.conf: %s", err->message);
g_clear_error(&err);
} else {
mpeg12_srcs = atoi(str);//MPEG12Source=0
g_free(str);
}
str = g_key_file_get_string(config, "A2DP", "SBCSinks", &err);
if (err) {
DBG("audio.conf: %s", err->message);
g_clear_error(&err);
} else {
sbc_sinks = atoi(str); //默认为1
g_free(str);
}
str = g_key_file_get_string(config, "A2DP", "MPEG12Sinks", &err);
if (err) {
DBG("audio.conf: %s", err->message);
g_clear_error(&err);
} else {
mpeg12_sinks = atoi(str); //默认为0
g_free(str);
}
proceed:
//没有connection,先得到connection
if (!connection)
connection = dbus_connection_ref(conn);
//找到servers中的a2dp_server
server = find_server(servers, src);
if (!server) {
int av_err;
//没有,就新建一个
server = g_new0(struct a2dp_server, 1);
if (!server)
return -ENOMEM;
//建一个avdpt的server,并开始一个l2cap的io监听
av_err = avdtp_init(src, config, &server->version);
if (av_err < 0) {
g_free(server);
return av_err;
}
//拷贝到server src中
bacpy(&server->src, src);
//把新建的server加入到servers中
servers = g_slist_append(servers, server);
}
if (config)
delay_reporting = g_key_file_get_boolean(config, "A2DP",
"DelayReporting", NULL);
//根据配置,看version,决定是1.3还是1.2
if (delay_reporting)
server->version = 0x0103;
else
server->version = 0x0102;
//source是enable的
server->source_enabled = source;
if (source) {
for (i = 0; i < sbc_srcs; i++)
a2dp_add_sep(src, AVDTP_SEP_TYPE_SOURCE,
A2DP_CODEC_SBC, delay_reporting, NULL, NULL);
for (i = 0; i < mpeg12_srcs; i++)
a2dp_add_sep(src, AVDTP_SEP_TYPE_SOURCE,
A2DP_CODEC_MPEG12, delay_reporting,
NULL, NULL);
}
//sink是没有enable的
server->sink_enabled = sink;
if (sink) {
for (i = 0; i < sbc_sinks; i++)
a2dp_add_sep(src, AVDTP_SEP_TYPE_SINK,
A2DP_CODEC_SBC, delay_reporting, NULL, NULL);
for (i = 0; i < mpeg12_sinks; i++)
a2dp_add_sep(src, AVDTP_SEP_TYPE_SINK,
A2DP_CODEC_MPEG12, delay_reporting,
NULL, NULL);
}
return 0;
}
int avdtp_init(const bdaddr_t *src, GKeyFile *config, uint16_t *version)
{
GError *err = NULL;
gboolean tmp, master = TRUE;
struct avdtp_server *server;
uint16_t ver = 0x0102;
if (!config)
goto proceed;
//master = false
tmp = g_key_file_get_boolean(config, "General",
"Master", &err);
if (err) {
DBG("audio.conf: %s", err->message);
g_clear_error(&err);
} else
master = tmp;
//auto_connect = true
tmp = g_key_file_get_boolean(config, "General", "AutoConnect",
&err);
if (err)
g_clear_error(&err);
else
auto_connect = tmp;
//这里是没有了,所以是0102,就是V1.2,支持delayreporting就是v1.3了
if (g_key_file_get_boolean(config, "A2DP", "DelayReporting", NULL))
ver = 0x0103;
proceed:
//新建avdtp的server
server = g_new0(struct avdtp_server, 1);
if (!server)
return -ENOMEM;
server->version = ver;
//version传给调用的
if (version)
*version = server->version;
//建一个l2cap的监听io
server->io = avdtp_server_socket(src, master);
if (!server->io) {
g_free(server);
return -1;
}
bacpy(&server->src, src);
//加入到servers列表中
servers = g_slist_append(servers, server);
return 0;
}
struct a2dp_sep *a2dp_add_sep(const bdaddr_t *src, uint8_t type,
uint8_t codec, gboolean delay_reporting,
struct media_endpoint *endpoint, int *err)
{
struct a2dp_server *server;
struct a2dp_sep *sep;
GSList **l;
uint32_t *record_id;
sdp_record_t *record;
struct avdtp_sep_ind *ind;
//找到a2dp server
server = find_server(servers, src);
if (server == NULL) {
if (err)
*err = -EINVAL;
return NULL;
}
if (type == AVDTP_SEP_TYPE_SINK && !server->sink_enabled) {
if (err)
*err = -EPROTONOSUPPORT;
return NULL;
}
//检查一下是否对应
if (type == AVDTP_SEP_TYPE_SOURCE && !server->source_enabled) {
if (err)
*err = -EPROTONOSUPPORT;
return NULL;
}
//初始化a2dp sep
sep = g_new0(struct a2dp_sep, 1);
//传入的是null
if (endpoint) {
ind = &endpoint_ind;
goto proceed;
}
//是sbc
ind = (codec == A2DP_CODEC_MPEG12) ? &mpeg_ind : &sbc_ind;
proceed:
//初始化一个local sep,并把它加入到server sep列表中
sep->lsep = avdtp_register_sep(&server->src, type,
AVDTP_MEDIA_TYPE_AUDIO, codec,
delay_reporting, ind, &cfm, sep);
if (sep->lsep == NULL) {
g_free(sep);
if (err)
*err = -EINVAL;
return NULL;
}
//初始化a2dp的sep
sep->server = server;
sep->endpoint = endpoint;
sep->codec = codec;
sep->type = type;
sep->delay_reporting = delay_reporting;
if (type == AVDTP_SEP_TYPE_SOURCE) {
l = &server->sources;
record_id = &server->source_record_id;
} else {
l = &server->sinks;
record_id = &server->sink_record_id;
}
//开始这个是0了
if (*record_id != 0)
goto add;
//service record
record = a2dp_record(type, server->version);
if (!record) {
error("Unable to allocate new service record");
avdtp_unregister_sep(sep->lsep);
g_free(sep);
if (err)
*err = -EINVAL;
return NULL;
}
//把record和server相关联,这里也会有UUIDS的property change
if (add_record_to_server(&server->src, record) < 0) {
error("Unable to register A2DP service record");\
sdp_record_free(record);
avdtp_unregister_sep(sep->lsep);
g_free(sep);
if (err)
*err = -EINVAL;
return NULL;
}
//record id用来表示record的handle
*record_id = record->handle;
add:
//加入到server source的列表中
*l = g_slist_append(*l, sep);
if (err)
*err = 0;
return sep;
}
至此,a2dp的probe函数就结束了,主要就是根据配置,新建了a2dp server和a2dp sep,并把对应的service record加入到了server中。
2-4 load_devices的分析
这个函数就是建立了一系列的文件,然后根据文件的内容会有一系列的函数进行对应的处理
static void load_devices(struct btd_adapter *adapter)
{
char filename[PATH_MAX + 1];
char srcaddr[18];
struct adapter_keys keys = { adapter, NULL };
int err;
//把bt的addrees取出保存到srcaddr中
ba2str(&adapter->bdaddr, srcaddr);
//新建profiles文件
create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "profiles");
//找到对应key和value,然后调用create_stored_device_from_profiles进行处理,这里是空的,没什么好做
textfile_foreach(filename, create_stored_device_from_profiles,
adapter);
//新建primary
create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "primary");
textfile_foreach(filename, create_stored_device_from_primary,
adapter);
//新建linkkeys
create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "linkkeys");
textfile_foreach(filename, create_stored_device_from_linkkeys, &keys);
//调用load keys,设置dev的key和debug keys元素
err = adapter_ops->load_keys(adapter->dev_id, keys.keys,
main_opts.debug_keys);
if (err < 0) {
error("Unable to load keys to adapter_ops: %s (%d)",
strerror(-err), -err);
g_slist_foreach(keys.keys, (GFunc) g_free, NULL);
g_slist_free(keys.keys);
}
//创建blocked
create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "blocked");
textfile_foreach(filename, create_stored_device_from_blocked, adapter);
//创建types
create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "types");
textfile_foreach(filename, create_stored_device_from_types, adapter);
}
2.4.2.4.2 btd_adapter_get_mode的分析
总的来说还是蛮简单的,就是根据配置,设置mode,on_mode,和pairable。
void btd_adapter_get_mode(struct btd_adapter *adapter, uint8_t *mode,
uint8_t *on_mode, gboolean *pairable)
{
char str[14], address[18];
ba2str(&adapter->bdaddr, address);
if (mode) {
//这里是false,所以,直接设置为main_opts.mode,就是MODE_CONNECTABLE
if (main_opts.remember_powered == FALSE)
*mode = main_opts.mode;
else if (read_device_mode(address, str, sizeof(str)) == 0)
*mode = get_mode(&adapter->bdaddr, str);
else
*mode = main_opts.mode;
}
if (on_mode) {
//false,read config中的on mode的值,默认为MODE_CONNECTABLE
if (main_opts.remember_powered == FALSE)
*on_mode = get_mode(&adapter->bdaddr, "on");
else if (read_on_mode(address, str, sizeof(str)) == 0)
*on_mode = get_mode(&adapter->bdaddr, str);
else
*on_mode = main_opts.mode;
}
//设置为adapter的pairable
if (pairable)
*pairable = adapter->pairable;
}
2.4.2.4.3 start_adapter的分析
adapter的启动,这个过程同样将会涉及到很多的command和event的交互,可以认为是打开蓝牙的第二波大规模的command和event交互了,所幸的是,有很多的内容是和之前的是类似的。所以,我们的分析相对而言会比较轻松一点。
static void start_adapter(int index)
{
struct dev_info *dev = &devs[index];
uint8_t inqmode;
uint16_t link_policy;
//发送set event mask的cmd
set_event_mask(index);
//根据是否支持simple pair来决定是否write simple pairing mode的cmd
if (dev->features[6] & LMP_SIMPLE_PAIR)
init_ssp_mode(index);
//看inquiry的mode,然后再决定是否write inquiry mode的cmd
inqmode = get_inquiry_mode(index);
if (inqmode)
write_inq_mode(index, inqmode);
//是否支持inquiry tx power,然后决定是否发送read inquiry response tx power level的cmd
if (dev->features[7] & LMP_INQ_TX_PWR)
hci_send_cmd(dev->sk, OGF_HOST_CTL,
OCF_READ_INQ_RESPONSE_TX_POWER_LEVEL, 0, NULL);
/* Set default link policy */
link_policy = main_opts.link_policy;
if (!(dev->features[0] & LMP_RSWITCH))
link_policy &= ~HCI_LP_RSWITCH;
if (!(dev->features[0] & LMP_HOLD))
link_policy &= ~HCI_LP_HOLD;
if (!(dev->features[0] & LMP_SNIFF))
link_policy &= ~HCI_LP_SNIFF;
if (!(dev->features[1] & LMP_PARK))
link_policy &= ~HCI_LP_PARK;
//发送write default link policy来设置link的策略
link_policy = htobs(link_policy);
hci_send_cmd(dev->sk, OGF_LINK_POLICY, OCF_WRITE_DEFAULT_LINK_POLICY,
sizeof(link_policy), &link_policy);
dev->current_cod = 0;
memset(dev->eir, 0, sizeof(dev->eir));
}
从log来看,在开始的时候只会发送set event mask和write default link policy的cmd。这两个cmd在kernel层的处理我们已经分析过了,都没有做什么,再回到bluez层,我们会发现其实也没有对这两个cmd的处理,所以,我们就不管了。继续往下分析好了。
2.4.2.4.4 btd_adapter_start的分析
初始化adaptere的一些内容,不可避免地仍然会涉及到各种command和event的交互。主要就是两个command,write local name和write device of class。
void btd_adapter_start(struct btd_adapter *adapter)
{
char address[18];
uint8_t cls[3];
gboolean powered;
ba2str(&adapter->bdaddr, address);
adapter->dev_class = 0;
adapter->off_requested = FALSE;
adapter->up = TRUE;
adapter->discov_timeout = get_discoverable_timeout(address);
adapter->pairable_timeout = get_pairable_timeout(address);
adapter->state = STATE_IDLE;
adapter->mode = MODE_CONNECTABLE;
if (main_opts.le)
adapter_ops->enable_le(adapter->dev_id);
//通过write local name来设置controller的name
adapter_ops->set_name(adapter->dev_id, adapter->name);
//得到config文件中的class的值
if (read_local_class(&adapter->bdaddr, cls) < 0) {
//若是没有得到,就拷贝main opts中的class
uint32_t class = htobl(main_opts.class);
memcpy(cls, &class, 3);
}
//调用write class of device command来设置device class
//但是因为cached_enable是true,所以,他并不会调用这个cmd
//而是在后面的disable_cod_cache中调用
btd_adapter_set_class(adapter, cls[1], cls[0]);
powered = TRUE;
//向上层通知powered的改变,为true了,也是property change,这个会在后面的分析中详细介绍
emit_property_changed(connection, adapter->path,
ADAPTER_INTERFACE, "Powered",
DBUS_TYPE_BOOLEAN, &powered);
//就headset中用到过,这里没有,所以直接返回了
call_adapter_powered_callbacks(adapter, TRUE);
//调用write class of device command来设置device class
adapter_ops->disable_cod_cache(adapter->dev_id);
info("Adapter %s has been enabled", adapter->path);
}
这个函数涉及到的两个cmd:write local name和write device of class,其中write local name的command complete是没有什么需要做的。而write device of class在bluez中是有很多操作的,我们需要详细分析一下:
1)write device of class的command complete分析:
static void write_class_complete(int index, uint8_t status)
{
struct dev_info *dev = &devs[index];
struct btd_adapter *adapter;
//status非0的话说明有问题,好像开始没有介绍,这里介绍一次后面不再说了
if (status)
return;
if (dev->pending_cod == 0)
return;
//设置当前的coditon
dev->current_cod = dev->pending_cod;
//把pending去除掉
dev->pending_cod = 0;
adapter = manager_find_adapter(&dev->bdaddr);
//保存class到config文件中,并通知上层property change
if (adapter)
btd_adapter_class_changed(adapter, dev->current_cod);
//根据ex inquiry的feature决定是否需要update
update_ext_inquiry_response(index);
//这里就直接return了
if (dev->wanted_cod == dev->current_cod)
return;
//若不是,则需要再次进行一次class的write
if (dev->wanted_cod & LIMITED_BIT &&
!(dev->current_cod & LIMITED_BIT))
hciops_set_limited_discoverable(index, TRUE);
else if (!(dev->wanted_cod & LIMITED_BIT) &&
(dev->current_cod & LIMITED_BIT))
hciops_set_limited_discoverable(index, FALSE);
else
write_class(index, dev->wanted_cod);
}
总的来说,他就是把class的值保存到对应的config文件中,然后向上层通知了class的property的change。
2.4.2.4.5 write scan enable,inquiry cancel的分析
从write scan enable的command complete处理来看,他会直接发送read scan enable的cmd。
case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE):
hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_READ_SCAN_ENABLE,
0, NULL);
break;
inquiry cancel的command complete:
static inline void cc_inquiry_cancel(int index, uint8_t status)
{
//status有问题,只会打印一下
if (status) {
error("Inquiry Cancel Failed with status 0x%02x", status);
return;
}
//设置状态位DISCOV_HALTED,不过初始化就是这个,所以在打开蓝牙的时候这个命令出问题,其实是没有关系的。事实上很多controller就是不支持这个cmd,还好问题也不大。
set_state (index, DISCOV_HALTED);
}
下面我们顺手再分析一下read scan enable这个cmd的event处理:
static void read_scan_complete(int index, uint8_t status, void *ptr)
{
struct btd_adapter *adapter;
read_scan_enable_rp *rp = ptr;
DBG("hci%d status %u", index, status);
adapter = manager_find_adapter_by_id(index);
if (!adapter) {
error("Unable to find matching adapter");
return;
}
//通知mode 的change
adapter_mode_changed(adapter, rp->enable);
}
void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode)
{
const gchar *path = adapter_get_path(adapter);
gboolean discoverable, pairable;
DBG("old 0x%02x new 0x%02x", adapter->scan_mode, scan_mode);
//没有变化就什么都不做
if (adapter->scan_mode == scan_mode){
#ifdef BOARD_HAVE_BLUETOOTH_BCM
/*we may reset scan_mode already in btd_adapter_stop(), so comes to here*/
set_mode_complete(adapter);
#endif
return;
}
//这个就是把discov timeout去除掉,开始也没有,所以,这里也就没有什么
adapter_remove_discov_timeout(adapter);
switch (scan_mode) {
case SCAN_DISABLED:
adapter->mode = MODE_OFF;
discoverable = FALSE;
pairable = FALSE;
break;
//我们是0x02
case SCAN_PAGE:
adapter->mode = MODE_CONNECTABLE;
discoverable = FALSE;
pairable = adapter->pairable;
break;
case (SCAN_PAGE | SCAN_INQUIRY):
adapter->mode = MODE_DISCOVERABLE;
discoverable = TRUE;
pairable = adapter->pairable;
if (adapter->discov_timeout != 0)
adapter_set_discov_timeout(adapter,
adapter->discov_timeout);
break;
case SCAN_INQUIRY:
/* Address the scenario where a low-level application like
* hciconfig changed the scan mode */
if (adapter->discov_timeout != 0)
adapter_set_discov_timeout(adapter,
adapter->discov_timeout);
/* ignore, this event should not be sent */
default:
/* ignore, reserved */
return;
}
/* If page scanning gets toggled emit the Pairable property */
//scan page的改变,需要通知上层pairable的property change
if ((adapter->scan_mode & SCAN_PAGE) != (scan_mode & SCAN_PAGE))
emit_property_changed(connection, adapter->path,
ADAPTER_INTERFACE, "Pairable",
DBUS_TYPE_BOOLEAN, &pairable);
//这里discoverable是false
if (!discoverable)
adapter_set_limited_discoverable(adapter, FALSE);
//再通知上层discoverable的property change
emit_property_changed(connection, path,
ADAPTER_INTERFACE, "Discoverable",
DBUS_TYPE_BOOLEAN, &discoverable);
//设置adapter的scan mode
adapter->scan_mode = scan_mode;
//设置mode完成
set_mode_complete(adapter);
}
所以,这里最重要的就是向上面发送了两个property change,分别为:Pairable=false和Discoverable=false
至此,enableNative的分析就全部结束了,他使用了rfkill来进行芯片的上电操作,调用了hciattach来进行各家芯片的初始化工作,通过ioctl来把hci device up,在这个过程中通过一系列的cmd和response的交互使得对应的蓝牙controller能够进行初始化,最后使能bluetoothd初始化bluez的方方面面,总得来说内容还是很多的。他留给我们的还有几个property change的处理的悬念,这些我们会在后面的文章中再和大家来一一分析。
若您觉得该文章对您有帮助,请在下面用鼠标轻轻按一下“顶”,哈哈~~·