redquark-amiberry-rb/src/hardfile.cpp

979 lines
24 KiB
C++
Raw Normal View History

2015-05-13 18:47:23 +00:00
/*
* UAE - The Un*x Amiga Emulator
*
* Hardfile emulation
*
* Copyright 1995 Bernd Schmidt
* 2002 Toni Wilen (scsi emulation, 64-bit support)
*/
#include "sysconfig.h"
#include "sysdeps.h"
2015-05-23 13:28:13 +00:00
#include "td-sdl/thread.h"
2015-05-13 18:47:23 +00:00
#include "options.h"
#include "memory.h"
#include "newcpu.h"
#include "custom.h"
2015-05-13 18:47:23 +00:00
#include "disk.h"
#include "autoconf.h"
#include "traps.h"
#include "filesys.h"
#include "execlib.h"
#include "native2amiga.h"
#include "gui.h"
#include "uae.h"
#include "execio.h"
2015-05-13 18:47:23 +00:00
#undef hf_log
#undef hf_log2
#undef hf_log3
#undef scsi_log
//#define hf_log write_log
//#define hf_log2 write_log
//#define hf_log3 write_log
//#define scsi_log write_log
#define hf_log(FORMATO, RESTO...)
#define hf_log2(FORMATO, RESTO...)
#define hf_log3(FORMATO, RESTO...)
#define scsi_log(FORMATO, RESTO...)
2015-05-13 18:47:23 +00:00
#define MAX_ASYNC_REQUESTS 50
#define ASYNC_REQUEST_NONE 0
#define ASYNC_REQUEST_TEMP 1
#define ASYNC_REQUEST_CHANGEINT 10
struct hardfileprivdata {
volatile uaecptr d_request[MAX_ASYNC_REQUESTS];
volatile int d_request_type[MAX_ASYNC_REQUESTS];
volatile uae_u32 d_request_data[MAX_ASYNC_REQUESTS];
smp_comm_pipe requests;
int thread_running;
uae_thread_id thread_id;
uae_sem_t sync_sem;
uaecptr base;
int changenum;
uaecptr changeint;
2015-05-13 18:47:23 +00:00
};
2015-10-11 14:23:51 +02:00
static uae_sem_t change_sem = 0;
2015-05-13 18:47:23 +00:00
static struct hardfileprivdata hardfpd[MAX_FILESYSTEM_UNITS];
static uae_u32 nscmd_cmd;
static void getchs2 (struct hardfiledata *hfd, int *cyl, int *cylsec, int *head, int *tracksec)
{
unsigned int total = (unsigned int)(hfd->virtsize / 1024);
int heads;
int sectors = 63;
/* do we have RDB values? */
if (hfd->cylinders) {
*cyl = hfd->cylinders;
*tracksec = hfd->sectors;
*head = hfd->heads;
*cylsec = hfd->sectors * hfd->heads;
return;
}
/* what about HDF settings? */
if (hfd->surfaces && hfd->secspertrack) {
*head = hfd->surfaces;
*tracksec = hfd->secspertrack;
*cylsec = (*head) * (*tracksec);
*cyl = (unsigned int)(hfd->virtsize / hfd->blocksize) / ((*tracksec) * (*head));
return;
}
/* no, lets guess something.. */
if (total <= 504 * 1024)
heads = 16;
else if (total <= 1008 * 1024)
heads = 32;
else if (total <= 2016 * 1024)
heads = 64;
else if (total <= 4032 * 1024)
heads = 128;
else
heads = 255;
*cyl = (unsigned int)(hfd->virtsize / hfd->blocksize) / (sectors * heads);
*cylsec = sectors * heads;
*tracksec = sectors;
*head = heads;
}
static void getchs (struct hardfiledata *hfd, int *cyl, int *cylsec, int *head, int *tracksec)
{
getchs2 (hfd, cyl, cylsec, head, tracksec);
hf_log (_T("CHS: %08X-%08X %d %d %d %d %d\n"),
(uae_u32)(hfd->virtsize >> 32),(uae_u32)hfd->virtsize,
*cyl, *cylsec, *head, *tracksec);
}
int hdf_open (struct hardfiledata *hfd, const TCHAR *pname)
{
hfd->adide = 0;
hfd->byteswap = 0;
if (!hdf_open_target (hfd, pname))
return 0;
return 1;
}
void hdf_close (struct hardfiledata *hfd)
{
hdf_close_target (hfd);
}
static int hdf_read2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
{
return hdf_read_target (hfd, buffer, offset, len);
}
static void adide_decode (void *v, int len)
{
int i;
uae_u8 *buffer = (uae_u8*)v;
for (i = 0; i < len; i += 2) {
uae_u8 *b = buffer + i;
uae_u16 w = (b[0] << 8) | (b[1] << 0);
uae_u16 o = 0;
if (w & 0x8000)
o |= 0x0001;
if (w & 0x0001)
o |= 0x0002;
if (w & 0x4000)
o |= 0x0004;
if (w & 0x0002)
o |= 0x0008;
if (w & 0x2000)
o |= 0x0010;
if (w & 0x0004)
o |= 0x0020;
if (w & 0x1000)
o |= 0x0040;
if (w & 0x0008)
o |= 0x0080;
if (w & 0x0800)
o |= 0x0100;
if (w & 0x0010)
o |= 0x0200;
if (w & 0x0400)
o |= 0x0400;
if (w & 0x0020)
o |= 0x0800;
if (w & 0x0200)
o |= 0x1000;
if (w & 0x0040)
o |= 0x2000;
if (w & 0x0100)
o |= 0x4000;
if (w & 0x0080)
o |= 0x8000;
b[0] = o >> 8;
b[1] = o >> 0;
}
}
static void adide_encode (void *v, int len)
{
int i;
uae_u8 *buffer = (uae_u8*)v;
for (i = 0; i < len; i += 2) {
uae_u8 *b = buffer + i;
uae_u16 w = (b[0] << 8) | (b[1] << 0);
uae_u16 o = 0;
if (w & 0x0001)
o |= 0x8000;
if (w & 0x0002)
o |= 0x0001;
if (w & 0x0004)
o |= 0x4000;
if (w & 0x0008)
o |= 0x0002;
if (w & 0x0010)
o |= 0x2000;
if (w & 0x0020)
o |= 0x0004;
if (w & 0x0040)
o |= 0x1000;
if (w & 0x0080)
o |= 0x0008;
if (w & 0x0100)
o |= 0x0800;
if (w & 0x0200)
o |= 0x0010;
if (w & 0x0400)
o |= 0x0400;
if (w & 0x0800)
o |= 0x0020;
if (w & 0x1000)
o |= 0x0200;
if (w & 0x2000)
o |= 0x0040;
if (w & 0x4000)
o |= 0x0100;
if (w & 0x8000)
o |= 0x0080;
b[0] = o >> 8;
b[1] = o >> 0;
}
}
static void hdf_byteswap (void *v, int len)
{
int i;
uae_u8 *b = (uae_u8*)v;
for (i = 0; i < len; i += 2) {
uae_u8 tmp = b[i];
b[i] = b[i + 1];
b[i + 1] = tmp;
}
}
int hdf_read_rdb (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
{
int v;
v = hdf_read (hfd, buffer, offset, len);
if (v > 0 && offset < 16 * 512 && !hfd->byteswap && !hfd->adide) {
uae_u8 *buf = (uae_u8*)buffer;
bool changed = false;
if (buf[0] == 0x39 && buf[1] == 0x10 && buf[2] == 0xd3 && buf[3] == 0x12) { // AdIDE encoded "CPRM"
hfd->adide = 1;
changed = true;
write_log (_T("HDF: adide scrambling detected\n"));
} else if (!memcmp (buf, "DRKS", 4)) {
hfd->byteswap = 1;
changed = true;
write_log (_T("HDF: byteswapped RDB detected\n"));
}
if (changed)
v = hdf_read (hfd, buffer, offset, len);
}
return v;
}
int hdf_read (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
{
int v;
if (!hfd->adide) {
v = hdf_read2 (hfd, buffer, offset, len);
} else {
offset += 512;
v = hdf_read2 (hfd, buffer, offset, len);
adide_decode (buffer, len);
}
if (hfd->byteswap)
hdf_byteswap (buffer, len);
return v;
}
static int hdf_write2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
{
return hdf_write_target (hfd, buffer, offset, len);
}
int hdf_write (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
{
int v;
if (hfd->byteswap)
hdf_byteswap (buffer, len);
if (!hfd->adide) {
v = hdf_write2 (hfd, buffer, offset, len);
} else {
offset += 512;
adide_encode (buffer, len);
v = hdf_write2 (hfd, buffer, offset, len);
adide_decode (buffer, len);
}
if (hfd->byteswap)
hdf_byteswap (buffer, len);
return v;
}
2015-09-09 21:49:41 +02:00
static uae_u64 cmd_readx (struct hardfiledata *hfd, uae_u8 *dataptr, uae_u64 offset, uae_u64 len)
{
gui_flicker_led (LED_HD, hfd->unitnum, 1);
hf_log3 (_T("cmd_read: %p %04x-%08x (%d) %08x (%d)\n"),
dataptr, (uae_u32)(offset >> 32), (uae_u32)offset, (uae_u32)(offset / hfd->blocksize), (uae_u32)len, (uae_u32)(len / hfd->blocksize));
return hdf_read (hfd, dataptr, offset, len);
2015-09-09 21:49:41 +02:00
}
2015-05-13 18:47:23 +00:00
static uae_u64 cmd_read (struct hardfiledata *hfd, uaecptr dataptr, uae_u64 offset, uae_u64 len)
{
addrbank *bank_data = &get_mem_bank (dataptr);
if (!bank_data || !bank_data->check (dataptr, len))
return 0;
return cmd_readx (hfd, bank_data->xlateaddr (dataptr), offset, len);
2015-09-09 21:49:41 +02:00
}
static uae_u64 cmd_writex (struct hardfiledata *hfd, uae_u8 *dataptr, uae_u64 offset, uae_u64 len)
{
gui_flicker_led (LED_HD, hfd->unitnum, 2);
hf_log3 (_T("cmd_write: %p %04x-%08x (%d) %08x (%d)\n"),
dataptr, (uae_u32)(offset >> 32), (uae_u32)offset, (uae_u32)(offset / hfd->blocksize), (uae_u32)len, (uae_u32)(len / hfd->blocksize));
return hdf_write (hfd, dataptr, offset, len);
2015-05-13 18:47:23 +00:00
}
static uae_u64 cmd_write (struct hardfiledata *hfd, uaecptr dataptr, uae_u64 offset, uae_u64 len)
{
addrbank *bank_data = &get_mem_bank (dataptr);
if (!bank_data || !bank_data->check (dataptr, len))
return 0;
return cmd_writex (hfd, bank_data->xlateaddr (dataptr), offset, len);
2015-09-09 21:49:41 +02:00
}
static int nodisk (struct hardfiledata *hfd)
{
if (hfd->drive_empty)
return 1;
return 0;
2015-09-09 21:49:41 +02:00
}
void hardfile_do_disk_change (struct uaedev_config_info *uci, int insert)
2015-09-09 21:49:41 +02:00
{
int fsid = uci->configoffset;
int j;
int newstate = insert ? 0 : 1;
struct hardfiledata *hfd;
hfd = get_hardfile_data (fsid);
if (!hfd)
return;
uae_sem_wait (&change_sem);
hardfpd[fsid].changenum++;
write_log(_T("uaehf.device:%d media status=%d\n"), fsid, insert);
hfd->drive_empty = newstate;
j = 0;
while (j < MAX_ASYNC_REQUESTS) {
if (hardfpd[fsid].d_request_type[j] == ASYNC_REQUEST_CHANGEINT) {
2015-09-09 21:49:41 +02:00
uae_Cause (hardfpd[fsid].d_request_data[j]);
}
j++;
}
if (hardfpd[fsid].changeint)
uae_Cause (hardfpd[fsid].changeint);
uae_sem_post (&change_sem);
2015-05-13 18:47:23 +00:00
}
static int add_async_request (struct hardfileprivdata *hfpd, uaecptr request, int type, uae_u32 data)
{
int i;
2015-05-13 18:47:23 +00:00
i = 0;
while (i < MAX_ASYNC_REQUESTS) {
if (hfpd->d_request[i] == request) {
2015-05-13 18:47:23 +00:00
hfpd->d_request_type[i] = type;
hfpd->d_request_data[i] = data;
hf_log (_T("old async request %p (%d) added\n"), request, type);
2015-05-13 18:47:23 +00:00
return 0;
}
i++;
}
i = 0;
while (i < MAX_ASYNC_REQUESTS) {
if (hfpd->d_request[i] == 0) {
2015-05-13 18:47:23 +00:00
hfpd->d_request[i] = request;
hfpd->d_request_type[i] = type;
hfpd->d_request_data[i] = data;
hf_log (_T("async request %p (%d) added (total=%d)\n"), request, type, i);
2015-05-13 18:47:23 +00:00
return 0;
}
i++;
}
hf_log (_T("async request overflow %p!\n"), request);
return -1;
2015-05-13 18:47:23 +00:00
}
static int release_async_request (struct hardfileprivdata *hfpd, uaecptr request)
{
int i = 0;
2015-05-13 18:47:23 +00:00
while (i < MAX_ASYNC_REQUESTS) {
if (hfpd->d_request[i] == request) {
2015-05-13 18:47:23 +00:00
int type = hfpd->d_request_type[i];
hfpd->d_request[i] = 0;
hfpd->d_request_data[i] = 0;
hfpd->d_request_type[i] = 0;
hf_log (_T("async request %p removed\n"), request);
2015-05-13 18:47:23 +00:00
return type;
}
i++;
}
hf_log (_T("tried to remove non-existing request %p\n"), request);
return -1;
2015-05-13 18:47:23 +00:00
}
static void abort_async (struct hardfileprivdata *hfpd, uaecptr request, int errcode, int type)
{
int i;
hf_log (_T("aborting async request %p\n"), request);
i = 0;
while (i < MAX_ASYNC_REQUESTS) {
if (hfpd->d_request[i] == request && hfpd->d_request_type[i] == ASYNC_REQUEST_TEMP) {
2015-05-13 18:47:23 +00:00
/* ASYNC_REQUEST_TEMP = request is processing */
sleep_millis (1);
i = 0;
continue;
}
i++;
}
i = release_async_request (hfpd, request);
if (i >= 0)
hf_log (_T("asyncronous request=%08X aborted, error=%d\n"), request, errcode);
2015-05-13 18:47:23 +00:00
}
static void *hardfile_thread (void *devs);
2015-09-09 21:49:41 +02:00
static int start_thread (TrapContext *context, int unit)
2015-05-13 18:47:23 +00:00
{
struct hardfileprivdata *hfpd = &hardfpd[unit];
2015-05-13 18:47:23 +00:00
if (hfpd->thread_running)
return 1;
memset (hfpd, 0, sizeof (struct hardfileprivdata));
hfpd->base = m68k_areg(regs, 6);
init_comm_pipe (&hfpd->requests, 100, 1);
uae_sem_init (&hfpd->sync_sem, 0, 0);
uae_start_thread (_T("hardfile"), hardfile_thread, hfpd, &(hfpd->thread_id));
uae_sem_wait (&hfpd->sync_sem);
return hfpd->thread_running;
2015-05-13 18:47:23 +00:00
}
static int mangleunit (int unit)
{
if (unit <= 99)
return unit;
if (unit == 100)
return 8;
if (unit == 110)
return 9;
return -1;
2015-05-13 18:47:23 +00:00
}
static uae_u32 REGPARAM2 hardfile_open (TrapContext *context)
{
uaecptr ioreq = m68k_areg(regs, 1); /* IOReq */
int unit = mangleunit(m68k_dreg (regs, 0));
struct hardfileprivdata *hfpd = &hardfpd[unit];
int err = IOERR_OPENFAIL;
int size = get_word (ioreq + 0x12);
/* boot device port size == 0!? KS 1.x size = 12??? */
if (size >= IOSTDREQ_SIZE || size == 0 || kickstart_version == 0xffff || kickstart_version < 39) {
2015-05-13 18:47:23 +00:00
/* Check unit number */
2015-09-09 21:49:41 +02:00
if (unit >= 0) {
struct hardfiledata *hfd = get_hardfile_data (unit);
if (hfd && hfd->handle_valid && start_thread (context, unit)) {
put_word (hfpd->base + 32, get_word (hfpd->base + 32) + 1);
put_long (ioreq + 24, unit); /* io_Unit */
put_byte (ioreq + 31, 0); /* io_Error */
put_byte (ioreq + 8, 7); /* ln_type = NT_REPLYMSG */
hf_log (_T("hardfile_open, unit %d (%d), OK\n"), unit, m68k_dreg (regs, 0));
return 0;
}
2015-05-13 18:47:23 +00:00
}
2015-09-09 21:49:41 +02:00
if (unit < 1000 || is_hardfile(unit) == FILESYS_VIRTUAL)
err = 50; /* c */
} else {
err = IOERR_BADLENGTH;
}
hf_log (_T("hardfile_open, unit %d (%d), ERR=%d\n"), unit, m68k_dreg (regs, 0), err);
put_long (ioreq + 20, (uae_u32)err);
put_byte (ioreq + 31, (uae_u8)err);
return (uae_u32)err;
2015-05-13 18:47:23 +00:00
}
static uae_u32 REGPARAM2 hardfile_close (TrapContext *context)
{
uaecptr request = m68k_areg(regs, 1); /* IOReq */
int unit = mangleunit (get_long (request + 24));
struct hardfileprivdata *hfpd = &hardfpd[unit];
2015-05-13 18:47:23 +00:00
if (!hfpd)
2015-05-13 18:47:23 +00:00
return 0;
put_word (hfpd->base + 32, get_word (hfpd->base + 32) - 1);
if (get_word(hfpd->base + 32) == 0)
write_comm_pipe_u32 (&hfpd->requests, 0, 1);
return 0;
2015-05-13 18:47:23 +00:00
}
static uae_u32 REGPARAM2 hardfile_expunge (TrapContext *context)
{
return 0; /* Simply ignore this one... */
2015-05-13 18:47:23 +00:00
}
static void outofbounds (int cmd, uae_u64 offset, uae_u64 len, uae_u64 max)
{
write_log (_T("UAEHF: cmd %d: out of bounds, %08X-%08X + %08X-%08X > %08X-%08X\n"), cmd,
(uae_u32)(offset >> 32),(uae_u32)offset,(uae_u32)(len >> 32),(uae_u32)len,
(uae_u32)(max >> 32),(uae_u32)max);
2015-05-13 18:47:23 +00:00
}
static void unaligned (int cmd, uae_u64 offset, uae_u64 len, int blocksize)
{
write_log (_T("UAEHF: cmd %d: unaligned access, %08X-%08X, %08X-%08X, %08X\n"), cmd,
(uae_u32)(offset >> 32),(uae_u32)offset,(uae_u32)(len >> 32),(uae_u32)len,
blocksize);
2015-05-13 18:47:23 +00:00
}
static uae_u32 hardfile_do_io (struct hardfiledata *hfd, struct hardfileprivdata *hfpd, uaecptr request)
{
uae_u32 dataptr, offset, actual = 0, cmd;
uae_u64 offset64;
int unit = get_long (request + 24);
uae_u32 error = 0, len;
int async = 0;
int bmask = hfd->blocksize - 1;
cmd = get_word (request + 28); /* io_Command */
dataptr = get_long (request + 40);
switch (cmd)
{
2015-05-13 18:47:23 +00:00
case CMD_READ:
if (nodisk (hfd))
2015-09-09 21:49:41 +02:00
goto no_disk;
offset = get_long (request + 44);
len = get_long (request + 36); /* io_Length */
if ((offset & bmask) || dataptr == 0) {
2015-05-13 18:47:23 +00:00
unaligned (cmd, offset, len, hfd->blocksize);
goto bad_command;
}
if (len & bmask) {
unaligned (cmd, offset, len, hfd->blocksize);
goto bad_len;
}
if (len + offset > hfd->virtsize) {
outofbounds (cmd, offset, len, hfd->virtsize);
goto bad_len;
}
actual = (uae_u32)cmd_read (hfd, dataptr, offset, len);
break;
2015-05-13 18:47:23 +00:00
case TD_READ64:
case NSCMD_TD_READ64:
if (nodisk (hfd))
2015-09-09 21:49:41 +02:00
goto no_disk;
offset64 = get_long (request + 44) | ((uae_u64)get_long (request + 32) << 32);
len = get_long (request + 36); /* io_Length */
if ((offset64 & bmask) || dataptr == 0) {
2015-05-13 18:47:23 +00:00
unaligned (cmd, offset64, len, hfd->blocksize);
goto bad_command;
}
if (len & bmask) {
unaligned (cmd, offset64, len, hfd->blocksize);
goto bad_len;
}
if (len + offset64 > hfd->virtsize) {
outofbounds (cmd, offset64, len, hfd->virtsize);
goto bad_len;
}
actual = (uae_u32)cmd_read (hfd, dataptr, offset64, len);
break;
2015-05-13 18:47:23 +00:00
case CMD_WRITE:
case CMD_FORMAT: /* Format */
if (nodisk (hfd))
2015-09-09 21:49:41 +02:00
goto no_disk;
if (hfd->readonly) {
2015-05-13 18:47:23 +00:00
error = 28; /* write protect */
} else {
2015-05-13 18:47:23 +00:00
offset = get_long (request + 44);
len = get_long (request + 36); /* io_Length */
if ((offset & bmask) || dataptr == 0) {
2015-05-13 18:47:23 +00:00
unaligned (cmd, offset, len, hfd->blocksize);
goto bad_command;
}
if (len & bmask) {
unaligned (cmd, offset, len, hfd->blocksize);
goto bad_len;
2015-05-13 18:47:23 +00:00
}
if (len + offset > hfd->virtsize) {
outofbounds (cmd, offset, len, hfd->virtsize);
goto bad_len;
2015-05-13 18:47:23 +00:00
}
actual = (uae_u32)cmd_write (hfd, dataptr, offset, len);
}
break;
2015-05-13 18:47:23 +00:00
case TD_WRITE64:
case TD_FORMAT64:
case NSCMD_TD_WRITE64:
case NSCMD_TD_FORMAT64:
if (nodisk (hfd))
2015-09-09 21:49:41 +02:00
goto no_disk;
if (hfd->readonly) {
2015-05-13 18:47:23 +00:00
error = 28; /* write protect */
} else {
2015-05-13 18:47:23 +00:00
offset64 = get_long (request + 44) | ((uae_u64)get_long (request + 32) << 32);
len = get_long (request + 36); /* io_Length */
if ((offset64 & bmask) || dataptr == 0) {
2015-05-13 18:47:23 +00:00
unaligned (cmd, offset64, len, hfd->blocksize);
goto bad_command;
}
if (len & bmask) {
unaligned (cmd, offset64, len, hfd->blocksize);
goto bad_len;
2015-05-13 18:47:23 +00:00
}
if (len + offset64 > hfd->virtsize) {
outofbounds (cmd, offset64, len, hfd->virtsize);
goto bad_len;
2015-05-13 18:47:23 +00:00
}
actual = (uae_u32)cmd_write (hfd, dataptr, offset64, len);
}
break;
bad_command:
error = IOERR_BADADDRESS;
break;
bad_len:
error = IOERR_BADLENGTH;
no_disk:
error = 29; /* no disk */
break;
2015-05-13 18:47:23 +00:00
case NSCMD_DEVICEQUERY:
put_long (dataptr + 0, 0);
put_long (dataptr + 4, 16); /* size */
put_word (dataptr + 8, NSDEVTYPE_TRACKDISK);
put_word (dataptr + 10, 0);
put_long (dataptr + 12, nscmd_cmd);
actual = 16;
break;
2015-05-13 18:47:23 +00:00
case CMD_GETDRIVETYPE:
actual = DRIVE_NEWSTYLE;
break;
2015-05-13 18:47:23 +00:00
case CMD_GETNUMTRACKS:
{
int cyl, cylsec, head, tracksec;
getchs (hfd, &cyl, &cylsec, &head, &tracksec);
actual = cyl * head;
break;
}
case CMD_GETGEOMETRY:
{
int cyl, cylsec, head, tracksec;
uae_u64 size;
getchs (hfd, &cyl, &cylsec, &head, &tracksec);
put_long (dataptr + 0, hfd->blocksize);
size = hfd->virtsize / hfd->blocksize;
if (size > 0x00ffffffff)
size = 0xffffffff;
put_long (dataptr + 4, (uae_u32)size);
put_long (dataptr + 8, cyl);
put_long (dataptr + 12, cylsec);
put_long (dataptr + 16, head);
put_long (dataptr + 20, tracksec);
put_long (dataptr + 24, 0); /* bufmemtype */
put_byte (dataptr + 28, 0); /* type = DG_DIRECT_ACCESS */
put_byte (dataptr + 29, 0); /* flags */
}
break;
2015-05-13 18:47:23 +00:00
case CMD_PROTSTATUS:
if (hfd->readonly)
actual = -1;
else
actual = 0;
break;
2015-05-13 18:47:23 +00:00
case CMD_CHANGESTATE:
actual = hfd->drive_empty ? 1 :0;
break;
2015-05-13 18:47:23 +00:00
/* Some commands that just do nothing and return zero */
2015-05-13 18:47:23 +00:00
case CMD_UPDATE:
case CMD_CLEAR:
case CMD_MOTOR:
case CMD_SEEK:
case TD_SEEK64:
case NSCMD_TD_SEEK64:
break;
2015-05-13 18:47:23 +00:00
case CMD_REMOVE:
hfpd->changeint = get_long (request + 40);
break;
2015-05-13 18:47:23 +00:00
2015-09-09 21:49:41 +02:00
case CMD_CHANGENUM:
actual = hfpd->changenum;
break;
2015-09-09 21:49:41 +02:00
2015-05-13 18:47:23 +00:00
case CMD_ADDCHANGEINT:
error = add_async_request (hfpd, request, ASYNC_REQUEST_CHANGEINT, get_long (request + 40));
if (!error)
2015-05-13 18:47:23 +00:00
async = 1;
break;
2015-05-13 18:47:23 +00:00
case CMD_REMCHANGEINT:
release_async_request (hfpd, request);
break;
2015-05-13 18:47:23 +00:00
case HD_SCSICMD: /* SCSI */
error = IOERR_NOCMD;
break;
2015-05-13 18:47:23 +00:00
default:
/* Command not understood. */
error = IOERR_NOCMD;
break;
}
put_long (request + 32, actual);
put_byte (request + 31, error);
2015-05-13 18:47:23 +00:00
hf_log2 (_T("hf: unit=%d, request=%p, cmd=%d offset=%u len=%d, actual=%d error%=%d\n"), unit, request,
get_word(request + 28), get_long (request + 44), get_long (request + 36), actual, error);
2015-05-13 18:47:23 +00:00
return async;
2015-05-13 18:47:23 +00:00
}
static uae_u32 REGPARAM2 hardfile_abortio (TrapContext *context)
{
uae_u32 request = m68k_areg(regs, 1);
int unit = mangleunit (get_long (request + 24));
struct hardfiledata *hfd = get_hardfile_data (unit);
2015-05-13 18:47:23 +00:00
struct hardfileprivdata *hfpd = &hardfpd[unit];
hf_log2 (_T("uaehf.device abortio "));
start_thread(context, unit);
if (!hfd || !hfpd || !hfpd->thread_running) {
put_byte (request + 31, 32);
hf_log2 (_T("error\n"));
return get_byte (request + 31);
}
put_byte (request + 31, -2);
hf_log2 (_T("unit=%d, request=%08X\n"), unit, request);
abort_async (hfpd, request, -2, 0);
return 0;
2015-05-13 18:47:23 +00:00
}
static int hardfile_can_quick (uae_u32 command)
{
switch (command)
{
case CMD_RESET:
case CMD_STOP:
case CMD_START:
case CMD_CHANGESTATE:
case CMD_PROTSTATUS:
case CMD_MOTOR:
case CMD_GETDRIVETYPE:
case CMD_GETNUMTRACKS:
case CMD_GETGEOMETRY:
case NSCMD_DEVICEQUERY:
return 1;
}
return 0;
2015-05-13 18:47:23 +00:00
}
static int hardfile_canquick (struct hardfiledata *hfd, uaecptr request)
{
uae_u32 command = get_word (request + 28);
return hardfile_can_quick (command);
2015-05-13 18:47:23 +00:00
}
static uae_u32 REGPARAM2 hardfile_beginio (TrapContext *context)
{
uae_u32 request = m68k_areg(regs, 1);
uae_u8 flags = get_byte (request + 30);
int cmd = get_word (request + 28);
int unit = mangleunit (get_long (request + 24));
struct hardfiledata *hfd = get_hardfile_data (unit);
struct hardfileprivdata *hfpd = &hardfpd[unit];
2015-05-13 18:47:23 +00:00
put_byte (request + 8, NT_MESSAGE);
start_thread(context, unit);
if (!hfd || !hfpd || !hfpd->thread_running) {
put_byte (request + 31, 32);
return get_byte (request + 31);
}
put_byte (request + 31, 0);
if ((flags & 1) && hardfile_canquick (hfd, request)) {
hf_log (_T("hf quickio unit=%d request=%p cmd=%d\n"), unit, request, cmd);
if (hardfile_do_io (hfd, hfpd, request))
hf_log2 (_T("uaehf.device cmd %d bug with IO_QUICK\n"), cmd);
return get_byte (request + 31);
} else {
hf_log2 (_T("hf asyncio unit=%d request=%p cmd=%d\n"), unit, request, cmd);
add_async_request (hfpd, request, ASYNC_REQUEST_TEMP, 0);
put_byte (request + 30, get_byte (request + 30) & ~1);
write_comm_pipe_u32 (&hfpd->requests, request, 1);
return 0;
}
2015-05-13 18:47:23 +00:00
}
static void *hardfile_thread (void *devs)
{
struct hardfileprivdata *hfpd = (struct hardfileprivdata *)devs;
uae_set_thread_priority (NULL, 1);
hfpd->thread_running = 1;
uae_sem_post (&hfpd->sync_sem);
for (;;) {
uaecptr request = (uaecptr)read_comm_pipe_u32_blocking (&hfpd->requests);
uae_sem_wait (&change_sem);
if (!request) {
// dbg_rem_thread(hfpd->thread_id);
2015-05-13 18:47:23 +00:00
hfpd->thread_running = 0;
uae_sem_post (&hfpd->sync_sem);
uae_sem_post (&change_sem);
return 0;
} else if (hardfile_do_io (get_hardfile_data (hfpd - &hardfpd[0]), hfpd, request) == 0) {
put_byte (request + 30, get_byte (request + 30) & ~1);
2015-05-13 18:47:23 +00:00
release_async_request (hfpd, request);
uae_ReplyMsg (request);
} else {
hf_log2 (_T("async request %08X\n"), request);
}
uae_sem_post (&change_sem);
}
// dbg_rem_thread(hfpd->thread_id);
2015-05-13 18:47:23 +00:00
}
void hardfile_reset (void)
{
2015-10-11 14:23:51 +02:00
int i, j;
struct hardfileprivdata *hfpd;
2015-05-13 18:47:23 +00:00
2015-10-11 14:23:51 +02:00
for (i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
hfpd = &hardfpd[i];
2015-10-11 14:23:51 +02:00
if (hfpd->base && valid_address(hfpd->base, 36) && get_word(hfpd->base + 32) > 0) {
2015-05-13 18:47:23 +00:00
for (j = 0; j < MAX_ASYNC_REQUESTS; j++) {
2015-10-11 14:23:51 +02:00
uaecptr request;
if ((request = hfpd->d_request[j]))
abort_async (hfpd, request, 0, 0);
2015-05-13 18:47:23 +00:00
}
2015-10-11 14:23:51 +02:00
}
if(hfpd->thread_running)
{
uae_sem_wait (&change_sem);
write_comm_pipe_u32(&hfpd->requests, 0, 1);
uae_sem_post (&change_sem);
uae_sem_wait (&hfpd->sync_sem);
uae_sem_destroy (&hfpd->sync_sem);
destroy_comm_pipe (&hfpd->requests);
2015-05-13 18:47:23 +00:00
}
2015-10-11 14:23:51 +02:00
memset (hfpd, 0, sizeof (struct hardfileprivdata));
}
2015-05-13 18:47:23 +00:00
}
void hardfile_install (void)
{
uae_u32 functable, datatable;
uae_u32 initcode, openfunc, closefunc, expungefunc;
uae_u32 beginiofunc, abortiofunc;
if(change_sem != 0)
uae_sem_destroy(&change_sem);
change_sem = 0;
uae_sem_init (&change_sem, 0, 1);
ROM_hardfile_resname = ds (_T("uaehf.device"));
ROM_hardfile_resid = ds (_T("UAE hardfile.device 0.2"));
nscmd_cmd = here ();
dw (NSCMD_DEVICEQUERY);
dw (CMD_RESET);
dw (CMD_READ);
dw (CMD_WRITE);
dw (CMD_UPDATE);
dw (CMD_CLEAR);
dw (CMD_START);
dw (CMD_STOP);
dw (CMD_FLUSH);
dw (CMD_MOTOR);
dw (CMD_SEEK);
dw (CMD_FORMAT);
dw (CMD_REMOVE);
dw (CMD_CHANGENUM);
dw (CMD_CHANGESTATE);
dw (CMD_PROTSTATUS);
dw (CMD_GETDRIVETYPE);
dw (CMD_GETGEOMETRY);
dw (CMD_ADDCHANGEINT);
dw (CMD_REMCHANGEINT);
dw (HD_SCSICMD);
dw (NSCMD_TD_READ64);
dw (NSCMD_TD_WRITE64);
dw (NSCMD_TD_SEEK64);
dw (NSCMD_TD_FORMAT64);
dw (0);
/* initcode */
initcode = filesys_initcode;
/* Open */
openfunc = here ();
calltrap (deftrap (hardfile_open)); dw (RTS);
/* Close */
closefunc = here ();
calltrap (deftrap (hardfile_close)); dw (RTS);
/* Expunge */
expungefunc = here ();
calltrap (deftrap (hardfile_expunge)); dw (RTS);
/* BeginIO */
beginiofunc = here ();
calltrap (deftrap (hardfile_beginio));
dw (RTS);
/* AbortIO */
abortiofunc = here ();
calltrap (deftrap (hardfile_abortio)); dw (RTS);
/* FuncTable */
functable = here ();
dl (openfunc); /* Open */
dl (closefunc); /* Close */
dl (expungefunc); /* Expunge */
dl (EXPANSION_nullfunc); /* Null */
dl (beginiofunc); /* BeginIO */
dl (abortiofunc); /* AbortIO */
dl (0xFFFFFFFFul); /* end of table */
/* DataTable */
datatable = here ();
dw (0xE000); /* INITBYTE */
dw (0x0008); /* LN_TYPE */
dw (0x0300); /* NT_DEVICE */
dw (0xC000); /* INITLONG */
dw (0x000A); /* LN_NAME */
dl (ROM_hardfile_resname);
dw (0xE000); /* INITBYTE */
dw (0x000E); /* LIB_FLAGS */
dw (0x0600); /* LIBF_SUMUSED | LIBF_CHANGED */
dw (0xD000); /* INITWORD */
dw (0x0014); /* LIB_VERSION */
dw (0x0004); /* 0.4 */
dw (0xD000);
dw (0x0016); /* LIB_REVISION */
dw (0x0000);
dw (0xC000);
dw (0x0018); /* LIB_IDSTRING */
dl (ROM_hardfile_resid);
dw (0x0000); /* end of table */
ROM_hardfile_init = here ();
dl (0x00000100); /* ??? */
dl (functable);
dl (datatable);
dl (initcode);
2015-05-13 18:47:23 +00:00
}