1 /*
2 * Copyright (c) 2020-2022 Huawei Device Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include "spi_core.h"
10 #include "hdf_log.h"
11 #include "osal_mem.h"
12 #include "spi_if.h"
13 #include "spi_service.h"
14
15 #define HDF_LOG_TAG spi_core
16
SpiCntlrOpen(struct SpiCntlr * cntlr,uint32_t csNum)17 int32_t SpiCntlrOpen(struct SpiCntlr *cntlr, uint32_t csNum)
18 {
19 int32_t ret;
20
21 if (cntlr == NULL) {
22 HDF_LOGE("%s: invalid parameter", __func__);
23 return HDF_ERR_INVALID_PARAM;
24 }
25 if (cntlr->method == NULL || cntlr->method->Open == NULL) {
26 HDF_LOGE("%s: Open not support", __func__);
27 return HDF_ERR_NOT_SUPPORT;
28 }
29 (void)OsalMutexLock(&(cntlr->lock));
30 cntlr->curCs = csNum;
31 ret = cntlr->method->Open(cntlr);
32 (void)OsalMutexUnlock(&(cntlr->lock));
33 return ret;
34 }
35
SpiCntlrClose(struct SpiCntlr * cntlr,uint32_t csNum)36 int32_t SpiCntlrClose(struct SpiCntlr *cntlr, uint32_t csNum)
37 {
38 int32_t ret;
39
40 if (cntlr == NULL) {
41 HDF_LOGE("%s: invalid parameter", __func__);
42 return HDF_ERR_INVALID_PARAM;
43 }
44 if (cntlr->method == NULL || cntlr->method->Close == NULL) {
45 HDF_LOGE("%s: Close not support", __func__);
46 return HDF_ERR_NOT_SUPPORT;
47 }
48 (void)OsalMutexLock(&(cntlr->lock));
49 cntlr->curCs = csNum;
50 ret = cntlr->method->Close(cntlr);
51 (void)OsalMutexUnlock(&(cntlr->lock));
52 return ret;
53 }
54
SpiCntlrTransfer(struct SpiCntlr * cntlr,uint32_t csNum,struct SpiMsg * msg,uint32_t count)55 int32_t SpiCntlrTransfer(struct SpiCntlr *cntlr, uint32_t csNum, struct SpiMsg *msg, uint32_t count)
56 {
57 int32_t ret;
58
59 if (cntlr == NULL) {
60 HDF_LOGE("%s: invalid parameter", __func__);
61 return HDF_ERR_INVALID_PARAM;
62 }
63 if (cntlr->method == NULL || cntlr->method->Transfer == NULL) {
64 HDF_LOGE("%s: transfer not support", __func__);
65 return HDF_ERR_NOT_SUPPORT;
66 }
67
68 (void)OsalMutexLock(&(cntlr->lock));
69 cntlr->curCs = csNum;
70 ret = cntlr->method->Transfer(cntlr, msg, count);
71 (void)OsalMutexUnlock(&(cntlr->lock));
72 return ret;
73 }
74
SpiCntlrSetCfg(struct SpiCntlr * cntlr,uint32_t csNum,struct SpiCfg * cfg)75 int32_t SpiCntlrSetCfg(struct SpiCntlr *cntlr, uint32_t csNum, struct SpiCfg *cfg)
76 {
77 int32_t ret;
78
79 if (cntlr == NULL) {
80 HDF_LOGE("%s: invalid parameter", __func__);
81 return HDF_ERR_INVALID_PARAM;
82 }
83
84 if (cntlr->method == NULL || cntlr->method->SetCfg == NULL) {
85 HDF_LOGE("%s: not support", __func__);
86 return HDF_ERR_NOT_SUPPORT;
87 }
88
89 (void)OsalMutexLock(&(cntlr->lock));
90 cntlr->curCs = csNum;
91 ret = cntlr->method->SetCfg(cntlr, cfg);
92 (void)OsalMutexUnlock(&(cntlr->lock));
93 return ret;
94 }
95
SpiCntlrGetCfg(struct SpiCntlr * cntlr,uint32_t csNum,struct SpiCfg * cfg)96 int32_t SpiCntlrGetCfg(struct SpiCntlr *cntlr, uint32_t csNum, struct SpiCfg *cfg)
97 {
98 int32_t ret;
99
100 if (cntlr == NULL) {
101 HDF_LOGE("%s: invalid parameter", __func__);
102 return HDF_ERR_INVALID_PARAM;
103 }
104
105 if (cntlr->method == NULL || cntlr->method->GetCfg == NULL) {
106 HDF_LOGE("%s: not support", __func__);
107 return HDF_ERR_NOT_SUPPORT;
108 }
109
110 (void)OsalMutexLock(&(cntlr->lock));
111 cntlr->curCs = csNum;
112 ret = cntlr->method->GetCfg(cntlr, cfg);
113 (void)OsalMutexUnlock(&(cntlr->lock));
114 return ret;
115 }
116
SpiMsgsRwProcess(struct HdfSBuf * data,uint32_t count,uint8_t * tmpFlag,struct SpiMsg * msgs,uint32_t * lenReply)117 static int32_t SpiMsgsRwProcess(
118 struct HdfSBuf *data, uint32_t count, uint8_t *tmpFlag, struct SpiMsg *msgs, uint32_t *lenReply)
119 {
120 int32_t i;
121 uint32_t len;
122 uint8_t *buf = NULL;
123 uint32_t rbufLen;
124 struct SpiUserMsg *userMsg = NULL;
125
126 for (i = 0; i < count; i++) {
127 if ((!HdfSbufReadBuffer(data, (const void **)&userMsg, &len)) || (userMsg == NULL) ||
128 (len != sizeof(struct SpiUserMsg))) {
129 HDF_LOGE("%s: read msg[%d] userMsg fail!", __func__, i);
130 return HDF_ERR_IO;
131 }
132
133 msgs[i].len = userMsg->len;
134 msgs[i].speed = userMsg->speed;
135 msgs[i].delayUs = userMsg->delayUs;
136 msgs[i].keepCs = userMsg->keepCs;
137 msgs[i].rbuf = NULL;
138 msgs[i].wbuf = NULL;
139 if ((userMsg->rwFlag & SPI_USER_MSG_READ) == SPI_USER_MSG_READ) {
140 (*lenReply) += msgs[i].len;
141 msgs[i].rbuf = tmpFlag; // tmpFlag is not mainpulated, only to mark rbuf not NULL
142 }
143 if ((userMsg->rwFlag & SPI_USER_MSG_WRITE) == SPI_USER_MSG_WRITE) {
144 if ((!HdfSbufReadBuffer(data, (const void **)&buf, &len)) || (buf == NULL) || (len != msgs[i].len)) {
145 HDF_LOGE("%s: read msg[%d] wbuf fail, len[%u], msgs[i].len[%u]!", __func__, i, len, msgs[i].len);
146 } else {
147 msgs[i].wbuf = buf;
148 }
149 }
150 }
151
152 if ((!HdfSbufReadUint32(data, &rbufLen)) || (rbufLen != *lenReply)) {
153 HDF_LOGE("%s: read rbufLen failed %u != %u!", __func__, rbufLen, *lenReply);
154 return HDF_ERR_IO;
155 }
156
157 return HDF_SUCCESS;
158 }
159
160 // data format:csNum -- count -- count data records:SpiUserMsg( if write data has write buffer data) -- rbufLen
SpiTransferRebuildMsgs(struct HdfSBuf * data,struct SpiMsg ** ppmsgs,uint32_t * pcount,uint8_t ** ppbuf)161 static int32_t SpiTransferRebuildMsgs(struct HdfSBuf *data, struct SpiMsg **ppmsgs, uint32_t *pcount, uint8_t **ppbuf)
162 {
163 uint32_t count;
164 int32_t i;
165 uint32_t lenReply = 0;
166 uint8_t *buf = NULL;
167 uint8_t tmpFlag = 0;
168 uint8_t *bufReply = NULL;
169 struct SpiMsg *msgs = NULL;
170
171 if (!HdfSbufReadUint32(data, &count) || (count == 0)) {
172 HDF_LOGE("%s: read count failed!", __func__);
173 return HDF_ERR_IO;
174 }
175
176 msgs = OsalMemCalloc(sizeof(struct SpiMsg) * count);
177 if (msgs == NULL) {
178 return HDF_ERR_MALLOC_FAIL;
179 }
180
181 if (SpiMsgsRwProcess(data, count, &tmpFlag, msgs, &lenReply) != HDF_SUCCESS) {
182 HDF_LOGE("%s: SpiMsgsRwProcess fail!", __func__);
183 return HDF_FAILURE;
184 }
185
186 if (lenReply > 0) {
187 bufReply = OsalMemCalloc(lenReply);
188 if (bufReply == NULL) {
189 return HDF_ERR_MALLOC_FAIL;
190 }
191 for (i = 0, buf = bufReply; i < count && buf < (bufReply + lenReply); i++) {
192 if (msgs[i].rbuf == &tmpFlag) {
193 msgs[i].rbuf = buf;
194 buf += msgs[i].len;
195 }
196 }
197 }
198
199 *ppmsgs = msgs;
200 *pcount = count;
201 *ppbuf = bufReply;
202
203 return HDF_SUCCESS;
204 }
205
SpiTransferWriteBackMsgs(struct HdfSBuf * reply,struct SpiMsg * msgs,uint32_t count)206 static int32_t SpiTransferWriteBackMsgs(struct HdfSBuf *reply, struct SpiMsg *msgs, uint32_t count)
207 {
208 uint32_t i;
209
210 for (i = 0; i < count; i++) {
211 if (msgs[i].rbuf == NULL) {
212 continue;
213 }
214
215 if (!HdfSbufWriteBuffer(reply, msgs[i].rbuf, msgs[i].len)) {
216 HDF_LOGE("%s: write msg[%u] reply failed!", __func__, i);
217 return HDF_ERR_IO;
218 }
219 }
220
221 return HDF_SUCCESS;
222 }
223
SpiIoTransfer(struct SpiCntlr * cntlr,uint32_t csNum,struct HdfSBuf * data,struct HdfSBuf * reply)224 static int32_t SpiIoTransfer(struct SpiCntlr *cntlr, uint32_t csNum, struct HdfSBuf *data, struct HdfSBuf *reply)
225 {
226 int32_t ret;
227 uint32_t count;
228 struct SpiMsg *msgs = NULL;
229 uint8_t *bufReply = NULL;
230
231 if (data == NULL || reply == NULL) {
232 return HDF_ERR_INVALID_PARAM;
233 }
234
235 ret = SpiTransferRebuildMsgs(data, &msgs, &count, &bufReply);
236 if (ret != HDF_SUCCESS) {
237 HDF_LOGE("%s: rebuild msgs fail:%d", __func__, ret);
238 goto EXIT;
239 }
240
241 ret = SpiCntlrTransfer(cntlr, csNum, msgs, count);
242 if (ret != HDF_SUCCESS) {
243 HDF_LOGE("%s: do transfer failed:%d", __func__, ret);
244 goto EXIT;
245 }
246
247 ret = SpiTransferWriteBackMsgs(reply, msgs, count);
248
249 EXIT:
250 OsalMemFree(bufReply);
251 OsalMemFree(msgs);
252 return ret;
253 }
254
SpiIoOpen(struct SpiCntlr * cntlr,uint32_t csNum)255 static inline int32_t SpiIoOpen(struct SpiCntlr *cntlr, uint32_t csNum)
256 {
257 return SpiCntlrOpen(cntlr, csNum);
258 }
259
SpiIoClose(struct SpiCntlr * cntlr,uint32_t csNum)260 static inline int32_t SpiIoClose(struct SpiCntlr *cntlr, uint32_t csNum)
261 {
262 return SpiCntlrClose(cntlr, csNum);
263 }
264
SpiIoSetConfig(struct SpiCntlr * cntlr,uint32_t csNum,struct HdfSBuf * data)265 static int32_t SpiIoSetConfig(struct SpiCntlr *cntlr, uint32_t csNum, struct HdfSBuf *data)
266 {
267 uint32_t len;
268 struct SpiCfg *cfg = NULL;
269
270 if (!HdfSbufReadBuffer(data, (const void **)&cfg, &len) || sizeof(*cfg) != len) {
271 HDF_LOGE("%s: read buffer failed!", __func__);
272 return HDF_ERR_IO;
273 }
274 return SpiCntlrSetCfg(cntlr, csNum, cfg);
275 }
276
SpiIoGetConfig(struct SpiCntlr * cntlr,uint32_t csNum,struct HdfSBuf * reply)277 static int32_t SpiIoGetConfig(struct SpiCntlr *cntlr, uint32_t csNum, struct HdfSBuf *reply)
278 {
279 int32_t ret;
280 struct SpiCfg cfg;
281
282 ret = SpiCntlrGetCfg(cntlr, csNum, &cfg);
283 if (ret != HDF_SUCCESS) {
284 HDF_LOGE("%s: get cfg failed!", __func__);
285 return ret;
286 }
287
288 if (!HdfSbufWriteBuffer(reply, &cfg, sizeof(cfg))) {
289 HDF_LOGE("%s: write buffer failed!", __func__);
290 return HDF_FAILURE;
291 }
292 return HDF_SUCCESS;
293 }
294
SpiIoDispatch(struct HdfDeviceIoClient * client,int cmd,struct HdfSBuf * data,struct HdfSBuf * reply)295 static int32_t SpiIoDispatch(struct HdfDeviceIoClient *client, int cmd, struct HdfSBuf *data, struct HdfSBuf *reply)
296 {
297 int32_t ret;
298 uint32_t csNum;
299 struct SpiCntlr *cntlr = NULL;
300
301 if (client == NULL || client->device == NULL || client->device->service == NULL) {
302 HDF_LOGE("%s: invalid client", __func__);
303 return HDF_ERR_INVALID_OBJECT;
304 }
305
306 cntlr = (struct SpiCntlr *)client->device->service;
307 if (data == NULL) {
308 HDF_LOGE("%s: data is NULL", __func__);
309 return HDF_ERR_INVALID_PARAM;
310 }
311
312 if (!HdfSbufReadUint32(data, &csNum)) {
313 HDF_LOGE("%s: read csNum failed!", __func__);
314 return HDF_ERR_IO;
315 }
316
317 switch (cmd) {
318 case SPI_IO_OPEN:
319 return SpiIoOpen(cntlr, csNum);
320 case SPI_IO_CLOSE:
321 return SpiIoClose(cntlr, csNum);
322 case SPI_IO_SET_CONFIG:
323 return SpiIoSetConfig(cntlr, csNum, data);
324 case SPI_IO_GET_CONFIG:
325 return SpiIoGetConfig(cntlr, csNum, reply);
326 case SPI_IO_TRANSFER:
327 return SpiIoTransfer(cntlr, csNum, data, reply);
328 default:
329 ret = HDF_ERR_NOT_SUPPORT;
330 break;
331 }
332 return ret;
333 }
334
SpiCntlrDestroy(struct SpiCntlr * cntlr)335 void SpiCntlrDestroy(struct SpiCntlr *cntlr)
336 {
337 if (cntlr == NULL) {
338 return;
339 }
340 (void)OsalMutexDestroy(&(cntlr->lock));
341 OsalMemFree(cntlr);
342 }
343
SpiCntlrCreate(struct HdfDeviceObject * device)344 struct SpiCntlr *SpiCntlrCreate(struct HdfDeviceObject *device)
345 {
346 struct SpiCntlr *cntlr = NULL;
347
348 if (device == NULL) {
349 HDF_LOGE("%s: invalid parameter", __func__);
350 return NULL;
351 }
352
353 cntlr = (struct SpiCntlr *)OsalMemCalloc(sizeof(*cntlr));
354 if (cntlr == NULL) {
355 HDF_LOGE("%s: OsalMemCalloc error", __func__);
356 return NULL;
357 }
358 cntlr->device = device;
359 device->service = &(cntlr->service);
360 device->service->Dispatch = SpiIoDispatch;
361 (void)OsalMutexInit(&cntlr->lock);
362 DListHeadInit(&cntlr->list);
363 cntlr->priv = NULL;
364 return cntlr;
365 }
366