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