@@ -51,9 +51,6 @@ LOG_MODULE_REGISTER(bt_rfcomm);
5151
5252static struct bt_rfcomm_server * servers ;
5353
54- /* Pool for dummy buffers to wake up the tx threads */
55- NET_BUF_POOL_DEFINE (dummy_pool , CONFIG_BT_MAX_CONN , 0 , 0 , NULL );
56-
5754#define RFCOMM_SESSION (_ch ) CONTAINER_OF(_ch, \
5855 struct bt_rfcomm_session, br_chan.chan)
5956
@@ -235,13 +232,37 @@ int bt_rfcomm_server_register(struct bt_rfcomm_server *server)
235232 return 0 ;
236233}
237234
235+ static void rfcomm_dlc_tx_trigger (struct bt_rfcomm_dlc * dlc )
236+ {
237+ int err ;
238+
239+ if ((dlc == NULL ) || (dlc -> tx_work .handler == NULL )) {
240+ return ;
241+ }
242+
243+ LOG_DBG ("DLC %p TX trigger" , dlc );
244+
245+ err = k_work_submit (& dlc -> tx_work );
246+ if (err < 0 ) {
247+ LOG_ERR ("Failed to submit tx work: %d" , err );
248+ }
249+ }
250+
251+ static void rfcomm_dlcs_tx_trigger (struct bt_rfcomm_dlc * dlcs )
252+ {
253+ for (struct bt_rfcomm_dlc * dlc = dlcs ; dlc != NULL ; dlc = dlc -> _next ) {
254+ rfcomm_dlc_tx_trigger (dlc );
255+ }
256+ }
257+
238258static void rfcomm_dlc_tx_give_credits (struct bt_rfcomm_dlc * dlc ,
239259 uint8_t credits )
240260{
241261 LOG_DBG ("dlc %p credits %u" , dlc , credits );
242262
243263 while (credits -- ) {
244264 k_sem_give (& dlc -> tx_credits );
265+ rfcomm_dlc_tx_trigger (dlc );
245266 }
246267
247268 LOG_DBG ("dlc %p updated credits %u" , dlc , k_sem_count_get (& dlc -> tx_credits ));
@@ -252,6 +273,8 @@ static void rfcomm_dlc_destroy(struct bt_rfcomm_dlc *dlc)
252273 LOG_DBG ("dlc %p" , dlc );
253274
254275 k_work_cancel_delayable (& dlc -> rtx_work );
276+ k_work_cancel (& dlc -> tx_work );
277+
255278 dlc -> state = BT_RFCOMM_STATE_IDLE ;
256279 dlc -> session = NULL ;
257280
@@ -274,16 +297,7 @@ static void rfcomm_dlc_disconnect(struct bt_rfcomm_dlc *dlc)
274297
275298 switch (old_state ) {
276299 case BT_RFCOMM_STATE_CONNECTED :
277- /* Queue a dummy buffer to wake up and stop the
278- * tx thread for states where it was running.
279- */
280- k_fifo_put (& dlc -> tx_queue , net_buf_alloc (& dummy_pool , K_NO_WAIT ));
281-
282- /* There could be a writer waiting for credits so return a
283- * dummy credit to wake it up.
284- */
285- rfcomm_dlc_tx_give_credits (dlc , 1 );
286- k_sem_give (& dlc -> session -> fc );
300+ rfcomm_dlc_tx_trigger (dlc );
287301 break ;
288302 default :
289303 rfcomm_dlc_destroy (dlc );
@@ -465,8 +479,17 @@ static void rfcomm_dlc_init(struct bt_rfcomm_dlc *dlc,
465479 uint8_t dlci ,
466480 bt_rfcomm_role_t role )
467481{
482+ struct k_work_sync sync ;
483+
468484 LOG_DBG ("dlc %p" , dlc );
469485
486+ if (dlc -> tx_work .handler != NULL ) {
487+ /* Make sure the tx_work is cancelled before reinitializing */
488+ k_work_cancel_sync (& dlc -> tx_work , & sync );
489+ /* Reset the work handler to NULL before the DLC connected */
490+ dlc -> tx_work .handler = NULL ;
491+ }
492+
470493 dlc -> dlci = dlci ;
471494 dlc -> session = session ;
472495 dlc -> rx_credit = RFCOMM_DEFAULT_CREDIT ;
@@ -533,19 +556,30 @@ static int rfcomm_send_dm(struct bt_rfcomm_session *session, uint8_t dlci)
533556 return rfcomm_send (session , buf );
534557}
535558
536- static void rfcomm_check_fc (struct bt_rfcomm_dlc * dlc )
559+ static bool rfcomm_check_fc (struct bt_rfcomm_dlc * dlc )
537560{
538- LOG_DBG ( "%p" , dlc ) ;
561+ int err ;
539562
540563 LOG_DBG ("Wait for credits or MSC FC %p" , dlc );
541564 /* Wait for credits or MSC FC */
542- k_sem_take (& dlc -> tx_credits , K_FOREVER );
565+ err = k_sem_take (& dlc -> tx_credits , K_NO_WAIT );
566+ if (err != 0 ) {
567+ LOG_DBG ("Credits not available" );
568+ return false;
569+ }
543570
571+ LOG_DBG ("Credits available" );
544572 if (dlc -> session -> cfc == BT_RFCOMM_CFC_SUPPORTED ) {
545- return ;
573+ LOG_DBG ("Credits available" );
574+ return true;
546575 }
547576
548- k_sem_take (& dlc -> session -> fc , K_FOREVER );
577+ err = k_sem_take (& dlc -> session -> fc , K_NO_WAIT );
578+ if (err != 0 ) {
579+ k_sem_give (& dlc -> tx_credits );
580+ LOG_DBG ("Flow control not available" );
581+ return false;
582+ }
549583
550584 /* Give the sems immediately so that sem will be available for all
551585 * the bufs in the queue. It will be blocked only once all the bufs
@@ -554,6 +588,9 @@ static void rfcomm_check_fc(struct bt_rfcomm_dlc *dlc)
554588 */
555589 k_sem_give (& dlc -> session -> fc );
556590 k_sem_give (& dlc -> tx_credits );
591+
592+ LOG_DBG ("Flow control available" );
593+ return true;
557594}
558595
559596static void bt_rfcomm_tx_destroy (struct bt_rfcomm_dlc * dlc , struct net_buf * buf )
@@ -581,55 +618,60 @@ static void rfcomm_sent(struct bt_conn *conn, void *user_data, int err)
581618
582619 dlc = (struct bt_rfcomm_dlc * )user_data ;
583620
621+ rfcomm_dlc_tx_trigger (dlc );
622+
584623 if (dlc && dlc -> ops && dlc -> ops -> sent ) {
585624 dlc -> ops -> sent (dlc , err );
586625 }
587626}
588627
589- static void rfcomm_dlc_tx_thread ( void * p1 , void * p2 , void * p3 )
628+ static void rfcomm_dlc_tx_worker ( struct k_work * work )
590629{
591- struct bt_rfcomm_dlc * dlc = p1 ;
592- k_timeout_t timeout = K_FOREVER ;
630+ struct bt_rfcomm_dlc * dlc = CONTAINER_OF (work , struct bt_rfcomm_dlc , tx_work );
593631 struct net_buf * buf ;
594632
595- LOG_DBG ("Started for dlc %p" , dlc );
596-
597- while (dlc -> state == BT_RFCOMM_STATE_CONNECTED ||
598- dlc -> state == BT_RFCOMM_STATE_USER_DISCONNECT ) {
599- /* Get next packet for dlc */
600- LOG_DBG ("Wait for buf %p" , dlc );
601- buf = k_fifo_get (& dlc -> tx_queue , timeout );
602- /* If its dummy buffer or non user disconnect then break */
603- if ((dlc -> state != BT_RFCOMM_STATE_CONNECTED &&
604- dlc -> state != BT_RFCOMM_STATE_USER_DISCONNECT ) ||
605- !buf || !buf -> len ) {
606- if (buf ) {
607- bt_rfcomm_tx_destroy (dlc , buf );
608- net_buf_unref (buf );
609- }
610- break ;
633+ LOG_DBG ("Work for dlc %p state %u" , dlc , dlc -> state );
634+
635+ if (dlc -> state < BT_RFCOMM_STATE_CONNECTED ) {
636+ return ;
637+ }
638+
639+ if (dlc -> state == BT_RFCOMM_STATE_CONNECTED ||
640+ dlc -> state == BT_RFCOMM_STATE_USER_DISCONNECT ) {
641+ if (k_fifo_is_empty (& dlc -> tx_queue ) == true) {
642+ goto user_disconnect ;
611643 }
612644
613- rfcomm_check_fc (dlc );
614- if (dlc -> state != BT_RFCOMM_STATE_CONNECTED &&
615- dlc -> state != BT_RFCOMM_STATE_USER_DISCONNECT ) {
616- bt_rfcomm_tx_destroy (dlc , buf );
617- net_buf_unref (buf );
618- break ;
645+ if (rfcomm_check_fc (dlc ) == false) {
646+ LOG_DBG ("FC or credit not available" );
647+ goto user_disconnect ;
619648 }
620649
650+ buf = k_fifo_get (& dlc -> tx_queue , K_NO_WAIT );
651+ LOG_DBG ("Tx buf %p" , buf );
621652 if (rfcomm_send_cb (dlc -> session , buf , rfcomm_sent , dlc ) < 0 ) {
622653 /* This fails only if channel is disconnected */
623654 dlc -> state = BT_RFCOMM_STATE_DISCONNECTED ;
624655 bt_rfcomm_tx_destroy (dlc , buf );
625- break ;
656+ LOG_ERR ("Failed to send buffer, disconnected" );
657+ goto disconnect ;
658+ }
659+
660+ if (k_fifo_is_empty (& dlc -> tx_queue ) == false) {
661+ rfcomm_dlc_tx_trigger (dlc );
662+ return ;
626663 }
627664
665+ user_disconnect :
628666 if (dlc -> state == BT_RFCOMM_STATE_USER_DISCONNECT ) {
629- timeout = K_NO_WAIT ;
667+ LOG_DBG ("Process user disconnect" );
668+ goto disconnect ;
630669 }
670+
671+ return ;
631672 }
632673
674+ disconnect :
633675 LOG_DBG ("dlc %p disconnected - cleaning up" , dlc );
634676
635677 /* Give back any allocated buffers */
@@ -844,11 +886,7 @@ static void rfcomm_dlc_connected(struct bt_rfcomm_dlc *dlc)
844886 k_work_cancel_delayable (& dlc -> rtx_work );
845887
846888 k_fifo_init (& dlc -> tx_queue );
847- k_thread_create (& dlc -> tx_thread , dlc -> stack ,
848- K_KERNEL_STACK_SIZEOF (dlc -> stack ),
849- rfcomm_dlc_tx_thread , dlc , NULL , NULL , K_PRIO_COOP (7 ),
850- 0 , K_NO_WAIT );
851- k_thread_name_set (& dlc -> tx_thread , "BT DLC" );
889+ k_work_init (& dlc -> tx_work , rfcomm_dlc_tx_worker );
852890
853891 if (dlc -> ops && dlc -> ops -> connected ) {
854892 dlc -> ops -> connected (dlc );
@@ -921,17 +959,7 @@ static int rfcomm_dlc_close(struct bt_rfcomm_dlc *dlc)
921959 break ;
922960 case BT_RFCOMM_STATE_CONNECTED :
923961 dlc -> state = BT_RFCOMM_STATE_DISCONNECTING ;
924-
925- /* Queue a dummy buffer to wake up and stop the
926- * tx thread.
927- */
928- k_fifo_put (& dlc -> tx_queue ,
929- net_buf_alloc (& dummy_pool , K_NO_WAIT ));
930-
931- /* There could be a writer waiting for credits so return a
932- * dummy credit to wake it up.
933- */
934- rfcomm_dlc_tx_give_credits (dlc , 1 );
962+ rfcomm_dlc_tx_trigger (dlc );
935963 break ;
936964 case BT_RFCOMM_STATE_DISCONNECTING :
937965 case BT_RFCOMM_STATE_DISCONNECTED :
@@ -1178,6 +1206,7 @@ static void rfcomm_handle_msc(struct bt_rfcomm_session *session,
11781206 * thread in sem_take().
11791207 */
11801208 k_sem_give (& dlc -> tx_credits );
1209+ rfcomm_dlc_tx_trigger (dlc );
11811210 }
11821211 }
11831212
@@ -1410,6 +1439,7 @@ static void rfcomm_handle_msg(struct bt_rfcomm_session *session,
14101439 */
14111440 k_sem_give (& session -> fc );
14121441 rfcomm_send_fcon (session , BT_RFCOMM_MSG_RESP_CR );
1442+ rfcomm_dlcs_tx_trigger (session -> dlcs );
14131443 break ;
14141444 case BT_RFCOMM_FCOFF :
14151445 if (session -> cfc == BT_RFCOMM_CFC_SUPPORTED ) {
@@ -1544,6 +1574,7 @@ int bt_rfcomm_dlc_send(struct bt_rfcomm_dlc *dlc, struct net_buf *buf)
15441574 net_buf_add_u8 (buf , fcs );
15451575
15461576 k_fifo_put (& dlc -> tx_queue , buf );
1577+ rfcomm_dlc_tx_trigger (dlc );
15471578
15481579 return buf -> len ;
15491580}
@@ -1802,9 +1833,7 @@ int bt_rfcomm_dlc_disconnect(struct bt_rfcomm_dlc *dlc)
18021833 * and stop the tx thread.
18031834 */
18041835 dlc -> state = BT_RFCOMM_STATE_USER_DISCONNECT ;
1805- k_fifo_put (& dlc -> tx_queue ,
1806- net_buf_alloc (& dummy_pool , K_NO_WAIT ));
1807-
1836+ rfcomm_dlc_tx_trigger (dlc );
18081837 k_work_reschedule (& dlc -> rtx_work , RFCOMM_DISC_TIMEOUT );
18091838
18101839 return 0 ;
0 commit comments