xref: /aosp_15_r20/external/libese/libese-teq1/teq1.c (revision 5c4dab75aa57366379dce576b1a9e082a44e2b3a)
1*5c4dab75SAndroid Build Coastguard Worker /*
2*5c4dab75SAndroid Build Coastguard Worker  * Copyright (C) 2017 The Android Open Source Project
3*5c4dab75SAndroid Build Coastguard Worker  *
4*5c4dab75SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*5c4dab75SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*5c4dab75SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*5c4dab75SAndroid Build Coastguard Worker  *
8*5c4dab75SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*5c4dab75SAndroid Build Coastguard Worker  *
10*5c4dab75SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*5c4dab75SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*5c4dab75SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*5c4dab75SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*5c4dab75SAndroid Build Coastguard Worker  * limitations under the License.
15*5c4dab75SAndroid Build Coastguard Worker  */
16*5c4dab75SAndroid Build Coastguard Worker 
17*5c4dab75SAndroid Build Coastguard Worker #include "include/ese/teq1.h"
18*5c4dab75SAndroid Build Coastguard Worker #include "../libese/include/ese/ese.h"
19*5c4dab75SAndroid Build Coastguard Worker #include "../libese/include/ese/log.h"
20*5c4dab75SAndroid Build Coastguard Worker 
21*5c4dab75SAndroid Build Coastguard Worker #include "teq1_private.h"
22*5c4dab75SAndroid Build Coastguard Worker 
teq1_rule_result_to_name(enum RuleResult result)23*5c4dab75SAndroid Build Coastguard Worker const char *teq1_rule_result_to_name(enum RuleResult result) {
24*5c4dab75SAndroid Build Coastguard Worker   switch (result) {
25*5c4dab75SAndroid Build Coastguard Worker   case kRuleResultComplete:
26*5c4dab75SAndroid Build Coastguard Worker     return "Complete";
27*5c4dab75SAndroid Build Coastguard Worker   case kRuleResultAbort:
28*5c4dab75SAndroid Build Coastguard Worker     return "Abort";
29*5c4dab75SAndroid Build Coastguard Worker   case kRuleResultContinue:
30*5c4dab75SAndroid Build Coastguard Worker     return "Continue";
31*5c4dab75SAndroid Build Coastguard Worker   case kRuleResultHardFail:
32*5c4dab75SAndroid Build Coastguard Worker     return "Hard failure";
33*5c4dab75SAndroid Build Coastguard Worker   case kRuleResultResetDevice:
34*5c4dab75SAndroid Build Coastguard Worker     return "Reset device";
35*5c4dab75SAndroid Build Coastguard Worker   case kRuleResultResetSession:
36*5c4dab75SAndroid Build Coastguard Worker     return "Reset session";
37*5c4dab75SAndroid Build Coastguard Worker   case kRuleResultRetransmit:
38*5c4dab75SAndroid Build Coastguard Worker     return "Retransmit";
39*5c4dab75SAndroid Build Coastguard Worker   case kRuleResultSingleShot:
40*5c4dab75SAndroid Build Coastguard Worker     return "Single shot";
41*5c4dab75SAndroid Build Coastguard Worker   };
42*5c4dab75SAndroid Build Coastguard Worker }
43*5c4dab75SAndroid Build Coastguard Worker 
teq1_pcb_to_name(uint8_t pcb)44*5c4dab75SAndroid Build Coastguard Worker const char *teq1_pcb_to_name(uint8_t pcb) {
45*5c4dab75SAndroid Build Coastguard Worker   switch (pcb) {
46*5c4dab75SAndroid Build Coastguard Worker   case I(0, 0):
47*5c4dab75SAndroid Build Coastguard Worker     return "I(0, 0)";
48*5c4dab75SAndroid Build Coastguard Worker   case I(0, 1):
49*5c4dab75SAndroid Build Coastguard Worker     return "I(0, 1)";
50*5c4dab75SAndroid Build Coastguard Worker   case I(1, 0):
51*5c4dab75SAndroid Build Coastguard Worker     return "I(1, 0)";
52*5c4dab75SAndroid Build Coastguard Worker   case I(1, 1):
53*5c4dab75SAndroid Build Coastguard Worker     return "I(1, 1)";
54*5c4dab75SAndroid Build Coastguard Worker   case R(0, 0, 0):
55*5c4dab75SAndroid Build Coastguard Worker     return "R(0, 0, 0)";
56*5c4dab75SAndroid Build Coastguard Worker   case R(0, 0, 1):
57*5c4dab75SAndroid Build Coastguard Worker     return "R(0, 0, 1)";
58*5c4dab75SAndroid Build Coastguard Worker   case R(0, 1, 0):
59*5c4dab75SAndroid Build Coastguard Worker     return "R(0, 1, 0)";
60*5c4dab75SAndroid Build Coastguard Worker   case R(0, 1, 1):
61*5c4dab75SAndroid Build Coastguard Worker     return "R(0, 1, 1)";
62*5c4dab75SAndroid Build Coastguard Worker   case R(1, 0, 0):
63*5c4dab75SAndroid Build Coastguard Worker     return "R(1, 0, 0)";
64*5c4dab75SAndroid Build Coastguard Worker   case R(1, 0, 1):
65*5c4dab75SAndroid Build Coastguard Worker     return "R(1, 0, 1)";
66*5c4dab75SAndroid Build Coastguard Worker   case R(1, 1, 0):
67*5c4dab75SAndroid Build Coastguard Worker     return "R(1, 1, 0)";
68*5c4dab75SAndroid Build Coastguard Worker   case R(1, 1, 1):
69*5c4dab75SAndroid Build Coastguard Worker     return "R(1, 1, 1)";
70*5c4dab75SAndroid Build Coastguard Worker   case S(RESYNC, REQUEST):
71*5c4dab75SAndroid Build Coastguard Worker     return "S(RESYNC, REQUEST)";
72*5c4dab75SAndroid Build Coastguard Worker   case S(RESYNC, RESPONSE):
73*5c4dab75SAndroid Build Coastguard Worker     return "S(RESYNC, RESPONSE)";
74*5c4dab75SAndroid Build Coastguard Worker   case S(IFS, REQUEST):
75*5c4dab75SAndroid Build Coastguard Worker     return "S(IFS, REQUEST)";
76*5c4dab75SAndroid Build Coastguard Worker   case S(IFS, RESPONSE):
77*5c4dab75SAndroid Build Coastguard Worker     return "S(IFS, RESPONSE)";
78*5c4dab75SAndroid Build Coastguard Worker   case S(ABORT, REQUEST):
79*5c4dab75SAndroid Build Coastguard Worker     return "S(ABORT, REQUEST)";
80*5c4dab75SAndroid Build Coastguard Worker   case S(ABORT, RESPONSE):
81*5c4dab75SAndroid Build Coastguard Worker     return "S(ABORT, RESPONSE)";
82*5c4dab75SAndroid Build Coastguard Worker   case S(WTX, REQUEST):
83*5c4dab75SAndroid Build Coastguard Worker     return "S(WTX, REQUEST)";
84*5c4dab75SAndroid Build Coastguard Worker   case S(WTX, RESPONSE):
85*5c4dab75SAndroid Build Coastguard Worker     return "S(WTX, RESPONSE)";
86*5c4dab75SAndroid Build Coastguard Worker   case 255:
87*5c4dab75SAndroid Build Coastguard Worker     return "INTERNAL-ERROR";
88*5c4dab75SAndroid Build Coastguard Worker   default:
89*5c4dab75SAndroid Build Coastguard Worker     return "???";
90*5c4dab75SAndroid Build Coastguard Worker   }
91*5c4dab75SAndroid Build Coastguard Worker }
92*5c4dab75SAndroid Build Coastguard Worker 
teq1_dump_buf(const char * prefix,const uint8_t * buf,uint32_t len)93*5c4dab75SAndroid Build Coastguard Worker void teq1_dump_buf(const char *prefix, const uint8_t *buf, uint32_t len) {
94*5c4dab75SAndroid Build Coastguard Worker   uint32_t recvd = 0;
95*5c4dab75SAndroid Build Coastguard Worker   for (recvd = 0; recvd < len; ++recvd)
96*5c4dab75SAndroid Build Coastguard Worker     ALOGV("%s[%u]: %.2X", prefix, recvd, buf[recvd]);
97*5c4dab75SAndroid Build Coastguard Worker }
98*5c4dab75SAndroid Build Coastguard Worker 
teq1_transmit(struct EseInterface * ese,const struct Teq1ProtocolOptions * opts,struct Teq1Frame * frame)99*5c4dab75SAndroid Build Coastguard Worker int teq1_transmit(struct EseInterface *ese,
100*5c4dab75SAndroid Build Coastguard Worker                   const struct Teq1ProtocolOptions *opts,
101*5c4dab75SAndroid Build Coastguard Worker                   struct Teq1Frame *frame) {
102*5c4dab75SAndroid Build Coastguard Worker   /* Set correct node address. */
103*5c4dab75SAndroid Build Coastguard Worker   frame->header.NAD = opts->node_address;
104*5c4dab75SAndroid Build Coastguard Worker 
105*5c4dab75SAndroid Build Coastguard Worker   /* Compute the LRC */
106*5c4dab75SAndroid Build Coastguard Worker   frame->INF[frame->header.LEN] = teq1_compute_LRC(frame);
107*5c4dab75SAndroid Build Coastguard Worker 
108*5c4dab75SAndroid Build Coastguard Worker   /*
109*5c4dab75SAndroid Build Coastguard Worker    * If the card does something weird, like expect an CRC/LRC based on a
110*5c4dab75SAndroid Build Coastguard Worker    * different header value, the preprocessing can handle it.
111*5c4dab75SAndroid Build Coastguard Worker    */
112*5c4dab75SAndroid Build Coastguard Worker   if (opts->preprocess) {
113*5c4dab75SAndroid Build Coastguard Worker     opts->preprocess(opts, frame, 1);
114*5c4dab75SAndroid Build Coastguard Worker   }
115*5c4dab75SAndroid Build Coastguard Worker 
116*5c4dab75SAndroid Build Coastguard Worker   /*
117*5c4dab75SAndroid Build Coastguard Worker    * Begins transmission and ignore errors.
118*5c4dab75SAndroid Build Coastguard Worker    * Failed transmissions will result eventually in a resync then reset.
119*5c4dab75SAndroid Build Coastguard Worker    */
120*5c4dab75SAndroid Build Coastguard Worker   teq1_trace_transmit(frame->header.PCB, frame->header.LEN);
121*5c4dab75SAndroid Build Coastguard Worker   teq1_dump_transmit(frame->val, sizeof(frame->header) + frame->header.LEN + 1);
122*5c4dab75SAndroid Build Coastguard Worker   ese->ops->hw_transmit(ese, frame->val,
123*5c4dab75SAndroid Build Coastguard Worker                         sizeof(frame->header) + frame->header.LEN + 1, 1);
124*5c4dab75SAndroid Build Coastguard Worker   /*
125*5c4dab75SAndroid Build Coastguard Worker    * Even though in practice any WTX BWT extension starts when the above
126*5c4dab75SAndroid Build Coastguard Worker    * transmit ends, it is easier to implement it in the polling timeout of
127*5c4dab75SAndroid Build Coastguard Worker    * receive.
128*5c4dab75SAndroid Build Coastguard Worker    */
129*5c4dab75SAndroid Build Coastguard Worker   return 0;
130*5c4dab75SAndroid Build Coastguard Worker }
131*5c4dab75SAndroid Build Coastguard Worker 
teq1_receive(struct EseInterface * ese,const struct Teq1ProtocolOptions * opts,float timeout,struct Teq1Frame * frame)132*5c4dab75SAndroid Build Coastguard Worker int teq1_receive(struct EseInterface *ese,
133*5c4dab75SAndroid Build Coastguard Worker                  const struct Teq1ProtocolOptions *opts, float timeout,
134*5c4dab75SAndroid Build Coastguard Worker                  struct Teq1Frame *frame) {
135*5c4dab75SAndroid Build Coastguard Worker   /* Poll the bus until we see the start of frame indicator, the interface NAD.
136*5c4dab75SAndroid Build Coastguard Worker    */
137*5c4dab75SAndroid Build Coastguard Worker   int bytes_consumed = ese->ops->poll(ese, opts->host_address, timeout, 0);
138*5c4dab75SAndroid Build Coastguard Worker   if (bytes_consumed < 0 || bytes_consumed > 1) {
139*5c4dab75SAndroid Build Coastguard Worker     /* Timed out or comm error. */
140*5c4dab75SAndroid Build Coastguard Worker     ALOGV("%s: comm error: %d", __func__, bytes_consumed);
141*5c4dab75SAndroid Build Coastguard Worker     return -1;
142*5c4dab75SAndroid Build Coastguard Worker   }
143*5c4dab75SAndroid Build Coastguard Worker   /* We polled for the NAD above -- if it was consumed, set it here. */
144*5c4dab75SAndroid Build Coastguard Worker   if (bytes_consumed) {
145*5c4dab75SAndroid Build Coastguard Worker     frame->header.NAD = opts->host_address;
146*5c4dab75SAndroid Build Coastguard Worker   }
147*5c4dab75SAndroid Build Coastguard Worker   /* Get the remainder of the header, but keep the line &open. */
148*5c4dab75SAndroid Build Coastguard Worker   ese->ops->hw_receive(ese, (uint8_t *)(&frame->header.NAD + bytes_consumed),
149*5c4dab75SAndroid Build Coastguard Worker                        sizeof(frame->header) - bytes_consumed, 0);
150*5c4dab75SAndroid Build Coastguard Worker   teq1_dump_receive((uint8_t *)(&frame->header.NAD + bytes_consumed),
151*5c4dab75SAndroid Build Coastguard Worker                     sizeof(frame->header) - bytes_consumed);
152*5c4dab75SAndroid Build Coastguard Worker   if (frame->header.LEN == 255) {
153*5c4dab75SAndroid Build Coastguard Worker     ALOGV("received invalid LEN of 255");
154*5c4dab75SAndroid Build Coastguard Worker     /* Close the receive window and return failure. */
155*5c4dab75SAndroid Build Coastguard Worker     ese->ops->hw_receive(ese, NULL, 0, 1);
156*5c4dab75SAndroid Build Coastguard Worker     return -1;
157*5c4dab75SAndroid Build Coastguard Worker   }
158*5c4dab75SAndroid Build Coastguard Worker   /*
159*5c4dab75SAndroid Build Coastguard Worker    * Get the data and the first byte of CRC data.
160*5c4dab75SAndroid Build Coastguard Worker    * Note, CRC support is not implemented. Only a single LRC byte is expected.
161*5c4dab75SAndroid Build Coastguard Worker    */
162*5c4dab75SAndroid Build Coastguard Worker   ese->ops->hw_receive(ese, (uint8_t *)(&(frame->INF[0])),
163*5c4dab75SAndroid Build Coastguard Worker                        frame->header.LEN + 1, 1);
164*5c4dab75SAndroid Build Coastguard Worker   teq1_dump_receive((uint8_t *)(&(frame->INF[0])), frame->header.LEN + 1);
165*5c4dab75SAndroid Build Coastguard Worker   teq1_trace_receive(frame->header.PCB, frame->header.LEN);
166*5c4dab75SAndroid Build Coastguard Worker 
167*5c4dab75SAndroid Build Coastguard Worker   /*
168*5c4dab75SAndroid Build Coastguard Worker    * If the card does something weird, like expect an CRC/LRC based on a
169*5c4dab75SAndroid Build Coastguard Worker    * different
170*5c4dab75SAndroid Build Coastguard Worker    * header value, the preprocessing should fix up here prior to the LRC check.
171*5c4dab75SAndroid Build Coastguard Worker    */
172*5c4dab75SAndroid Build Coastguard Worker   if (opts->preprocess) {
173*5c4dab75SAndroid Build Coastguard Worker     opts->preprocess(opts, frame, 0);
174*5c4dab75SAndroid Build Coastguard Worker   }
175*5c4dab75SAndroid Build Coastguard Worker 
176*5c4dab75SAndroid Build Coastguard Worker   /* LRC and other protocol goodness checks are not done here. */
177*5c4dab75SAndroid Build Coastguard Worker   return frame->header.LEN; /* Return data bytes read. */
178*5c4dab75SAndroid Build Coastguard Worker }
179*5c4dab75SAndroid Build Coastguard Worker 
teq1_fill_info_block(struct Teq1State * state,struct Teq1Frame * frame)180*5c4dab75SAndroid Build Coastguard Worker uint8_t teq1_fill_info_block(struct Teq1State *state, struct Teq1Frame *frame) {
181*5c4dab75SAndroid Build Coastguard Worker   uint32_t inf_len = INF_LEN;
182*5c4dab75SAndroid Build Coastguard Worker   if (state->ifs < inf_len) {
183*5c4dab75SAndroid Build Coastguard Worker     inf_len = state->ifs;
184*5c4dab75SAndroid Build Coastguard Worker   }
185*5c4dab75SAndroid Build Coastguard Worker   switch (bs_get(PCB.type, frame->header.PCB)) {
186*5c4dab75SAndroid Build Coastguard Worker   case kPcbTypeInfo0:
187*5c4dab75SAndroid Build Coastguard Worker   case kPcbTypeInfo1: {
188*5c4dab75SAndroid Build Coastguard Worker     uint32_t len = state->app_data.tx_total;
189*5c4dab75SAndroid Build Coastguard Worker     uint32_t copied = 0;
190*5c4dab75SAndroid Build Coastguard Worker     if (len > inf_len) {
191*5c4dab75SAndroid Build Coastguard Worker       len = inf_len;
192*5c4dab75SAndroid Build Coastguard Worker     }
193*5c4dab75SAndroid Build Coastguard Worker     copied = ese_sg_to_buf(state->app_data.tx, state->app_data.tx_count,
194*5c4dab75SAndroid Build Coastguard Worker                            state->app_data.tx_offset, len, frame->INF);
195*5c4dab75SAndroid Build Coastguard Worker     if (copied != len) {
196*5c4dab75SAndroid Build Coastguard Worker       ALOGE("Failed to copy %x bytes of app data for transmission",
197*5c4dab75SAndroid Build Coastguard Worker             frame->header.LEN);
198*5c4dab75SAndroid Build Coastguard Worker       /* TODO(wad): This return code is largely ignored. Is the precondition
199*5c4dab75SAndroid Build Coastguard Worker        * checking elsewhere enough? */
200*5c4dab75SAndroid Build Coastguard Worker       return 255;
201*5c4dab75SAndroid Build Coastguard Worker     }
202*5c4dab75SAndroid Build Coastguard Worker     frame->header.LEN = (len & 0xff);
203*5c4dab75SAndroid Build Coastguard Worker     ALOGV("Copying %x bytes of app data for transmission", frame->header.LEN);
204*5c4dab75SAndroid Build Coastguard Worker     /* Incrementing here means the caller MUST handle retransmit with prepared
205*5c4dab75SAndroid Build Coastguard Worker      * data. */
206*5c4dab75SAndroid Build Coastguard Worker     state->app_data.tx_offset += copied;
207*5c4dab75SAndroid Build Coastguard Worker     state->app_data.tx_total -= copied;
208*5c4dab75SAndroid Build Coastguard Worker     /* Perform chained transmission if needed. */
209*5c4dab75SAndroid Build Coastguard Worker     bs_assign(&frame->header.PCB, PCB.I.more_data, 0);
210*5c4dab75SAndroid Build Coastguard Worker     if (state->app_data.tx_total > 0) {
211*5c4dab75SAndroid Build Coastguard Worker       frame->header.PCB |= bs_mask(PCB.I.more_data, 1);
212*5c4dab75SAndroid Build Coastguard Worker     }
213*5c4dab75SAndroid Build Coastguard Worker     return len;
214*5c4dab75SAndroid Build Coastguard Worker   }
215*5c4dab75SAndroid Build Coastguard Worker   case kPcbTypeSupervisory:
216*5c4dab75SAndroid Build Coastguard Worker   case kPcbTypeReceiveReady:
217*5c4dab75SAndroid Build Coastguard Worker   default:
218*5c4dab75SAndroid Build Coastguard Worker     break;
219*5c4dab75SAndroid Build Coastguard Worker   }
220*5c4dab75SAndroid Build Coastguard Worker   return 255; /* Invalid block type. */
221*5c4dab75SAndroid Build Coastguard Worker }
222*5c4dab75SAndroid Build Coastguard Worker 
teq1_get_app_data(struct Teq1State * state,const struct Teq1Frame * frame)223*5c4dab75SAndroid Build Coastguard Worker void teq1_get_app_data(struct Teq1State *state, const struct Teq1Frame *frame) {
224*5c4dab75SAndroid Build Coastguard Worker   switch (bs_get(PCB.type, frame->header.PCB)) {
225*5c4dab75SAndroid Build Coastguard Worker   case kPcbTypeInfo0:
226*5c4dab75SAndroid Build Coastguard Worker   case kPcbTypeInfo1: {
227*5c4dab75SAndroid Build Coastguard Worker     uint32_t len = frame->header.LEN;
228*5c4dab75SAndroid Build Coastguard Worker     /* TODO(wad): Some data will be left on the table. Should this error out? */
229*5c4dab75SAndroid Build Coastguard Worker     if (len > state->app_data.rx_total) {
230*5c4dab75SAndroid Build Coastguard Worker       len = state->app_data.rx_total;
231*5c4dab75SAndroid Build Coastguard Worker     }
232*5c4dab75SAndroid Build Coastguard Worker     ese_sg_from_buf(state->app_data.rx, state->app_data.rx_count,
233*5c4dab75SAndroid Build Coastguard Worker                     state->app_data.rx_offset, len, frame->INF);
234*5c4dab75SAndroid Build Coastguard Worker     /* The original caller must retain the starting pointer to determine
235*5c4dab75SAndroid Build Coastguard Worker      * actual available data.
236*5c4dab75SAndroid Build Coastguard Worker      */
237*5c4dab75SAndroid Build Coastguard Worker     state->app_data.rx_total -= len;
238*5c4dab75SAndroid Build Coastguard Worker     state->app_data.rx_offset += len;
239*5c4dab75SAndroid Build Coastguard Worker     return;
240*5c4dab75SAndroid Build Coastguard Worker   }
241*5c4dab75SAndroid Build Coastguard Worker   case kPcbTypeReceiveReady:
242*5c4dab75SAndroid Build Coastguard Worker   case kPcbTypeSupervisory:
243*5c4dab75SAndroid Build Coastguard Worker   default:
244*5c4dab75SAndroid Build Coastguard Worker     break;
245*5c4dab75SAndroid Build Coastguard Worker   }
246*5c4dab75SAndroid Build Coastguard Worker   return;
247*5c4dab75SAndroid Build Coastguard Worker }
248*5c4dab75SAndroid Build Coastguard Worker 
249*5c4dab75SAndroid Build Coastguard Worker /* Returns an R(0) frame with error bits set. */
teq1_frame_error_check(struct Teq1State * state,struct Teq1Frame * tx_frame,struct Teq1Frame * rx_frame)250*5c4dab75SAndroid Build Coastguard Worker uint8_t teq1_frame_error_check(struct Teq1State *state,
251*5c4dab75SAndroid Build Coastguard Worker                                struct Teq1Frame *tx_frame,
252*5c4dab75SAndroid Build Coastguard Worker                                struct Teq1Frame *rx_frame) {
253*5c4dab75SAndroid Build Coastguard Worker   uint8_t lrc = 0;
254*5c4dab75SAndroid Build Coastguard Worker   int chained = 0;
255*5c4dab75SAndroid Build Coastguard Worker   if (rx_frame->header.PCB == 255) {
256*5c4dab75SAndroid Build Coastguard Worker     return R(0, 1, 0); /* Other error */
257*5c4dab75SAndroid Build Coastguard Worker   }
258*5c4dab75SAndroid Build Coastguard Worker 
259*5c4dab75SAndroid Build Coastguard Worker   lrc = teq1_compute_LRC(rx_frame);
260*5c4dab75SAndroid Build Coastguard Worker   if (rx_frame->INF[rx_frame->header.LEN] != lrc) {
261*5c4dab75SAndroid Build Coastguard Worker     ALOGE("Invalid LRC %x instead of %x", rx_frame->INF[rx_frame->header.LEN],
262*5c4dab75SAndroid Build Coastguard Worker           lrc);
263*5c4dab75SAndroid Build Coastguard Worker     return R(0, 0, 1); /* Parity error */
264*5c4dab75SAndroid Build Coastguard Worker   }
265*5c4dab75SAndroid Build Coastguard Worker 
266*5c4dab75SAndroid Build Coastguard Worker   /* Check if we were chained and increment the last sent sequence. */
267*5c4dab75SAndroid Build Coastguard Worker   switch (bs_get(PCB.type, tx_frame->header.PCB)) {
268*5c4dab75SAndroid Build Coastguard Worker   case kPcbTypeInfo0:
269*5c4dab75SAndroid Build Coastguard Worker   case kPcbTypeInfo1:
270*5c4dab75SAndroid Build Coastguard Worker     chained = bs_get(PCB.I.more_data, tx_frame->header.PCB);
271*5c4dab75SAndroid Build Coastguard Worker     state->card_state->seq.interface =
272*5c4dab75SAndroid Build Coastguard Worker         bs_get(PCB.I.send_seq, tx_frame->header.PCB);
273*5c4dab75SAndroid Build Coastguard Worker   }
274*5c4dab75SAndroid Build Coastguard Worker 
275*5c4dab75SAndroid Build Coastguard Worker   /* Check if we've gone down an easy to catch error hole. The rest will turn up
276*5c4dab75SAndroid Build Coastguard Worker    * on the
277*5c4dab75SAndroid Build Coastguard Worker    * txrx switch.
278*5c4dab75SAndroid Build Coastguard Worker    */
279*5c4dab75SAndroid Build Coastguard Worker   switch (bs_get(PCB.type, rx_frame->header.PCB)) {
280*5c4dab75SAndroid Build Coastguard Worker   case kPcbTypeSupervisory:
281*5c4dab75SAndroid Build Coastguard Worker     if (rx_frame->header.PCB != S(RESYNC, RESPONSE) &&
282*5c4dab75SAndroid Build Coastguard Worker         rx_frame->header.LEN != 1) {
283*5c4dab75SAndroid Build Coastguard Worker       ALOGE("Invalid supervisory RX frame.");
284*5c4dab75SAndroid Build Coastguard Worker       return R(0, 1, 0);
285*5c4dab75SAndroid Build Coastguard Worker     }
286*5c4dab75SAndroid Build Coastguard Worker     break;
287*5c4dab75SAndroid Build Coastguard Worker   case kPcbTypeReceiveReady:
288*5c4dab75SAndroid Build Coastguard Worker     if (rx_frame->header.LEN != 0) {
289*5c4dab75SAndroid Build Coastguard Worker       ALOGE("Invalid ReceiveReady RX frame.");
290*5c4dab75SAndroid Build Coastguard Worker       return R(0, 1, 0);
291*5c4dab75SAndroid Build Coastguard Worker     }
292*5c4dab75SAndroid Build Coastguard Worker     break;
293*5c4dab75SAndroid Build Coastguard Worker   case kPcbTypeInfo0:
294*5c4dab75SAndroid Build Coastguard Worker   case kPcbTypeInfo1:
295*5c4dab75SAndroid Build Coastguard Worker     /* I-blocks must always alternate for each endpoint. */
296*5c4dab75SAndroid Build Coastguard Worker     if ((bs_get(PCB.I.send_seq, rx_frame->header.PCB)) ==
297*5c4dab75SAndroid Build Coastguard Worker         state->card_state->seq.card) {
298*5c4dab75SAndroid Build Coastguard Worker       ALOGW("Got seq %d expected %d",
299*5c4dab75SAndroid Build Coastguard Worker             bs_get(PCB.I.send_seq, rx_frame->header.PCB),
300*5c4dab75SAndroid Build Coastguard Worker             state->card_state->seq.card);
301*5c4dab75SAndroid Build Coastguard Worker       ALOGE("Invalid Info RX frame.");
302*5c4dab75SAndroid Build Coastguard Worker       return R(0, 1, 0);
303*5c4dab75SAndroid Build Coastguard Worker     }
304*5c4dab75SAndroid Build Coastguard Worker     /* Update the card's last I-block seq. */
305*5c4dab75SAndroid Build Coastguard Worker     state->card_state->seq.card = bs_get(PCB.I.send_seq, rx_frame->header.PCB);
306*5c4dab75SAndroid Build Coastguard Worker   default:
307*5c4dab75SAndroid Build Coastguard Worker     break;
308*5c4dab75SAndroid Build Coastguard Worker   };
309*5c4dab75SAndroid Build Coastguard Worker   return 0;
310*5c4dab75SAndroid Build Coastguard Worker }
311*5c4dab75SAndroid Build Coastguard Worker 
teq1_rules(struct Teq1State * state,struct Teq1Frame * tx_frame,struct Teq1Frame * rx_frame,struct Teq1Frame * next_tx)312*5c4dab75SAndroid Build Coastguard Worker enum RuleResult teq1_rules(struct Teq1State *state, struct Teq1Frame *tx_frame,
313*5c4dab75SAndroid Build Coastguard Worker                            struct Teq1Frame *rx_frame,
314*5c4dab75SAndroid Build Coastguard Worker                            struct Teq1Frame *next_tx) {
315*5c4dab75SAndroid Build Coastguard Worker   /* Rule 1 is enforced by first call∴ Start with I(0,M). */
316*5c4dab75SAndroid Build Coastguard Worker   /* 0 = TX, 1 = RX */
317*5c4dab75SAndroid Build Coastguard Worker   /* msb = tx pcb, lsb = rx pcb */
318*5c4dab75SAndroid Build Coastguard Worker   /* BUG_ON(!rx_frame && !tx_frame && !next_tx); */
319*5c4dab75SAndroid Build Coastguard Worker   uint16_t txrx = TEQ1_RULE(tx_frame->header.PCB, rx_frame->header.PCB);
320*5c4dab75SAndroid Build Coastguard Worker   uint8_t R_err;
321*5c4dab75SAndroid Build Coastguard Worker 
322*5c4dab75SAndroid Build Coastguard Worker   while (1) {
323*5c4dab75SAndroid Build Coastguard Worker     /* Timeout errors come like invalid frames: 255. */
324*5c4dab75SAndroid Build Coastguard Worker     if ((R_err = teq1_frame_error_check(state, tx_frame, rx_frame)) != 0) {
325*5c4dab75SAndroid Build Coastguard Worker       ALOGW("incoming frame failed the error check");
326*5c4dab75SAndroid Build Coastguard Worker       state->last_error_message = "Invalid frame received";
327*5c4dab75SAndroid Build Coastguard Worker       /* Mark the frame as bad for our rule evaluation. */
328*5c4dab75SAndroid Build Coastguard Worker       txrx = TEQ1_RULE(tx_frame->header.PCB, 255);
329*5c4dab75SAndroid Build Coastguard Worker       state->errors++;
330*5c4dab75SAndroid Build Coastguard Worker       /* Rule 6.4 */
331*5c4dab75SAndroid Build Coastguard Worker       if (state->errors >= 6) {
332*5c4dab75SAndroid Build Coastguard Worker         return kRuleResultResetDevice;
333*5c4dab75SAndroid Build Coastguard Worker       }
334*5c4dab75SAndroid Build Coastguard Worker       /* Rule 7.4.2 */
335*5c4dab75SAndroid Build Coastguard Worker       if (state->errors >= 3) {
336*5c4dab75SAndroid Build Coastguard Worker         /* Rule 7.4.1: state should start with error count = 2 */
337*5c4dab75SAndroid Build Coastguard Worker         if (tx_frame->header.PCB != S(RESYNC, REQUEST)) {
338*5c4dab75SAndroid Build Coastguard Worker           next_tx->header.PCB = S(RESYNC, REQUEST);
339*5c4dab75SAndroid Build Coastguard Worker           return kRuleResultContinue;
340*5c4dab75SAndroid Build Coastguard Worker         }
341*5c4dab75SAndroid Build Coastguard Worker         return kRuleResultRetransmit;
342*5c4dab75SAndroid Build Coastguard Worker       }
343*5c4dab75SAndroid Build Coastguard Worker     }
344*5c4dab75SAndroid Build Coastguard Worker 
345*5c4dab75SAndroid Build Coastguard Worker     /* Specific matches */
346*5c4dab75SAndroid Build Coastguard Worker     switch (txrx) {
347*5c4dab75SAndroid Build Coastguard Worker     /*** Rule 2.1: I() -> I() ***/
348*5c4dab75SAndroid Build Coastguard Worker     /* Error check will determine if the card seq is right. */
349*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(0, 0), I(0, 0)):
350*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(0, 0), I(1, 0)):
351*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(1, 0), I(1, 0)):
352*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(1, 0), I(0, 0)):
353*5c4dab75SAndroid Build Coastguard Worker       /* Read app data & return. */
354*5c4dab75SAndroid Build Coastguard Worker       teq1_get_app_data(state, rx_frame);
355*5c4dab75SAndroid Build Coastguard Worker       return kRuleResultComplete;
356*5c4dab75SAndroid Build Coastguard Worker 
357*5c4dab75SAndroid Build Coastguard Worker     /* Card begins chained response. */
358*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(0, 0), I(0, 1)):
359*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(1, 0), I(1, 1)):
360*5c4dab75SAndroid Build Coastguard Worker       /* Prep R(N(S)) */
361*5c4dab75SAndroid Build Coastguard Worker       teq1_get_app_data(state, rx_frame);
362*5c4dab75SAndroid Build Coastguard Worker       next_tx->header.PCB =
363*5c4dab75SAndroid Build Coastguard Worker           TEQ1_R(!bs_get(PCB.I.send_seq, rx_frame->header.PCB), 0, 0);
364*5c4dab75SAndroid Build Coastguard Worker       next_tx->header.LEN = 0;
365*5c4dab75SAndroid Build Coastguard Worker       return kRuleResultContinue;
366*5c4dab75SAndroid Build Coastguard Worker 
367*5c4dab75SAndroid Build Coastguard Worker     /*** Rule 2.2, Rule 5: Chained transmission ***/
368*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(0, 1), R(1, 0, 0)):
369*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(1, 1), R(0, 0, 0)):
370*5c4dab75SAndroid Build Coastguard Worker       /* Send next block -- error-checking assures the R seq is our next seq. */
371*5c4dab75SAndroid Build Coastguard Worker       next_tx->header.PCB =
372*5c4dab75SAndroid Build Coastguard Worker           TEQ1_I(bs_get(PCB.R.next_seq, rx_frame->header.PCB), 0);
373*5c4dab75SAndroid Build Coastguard Worker       teq1_fill_info_block(state, next_tx); /* Sets M-bit and LEN. */
374*5c4dab75SAndroid Build Coastguard Worker       return kRuleResultContinue;
375*5c4dab75SAndroid Build Coastguard Worker 
376*5c4dab75SAndroid Build Coastguard Worker     /*** Rule 3 ***/
377*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(0, 0), S(WTX, REQUEST)):
378*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(1, 0), S(WTX, REQUEST)):
379*5c4dab75SAndroid Build Coastguard Worker       /* Note: Spec is unclear on if WTX can occur during chaining so we make it
380*5c4dab75SAndroid Build Coastguard Worker       an error for now.
381*5c4dab75SAndroid Build Coastguard Worker       case TEQ1_RULE(I(0, 1), S(WTX, REQUEST)):
382*5c4dab75SAndroid Build Coastguard Worker       case TEQ1_RULE(I(1, 1), S(WTX, REQUEST)):
383*5c4dab75SAndroid Build Coastguard Worker       */
384*5c4dab75SAndroid Build Coastguard Worker       /* Send S(WTX, RESPONSE) with same INF */
385*5c4dab75SAndroid Build Coastguard Worker       next_tx->header.PCB = S(WTX, RESPONSE);
386*5c4dab75SAndroid Build Coastguard Worker       next_tx->header.LEN = 1;
387*5c4dab75SAndroid Build Coastguard Worker       next_tx->INF[0] = rx_frame->INF[0];
388*5c4dab75SAndroid Build Coastguard Worker       state->wait_mult = rx_frame->INF[0];
389*5c4dab75SAndroid Build Coastguard Worker       /* Then wait BWT*INF[0] after transmission. */
390*5c4dab75SAndroid Build Coastguard Worker       return kRuleResultSingleShot; /* Send then call back in with same tx_frame
391*5c4dab75SAndroid Build Coastguard Worker                                        and new rx_frame. */
392*5c4dab75SAndroid Build Coastguard Worker 
393*5c4dab75SAndroid Build Coastguard Worker     /*** Rule 4 ***/
394*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(S(IFS, REQUEST), S(IFS, RESPONSE)):
395*5c4dab75SAndroid Build Coastguard Worker       /* XXX: Check INFs match. */
396*5c4dab75SAndroid Build Coastguard Worker       return kRuleResultComplete; /* This is treated as an unique operation. */
397*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(0, 0), S(IFS, REQUEST)):
398*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(0, 1), S(IFS, REQUEST)):
399*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(1, 0), S(IFS, REQUEST)):
400*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(1, 1), S(IFS, REQUEST)):
401*5c4dab75SAndroid Build Coastguard Worker     /* Don't support a IFS_REQUEST if we sent an error R-block. */
402*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(R(0, 0, 0), S(IFS, REQUEST)):
403*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(R(1, 0, 0), S(IFS, REQUEST)):
404*5c4dab75SAndroid Build Coastguard Worker       next_tx->header.PCB = S(IFS, RESPONSE);
405*5c4dab75SAndroid Build Coastguard Worker       next_tx->header.LEN = 1;
406*5c4dab75SAndroid Build Coastguard Worker       next_tx->INF[0] = rx_frame->INF[0];
407*5c4dab75SAndroid Build Coastguard Worker       state->ifs = rx_frame->INF[0];
408*5c4dab75SAndroid Build Coastguard Worker       return kRuleResultSingleShot;
409*5c4dab75SAndroid Build Coastguard Worker 
410*5c4dab75SAndroid Build Coastguard Worker     /*** Rule 5  (see Rule 2.2 for the chained-tx side. ) ***/
411*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(R(0, 0, 0), I(0, 0)):
412*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(R(1, 0, 0), I(1, 0)):
413*5c4dab75SAndroid Build Coastguard Worker       /* Chaining ended with terminal I-block. */
414*5c4dab75SAndroid Build Coastguard Worker       teq1_get_app_data(state, rx_frame);
415*5c4dab75SAndroid Build Coastguard Worker       return kRuleResultComplete;
416*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(R(0, 0, 0), I(0, 1)):
417*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(R(1, 0, 0), I(1, 1)):
418*5c4dab75SAndroid Build Coastguard Worker       /* Chaining continued; consume partial data and send R(N(S)) */
419*5c4dab75SAndroid Build Coastguard Worker       teq1_get_app_data(state, rx_frame);
420*5c4dab75SAndroid Build Coastguard Worker       /* The card seq bit will be tracked/validated earlier. */
421*5c4dab75SAndroid Build Coastguard Worker       next_tx->header.PCB =
422*5c4dab75SAndroid Build Coastguard Worker           TEQ1_R(!bs_get(PCB.I.send_seq, rx_frame->header.PCB), 0, 0);
423*5c4dab75SAndroid Build Coastguard Worker       return kRuleResultContinue;
424*5c4dab75SAndroid Build Coastguard Worker 
425*5c4dab75SAndroid Build Coastguard Worker     /* Rule 6: Interface can send a RESYNC */
426*5c4dab75SAndroid Build Coastguard Worker     /* Rule 6.1: timeout BWT right. No case here. */
427*5c4dab75SAndroid Build Coastguard Worker     /* Rule 6.2, 6.3 */
428*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(S(RESYNC, REQUEST), S(RESYNC, RESPONSE)):
429*5c4dab75SAndroid Build Coastguard Worker       /* Rule 6.5: indicates that the card should assume its prior
430*5c4dab75SAndroid Build Coastguard Worker        * block was lost _and_ the interface gets transmit privilege,
431*5c4dab75SAndroid Build Coastguard Worker        * so we just start fresh.
432*5c4dab75SAndroid Build Coastguard Worker        */
433*5c4dab75SAndroid Build Coastguard Worker       return kRuleResultResetSession; /* Start a new exchange (rule 6.3) */
434*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(S(RESYNC, REQUEST), 255):
435*5c4dab75SAndroid Build Coastguard Worker       /* Retransmit the same frame up to 3 times. */
436*5c4dab75SAndroid Build Coastguard Worker       return kRuleResultRetransmit;
437*5c4dab75SAndroid Build Coastguard Worker 
438*5c4dab75SAndroid Build Coastguard Worker     /* Rule 7.1, 7.5, 7.6 */
439*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(0, 0), 255):
440*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(1, 0), 255):
441*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(0, 1), 255):
442*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(1, 1), 255):
443*5c4dab75SAndroid Build Coastguard Worker       next_tx->header.PCB = R_err;
444*5c4dab75SAndroid Build Coastguard Worker       bs_assign(&next_tx->header.PCB, PCB.R.next_seq,
445*5c4dab75SAndroid Build Coastguard Worker                 bs_get(PCB.I.send_seq, tx_frame->header.PCB));
446*5c4dab75SAndroid Build Coastguard Worker       ALOGW("Rule 7.1,7.5,7.6: bad rx - sending error R: %x = %s",
447*5c4dab75SAndroid Build Coastguard Worker             next_tx->header.PCB, teq1_pcb_to_name(next_tx->header.PCB));
448*5c4dab75SAndroid Build Coastguard Worker       return kRuleResultSingleShot; /* So we still can retransmit the original.
449*5c4dab75SAndroid Build Coastguard Worker                                        */
450*5c4dab75SAndroid Build Coastguard Worker 
451*5c4dab75SAndroid Build Coastguard Worker     /* Caught in the error check. */
452*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(0, 0), R(1, 0, 0)):
453*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(0, 0), R(1, 0, 1)):
454*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(0, 0), R(1, 1, 0)):
455*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(0, 0), R(1, 1, 1)):
456*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(1, 0), R(0, 0, 0)):
457*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(1, 0), R(0, 0, 1)):
458*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(1, 0), R(0, 1, 0)):
459*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(1, 0), R(0, 1, 1)):
460*5c4dab75SAndroid Build Coastguard Worker       next_tx->header.PCB =
461*5c4dab75SAndroid Build Coastguard Worker           TEQ1_R(bs_get(PCB.I.send_seq, tx_frame->header.PCB), 0, 0);
462*5c4dab75SAndroid Build Coastguard Worker       ALOGW("Rule 7.1,7.5,7.6: weird rx - sending error R: %x = %s",
463*5c4dab75SAndroid Build Coastguard Worker             next_tx->header.PCB, teq1_pcb_to_name(next_tx->header.PCB));
464*5c4dab75SAndroid Build Coastguard Worker       return kRuleResultSingleShot;
465*5c4dab75SAndroid Build Coastguard Worker 
466*5c4dab75SAndroid Build Coastguard Worker     /* Rule 7.2: Retransmit the _same_ R-block. */
467*5c4dab75SAndroid Build Coastguard Worker     /* The remainder of this rule is implemented in the next switch. */
468*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(R(0, 0, 0), 255):
469*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(R(0, 0, 1), 255):
470*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(R(0, 1, 0), 255):
471*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(R(0, 1, 1), 255):
472*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(R(1, 0, 0), 255):
473*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(R(1, 0, 1), 255):
474*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(R(1, 1, 0), 255):
475*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(R(1, 1, 1), 255):
476*5c4dab75SAndroid Build Coastguard Worker       return kRuleResultRetransmit;
477*5c4dab75SAndroid Build Coastguard Worker 
478*5c4dab75SAndroid Build Coastguard Worker     /* Rule 7.3 request */
479*5c4dab75SAndroid Build Coastguard Worker     /* Note, 7.3 for transmission of S(*, RESPONSE) won't be seen because they
480*5c4dab75SAndroid Build Coastguard Worker      * are
481*5c4dab75SAndroid Build Coastguard Worker      * single shots.
482*5c4dab75SAndroid Build Coastguard Worker      * Instead, the invalid block will be handled as invalid for the prior TX.
483*5c4dab75SAndroid Build Coastguard Worker      * This should yield the correct R-block.
484*5c4dab75SAndroid Build Coastguard Worker      */
485*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(0, 0), R(0, 0, 0)):
486*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(0, 0), R(0, 0, 1)):
487*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(0, 0), R(0, 1, 0)):
488*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(0, 0), R(0, 1, 1)):
489*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(1, 0), R(1, 0, 0)):
490*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(1, 0), R(1, 1, 0)):
491*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(1, 0), R(1, 0, 1)):
492*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(1, 0), R(1, 1, 1)):
493*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(0, 1), R(0, 0, 0)):
494*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(0, 1), R(0, 1, 0)):
495*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(0, 1), R(0, 0, 1)):
496*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(0, 1), R(0, 1, 1)):
497*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(1, 1), R(1, 0, 0)):
498*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(1, 1), R(1, 1, 0)):
499*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(1, 1), R(1, 0, 1)):
500*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(1, 1), R(1, 1, 1)):
501*5c4dab75SAndroid Build Coastguard Worker       /* Retransmit I-block */
502*5c4dab75SAndroid Build Coastguard Worker       return kRuleResultRetransmit;
503*5c4dab75SAndroid Build Coastguard Worker 
504*5c4dab75SAndroid Build Coastguard Worker     /* Rule 8 is card only. */
505*5c4dab75SAndroid Build Coastguard Worker     /* Rule 9: aborting a chain.
506*5c4dab75SAndroid Build Coastguard Worker      * If a S(ABORT) is injected into this engine, then we may have sent an
507*5c4dab75SAndroid Build Coastguard Worker      * abort.
508*5c4dab75SAndroid Build Coastguard Worker      */
509*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(S(ABORT, REQUEST), S(ABORT, RESPONSE)):
510*5c4dab75SAndroid Build Coastguard Worker       /* No need to send back a R() because we want to keep transmit. */
511*5c4dab75SAndroid Build Coastguard Worker       return kRuleResultComplete; /* If we sent it, then we are complete. */
512*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(S(ABORT, RESPONSE), R(0, 0, 0)):
513*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(S(ABORT, RESPONSE), R(1, 0, 0)):
514*5c4dab75SAndroid Build Coastguard Worker       /* Card triggered abortion complete but we can resume sending. */
515*5c4dab75SAndroid Build Coastguard Worker       return kRuleResultAbort;
516*5c4dab75SAndroid Build Coastguard Worker     /* An abort request can interrupt a chain anywhere and could occur
517*5c4dab75SAndroid Build Coastguard Worker      * after a failure path too.
518*5c4dab75SAndroid Build Coastguard Worker      */
519*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(0, 1), S(ABORT, REQUEST)):
520*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(I(1, 1), S(ABORT, REQUEST)):
521*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(R(0, 0, 0), S(ABORT, REQUEST)):
522*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(R(0, 0, 1), S(ABORT, REQUEST)):
523*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(R(0, 1, 0), S(ABORT, REQUEST)):
524*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(R(0, 1, 1), S(ABORT, REQUEST)):
525*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(R(1, 0, 0), S(ABORT, REQUEST)):
526*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(R(1, 0, 1), S(ABORT, REQUEST)):
527*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(R(1, 1, 0), S(ABORT, REQUEST)):
528*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(R(1, 1, 1), S(ABORT, REQUEST)):
529*5c4dab75SAndroid Build Coastguard Worker       next_tx->header.PCB = S(ABORT, REQUEST);
530*5c4dab75SAndroid Build Coastguard Worker       return kRuleResultContinue; /* Takes over prior flow. */
531*5c4dab75SAndroid Build Coastguard Worker     case TEQ1_RULE(S(ABORT, RESPONSE), 255):
532*5c4dab75SAndroid Build Coastguard Worker       return kRuleResultRetransmit;
533*5c4dab75SAndroid Build Coastguard Worker     /* Note, other blocks should be caught below. */
534*5c4dab75SAndroid Build Coastguard Worker     default:
535*5c4dab75SAndroid Build Coastguard Worker       break;
536*5c4dab75SAndroid Build Coastguard Worker     }
537*5c4dab75SAndroid Build Coastguard Worker 
538*5c4dab75SAndroid Build Coastguard Worker     /* Note, only S(ABORT, REQUEST) and S(IFS, REQUEST) are supported
539*5c4dab75SAndroid Build Coastguard Worker      * for transmitting to the card. Others will result in error
540*5c4dab75SAndroid Build Coastguard Worker      * flows.
541*5c4dab75SAndroid Build Coastguard Worker      *
542*5c4dab75SAndroid Build Coastguard Worker      * For supported flows: If an operation was paused to
543*5c4dab75SAndroid Build Coastguard Worker      * send it, the caller may then switch to that state and resume.
544*5c4dab75SAndroid Build Coastguard Worker      */
545*5c4dab75SAndroid Build Coastguard Worker     if (rx_frame->header.PCB != 255) {
546*5c4dab75SAndroid Build Coastguard Worker       ALOGW("Unexpected frame. Marking error and re-evaluating.");
547*5c4dab75SAndroid Build Coastguard Worker       rx_frame->header.PCB = 255;
548*5c4dab75SAndroid Build Coastguard Worker       continue;
549*5c4dab75SAndroid Build Coastguard Worker     }
550*5c4dab75SAndroid Build Coastguard Worker 
551*5c4dab75SAndroid Build Coastguard Worker     return kRuleResultHardFail;
552*5c4dab75SAndroid Build Coastguard Worker   }
553*5c4dab75SAndroid Build Coastguard Worker }
554*5c4dab75SAndroid Build Coastguard Worker 
555*5c4dab75SAndroid Build Coastguard Worker /*
556*5c4dab75SAndroid Build Coastguard Worker  * TODO(wad): Consider splitting teq1_transcieve() into
557*5c4dab75SAndroid Build Coastguard Worker  *   teq1_transcieve_init() and teq1_transceive_process_one()
558*5c4dab75SAndroid Build Coastguard Worker  *   if testing becomes onerous given the loop below.
559*5c4dab75SAndroid Build Coastguard Worker  */
teq1_transceive(struct EseInterface * ese,const struct Teq1ProtocolOptions * opts,const struct EseSgBuffer * tx_bufs,uint8_t tx_segs,struct EseSgBuffer * rx_bufs,uint8_t rx_segs)560*5c4dab75SAndroid Build Coastguard Worker ESE_API uint32_t teq1_transceive(struct EseInterface *ese,
561*5c4dab75SAndroid Build Coastguard Worker                                  const struct Teq1ProtocolOptions *opts,
562*5c4dab75SAndroid Build Coastguard Worker                                  const struct EseSgBuffer *tx_bufs,
563*5c4dab75SAndroid Build Coastguard Worker                                  uint8_t tx_segs, struct EseSgBuffer *rx_bufs,
564*5c4dab75SAndroid Build Coastguard Worker                                  uint8_t rx_segs) {
565*5c4dab75SAndroid Build Coastguard Worker   struct Teq1Frame tx_frame[2];
566*5c4dab75SAndroid Build Coastguard Worker   struct Teq1Frame rx_frame;
567*5c4dab75SAndroid Build Coastguard Worker   struct Teq1Frame *tx = &tx_frame[0];
568*5c4dab75SAndroid Build Coastguard Worker   int active = 0;
569*5c4dab75SAndroid Build Coastguard Worker   bool was_reset = false;
570*5c4dab75SAndroid Build Coastguard Worker   bool needs_hw_reset = false;
571*5c4dab75SAndroid Build Coastguard Worker   int session_resets = 0;
572*5c4dab75SAndroid Build Coastguard Worker   bool done = false;
573*5c4dab75SAndroid Build Coastguard Worker   enum RuleResult result = kRuleResultComplete;
574*5c4dab75SAndroid Build Coastguard Worker   uint32_t rx_total = ese_sg_length(rx_bufs, rx_segs);
575*5c4dab75SAndroid Build Coastguard Worker   struct Teq1CardState *card_state = (struct Teq1CardState *)(&ese->pad[0]);
576*5c4dab75SAndroid Build Coastguard Worker   struct Teq1State init_state = TEQ1_INIT_STATE(
577*5c4dab75SAndroid Build Coastguard Worker       tx_bufs, tx_segs, ese_sg_length(tx_bufs, tx_segs), rx_bufs, rx_segs,
578*5c4dab75SAndroid Build Coastguard Worker       ese_sg_length(rx_bufs, rx_segs), card_state);
579*5c4dab75SAndroid Build Coastguard Worker   struct Teq1State state = TEQ1_INIT_STATE(
580*5c4dab75SAndroid Build Coastguard Worker       tx_bufs, tx_segs, ese_sg_length(tx_bufs, tx_segs), rx_bufs, rx_segs,
581*5c4dab75SAndroid Build Coastguard Worker       ese_sg_length(rx_bufs, rx_segs), card_state);
582*5c4dab75SAndroid Build Coastguard Worker 
583*5c4dab75SAndroid Build Coastguard Worker   _static_assert(TEQ1HEADER_SIZE == sizeof(struct Teq1Header),
584*5c4dab75SAndroid Build Coastguard Worker                  "Ensure compiler alignment/padding matches wire protocol.");
585*5c4dab75SAndroid Build Coastguard Worker   _static_assert(TEQ1FRAME_SIZE == sizeof(struct Teq1Frame),
586*5c4dab75SAndroid Build Coastguard Worker                  "Ensure compiler alignment/padding matches wire protocol.");
587*5c4dab75SAndroid Build Coastguard Worker 
588*5c4dab75SAndroid Build Coastguard Worker   /* First I-block is always I(0, M). After that, modulo 2. */
589*5c4dab75SAndroid Build Coastguard Worker   tx->header.PCB = TEQ1_I(!card_state->seq.interface, 0);
590*5c4dab75SAndroid Build Coastguard Worker   teq1_fill_info_block(&state, tx);
591*5c4dab75SAndroid Build Coastguard Worker 
592*5c4dab75SAndroid Build Coastguard Worker   teq1_trace_header();
593*5c4dab75SAndroid Build Coastguard Worker   while (!done) {
594*5c4dab75SAndroid Build Coastguard Worker     /* Populates the node address and LRC prior to attempting to transmit. */
595*5c4dab75SAndroid Build Coastguard Worker     teq1_transmit(ese, opts, tx);
596*5c4dab75SAndroid Build Coastguard Worker 
597*5c4dab75SAndroid Build Coastguard Worker     /* If tx was pointed to the inactive frame for a single shot, restore it
598*5c4dab75SAndroid Build Coastguard Worker      * now. */
599*5c4dab75SAndroid Build Coastguard Worker     tx = &tx_frame[active];
600*5c4dab75SAndroid Build Coastguard Worker 
601*5c4dab75SAndroid Build Coastguard Worker     /* Clear the RX frame. */
602*5c4dab75SAndroid Build Coastguard Worker     ese_memset(&rx_frame, 0xff, sizeof(rx_frame));
603*5c4dab75SAndroid Build Coastguard Worker 
604*5c4dab75SAndroid Build Coastguard Worker     /* -1 indicates a timeout or failure from hardware. */
605*5c4dab75SAndroid Build Coastguard Worker     if (teq1_receive(ese, opts, opts->bwt * (float)state.wait_mult, &rx_frame) <
606*5c4dab75SAndroid Build Coastguard Worker         0) {
607*5c4dab75SAndroid Build Coastguard Worker       /* TODO(wad): If the ese_error(ese) == 1, should this go ahead and fail?
608*5c4dab75SAndroid Build Coastguard Worker        */
609*5c4dab75SAndroid Build Coastguard Worker       /* Failures are considered invalid blocks in the rule engine below. */
610*5c4dab75SAndroid Build Coastguard Worker       rx_frame.header.PCB = 255;
611*5c4dab75SAndroid Build Coastguard Worker     }
612*5c4dab75SAndroid Build Coastguard Worker     /* Always reset |wait_mult| once we have calculated the timeout. */
613*5c4dab75SAndroid Build Coastguard Worker     state.wait_mult = 1;
614*5c4dab75SAndroid Build Coastguard Worker 
615*5c4dab75SAndroid Build Coastguard Worker     /* Clear the inactive frame header for use as |next_tx|. */
616*5c4dab75SAndroid Build Coastguard Worker     ese_memset(&tx_frame[!active].header, 0, sizeof(tx_frame[!active].header));
617*5c4dab75SAndroid Build Coastguard Worker 
618*5c4dab75SAndroid Build Coastguard Worker     result = teq1_rules(&state, tx, &rx_frame, &tx_frame[!active]);
619*5c4dab75SAndroid Build Coastguard Worker     ALOGV("[ %s ]", teq1_rule_result_to_name(result));
620*5c4dab75SAndroid Build Coastguard Worker     switch (result) {
621*5c4dab75SAndroid Build Coastguard Worker     case kRuleResultComplete:
622*5c4dab75SAndroid Build Coastguard Worker       done = true;
623*5c4dab75SAndroid Build Coastguard Worker       break;
624*5c4dab75SAndroid Build Coastguard Worker     case kRuleResultRetransmit:
625*5c4dab75SAndroid Build Coastguard Worker       /* TODO(wad) Find a clean way to move into teq1_rules(). */
626*5c4dab75SAndroid Build Coastguard Worker       if (state.retransmits++ < 3) {
627*5c4dab75SAndroid Build Coastguard Worker         continue;
628*5c4dab75SAndroid Build Coastguard Worker       }
629*5c4dab75SAndroid Build Coastguard Worker       ALOGE("More than three retransmits have occurred");
630*5c4dab75SAndroid Build Coastguard Worker       if (tx->header.PCB == S(RESYNC, REQUEST)) {
631*5c4dab75SAndroid Build Coastguard Worker         /* More than three RESYNC retranmits have occurred. */
632*5c4dab75SAndroid Build Coastguard Worker         ese_set_error(ese, kTeq1ErrorHardFail);
633*5c4dab75SAndroid Build Coastguard Worker         return 0;
634*5c4dab75SAndroid Build Coastguard Worker       }
635*5c4dab75SAndroid Build Coastguard Worker       /* Fall through */
636*5c4dab75SAndroid Build Coastguard Worker       ALOGE("Triggering resynchronization.");
637*5c4dab75SAndroid Build Coastguard Worker       tx_frame[!active].header.PCB = S(RESYNC, REQUEST);
638*5c4dab75SAndroid Build Coastguard Worker     case kRuleResultContinue:
639*5c4dab75SAndroid Build Coastguard Worker       active = !active;
640*5c4dab75SAndroid Build Coastguard Worker       tx = &tx_frame[active];
641*5c4dab75SAndroid Build Coastguard Worker       /* Reset this to 0 to use the counter for RESYNC transmits. */
642*5c4dab75SAndroid Build Coastguard Worker       state.retransmits = 0;
643*5c4dab75SAndroid Build Coastguard Worker       /* Errors are not reset until the session is reset. */
644*5c4dab75SAndroid Build Coastguard Worker       continue;
645*5c4dab75SAndroid Build Coastguard Worker     case kRuleResultHardFail:
646*5c4dab75SAndroid Build Coastguard Worker       ese_set_error(ese, kTeq1ErrorHardFail);
647*5c4dab75SAndroid Build Coastguard Worker       return 0;
648*5c4dab75SAndroid Build Coastguard Worker     case kRuleResultAbort:
649*5c4dab75SAndroid Build Coastguard Worker       ese_set_error(ese, kTeq1ErrorAbort);
650*5c4dab75SAndroid Build Coastguard Worker       return 0;
651*5c4dab75SAndroid Build Coastguard Worker     case kRuleResultSingleShot:
652*5c4dab75SAndroid Build Coastguard Worker       /*
653*5c4dab75SAndroid Build Coastguard Worker        * Send the next_tx on loop, but tell the rule engine that
654*5c4dab75SAndroid Build Coastguard Worker        * the last sent state hasn't changed. This allows for easy error
655*5c4dab75SAndroid Build Coastguard Worker        * and supervisory block paths without nesting state.
656*5c4dab75SAndroid Build Coastguard Worker        */
657*5c4dab75SAndroid Build Coastguard Worker       tx = &tx_frame[!active];
658*5c4dab75SAndroid Build Coastguard Worker       continue;
659*5c4dab75SAndroid Build Coastguard Worker     case kRuleResultResetDevice:
660*5c4dab75SAndroid Build Coastguard Worker       needs_hw_reset = true;
661*5c4dab75SAndroid Build Coastguard Worker     /* Fall through to session reset. */
662*5c4dab75SAndroid Build Coastguard Worker     case kRuleResultResetSession:
663*5c4dab75SAndroid Build Coastguard Worker       /* Reset to initial state and possibly do hw reset */
664*5c4dab75SAndroid Build Coastguard Worker       if (session_resets++ > 4) {
665*5c4dab75SAndroid Build Coastguard Worker         /* If there have been more than 4 resyncs without a
666*5c4dab75SAndroid Build Coastguard Worker          * physical reset, we should pull the plug.
667*5c4dab75SAndroid Build Coastguard Worker          */
668*5c4dab75SAndroid Build Coastguard Worker         needs_hw_reset = true;
669*5c4dab75SAndroid Build Coastguard Worker       }
670*5c4dab75SAndroid Build Coastguard Worker       if (needs_hw_reset) {
671*5c4dab75SAndroid Build Coastguard Worker         needs_hw_reset = false;
672*5c4dab75SAndroid Build Coastguard Worker         if (was_reset || !ese->ops->hw_reset || ese->ops->hw_reset(ese) == -1) {
673*5c4dab75SAndroid Build Coastguard Worker           ese_set_error(ese, kTeq1ErrorDeviceReset);
674*5c4dab75SAndroid Build Coastguard Worker           return 0; /* Don't keep resetting -- hard fail. */
675*5c4dab75SAndroid Build Coastguard Worker         }
676*5c4dab75SAndroid Build Coastguard Worker         was_reset = true;
677*5c4dab75SAndroid Build Coastguard Worker         session_resets = 0;
678*5c4dab75SAndroid Build Coastguard Worker       }
679*5c4dab75SAndroid Build Coastguard Worker       state = init_state;
680*5c4dab75SAndroid Build Coastguard Worker       TEQ1_INIT_CARD_STATE(state.card_state);
681*5c4dab75SAndroid Build Coastguard Worker       /* Reset the active frame. */
682*5c4dab75SAndroid Build Coastguard Worker       ese_memset(tx, 0, sizeof(*tx));
683*5c4dab75SAndroid Build Coastguard Worker       /* Load initial I-block. */
684*5c4dab75SAndroid Build Coastguard Worker       tx->header.PCB = I(0, 0);
685*5c4dab75SAndroid Build Coastguard Worker       teq1_fill_info_block(&state, tx);
686*5c4dab75SAndroid Build Coastguard Worker       continue;
687*5c4dab75SAndroid Build Coastguard Worker     }
688*5c4dab75SAndroid Build Coastguard Worker   }
689*5c4dab75SAndroid Build Coastguard Worker   /* Return the number of bytes used in the RX buffers. */
690*5c4dab75SAndroid Build Coastguard Worker   return rx_total - state.app_data.rx_total;
691*5c4dab75SAndroid Build Coastguard Worker }
692*5c4dab75SAndroid Build Coastguard Worker 
teq1_compute_LRC(const struct Teq1Frame * frame)693*5c4dab75SAndroid Build Coastguard Worker ESE_API uint8_t teq1_compute_LRC(const struct Teq1Frame *frame) {
694*5c4dab75SAndroid Build Coastguard Worker   uint8_t lrc = 0;
695*5c4dab75SAndroid Build Coastguard Worker   const uint8_t *buffer = frame->val;
696*5c4dab75SAndroid Build Coastguard Worker   const uint8_t *end = buffer + frame->header.LEN + sizeof(frame->header);
697*5c4dab75SAndroid Build Coastguard Worker   while (buffer < end) {
698*5c4dab75SAndroid Build Coastguard Worker     lrc ^= *buffer++;
699*5c4dab75SAndroid Build Coastguard Worker   }
700*5c4dab75SAndroid Build Coastguard Worker   return lrc;
701*5c4dab75SAndroid Build Coastguard Worker }
702