summaryrefslogtreecommitdiff
path: root/firmware/common/disk.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/common/disk.c')
-rw-r--r--firmware/common/disk.c451
1 files changed, 297 insertions, 154 deletions
diff --git a/firmware/common/disk.c b/firmware/common/disk.c
index 5a55a3b6ac..3a2d27e0d7 100644
--- a/firmware/common/disk.c
+++ b/firmware/common/disk.c
@@ -19,14 +19,25 @@
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#include <stdio.h> 21#include <stdio.h>
22#include <string.h>
23#include "config.h"
22#include "kernel.h" 24#include "kernel.h"
23#include "storage.h" 25#include "storage.h"
24#include "debug.h" 26#include "debug.h"
25#include "fat.h" 27#include "disk_cache.h"
26#include "dir.h" /* for release_dirs() */ 28#include "fileobj_mgr.h"
27#include "file.h" /* for release_files() */ 29#include "dir.h"
30#include "dircache_redirect.h"
28#include "disk.h" 31#include "disk.h"
29#include <string.h> 32
33#ifndef CONFIG_DEFAULT_PARTNUM
34#define CONFIG_DEFAULT_PARTNUM 0
35#endif
36
37#define disk_reader_lock() file_internal_lock_READER()
38#define disk_reader_unlock() file_internal_unlock_READER()
39#define disk_writer_lock() file_internal_lock_WRITER()
40#define disk_writer_unlock() file_internal_unlock_WRITER()
30 41
31/* Partition table entry layout: 42/* Partition table entry layout:
32 ----------------------- 43 -----------------------
@@ -42,11 +53,18 @@
42 12-15: nr of sectors in partition 53 12-15: nr of sectors in partition
43*/ 54*/
44 55
45#define BYTES2INT32(array,pos) \ 56#define BYTES2INT32(array, pos) \
46 ((long)array[pos] | ((long)array[pos+1] << 8 ) | \ 57 (((uint32_t)array[pos+0] << 0) | \
47 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 )) 58 ((uint32_t)array[pos+1] << 8) | \
59 ((uint32_t)array[pos+2] << 16) | \
60 ((uint32_t)array[pos+3] << 24))
61
62#define BYTES2INT16(array, pos) \
63 (((uint32_t)array[pos+0] << 0) | \
64 ((uint32_t)array[pos+1] << 8))
48 65
49static const unsigned char fat_partition_types[] = { 66static const unsigned char fat_partition_types[] =
67{
50 0x0b, 0x1b, /* FAT32 + hidden variant */ 68 0x0b, 0x1b, /* FAT32 + hidden variant */
51 0x0c, 0x1c, /* FAT32 (LBA) + hidden variant */ 69 0x0c, 0x1c, /* FAT32 (LBA) + hidden variant */
52#ifdef HAVE_FAT16SUPPORT 70#ifdef HAVE_FAT16SUPPORT
@@ -56,159 +74,135 @@ static const unsigned char fat_partition_types[] = {
56#endif 74#endif
57}; 75};
58 76
59static struct partinfo part[NUM_DRIVES*4]; /* space for 4 partitions on 2 drives */ 77/* space for 4 partitions on 2 drives */
60static int vol_drive[NUM_VOLUMES]; /* mounted to which drive (-1 if none) */ 78static struct partinfo part[NUM_DRIVES*4];
61static struct mutex disk_mutex; 79/* mounted to which drive (-1 if none) */
80static int vol_drive[NUM_VOLUMES];
81
82static int get_free_volume(void)
83{
84 for (int i = 0; i < NUM_VOLUMES; i++)
85 {
86 if (vol_drive[i] == -1) /* unassigned? */
87 return i;
88 }
89
90 return -1; /* none found */
91}
62 92
63#ifdef MAX_LOG_SECTOR_SIZE 93#ifdef MAX_LOG_SECTOR_SIZE
64static int disk_sector_multiplier[NUM_DRIVES] = {[0 ... NUM_DRIVES-1] = 1}; 94static int disk_sector_multiplier[NUM_DRIVES] =
95 { [0 ... NUM_DRIVES-1] = 1 };
65 96
66int disk_get_sector_multiplier(IF_MD_NONVOID(int drive)) 97int disk_get_sector_multiplier(IF_MD_NONVOID(int drive))
67{ 98{
68 #ifdef HAVE_MULTIDRIVE 99 if (!CHECK_DRV(drive))
69 return disk_sector_multiplier[drive]; 100 return 0;
70 #else 101
71 return disk_sector_multiplier[0]; 102 disk_reader_lock();
72 #endif 103 int multiplier = disk_sector_multiplier[IF_MD_DRV(drive)];
104 disk_reader_unlock();
105 return multiplier;
73} 106}
74#endif 107#endif /* MAX_LOG_SECTOR_SIZE */
75 108
76struct partinfo* disk_init(IF_MD_NONVOID(int drive)) 109bool disk_init(IF_MD_NONVOID(int drive))
77{ 110{
78 int i; 111 if (!CHECK_DRV(drive))
79#ifdef HAVE_MULTIDRIVE 112 return false; /* out of space in table */
80 /* For each drive, start at a different position, in order not to destroy
81 the first entry of drive 0.
82 That one is needed to calculate config sector position. */
83 struct partinfo* pinfo = &part[drive*4];
84 if ((size_t)drive >= sizeof(part)/sizeof(*part)/4)
85 return NULL; /* out of space in table */
86#else
87 struct partinfo* pinfo = part;
88 const int drive = 0;
89 (void)drive;
90#endif
91 113
92 unsigned char* sector = fat_get_sector_buffer(); 114 unsigned char *sector = dc_get_buffer();
93 storage_read_sectors(IF_MD(drive,) 0,1, sector); 115 if (!sector)
94 /* check that the boot sector is initialized */ 116 return false;
95 if ( (sector[510] != 0x55) ||
96 (sector[511] != 0xaa)) {
97 fat_release_sector_buffer();
98 DEBUGF("Bad boot sector signature\n");
99 return NULL;
100 }
101 117
102 /* parse partitions */ 118 memset(sector, 0, SECTOR_SIZE);
103 for ( i=0; i<4; i++ ) { 119 storage_read_sectors(IF_MD(drive,) 0, 1, sector);
104 unsigned char* ptr = sector + 0x1be + 16*i;
105 pinfo[i].type = ptr[4];
106 pinfo[i].start = BYTES2INT32(ptr, 8);
107 pinfo[i].size = BYTES2INT32(ptr, 12);
108 120
109 DEBUGF("Part%d: Type %02x, start: %08lx size: %08lx\n", 121 bool init = false;
110 i,pinfo[i].type,pinfo[i].start,pinfo[i].size);
111 122
112 /* extended? */ 123 /* check that the boot sector is initialized */
113 if ( pinfo[i].type == 5 ) { 124 if (BYTES2INT16(sector, 510) == 0xaa55)
114 /* not handled yet */ 125 {
115 } 126 /* For each drive, start at a different position, in order not to
116 } 127 destroy the first entry of drive 0. That one is needed to calculate
117 fat_release_sector_buffer(); 128 config sector position. */
118 return pinfo; 129 struct partinfo *pinfo = &part[IF_MD_DRV(drive)*4];
119}
120 130
121struct partinfo* disk_partinfo(int partition) 131 disk_writer_lock();
122{
123 return &part[partition];
124}
125 132
126void disk_init_subsystem(void) 133 /* parse partitions */
127{ 134 for (int i = 0; i < 4; i++)
128 mutex_init(&disk_mutex); 135 {
129} 136 unsigned char* ptr = sector + 0x1be + 16*i;
137 pinfo[i].type = ptr[4];
138 pinfo[i].start = BYTES2INT32(ptr, 8);
139 pinfo[i].size = BYTES2INT32(ptr, 12);
130 140
131int disk_mount_all(void) 141 DEBUGF("Part%d: Type %02x, start: %08lx size: %08lx\n",
132{ 142 i,pinfo[i].type,pinfo[i].start,pinfo[i].size);
133 int mounted=0;
134 int i;
135
136#ifdef HAVE_HOTSWAP
137 mutex_lock(&disk_mutex);
138#endif
139 143
140 fat_init(); /* reset all mounted partitions */ 144 /* extended? */
141 for (i=0; i<NUM_VOLUMES; i++) 145 if ( pinfo[i].type == 5 )
142 vol_drive[i] = -1; /* mark all as unassigned */ 146 {
147 /* not handled yet */
148 }
149 }
143 150
144#ifndef HAVE_MULTIDRIVE 151 disk_writer_unlock();
145 mounted = disk_mount(0); 152
146#else 153 init = true;
147 for(i=0;i<NUM_DRIVES;i++) 154 }
155 else
148 { 156 {
149#ifdef HAVE_HOTSWAP 157 DEBUGF("Bad boot sector signature\n");
150 if (storage_present(i))
151#endif
152 mounted += disk_mount(i);
153 } 158 }
154#endif
155 159
156#ifdef HAVE_HOTSWAP 160 dc_release_buffer(sector);
157 mutex_unlock(&disk_mutex); 161 return init;
158#endif
159 return mounted;
160} 162}
161 163
162static int get_free_volume(void) 164bool disk_partinfo(int partition, struct partinfo *info)
163{ 165{
164 int i; 166 if (partition < 0 || partition >= (int)ARRAYLEN(part) || !info)
165 for (i=0; i<NUM_VOLUMES; i++) 167 return false;
166 {
167 if (vol_drive[i] == -1) /* unassigned? */
168 return i;
169 }
170 168
171 return -1; /* none found */ 169 disk_reader_lock();
170 *info = part[partition];
171 disk_reader_unlock();
172 return true;
172} 173}
173 174
174int disk_mount(int drive) 175int disk_mount(int drive)
175{ 176{
176 int mounted = 0; /* reset partition-on-drive flag */ 177 int mounted = 0; /* reset partition-on-drive flag */
177 int volume;
178 struct partinfo* pinfo;
179 178
180#ifdef HAVE_HOTSWAP 179 disk_writer_lock();
181 mutex_lock(&disk_mutex);
182#endif
183 180
184 volume = get_free_volume(); 181 int volume = get_free_volume();
185 pinfo = disk_init(IF_MD(drive));
186#ifdef MAX_LOG_SECTOR_SIZE
187 disk_sector_multiplier[drive] = 1;
188#endif
189 182
190 if (pinfo == NULL) 183 if (!disk_init(IF_MD(drive)))
191 { 184 {
192#ifdef HAVE_HOTSWAP 185 disk_writer_unlock();
193 mutex_unlock(&disk_mutex);
194#endif
195 return 0; 186 return 0;
196 } 187 }
197#if defined(TOSHIBA_GIGABEAT_S) 188
198 int i = 1; /* For the Gigabeat S, we mount the second partition */ 189 struct partinfo *pinfo = &part[IF_MD_DRV(drive)*4];
199#else 190#ifdef MAX_LOG_SECTOR_SIZE
200 int i = 0; 191 disk_sector_multiplier[IF_MD_DRV(drive)] = 1;
201#endif 192#endif
202 for (; volume != -1 && i<4 && mounted<NUM_VOLUMES_PER_DRIVE; i++) 193
194 for (int i = CONFIG_DEFAULT_PARTNUM;
195 volume != -1 && i < 4 && mounted < NUM_VOLUMES_PER_DRIVE;
196 i++)
203 { 197 {
204 if (memchr(fat_partition_types, pinfo[i].type, 198 if (memchr(fat_partition_types, pinfo[i].type,
205 sizeof(fat_partition_types)) == NULL) 199 sizeof(fat_partition_types)) == NULL)
206 continue; /* not an accepted partition type */ 200 continue; /* not an accepted partition type */
207 201
208#ifdef MAX_LOG_SECTOR_SIZE 202 bool success = false;
209 int j; 203
210 204 #ifdef MAX_LOG_SECTOR_SIZE
211 for (j = 1; j <= (MAX_LOG_SECTOR_SIZE/SECTOR_SIZE); j <<= 1) 205 for (int j = 1; j <= (MAX_LOG_SECTOR_SIZE/SECTOR_SIZE); j <<= 1)
212 { 206 {
213 if (!fat_mount(IF_MV(volume,) IF_MD(drive,) pinfo[i].start * j)) 207 if (!fat_mount(IF_MV(volume,) IF_MD(drive,) pinfo[i].start * j))
214 { 208 {
@@ -218,93 +212,242 @@ int disk_mount(int drive)
218 vol_drive[volume] = drive; /* remember the drive for this volume */ 212 vol_drive[volume] = drive; /* remember the drive for this volume */
219 volume = get_free_volume(); /* prepare next entry */ 213 volume = get_free_volume(); /* prepare next entry */
220 disk_sector_multiplier[drive] = j; 214 disk_sector_multiplier[drive] = j;
215 success = true;
221 break; 216 break;
222 } 217 }
223 } 218 }
224#else 219 #else /* ndef MAX_LOG_SECTOR_SIZE */
225 if (!fat_mount(IF_MV(volume,) IF_MD(drive,) pinfo[i].start)) 220 if (!fat_mount(IF_MV(volume,) IF_MD(drive,) pinfo[i].start))
226 { 221 {
227 mounted++; 222 mounted++;
228 vol_drive[volume] = drive; /* remember the drive for this volume */ 223 vol_drive[volume] = drive; /* remember the drive for this volume */
229 volume = get_free_volume(); /* prepare next entry */ 224 volume = get_free_volume(); /* prepare next entry */
225 success = true;
230 } 226 }
231#endif 227 #endif /* MAX_LOG_SECTOR_SIZE */
228
229 if (success)
230 volume_onmount_internal(IF_MV(volume));
232 } 231 }
233 232
234 if (mounted == 0 && volume != -1) /* none of the 4 entries worked? */ 233 if (mounted == 0 && volume != -1) /* none of the 4 entries worked? */
235 { /* try "superfloppy" mode */ 234 { /* try "superfloppy" mode */
236 DEBUGF("No partition found, trying to mount sector 0.\n"); 235 DEBUGF("No partition found, trying to mount sector 0.\n");
236
237 if (!fat_mount(IF_MV(volume,) IF_MD(drive,) 0)) 237 if (!fat_mount(IF_MV(volume,) IF_MD(drive,) 0))
238 { 238 {
239#ifdef MAX_LOG_SECTOR_SIZE 239 #ifdef MAX_LOG_SECTOR_SIZE
240 disk_sector_multiplier[drive] = fat_get_bytes_per_sector(IF_MV(volume))/SECTOR_SIZE; 240 disk_sector_multiplier[drive] =
241#endif 241 fat_get_bytes_per_sector(IF_MV(volume)) / SECTOR_SIZE;
242 #endif
242 mounted = 1; 243 mounted = 1;
243 vol_drive[volume] = drive; /* remember the drive for this volume */ 244 vol_drive[volume] = drive; /* remember the drive for this volume */
245 volume_onmount_internal(IF_MV(volume));
244 } 246 }
245 } 247 }
246#ifdef HAVE_HOTSWAP 248
247 mutex_unlock(&disk_mutex); 249 disk_writer_unlock();
248#endif 250 return mounted;
251}
252
253int disk_mount_all(void)
254{
255 int mounted = 0;
256
257 disk_writer_lock();
258
259 /* reset all mounted partitions */
260 volume_onunmount_internal(IF_MV(-1));
261 fat_init();
262
263 for (int i = 0; i < NUM_VOLUMES; i++)
264 vol_drive[i] = -1; /* mark all as unassigned */
265
266 for (int i = 0; i < NUM_DRIVES; i++)
267 {
268 #ifdef HAVE_HOTSWAP
269 if (storage_present(i))
270 #endif
271 mounted += disk_mount(i);
272 }
273
274 disk_writer_unlock();
249 return mounted; 275 return mounted;
250} 276}
251 277
252int disk_unmount(int drive) 278int disk_unmount(int drive)
253{ 279{
280 if (!CHECK_DRV(drive))
281 return 0;
282
254 int unmounted = 0; 283 int unmounted = 0;
255 int i; 284
256#ifdef HAVE_HOTSWAP 285 disk_writer_lock();
257 mutex_lock(&disk_mutex); 286
258#endif 287 for (int i = 0; i < NUM_VOLUMES; i++)
259 for (i=0; i<NUM_VOLUMES; i++)
260 { 288 {
261 if (vol_drive[i] == drive) 289 if (vol_drive[i] == drive)
262 { /* force releasing resources */ 290 { /* force releasing resources */
263 vol_drive[i] = -1; /* mark unused */ 291 vol_drive[i] = -1; /* mark unused */
292
293 volume_onunmount_internal(IF_MV(i));
294 fat_unmount(IF_MV(i));
295
264 unmounted++; 296 unmounted++;
265 release_files(i);
266 release_dirs(i);
267 fat_unmount(i, false);
268 } 297 }
269 } 298 }
270#ifdef HAVE_HOTSWAP
271 mutex_unlock(&disk_mutex);
272#endif
273 299
300 disk_writer_unlock();
274 return unmounted; 301 return unmounted;
275} 302}
276 303
277int disk_unmount_all(void) 304int disk_unmount_all(void)
278{ 305{
279#ifndef HAVE_MULTIDRIVE
280 return disk_unmount(0);
281#else /* HAVE_MULTIDRIVE */
282 int unmounted = 0; 306 int unmounted = 0;
283 int i; 307
284 for (i = 0; i < NUM_DRIVES; i++) 308 disk_writer_lock();
309
310 volume_onunmount_internal(IF_MV(-1));
311
312 for (int i = 0; i < NUM_DRIVES; i++)
285 { 313 {
286#ifdef HAVE_HOTSWAP 314 #ifdef HAVE_HOTSWAP
287 if (storage_present(i)) 315 if (storage_present(i))
288#endif 316 #endif
289 unmounted += disk_unmount(i); 317 unmounted += disk_unmount(i);
290 } 318 }
291 319
320 disk_writer_unlock();
292 return unmounted; 321 return unmounted;
293#endif /* HAVE_MULTIDRIVE */ 322}
323
324bool disk_present(IF_MD_NONVOID(int drive))
325{
326 int rc = -1;
327
328 if (CHECK_DRV(drive))
329 {
330 void *sector = dc_get_buffer();
331 if (sector)
332 {
333 rc = storage_read_sectors(IF_MD(drive,) 0, 1, sector);
334 dc_release_buffer(sector);
335 }
336 }
337
338 return rc == 0;
339}
340
341
342/** Volume-centric functions **/
343
344void volume_recalc_free(IF_MV_NONVOID(int volume))
345{
346 if (!CHECK_VOL(volume))
347 return;
348
349 /* FIXME: this is crummy but the only way to ensure a correct freecount
350 if other threads are writing and changing the fsinfo; it is possible
351 to get multiple threads calling here and also writing and get correct
352 freespace counts, however a bit complicated to do; if thou desireth I
353 shall implement the concurrent version -- jethead71 */
354 disk_writer_lock();
355 fat_recalc_free(IF_MV(volume));
356 disk_writer_unlock();
357}
358
359unsigned int volume_get_cluster_size(IF_MV_NONVOID(int volume))
360{
361 if (!CHECK_VOL(volume))
362 return 0;
363
364 disk_reader_lock();
365 unsigned int clustersize = fat_get_cluster_size(IF_MV(volume));
366 disk_reader_unlock();
367 return clustersize;
368}
369
370void volume_size(IF_MV(int volume,) unsigned long *sizep, unsigned long *freep)
371{
372 disk_reader_lock();
373
374 if (!CHECK_VOL(volume) || !fat_size(IF_MV(volume,) sizep, freep))
375 {
376 if (freep) *sizep = 0;
377 if (freep) *freep = 0;
378 }
379
380 disk_reader_unlock();
381}
382
383#if defined (HAVE_HOTSWAP) || defined (HAVE_MULTIDRIVE) \
384 || defined (HAVE_DIRCACHE)
385enum volume_info_type
386{
387#ifdef HAVE_HOTSWAP
388 VP_REMOVABLE,
389 VP_PRESENT,
390#endif
391#if defined (HAVE_MULTIDRIVE) || defined (HAVE_DIRCACHE)
392 VP_DRIVE,
393#endif
394};
395
396static int volume_properties(int volume, enum volume_info_type infotype)
397{
398 int res = -1;
399
400 disk_reader_lock();
401
402 if (CHECK_VOL(volume))
403 {
404 int vd = vol_drive[volume];
405 switch (infotype)
406 {
407 #ifdef HAVE_HOTSWAP
408 case VP_REMOVABLE:
409 res = storage_removable(vd) ? 1 : 0;
410 break;
411 case VP_PRESENT:
412 res = storage_present(vd) ? 1 : 0;
413 break;
414 #endif
415 #if defined(HAVE_MULTIDRIVE) || defined(HAVE_DIRCACHE)
416 case VP_DRIVE:
417 res = vd;
418 break;
419 #endif
420 }
421 }
422
423 disk_reader_unlock();
424 return res;
294} 425}
295 426
296#ifdef HAVE_HOTSWAP 427#ifdef HAVE_HOTSWAP
297bool volume_removable(int volume) 428bool volume_removable(int volume)
298{ 429{
299 if(vol_drive[volume] == -1) 430 return volume_properties(volume, VP_REMOVABLE) > 0;
300 return false;
301 return storage_removable(vol_drive[volume]);
302} 431}
303 432
304bool volume_present(int volume) 433bool volume_present(int volume)
305{ 434{
306 if(vol_drive[volume] == -1) 435 return volume_properties(volume, VP_PRESENT) > 0;
307 return false;
308 return storage_present(vol_drive[volume]);
309} 436}
310#endif 437#endif /* HAVE_HOTSWAP */
438
439#ifdef HAVE_MULTIDRIVE
440int volume_drive(int volume)
441{
442 return volume_properties(volume, VP_DRIVE);
443}
444#endif /* HAVE_MULTIDRIVE */
445
446#ifdef HAVE_DIRCACHE
447bool volume_ismounted(IF_MV_NONVOID(int volume))
448{
449 return volume_properties(IF_MV_VOL(volume), VP_DRIVE) >= 0;
450}
451#endif /* HAVE_DIRCACHE */
452
453#endif /* HAVE_HOTSWAP || HAVE_MULTIDRIVE || HAVE_DIRCACHE */