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