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