puae 2.3.0

parent 5574379d
ahitweak
This is a program you can start from shell or user-startup
and allow you to tune the ahi driver for better latency,because on winxp the
playpointer position have a delay depend on system and soundcard
I can reach with
ahitweak 200
latency of 4 ms with my sb-PCI512 on winxp (simular sb-live)
to get hd-rec working with 4ms
You see thats more a function to get the best for realtime Music without special
ASIO drivers
Most users dont need that
But if you have crackle problems WITH 16 BIT AHI
play a song and try values of 50 200 500 2000 -50 -200 -500 -2000
Maybe that help
p96refresh (winuae only)
Start this program to get higher mousepointer redraw rates than 50 hz
with P96.Actions are seen immediatly after call.You can start this in your
user-startup for automatic on boot
Example:
p96refresh 75
set redraw rate to 75 hz.Best is if you set rate
to your monitor refresh rate or monitor refreshrate*2
Dont set it higher or you get speedloss > 2%
rtg.library: (help also on Standard UAE)
This avoid large slowdown and redraw problems in picasso96 with JIT
copy it in libs:pacasso96
picasso96fix (help also on Standard UAE)
This allow larger Screen Width than 1024
start it BEFORE the loadwb instruction in startup-sequence
uae_german (help also on Standard UAE (i hope ?))
This is a German keymap to reach @\~{[]} with ALT-GR like windows
Copy it in devs/keymaps and choose it in the keymap-prefs
uae/uae.audio (winuae only)
This is the AHI Driver.This allow support for record and playback upto 96 khz
copy uae to devs:audiomodes
copy uae.audio to devs:ahi
If you install correct the driver should show Version 4.3 Date 22.5.02
and offer you only 1 Mode UAE hifi stereo++.
This driver work fully independent from paula sound.For a speed
boost on slower systems you can set paula buffer to 5 or 6 choose 11 khz mono
thats enough to hear system sound
./bootstrap.sh
./configure --with-sdl --with-sdl-gl --with-sdl-gfx --with-sdl-sound --with-caps --with-gayle --enable-drvsnd --enable-amax --enable-cd32 --enable-scsi-device
make clean
make
# P-UAE
#
# 2010 Mustafa TUFAN
#
./bootstrap.sh
./configure --with-sdl --with-sdl-gl --with-sdl-gfx --with-sdl-sound --with-caps --enable-drvsnd --enable-amax --enable-cd32 --enable-scsi-device --enable-a2091 --enable-gayle --enable-ncr CFLAGS="-m32" LDFLAGS="-m32" CPPFLAGS="-m32"
make clean
make
# P-UAE
#
# 2010 Mustafa TUFAN
#
./bootstrap.sh
./configure --with-sdl --with-sdl-gl --with-sdl-gfx --with-sdl-sound --with-caps --enable-drvsnd --enable-amax --enable-cd32 --enable-scsi-device --enable-a2091 --enable-gayle --enable-ncr --target=i586 CFLAGS="-m32" LDFLAGS="-m32" CPPFLAGS="-m32"
make clean
make
struct netdriverdata
{
TCHAR *name;
TCHAR *desc;
int mtu;
uae_u8 mac[6];
int active;
};
typedef void (uaenet_gotfunc)(struct s2devstruct *dev, const uae_u8 *data, int len);
typedef int (uaenet_getfunc)(struct s2devstruct *dev, uae_u8 *d, int *len);
#define MAX_TOTAL_NET_DEVICES 10
extern struct netdriverdata *uaenet_enumerate (struct netdriverdata **out, const TCHAR *name);
extern void uaenet_enumerate_free (struct netdriverdata *tcp);
extern void uaenet_close_driver (struct netdriverdata *tc);
extern int uaenet_getdatalenght (void);
extern int uaenet_getbytespending (void*);
extern int uaenet_open (void*, struct netdriverdata*, void*, uaenet_gotfunc*, uaenet_getfunc*, int);
extern void uaenet_close (void*);
extern void uaenet_trigger (void*);
/*
* UAE - The Un*x Amiga Emulator
*
* Not a parser, but parallel and serial emulation for Linux
*
* Copyright 2010 Mustafa TUFAN
*/
#include "sysconfig.h"
#undef SERIAL_ENET
#include "sysdeps.h"
#include "options.h"
#include "gensound.h"
#include "events.h"
#include "uae.h"
#include "include/memory.h"
#include "custom.h"
#include "autoconf.h"
#include "newcpu.h"
#include "traps.h"
#include "threaddep/thread.h"
#include "serial.h"
#include "savestate.h"
#include "xwin.h"
#include "drawing.h"
#define MIN_PRTBYTES 10
struct uaeserialdata
{
long hCom;
long evtr, evtw, evtt, evtwce;
long olr, olw, olwce;
int writeactive;
void *readdata, *writedata;
volatile int threadactive;
uae_sem_t change_sem, sync_sem;
void *user;
};
int uaeser_getdatalength (void)
{
return sizeof (struct uaeserialdata);
}
void uaeser_initdata (void *vsd, void *user)
{
}
int uaeser_query (void *vsd, uae_u16 *status, uae_u32 *pending)
{
return 0;
}
int uaeser_break (void *vsd, int brklen)
{
return 0;
}
int uaeser_setparams (void *vsd, int baud, int rbuffer, int bits, int sbits, int rtscts, int parity, uae_u32 xonxoff)
{
return 0;
}
void uaeser_trigger (void *vsd)
{
}
int uaeser_write (void *vsd, uae_u8 *data, uae_u32 len)
{
return 0;
}
int uaeser_read (void *vsd, uae_u8 *data, uae_u32 len)
{
return 0;
}
void uaeser_clearbuffers (void *vsd)
{
}
int uaeser_open (void *vsd, void *user, int unit)
{
return 0;
}
void uaeser_close (void *vsd)
{
}
#define SERIAL_WRITE_BUFFER 100
#define SERIAL_READ_BUFFER 100
static uae_u8 outputbuffer[SERIAL_WRITE_BUFFER];
static uae_u8 outputbufferout[SERIAL_WRITE_BUFFER];
static uae_u8 inputbuffer[SERIAL_READ_BUFFER];
static int datainoutput;
static int dataininput, dataininputcnt;
static int writepending;
/*
* UAE - The Un*x Amiga Emulator
*
* Not a parser, but parallel and serial emulation for Linux
*
* Copyright 2010 Mustafa TUFAN
*/
#include "sysconfig.h"
#undef SERIAL_ENET
#include "sysdeps.h"
#include "options.h"
#include "gensound.h"
#include "events.h"
#include "uae.h"
#include "include/memory.h"
#include "custom.h"
#include "autoconf.h"
#include "newcpu.h"
#include "traps.h"
#include "threaddep/thread.h"
#include "serial.h"
#include "savestate.h"
#include "xwin.h"
#include "drawing.h"
#define MIN_PRTBYTES 10
struct uaeserialdata
{
long hCom;
long evtr, evtw, evtt, evtwce;
long olr, olw, olwce;
int writeactive;
void *readdata, *writedata;
volatile int threadactive;
uae_sem_t change_sem, sync_sem;
void *user;
};
int uaeser_getdatalength (void)
{
return sizeof (struct uaeserialdata);
}
void uaeser_initdata (void *vsd, void *user)
{
}
int uaeser_query (void *vsd, uae_u16 *status, uae_u32 *pending)
{
return 0;
}
int uaeser_break (void *vsd, int brklen)
{
return 0;
}
int uaeser_setparams (void *vsd, int baud, int rbuffer, int bits, int sbits, int rtscts, int parity, uae_u32 xonxoff)
{
return 0;
}
void uaeser_trigger (void *vsd)
{
}
int uaeser_write (void *vsd, uae_u8 *data, uae_u32 len)
{
return 0;
}
int uaeser_read (void *vsd, uae_u8 *data, uae_u32 len)
{
return 0;
}
void uaeser_clearbuffers (void *vsd)
{
}
int uaeser_open (void *vsd, void *user, int unit)
{
return 0;
}
void uaeser_close (void *vsd)
{
}
#define SERIAL_WRITE_BUFFER 100
#define SERIAL_READ_BUFFER 100
static uae_u8 outputbuffer[SERIAL_WRITE_BUFFER];
static uae_u8 outputbufferout[SERIAL_WRITE_BUFFER];
static uae_u8 inputbuffer[SERIAL_READ_BUFFER];
static int datainoutput;
static int dataininput, dataininputcnt;
static int writepending;
/*
* UAE - The Un*x Amiga Emulator
*
* Not a parser, but parallel and serial emulation for Linux
*
* Copyright 2010 Mustafa TUFAN
*/
#include "sysconfig.h"
#undef SERIAL_ENET
#include "sysdeps.h"
#include "options.h"
#include "gensound.h"
#include "events.h"
#include "uae.h"
#include "include/memory.h"
#include "custom.h"
#include "autoconf.h"
#include "newcpu.h"
#include "traps.h"
#include "threaddep/thread.h"
#include "serial.h"
#include "savestate.h"
#include "xwin.h"
#include "drawing.h"
#define MIN_PRTBYTES 10
struct uaeserialdata
{
long hCom;
long evtr, evtw, evtt, evtwce;
long olr, olw, olwce;
int writeactive;
void *readdata, *writedata;
volatile int threadactive;
uae_sem_t change_sem, sync_sem;
void *user;
};
int uaeser_getdatalength (void)
{
return sizeof (struct uaeserialdata);
}
void uaeser_initdata (void *vsd, void *user)
{
}
int uaeser_query (void *vsd, uae_u16 *status, uae_u32 *pending)
{
return 0;
}
int uaeser_break (void *vsd, int brklen)
{
return 0;
}
int uaeser_setparams (void *vsd, int baud, int rbuffer, int bits, int sbits, int rtscts, int parity, uae_u32 xonxoff)
{
return 0;
}
void uaeser_trigger (void *vsd)
{
}
int uaeser_write (void *vsd, uae_u8 *data, uae_u32 len)
{
return 0;
}
int uaeser_read (void *vsd, uae_u8 *data, uae_u32 len)
{
return 0;
}
void uaeser_clearbuffers (void *vsd)
{
}
int uaeser_open (void *vsd, void *user, int unit)
{
return 0;
}
void uaeser_close (void *vsd)
{
}
#define SERIAL_WRITE_BUFFER 100
#define SERIAL_READ_BUFFER 100
static uae_u8 outputbuffer[SERIAL_WRITE_BUFFER];
static uae_u8 outputbufferout[SERIAL_WRITE_BUFFER];
static uae_u8 inputbuffer[SERIAL_READ_BUFFER];
static int datainoutput;
static int dataininput, dataininputcnt;
static int writepending;
/*
* UAE - The Un*x Amiga Emulator
*
* Not a parser, but parallel and serial emulation for Linux
*
* Copyright 2010 Mustafa TUFAN
*/
#include "sysconfig.h"
#undef SERIAL_ENET
#include "sysdeps.h"
#include "options.h"
#include "gensound.h"
#include "events.h"
#include "uae.h"
#include "include/memory.h"
#include "custom.h"
#include "autoconf.h"
#include "newcpu.h"
#include "traps.h"
#include "threaddep/thread.h"
#include "serial.h"
#include "savestate.h"
#include "xwin.h"
#include "drawing.h"
#define MIN_PRTBYTES 10
struct uaeserialdata
{
long hCom;
long evtr, evtw, evtt, evtwce;
long olr, olw, olwce;
int writeactive;
void *readdata, *writedata;
volatile int threadactive;
uae_sem_t change_sem, sync_sem;
void *user;
};
int uaeser_getdatalength (void)
{
return sizeof (struct uaeserialdata);
}
void uaeser_initdata (void *vsd, void *user)
{
}
int uaeser_query (void *vsd, uae_u16 *status, uae_u32 *pending)
{
return 0;
}
int uaeser_break (void *vsd, int brklen)
{
return 0;
}
int uaeser_setparams (void *vsd, int baud, int rbuffer, int bits, int sbits, int rtscts, int parity, uae_u32 xonxoff)
{
return 0;
}
void uaeser_trigger (void *vsd)
{
}
int uaeser_write (void *vsd, uae_u8 *data, uae_u32 len)
{
return 0;
}
int uaeser_read (void *vsd, uae_u8 *data, uae_u32 len)
{
return 0;
}
void uaeser_clearbuffers (void *vsd)
{
}
int uaeser_open (void *vsd, void *user, int unit)
{
return 0;
}
void uaeser_close (void *vsd)
{
}
#define SERIAL_WRITE_BUFFER 100
#define SERIAL_READ_BUFFER 100
static uae_u8 outputbuffer[SERIAL_WRITE_BUFFER];
static uae_u8 outputbufferout[SERIAL_WRITE_BUFFER];
static uae_u8 inputbuffer[SERIAL_READ_BUFFER];
static int datainoutput;
static int dataininput, dataininputcnt;
static int writepending;
/*
* UAE - The Un*x Amiga Emulator
*
* Not a parser, but parallel and serial emulation for Linux
*
* Copyright 2010 Mustafa TUFAN
*/
#include "sysconfig.h"
#undef SERIAL_ENET
#include "sysdeps.h"
#include "options.h"
#include "gensound.h"
#include "events.h"
#include "uae.h"
#include "include/memory.h"
#include "custom.h"
#include "autoconf.h"
#include "newcpu.h"
#include "traps.h"
#include "threaddep/thread.h"
#include "serial.h"
#include "savestate.h"
#include "xwin.h"
#include "drawing.h"
#define MIN_PRTBYTES 10
struct uaeserialdata
{
long hCom;
long evtr, evtw, evtt, evtwce;
long olr, olw, olwce;
int writeactive;
void *readdata, *writedata;
volatile int threadactive;
uae_sem_t change_sem, sync_sem;
void *user;
};
int uaeser_getdatalength (void)
{
return sizeof (struct uaeserialdata);
}
void uaeser_initdata (void *vsd, void *user)
{
}
int uaeser_query (void *vsd, uae_u16 *status, uae_u32 *pending)
{
return 0;
}
int uaeser_break (void *vsd, int brklen)
{
return 0;
}
int uaeser_setparams (void *vsd, int baud, int rbuffer, int bits, int sbits, int rtscts, int parity, uae_u32 xonxoff)
{
return 0;
}
void uaeser_trigger (void *vsd)
{
}
int uaeser_write (void *vsd, uae_u8 *data, uae_u32 len)
{
return 0;
}
int uaeser_read (void *vsd, uae_u8 *data, uae_u32 len)
{
return 0;
}
void uaeser_clearbuffers (void *vsd)
{
}
int uaeser_open (void *vsd, void *user, int unit)
{
return 0;
}
void uaeser_close (void *vsd)
{
}
#define SERIAL_WRITE_BUFFER 100
#define SERIAL_READ_BUFFER 100
static uae_u8 outputbuffer[SERIAL_WRITE_BUFFER];
static uae_u8 outputbufferout[SERIAL_WRITE_BUFFER];
static uae_u8 inputbuffer[SERIAL_READ_BUFFER];
static int datainoutput;
static int dataininput, dataininputcnt;
static int writepending;
/*
* UAE - The Un*x Amiga Emulator
*
* SanaII emulation
*
* partially based on code from 3c589 PCMCIA driver by Neil Cafferke
*
* Copyright 2007 Toni Wilen
*
*/
#include "sysconfig.h"
#include "sysdeps.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 "uae.h"
#include "sana2.h"
#include "uaenet.h"
#include "execio.h"
#define TRUE 1
#define FALSE 0
#define SANA2NAME "uaenet.device"
#define MAX_ASYNC_REQUESTS 200
#define MAX_OPEN_DEVICES 20
#define S2_START (CMD_NONSTD) // 9
#define S2_DEVICEQUERY (S2_START+ 0) // 9
#define S2_GETSTATIONADDRESS (S2_START+ 1) // 10
#define S2_CONFIGINTERFACE (S2_START+ 2) // 11
#define S2_ADDMULTICASTADDRESS (S2_START+ 5) // 14
#define S2_DELMULTICASTADDRESS (S2_START+ 6) // 15
#define S2_MULTICAST (S2_START+ 7) // 16
#define S2_BROADCAST (S2_START+ 8) // 17
#define S2_TRACKTYPE (S2_START+ 9) // 18
#define S2_UNTRACKTYPE (S2_START+10) // 19
#define S2_GETTYPESTATS (S2_START+11) // 20
#define S2_GETSPECIALSTATS (S2_START+12) // 21
#define S2_GETGLOBALSTATS (S2_START+13) // 22
#define S2_ONEVENT (S2_START+14) // 23
#define S2_READORPHAN (S2_START+15) // 24
#define S2_ONLINE (S2_START+16) // 25
#define S2_OFFLINE (S2_START+17) // 26
#define S2_ADDMULTICASTADDRESSES 0xC000
#define S2_DELMULTICASTADDRESSES 0xC001
#define S2_GETPEERADDRESS 0xC002
#define S2_GETDNSADDRESS 0xC003
#define S2_GETEXTENDEDGLOBALSTATS 0xC004
#define S2_CONNECT 0xC005
#define S2_DISCONNECT 0xC006
#define S2_SAMPLE_THROUGHPUT 0xC007
#define S2WireType_Ethernet 1
#define S2WireType_IEEE802 6
#define SANA2_MAX_ADDR_BITS (128)
#define SANA2_MAX_ADDR_BYTES ((SANA2_MAX_ADDR_BITS+7)/8)
#define ADDR_SIZE 6
#define ETH_HEADER_SIZE (ADDR_SIZE + ADDR_SIZE + 2)
#define S2ERR_NO_ERROR 0 /* peachy-keen */
#define S2ERR_NO_RESOURCES 1 /* resource allocation failure */
#define S2ERR_BAD_ARGUMENT 3 /* garbage somewhere */
#define S2ERR_BAD_STATE 4 /* inappropriate state */
#define S2ERR_BAD_ADDRESS 5 /* who? */
#define S2ERR_MTU_EXCEEDED 6 /* too much to chew */
#define S2ERR_NOT_SUPPORTED 8 /* hardware can't support cmd */
#define S2ERR_SOFTWARE 9 /* software error detected */
#define S2ERR_OUTOFSERVICE 10 /* driver is OFFLINE */
#define S2ERR_TX_FAILURE 11 /* Transmission attempt failed */
#define S2WERR_GENERIC_ERROR 0 /* no specific info available */
#define S2WERR_NOT_CONFIGURED 1 /* unit not configured */
#define S2WERR_UNIT_ONLINE 2 /* unit is currently online */
#define S2WERR_UNIT_OFFLINE 3 /* unit is currently offline */
#define S2WERR_ALREADY_TRACKED 4 /* protocol already tracked */
#define S2WERR_NOT_TRACKED 5 /* protocol not tracked */
#define S2WERR_BUFF_ERROR 6 /* buff mgt func returned error */
#define S2WERR_SRC_ADDRESS 7 /* source address problem */
#define S2WERR_DST_ADDRESS 8 /* destination address problem */
#define S2WERR_BAD_BROADCAST 9 /* broadcast address problem */
#define S2WERR_BAD_MULTICAST 10 /* multicast address problem */
#define S2WERR_MULTICAST_FULL 11 /* multicast address list full */
#define S2WERR_BAD_EVENT 12 /* unsupported event class */
#define S2WERR_BAD_STATDATA 13 /* statdata failed sanity check */
#define S2WERR_IS_CONFIGURED 15 /* attempt to config twice */
#define S2WERR_NULL_POINTER 16 /* null pointer detected */
#define S2WERR_TOO_MANY_RETIRES 17 /* tx failed - too many retries */
#define S2WERR_RCVREL_HDW_ERR 18 /* Driver fixable HW error */
#define S2EVENT_ERROR (1L<<0) /* error catch all */
#define S2EVENT_TX (1L<<1) /* transmitter error catch all */
#define S2EVENT_RX (1L<<2) /* receiver error catch all */
#define S2EVENT_ONLINE (1L<<3) /* unit is in service */
#define S2EVENT_OFFLINE (1L<<4) /* unit is not in service */
#define S2EVENT_BUFF (1L<<5) /* buff mgt function error */
#define S2EVENT_HARDWARE (1L<<6) /* hardware error catch all */
#define S2EVENT_SOFTWARE (1L<<7) /* software error catch all */
#define KNOWN_EVENTS (S2EVENT_ERROR|S2EVENT_TX|S2EVENT_RX|S2EVENT_ONLINE|\
S2EVENT_OFFLINE|S2EVENT_BUFF|S2EVENT_HARDWARE|S2EVENT_SOFTWARE)
#define SANA2OPB_MINE 0
#define SANA2OPF_MINE (1<<SANA2OPB_MINE)
#define SANA2OPB_PROM 1
#define SANA2OPF_PROM (1<<SANA2OPB_PROM)
#define SANA2IOB_RAW 7
#define SANA2IOF_RAW (1<<SANA2IOB_RAW)
#define SANA2IOB_BCAST 6
#define SANA2IOF_BCAST (1<<SANA2IOB_BCAST)
#define SANA2IOB_MCAST 5
#define SANA2IOF_MCAST (1<<SANA2IOB_MCAST)
#define S2_Dummy (TAG_USER + 0xB0000)
#define S2_CopyToBuff (S2_Dummy + 1)
#define S2_CopyFromBuff (S2_Dummy + 2)
#define S2_PacketFilter (S2_Dummy + 3)
#define S2_CopyToBuff16 (S2_Dummy + 4)
#define S2_CopyFromBuff16 (S2_Dummy + 5)
#define S2_CopyToBuff32 (S2_Dummy + 6)
#define S2_CopyFromBuff32 (S2_Dummy + 7)
#define S2_DMACopyToBuff32 (S2_Dummy + 8)
#define S2_DMACopyFromBuff32 (S2_Dummy + 9)
#define SANA2_IOREQSIZE (32 + 4 + 4 + SANA2_MAX_ADDR_BYTES * 2 + 4 + 4 + 4 + 4)
struct s2packet {
struct s2packet *next;
uae_u8 *data;
int len;
};
volatile int uaenet_int_requested;
volatile int uaenet_vsync_requested;
static int uaenet_int_late;
static uaecptr timerdevname;
static uaecptr ROM_netdev_resname = 0,
ROM_netdev_resid = 0,
ROM_netdev_init = 0;
static TCHAR *getdevname (void)
{
return "uaenet.device";
}
struct asyncreq {
struct asyncreq *next;
uaecptr request;
struct s2packet *s2p;
int ready;
};
struct mcast {
struct mcast *next;
uae_u64 start;
uae_u64 end;
int cnt;
};
struct s2devstruct {
int unit, opencnt, exclusive, promiscuous;
struct asyncreq *ar;
struct asyncreq *s2p;
struct mcast *mc;
smp_comm_pipe requests;
int thread_running;
uae_sem_t sync_sem;
void *sysdata;
uae_u32 packetsreceived;
uae_u32 packetssent;
uae_u32 baddata;
uae_u32 overruns;
uae_u32 unknowntypesreceived;
uae_u32 reconfigurations;
uae_u32 online_micro;
uae_u32 online_secs;
int configured;
int adapter;
int online;
struct netdriverdata *td;
struct s2packet *readqueue;
uae_u8 mac[ADDR_SIZE];
int flush_timeout;
int flush_timeout_cnt;
};
#define FLUSH_TIMEOUT 20
struct priv_s2devstruct {
int inuse;
int unit;
int flags; /* OpenDevice() */
int promiscuous;
uae_u8 tracks[65536];
int trackcnt;
uae_u32 packetsreceived;
uae_u32 packetssent;
uae_u32 bytessent;
uae_u32 bytesreceived;
uae_u32 packetsdropped;
uaecptr copytobuff;
uaecptr copyfrombuff;
uaecptr packetfilter;
uaecptr tempbuf;
uaecptr timerbase;
struct netdriverdata *td;
int tmp;
};
static struct netdriverdata *td;
static struct s2devstruct devst[MAX_TOTAL_NET_DEVICES];
static struct priv_s2devstruct pdevst[MAX_OPEN_DEVICES];
static uae_u32 nscmd_cmd;
static uae_sem_t change_sem, async_sem;
static struct s2devstruct *gets2devstruct (int unit)
{
if (unit >= MAX_TOTAL_NET_DEVICES || unit < 0)
return 0;
return &devst[unit];
}
static struct priv_s2devstruct *getps2devstruct (uaecptr request)
{
int i = get_long (request + 24);
if (i < 0 || i >= MAX_OPEN_DEVICES || pdevst[i].inuse == 0) {
write_log ("%s: corrupt iorequest %08X %d\n", SANA2NAME, request, i);
return 0;
}
return &pdevst[i];
}
static void *dev_thread (void *devs);
static int start_thread (struct s2devstruct *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 (SANA2NAME, dev_thread, dev, NULL);
uae_sem_wait (&dev->sync_sem);
return dev->thread_running;
}
static uae_u32 REGPARAM2 dev_close_2 (TrapContext *context)
{
uae_u32 request = m68k_areg (regs, 1);
struct priv_s2devstruct *pdev = getps2devstruct (request);
struct s2devstruct *dev;
if (!pdev) {
write_log ("%s close with unknown request %08X!?\n", SANA2NAME, request);
return 0;
}
dev = gets2devstruct (pdev->unit);
if (!dev) {
write_log ("%s:%d close with unknown request %08X!?\n", SANA2NAME, pdev->unit, request);
return 0;
}
if (log_net)
write_log ("%s:%d close, open=%d req=%08X\n", SANA2NAME, pdev->unit, dev->opencnt, request);
put_long (request + 24, 0);
dev->opencnt--;
pdev->inuse = 0;
if (!dev->opencnt) {
dev->exclusive = 0;
if (pdev->tempbuf) {
m68k_areg (regs, 1) = pdev->tempbuf;
m68k_dreg (regs, 0) = pdev->td->mtu + ETH_HEADER_SIZE + 2;
CallLib (context, get_long (4), -0xD2); /* FreeMem */
pdev->tempbuf = 0;
}
uaenet_close (dev->sysdata);
xfree (dev->sysdata);
dev->sysdata = NULL;
write_comm_pipe_u32 (&dev->requests, 0, 1);
write_log ("%s: opencnt == 0, all instances closed\n", SANA2NAME);
}
put_word (m68k_areg (regs, 6) + 32, get_word (m68k_areg (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);
put_long (ioreq + 32, 0); /* io_device */
if (log_net)
write_log ("-> failed with error %d\n", error);
return (uae_u32)-1;
}
static uae_u32 REGPARAM2 uaenet_int_handler (TrapContext *ctx);
static int irq_init;
static int initint (TrapContext *ctx)
{
uae_u32 tmp1;
uaecptr p;
if (irq_init)
return 1;
m68k_dreg (regs, 0) = 26;
m68k_dreg (regs, 1) = 65536 + 1;
p = CallLib (ctx, get_long (4), -0xC6); /* AllocMem */
if (!p)
return 0;
tmp1 = here ();
calltrap (deftrap2 (uaenet_int_handler, TRAPFLAG_EXTRA_STACK, "uaenet_int_handler"));
put_word (p + 8, 0x020a);
put_long (p + 10, ROM_netdev_resid);
put_long (p + 18, tmp1);
m68k_areg (regs, 1) = p;
m68k_dreg (regs, 0) = 13; /* EXTER */
dw (0x4a80); /* TST.L D0 */
dw (0x4e75); /* RTS */
CallLib (ctx, get_long (4), -168); /* AddIntServer */
irq_init = 1;
return 1;
}
static uae_u32 REGPARAM2 dev_expunge (TrapContext *context)
{
return 0;
}
static uae_u32 REGPARAM2 diskdev_expunge (TrapContext *context)
{
return 0;
}
static void freepacket (struct s2packet *s2p)
{
xfree (s2p->data);
xfree (s2p);
}
static void add_async_packet (struct s2devstruct *dev, struct s2packet *s2p, uaecptr request)
{
struct asyncreq *ar, *ar2;
ar = xcalloc (struct asyncreq, 1);
ar->s2p = s2p;
if (!dev->s2p) {
dev->s2p = ar;
} else {
ar2 = dev->s2p;
while (ar2->next)
ar2 = ar2->next;
ar2->next = ar;
}
ar->request = request;
}
static void rem_async_packet (struct s2devstruct *dev, uaecptr request)
{
struct asyncreq *ar, *prevar;
uae_sem_wait (&async_sem);
ar = dev->s2p;
prevar = NULL;
while (ar) {
if (ar->request == request) {
if (prevar == NULL)
dev->s2p = ar->next;
else
prevar->next = ar->next;
uae_sem_post (&async_sem);
freepacket (ar->s2p);
xfree (ar);
return;
}
prevar = ar;
ar = ar->next;
}
uae_sem_post (&async_sem);
}
static struct asyncreq *get_async_request (struct s2devstruct *dev, uaecptr request, int ready)
{
struct asyncreq *ar;
int ret = 0;
uae_sem_wait (&async_sem);
ar = dev->ar;
while (ar) {
if (ar->request == request) {
if (ready)
ar->ready = 1;
break;
}
ar = ar->next;
}
uae_sem_post (&async_sem);
return ar;
}
static int add_async_request (struct s2devstruct *dev, uaecptr request)
{
struct asyncreq *ar, *ar2;
if (log_net)
write_log ("%s:%d async request %x added\n", getdevname(), dev->unit, request);
uae_sem_wait (&async_sem);
ar = xcalloc (struct asyncreq, 1);
ar->request = request;
if (!dev->ar) {
dev->ar = ar;
} else {
ar2 = dev->ar;
while (ar2->next)
ar2 = ar2->next;
ar2->next = ar;
}
uae_sem_post (&async_sem);
return 1;
}
static int release_async_request (struct s2devstruct *dev, uaecptr request)
{
struct asyncreq *ar, *prevar;
uae_sem_wait (&async_sem);
ar = dev->ar;
prevar = NULL;
while (ar) {
if (ar->request == request) {
if (prevar == NULL)
dev->ar = ar->next;
else
prevar->next = ar->next;
uae_sem_post (&async_sem);
xfree (ar);
if (log_net)
write_log ("%s:%d async request %x removed\n", getdevname(), dev->unit, request);
return 1;
}
prevar = ar;
ar = ar->next;
}
uae_sem_post (&async_sem);
write_log ("%s:%d async request %x not found for removal!\n", getdevname(), dev->unit, request);
return 0;
}
static void do_abort_async (struct s2devstruct *dev, uaecptr request)
{
put_byte (request + 30, get_byte (request + 30) | 0x20);
put_byte (request + 31, IOERR_ABORTED);
put_long (request + 32, S2WERR_GENERIC_ERROR);
write_comm_pipe_u32 (&dev->requests, request, 1);
}
static void abort_async (struct s2devstruct *dev, uaecptr request)
{
struct asyncreq *ar = get_async_request (dev, request, 1);
if (!ar) {
write_log ("%s:%d: abort async but no request %x found!\n", getdevname(), dev->unit, request);
return;
}
if (log_net)
write_log ("%s:%d asyncronous request=%08X aborted\n", getdevname(), dev->unit, request);
do_abort_async (dev, request);
}
static void signalasync (struct s2devstruct *dev, struct asyncreq *ar, int actual, int err)
{
uaecptr request = ar->request;
int command = get_word (request + 28);
if (log_net)
write_log ("%s:%d CMD=%d async request %x completed\n", getdevname(), dev->unit, command, request);
put_long (request + 32, actual);
put_byte (request + 31, err);
ar->ready = 1;
write_comm_pipe_u32 (&dev->requests, request, 1);
}
static uae_u32 copytobuff (TrapContext *ctx, uaecptr from, uaecptr to, uae_u32 len, uaecptr func)
{
m68k_areg (regs, 0) = to;
m68k_areg (regs, 1) = from;
m68k_dreg (regs, 0) = len;
return CallFunc (ctx, func);
}
static uae_u32 copyfrombuff (TrapContext *ctx, uaecptr from, uaecptr to, uae_u32 len, uaecptr func)
{
m68k_areg (regs, 0) = to;
m68k_areg (regs, 1) = from;
m68k_dreg (regs, 0) = len;
return CallFunc (ctx, func);
}
static uae_u32 packetfilter (TrapContext *ctx, uaecptr hook, uaecptr ios2, uaecptr data)
{
uae_u32 a2, v;
a2 = m68k_areg (regs, 2);
m68k_areg (regs, 0) = hook;
m68k_areg (regs, 2) = ios2;
m68k_areg (regs, 1) = data;
v = CallFunc (ctx, get_long (hook + 8));
m68k_areg (regs, 2) = a2;
return v;
}
static int isbroadcast (const uae_u8 *d)
{
if (d[0] == 0xff && d[1] == 0xff && d[2] == 0xff &&
d[3] == 0xff && d[4] == 0xff && d[5] == 0xff)
return 1;
return 0;
}
static int ismulticast (const uae_u8 *d)
{
if (isbroadcast (d))
return 0;
if (d[0] & 1)
return 1;
return 0;
}
static uae_u64 addrto64 (const uae_u8 *d)
{
int i;
uae_u64 addr = 0;
for (i = 0; i < ADDR_SIZE; i++) {
addr <<= 8;
addr |= d[i];
}
return addr;
}
static uae_u64 amigaaddrto64 (uaecptr d)
{
int i;
uae_u64 addr = 0;
for (i = 0; i < ADDR_SIZE; i++) {
addr <<= 8;
addr |= get_byte (d + i);
}
return addr;
}
static void addmulticastaddresses (struct s2devstruct *dev, uae_u64 start, uae_u64 end)
{
struct mcast *mc, *mc2;
if (!end)
end = start;
mc = dev->mc;
while (mc) {
if (start == mc->start && end == mc->end) {
mc->cnt++;
return;
}
mc = mc->next;
}
mc = xcalloc (struct mcast, 1);
mc->start = start;
mc->end = end;
mc->cnt = 1;
if (!dev->mc) {
dev->mc = mc;
} else {
mc2 = dev->mc;
while (mc2->next)
mc2 = mc2->next;
mc2->next = mc;
}
}
static int delmulticastaddresses (struct s2devstruct *dev, uae_u64 start, uae_u64 end)
{
struct mcast *mc, *prevmc;
if (!end)
end = start;
mc = dev->mc;
prevmc = NULL;
while (mc) {
if (start == mc->start && end == mc->end) {
mc->cnt--;
if (mc->cnt > 0)
return 1;
if (prevmc == NULL)
dev->mc = mc->next;
else
prevmc->next = mc->next;
xfree (mc);
return 1;
}
prevmc = mc;
mc = mc->next;
}
return 0;
}
static struct s2packet *createreadpacket (struct s2devstruct *dev, const uae_u8 *d, int len)
{
struct s2packet *s2p = xcalloc (struct s2packet, 1);
s2p->data = xmalloc (uae_u8, dev->td->mtu + ETH_HEADER_SIZE + 2);
memcpy (s2p->data, d, len);
s2p->len = len;
return s2p;
}
static int handleread (TrapContext *ctx, struct priv_s2devstruct *pdev, uaecptr request, uae_u8 *d, int len, int cmd)
{
uae_u8 flags = get_byte (request + 30);
uaecptr data = get_long (request + 32 + 4 + 4 + SANA2_MAX_ADDR_BYTES * 2 + 4);
uaecptr srcaddr = request + 32 + 4 + 4;
uaecptr dstaddr = request + 32 + 4 + 4 + SANA2_MAX_ADDR_BYTES;
uae_u16 type = (d[2 * ADDR_SIZE] << 8) | d[2 * ADDR_SIZE + 1];
uae_u32 v = 0;
uaecptr data2;
memcpyha_safe (pdev->tempbuf, d, len);
memcpyha_safe (dstaddr, d, ADDR_SIZE);
memcpyha_safe (srcaddr, d + ADDR_SIZE, ADDR_SIZE);
put_long (request + 32 + 4, type);
if (pdev->tracks[type]) {
pdev->bytesreceived += len;
pdev->packetsreceived++;
}
flags &= ~(SANA2IOF_BCAST | SANA2IOF_MCAST);
if (isbroadcast (d))
flags |= SANA2IOF_BCAST;
else if (ismulticast (d))
flags |= SANA2IOF_MCAST;
put_byte (request + 30, flags);
data2 = pdev->tempbuf;
if (!(flags & SANA2IOF_RAW)) {
len -= ETH_HEADER_SIZE;
data2 += ETH_HEADER_SIZE;
}
put_long (request + 32 + 4 + 4 + SANA2_MAX_ADDR_BYTES * 2, len);
if (pdev->packetfilter && cmd == CMD_READ && packetfilter (ctx, pdev->packetfilter, request, data2) == 0)
return 0;
if (!copytobuff (ctx, data2, data, len, pdev->copytobuff)) {
put_long (request + 32, S2WERR_BUFF_ERROR);
put_byte (request + 31, S2ERR_NO_RESOURCES);
}
return 1;
}
void uaenet_gotdata (struct s2devstruct *dev, const uae_u8 *d, int len)
{
uae_u16 type;
struct mcast *mc;
struct s2packet *s2p;
if (!dev->online)
return;
/* drop if bogus size */
if (len < ETH_HEADER_SIZE || len >= dev->td->mtu + ETH_HEADER_SIZE + 2)
return;
/* drop if dst == broadcast and src == me */
if (isbroadcast (d) && !memcmp (d + 6, dev->td->mac, ADDR_SIZE))
return;
/* drop if not promiscuous and dst != broadcast and dst != me */
if (!dev->promiscuous && !isbroadcast (d) && memcmp (d, dev->td->mac, ADDR_SIZE))
return;
/* drop if multicast with unknown address */
if (ismulticast (d)) {
uae_u64 mac64 = addrto64 (d);
/* multicast */
mc = dev->mc;
while (mc) {
if (mac64 >= mc->start && mac64 <= mc->end)
break;
mc = mc->next;
}
if (!mc)
return;
}
type = (d[12] << 8) | d[13];
s2p = createreadpacket (dev, d, len);
if (log_net)
write_log ("<-DST:%02X.%02X.%02X.%02X.%02X.%02X SRC:%02X.%02X.%02X.%02X.%02X.%02X E=%04X L=%d P=%p\n",
d[0], d[1], d[2], d[3], d[4], d[5],
d[6], d[7], d[8], d[9], d[10], d[11],
type, len, s2p);
uae_sem_wait (&async_sem);
if (!dev->readqueue) {
dev->readqueue = s2p;
} else {
struct s2packet *s2p2 = dev->readqueue;
while (s2p2->next)
s2p2 = s2p2->next;
s2p2->next = s2p;
}
uaenet_int_requested = 1;
uae_sem_post (&async_sem);
}
static struct s2packet *createwritepacket (TrapContext *ctx, uaecptr request)
{
uae_u8 flags = get_byte (request + 30);
uae_u32 datalength = get_long (request + 32 + 4 + 4 + SANA2_MAX_ADDR_BYTES * 2);
uaecptr data = get_long (request + 32 + 4 + 4 + SANA2_MAX_ADDR_BYTES * 2 + 4);
uaecptr srcaddr = request + 32 + 4 + 4;
uaecptr dstaddr = request + 32 + 4 + 4 + SANA2_MAX_ADDR_BYTES;
uae_u16 packettype = get_long (request + 32 + 4);
struct priv_s2devstruct *pdev = getps2devstruct (request);
struct s2packet *s2p;
if (!pdev)
return NULL;
if (!copyfrombuff (ctx, data, pdev->tempbuf, datalength, pdev->copyfrombuff))
return NULL;
s2p = xcalloc (struct s2packet, 1);
s2p->data = xmalloc (uae_u8, pdev->td->mtu + ETH_HEADER_SIZE + 2);
if (flags & SANA2IOF_RAW) {
memcpyah_safe (s2p->data, pdev->tempbuf, datalength);
packettype = (s2p->data[2 * ADDR_SIZE + 0] << 8) | (s2p->data[2 * ADDR_SIZE + 1]);
s2p->len = datalength;
} else {
memcpyah_safe (s2p->data + ETH_HEADER_SIZE, pdev->tempbuf, datalength);
memcpy (s2p->data + ADDR_SIZE, pdev->td->mac, ADDR_SIZE);
memcpyah_safe (s2p->data, dstaddr, ADDR_SIZE);
s2p->data[2 * ADDR_SIZE + 0] = packettype >> 8;
s2p->data[2 * ADDR_SIZE + 1] = packettype;
s2p->len = datalength + ETH_HEADER_SIZE;
}
if (pdev->tracks[packettype]) {
pdev->packetssent++;
pdev->bytessent += datalength;
}
return s2p;
}
static int uaenet_getdata (struct s2devstruct *dev, uae_u8 *d, int *len)
{
int gotit;
struct asyncreq *ar;
uae_sem_wait (&async_sem);
ar = dev->ar;
gotit = 0;
while (ar && !gotit) {
if (!ar->ready) {
uaecptr request = ar->request;
int command = get_word (request + 28);
uae_u32 packettype = get_long (request + 32 + 4);
if (command == CMD_WRITE || command == S2_BROADCAST || command == S2_MULTICAST) {
struct priv_s2devstruct *pdev = getps2devstruct (request);
struct asyncreq *ars2p = dev->s2p;
while (ars2p) {
if (ars2p->request == request) {
*len = ars2p->s2p->len;
memcpy (d, ars2p->s2p->data, *len);
if (log_net)
write_log ("->DST:%02X.%02X.%02X.%02X.%02X.%02X SRC:%02X.%02X.%02X.%02X.%02X.%02X E=%04X S=%d\n",
d[0], d[1], d[2], d[3], d[4], d[5],
d[6], d[7], d[8], d[9], d[10], d[11],
packettype, *len);
gotit = 1;
dev->packetssent++;
signalasync (dev, ar, *len, 0);
break;
}
ars2p = ars2p->next;
}
}
}
ar = ar->next;
}
uae_sem_post (&async_sem);
return gotit;
}
static uae_u32 REGPARAM2 dev_open_2 (TrapContext *context)
{
uaecptr ioreq = m68k_areg (regs, 1);
uae_u32 unit = m68k_dreg (regs, 0);
uae_u32 flags = m68k_dreg (regs, 1);
uaecptr buffermgmt;
struct s2devstruct *dev = gets2devstruct (unit);
struct priv_s2devstruct *pdev = 0;
int i;
uaecptr tagp, tagpnext;
if (!dev)
return openfail (ioreq, IOERR_OPENFAIL);
if (!initint(context))
return openfail (ioreq, IOERR_SELFTEST);
if (log_net)
write_log ("opening %s:%d opencnt=%d ioreq=%08X\n", SANA2NAME, unit, dev->opencnt, ioreq);
if (get_word (ioreq + 0x12) < IOSTDREQ_SIZE)
return openfail (ioreq, IOERR_BADLENGTH);
if ((flags & SANA2OPF_PROM) && dev->opencnt > 0)
return openfail (ioreq, IOERR_UNITBUSY);
for (i = 0; i < MAX_OPEN_DEVICES; i++) {
pdev = &pdevst[i];
if (pdev->inuse == 0)
break;
}
if (i == MAX_OPEN_DEVICES)
return openfail (ioreq, IOERR_UNITBUSY);
put_long (ioreq + 24, pdev - pdevst);
pdev->unit = unit;
pdev->flags = flags;
pdev->inuse = 1;
pdev->td = &td[unit];
pdev->promiscuous = (flags & SANA2OPF_PROM) ? 1 : 0;
if (pdev->td->active == 0)
return openfail (ioreq, IOERR_OPENFAIL);
if (dev->opencnt == 0) {
dev->unit = unit;
dev->sysdata = xcalloc (uae_u8, uaenet_getdatalenght ());
if (!uaenet_open (dev->sysdata, pdev->td, dev, uaenet_gotdata, uaenet_getdata, pdev->promiscuous)) {
xfree (dev->sysdata);
dev->sysdata = NULL;
return openfail (ioreq, IOERR_OPENFAIL);
}
write_log ("%s: initializing unit %d\n", getdevname (), unit);
dev->td = pdev->td;
dev->adapter = pdev->td->active;
if (dev->adapter) {
dev->online = 1;
dev->configured = 1;
}
start_thread (dev);
}
if (kickstart_version >= 36) {
m68k_areg (regs, 0) = get_long (4) + 350;
m68k_areg (regs, 1) = timerdevname;
CallLib (context, get_long (4), -0x114); /* FindName('timer.device') */
pdev->timerbase = m68k_dreg (regs, 0);
}
pdev->copyfrombuff = pdev->copytobuff = pdev->packetfilter = 0;
pdev->tempbuf = 0;
if (get_word (ioreq + 0x12) >= SANA2_IOREQSIZE) {
buffermgmt = get_long (ioreq + 32 + 4 + 4 + SANA2_MAX_ADDR_BYTES * 2 + 4 + 4 + 4);
tagpnext = buffermgmt;
while (tagpnext) {
uae_u32 tag = get_long (tagpnext);
uae_u32 val = get_long (tagpnext + 4);
tagp = tagpnext;
tagpnext += 8;
switch (tag)
{
case TAG_DONE:
tagpnext = 0;
break;
case TAG_IGNORE:
break;
case TAG_MORE:
tagpnext = val;
break;
case TAG_SKIP:
tagpnext = tagp + val * 8;
break;
case S2_CopyToBuff:
pdev->copytobuff = val;
break;
case S2_CopyFromBuff:
pdev->copyfrombuff = val;
break;
case S2_PacketFilter:
pdev->packetfilter = val;
break;
}
}
if (log_net)
write_log ("%s:%d CTB=%08x CFB=%08x PF=%08x\n",
getdevname(), unit, pdev->copytobuff, pdev->copyfrombuff, pdev->packetfilter);
m68k_dreg (regs, 0) = dev->td->mtu + ETH_HEADER_SIZE + 2;
m68k_dreg (regs, 1) = 1;
pdev->tempbuf = CallLib (context, get_long (4), -0xC6); /* AllocMem */
if (!pdev->tempbuf) {
if (dev->opencnt == 0) {
uaenet_close (dev->sysdata);
xfree (dev->sysdata);
dev->sysdata = NULL;
}
return openfail (ioreq, S2ERR_BAD_ARGUMENT);
}
/* buffermanagement */
put_long (ioreq + 32 + 4 + 4 + SANA2_MAX_ADDR_BYTES * 2 + 4 + 4 + 4, pdev->tempbuf);
}
dev->exclusive = flags & SANA2OPF_MINE;
dev->opencnt++;
put_word (m68k_areg (regs, 6) + 32, get_word (m68k_areg (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);
}
void checkevents (struct s2devstruct *dev, int mask, int sem)
{
struct asyncreq *ar;
if (sem)
uae_sem_wait (&async_sem);
ar = dev->ar;
while (ar) {
if (!ar->ready) {
uaecptr request = ar->request;
int command = get_word (request + 28);
uae_u32 cmask = get_long (request + 32);
if (command == S2_ONEVENT && (mask & cmask))
signalasync (dev, ar, 0, 0);
}
ar = ar->next;
}
if (sem)
uae_sem_post (&async_sem);
}
static int checksize (uaecptr request, struct s2devstruct *dev)
{
uae_u32 datalength = get_long (request + 32 + 4 + 4 + SANA2_MAX_ADDR_BYTES * 2);
if (datalength > dev->td->mtu)
return 0;
return 1;
}
static void flush (struct priv_s2devstruct *pdev)
{
struct asyncreq *ar;
struct s2devstruct *dev;
dev = gets2devstruct (pdev->unit);
ar = dev->ar;
while (ar) {
if (!ar->ready && getps2devstruct (ar->request) == pdev) {
ar->ready = 1;
do_abort_async (dev, ar->request);
}
ar = ar->next;
}
}
static int dev_do_io_2 (struct s2devstruct *dev, uaecptr request, int quick)
{
uae_u8 flags = get_byte (request + 30);
uae_u32 command = get_word (request + 28);
uae_u32 packettype = get_long (request + 32 + 4);
uaecptr data = get_long (request + 32 + 4 + 4 + SANA2_MAX_ADDR_BYTES * 2 + 4);
uae_u32 datalength = get_long (request + 32 + 4 + 4 + SANA2_MAX_ADDR_BYTES * 2);
uaecptr srcaddr = request + 32 + 4 + 4;
uaecptr dstaddr = request + 32 + 4 + 4 + SANA2_MAX_ADDR_BYTES;
uaecptr statdata = get_long (request + 32 + 4 + 4 + SANA2_MAX_ADDR_BYTES * 2 + 4 + 4);
uaecptr buffermgmt = get_long (request + 32 + 4 + 4 + SANA2_MAX_ADDR_BYTES * 2 + 4 + 4 + 4);
uae_u32 io_error = 0;
uae_u32 wire_error = 0;
int i;
int async = 0;
struct priv_s2devstruct *pdev = getps2devstruct (request);
if (log_net)
write_log ("S2: C=%02d T=%04X S=%02X%02X%02X%02X%02X%02X D=%02X%02X%02X%02X%02X%02X L=%d D=%08X SD=%08X BM=%08X\n",
command, packettype,
get_byte (srcaddr + 0), get_byte (srcaddr + 1), get_byte (srcaddr + 2), get_byte (srcaddr + 3), get_byte (srcaddr + 4), get_byte (srcaddr + 5),
get_byte (dstaddr + 0), get_byte (dstaddr + 1), get_byte (dstaddr + 2), get_byte (dstaddr + 3), get_byte (dstaddr + 4), get_byte (dstaddr + 5),
datalength, data, statdata, buffermgmt);
if (command == CMD_READ || command == S2_READORPHAN || command == CMD_WRITE || command == S2_BROADCAST || command == S2_MULTICAST) {
if (!pdev->copyfrombuff || !pdev->copytobuff) {
io_error = S2ERR_BAD_ARGUMENT;
wire_error = S2WERR_BUFF_ERROR;
goto end;
}
}
switch (command)
{
case CMD_READ:
if (!dev->online)
goto offline;
async = 1;
break;
case S2_READORPHAN:
if (!dev->online)
goto offline;
async = 1;
break;
case S2_BROADCAST:
case CMD_WRITE:
if (!dev->online)
goto offline;
if (!checksize (request, dev))
goto toobig;
async = 1;
break;
case S2_MULTICAST:
if (!dev->online)
goto offline;
if ((get_byte (dstaddr + 0) & 1) == 0) {
io_error = S2ERR_BAD_ADDRESS;
wire_error = S2WERR_BAD_MULTICAST;
goto end;
}
if (!checksize (request, dev))
goto toobig;
async = 1;
break;
case CMD_FLUSH:
dev->flush_timeout_cnt = 0;
dev->flush_timeout = FLUSH_TIMEOUT;
if (log_net)
write_log ("CMD_FLUSH started %08x\n", request);
uae_sem_wait (&async_sem);
flush (pdev);
uae_sem_post (&async_sem);
async = 1;
uaenet_vsync_requested++;
break;
case S2_ADDMULTICASTADDRESS:
addmulticastaddresses (dev, amigaaddrto64 (srcaddr), 0);
break;
case S2_DELMULTICASTADDRESS:
if (!delmulticastaddresses (dev, amigaaddrto64 (srcaddr), 0)) {
io_error = S2ERR_BAD_STATE;
wire_error = S2WERR_BAD_MULTICAST;
}
break;
case S2_ADDMULTICASTADDRESSES:
addmulticastaddresses (dev, amigaaddrto64 (srcaddr), amigaaddrto64 (dstaddr));
break;
case S2_DELMULTICASTADDRESSES:
if (!delmulticastaddresses (dev, amigaaddrto64 (srcaddr), amigaaddrto64 (dstaddr))) {
io_error = S2ERR_BAD_STATE;
wire_error = S2WERR_BAD_MULTICAST;
}
break;
case S2_DEVICEQUERY:
{
int size = get_long (statdata);
if (size > 30)
size = 30;
put_long (statdata + 4, size);
if (size >= 12)
put_long (statdata + 8, 0);
if (size >= 16)
put_long (statdata + 12, 0);
if (size >= 18)
put_word (statdata + 16, ADDR_SIZE * 8);
if (size >= 22)
put_long (statdata + 18, dev->td->mtu);
if (size >= 26)
put_long (statdata + 22, 10000000);
if (size >= 30)
put_long (statdata + 26, S2WireType_Ethernet);
}
break;
case S2_GETTYPESTATS:
if (pdev->trackcnt) {
put_long (statdata + 0, pdev->packetssent);
put_long (statdata + 4, pdev->packetsreceived);
put_long (statdata + 8, pdev->bytessent);
put_long (statdata + 12, pdev->bytesreceived);
put_long (statdata + 16, pdev->packetsdropped);
} else {
io_error = S2ERR_BAD_STATE;
wire_error = S2WERR_NOT_TRACKED;
}
break;
case S2_GETGLOBALSTATS:
put_long (statdata + 0, dev->packetsreceived);
put_long (statdata + 4, dev->packetssent);
put_long (statdata + 8, dev->baddata);
put_long (statdata + 12, dev->overruns);
put_long (statdata + 16, 0);
put_long (statdata + 20, dev->unknowntypesreceived);
put_long (statdata + 24, dev->reconfigurations);
put_long (statdata + 28, dev->online_secs);
put_long (statdata + 32, dev->online_micro);
break;
case S2_GETSPECIALSTATS:
put_long (statdata + 1, 0);
break;
case S2_GETSTATIONADDRESS:
for (i = 0; i < ADDR_SIZE; i++) {
put_byte (srcaddr + i, dev->td->mac[i]);
put_byte (dstaddr + i, dev->td->mac[i]);
}
break;
case S2_CONFIGINTERFACE:
if (dev->configured) {
io_error = S2ERR_BAD_STATE;
wire_error = S2WERR_IS_CONFIGURED;
} else {
dev->configured = TRUE;
}
break;
case S2_ONLINE:
if (!dev->configured) {
io_error = S2ERR_BAD_STATE;
wire_error = S2WERR_NOT_CONFIGURED;
}
if (!dev->adapter) {
io_error = S2ERR_OUTOFSERVICE;
wire_error = S2WERR_RCVREL_HDW_ERR;
}
if (!io_error) {
uaenet_vsync_requested++;
async = 1;
}
break;
case S2_TRACKTYPE:
if (packettype <= 65535) {
if (pdev->tracks[packettype]) {
io_error = S2ERR_BAD_STATE;
wire_error = S2WERR_ALREADY_TRACKED;
} else {
pdev->tracks[packettype] = 1;
pdev->trackcnt++;
}
} else {
io_error = S2ERR_BAD_ARGUMENT;
}
break;
case S2_UNTRACKTYPE:
if (packettype <= 65535) {
if (!pdev->tracks[packettype]) {
io_error = S2ERR_BAD_STATE;
wire_error = S2WERR_NOT_TRACKED;
} else {
pdev->tracks[packettype] = 0;
pdev->trackcnt--;
}
} else {
io_error = S2ERR_BAD_ARGUMENT;
}
break;
case S2_OFFLINE:
if (dev->online) {
dev->online = 0;
checkevents (dev, S2EVENT_OFFLINE, 1);
}
break;
case S2_ONEVENT:
{
uae_u32 events;
uae_u32 wanted_events = get_long (request + 32);
if (wanted_events & ~KNOWN_EVENTS) {
io_error = S2ERR_NOT_SUPPORTED;
events = S2WERR_BAD_EVENT;
} else {
if (dev->online)
events = S2EVENT_ONLINE;
else
events = S2EVENT_OFFLINE;
events &= wanted_events;
if (events) {
wire_error = events;
} else {
async = 1;
}
}
}
break;
default:
io_error = IOERR_NOCMD;
break;
offline:
io_error = S2ERR_OUTOFSERVICE;
wire_error = S2WERR_UNIT_OFFLINE;
break;
toobig:
io_error = S2ERR_MTU_EXCEEDED;
wire_error = S2WERR_GENERIC_ERROR;
break;
}
end:
if (log_net && (io_error || wire_error))
write_log ("-> %d (%d)\n", io_error, wire_error);
put_long (request + 32, wire_error);
put_byte (request + 31, io_error);
return async;
}
static int dev_do_io (struct s2devstruct *dev, uaecptr request, int quick)
{
uae_u32 command = get_word (request + 28);
struct priv_s2devstruct *pdev = getps2devstruct (request);
uaecptr data = get_long (request + 32 + 4 + 4 + SANA2_MAX_ADDR_BYTES * 2 + 4);
put_byte (request + 31, 0);
if (!pdev) {
write_log ("%s unknown iorequest %08x\n", getdevname (), request);
return 0;
}
if (command == NSCMD_DEVICEQUERY) {
uae_u32 data = get_long (request + 40); /* io_data */
put_long (data + 0, 0);
put_long (data + 4, 16); /* size */
put_word (data + 8, 7); /* NSDEVTYPE_SANA2 */
put_word (data + 10, 0);
put_long (data + 12, nscmd_cmd);
put_long (request + 32, 16); /* io_actual */
return 0;
} else if (get_word (request + 0x12) < SANA2_IOREQSIZE) {
put_byte (request + 31, IOERR_BADLENGTH);
return 0;
}
return dev_do_io_2 (dev, request, quick);
}
static int dev_can_quick (uae_u32 command)
{
switch (command)
{
case NSCMD_DEVICEQUERY:
case S2_DEVICEQUERY:
case S2_CONFIGINTERFACE:
case S2_GETSTATIONADDRESS:
case S2_TRACKTYPE:
case S2_UNTRACKTYPE:
return 1;
}
return 0;
}
static int dev_canquick (struct s2devstruct *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 (regs, 1);
uae_u8 flags = get_byte (request + 30);
int command = get_word (request + 28);
struct priv_s2devstruct *pdev = getps2devstruct (request);
struct s2devstruct *dev;
put_byte (request + 8, NT_MESSAGE);
if (!pdev) {
write_log ("%s unknown iorequest (1) %08x\n", getdevname (), request);
put_byte (request + 31, 32);
return get_byte (request + 31);
}
dev = gets2devstruct (pdev->unit);
if (!dev) {
write_log ("%s unknown iorequest (2) %08x\n", getdevname (), request);
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, 1))
write_log ("%s: command %d bug with IO_QUICK\n", SANA2NAME, command);
return get_byte (request + 31);
} else {
if (command == CMD_WRITE || command == S2_BROADCAST || command == S2_MULTICAST) {
struct s2packet *s2p;
if (!pdev->copyfrombuff || !pdev->copytobuff) {
put_long (request + 32, S2ERR_BAD_ARGUMENT);
put_byte (request + 31, S2WERR_BUFF_ERROR);
} else {
if (command == S2_BROADCAST) {
uaecptr dstaddr = request + 32 + 4 + 4 + SANA2_MAX_ADDR_BYTES;
put_byte (dstaddr + 0, 0xff);
put_byte (dstaddr + 1, 0xff);
put_byte (dstaddr + 2, 0xff);
put_byte (dstaddr + 3, 0xff);
put_byte (dstaddr + 4, 0xff);
put_byte (dstaddr + 5, 0xff);
}
s2p = createwritepacket (context, request);
if (s2p) {
uae_sem_wait (&async_sem);
add_async_packet (dev, s2p, request);
uae_sem_post (&async_sem);
}
if (!s2p) {
put_long (request + 32, S2WERR_BUFF_ERROR);
put_byte (request + 31, S2ERR_NO_RESOURCES);
}
}
}
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 s2devstruct *dev = (struct s2devstruct*)devs;
uae_set_thread_priority (2);
dev->thread_running = 1;
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);
write_log ("%s: dev_thread killed\n", getdevname ());
return 0;
} else if (get_async_request (dev, request, 1)) {
uae_ReplyMsg (request);
release_async_request (dev, request);
rem_async_packet (dev, request);
} else if (dev_do_io (dev, request, 0) == 0) {
uae_ReplyMsg (request);
rem_async_packet (dev, request);
} else {
add_async_request (dev, request);
uaenet_trigger (dev->sysdata);
}
uae_sem_post (&change_sem);
}
return 0;
}
static uae_u32 REGPARAM2 dev_init_2 (TrapContext *context)
{
uae_u32 base = m68k_dreg (regs,0);
if (log_net)
write_log ("%s init\n", SANA2NAME);
return base;
}
static uae_u32 REGPARAM2 dev_init (TrapContext *context)
{
return dev_init_2 (context);
}
static uae_u32 REGPARAM2 dev_abortio (TrapContext *context)
{
uae_u32 request = m68k_areg (regs, 1);
struct priv_s2devstruct *pdev = getps2devstruct (request);
struct s2devstruct *dev;
if (!pdev) {
write_log ("%s abortio but no request %08x found!\n", getdevname(), request);
put_byte (request + 31, 32);
return get_byte (request + 31);
}
dev = gets2devstruct (pdev->unit);
if (!dev) {
write_log ("%s (%d) abortio but no request %08x found!\n", getdevname(), pdev->unit, request);
put_byte (request + 31, 32);
return get_byte (request + 31);
}
if (log_net)
write_log ("%s:%d abortio %08x\n", getdevname(), dev->unit, request);
abort_async (dev, request);
return 0;
}
static uae_u32 REGPARAM2 uaenet_int_handler (TrapContext *ctx)
{
int i, j;
int gotit;
struct asyncreq *ar;
if (uae_sem_trywait (&async_sem)) {
uaenet_int_requested = 0;
uaenet_int_late = 1;
return 0;
}
for (i = 0; i < MAX_OPEN_DEVICES; i++)
pdevst[i].tmp = 0;
for (i = 0; i < MAX_TOTAL_NET_DEVICES; i++) {
struct s2devstruct *dev = &devst[i];
struct s2packet *p;
if (dev->online) {
while (dev->readqueue) {
uae_u16 type;
p = dev->readqueue;
type = (p->data[2 * ADDR_SIZE] << 8) | p->data[2 * ADDR_SIZE + 1];
ar = dev->ar;
gotit = 0;
while (ar) {
if (!ar->ready) {
uaecptr request = ar->request;
int command = get_word (request + 28);
uae_u32 packettype = get_long (request + 32 + 4);
if (command == CMD_READ && (packettype == type || (packettype <= 1500 && type <= 1500))) {
struct priv_s2devstruct *pdev = getps2devstruct (request);
if (pdev && pdev->tmp == 0) {
if (handleread (ctx, pdev, request, p->data, p->len, command)) {
if (log_net)
write_log ("-> %p Accepted, CMD_READ, REQ=%08X LEN=%d\n", p, request, p->len);
write_comm_pipe_u32 (&dev->requests, request, 1);
dev->packetsreceived++;
gotit = 1;
pdev->tmp = 1;
} else {
if (log_net)
write_log ("-> %p PacketFilter() rejected, CMD_READ, REQ=%08X LEN=%d\n", p, request, p->len);
pdev->tmp = -1;
}
}
}
}
ar = ar->next;
}
ar = dev->ar;
while (ar) {
if (!ar->ready) {
uaecptr request = ar->request;
int command = get_word (request + 28);
if (command == S2_READORPHAN) {
struct priv_s2devstruct *pdev = getps2devstruct (request);
if (pdev && pdev->tmp <= 0) {
if (log_net)
write_log ("-> %p Accepted, S2_READORPHAN, REQ=%08X LEN=%d\n", p, request, p->len);
handleread (ctx, pdev, request, p->data, p->len, command);
write_comm_pipe_u32 (&dev->requests, request, 1);
dev->packetsreceived++;
dev->unknowntypesreceived++;
gotit = 1;
pdev->tmp = 1;
}
}
}
ar = ar->next;
}
if (!gotit) {
if (log_net)
write_log ("-> %p packet dropped, LEN=%d\n", p, p->len);
for (j = 0; j < MAX_OPEN_DEVICES; j++) {
if (pdevst[j].unit == dev->unit) {
if (pdevst[j].tracks[type])
pdevst[j].packetsdropped++;
}
}
}
dev->readqueue = dev->readqueue->next;
freepacket (p);
}
} else {
while (dev->readqueue) {
p = dev->readqueue;
dev->readqueue = dev->readqueue->next;
freepacket (p);
}
}
ar = dev->ar;
while (ar) {
if (!ar->ready) {
uaecptr request = ar->request;
int command = get_word (request + 28);
if (command == S2_ONLINE) {
struct priv_s2devstruct *pdev = getps2devstruct (request);
dev->packetsreceived = 0;
dev->packetssent = 0;
dev->baddata = 0;
dev->overruns = 0;
dev->unknowntypesreceived = 0;
dev->reconfigurations = 0;
if (pdev && pdev->timerbase) {
m68k_areg (regs, 0) = pdev->tempbuf;
CallLib (ctx, pdev->timerbase, -0x42); /* GetSysTime() */
} else {
put_long (pdev->tempbuf + 0, 0);
put_long (pdev->tempbuf + 4, 0);
}
dev->online_secs = get_long (pdev->tempbuf + 0);
dev->online_micro = get_long (pdev->tempbuf + 4);
checkevents (dev, S2EVENT_ONLINE, 0);
dev->online = 1;
write_comm_pipe_u32 (&dev->requests, request, 1);
uaenet_vsync_requested--;
} else if (command == CMD_FLUSH) {
/* do not reply CMD_FLUSH until all other requests are gone */
if (dev->ar->next == NULL) {
if (log_net)
write_log ("CMD_FLUSH replied %08x\n", request);
write_comm_pipe_u32 (&dev->requests, request, 1);
uaenet_vsync_requested--;
} else {
struct priv_s2devstruct *pdev = getps2devstruct (request);
if (pdev) {
dev->flush_timeout--;
if (dev->flush_timeout <= 0) {
dev->flush_timeout = FLUSH_TIMEOUT;
if (dev->flush_timeout_cnt > 1)
write_log ("WARNING: %s:%d CMD_FLUSH possibly frozen..\n", getdevname(), pdev->unit);
dev->flush_timeout_cnt++;
flush (pdev);
}
}
}
}
}
ar = ar->next;
}
}
if (uaenet_int_late)
uaenet_int_requested = 1;
else
uaenet_int_requested = 0;
uaenet_int_late = 0;
uae_sem_post (&async_sem);
return 0;
}
static void dev_reset (void)
{
int i;
struct s2devstruct *dev;
int unitnum = 0;
write_log ("%s reset\n", getdevname());
for (i = 0; i < MAX_TOTAL_NET_DEVICES; i++) {
dev = &devst[i];
if (dev->opencnt) {
struct asyncreq *ar = dev->ar;
while (ar) {
if (!ar->ready) {
dev->ar->ready = 1;
do_abort_async (dev, ar->request);
}
ar = ar->next;
}
write_comm_pipe_u32 (&dev->requests, 0, 1);
uae_sem_wait (&dev->sync_sem);
}
while (dev->mc)
delmulticastaddresses (dev, dev->mc->start, dev->mc->end);
memset (dev, 0, sizeof (struct s2devstruct));
}
for (i = 0; i < MAX_OPEN_DEVICES; i++)
memset (&pdevst[i], 0, sizeof (struct priv_s2devstruct));
uaenet_vsync_requested = 0;
uaenet_int_requested = 0;
irq_init = 0;
}
uaecptr netdev_startup (uaecptr resaddr)
{
if (!currprefs.sana2)
return resaddr;
if (log_net)
write_log ("netdev_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_netdev_resname);
put_long (resaddr + 0x12, ROM_netdev_resid);
put_long (resaddr + 0x16, ROM_netdev_init); /* calls scsidev_init */
resaddr += 0x1A;
return resaddr;
}
void netdev_install (void)
{
uae_u32 functable, datatable;
uae_u32 initcode, openfunc, closefunc, expungefunc;
uae_u32 beginiofunc, abortiofunc;
if (!currprefs.sana2)
return;
if (log_net)
write_log ("netdev_install(): 0x%x\n", here ());
uaenet_enumerate_free (td);
uaenet_enumerate (&td, NULL);
ROM_netdev_resname = ds (getdevname());
ROM_netdev_resid = ds ("UAE net.device 0.2");
timerdevname = ds ("timer.device");
/* initcode */
initcode = here ();
calltrap (deftrap2 (dev_init, TRAPFLAG_EXTRA_STACK, "uaenet.init")); dw (RTS);
/* Open */
openfunc = here ();
calltrap (deftrap2 (dev_open, TRAPFLAG_EXTRA_STACK, "uaenet.open")); dw (RTS);
/* Close */
closefunc = here ();
calltrap (deftrap2 (dev_close, TRAPFLAG_EXTRA_STACK, "uaenet.close")); dw (RTS);
/* Expunge */
expungefunc = here ();
calltrap (deftrap2 (dev_expunge, TRAPFLAG_EXTRA_STACK, "uaenet.expunge")); dw (RTS);
/* BeginIO */
beginiofunc = here ();
calltrap (deftrap2 (dev_beginio, TRAPFLAG_EXTRA_STACK, "uaenet.beginio")); dw (RTS);
/* AbortIO */
abortiofunc = here ();
calltrap (deftrap2 (dev_abortio, TRAPFLAG_EXTRA_STACK, "uaenet.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_netdev_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_netdev_resid);
dw (0x0000); /* end of table */
ROM_netdev_init = here ();
dl (0x00000100); /* size of device base */
dl (functable);
dl (datatable);
dl (initcode);
nscmd_cmd = here ();
dw (CMD_READ);
dw (CMD_WRITE);
dw (CMD_FLUSH);
dw (S2_DEVICEQUERY);
dw (S2_GETSTATIONADDRESS);
dw (S2_CONFIGINTERFACE);
dw (S2_ADDMULTICASTADDRESS);
dw (S2_DELMULTICASTADDRESS);
dw (S2_MULTICAST);
dw (S2_BROADCAST);
dw (S2_TRACKTYPE);
dw (S2_UNTRACKTYPE);
dw (S2_GETTYPESTATS);
dw (S2_GETSPECIALSTATS);
dw (S2_GETGLOBALSTATS);
dw (S2_ONEVENT);
dw (S2_READORPHAN);
dw (S2_ONLINE);
dw (S2_OFFLINE);
dw (S2_ADDMULTICASTADDRESSES);
dw (S2_DELMULTICASTADDRESSES);
dw (NSCMD_DEVICEQUERY);
dw (0);
}
void netdev_start_threads (void)
{
if (!currprefs.sana2)
return;
if (log_net)
write_log ("netdev_start_threads()\n");
uae_sem_init (&change_sem, 0, 1);
uae_sem_init (&async_sem, 0, 1);
}
void netdev_reset (void)
{
if (!currprefs.sana2)
return;
dev_reset ();
}
/*
* UAE - The Un*x Amiga Emulator
*
* Linux uaenet emulation
*
* Copyright 2007 Toni Wilen
* 2010 Mustafa TUFAN
*/
#include "sysconfig.h"
#include <stdio.h>
#define HAVE_REMOTE
#define WPCAP
#include "pcap.h"
#include "packet32.h"
#include "ntddndis.h"
#include "sysdeps.h"
#include "options.h"
#include "threaddep/thread.h"
#include "uaenet.h"
static struct netdriverdata tds[MAX_TOTAL_NET_DEVICES];
static int enumerated;
struct uaenetdatawin32
{
HANDLE evttw;
void *readdata, *writedata;
uae_sem_t change_sem;
volatile int threadactiver;
uae_thread_id tidr;
uae_sem_t sync_semr;
volatile int threadactivew;
uae_thread_id tidw;
uae_sem_t sync_semw;
void *user;
struct netdriverdata *tc;
uae_u8 *readbuffer;
uae_u8 *writebuffer;
int mtu;
char errbuf[PCAP_ERRBUF_SIZE];
pcap_t *fp;
uaenet_gotfunc *gotfunc;
uaenet_getfunc *getfunc;
};
int uaenet_getdatalenght (void)
{
return sizeof (struct uaenetdatawin32);
}
static void uaeser_initdata (struct uaenetdatawin32 *sd, void *user)
{
memset (sd, 0, sizeof (struct uaenetdatawin32));
sd->evttw = 0;
sd->user = user;
sd->fp = NULL;
}
static void *uaenet_trap_threadr (void *arg)
{
struct uaenetdatawin32 *sd = (struct uaenetdatawin32*)arg;
struct pcap_pkthdr *header;
const u_char *pkt_data;
uae_set_thread_priority (NULL, 1);
sd->threadactiver = 1;
uae_sem_post (&sd->sync_semr);
while (sd->threadactiver == 1) {
int r;
r = pcap_next_ex (sd->fp, &header, &pkt_data);
if (r == 1) {
uae_sem_wait (&sd->change_sem);
sd->gotfunc ((struct s2devstruct*)sd->user, pkt_data, header->len);
uae_sem_post (&sd->change_sem);
}
if (r < 0) {
write_log ("pcap_next_ex failed, err=%d\n", r);
break;
}
}
sd->threadactiver = 0;
uae_sem_post (&sd->sync_semr);
return 0;
}
static void *uaenet_trap_threadw (void *arg)
{
struct uaenetdatawin32 *sd = (struct uaenetdatawin32*)arg;
uae_set_thread_priority (NULL, 1);
sd->threadactivew = 1;
uae_sem_post (&sd->sync_semw);
while (sd->threadactivew == 1) {
int donotwait = 0;
int towrite = sd->mtu;
uae_sem_wait (&sd->change_sem);
if (sd->getfunc ((struct s2devstruct*)sd->user, sd->writebuffer, &towrite)) {
pcap_sendpacket (sd->fp, sd->writebuffer, towrite);
donotwait = 1;
}
uae_sem_post (&sd->change_sem);
if (!donotwait)
WaitForSingleObject (sd->evttw, INFINITE);
}
sd->threadactivew = 0;
uae_sem_post (&sd->sync_semw);
return 0;
}
void uaenet_trigger (void *vsd)
{
struct uaenetdatawin32 *sd = (struct uaenetdatawin32*)vsd;
if (!sd)
return;
SetEvent (sd->evttw);
}
int uaenet_open (void *vsd, struct netdriverdata *tc, void *user, uaenet_gotfunc *gotfunc, uaenet_getfunc *getfunc, int promiscuous)
{
struct uaenetdatawin32 *sd = (struct uaenetdatawin32*)vsd;
char *s;
s = ua (tc->name);
sd->fp = pcap_open (s, 65536, (promiscuous ? PCAP_OPENFLAG_PROMISCUOUS : 0) | PCAP_OPENFLAG_MAX_RESPONSIVENESS, 100, NULL, sd->errbuf);
xfree (s);
if (sd->fp == NULL) {
TCHAR *ss = au (sd->errbuf);
write_log ("'%s' failed to open: %s\n", tc->name, ss);
xfree (ss);
return 0;
}
sd->tc = tc;
sd->user = user;
sd->evttw = CreateEvent (NULL, FALSE, FALSE, NULL);
if (!sd->evttw)
goto end;
sd->mtu = tc->mtu;
sd->readbuffer = xmalloc (uae_u8, sd->mtu);
sd->writebuffer = xmalloc (uae_u8, sd->mtu);
sd->gotfunc = gotfunc;
sd->getfunc = getfunc;
uae_sem_init (&sd->change_sem, 0, 1);
uae_sem_init (&sd->sync_semr, 0, 0);
uae_start_thread ("uaenet_win32r", uaenet_trap_threadr, sd, &sd->tidr);
uae_sem_wait (&sd->sync_semr);
uae_sem_init (&sd->sync_semw, 0, 0);
uae_start_thread ("uaenet_win32w", uaenet_trap_threadw, sd, &sd->tidw);
uae_sem_wait (&sd->sync_semw);
write_log ("uaenet_win32 initialized\n");
return 1;
end:
uaenet_close (sd);
return 0;
}
void uaenet_close (void *vsd)
{
struct uaenetdatawin32 *sd = (struct uaenetdatawin32*)vsd;
if (!sd)
return;
if (sd->threadactiver) {
sd->threadactiver = -1;
}
if (sd->threadactivew) {
sd->threadactivew = -1;
SetEvent (sd->evttw);
}
if (sd->threadactiver) {
while (sd->threadactiver)
Sleep(10);
write_log ("uaenet_win32 thread %d killed\n", sd->tidr);
uae_end_thread (&sd->tidr);
}
if (sd->threadactivew) {
while (sd->threadactivew)
Sleep(10);
CloseHandle (sd->evttw);
write_log ("uaenet_win32 thread %d killed\n", sd->tidw);
uae_end_thread (&sd->tidw);
}
xfree (sd->readbuffer);
xfree (sd->writebuffer);
if (sd->fp)
pcap_close (sd->fp);
uaeser_initdata (sd, sd->user);
write_log ("uaenet_win32 closed\n");
}
void uaenet_enumerate_free (struct netdriverdata *tcp)
{
int i;
if (!tcp)
return;
for (i = 0; i < MAX_TOTAL_NET_DEVICES; i++) {
xfree (tcp[i].name);
xfree (tcp[i].desc);
tcp[i].name = NULL;
tcp[i].desc = NULL;
tcp[i].active = 0;
}
}
static struct netdriverdata *enumit (const TCHAR *name)
{
int cnt;
for (cnt = 0; cnt < MAX_TOTAL_NET_DEVICES; cnt++) {
TCHAR mac[20];
struct netdriverdata *tc = tds + cnt;
_stprintf (mac, "%02X:%02X:%02X:%02X:%02X:%02X",
tc->mac[0], tc->mac[1], tc->mac[2], tc->mac[3], tc->mac[4], tc->mac[5]);
if (tc->active && name && (!_tcsicmp (name, tc->name) || !_tcsicmp (name, mac)))
return tc;
}
return NULL;
}
struct netdriverdata *uaenet_enumerate (struct netdriverdata **out, const TCHAR *name)
{
static int done;
char errbuf[PCAP_ERRBUF_SIZE];
pcap_if_t *alldevs, *d;
int cnt;
HMODULE hm;
LPADAPTER lpAdapter = 0;
PPACKET_OID_DATA OidData;
struct netdriverdata *tc, *tcp;
pcap_t *fp;
int val;
TCHAR *ss;
if (enumerated) {
if (out)
*out = tds;
return enumit (name);
}
tcp = tds;
hm = LoadLibrary ("wpcap.dll");
if (hm == NULL) {
write_log ("uaenet: winpcap not installed (wpcap.dll)\n");
return NULL;
}
FreeLibrary (hm);
hm = LoadLibrary ("packet.dll");
if (hm == NULL) {
write_log ("uaenet: winpcap not installed (packet.dll)\n");
return NULL;
}
FreeLibrary (hm);
if (!isdllversion ("wpcap.dll", 4, 0, 0, 0)) {
write_log ("uaenet: too old winpcap, v4 or newer required\n");
return NULL;
}
ss = au (pcap_lib_version ());
if (!done)
write_log ("uaenet: %s\n", ss);
xfree (ss);
if (pcap_findalldevs_ex (PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1) {
ss = au (errbuf);
write_log ("uaenet: failed to get interfaces: %s\n", ss);
xfree (ss);
return NULL;
}
if (!done)
write_log ("uaenet: detecting interfaces\n");
for(cnt = 0, d = alldevs; d != NULL; d = d->next) {
char *n2;
TCHAR *ss2;
tc = tcp + cnt;
if (cnt >= MAX_TOTAL_NET_DEVICES) {
write_log ("buffer overflow\n");
break;
}
ss = au (d->name);
ss2 = d->description ? au (d->description) : "(no description)";
write_log ("%s\n- %s\n", ss, ss2);
xfree (ss2);
xfree (ss);
n2 = d->name;
if (strlen (n2) <= strlen (PCAP_SRC_IF_STRING)) {
write_log ("- corrupt name\n");
continue;
}
fp = pcap_open (d->name, 65536, 0, 0, NULL, errbuf);
if (!fp) {
ss = au (errbuf);
write_log ("- pcap_open() failed: %s\n", ss);
xfree (ss);
continue;
}
val = pcap_datalink (fp);
pcap_close (fp);
if (val != DLT_EN10MB) {
if (!done)
write_log ("- not an ethernet adapter (%d)\n", val);
continue;
}
lpAdapter = PacketOpenAdapter (n2 + strlen (PCAP_SRC_IF_STRING));
if (lpAdapter == NULL) {
if (!done)
write_log ("- PacketOpenAdapter() failed\n");
continue;
}
OidData = (PPACKET_OID_DATA)xcalloc (uae_u8, 6 + sizeof(PACKET_OID_DATA));
if (OidData) {
OidData->Length = 6;
OidData->Oid = OID_802_3_CURRENT_ADDRESS;
if (PacketRequest (lpAdapter, FALSE, OidData)) {
memcpy (tc->mac, OidData->Data, 6);
if (!done)
write_log ("- MAC %02X:%02X:%02X:%02X:%02X:%02X (%d)\n",
tc->mac[0], tc->mac[1], tc->mac[2],
tc->mac[3], tc->mac[4], tc->mac[5], cnt++);
tc->active = 1;
tc->mtu = 1500;
tc->name = au (d->name);
tc->desc = au (d->description);
} else {
write_log (" - failed to get MAC\n");
}
xfree (OidData);
}
PacketCloseAdapter (lpAdapter);
}
if (!done)
write_log ("uaenet: end of detection\n");
done = 1;
pcap_freealldevs (alldevs);
enumerated = 1;
if (out)
*out = tds;
return enumit (name);
}
void uaenet_close_driver (struct netdriverdata *tc)
{
int i;
if (!tc)
return;
for (i = 0; i < MAX_TOTAL_NET_DEVICES; i++) {
tc[i].active = 0;
}
}
/*
* UAE - The Un*x Amiga Emulator
*
* uaeserial.device
*
* Copyright 2004/2006 Toni Wilen
*
*/
#include "sysconfig.h"
#include "sysdeps.h"
#include "threaddep/thread.h"
#include "options.h"
#include "memory.h"
#include "custom.h"
#include "newcpu.h"
#include "traps.h"
#include "autoconf.h"
#include "execlib.h"
#include "native2amiga.h"
#include "uaeserial.h"
#include "serial.h"
#include "execio.h"
#define MAX_TOTAL_DEVICES 8
int log_uaeserial = 0;
#define SDCMD_QUERY 9
#define SDCMD_BREAK 10
#define SDCMD_SETPARAMS 11
#define SerErr_DevBusy 1
#define SerErr_BaudMismatch 2
#define SerErr_BufErr 4
#define SerErr_InvParam 5
#define SerErr_LineErr 6
#define SerErr_ParityErr 9
#define SerErr_TimerErr 11
#define SerErr_BufOverflow 12
#define SerErr_NoDSR 13
#define SerErr_DetectedBreak 15
#define SERB_XDISABLED 7 /* io_SerFlags xOn-xOff feature disabled bit */
#define SERF_XDISABLED (1<<7) /* " xOn-xOff feature disabled mask */
#define SERB_EOFMODE 6 /* " EOF mode enabled bit */
#define SERF_EOFMODE (1<<6) /* " EOF mode enabled mask */
#define SERB_SHARED 5 /* " non-exclusive access bit */
#define SERF_SHARED (1<<5) /* " non-exclusive access mask */
#define SERB_RAD_BOOGIE 4 /* " high-speed mode active bit */
#define SERF_RAD_BOOGIE (1<<4) /* " high-speed mode active mask */
#define SERB_QUEUEDBRK 3 /* " queue this Break ioRqst */
#define SERF_QUEUEDBRK (1<<3) /* " queue this Break ioRqst */
#define SERB_7WIRE 2 /* " RS232 7-wire protocol */
#define SERF_7WIRE (1<<2) /* " RS232 7-wire protocol */
#define SERB_PARTY_ODD 1 /* " parity feature enabled bit */
#define SERF_PARTY_ODD (1<<1) /* " parity feature enabled mask */
#define SERB_PARTY_ON 0 /* " parity-enabled bit */
#define SERF_PARTY_ON (1<<0) /* " parity-enabled mask */
#define IO_STATB_XOFFREAD 12 /* io_Status receive currently xOFF'ed bit */
#define IO_STATF_XOFFREAD (1<<12) /* " receive currently xOFF'ed mask */
#define IO_STATB_XOFFWRITE 11 /* " transmit currently xOFF'ed bit */
#define IO_STATF_XOFFWRITE (1<<11) /* " transmit currently xOFF'ed mask */
#define IO_STATB_READBREAK 10 /* " break was latest input bit */
#define IO_STATF_READBREAK (1<<10) /* " break was latest input mask */
#define IO_STATB_WROTEBREAK 9 /* " break was latest output bit */
#define IO_STATF_WROTEBREAK (1<<9) /* " break was latest output mask */
#define IO_STATB_OVERRUN 8 /* " status word RBF overrun bit */
#define IO_STATF_OVERRUN (1<<8) /* " status word RBF overrun mask */
#define io_CtlChar 0x30 /* ULONG control char's (order = xON,xOFF,INQ,ACK) */
#define io_RBufLen 0x34 /* ULONG length in bytes of serial port's read buffer */
#define io_ExtFlags 0x38 /* ULONG additional serial flags (see bitdefs below) */
#define io_Baud 0x3c /* ULONG baud rate requested (true baud) */
#define io_BrkTime 0x40 /* ULONG duration of break signal in MICROseconds */
#define io_TermArray0 0x44 /* ULONG termination character array */
#define io_TermArray1 0x48 /* ULONG termination character array */
#define io_ReadLen 0x4c /* UBYTE bits per read character (# of bits) */
#define io_WriteLen 0x4d /* UBYTE bits per write character (# of bits) */
#define io_StopBits 0x4e /* UBYTE stopbits for read (# of bits) */
#define io_SerFlags 0x4f /* UBYTE see SerFlags bit definitions below */
#define io_Status 0x50 /* UWORD */
/* status of serial port, as follows:
* BIT ACTIVE FUNCTION
* 0 --- reserved
* 1 --- reserved
* 2 high Connected to parallel "select" on the A1000.
* Connected to both the parallel "select" and
* serial "ring indicator" pins on the A500
* & A2000. Take care when making cables.
* 3 low Data Set Ready
* 4 low Clear To Send
* 5 low Carrier Detect
* 6 low Ready To Send
* 7 low Data Terminal Ready
* 8 high read overrun
* 9 high break sent
* 10 high break received
* 11 high transmit x-OFFed
* 12 high receive x-OFFed
* 13-15 reserved
*/
struct asyncreq {
struct asyncreq *next;
uaecptr request;
int ready;
};
struct devstruct {
int open;
int unit;
int uniq;
int exclusive;
struct asyncreq *ar;
smp_comm_pipe requests;
int thread_running;
uae_sem_t sync_sem;
void *sysdata;
};
static int uniq;
static uae_u32 nscmd_cmd;
static struct devstruct devst[MAX_TOTAL_DEVICES];
static uae_sem_t change_sem, async_sem;
static TCHAR *getdevname (void)
{
return "uaeserial.device";
}
static void io_log (TCHAR *msg, uaecptr request)
{
if (log_uaeserial)
write_log ("%s: %08X %d %08X %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 struct devstruct *getdevstruct (int uniq)
{
int i;
for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
if (devst[i].uniq == uniq)
return &devst[i];
}
return 0;
}
static void *dev_thread (void *devs);
static int start_thread (struct devstruct *dev)
{
init_comm_pipe (&dev->requests, 100, 1);
uae_sem_init (&dev->sync_sem, 0, 0);
uae_start_thread ("uaeserial", dev_thread, dev, NULL);
uae_sem_wait (&dev->sync_sem);
return dev->thread_running;
}
static void dev_close_3 (struct devstruct *dev)
{
uaeser_close (dev->sysdata);
dev->open = 0;
xfree (dev->sysdata);
write_comm_pipe_u32 (&dev->requests, 0, 1);
}
static uae_u32 REGPARAM2 dev_close (TrapContext *context)
{
uae_u32 request = m68k_areg (regs, 1);
struct devstruct *dev;
dev = getdevstruct (get_long (request + 24));
if (!dev)
return 0;
if (log_uaeserial)
write_log ("%s:%d close, req=%x\n", getdevname(), dev->unit, request);
dev_close_3 (dev);
put_long (request + 24, 0);
put_word (m68k_areg (regs, 6) + 32, get_word (m68k_areg (regs, 6) + 32) - 1);
return 0;
}
static void resetparams (struct devstruct *dev, uaecptr req)
{
put_long (req + io_CtlChar, 0x00001311);
put_long (req + io_RBufLen, 1024);
put_long (req + io_ExtFlags, 0);
put_long (req + io_Baud, 9600);
put_long (req + io_BrkTime, 250000);
put_long (req + io_TermArray0, 0);
put_long (req + io_TermArray1, 0);
put_byte (req + io_ReadLen, 8);
put_byte (req + io_WriteLen, 8);
put_byte (req + io_StopBits, 1);
put_byte (req + io_SerFlags, get_byte (req + io_SerFlags) & (SERF_XDISABLED | SERF_SHARED | SERF_7WIRE));
put_word (req + io_Status, 0);
}
static int setparams (struct devstruct *dev, uaecptr req)
{
int v;
int rbuffer, baud, rbits, wbits, sbits, rtscts, parity, xonxoff;
rbuffer = get_long (req + io_RBufLen);
v = get_long (req + io_ExtFlags);
if (v) {
write_log ("UAESER: io_ExtFlags=%08x, not supported\n", v);
return 5;
}
baud = get_long (req + io_Baud);
v = get_byte (req + io_SerFlags);
if (v & SERF_EOFMODE) {
write_log ("UAESER: SERF_EOFMODE not supported\n");
return 5;
}
xonxoff = (v & SERF_XDISABLED) ? 0 : 1;
if (xonxoff) {
xonxoff |= (get_long (req + io_CtlChar) << 8) & 0x00ffff00;
}
rtscts = (v & SERF_7WIRE) ? 1 : 0;
parity = 0;
if (v & SERF_PARTY_ON)
parity = (v & SERF_PARTY_ODD) ? 1 : 2;
rbits = get_byte (req + io_ReadLen);
wbits = get_byte (req + io_WriteLen);
sbits = get_byte (req + io_StopBits);
if ((rbits != 7 && rbits != 8) || (wbits != 7 && wbits != 8) || (sbits != 1 && sbits != 2) || rbits != wbits) {
write_log ("UAESER: Read=%d, Write=%d, Stop=%d, not supported\n", rbits, wbits, sbits);
return 5;
}
write_log ("%s:%d BAUD=%d BUF=%d BITS=%d+%d RTSCTS=%d PAR=%d XO=%06X\n",
getdevname(), dev->unit,
baud, rbuffer, rbits, sbits, rtscts, parity, xonxoff);
v = uaeser_setparams (dev->sysdata, baud, rbuffer,
rbits, sbits, rtscts, parity, xonxoff);
if (v) {
write_log ("->failed\n");
return v;
}
return 0;
}
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 (TrapContext *context)
{
uaecptr ioreq = m68k_areg (regs, 1);
uae_u32 unit = m68k_dreg (regs, 0);
uae_u32 flags = m68k_dreg (regs, 1);
struct devstruct *dev;
int i, err;
if (get_word (ioreq + 0x12) < IOSTDREQ_SIZE)
return openfail (ioreq, IOERR_BADLENGTH);
for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
if (devst[i].open && devst[i].unit == unit && devst[i].exclusive)
return openfail (ioreq, IOERR_UNITBUSY);
}
for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
if (!devst[i].open)
break;
}
if (i == MAX_TOTAL_DEVICES)
return openfail (ioreq, IOERR_OPENFAIL);
dev = &devst[i];
dev->sysdata = xcalloc (uae_u8, uaeser_getdatalength ());
if (!uaeser_open (dev->sysdata, dev, unit)) {
xfree (dev->sysdata);
return openfail (ioreq, IOERR_OPENFAIL);
}
dev->unit = unit;
dev->open = 1;
dev->uniq = ++uniq;
dev->exclusive = (get_word (ioreq + io_SerFlags) & SERF_SHARED) ? 0 : 1;
put_long (ioreq + 24, dev->uniq);
resetparams (dev, ioreq);
err = setparams (dev, ioreq);
if (err) {
uaeser_close (dev->sysdata);
dev->open = 0;
xfree (dev->sysdata);
return openfail (ioreq, err);
}
if (log_uaeserial)
write_log ("%s:%d open ioreq=%08X\n", getdevname(), unit, ioreq);
start_thread (dev);
put_word (m68k_areg (regs, 6) + 32, get_word (m68k_areg (regs, 6) + 32) + 1);
put_byte (ioreq + 31, 0);
put_byte (ioreq + 8, 7);
return 0;
}
static uae_u32 REGPARAM2 dev_expunge (TrapContext *context)
{
return 0;
}
static struct asyncreq *get_async_request (struct devstruct *dev, uaecptr request, int ready)
{
struct asyncreq *ar;
int ret = 0;
uae_sem_wait (&async_sem);
ar = dev->ar;
while (ar) {
if (ar->request == request) {
if (ready)
ar->ready = 1;
break;
}
ar = ar->next;
}
uae_sem_post (&async_sem);
return ar;
}
static int add_async_request (struct devstruct *dev, uaecptr request)
{
struct asyncreq *ar, *ar2;
if (log_uaeserial)
write_log ("%s:%d async request %x added\n", getdevname(), dev->unit, request);
uae_sem_wait (&async_sem);
ar = xcalloc (struct asyncreq, 1);
ar->request = request;
if (!dev->ar) {
dev->ar = ar;
} else {
ar2 = dev->ar;
while (ar2->next)
ar2 = ar2->next;
ar2->next = ar;
}
uae_sem_post (&async_sem);
return 1;
}
static int release_async_request (struct devstruct *dev, uaecptr request)
{
struct asyncreq *ar, *prevar;
uae_sem_wait (&async_sem);
ar = dev->ar;
prevar = NULL;
while (ar) {
if (ar->request == request) {
if (prevar == NULL)
dev->ar = ar->next;
else
prevar->next = ar->next;
uae_sem_post (&async_sem);
xfree (ar);
if (log_uaeserial)
write_log ("%s:%d async request %x removed\n", getdevname(), dev->unit, request);
return 1;
}
prevar = ar;
ar = ar->next;
}
uae_sem_post (&async_sem);
write_log ("%s:%d async request %x not found for removal!\n", getdevname(), dev->unit, request);
return 0;
}
static void abort_async (struct devstruct *dev, uaecptr request)
{
struct asyncreq *ar = get_async_request (dev, request, 1);
if (!ar) {
write_log ("%s:%d: abort async but no request %x found!\n", getdevname(), dev->unit, request);
return;
}
if (log_uaeserial)
write_log ("%s:%d asyncronous request=%08X aborted\n", getdevname(), dev->unit, request);
put_byte (request + 31, IOERR_ABORTED);
put_byte (request + 30, get_byte (request + 30) | 0x20);
write_comm_pipe_u32 (&dev->requests, request, 1);
}
static uae_u8 *memmap(uae_u32 addr, uae_u32 len)
{
addrbank *bank_data = &get_mem_bank (addr);
if (!bank_data->check (addr, len))
return NULL;
return bank_data->xlateaddr (addr);
}
void uaeser_signal (void *vdev, int sigmask)
{
struct devstruct *dev = (struct devstruct*)vdev;
struct asyncreq *ar;
int i = 0;
uae_sem_wait (&async_sem);
ar = dev->ar;
while (ar) {
if (!ar->ready) {
uaecptr request = ar->request;
uae_u32 io_data = get_long (request + 40); // 0x28
uae_u32 io_length = get_long (request + 36); // 0x24
int command = get_word (request + 28);
uae_u32 io_error = 0, io_actual = 0;
uae_u8 *addr;
int io_done = 0;
switch (command)
{
case SDCMD_BREAK:
if (ar == dev->ar) {
uaeser_break (dev->sysdata, get_long (request + io_BrkTime));
io_done = 1;
}
break;
case CMD_READ:
if (sigmask & 1) {
addr = memmap(io_data, io_length);
if (addr) {
if (uaeser_read (dev->sysdata, addr, io_length)) {
io_error = 0;
io_actual = io_length;
io_done = 1;
}
} else {
io_error = IOERR_BADADDRESS;
io_done = 1;
}
}
break;
case CMD_WRITE:
if (sigmask & 2) {
io_error = IOERR_BADADDRESS;
addr = memmap(io_data, io_length);
if (addr && uaeser_write (dev->sysdata, addr, io_length))
io_error = 0;
io_actual = io_length;
io_done = 1;
}
break;
default:
write_log ("%s:%d incorrect async request %x (cmd=%d) signaled?!", getdevname(), dev->unit, request, command);
break;
}
if (io_done) {
if (log_uaeserial)
write_log ("%s:%d async request %x completed\n", getdevname(), dev->unit, request);
put_long (request + 32, io_actual);
put_byte (request + 31, io_error);
ar->ready = 1;
write_comm_pipe_u32 (&dev->requests, request, 1);
}
}
ar = ar->next;
}
uae_sem_post (&async_sem);
}
static void cmd_reset(struct devstruct *dev, uaecptr req)
{
while (dev->ar)
abort_async (dev, dev->ar->request);
put_long (req + io_RBufLen, 8192);
put_long (req + io_ExtFlags, 0);
put_long (req + io_Baud, 57600);
put_long (req + io_BrkTime, 250000);
put_long (req + io_TermArray0, 0);
put_long (req + io_TermArray1, 0);
put_long (req + io_ReadLen, 8);
put_long (req + io_WriteLen, 8);
put_long (req + io_StopBits, 1);
put_long (req + io_SerFlags, SERF_XDISABLED);
put_word (req + io_Status, 0);
}
static int dev_do_io (struct devstruct *dev, uaecptr request, int quick)
{
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;
uae_u16 io_status;
int async = 0;
if (!dev)
return 0;
command = get_word (request + 28);
io_log ("dev_io_START",request);
switch (command)
{
case SDCMD_QUERY:
if (uaeser_query (dev->sysdata, &io_status, &io_actual))
put_byte (request + io_Status, io_status);
else
io_error = IOERR_BADADDRESS;
break;
case SDCMD_SETPARAMS:
io_error = setparams(dev, request);
break;
case CMD_WRITE:
async = 1;
break;
case CMD_READ:
async = 1;
break;
case SDCMD_BREAK:
if (get_byte (request + io_SerFlags) & SERF_QUEUEDBRK) {
async = 1;
} else {
uaeser_break (dev->sysdata, get_long (request + io_BrkTime));
}
break;
case CMD_CLEAR:
uaeser_clearbuffers(dev->sysdata);
break;
case CMD_RESET:
cmd_reset(dev, request);
break;
case CMD_FLUSH:
case CMD_START:
case CMD_STOP:
break;
case NSCMD_DEVICEQUERY:
put_long (io_data + 0, 0);
put_long (io_data + 4, 16); /* size */
put_word (io_data + 8, NSDEVTYPE_SERIAL);
put_word (io_data + 10, 0);
put_long (io_data + 12, nscmd_cmd);
io_actual = 16;
break;
default:
io_error = IOERR_NOCMD;
break;
}
put_long (request + 32, io_actual);
put_byte (request + 31, io_error);
io_log ("dev_io_END",request);
return async;
}
static int dev_canquick (struct devstruct *dev, uaecptr request)
{
return 0;
}
static uae_u32 REGPARAM2 dev_beginio (TrapContext *context)
{
uae_u32 request = m68k_areg (regs, 1);
uae_u8 flags = get_byte (request + 30);
int command = get_word (request + 28);
struct devstruct *dev = getdevstruct (get_long (request + 24));
put_byte (request + 8, NT_MESSAGE);
if (!dev) {
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, 1))
write_log ("device %s:%d command %d bug with IO_QUICK\n", getdevname(), dev->unit, command);
return get_byte (request + 31);
} else {
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 = (struct devstruct*)devs;
uae_set_thread_priority (2);
dev->thread_running = 1;
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);
return 0;
} else if (get_async_request (dev, request, 1)) {
uae_ReplyMsg (request);
release_async_request (dev, request);
} else if (dev_do_io (dev, request, 0) == 0) {
uae_ReplyMsg (request);
} else {
add_async_request (dev, request);
uaeser_trigger (dev->sysdata);
}
uae_sem_post (&change_sem);
}
return 0;
}
static uae_u32 REGPARAM2 dev_init (TrapContext *context)
{
uae_u32 base = m68k_dreg (regs, 0);
if (log_uaeserial)
write_log ("%s init\n", getdevname ());
return base;
}
static uae_u32 REGPARAM2 dev_abortio (TrapContext *context)
{
uae_u32 request = m68k_areg (regs, 1);
struct devstruct *dev = getdevstruct (get_long (request + 24));
if (!dev) {
put_byte (request + 31, 32);
return get_byte (request + 31);
}
abort_async (dev, request);
return 0;
}
static void dev_reset (void)
{
int i;
struct devstruct *dev;
for (i = 0; i < MAX_TOTAL_DEVICES; i++) {
dev = &devst[i];
if (dev->open) {
while (dev->ar)
abort_async (dev, dev->ar->request);
dev_close_3 (dev);
uae_sem_wait (&dev->sync_sem);
}
memset (dev, 0, sizeof (struct devstruct));
}
}
static uaecptr ROM_uaeserialdev_resname = 0,
ROM_uaeserialdev_resid = 0,
ROM_uaeserialdev_init = 0;
uaecptr uaeserialdev_startup (uaecptr resaddr)
{
if (!currprefs.uaeserial)
return resaddr;
if (log_uaeserial)
write_log ("uaeserialdev_startup(0x%x)\n", resaddr);
/* Build a struct Resident. This will set up and initialize
* the serial.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_uaeserialdev_resname);
put_long (resaddr + 0x12, ROM_uaeserialdev_resid);
put_long (resaddr + 0x16, ROM_uaeserialdev_init);
resaddr += 0x1A;
return resaddr;
}
void uaeserialdev_install (void)
{
uae_u32 functable, datatable;
uae_u32 initcode, openfunc, closefunc, expungefunc;
uae_u32 beginiofunc, abortiofunc;
if (!currprefs.uaeserial)
return;
ROM_uaeserialdev_resname = ds ("uaeserial.device");
ROM_uaeserialdev_resid = ds ("UAE serial.device 0.1");
/* 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_uaeserialdev_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_uaeserialdev_resid);
dw (0x0000); /* end of table */
ROM_uaeserialdev_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_CLEAR);
dw (CMD_START);
dw (CMD_STOP);
dw (CMD_FLUSH);
dw (SDCMD_BREAK);
dw (SDCMD_SETPARAMS);
dw (SDCMD_QUERY);
dw (0);
}
void uaeserialdev_start_threads (void)
{
uae_sem_init (&change_sem, 0, 1);
uae_sem_init (&async_sem, 0, 1);
}
void uaeserialdev_reset (void)
{
if (!currprefs.uaeserial)
return;
dev_reset ();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment