blob: f6b836cca88904efb14a8091809279a4b30012dc [file] [log] [blame]
Björn Stenbergc7f79342002-05-03 11:59:53 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
Nicolas Pennequin357ffb32008-05-05 10:32:46 +000010 * Copyright (C) 2002 by Björn Stenberg
Björn Stenbergc7f79342002-05-03 11:59:53 +000011 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * 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 Stenbergc7f79342002-05-03 11:59:53 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
Björn Stenberg6573d6d2002-05-30 19:41:35 +000021#include <stdio.h>
Björn Stenbergc7f79342002-05-03 11:59:53 +000022#include "ata.h"
23#include "debug.h"
Jörg Hohensohn1a5962f2004-12-29 22:10:24 +000024#include "fat.h"
Michael Sevakis1167e3c2007-06-30 02:08:27 +000025#ifdef HAVE_HOTSWAP
26#include "hotswap.h"
Kevin Ferrare011a3252007-07-20 17:06:55 +000027#include "dir.h" /* for release_dirs() */
28#include "file.h" /* for release_files() */
Jörg Hohensohn1a5962f2004-12-29 22:10:24 +000029#endif
Björn Stenbergc7f79342002-05-03 11:59:53 +000030#include "disk.h"
Maurus Cuelenaere95167e02008-04-24 20:08:28 +000031#include <string.h>
Björn Stenbergc7f79342002-05-03 11:59:53 +000032
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 Bernardycea551d2005-01-23 23:29:35 +000047#define BYTES2INT32(array,pos) \
Jean-Philippe Bernardya83214d2005-02-27 20:44:26 +000048 ((long)array[pos] | ((long)array[pos+1] << 8 ) | \
Jean-Philippe Bernardycea551d2005-01-23 23:29:35 +000049 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
Björn Stenbergc7f79342002-05-03 11:59:53 +000050
Jens Arnold3cec5e22008-05-15 22:23:14 +000051static 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 Hohensohn1a5962f2004-12-29 22:10:24 +000061static struct partinfo part[8]; /* space for 4 partitions on 2 drives */
Jörg Hohensohndc7534b2005-01-28 21:32:16 +000062static int vol_drive[NUM_VOLUMES]; /* mounted to which drive (-1 if none) */
Björn Stenbergc7f79342002-05-03 11:59:53 +000063
Björn Stenberg2f7cffa2008-02-11 14:26:25 +000064#ifdef MAX_LOG_SECTOR_SIZE
65int disk_sector_multiplier = 1;
66#endif
Jens Arnold3cec5e22008-05-15 22:23:14 +000067
Jörg Hohensohnda848572004-12-28 22:16:07 +000068struct partinfo* disk_init(IF_MV_NONVOID(int drive))
Björn Stenbergc7f79342002-05-03 11:59:53 +000069{
70 int i;
71 unsigned char sector[512];
Jörg Hohensohnda848572004-12-28 22:16:07 +000072#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 Stenbergc7f79342002-05-03 11:59:53 +000082
Maurus Cuelenaere95167e02008-04-24 20:08:28 +000083 ata_read_sectors(IF_MV2(drive,) 0,1, &sector);
Maurus Cuelenaeree031db42008-05-14 18:55:19 +000084#ifndef CREATIVE_ZVx
Björn Stenbergc7f79342002-05-03 11:59:53 +000085 /* 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 Stenberg6573d6d2002-05-30 19:41:35 +000089 return NULL;
Björn Stenbergc7f79342002-05-03 11:59:53 +000090 }
91
92 /* parse partitions */
93 for ( i=0; i<4; i++ ) {
94 unsigned char* ptr = sector + 0x1be + 16*i;
Jörg Hohensohnda848572004-12-28 22:16:07 +000095 pinfo[i].type = ptr[4];
96 pinfo[i].start = BYTES2INT32(ptr, 8);
97 pinfo[i].size = BYTES2INT32(ptr, 12);
Björn Stenbergc7f79342002-05-03 11:59:53 +000098
Jean-Philippe Bernardycea551d2005-01-23 23:29:35 +000099 DEBUGF("Part%d: Type %02x, start: %08lx size: %08lx\n",
Jörg Hohensohnda848572004-12-28 22:16:07 +0000100 i,pinfo[i].type,pinfo[i].start,pinfo[i].size);
Björn Stenbergc7f79342002-05-03 11:59:53 +0000101
102 /* extended? */
Jörg Hohensohnda848572004-12-28 22:16:07 +0000103 if ( pinfo[i].type == 5 ) {
Björn Stenbergc7f79342002-05-03 11:59:53 +0000104 /* not handled yet */
105 }
106 }
Maurus Cuelenaere95167e02008-04-24 20:08:28 +0000107#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 Hohensohnda848572004-12-28 22:16:07 +0000147 return pinfo;
Björn Stenbergc7f79342002-05-03 11:59:53 +0000148}
Björn Stenberg4d55c2f2002-10-10 12:01:58 +0000149
150struct partinfo* disk_partinfo(int partition)
151{
152 return &part[partition];
153}
154
Jörg Hohensohn1a5962f2004-12-29 22:10:24 +0000155int disk_mount_all(void)
156{
Jörg Hohensohndc7534b2005-01-28 21:32:16 +0000157 int mounted;
158 int i;
Jens Arnoldfe1ce9d2005-05-16 15:21:09 +0000159
Michael Sevakise37044f2008-03-12 11:08:41 +0000160#ifdef HAVE_HOTSWAP
Michael Sevakis1167e3c2007-06-30 02:08:27 +0000161 card_enable_monitoring(false);
Jens Arnoldfe1ce9d2005-05-16 15:21:09 +0000162#endif
Jörg Hohensohndc7534b2005-01-28 21:32:16 +0000163
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 Sevakis1167e3c2007-06-30 02:08:27 +0000169#ifdef HAVE_HOTSWAP
170 if (card_detect())
Jörg Hohensohn1a5962f2004-12-29 22:10:24 +0000171 {
Jörg Hohensohndc7534b2005-01-28 21:32:16 +0000172 mounted += disk_mount(1); /* try 2nd "drive", too */
Jörg Hohensohn1a5962f2004-12-29 22:10:24 +0000173 }
Michael Sevakis06a52992008-03-12 10:03:52 +0000174
Michael Sevakis1167e3c2007-06-30 02:08:27 +0000175 card_enable_monitoring(true);
Jens Arnoldfe1ce9d2005-05-16 15:21:09 +0000176#endif
Jörg Hohensohn1a5962f2004-12-29 22:10:24 +0000177
Jörg Hohensohn1a5962f2004-12-29 22:10:24 +0000178 return mounted;
179}
180
Jörg Hohensohndc7534b2005-01-28 21:32:16 +0000181static 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
193int disk_mount(int drive)
194{
Jörg Hohensohndc7534b2005-01-28 21:32:16 +0000195 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 Cuelenaeree031db42008-05-14 18:55:19 +0000203#if defined(TOSHIBA_GIGABEAT_S) || defined(CREATIVE_ZVx)
Mark Arigoe66ddd72008-01-09 07:24:43 +0000204 int i = 1; /* For the Gigabeat S, we mount the second partition */
Nicolas Pennequinc2ca8c72007-11-27 15:40:29 +0000205#else
Mark Arigoe66ddd72008-01-09 07:24:43 +0000206 int i = 0;
Nicolas Pennequinc2ca8c72007-11-27 15:40:29 +0000207#endif
Nicolas Pennequind5430992007-11-27 15:55:06 +0000208 for (; volume != -1 && i<4; i++)
Jörg Hohensohndc7534b2005-01-28 21:32:16 +0000209 {
Jens Arnold3cec5e22008-05-15 22:23:14 +0000210 if (memchr(fat_partition_types, pinfo[i].type,
211 sizeof(fat_partition_types)) == NULL)
212 continue; /* not an accepted partition type */
213
Jens Arnoldc5d71aa2007-05-23 17:51:18 +0000214#ifdef MAX_LOG_SECTOR_SIZE
Jens Arnoldef3e1292006-12-04 21:37:22 +0000215 int j;
Jens Arnold3cec5e22008-05-15 22:23:14 +0000216
Jens Arnoldc5d71aa2007-05-23 17:51:18 +0000217 for (j = 1; j <= (MAX_LOG_SECTOR_SIZE/SECTOR_SIZE); j <<= 1)
Jens Arnoldef3e1292006-12-04 21:37:22 +0000218 {
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 Stenberg2f7cffa2008-02-11 14:26:25 +0000226 if (drive == 0)
227 disk_sector_multiplier = j;
Jens Arnoldef3e1292006-12-04 21:37:22 +0000228 break;
229 }
230 }
231#else
Jörg Hohensohndc7534b2005-01-28 21:32:16 +0000232 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 Arnoldef3e1292006-12-04 21:37:22 +0000238#endif
Jörg Hohensohndc7534b2005-01-28 21:32:16 +0000239 }
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
254int 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 */