* Copyright 2003-2004, Axel DΓΆrfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "atari.h"
#include <ByteOrder.h>
#include <KernelExport.h>
#include <ddm_modules.h>
#ifdef _BOOT_MODE
# include <boot/partitions.h>
#else
# include <DiskDeviceTypes.h>
#endif
#include <util/kernel_cpp.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#define SECTSZ 512
#ifdef TRACE_ATARI_PARTITION
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
#define ATARI_PARTITION_MODULE_NAME "partitioning_systems/atari/v1"
#define ATARI_PARTITION_NAME "Atari Partition Map"
#if 0
template<typename Type> bool
validate_check_sum(Type *type)
{
if (type->SummedLongs() != sizeof(*type) / sizeof(uint32))
return false;
uint32 *longs = (uint32 *)type;
uint32 sum = 0;
for (uint32 i = 0; i < type->SummedLongs(); i++)
sum += B_BENDIAN_TO_HOST_INT32(longs[i]);
#ifdef TRACE_ATARI_PARTITION
if (sum != 0)
TRACE(("search_rdb: check sum is incorrect!\n"));
#endif
return sum == 0;
}
#endif
static status_t
atari_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
case B_MODULE_UNINIT:
return B_OK;
}
return B_ERROR;
}
static float
atari_identify_partition(int fd, partition_data *partition, void **_cookie)
{
uint8 buffer[512];
atari_root_block *arb = (atari_root_block *)buffer;
float weight = 0.5;
int i;
ssize_t bytesRead = read_pos(fd, 0, buffer, sizeof(buffer));
if (bytesRead < (ssize_t)sizeof(buffer)) {
TRACE(("%s: read error: %ld\n", __FUNCTION__, bytesRead));
return B_ERROR;
}
if (partition->offset)
return B_ERROR;
if (arb->Checksum() == 0x55aa)
weight -= 0.1;
if (arb->_reserved_1[0] != 0x00)
weight -= 10;
if (arb->MaxPartitionSize() < 10)
weight -= 20;
if ((arb->BadSectorsStart()+arb->BadSectorsCount())*(off_t)SECTSZ > partition->size)
return B_ERROR;
for (i = 0; i < 4; i++) {
struct atari_partition_entry *p = &arb->partitions[i];
if (p->Flags() & ATARI_PART_EXISTS) {
if (p->Flags() & ~ (ATARI_PART_EXISTS|ATARI_PART_BOOTABLE))
weight -= 10.0;
if (!isalnum(p->id[0]))
weight -= 1.0;
if (!isalnum(p->id[1]))
weight -= 1.0;
if (!isalnum(p->id[2]))
weight -= 1.0;
if ((arb->BadSectorsStart() < p->Start()) &&
((arb->BadSectorsStart() + arb->BadSectorsCount()) > p->Start()))
weight -= 10;
if ((p->Start()+p->Size())*(off_t)SECTSZ > partition->size)
return B_ERROR;
} else {
if (p->Flags() || p->id[0] || p->id[1] || p->id[2] ||
p->Start() || p->Size())
weight -= 10.0;
else
weight += 0.1;
}
}
if (arb->Checksum() != ATARI_BOOTABLE_MAGIC)
weight -= 0.1;
if (weight > 1.0)
weight = 1.0;
if (weight > 0.0) {
arb = new atari_root_block();
memcpy(arb, buffer, sizeof(atari_root_block));
*_cookie = (void *)arb;
return weight;
}
return B_ERROR;
}
static status_t
atari_scan_partition(int fd, partition_data *partition, void *_cookie)
{
TRACE(("atari_scan_partition(cookie = %p)\n", _cookie));
atari_root_block &arb = *(atari_root_block *)_cookie;
partition->status = B_PARTITION_VALID;
partition->flags |= B_PARTITION_PARTITIONING_SYSTEM
| B_PARTITION_READ_ONLY;
partition->content_size = partition->size;
uint32 index = 0;
status_t status = B_ENTRY_NOT_FOUND;
for (index = 0; index < 4; index++) {
struct atari_partition_entry *p = &arb.partitions[index];
if (!(p->Flags() & ATARI_PART_EXISTS))
continue;
TRACE(("atari: file system: %.3s\n", p->id));
if ((p->Start() + p->Size())*(uint64)SECTSZ > (uint64)partition->size) {
TRACE(("atari: child partition exceeds existing space (%lld bytes)\n", p->Size()*SECTSZ));
continue;
}
if (!isalnum(p->id[0]))
continue;
if (!isalnum(p->id[1]))
continue;
if (!isalnum(p->id[2]))
continue;
partition_data *child = create_child_partition(partition->id, index,
partition->offset + p->Start() * (uint64)SECTSZ,
p->Size() * (uint64)SECTSZ, -1);
if (child == NULL) {
TRACE(("atari: Creating child at index %ld failed\n", index - 1));
return B_ERROR;
}
#warning M68K: use a lookup table ?
char type[] = "??? Partition";
memcpy(type, p->id, 3);
child->type = strdup(type);
child->block_size = SECTSZ;
status = B_OK;
}
if (status == B_ENTRY_NOT_FOUND)
return B_OK;
return status;
}
static void
atari_free_identify_partition_cookie(partition_data *partition, void *_cookie)
{
delete (atari_root_block *)_cookie;
}
#ifndef _BOOT_MODE
static partition_module_info sAtariPartitionModule = {
#else
partition_module_info gAtariPartitionModule = {
#endif
{
ATARI_PARTITION_MODULE_NAME,
0,
atari_std_ops
},
"atari",
ATARI_PARTITION_NAME,
0,
atari_identify_partition,
atari_scan_partition,
atari_free_identify_partition_cookie,
NULL,
};
#ifndef _BOOT_MODE
partition_module_info *modules[] = {
&sAtariPartitionModule,
NULL
};
#endif