Subversion Repositories freemyipod

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
46 theseven 1
/***************************************************************************
2
 *             __________               __   ___.
3
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
4
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
5
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
6
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
7
 *                     \/            \/     \/    \/            \/
8
 * $Id: disk.c 26629 2010-06-06 13:28:13Z gevaerts $
9
 *
10
 * Copyright (C) 2002 by Björn Stenberg
11
 *
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.
16
 *
17
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18
 * KIND, either express or implied.
19
 *
20
 ****************************************************************************/
49 theseven 21
#include "global.h"
22
#include "thread.h"
46 theseven 23
#include "storage.h"
24
#include "debug.h"
25
#include "fat.h"
26
#ifdef HAVE_HOTSWAP
27
#include "dir.h" /* for release_dirs() */
28
#include "file.h" /* for release_files() */
29
#endif
30
#include "disk.h"
58 theseven 31
#include "util.h"
115 theseven 32
#include "libc/include/string.h"
46 theseven 33
 
34
/* Partition table entry layout:
35
   -----------------------
36
   0: 0x80 - active
37
   1: starting head
38
   2: starting sector
39
   3: starting cylinder
40
   4: partition type
41
   5: end head
42
   6: end sector
43
   7: end cylinder
44
   8-11: starting sector (LBA)
45
   12-15: nr of sectors in partition
46
*/
47
 
