1630 lines
42 KiB
C++
1630 lines
42 KiB
C++
/*
|
|
* UAE - The Un*x Amiga Emulator
|
|
*
|
|
* scsi.device emulation
|
|
*
|
|
* Copyright 1995 Bernd Schmidt
|
|
* Copyright 1999 Patrick Ohly
|
|
* Copyright 2001 Brian King
|
|
* Copyright 2002 Toni Wilen
|
|
*
|
|
*/
|
|
|
|
#include "sysconfig.h"
|
|
#include "sysdeps.h"
|
|
|
|
#ifdef SCSIEMU
|
|
|
|
#include "threaddep/thread.h"
|
|
#include "options.h"
|
|
#include "memory.h"
|
|
#include "autoconf.h"
|
|
#include "traps.h"
|
|
#include "execlib.h"
|
|
#include "native2amiga.h"
|
|
#include "blkdev.h"
|
|
#include "scsidev.h"
|
|
#include "uae.h"
|
|
#include "execio.h"
|
|
#include "savestate.h"
|
|
|
|
#define CDDEV_COMMANDS
|
|
|
|
#define UAEDEV_SCSI _T("uaescsi.device")
|
|
#define UAEDEV_SCSI_ID 1
|
|
#define UAEDEV_DISK _T("uaedisk.device")
|
|
#define UAEDEV_DISK_ID 2
|
|
|
|
#define MAX_ASYNC_REQUESTS 20
|
|
#define MAX_OPEN_DEVICES 20
|
|
|
|
#define ASYNC_REQUEST_NONE 0
|
|
#define ASYNC_REQUEST_TEMP 1
|
|
#define ASYNC_REQUEST_CHANGEINT 10
|
|
#define ASYNC_REQUEST_FRAMEINT 11
|
|
|
|
struct devstruct {
|
|
int unitnum, aunit;
|
|
int opencnt;
|
|
int changenum;
|
|
int drivetype;
|
|
int iscd;
|
|
volatile uaecptr d_request[MAX_ASYNC_REQUESTS];
|
|
volatile uae_u8 *d_request_iobuf[MAX_ASYNC_REQUESTS];
|
|
volatile int d_request_type[MAX_ASYNC_REQUESTS];
|
|
volatile uae_u32 d_request_data[MAX_ASYNC_REQUESTS];
|
|
struct device_info di;
|
|
uaecptr changeint;
|
|
int changeint_mediastate;
|
|
|
|
int configblocksize;
|
|
int volumelevel;
|
|
int fadeframes;
|
|
int fadetarget;
|
|
int fadecounter;
|
|
|
|
smp_comm_pipe requests;
|
|
int thread_running;
|
|
uae_sem_t sync_sem;
|
|
TCHAR *tape_directory;
|
|
bool readonly;
|
|
};
|
|
|
|
struct priv_devstruct {
|
|
int inuse;
|
|
int unit;
|
|
int mode;
|
|
int type;
|
|
int flags; /* OpenDevice() */
|
|
};
|
|
|
|
static struct devstruct devst[MAX_TOTAL_SCSI_DEVICES];
|
|
static struct priv_devstruct pdevst[MAX_OPEN_DEVICES];
|
|
static uae_u32 nscmd_cmd;
|
|
static uae_sem_t change_sem;
|
|
|
|
static struct device_info *devinfo (struct devstruct *devst, struct device_info *di)
|
|
{
|
|
struct device_info *dio = sys_command_info (devst->unitnum, di, 0);
|
|
if (dio) {
|
|
if (!devst->configblocksize)
|
|
devst->configblocksize = dio->bytespersector;
|
|
}
|
|
return di;
|
|
}
|
|
|
|
static void io_log(const TCHAR *msg, uae_u8 *iobuf, uaecptr request)
|
|
{
|
|
//if (log_scsi)
|
|
// write_log (_T("%s: %08X %d %08X %d %d io_actual=%d io_error=%d\n"),
|
|
// msg, request, get_word_host(iobuf + 28), get_long_host(iobuf + 40),
|
|
// get_long_host(iobuf + 36), get_long_host(iobuf + 44),
|
|
// get_long_host(iobuf + 32), get_byte_host(iobuf + 31));
|
|
}
|
|
|
|
static struct devstruct *getdevstruct (int unit)
|
|
{
|
|
int i;
|
|
for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
|
|
if (unit >= 0 && devst[i].aunit == unit)
|
|
return &devst[i];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static struct priv_devstruct *getpdevstruct(TrapContext *ctx, uaecptr request)
|
|
{
|
|
int i = trap_get_long(ctx, request + 24);
|
|
if (i < 0 || i >= MAX_OPEN_DEVICES || pdevst[i].inuse == 0) {
|
|
write_log (_T("uaescsi.device: corrupt iorequest %08X %d\n"), request, i);
|
|
return 0;
|
|
}
|
|
return &pdevst[i];
|
|
}
|
|
|
|
static const TCHAR *getdevname (int type)
|
|
{
|
|
switch (type) {
|
|
case UAEDEV_SCSI_ID:
|
|
return UAEDEV_SCSI;
|
|
case UAEDEV_DISK_ID:
|
|
return UAEDEV_DISK;
|
|
default:
|
|
return _T("NULL");
|
|
}
|
|
}
|
|
|
|
static int dev_thread(void *devs);
|
|
static int start_thread(struct devstruct *dev)
|
|
{
|
|
if (dev->thread_running)
|
|
return 1;
|
|
init_comm_pipe (&dev->requests, 300, 3);
|
|
uae_sem_init (&dev->sync_sem, 0, 0);
|
|
uae_start_thread (_T("uaescsi"), dev_thread, dev, NULL);
|
|
uae_sem_wait (&dev->sync_sem);
|
|
return dev->thread_running;
|
|
}
|
|
|
|
static void dev_close_3(struct devstruct *dev, struct priv_devstruct *pdev)
|
|
{
|
|
if (!dev->opencnt) return;
|
|
dev->opencnt--;
|
|
if (!dev->opencnt) {
|
|
sys_command_close (dev->unitnum);
|
|
pdev->inuse = 0;
|
|
write_comm_pipe_pvoid(&dev->requests, NULL, 0);
|
|
write_comm_pipe_pvoid(&dev->requests, NULL, 0);
|
|
write_comm_pipe_u32(&dev->requests, 0, 1);
|
|
}
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 dev_close_2(TrapContext *ctx)
|
|
{
|
|
uae_u32 request = trap_get_areg(ctx, 1);
|
|
struct priv_devstruct *pdev = getpdevstruct(ctx, request);
|
|
struct devstruct *dev;
|
|
|
|
if (!pdev)
|
|
return 0;
|
|
dev = getdevstruct(pdev->unit);
|
|
//if (log_scsi)
|
|
// write_log (_T("%s:%d close, req=%08X\n"), getdevname (pdev->type), pdev->unit, request);
|
|
if (!dev)
|
|
return 0;
|
|
dev_close_3 (dev, pdev);
|
|
trap_put_long(ctx, request + 24, 0);
|
|
trap_put_word(ctx, trap_get_areg(ctx, 6) + 32, trap_get_word(ctx, trap_get_areg(ctx, 6) + 32) - 1);
|
|
return 0;
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 dev_close(TrapContext *context)
|
|
{
|
|
return dev_close_2(context);
|
|
}
|
|
static uae_u32 REGPARAM2 diskdev_close(TrapContext *context)
|
|
{
|
|
return dev_close_2(context);
|
|
}
|
|
|
|
static int openfail(TrapContext *ctx, uaecptr ioreq, int error)
|
|
{
|
|
trap_put_long(ctx, ioreq + 20, -1);
|
|
trap_put_byte(ctx, ioreq + 31, error);
|
|
return (uae_u32)-1;
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 dev_open_2(TrapContext *ctx, int type)
|
|
{
|
|
uaecptr ioreq = trap_get_areg(ctx, 1);
|
|
uae_u32 unit = trap_get_dreg(ctx, 0);
|
|
uae_u32 flags = trap_get_dreg(ctx, 1);
|
|
struct devstruct *dev = getdevstruct(unit);
|
|
struct priv_devstruct *pdev = 0;
|
|
int i, v;
|
|
|
|
//if (log_scsi)
|
|
// write_log (_T("opening %s:%d ioreq=%08X\n"), getdevname (type), unit, ioreq);
|
|
uae_u16 len = trap_get_word(ctx, ioreq + 0x12);
|
|
if (len < IOSTDREQ_SIZE && len > 0)
|
|
return openfail(ctx, ioreq, IOERR_BADLENGTH);
|
|
if (!dev)
|
|
return openfail(ctx, ioreq, 32); /* badunitnum */
|
|
if (!dev->opencnt) {
|
|
for (i = 0; i < MAX_OPEN_DEVICES; i++) {
|
|
pdev = &pdevst[i];
|
|
if (pdev->inuse == 0)
|
|
break;
|
|
}
|
|
//if (dev->drivetype == INQ_SEQD) {
|
|
// v = sys_command_open_tape(dev->unitnum, dev->tape_directory, dev->readonly);
|
|
//} else {
|
|
v = sys_command_open(dev->unitnum);
|
|
//}
|
|
if (!v)
|
|
return openfail(ctx, ioreq, IOERR_OPENFAIL);
|
|
pdev->type = type;
|
|
pdev->unit = unit;
|
|
pdev->flags = flags;
|
|
pdev->inuse = 1;
|
|
trap_put_long(ctx, ioreq + 24, pdev - pdevst);
|
|
start_thread (dev);
|
|
} else {
|
|
for (i = 0; i < MAX_OPEN_DEVICES; i++) {
|
|
pdev = &pdevst[i];
|
|
if (pdev->inuse && pdev->unit == unit) break;
|
|
}
|
|
if (i == MAX_OPEN_DEVICES)
|
|
return openfail(ctx, ioreq, IOERR_OPENFAIL);
|
|
trap_put_long(ctx, ioreq + 24, pdev - pdevst);
|
|
}
|
|
dev->opencnt++;
|
|
|
|
trap_put_word(ctx, trap_get_areg(ctx, 6) + 32, trap_get_word(ctx, trap_get_areg(ctx, 6) + 32) + 1);
|
|
trap_put_byte(ctx, ioreq + 31, 0);
|
|
trap_put_byte(ctx, ioreq + 8, 7);
|
|
return 0;
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 dev_open(TrapContext *ctx)
|
|
{
|
|
return dev_open_2(ctx, UAEDEV_SCSI_ID);
|
|
}
|
|
static uae_u32 REGPARAM2 diskdev_open (TrapContext *ctx)
|
|
{
|
|
return dev_open_2(ctx, UAEDEV_DISK_ID);
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 dev_expunge(TrapContext *ctx)
|
|
{
|
|
return 0;
|
|
}
|
|
static uae_u32 REGPARAM2 diskdev_expunge(TrapContext *ctx)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int is_async_request(struct devstruct *dev, uaecptr request)
|
|
{
|
|
int i = 0;
|
|
while (i < MAX_ASYNC_REQUESTS) {
|
|
if (dev->d_request[i] == request)
|
|
return 1;
|
|
i++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#if 0
|
|
static int scsiemul_switchscsi (const TCHAR *name)
|
|
{
|
|
struct devstruct *dev = NULL;
|
|
struct device_info *discsi, discsi2;
|
|
int i, opened[MAX_TOTAL_SCSI_DEVICES];
|
|
bool wasopen = false;
|
|
|
|
for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++)
|
|
opened[i] = sys_command_isopen (i);
|
|
|
|
dev = &devst[0];
|
|
if (dev->opencnt)
|
|
wasopen = true;
|
|
sys_command_close (dev->unitnum);
|
|
|
|
dev = NULL;
|
|
if (device_func_init (DEVICE_TYPE_ANY)) {
|
|
if (devst[0].di.media_inserted < 0)
|
|
devst[0].di.media_inserted = 0;
|
|
i = 0;
|
|
while (i < MAX_TOTAL_SCSI_DEVICES && dev == NULL) {
|
|
discsi = 0;
|
|
if (sys_command_open ( i)) {
|
|
discsi = sys_command_info (i, &discsi2, 0);
|
|
if (discsi && discsi->type == INQ_ROMD) {
|
|
if (!_tcsicmp (currprefs.cdimagefile[0], discsi->label)) {
|
|
dev = &devst[0];
|
|
dev->unitnum = i;
|
|
dev->drivetype = discsi->type;
|
|
memcpy (&dev->di, discsi, sizeof (struct device_info));
|
|
dev->iscd = 1;
|
|
write_log (_T("%s mounted as uaescsi.device:0\n"), discsi->label);
|
|
if (dev->di.media_inserted) {
|
|
dev->di.media_inserted = 0;
|
|
scsi_do_disk_change (dev->di.id, 1, NULL);
|
|
}
|
|
}
|
|
}
|
|
if (opened[i] == 0 && !wasopen)
|
|
sys_command_close ( i);
|
|
}
|
|
i++;
|
|
}
|
|
if (dev)
|
|
return dev->unitnum;
|
|
}
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
// pollmode is 1 if no change interrupts found -> increase time of media change
|
|
int scsi_do_disk_change(int unitnum, int insert, int *pollmode)
|
|
{
|
|
int i, j, ret;
|
|
|
|
ret = -1;
|
|
if (!change_sem)
|
|
return ret;
|
|
uae_sem_wait (&change_sem);
|
|
for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
|
|
struct devstruct *dev = &devst[i];
|
|
if (dev->di.unitnum == unitnum + 1) {
|
|
ret = i;
|
|
if ((dev->changeint_mediastate > 0 && insert == 0) || (dev->changeint_mediastate <= 0 && insert)) {
|
|
dev->changeint_mediastate = insert;
|
|
if (pollmode)
|
|
*pollmode = 1;
|
|
if (dev->aunit >= 0) {
|
|
struct priv_devstruct *pdev = &pdevst[dev->aunit];
|
|
devinfo (dev, &dev->di);
|
|
}
|
|
dev->changenum++;
|
|
j = 0;
|
|
while (j < MAX_ASYNC_REQUESTS) {
|
|
if (dev->d_request_type[j] == ASYNC_REQUEST_CHANGEINT) {
|
|
uae_Cause (dev->d_request_data[j]);
|
|
if (pollmode)
|
|
*pollmode = 0;
|
|
}
|
|
j++;
|
|
}
|
|
if (dev->changeint) {
|
|
uae_Cause (dev->changeint);
|
|
if (pollmode)
|
|
*pollmode = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
uae_sem_post (&change_sem);
|
|
return ret;
|
|
}
|
|
|
|
static int add_async_request(struct devstruct *dev, uae_u8 *iobuf, uaecptr request, int type, uae_u32 data)
|
|
{
|
|
int i;
|
|
|
|
//if (log_scsi)
|
|
// write_log (_T("async request %08x (%d) %p added\n"), request, type, iobuf);
|
|
i = 0;
|
|
while (i < MAX_ASYNC_REQUESTS) {
|
|
if (dev->d_request[i] == request) {
|
|
dev->d_request_type[i] = type;
|
|
dev->d_request_data[i] = data;
|
|
return 0;
|
|
}
|
|
i++;
|
|
}
|
|
i = 0;
|
|
while (i < MAX_ASYNC_REQUESTS) {
|
|
if (dev->d_request[i] == 0) {
|
|
dev->d_request_iobuf[i] = iobuf;
|
|
dev->d_request[i] = request;
|
|
dev->d_request_type[i] = type;
|
|
dev->d_request_data[i] = data;
|
|
return 0;
|
|
}
|
|
i++;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int release_async_request(struct devstruct *dev, uaecptr request)
|
|
{
|
|
int i = 0;
|
|
|
|
//if (log_scsi)
|
|
// write_log (_T("async request %08x removed\n"), request);
|
|
while (i < MAX_ASYNC_REQUESTS) {
|
|
if (dev->d_request[i] == request) {
|
|
int type = dev->d_request_type[i];
|
|
dev->d_request[i] = 0;
|
|
xfree((uae_u8*)dev->d_request_iobuf[i]);
|
|
dev->d_request_iobuf[i] = 0;
|
|
dev->d_request_data[i] = 0;
|
|
dev->d_request_type[i] = 0;
|
|
return type;
|
|
}
|
|
i++;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static void abort_async(struct devstruct *dev, uaecptr request, int errcode, int type)
|
|
{
|
|
int i;
|
|
i = 0;
|
|
while (i < MAX_ASYNC_REQUESTS) {
|
|
if (dev->d_request[i] == request && dev->d_request_type[i] == ASYNC_REQUEST_TEMP) {
|
|
/* ASYNC_REQUEST_TEMP = request is processing */
|
|
sleep_millis (10);
|
|
i = 0;
|
|
continue;
|
|
}
|
|
i++;
|
|
}
|
|
i = release_async_request (dev, request);
|
|
//if (i >= 0 && log_scsi)
|
|
// write_log (_T("asyncronous request=%08X aborted, error=%d\n"), request, errcode);
|
|
}
|
|
|
|
static int command_read(TrapContext *ctx, struct devstruct *dev, uaecptr data, uae_u64 offset, uae_u32 length, uae_u32 *io_actual)
|
|
{
|
|
int blocksize = dev->di.bytespersector;
|
|
|
|
length /= blocksize;
|
|
offset /= blocksize;
|
|
while (length > 0) {
|
|
uae_u8 buffer[4096];
|
|
if (!sys_command_read (dev->unitnum, buffer, offset, 1))
|
|
return 20;
|
|
trap_memcpyha_safe(ctx, data, buffer, blocksize);
|
|
data += blocksize;
|
|
offset++;
|
|
length--;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int command_write(TrapContext *ctx, struct devstruct *dev, uaecptr data, uae_u64 offset, uae_u32 length, uae_u32 *io_actual)
|
|
{
|
|
uae_u32 blocksize = dev->di.bytespersector;
|
|
length /= blocksize;
|
|
offset /= blocksize;
|
|
while (length > 0) {
|
|
uae_u8 buffer[4096];
|
|
int err;
|
|
trap_memcpyah_safe(ctx, buffer, data, blocksize);
|
|
err = sys_command_write (dev->unitnum, buffer, offset, 1);
|
|
if (!err)
|
|
return 20;
|
|
if (err < 0)
|
|
return 28; // write protected
|
|
data += blocksize;
|
|
offset++;
|
|
length--;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int command_cd_read(TrapContext *ctx, struct devstruct *dev, uaecptr data, uae_u64 offset, uae_u32 length, uae_u32 *io_actual)
|
|
{
|
|
uae_u32 len, sector, startoffset;
|
|
int blocksize;
|
|
|
|
blocksize = dev->configblocksize;
|
|
*io_actual = 0;
|
|
startoffset = offset % blocksize;
|
|
offset -= startoffset;
|
|
sector = offset / blocksize;
|
|
while (length > 0) {
|
|
uae_u8 temp[4096];
|
|
if (blocksize != 2048) {
|
|
if (!sys_command_cd_rawread (dev->unitnum, temp, sector, 1, blocksize))
|
|
return 20;
|
|
} else {
|
|
if (!sys_command_cd_read (dev->unitnum, temp, sector, 1))
|
|
return 20;
|
|
}
|
|
if (startoffset > 0) {
|
|
len = blocksize - startoffset;
|
|
if (len > length)
|
|
len = length;
|
|
trap_memcpyha_safe(ctx, data, temp + startoffset, len);
|
|
length -= len;
|
|
data += len;
|
|
startoffset = 0;
|
|
*io_actual += len;
|
|
} else if (length >= blocksize) {
|
|
len = blocksize;
|
|
trap_memcpyha_safe(ctx, data, temp, len);
|
|
length -= len;
|
|
data += len;
|
|
*io_actual += len;
|
|
} else {
|
|
trap_memcpyha_safe(ctx, data, temp, length);
|
|
*io_actual += length;
|
|
length = 0;
|
|
}
|
|
sector++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int dev_do_io_other(TrapContext *ctx, struct devstruct *dev, uae_u8 *iobuf, uaecptr request)
|
|
{
|
|
uae_u32 command;
|
|
uae_u32 io_data = get_long_host(iobuf + 40); // 0x28
|
|
uae_u32 io_length = get_long_host(iobuf + 36); // 0x24
|
|
uae_u32 io_actual = get_long_host(iobuf + 32); // 0x20
|
|
uae_u32 io_offset = get_long_host(iobuf + 44); // 0x2c
|
|
uae_u32 io_error = 0;
|
|
struct priv_devstruct *pdev = getpdevstruct(ctx, request);
|
|
|
|
if (!pdev)
|
|
return 0;
|
|
command = get_word_host(iobuf + 28);
|
|
|
|
//if (log_scsi)
|
|
// write_log (_T("SCSI OTHER %d: DATA=%08X LEN=%08X OFFSET=%08X ACTUAL=%08X\n"),
|
|
// command, io_data, io_length, io_offset, io_actual);
|
|
switch (command)
|
|
{
|
|
case CMD_UPDATE:
|
|
case CMD_CLEAR:
|
|
case CMD_FLUSH:
|
|
case CMD_MOTOR:
|
|
case CMD_SEEK:
|
|
io_actual = 0;
|
|
break;
|
|
case CMD_GETDRIVETYPE:
|
|
io_actual = dev->drivetype;
|
|
break;
|
|
case HD_SCSICMD:
|
|
{
|
|
uae_u32 sdd = get_long_host(iobuf + 40);
|
|
io_error = sys_command_scsi_direct(ctx, dev->unitnum, dev->drivetype, sdd);
|
|
//if (log_scsi)
|
|
// write_log (_T("scsidev other: did io: sdd %08x request %08x error %d\n"), sdd, request, get_byte (request + 31));
|
|
}
|
|
break;
|
|
default:
|
|
io_error = IOERR_NOCMD;
|
|
break;
|
|
}
|
|
|
|
put_long_host(iobuf + 32, io_actual);
|
|
put_byte_host(iobuf + 31, io_error);
|
|
io_log (_T("dev_io_other"), iobuf, request);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int dev_do_io_tape (TrapContext *ctx, struct devstruct *dev, uae_u8 *iobuf, uaecptr request)
|
|
{
|
|
uae_u32 command;
|
|
uae_u32 io_data = get_long_host(iobuf + 40); // 0x28
|
|
uae_u32 io_length = get_long_host(iobuf + 36); // 0x24
|
|
uae_u32 io_actual = get_long_host(iobuf + 32); // 0x20
|
|
uae_u32 io_offset = get_long_host(iobuf + 44); // 0x2c
|
|
uae_u32 io_error = 0;
|
|
struct priv_devstruct *pdev = getpdevstruct(ctx, request);
|
|
|
|
if (!pdev)
|
|
return 0;
|
|
command = get_word_host(iobuf + 28);
|
|
|
|
//if (log_scsi)
|
|
// write_log (_T("TAPE %d: DATA=%08X LEN=%08X OFFSET=%08X ACTUAL=%08X\n"),
|
|
// command, io_data, io_length, io_offset, io_actual);
|
|
switch (command)
|
|
{
|
|
case CMD_UPDATE:
|
|
case CMD_CLEAR:
|
|
case CMD_FLUSH:
|
|
case CMD_MOTOR:
|
|
case CMD_SEEK:
|
|
io_actual = 0;
|
|
break;
|
|
case CMD_GETDRIVETYPE:
|
|
io_actual = dev->drivetype;
|
|
break;
|
|
case HD_SCSICMD:
|
|
{
|
|
uae_u32 sdd = get_long_host(iobuf + 40);
|
|
io_error = sys_command_scsi_direct(ctx, dev->unitnum, INQ_SEQD, sdd);
|
|
//if (log_scsi)
|
|
// write_log (_T("scsidev tape: did io: sdd %08x request %08x error %d\n"), sdd, request, get_byte (request + 31));
|
|
}
|
|
break;
|
|
default:
|
|
io_error = IOERR_NOCMD;
|
|
break;
|
|
}
|
|
|
|
put_long_host(iobuf + 32, io_actual);
|
|
put_byte_host(iobuf + 31, io_error);
|
|
io_log (_T("dev_io_tape"), iobuf, request);
|
|
return 0;
|
|
}
|
|
|
|
static int dev_do_io_cd (TrapContext *ctx, struct devstruct *dev, uae_u8 *iobuf, uaecptr request)
|
|
{
|
|
uae_u32 command;
|
|
uae_u32 io_data = get_long_host(iobuf + 40); // 0x28
|
|
uae_u32 io_length = get_long_host(iobuf + 36); // 0x24
|
|
uae_u32 io_actual = get_long_host(iobuf + 32); // 0x20
|
|
uae_u32 io_offset = get_long_host(iobuf + 44); // 0x2c
|
|
uae_u32 io_error = 0;
|
|
uae_u64 io_offset64;
|
|
int async = 0;
|
|
int bmask = dev->di.bytespersector - 1;
|
|
struct priv_devstruct *pdev = getpdevstruct(ctx, request);
|
|
|
|
if (!pdev)
|
|
return 0;
|
|
command = get_word_host(iobuf + 28);
|
|
|
|
//if (log_scsi)
|
|
// write_log (_T("CD %d: DATA=%08X LEN=%08X OFFSET=%08X ACTUAL=%08X\n"),
|
|
// command, io_data, io_length, io_offset, io_actual);
|
|
|
|
switch (command)
|
|
{
|
|
case CMD_READ:
|
|
if (dev->di.media_inserted <= 0)
|
|
goto no_media;
|
|
if (dev->drivetype == INQ_ROMD) {
|
|
io_error = command_cd_read(ctx, dev, io_data, io_offset, io_length, &io_actual);
|
|
} else {
|
|
if ((io_offset & bmask) || bmask == 0 || io_data == 0)
|
|
goto bad_command;
|
|
if ((io_length & bmask) || io_length == 0)
|
|
goto bad_len;
|
|
io_error = command_read(ctx, dev, io_data, io_offset, io_length, &io_actual);
|
|
}
|
|
break;
|
|
case TD_READ64:
|
|
case NSCMD_TD_READ64:
|
|
if (dev->di.media_inserted <= 0)
|
|
goto no_media;
|
|
io_offset64 = get_long_host(iobuf + 44) | ((uae_u64)get_long_host(iobuf + 32) << 32);
|
|
if ((io_offset64 & bmask) || bmask == 0 || io_data == 0)
|
|
goto bad_command;
|
|
if ((io_length & bmask) || io_length == 0)
|
|
goto bad_len;
|
|
if (dev->drivetype == INQ_ROMD)
|
|
io_error = command_cd_read(ctx, dev, io_data, io_offset64, io_length, &io_actual);
|
|
else
|
|
io_error = command_read(ctx, dev, io_data, io_offset64, io_length, &io_actual);
|
|
break;
|
|
|
|
case CMD_WRITE:
|
|
if (dev->di.media_inserted <= 0)
|
|
goto no_media;
|
|
if (dev->di.write_protected || dev->drivetype == INQ_ROMD) {
|
|
io_error = 28; /* writeprotect */
|
|
} else if ((io_offset & bmask) || bmask == 0 || io_data == 0) {
|
|
goto bad_command;
|
|
} else if ((io_length & bmask) || io_length == 0) {
|
|
goto bad_len;
|
|
} else {
|
|
io_error = command_write(ctx, dev, io_data, io_offset, io_length, &io_actual);
|
|
}
|
|
break;
|
|
case TD_WRITE64:
|
|
case NSCMD_TD_WRITE64:
|
|
if (dev->di.media_inserted <= 0)
|
|
goto no_media;
|
|
io_offset64 = get_long_host(iobuf + 44) | ((uae_u64)get_long_host(iobuf + 32) << 32);
|
|
if (dev->di.write_protected || dev->drivetype == INQ_ROMD) {
|
|
io_error = 28; /* writeprotect */
|
|
} else if ((io_offset64 & bmask) || bmask == 0 || io_data == 0) {
|
|
goto bad_command;
|
|
} else if ((io_length & bmask) || io_length == 0) {
|
|
goto bad_len;
|
|
} else {
|
|
io_error = command_write(ctx, dev, io_data, io_offset64, io_length, &io_actual);
|
|
}
|
|
break;
|
|
|
|
case CMD_FORMAT:
|
|
if (dev->di.media_inserted <= 0)
|
|
goto no_media;
|
|
if (dev->di.write_protected || dev->drivetype == INQ_ROMD) {
|
|
io_error = 28; /* writeprotect */
|
|
} else if ((io_offset & bmask) || bmask == 0 || io_data == 0) {
|
|
goto bad_command;
|
|
} else if ((io_length & bmask) || io_length == 0) {
|
|
goto bad_len;
|
|
} else {
|
|
io_error = command_write(ctx, dev, io_data, io_offset, io_length, &io_actual);
|
|
}
|
|
break;
|
|
case TD_FORMAT64:
|
|
case NSCMD_TD_FORMAT64:
|
|
if (dev->di.media_inserted <= 0)
|
|
goto no_media;
|
|
io_offset64 = get_long_host(iobuf + 44) | ((uae_u64)get_long_host(iobuf + 32) << 32);
|
|
if (dev->di.write_protected || dev->drivetype == INQ_ROMD) {
|
|
io_error = 28; /* writeprotect */
|
|
} else if ((io_offset64 & bmask) || bmask == 0 || io_data == 0) {
|
|
goto bad_command;
|
|
} else if ((io_length & bmask) || io_length == 0) {
|
|
goto bad_len;
|
|
} else {
|
|
io_error = command_write(ctx, dev, io_data, io_offset64, io_length, &io_actual);
|
|
}
|
|
break;
|
|
|
|
case CMD_UPDATE:
|
|
case CMD_CLEAR:
|
|
case CMD_FLUSH:
|
|
case CMD_MOTOR:
|
|
case CMD_SEEK:
|
|
io_actual = 0;
|
|
break;
|
|
case CMD_REMOVE:
|
|
io_actual = dev->changeint;
|
|
dev->changeint = io_data;
|
|
dev->changeint_mediastate = dev->di.media_inserted;
|
|
break;
|
|
case CMD_CHANGENUM:
|
|
io_actual = dev->changenum;
|
|
break;
|
|
case CMD_CHANGESTATE:
|
|
if (dev->di.media_inserted >= 0) {
|
|
io_actual = devinfo (dev, &dev->di)->media_inserted > 0 ? 0 : 1;
|
|
} else {
|
|
io_actual = 1;
|
|
}
|
|
break;
|
|
case CMD_PROTSTATUS:
|
|
io_actual = devinfo (dev, &dev->di)->write_protected ? -1 : 0;
|
|
break;
|
|
case CMD_GETDRIVETYPE:
|
|
io_actual = dev->drivetype;
|
|
break;
|
|
case CMD_GETNUMTRACKS:
|
|
if (dev->di.media_inserted <= 0)
|
|
goto no_media;
|
|
io_actual = dev->di.cylinders;
|
|
break;
|
|
case CMD_GETGEOMETRY:
|
|
{
|
|
struct device_info *di;
|
|
uae_u8 geom[30];
|
|
di = devinfo (dev, &dev->di);
|
|
if (di->media_inserted <= 0)
|
|
goto no_media;
|
|
put_long_host(geom + 0, di->bytespersector);
|
|
put_long_host(geom + 4, di->sectorspertrack * di->trackspercylinder * di->cylinders);
|
|
put_long_host(geom + 8, di->cylinders);
|
|
put_long_host(geom + 12, di->sectorspertrack * di->trackspercylinder);
|
|
put_long_host(geom + 16, di->trackspercylinder);
|
|
put_long_host(geom + 20, di->sectorspertrack);
|
|
put_long_host(geom + 24, 0); /* bufmemtype */
|
|
put_byte_host(geom + 28, di->type);
|
|
put_byte_host(geom + 29, di->removable ? 1 : 0); /* flags */
|
|
trap_put_bytes(ctx, geom, io_data, sizeof geom);
|
|
io_actual = 30;
|
|
}
|
|
break;
|
|
case CMD_ADDCHANGEINT:
|
|
dev->changeint_mediastate = dev->di.media_inserted;
|
|
io_error = add_async_request (dev, iobuf, request, ASYNC_REQUEST_CHANGEINT, io_data);
|
|
if (!io_error)
|
|
async = 1;
|
|
break;
|
|
case CMD_REMCHANGEINT:
|
|
release_async_request (dev, request);
|
|
break;
|
|
|
|
case CD_TOCLSN:
|
|
case CD_TOCMSF:
|
|
{
|
|
int msf = command == CD_TOCMSF;
|
|
struct cd_toc_head toc;
|
|
if (sys_command_cd_toc (dev->di.unitnum, &toc)) {
|
|
if (io_offset == 0 && io_length > 0) {
|
|
int pos = toc.lastaddress;
|
|
trap_put_byte(ctx, io_data, toc.first_track);
|
|
trap_put_byte(ctx, io_data + 1, toc.last_track);
|
|
if (msf)
|
|
pos = lsn2msf (pos);
|
|
trap_put_long(ctx, io_data + 2, pos);
|
|
io_offset++;
|
|
io_length--;
|
|
io_data += 6;
|
|
io_actual++;
|
|
}
|
|
for (int i = toc.first_track_offset; i < toc.last_track_offset && io_length > 0; i++) {
|
|
if (io_offset == toc.toc[i].point) {
|
|
int pos = toc.toc[i].paddress;
|
|
trap_put_byte(ctx, io_data, (toc.toc[i].control << 4) | toc.toc[i].adr);
|
|
trap_put_byte(ctx, io_data + 1, toc.toc[i].point);
|
|
if (msf)
|
|
pos = lsn2msf (pos);
|
|
trap_put_long(ctx, io_data + 2, pos);
|
|
io_offset++;
|
|
io_length--;
|
|
io_data += 6;
|
|
io_actual++;
|
|
}
|
|
}
|
|
} else {
|
|
io_error = IOERR_NotSpecified;
|
|
}
|
|
}
|
|
break;
|
|
case CD_ADDFRAMEINT:
|
|
io_error = add_async_request (dev, iobuf, request, ASYNC_REQUEST_FRAMEINT, io_data);
|
|
if (!io_error)
|
|
async = 1;
|
|
break;
|
|
case CD_REMFRAMEINT:
|
|
release_async_request (dev, request);
|
|
break;
|
|
case CD_ATTENUATE:
|
|
{
|
|
if (io_offset != -1) {
|
|
dev->fadeframes = io_length & 0x7fff;
|
|
dev->fadetarget = io_offset & 0x7fff;
|
|
}
|
|
io_actual = dev->volumelevel;
|
|
}
|
|
break;
|
|
case CD_INFO:
|
|
{
|
|
uae_u16 status = 0;
|
|
struct cd_toc_head toc;
|
|
uae_u8 cdinfo[34] = { 0 };
|
|
uae_u8 subq[SUBQ_SIZE] = { 0 };
|
|
sys_command_cd_qcode (dev->di.unitnum, subq, -1, false);
|
|
status |= 1 << 0; // door closed
|
|
if (dev->di.media_inserted) {
|
|
status |= 1 << 1;
|
|
status |= 1 << 2; // motor on
|
|
if (sys_command_cd_toc (dev->di.unitnum, &toc)) {
|
|
status |= 1 << 3; // toc
|
|
if (subq[1] == AUDIO_STATUS_IN_PROGRESS || subq[1] == AUDIO_STATUS_PAUSED)
|
|
status |= 1 << 5; // audio play
|
|
if (subq[1] == AUDIO_STATUS_PAUSED)
|
|
status |= 1 << 6; // paused
|
|
if (isdatatrack (&toc, 0))
|
|
status |= 1 << 4; // data track
|
|
}
|
|
}
|
|
put_word_host(cdinfo + 0, 75); // PlaySpeed
|
|
put_word_host(cdinfo + 2, 1200); // ReadSpeed (randomly chose 16x)
|
|
put_word_host(cdinfo + 4, 1200); // ReadXLSpeed
|
|
put_word_host(cdinfo + 6, dev->configblocksize); // SectorSize
|
|
put_word_host(cdinfo + 8, -1); // XLECC
|
|
put_word_host(cdinfo + 10, 0); // EjectReset
|
|
put_word_host(cdinfo + 12, 0); // Reserved * 4
|
|
put_word_host(cdinfo + 14, 0);
|
|
put_word_host(cdinfo + 16, 0);
|
|
put_word_host(cdinfo + 18, 0);
|
|
put_word_host(cdinfo + 20, 1200); // MaxSpeed
|
|
put_word_host(cdinfo + 22, 0xffff); // AudioPrecision (volume)
|
|
put_word_host(cdinfo + 24, status); // Status
|
|
put_word_host(cdinfo + 26, 0); // Reserved2 * 4
|
|
put_word_host(cdinfo + 28, 0);
|
|
put_word_host(cdinfo + 30, 0);
|
|
put_word_host(cdinfo + 32, 0);
|
|
io_actual = 34;
|
|
trap_put_bytes(ctx, cdinfo, io_data, io_actual);
|
|
}
|
|
break;
|
|
case CD_CONFIG:
|
|
{
|
|
while (trap_get_long(ctx, io_data) != TAG_DONE) {
|
|
uae_u32 tag = trap_get_long(ctx, io_data);
|
|
uae_u32 data = trap_get_long(ctx, io_data + 4);
|
|
if (tag == 4) {
|
|
// TAGCD_SECTORSIZE
|
|
if (data == 2048 || data == 2336 || data == 2352)
|
|
dev->configblocksize = data;
|
|
else
|
|
io_error = IOERR_BADADDRESS;
|
|
|
|
}
|
|
io_data += 8;
|
|
}
|
|
break;
|
|
}
|
|
case CD_PAUSE:
|
|
{
|
|
int old = sys_command_cd_pause (dev->di.unitnum, io_length);
|
|
if (old >= 0)
|
|
io_actual = old;
|
|
else
|
|
io_error = IOERR_BADADDRESS;
|
|
break;
|
|
}
|
|
case CD_PLAYLSN:
|
|
{
|
|
int start = io_offset;
|
|
int end = io_length + start;
|
|
if (!sys_command_cd_play (dev->di.unitnum, start, end, 0))
|
|
io_error = IOERR_BADADDRESS;
|
|
}
|
|
break;
|
|
case CD_PLAYMSF:
|
|
{
|
|
int start = msf2lsn (io_offset);
|
|
int end = msf2lsn (io_length) + start;
|
|
if (!sys_command_cd_play (dev->di.unitnum, start, end, 0))
|
|
io_error = IOERR_BADADDRESS;
|
|
}
|
|
break;
|
|
case CD_PLAYTRACK:
|
|
{
|
|
struct cd_toc_head toc;
|
|
int ok = 0;
|
|
if (sys_command_cd_toc (dev->di.unitnum, &toc)) {
|
|
for (int i = toc.first_track_offset; i < toc.last_track_offset; i++) {
|
|
if (i == io_offset && i + io_length <= toc.last_track_offset) {
|
|
ok = sys_command_cd_play (dev->di.unitnum, toc.toc[i].address, toc.toc[i + io_length].address, 0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!ok)
|
|
io_error = IOERR_BADADDRESS;
|
|
}
|
|
break;
|
|
case CD_QCODEMSF:
|
|
case CD_QCODELSN:
|
|
{
|
|
uae_u8 subq[SUBQ_SIZE];
|
|
if (sys_command_cd_qcode (dev->di.unitnum, subq, -1, false)) {
|
|
if (subq[1] == AUDIO_STATUS_IN_PROGRESS || subq[1] == AUDIO_STATUS_PAUSED) {
|
|
uae_u8 subqdata[12];
|
|
put_byte_host(subqdata + 0, subq[4 + 0]);
|
|
put_byte_host(subqdata + 1, frombcd (subq[4 + 1]));
|
|
put_byte_host(subqdata + 2, frombcd (subq[4 + 2]));
|
|
put_byte_host(subqdata + 3, subq[4 + 6]);
|
|
int trackpos = fromlongbcd (subq + 4 + 3);
|
|
int diskpos = fromlongbcd (subq + 4 + 7);
|
|
if (command == CD_QCODELSN) {
|
|
trackpos = msf2lsn (trackpos);
|
|
diskpos = msf2lsn (diskpos);
|
|
}
|
|
put_long_host(subqdata + 4, trackpos);
|
|
put_long_host(subqdata + 8, diskpos);
|
|
io_actual = 12;
|
|
trap_put_bytes(ctx, subqdata, io_data, io_actual);
|
|
} else {
|
|
io_error = IOERR_InvalidState;
|
|
}
|
|
} else {
|
|
io_error = IOERR_BADADDRESS;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case HD_SCSICMD:
|
|
{
|
|
uae_u32 sdd = get_long_host(iobuf + 40);
|
|
io_error = sys_command_scsi_direct(ctx, dev->unitnum, INQ_ROMD, sdd);
|
|
io_actual = 0;
|
|
//if (log_scsi)
|
|
// write_log (_T("scsidev cd: did io: sdd %08x request %08x error %d\n"), sdd, request, io_error);
|
|
}
|
|
break;
|
|
case NSCMD_DEVICEQUERY:
|
|
trap_put_long(ctx, io_data + 0, 0);
|
|
trap_put_long(ctx, io_data + 4, 16); /* size */
|
|
trap_put_word(ctx, io_data + 8, NSDEVTYPE_TRACKDISK);
|
|
trap_put_word(ctx, io_data + 10, 0);
|
|
trap_put_long(ctx, io_data + 12, nscmd_cmd);
|
|
io_actual = 16;
|
|
break;
|
|
default:
|
|
io_error = IOERR_NOCMD;
|
|
break;
|
|
bad_len:
|
|
io_error = IOERR_BADLENGTH;
|
|
break;
|
|
bad_command:
|
|
io_error = IOERR_BADADDRESS;
|
|
break;
|
|
no_media:
|
|
io_error = TDERR_DiskChanged;
|
|
break;
|
|
}
|
|
put_long_host(iobuf + 32, io_actual);
|
|
put_byte_host(iobuf + 31, io_error);
|
|
io_log (_T("dev_io_cd"), iobuf, request);
|
|
return async;
|
|
}
|
|
|
|
static int dev_do_io(TrapContext *ctx, struct devstruct *dev, uae_u8 *iobuf, uaecptr request)
|
|
{
|
|
if (dev->drivetype == INQ_SEQD) {
|
|
return dev_do_io_tape(ctx, dev, iobuf, request);
|
|
} else if (dev->drivetype == INQ_ROMD) {
|
|
return dev_do_io_cd(ctx, dev, iobuf, request);
|
|
} else {
|
|
return dev_do_io_other(ctx, dev, iobuf, request);
|
|
}
|
|
}
|
|
|
|
static int dev_can_quick(uae_u32 command)
|
|
{
|
|
switch (command)
|
|
{
|
|
case CMD_RESET:
|
|
case CMD_STOP:
|
|
case CMD_START:
|
|
case CMD_CHANGESTATE:
|
|
case CMD_PROTSTATUS:
|
|
case CMD_GETDRIVETYPE:
|
|
return 1;
|
|
case CMD_GETNUMTRACKS:
|
|
case CMD_ADDCHANGEINT:
|
|
case CMD_REMCHANGEINT:
|
|
case CD_ADDFRAMEINT:
|
|
case CD_REMFRAMEINT:
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int dev_canquick(struct devstruct *dev, uae_u8 *iobuf, uaecptr request)
|
|
{
|
|
uae_u32 command = get_word_host(iobuf + 28);
|
|
return dev_can_quick (command);
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 dev_beginio(TrapContext *ctx)
|
|
{
|
|
uae_u32 request = trap_get_areg(ctx, 1);
|
|
|
|
uae_u8 *iobuf = xmalloc(uae_u8, 48);
|
|
|
|
trap_get_bytes(ctx, iobuf, request, 48);
|
|
|
|
uae_u8 flags = get_byte_host(iobuf + 30);
|
|
int command = get_word_host(iobuf + 28);
|
|
struct priv_devstruct *pdev = getpdevstruct(ctx, request);
|
|
struct devstruct *dev;
|
|
int canquick;
|
|
|
|
put_byte_host(iobuf + 8, NT_MESSAGE);
|
|
if (!pdev) {
|
|
uae_u8 err = 32;
|
|
put_byte_host(iobuf + 31, err);
|
|
trap_put_bytes(ctx, iobuf + 8, request + 8, 48 - 8);
|
|
xfree(iobuf);
|
|
return err;
|
|
}
|
|
dev = getdevstruct (pdev->unit);
|
|
if (!dev) {
|
|
uae_u8 err = 32;
|
|
put_byte_host(iobuf + 31, err);
|
|
trap_put_bytes(ctx, iobuf + 8, request + 8, 48 - 8);
|
|
xfree(iobuf);
|
|
return err;
|
|
}
|
|
|
|
put_byte_host(iobuf + 31, 0);
|
|
canquick = dev_canquick (dev, iobuf, request);
|
|
if (((flags & 1) && canquick) || (canquick < 0)) {
|
|
bool async = dev_do_io(ctx, dev, iobuf, request) != 0;
|
|
uae_u8 v = get_byte_host(iobuf + 31);
|
|
trap_put_bytes(ctx, iobuf + 8, request + 8, 48 - 8);
|
|
if (!async)
|
|
xfree(iobuf);
|
|
if (!(flags & 1) && !async)
|
|
uae_ReplyMsg (request);
|
|
return v;
|
|
} else {
|
|
add_async_request (dev, iobuf, request, ASYNC_REQUEST_TEMP, 0);
|
|
put_byte_host(iobuf + 30, get_byte_host(iobuf + 30) & ~1);
|
|
trap_put_bytes(ctx, iobuf + 8, request + 8, 48 - 8);
|
|
trap_set_background(ctx);
|
|
write_comm_pipe_pvoid(&dev->requests, ctx, 0);
|
|
write_comm_pipe_pvoid(&dev->requests, iobuf, 0);
|
|
write_comm_pipe_u32(&dev->requests, request, 1);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int dev_thread (void *devs)
|
|
{
|
|
struct devstruct *dev = (struct devstruct*)devs;
|
|
|
|
uae_set_thread_priority (NULL, 1);
|
|
dev->thread_running = 1;
|
|
uae_sem_post (&dev->sync_sem);
|
|
for (;;) {
|
|
TrapContext *ctx = (TrapContext*)read_comm_pipe_pvoid_blocking(&dev->requests);
|
|
uae_u8 *iobuf = (uae_u8*)read_comm_pipe_pvoid_blocking(&dev->requests);
|
|
uaecptr request = (uaecptr)read_comm_pipe_u32_blocking (&dev->requests);
|
|
uae_sem_wait (&change_sem);
|
|
if (!request) {
|
|
dev->thread_running = 0;
|
|
uae_sem_post (&dev->sync_sem);
|
|
uae_sem_post (&change_sem);
|
|
return 0;
|
|
} else if (dev_do_io(ctx, dev, iobuf, request) == 0) {
|
|
put_byte_host(iobuf + 30, get_byte_host(iobuf + 30) & ~1);
|
|
trap_put_bytes(ctx, iobuf + 8, request + 8, 48 - 8);
|
|
release_async_request (dev, request);
|
|
uae_ReplyMsg (request);
|
|
} else {
|
|
//if (log_scsi)
|
|
// write_log (_T("%s:%d async request %08X\n"), getdevname(0), dev->unitnum, request);
|
|
trap_put_bytes(ctx, iobuf + 8, request + 8, 48 - 8);
|
|
}
|
|
trap_background_set_complete(ctx);
|
|
uae_sem_post (&change_sem);
|
|
}
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 dev_init_2(TrapContext *ctx, int type)
|
|
{
|
|
uae_u32 base = trap_get_dreg(ctx, 0);
|
|
//if (log_scsi)
|
|
// write_log (_T("%s init\n"), getdevname (type));
|
|
return base;
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 dev_init(TrapContext *ctx)
|
|
{
|
|
return dev_init_2(ctx, UAEDEV_SCSI_ID);
|
|
}
|
|
static uae_u32 REGPARAM2 diskdev_init(TrapContext *ctx)
|
|
{
|
|
return dev_init_2(ctx, UAEDEV_DISK_ID);
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 dev_abortio (TrapContext *ctx)
|
|
{
|
|
uae_u32 request = trap_get_areg(ctx, 1);
|
|
struct priv_devstruct *pdev = getpdevstruct(ctx, request);
|
|
struct devstruct *dev;
|
|
|
|
if (!pdev) {
|
|
uae_u8 err = 32;
|
|
trap_put_byte(ctx, request + 31, err);
|
|
return err;
|
|
}
|
|
dev = getdevstruct (pdev->unit);
|
|
if (!dev) {
|
|
uae_u8 err = 32;
|
|
trap_put_byte(ctx, request + 31, err);
|
|
return err;
|
|
}
|
|
trap_put_byte(ctx, request + 31, IOERR_ABORTED);
|
|
//if (log_scsi)
|
|
// write_log (_T("abortio %s unit=%d, request=%08X\n"), getdevname (pdev->type), pdev->unit, request);
|
|
abort_async(dev, request, IOERR_ABORTED, 0);
|
|
return 0;
|
|
}
|
|
|
|
#define BTL2UNIT(bus, target, lun) (2 * (bus) + (target) / 8) * 100 + (lun) * 10 + (target % 8)
|
|
|
|
uae_u32 scsi_get_cd_drive_mask (void)
|
|
{
|
|
uae_u32 mask = 0;
|
|
for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
|
|
struct devstruct *dev = &devst[i];
|
|
if (dev->iscd)
|
|
mask |= 1 << i;
|
|
}
|
|
return mask;
|
|
}
|
|
uae_u32 scsi_get_cd_drive_media_mask (void)
|
|
{
|
|
uae_u32 mask = 0;
|
|
for (int i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
|
|
struct devstruct *dev = &devst[i];
|
|
if (dev->iscd && dev->changeint_mediastate)
|
|
mask |= 1 << i;
|
|
}
|
|
return mask;
|
|
}
|
|
int scsi_add_tape (struct uaedev_config_info *uci)
|
|
{
|
|
for (int i = 4; i < MAX_TOTAL_SCSI_DEVICES; i++) {
|
|
struct devstruct *dev = &devst[i];
|
|
if (dev->unitnum >= 0 || dev->drivetype > 0)
|
|
continue;
|
|
//if (sys_command_open_tape (i, uci->rootdir, uci->readonly)) {
|
|
// dev->drivetype = INQ_SEQD;
|
|
// dev->aunit = i;
|
|
// dev->unitnum = i;
|
|
// dev->tape_directory = my_strdup (uci->rootdir);
|
|
// write_log (_T("%s:%d = '%s''\n"), UAEDEV_SCSI, dev->aunit, uci->rootdir);
|
|
// return i;
|
|
//}
|
|
}
|
|
return -1;
|
|
}
|
|
static void dev_reset (void)
|
|
{
|
|
int i, j;
|
|
struct devstruct *dev;
|
|
int unitnum = 0;
|
|
|
|
for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
|
|
dev = &devst[i];
|
|
if (dev->opencnt > 0) {
|
|
for (j = 0; j < MAX_ASYNC_REQUESTS; j++) {
|
|
uaecptr request;
|
|
if ((request = dev->d_request[i]))
|
|
abort_async (dev, request, 0, 0);
|
|
}
|
|
dev->opencnt = 1;
|
|
if (dev->unitnum >= 0)
|
|
sys_command_close (dev->unitnum);
|
|
}
|
|
memset (dev, 0, sizeof (struct devstruct));
|
|
xfree (dev->tape_directory);
|
|
dev->unitnum = dev->aunit = -1;
|
|
}
|
|
for (i = 0; i < MAX_OPEN_DEVICES; i++)
|
|
memset (&pdevst[i], 0, sizeof (struct priv_devstruct));
|
|
|
|
device_func_init (0);
|
|
i = 0;
|
|
while (i < MAX_TOTAL_SCSI_DEVICES) {
|
|
dev = &devst[i];
|
|
struct device_info *discsi, discsi2;
|
|
if (sys_command_open (i)) {
|
|
discsi = sys_command_info (i, &discsi2, 0);
|
|
if (discsi) {
|
|
dev->unitnum = i;
|
|
dev->drivetype = discsi->type;
|
|
memcpy (&dev->di, discsi, sizeof (struct device_info));
|
|
dev->changeint_mediastate = discsi->media_inserted;
|
|
dev->configblocksize = discsi->bytespersector;
|
|
if (discsi->type == INQ_ROMD)
|
|
dev->iscd = 1;
|
|
} else {
|
|
sys_command_close (i);
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
unitnum = 0;
|
|
for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
|
|
dev = &devst[i];
|
|
if (dev->unitnum >= 0)
|
|
sys_command_close (dev->unitnum);
|
|
if (dev->unitnum >= 0 && dev->iscd) {
|
|
dev->aunit = unitnum;
|
|
dev->volumelevel = 0x7fff;
|
|
unitnum++;
|
|
}
|
|
}
|
|
if (unitnum == 0)
|
|
unitnum = 1;
|
|
for (i = 0; i < MAX_TOTAL_SCSI_DEVICES; i++) {
|
|
dev = &devst[i];
|
|
if (dev->unitnum >= 0) {
|
|
if (!dev->iscd) {
|
|
dev->aunit = unitnum;
|
|
unitnum++;
|
|
}
|
|
write_log (_T("%s:%d = %s:'%s',%d\n"), UAEDEV_SCSI, dev->aunit, dev->di.backend, dev->di.label, dev->di.type);
|
|
}
|
|
dev->di.label[0] = 0;
|
|
}
|
|
}
|
|
|
|
static uaecptr ROM_scsidev_resname = 0,
|
|
ROM_scsidev_resid = 0,
|
|
ROM_scsidev_init = 0;
|
|
|
|
static uaecptr ROM_diskdev_resname = 0,
|
|
ROM_diskdev_resid = 0,
|
|
ROM_diskdev_init = 0;
|
|
|
|
|
|
static uaecptr diskdev_startup (TrapContext *ctx, uaecptr resaddr)
|
|
{
|
|
/* Build a struct Resident. This will set up and initialize
|
|
* the cd.device */
|
|
//if (log_scsi)
|
|
// write_log (_T("diskdev_startup(0x%x)\n"), resaddr);
|
|
trap_put_word(ctx, resaddr + 0x0, 0x4AFC);
|
|
trap_put_long(ctx, resaddr + 0x2, resaddr);
|
|
trap_put_long(ctx, resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */
|
|
trap_put_word(ctx, resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */
|
|
trap_put_word(ctx, resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */
|
|
trap_put_long(ctx, resaddr + 0xE, ROM_diskdev_resname);
|
|
trap_put_long(ctx, resaddr + 0x12, ROM_diskdev_resid);
|
|
trap_put_long(ctx, resaddr + 0x16, ROM_diskdev_init);
|
|
resaddr += 0x1A;
|
|
return resaddr;
|
|
}
|
|
|
|
uaecptr scsidev_startup(TrapContext *ctx, uaecptr resaddr)
|
|
{
|
|
if (currprefs.scsi != 1)
|
|
return resaddr;
|
|
//if (log_scsi)
|
|
// write_log (_T("scsidev_startup(0x%x)\n"), resaddr);
|
|
/* Build a struct Resident. This will set up and initialize
|
|
* the uaescsi.device */
|
|
trap_put_word(ctx, resaddr + 0x0, 0x4AFC);
|
|
trap_put_long(ctx, resaddr + 0x2, resaddr);
|
|
trap_put_long(ctx, resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */
|
|
trap_put_word(ctx, resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */
|
|
trap_put_word(ctx, resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */
|
|
trap_put_long(ctx, resaddr + 0xE, ROM_scsidev_resname);
|
|
trap_put_long(ctx, resaddr + 0x12, ROM_scsidev_resid);
|
|
trap_put_long(ctx, resaddr + 0x16, ROM_scsidev_init); /* calls scsidev_init */
|
|
resaddr += 0x1A;
|
|
return resaddr;
|
|
//return diskdev_startup(ctx, resaddr);
|
|
}
|
|
|
|
static void diskdev_install (void)
|
|
{
|
|
uae_u32 functable, datatable;
|
|
uae_u32 initcode, openfunc, closefunc, expungefunc;
|
|
uae_u32 beginiofunc, abortiofunc;
|
|
|
|
if (currprefs.scsi != 1)
|
|
return;
|
|
//if (log_scsi)
|
|
// write_log (_T("diskdev_install(): 0x%x\n"), here ());
|
|
|
|
ROM_diskdev_resname = ds (UAEDEV_DISK);
|
|
ROM_diskdev_resid = ds (_T("UAE disk.device 0.1"));
|
|
|
|
/* initcode */
|
|
initcode = here ();
|
|
calltrap (deftrap (diskdev_init)); dw (RTS);
|
|
|
|
/* Open */
|
|
openfunc = here ();
|
|
calltrap (deftrap (diskdev_open)); dw (RTS);
|
|
|
|
/* Close */
|
|
closefunc = here ();
|
|
calltrap (deftrap (diskdev_close)); dw (RTS);
|
|
|
|
/* Expunge */
|
|
expungefunc = here ();
|
|
calltrap (deftrap (diskdev_expunge)); dw (RTS);
|
|
|
|
/* BeginIO */
|
|
beginiofunc = here ();
|
|
calltrap (deftrap (dev_beginio));
|
|
dw (RTS);
|
|
|
|
/* AbortIO */
|
|
abortiofunc = here ();
|
|
calltrap (deftrap (dev_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_diskdev_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); /* INITWORD */
|
|
dw (0x0016); /* LIB_REVISION */
|
|
dw (0x0000); /* end of table already ??? */
|
|
dw (0xC000); /* INITLONG */
|
|
dw (0x0018); /* LIB_IDSTRING */
|
|
dl (ROM_diskdev_resid);
|
|
dw (0x0000); /* end of table */
|
|
|
|
ROM_diskdev_init = here ();
|
|
dl (0x00000100); /* size of device base */
|
|
dl (functable);
|
|
dl (datatable);
|
|
dl (initcode);
|
|
}
|
|
|
|
|
|
void scsidev_install (void)
|
|
{
|
|
uae_u32 functable, datatable;
|
|
uae_u32 initcode, openfunc, closefunc, expungefunc;
|
|
uae_u32 beginiofunc, abortiofunc;
|
|
|
|
if (currprefs.scsi != 1)
|
|
return;
|
|
//if (log_scsi)
|
|
// write_log (_T("scsidev_install(): 0x%x\n"), here ());
|
|
|
|
ROM_scsidev_resname = ds (UAEDEV_SCSI);
|
|
ROM_scsidev_resid = ds (_T("UAE scsi.device 0.2"));
|
|
|
|
/* initcode */
|
|
initcode = here ();
|
|
calltrap (deftrap (dev_init)); dw (RTS);
|
|
|
|
/* Open */
|
|
openfunc = here ();
|
|
calltrap (deftrap (dev_open)); dw (RTS);
|
|
|
|
/* Close */
|
|
closefunc = here ();
|
|
calltrap (deftrap (dev_close)); dw (RTS);
|
|
|
|
/* Expunge */
|
|
expungefunc = here ();
|
|
calltrap (deftrap (dev_expunge)); dw (RTS);
|
|
|
|
/* BeginIO */
|
|
beginiofunc = here ();
|
|
calltrap (deftrap (dev_beginio));
|
|
dw (RTS);
|
|
|
|
/* AbortIO */
|
|
abortiofunc = here ();
|
|
calltrap (deftrap (dev_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_scsidev_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); /* INITWORD */
|
|
dw (0x0016); /* LIB_REVISION */
|
|
dw (0x0000);
|
|
dw (0xC000); /* INITLONG */
|
|
dw (0x0018); /* LIB_IDSTRING */
|
|
dl (ROM_scsidev_resid);
|
|
dw (0x0000); /* end of table */
|
|
|
|
ROM_scsidev_init = here ();
|
|
dl (0x00000100); /* size of device base */
|
|
dl (functable);
|
|
dl (datatable);
|
|
dl (initcode);
|
|
|
|
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);
|
|
|
|
diskdev_install ();
|
|
}
|
|
|
|
void scsidev_start_threads (void)
|
|
{
|
|
if (currprefs.scsi != 1) /* quite useless.. */
|
|
return;
|
|
//if (log_scsi)
|
|
// write_log (_T("scsidev_start_threads()\n"));
|
|
uae_sem_init (&change_sem, 0, 1);
|
|
}
|
|
|
|
void scsidev_reset (void)
|
|
{
|
|
if (currprefs.scsi != 1)
|
|
return;
|
|
dev_reset ();
|
|
}
|
|
|
|
#ifdef SAVESTATE
|
|
|
|
uae_u8 *save_scsidev (int num, int *len, uae_u8 *dstptr)
|
|
{
|
|
uae_u8 *dstbak, *dst;
|
|
struct priv_devstruct *pdev;
|
|
struct devstruct *dev;
|
|
|
|
pdev = &pdevst[num];
|
|
if (!pdev->inuse)
|
|
return NULL;
|
|
if (dstptr)
|
|
dstbak = dst = dstptr;
|
|
else
|
|
dstbak = dst = xmalloc (uae_u8, 1000);
|
|
save_u32 (num);
|
|
save_u32 (0);
|
|
save_u32 (pdev->unit);
|
|
save_u32 (pdev->type);
|
|
save_u32 (pdev->mode);
|
|
save_u32 (pdev->flags);
|
|
dev = getdevstruct (pdev->unit);
|
|
if (dev) {
|
|
save_u32 (0);
|
|
save_u32 (dev->aunit);
|
|
save_u32 (dev->opencnt);
|
|
save_u32 (dev->changenum);
|
|
save_u32 (dev->changeint);
|
|
save_u32 (dev->changeint_mediastate);
|
|
save_u32 (dev->configblocksize);
|
|
save_u32 (dev->fadecounter);
|
|
save_u32 (dev->fadeframes);
|
|
save_u32 (dev->fadetarget);
|
|
for (int i = 0; i < MAX_ASYNC_REQUESTS; i++) {
|
|
if (dev->d_request[i]) {
|
|
save_u32 (dev->d_request[i]);
|
|
save_u32 (dev->d_request_type[i]);
|
|
save_u32 (dev->d_request_data[i]);
|
|
}
|
|
}
|
|
save_u32 (0xffffffff);
|
|
} else {
|
|
save_u32 (0xffffffff);
|
|
}
|
|
*len = dst - dstbak;
|
|
return dstbak;
|
|
}
|
|
|
|
uae_u8 *restore_scsidev (uae_u8 *src)
|
|
{
|
|
struct priv_devstruct *pdev;
|
|
struct devstruct *dev;
|
|
int i;
|
|
|
|
int num = restore_u32 ();
|
|
if (num == 0)
|
|
dev_reset ();
|
|
pdev = &pdevst[num];
|
|
restore_u32 ();
|
|
restore_u32 ();
|
|
pdev->type = restore_u32 ();
|
|
pdev->mode = restore_u32 ();
|
|
pdev->flags = restore_u32 ();
|
|
if (restore_u32 () != 0xffffffff) {
|
|
dev = getdevstruct (pdev->unit);
|
|
if (dev) {
|
|
dev->aunit = restore_u32 ();
|
|
dev->opencnt = restore_u32 ();
|
|
dev->changenum = restore_u32 ();
|
|
dev->changeint = restore_u32 ();
|
|
dev->changeint_mediastate = restore_u32 ();
|
|
dev->configblocksize = restore_u32 ();
|
|
dev->fadecounter = restore_u32 ();
|
|
dev->fadeframes = restore_u32 ();
|
|
dev->fadetarget = restore_u32 ();
|
|
i = 0;
|
|
for (;;) {
|
|
uae_u32 v = restore_u32 ();
|
|
if (v == 0xffffffff)
|
|
break;
|
|
dev->d_request[i] = v;
|
|
dev->d_request_type[i] = restore_u32 ();
|
|
dev->d_request_data[i] = restore_u32 ();
|
|
}
|
|
}
|
|
}
|
|
return src;
|
|
}
|
|
|
|
#endif /* SAVESTATE */
|
|
|
|
#endif /* SCSIEMU */
|