3
* MCAP for BlueZ - Bluetooth protocol stack for Linux
5
* Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos.
6
* Copyright (C) 2010 Signove
9
* Santiago Carot-Nemesio <sancane at gmail.com>
10
* Jose Antonio Santos-Cadenas <santoscadenas at gmail.com>
11
* Elvis PfĆ¼tzenreuter <epx at signove.com>
13
* This program is free software; you can redistribute it and/or modify
14
* it under the terms of the GNU General Public License as published by
15
* the Free Software Foundation; either version 2 of the License, or
16
* (at your option) any later version.
18
* This program is distributed in the hope that it will be useful,
19
* but WITHOUT ANY WARRANTY; without even the implied warranty of
20
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
* GNU General Public License for more details.
23
* You should have received a copy of the GNU General Public License
24
* along with this program; if not, write to the Free Software
25
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31
#include <netinet/in.h>
34
#include <bluetooth/bluetooth.h>
35
#include <bluetooth/l2cap.h>
36
#include "../src/adapter.h"
37
#include "../src/manager.h"
38
#include <sys/ioctl.h>
43
#include <bluetooth/bluetooth.h>
46
#include "mcap_internal.h"
48
#define MCAP_BTCLOCK_HALF (MCAP_BTCLOCK_FIELD / 2)
49
#define CLK CLOCK_MONOTONIC
51
#define MCAP_CSP_ERROR g_quark_from_static_string("mcap-csp-error-quark")
52
#define MAX_RETRIES 10
53
#define SAMPLE_COUNT 20
56
uint64_t base_tmstamp; /* CSP base timestamp */
57
struct timespec base_time; /* CSP base time when timestamp set */
58
guint local_caps; /* CSP-Master: have got remote caps */
59
guint remote_caps; /* CSP-Slave: remote master got caps */
60
guint rem_req_acc; /* CSP-Slave: accuracy required by master */
61
guint ind_expected; /* CSP-Master: indication expected */
62
MCAPCtrl csp_req; /* CSP-Master: Request control flag */
63
guint ind_timer; /* CSP-Slave: indication timer */
64
guint set_timer; /* CSP-Slave: delayed set timer */
65
void *set_data; /* CSP-Slave: delayed set data */
66
void *csp_priv_data; /* CSP-Master: In-flight request data */
69
struct mcap_sync_cap_cbdata {
74
struct mcap_sync_set_cbdata {
80
int ts_acc; /* timestamp accuracy */
81
int ts_res; /* timestamp resolution */
82
int latency; /* Read BT clock latency */
83
int preempt_thresh; /* Preemption threshold for latency */
84
int syncleadtime_ms; /* SyncLeadTime in ms */
87
struct sync_set_data {
89
uint32_t sched_btclock;
95
/* Ripped from lib/sdp.c */
97
#if __BYTE_ORDER == __BIG_ENDIAN
100
static inline uint64_t ntoh64(uint64_t n)
103
uint64_t tmp = ntohl(n & 0x00000000ffffffff);
110
#define hton64(x) ntoh64(x)
112
static gboolean csp_caps_initialized = FALSE;
113
struct csp_caps _caps;
115
static int send_sync_cmd(struct mcap_mcl *mcl, const void *buf, uint32_t size)
122
sock = g_io_channel_unix_get_fd(mcl->cc);
123
return mcap_send_data(sock, buf, size);
126
static int send_unsupported_cap_req(struct mcap_mcl *mcl)
128
mcap_md_sync_cap_rsp *cmd;
131
cmd = g_new0(mcap_md_sync_cap_rsp, 1);
132
cmd->op = MCAP_MD_SYNC_CAP_RSP;
133
cmd->rc = MCAP_REQUEST_NOT_SUPPORTED;
135
sent = send_sync_cmd(mcl, cmd, sizeof(*cmd));
141
static int send_unsupported_set_req(struct mcap_mcl *mcl)
143
mcap_md_sync_set_rsp *cmd;
146
cmd = g_new0(mcap_md_sync_set_rsp, 1);
147
cmd->op = MCAP_MD_SYNC_SET_RSP;
148
cmd->rc = MCAP_REQUEST_NOT_SUPPORTED;
150
sent = send_sync_cmd(mcl, cmd, sizeof(*cmd));
156
static void reset_tmstamp(struct mcap_csp *csp, struct timespec *base_time,
157
uint64_t new_tmstamp)
159
csp->base_tmstamp = new_tmstamp;
161
csp->base_time = *base_time;
163
clock_gettime(CLK, &csp->base_time);
166
void mcap_sync_init(struct mcap_mcl *mcl)
168
if (!mcl->mi->csp_enabled) {
173
mcl->csp = g_new0(struct mcap_csp, 1);
175
mcl->csp->rem_req_acc = 10000; /* safe divisor */
176
mcl->csp->set_data = NULL;
177
mcl->csp->csp_priv_data = NULL;
179
reset_tmstamp(mcl->csp, NULL, 0);
182
void mcap_sync_stop(struct mcap_mcl *mcl)
187
if (mcl->csp->ind_timer)
188
g_source_remove(mcl->csp->ind_timer);
190
if (mcl->csp->set_timer)
191
g_source_remove(mcl->csp->set_timer);
193
if (mcl->csp->set_data)
194
g_free(mcl->csp->set_data);
196
if (mcl->csp->csp_priv_data)
197
g_free(mcl->csp->csp_priv_data);
199
mcl->csp->ind_timer = 0;
200
mcl->csp->set_timer = 0;
201
mcl->csp->set_data = NULL;
202
mcl->csp->csp_priv_data = NULL;
208
static uint64_t time_us(struct timespec *tv)
210
return tv->tv_sec * 1000000 + tv->tv_nsec / 1000;
213
static int64_t bt2us(int bt)
218
static int bt2ms(int bt)
220
return bt * 312.5 / 1000;
223
static int btoffset(uint32_t btclk1, uint32_t btclk2)
225
int offset = btclk2 - btclk1;
227
if (offset <= -MCAP_BTCLOCK_HALF)
228
offset += MCAP_BTCLOCK_FIELD;
229
else if (offset > MCAP_BTCLOCK_HALF)
230
offset -= MCAP_BTCLOCK_FIELD;
235
static int btdiff(uint32_t btclk1, uint32_t btclk2)
237
return btoffset(btclk1, btclk2);
240
static gboolean valid_btclock(uint32_t btclk)
242
return btclk <= MCAP_BTCLOCK_MAX;
245
/* This call may fail; either deal with retry or use read_btclock_retry */
246
static gboolean read_btclock(struct mcap_mcl *mcl, uint32_t *btclock,
247
uint16_t *btaccuracy)
249
int ret, handle, which = 1;
250
struct btd_adapter *adapter;
252
adapter = manager_find_adapter(&mcl->mi->src);
257
if (btd_adapter_get_conn_handle(adapter, &mcl->addr, &handle))
260
ret = btd_adapter_read_clock(adapter, handle, which, 1000, btclock,
263
return ret < 0 ? FALSE : TRUE;
266
static gboolean read_btclock_retry(struct mcap_mcl *mcl, uint32_t *btclock,
267
uint16_t *btaccuracy)
271
while (--retries >= 0) {
272
if (read_btclock(mcl, btclock, btaccuracy))
274
DBG("CSP: retrying to read bt clock...");
280
static gboolean get_btrole(struct mcap_mcl *mcl)
288
sock = g_io_channel_unix_get_fd(mcl->cc);
291
if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags, &len))
292
DBG("CSP: could not read role");
294
return flags & L2CAP_LM_MASTER;
297
uint64_t mcap_get_timestamp(struct mcap_mcl *mcl,
298
struct timespec *given_time)
304
return MCAP_TMSTAMP_DONTSET;
309
clock_gettime(CLK, &now);
311
tmstamp = time_us(&now) - time_us(&mcl->csp->base_time)
312
+ mcl->csp->base_tmstamp;
317
uint32_t mcap_get_btclock(struct mcap_mcl *mcl)
323
return MCAP_BTCLOCK_IMMEDIATE;
325
if (!read_btclock_retry(mcl, &btclock, &accuracy))
326
btclock = 0xffffffff;
331
static gboolean initialize_caps(struct mcap_mcl *mcl)
333
struct timespec t1, t2;
334
int latencies[SAMPLE_COUNT];
335
int latency, avg, dev;
341
clock_getres(CLK, &t1);
343
_caps.ts_res = time_us(&t1);
344
if (_caps.ts_res < 1)
347
_caps.ts_acc = 20; /* ppm, estimated */
349
/* A little exercise before measuing latency */
350
clock_gettime(CLK, &t1);
351
read_btclock_retry(mcl, &btclock, &btaccuracy);
353
/* Read clock a number of times and measure latency */
356
retries = MAX_RETRIES;
357
while (i < SAMPLE_COUNT && retries > 0) {
358
clock_gettime(CLK, &t1);
359
if (!read_btclock(mcl, &btclock, &btaccuracy)) {
363
clock_gettime(CLK, &t2);
365
latency = time_us(&t2) - time_us(&t1);
366
latencies[i] = latency;
374
/* Calculate average and deviation */
377
for (i = 0; i < SAMPLE_COUNT; ++i)
378
dev += abs(latencies[i] - avg);
381
/* Calculate corrected average, without 'freak' latencies */
383
for (i = 0; i < SAMPLE_COUNT; ++i) {
384
if (latencies[i] > (avg + dev * 6))
387
latency += latencies[i];
389
latency /= SAMPLE_COUNT;
391
_caps.latency = latency;
392
_caps.preempt_thresh = latency * 4;
393
_caps.syncleadtime_ms = latency * 50 / 1000;
395
csp_caps_initialized = TRUE;
399
static struct csp_caps *caps(struct mcap_mcl *mcl)
401
if (!csp_caps_initialized)
402
if (!initialize_caps(mcl)) {
403
/* Temporary failure in reading BT clock */
410
static int send_sync_cap_rsp(struct mcap_mcl *mcl, uint8_t rspcode,
411
uint8_t btclockres, uint16_t synclead,
412
uint16_t tmstampres, uint16_t tmstampacc)
414
mcap_md_sync_cap_rsp *rsp;
417
rsp = g_new0(mcap_md_sync_cap_rsp, 1);
419
rsp->op = MCAP_MD_SYNC_CAP_RSP;
422
rsp->btclock = btclockres;
423
rsp->sltime = htons(synclead);
424
rsp->timestnr = htons(tmstampres);
425
rsp->timestna = htons(tmstampacc);
427
sent = send_sync_cmd(mcl, rsp, sizeof(*rsp));
433
static void proc_sync_cap_req(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
435
mcap_md_sync_cap_req *req;
436
uint16_t required_accuracy;
437
uint16_t our_accuracy;
441
if (len != sizeof(mcap_md_sync_cap_req)) {
442
send_sync_cap_rsp(mcl, MCAP_INVALID_PARAM_VALUE,
448
send_sync_cap_rsp(mcl, MCAP_RESOURCE_UNAVAILABLE,
453
req = (mcap_md_sync_cap_req *) cmd;
454
required_accuracy = ntohs(req->timest);
455
our_accuracy = caps(mcl)->ts_acc;
457
if (required_accuracy < our_accuracy || required_accuracy < 1) {
458
send_sync_cap_rsp(mcl, MCAP_RESOURCE_UNAVAILABLE,
463
if (!read_btclock_retry(mcl, &btclock, &btres)) {
464
send_sync_cap_rsp(mcl, MCAP_RESOURCE_UNAVAILABLE,
469
mcl->csp->remote_caps = 1;
470
mcl->csp->rem_req_acc = required_accuracy;
472
send_sync_cap_rsp(mcl, MCAP_SUCCESS, btres,
473
caps(mcl)->syncleadtime_ms,
474
caps(mcl)->ts_res, our_accuracy);
477
static int send_sync_set_rsp(struct mcap_mcl *mcl, uint8_t rspcode,
478
uint32_t btclock, uint64_t timestamp,
481
mcap_md_sync_set_rsp *rsp;
484
rsp = g_new0(mcap_md_sync_set_rsp, 1);
486
rsp->op = MCAP_MD_SYNC_SET_RSP;
488
rsp->btclock = htonl(btclock);
489
rsp->timestst = hton64(timestamp);
490
rsp->timestsa = htons(tmstampres);
492
sent = send_sync_cmd(mcl, rsp, sizeof(*rsp));
498
static gboolean get_all_clocks(struct mcap_mcl *mcl, uint32_t *btclock,
499
struct timespec *base_time,
510
latency = caps(mcl)->preempt_thresh + 1;
512
while (latency > caps(mcl)->preempt_thresh && --retry >= 0) {
514
clock_gettime(CLK, &t0);
516
if (!read_btclock(mcl, btclock, &btres))
519
clock_gettime(CLK, base_time);
521
/* Tries to detect preemption between clock_gettime
522
* and read_btclock by measuring transaction time
524
latency = time_us(base_time) - time_us(&t0);
527
*timestamp = mcap_get_timestamp(mcl, base_time);
532
static gboolean sync_send_indication(gpointer user_data)
534
struct mcap_mcl *mcl;
535
mcap_md_sync_info_ind *cmd;
538
struct timespec base_time;
549
if (!get_all_clocks(mcl, &btclock, &base_time, &tmstamp))
552
cmd = g_new0(mcap_md_sync_info_ind, 1);
554
cmd->op = MCAP_MD_SYNC_INFO_IND;
555
cmd->btclock = htonl(btclock);
556
cmd->timestst = hton64(tmstamp);
557
cmd->timestsa = htons(caps(mcl)->latency);
559
sent = send_sync_cmd(mcl, cmd, sizeof(*cmd));
565
static gboolean proc_sync_set_req_phase2(gpointer user_data)
567
struct mcap_mcl *mcl;
568
struct sync_set_data *data;
570
uint32_t sched_btclock;
571
uint64_t new_tmstamp;
576
struct timespec base_time;
586
if (!mcl->csp->set_data)
589
data = mcl->csp->set_data;
590
update = data->update;
591
sched_btclock = data->sched_btclock;
592
new_tmstamp = data->timestamp;
593
ind_freq = data->ind_freq;
597
send_sync_set_rsp(mcl, MCAP_UNSPECIFIED_ERROR, 0, 0, 0);
601
if (!get_all_clocks(mcl, &btclock, &base_time, &tmstamp)) {
602
send_sync_set_rsp(mcl, MCAP_UNSPECIFIED_ERROR, 0, 0, 0);
606
if (get_btrole(mcl) != role) {
607
send_sync_set_rsp(mcl, MCAP_INVALID_OPERATION, 0, 0, 0);
611
reset = (new_tmstamp != MCAP_TMSTAMP_DONTSET);
614
if (sched_btclock != MCAP_BTCLOCK_IMMEDIATE) {
615
delay = bt2us(btdiff(sched_btclock, btclock));
616
if (delay >= 0 || ((new_tmstamp - delay) > 0)) {
617
new_tmstamp += delay;
618
DBG("CSP: reset w/ delay %dus, compensated",
621
DBG("CSP: reset w/ delay %dus, uncompensated",
625
reset_tmstamp(mcl->csp, &base_time, new_tmstamp);
626
tmstamp = new_tmstamp;
629
tmstampacc = caps(mcl)->latency + caps(mcl)->ts_acc;
631
if (mcl->csp->ind_timer) {
632
g_source_remove(mcl->csp->ind_timer);
633
mcl->csp->ind_timer = 0;
637
int when = ind_freq + caps(mcl)->syncleadtime_ms;
638
mcl->csp->ind_timer = g_timeout_add(when,
639
sync_send_indication,
643
send_sync_set_rsp(mcl, MCAP_SUCCESS, btclock, tmstamp, tmstampacc);
645
/* First indication after set is immediate */
647
sync_send_indication(mcl);
652
static void proc_sync_set_req(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
654
mcap_md_sync_set_req *req;
655
uint32_t sched_btclock, cur_btclock;
659
struct sync_set_data *set_data;
660
int phase2_delay, ind_freq, when;
662
if (len != sizeof(mcap_md_sync_set_req)) {
663
send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0);
667
req = (mcap_md_sync_set_req *) cmd;
668
sched_btclock = ntohl(req->btclock);
669
update = req->timestui;
670
timestamp = ntoh64(req->timestst);
672
if (sched_btclock != MCAP_BTCLOCK_IMMEDIATE &&
673
!valid_btclock(sched_btclock)) {
674
send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0);
679
send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0);
683
if (!mcl->csp->remote_caps) {
684
/* Remote side did not ask our capabilities yet */
685
send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0);
690
send_sync_set_rsp(mcl, MCAP_UNSPECIFIED_ERROR, 0, 0, 0);
694
if (!read_btclock_retry(mcl, &cur_btclock, &btres)) {
695
send_sync_set_rsp(mcl, MCAP_UNSPECIFIED_ERROR, 0, 0, 0);
699
if (sched_btclock == MCAP_BTCLOCK_IMMEDIATE)
702
phase2_delay = btdiff(cur_btclock, sched_btclock);
704
if (phase2_delay < 0) {
705
/* can not reset in the past tense */
706
send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE,
711
/* Convert to miliseconds */
712
phase2_delay = bt2ms(phase2_delay);
714
if (phase2_delay > 61*1000) {
715
/* More than 60 seconds in the future */
716
send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE,
719
} else if (phase2_delay < caps(mcl)->latency / 1000) {
720
/* Too fast for us to do in time */
721
send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE,
728
/* Indication frequency: required accuracy divided by ours */
729
/* Converted to milisseconds */
730
ind_freq = (1000 * mcl->csp->rem_req_acc) / caps(mcl)->ts_acc;
732
if (ind_freq < MAX(caps(mcl)->latency * 2 / 1000, 100)) {
733
/* Too frequent, we can't handle */
734
send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE,
739
DBG("CSP: indication every %dms", ind_freq);
743
if (mcl->csp->ind_timer) {
744
/* Old indications are no longer sent */
745
g_source_remove(mcl->csp->ind_timer);
746
mcl->csp->ind_timer = 0;
749
if (!mcl->csp->set_data)
750
mcl->csp->set_data = g_new0(struct sync_set_data, 1);
752
set_data = (struct sync_set_data *) mcl->csp->set_data;
754
set_data->update = update;
755
set_data->sched_btclock = sched_btclock;
756
set_data->timestamp = timestamp;
757
set_data->ind_freq = ind_freq;
758
set_data->role = get_btrole(mcl);
760
/* TODO is there some way to schedule a call based directly on
761
* a BT clock value, instead of this estimation that uses
764
if (phase2_delay > 0) {
765
when = phase2_delay + caps(mcl)->syncleadtime_ms;
766
mcl->csp->set_timer = g_timeout_add(when,
767
proc_sync_set_req_phase2,
770
proc_sync_set_req_phase2(mcl);
772
/* First indication is immediate */
774
sync_send_indication(mcl);
777
static void proc_sync_cap_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
779
mcap_md_sync_cap_rsp *rsp;
785
struct mcap_sync_cap_cbdata *cbdata;
789
if (mcl->csp->csp_req != MCAP_MD_SYNC_CAP_REQ) {
790
DBG("CSP: got unexpected cap respose");
794
if (!mcl->csp->csp_priv_data) {
795
DBG("CSP: no priv data for cap respose");
799
cbdata = mcl->csp->csp_priv_data;
801
user_data = cbdata->user_data;
804
mcl->csp->csp_priv_data = NULL;
805
mcl->csp->csp_req = 0;
807
if (len != sizeof(mcap_md_sync_cap_rsp)) {
808
DBG("CSP: got corrupted cap respose");
812
rsp = (mcap_md_sync_cap_rsp *) cmd;
814
btclockres = rsp->btclock;
815
synclead = ntohs(rsp->sltime);
816
tmstampres = ntohs(rsp->timestnr);
817
tmstampacc = ntohs(rsp->timestna);
820
mcl->csp->local_caps = TRUE;
822
cb(mcl, mcap_err, btclockres, synclead, tmstampres, tmstampacc, NULL,
826
static void proc_sync_set_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
828
mcap_md_sync_set_rsp *rsp;
833
struct mcap_sync_set_cbdata *cbdata;
837
if (mcl->csp->csp_req != MCAP_MD_SYNC_SET_REQ) {
838
DBG("CSP: got unexpected set respose");
842
if (!mcl->csp->csp_priv_data) {
843
DBG("CSP: no priv data for set respose");
847
cbdata = mcl->csp->csp_priv_data;
849
user_data = cbdata->user_data;
852
mcl->csp->csp_priv_data = NULL;
853
mcl->csp->csp_req = 0;
855
if (len != sizeof(mcap_md_sync_set_rsp)) {
856
DBG("CSP: got corrupted set respose");
860
rsp = (mcap_md_sync_set_rsp *) cmd;
862
btclock = ntohl(rsp->btclock);
863
timestamp = ntoh64(rsp->timestst);
864
accuracy = ntohs(rsp->timestsa);
866
if (!mcap_err && !valid_btclock(btclock))
867
mcap_err = MCAP_ERROR_INVALID_ARGS;
869
cb(mcl, mcap_err, btclock, timestamp, accuracy, NULL, user_data);
872
static void proc_sync_info_ind(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
874
mcap_md_sync_info_ind *req;
875
struct sync_info_ind_data data;
878
if (!mcl->csp->ind_expected) {
879
DBG("CSP: received unexpected info indication");
883
if (len != sizeof(mcap_md_sync_info_ind))
886
req = (mcap_md_sync_info_ind *) cmd;
888
btclock = ntohl(req->btclock);
890
if (!valid_btclock(btclock))
893
data.btclock = btclock;
894
data.timestamp = ntoh64(req->timestst);
895
data.accuracy = ntohs(req->timestsa);
897
if (mcl->mi->mcl_sync_infoind_cb)
898
mcl->mi->mcl_sync_infoind_cb(mcl, &data);
901
void proc_sync_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len)
903
if (!mcl->mi->csp_enabled || !mcl->csp) {
905
case MCAP_MD_SYNC_CAP_REQ:
906
send_unsupported_cap_req(mcl);
908
case MCAP_MD_SYNC_SET_REQ:
909
send_unsupported_set_req(mcl);
916
case MCAP_MD_SYNC_CAP_REQ:
917
proc_sync_cap_req(mcl, cmd, len);
919
case MCAP_MD_SYNC_CAP_RSP:
920
proc_sync_cap_rsp(mcl, cmd, len);
922
case MCAP_MD_SYNC_SET_REQ:
923
proc_sync_set_req(mcl, cmd, len);
925
case MCAP_MD_SYNC_SET_RSP:
926
proc_sync_set_rsp(mcl, cmd, len);
928
case MCAP_MD_SYNC_INFO_IND:
929
proc_sync_info_ind(mcl, cmd, len);
934
void mcap_sync_cap_req(struct mcap_mcl *mcl, uint16_t reqacc,
935
mcap_sync_cap_cb cb, gpointer user_data,
938
struct mcap_sync_cap_cbdata *cbdata;
939
mcap_md_sync_cap_req *cmd;
941
if (!mcl->mi->csp_enabled || !mcl->csp) {
944
MCAP_ERROR_RESOURCE_UNAVAILABLE,
945
"CSP not enabled for the instance");
949
if (mcl->csp->csp_req) {
952
MCAP_ERROR_RESOURCE_UNAVAILABLE,
953
"Pending CSP request");
957
mcl->csp->csp_req = MCAP_MD_SYNC_CAP_REQ;
958
cmd = g_new0(mcap_md_sync_cap_req, 1);
960
cmd->op = MCAP_MD_SYNC_CAP_REQ;
961
cmd->timest = htons(reqacc);
963
cbdata = g_new0(struct mcap_sync_cap_cbdata, 1);
965
cbdata->user_data = user_data;
966
mcl->csp->csp_priv_data = cbdata;
968
send_sync_cmd(mcl, cmd, sizeof(*cmd));
973
void mcap_sync_set_req(struct mcap_mcl *mcl, uint8_t update, uint32_t btclock,
974
uint64_t timestamp, mcap_sync_set_cb cb,
975
gpointer user_data, GError **err)
977
mcap_md_sync_set_req *cmd;
978
struct mcap_sync_set_cbdata *cbdata;
980
if (!mcl->mi->csp_enabled || !mcl->csp) {
983
MCAP_ERROR_RESOURCE_UNAVAILABLE,
984
"CSP not enabled for the instance");
988
if (!mcl->csp->local_caps) {
991
MCAP_ERROR_RESOURCE_UNAVAILABLE,
992
"Did not get CSP caps from slave yet");
996
if (mcl->csp->csp_req) {
999
MCAP_ERROR_RESOURCE_UNAVAILABLE,
1000
"Pending CSP request");
1004
mcl->csp->csp_req = MCAP_MD_SYNC_SET_REQ;
1005
cmd = g_new0(mcap_md_sync_set_req, 1);
1007
cmd->op = MCAP_MD_SYNC_SET_REQ;
1008
cmd->timestui = update;
1009
cmd->btclock = htonl(btclock);
1010
cmd->timestst = hton64(timestamp);
1012
mcl->csp->ind_expected = update;
1014
cbdata = g_new0(struct mcap_sync_set_cbdata, 1);
1016
cbdata->user_data = user_data;
1017
mcl->csp->csp_priv_data = cbdata;
1019
send_sync_cmd(mcl, cmd, sizeof(*cmd));
1024
void mcap_enable_csp(struct mcap_instance *mi)
1026
mi->csp_enabled = TRUE;
1029
void mcap_disable_csp(struct mcap_instance *mi)
1031
mi->csp_enabled = FALSE;