1 /*
2 * Copyright (C) 2016 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 * Implement a simple T=1 echo endpoint.
17 */
18
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22
23 #include "../libese-teq1/include/ese/teq1.h"
24 #include "../libese/include/ese/ese.h"
25 #include "../libese/include/ese/log.h"
26
27 struct EchoState {
28 struct Teq1Frame frame;
29 uint8_t *rx_fill;
30 uint8_t *tx_sent;
31 int recvd;
32 };
33
34 #define ECHO_STATE(ese) (*(struct EchoState **)(&ese->pad[1]))
35
echo_open(struct EseInterface * ese,void * hw_opts)36 static int echo_open(struct EseInterface *ese, void *hw_opts) {
37 struct EchoState *es = hw_opts; /* shorter than __attribute */
38 struct EchoState **es_ptr;
39 if (sizeof(ese->pad) < sizeof(struct EchoState *)) {
40 /* This is a compile-time correctable error only. */
41 ALOGE("Pad size too small to use Echo HW (%zu < %zu)", sizeof(ese->pad),
42 sizeof(struct EchoState *));
43 return -1;
44 }
45 es_ptr = &ECHO_STATE(ese);
46 *es_ptr = malloc(sizeof(struct EchoState));
47 if (!*es_ptr) {
48 return -1;
49 }
50 es = ECHO_STATE(ese);
51 es->rx_fill = &es->frame.header.NAD;
52 es->tx_sent = es->rx_fill;
53 es->recvd = 0;
54 return 0;
55 }
56
echo_close(struct EseInterface * ese)57 static void echo_close(struct EseInterface *ese) {
58 struct EchoState *es;
59 es = ECHO_STATE(ese);
60 if (!es) {
61 return;
62 }
63 free(es);
64 es = NULL;
65 }
66
echo_receive(struct EseInterface * ese,uint8_t * buf,uint32_t len,int complete)67 static uint32_t echo_receive(struct EseInterface *ese, uint8_t *buf,
68 uint32_t len, int complete) {
69 struct EchoState *es = ECHO_STATE(ese);
70 ALOGV("interface attempting to read data");
71 if (!es->recvd) {
72 return 0;
73 }
74
75 if (len > sizeof(es->frame) - (es->tx_sent - &es->frame.header.NAD)) {
76 return 0;
77 }
78
79 /* NAD was polled for so skip it. */
80 memcpy(buf, es->tx_sent, len);
81 es->tx_sent += len;
82 if (complete) {
83 es->tx_sent = &es->frame.header.NAD;
84 es->recvd = 0;
85 ALOGV("card sent a frame");
86 }
87 return sizeof(es->frame.header) + es->frame.header.LEN;
88 }
89
echo_transmit(struct EseInterface * ese,const uint8_t * buf,uint32_t len,int complete)90 static uint32_t echo_transmit(struct EseInterface *ese, const uint8_t *buf,
91 uint32_t len, int complete) {
92 struct EchoState *es = ECHO_STATE(ese);
93 ALOGV("interface transmitting data");
94 if (len > sizeof(es->frame) - (es->rx_fill - &es->frame.header.NAD)) {
95 return 0;
96 }
97 memcpy(es->rx_fill, buf, len);
98 es->rx_fill += len;
99 es->recvd = complete;
100 if (complete) {
101 es->frame.header.NAD = 0x00;
102 if (teq1_compute_LRC(&es->frame) != es->frame.INF[es->frame.header.LEN]) {
103 ALOGV("card received frame with bad LRC");
104 return 0;
105 }
106 ALOGV("card received valid frame");
107 es->rx_fill = &es->frame.header.NAD;
108 }
109 return len;
110 }
111
echo_poll(struct EseInterface * ese,uint8_t poll_for,float timeout,int complete)112 static int echo_poll(struct EseInterface *ese, uint8_t poll_for, float timeout,
113 int complete) {
114 struct EchoState *es = ECHO_STATE(ese);
115 const struct Teq1ProtocolOptions *opts = ese->ops->opts;
116 ALOGV("interface polling for start of frame/host node address: %x", poll_for);
117 /* In reality, we should be polling at intervals up to the timeout. */
118 if (timeout > 0.0) {
119 usleep(timeout * 1000);
120 }
121 if (poll_for == opts->host_address) {
122 ALOGV("interface received NAD");
123 if (!complete) {
124 es->tx_sent++; /* Consume the polled byte: NAD */
125 }
126 return 1;
127 }
128 return -1;
129 }
130
echo_preprocess(const struct Teq1ProtocolOptions * const opts,struct Teq1Frame * frame,int tx)131 int echo_preprocess(const struct Teq1ProtocolOptions *const opts,
132 struct Teq1Frame *frame, int tx) {
133 if (tx) {
134 /* Recompute the LRC with the NAD of 0x00 */
135 frame->header.NAD = 0x00;
136 frame->INF[frame->header.LEN] = teq1_compute_LRC(frame);
137 frame->header.NAD = opts->node_address;
138 ALOGV("interface is preprocessing outbound frame");
139 } else {
140 /* Replace the NAD with 0x00 so the LRC check passes. */
141 frame->header.NAD = 0x00;
142 ALOGV("interface is preprocessing inbound frame");
143 }
144 return 0;
145 }
146
147 static const struct Teq1ProtocolOptions kTeq1Options = {
148 .host_address = 0xAA,
149 .node_address = 0xBB,
150 .bwt = 3.14152f,
151 .etu = 1.0f,
152 .preprocess = &echo_preprocess,
153 };
154
echo_transceive(struct EseInterface * ese,const struct EseSgBuffer * tx_buf,uint32_t tx_len,struct EseSgBuffer * rx_buf,uint32_t rx_len)155 uint32_t echo_transceive(struct EseInterface *ese,
156 const struct EseSgBuffer *tx_buf, uint32_t tx_len,
157 struct EseSgBuffer *rx_buf, uint32_t rx_len) {
158 return teq1_transceive(ese, &kTeq1Options, tx_buf, tx_len, rx_buf, rx_len);
159 }
160
161 static const char *kErrorMessages[] = {
162 "T=1 hard failure.", /* TEQ1_ERROR_HARD_FAIL */
163 "T=1 abort.", /* TEQ1_ERROR_ABORT */
164 "T=1 device reset failed.", /* TEQ1_ERROR_DEVICE_ABORT */
165 };
166
167 static const struct EseOperations ops = {
168 .name = "eSE Echo Hardware (fake)",
169 .open = &echo_open,
170 .hw_receive = &echo_receive,
171 .hw_transmit = &echo_transmit,
172 .transceive = &echo_transceive,
173 .poll = &echo_poll,
174 .close = &echo_close,
175 .opts = &kTeq1Options,
176 .errors = kErrorMessages,
177 .errors_count = sizeof(kErrorMessages),
178 };
179 ESE_DEFINE_HW_OPS(ESE_HW_ECHO, ops);
180