mirror of
https://github.com/Oibaf66/uae-wii.git
synced 2024-11-29 14:04:17 +01:00
951 lines
23 KiB
C
951 lines
23 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"
|
||
|
|
||
|
#include "uae.h"
|
||
|
#include "threaddep/thread.h"
|
||
|
#include "options.h"
|
||
|
#include "memory.h"
|
||
|
#include "custom.h"
|
||
|
#include "events.h"
|
||
|
#include "newcpu.h"
|
||
|
#include "autoconf.h"
|
||
|
#include "traps.h"
|
||
|
#include "execlib.h"
|
||
|
#include "native2amiga.h"
|
||
|
#include "blkdev.h"
|
||
|
#include "scsidev.h"
|
||
|
#include "sleep.h"
|
||
|
|
||
|
#define CDDEV_COMMANDS
|
||
|
|
||
|
#define UAEDEV_SCSI "uaescsi.device"
|
||
|
#define UAEDEV_SCSI_ID 1
|
||
|
#define UAEDEV_DISK "uaedisk.device"
|
||
|
#define UAEDEV_DISK_ID 2
|
||
|
|
||
|
#define MAX_ASYNC_REQUESTS 20
|
||
|
#define MAX_OPEN_DEVICES 20
|
||
|
|
||
|
#define CMD_INVALID 0
|
||
|
#define CMD_RESET 1
|
||
|
#define CMD_READ 2
|
||
|
#define CMD_WRITE 3
|
||
|
#define CMD_UPDATE 4
|
||
|
#define CMD_CLEAR 5
|
||
|
#define CMD_STOP 6
|
||
|
#define CMD_START 7
|
||
|
#define CMD_FLUSH 8
|
||
|
#define CMD_MOTOR 9
|
||
|
#define CMD_SEEK 10
|
||
|
#define CMD_FORMAT 11
|
||
|
#define CMD_REMOVE 12
|
||
|
#define CMD_CHANGENUM 13
|
||
|
#define CMD_CHANGESTATE 14
|
||
|
#define CMD_PROTSTATUS 15
|
||
|
#define CMD_GETDRIVETYPE 18
|
||
|
#define CMD_GETNUMTRACKS 19
|
||
|
#define CMD_ADDCHANGEINT 20
|
||
|
#define CMD_REMCHANGEINT 21
|
||
|
#define CMD_GETGEOMETRY 22
|
||
|
|
||
|
#define CD_INFO 32
|
||
|
#define CD_CONFIG 33
|
||
|
#define CD_TOCMSF 34
|
||
|
#define CD_TOCLSN 35
|
||
|
#define CD_READXL 36
|
||
|
#define CD_PLAYTRACK 37
|
||
|
#define CD_PLAYMSF 38
|
||
|
#define CD_PLAYLSN 39
|
||
|
#define CD_PAUSE 40
|
||
|
#define CD_SEARCH 41
|
||
|
#define CD_QCODEMSF 42
|
||
|
#define CD_QCODELSN 43
|
||
|
#define CD_ATTENUATE 44
|
||
|
#define CD_ADDFRAMEINT 45
|
||
|
#define CD_REMFRAMEINT 46
|
||
|
|
||
|
#define ASYNC_REQUEST_NONE 0
|
||
|
#define ASYNC_REQUEST_TEMP 1
|
||
|
#define ASYNC_REQUEST_CHANGEINT 10
|
||
|
#define ASYNC_REQUEST_FRAMEINT 11
|
||
|
#define ASYNC_REQUEST_PLAY 12
|
||
|
#define ASYNC_REQUEST_READXL 13
|
||
|
#define ASYNC_REQUEST_FRAMECALL 14
|
||
|
|
||
|
struct devstruct {
|
||
|
int unitnum, aunit;
|
||
|
int opencnt;
|
||
|
int changenum;
|
||
|
int allow_scsi;
|
||
|
int allow_ioctl;
|
||
|
int drivetype;
|
||
|
int iscd;
|
||
|
volatile uaecptr d_request[MAX_ASYNC_REQUESTS];
|
||
|
volatile int d_request_type[MAX_ASYNC_REQUESTS];
|
||
|
volatile uae_u32 d_request_data[MAX_ASYNC_REQUESTS];
|
||
|
struct device_info di;
|
||
|
|
||
|
smp_comm_pipe requests;
|
||
|
uae_thread_id tid;
|
||
|
int thread_running;
|
||
|
uae_sem_t sync_sem;
|
||
|
};
|
||
|
|
||
|
struct priv_devstruct {
|
||
|
int inuse;
|
||
|
int unit;
|
||
|
int mode;
|
||
|
int scsi;
|
||
|
int ioctl;
|
||
|
int noscsi;
|
||
|
int type;
|
||
|
int flags; /* OpenDevice() */
|
||
|
};
|
||
|
|
||
|
static struct devstruct devst[MAX_TOTAL_DEVICES];
|
||
|
static struct priv_devstruct pdevst[MAX_OPEN_DEVICES];
|
||
|
|
||
|
static uae_sem_t change_sem;
|
||
|
|
||
|
static struct device_info *devinfo (int mode, int unitnum, struct device_info *di)
|
||
|
{
|
||
|
return sys_command_info (mode, unitnum, di);
|
||
|
}
|
||
|
|
||
|
static void io_log (const char *msg, uaecptr request)
|
||
|
{
|
||
|
if (log_scsi)
|
||
|
write_log ("%s: %08X %d %08.8X %d %d io_actual=%d io_error=%d\n",
|
||
|
msg, request,get_word(request + 28),get_long(request + 40),get_long(request + 36),get_long(request + 44),
|
||
|
get_long (request + 32), get_byte (request + 31));
|
||
|
}
|
||
|
|
||
|
STATIC_INLINE void memcpyha (uae_u32 dst, const uae_u8 *src, int size)
|
||
|
{
|
||
|
while (size--)
|
||
|
put_byte (dst++, *src++);
|
||
|
}
|
||
|
|
||
|
STATIC_INLINE struct devstruct *getdevstruct (int unit)
|
||
|
{
|
||
|
int i;
|
||
|
for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
|
||
|
if (unit >= 0 && devst[i].aunit == unit) return &devst[i];
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static struct priv_devstruct *getpdevstruct (uaecptr request)
|
||
|
{
|
||
|
int i = get_long (request + 24);
|
||
|
if (i < 0 || i >= MAX_OPEN_DEVICES || pdevst[i].inuse == 0) {
|
||
|
write_log ("uaescsi.device: corrupt iorequest %08.8X %d\n", request, i);
|
||
|
return 0;
|
||
|
}
|
||
|
return &pdevst[i];
|
||
|
}
|
||
|
|
||
|
static const char *getdevname (int type)
|
||
|
{
|
||
|
switch (type) {
|
||
|
case UAEDEV_SCSI_ID:
|
||
|
return UAEDEV_SCSI;
|
||
|
case UAEDEV_DISK_ID:
|
||
|
return UAEDEV_DISK;
|
||
|
default:
|
||
|
abort ();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void *dev_thread (void *devs);
|
||
|
static int start_thread (struct devstruct *dev)
|
||
|
{
|
||
|
if (dev->thread_running)
|
||
|
return 1;
|
||
|
init_comm_pipe (&dev->requests, 100, 1);
|
||
|
uae_sem_init (&dev->sync_sem, 0, 0);
|
||
|
uae_start_thread (dev_thread, dev, &dev->tid);
|
||
|
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) {
|
||
|
if (pdev->scsi)
|
||
|
sys_command_close (DF_SCSI, dev->unitnum);
|
||
|
if (pdev->ioctl)
|
||
|
sys_command_close (DF_IOCTL, dev->unitnum);
|
||
|
pdev->inuse = 0;
|
||
|
write_comm_pipe_u32 (&dev->requests, 0, 1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static uae_u32 REGPARAM2 dev_close_2 (TrapContext *context)
|
||
|
{
|
||
|
uae_u32 request = m68k_areg (&context->regs, 1);
|
||
|
struct priv_devstruct *pdev = getpdevstruct (request);
|
||
|
struct devstruct *dev;
|
||
|
|
||
|
if (!pdev)
|
||
|
return 0;
|
||
|
dev = getdevstruct (pdev->unit);
|
||
|
if (log_scsi)
|
||
|
write_log ("%s:%d close, req=%08.8X\n", getdevname (pdev->type), pdev->unit, request);
|
||
|
if (!dev)
|
||
|
return 0;
|
||
|
dev_close_3 (dev, pdev);
|
||
|
put_long (request + 24, 0);
|
||
|
put_word (m68k_areg (&context->regs, 6) + 32, get_word (m68k_areg (&context->regs, 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 (uaecptr ioreq, int error)
|
||
|
{
|
||
|
put_long (ioreq + 20, -1);
|
||
|
put_byte (ioreq + 31, error);
|
||
|
return (uae_u32)-1;
|
||
|
}
|
||
|
|
||
|
static uae_u32 REGPARAM2 dev_open_2 (TrapContext *context, int type)
|
||
|
{
|
||
|
uaecptr ioreq = m68k_areg (&context->regs, 1);
|
||
|
uae_u32 unit = m68k_dreg (&context->regs, 0);
|
||
|
uae_u32 flags = m68k_dreg (&context->regs, 1);
|
||
|
struct devstruct *dev = getdevstruct (unit);
|
||
|
struct priv_devstruct *pdev = 0;
|
||
|
int i;
|
||
|
|
||
|
if (log_scsi)
|
||
|
write_log ("opening %s:%d ioreq=%08.8X\n", getdevname (type), unit, ioreq);
|
||
|
if (!dev)
|
||
|
return openfail (ioreq, 32); /* badunitnum */
|
||
|
if (!dev->opencnt) {
|
||
|
for (i = 0; i < MAX_OPEN_DEVICES; i++) {
|
||
|
pdev = &pdevst[i];
|
||
|
if (pdev->inuse == 0) break;
|
||
|
}
|
||
|
if (type == UAEDEV_SCSI_ID && sys_command_open (DF_SCSI, dev->unitnum)) {
|
||
|
pdev->scsi = 1;
|
||
|
pdev->mode = DF_SCSI;
|
||
|
}
|
||
|
if (type == UAEDEV_DISK_ID && sys_command_open (DF_IOCTL, dev->unitnum)) {
|
||
|
pdev->ioctl = 1;
|
||
|
pdev->mode = DF_IOCTL;
|
||
|
}
|
||
|
if (!pdev->scsi && !pdev->ioctl)
|
||
|
return openfail (ioreq, -1);
|
||
|
pdev->type = type;
|
||
|
pdev->unit = unit;
|
||
|
pdev->flags = flags;
|
||
|
pdev->inuse = 1;
|
||
|
put_long (ioreq + 24, pdev - pdevst);
|
||
|
start_thread (dev);
|
||
|
} else {
|
||
|
for (i = 0; i < MAX_OPEN_DEVICES; i++) {
|
||
|
pdev = &pdevst[i];
|
||
|
if (pdev->inuse && pdev->unit == (int)unit) break;
|
||
|
}
|
||
|
if (i == MAX_OPEN_DEVICES)
|
||
|
return openfail (ioreq, -1);
|
||
|
put_long (ioreq + 24, pdev - pdevst);
|
||
|
}
|
||
|
dev->opencnt++;
|
||
|
|
||
|
put_word (m68k_areg (&context->regs, 6) + 32, get_word (m68k_areg (&context->regs, 6) + 32) + 1);
|
||
|
put_byte (ioreq + 31, 0);
|
||
|
put_byte (ioreq + 8, 7);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static uae_u32 REGPARAM2 dev_open (TrapContext *context)
|
||
|
{
|
||
|
return dev_open_2 (context, UAEDEV_SCSI_ID);
|
||
|
}
|
||
|
static uae_u32 REGPARAM2 diskdev_open (TrapContext *context)
|
||
|
{
|
||
|
return dev_open_2 (context, UAEDEV_DISK_ID);
|
||
|
}
|
||
|
|
||
|
static uae_u32 REGPARAM2 dev_expunge (TrapContext *context)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
static uae_u32 REGPARAM2 diskdev_expunge (TrapContext *context)
|
||
|
{
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
void scsi_do_disk_change (int device_id, int insert)
|
||
|
{
|
||
|
int i, j;
|
||
|
|
||
|
uae_sem_wait (&change_sem);
|
||
|
for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
|
||
|
if (devst[i].di.id == device_id) {
|
||
|
devst[i].changenum++;
|
||
|
j = 0;
|
||
|
while (j < MAX_ASYNC_REQUESTS) {
|
||
|
if (devst[i].d_request_type[j] == ASYNC_REQUEST_CHANGEINT) {
|
||
|
uae_Cause (devst[i].d_request_data[j]);
|
||
|
}
|
||
|
j++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
uae_sem_post (&change_sem);
|
||
|
}
|
||
|
|
||
|
static int add_async_request (struct devstruct *dev, uaecptr request, int type, uae_u32 data)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
if (log_scsi)
|
||
|
write_log ("async request %p (%d) added\n", request, type);
|
||
|
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[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 ("async request %p 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;
|
||
|
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 */
|
||
|
uae_msleep (10);
|
||
|
i = 0;
|
||
|
continue;
|
||
|
}
|
||
|
i++;
|
||
|
}
|
||
|
i = release_async_request (dev, request);
|
||
|
if (i >= 0 && log_scsi)
|
||
|
write_log ("asyncronous request=%08.8X aborted, error=%d\n", request, errcode);
|
||
|
}
|
||
|
|
||
|
static int command_read (int mode, struct devstruct *dev, uaecptr data, int offset, int length, uae_u32 *io_actual)
|
||
|
{
|
||
|
const uae_u8 *temp;
|
||
|
int len, sector;
|
||
|
|
||
|
int startoffset = offset % dev->di.bytespersector;
|
||
|
offset -= startoffset;
|
||
|
sector = offset / dev->di.bytespersector;
|
||
|
*io_actual = 0;
|
||
|
while (length > 0) {
|
||
|
temp = sys_command_read (mode, dev->unitnum, sector);
|
||
|
if (!temp) return 20;
|
||
|
if (startoffset > 0) {
|
||
|
len = dev->di.bytespersector - startoffset;
|
||
|
if (len > length) len = length;
|
||
|
memcpyha (data, temp + startoffset, len);
|
||
|
length -= len;
|
||
|
data += len;
|
||
|
startoffset = 0;
|
||
|
*io_actual += len;
|
||
|
} else if (length >= dev->di.bytespersector) {
|
||
|
len = dev->di.bytespersector;
|
||
|
memcpyha (data, temp, len);
|
||
|
length -= len;
|
||
|
data += len;
|
||
|
*io_actual += len;
|
||
|
} else {
|
||
|
memcpyha (data, temp, length);
|
||
|
*io_actual += length;
|
||
|
length = 0;
|
||
|
}
|
||
|
sector++;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int dev_do_io (struct devstruct *dev, uaecptr request)
|
||
|
{
|
||
|
uae_u32 command;
|
||
|
uae_u32 io_data = get_long (request + 40); // 0x28
|
||
|
uae_u32 io_length = get_long (request + 36); // 0x24
|
||
|
uae_u32 io_actual = get_long (request + 32); // 0x20
|
||
|
uae_u32 io_offset = get_long (request + 44); // 0x2c
|
||
|
uae_u32 io_error = 0;
|
||
|
int async = 0;
|
||
|
struct device_info di;
|
||
|
struct priv_devstruct *pdev = getpdevstruct (request);
|
||
|
|
||
|
if (!pdev)
|
||
|
return 0;
|
||
|
command = get_word (request+28);
|
||
|
|
||
|
switch (command)
|
||
|
{
|
||
|
case CMD_READ:
|
||
|
io_error = command_read (pdev->mode, dev, io_data, io_offset, io_length, &io_actual);
|
||
|
break;
|
||
|
case CMD_WRITE:
|
||
|
case CMD_FORMAT:
|
||
|
io_error = 28; /* writeprotect */
|
||
|
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 = 0;
|
||
|
break;
|
||
|
case CMD_CHANGENUM:
|
||
|
io_actual = dev->changenum;
|
||
|
break;
|
||
|
case CMD_CHANGESTATE:
|
||
|
io_actual = devinfo(pdev->mode, dev->unitnum, &di)->media_inserted ? 0 : 1;
|
||
|
break;
|
||
|
case CMD_PROTSTATUS:
|
||
|
io_actual = devinfo(pdev->mode, dev->unitnum, &di)->write_protected ? -1 : 0;
|
||
|
break;
|
||
|
case CMD_GETDRIVETYPE:
|
||
|
io_actual = dev->drivetype;
|
||
|
break;
|
||
|
case CMD_GETNUMTRACKS:
|
||
|
io_actual = dev->di.cylinders;
|
||
|
break;
|
||
|
case CMD_ADDCHANGEINT:
|
||
|
io_error = add_async_request (dev, request, ASYNC_REQUEST_CHANGEINT, io_data);
|
||
|
if (!io_error)
|
||
|
async = 1;
|
||
|
break;
|
||
|
case CMD_REMCHANGEINT:
|
||
|
release_async_request (dev, request);
|
||
|
break;
|
||
|
case 28: /* HD_SCSICMD */
|
||
|
if (dev->allow_scsi && pdev->scsi) {
|
||
|
uae_u32 sdd = get_long (request + 40);
|
||
|
io_error = sys_command_scsi_direct (dev->unitnum, sdd);
|
||
|
if (log_scsi)
|
||
|
write_log ("scsidev: did io: sdd %p request %p error %d\n", sdd, request, get_byte (request + 31));
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
io_error = -3;
|
||
|
break;
|
||
|
}
|
||
|
put_long (request + 32, io_actual);
|
||
|
put_byte (request + 31, io_error);
|
||
|
io_log ("dev_io",request);
|
||
|
return async;
|
||
|
}
|
||
|
|
||
|
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:
|
||
|
case CMD_GETNUMTRACKS:
|
||
|
return 1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int dev_canquick (struct devstruct *dev, uaecptr request)
|
||
|
{
|
||
|
uae_u32 command = get_word (request + 28);
|
||
|
return dev_can_quick (command);
|
||
|
}
|
||
|
|
||
|
static uae_u32 REGPARAM2 dev_beginio (TrapContext *context)
|
||
|
{
|
||
|
uae_u32 request = m68k_areg (&context->regs, 1);
|
||
|
uae_u8 flags = get_byte (request + 30);
|
||
|
int command = get_word (request + 28);
|
||
|
struct priv_devstruct *pdev = getpdevstruct (request);
|
||
|
struct devstruct *dev = getdevstruct (pdev->unit);
|
||
|
|
||
|
put_byte (request+8, NT_MESSAGE);
|
||
|
if (!dev || !pdev) {
|
||
|
put_byte (request + 31, 32);
|
||
|
return get_byte (request + 31);
|
||
|
}
|
||
|
put_byte (request+31, 0);
|
||
|
if ((flags & 1) && dev_canquick (dev, request)) {
|
||
|
if (dev_do_io (dev, request))
|
||
|
write_log ("device %s command %d bug with IO_QUICK\n", getdevname (pdev->type), command);
|
||
|
return get_byte (request + 31);
|
||
|
} else {
|
||
|
add_async_request (dev, request, ASYNC_REQUEST_TEMP, 0);
|
||
|
put_byte (request+30, get_byte (request + 30) & ~1);
|
||
|
write_comm_pipe_u32 (&dev->requests, request, 1);
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void *dev_thread (void *devs)
|
||
|
{
|
||
|
struct devstruct *dev = devs;
|
||
|
|
||
|
uae_set_thread_priority (2);
|
||
|
dev->thread_running = 1;
|
||
|
|
||
|
sys_command_open_thread (DF_SCSI, dev->unitnum);
|
||
|
sys_command_open_thread (DF_IOCTL, dev->unitnum);
|
||
|
|
||
|
uae_sem_post (&dev->sync_sem);
|
||
|
for (;;) {
|
||
|
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);
|
||
|
break;
|
||
|
} else if (dev_do_io (dev, request) == 0) {
|
||
|
put_byte (request + 30, get_byte (request + 30) & ~1);
|
||
|
release_async_request (dev, request);
|
||
|
uae_ReplyMsg (request);
|
||
|
} else {
|
||
|
if (log_scsi)
|
||
|
write_log ("async request %08.8X\n", request);
|
||
|
}
|
||
|
uae_sem_post (&change_sem);
|
||
|
}
|
||
|
|
||
|
sys_command_close_thread (DF_SCSI, dev->unitnum);
|
||
|
sys_command_close_thread (DF_IOCTL, dev->unitnum);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static uae_u32 REGPARAM2 dev_init_2 (TrapContext *context, int type)
|
||
|
{
|
||
|
uae_u32 base = m68k_dreg (&context->regs,0);
|
||
|
if (log_scsi)
|
||
|
write_log ("%s init\n", getdevname (type));
|
||
|
return base;
|
||
|
}
|
||
|
|
||
|
static uae_u32 REGPARAM2 dev_init (TrapContext *context)
|
||
|
{
|
||
|
return dev_init_2 (context, UAEDEV_SCSI_ID);
|
||
|
}
|
||
|
static uae_u32 REGPARAM2 diskdev_init (TrapContext *context)
|
||
|
{
|
||
|
return dev_init_2 (context, UAEDEV_DISK_ID);
|
||
|
}
|
||
|
|
||
|
static uae_u32 REGPARAM2 dev_abortio (TrapContext *context)
|
||
|
{
|
||
|
uae_u32 request = m68k_areg (&context->regs, 1);
|
||
|
struct priv_devstruct *pdev = getpdevstruct (request);
|
||
|
struct devstruct *dev;
|
||
|
|
||
|
if (!pdev) {
|
||
|
put_byte (request + 31, 32);
|
||
|
return get_byte (request + 31);
|
||
|
}
|
||
|
dev = getdevstruct (pdev->unit);
|
||
|
if (!dev) {
|
||
|
put_byte (request + 31, 32);
|
||
|
return get_byte (request + 31);
|
||
|
}
|
||
|
put_byte (request + 31, -2);
|
||
|
if (log_scsi)
|
||
|
write_log ("abortio %s unit=%d, request=%08.8X\n", getdevname (pdev->type), pdev->unit, request);
|
||
|
abort_async (dev, request, -2, 0);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#define BTL2UNIT(bus, target, lun) (2 * (bus) + (target) / 8) * 100 + (lun) * 10 + (target % 8)
|
||
|
|
||
|
/*
|
||
|
* Shut down SCSI layer
|
||
|
*/
|
||
|
static void dev_exit (void)
|
||
|
{
|
||
|
int i, j;
|
||
|
struct devstruct *dev;
|
||
|
|
||
|
for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
|
||
|
dev = &devst[i];
|
||
|
if (dev->opencnt > 0) {
|
||
|
/* Abort any outstanding requests */
|
||
|
for (j = 0; j < MAX_ASYNC_REQUESTS; j++) {
|
||
|
uaecptr request;
|
||
|
if ((request = dev->d_request[i]))
|
||
|
abort_async (dev, request, 0, 0);
|
||
|
}
|
||
|
|
||
|
/* Kill dev thread and wait for it to die */
|
||
|
write_comm_pipe_u32 (&dev->requests, 0, 1);
|
||
|
uae_sem_wait (&dev->sync_sem);
|
||
|
|
||
|
/* Close device */
|
||
|
dev->opencnt = 0;
|
||
|
sys_command_close (DF_SCSI, dev->unitnum);
|
||
|
sys_command_close (DF_IOCTL, dev->unitnum);
|
||
|
}
|
||
|
memset (dev, 0, sizeof (struct devstruct));
|
||
|
dev->unitnum = dev->aunit = -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void dev_reset (void)
|
||
|
{
|
||
|
int i, j;
|
||
|
struct devstruct *dev;
|
||
|
struct device_info *discsi, discsi2;
|
||
|
int unitnum = 0;
|
||
|
|
||
|
device_func_init (DEVICE_TYPE_SCSI);
|
||
|
|
||
|
dev_exit();
|
||
|
|
||
|
for (i = 0; i < MAX_OPEN_DEVICES; i++)
|
||
|
memset (&pdevst[i], 0, sizeof (struct priv_devstruct));
|
||
|
|
||
|
i = j = 0;
|
||
|
while (i < MAX_TOTAL_DEVICES) {
|
||
|
dev = &devst[i];
|
||
|
discsi = 0;
|
||
|
if (sys_command_open (DF_SCSI, j)) {
|
||
|
discsi = sys_command_info (DF_SCSI, j, &discsi2);
|
||
|
sys_command_close (DF_SCSI, j);
|
||
|
}
|
||
|
if (discsi) {
|
||
|
dev->unitnum = j;
|
||
|
dev->allow_scsi = 1;
|
||
|
dev->drivetype = discsi->type;
|
||
|
memcpy (&dev->di, discsi, sizeof (struct device_info));
|
||
|
if (discsi->type == INQ_ROMD)
|
||
|
dev->iscd = 1;
|
||
|
}
|
||
|
i++;
|
||
|
j++;
|
||
|
}
|
||
|
unitnum = 0;
|
||
|
for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
|
||
|
dev = &devst[i];
|
||
|
if (dev->unitnum >= 0 && dev->iscd) {
|
||
|
dev->aunit = unitnum;
|
||
|
unitnum++;
|
||
|
}
|
||
|
}
|
||
|
if (unitnum == 0)
|
||
|
unitnum = 1;
|
||
|
for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
|
||
|
dev = &devst[i];
|
||
|
if (dev->unitnum >= 0) {
|
||
|
if (!dev->iscd) {
|
||
|
dev->aunit = unitnum;
|
||
|
unitnum++;
|
||
|
}
|
||
|
write_log ("%s = %s:%d\n", dev->di.label, UAEDEV_SCSI, dev->aunit);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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 (uaecptr resaddr)
|
||
|
{
|
||
|
/* Build a struct Resident. This will set up and initialize
|
||
|
* the cd.device */
|
||
|
if (log_scsi)
|
||
|
write_log ("diskdev_startup(0x%x)\n", resaddr);
|
||
|
put_word(resaddr + 0x0, 0x4AFC);
|
||
|
put_long(resaddr + 0x2, resaddr);
|
||
|
put_long(resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */
|
||
|
put_word(resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */
|
||
|
put_word(resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */
|
||
|
put_long(resaddr + 0xE, ROM_diskdev_resname);
|
||
|
put_long(resaddr + 0x12, ROM_diskdev_resid);
|
||
|
put_long(resaddr + 0x16, ROM_diskdev_init);
|
||
|
resaddr += 0x1A;
|
||
|
return resaddr;
|
||
|
}
|
||
|
|
||
|
uaecptr scsidev_startup (uaecptr resaddr)
|
||
|
{
|
||
|
if (!currprefs.scsi)
|
||
|
return resaddr;
|
||
|
if (log_scsi)
|
||
|
write_log ("scsidev_startup(0x%x)\n", resaddr);
|
||
|
/* Build a struct Resident. This will set up and initialize
|
||
|
* the uaescsi.device */
|
||
|
put_word(resaddr + 0x0, 0x4AFC);
|
||
|
put_long(resaddr + 0x2, resaddr);
|
||
|
put_long(resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */
|
||
|
put_word(resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */
|
||
|
put_word(resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */
|
||
|
put_long(resaddr + 0xE, ROM_scsidev_resname);
|
||
|
put_long(resaddr + 0x12, ROM_scsidev_resid);
|
||
|
put_long(resaddr + 0x16, ROM_scsidev_init); /* calls scsidev_init */
|
||
|
resaddr += 0x1A;
|
||
|
return resaddr;
|
||
|
return diskdev_startup (resaddr);
|
||
|
}
|
||
|
|
||
|
static void diskdev_install (void)
|
||
|
{
|
||
|
uae_u32 functable, datatable;
|
||
|
uae_u32 initcode, openfunc, closefunc, expungefunc;
|
||
|
uae_u32 beginiofunc, abortiofunc;
|
||
|
|
||
|
if (!currprefs.scsi)
|
||
|
return;
|
||
|
if (log_scsi)
|
||
|
write_log ("diskdev_install(): 0x%x\n", here ());
|
||
|
|
||
|
ROM_diskdev_resname = ds (UAEDEV_DISK);
|
||
|
ROM_diskdev_resid = ds ("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)
|
||
|
return;
|
||
|
if (log_scsi)
|
||
|
write_log ("scsidev_install(): 0x%x\n", here ());
|
||
|
|
||
|
ROM_scsidev_resname = ds (UAEDEV_SCSI);
|
||
|
ROM_scsidev_resid = ds ("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); /* end of table already ??? */
|
||
|
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);
|
||
|
|
||
|
diskdev_install ();
|
||
|
}
|
||
|
|
||
|
void scsidev_start_threads (void)
|
||
|
{
|
||
|
if (!currprefs.scsi) /* quite useless.. */
|
||
|
return;
|
||
|
if (log_scsi)
|
||
|
write_log ("scsidev_start_threads()\n");
|
||
|
uae_sem_init (&change_sem, 0, 1);
|
||
|
}
|
||
|
|
||
|
void scsidev_exit (void)
|
||
|
{
|
||
|
if (!currprefs.scsi)
|
||
|
return;
|
||
|
dev_exit ();
|
||
|
}
|
||
|
|
||
|
void scsidev_reset (void)
|
||
|
{
|
||
|
if (!currprefs.scsi)
|
||
|
return;
|
||
|
dev_reset ();
|
||
|
}
|