1 // Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <string.h>
16 #include "diskio_impl.h"
17 #include "ffconf.h"
18 #include "ff.h"
19 #include "esp_log.h"
20 #include "diskio_wl.h"
21 #include "wear_levelling.h"
22 #include "esp_compiler.h"
23 
24 static const char* TAG = "ff_diskio_spiflash";
25 
26 wl_handle_t ff_wl_handles[FF_VOLUMES] = {
27         WL_INVALID_HANDLE,
28         WL_INVALID_HANDLE,
29 };
30 
ff_wl_initialize(BYTE pdrv)31 DSTATUS ff_wl_initialize (BYTE pdrv)
32 {
33     return 0;
34 }
35 
ff_wl_status(BYTE pdrv)36 DSTATUS ff_wl_status (BYTE pdrv)
37 {
38     return 0;
39 }
40 
ff_wl_read(BYTE pdrv,BYTE * buff,DWORD sector,UINT count)41 DRESULT ff_wl_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count)
42 {
43     ESP_LOGV(TAG, "ff_wl_read - pdrv=%i, sector=%i, count=%i\n", (unsigned int)pdrv, (unsigned int)sector, (unsigned int)count);
44     wl_handle_t wl_handle = ff_wl_handles[pdrv];
45     assert(wl_handle + 1);
46     esp_err_t err = wl_read(wl_handle, sector * wl_sector_size(wl_handle), buff, count * wl_sector_size(wl_handle));
47     if (unlikely(err != ESP_OK)) {
48         ESP_LOGE(TAG, "wl_read failed (%d)", err);
49         return RES_ERROR;
50     }
51     return RES_OK;
52 }
53 
ff_wl_write(BYTE pdrv,const BYTE * buff,DWORD sector,UINT count)54 DRESULT ff_wl_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count)
55 {
56     ESP_LOGV(TAG, "ff_wl_write - pdrv=%i, sector=%i, count=%i\n", (unsigned int)pdrv, (unsigned int)sector, (unsigned int)count);
57     wl_handle_t wl_handle = ff_wl_handles[pdrv];
58     assert(wl_handle + 1);
59     esp_err_t err = wl_erase_range(wl_handle, sector * wl_sector_size(wl_handle), count * wl_sector_size(wl_handle));
60     if (unlikely(err != ESP_OK)) {
61         ESP_LOGE(TAG, "wl_erase_range failed (%d)", err);
62         return RES_ERROR;
63     }
64     err = wl_write(wl_handle, sector * wl_sector_size(wl_handle), buff, count * wl_sector_size(wl_handle));
65     if (unlikely(err != ESP_OK)) {
66         ESP_LOGE(TAG, "wl_write failed (%d)", err);
67         return RES_ERROR;
68     }
69     return RES_OK;
70 }
71 
ff_wl_ioctl(BYTE pdrv,BYTE cmd,void * buff)72 DRESULT ff_wl_ioctl (BYTE pdrv, BYTE cmd, void *buff)
73 {
74     wl_handle_t wl_handle = ff_wl_handles[pdrv];
75     ESP_LOGV(TAG, "ff_wl_ioctl: cmd=%i\n", cmd);
76     assert(wl_handle + 1);
77     switch (cmd) {
78     case CTRL_SYNC:
79         return RES_OK;
80     case GET_SECTOR_COUNT:
81         *((DWORD *) buff) = wl_size(wl_handle) / wl_sector_size(wl_handle);
82         return RES_OK;
83     case GET_SECTOR_SIZE:
84         *((WORD *) buff) = wl_sector_size(wl_handle);
85         return RES_OK;
86     case GET_BLOCK_SIZE:
87         return RES_ERROR;
88     }
89     return RES_ERROR;
90 }
91 
92 
ff_diskio_register_wl_partition(BYTE pdrv,wl_handle_t flash_handle)93 esp_err_t ff_diskio_register_wl_partition(BYTE pdrv, wl_handle_t flash_handle)
94 {
95     if (pdrv >= FF_VOLUMES) {
96         return ESP_ERR_INVALID_ARG;
97     }
98     static const ff_diskio_impl_t wl_impl = {
99         .init = &ff_wl_initialize,
100         .status = &ff_wl_status,
101         .read = &ff_wl_read,
102         .write = &ff_wl_write,
103         .ioctl = &ff_wl_ioctl
104     };
105     ff_wl_handles[pdrv] = flash_handle;
106     ff_diskio_register(pdrv, &wl_impl);
107     return ESP_OK;
108 }
109 
ff_diskio_get_pdrv_wl(wl_handle_t flash_handle)110 BYTE ff_diskio_get_pdrv_wl(wl_handle_t flash_handle)
111 {
112     for (int i = 0; i < FF_VOLUMES; i++) {
113         if (flash_handle == ff_wl_handles[i]) {
114             return i;
115         }
116     }
117     return 0xff;
118 }
119 
ff_diskio_clear_pdrv_wl(wl_handle_t flash_handle)120 void ff_diskio_clear_pdrv_wl(wl_handle_t flash_handle)
121 {
122     for (int i = 0; i < FF_VOLUMES; i++) {
123         if (flash_handle == ff_wl_handles[i]) {
124             ff_wl_handles[i] = WL_INVALID_HANDLE;
125         }
126     }
127 }
128