1 /*
2 * Copyright (c) 2020-2023 Huawei Device Co., Ltd. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific prior written
16 * permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "fs/driver.h"
32 #include "securec.h"
33 #include "user_copy.h"
34 #include "hdf_log.h"
35 #include "osal_mem.h"
36 #include "spi_dev.h"
37
38 #define HDF_LOG_TAG spi_dev
39 #define HDF_SPI_FS_MODE 0660
40
41 #ifdef LOSCFG_FS_VFS
SpiDevGetDevFromFilep(struct file * filep)42 static struct SpiDev *SpiDevGetDevFromFilep(struct file *filep)
43 {
44 if (filep == NULL) {
45 HDF_LOGE("SpiDevGetDevFromFilep: filep is invalid!");
46 return NULL;
47 }
48
49 struct Vnode *vnode = filep->f_vnode;
50 struct SpiDev *dev = (struct SpiDev *)(((struct drv_data *)vnode->data)->priv);
51
52 if (dev == NULL || dev->cntlr == NULL) {
53 HDF_LOGE("SpiDevGetDevFromFilep: dev is invalid!");
54 return NULL;
55 }
56 return dev;
57 }
58
SpiDevOpen(struct file * filep)59 static int32_t SpiDevOpen(struct file *filep)
60 {
61 struct SpiDev *dev = NULL;
62
63 dev = SpiDevGetDevFromFilep(filep);
64 if (dev == NULL) {
65 HDF_LOGE("SpiDevOpen: dev is null!");
66 return HDF_ERR_INVALID_PARAM;
67 }
68 HDF_LOGE("SpiDevOpen: spi bus is %d, cs is %d!", dev->cntlr->busNum, dev->csNum);
69 return HDF_SUCCESS;
70 }
71
SpiDevRead(struct file * filep,char * buf,size_t size)72 static ssize_t SpiDevRead(struct file *filep, char *buf, size_t size)
73 {
74 int32_t ret;
75 struct SpiMsg msg = {0};
76 uint8_t *tmpReadBuf = NULL;
77 struct SpiDev *dev = NULL;
78
79 if (buf == NULL || size == 0) {
80 HDF_LOGE("SpiDevRead: buf or size %d is invalid!", size);
81 return HDF_ERR_INVALID_PARAM;
82 }
83 dev = SpiDevGetDevFromFilep(filep);
84 if (dev == NULL) {
85 HDF_LOGE("SpiDevRead: spi get dev fail!");
86 return HDF_ERR_INVALID_PARAM;
87 }
88 msg.len = size;
89 msg.wbuf = NULL;
90 if (LOS_IsUserAddressRange((vaddr_t)(uintptr_t)buf, size)) {
91 tmpReadBuf = (uint8_t *)OsalMemCalloc(size);
92 if (tmpReadBuf == NULL) {
93 HDF_LOGE("SpiDevRead: OsalMemCalloc error!");
94 return HDF_ERR_MALLOC_FAIL;
95 }
96 msg.rbuf = tmpReadBuf;
97 ret = SpiCntlrTransfer(dev->cntlr, dev->csNum, &msg, 1);
98 if (ret == HDF_SUCCESS) {
99 ret = LOS_CopyFromKernel(buf, size, tmpReadBuf, size);
100 }
101 OsalMemFree(tmpReadBuf);
102 return ret;
103 } else {
104 msg.rbuf = (uint8_t *)buf;
105 return SpiCntlrTransfer(dev->cntlr, dev->csNum, &msg, 1);
106 }
107 }
108
SpiDevWrite(struct file * filep,const char * buf,size_t size)109 static ssize_t SpiDevWrite(struct file *filep, const char *buf, size_t size)
110 {
111 int32_t ret;
112 struct SpiMsg msg = {0};
113 uint8_t *tmpWriteBuf = NULL;
114 struct SpiDev *dev = NULL;
115
116 if (buf == NULL || size == 0) {
117 HDF_LOGE("SpiDevWrite: buf or size %d is invalid!", size);
118 return HDF_ERR_INVALID_PARAM;
119 }
120 dev = SpiDevGetDevFromFilep(filep);
121 if (dev == NULL) {
122 HDF_LOGE("SpiDevWrite: spi get dev fail!");
123 return HDF_ERR_INVALID_PARAM;
124 }
125 msg.len = size;
126 msg.rbuf = NULL;
127 if (LOS_IsUserAddressRange((vaddr_t)(uintptr_t)buf, size)) {
128 tmpWriteBuf = (uint8_t *)OsalMemCalloc(size);
129 if (tmpWriteBuf == NULL) {
130 HDF_LOGE("SpiDevWrite: OsalMemCalloc error!");
131 return HDF_ERR_MALLOC_FAIL;
132 }
133 ret = LOS_CopyToKernel(tmpWriteBuf, size, buf, size);
134 if (ret != LOS_OK) {
135 OsalMemFree(tmpWriteBuf);
136 return ret;
137 }
138 msg.wbuf = tmpWriteBuf;
139 ret = SpiCntlrTransfer(dev->cntlr, dev->csNum, &msg, 1);
140 OsalMemFree(tmpWriteBuf);
141 return ret;
142 } else {
143 msg.wbuf = (uint8_t *)buf;
144 return SpiCntlrTransfer(dev->cntlr, dev->csNum, &msg, 1);
145 }
146 }
147
SpiDevGetCfg(struct SpiDev * dev,struct SpiCfg * mask,unsigned long arg)148 static int32_t SpiDevGetCfg(struct SpiDev *dev, struct SpiCfg *mask, unsigned long arg)
149 {
150 int32_t ret;
151 uint32_t tmp = 0;
152 struct SpiCfg cfg = {0};
153 struct SpiCntlr *cntlr = dev->cntlr;
154
155 if (arg == 0) {
156 HDF_LOGE("SpiDevGetCfg: arg is 0!");
157 return HDF_ERR_INVALID_PARAM;
158 }
159 ret = SpiCntlrGetCfg(cntlr, dev->csNum, &cfg);
160 if (ret != HDF_SUCCESS) {
161 HDF_LOGE("SpiDevGetCfg: GetCfg error!");
162 return HDF_FAILURE;
163 }
164 if (mask->mode == 1) {
165 tmp = cfg.mode;
166 HDF_LOGI("SpiDevGetCfg: get mode 0x%x!", tmp);
167 } else if (mask->bitsPerWord == 1) {
168 tmp = cfg.bitsPerWord;
169 HDF_LOGI("SpiDevGetCfg: get word %u!", tmp);
170 } else if (mask->maxSpeedHz == 1) {
171 tmp = cfg.maxSpeedHz;
172 HDF_LOGI("SpiDevGetCfg: get maxspeed %d!", tmp);
173 }
174 ret = LOS_CopyFromKernel((void *)(uintptr_t)arg, sizeof(uint32_t), (void *)&tmp, sizeof(uint32_t));
175 if (ret != 0) {
176 HDF_LOGE("SpiDevGetCfg: memery copy error!");
177 }
178 return ret;
179 }
180
SpiDevSetCfg(struct SpiDev * dev,struct SpiCfg * mask,unsigned long arg)181 static int32_t SpiDevSetCfg(struct SpiDev *dev, struct SpiCfg *mask, unsigned long arg)
182 {
183 int32_t ret;
184 uint32_t tmp;
185 struct SpiCfg cfg = {0};
186 struct SpiCntlr *cntlr = dev->cntlr;
187
188 if (arg == 0) {
189 HDF_LOGE("SpiDevSetCfg: arg is 0!");
190 return HDF_ERR_INVALID_PARAM;
191 }
192 ret = LOS_CopyToKernel((void *)&tmp, sizeof(uint32_t), (void *)(uintptr_t)arg, sizeof(uint32_t));
193 if (ret != 0) {
194 HDF_LOGE("SpiDevSetCfg: memery copy error!");
195 return ret;
196 }
197
198 ret = SpiCntlrGetCfg(cntlr, dev->csNum, &cfg);
199 if (ret != HDF_SUCCESS) {
200 HDF_LOGE("SpiDevSetCfg: GetCfg error!");
201 return HDF_FAILURE;
202 }
203 if (mask->mode == 1) {
204 HDF_LOGI("SpiDevSetCfg: set mode 0x%x!", tmp);
205 cfg.mode = tmp;
206 } else if (mask->bitsPerWord == 1) {
207 HDF_LOGI("SpiDevSetCfg: set word %u!", tmp);
208 cfg.bitsPerWord = tmp;
209 } else if (mask->maxSpeedHz == 1) {
210 HDF_LOGI("SpiDevSetCfg: set maxspeed %d!", tmp);
211 cfg.maxSpeedHz = tmp;
212 }
213 return SpiCntlrSetCfg(cntlr, dev->csNum, &cfg);
214 }
215
SpiDevGetIocMsgFromUser(unsigned long arg)216 static struct SpiIocMsg *SpiDevGetIocMsgFromUser(unsigned long arg)
217 {
218 int32_t ret;
219 struct SpiIocMsg *umsg = NULL;
220
221 if (arg == 0) {
222 HDF_LOGE("SpiDevGetIocMsgFromUser: arg is 0!");
223 return NULL;
224 }
225 umsg = (struct SpiIocMsg *)OsalMemCalloc(sizeof(struct SpiIocMsg));
226 if (umsg == NULL) {
227 HDF_LOGE("SpiDevGetIocMsgFromUser: melloc umsg error!");
228 return NULL;
229 }
230 ret = LOS_CopyToKernel((void *)umsg, sizeof(struct SpiIocMsg), (void *)(uintptr_t)arg, sizeof(struct SpiIocMsg));
231 if (ret != 0) {
232 HDF_LOGE("SpiDevGetIocMsgFromUser: copy to kernel error!");
233 OsalMemFree(umsg);
234 return NULL;
235 }
236 return umsg;
237 }
238
SpiDevGetSpiMsgFromUser(struct SpiIocMsg * umsg)239 static struct SpiMsg *SpiDevGetSpiMsgFromUser(struct SpiIocMsg *umsg)
240 {
241 int32_t ret;
242 int32_t count;
243 struct SpiMsg *msg = NULL;
244
245 count = umsg->count;
246 msg = (struct SpiMsg *)OsalMemCalloc(sizeof(struct SpiMsg) * count + sizeof(struct SpiMsg) * count);
247 if (msg == NULL) {
248 HDF_LOGE("SpiDevGetSpiMsgFromUser: melloc msg error!");
249 return NULL;
250 }
251 ret = LOS_CopyToKernel((void *)msg, sizeof(struct SpiMsg) * count,
252 (void *)(umsg->msg), sizeof(struct SpiMsg) * count);
253 if (ret != 0) {
254 HDF_LOGE("SpiDevGetSpiMsgFromUser: copy to kernel error!");
255 OsalMemFree(msg);
256 return NULL;
257 }
258 return msg;
259 }
260
SpiDevRealTransfer(struct SpiDev * dev,struct SpiMsg * msg,struct SpiMsg * kmsg,int32_t count)261 static int32_t SpiDevRealTransfer(struct SpiDev *dev, struct SpiMsg *msg, struct SpiMsg *kmsg, int32_t count)
262 {
263 int32_t i;
264 int32_t len = 0;
265 uint32_t pos = 0;
266 uint8_t *wbuf = NULL;
267 uint8_t *rbuf = NULL;
268
269 for (i = 0; i < count; i++) {
270 len += msg[i].len;
271 }
272 if (len <= 0) {
273 HDF_LOGE("SpiDevRealTransfer: err, msg total len is %d!", len);
274 return HDF_ERR_INVALID_PARAM;
275 }
276 wbuf = (uint8_t *)OsalMemCalloc(sizeof(uint8_t) * (len + len));
277 if (wbuf == NULL) {
278 HDF_LOGE("SpiDevRealTransfer: melloc wbuf error!");
279 return HDF_ERR_MALLOC_FAIL;
280 }
281 rbuf = wbuf + sizeof(uint8_t) * len;
282 for (i = 0; i < count; i++) {
283 if (LOS_CopyToKernel(wbuf + pos, msg[i].len, (void *)msg[i].wbuf, msg[i].len) != 0) {
284 HDF_LOGE("SpiDevRealTransfer: copy to kernel error!");
285 OsalMemFree(wbuf);
286 return HDF_ERR_IO;
287 }
288 kmsg[i].wbuf = wbuf + pos;
289 kmsg[i].rbuf = rbuf + pos;
290 kmsg[i].len = msg[i].len;
291 kmsg[i].keepCs = msg[i].keepCs;
292 kmsg[i].delayUs = msg[i].delayUs;
293 kmsg[i].speed = msg[i].speed;
294 pos += msg[i].len;
295 }
296 if (SpiCntlrTransfer(dev->cntlr, dev->csNum, kmsg, count) != HDF_SUCCESS) {
297 HDF_LOGE("SpiDevRealTransfer: transfer error!");
298 OsalMemFree(wbuf);
299 return HDF_FAILURE;
300 }
301 for (i = 0; i < count; i++) {
302 if (LOS_CopyFromKernel((void *)msg[i].rbuf, msg[i].len, (void *)kmsg[i].rbuf, msg[i].len) != 0) {
303 HDF_LOGE("SpiDevRealTransfer: copy from kernel error!");
304 OsalMemFree(wbuf);
305 return HDF_ERR_IO;
306 }
307 }
308 OsalMemFree(wbuf);
309 return HDF_SUCCESS;
310 }
311
SpiDevTransfer(struct SpiDev * dev,unsigned long arg)312 static int32_t SpiDevTransfer(struct SpiDev *dev, unsigned long arg)
313 {
314 int32_t ret;
315 int32_t count;
316 struct SpiMsg *msg = NULL;
317 struct SpiMsg *kmsg = NULL;
318 struct SpiIocMsg *umsg = NULL;
319
320 if (!LOS_IsUserAddressRange((vaddr_t)(uintptr_t)arg, sizeof(struct SpiIocMsg))) {
321 umsg = (struct SpiIocMsg *)(uintptr_t)arg;
322 return SpiCntlrTransfer(dev->cntlr, dev->csNum, umsg->msg, umsg->count);
323 }
324 umsg = SpiDevGetIocMsgFromUser(arg);
325 if (umsg == NULL) {
326 HDF_LOGE("SpiDevTransfer: melloc umsg error!");
327 return HDF_ERR_MALLOC_FAIL;
328 }
329 count = umsg->count;
330 if (count <= 0) {
331 HDF_LOGE("SpiDevTransfer: umsg error!");
332 OsalMemFree(umsg);
333 return HDF_ERR_INVALID_OBJECT;
334 }
335 msg = SpiDevGetSpiMsgFromUser(umsg);
336 if (msg == NULL) {
337 OsalMemFree(umsg);
338 return HDF_ERR_IO;
339 }
340 kmsg = msg + count;
341 ret = SpiDevRealTransfer(dev, msg, kmsg, count);
342 if (ret != HDF_SUCCESS) {
343 HDF_LOGE("SpiDevTransfer: spi dev transfer error: %d!", ret);
344 }
345 OsalMemFree(msg);
346 OsalMemFree(umsg);
347 return ret;
348 }
349
SpiDevIoctl(struct file * filep,int32_t cmd,unsigned long arg)350 static int32_t SpiDevIoctl(struct file *filep, int32_t cmd, unsigned long arg)
351 {
352 int ret;
353 struct SpiCfg mask = {0};
354 struct SpiDev *dev = NULL;
355
356 dev = SpiDevGetDevFromFilep(filep);
357 if (dev == NULL) {
358 HDF_LOGE("SpiDevIoctl: dev is null!");
359 return HDF_ERR_INVALID_PARAM;
360 }
361 switch (cmd) {
362 case SPI_IOC_MESSAGE:
363 ret = SpiDevTransfer(dev, arg);
364 break;
365 case SPI_IOC_RD_MODE:
366 mask.mode = 1;
367 ret = SpiDevGetCfg(dev, &mask, arg);
368 break;
369 case SPI_IOC_RD_BITS_PER_WORD:
370 mask.bitsPerWord = 1;
371 ret = SpiDevGetCfg(dev, &mask, arg);
372 break;
373 case SPI_IOC_RD_MAX_SPEED_HZ:
374 mask.maxSpeedHz = 1;
375 ret = SpiDevGetCfg(dev, &mask, arg);
376 break;
377 case SPI_IOC_WR_MODE:
378 mask.mode = 1;
379 ret = SpiDevSetCfg(dev, &mask, arg);
380 break;
381 case SPI_IOC_WR_BITS_PER_WORD:
382 mask.bitsPerWord = 1;
383 ret = SpiDevSetCfg(dev, &mask, arg);
384 break;
385 case SPI_IOC_WR_MAX_SPEED_HZ:
386 mask.maxSpeedHz = 1;
387 ret = SpiDevSetCfg(dev, &mask, arg);
388 break;
389 default:
390 HDF_LOGE("SpiDevIoctl: cmd %d is not support!", cmd);
391 ret = HDF_ERR_NOT_SUPPORT;
392 break;
393 }
394 return ret;
395 }
396
397 const struct file_operations_vfs g_spiDevFops = {
398 .open = SpiDevOpen,
399 .read = SpiDevRead,
400 .write = SpiDevWrite,
401 .ioctl = SpiDevIoctl,
402 };
403
404 #define MAX_DEV_NAME_SIZE 32
SpiAddRemoveDev(struct SpiDev * dev,bool add)405 static void SpiAddRemoveDev(struct SpiDev *dev, bool add)
406 {
407 int32_t ret;
408 char *devName = NULL;
409
410 if (dev == NULL || dev->cntlr == NULL) {
411 HDF_LOGE("SpiAddRemoveDev invalid parameter!");
412 return;
413 }
414 devName = (char *)OsalMemCalloc(sizeof(char) * (MAX_DEV_NAME_SIZE + 1));
415 if (devName == NULL) {
416 HDF_LOGE("SpiAddRemoveDev: OsalMemCalloc error!");
417 return;
418 }
419 ret = snprintf_s(devName, MAX_DEV_NAME_SIZE + 1, MAX_DEV_NAME_SIZE, "/dev/spidev%u.%u",
420 dev->cntlr->busNum, dev->csNum);
421 if (ret < 0) {
422 HDF_LOGE("SpiAddRemoveDev snprintf_s fail!");
423 OsalMemFree(devName);
424 return;
425 }
426 if (add) {
427 HDF_LOGI("create /dev/spidev%u.%u", dev->cntlr->busNum, dev->csNum);
428 if (register_driver(devName, &g_spiDevFops, HDF_SPI_FS_MODE, dev) != HDF_SUCCESS) {
429 HDF_LOGE("SpiAddRemoveDev: gen /dev/spidev%u.%u", dev->cntlr->busNum, dev->csNum);
430 }
431 } else {
432 if (unregister_driver(devName) != HDF_SUCCESS) {
433 HDF_LOGE("SpiAddRemoveDev: remove /dev/spidev%u.%u", dev->cntlr->busNum, dev->csNum);
434 }
435 }
436 OsalMemFree(devName);
437 }
438
SpiAddDev(struct SpiDev * device)439 void SpiAddDev(struct SpiDev *device)
440 {
441 SpiAddRemoveDev(device, true);
442 }
443
SpiRemoveDev(struct SpiDev * device)444 void SpiRemoveDev(struct SpiDev *device)
445 {
446 SpiAddRemoveDev(device, false);
447 }
448 #else
SpiAddDev(struct SpiDev * device)449 void SpiAddDev(struct SpiDev *device)
450 {
451 if (device != NULL && device->cntlr != NULL) {
452 HDF_LOGE("SpiAddDev: add /dev/spidev%d.%d error", device->csNum, device->cntlr->busNum);
453 }
454 HDF_LOGE("SpiAddDev: LOSCFG_FS_VFS not define");
455 }
456
SpiRemoveDev(struct SpiDev * device)457 void SpiRemoveDev(struct SpiDev *device)
458 {
459 if (device != NULL && device->cntlr != NULL) {
460 HDF_LOGE("SpiRemoveDev: remove /dev/spidev%d.%d error", device->csNum, device->cntlr->busNum);
461 }
462 HDF_LOGE("SpiRemoveDev: LOSCFG_FS_VFS not define");
463 }
464 #endif /* end of LOSCFG_FS_VFS */
465