A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 503 lines 15 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id: fat32format.c 30351 2011-08-25 19:58:47Z thomasjfox $ 9 * 10 * 11 * FAT32 formatting functions. Based on: 12 * 13 * Fat32 formatter version 1.03 14 * (c) Tom Thornhill 2005 15 * This software is covered by the GPL. 16 * By using this tool, you agree to absolve Ridgecrop of an liabilities for 17 * lost data. 18 * Please backup any data you value before using this tool. 19 * 20 * 21 * Modified June 2007 by Dave Chapman for use in ipodpatcher 22 * Modified September 2011 by Frank Gevaerts for use in sansa eraser 23 * 24 * 25 * This program is free software; you can redistribute it and/or 26 * modify it under the terms of the GNU General Public License 27 * as published by the Free Software Foundation; either version 2 28 * of the License, or (at your option) any later version. 29 * 30 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 31 * KIND, either express or implied. 32 * 33 ****************************************************************************/ 34 35#include <stdio.h> 36#include <stdlib.h> 37#include "common.h" 38#include "cpu.h" 39#include "file.h" 40#include "system.h" 41#include "kernel.h" 42#include "lcd.h" 43#include "font.h" 44#include "storage.h" 45#include "button.h" 46#include "disk.h" 47#include <string.h> 48#include "i2c.h" 49#include "backlight-target.h" 50#include "power.h" 51 52#define SECTOR_SIZE 512 53 54/* The following functions are not the most efficient, but are 55 self-contained and don't require needing to know endianness of CPU 56 at compile-time. 57 58 Note that htole16/htole32 exist on some platforms, so for 59 simplicity we use different names. 60 61*/ 62 63static uint16_t rb_htole16(uint16_t x) 64{ 65 uint16_t test = 0x1234; 66 unsigned char* p = (unsigned char*)&test; 67 68 if (p[0]==0x12) { 69 /* Big-endian */ 70 return swap16(x); 71 } else { 72 return x; 73 } 74} 75 76static uint32_t rb_htole32(uint32_t x) 77{ 78 uint32_t test = 0x12345678; 79 unsigned char* p = (unsigned char*)&test; 80 81 if (p[0]==0x12) { 82 /* Big-endian */ 83 return swap32(x); 84 } else { 85 return x; 86 } 87} 88 89 90/* A large aligned buffer for disk I/O */ 91unsigned char sectorbuf[128*SECTOR_SIZE]; 92 93/* TODO: Pass these as parameters to the various create_ functions */ 94 95/* can be zero for default or 1,2,4,8,16,32 or 64 */ 96static int sectors_per_cluster = 0; 97 98/* Recommended values */ 99static uint32_t ReservedSectCount = 32; 100static uint32_t NumFATs = 2; 101static uint32_t BackupBootSect = 6; 102static uint32_t VolumeId=0; /* calculated before format */ 103 104/* Calculated later */ 105static uint32_t FatSize=0; 106static uint32_t BytesPerSect=0; 107static uint32_t SectorsPerCluster=0; 108static uint32_t TotalSectors=0; 109static uint32_t SystemAreaSize=0; 110static uint32_t UserAreaSize=0; 111static uint8_t VolId[12] = "NO NAME "; 112 113 114struct FAT_BOOTSECTOR32 115{ 116 /* Common fields. */ 117 uint8_t sJmpBoot[3]; 118 char sOEMName[8]; 119 uint16_t wBytsPerSec; 120 uint8_t bSecPerClus; 121 uint16_t wRsvdSecCnt; 122 uint8_t bNumFATs; 123 uint16_t wRootEntCnt; 124 uint16_t wTotSec16; /* if zero, use dTotSec32 instead */ 125 uint8_t bMedia; 126 uint16_t wFATSz16; 127 uint16_t wSecPerTrk; 128 uint16_t wNumHeads; 129 uint32_t dHiddSec; 130 uint32_t dTotSec32; 131 132 /* Fat 32/16 only */ 133 uint32_t dFATSz32; 134 uint16_t wExtFlags; 135 uint16_t wFSVer; 136 uint32_t dRootClus; 137 uint16_t wFSInfo; 138 uint16_t wBkBootSec; 139 uint8_t Reserved[12]; 140 uint8_t bDrvNum; 141 uint8_t Reserved1; 142 uint8_t bBootSig; /* == 0x29 if next three fields are ok */ 143 uint32_t dBS_VolID; 144 uint8_t sVolLab[11]; 145 uint8_t sBS_FilSysType[8]; 146} __attribute__((packed)); 147 148struct FAT_FSINFO { 149 uint32_t dLeadSig; // 0x41615252 150 uint8_t sReserved1[480]; // zeros 151 uint32_t dStrucSig; // 0x61417272 152 uint32_t dFree_Count; // 0xFFFFFFFF 153 uint32_t dNxt_Free; // 0xFFFFFFFF 154 uint8_t sReserved2[12]; // zeros 155 uint32_t dTrailSig; // 0xAA550000 156} __attribute__((packed)); 157 158 159/* Write "count" zero sectors, starting at sector "sector" */ 160static int zero_sectors(uint32_t sector, int count) 161{ 162 int n; 163 164 memset(sectorbuf, 0, 128 * SECTOR_SIZE); 165 166 /* Write 128 sectors at a time */ 167 while (count) { 168 if (count >= 128) 169 n = 128; 170 else 171 n = count; 172 173 if (storage_write_sectors(sector,n,sectorbuf) < 0) { 174 printf("[ERR] Write failed in zero_sectors\n"); 175 return -1; 176 } 177 sector += n; 178 count -= n; 179 } 180 181 return 0; 182} 183 184 185/* 18628.2 CALCULATING THE VOLUME SERIAL NUMBER 187 188For example, say a disk was formatted on 26 Dec 95 at 9:55 PM and 41.94 189seconds. DOS takes the date and time just before it writes it to the 190disk. 191 192Low order word is calculated: Volume Serial Number is: 193 Month & Day 12/26 0c1ah 194 Sec & Hundrenths 41:94 295eh 3578:1d02 195 ----- 196 3578h 197 198High order word is calculated: 199 Hours & Minutes 21:55 1537h 200 Year 1995 07cbh 201 ----- 202 1d02h 203*/ 204static uint32_t get_volume_id ( void ) 205{ 206 /* TODO */ 207#if 0 208 SYSTEMTIME s; 209 uint32_t d; 210 uint16_t lo,hi,tmp; 211 212 GetLocalTime( &s ); 213 214 lo = s.wDay + ( s.wMonth << 8 ); 215 tmp = (s.wMilliseconds/10) + (s.wSecond << 8 ); 216 lo += tmp; 217 218 hi = s.wMinute + ( s.wHour << 8 ); 219 hi += s.wYear; 220 221 d = lo + (hi << 16); 222 return(d); 223#endif 224 return(0); 225} 226 227/* 228This is the Microsoft calculation from FATGEN 229 230 uint32_t RootDirSectors = 0; 231 uint32_t TmpVal1, TmpVal2, FATSz; 232 233 TmpVal1 = DskSize - ( ReservedSecCnt + RootDirSectors); 234 TmpVal2 = (256 * SecPerClus) + NumFATs; 235 TmpVal2 = TmpVal2 / 2; 236 FATSz = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2; 237 238 return( FatSz ); 239*/ 240 241 242static uint32_t get_fat_size_sectors(uint32_t DskSize, uint32_t ReservedSecCnt, 243 uint32_t SecPerClus, uint32_t NumFATs, 244 uint32_t BytesPerSect) 245{ 246 uint32_t Numerator, Denominator; 247 uint32_t FatElementSize = 4; 248 uint32_t FatSz; 249 250 /* This is based on 251 http://hjem.get2net.dk/rune_moeller_barnkob/filesystems/fat.html 252 I've made the obvious changes for FAT32 253 */ 254 255 Numerator = FatElementSize * ( DskSize - ReservedSecCnt ); 256 Denominator = ( SecPerClus * BytesPerSect ) + ( FatElementSize * NumFATs ); 257 FatSz = Numerator / Denominator; 258 259 /* round up */ 260 FatSz += 1; 261 262 return((uint32_t)FatSz); 263} 264 265static uint8_t get_spc(uint32_t ClusterSizeKB, uint32_t BytesPerSect) 266{ 267 uint32_t spc = ( ClusterSizeKB * 1024 ) / BytesPerSect; 268 return( (uint8_t) spc ); 269} 270 271static uint8_t get_sectors_per_cluster(uint32_t DiskSizeSectors, 272 uint32_t BytesPerSect) 273{ 274 uint8_t ret = 0x01; /* 1 sector per cluster */ 275 int32_t DiskSizeMB = DiskSizeSectors / ( 1024*1024 / SECTOR_SIZE); 276 277 /* 512 MB to 8,191 MB 4 KB */ 278 if ( DiskSizeMB > 512 ) 279 ret = get_spc( 4, BytesPerSect ); /* ret = 0x8; */ 280 281 /* 8,192 MB to 16,383 MB 8 KB */ 282 if ( DiskSizeMB > 8192 ) 283 ret = get_spc( 8, BytesPerSect ); /* ret = 0x10; */ 284 285 /* 16,384 MB to 32,767 MB 16 KB */ 286 if ( DiskSizeMB > 16384 ) 287 ret = get_spc( 16, BytesPerSect ); /* ret = 0x20; */ 288 289 /* Larger than 32,768 MB 32 KB */ 290 if ( DiskSizeMB > 32768 ) 291 ret = get_spc( 32, BytesPerSect ); /* ret = 0x40; */ 292 293 return( ret ); 294 295} 296 297static void create_boot_sector(unsigned char* buf) 298{ 299 struct FAT_BOOTSECTOR32* pFAT32BootSect = (struct FAT_BOOTSECTOR32*)buf; 300 301 /* fill out the boot sector and fs info */ 302 pFAT32BootSect->sJmpBoot[0]=0xEB; 303 pFAT32BootSect->sJmpBoot[1]=0x5A; 304 pFAT32BootSect->sJmpBoot[2]=0x90; 305 memcpy(pFAT32BootSect->sOEMName, "MSWIN4.1", 8 ); 306 pFAT32BootSect->wBytsPerSec = rb_htole16(BytesPerSect); 307 pFAT32BootSect->bSecPerClus = SectorsPerCluster ; 308 pFAT32BootSect->wRsvdSecCnt = rb_htole16(ReservedSectCount); 309 pFAT32BootSect->bNumFATs = NumFATs; 310 pFAT32BootSect->wRootEntCnt = rb_htole16(0); 311 pFAT32BootSect->wTotSec16 = rb_htole16(0); 312 pFAT32BootSect->bMedia = 0xF8; 313 pFAT32BootSect->wFATSz16 = rb_htole16(0); 314 pFAT32BootSect->wSecPerTrk = 63; 315 pFAT32BootSect->wNumHeads = 255; 316 pFAT32BootSect->dHiddSec = 0; 317 pFAT32BootSect->dTotSec32 = rb_htole32(TotalSectors); 318 pFAT32BootSect->dFATSz32 = rb_htole32(FatSize); 319 pFAT32BootSect->wExtFlags = rb_htole16(0); 320 pFAT32BootSect->wFSVer = rb_htole16(0); 321 pFAT32BootSect->dRootClus = rb_htole32(2); 322 pFAT32BootSect->wFSInfo = rb_htole16(1); 323 pFAT32BootSect->wBkBootSec = rb_htole16(BackupBootSect); 324 pFAT32BootSect->bDrvNum = 0x80; 325 pFAT32BootSect->Reserved1 = 0; 326 pFAT32BootSect->bBootSig = 0x29; 327 pFAT32BootSect->dBS_VolID = rb_htole32(VolumeId); 328 memcpy(pFAT32BootSect->sVolLab, VolId, 11); 329 memcpy(pFAT32BootSect->sBS_FilSysType, "FAT32 ", 8 ); 330 331 buf[510] = 0x55; 332 buf[511] = 0xaa; 333} 334 335static void create_fsinfo(unsigned char* buf) 336{ 337 struct FAT_FSINFO* pFAT32FsInfo = (struct FAT_FSINFO*)buf; 338 339 /* FSInfo sect */ 340 pFAT32FsInfo->dLeadSig = rb_htole32(0x41615252); 341 pFAT32FsInfo->dStrucSig = rb_htole32(0x61417272); 342 pFAT32FsInfo->dFree_Count = rb_htole32((uint32_t) -1); 343 pFAT32FsInfo->dNxt_Free = rb_htole32((uint32_t) -1); 344 pFAT32FsInfo->dTrailSig = rb_htole32(0xaa550000); 345 pFAT32FsInfo->dFree_Count = rb_htole32((UserAreaSize/SectorsPerCluster)-1); 346 347 /* clusters 0-1 reserved, we used cluster 2 for the root dir */ 348 pFAT32FsInfo->dNxt_Free = rb_htole32(3); 349} 350 351static void create_firstfatsector(unsigned char* buf) 352{ 353 uint32_t* p = (uint32_t*)buf; /* We know the buffer is aligned */ 354 355 /* First FAT Sector */ 356 p[0] = rb_htole32(0x0ffffff8); /* Reserved cluster 1 media id in low byte */ 357 p[1] = rb_htole32(0x0fffffff); /* Reserved cluster 2 EOC */ 358 p[2] = rb_htole32(0x0fffffff); /* end of cluster chain for root dir */ 359} 360 361int format_partition(int start, int size) 362{ 363 uint32_t i; 364 uint32_t qTotalSectors=0; 365 uint32_t FatNeeded; 366 367 VolumeId = get_volume_id( ); 368 369 /* Only support hard disks at the moment */ 370 if ( SECTOR_SIZE != 512 ) 371 { 372 printf("[ERR] Only disks with 512 bytes per sector are supported.\n"); 373 return -1; 374 } 375 BytesPerSect = SECTOR_SIZE; 376 377 /* Checks on Disk Size */ 378 qTotalSectors = size; 379 380 /* low end limit - 65536 sectors */ 381 if ( qTotalSectors < 65536 ) 382 { 383 /* I suspect that most FAT32 implementations would mount this 384 volume just fine, but the spec says that we shouldn't do 385 this, so we won't */ 386 387 printf("[ERR] This drive is too small for FAT32 - there must be at least 64K clusters\n" ); 388 return -1; 389 } 390 391 if ( qTotalSectors >= 0xffffffff ) 392 { 393 /* This is a more fundamental limitation on FAT32 - the total 394 sector count in the root dir is 32bit. With a bit of 395 creativity, FAT32 could be extended to handle at least 2^28 396 clusters There would need to be an extra field in the 397 FSInfo sector, and the old sector count could be set to 398 0xffffffff. This is non standard though, the Windows FAT 399 driver FASTFAT.SYS won't understand this. Perhaps a future 400 version of FAT32 and FASTFAT will handle this. */ 401 402 printf("[ERR] This drive is too big for FAT32 - max 2TB supported\n"); 403 } 404 405 if ( sectors_per_cluster ) { 406 SectorsPerCluster = sectors_per_cluster; 407 } else { 408 SectorsPerCluster = get_sectors_per_cluster(size, 409 BytesPerSect ); 410 } 411 412 TotalSectors = (uint32_t) qTotalSectors; 413 414 FatSize = get_fat_size_sectors(TotalSectors, ReservedSectCount, 415 SectorsPerCluster, NumFATs, BytesPerSect ); 416 417 UserAreaSize = TotalSectors - ReservedSectCount - (NumFATs*FatSize); 418 419 /* First zero out ReservedSect + FatSize * NumFats + SectorsPerCluster */ 420 SystemAreaSize = (ReservedSectCount+(NumFATs*FatSize) + SectorsPerCluster); 421 422 /* Work out the Cluster count */ 423 FatNeeded = UserAreaSize/SectorsPerCluster; 424 425 /* check for a cluster count of >2^28, since the upper 4 bits of 426 the cluster values in the FAT are reserved. */ 427 if (FatNeeded > 0x0FFFFFFF) { 428 printf("[ERR] This drive has more than 2^28 clusters, try to specify a larger cluster size\n" ); 429 return -1; 430 } 431 432 /* Sanity check, make sure the fat is big enough. 433 Convert the cluster count into a Fat sector count, and check 434 the fat size value we calculated earlier is OK. */ 435 436 FatNeeded *=4; 437 FatNeeded += (BytesPerSect-1); 438 FatNeeded /= BytesPerSect; 439 440 if ( FatNeeded > FatSize ) { 441 printf("[ERR] Drive too big to format\n"); 442 return -1; 443 } 444 445 /* 446 Write boot sector, fats 447 Sector 0 Boot Sector 448 Sector 1 FSInfo 449 Sector 2 More boot code - we write zeros here 450 Sector 3 unused 451 Sector 4 unused 452 Sector 5 unused 453 Sector 6 Backup boot sector 454 Sector 7 Backup FSInfo sector 455 Sector 8 Backup 'more boot code' 456 zero'd sectors upto ReservedSectCount 457 FAT1 ReservedSectCount to ReservedSectCount + FatSize 458 ... 459 FATn ReservedSectCount to ReservedSectCount + FatSize 460 RootDir - allocated to cluster2 461 */ 462 463 464 printf("[INFO] Formatting partition:..."); 465 466 /* Once zero_sectors has run, any data on the drive is basically lost... */ 467 printf("[INFO] Clearing out %d sectors for Reserved sectors, fats and root cluster...\n", SystemAreaSize ); 468 469 zero_sectors(start, SystemAreaSize); 470 471 printf("[INFO] Initialising reserved sectors and FATs...\n" ); 472 473 /* Create the boot sector structure */ 474 create_boot_sector(sectorbuf); 475 create_fsinfo(sectorbuf + 512); 476 477 if (storage_write_sectors(start,2,sectorbuf)) { 478 printf("[ERR] Write failed (first copy of bootsect/fsinfo)\n"); 479 return -1; 480 } 481 482 if (storage_write_sectors(start + BackupBootSect,2,sectorbuf)) { 483 printf("[ERR] Write failed (first copy of bootsect/fsinfo)\n"); 484 return -1; 485 } 486 487 /* Create the first FAT sector */ 488 create_firstfatsector(sectorbuf); 489 490 /* Write the first fat sector in the right places */ 491 for ( i=0; i<NumFATs; i++ ) { 492 int SectorStart = ReservedSectCount + (i * FatSize ); 493 494 if (storage_write_sectors(start + SectorStart,1,sectorbuf)) { 495 printf("[ERR] Write failed (first copy of bootsect/fsinfo)\n"); 496 return -1; 497 } 498 } 499 500 printf("[INFO] Format successful\n"); 501 502 return 0; 503}