1
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
45
46
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
83
84
85
86
87
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
117
118
130
131
143
144
156
157
166
167
172
173
174
175
176
177
178
181
182
183
184
187
188
189
190
191
192
193
194
195
196
197
198
201
202
207
212
217
218
219
220
221
222
223
224
236
237
238
239
240
241
244
245
246
247
248
249
256
257
258
259
270
271
272
273
274
275
276
277
278
279
280
281
282
283
287
288
291
292
293
300
301
302
303
304
305
306
307
308
309
310
311
316
317
318
319
320
321
330
340
354
357
366
368
369
370
371
372
373
374
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
396
397
398
399
400
401
402
403
404
405
406
407
408
413
414
415
421
422
423
424
425
426
428
429
430
431
432
433
434
435
436
437
439
440
441
442
443
444
445
450
451
452
456
457
458
459
460
461
462
463
468
469
470
476
477
488
489
490
491
492
497
498
499
500
501
502
503
504
505
510
511
512
518
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
542
543
544
545
546
547
548
549
550
551
552
555
556
557
562
567
568
569
570
581
590
591
592
602
603
604
620
621
622
623
629
630
634
635
636
637
638
639
640
641
642
647
648
649
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
687
688
689
697
698
699
704
705
706
707
708
709
710
711
730
731
738
739
740
741
742
743
744
747
750
753
756
759
762
763
764
765
766
767
768
769
770
771
772
773
774
775
779
780
781
782
783
784
788
792
793
795
796
797
798
799
800
801
802
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
832
833
834
835
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
875
876
882
888
913
931
956
957
958
959
962
963
964
965
969
970
971
972
973
979
980
981
986
987
988
989
990
995
997
998
999
1000
1001
1002
1003
1004
1005
1006
1009
1014
1015
1016
1017
1018
1019
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1044
1045
1046
1047
1048
1049
1050
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1078
1079
1082
1083
1084
1085
1091
1092
1093
1094
1095
1099
1100
1101
1102
1103
1104
1105
1106
1111
1112
1113
1114
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1134
1135
1136
1137
1138
1139
1145
1146
1147
1148
1149
1150
1151
1152
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1229
1230
1231
1232
1233
1234
1235
1236
1237
1251
1252
1253
1254
1255
/* ... */
#include <string.h>
#include "btc_l2cap.h"
#include "stack/l2c_api.h"
#include "btc/btc_manage.h"
#include "btc/btc_task.h"
#include "bta/bta_jv_api.h"
#include "common/bt_trace.h"
#include "osi/allocator.h"
#include "esp_l2cap_bt_api.h"
#include "osi/list.h"
#include "freertos/ringbuf.h"
#include "osi/mutex.h"
#include "osi/alarm.h"
#include <sys/errno.h>
#include <sys/lock.h>
#include <sys/fcntl.h>
#include "esp_vfs.h"
#include "esp_vfs_dev.h"
#include "stack/port_api.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "btc_sdp.h"
#include "btc/btc_task.h"
#include "stack/btu.h"24 includes
#if (defined BTC_L2CAP_INCLUDED && BTC_L2CAP_INCLUDED == TRUE)
#define SLOT_WRITE_BIT(i) (1UL << (i - 1))
#define SLOT_CLOSE_BIT(i) (1UL << (i + BTA_JV_MAX_L2C_CONN - 1))
#define VFS_WRITE_TIMEOUT (40 * 1000)
#define SLOT_TX_QUEUE_SIZE 10
#define SLOT_TX_QUEUE_LOW_WM 4
#define SLOT_TX_DATA_HIGH_WM (SLOT_TX_QUEUE_SIZE * BTA_JV_DEF_RFC_MTU)
#define VFS_CLOSE_TIMEOUT (20 * 1000)
#define BTC_L2CAP_ROLE_MASTER 0
#define BTC_L2CAP_ROLE_SLAVE 19 defines
typedef struct {
bool peer_fc;
bool user_fc;
fixed_queue_t *queue;
uint32_t data_size;
}{...} slot_data_t;
typedef struct {
bool connected;
bool is_server;
bool fix_chan;
uint16_t psm;
uint8_t serial;
uint8_t max_session;
uint32_t id;
uint32_t handle;
int fd;
int tx_mtu;
uint8_t *write_data;
osi_alarm_t *close_alarm;
void *alarm_arg;
uint8_t role;
uint16_t security;
esp_bd_addr_t addr;
slot_data_t rx;
slot_data_t tx;
uint8_t service_uuid[16];
}{...} l2cap_slot_t;
typedef struct {
l2cap_slot_t *l2cap_slots[BTA_JV_MAX_L2C_CONN + 1];
uint32_t l2cap_slot_id;
osi_mutex_t l2cap_slot_mutex;
EventGroupHandle_t tx_event_group;
esp_vfs_id_t l2cap_vfs_id;
}{...} l2cap_local_param_t;
static l2cap_local_param_t l2cap_local_param;
static const tL2CAP_FCR_OPTS obex_l2c_fcr_opts_def =
{
L2CAP_FCR_ERTM_MODE,
OBX_FCR_OPT_TX_WINDOW_SIZE_BR_EDR,
OBX_FCR_OPT_MAX_TX_B4_DISCNT,
OBX_FCR_OPT_RETX_TOUT,
OBX_FCR_OPT_MONITOR_TOUT,
OBX_FCR_OPT_MAX_PDU_SIZE
}{...};
static const tL2CAP_ERTM_INFO obex_l2c_etm_opt =
{
L2CAP_FCR_ERTM_MODE,
L2CAP_FCR_CHAN_OPT_ERTM,
OBX_USER_RX_POOL_ID,
OBX_USER_TX_POOL_ID,
OBX_FCR_RX_POOL_ID,
OBX_FCR_TX_POOL_ID
}{...};
#if L2CAP_DYNAMIC_MEMORY == FALSE
#define is_l2cap_init() (l2cap_local_param.l2cap_slot_mutex != NULL)
#else
#define is_l2cap_init() (&l2cap_local_param != NULL && l2cap_local_param.l2cap_slot_mutex != NULL)
#endif
static void l2cap_osi_free(void *p)
{
osi_free(p);
}{...}
static l2cap_slot_t *l2cap_find_slot_by_handle(uint32_t handle)
{
l2cap_slot_t *slot = NULL;
for (size_t i = 1; i <= BTA_JV_MAX_L2C_CONN; i++) {
slot = l2cap_local_param.l2cap_slots[i];
if (slot != NULL && slot->handle == handle) {
return slot;
}{...}
}{...}
return NULL;
}{...}
static l2cap_slot_t *l2cap_find_slot_by_id(uint32_t id)
{
l2cap_slot_t *slot = NULL;
for (size_t i = 1; i <= BTA_JV_MAX_L2C_CONN; i++) {
slot = l2cap_local_param.l2cap_slots[i];
if (slot != NULL && slot->id == id) {
return slot;
}{...}
}{...}
return NULL;
}{...}
static l2cap_slot_t *l2cap_find_slot_by_fd(int fd)
{
l2cap_slot_t *slot = NULL;
for (size_t i = 1; i <= BTA_JV_MAX_L2C_CONN; i++) {
slot = l2cap_local_param.l2cap_slots[i];
if (slot != NULL && slot->fd == fd) {
return slot;
}{...}
}{...}
return NULL;
}{...}
static int init_slot_data(slot_data_t *slot_data, size_t queue_size)
{
memset(slot_data, 0, sizeof(slot_data_t));
if ((slot_data->queue = fixed_queue_new(queue_size)) == NULL) {
return -1;
}{...}
slot_data->data_size = 0;
return 0;
}{...}
static void free_slot_data(slot_data_t *slot_data)
{
fixed_queue_free(slot_data->queue, l2cap_osi_free);
slot_data->queue = NULL;
}{...}
static l2cap_slot_t *l2cap_malloc_slot(void)
{
uint8_t err_no = 0;
l2cap_slot_t **slot = NULL;
if (++l2cap_local_param.l2cap_slot_id == 0) {
l2cap_local_param.l2cap_slot_id = 1;
}{...}
for (size_t i = 1; i <= BTA_JV_MAX_L2C_CONN; i++) {
slot = &l2cap_local_param.l2cap_slots[i];
if ((*slot) == NULL) {
if (((*slot) = (l2cap_slot_t *)osi_malloc(sizeof(l2cap_slot_t))) == NULL) {
return NULL;
}{...}
(*slot)->id = l2cap_local_param.l2cap_slot_id;
(*slot)->psm = 0;
(*slot)->serial = i;
(*slot)->handle = 0xffff;
(*slot)->fd = -1;
(*slot)->connected = false;
(*slot)->is_server = false;
(*slot)->write_data = NULL;
(*slot)->close_alarm = NULL;
(*slot)->alarm_arg = NULL;
if (l2cap_local_param.tx_event_group) {
xEventGroupClearBits(l2cap_local_param.tx_event_group, SLOT_WRITE_BIT(i) | SLOT_CLOSE_BIT(i));
}{...}
if (init_slot_data(&(*slot)->rx, QUEUE_SIZE_MAX)) {
BTC_TRACE_ERROR("%s unable to malloc rx queue!", __func__);
err_no = 1;
goto err;
}{...}
if (init_slot_data(&(*slot)->tx, SLOT_TX_QUEUE_SIZE)) {
BTC_TRACE_ERROR("%s unable to malloc tx queue!", __func__);
err_no = 2;
goto err;
}{...}
if (esp_vfs_register_fd(l2cap_local_param.l2cap_vfs_id, &(*slot)->fd) != ESP_OK) {
BTC_TRACE_ERROR("%s unable to register fd!", __func__);
err_no = 3;
goto err;
}{...}
return (*slot);
}{...}
}{...}
return NULL;
err:
switch (err_no) {
case 3:
free_slot_data(&(*slot)->tx);...
case 2:
free_slot_data(&(*slot)->rx);...
case 1:
osi_free((*slot));
(*slot) = NULL;
break;...
default:
break;...
}{...}
return (*slot);
}{...}
static void l2cap_free_slot(l2cap_slot_t *slot)
{
if (!slot) {
return;
}{...}
l2cap_local_param.l2cap_slots[slot->serial] = NULL;
esp_vfs_unregister_fd(l2cap_local_param.l2cap_vfs_id, slot->fd);
xEventGroupSetBits(l2cap_local_param.tx_event_group, SLOT_CLOSE_BIT(slot->serial));
free_slot_data(&slot->tx);
free_slot_data(&slot->rx);
if (slot->close_alarm) {
osi_alarm_free(slot->close_alarm);
if (slot->alarm_arg) {
osi_free(slot->alarm_arg);
slot->alarm_arg = NULL;
}{...}
}{...}
osi_free(slot);
}{...}
static void l2cap_free_pending_slots(void)
{
l2cap_slot_t *slot = NULL;
for (size_t i = 1; i <= BTA_JV_MAX_L2C_CONN; i++) {
slot = l2cap_local_param.l2cap_slots[i];
if (slot) {
BTC_TRACE_WARNING("%s found slot(handle=0x%x) pending to close, close it now!", __func__, slot->handle);
l2cap_free_slot(slot);
}{...}
}{...}
}{...}
static void close_timeout_handler(void *arg)
{
btc_msg_t msg;
bt_status_t status;
l2cap_slot_t *slot = (l2cap_slot_t *)arg;
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_L2CAP;
msg.act = BTA_JV_L2CAP_CLOSE_EVT;
status = btc_transfer_context(&msg, slot->alarm_arg, sizeof(tBTA_JV), NULL, NULL);
if (slot->alarm_arg) {
osi_free(slot->alarm_arg);
slot->alarm_arg = NULL;
}{...}
if (status != BT_STATUS_SUCCESS) {
BTC_TRACE_ERROR("%s btc_transfer_context failed", __func__);
}{...}
}{...}
static inline void btc_l2cap_cb_to_app(esp_bt_l2cap_cb_event_t event, esp_bt_l2cap_cb_param_t *param)
{
esp_bt_l2cap_cb_t btc_l2cap_cb = (esp_bt_l2cap_cb_t)btc_profile_cb_get(BTC_PID_L2CAP);
if (btc_l2cap_cb) {
btc_l2cap_cb(event, param);
}{...}
}{...}
static void *btc_l2cap_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data)
{
bt_status_t status;
btc_msg_t msg;
uint32_t id = (uintptr_t)user_data;
l2cap_slot_t *slot = NULL;
switch (event) {
case BTA_JV_L2CAP_OPEN_EVT:
slot = l2cap_find_slot_by_id(id);
if (!slot) {
BTC_TRACE_ERROR("%s unable to find L2CAP slot, event:%d!", __func__, event);
p_data->l2c_open.status = ESP_BT_L2CAP_NO_CONNECTION;
break;
}{...}
slot->connected = TRUE;
slot->handle = p_data->l2c_open.handle;
slot->tx_mtu = p_data->l2c_open.tx_mtu;
BTA_JvSetPmProfile(p_data->l2c_open.handle, BTA_JV_PM_ID_1, BTA_JV_CONN_OPEN);
break;...
case BTA_JV_L2CAP_START_EVT:
slot = l2cap_find_slot_by_id(id);
if (!slot) {
BTC_TRACE_ERROR("%s unable to find L2CAP slot, event:%d!", __func__, event);
p_data->l2c_open.status = ESP_BT_L2CAP_NO_CONNECTION;
break;
}{...}
slot->handle = p_data->l2c_start.handle;
break;...
case BTA_JV_L2CAP_CLOSE_EVT:
slot = l2cap_find_slot_by_id(id);
if (!slot) {
BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
p_data->l2c_close.status = ESP_BT_L2CAP_NO_CONNECTION;
break;
}{...}
p_data->l2c_close.status = BTA_JV_SUCCESS;
p_data->l2c_close.user_data = (void *)(uintptr_t)slot->id;
break;...
case BTA_JV_L2CAP_CL_INIT_EVT:
slot = l2cap_find_slot_by_id(id);
if (!slot) {
BTC_TRACE_ERROR("%s unable to find L2CAP slot, event:%d!", __func__, event);
p_data->l2c_cl_init.status = ESP_BT_L2CAP_FAILURE;
break;
}{...}
if (p_data->l2c_cl_init.status == BTA_JV_SUCCESS) {
slot->handle = p_data->l2c_cl_init.handle;
}{...} else {
l2cap_free_slot(slot);
}{...}
break;...
case BTA_JV_L2CAP_DATA_IND_EVT:
break;...
case BTA_JV_FREE_SCN_EVT:
slot = l2cap_find_slot_by_id(id);
if (slot) {
l2cap_free_slot(slot);
}{...} else {
BTC_TRACE_ERROR("%s unable to find L2CAP slot, event:%d!", __func__, event);
p_data->free_scn.status = ESP_BT_L2CAP_NO_CONNECTION;
}{...}
break;...
default:
break;...
}{...}
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_L2CAP;
msg.act = event;
status = btc_transfer_context(&msg, p_data, sizeof(tBTA_JV), NULL, NULL);
if (status != BT_STATUS_SUCCESS) {
BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__);
}{...}
return NULL;
}{...}
static void btc_l2cap_dm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data)
{
bt_status_t status;
btc_msg_t msg;
switch (event) {
default:
msg.sig = BTC_SIG_API_CB;
msg.pid = BTC_PID_L2CAP;
msg.act = event;
status = btc_transfer_context(&msg, p_data, sizeof(tBTA_JV), NULL, NULL);
if (status != BT_STATUS_SUCCESS) {
BTC_TRACE_ERROR("%s btc_transfer_context failed\n", __func__);
}{...}
break;...
}{...}
return;
}{...}
static void btc_l2cap_init(void)
{
esp_bt_l2cap_status_t ret = ESP_BT_L2CAP_SUCCESS;
esp_bt_l2cap_cb_param_t param;
do {
if (is_l2cap_init()) {
BTC_TRACE_ERROR("%s L2CAP has been initiated, shall uninit first!", __func__);
ret = ESP_BT_L2CAP_NEED_DEINIT;
break;
}{...}
#if L2CAP_DYNAMIC_MEMORY == TRUE
if ((l2cap_local_param_ptr = (l2cap_local_param_t *)osi_malloc(sizeof(l2cap_local_param_t))) == NULL) {
BTC_TRACE_ERROR("%s malloc failed\n", __func__);
ret = ESP_BT_L2CAP_NO_RESOURCE;
break;
}{...}
memset((void *)l2cap_local_param_ptr, 0, sizeof(l2cap_local_param_t));/* ... */
#endif
l2cap_local_param.l2cap_vfs_id = -1;
if (osi_mutex_new(&l2cap_local_param.l2cap_slot_mutex) != 0) {
#if L2CAP_DYNAMIC_MEMORY == TRUE
osi_free(l2cap_local_param_ptr);
l2cap_local_param_ptr = NULL;/* ... */
#endif
BTC_TRACE_ERROR("%s osi_mutex_new failed\n", __func__);
ret = ESP_BT_L2CAP_NO_RESOURCE;
break;
}{...}
if ((l2cap_local_param.tx_event_group = xEventGroupCreate()) == NULL) {
BTC_TRACE_ERROR("%s create tx_event_group failed\n", __func__);
osi_mutex_free(&l2cap_local_param.l2cap_slot_mutex);
#if L2CAP_DYNAMIC_MEMORY == TRUE
osi_free(l2cap_local_param_ptr);
l2cap_local_param_ptr = NULL;/* ... */
#endif
ret = ESP_BT_L2CAP_NO_RESOURCE;
break;
}{...}
l2cap_local_param.l2cap_slot_id = 0;
ret = BTA_JvEnable((tBTA_JV_DM_CBACK *)btc_l2cap_dm_inter_cb);
if (BTA_JV_ALREADY_DONE == ret) {
ret = ESP_BT_L2CAP_SUCCESS;
param.init.status = ESP_BT_L2CAP_SUCCESS;
btc_l2cap_cb_to_app(ESP_BT_L2CAP_INIT_EVT, ¶m);
}{...}
}{...} while (0);
if (ret != ESP_BT_L2CAP_SUCCESS) {
param.init.status = ret;
btc_l2cap_cb_to_app(ESP_BT_L2CAP_INIT_EVT, ¶m);
}{...}
}{...}
static void btc_l2cap_uninit(void)
{
esp_bt_l2cap_status_t ret = ESP_BT_L2CAP_SUCCESS;
do {
if (!is_l2cap_init()) {
BTC_TRACE_ERROR("%s L2CAP has not been initiated, shall init first!", __func__);
ret = ESP_BT_L2CAP_NEED_INIT;
break;
}{...}
osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
for (size_t i = 1; i <= BTA_JV_MAX_L2C_CONN; i++) {
if (l2cap_local_param.l2cap_slots[i] != NULL && !l2cap_local_param.l2cap_slots[i]->is_server) {
BTA_JvL2capClose(l2cap_local_param.l2cap_slots[i]->handle, (tBTA_JV_L2CAP_CBACK *)btc_l2cap_inter_cb,
(void *)l2cap_local_param.l2cap_slots[i]->id);
}{...}
}{...}
for (size_t i = 1; i <= BTA_JV_MAX_L2C_CONN; i++) {
if (l2cap_local_param.l2cap_slots[i] != NULL && l2cap_local_param.l2cap_slots[i]->is_server) {
if (l2cap_local_param.l2cap_slots[i]->handle != 0xffff) {
BTA_JvL2capStopServer(l2cap_local_param.l2cap_slots[i]->psm,
(void *)l2cap_local_param.l2cap_slots[i]->id);
}{...}
BTA_JvFreeChannel(l2cap_local_param.l2cap_slots[i]->psm, BTA_JV_CONN_TYPE_L2CAP,
(tBTA_JV_RFCOMM_CBACK *)btc_l2cap_inter_cb, (void *)l2cap_local_param.l2cap_slots[i]->id);
}{...}
}{...}
BTA_JvDisable((tBTA_JV_L2CAP_CBACK *)btc_l2cap_inter_cb);
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
}{...} while(0);
if (ret != ESP_BT_L2CAP_SUCCESS) {
esp_bt_l2cap_cb_param_t param;
param.uninit.status = ret;
btc_l2cap_cb_to_app(ESP_BT_L2CAP_UNINIT_EVT, ¶m);
}{...}
}{...}
static void btc_l2cap_start_srv(btc_l2cap_args_t *arg)
{
esp_bt_l2cap_status_t ret = ESP_BT_L2CAP_SUCCESS;
tL2CAP_CFG_INFO cfg;
do {
if (!is_l2cap_init()) {
BTC_TRACE_ERROR("%s L2CAP have not been init\n", __func__);
ret = ESP_BT_L2CAP_NEED_INIT;
break;
}{...}
osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
l2cap_slot_t *slot = l2cap_malloc_slot();
if (!slot) {
BTC_TRACE_ERROR("%s unable to malloc L2CAP slot!", __func__);
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
ret = ESP_BT_L2CAP_NO_RESOURCE;
break;
}{...}
/* ... */
slot->is_server = true;
slot->security = arg->start_srv.sec_mask;
slot->role = BTC_L2CAP_ROLE_SLAVE;
slot->psm = arg->start_srv.local_psm;
memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
cfg.fcr_present = TRUE;
cfg.fcr = obex_l2c_fcr_opts_def;
BTA_JvL2capStartServer(slot->security, slot->role, &obex_l2c_etm_opt, slot->psm,
L2CAP_MAX_SDU_LENGTH, &cfg, (tBTA_JV_L2CAP_CBACK *)btc_l2cap_inter_cb, (void *)slot->id);
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
}{...} while(0);
if (ret != ESP_BT_L2CAP_SUCCESS) {
esp_bt_l2cap_cb_param_t param;
param.start.status = ret;
param.start.handle = 0xffff;
param.start.sec_id = 0;
btc_l2cap_cb_to_app(ESP_BT_L2CAP_START_EVT, ¶m);
}{...}
return;
}{...}
static void btc_l2cap_stop_srv(btc_l2cap_args_t *arg)
{
esp_bt_l2cap_status_t ret = ESP_BT_L2CAP_SUCCESS;
bool is_remove_all = false;
uint8_t i, j, srv_cnt = 0;
uint8_t *srv_psm_arr = osi_malloc(BTA_JV_MAX_L2C_CONN);
if (arg->stop_srv.psm == BTC_L2CAP_INVALID_PSM) {
is_remove_all = true;
}{...}
do {
if (!is_l2cap_init()) {
BTC_TRACE_ERROR("%s L2CAP have not been init\n", __func__);
ret = ESP_BT_L2CAP_NEED_INIT;
break;
}{...}
if (srv_psm_arr == NULL) {
BTC_TRACE_ERROR("%s malloc srv_psm_arr failed\n", __func__);
ret = ESP_BT_L2CAP_NO_RESOURCE;
break;
}{...}
osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
for (i = 1; i <= BTA_JV_MAX_L2C_CONN; i++) {
if (l2cap_local_param.l2cap_slots[i] != NULL && l2cap_local_param.l2cap_slots[i]->is_server &&
l2cap_local_param.l2cap_slots[i]->handle != 0xffff) {
if (is_remove_all) {
srv_psm_arr[srv_cnt++] = l2cap_local_param.l2cap_slots[i]->psm;
}{...} else if (l2cap_local_param.l2cap_slots[i]->psm == arg->stop_srv.psm) {
srv_psm_arr[srv_cnt++] = l2cap_local_param.l2cap_slots[i]->psm;
break;
}{...}
}{...}
}{...}
if (srv_cnt == 0) {
if (is_remove_all) {
BTC_TRACE_ERROR("%s can not find any server!\n", __func__);
}{...} else {
BTC_TRACE_ERROR("%s can not find server:%d!\n", __func__, arg->stop_srv.psm);
}{...}
ret = ESP_BT_L2CAP_NO_SERVER;
break;
}{...}
for (j = 0; j < srv_cnt; j++) {
for (i = 1; i <= BTA_JV_MAX_L2C_CONN; i++) {
if (l2cap_local_param.l2cap_slots[i] != NULL && l2cap_local_param.l2cap_slots[i]->connected &&
l2cap_local_param.l2cap_slots[i]->handle != 0xffff &&
l2cap_local_param.l2cap_slots[i]->psm == srv_psm_arr[j]) {
BTA_JvL2capClose(l2cap_local_param.l2cap_slots[i]->handle, (tBTA_JV_L2CAP_CBACK *)btc_l2cap_inter_cb,
(void *)l2cap_local_param.l2cap_slots[i]->id);
}{...}
}{...}
}{...}
for (j = 0; j < srv_cnt; j++) {
for (i = 1; i <= BTA_JV_MAX_L2C_CONN; i++) {
if (l2cap_local_param.l2cap_slots[i] != NULL && l2cap_local_param.l2cap_slots[i]->is_server &&
l2cap_local_param.l2cap_slots[i]->handle != 0xffff &&
l2cap_local_param.l2cap_slots[i]->psm == srv_psm_arr[j]) {
if (l2cap_local_param.l2cap_slots[i]->handle > 0) {
BTA_JvL2capStopServer(l2cap_local_param.l2cap_slots[i]->psm,
(void *)l2cap_local_param.l2cap_slots[i]->id);
}{...}
BTA_JvFreeChannel(l2cap_local_param.l2cap_slots[i]->psm, BTA_JV_CONN_TYPE_L2CAP,
(tBTA_JV_RFCOMM_CBACK *)btc_l2cap_inter_cb, (void *)l2cap_local_param.l2cap_slots[i]->id);
}{...}
}{...}
}{...}
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
}{...} while (0);
if (ret != ESP_BT_L2CAP_SUCCESS) {
esp_bt_l2cap_cb_param_t param;
param.srv_stop.status = ret;
param.srv_stop.psm = BTC_L2CAP_INVALID_PSM;
btc_l2cap_cb_to_app(ESP_BT_L2CAP_SRV_STOP_EVT, ¶m);
}{...}
if (srv_psm_arr) {
osi_free(srv_psm_arr);
srv_psm_arr = NULL;
}{...}
}{...}
static void btc_l2cap_connect(btc_l2cap_args_t *arg)
{
esp_bt_l2cap_status_t ret = ESP_BT_L2CAP_SUCCESS;
tL2CAP_CFG_INFO cfg;
do {
if (!is_l2cap_init()) {
BTC_TRACE_ERROR("%s L2CAP have not been init\n", __func__);
ret = ESP_BT_L2CAP_NEED_INIT;
break;
}{...}
osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
l2cap_slot_t *slot = l2cap_malloc_slot();
if (!slot) {
BTC_TRACE_ERROR("%s unable to malloc L2CAP slot!", __func__);
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
ret = ESP_BT_L2CAP_NO_RESOURCE;
break;
}{...}
slot->security = arg->connect.sec_mask;
slot->role = BTC_L2CAP_ROLE_MASTER;
slot->psm = arg->connect.remote_psm;
memcpy(slot->addr, arg->connect.peer_bd_addr, ESP_BD_ADDR_LEN);
memset(&cfg, 0, sizeof(tL2CAP_CFG_INFO));
cfg.fcr_present = TRUE;
cfg.fcr = obex_l2c_fcr_opts_def;
BTA_JvL2capConnect(slot->security, slot->role, &obex_l2c_etm_opt, slot->psm,
L2CAP_MAX_SDU_LENGTH, &cfg, slot->addr, (tBTA_JV_L2CAP_CBACK *)btc_l2cap_inter_cb, (void *)slot->id);
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
}{...} while (0);
if (ret != ESP_BT_L2CAP_SUCCESS) {
esp_bt_l2cap_cb_param_t param;
param.open.status = ret;
param.open.handle = 0;
param.open.fd = -1;
param.open.tx_mtu = 0;
memset(param.open.rem_bda, 0, ESP_BD_ADDR_LEN);
btc_l2cap_cb_to_app(ESP_BT_L2CAP_OPEN_EVT, ¶m);
}{...}
}{...}
static void btc_l2cap_write(uint32_t handle)
{
do {
if (!is_l2cap_init()) {
BTC_TRACE_ERROR("%s L2CAP have not been init\n", __func__);
break;
}{...}
l2cap_slot_t *slot = NULL;
slot = l2cap_find_slot_by_handle(handle);
if (!slot || (slot && !slot->connected)) {
if (!slot) {
BTC_TRACE_ERROR("%s unable to find l2cap slot!", __func__);
}{...} else {
BTC_TRACE_ERROR("%s l2cap has been disconnected already!", __func__);
}{...}
break;
}{...}
BT_HDR *p_buf;
if ((p_buf = fixed_queue_try_peek_first(slot->tx.queue)) != NULL && p_buf->layer_specific == 0) {
p_buf->event++;
p_buf->layer_specific = 1;
BTA_JvL2capWrite(handle, slot->id, p_buf->data + p_buf->offset, p_buf->len, (void *)slot->id);
}{...}
}{...} while (0);
}{...}
static void btc_l2cap_disconnect(uint32_t handle)
{
esp_bt_l2cap_status_t ret = ESP_BT_L2CAP_SUCCESS;
do {
if (!is_l2cap_init()) {
BTC_TRACE_ERROR("%s L2CAP have not been init\n", __func__);
ret = ESP_BT_L2CAP_NEED_INIT;
break;
}{...}
l2cap_slot_t *slot = NULL;
slot = l2cap_find_slot_by_handle(handle);
if (!slot || (slot && !slot->connected)) {
if (!slot) {
BTC_TRACE_ERROR("%s unable to find L2CAP slot! disconnect fail!", __func__);
}{...} else {
BTC_TRACE_ERROR("%s L2CAP has been disconnected already!", __func__);
}{...}
ret = ESP_BT_L2CAP_NO_CONNECTION;
break;
}{...}
BTA_JvL2capClose(handle, (tBTA_JV_L2CAP_CBACK *)btc_l2cap_inter_cb, (void *)slot->id);
}{...} while(0);
if (ret != ESP_BT_L2CAP_SUCCESS) {
esp_bt_l2cap_cb_param_t param;
param.close.status = ret;
param.close.handle = 0;
param.close.async = FALSE;
btc_l2cap_cb_to_app(ESP_BT_L2CAP_CLOSE_EVT, ¶m);
}{...}
}{...}
void btc_l2cap_call_handler(btc_msg_t *msg)
{
btc_l2cap_args_t *arg = (btc_l2cap_args_t *)(msg->arg);
switch (msg->act) {
case BTC_L2CAP_ACT_INIT:
btc_l2cap_init();
break;...
case BTC_L2CAP_ACT_UNINIT:
btc_l2cap_uninit();
break;...
case BTC_L2CAP_ACT_CONNECT:
btc_l2cap_connect(arg);
break;...
case BTC_L2CAP_ACT_START_SRV:
btc_l2cap_start_srv(arg);
break;...
case BTC_L2CAP_ACT_STOP_SRV:
btc_l2cap_stop_srv(arg);
break;...
default:
BTC_TRACE_ERROR("%s: Unhandled event (%d)!\n", __FUNCTION__, msg->act);
break;...
}{...}
}{...}
void btc_l2cap_cb_handler(btc_msg_t *msg)
{
esp_bt_l2cap_cb_param_t param;
tBTA_JV *p_data = (tBTA_JV *)msg->arg;
l2cap_slot_t *slot = NULL;
uint8_t event = msg->act;
uint8_t serial = 0;
uint32_t count = 0;
switch (event) {
case BTA_JV_ENABLE_EVT:
param.init.status = p_data->status;
btc_l2cap_cb_to_app(ESP_BT_L2CAP_INIT_EVT, ¶m);
break;...
case BTA_JV_DISABLE_EVT:
param.uninit.status = ESP_BT_L2CAP_SUCCESS;
l2cap_free_pending_slots();
BTA_JvFree();
osi_mutex_free(&l2cap_local_param.l2cap_slot_mutex);
if (l2cap_local_param.tx_event_group) {
vEventGroupDelete(l2cap_local_param.tx_event_group);
l2cap_local_param.tx_event_group = NULL;
}{...}
if (l2cap_local_param.l2cap_vfs_id != -1) {
esp_vfs_unregister_with_id(l2cap_local_param.l2cap_vfs_id);
l2cap_local_param.l2cap_vfs_id = -1;
}{...}
#if L2CAP_DYNAMIC_MEMORY == TRUE
osi_free(l2cap_local_param_ptr);
l2cap_local_param_ptr = NULL;/* ... */
#endif
btc_l2cap_cb_to_app(ESP_BT_L2CAP_UNINIT_EVT, ¶m);
break;...
case BTA_JV_L2CAP_OPEN_EVT:
do {
osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = l2cap_find_slot_by_handle(p_data->l2c_open.handle);
if (!slot) {
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
BTC_TRACE_ERROR("%s unable to find L2CAP slot, event:%d!", __func__, event);
param.open.status = ESP_BT_L2CAP_NO_CONNECTION;
break;
}{...}
param.open.fd = slot->fd;
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
param.open.status = p_data->l2c_open.status;
}{...} while (0);
param.open.handle = p_data->l2c_open.handle;
param.open.tx_mtu = p_data->l2c_open.tx_mtu;
memcpy(param.open.rem_bda, p_data->l2c_open.rem_bda, ESP_BD_ADDR_LEN);
btc_l2cap_cb_to_app(ESP_BT_L2CAP_OPEN_EVT, ¶m);
break;...
case BTA_JV_L2CAP_CLOSE_EVT:
param.close.status = p_data->l2c_close.status;
param.close.handle = p_data->l2c_close.handle;
param.close.async = p_data->l2c_close.async;
bool need_call = true;
do {
osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
uint32_t id = (uintptr_t)p_data->l2c_close.user_data;
slot = l2cap_find_slot_by_id(id);
if (!slot) {
param.close.status = ESP_BT_L2CAP_NO_CONNECTION;
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
BTC_TRACE_ERROR("%s unable to find RFCOMM slot, event:%d!", __func__, event);
break;
}{...}
if (slot->close_alarm == NULL && slot->rx.queue && fixed_queue_length(slot->rx.queue) > 0) {
tBTA_JV *p_arg = NULL;
if ((p_arg = osi_malloc(sizeof(tBTA_JV))) == NULL) {
param.close.status = ESP_BT_L2CAP_NO_RESOURCE;
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
BTC_TRACE_ERROR("%s unable to malloc slot close_alarm arg!", __func__);
break;
}{...}
memcpy(p_arg, p_data, sizeof(tBTA_JV));
slot->alarm_arg = (void *)p_arg;
if ((slot->close_alarm =
osi_alarm_new("slot", close_timeout_handler, (void *)slot, VFS_CLOSE_TIMEOUT)) == NULL) {
osi_free(p_arg);
slot->alarm_arg = NULL;
param.close.status = ESP_BT_L2CAP_NO_RESOURCE;
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
BTC_TRACE_ERROR("%s unable to malloc slot close_alarm!", __func__);
break;
}{...}
if (osi_alarm_set(slot->close_alarm, VFS_CLOSE_TIMEOUT) != OSI_ALARM_ERR_PASS) {
osi_free(p_arg);
slot->alarm_arg = NULL;
osi_alarm_free(slot->close_alarm);
param.close.status = ESP_BT_L2CAP_BUSY;
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
BTC_TRACE_ERROR("%s set slot close_alarm failed!", __func__);
break;
}{...}
BTC_TRACE_WARNING("%s slot rx data will be discard in %d milliseconds!",
__func__, VFS_CLOSE_TIMEOUT);
slot->connected = false;
need_call = false;
}{...}
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
}{...} while (0);
if (need_call) {
btc_l2cap_cb_to_app(ESP_BT_L2CAP_CLOSE_EVT, ¶m);
osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
l2cap_free_slot(slot);
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
}{...}
break;...
case BTA_JV_L2CAP_START_EVT:
param.start.status = p_data->l2c_start.status;
param.start.handle = p_data->l2c_start.handle;
param.start.sec_id = p_data->l2c_start.sec_id;
btc_l2cap_cb_to_app(ESP_BT_L2CAP_START_EVT, ¶m);
break;...
case BTA_JV_L2CAP_CL_INIT_EVT:
param.cl_init.status = p_data->l2c_cl_init.status;
param.cl_init.handle = p_data->l2c_cl_init.handle;
param.cl_init.sec_id = p_data->l2c_cl_init.sec_id;
btc_l2cap_cb_to_app(ESP_BT_L2CAP_CL_INIT_EVT, ¶m);
break;...
case BTA_JV_L2CAP_DATA_IND_EVT:
osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = l2cap_find_slot_by_handle(p_data->data_ind.handle);
if (!slot) {
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
BTC_TRACE_ERROR("%s unable to find L2CAP slot, event:%d!", __func__, event);
break;
}{...}
if (BTA_JvL2capReady(p_data->data_ind.handle, &count) == BTA_JV_SUCCESS && count > 0) {
BT_HDR *p_data_buf = osi_malloc(count + sizeof(BT_HDR));
if (p_data_buf == NULL) {
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
BTC_TRACE_ERROR("%s, %d count = %d malloc failed!", __func__, __LINE__, count);
break;
}{...}
memset(p_data_buf, 0, count + sizeof(BT_HDR));
p_data_buf->len = BTA_JvL2capRead(p_data->data_ind.handle, slot->id, p_data_buf->data, count);
if (p_data_buf->len > 0) {
fixed_queue_enqueue(slot->rx.queue, p_data_buf, FIXED_QUEUE_MAX_TIMEOUT);
}{...} else {
osi_free(p_data_buf);
}{...}
}{...}
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
break;...
case BTA_JV_L2CAP_CONG_EVT:
osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = l2cap_find_slot_by_handle(p_data->l2c_cong.handle);
if (!slot) {
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
BTC_TRACE_ERROR("%s unable to find L2CAP slot, event:%d!", __func__, event);
break;
}{...}
if (!p_data->l2c_cong.cong) {
BT_HDR *p_buf;
if ((p_buf = fixed_queue_try_peek_first(slot->tx.queue)) != NULL && p_buf->layer_specific == 0) {
p_buf->event++;
p_buf->layer_specific = 1;
BTA_JvL2capWrite(p_data->l2c_cong.handle, slot->id, p_buf->data + p_buf->offset, p_buf->len, (void *)slot->id);
}{...}
}{...}
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
break;...
case BTA_JV_L2CAP_READ_EVT:
osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = l2cap_find_slot_by_handle(p_data->l2c_read.handle);
if (!slot) {
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
BTC_TRACE_ERROR("%s unable to find L2CAP slot, event:%d!", __func__, event);
break;
}{...}
if (BTA_JvL2capReady(p_data->l2c_read.handle, &count) == BTA_JV_SUCCESS && count > 0) {
BT_HDR *p_data_buf = osi_malloc(count + sizeof(BT_HDR));
if (p_data_buf == NULL) {
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
BTC_TRACE_ERROR("%s, %d count = %d malloc failed!", __func__, __LINE__, count);
break;
}{...}
memset(p_data_buf, 0, count + sizeof(BT_HDR));
p_data_buf->len = BTA_JvL2capRead(p_data->l2c_read.handle, slot->id, p_data_buf->data, count);
if (p_data_buf->len > 0) {
fixed_queue_enqueue(slot->rx.queue, p_data_buf, FIXED_QUEUE_MAX_TIMEOUT);
}{...} else {
osi_free(p_data_buf);
}{...}
}{...}
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
break;...
case BTA_JV_L2CAP_WRITE_EVT:
osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = l2cap_find_slot_by_handle(p_data->l2c_write.handle);
if (!slot) {
BTC_TRACE_ERROR("%s unable to find L2CAP slot!, handle:%d", __func__, p_data->l2c_write.handle);
}{...}
if (slot) {
BT_HDR *p_buf;
serial = slot->serial;
if ((p_buf = fixed_queue_try_peek_first(slot->tx.queue)) == NULL) {
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
break;
}{...}
if (p_data->l2c_write.status == BTA_JV_SUCCESS) {
p_buf->len -= p_data->l2c_write.len;
p_buf->offset += p_data->l2c_write.len;
p_buf->layer_specific = 0;
if (p_buf->len == 0) {
osi_free(fixed_queue_dequeue(slot->tx.queue, FIXED_QUEUE_MAX_TIMEOUT));
if (fixed_queue_length(slot->tx.queue) <= SLOT_TX_QUEUE_LOW_WM) {
xEventGroupSetBits(l2cap_local_param.tx_event_group, SLOT_WRITE_BIT(serial));
}{...}
}{...}
if ((p_buf = fixed_queue_try_peek_first(slot->tx.queue)) != NULL && p_buf->layer_specific == 0 &&
!p_data->l2c_write.cong) {
p_buf->layer_specific = 1;
p_buf->event++;
BTA_JvL2capWrite(p_data->l2c_write.handle, slot->id, p_buf->data + p_buf->offset, p_buf->len, (void *)slot->id);
}{...}
}{...}
}{...}
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
break;...
case BTA_JV_FREE_SCN_EVT:
param.srv_stop.status = p_data->free_scn.status;
param.srv_stop.psm = p_data->free_scn.scn;
btc_l2cap_cb_to_app(ESP_BT_L2CAP_SRV_STOP_EVT, ¶m);
break;...
default:
break;...
}{...}
return;
}{...}
static ssize_t l2cap_vfs_write(int fd, const void * data, size_t size)
{
assert(data != NULL);
errno = 0;
if (size == 0) {
return 0;
}{...}
if (!is_l2cap_init()) {
BTC_TRACE_ERROR("%s L2CAP have not been init\n", __func__);
errno = ESRCH;
return -1;
}{...}
l2cap_slot_t *slot = NULL;
uint8_t serial = 0;
osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = l2cap_find_slot_by_fd(fd);
if (!slot) {
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
BTC_TRACE_ERROR("%s unable to find L2CAP slot!", __func__);
errno = ENOENT;
return -1;
}{...}
serial = slot->serial;
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
ssize_t sent = 0, write_size = 0;
size_t tx_len;
BT_HDR *p_buf = NULL;
bool enqueue_status= false;
EventBits_t tx_event_group_val = 0;
while (1) {
tx_event_group_val = 0;
if (size) {
if (p_buf == NULL) {
write_size = size < slot->tx_mtu ? size : slot->tx_mtu;
if ((p_buf = osi_malloc(sizeof(BT_HDR) + write_size)) == NULL) {
BTC_TRACE_ERROR("%s malloc failed!", __func__);
errno = ENOMEM;
sent = -1;
break;
}{...}
p_buf->offset = 0;
p_buf->len = write_size;
p_buf->event = 0;
p_buf->layer_specific = 0;
memcpy((UINT8 *)(p_buf + 1), data + sent, write_size);
}{...}
}{...} else {
break;
}{...}
osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
if ((slot = l2cap_local_param.l2cap_slots[serial]) != NULL) {
tx_len = fixed_queue_length(slot->tx.queue);
enqueue_status = fixed_queue_enqueue(slot->tx.queue, p_buf, 0);
if (!enqueue_status) {
BTC_TRACE_DEBUG("%s tx_len:%d, fd:%d\n", __func__, fixed_queue_length(slot->tx.queue), fd);
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
tx_event_group_val =
xEventGroupWaitBits(l2cap_local_param.tx_event_group, SLOT_WRITE_BIT(serial) | SLOT_CLOSE_BIT(serial), pdTRUE,
pdFALSE, VFS_WRITE_TIMEOUT / portTICK_PERIOD_MS);
if (tx_event_group_val & SLOT_CLOSE_BIT(serial)) {
BTC_TRACE_ERROR("%s exit for L2CAP close, fd:%d!", __func__, fd);
errno = EPIPE;
sent = -1;
break;
}{...} else if (tx_event_group_val & SLOT_WRITE_BIT(serial)) {
continue;
}{...} else if (tx_event_group_val == 0) {
BTC_TRACE_ERROR("%s exit for time out, fd:%d!", __func__, fd);
errno = EBUSY;
sent = -1;
break;
}{...}
}{...}
if (tx_len == 0) {
btc_l2cap_write(slot->handle);
}{...}
sent += write_size;
size -= write_size;
p_buf = NULL;
}{...} else {
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
errno = EPIPE;
sent = -1;
break;
}{...}
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
}{...}
if (p_buf) {
osi_free(p_buf);
p_buf = NULL;
}{...}
return sent;
}{...}
static int l2cap_vfs_close(int fd)
{
errno = 0;
if (!is_l2cap_init()) {
BTC_TRACE_ERROR("%s L2CAP have not been init\n", __func__);
errno = ESRCH;
return -1;
}{...}
l2cap_slot_t *slot = NULL;
osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = l2cap_find_slot_by_fd(fd);
if (!slot) {
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
BTC_TRACE_ERROR("%s unable to find L2CAP slot!", __func__);
errno = ENOENT;
return -1;
}{...}
btc_l2cap_disconnect(slot->handle);
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
return 0;
}{...}
static ssize_t l2cap_vfs_read(int fd, void * dst, size_t size)
{
assert(dst != NULL);
errno = 0;
if (!is_l2cap_init()) {
BTC_TRACE_ERROR("%s L2CAP have not been init\n", __func__);
errno = ESRCH;
return -1;
}{...}
l2cap_slot_t *slot = NULL;
uint8_t serial = 0;
osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
slot = l2cap_find_slot_by_fd(fd);
if (!slot) {
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
BTC_TRACE_ERROR("%s unable to find L2CAP slot!", __func__);
errno = ENOENT;
return -1;
}{...}
serial = slot->serial;
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
ssize_t item_size = 0;
BT_HDR *p_buf;
while (1) {
osi_mutex_lock(&l2cap_local_param.l2cap_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
if ((slot = l2cap_local_param.l2cap_slots[serial]) != NULL) {
if (fixed_queue_length(slot->rx.queue) > 0) {
if ((p_buf = (BT_HDR *)fixed_queue_try_peek_first(slot->rx.queue)) != NULL && p_buf->len == 0) {
osi_free(fixed_queue_dequeue(slot->rx.queue, FIXED_QUEUE_MAX_TIMEOUT));
p_buf = NULL;
}{...}
if (size == 0 || (p_buf = (BT_HDR *)fixed_queue_try_peek_first(slot->rx.queue)) == NULL) {
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
break;
}{...}
}{...} else {
/* ... */
if (slot->close_alarm && osi_alarm_is_active(slot->close_alarm)) {
osi_alarm_cancel(slot->close_alarm);
osi_alarm_set(slot->close_alarm, 0);
}{...}
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
break;
}{...}
}{...} else {
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
BTC_TRACE_ERROR("%s peer close, data will be discarded!\n", __func__);
errno = EPIPE;
item_size = -1;
break;
}{...}
osi_mutex_unlock(&l2cap_local_param.l2cap_slot_mutex);
if (p_buf->len <= size) {
memcpy(dst, p_buf->data + p_buf->offset, p_buf->len);
size -= p_buf->len;
item_size += p_buf->len;
dst += p_buf->len;
p_buf->offset += p_buf->len;
p_buf->len = 0;
}{...} else {
memcpy(dst, p_buf->data + p_buf->offset, size);
item_size += size;
p_buf->offset += size;
p_buf->len -= size;
size = 0;
}{...}
}{...}
return item_size;
}{...}
esp_err_t btc_l2cap_vfs_register(void)
{
esp_err_t ret = ESP_OK;
do {
if (!is_l2cap_init()) {
BTC_TRACE_ERROR("%s L2CAP have not been init\n", __func__);
ret = ESP_FAIL;
break;
}{...}
esp_vfs_t vfs = {
.flags = ESP_VFS_FLAG_DEFAULT,
.write = l2cap_vfs_write,
.open = NULL,
.fstat = NULL,
.close = l2cap_vfs_close,
.read = l2cap_vfs_read,
.fcntl = NULL
}{...};
if (esp_vfs_register_with_id(&vfs, NULL, &l2cap_local_param.l2cap_vfs_id) != ESP_OK) {
ret = ESP_FAIL;
break;
}{...}
}{...} while (0);
return ret;
}{...}
esp_err_t btc_l2cap_vfs_unregister(void)
{
esp_err_t ret = ESP_OK;
do {
if (!is_l2cap_init()) {
BTC_TRACE_ERROR("%s L2CAP have not been init\n", __func__);
ret = ESP_FAIL;
break;
}{...}
if (l2cap_local_param.l2cap_vfs_id != -1) {
if (esp_vfs_unregister_with_id(l2cap_local_param.l2cap_vfs_id) != ESP_OK) {
ret = ESP_FAIL;
}{...}
}{...}
l2cap_local_param.l2cap_vfs_id = -1;
}{...} while (0);
return ret;
}{...}
/* ... */
#endif