7ba223245ace7581662cfaba64600ba9f2692acb
[my-code/arm.git] / betty / pffs.c
1 /*
2  * pffs.c - pseudo flash filesystem
3  *
4  * author: hackbard@hackdaworld.org
5  *
6  */
7
8 #include "pffs.h"
9
10 /*
11  * functions
12  */
13
14 #define pffs_check_magic(data) (((data)&PFFS_INDEX_MAGIC_MASK)==PFFS_INDEX_MAGIC)
15 #define pffs_fnlen(data) (((data)&PFFS_FNLEN_MASK)>>4)
16 #define pffs_daddr_msb(data) (((data)&PFFS_LEN_MSB_MASK))
17 #define pffs_sec_erase(pffs,sec) pffs->fe(pffs->base_addr|pffs->sec_addr[sec])
18
19 u32 pffs_find_index(t_pffs *pffs,u8 sector) {
20
21         u16 data;
22
23         pffs->fr(pffs->base_addr+pffs->sec_addr[sector],&data,2);
24
25         if((data&0xf000)==PFFS_INDEX_MAGIC) {
26                 pffs->index_sec=sector;
27                 return PFFS_INDEX_FOUND;
28         }
29
30         return PFFS_NO_INDEX_FOUND;
31 }
32
33 int pffs_sec_empty(t_pffs *pffs,u8 sec) {
34
35         u32 addr;
36         u16 data;
37
38         addr=pffs->base_addr|pffs->sec_addr[sec];
39
40         while(addr<(pffs->base_addr|pffs->sec_addr[sec+1])) {
41                 pffs->fr(addr,&data,2);
42                 if(data!=0xffff)
43                         return PFFS_SEC_NOT_EMPTY;
44                 addr+=2;
45         }
46
47         return PFFS_SEC_EMPTY;
48 }
49
50 int pffs_find_data_tmp(t_pffs *pffs,u8 sector) {
51
52         u32 iaddr,daddr,dend,dstart;
53         u16 data[3];
54         u8 fnlen;
55
56         iaddr=pffs->base_addr|pffs->sec_addr[pffs->index_sec];
57         dstart=pffs->sec_addr[sector];
58         dend=pffs->sec_addr[sector+1];
59
60         while(iaddr<(pffs->base_addr|pffs->sec_addr[sector+1])) {
61                 pffs->fr(iaddr,data,6);
62                 if(pffs_check_magic(data[0]))
63                         break;
64                 daddr=pffs_daddr_msb(data[0])|data[1];
65                 if((daddr+data[2]<dstart)|(daddr>=dend)) {
66                         fnlen=pffs_fnlen(data[0]);
67                         iaddr+=(6+fnlen+fnlen);
68                         continue;
69                 }
70                 else
71                         return PFFS_NO_DATA_TMP;
72         }
73
74         pffs->data_tmp_sec=sector;
75         if(pffs_sec_empty(pffs,sector)!=PFFS_SEC_EMPTY)
76                 pffs->fe(pffs->base_addr|dstart);
77
78         return PFFS_DATA_TMP_FOUND;;
79 }
80
81 int pffs_orientate(t_pffs *pffs) {
82
83         u8 sec,sec0,sec1,found;
84
85         sec0=pffs->sec_num_index[0];
86         sec1=pffs->sec_num_index[1];
87
88         found=0;
89
90         /* check index sectors */
91         if(pffs_find_index(pffs,sec0)==PFFS_INDEX_FOUND)
92                 found=1;
93         else if(pffs_find_index(pffs,sec1)==PFFS_INDEX_FOUND)
94                 found=1;
95
96         /* chose temp data sector */
97         if(found) {
98                 sec0=pffs->sec_num_data[0];
99                 sec1=pffs->sec_num_data[1];
100                 for(sec=sec1;sec>=sec0;sec--)
101                         if(pffs_find_data_tmp(pffs,sec)==PFFS_DATA_TMP_FOUND)
102                                 break;
103
104                 return PFFS_INDEX_FOUND;
105         }
106
107         /* initial run => no data + no index assumed => check whether erased! */
108         // erase index sectors
109         if(!pffs_sec_empty(pffs,sec0))
110                 pffs_sec_erase(pffs,sec0);
111         if(!pffs_sec_empty(pffs,sec1))
112                 pffs_sec_erase(pffs,sec1);
113         pffs->index_sec=sec0;
114         // erase data sectors
115         sec0=pffs->sec_num_data[0];
116         sec1=pffs->sec_num_data[1];
117         pffs->data_tmp_sec=sec1;
118         for(sec=sec0;sec<=sec1;sec++)
119                 if(!pffs_sec_empty(pffs,sec))
120                         pffs_sec_erase(pffs,sec);
121
122         return 0;
123 }
124
125 int pffs_get_data_sec(t_pffs_fd *fd) {
126
127         t_pffs *pffs;
128         u8 sec,sec0,sec1;
129
130         pffs->fd->pffs;
131         sec0=pffs->sec_num_data[0];
132         sec1=pffs->sec_num_data[1];
133
134         for(sec=sec0;sec<sec1;sec++) {
135                 if((addr<pffs->sec_addr[sec+1])&(addr>=pffs->sec_addr[sec])) {
136                         fd->data_sec=sec;
137                         break;
138                 }
139         }
140
141         return 0;
142 }
143
144 int pffs_rearrange(t_pffs *pffs) {
145
146         
147
148         return 0;
149 }
150
151 int pffs_flash_register(t_pffs *pffs,u32 base_addr,u32 *sec_addr,
152                         u8 sec_num_data_min,u8 sec_num_data_max,
153                         u8 sec_num_index0,u8 sec_num_index1,
154                         int (*fw)(u32 addr,u16 *buf,int len),
155                         int (*fr)(u32 addr,u16 *buf,int len),
156                         int (*fe)(u32 addr)) {
157
158         /* assign physical flash specs */
159         pffs->base_addr=base_addr;
160         pffs->sec_addr=sec_addr;
161
162         /* specified index and data sectors */
163         pffs->sec_num_data[0]=sec_num_data_min;
164         pffs->sec_num_data[1]=sec_num_data_max;
165         pffs->sec_num_index[0]=sec_num_index0;
166         pffs->sec_num_index[1]=sec_num_index1;
167
168         /* flash acccess function pointers */
169         pffs->fw=fw;
170         pffs->fr=fr;
171         pffs->fe=fe;
172
173         pffs->state|=PFFS_REGISTERED;
174
175         return 0;
176 }
177
178 int pffs_init(t_pffs *pffs) {
179
180         /* check whether a flash is registered */
181         if(!(pffs->state&PFFS_REGISTERED))
182                 return -1;
183
184         /* orientate */
185         pffs_orientate(pffs);
186
187         return 0;
188 }
189
190 int pffs_find_file(t_pffs *pffs,char *file,u32 *iaddr,u32 *daddr,u16 *len) {
191
192         u8 fnl;
193         u16 data[PFFS_MAX_FILENAME_SIZE+PFFS_HEADER_SIZE];
194
195         *iaddr=pffs->base_addr|pffs->sec_addr[pffs->index_sec];
196
197         while(*iaddr<pffs->sec_addr[pffs->index_sec+1]) {
198                 pffs->fr(*iaddr,data,3);
199
200                 if(!pffs_check_magic(data[0]))
201                         break;
202
203                 fnl=pffs_fnlen(data[0]);
204                 pffs->fr(*iaddr+6,data+3,fnl+fnl);
205
206                 if(!strncmp(file,(char *)(data+3),fnl+fnl)) {
207                         *daddr=pffs->base_addr|((data[0]&0x000f)<<16)|data[1];
208                         *len=data[2];
209                         return PFFS_FILE_FOUND;
210                 }
211
212                 *iaddr+=(6+fnl+fnl);
213         }
214         
215         return PFFS_FILE_NOT_FOUND;
216 }
217
218 int pffs_open_read(t_pffs_fd *fd) {
219
220         int ret;
221
222         ret=pffs_find_file(fd->pffs,fd->file,
223                            &(fd->iaddr),&(fd->daddr),&(fd->len));
224
225         if(ret==PFFS_FILE_FOUND) {
226                 fd->dptr=fd->daddr;
227                 fd->mode=PFFS_READ;
228         }
229
230         return ret;
231 }
232
233 int pffs_write_index_init(t_pffs_fd *fd) {
234
235         t_pffs *pffs;
236         u16 data[PFFS_HEADER_SIZE+PFFS_MAX_FILENAME_SIZE];
237
238         pffs=fd->pffs;
239         fns=fd->fn-size;
240
241         if(fd->iaddr+6+fns+fns>=pffs->sec_addr[pffs->index_sec+1])
242                 return PFFS_NO_INDEX_SPACE_LEFT;
243
244         data[0]=0x7f00|(fns<<4)|((fd->daddr>>16)&0xf);
245         data[1]=fd->daddr&0xffff;
246         pffs->fw(fd->iaddr,data,4);
247         pffs->fw(fd->iaddr+6,fd->file,fns+fns);
248         
249         return PFFS_INDEX_WROTE_INIT;
250 }
251
252 int pffs_write_finish(t_pffs_fd *fd) {
253
254         fd->pffs->fw(fd->iaddr+4,&(fd->len),2);
255
256         return 0;
257 }
258
259 int pffs_open_write(t_pffs_fd *fd) {
260
261         int ret;
262
263         ret=pffs_find_file(fd->pffs,fd->file,
264                            &(fd->iaddr),&(fd->daddr),&(fd->len));
265
266         switch(ret) {
267                 case PFFS_FILE_NOT_FOUND:
268                         ret=pffs_write_index_init();
269                         if(ret!=PFFS_INDEX_WROTE_INIT)
270                                 break;
271                         fd->dptr=fd->daddr;
272                         fd->len=0;
273                         fd->mode=PFFS_WRITE;
274                         break;
275                 case PFFS_FILE_FOUND:
276                 default:
277                         break;
278         }
279
280         return ret;
281 }                       
282
283 int pffs_open(t_pffs *pffs,t_pffs_fd *fd,char *file,u8 mode) {
284
285         int ret;
286
287         /* the pffs struct */
288         fd->pffs=pffs;
289
290         /* filename */
291         fd->fn_size=strlen(file);
292         if(fd->fn_size&1)
293                 fd->file[fd->fn_size++]='\0';
294         fd->fn_size>>1;
295         if(fd->fn_size>PFFS_MAX_FILENAME_SIZE)
296                 return PFFS_FILENAME_TOO_LONG;
297         strncpy(fd->file,file,fd->fn_size+fd->fn_size);
298
299         /* clear fd mode */
300         fd->mode=0;
301
302         /* action */
303         switch(mode) {
304                 case PFFS_READ:
305                         ret=pffs_open_read(fd);
306                         break;
307                 case PFFS_WRITE:
308                         ret=pffs_open_write(fd);
309                         break;
310                 case PFFS_RDWR:
311                 default:
312                         return PFFS_MODE_UNSUPPORTED;
313         }
314
315         return ret;
316 }
317
318 int pffs_read(t_pffs_fd *fd,u8 *buf,int len) {
319
320         int missing;
321         int sec_end;
322
323         /* check whether valid */
324         if(!(fd->mode&PFFS_READ))
325                 return PFFS_EINVAL;
326
327         /* check len */
328         if(len&1)
329                 return PFFS_INVALID_LEN;
330
331         /* check how much we read */
332         missing=fd->len-(fd->dptr-fd->daddr);
333         if(len>missing)
334                 len=missing;
335
336         if((fd->dptr+len)>=pffs->sec_addr[pffs->sec_num_data[1]+1])
337                 sec_end=pffs->sec_addr[pffs->sec_num_data[1]+1]-fd->dptr;
338
339
340         /* read */
341         fd->pffs->fr(fd->dptr,(u16 *)buf,len);
342         fd->dptr+=len;;
343
344         return len;
345 }
346
347 int pffs_write(t_pffs_fd *fd,u8 buf,int len) {
348
349         /* check whether valid */
350         if(!(fd->mode&PFFS_WRITE))
351                 return PFFS_EINVAL;
352
353         /* check len */
354         if(len&1)
355                 return PFFS_INVALID_LEN;
356
357         missing=PFFS_MAX_FILE_SIZE-fd->len;
358         if(len>missing)
359                 len=missing;
360
361         /* check for  */
362         if(fd->dptr+len>=pffs->)
363 }
364