xref: /aosp_15_r20/system/chre/chpp/platform/linux/link.c (revision 84e339476a462649f82315436d70fd732297a399)
1*84e33947SAndroid Build Coastguard Worker /*
2*84e33947SAndroid Build Coastguard Worker  * Copyright (C) 2020 The Android Open Source Project
3*84e33947SAndroid Build Coastguard Worker  *
4*84e33947SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*84e33947SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*84e33947SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*84e33947SAndroid Build Coastguard Worker  *
8*84e33947SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*84e33947SAndroid Build Coastguard Worker  *
10*84e33947SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*84e33947SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*84e33947SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*84e33947SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*84e33947SAndroid Build Coastguard Worker  * limitations under the License.
15*84e33947SAndroid Build Coastguard Worker  */
16*84e33947SAndroid Build Coastguard Worker 
17*84e33947SAndroid Build Coastguard Worker #include "chpp/link.h"
18*84e33947SAndroid Build Coastguard Worker 
19*84e33947SAndroid Build Coastguard Worker #include <inttypes.h>
20*84e33947SAndroid Build Coastguard Worker #include <stddef.h>
21*84e33947SAndroid Build Coastguard Worker #include <stdint.h>
22*84e33947SAndroid Build Coastguard Worker #include <string.h>
23*84e33947SAndroid Build Coastguard Worker 
24*84e33947SAndroid Build Coastguard Worker #include "chpp/log.h"
25*84e33947SAndroid Build Coastguard Worker #include "chpp/macros.h"
26*84e33947SAndroid Build Coastguard Worker #include "chpp/notifier.h"
27*84e33947SAndroid Build Coastguard Worker #include "chpp/platform/platform_link.h"
28*84e33947SAndroid Build Coastguard Worker #include "chpp/transport.h"
29*84e33947SAndroid Build Coastguard Worker 
30*84e33947SAndroid Build Coastguard Worker // The set of signals to use for the linkSendThread.
31*84e33947SAndroid Build Coastguard Worker #define SIGNAL_EXIT UINT32_C(1 << 0)
32*84e33947SAndroid Build Coastguard Worker #define SIGNAL_DATA UINT32_C(1 << 1)
33*84e33947SAndroid Build Coastguard Worker #define SIGNAL_DATA_RX UINT32_C(1 << 2)
34*84e33947SAndroid Build Coastguard Worker 
35*84e33947SAndroid Build Coastguard Worker struct ChppNotifier gCycleSendThreadNotifier;
36*84e33947SAndroid Build Coastguard Worker 
cycleSendThread(void)37*84e33947SAndroid Build Coastguard Worker void cycleSendThread(void) {
38*84e33947SAndroid Build Coastguard Worker   chppNotifierSignal(&gCycleSendThreadNotifier, 1);
39*84e33947SAndroid Build Coastguard Worker }
40*84e33947SAndroid Build Coastguard Worker 
41*84e33947SAndroid Build Coastguard Worker /**
42*84e33947SAndroid Build Coastguard Worker  * This thread is used to "send" TX data to the remote endpoint. The remote
43*84e33947SAndroid Build Coastguard Worker  * endpoint is defined by the ChppTransportState pointer, so a loopback link
44*84e33947SAndroid Build Coastguard Worker  * with a single CHPP instance can be supported.
45*84e33947SAndroid Build Coastguard Worker  */
linkSendThread(void * linkContext)46*84e33947SAndroid Build Coastguard Worker static void *linkSendThread(void *linkContext) {
47*84e33947SAndroid Build Coastguard Worker   struct ChppLinuxLinkState *context =
48*84e33947SAndroid Build Coastguard Worker       (struct ChppLinuxLinkState *)(linkContext);
49*84e33947SAndroid Build Coastguard Worker   while (true) {
50*84e33947SAndroid Build Coastguard Worker     if (context->manualSendCycle) {
51*84e33947SAndroid Build Coastguard Worker       chppNotifierWait(&gCycleSendThreadNotifier);
52*84e33947SAndroid Build Coastguard Worker     }
53*84e33947SAndroid Build Coastguard Worker     uint32_t signal = chppNotifierTimedWait(&context->notifier, CHPP_TIME_MAX);
54*84e33947SAndroid Build Coastguard Worker 
55*84e33947SAndroid Build Coastguard Worker     if (signal & SIGNAL_EXIT) {
56*84e33947SAndroid Build Coastguard Worker       break;
57*84e33947SAndroid Build Coastguard Worker     }
58*84e33947SAndroid Build Coastguard Worker 
59*84e33947SAndroid Build Coastguard Worker     if (signal & SIGNAL_DATA) {
60*84e33947SAndroid Build Coastguard Worker       enum ChppLinkErrorCode error;
61*84e33947SAndroid Build Coastguard Worker 
62*84e33947SAndroid Build Coastguard Worker       chppMutexLock(&context->mutex);
63*84e33947SAndroid Build Coastguard Worker 
64*84e33947SAndroid Build Coastguard Worker       if (context->remoteLinkState == NULL) {
65*84e33947SAndroid Build Coastguard Worker         CHPP_LOGW("remoteLinkState is NULL");
66*84e33947SAndroid Build Coastguard Worker         error = CHPP_LINK_ERROR_NONE_SENT;
67*84e33947SAndroid Build Coastguard Worker 
68*84e33947SAndroid Build Coastguard Worker       } else if (!context->linkEstablished) {
69*84e33947SAndroid Build Coastguard Worker         CHPP_LOGE("No (fake) link");
70*84e33947SAndroid Build Coastguard Worker         error = CHPP_LINK_ERROR_NO_LINK;
71*84e33947SAndroid Build Coastguard Worker 
72*84e33947SAndroid Build Coastguard Worker       } else {
73*84e33947SAndroid Build Coastguard Worker         // Use notifiers only when there are 2 different link layers (i.e. no
74*84e33947SAndroid Build Coastguard Worker         // loopback). Otherwise call chppRxDataCb directly.
75*84e33947SAndroid Build Coastguard Worker         if (context->rxInRemoteEndpointWorker &&
76*84e33947SAndroid Build Coastguard Worker             context->remoteLinkState != context) {
77*84e33947SAndroid Build Coastguard Worker           chppNotifierSignal(&context->remoteLinkState->notifier,
78*84e33947SAndroid Build Coastguard Worker                              SIGNAL_DATA_RX);
79*84e33947SAndroid Build Coastguard Worker 
80*84e33947SAndroid Build Coastguard Worker           // Wait for the RX thread to consume the buffer before we can modify
81*84e33947SAndroid Build Coastguard Worker           // it.
82*84e33947SAndroid Build Coastguard Worker           chppNotifierTimedWait(&context->rxNotifier, CHPP_TIME_MAX);
83*84e33947SAndroid Build Coastguard Worker         } else if (!chppRxDataCb(context->remoteLinkState->transportContext,
84*84e33947SAndroid Build Coastguard Worker                                  context->buf, context->bufLen)) {
85*84e33947SAndroid Build Coastguard Worker           CHPP_LOGW("chppRxDataCb return state!=preamble (packet incomplete)");
86*84e33947SAndroid Build Coastguard Worker         }
87*84e33947SAndroid Build Coastguard Worker         error = CHPP_LINK_ERROR_NONE_SENT;
88*84e33947SAndroid Build Coastguard Worker       }
89*84e33947SAndroid Build Coastguard Worker 
90*84e33947SAndroid Build Coastguard Worker       context->bufLen = 0;
91*84e33947SAndroid Build Coastguard Worker       chppLinkSendDoneCb(context->transportContext, error);
92*84e33947SAndroid Build Coastguard Worker 
93*84e33947SAndroid Build Coastguard Worker       chppMutexUnlock(&context->mutex);
94*84e33947SAndroid Build Coastguard Worker     }
95*84e33947SAndroid Build Coastguard Worker 
96*84e33947SAndroid Build Coastguard Worker     if (signal & SIGNAL_DATA_RX) {
97*84e33947SAndroid Build Coastguard Worker       CHPP_NOT_NULL(context->transportContext);
98*84e33947SAndroid Build Coastguard Worker       CHPP_NOT_NULL(context->remoteLinkState);
99*84e33947SAndroid Build Coastguard Worker       // Process RX data which are the TX data from the remote link.
100*84e33947SAndroid Build Coastguard Worker       chppRxDataCb(context->transportContext, context->remoteLinkState->buf,
101*84e33947SAndroid Build Coastguard Worker                    context->remoteLinkState->bufLen);
102*84e33947SAndroid Build Coastguard Worker       // Unblock the TX thread when the buffer has been consumed.
103*84e33947SAndroid Build Coastguard Worker       chppNotifierSignal(&context->remoteLinkState->rxNotifier, 0x01);
104*84e33947SAndroid Build Coastguard Worker     }
105*84e33947SAndroid Build Coastguard Worker   }
106*84e33947SAndroid Build Coastguard Worker 
107*84e33947SAndroid Build Coastguard Worker   return NULL;
108*84e33947SAndroid Build Coastguard Worker }
109*84e33947SAndroid Build Coastguard Worker 
init(void * linkContext,struct ChppTransportState * transportContext)110*84e33947SAndroid Build Coastguard Worker static void init(void *linkContext,
111*84e33947SAndroid Build Coastguard Worker                  struct ChppTransportState *transportContext) {
112*84e33947SAndroid Build Coastguard Worker   struct ChppLinuxLinkState *context =
113*84e33947SAndroid Build Coastguard Worker       (struct ChppLinuxLinkState *)(linkContext);
114*84e33947SAndroid Build Coastguard Worker   context->bufLen = 0;
115*84e33947SAndroid Build Coastguard Worker   context->transportContext = transportContext;
116*84e33947SAndroid Build Coastguard Worker   chppMutexInit(&context->mutex);
117*84e33947SAndroid Build Coastguard Worker   chppNotifierInit(&context->notifier);
118*84e33947SAndroid Build Coastguard Worker   chppNotifierInit(&context->rxNotifier);
119*84e33947SAndroid Build Coastguard Worker   chppNotifierInit(&gCycleSendThreadNotifier);
120*84e33947SAndroid Build Coastguard Worker   pthread_create(&context->linkSendThread, NULL /* attr */, linkSendThread,
121*84e33947SAndroid Build Coastguard Worker                  context);
122*84e33947SAndroid Build Coastguard Worker   if (context->linkThreadName != NULL) {
123*84e33947SAndroid Build Coastguard Worker     pthread_setname_np(context->linkSendThread, context->linkThreadName);
124*84e33947SAndroid Build Coastguard Worker   }
125*84e33947SAndroid Build Coastguard Worker }
126*84e33947SAndroid Build Coastguard Worker 
deinit(void * linkContext)127*84e33947SAndroid Build Coastguard Worker static void deinit(void *linkContext) {
128*84e33947SAndroid Build Coastguard Worker   struct ChppLinuxLinkState *context =
129*84e33947SAndroid Build Coastguard Worker       (struct ChppLinuxLinkState *)(linkContext);
130*84e33947SAndroid Build Coastguard Worker   context->bufLen = 0;
131*84e33947SAndroid Build Coastguard Worker   chppNotifierSignal(&context->notifier, SIGNAL_EXIT);
132*84e33947SAndroid Build Coastguard Worker   if (context->manualSendCycle) {
133*84e33947SAndroid Build Coastguard Worker     // Unblock the send thread so it exits.
134*84e33947SAndroid Build Coastguard Worker     cycleSendThread();
135*84e33947SAndroid Build Coastguard Worker   }
136*84e33947SAndroid Build Coastguard Worker   pthread_join(context->linkSendThread, NULL /* retval */);
137*84e33947SAndroid Build Coastguard Worker   chppNotifierDeinit(&context->notifier);
138*84e33947SAndroid Build Coastguard Worker   chppNotifierDeinit(&context->rxNotifier);
139*84e33947SAndroid Build Coastguard Worker   chppNotifierDeinit(&gCycleSendThreadNotifier);
140*84e33947SAndroid Build Coastguard Worker   chppMutexDeinit(&context->mutex);
141*84e33947SAndroid Build Coastguard Worker }
142*84e33947SAndroid Build Coastguard Worker 
send(void * linkContext,size_t len)143*84e33947SAndroid Build Coastguard Worker static enum ChppLinkErrorCode send(void *linkContext, size_t len) {
144*84e33947SAndroid Build Coastguard Worker   struct ChppLinuxLinkState *context =
145*84e33947SAndroid Build Coastguard Worker       (struct ChppLinuxLinkState *)(linkContext);
146*84e33947SAndroid Build Coastguard Worker   bool success = false;
147*84e33947SAndroid Build Coastguard Worker   chppMutexLock(&context->mutex);
148*84e33947SAndroid Build Coastguard Worker   if (context->bufLen != 0) {
149*84e33947SAndroid Build Coastguard Worker     CHPP_LOGE("Failed to send data - link layer busy");
150*84e33947SAndroid Build Coastguard Worker   } else if (!context->isLinkActive) {
151*84e33947SAndroid Build Coastguard Worker     success = false;
152*84e33947SAndroid Build Coastguard Worker   } else {
153*84e33947SAndroid Build Coastguard Worker     success = true;
154*84e33947SAndroid Build Coastguard Worker     context->bufLen = len;
155*84e33947SAndroid Build Coastguard Worker   }
156*84e33947SAndroid Build Coastguard Worker   chppMutexUnlock(&context->mutex);
157*84e33947SAndroid Build Coastguard Worker 
158*84e33947SAndroid Build Coastguard Worker   if (success) {
159*84e33947SAndroid Build Coastguard Worker     chppNotifierSignal(&context->notifier, SIGNAL_DATA);
160*84e33947SAndroid Build Coastguard Worker   }
161*84e33947SAndroid Build Coastguard Worker 
162*84e33947SAndroid Build Coastguard Worker   return success ? CHPP_LINK_ERROR_NONE_QUEUED : CHPP_LINK_ERROR_BUSY;
163*84e33947SAndroid Build Coastguard Worker }
164*84e33947SAndroid Build Coastguard Worker 
doWork(void * linkContext,uint32_t signal)165*84e33947SAndroid Build Coastguard Worker static void doWork(void *linkContext, uint32_t signal) {
166*84e33947SAndroid Build Coastguard Worker   UNUSED_VAR(linkContext);
167*84e33947SAndroid Build Coastguard Worker   UNUSED_VAR(signal);
168*84e33947SAndroid Build Coastguard Worker }
169*84e33947SAndroid Build Coastguard Worker 
reset(void * linkContext)170*84e33947SAndroid Build Coastguard Worker static void reset(void *linkContext) {
171*84e33947SAndroid Build Coastguard Worker   struct ChppLinuxLinkState *context =
172*84e33947SAndroid Build Coastguard Worker       (struct ChppLinuxLinkState *)(linkContext);
173*84e33947SAndroid Build Coastguard Worker   deinit(context);
174*84e33947SAndroid Build Coastguard Worker   init(context, context->transportContext);
175*84e33947SAndroid Build Coastguard Worker }
176*84e33947SAndroid Build Coastguard Worker 
getConfig(void * linkContext)177*84e33947SAndroid Build Coastguard Worker static struct ChppLinkConfiguration getConfig(void *linkContext) {
178*84e33947SAndroid Build Coastguard Worker   UNUSED_VAR(linkContext);
179*84e33947SAndroid Build Coastguard Worker   const struct ChppLinkConfiguration config = {
180*84e33947SAndroid Build Coastguard Worker       .txBufferLen = CHPP_LINUX_LINK_TX_MTU_BYTES,
181*84e33947SAndroid Build Coastguard Worker       .rxBufferLen = CHPP_LINUX_LINK_RX_MTU_BYTES,
182*84e33947SAndroid Build Coastguard Worker   };
183*84e33947SAndroid Build Coastguard Worker   return config;
184*84e33947SAndroid Build Coastguard Worker }
185*84e33947SAndroid Build Coastguard Worker 
getTxBuffer(void * linkContext)186*84e33947SAndroid Build Coastguard Worker static uint8_t *getTxBuffer(void *linkContext) {
187*84e33947SAndroid Build Coastguard Worker   struct ChppLinuxLinkState *context =
188*84e33947SAndroid Build Coastguard Worker       (struct ChppLinuxLinkState *)(linkContext);
189*84e33947SAndroid Build Coastguard Worker   return &context->buf[0];
190*84e33947SAndroid Build Coastguard Worker }
191*84e33947SAndroid Build Coastguard Worker 
192*84e33947SAndroid Build Coastguard Worker const struct ChppLinkApi gLinuxLinkApi = {
193*84e33947SAndroid Build Coastguard Worker     .init = &init,
194*84e33947SAndroid Build Coastguard Worker     .deinit = &deinit,
195*84e33947SAndroid Build Coastguard Worker     .send = &send,
196*84e33947SAndroid Build Coastguard Worker     .doWork = &doWork,
197*84e33947SAndroid Build Coastguard Worker     .reset = &reset,
198*84e33947SAndroid Build Coastguard Worker     .getConfig = &getConfig,
199*84e33947SAndroid Build Coastguard Worker     .getTxBuffer = &getTxBuffer,
200*84e33947SAndroid Build Coastguard Worker };
201*84e33947SAndroid Build Coastguard Worker 
getLinuxLinkApi(void)202*84e33947SAndroid Build Coastguard Worker const struct ChppLinkApi *getLinuxLinkApi(void) {
203*84e33947SAndroid Build Coastguard Worker   return &gLinuxLinkApi;
204*84e33947SAndroid Build Coastguard Worker }
205