• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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