--- zzzz-none-000/linux-2.4.17/fs/partitions/acorn.c 2001-10-02 03:03:26.000000000 +0000 +++ sangam-fb-322/linux-2.4.17/fs/partitions/acorn.c 2004-11-24 13:22:10.000000000 +0000 @@ -7,7 +7,10 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * Scan ADFS partitions on hard disk drives. + * Scan ADFS partitions on hard disk drives. Unfortunately, there + * isn't a standard for partitioning drives on Acorn machines, so + * every single manufacturer of SCSI and IDE cards created their own + * method. */ #include #include @@ -17,10 +20,18 @@ #include #include #include +#include #include "check.h" #include "acorn.h" +/* + * Partition types. (Oh for reusability) + */ +#define PARTITION_RISCIX_MFM 1 +#define PARTITION_RISCIX_SCSI 2 +#define PARTITION_LINUX 9 + static void adfspart_setgeometry(kdev_t dev, unsigned int secspertrack, unsigned int heads) { @@ -60,6 +71,21 @@ } #ifdef CONFIG_ACORN_PARTITION_RISCIX + +struct riscix_part { + __u32 start; + __u32 length; + __u32 one; + char name[16]; +}; + +struct riscix_record { + __u32 magic; +#define RISCIX_MAGIC (0x4a657320) + __u32 date; + struct riscix_part part[8]; +}; + static int riscix_partition(struct gendisk *hd, struct block_device *bdev, unsigned long first_sect, int minor, unsigned long nr_sects) @@ -101,6 +127,15 @@ } #endif +#define LINUX_NATIVE_MAGIC 0xdeafa1de +#define LINUX_SWAP_MAGIC 0xdeafab1e + +struct linux_part { + __u32 magic; + __u32 start_sect; + __u32 nr_sects; +}; + static int linux_partition(struct gendisk *hd, struct block_device *bdev, unsigned long first_sect, int minor, unsigned long nr_sects) @@ -135,7 +170,7 @@ } #ifdef CONFIG_ACORN_PARTITION_CUMANA -static int +int adfspart_check_CUMANA(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int minor) { @@ -146,7 +181,7 @@ int first = 1; /* - * Try Cumana style partitions - sector 3 contains ADFS boot block + * Try Cumana style partitions - sector 6 contains ADFS boot block * with pointer to next 'drive'. * * There are unknowns in this code - is the 'cylinder number' of the @@ -228,7 +263,7 @@ * hda1 = ADFS partition on first drive. * hda2 = non-ADFS partition. */ -static int +int adfspart_check_ADFS(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int minor) { @@ -281,11 +316,18 @@ break; } } + printk("\n"); return 1; } #endif #ifdef CONFIG_ACORN_PARTITION_ICS + +struct ics_part { + __u32 start; + __s32 size; +}; + static int adfspart_check_ICSLinux(struct block_device *bdev, unsigned long block) { Sector sect; @@ -302,6 +344,22 @@ } /* + * Check for a valid ICS partition using the checksum. + */ +static inline int valid_ics_sector(const unsigned char *data) +{ + unsigned long sum; + int i; + + for (i = 0, sum = 0x50617274; i < 508; i++) + sum += data[i]; + + sum -= le32_to_cpu(*(__u32 *)(&data[508])); + + return sum == 0; +} + +/* * Purpose: allocate ICS partitions. * Params : hd - pointer to gendisk structure to store partition info. * dev - device number to access. @@ -313,15 +371,14 @@ * hda2 = ADFS partition 1 on first drive. * ..etc.. */ -static int +int adfspart_check_ICS(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int minor) { + const unsigned char *data; + const struct ics_part *p; + unsigned int mask = (1 << hd->minor_shift) - 1; Sector sect; - unsigned char *data; - unsigned long sum; - unsigned int i, mask = (1 << hd->minor_shift) - 1; - struct ics_part *p; /* * Try ICS style partitions - sector 0 contains partition info. @@ -330,21 +387,14 @@ if (!data) return -1; - /* - * check for a valid checksum - */ - for (i = 0, sum = 0x50617274; i < 508; i++) - sum += data[i]; - - sum -= le32_to_cpu(*(__u32 *)(&data[508])); - if (sum) { + if (!valid_ics_sector(data)) { put_dev_sector(sect); - return 0; /* not ICS partition table */ + return 0; } printk(" [ICS]"); - for (p = (struct ics_part *)data; p->size; p++) { + for (p = (const struct ics_part *)data; p->size; p++) { unsigned long start; long size; @@ -354,12 +404,19 @@ start = le32_to_cpu(p->start); size = le32_to_cpu(p->size); + /* + * Negative sizes tell the RISC OS ICS driver to ignore + * this partition - in effect it says that this does not + * contain an ADFS filesystem. + */ if (size < 0) { size = -size; /* - * We use the first sector to identify what type - * this partition is... + * Our own extension - We use the first sector + * of the partition to identify what type this + * partition is. We must not make this visible + * to the filesystem. */ if (size > 1 && adfspart_check_ICSLinux(bdev, start)) { start += 1; @@ -374,10 +431,32 @@ } put_dev_sector(sect); + printk("\n"); return 1; } #endif +#ifdef CONFIG_ACORN_PARTITION_POWERTEC +struct ptec_part { + __u32 unused1; + __u32 unused2; + __u32 start; + __u32 size; + __u32 unused5; + char type[8]; +}; + +static inline int valid_ptec_sector(const unsigned char *data) +{ + unsigned char checksum = 0x2a; + int i; + + for (i = 0; i < 511; i++) + checksum += data[i]; + + return checksum == data[511]; +} + /* * Purpose: allocate ICS partitions. * Params : hd - pointer to gendisk structure to store partition info. @@ -390,32 +469,27 @@ * hda2 = ADFS partition 1 on first drive. * ..etc.. */ -#ifdef CONFIG_ACORN_PARTITION_POWERTEC -static int +int adfspart_check_POWERTEC(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int minor) { Sector sect; - unsigned char *data; - struct ptec_partition *p; - unsigned char checksum; + const unsigned char *data; + const struct ptec_part *p; int i; data = read_dev_sector(bdev, 0, §); if (!data) return -1; - for (checksum = 0x2a, i = 0; i < 511; i++) - checksum += data[i]; - - if (checksum != data[511]) { + if (!valid_ptec_sector(data)) { put_dev_sector(sect); return 0; } printk(" [POWERTEC]"); - for (i = 0, p = (struct ptec_partition *)data; i < 12; i++, p++) { + for (i = 0, p = (const struct ptec_part *)data; i < 12; i++, p++) { unsigned long start; unsigned long size; @@ -429,49 +503,82 @@ } put_dev_sector(sect); + printk("\n"); return 1; } #endif -static int (*partfn[])(struct gendisk *, struct block_device *, unsigned long, int) = { -#ifdef CONFIG_ACORN_PARTITION_ICS - adfspart_check_ICS, -#endif -#ifdef CONFIG_ACORN_PARTITION_POWERTEC - adfspart_check_POWERTEC, -#endif -#ifdef CONFIG_ACORN_PARTITION_CUMANA - adfspart_check_CUMANA, -#endif -#ifdef CONFIG_ACORN_PARTITION_ADFS - adfspart_check_ADFS, -#endif - NULL +#ifdef CONFIG_ACORN_PARTITION_EESOX +struct eesox_part { + char magic[6]; + char name[10]; + u32 start; + u32 unused6; + u32 unused7; + u32 unused8; }; + /* - * Purpose: initialise all the partitions on an ADFS drive. - * These may be other ADFS partitions or a Linux/RiscBSD/RISCiX - * partition. + * Guess who created this format? + */ +static const char eesox_name[] = { + 'N', 'e', 'i', 'l', ' ', + 'C', 'r', 'i', 't', 'c', 'h', 'e', 'l', 'l', ' ', ' ' +}; + +/* + * EESOX SCSI partition format. * - * Params : hd - pointer to gendisk structure - * dev - device number to access - * first_sect - first available sector on the disk. - * first_minor - first available minor on this device. + * This is a goddamned awful partition format. We don't seem to store + * the size of the partition in this table, only the start addresses. * - * Returns: -1 on error, 0 if not ADFS format, 1 if ok. + * There are two possibilities where the size comes from: + * 1. The individual ADFS boot block entries that are placed on the disk. + * 2. The start address of the next entry. */ -int acorn_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sect, int first_minor) +int +adfspart_check_EESOX(struct gendisk *hd, struct block_device *bdev, + unsigned long first_sector, int minor) { + Sector sect; + const unsigned char *data; + unsigned char buffer[256]; + struct eesox_part *p; + u32 start = first_sector; int i; - for (i = 0; partfn[i]; i++) { - int r = partfn[i](hd, bdev, first_sect, first_minor); - if (r) { - if (r > 0) - printk("\n"); - return r; - } + data = read_dev_sector(bdev, 7, §); + if (!data) + return -1; + + /* + * "Decrypt" the partition table. God knows why... + */ + for (i = 0; i < 256; i++) + buffer[i] = data[i] ^ eesox_name[i & 15]; + + put_dev_sector(sect); + + for (i = 0, p = (struct eesox_part *)buffer; i < 8; i++, p++) { + u32 next; + + if (memcmp(p->magic, "Eesox", 6)) + break; + + next = le32_to_cpu(p->start) + first_sector; + if (i) + add_gd_partition(hd, minor++, start, next - start); + start = next; + } + + if (i != 0) { + unsigned long size; + + size = hd->part[MINOR(to_kdev_t(bdev->bd_dev))].nr_sects; + add_gd_partition(hd, minor++, start, size - start); + printk("\n"); } - return 0; + + return i ? 1 : 0; } +#endif