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