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