• 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 "i2c_dev.h"
32 #include <fs/driver.h>
33 #include "i2c_core.h"
34 #include "osal_mem.h"
35 #include "user_copy.h"
36 
37 #define I2C_FS_MODE                 0660
38 #define I2C_RDWR_IOCTL_MAX_MSGS     42
39 #define I2C_BUF_MAX                 8192
40 #define I2C_NAME_SIZE               32
41 #define I2C_CNTLR_MAX               32
42 
43 struct I2cClient {
44     DevHandle handle;
45     struct I2cHost *host;
46     uint16_t addr;
47     uint16_t flags;
48 };
49 
I2cMsgInitFromUser(struct I2cMsg * kMsgs,struct i2c_msg * uMsgs)50 static inline int32_t I2cMsgInitFromUser(struct I2cMsg *kMsgs, struct i2c_msg *uMsgs)
51 {
52     int32_t ret;
53 
54     kMsgs->len = uMsgs->len;
55     kMsgs->addr = uMsgs->addr;
56     kMsgs->flags = uMsgs->flags;
57     if ((uMsgs->flags & I2C_M_RD) != 0) {
58         return HDF_SUCCESS;
59     }
60     ret = LOS_CopyToKernel((void *)(kMsgs->buf), kMsgs->len, (void *)(uMsgs->buf), uMsgs->len);
61     return (ret == LOS_OK) ? HDF_SUCCESS : HDF_ERR_IO;
62 }
63 
I2cMsgBackToUser(struct I2cMsg * kMsgs,struct i2c_msg * uMsgs)64 static inline int32_t I2cMsgBackToUser(struct I2cMsg *kMsgs, struct i2c_msg *uMsgs)
65 {
66     int32_t ret;
67 
68     if ((kMsgs->flags & I2C_M_RD) == 0) {
69         return HDF_SUCCESS;
70     }
71     ret = LOS_CopyFromKernel((void *)(uMsgs->buf), uMsgs->len, (void *)(kMsgs->buf), kMsgs->len);
72     return (ret == LOS_OK) ? HDF_SUCCESS : HDF_ERR_IO;
73 }
74 
I2cMsgsCopyBackToUser(I2cIoctlWrap * wrap,struct I2cMsg * kMsgs,struct i2c_msg * uMsgs)75 static inline int32_t I2cMsgsCopyBackToUser(I2cIoctlWrap *wrap,
76     struct I2cMsg *kMsgs, struct i2c_msg *uMsgs)
77 {
78     int ret;
79     unsigned int i;
80 
81     for (i = 0; i < wrap->nmsgs; i++) {
82         ret = I2cMsgBackToUser(&kMsgs[i], &uMsgs[i]);
83         if (ret != HDF_SUCCESS) {
84             break;
85         }
86     }
87     return ret;
88 }
89 
I2cMsgsDestroy(struct I2cMsg * kMsgs,struct i2c_msg * uMsgs)90 static void I2cMsgsDestroy(struct I2cMsg *kMsgs, struct i2c_msg *uMsgs)
91 {
92     if (kMsgs != NULL) {
93         if (kMsgs[0].buf != NULL) {
94             OsalMemFree(kMsgs[0].buf);
95             kMsgs[0].buf = NULL;
96         }
97     }
98     if (uMsgs != NULL) {
99         OsalMemFree(uMsgs);
100     }
101 }
102 
I2cMsgsCreateFromUser(I2cIoctlWrap * wrap,struct I2cMsg ** kMsgsPp,struct i2c_msg ** uMsgsPp)103 static int32_t I2cMsgsCreateFromUser(I2cIoctlWrap *wrap,
104     struct I2cMsg **kMsgsPp, struct i2c_msg **uMsgsPp)
105 {
106     int32_t ret;
107     size_t i;
108     size_t bufLen;
109     struct i2c_msg *uMsgs = NULL;
110     struct I2cMsg *kMsgs = NULL;
111     uint8_t *dataBuf = NULL;
112 
113     uMsgs = (struct i2c_msg *)OsalMemCalloc((sizeof(*uMsgs) + sizeof(*kMsgs)) * wrap->nmsgs);
114     if (uMsgs == NULL) {
115         return HDF_ERR_MALLOC_FAIL;
116     }
117     kMsgs = (struct I2cMsg *)((uint8_t *)uMsgs + sizeof(*uMsgs) * wrap->nmsgs);
118 
119     ret = LOS_CopyToKernel((void *)uMsgs, sizeof(*uMsgs) * wrap->nmsgs,
120         (void *)wrap->msgs, sizeof(*uMsgs) * wrap->nmsgs);
121     if (ret != LOS_OK) {
122         HDF_LOGE("%s: copy msgs from user fail!", __func__);
123         goto __ERR__;
124     }
125 
126     for (i = 0, bufLen = 0; i < wrap->nmsgs; i++) {
127         if (uMsgs[i].buf == NULL || uMsgs[i].len == 0) {
128             ret = HDF_ERR_INVALID_PARAM;
129             goto __ERR__;
130         }
131         bufLen += uMsgs[i].len;
132     }
133     if (bufLen >= I2C_BUF_MAX) {
134         HDF_LOGE("%s: buf too long:%u", __func__, bufLen);
135         ret = HDF_ERR_INVALID_PARAM;
136         goto __ERR__;
137     }
138 
139     dataBuf = (uint8_t *)OsalMemCalloc(bufLen);
140     if (dataBuf == NULL) {
141         ret = HDF_ERR_MALLOC_FAIL;
142         goto __ERR__;
143     }
144 
145     for (i = 0; i < wrap->nmsgs; i++) {
146         kMsgs[i].buf = dataBuf;
147         dataBuf += uMsgs[i].len;
148         ret = I2cMsgInitFromUser(&kMsgs[i], &uMsgs[i]);
149         if (ret != HDF_SUCCESS) {
150             goto __ERR__;
151         }
152     }
153 
154     *kMsgsPp = kMsgs;
155     *uMsgsPp = uMsgs;
156     return HDF_SUCCESS;
157 
158 __ERR__:
159     I2cMsgsDestroy(kMsgs, uMsgs);
160     return ret;
161 }
162 
I2cCntlrRead(DevHandle handle,uint16_t addr,uint8_t * buf,int16_t len,uint16_t flags)163 static int32_t I2cCntlrRead(DevHandle handle, uint16_t addr,
164     uint8_t *buf, int16_t len, uint16_t flags)
165 {
166     int32_t ret;
167     struct I2cMsg msg;
168 
169     msg.addr = addr;
170     msg.buf = buf;
171     msg.len = (uint16_t)len;
172     msg.flags = flags | I2C_FLAG_READ;
173 
174     ret = I2cTransfer(handle, &msg, 1);
175     return (ret == 1) ? HDF_SUCCESS : ret;
176 }
177 
I2cFsRead(struct file * filep,char * buf,size_t count)178 static ssize_t I2cFsRead(struct file *filep, char *buf, size_t count)
179 {
180     int32_t ret;
181     uint8_t *kbuf = NULL;
182     struct I2cClient *client = filep->f_priv;
183 
184     if (client == NULL) {
185         HDF_LOGE("%s: client is null!", __func__);
186         return 0;
187     }
188 
189     kbuf = (uint8_t *)OsalMemCalloc(count);
190     if (kbuf == NULL) {
191         HDF_LOGE("%s: malloc kbuf fail!", __func__);
192         return 0;
193     }
194 
195     ret = I2cCntlrRead(client->handle, client->addr, kbuf, count, client->flags);
196     PLAT_LOGV("%s: I2cRead called, ret:%d", __func__, ret);
197 
198     if (ret == HDF_SUCCESS) {
199         if (LOS_CopyFromKernel(buf, count, kbuf, count) != LOS_OK) {
200             HDF_LOGE("%s: copy from kernel fail:%d", __func__, ret);
201             ret = HDF_ERR_IO;
202         }
203     }
204     OsalMemFree(kbuf);
205     return (ret == HDF_SUCCESS) ? count : 0;
206 }
207 
I2cCntlrWrite(DevHandle handle,uint16_t addr,const uint8_t * buf,int16_t len,uint16_t flags)208 static int32_t I2cCntlrWrite(DevHandle handle, uint16_t addr,
209     const uint8_t *buf, int16_t len, uint16_t flags)
210 {
211     int32_t ret;
212     struct I2cMsg msg;
213 
214     msg.addr = addr;
215     msg.buf = (uint8_t *)buf;
216     msg.len = (uint16_t)len;
217     msg.flags = flags & (~I2C_FLAG_READ);
218 
219     ret = I2cTransfer(handle, &msg, 1);
220     return (ret == 1) ? HDF_SUCCESS : ret;
221 }
222 
223 
I2cFsWrite(struct file * filep,const char * buf,size_t count)224 static ssize_t I2cFsWrite(struct file *filep, const char *buf, size_t count)
225 {
226     int32_t ret;
227     uint8_t *kbuf = NULL;
228     struct I2cClient *client = filep->f_priv;
229 
230     if (client == NULL) {
231         HDF_LOGE("%s: client is null!", __func__);
232         return 0;
233     }
234 
235     kbuf = (uint8_t *)OsalMemCalloc(count);
236     if (kbuf == NULL) {
237         HDF_LOGE("%s: malloc kbuf fail!", __func__);
238         return 0;
239     }
240     if (LOS_CopyToKernel(kbuf, count, buf, count) != LOS_OK) {
241         HDF_LOGE("%s: copy to kernel fail!", __func__);
242         OsalMemFree(kbuf);
243         return 0;
244     }
245 
246     ret = I2cCntlrWrite(client->handle, client->addr, kbuf, count, client->flags);
247     PLAT_LOGV("%s: I2cWrite called, ret:%d", __func__, ret);
248 
249     OsalMemFree(kbuf);
250     return (ret == HDF_SUCCESS) ? count : 0;
251 }
252 
I2cIoctlReadWrite(const struct I2cClient * client,const void * arg)253 static int I2cIoctlReadWrite(const struct I2cClient *client, const void *arg)
254 {
255     int ret;
256     I2cIoctlWrap wrap;
257     struct i2c_msg *uMsgs = NULL;
258     struct I2cMsg *kMsgs = NULL;
259 
260     if (arg == NULL) {
261         HDF_LOGE("%s: arg is null!", __func__);
262         return HDF_ERR_INVALID_PARAM;
263     }
264 
265     ret = LOS_CopyToKernel(&wrap, sizeof(wrap), (void *)arg, sizeof(wrap));
266     if (ret != LOS_OK) {
267         HDF_LOGE("%s: copy wrap fail!", __func__);
268         return HDF_ERR_IO;
269     }
270 
271     if (wrap.msgs == NULL || wrap.nmsgs == 0 || wrap.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS) {
272         HDF_LOGE("%s: wrap msgs is null or invalid num:%u!", __func__, wrap.nmsgs);
273         return HDF_ERR_INVALID_PARAM;
274     }
275 
276     ret = I2cMsgsCreateFromUser(&wrap, &kMsgs, &uMsgs);
277     if (ret != HDF_SUCCESS) {
278         HDF_LOGE("%s: recreate msgs fail!", __func__);
279         return ret;
280     }
281 
282     ret = I2cTransfer(client->handle, kMsgs, wrap.nmsgs);
283     PLAT_LOGV("%s: I2cTransfer called, ret:%d", __func__, ret);
284     if ((unsigned int)ret == wrap.nmsgs) {
285         ret = I2cMsgsCopyBackToUser(&wrap, kMsgs, uMsgs);
286         if (ret != HDF_SUCCESS) {
287             HDF_LOGE("%s: copy back fail! ret:%d", __func__, ret);
288         }
289     } else {
290         HDF_LOGE("%s: transfer fail, ret:%d, nmsgs:%u", __func__, ret, wrap.nmsgs);
291     }
292 
293     I2cMsgsDestroy(kMsgs, uMsgs);
294     return ret;
295 }
296 
I2cFsIoctl(struct file * filep,int cmd,unsigned long arg)297 static int I2cFsIoctl(struct file *filep, int cmd, unsigned long arg)
298 {
299     int retval = ENOERR;
300     struct I2cClient *client = filep->f_priv;
301 
302     switch (cmd) {
303         case IOCTL_CLIENT_FORCE:
304         case IOCTL_CLIENT:
305             if ((((client->flags & I2C_M_TEN) == 0) && arg > 0xfe) || (arg > 0x3ff)) {
306                 HDF_LOGE("%s:Not support arg(%0lu)!!!", __func__, arg);
307                 retval = -EINVAL;
308                 break;
309             }
310             client->addr = arg;
311             break;
312         case IOCTL_RDWR: {
313             retval = I2cIoctlReadWrite(client, (void *)(uintptr_t)arg);
314             break;
315         }
316         case IOCTL_16BIT_REG:
317             if (arg == 0) {
318                 client->flags &= ~I2C_M_16BIT_REG;
319             } else {
320                 client->flags |= I2C_M_16BIT_REG;
321             }
322             break;
323         case IOCTL_16BIT_DATA:
324             if (arg == 0) {
325                 client->flags &= ~I2C_M_16BIT_DATA;
326             } else {
327                 client->flags |= I2C_M_16BIT_DATA;
328             }
329             break;
330         case IOCTL_TENBIT:
331             if (arg == 0) {
332                 client->flags &= ~I2C_M_TEN;
333             } else {
334                 client->flags |= I2C_M_TEN;
335             }
336             break;
337         case IOCTL_PEC:
338         case IOCTL_RETRIES:
339         case IOCTL_TIMEOUT:
340         default:
341             HDF_LOGE("Not support cmd(%0d)!!!", cmd);
342             retval = -EINVAL;
343     }
344     return retval;
345 }
346 
I2cFsOpen(struct file * filep)347 static int I2cFsOpen(struct file *filep)
348 {
349     DevHandle handle = NULL;
350     struct I2cClient *client = NULL;
351     struct drv_data *drvData = NULL;
352     int16_t id;
353 
354     if (filep == NULL || filep->f_vnode == NULL || filep->f_vnode->data == NULL) {
355         HDF_LOGE("%s: function parameter is null", __func__);
356         return -EINVAL;
357     }
358     drvData = (struct drv_data *)filep->f_vnode->data;
359     id = (int16_t)(uintptr_t)drvData->priv;
360 
361     handle = I2cOpen(id);
362     if (handle == NULL) {
363         HDF_LOGE("%s:Fail to get host:%d handle!", __func__, id);
364         return -1;
365     }
366 
367     client = (struct I2cClient *)OsalMemCalloc(sizeof(*client));
368     if (client == NULL) {
369         HDF_LOGE("%s:Fail to malloc client-%d!", __func__, id);
370         return -1;
371     }
372     client->handle = handle;
373 
374     /* record the client as file private data */
375     filep->f_priv = client;
376     return 0;
377 }
378 
I2cFsClose(struct file * filep)379 static int I2cFsClose(struct file *filep)
380 {
381     struct I2cClient *client = filep->f_priv;
382 
383     if (client == NULL) {
384         HDF_LOGE("%s: has't opened!", __func__);
385         return 0;
386     }
387 
388     if (client->handle == NULL) {
389         return 0;
390     }
391     I2cClose(client->handle);
392     client->handle = NULL;
393     OsalMemFree(client);
394     client = NULL;
395 
396     filep->f_priv = NULL;
397     return 0;
398 }
399 
I2cFsMap(struct file * filep,LosVmMapRegion * region)400 static ssize_t I2cFsMap(struct file* filep, LosVmMapRegion *region)
401 {
402     size_t size = region->range.size;
403 
404     (void)filep;
405     PADDR_T paddr = region->pgOff << PAGE_SHIFT;
406     VADDR_T vaddr = region->range.base;
407     LosVmSpace *space = LOS_SpaceGet(vaddr);
408 
409     if ((space == NULL) || ((paddr >= SYS_MEM_BASE) && (paddr < SYS_MEM_END))) {
410         return -EINVAL;
411     }
412 
413     if (LOS_ArchMmuMap(&space->archMmu, vaddr, paddr, size >> PAGE_SHIFT, region->regionFlags) <= 0) {
414         return -EAGAIN;
415     }
416 
417     return 0;
418 }
419 
420 static const struct file_operations_vfs g_i2cFops = {
421     .open = I2cFsOpen,
422     .close = I2cFsClose,
423     .read = I2cFsRead,
424     .write = I2cFsWrite,
425     .ioctl = I2cFsIoctl,
426     .mmap = I2cFsMap,
427 };
428 
I2cAddVfsById(int16_t id)429 int32_t I2cAddVfsById(int16_t id)
430 {
431 #ifdef LOSCFG_FS_VFS
432     int32_t ret;
433     char *name = NULL;
434 
435     if (id < 0 || id >= I2C_CNTLR_MAX) {
436         HDF_LOGE("%s: id:%d exceed max:%d", __func__, id, I2C_CNTLR_MAX);
437         return HDF_ERR_INVALID_PARAM;
438     }
439     name = (char *)OsalMemCalloc(I2C_NAME_SIZE);
440     if (name == NULL) {
441         HDF_LOGE("%s: malloc name fail!", __func__);
442         return HDF_ERR_MALLOC_FAIL;
443     }
444     /* create /dev/i2c-x device files for the i2c adatpers */
445     ret = snprintf_s(name, I2C_NAME_SIZE, I2C_NAME_SIZE - 1, "/dev/i2c-%d", id);
446     if (ret < 0) {
447         HDF_LOGE("%s: format name fail! ret:%d", __func__, ret);
448         OsalMemFree(name);
449         return ret;
450     }
451     ret = register_driver(name, &g_i2cFops, I2C_FS_MODE, (void *)((uintptr_t)id));
452     if (ret != 0) {
453         HDF_LOGE("%s: register %s fail! ret:%d", __func__, name, ret);
454     }
455     OsalMemFree(name);
456     return ret;
457 #else /* LOSCFG_FS_VFS */
458     (void)id;
459     return HDF_SUCCESS;
460 #endif
461 }
462 
I2cRemoveVfsById(int16_t id)463 void I2cRemoveVfsById(int16_t id)
464 {
465 #ifdef LOSCFG_FS_VFS
466     int32_t ret;
467     char *name = NULL;
468 
469     if (id < 0 || id >= I2C_CNTLR_MAX) {
470         HDF_LOGE("%s: id:%d exceed max:%d", __func__, id, I2C_CNTLR_MAX);
471         return;
472     }
473     name = (char *)OsalMemCalloc(I2C_NAME_SIZE);
474     if (name == NULL) {
475         HDF_LOGE("%s: malloc name fail!", __func__);
476         return;
477     }
478     /* remove /dev/i2c-x device files for the i2c controllers */
479     ret = snprintf_s(name, I2C_NAME_SIZE, I2C_NAME_SIZE - 1, "/dev/i2c-%d", id);
480     if (ret < 0) {
481         HDF_LOGE("%s: format name fail! ret:%d", __func__, ret);
482         OsalMemFree(name);
483         return;
484     }
485     ret = unregister_driver(name);
486     if (ret != 0) {
487         HDF_LOGE("%s: unregister %s fail!", __func__, name);
488     }
489     OsalMemFree(name);
490 #else
491     (void)id;
492 #endif /* LOSCFG_FS_VFS */
493 }
494