作為一個程序員,咋廢話就不多說了,直接看代碼吧,哈哈~~
2)adapter的初始化
[cpp]
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是必然會定義了的
[cpp]
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關聯起來
[cpp]
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進行初始化。
[cpp]
//其實就是遍歷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函數分析
[cpp]
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的分析
這個函數就是建立了一系列的文件,然後根據文件的內容會有一系列的函數進行對應的處理
[cpp]
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。
[cpp]
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交互了,所幸的是,有很多的內容是和之前的是類似的。所以,我們的分析相對而言會比較輕松一點。
[cpp]
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。
[cpp]
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分析:
[cpp]
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。
[cpp]
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