Björn Stenberg | c7f7934 | 2002-05-03 11:59:53 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
| 8 | * $Id$ |
| 9 | * |
Nicolas Pennequin | 357ffb3 | 2008-05-05 10:32:46 +0000 | [diff] [blame] | 10 | * Copyright (C) 2002 by Björn Stenberg |
Björn Stenberg | c7f7934 | 2002-05-03 11:59:53 +0000 | [diff] [blame] | 11 | * |
Daniel Stenberg | 2acc0ac | 2008-06-28 18:10:04 +0000 | [diff] [blame^] | 12 | * This program is free software; you can redistribute it and/or |
| 13 | * modify it under the terms of the GNU General Public License |
| 14 | * as published by the Free Software Foundation; either version 2 |
| 15 | * of the License, or (at your option) any later version. |
Björn Stenberg | c7f7934 | 2002-05-03 11:59:53 +0000 | [diff] [blame] | 16 | * |
| 17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| 18 | * KIND, either express or implied. |
| 19 | * |
| 20 | ****************************************************************************/ |
Björn Stenberg | 6573d6d | 2002-05-30 19:41:35 +0000 | [diff] [blame] | 21 | #include <stdio.h> |
Björn Stenberg | c7f7934 | 2002-05-03 11:59:53 +0000 | [diff] [blame] | 22 | #include "ata.h" |
| 23 | #include "debug.h" |
Jörg Hohensohn | 1a5962f | 2004-12-29 22:10:24 +0000 | [diff] [blame] | 24 | #include "fat.h" |
Michael Sevakis | 1167e3c | 2007-06-30 02:08:27 +0000 | [diff] [blame] | 25 | #ifdef HAVE_HOTSWAP |
| 26 | #include "hotswap.h" |
Kevin Ferrare | 011a325 | 2007-07-20 17:06:55 +0000 | [diff] [blame] | 27 | #include "dir.h" /* for release_dirs() */ |
| 28 | #include "file.h" /* for release_files() */ |
Jörg Hohensohn | 1a5962f | 2004-12-29 22:10:24 +0000 | [diff] [blame] | 29 | #endif |
Björn Stenberg | c7f7934 | 2002-05-03 11:59:53 +0000 | [diff] [blame] | 30 | #include "disk.h" |
Maurus Cuelenaere | 95167e0 | 2008-04-24 20:08:28 +0000 | [diff] [blame] | 31 | #include <string.h> |
Björn Stenberg | c7f7934 | 2002-05-03 11:59:53 +0000 | [diff] [blame] | 32 | |
| 33 | /* Partition table entry layout: |
| 34 | ----------------------- |
| 35 | 0: 0x80 - active |
| 36 | 1: starting head |
| 37 | 2: starting sector |
| 38 | 3: starting cylinder |
| 39 | 4: partition type |
| 40 | 5: end head |
| 41 | 6: end sector |
| 42 | 7: end cylinder |
| 43 | 8-11: starting sector (LBA) |
| 44 | 12-15: nr of sectors in partition |
| 45 | */ |
| 46 | |
Jean-Philippe Bernardy | cea551d | 2005-01-23 23:29:35 +0000 | [diff] [blame] | 47 | #define BYTES2INT32(array,pos) \ |
Jean-Philippe Bernardy | a83214d | 2005-02-27 20:44:26 +0000 | [diff] [blame] | 48 | ((long)array[pos] | ((long)array[pos+1] << 8 ) | \ |
Jean-Philippe Bernardy | cea551d | 2005-01-23 23:29:35 +0000 | [diff] [blame] | 49 | ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 )) |
Björn Stenberg | c7f7934 | 2002-05-03 11:59:53 +0000 | [diff] [blame] | 50 | |
Jens Arnold | 3cec5e2 | 2008-05-15 22:23:14 +0000 | [diff] [blame] | 51 | static const unsigned char fat_partition_types[] = { |
| 52 | 0x0b, 0x1b, /* FAT32 + hidden variant */ |
| 53 | 0x0c, 0x1c, /* FAT32 (LBA) + hidden variant */ |
| 54 | #ifdef HAVE_FAT16SUPPORT |
| 55 | 0x04, 0x14, /* FAT16 <= 32MB + hidden variant */ |
| 56 | 0x06, 0x16, /* FAT16 > 32MB + hidden variant */ |
| 57 | 0x0e, 0x1e, /* FAT16 (LBA) + hidden variant */ |
| 58 | #endif |
| 59 | }; |
| 60 | |
Jörg Hohensohn | 1a5962f | 2004-12-29 22:10:24 +0000 | [diff] [blame] | 61 | static struct partinfo part[8]; /* space for 4 partitions on 2 drives */ |
Jörg Hohensohn | dc7534b | 2005-01-28 21:32:16 +0000 | [diff] [blame] | 62 | static int vol_drive[NUM_VOLUMES]; /* mounted to which drive (-1 if none) */ |
Björn Stenberg | c7f7934 | 2002-05-03 11:59:53 +0000 | [diff] [blame] | 63 | |
Björn Stenberg | 2f7cffa | 2008-02-11 14:26:25 +0000 | [diff] [blame] | 64 | #ifdef MAX_LOG_SECTOR_SIZE |
| 65 | int disk_sector_multiplier = 1; |
| 66 | #endif |
Jens Arnold | 3cec5e2 | 2008-05-15 22:23:14 +0000 | [diff] [blame] | 67 | |
Jörg Hohensohn | da84857 | 2004-12-28 22:16:07 +0000 | [diff] [blame] | 68 | struct partinfo* disk_init(IF_MV_NONVOID(int drive)) |
Björn Stenberg | c7f7934 | 2002-05-03 11:59:53 +0000 | [diff] [blame] | 69 | { |
| 70 | int i; |
| 71 | unsigned char sector[512]; |
Jörg Hohensohn | da84857 | 2004-12-28 22:16:07 +0000 | [diff] [blame] | 72 | #ifdef HAVE_MULTIVOLUME |
| 73 | /* For each drive, start at a different position, in order not to destroy |
| 74 | the first entry of drive 0. |
| 75 | That one is needed to calculate config sector position. */ |
| 76 | struct partinfo* pinfo = &part[drive*4]; |
| 77 | if ((size_t)drive >= sizeof(part)/sizeof(*part)/4) |
| 78 | return NULL; /* out of space in table */ |
| 79 | #else |
| 80 | struct partinfo* pinfo = part; |
| 81 | #endif |
Björn Stenberg | c7f7934 | 2002-05-03 11:59:53 +0000 | [diff] [blame] | 82 | |
Maurus Cuelenaere | 95167e0 | 2008-04-24 20:08:28 +0000 | [diff] [blame] | 83 | ata_read_sectors(IF_MV2(drive,) 0,1, §or); |
Maurus Cuelenaere | e031db4 | 2008-05-14 18:55:19 +0000 | [diff] [blame] | 84 | #ifndef CREATIVE_ZVx |
Björn Stenberg | c7f7934 | 2002-05-03 11:59:53 +0000 | [diff] [blame] | 85 | /* check that the boot sector is initialized */ |
| 86 | if ( (sector[510] != 0x55) || |
| 87 | (sector[511] != 0xaa)) { |
| 88 | DEBUGF("Bad boot sector signature\n"); |
Björn Stenberg | 6573d6d | 2002-05-30 19:41:35 +0000 | [diff] [blame] | 89 | return NULL; |
Björn Stenberg | c7f7934 | 2002-05-03 11:59:53 +0000 | [diff] [blame] | 90 | } |
| 91 | |
| 92 | /* parse partitions */ |
| 93 | for ( i=0; i<4; i++ ) { |
| 94 | unsigned char* ptr = sector + 0x1be + 16*i; |
Jörg Hohensohn | da84857 | 2004-12-28 22:16:07 +0000 | [diff] [blame] | 95 | pinfo[i].type = ptr[4]; |
| 96 | pinfo[i].start = BYTES2INT32(ptr, 8); |
| 97 | pinfo[i].size = BYTES2INT32(ptr, 12); |
Björn Stenberg | c7f7934 | 2002-05-03 11:59:53 +0000 | [diff] [blame] | 98 | |
Jean-Philippe Bernardy | cea551d | 2005-01-23 23:29:35 +0000 | [diff] [blame] | 99 | DEBUGF("Part%d: Type %02x, start: %08lx size: %08lx\n", |
Jörg Hohensohn | da84857 | 2004-12-28 22:16:07 +0000 | [diff] [blame] | 100 | i,pinfo[i].type,pinfo[i].start,pinfo[i].size); |
Björn Stenberg | c7f7934 | 2002-05-03 11:59:53 +0000 | [diff] [blame] | 101 | |
| 102 | /* extended? */ |
Jörg Hohensohn | da84857 | 2004-12-28 22:16:07 +0000 | [diff] [blame] | 103 | if ( pinfo[i].type == 5 ) { |
Björn Stenberg | c7f7934 | 2002-05-03 11:59:53 +0000 | [diff] [blame] | 104 | /* not handled yet */ |
| 105 | } |
| 106 | } |
Maurus Cuelenaere | 95167e0 | 2008-04-24 20:08:28 +0000 | [diff] [blame] | 107 | #else |
| 108 | struct partition_struct |
| 109 | { |
| 110 | unsigned int end; |
| 111 | unsigned int start; |
| 112 | char name[8]; |
| 113 | }; |
| 114 | struct hdd_struct |
| 115 | { |
| 116 | unsigned char MBLK[4]; |
| 117 | int sector_size; |
| 118 | long long total_disk_size; |
| 119 | struct partition_struct partitions[4]; |
| 120 | }; |
| 121 | struct hdd_struct* hdd_struct = (struct hdd_struct*)sector; |
| 122 | |
| 123 | if(hdd_struct->MBLK[0] != 0x4B || |
| 124 | hdd_struct->MBLK[1] != 0x4C || |
| 125 | hdd_struct->MBLK[2] != 0x42 || |
| 126 | hdd_struct->MBLK[3] != 0x4D) /* 0x4B4C424D = KLBM */ |
| 127 | { |
| 128 | DEBUGF("Bad boot sector signature\n"); |
| 129 | return NULL; |
| 130 | } |
| 131 | else |
| 132 | { |
| 133 | /* parse partitions */ |
| 134 | for ( i=0; i<4; i++ ) { |
| 135 | if(hdd_struct->partitions[i].name[0] != 0) |
| 136 | { |
| 137 | pinfo[i].type = ( strcmp(hdd_struct->partitions[i].name, "cfs") == 0 ? PARTITION_TYPE_FAT32_LBA : 0); |
| 138 | pinfo[i].start = hdd_struct->partitions[i].start; |
| 139 | pinfo[i].size = (hdd_struct->partitions[i].end - hdd_struct->partitions[i].start); |
| 140 | |
| 141 | DEBUGF("Part%d: Type %02x, start: %08lx size: %08lx\n", |
| 142 | i,pinfo[i].type,pinfo[i].start,pinfo[i].size); |
| 143 | } |
| 144 | } |
| 145 | } |
| 146 | #endif |
Jörg Hohensohn | da84857 | 2004-12-28 22:16:07 +0000 | [diff] [blame] | 147 | return pinfo; |
Björn Stenberg | c7f7934 | 2002-05-03 11:59:53 +0000 | [diff] [blame] | 148 | } |
Björn Stenberg | 4d55c2f | 2002-10-10 12:01:58 +0000 | [diff] [blame] | 149 | |
| 150 | struct partinfo* disk_partinfo(int partition) |
| 151 | { |
| 152 | return &part[partition]; |
| 153 | } |
| 154 | |
Jörg Hohensohn | 1a5962f | 2004-12-29 22:10:24 +0000 | [diff] [blame] | 155 | int disk_mount_all(void) |
| 156 | { |
Jörg Hohensohn | dc7534b | 2005-01-28 21:32:16 +0000 | [diff] [blame] | 157 | int mounted; |
| 158 | int i; |
Jens Arnold | fe1ce9d | 2005-05-16 15:21:09 +0000 | [diff] [blame] | 159 | |
Michael Sevakis | e37044f | 2008-03-12 11:08:41 +0000 | [diff] [blame] | 160 | #ifdef HAVE_HOTSWAP |
Michael Sevakis | 1167e3c | 2007-06-30 02:08:27 +0000 | [diff] [blame] | 161 | card_enable_monitoring(false); |
Jens Arnold | fe1ce9d | 2005-05-16 15:21:09 +0000 | [diff] [blame] | 162 | #endif |
Jörg Hohensohn | dc7534b | 2005-01-28 21:32:16 +0000 | [diff] [blame] | 163 | |
| 164 | fat_init(); /* reset all mounted partitions */ |
| 165 | for (i=0; i<NUM_VOLUMES; i++) |
| 166 | vol_drive[i] = -1; /* mark all as unassigned */ |
| 167 | |
| 168 | mounted = disk_mount(0); |
Michael Sevakis | 1167e3c | 2007-06-30 02:08:27 +0000 | [diff] [blame] | 169 | #ifdef HAVE_HOTSWAP |
| 170 | if (card_detect()) |
Jörg Hohensohn | 1a5962f | 2004-12-29 22:10:24 +0000 | [diff] [blame] | 171 | { |
Jörg Hohensohn | dc7534b | 2005-01-28 21:32:16 +0000 | [diff] [blame] | 172 | mounted += disk_mount(1); /* try 2nd "drive", too */ |
Jörg Hohensohn | 1a5962f | 2004-12-29 22:10:24 +0000 | [diff] [blame] | 173 | } |
Michael Sevakis | 06a5299 | 2008-03-12 10:03:52 +0000 | [diff] [blame] | 174 | |
Michael Sevakis | 1167e3c | 2007-06-30 02:08:27 +0000 | [diff] [blame] | 175 | card_enable_monitoring(true); |
Jens Arnold | fe1ce9d | 2005-05-16 15:21:09 +0000 | [diff] [blame] | 176 | #endif |
Jörg Hohensohn | 1a5962f | 2004-12-29 22:10:24 +0000 | [diff] [blame] | 177 | |
Jörg Hohensohn | 1a5962f | 2004-12-29 22:10:24 +0000 | [diff] [blame] | 178 | return mounted; |
| 179 | } |
| 180 | |
Jörg Hohensohn | dc7534b | 2005-01-28 21:32:16 +0000 | [diff] [blame] | 181 | static int get_free_volume(void) |
| 182 | { |
| 183 | int i; |
| 184 | for (i=0; i<NUM_VOLUMES; i++) |
| 185 | { |
| 186 | if (vol_drive[i] == -1) /* unassigned? */ |
| 187 | return i; |
| 188 | } |
| 189 | |
| 190 | return -1; /* none found */ |
| 191 | } |
| 192 | |
| 193 | int disk_mount(int drive) |
| 194 | { |
Jörg Hohensohn | dc7534b | 2005-01-28 21:32:16 +0000 | [diff] [blame] | 195 | int mounted = 0; /* reset partition-on-drive flag */ |
| 196 | int volume = get_free_volume(); |
| 197 | struct partinfo* pinfo = disk_init(IF_MV(drive)); |
| 198 | |
| 199 | if (pinfo == NULL) |
| 200 | { |
| 201 | return 0; |
| 202 | } |
Maurus Cuelenaere | e031db4 | 2008-05-14 18:55:19 +0000 | [diff] [blame] | 203 | #if defined(TOSHIBA_GIGABEAT_S) || defined(CREATIVE_ZVx) |
Mark Arigo | e66ddd7 | 2008-01-09 07:24:43 +0000 | [diff] [blame] | 204 | int i = 1; /* For the Gigabeat S, we mount the second partition */ |
Nicolas Pennequin | c2ca8c7 | 2007-11-27 15:40:29 +0000 | [diff] [blame] | 205 | #else |
Mark Arigo | e66ddd7 | 2008-01-09 07:24:43 +0000 | [diff] [blame] | 206 | int i = 0; |
Nicolas Pennequin | c2ca8c7 | 2007-11-27 15:40:29 +0000 | [diff] [blame] | 207 | #endif |
Nicolas Pennequin | d543099 | 2007-11-27 15:55:06 +0000 | [diff] [blame] | 208 | for (; volume != -1 && i<4; i++) |
Jörg Hohensohn | dc7534b | 2005-01-28 21:32:16 +0000 | [diff] [blame] | 209 | { |
Jens Arnold | 3cec5e2 | 2008-05-15 22:23:14 +0000 | [diff] [blame] | 210 | if (memchr(fat_partition_types, pinfo[i].type, |
| 211 | sizeof(fat_partition_types)) == NULL) |
| 212 | continue; /* not an accepted partition type */ |
| 213 | |
Jens Arnold | c5d71aa | 2007-05-23 17:51:18 +0000 | [diff] [blame] | 214 | #ifdef MAX_LOG_SECTOR_SIZE |
Jens Arnold | ef3e129 | 2006-12-04 21:37:22 +0000 | [diff] [blame] | 215 | int j; |
Jens Arnold | 3cec5e2 | 2008-05-15 22:23:14 +0000 | [diff] [blame] | 216 | |
Jens Arnold | c5d71aa | 2007-05-23 17:51:18 +0000 | [diff] [blame] | 217 | for (j = 1; j <= (MAX_LOG_SECTOR_SIZE/SECTOR_SIZE); j <<= 1) |
Jens Arnold | ef3e129 | 2006-12-04 21:37:22 +0000 | [diff] [blame] | 218 | { |
| 219 | if (!fat_mount(IF_MV2(volume,) IF_MV2(drive,) pinfo[i].start * j)) |
| 220 | { |
| 221 | pinfo[i].start *= j; |
| 222 | pinfo[i].size *= j; |
| 223 | mounted++; |
| 224 | vol_drive[volume] = drive; /* remember the drive for this volume */ |
| 225 | volume = get_free_volume(); /* prepare next entry */ |
Björn Stenberg | 2f7cffa | 2008-02-11 14:26:25 +0000 | [diff] [blame] | 226 | if (drive == 0) |
| 227 | disk_sector_multiplier = j; |
Jens Arnold | ef3e129 | 2006-12-04 21:37:22 +0000 | [diff] [blame] | 228 | break; |
| 229 | } |
| 230 | } |
| 231 | #else |
Jörg Hohensohn | dc7534b | 2005-01-28 21:32:16 +0000 | [diff] [blame] | 232 | if (!fat_mount(IF_MV2(volume,) IF_MV2(drive,) pinfo[i].start)) |
| 233 | { |
| 234 | mounted++; |
| 235 | vol_drive[volume] = drive; /* remember the drive for this volume */ |
| 236 | volume = get_free_volume(); /* prepare next entry */ |
| 237 | } |
Jens Arnold | ef3e129 | 2006-12-04 21:37:22 +0000 | [diff] [blame] | 238 | #endif |
Jörg Hohensohn | dc7534b | 2005-01-28 21:32:16 +0000 | [diff] [blame] | 239 | } |
| 240 | |
| 241 | if (mounted == 0 && volume != -1) /* none of the 4 entries worked? */ |
| 242 | { /* try "superfloppy" mode */ |
| 243 | DEBUGF("No partition found, trying to mount sector 0.\n"); |
| 244 | if (!fat_mount(IF_MV2(volume,) IF_MV2(drive,) 0)) |
| 245 | { |
| 246 | mounted = 1; |
| 247 | vol_drive[volume] = drive; /* remember the drive for this volume */ |
| 248 | } |
| 249 | } |
| 250 | return mounted; |
| 251 | } |
| 252 | |
| 253 | #ifdef HAVE_HOTSWAP |
| 254 | int disk_unmount(int drive) |
| 255 | { |
| 256 | int unmounted = 0; |
| 257 | int i; |
| 258 | for (i=0; i<NUM_VOLUMES; i++) |
| 259 | { |
| 260 | if (vol_drive[i] == drive) |
| 261 | { /* force releasing resources */ |
| 262 | vol_drive[i] = -1; /* mark unused */ |
| 263 | unmounted++; |
| 264 | release_files(i); |
| 265 | release_dirs(i); |
| 266 | fat_unmount(i, false); |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | return unmounted; |
| 271 | } |
| 272 | #endif /* #ifdef HAVE_HOTSWAP */ |