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