48
#define BYTES2INT32(array,pos)                  \
49
    ((long)array[pos] | ((long)array[pos+1] << 8 ) |        \
50
     ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
51
 
52
static const unsigned char fat_partition_types[] = {
53
    0x0b, 0x1b, /* FAT32 + hidden variant */
54
    0x0c, 0x1c, /* FAT32 (LBA) + hidden variant */
55
#ifdef HAVE_FAT16SUPPORT
56
    0x04, 0x14, /* FAT16 <= 32MB + hidden variant */
57
    0x06, 0x16, /* FAT16  > 32MB + hidden variant */
58
    0x0e, 0x1e, /* FAT16 (LBA) + hidden variant */
59
#endif
60
};
61
 
62
static struct partinfo part[NUM_DRIVES*4]; /* space for 4 partitions on 2 drives */
63
static int vol_drive[NUM_VOLUMES]; /* mounted to which drive (-1 if none) */
64
static struct mutex disk_mutex;
65
 
962 theseven 66
int disk_init(IF_MD2(int drive,) struct partinfo** partinfo)
46 theseven 67
{
68
    int i;
69
#ifdef HAVE_MULTIDRIVE
47 farthen 70
    /* For each drive, start at a different position, in order not to destroy
71
       the first entry of drive 0.
46 theseven 72
       That one is needed to calculate config sector position. */
73
    struct partinfo* pinfo = &part[drive*4];
74
    if ((size_t)drive >= sizeof(part)/sizeof(*part)/4)
75
        return NULL; /* out of space in table */
76
#else
77
    struct partinfo* pinfo = part;
78
    const int drive = 0;
79
    (void)drive;
80
#endif
962 theseven 81
    *partinfo = pinfo;
46 theseven 82
 
58 theseven 83
    unsigned char* sector = fat_get_sector_buffer();
962 theseven 84
    int rc = storage_read_sectors(IF_MD2(drive,) 0, 1, sector);
85
    if (IS_ERR(rc))
86
    {
87
        fat_release_sector_buffer();
88
        PASS_RC(rc, 1, 0);
89
    }
46 theseven 90
    /* check that the boot sector is initialized */
91
    if ( (sector[510] != 0x55) ||
92
         (sector[511] != 0xaa)) {
58 theseven 93
        fat_release_sector_buffer();
50 theseven 94
        DEBUGF("Bad boot sector signature");
962 theseven 95
        RET_ERR(1);
46 theseven 96
    }
97
 
98
    /* parse partitions */
99
    for ( i=0; i<4; i++ ) {
100
        unsigned char* ptr = sector + 0x1be + 16*i;
101
        pinfo[i].type  = ptr[4];
102
        pinfo[i].start = BYTES2INT32(ptr, 8);
103
        pinfo[i].size  = BYTES2INT32(ptr, 12);
104
 
50 theseven 105
        DEBUGF("Part%d: Type %02x, start: %08lx size: %08lx",
46 theseven 106
               i,pinfo[i].type,pinfo[i].start,pinfo[i].size);
107
 
108
        /* extended? */
109
        if ( pinfo[i].type == 5 ) {
110
            /* not handled yet */
111
        }
112
    }
58 theseven 113
    fat_release_sector_buffer();
962 theseven 114
    return 0;
46 theseven 115
}
116
 
117
struct partinfo* disk_partinfo(int partition)
118
{
119
    return &part[partition];
120
}
121
 
122
void disk_init_subsystem(void)
123
{
124
   mutex_init(&disk_mutex);
125
}
126
 
127
int disk_mount_all(void)
128
{
129
    int mounted=0;
130
    int i;
962 theseven 131
    int rc;
46 theseven 132
 
133
#ifdef HAVE_HOTSWAP
143 theseven 134
    mutex_lock(&disk_mutex, TIMEOUT_BLOCK);
46 theseven 135
#endif
136
 
137
    fat_init(); /* reset all mounted partitions */
138
    for (i=0; i<NUM_VOLUMES; i++)
139
        vol_drive[i] = -1; /* mark all as unassigned */
140
 
141
#ifndef HAVE_MULTIDRIVE
962 theseven 142
    PASS_RC(disk_mount(0), 0, 0);
46 theseven 143
#else
144
    for(i=0;i<NUM_DRIVES;i++)
145
    {
146
#ifdef HAVE_HOTSWAP
147
        if (storage_present(i))
148
#endif
962 theseven 149
        {
150
            rc = disk_mount(i);
151
            if (!IS_ERR(rc)) mounted += rc;
152
        }
46 theseven 153
    }
154
#endif
155
 
156
#ifdef HAVE_HOTSWAP
157
    mutex_unlock(&disk_mutex);
158
#endif
962 theseven 159
    if (!mounted) PASS_RC(rc, 0, 0);
46 theseven 160
    return mounted;
161
}
162
 
163
static int get_free_volume(void)
164
{
165
    int i;
166
    for (i=0; i<NUM_VOLUMES; i++)
167
    {
168
        if (vol_drive[i] == -1) /* unassigned? */
169
            return i;
170
    }
171
 
172
    return -1; /* none found */
173
}
174
 
175
int disk_mount(int drive)
176
{
177
    int i;
962 theseven 178
    int rc;
46 theseven 179
    int mounted = 0; /* reset partition-on-drive flag */
180
    int volume;
181
    struct partinfo* pinfo;
182
 
183
#ifdef HAVE_HOTSWAP
143 theseven 184
    mutex_lock(&disk_mutex, TIMEOUT_BLOCK);
46 theseven 185
#endif
186
 
187
    volume = get_free_volume();
962 theseven 188
    PASS_RC_MTX(disk_init(IF_MD2(drive,) &pinfo), 2, 0, &disk_mutex);
46 theseven 189
 
190
    if (pinfo == NULL)
191
    {
192
#ifdef HAVE_HOTSWAP
193
        mutex_unlock(&disk_mutex);
194
#endif
962 theseven 195
        RET_ERR(1);
46 theseven 196
    }
197
    for (i = 0; volume != -1 && i<4 && mounted<NUM_VOLUMES_PER_DRIVE; i++)
198
    {
199
        if (memchr(fat_partition_types, pinfo[i].type,
200
                   sizeof(fat_partition_types)) == NULL)
201
            continue;  /* not an accepted partition type */
962 theseven 202
 
203
        rc = fat_mount(IF_MV2(volume,) IF_MD2(drive,) pinfo[i].start);
204
        if (!IS_ERR(rc))
46 theseven 205
        {
206
            mounted++;
207
            vol_drive[volume] = drive; /* remember the drive for this volume */
208
            volume = get_free_volume(); /* prepare next entry */
209
        }
210
    }
211
 
212
    if (mounted == 0 && volume != -1) /* none of the 4 entries worked? */
213
    {   /* try "superfloppy" mode */
50 theseven 214
        DEBUGF("No partition found, trying to mount sector 0.");
962 theseven 215
        rc = fat_mount(IF_MV2(volume,) IF_MD2(drive,) 0);
216
        if (!IS_ERR(rc))
46 theseven 217
        {
218
            mounted = 1;
219
            vol_drive[volume] = drive; /* remember the drive for this volume */
220
        }
221
    }
222
#ifdef HAVE_HOTSWAP
223
    mutex_unlock(&disk_mutex);
224
#endif
962 theseven 225
    if (!mounted) PASS_RC(rc, 2, 2);
46 theseven 226
    return mounted;
227
}
228
 
229
#ifdef HAVE_HOTSWAP
230
int disk_unmount(int drive)
231
{
232
    int unmounted = 0;
233
    int i;
143 theseven 234
    mutex_lock(&disk_mutex, TIMEOUT_BLOCK);
46 theseven 235
    for (i=0; i<NUM_VOLUMES; i++)
236
    {
237
        if (vol_drive[i] == drive)
238
        {   /* force releasing resources */
239
            vol_drive[i] = -1; /* mark unused */
240
            unmounted++;
241
            release_files(i);
242
            release_dirs(i);
243
            fat_unmount(i, false);
244
        }
245
    }
246
    mutex_unlock(&disk_mutex);
247
 
248
    return unmounted;
249
}
250
#endif /* #ifdef HAVE_HOTSWAP */