Initial Amiga RDB read-only support. Code itself is tested, but not yet in

this "shell" (the new DiskDeviceManager module API).
Hope for the best :-)


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4440 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2003-09-02 00:59:45 +00:00
parent edd19f3d5c
commit 91b4829872
4 changed files with 392 additions and 0 deletions
@@ -1,3 +1,4 @@
SubDir OBOS_TOP src add-ons kernel partitioning_systems ;
SubInclude OBOS_TOP src add-ons kernel partitioning_systems intel ;
SubInclude OBOS_TOP src add-ons kernel partitioning_systems amiga ;
@@ -0,0 +1,14 @@
SubDir OBOS_TOP src add-ons kernel partitioning_systems amiga ;
UsePrivateHeaders [ FDirName kernel disk_device_manager ] ;
UsePrivateHeaders [ FDirName storage ] ;
# For now build a userland version only.
Addon <partitioning_system>amiga_rdb : userland partitioning_systems :
amiga_rdb.cpp
;
LinkSharedOSLibs <partitioning_system>amiga_rdb :
libkernelland_emu.so
libdisk_device_manager.so
;
@@ -0,0 +1,202 @@
/*
** Copyright 2003, Axel Dörfler, [email protected]. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
#include "amiga_rdb.h"
#include <ByteOrder.h>
#include <ddm_modules.h>
#include <DiskDeviceTypes.h>
#include <KernelExport.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#define TRACE_AMIGA_RDB 1
#if TRACE_AMIGA_RDB
# define TRACE(x) printf x
#else
# define TRACE(x) ;
#endif
static const char *kPartitionModuleName = "partitioning_systems/amiga/rdb/v1";
#if TRACE_AMIGA_RDB
static char *
get_tupel(uint32 id)
{
static unsigned char tupel[5];
tupel[0] = 0xff & (id >> 24);
tupel[1] = 0xff & (id >> 16);
tupel[2] = 0xff & (id >> 8);
tupel[3] = 0xff & (id);
tupel[4] = 0;
for (int16 i = 0;i < 4;i++) {
if (tupel[i] < ' ' || tupel[i] > 128)
tupel[i] = '.';
}
return (char *)tupel;
}
#endif
status_t
get_next_partition(int fd, rigid_disk_block &rdb, uint32 &cookie, partition_block &partition)
{
if (cookie == 0) {
// first entry
cookie = rdb.partition_list;
} else if (cookie == 0xffffffff) {
// last entry
return B_ENTRY_NOT_FOUND;
}
ssize_t bytesRead = read_pos(fd, (off_t)cookie * rdb.block_size, (void *)&partition,
sizeof(partition_block));
if (bytesRead < (ssize_t)sizeof(partition_block))
return B_ERROR;
cookie = partition.next;
return B_OK;
}
bool
search_rdb(int fd, rigid_disk_block *_rdb)
{
rigid_disk_block *rdb;
uint8 buffer[512];
for (int32 sector = 0; sector < RDB_LOCATION_LIMIT; sector++) {
ssize_t bytesRead = read(fd, buffer, sizeof(buffer));
if (bytesRead < (ssize_t)sizeof(buffer))
return false;
rdb = (rigid_disk_block *)buffer;
if (rdb->id == RDB_DISK_ID && rdb->summed_longs == sizeof(rigid_disk_block) / sizeof(uint32)) {
// check checksum
uint32 *longs = (uint32 *)buffer;
uint32 sum = 0;
for (uint32 i = 0; i < rdb->summed_longs; i++)
sum += longs[i];
if (sum != 0) {
TRACE(("amiga_rdb: check sum is incorrect!\n"));
return false;
}
*_rdb = *rdb;
return true;
}
}
return false;
}
// #pragma mark -
// AmigaRDB public module interface
static status_t
amiga_rdb_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
case B_MODULE_UNINIT:
return B_OK;
}
return B_ERROR;
}
static float
amiga_rdb_identify_partition(int fd, partition_data *partition, void **_cookie)
{
rigid_disk_block *rdb = new rigid_disk_block();
if (!search_rdb(fd, rdb)) {
delete rdb;
return B_ERROR;
}
*_cookie = (void *)rdb;
return 0.5f;
}
static status_t
amiga_rdb_scan_partition(int fd, partition_data *partition, void *_cookie)
{
rigid_disk_block &rdb = *(rigid_disk_block *)_cookie;
partition->status = B_PARTITION_VALID;
partition->flags |= B_PARTITION_PARTITIONING_SYSTEM
| B_PARTITION_READ_ONLY;
partition->content_size = partition->size;
// scan all children
partition_block partitionBlock;
uint32 index = 0, cookie = 0;
status_t status;
while ((status = get_next_partition(fd, rdb, cookie, partitionBlock)) == B_OK) {
disk_environment &environment = *(disk_environment *)&partitionBlock.environment[0];
TRACE(("amiga_rdb: file system: %s\n", get_tupel(environment.dos_type)));
partition_data *child = create_child_partition(partition->id, index++, -1);
if (child == NULL) {
TRACE(("Creating child at index %ld failed\n", index - 1));
return B_ERROR;
}
child->offset = partition->offset + environment.Start();
child->size = environment.Size();
child->block_size = partition->block_size;
}
if (status == B_ENTRY_NOT_FOUND)
return B_OK;
return status;
}
static void
amiga_rdb_free_identify_partition_cookie(partition_data *partition, void *_cookie)
{
delete (rigid_disk_block *)_cookie;
}
static partition_module_info amiga_rdb_partition_module = {
{
kPartitionModuleName,
0,
amiga_rdb_std_ops
},
kPartitionTypeAmiga, // pretty_name
0, // flags
// scanning
amiga_rdb_identify_partition, // identify_partition
amiga_rdb_scan_partition, // scan_partition
amiga_rdb_free_identify_partition_cookie, // free_identify_partition_cookie
NULL,
// amiga_rdb_free_partition_cookie, // free_partition_cookie
// amiga_rdb_free_partition_content_cookie, // free_partition_content_cookie
};
partition_module_info *modules[] = {
&amiga_rdb_partition_module,
NULL
};
@@ -0,0 +1,175 @@
/*
** Copyright 2003, Axel Dörfler, [email protected]. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
#ifndef AMIGA_RDB_H
#define AMIGA_RDB_H
#include "SupportDefs.h"
#include "ByteOrder.h"
struct rigid_disk_block {
uint32 id;
uint32 summed_longs;
int32 check_sum;
uint32 host_id;
uint32 block_size;
uint32 flags;
/* block list heads */
uint32 bad_block_list;
uint32 partition_list;
uint32 fs_header_list;
uint32 drive_init;
uint32 __reserved1[6];
/* physical drive characteristics */
uint32 cylinders;
uint32 sectors;
uint32 heads;
uint32 interleave;
uint32 park;
uint32 __reserved2[3];
uint32 write_precompensation;
uint32 reduced_write;
uint32 step_rate;
uint32 __reserved3[5];
/* logical drive characteristics */
uint32 rdb_blocks_low;
uint32 rdb_blocks_high;
uint32 low_cylinder;
uint32 high_cylinder;
uint32 cylinder_blocks;
uint32 auto_park_seconds;
uint32 __reserved4[2];
/* drive identification */
char disk_vendor[8];
char disk_product[16];
char disk_revision[4];
char controller_vendor[8];
char controller_product[16];
char controller_revision[4];
uint32 __reserved5[10];
};
#define RDB_DISK_ID 'RDSK'
#define RDB_LOCATION_LIMIT 16
enum rdb_flags {
RDB_LAST = 0x01,
RDB_LAST_LUN = 0x02,
RDB_LAST_TID = 0x04,
RDB_NO_RESELECT = 0x08,
RDB_HAS_DISK_ID = 0x10,
RDB_HAS_CONTROLLER_ID = 0x20,
RDB_SUPPORTS_SYNCHRONOUS = 0x40,
};
/************* bad blocks *************/
struct bad_block_entry {
};
struct bad_block_block {
};
#define RDB_BAD_BLOCK_ID 'BADB'
/************* partition block *************/
struct partition_block {
uint32 id;
uint32 summed_longs;
int32 check_sum;
uint32 host_id;
uint32 next;
uint32 flags;
uint32 __reserved1[2];
uint32 open_device_flags;
uint8 drive_name[32]; // BSTR form (Pascal like string)
uint32 __reserved2[15];
uint32 environment[17];
uint32 __reserved3[15];
};
#define RDB_PARTITION_ID 'PART'
enum rdb_partition_flags {
RDB_PARTITION_BOOTABLE = 0x01,
RDB_PARTITION_NO_MOUNT = 0x02,
};
/************* disk environment *************/
struct disk_environment {
uint32 table_size; // size of this environment
uint32 long_block_size; // block size in longs (128 == 512 byte)
uint32 sec_org; // always 0
uint32 surfaces;
uint32 sectors_per_block;
uint32 blocks_per_track;
uint32 reserved_blocks_at_start;
uint32 reserved_blocks_at_end;
uint32 interleave;
uint32 first_cylinder;
uint32 last_cylinder;
uint32 num_buffers;
uint32 buffer_mem_type;
uint32 max_transfer;
uint32 dma_mask;
int32 boot_priority;
uint32 dos_type;
uint32 baud_rate;
uint32 control;
uint32 boot_blocks;
uint32 FirstCylinder() { return B_BENDIAN_TO_HOST_INT32(first_cylinder); }
uint32 LastCylinder() { return B_BENDIAN_TO_HOST_INT32(last_cylinder); }
uint32 Surfaces() { return B_BENDIAN_TO_HOST_INT32(surfaces); }
uint32 BlocksPerTrack() { return B_BENDIAN_TO_HOST_INT32(blocks_per_track); }
uint32 LongBlockSize() { return B_BENDIAN_TO_HOST_INT32(long_block_size); }
uint64 Start()
{
return uint64(FirstCylinder()) * BlocksPerTrack() * Surfaces()
* LongBlockSize() * sizeof(long);
}
uint64 Size()
{
return uint64(LastCylinder() + 1 - FirstCylinder()) * BlocksPerTrack() * Surfaces()
* LongBlockSize() * sizeof(long);
}
};
/************* file system header block *************/
struct fs_header_block {
};
#define RDB_FS_HEADER_ID 'FSHD'
struct load_seg_block {
};
#define RDB_LOAD_SEG_ID 'LSEG'
#endif /* AMIGA_RDB_H */