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 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 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 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 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 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 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 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