blob: 84b7f0f34971b0491ac1919967fdab95d123256c [file] [log] [blame]
Will Drewryd4ae5282017-01-03 22:06:26 -06001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Will Drewryde2cad72017-03-10 15:53:34 -060017#include "include/ese/teq1.h"
18#include "../libese/include/ese/ese.h"
19#include "../libese/include/ese/log.h"
Will Drewryd4ae5282017-01-03 22:06:26 -060020
21#include "teq1_private.h"
22
23const char *teq1_rule_result_to_name(enum RuleResult result) {
24 switch (result) {
25 case kRuleResultComplete:
26 return "Complete";
27 case kRuleResultAbort:
28 return "Abort";
29 case kRuleResultContinue:
30 return "Continue";
31 case kRuleResultHardFail:
32 return "Hard failure";
33 case kRuleResultResetDevice:
34 return "Reset device";
35 case kRuleResultResetSession:
36 return "Reset session";
37 case kRuleResultRetransmit:
38 return "Retransmit";
39 case kRuleResultSingleShot:
40 return "Single shot";
41 };
42}
43
44const char *teq1_pcb_to_name(uint8_t pcb) {
45 switch (pcb) {
46 case I(0, 0):
47 return "I(0, 0)";
48 case I(0, 1):
49 return "I(0, 1)";
50 case I(1, 0):
51 return "I(1, 0)";
52 case I(1, 1):
53 return "I(1, 1)";
54 case R(0, 0, 0):
55 return "R(0, 0, 0)";
56 case R(0, 0, 1):
57 return "R(0, 0, 1)";
58 case R(0, 1, 0):
59 return "R(0, 1, 0)";
60 case R(0, 1, 1):
61 return "R(0, 1, 1)";
62 case R(1, 0, 0):
63 return "R(1, 0, 0)";
64 case R(1, 0, 1):
65 return "R(1, 0, 1)";
66 case R(1, 1, 0):
67 return "R(1, 1, 0)";
68 case R(1, 1, 1):
69 return "R(1, 1, 1)";
70 case S(RESYNC, REQUEST):
71 return "S(RESYNC, REQUEST)";
72 case S(RESYNC, RESPONSE):
73 return "S(RESYNC, RESPONSE)";
74 case S(IFS, REQUEST):
75 return "S(IFS, REQUEST)";
76 case S(IFS, RESPONSE):
77 return "S(IFS, RESPONSE)";
78 case S(ABORT, REQUEST):
79 return "S(ABORT, REQUEST)";
80 case S(ABORT, RESPONSE):
81 return "S(ABORT, RESPONSE)";
82 case S(WTX, REQUEST):
83 return "S(WTX, REQUEST)";
84 case S(WTX, RESPONSE):
85 return "S(WTX, RESPONSE)";
86 case 255:
87 return "INTERNAL-ERROR";
88 default:
89 return "???";
90 }
91}
92
Will Drewryde2cad72017-03-10 15:53:34 -060093void teq1_dump_buf(const char *prefix, const uint8_t *buf, uint32_t len) {
94 uint32_t recvd = 0;
95 for (recvd = 0; recvd < len; ++recvd)
96 ALOGV("%s[%u]: %.2X", prefix, recvd, buf[recvd]);
97}
Will Drewryd4ae5282017-01-03 22:06:26 -060098
Will Drewryde2cad72017-03-10 15:53:34 -060099int teq1_transmit(struct EseInterface *ese,
100 const struct Teq1ProtocolOptions *opts,
101 struct Teq1Frame *frame) {
Will Drewryd4ae5282017-01-03 22:06:26 -0600102 /* Set correct node address. */
103 frame->header.NAD = opts->node_address;
104
105 /* Compute the LRC */
106 frame->INF[frame->header.LEN] = teq1_compute_LRC(frame);
107
108 /*
109 * If the card does something weird, like expect an CRC/LRC based on a
Will Drewryde2cad72017-03-10 15:53:34 -0600110 * different header value, the preprocessing can handle it.
Will Drewryd4ae5282017-01-03 22:06:26 -0600111 */
Will Drewryde2cad72017-03-10 15:53:34 -0600112 if (opts->preprocess) {
Will Drewryd4ae5282017-01-03 22:06:26 -0600113 opts->preprocess(opts, frame, 1);
Will Drewryde2cad72017-03-10 15:53:34 -0600114 }
Will Drewryd4ae5282017-01-03 22:06:26 -0600115
116 /*
117 * Begins transmission and ignore errors.
118 * Failed transmissions will result eventually in a resync then reset.
119 */
Will Drewryde2cad72017-03-10 15:53:34 -0600120 teq1_trace_transmit(frame->header.PCB, frame->header.LEN);
121 teq1_dump_transmit(frame->val, sizeof(frame->header) + frame->header.LEN + 1);
Will Drewryd4ae5282017-01-03 22:06:26 -0600122 ese->ops->hw_transmit(ese, frame->val,
123 sizeof(frame->header) + frame->header.LEN + 1, 1);
Will Drewryde2cad72017-03-10 15:53:34 -0600124 /*
125 * Even though in practice any WTX BWT extension starts when the above
126 * transmit ends, it is easier to implement it in the polling timeout of
127 * receive.
Will Drewryd4ae5282017-01-03 22:06:26 -0600128 */
129 return 0;
130}
131
Will Drewryde2cad72017-03-10 15:53:34 -0600132int teq1_receive(struct EseInterface *ese,
133 const struct Teq1ProtocolOptions *opts, float timeout,
Will Drewryd4ae5282017-01-03 22:06:26 -0600134 struct Teq1Frame *frame) {
Will Drewryd4ae5282017-01-03 22:06:26 -0600135 /* Poll the bus until we see the start of frame indicator, the interface NAD.
136 */
Will Drewryde2cad72017-03-10 15:53:34 -0600137 int bytes_consumed = ese->ops->poll(ese, opts->host_address, timeout, 0);
138 if (bytes_consumed < 0 || bytes_consumed > 1) {
Will Drewryd4ae5282017-01-03 22:06:26 -0600139 /* Timed out or comm error. */
Will Drewryde2cad72017-03-10 15:53:34 -0600140 ALOGV("%s: comm error: %d", __func__, bytes_consumed);
Will Drewryd4ae5282017-01-03 22:06:26 -0600141 return -1;
142 }
Will Drewryde2cad72017-03-10 15:53:34 -0600143 /* We polled for the NAD above -- if it was consumed, set it here. */
144 if (bytes_consumed) {
145 frame->header.NAD = opts->host_address;
146 }
Will Drewryd4ae5282017-01-03 22:06:26 -0600147 /* Get the remainder of the header, but keep the line &open. */
Will Drewryde2cad72017-03-10 15:53:34 -0600148 ese->ops->hw_receive(ese, (uint8_t *)(&frame->header.NAD + bytes_consumed),
149 sizeof(frame->header) - bytes_consumed, 0);
150 teq1_dump_receive((uint8_t *)(&frame->header.NAD + bytes_consumed),
151 sizeof(frame->header) - bytes_consumed);
Will Drewryd4ae5282017-01-03 22:06:26 -0600152 if (frame->header.LEN == 255) {
153 ALOGV("received invalid LEN of 255");
154 /* Close the receive window and return failure. */
155 ese->ops->hw_receive(ese, NULL, 0, 1);
156 return -1;
157 }
158 /*
159 * Get the data and the first byte of CRC data.
160 * Note, CRC support is not implemented. Only a single LRC byte is expected.
161 */
162 ese->ops->hw_receive(ese, (uint8_t *)(&(frame->INF[0])),
163 frame->header.LEN + 1, 1);
Will Drewryde2cad72017-03-10 15:53:34 -0600164 teq1_dump_receive((uint8_t *)(&(frame->INF[0])), frame->header.LEN + 1);
165 teq1_trace_receive(frame->header.PCB, frame->header.LEN);
Will Drewryd4ae5282017-01-03 22:06:26 -0600166
167 /*
168 * If the card does something weird, like expect an CRC/LRC based on a
169 * different
170 * header value, the preprocessing should fix up here prior to the LRC check.
171 */
Will Drewryde2cad72017-03-10 15:53:34 -0600172 if (opts->preprocess) {
Will Drewryd4ae5282017-01-03 22:06:26 -0600173 opts->preprocess(opts, frame, 0);
Will Drewryde2cad72017-03-10 15:53:34 -0600174 }
Will Drewryd4ae5282017-01-03 22:06:26 -0600175
176 /* LRC and other protocol goodness checks are not done here. */
177 return frame->header.LEN; /* Return data bytes read. */
178}
179
180uint8_t teq1_fill_info_block(struct Teq1State *state, struct Teq1Frame *frame) {
181 uint32_t inf_len = INF_LEN;
Will Drewryde2cad72017-03-10 15:53:34 -0600182 if (state->ifs < inf_len) {
Will Drewryd4ae5282017-01-03 22:06:26 -0600183 inf_len = state->ifs;
Will Drewryde2cad72017-03-10 15:53:34 -0600184 }
185 switch (bs_get(PCB.type, frame->header.PCB)) {
Will Drewryd4ae5282017-01-03 22:06:26 -0600186 case kPcbTypeInfo0:
187 case kPcbTypeInfo1: {
Will Drewry8f367fc2017-03-30 22:07:48 -0500188 uint32_t len = state->app_data.tx_total;
189 uint32_t copied = 0;
Will Drewryde2cad72017-03-10 15:53:34 -0600190 if (len > inf_len) {
Will Drewryd4ae5282017-01-03 22:06:26 -0600191 len = inf_len;
Will Drewryde2cad72017-03-10 15:53:34 -0600192 }
Will Drewry8f367fc2017-03-30 22:07:48 -0500193 copied = ese_sg_to_buf(state->app_data.tx, state->app_data.tx_count,
194 state->app_data.tx_offset, len, frame->INF);
195 if (copied != len) {
196 ALOGE("Failed to copy %x bytes of app data for transmission",
197 frame->header.LEN);
198 /* TODO(wad): This return code is largely ignored. Is the precondition
199 * checking elsewhere enough? */
200 return 255;
201 }
Will Drewryd4ae5282017-01-03 22:06:26 -0600202 frame->header.LEN = (len & 0xff);
203 ALOGV("Copying %x bytes of app data for transmission", frame->header.LEN);
204 /* Incrementing here means the caller MUST handle retransmit with prepared
205 * data. */
Will Drewry8f367fc2017-03-30 22:07:48 -0500206 state->app_data.tx_offset += copied;
207 state->app_data.tx_total -= copied;
Will Drewryd4ae5282017-01-03 22:06:26 -0600208 /* Perform chained transmission if needed. */
Will Drewryde2cad72017-03-10 15:53:34 -0600209 bs_assign(&frame->header.PCB, PCB.I.more_data, 0);
Will Drewry8f367fc2017-03-30 22:07:48 -0500210 if (state->app_data.tx_total > 0) {
Will Drewryde2cad72017-03-10 15:53:34 -0600211 frame->header.PCB |= bs_mask(PCB.I.more_data, 1);
212 }
Will Drewryd4ae5282017-01-03 22:06:26 -0600213 return len;
214 }
215 case kPcbTypeSupervisory:
216 case kPcbTypeReceiveReady:
217 default:
218 break;
219 }
220 return 255; /* Invalid block type. */
221}
222
Will Drewry8f367fc2017-03-30 22:07:48 -0500223void teq1_get_app_data(struct Teq1State *state, const struct Teq1Frame *frame) {
Will Drewryde2cad72017-03-10 15:53:34 -0600224 switch (bs_get(PCB.type, frame->header.PCB)) {
Will Drewryd4ae5282017-01-03 22:06:26 -0600225 case kPcbTypeInfo0:
226 case kPcbTypeInfo1: {
Will Drewry8f367fc2017-03-30 22:07:48 -0500227 uint32_t len = frame->header.LEN;
Will Drewryd4ae5282017-01-03 22:06:26 -0600228 /* TODO(wad): Some data will be left on the table. Should this error out? */
Will Drewry8f367fc2017-03-30 22:07:48 -0500229 if (len > state->app_data.rx_total) {
230 len = state->app_data.rx_total;
Will Drewryde2cad72017-03-10 15:53:34 -0600231 }
Will Drewry8f367fc2017-03-30 22:07:48 -0500232 ese_sg_from_buf(state->app_data.rx, state->app_data.rx_count,
233 state->app_data.rx_offset, len, frame->INF);
Will Drewryd4ae5282017-01-03 22:06:26 -0600234 /* The original caller must retain the starting pointer to determine
235 * actual available data.
236 */
Will Drewry8f367fc2017-03-30 22:07:48 -0500237 state->app_data.rx_total -= len;
238 state->app_data.rx_offset += len;
Will Drewryd4ae5282017-01-03 22:06:26 -0600239 return;
240 }
241 case kPcbTypeReceiveReady:
242 case kPcbTypeSupervisory:
243 default:
244 break;
245 }
246 return;
247}
248
249/* Returns an R(0) frame with error bits set. */
250uint8_t teq1_frame_error_check(struct Teq1State *state,
251 struct Teq1Frame *tx_frame,
252 struct Teq1Frame *rx_frame) {
253 uint8_t lrc = 0;
254 int chained = 0;
Will Drewryde2cad72017-03-10 15:53:34 -0600255 if (rx_frame->header.PCB == 255) {
Will Drewryd4ae5282017-01-03 22:06:26 -0600256 return R(0, 1, 0); /* Other error */
Will Drewryde2cad72017-03-10 15:53:34 -0600257 }
Will Drewryd4ae5282017-01-03 22:06:26 -0600258
259 lrc = teq1_compute_LRC(rx_frame);
260 if (rx_frame->INF[rx_frame->header.LEN] != lrc) {
Will Drewry8f830232017-03-13 13:07:54 -0500261 ALOGE("Invalid LRC %x instead of %x", rx_frame->INF[rx_frame->header.LEN],
Will Drewryd4ae5282017-01-03 22:06:26 -0600262 lrc);
263 return R(0, 0, 1); /* Parity error */
264 }
265
266 /* Check if we were chained and increment the last sent sequence. */
Will Drewryde2cad72017-03-10 15:53:34 -0600267 switch (bs_get(PCB.type, tx_frame->header.PCB)) {
Will Drewryd4ae5282017-01-03 22:06:26 -0600268 case kPcbTypeInfo0:
269 case kPcbTypeInfo1:
Will Drewryde2cad72017-03-10 15:53:34 -0600270 chained = bs_get(PCB.I.more_data, tx_frame->header.PCB);
271 state->card_state->seq.interface =
272 bs_get(PCB.I.send_seq, tx_frame->header.PCB);
Will Drewryd4ae5282017-01-03 22:06:26 -0600273 }
274
275 /* Check if we've gone down an easy to catch error hole. The rest will turn up
276 * on the
277 * txrx switch.
278 */
Will Drewryde2cad72017-03-10 15:53:34 -0600279 switch (bs_get(PCB.type, rx_frame->header.PCB)) {
Will Drewryd4ae5282017-01-03 22:06:26 -0600280 case kPcbTypeSupervisory:
Will Drewryde2cad72017-03-10 15:53:34 -0600281 if (rx_frame->header.PCB != S(RESYNC, RESPONSE) &&
282 rx_frame->header.LEN != 1) {
Will Drewryd660eb42017-07-25 13:33:55 -0500283 ALOGE("Invalid supervisory RX frame.");
Will Drewryd4ae5282017-01-03 22:06:26 -0600284 return R(0, 1, 0);
Will Drewryde2cad72017-03-10 15:53:34 -0600285 }
Will Drewryd4ae5282017-01-03 22:06:26 -0600286 break;
287 case kPcbTypeReceiveReady:
Will Drewryde2cad72017-03-10 15:53:34 -0600288 if (rx_frame->header.LEN != 0) {
Will Drewryd660eb42017-07-25 13:33:55 -0500289 ALOGE("Invalid ReceiveReady RX frame.");
Will Drewryd4ae5282017-01-03 22:06:26 -0600290 return R(0, 1, 0);
Will Drewryde2cad72017-03-10 15:53:34 -0600291 }
Will Drewryd4ae5282017-01-03 22:06:26 -0600292 break;
293 case kPcbTypeInfo0:
294 case kPcbTypeInfo1:
295 /* I-blocks must always alternate for each endpoint. */
Will Drewryde2cad72017-03-10 15:53:34 -0600296 if ((bs_get(PCB.I.send_seq, rx_frame->header.PCB)) ==
297 state->card_state->seq.card) {
Will Drewry8f830232017-03-13 13:07:54 -0500298 ALOGW("Got seq %d expected %d",
Will Drewryde2cad72017-03-10 15:53:34 -0600299 bs_get(PCB.I.send_seq, rx_frame->header.PCB),
Will Drewryd4ae5282017-01-03 22:06:26 -0600300 state->card_state->seq.card);
Will Drewryd660eb42017-07-25 13:33:55 -0500301 ALOGE("Invalid Info RX frame.");
Will Drewryd4ae5282017-01-03 22:06:26 -0600302 return R(0, 1, 0);
303 }
304 /* Update the card's last I-block seq. */
Will Drewryde2cad72017-03-10 15:53:34 -0600305 state->card_state->seq.card = bs_get(PCB.I.send_seq, rx_frame->header.PCB);
Will Drewryd4ae5282017-01-03 22:06:26 -0600306 default:
307 break;
308 };
309 return 0;
310}
311
312enum RuleResult teq1_rules(struct Teq1State *state, struct Teq1Frame *tx_frame,
313 struct Teq1Frame *rx_frame,
314 struct Teq1Frame *next_tx) {
315 /* Rule 1 is enforced by first call∴ Start with I(0,M). */
316 /* 0 = TX, 1 = RX */
317 /* msb = tx pcb, lsb = rx pcb */
318 /* BUG_ON(!rx_frame && !tx_frame && !next_tx); */
Will Drewryde2cad72017-03-10 15:53:34 -0600319 uint16_t txrx = TEQ1_RULE(tx_frame->header.PCB, rx_frame->header.PCB);
320 uint8_t R_err;
Will Drewryd4ae5282017-01-03 22:06:26 -0600321
322 while (1) {
323 /* Timeout errors come like invalid frames: 255. */
Will Drewryde2cad72017-03-10 15:53:34 -0600324 if ((R_err = teq1_frame_error_check(state, tx_frame, rx_frame)) != 0) {
Will Drewry8f830232017-03-13 13:07:54 -0500325 ALOGW("incoming frame failed the error check");
Will Drewryd4ae5282017-01-03 22:06:26 -0600326 state->last_error_message = "Invalid frame received";
327 /* Mark the frame as bad for our rule evaluation. */
Will Drewryde2cad72017-03-10 15:53:34 -0600328 txrx = TEQ1_RULE(tx_frame->header.PCB, 255);
Will Drewryd4ae5282017-01-03 22:06:26 -0600329 state->errors++;
330 /* Rule 6.4 */
Will Drewryde2cad72017-03-10 15:53:34 -0600331 if (state->errors >= 6) {
Will Drewryd4ae5282017-01-03 22:06:26 -0600332 return kRuleResultResetDevice;
333 }
334 /* Rule 7.4.2 */
335 if (state->errors >= 3) {
336 /* Rule 7.4.1: state should start with error count = 2 */
Will Drewry578c5042017-04-21 15:20:45 -0500337 if (tx_frame->header.PCB != S(RESYNC, REQUEST)) {
338 next_tx->header.PCB = S(RESYNC, REQUEST);
339 return kRuleResultContinue;
340 }
341 return kRuleResultRetransmit;
Will Drewryd4ae5282017-01-03 22:06:26 -0600342 }
343 }
344
345 /* Specific matches */
346 switch (txrx) {
347 /*** Rule 2.1: I() -> I() ***/
348 /* Error check will determine if the card seq is right. */
349 case TEQ1_RULE(I(0, 0), I(0, 0)):
350 case TEQ1_RULE(I(0, 0), I(1, 0)):
351 case TEQ1_RULE(I(1, 0), I(1, 0)):
352 case TEQ1_RULE(I(1, 0), I(0, 0)):
353 /* Read app data & return. */
354 teq1_get_app_data(state, rx_frame);
355 return kRuleResultComplete;
356
Will Drewryd4ae5282017-01-03 22:06:26 -0600357 /* Card begins chained response. */
358 case TEQ1_RULE(I(0, 0), I(0, 1)):
359 case TEQ1_RULE(I(1, 0), I(1, 1)):
360 /* Prep R(N(S)) */
361 teq1_get_app_data(state, rx_frame);
Will Drewryde2cad72017-03-10 15:53:34 -0600362 next_tx->header.PCB =
363 TEQ1_R(!bs_get(PCB.I.send_seq, rx_frame->header.PCB), 0, 0);
Will Drewryd4ae5282017-01-03 22:06:26 -0600364 next_tx->header.LEN = 0;
365 return kRuleResultContinue;
366
367 /*** Rule 2.2, Rule 5: Chained transmission ***/
368 case TEQ1_RULE(I(0, 1), R(1, 0, 0)):
369 case TEQ1_RULE(I(1, 1), R(0, 0, 0)):
Will Drewryde2cad72017-03-10 15:53:34 -0600370 /* Send next block -- error-checking assures the R seq is our next seq. */
371 next_tx->header.PCB =
372 TEQ1_I(bs_get(PCB.R.next_seq, rx_frame->header.PCB), 0);
Will Drewryd4ae5282017-01-03 22:06:26 -0600373 teq1_fill_info_block(state, next_tx); /* Sets M-bit and LEN. */
374 return kRuleResultContinue;
375
376 /*** Rule 3 ***/
377 case TEQ1_RULE(I(0, 0), S(WTX, REQUEST)):
378 case TEQ1_RULE(I(1, 0), S(WTX, REQUEST)):
379 /* Note: Spec is unclear on if WTX can occur during chaining so we make it
380 an error for now.
381 case TEQ1_RULE(I(0, 1), S(WTX, REQUEST)):
382 case TEQ1_RULE(I(1, 1), S(WTX, REQUEST)):
383 */
384 /* Send S(WTX, RESPONSE) with same INF */
Will Drewryde2cad72017-03-10 15:53:34 -0600385 next_tx->header.PCB = S(WTX, RESPONSE);
Will Drewryd4ae5282017-01-03 22:06:26 -0600386 next_tx->header.LEN = 1;
387 next_tx->INF[0] = rx_frame->INF[0];
388 state->wait_mult = rx_frame->INF[0];
389 /* Then wait BWT*INF[0] after transmission. */
390 return kRuleResultSingleShot; /* Send then call back in with same tx_frame
391 and new rx_frame. */
392
393 /*** Rule 4 ***/
394 case TEQ1_RULE(S(IFS, REQUEST), S(IFS, RESPONSE)):
395 /* XXX: Check INFs match. */
396 return kRuleResultComplete; /* This is treated as an unique operation. */
397 case TEQ1_RULE(I(0, 0), S(IFS, REQUEST)):
398 case TEQ1_RULE(I(0, 1), S(IFS, REQUEST)):
399 case TEQ1_RULE(I(1, 0), S(IFS, REQUEST)):
400 case TEQ1_RULE(I(1, 1), S(IFS, REQUEST)):
401 /* Don't support a IFS_REQUEST if we sent an error R-block. */
402 case TEQ1_RULE(R(0, 0, 0), S(IFS, REQUEST)):
403 case TEQ1_RULE(R(1, 0, 0), S(IFS, REQUEST)):
Will Drewryde2cad72017-03-10 15:53:34 -0600404 next_tx->header.PCB = S(IFS, RESPONSE);
Will Drewryd4ae5282017-01-03 22:06:26 -0600405 next_tx->header.LEN = 1;
406 next_tx->INF[0] = rx_frame->INF[0];
407 state->ifs = rx_frame->INF[0];
408 return kRuleResultSingleShot;
409
410 /*** Rule 5 (see Rule 2.2 for the chained-tx side. ) ***/
411 case TEQ1_RULE(R(0, 0, 0), I(0, 0)):
412 case TEQ1_RULE(R(1, 0, 0), I(1, 0)):
413 /* Chaining ended with terminal I-block. */
414 teq1_get_app_data(state, rx_frame);
415 return kRuleResultComplete;
416 case TEQ1_RULE(R(0, 0, 0), I(0, 1)):
417 case TEQ1_RULE(R(1, 0, 0), I(1, 1)):
418 /* Chaining continued; consume partial data and send R(N(S)) */
419 teq1_get_app_data(state, rx_frame);
Will Drewryde2cad72017-03-10 15:53:34 -0600420 /* The card seq bit will be tracked/validated earlier. */
421 next_tx->header.PCB =
422 TEQ1_R(!bs_get(PCB.I.send_seq, rx_frame->header.PCB), 0, 0);
Will Drewryd4ae5282017-01-03 22:06:26 -0600423 return kRuleResultContinue;
424
425 /* Rule 6: Interface can send a RESYNC */
426 /* Rule 6.1: timeout BWT right. No case here. */
427 /* Rule 6.2, 6.3 */
428 case TEQ1_RULE(S(RESYNC, REQUEST), S(RESYNC, RESPONSE)):
429 /* Rule 6.5: indicates that the card should assume its prior
430 * block was lost _and_ the interface gets transmit privilege,
431 * so we just start fresh.
432 */
433 return kRuleResultResetSession; /* Start a new exchange (rule 6.3) */
434 case TEQ1_RULE(S(RESYNC, REQUEST), 255):
435 /* Retransmit the same frame up to 3 times. */
436 return kRuleResultRetransmit;
437
438 /* Rule 7.1, 7.5, 7.6 */
439 case TEQ1_RULE(I(0, 0), 255):
440 case TEQ1_RULE(I(1, 0), 255):
441 case TEQ1_RULE(I(0, 1), 255):
442 case TEQ1_RULE(I(1, 1), 255):
Will Drewryde2cad72017-03-10 15:53:34 -0600443 next_tx->header.PCB = R_err;
444 bs_assign(&next_tx->header.PCB, PCB.R.next_seq,
445 bs_get(PCB.I.send_seq, tx_frame->header.PCB));
Will Drewry8f830232017-03-13 13:07:54 -0500446 ALOGW("Rule 7.1,7.5,7.6: bad rx - sending error R: %x = %s",
Will Drewryde2cad72017-03-10 15:53:34 -0600447 next_tx->header.PCB, teq1_pcb_to_name(next_tx->header.PCB));
Will Drewryd4ae5282017-01-03 22:06:26 -0600448 return kRuleResultSingleShot; /* So we still can retransmit the original.
449 */
450
451 /* Caught in the error check. */
452 case TEQ1_RULE(I(0, 0), R(1, 0, 0)):
453 case TEQ1_RULE(I(0, 0), R(1, 0, 1)):
454 case TEQ1_RULE(I(0, 0), R(1, 1, 0)):
455 case TEQ1_RULE(I(0, 0), R(1, 1, 1)):
456 case TEQ1_RULE(I(1, 0), R(0, 0, 0)):
457 case TEQ1_RULE(I(1, 0), R(0, 0, 1)):
458 case TEQ1_RULE(I(1, 0), R(0, 1, 0)):
459 case TEQ1_RULE(I(1, 0), R(0, 1, 1)):
Will Drewryde2cad72017-03-10 15:53:34 -0600460 next_tx->header.PCB =
461 TEQ1_R(bs_get(PCB.I.send_seq, tx_frame->header.PCB), 0, 0);
Will Drewry8f830232017-03-13 13:07:54 -0500462 ALOGW("Rule 7.1,7.5,7.6: weird rx - sending error R: %x = %s",
Will Drewryde2cad72017-03-10 15:53:34 -0600463 next_tx->header.PCB, teq1_pcb_to_name(next_tx->header.PCB));
Will Drewryd4ae5282017-01-03 22:06:26 -0600464 return kRuleResultSingleShot;
465
466 /* Rule 7.2: Retransmit the _same_ R-block. */
467 /* The remainder of this rule is implemented in the next switch. */
468 case TEQ1_RULE(R(0, 0, 0), 255):
469 case TEQ1_RULE(R(0, 0, 1), 255):
470 case TEQ1_RULE(R(0, 1, 0), 255):
471 case TEQ1_RULE(R(0, 1, 1), 255):
472 case TEQ1_RULE(R(1, 0, 0), 255):
473 case TEQ1_RULE(R(1, 0, 1), 255):
474 case TEQ1_RULE(R(1, 1, 0), 255):
475 case TEQ1_RULE(R(1, 1, 1), 255):
476 return kRuleResultRetransmit;
477
478 /* Rule 7.3 request */
479 /* Note, 7.3 for transmission of S(*, RESPONSE) won't be seen because they
480 * are
481 * single shots.
482 * Instead, the invalid block will be handled as invalid for the prior TX.
483 * This should yield the correct R-block.
484 */
485 case TEQ1_RULE(I(0, 0), R(0, 0, 0)):
486 case TEQ1_RULE(I(0, 0), R(0, 0, 1)):
487 case TEQ1_RULE(I(0, 0), R(0, 1, 0)):
488 case TEQ1_RULE(I(0, 0), R(0, 1, 1)):
489 case TEQ1_RULE(I(1, 0), R(1, 0, 0)):
490 case TEQ1_RULE(I(1, 0), R(1, 1, 0)):
491 case TEQ1_RULE(I(1, 0), R(1, 0, 1)):
492 case TEQ1_RULE(I(1, 0), R(1, 1, 1)):
493 case TEQ1_RULE(I(0, 1), R(0, 0, 0)):
494 case TEQ1_RULE(I(0, 1), R(0, 1, 0)):
495 case TEQ1_RULE(I(0, 1), R(0, 0, 1)):
496 case TEQ1_RULE(I(0, 1), R(0, 1, 1)):
497 case TEQ1_RULE(I(1, 1), R(1, 0, 0)):
498 case TEQ1_RULE(I(1, 1), R(1, 1, 0)):
499 case TEQ1_RULE(I(1, 1), R(1, 0, 1)):
500 case TEQ1_RULE(I(1, 1), R(1, 1, 1)):
501 /* Retransmit I-block */
502 return kRuleResultRetransmit;
503
504 /* Rule 8 is card only. */
505 /* Rule 9: aborting a chain.
506 * If a S(ABORT) is injected into this engine, then we may have sent an
507 * abort.
508 */
509 case TEQ1_RULE(S(ABORT, REQUEST), S(ABORT, RESPONSE)):
510 /* No need to send back a R() because we want to keep transmit. */
511 return kRuleResultComplete; /* If we sent it, then we are complete. */
512 case TEQ1_RULE(S(ABORT, RESPONSE), R(0, 0, 0)):
513 case TEQ1_RULE(S(ABORT, RESPONSE), R(1, 0, 0)):
514 /* Card triggered abortion complete but we can resume sending. */
515 return kRuleResultAbort;
516 /* An abort request can interrupt a chain anywhere and could occur
517 * after a failure path too.
518 */
519 case TEQ1_RULE(I(0, 1), S(ABORT, REQUEST)):
520 case TEQ1_RULE(I(1, 1), S(ABORT, REQUEST)):
521 case TEQ1_RULE(R(0, 0, 0), S(ABORT, REQUEST)):
522 case TEQ1_RULE(R(0, 0, 1), S(ABORT, REQUEST)):
523 case TEQ1_RULE(R(0, 1, 0), S(ABORT, REQUEST)):
524 case TEQ1_RULE(R(0, 1, 1), S(ABORT, REQUEST)):
525 case TEQ1_RULE(R(1, 0, 0), S(ABORT, REQUEST)):
526 case TEQ1_RULE(R(1, 0, 1), S(ABORT, REQUEST)):
527 case TEQ1_RULE(R(1, 1, 0), S(ABORT, REQUEST)):
528 case TEQ1_RULE(R(1, 1, 1), S(ABORT, REQUEST)):
Will Drewryde2cad72017-03-10 15:53:34 -0600529 next_tx->header.PCB = S(ABORT, REQUEST);
Will Drewryd4ae5282017-01-03 22:06:26 -0600530 return kRuleResultContinue; /* Takes over prior flow. */
531 case TEQ1_RULE(S(ABORT, RESPONSE), 255):
532 return kRuleResultRetransmit;
533 /* Note, other blocks should be caught below. */
534 default:
535 break;
536 }
537
538 /* Note, only S(ABORT, REQUEST) and S(IFS, REQUEST) are supported
539 * for transmitting to the card. Others will result in error
540 * flows.
541 *
542 * For supported flows: If an operation was paused to
543 * send it, the caller may then switch to that state and resume.
544 */
Will Drewryde2cad72017-03-10 15:53:34 -0600545 if (rx_frame->header.PCB != 255) {
Will Drewry8f830232017-03-13 13:07:54 -0500546 ALOGW("Unexpected frame. Marking error and re-evaluating.");
Will Drewryde2cad72017-03-10 15:53:34 -0600547 rx_frame->header.PCB = 255;
Will Drewryd4ae5282017-01-03 22:06:26 -0600548 continue;
549 }
550
551 return kRuleResultHardFail;
552 }
553}
554
555/*
556 * TODO(wad): Consider splitting teq1_transcieve() into
557 * teq1_transcieve_init() and teq1_transceive_process_one()
558 * if testing becomes onerous given the loop below.
559 */
Will Drewry8f367fc2017-03-30 22:07:48 -0500560ESE_API uint32_t teq1_transceive(struct EseInterface *ese,
561 const struct Teq1ProtocolOptions *opts,
562 const struct EseSgBuffer *tx_bufs,
563 uint8_t tx_segs, struct EseSgBuffer *rx_bufs,
564 uint8_t rx_segs) {
Will Drewryd4ae5282017-01-03 22:06:26 -0600565 struct Teq1Frame tx_frame[2];
566 struct Teq1Frame rx_frame;
567 struct Teq1Frame *tx = &tx_frame[0];
Will Drewryd4ae5282017-01-03 22:06:26 -0600568 int active = 0;
Will Drewryde2cad72017-03-10 15:53:34 -0600569 bool was_reset = false;
Will Drewryd660eb42017-07-25 13:33:55 -0500570 bool needs_hw_reset = false;
571 int session_resets = 0;
Will Drewryde2cad72017-03-10 15:53:34 -0600572 bool done = false;
Will Drewryd4ae5282017-01-03 22:06:26 -0600573 enum RuleResult result = kRuleResultComplete;
Will Drewry8f367fc2017-03-30 22:07:48 -0500574 uint32_t rx_total = ese_sg_length(rx_bufs, rx_segs);
Will Drewryd4ae5282017-01-03 22:06:26 -0600575 struct Teq1CardState *card_state = (struct Teq1CardState *)(&ese->pad[0]);
Will Drewry8f367fc2017-03-30 22:07:48 -0500576 struct Teq1State init_state = TEQ1_INIT_STATE(
577 tx_bufs, tx_segs, ese_sg_length(tx_bufs, tx_segs), rx_bufs, rx_segs,
578 ese_sg_length(rx_bufs, rx_segs), card_state);
579 struct Teq1State state = TEQ1_INIT_STATE(
580 tx_bufs, tx_segs, ese_sg_length(tx_bufs, tx_segs), rx_bufs, rx_segs,
581 ese_sg_length(rx_bufs, rx_segs), card_state);
Will Drewryd4ae5282017-01-03 22:06:26 -0600582
Will Drewryde2cad72017-03-10 15:53:34 -0600583 _static_assert(TEQ1HEADER_SIZE == sizeof(struct Teq1Header),
584 "Ensure compiler alignment/padding matches wire protocol.");
585 _static_assert(TEQ1FRAME_SIZE == sizeof(struct Teq1Frame),
586 "Ensure compiler alignment/padding matches wire protocol.");
587
Will Drewryd4ae5282017-01-03 22:06:26 -0600588 /* First I-block is always I(0, M). After that, modulo 2. */
Will Drewryde2cad72017-03-10 15:53:34 -0600589 tx->header.PCB = TEQ1_I(!card_state->seq.interface, 0);
Will Drewryd4ae5282017-01-03 22:06:26 -0600590 teq1_fill_info_block(&state, tx);
591
592 teq1_trace_header();
593 while (!done) {
594 /* Populates the node address and LRC prior to attempting to transmit. */
Will Drewryde2cad72017-03-10 15:53:34 -0600595 teq1_transmit(ese, opts, tx);
Will Drewryd4ae5282017-01-03 22:06:26 -0600596
597 /* If tx was pointed to the inactive frame for a single shot, restore it
598 * now. */
599 tx = &tx_frame[active];
600
601 /* Clear the RX frame. */
Will Drewryde2cad72017-03-10 15:53:34 -0600602 ese_memset(&rx_frame, 0xff, sizeof(rx_frame));
Will Drewryd4ae5282017-01-03 22:06:26 -0600603
604 /* -1 indicates a timeout or failure from hardware. */
Will Drewryde2cad72017-03-10 15:53:34 -0600605 if (teq1_receive(ese, opts, opts->bwt * (float)state.wait_mult, &rx_frame) <
606 0) {
Will Drewryd4ae5282017-01-03 22:06:26 -0600607 /* TODO(wad): If the ese_error(ese) == 1, should this go ahead and fail?
608 */
609 /* Failures are considered invalid blocks in the rule engine below. */
Will Drewryde2cad72017-03-10 15:53:34 -0600610 rx_frame.header.PCB = 255;
Will Drewryd4ae5282017-01-03 22:06:26 -0600611 }
612 /* Always reset |wait_mult| once we have calculated the timeout. */
613 state.wait_mult = 1;
614
615 /* Clear the inactive frame header for use as |next_tx|. */
Will Drewryde2cad72017-03-10 15:53:34 -0600616 ese_memset(&tx_frame[!active].header, 0, sizeof(tx_frame[!active].header));
Will Drewryd4ae5282017-01-03 22:06:26 -0600617
618 result = teq1_rules(&state, tx, &rx_frame, &tx_frame[!active]);
619 ALOGV("[ %s ]", teq1_rule_result_to_name(result));
620 switch (result) {
621 case kRuleResultComplete:
Will Drewryde2cad72017-03-10 15:53:34 -0600622 done = true;
Will Drewryd4ae5282017-01-03 22:06:26 -0600623 break;
624 case kRuleResultRetransmit:
625 /* TODO(wad) Find a clean way to move into teq1_rules(). */
Will Drewryde2cad72017-03-10 15:53:34 -0600626 if (state.retransmits++ < 3) {
Will Drewryd4ae5282017-01-03 22:06:26 -0600627 continue;
Will Drewryde2cad72017-03-10 15:53:34 -0600628 }
Will Drewry578c5042017-04-21 15:20:45 -0500629 ALOGE("More than three retransmits have occurred");
Will Drewryde2cad72017-03-10 15:53:34 -0600630 if (tx->header.PCB == S(RESYNC, REQUEST)) {
Will Drewryd660eb42017-07-25 13:33:55 -0500631 /* More than three RESYNC retranmits have occurred. */
Will Drewryde2cad72017-03-10 15:53:34 -0600632 ese_set_error(ese, kTeq1ErrorHardFail);
Will Drewryd4ae5282017-01-03 22:06:26 -0600633 return 0;
634 }
635 /* Fall through */
Will Drewry578c5042017-04-21 15:20:45 -0500636 ALOGE("Triggering resynchronization.");
Will Drewryde2cad72017-03-10 15:53:34 -0600637 tx_frame[!active].header.PCB = S(RESYNC, REQUEST);
Will Drewryd4ae5282017-01-03 22:06:26 -0600638 case kRuleResultContinue:
639 active = !active;
640 tx = &tx_frame[active];
Will Drewryd660eb42017-07-25 13:33:55 -0500641 /* Reset this to 0 to use the counter for RESYNC transmits. */
Will Drewryd4ae5282017-01-03 22:06:26 -0600642 state.retransmits = 0;
Will Drewryd660eb42017-07-25 13:33:55 -0500643 /* Errors are not reset until the session is reset. */
Will Drewryd4ae5282017-01-03 22:06:26 -0600644 continue;
645 case kRuleResultHardFail:
Will Drewryde2cad72017-03-10 15:53:34 -0600646 ese_set_error(ese, kTeq1ErrorHardFail);
Will Drewryd4ae5282017-01-03 22:06:26 -0600647 return 0;
648 case kRuleResultAbort:
Will Drewryde2cad72017-03-10 15:53:34 -0600649 ese_set_error(ese, kTeq1ErrorAbort);
Will Drewryd4ae5282017-01-03 22:06:26 -0600650 return 0;
651 case kRuleResultSingleShot:
652 /*
653 * Send the next_tx on loop, but tell the rule engine that
654 * the last sent state hasn't changed. This allows for easy error
655 * and supervisory block paths without nesting state.
656 */
657 tx = &tx_frame[!active];
658 continue;
659 case kRuleResultResetDevice:
Will Drewryd660eb42017-07-25 13:33:55 -0500660 needs_hw_reset = true;
Will Drewryd4ae5282017-01-03 22:06:26 -0600661 /* Fall through to session reset. */
662 case kRuleResultResetSession:
Will Drewryd660eb42017-07-25 13:33:55 -0500663 /* Reset to initial state and possibly do hw reset */
664 if (session_resets++ > 4) {
665 /* If there have been more than 4 resyncs without a
666 * physical reset, we should pull the plug.
667 */
668 needs_hw_reset = true;
669 }
670 if (needs_hw_reset) {
671 needs_hw_reset = false;
672 if (was_reset || !ese->ops->hw_reset || ese->ops->hw_reset(ese) == -1) {
673 ese_set_error(ese, kTeq1ErrorDeviceReset);
674 return 0; /* Don't keep resetting -- hard fail. */
675 }
676 was_reset = true;
677 session_resets = 0;
678 }
Will Drewryd4ae5282017-01-03 22:06:26 -0600679 state = init_state;
680 TEQ1_INIT_CARD_STATE(state.card_state);
681 /* Reset the active frame. */
Will Drewryde2cad72017-03-10 15:53:34 -0600682 ese_memset(tx, 0, sizeof(*tx));
Will Drewryd4ae5282017-01-03 22:06:26 -0600683 /* Load initial I-block. */
Will Drewryde2cad72017-03-10 15:53:34 -0600684 tx->header.PCB = I(0, 0);
Will Drewryd4ae5282017-01-03 22:06:26 -0600685 teq1_fill_info_block(&state, tx);
686 continue;
687 }
688 }
Will Drewry8f367fc2017-03-30 22:07:48 -0500689 /* Return the number of bytes used in the RX buffers. */
690 return rx_total - state.app_data.rx_total;
Will Drewryd4ae5282017-01-03 22:06:26 -0600691}
692
Will Drewry8f367fc2017-03-30 22:07:48 -0500693ESE_API uint8_t teq1_compute_LRC(const struct Teq1Frame *frame) {
Will Drewryd4ae5282017-01-03 22:06:26 -0600694 uint8_t lrc = 0;
695 const uint8_t *buffer = frame->val;
696 const uint8_t *end = buffer + frame->header.LEN + sizeof(frame->header);
697 while (buffer < end) {
698 lrc ^= *buffer++;
699 }
700 return lrc;
701}