1 /*
2 * Copyright (c) 2020-2021 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("%s: filep is invalid", __func__);
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("%s: dev is invalid", __func__);
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 return HDF_ERR_INVALID_PARAM;
66 }
67 HDF_LOGE("%s: spi bus is %d, cs is %d", __func__, dev->cntlr->busNum, dev->csNum);
68 return HDF_SUCCESS;
69 }
70
SpiDevRead(struct file * filep,char * buf,size_t size)71 static ssize_t SpiDevRead(struct file *filep, char *buf, size_t size)
72 {
73 int32_t ret;
74 struct SpiMsg msg = {0};
75 uint8_t *tmpReadBuf = NULL;
76 struct SpiDev *dev = NULL;
77
78 if (buf == NULL || size == 0) {
79 HDF_LOGE("%s: buf or size %d is invalid", __func__, size);
80 return HDF_ERR_INVALID_PARAM;
81 }
82 dev = SpiDevGetDevFromFilep(filep);
83 if (dev == NULL) {
84 return HDF_ERR_INVALID_PARAM;
85 }
86 msg.len = size;
87 msg.wbuf = NULL;
88 if (LOS_IsUserAddressRange((vaddr_t)(uintptr_t)buf, size)) {
89 tmpReadBuf = (uint8_t *)OsalMemCalloc(size);
90 if (tmpReadBuf == NULL) {
91 HDF_LOGE("%s: OsalMemCalloc error", __func__);
92 return HDF_ERR_MALLOC_FAIL;
93 }
94 msg.rbuf = tmpReadBuf;
95 ret = SpiCntlrTransfer(dev->cntlr, dev->csNum, &msg, 1);
96 if (ret == HDF_SUCCESS) {
97 ret = LOS_CopyFromKernel(buf, size, tmpReadBuf, size);
98 }
99 OsalMemFree(tmpReadBuf);
100 return ret;
101 } else {
102 msg.rbuf = (uint8_t *)buf;
103 return SpiCntlrTransfer(dev->cntlr, dev->csNum, &msg, 1);
104 }
105 }
106
SpiDevWrite(struct file * filep,const char * buf,size_t size)107 static ssize_t SpiDevWrite(struct file *filep, const char *buf, size_t size)
108 {
109 int32_t ret;
110 struct SpiMsg msg = {0};
111 uint8_t *tmpWriteBuf = NULL;
112 struct SpiDev *dev = NULL;
113
114 if (buf == NULL || size == 0) {
115 HDF_LOGE("%s: buf or size %d is invalid", __func__, size);
116 return HDF_ERR_INVALID_PARAM;
117 }
118 dev = SpiDevGetDevFromFilep(filep);
119 if (dev == NULL) {
120 return HDF_ERR_INVALID_PARAM;
121 }
122 msg.len = size;
123 msg.rbuf = NULL;
124 if (LOS_IsUserAddressRange((vaddr_t)(uintptr_t)buf, size)) {
125 tmpWriteBuf = (uint8_t *)OsalMemCalloc(size);
126 if (tmpWriteBuf == NULL) {
127 HDF_LOGE("%s: OsalMemCalloc error", __func__);
128 return HDF_ERR_MALLOC_FAIL;
129 }
130 ret = LOS_CopyToKernel(tmpWriteBuf, size, buf, size);
131 if (ret != LOS_OK) {
132 OsalMemFree(tmpWriteBuf);
133 return ret;
134 }
135 msg.wbuf = tmpWriteBuf;
136 ret = SpiCntlrTransfer(dev->cntlr, dev->csNum, &msg, 1);
137 OsalMemFree(tmpWriteBuf);
138 return ret;
139 } else {
140 msg.wbuf = (uint8_t *)buf;
141 return SpiCntlrTransfer(dev->cntlr, dev->csNum, &msg, 1);
142 }
143 }
144
SpiDevGetCfg(struct SpiDev * dev,struct SpiCfg * mask,unsigned long arg)145 static int32_t SpiDevGetCfg(struct SpiDev *dev, struct SpiCfg *mask, unsigned long arg)
146 {
147 int32_t ret;
148 uint32_t tmp = 0;
149 struct SpiCfg cfg = {0};
150 struct SpiCntlr *cntlr = dev->cntlr;
151
152 if (arg == 0) {
153 HDF_LOGE("%s: arg is 0", __func__);
154 return HDF_ERR_INVALID_PARAM;
155 }
156 ret = SpiCntlrGetCfg(cntlr, dev->csNum, &cfg);
157 if (ret != HDF_SUCCESS) {
158 HDF_LOGE("%s: GetCfg error", __func__);
159 return HDF_FAILURE;
160 }
161 if (mask->mode == 1) {
162 tmp = cfg.mode;
163 HDF_LOGI("%s: get mode 0x%x", __func__, tmp);
164 } else if (mask->bitsPerWord == 1) {
165 tmp = cfg.bitsPerWord;
166 HDF_LOGI("%s: get word %u", __func__, tmp);
167 } else if (mask->maxSpeedHz == 1) {
168 tmp = cfg.maxSpeedHz;
169 HDF_LOGI("%s: get maxspeed %d", __func__, tmp);
170 }
171 ret = LOS_CopyFromKernel((void *)(uintptr_t)arg, sizeof(uint32_t), (void *)&tmp, sizeof(uint32_t));
172 if (ret != 0) {
173 HDF_LOGE("%s: memery copy error", __func__);
174 }
175 return ret;
176 }
177
SpiDevSetCfg(struct SpiDev * dev,struct SpiCfg * mask,unsigned long arg)178 static int32_t SpiDevSetCfg(struct SpiDev *dev, struct SpiCfg *mask, unsigned long arg)
179 {
180 int32_t ret;
181 uint32_t tmp;
182 struct SpiCfg cfg = {0};
183 struct SpiCntlr *cntlr = dev->cntlr;
184
185 if (arg == 0) {
186 HDF_LOGE("%s: arg is 0", __func__);
187 return HDF_ERR_INVALID_PARAM;
188 }
189 ret = LOS_CopyToKernel((void *)&tmp, sizeof(uint32_t), (void *)(uintptr_t)arg, sizeof(uint32_t));
190 if (ret != 0) {
191 HDF_LOGE("%s: memery copy error", __func__);
192 return ret;
193 }
194
195 ret = SpiCntlrGetCfg(cntlr, dev->csNum, &cfg);
196 if (ret != HDF_SUCCESS) {
197 HDF_LOGE("%s: GetCfg error", __func__);
198 return HDF_FAILURE;
199 }
200 if (mask->mode == 1) {
201 HDF_LOGI("%s: set mode 0x%x", __func__, tmp);
202 cfg.mode = tmp;
203 } else if (mask->bitsPerWord == 1) {
204 HDF_LOGI("%s: set word %u", __func__, tmp);
205 cfg.bitsPerWord = tmp;
206 } else if (mask->maxSpeedHz == 1) {
207 HDF_LOGI("%s: set maxspeed %d", __func__, tmp);
208 cfg.maxSpeedHz = tmp;
209 }
210 return SpiCntlrSetCfg(cntlr, dev->csNum, &cfg);
211 }
212
SpiDevGetIocMsgFromUser(unsigned long arg)213 static struct SpiIocMsg *SpiDevGetIocMsgFromUser(unsigned long arg)
214 {
215 int32_t ret;
216 struct SpiIocMsg *umsg = NULL;
217
218 if (arg == 0) {
219 HDF_LOGE("%s: arg is 0", __func__);
220 return NULL;
221 }
222 umsg = (struct SpiIocMsg *)OsalMemCalloc(sizeof(struct SpiIocMsg));
223 if (umsg == NULL) {
224 HDF_LOGE("%s: melloc umsg error", __func__);
225 return NULL;
226 }
227 ret = LOS_CopyToKernel((void *)umsg, sizeof(struct SpiIocMsg), (void *)(uintptr_t)arg, sizeof(struct SpiIocMsg));
228 if (ret != 0) {
229 HDF_LOGE("%s: copy to kernel error", __func__);
230 OsalMemFree(umsg);
231 return NULL;
232 }
233 return umsg;
234 }
235
SpiDevGetSpiMsgFromUser(struct SpiIocMsg * umsg)236 static struct SpiMsg *SpiDevGetSpiMsgFromUser(struct SpiIocMsg *umsg)
237 {
238 int32_t ret;
239 int32_t count;
240 struct SpiMsg *msg = NULL;
241
242 count = umsg->count;
243 msg = (struct SpiMsg *)OsalMemCalloc(sizeof(struct SpiMsg) * count + sizeof(struct SpiMsg) * count);
244 if (msg == NULL) {
245 HDF_LOGE("%s: melloc msg error", __func__);
246 return NULL;
247 }
248 ret = LOS_CopyToKernel((void *)msg, sizeof(struct SpiMsg) * count,
249 (void *)(umsg->msg), sizeof(struct SpiMsg) * count);
250 if (ret != 0) {
251 HDF_LOGE("%s: copy to kernel error", __func__);
252 OsalMemFree(msg);
253 return NULL;
254 }
255 return msg;
256 }
257
SpiDevRealTransfer(struct SpiDev * dev,struct SpiMsg * msg,struct SpiMsg * kmsg,int32_t count)258 static int32_t SpiDevRealTransfer(struct SpiDev *dev, struct SpiMsg *msg, struct SpiMsg *kmsg, int32_t count)
259 {
260 int32_t i;
261 int32_t len = 0;
262 uint32_t pos = 0;
263 uint8_t *wbuf = NULL;
264 uint8_t *rbuf = NULL;
265
266 for (i = 0; i < count; i++) {
267 len += msg[i].len;
268 }
269 if (len <= 0) {
270 HDF_LOGE("%s: err, msg total len is %d", __func__, len);
271 return HDF_ERR_INVALID_PARAM;
272 }
273 wbuf = (uint8_t *)OsalMemCalloc(sizeof(uint8_t) * (len + len));
274 if (wbuf == NULL) {
275 HDF_LOGE("%s: melloc wbuf error", __func__);
276 return HDF_ERR_MALLOC_FAIL;
277 }
278 rbuf = wbuf + sizeof(uint8_t) * len;
279 for (i = 0; i < count; i++) {
280 if (LOS_CopyToKernel(wbuf + pos, msg[i].len, (void *)msg[i].wbuf, msg[i].len) != 0) {
281 HDF_LOGE("%s: copy to kernel error", __func__);
282 OsalMemFree(wbuf);
283 return HDF_ERR_IO;
284 }
285 kmsg[i].wbuf = wbuf + pos;
286 kmsg[i].rbuf = rbuf + pos;
287 kmsg[i].len = msg[i].len;
288 kmsg[i].keepCs = msg[i].keepCs;
289 kmsg[i].delayUs = msg[i].delayUs;
290 kmsg[i].speed = msg[i].speed;
291 pos += msg[i].len;
292 }
293 if (SpiCntlrTransfer(dev->cntlr, dev->csNum, kmsg, count) != HDF_SUCCESS) {
294 HDF_LOGE("%s: transfer error", __func__);
295 OsalMemFree(wbuf);
296 return HDF_FAILURE;
297 }
298 for (i = 0; i < count; i++) {
299 if (LOS_CopyFromKernel((void *)msg[i].rbuf, msg[i].len, (void *)kmsg[i].rbuf, msg[i].len) != 0) {
300 HDF_LOGE("%s: copy from kernel error", __func__);
301 OsalMemFree(wbuf);
302 return HDF_ERR_IO;
303 }
304 }
305 OsalMemFree(wbuf);
306 return HDF_SUCCESS;
307 }
308
SpiDevTransfer(struct SpiDev * dev,unsigned long arg)309 static int32_t SpiDevTransfer(struct SpiDev *dev, unsigned long arg)
310 {
311 int32_t ret;
312 int32_t count;
313 struct SpiMsg *msg = NULL;
314 struct SpiMsg *kmsg = NULL;
315 struct SpiIocMsg *umsg = NULL;
316
317 if (!LOS_IsUserAddressRange((vaddr_t)(uintptr_t)arg, sizeof(struct SpiIocMsg))) {
318 umsg = (struct SpiIocMsg *)(uintptr_t)arg;
319 return SpiCntlrTransfer(dev->cntlr, dev->csNum, umsg->msg, umsg->count);
320 }
321 umsg = SpiDevGetIocMsgFromUser(arg);
322 if (umsg == NULL) {
323 HDF_LOGE("%s: melloc umsg error", __func__);
324 return HDF_ERR_MALLOC_FAIL;
325 }
326 count = umsg->count;
327 if (count <= 0) {
328 HDF_LOGE("%s: umsg error", __func__);
329 OsalMemFree(umsg);
330 return HDF_ERR_INVALID_OBJECT;
331 }
332 msg = SpiDevGetSpiMsgFromUser(umsg);
333 if (msg == NULL) {
334 OsalMemFree(umsg);
335 return HDF_ERR_IO;
336 }
337 kmsg = msg + count;
338 ret = SpiDevRealTransfer(dev, msg, kmsg, count);
339 if (ret != HDF_SUCCESS) {
340 HDF_LOGE("%s: spi dev transfer error %d", __func__, ret);
341 }
342 OsalMemFree(msg);
343 OsalMemFree(umsg);
344 return ret;
345 }
346
SpiDevIoctl(struct file * filep,int32_t cmd,unsigned long arg)347 static int32_t SpiDevIoctl(struct file *filep, int32_t cmd, unsigned long arg)
348 {
349 int ret;
350 struct SpiCfg mask = {0};
351 struct SpiDev *dev = NULL;
352
353 dev = SpiDevGetDevFromFilep(filep);
354 if (dev == NULL) {
355 return HDF_ERR_INVALID_PARAM;
356 }
357 switch (cmd) {
358 case SPI_IOC_MESSAGE:
359 ret = SpiDevTransfer(dev, arg);
360 break;
361 case SPI_IOC_RD_MODE:
362 mask.mode = 1;
363 ret = SpiDevGetCfg(dev, &mask, arg);
364 break;
365 case SPI_IOC_RD_BITS_PER_WORD:
366 mask.bitsPerWord = 1;
367 ret = SpiDevGetCfg(dev, &mask, arg);
368 break;
369 case SPI_IOC_RD_MAX_SPEED_HZ:
370 mask.maxSpeedHz = 1;
371 ret = SpiDevGetCfg(dev, &mask, arg);
372 break;
373 case SPI_IOC_WR_MODE:
374 mask.mode = 1;
375 ret = SpiDevSetCfg(dev, &mask, arg);
376 break;
377 case SPI_IOC_WR_BITS_PER_WORD:
378 mask.bitsPerWord = 1;
379 ret = SpiDevSetCfg(dev, &mask, arg);
380 break;
381 case SPI_IOC_WR_MAX_SPEED_HZ:
382 mask.maxSpeedHz = 1;
383 ret = SpiDevSetCfg(dev, &mask, arg);
384 break;
385 default:
386 HDF_LOGE("%s: cmd %d not support", __func__, cmd);
387 ret = HDF_ERR_NOT_SUPPORT;
388 break;
389 }
390 return ret;
391 }
392
393 const struct file_operations_vfs g_spiDevFops = {
394 .open = SpiDevOpen,
395 .read = SpiDevRead,
396 .write = SpiDevWrite,
397 .ioctl = SpiDevIoctl,
398 };
399
400 #define MAX_DEV_NAME_SIZE 32
SpiAddRemoveDev(struct SpiDev * dev,bool add)401 static void SpiAddRemoveDev(struct SpiDev *dev, bool add)
402 {
403 int32_t ret;
404 char *devName = NULL;
405
406 if (dev == NULL || dev->cntlr == NULL) {
407 HDF_LOGE("%s invalid parameter", __func__);
408 return;
409 }
410 devName = (char *)OsalMemCalloc(sizeof(char) * (MAX_DEV_NAME_SIZE + 1));
411 if (devName == NULL) {
412 HDF_LOGE("%s: OsalMemCalloc error", __func__);
413 return;
414 }
415 ret = snprintf_s(devName, MAX_DEV_NAME_SIZE + 1, MAX_DEV_NAME_SIZE, "/dev/spidev%u.%u",
416 dev->cntlr->busNum, dev->csNum);
417 if (ret < 0) {
418 HDF_LOGE("%s snprintf_s failed", __func__);
419 OsalMemFree(devName);
420 return;
421 }
422 if (add) {
423 HDF_LOGI("create /dev/spidev%u.%u", dev->cntlr->busNum, dev->csNum);
424 if (register_driver(devName, &g_spiDevFops, HDF_SPI_FS_MODE, dev) != HDF_SUCCESS) {
425 HDF_LOGE("%s: gen /dev/spidev%u.%u", __func__, dev->cntlr->busNum, dev->csNum);
426 }
427 } else {
428 if (unregister_driver(devName) != HDF_SUCCESS) {
429 HDF_LOGE("%s: remove /dev/spidev%u.%u", __func__, dev->cntlr->busNum, dev->csNum);
430 }
431 }
432 OsalMemFree(devName);
433 }
434
SpiAddDev(struct SpiDev * device)435 void SpiAddDev(struct SpiDev *device)
436 {
437 SpiAddRemoveDev(device, true);
438 }
439
SpiRemoveDev(struct SpiDev * device)440 void SpiRemoveDev(struct SpiDev *device)
441 {
442 SpiAddRemoveDev(device, false);
443 }
444 #else
SpiAddDev(struct SpiDev * device)445 void SpiAddDev(struct SpiDev *device)
446 {
447 if (device != NULL && device->cntlr != NULL) {
448 HDF_LOGE("%s: add /dev/spidev%d.%d error", __func__, device->csNum, device->cntlr->busNum);
449 }
450 HDF_LOGE("%s: LOSCFG_FS_VFS not define", __func__);
451 }
452
SpiRemoveDev(struct SpiDev * device)453 void SpiRemoveDev(struct SpiDev *device)
454 {
455 if (device != NULL && device->cntlr != NULL) {
456 HDF_LOGE("%s: remove /dev/spidev%d.%d error", __func__, device->csNum, device->cntlr->busNum);
457 }
458 HDF_LOGE("%s: LOSCFG_FS_VFS not define", __func__);
459 }
460 #endif /* end of LOSCFG_FS_VFS */
461