1 /*
2 * Copyright (c) 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 "errno.h"
32 #include "fs/fs.h"
33 #include "los_config.h"
34 #include "los_mux.h"
35 #include "stdio.h"
36 #include "string.h"
37 #include "user_copy.h"
38
39 #include "hdf_log.h"
40 #include "mtd_char.h"
41 #include "mtd_core.h"
42 #include "mtd_legacy_lite.h"
43 #include "mtd_partition.h"
44 #include "mtd_user.h"
45 #include "osal_mem.h"
46
47 struct MtdFileInfo {
48 unsigned int partIndex;
49 int mode;
50 };
51
52 /*
53 * open device interface
54 */
MtdCharOpen(FAR struct file * filep)55 static int MtdCharOpen(FAR struct file *filep)
56 {
57 struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
58 mtd_partition *partition = (mtd_partition *)drv->priv;
59 struct MtdFileInfo *mfi = NULL;
60
61 if (partition->user_num != 0) { // be opened
62 return -EBUSY;
63 }
64
65 mfi = (struct MtdFileInfo *)malloc(sizeof(*mfi));
66 if (mfi == NULL) {
67 PRINTK("%s: malloc mtd file info failed", __func__);
68 return -ENOMEM;
69 }
70
71 (void)LOS_MuxLock(&partition->lock, LOS_WAIT_FOREVER);
72
73 partition->user_num = 1;
74
75 (void)LOS_MuxUnlock(&partition->lock);
76 mfi->partIndex = partition->patitionnum;
77 filep->f_pos = 0;
78 filep->f_priv = (void *)mfi;
79
80 return ENOERR;
81 }
82
83 /*
84 * close device interface
85 */
MtdCharClose(FAR struct file * filep)86 static int MtdCharClose(FAR struct file *filep)
87 {
88 struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
89 mtd_partition *partition = (mtd_partition *)drv->priv;
90 struct MtdFileInfo *mfi = (struct MtdFileInfo *)(filep->f_priv);
91
92 (void)LOS_MuxLock(&partition->lock, LOS_WAIT_FOREVER);
93
94 partition->user_num = 0;
95
96 (void)LOS_MuxUnlock(&partition->lock);
97 free(mfi);
98 filep->f_priv = NULL;
99
100 return ENOERR;
101 }
102
103 /*
104 * read device interface
105 */
MtdCharRead(FAR struct file * filep,FAR char * buffer,size_t buflen)106 static ssize_t MtdCharRead(FAR struct file *filep, FAR char *buffer, size_t buflen)
107 {
108 ssize_t ret = 0;
109 off_t ppos = filep->f_pos;
110 struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
111 mtd_partition *partition = (mtd_partition *)drv->priv;
112 struct MtdFileInfo *mfi = (struct MtdFileInfo *)filep->f_priv;
113 struct MtdDev *mtdDev = (struct MtdDev *)(partition->mtd_info);
114 struct MtdDevice *mtdDevice = (struct MtdDevice *)mtdDev->priv;
115 size_t blockSize = mtdDevice->eraseSize;
116 size_t partStart = partition->start_block * blockSize;
117 size_t partSize = (partition->end_block + 1 - partition->start_block) * blockSize;
118 size_t partOobSize = (partSize >> mtdDevice->writeSizeShift) * mtdDevice->oobSize;
119
120 (void)LOS_MuxLock(&partition->lock, LOS_WAIT_FOREVER);
121 if (ppos < 0 || ppos > partSize) {
122 PRINTK("%s: current file offset:0x%x invalid\n", __func__, ppos);
123 ret = -EINVAL;
124 goto out1;
125 }
126
127 if ((mfi->mode == MTD_FILE_MODE_OOB && (ppos + buflen) > (partSize + partOobSize)) ||
128 (mfi->mode != MTD_FILE_MODE_OOB && (ppos + buflen) > partSize)) {
129 PRINTK("%s: buffer to large, buflen:0x%x\n", __func__, buflen);
130 ret = -EINVAL;
131 goto out1;
132 }
133
134 if (!buflen) {
135 ret = ENOERR;
136 goto out1;
137 }
138
139 if (mfi->mode == MTD_FILE_MODE_OOB) {
140 ret = MtdDeviceReadWithOob(mtdDevice, partStart + ppos, buflen, (uint8_t *)buffer);
141 } else {
142 ret = MtdDeviceRead(mtdDevice, partStart + ppos, buflen, (uint8_t *)buffer);
143 }
144
145 if (ret != HDF_SUCCESS) {
146 PRINTK("%s: read err in mode %d\n", __func__, mfi->mode);
147 goto out1;
148 }
149
150 filep->f_pos += (mfi->mode == MTD_FILE_MODE_OOB) ?
151 (buflen - (buflen >> mtdDevice->writeSizeShift) * mtdDevice->oobSize) : buflen;
152
153 out1:
154 (void)LOS_MuxUnlock(&partition->lock);
155 return ret;
156 }
157
158 /*
159 * write device interface
160 */
MtdCharWrite(FAR struct file * filep,FAR const char * buffer,size_t buflen)161 static ssize_t MtdCharWrite(FAR struct file *filep, FAR const char *buffer, size_t buflen)
162 {
163 ssize_t ret = 0;
164 off_t ppos = filep->f_pos;
165 struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
166 mtd_partition *partition = (mtd_partition *)drv->priv;
167 struct MtdFileInfo *mfi = (struct MtdFileInfo *)filep->f_priv;
168 struct MtdDev *mtdDev = (struct MtdDev *)(partition->mtd_info);
169 struct MtdDevice *mtdDevice = (struct MtdDevice *)mtdDev->priv;
170 size_t blockSize = mtdDevice->eraseSize;
171 size_t partStart = partition->start_block * blockSize;
172 size_t partSize = (partition->end_block + 1 - partition->start_block) * blockSize;
173 size_t partOobSize = (partSize >> mtdDevice->writeSizeShift) * mtdDevice->oobSize;
174
175
176 (void)LOS_MuxLock(&partition->lock, LOS_WAIT_FOREVER);
177 if (ppos < 0 || ppos > partSize) {
178 PRINTK("%s: current file offset:0x%x invalid\n", __func__, ppos);
179 ret = -EINVAL;
180 goto out1;
181 }
182
183 if ((mfi->mode == MTD_FILE_MODE_OOB && (ppos + buflen) > (partSize + partOobSize)) ||
184 (mfi->mode != MTD_FILE_MODE_OOB && (ppos + buflen) > partSize)) {
185 PRINTK("%s: buffer to large, buflen:0x%x\n", __func__, buflen);
186 ret = -EINVAL;
187 goto out1;
188 }
189
190 if (!buflen) {
191 ret = 0;
192 goto out1;
193 }
194
195 if (mfi->mode == MTD_FILE_MODE_OOB) {
196 ret = MtdDeviceWriteWithOob(mtdDevice, partStart + ppos, buflen, (const uint8_t *)buffer);
197 } else {
198 ret = MtdDeviceWrite(mtdDevice, partStart + ppos, buflen, (const uint8_t *)buffer);
199 }
200
201 if (ret != HDF_SUCCESS) {
202 PRINTK("%s: write err in mode %d\n", __func__, mfi->mode);
203 goto out1;
204 }
205
206 filep->f_pos += (mfi->mode == MTD_FILE_MODE_OOB) ?
207 (buflen - (buflen >> mtdDevice->writeSizeShift) * mtdDevice->oobSize) : buflen;
208
209 out1:
210 (void)LOS_MuxUnlock(&partition->lock);
211 return ret;
212 }
213
214 /*
215 * lseek device interface
216 */
MtdCharLseek(FAR struct file * filep,off_t offset,int whence)217 static off_t MtdCharLseek(FAR struct file *filep, off_t offset, int whence)
218 {
219 struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
220 mtd_partition *partition = (mtd_partition *)drv->priv;
221
222 (void)LOS_MuxLock(&partition->lock, LOS_WAIT_FOREVER);
223
224 struct MtdDev *mtdDev = (struct MtdDev *)(partition->mtd_info);
225 size_t blockSize = mtdDev->eraseSize;
226 size_t endAddr = (partition->end_block + 1) * blockSize;
227 size_t startAddr = partition->start_block * blockSize;
228
229 switch (whence) {
230 case SEEK_SET:
231 if (offset >= 0 && (size_t)offset < endAddr - startAddr) {
232 filep->f_pos = (size_t)offset;
233 goto out1;
234 } else {
235 goto err1;
236 }
237
238 case SEEK_CUR:
239 if (offset + (size_t)filep->f_pos >= 0 &&
240 (size_t)(offset + filep->f_pos) < (endAddr - startAddr)) {
241 filep->f_pos += offset;
242 goto out1;
243 } else {
244 goto err1;
245 }
246
247 case SEEK_END:
248 if (offset < 0 && (offset + endAddr) >= startAddr) {
249 filep->f_pos = (off_t)(offset + endAddr - startAddr);
250 goto out1;
251 } else {
252 goto err1;
253 }
254
255 default:
256 goto err1;
257 }
258 err1:
259 (void)LOS_MuxUnlock(&partition->lock);
260 return -EINVAL;
261 out1:
262 (void)LOS_MuxUnlock(&partition->lock);
263 return filep->f_pos;
264 }
265
MtdCharGetMtdInfo(const struct MtdDevice * mtdDevice,struct MtdInfo * mtdInfo)266 static void MtdCharGetMtdInfo(const struct MtdDevice *mtdDevice, struct MtdInfo *mtdInfo)
267 {
268 mtdInfo->type = (mtdDevice->type == MTD_TYPE_NOR || mtdDevice->type == MTD_TYPE_SPI_NOR) ?
269 MTD_NORFLASH : MTD_NANDFLASH;
270 mtdInfo->size = mtdDevice->capacity;
271 mtdInfo->erasesize = mtdDevice->eraseSize;
272 mtdInfo->writesize = mtdDevice->writeSize;
273 mtdInfo->oobsize = mtdDevice->oobSize;
274 }
275
MtdCharIoctlGetInfo(const mtd_partition * part,const struct MtdDevice * mtdDevice,int cmd,unsigned long arg)276 static int MtdCharIoctlGetInfo(const mtd_partition *part, const struct MtdDevice *mtdDevice,
277 int cmd, unsigned long arg)
278 {
279 int ret;
280 struct MtdInfo mtdInfo;
281 size_t startAddr;
282 size_t endAddr;
283
284 (void)cmd;
285
286 MtdCharGetMtdInfo(mtdDevice, &mtdInfo);
287 startAddr = part->start_block * mtdDevice->eraseSize;
288 endAddr = (part->end_block + 1) * mtdDevice->eraseSize;
289 ret = LOS_CopyFromKernel((void *)(uintptr_t)arg, sizeof(mtdInfo), (void *)&mtdInfo, sizeof(mtdInfo));
290 if (ret == 0) {
291 ((struct MtdInfo *)(uintptr_t)arg)->size = endAddr - startAddr;
292 }
293 return ret;
294 }
295
MtdCharIoctlErase(const mtd_partition * part,struct MtdDevice * mtdDevice,int cmd,unsigned long arg)296 static int MtdCharIoctlErase(const mtd_partition *part, struct MtdDevice *mtdDevice,
297 int cmd, unsigned long arg)
298 {
299 int ret;
300 struct EraseInfo erase;
301 size_t startAddr;
302
303 (void)cmd;
304 ret = LOS_CopyToKernel((void *)&erase, sizeof(erase), (void *)(uintptr_t)arg, sizeof(erase));
305 if (ret != 0) {
306 return -EINVAL;
307 }
308
309 startAddr = part->start_block * mtdDevice->eraseSize;
310 return (int)MtdDeviceErase(mtdDevice, startAddr + erase.start, startAddr + erase.length, NULL);
311 }
312
MtdCharIoctlGetBadBlock(const mtd_partition * part,struct MtdDevice * mtdDevice,int cmd,unsigned long arg)313 static int MtdCharIoctlGetBadBlock(const mtd_partition *part, struct MtdDevice *mtdDevice,
314 int cmd, unsigned long arg)
315 {
316 int ret;
317 loff_t offs;
318 size_t startAddr;
319
320 (void)cmd;
321 ret = LOS_CopyToKernel((void *)&offs, sizeof(offs), (void *)(uintptr_t)arg, sizeof(offs));
322 if (ret != 0) {
323 return -EINVAL;
324 }
325
326 startAddr = part->start_block * mtdDevice->eraseSize;
327 return (int)MtdDeviceIsBadBlock(mtdDevice, (loff_t)startAddr + offs);
328 }
329
MtdCharIoctlSetBadBlock(const mtd_partition * part,struct MtdDevice * mtdDevice,int cmd,unsigned long arg)330 static int MtdCharIoctlSetBadBlock(const mtd_partition *part, struct MtdDevice *mtdDevice,
331 int cmd, unsigned long arg)
332 {
333 int ret;
334 loff_t offs;
335 size_t startAddr;
336
337 (void)cmd;
338 ret = LOS_CopyToKernel((void *)&offs, sizeof(offs), (void *)(uintptr_t)arg, sizeof(offs));
339 if (ret != 0) {
340 return -EINVAL;
341 }
342
343 startAddr = part->start_block * mtdDevice->eraseSize;
344 return (int)MtdDeviceMarkBadBlock(mtdDevice, (loff_t)startAddr + offs);
345 }
346
347 /*
348 * ioctl device interface
349 */
MtdCharIoctl(FAR struct file * filep,int cmd,unsigned long arg)350 static int MtdCharIoctl(FAR struct file *filep, int cmd, unsigned long arg)
351 {
352 int ret = ENOERR;
353 struct drv_data *drv = (struct drv_data *)filep->f_vnode->data;
354 mtd_partition *partition = (mtd_partition *)drv->priv;
355 struct MtdFileInfo *mfi = (struct MtdFileInfo *)filep->f_priv;
356 struct MtdDev *mtdDev = (struct MtdDev *)(partition->mtd_info);
357 struct MtdDevice *mtdDevice = (struct MtdDevice *)mtdDev->priv;
358
359 (void)LOS_MuxLock(&partition->lock, LOS_WAIT_FOREVER);
360
361 switch (cmd) {
362 case MTD_IOC_GETINFO: {
363 ret = MtdCharIoctlGetInfo(partition, mtdDevice, cmd, arg);
364 }
365 case MTD_IOC_ERASE:
366 case MTD_IOC_ERASE64: {
367 ret = MtdCharIoctlErase(partition, mtdDevice, cmd, arg);
368 }
369 case MTD_IOC_GETBADBLOCK: {
370 ret = MtdCharIoctlGetBadBlock(partition, mtdDevice, cmd, arg);
371 }
372 case MTD_IOC_SETBADBLOCK: {
373 ret = MtdCharIoctlSetBadBlock(partition, mtdDevice, cmd, arg);
374 }
375 case MTD_IOC_SETFILEMODE:
376 mfi->mode = 0;
377 if (arg >= MTD_FILE_MODE_MAX) {
378 PRINTK("%s: invalid mtd file mode:%d\n", __func__, arg);
379 ret = -EINVAL;
380 break;
381 }
382 mfi->mode = arg;
383 break;
384 default:
385 ret = -EINVAL;
386 }
387
388 (void)LOS_MuxUnlock(&partition->lock);
389
390 return ret;
391 }
392
MtdCharMap(FAR struct file * filep,FAR LosVmMapRegion * region)393 static ssize_t MtdCharMap(FAR struct file* filep, FAR LosVmMapRegion *region)
394 {
395 PRINTK("%s %d, mmap is not support\n", __FUNCTION__, __LINE__);
396 return 0;
397 }
398
399 static const struct file_operations_vfs g_MtdCharFops = {
400 .open = MtdCharOpen,
401 .close = MtdCharClose,
402 .read = MtdCharRead,
403 .write = MtdCharWrite,
404 .seek = MtdCharLseek,
405 .ioctl = MtdCharIoctl,
406 .mmap = MtdCharMap,
407 #ifndef CONFIG_DISABLE_POLL
408 .poll = NULL,
409 #endif
410 .unlink = NULL,
411 };
412
ToLiteOsMtdType(enum MtdDevType hdfType)413 static int ToLiteOsMtdType(enum MtdDevType hdfType)
414 {
415 int ret = HDF_FAILURE;
416
417 switch (hdfType) {
418 case MTD_TYPE_NAND:
419 case MTD_TYPE_SPI_NAND:
420 ret = MTD_NANDFLASH;
421 break;
422 case MTD_TYPE_NOR:
423 case MTD_TYPE_SPI_NOR:
424 ret = MTD_NORFLASH;
425 break;
426 default:
427 ret = MTD_TYPE_MAX;
428 break;
429 }
430 return ret;
431 }
432
HdfMtdDevErase(struct MtdDev * mtdDev,UINT64 start,UINT64 len,UINT64 * failAddr)433 int HdfMtdDevErase(struct MtdDev *mtdDev, UINT64 start, UINT64 len, UINT64 *failAddr)
434 {
435 int ret;
436 off_t failPos;
437
438 if (mtdDev == NULL) {
439 return HDF_ERR_INVALID_OBJECT;
440 }
441 ret = MtdDeviceErase((struct MtdDevice *)mtdDev->priv, start, len, &failPos);
442 if (ret != HDF_SUCCESS) {
443 *failAddr = failPos;
444 }
445 return ret;
446 }
447
HdfMtdDevRead(struct MtdDev * mtdDev,UINT64 start,UINT64 len,const char * buf)448 int HdfMtdDevRead(struct MtdDev *mtdDev, UINT64 start, UINT64 len, const char *buf)
449 {
450 if (mtdDev == NULL) {
451 return HDF_ERR_INVALID_OBJECT;
452 }
453 return MtdDeviceRead((struct MtdDevice *)mtdDev->priv, start, len, (uint8_t *)buf);
454 }
455
HdfMtdDevWrite(struct MtdDev * mtdDev,UINT64 start,UINT64 len,const char * buf)456 int HdfMtdDevWrite(struct MtdDev *mtdDev, UINT64 start, UINT64 len, const char *buf)
457 {
458 if (mtdDev == NULL) {
459 return HDF_ERR_INVALID_OBJECT;
460 }
461 return MtdDeviceWrite((struct MtdDevice *)mtdDev->priv, start, len, (const uint8_t *)buf);
462 }
463
MtdCharGetName(struct MtdDevice * mtdDevice)464 static const char *MtdCharGetName(struct MtdDevice *mtdDevice)
465 {
466 switch (mtdDevice->type) {
467 case MTD_TYPE_SPI_NOR:
468 return "spinor";
469 case MTD_TYPE_SPI_NAND:
470 return "nand";
471 default:
472 HDF_LOGE("%s: mtd type:%d not support", __func__, mtdDevice->type);
473 return NULL;
474 }
475 }
476
MtdCharOsInit(struct MtdDevice * mtdDevice)477 int32_t MtdCharOsInit(struct MtdDevice *mtdDevice)
478 {
479 struct MtdDev *mtdDev = NULL;
480 const char *devName = NULL;
481
482 if (mtdDevice == NULL) {
483 return HDF_ERR_INVALID_OBJECT;
484 }
485
486 devName = MtdCharGetName(mtdDevice);
487 if (devName == NULL) {
488 return HDF_FAILURE;
489 }
490
491 if (GetMtdInfo(devName) == 0) {
492 HDF_LOGE("%s: MtdDev(%s) already been added", __func__, devName);
493 return HDF_ERR_NOT_SUPPORT;
494 }
495
496 mtdDev = (struct MtdDev *)OsalMemCalloc(sizeof(*mtdDev));
497 if (mtdDev == NULL) {
498 return HDF_ERR_IO;
499 }
500 mtdDev->priv = mtdDevice;
501 mtdDev->type = ToLiteOsMtdType(mtdDevice->type);
502 mtdDev->size = mtdDevice->capacity;
503 mtdDev->eraseSize = mtdDevice->eraseSize;
504 mtdDev->erase = HdfMtdDevErase;
505 mtdDev->read = HdfMtdDevRead;
506 mtdDev->write = HdfMtdDevWrite;
507 AddMtdList((char *)devName, mtdDev);
508 HDF_LOGI("%s: add MtdDev(%s) done", __func__, devName);
509 mtdDevice->osData = mtdDev;
510
511 MtdDeviceLegacyFillMtdInfo(mtdDevice);
512 return HDF_SUCCESS;
513 }
514
MtdCharOsUninit(struct MtdDevice * mtdDevice)515 void MtdCharOsUninit(struct MtdDevice *mtdDevice)
516 {
517 struct MtdDev *mtdDev = NULL;
518 const char *devName = NULL;
519
520 if (mtdDevice == NULL) {
521 return;
522 }
523
524 devName = MtdCharGetName(mtdDevice);
525 if (devName == NULL) {
526 return;
527 }
528
529 mtdDev = (struct MtdDev *)mtdDevice->osData;
530 (void)DelMtdList(mtdDev);
531 HDF_LOGI("%s: remove MtdDev(%s) done", __func__, devName);
532 }
533
GetMtdCharFops(VOID)534 const struct file_operations_vfs *GetMtdCharFops(VOID)
535 {
536 return &g_MtdCharFops;
537 }
538