1/*
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
17#include "include/ese/ese.h"
18#include "include/ese/log.h"
19
20#include "ese_private.h"
21
22static const char kUnknownHw[] = "unknown hw";
23static const char kNullEse[] = "NULL EseInterface";
24static const char *kEseErrorMessages[] = {
25    "Hardware supplied no transceive implementation.",
26    "Timed out polling for value.",
27};
28#define ESE_MESSAGES(x) (sizeof(x) / sizeof((x)[0]))
29
30API const char *ese_name(const struct EseInterface *ese) {
31  if (!ese) {
32    return kNullEse;
33  }
34  if (ese->ops->name) {
35    return ese->ops->name;
36  }
37  return kUnknownHw;
38}
39
40API int ese_open(struct EseInterface *ese, void *hw_opts) {
41  if (!ese) {
42    return -1;
43  }
44  ALOGV("opening interface '%s'", ese_name(ese));
45  if (ese->ops->open) {
46    return ese->ops->open(ese, hw_opts);
47  }
48  return 0;
49}
50
51API const char *ese_error_message(const struct EseInterface *ese) {
52  return ese->error.message;
53}
54
55API int ese_error_code(const struct EseInterface *ese) {
56  return ese->error.code;
57}
58
59API bool ese_error(const struct EseInterface *ese) { return ese->error.is_err; }
60
61API void ese_set_error(struct EseInterface *ese, int code) {
62  if (!ese) {
63    return;
64  }
65  /* Negative values are reserved for API wide messages. */
66  ese->error.code = code;
67  ese->error.is_err = true;
68  if (code < 0) {
69    code = -(code + 1); /* Start at 0. */
70    if ((uint32_t)(code) >= ESE_MESSAGES(kEseErrorMessages)) {
71      LOG_ALWAYS_FATAL("Unknown global error code passed to ese_set_error(%d)",
72                       code);
73    }
74    ese->error.message = kEseErrorMessages[code];
75    return;
76  }
77  if ((uint32_t)(code) >= ese->ops->errors_count) {
78    LOG_ALWAYS_FATAL("Unknown hw error code passed to ese_set_error(%d)", code);
79  }
80  ese->error.message = ese->ops->errors[code];
81}
82
83/* Blocking. */
84API int ese_transceive(struct EseInterface *ese, const uint8_t *tx_buf,
85                       uint32_t tx_len, uint8_t *rx_buf, uint32_t rx_max) {
86  uint32_t recvd = 0;
87  if (!ese) {
88    return -1;
89  }
90
91  if (ese->ops->transceive) {
92    recvd = ese->ops->transceive(ese, tx_buf, tx_len, rx_buf, rx_max);
93    return ese_error(ese) ? -1 : recvd;
94  }
95
96  if (ese->ops->hw_transmit && ese->ops->hw_receive) {
97    ese->ops->hw_transmit(ese, tx_buf, tx_len, 1);
98    if (!ese_error(ese)) {
99      recvd = ese->ops->hw_receive(ese, rx_buf, rx_max, 1);
100    }
101    return ese_error(ese) ? -1 : recvd;
102  }
103
104  ese_set_error(ese, kEseGlobalErrorNoTransceive);
105  return -1;
106}
107
108API void ese_close(struct EseInterface *ese) {
109  if (!ese) {
110    return;
111  }
112  ALOGV("closing interface '%s'", ese_name(ese));
113  if (!ese->ops->close) {
114    return;
115  }
116  ese->ops->close(ese);
117}
118