aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/audio/Makefile.objs2
-rw-r--r--hw/audio/adlib.c47
-rw-r--r--hw/audio/fmopl.c277
-rw-r--r--hw/audio/fmopl.h175
-rw-r--r--hw/audio/gus.c2
-rw-r--r--hw/audio/gusemu.h22
-rw-r--r--hw/audio/gusemu_hal.c74
-rw-r--r--hw/audio/gusemu_mixer.c28
-rw-r--r--hw/audio/hda-codec.c3
-rw-r--r--hw/audio/intel-hda.c5
-rw-r--r--hw/audio/intel-hda.h2
-rw-r--r--hw/char/Makefile.objs1
-rw-r--r--hw/char/terminal3270.c293
-rw-r--r--hw/input/hid.c4
-rw-r--r--hw/input/trace-events1
-rw-r--r--hw/openrisc/cputimer.c1
-rw-r--r--hw/s390x/3270-ccw.c174
-rw-r--r--hw/s390x/Makefile.objs1
-rw-r--r--hw/s390x/css.c24
-rw-r--r--hw/s390x/ipl.c39
-rw-r--r--hw/s390x/ipl.h3
-rw-r--r--hw/s390x/s390-virtio-ccw.c37
-rw-r--r--hw/s390x/sclp.c9
-rw-r--r--hw/usb/ccid-card-passthru.c2
-rw-r--r--hw/usb/redirect.c2
-rw-r--r--hw/vfio/common.c14
-rw-r--r--hw/vfio/pci.c4
-rw-r--r--hw/xen/xen-common.c2
28 files changed, 760 insertions, 488 deletions
diff --git a/hw/audio/Makefile.objs b/hw/audio/Makefile.objs
index 7ce85a2e88..bb6f07a91e 100644
--- a/hw/audio/Makefile.objs
+++ b/hw/audio/Makefile.objs
@@ -14,5 +14,3 @@ common-obj-$(CONFIG_PL041) += pl041.o lm4549.o
common-obj-$(CONFIG_CS4231) += cs4231.o
common-obj-$(CONFIG_MARVELL_88W8618) += marvell_88w8618.o
common-obj-$(CONFIG_MILKYMIST) += milkymist-ac97.o
-
-$(obj)/adlib.o $(obj)/fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c
index 7836446fc8..09b8248cda 100644
--- a/hw/audio/adlib.c
+++ b/hw/audio/adlib.c
@@ -33,11 +33,7 @@
#define ADLIB_KILL_TIMERS 1
-#ifdef HAS_YMF262
-#define ADLIB_DESC "Yamaha YMF262 (OPL3)"
-#else
#define ADLIB_DESC "Yamaha YM3812 (OPL2)"
-#endif
#ifdef DEBUG
#include "qemu/timer.h"
@@ -50,14 +46,8 @@
#define ldebug(...)
#endif
-#ifdef HAS_YMF262
-#include "ymf262.h"
-void YMF262UpdateOneQEMU (int which, INT16 *dst, int length);
-#define SHIFT 2
-#else
#include "fmopl.h"
#define SHIFT 1
-#endif
#define TYPE_ADLIB "adlib"
#define ADLIB(obj) OBJECT_CHECK(AdlibState, (obj), TYPE_ADLIB)
@@ -80,9 +70,7 @@ typedef struct {
SWVoiceOut *voice;
int left, pos, samples;
QEMUAudioTimeStamp ats;
-#ifndef HAS_YMF262
FM_OPL *opl;
-#endif
PortioList port_list;
} AdlibState;
@@ -90,11 +78,7 @@ static AdlibState *glob_adlib;
static void adlib_stop_opl_timer (AdlibState *s, size_t n)
{
-#ifdef HAS_YMF262
- YMF262TimerOver (0, n);
-#else
OPLTimerOver (s->opl, n);
-#endif
s->ticking[n] = 0;
}
@@ -131,11 +115,7 @@ static void adlib_write(void *opaque, uint32_t nport, uint32_t val)
adlib_kill_timers (s);
-#ifdef HAS_YMF262
- YMF262Write (0, a, val);
-#else
OPLWrite (s->opl, a, val);
-#endif
}
static uint32_t adlib_read(void *opaque, uint32_t nport)
@@ -145,12 +125,8 @@ static uint32_t adlib_read(void *opaque, uint32_t nport)
int a = nport & 3;
adlib_kill_timers (s);
-
-#ifdef HAS_YMF262
- data = YMF262Read (0, a);
-#else
data = OPLRead (s->opl, a);
-#endif
+
return data;
}
@@ -240,11 +216,7 @@ static void adlib_callback (void *opaque, int free)
return;
}
-#ifdef HAS_YMF262
- YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples);
-#else
YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples);
-#endif
while (samples) {
written = write_audio (s, samples);
@@ -263,14 +235,10 @@ static void adlib_callback (void *opaque, int free)
static void Adlib_fini (AdlibState *s)
{
-#ifdef HAS_YMF262
- YMF262Shutdown ();
-#else
if (s->opl) {
OPLDestroy (s->opl);
s->opl = NULL;
}
-#endif
g_free(s->mixbuf);
@@ -297,17 +265,7 @@ static void adlib_realizefn (DeviceState *dev, Error **errp)
}
glob_adlib = s;
-#ifdef HAS_YMF262
- if (YMF262Init (1, 14318180, s->freq)) {
- error_setg (errp, "YMF262Init %d failed", s->freq);
- return;
- }
- else {
- YMF262SetTimerHandler (0, timer_handler, 0);
- s->enabled = 1;
- }
-#else
- s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, s->freq);
+ s->opl = OPLCreate (3579545, s->freq);
if (!s->opl) {
error_setg (errp, "OPLCreate %d failed", s->freq);
return;
@@ -316,7 +274,6 @@ static void adlib_realizefn (DeviceState *dev, Error **errp)
OPLSetTimerHandler (s->opl, timer_handler, 0);
s->enabled = 1;
}
-#endif
as.freq = s->freq;
as.nchannels = SHIFT;
diff --git a/hw/audio/fmopl.c b/hw/audio/fmopl.c
index 731110fe86..202f752c5d 100644
--- a/hw/audio/fmopl.c
+++ b/hw/audio/fmopl.c
@@ -30,21 +30,15 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#define HAS_YM3812 1
-
#include "qemu/osdep.h"
#include <math.h>
//#include "driver.h" /* use M.A.M.E. */
#include "fmopl.h"
-
+#include "qemu/osdep.h"
#ifndef PI
#define PI 3.14159265358979323846
#endif
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-#endif
-
/* -------------------- for debug --------------------- */
/* #define OPL_OUTPUT_LOG */
#ifdef OPL_OUTPUT_LOG
@@ -124,7 +118,7 @@ static const int slot_array[32]=
/* key scale level */
/* table is 3dB/OCT , DV converts this in TL step at 6dB/OCT */
#define DV (EG_STEP/2)
-static const UINT32 KSL_TABLE[8*16]=
+static const uint32_t KSL_TABLE[8*16]=
{
/* OCT 0 */
0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
@@ -172,7 +166,7 @@ static const UINT32 KSL_TABLE[8*16]=
/* sustain lebel table (3db per step) */
/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/
#define SC(db) (db*((3/EG_STEP)*(1<<ENV_BITS)))+EG_DST
-static const INT32 SL_TABLE[16]={
+static const int32_t SL_TABLE[16]={
SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7),
SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31)
};
@@ -182,22 +176,22 @@ static const INT32 SL_TABLE[16]={
/* TotalLevel : 48 24 12 6 3 1.5 0.75 (dB) */
/* TL_TABLE[ 0 to TL_MAX ] : plus section */
/* TL_TABLE[ TL_MAX to TL_MAX+TL_MAX-1 ] : minus section */
-static INT32 *TL_TABLE;
+static int32_t *TL_TABLE;
/* pointers to TL_TABLE with sinwave output offset */
-static INT32 **SIN_TABLE;
+static int32_t **SIN_TABLE;
/* LFO table */
-static INT32 *AMS_TABLE;
-static INT32 *VIB_TABLE;
+static int32_t *AMS_TABLE;
+static int32_t *VIB_TABLE;
/* envelope output curve table */
/* attack + decay + OFF */
-static INT32 ENV_CURVE[2*EG_ENT+1];
+static int32_t ENV_CURVE[2*EG_ENT+1];
/* multiple table */
#define ML 2
-static const UINT32 MUL_TABLE[16]= {
+static const uint32_t MUL_TABLE[16]= {
/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 */
0.50*ML, 1.00*ML, 2.00*ML, 3.00*ML, 4.00*ML, 5.00*ML, 6.00*ML, 7.00*ML,
8.00*ML, 9.00*ML,10.00*ML,10.00*ML,12.00*ML,12.00*ML,15.00*ML,15.00*ML
@@ -205,7 +199,7 @@ static const UINT32 MUL_TABLE[16]= {
#undef ML
/* dummy attack / decay rate ( when rate == 0 ) */
-static INT32 RATE_0[16]=
+static int32_t RATE_0[16]=
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
/* -------------------- static state --------------------- */
@@ -221,14 +215,14 @@ static OPL_CH *S_CH;
static OPL_CH *E_CH;
static OPL_SLOT *SLOT7_1, *SLOT7_2, *SLOT8_1, *SLOT8_2;
-static INT32 outd[1];
-static INT32 ams;
-static INT32 vib;
-static INT32 *ams_table;
-static INT32 *vib_table;
-static INT32 amsIncr;
-static INT32 vibIncr;
-static INT32 feedback2; /* connect for SLOT 2 */
+static int32_t outd[1];
+static int32_t ams;
+static int32_t vib;
+static int32_t *ams_table;
+static int32_t *vib_table;
+static int32_t amsIncr;
+static int32_t vibIncr;
+static int32_t feedback2; /* connect for SLOT 2 */
/* log output level */
#define LOG_ERR 3 /* ERROR */
@@ -262,8 +256,6 @@ static inline void OPL_STATUS_SET(FM_OPL *OPL,int flag)
if(OPL->status & OPL->statusmask)
{ /* IRQ on */
OPL->status |= 0x80;
- /* callback user interrupt handler (IRQ is OFF to ON) */
- if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1);
}
}
}
@@ -278,8 +270,6 @@ static inline void OPL_STATUS_RESET(FM_OPL *OPL,int flag)
if (!(OPL->status & OPL->statusmask) )
{
OPL->status &= 0x7f;
- /* callback user interrupt handler (IRQ is ON to OFF) */
- if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0);
}
}
}
@@ -321,7 +311,7 @@ static inline void OPL_KEYOFF(OPL_SLOT *SLOT)
/* ---------- calcrate Envelope Generator & Phase Generator ---------- */
/* return : envelope output */
-static inline UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT )
+static inline uint32_t OPL_CALC_SLOT( OPL_SLOT *SLOT )
{
/* calcrate envelope generator */
if( (SLOT->evc+=SLOT->evs) >= SLOT->eve )
@@ -361,7 +351,7 @@ static inline UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT )
/* set algorithm connection */
static void set_algorithm( OPL_CH *CH)
{
- INT32 *carrier = &outd[0];
+ int32_t *carrier = &outd[0];
CH->connect1 = CH->CON ? carrier : &feedback2;
CH->connect2 = carrier;
}
@@ -453,7 +443,7 @@ static inline void set_sl_rr(FM_OPL *OPL,int slot,int v)
/* ---------- calcrate one of channel ---------- */
static inline void OPL_CALC_CH( OPL_CH *CH )
{
- UINT32 env_out;
+ uint32_t env_out;
OPL_SLOT *SLOT;
feedback2 = 0;
@@ -498,9 +488,9 @@ static inline void OPL_CALC_CH( OPL_CH *CH )
#define WHITE_NOISE_db 6.0
static inline void OPL_CALC_RH( OPL_CH *CH )
{
- UINT32 env_tam,env_sd,env_top,env_hh;
+ uint32_t env_tam,env_sd,env_top,env_hh;
int whitenoise = (rand()&1)*(WHITE_NOISE_db/EG_STEP);
- INT32 tone8;
+ int32_t tone8;
OPL_SLOT *SLOT;
int env_out;
@@ -618,20 +608,20 @@ static int OPLOpenTable( void )
double pom;
/* allocate dynamic tables */
- if( (TL_TABLE = malloc(TL_MAX*2*sizeof(INT32))) == NULL)
+ if( (TL_TABLE = malloc(TL_MAX*2*sizeof(int32_t))) == NULL)
return 0;
- if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(INT32 *))) == NULL)
+ if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(int32_t *))) == NULL)
{
free(TL_TABLE);
return 0;
}
- if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(INT32))) == NULL)
+ if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(int32_t))) == NULL)
{
free(TL_TABLE);
free(SIN_TABLE);
return 0;
}
- if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(INT32))) == NULL)
+ if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(int32_t))) == NULL)
{
free(TL_TABLE);
free(SIN_TABLE);
@@ -763,18 +753,15 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
{
case 0x01:
/* wave selector enable */
- if(OPL->type&OPL_TYPE_WAVESEL)
+ OPL->wavesel = v&0x20;
+ if(!OPL->wavesel)
{
- OPL->wavesel = v&0x20;
- if(!OPL->wavesel)
+ /* preset compatible mode */
+ int c;
+ for(c=0;c<OPL->max_ch;c++)
{
- /* preset compatible mode */
- int c;
- for(c=0;c<OPL->max_ch;c++)
- {
- OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0];
- OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0];
- }
+ OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0];
+ OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0];
}
}
return;
@@ -791,8 +778,8 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
}
else
{ /* set IRQ mask ,timer enable*/
- UINT8 st1 = v&1;
- UINT8 st2 = (v>>1)&1;
+ uint8_t st1 = v&1;
+ uint8_t st2 = (v>>1)&1;
/* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */
OPL_STATUS_RESET(OPL,v&0x78);
OPL_STATUSMASK_SET(OPL,((~v)&0x78)|0x01);
@@ -812,57 +799,6 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
}
}
return;
-#if BUILD_Y8950
- case 0x06: /* Key Board OUT */
- if(OPL->type&OPL_TYPE_KEYBOARD)
- {
- if(OPL->keyboardhandler_w)
- OPL->keyboardhandler_w(OPL->keyboard_param,v);
- else
- LOG(LOG_WAR,("OPL:write unmapped KEYBOARD port\n"));
- }
- return;
- case 0x07: /* DELTA-T control : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */
- if(OPL->type&OPL_TYPE_ADPCM)
- YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
- return;
- case 0x08: /* MODE,DELTA-T : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */
- OPL->mode = v;
- v&=0x1f; /* for DELTA-T unit */
- case 0x09: /* START ADD */
- case 0x0a:
- case 0x0b: /* STOP ADD */
- case 0x0c:
- case 0x0d: /* PRESCALE */
- case 0x0e:
- case 0x0f: /* ADPCM data */
- case 0x10: /* DELTA-N */
- case 0x11: /* DELTA-N */
- case 0x12: /* EG-CTRL */
- if(OPL->type&OPL_TYPE_ADPCM)
- YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
- return;
-#if 0
- case 0x15: /* DAC data */
- case 0x16:
- case 0x17: /* SHIFT */
- return;
- case 0x18: /* I/O CTRL (Direction) */
- if(OPL->type&OPL_TYPE_IO)
- OPL->portDirection = v&0x0f;
- return;
- case 0x19: /* I/O DATA */
- if(OPL->type&OPL_TYPE_IO)
- {
- OPL->portLatch = v;
- if(OPL->porthandler_w)
- OPL->porthandler_w(OPL->port_param,v&OPL->portDirection);
- }
- return;
- case 0x1a: /* PCM data */
- return;
-#endif
-#endif
}
break;
case 0x20: /* am,vib,ksr,eg type,mul */
@@ -891,7 +827,7 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
case 0xbd:
/* amsep,vibdep,r,bd,sd,tom,tc,hh */
{
- UINT8 rkey = OPL->rhythm^v;
+ uint8_t rkey = OPL->rhythm^v;
OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0];
OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0];
OPL->rhythm = v&0x3f;
@@ -1032,20 +968,19 @@ static void OPL_UnLockTable(void)
OPLCloseTable();
}
-#if (BUILD_YM3812 || BUILD_YM3526)
/*******************************************************************************/
/* YM3812 local section */
/*******************************************************************************/
/* ---------- update one of chip ----------- */
-void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
+void YM3812UpdateOne(FM_OPL *OPL, int16_t *buffer, int length)
{
int i;
int data;
- OPLSAMPLE *buf = buffer;
- UINT32 amsCnt = OPL->amsCnt;
- UINT32 vibCnt = OPL->vibCnt;
- UINT8 rhythm = OPL->rhythm&0x20;
+ int16_t *buf = buffer;
+ uint32_t amsCnt = OPL->amsCnt;
+ uint32_t vibCnt = OPL->vibCnt;
+ uint8_t rhythm = OPL->rhythm&0x20;
OPL_CH *CH,*R_CH;
if( (void *)OPL != cur_chip ){
@@ -1095,72 +1030,9 @@ void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
}
#endif
}
-#endif /* (BUILD_YM3812 || BUILD_YM3526) */
-
-#if BUILD_Y8950
-
-void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
-{
- int i;
- int data;
- OPLSAMPLE *buf = buffer;
- UINT32 amsCnt = OPL->amsCnt;
- UINT32 vibCnt = OPL->vibCnt;
- UINT8 rhythm = OPL->rhythm&0x20;
- OPL_CH *CH,*R_CH;
- YM_DELTAT *DELTAT = OPL->deltat;
-
- /* setup DELTA-T unit */
- YM_DELTAT_DECODE_PRESET(DELTAT);
-
- if( (void *)OPL != cur_chip ){
- cur_chip = (void *)OPL;
- /* channel pointers */
- S_CH = OPL->P_CH;
- E_CH = &S_CH[9];
- /* rhythm slot */
- SLOT7_1 = &S_CH[7].SLOT[SLOT1];
- SLOT7_2 = &S_CH[7].SLOT[SLOT2];
- SLOT8_1 = &S_CH[8].SLOT[SLOT1];
- SLOT8_2 = &S_CH[8].SLOT[SLOT2];
- /* LFO state */
- amsIncr = OPL->amsIncr;
- vibIncr = OPL->vibIncr;
- ams_table = OPL->ams_table;
- vib_table = OPL->vib_table;
- }
- R_CH = rhythm ? &S_CH[6] : E_CH;
- for( i=0; i < length ; i++ )
- {
- /* channel A channel B channel C */
- /* LFO */
- ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT];
- vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT];
- outd[0] = 0;
- /* deltaT ADPCM */
- if( DELTAT->portstate )
- YM_DELTAT_ADPCM_CALC(DELTAT);
- /* FM part */
- for(CH=S_CH ; CH < R_CH ; CH++)
- OPL_CALC_CH(CH);
- /* Rythn part */
- if(rhythm)
- OPL_CALC_RH(S_CH);
- /* limit check */
- data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT );
- /* store to sound buffer */
- buf[i] = data >> OPL_OUTSB;
- }
- OPL->amsCnt = amsCnt;
- OPL->vibCnt = vibCnt;
- /* deltaT START flag */
- if( !DELTAT->portstate )
- OPL->status &= 0xfe;
-}
-#endif
/* ---------- reset one of chip ---------- */
-void OPLResetChip(FM_OPL *OPL)
+static void OPLResetChip(FM_OPL *OPL)
{
int c,s;
int i;
@@ -1189,23 +1061,11 @@ void OPLResetChip(FM_OPL *OPL)
CH->SLOT[s].evs = 0;
}
}
-#if BUILD_Y8950
- if(OPL->type&OPL_TYPE_ADPCM)
- {
- YM_DELTAT *DELTAT = OPL->deltat;
-
- DELTAT->freqbase = OPL->freqbase;
- DELTAT->output_pointer = outd;
- DELTAT->portshift = 5;
- DELTAT->output_range = DELTAT_MIXING_LEVEL<<TL_BITS;
- YM_DELTAT_ADPCM_Reset(DELTAT,0);
- }
-#endif
}
/* ---------- Create one of vietual YM3812 ---------- */
/* 'rate' is sampling rate and 'bufsiz' is the size of the */
-FM_OPL *OPLCreate(int type, int clock, int rate)
+FM_OPL *OPLCreate(int clock, int rate)
{
char *ptr;
FM_OPL *OPL;
@@ -1216,9 +1076,6 @@ FM_OPL *OPLCreate(int type, int clock, int rate)
/* allocate OPL state space */
state_size = sizeof(FM_OPL);
state_size += sizeof(OPL_CH)*max_ch;
-#if BUILD_Y8950
- if(type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT);
-#endif
/* allocate memory block */
ptr = malloc(state_size);
if(ptr==NULL) return NULL;
@@ -1226,11 +1083,7 @@ FM_OPL *OPLCreate(int type, int clock, int rate)
memset(ptr,0,state_size);
OPL = (FM_OPL *)ptr; ptr+=sizeof(FM_OPL);
OPL->P_CH = (OPL_CH *)ptr; ptr+=sizeof(OPL_CH)*max_ch;
-#if BUILD_Y8950
- if(type&OPL_TYPE_ADPCM) OPL->deltat = (YM_DELTAT *)ptr; ptr+=sizeof(YM_DELTAT);
-#endif
/* set channel state pointer */
- OPL->type = type;
OPL->clock = clock;
OPL->rate = rate;
OPL->max_ch = max_ch;
@@ -1280,31 +1133,7 @@ void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOff
OPL->TimerHandler = TimerHandler;
OPL->TimerParam = channelOffset;
}
-void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param)
-{
- OPL->IRQHandler = IRQHandler;
- OPL->IRQParam = param;
-}
-void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param)
-{
- OPL->UpdateHandler = UpdateHandler;
- OPL->UpdateParam = param;
-}
-#if BUILD_Y8950
-void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param)
-{
- OPL->porthandler_w = PortHandler_w;
- OPL->porthandler_r = PortHandler_r;
- OPL->port_param = param;
-}
-void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param)
-{
- OPL->keyboardhandler_w = KeyboardHandler_w;
- OPL->keyboardhandler_r = KeyboardHandler_r;
- OPL->keyboard_param = param;
-}
-#endif
/* ---------- YM3812 I/O interface ---------- */
int OPLWrite(FM_OPL *OPL,int a,int v)
{
@@ -1314,7 +1143,6 @@ int OPLWrite(FM_OPL *OPL,int a,int v)
}
else
{ /* data port */
- if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
#ifdef OPL_OUTPUT_LOG
if(opl_dbg_fp)
{
@@ -1338,28 +1166,12 @@ unsigned char OPLRead(FM_OPL *OPL,int a)
switch(OPL->address)
{
case 0x05: /* KeyBoard IN */
- if(OPL->type&OPL_TYPE_KEYBOARD)
- {
- if(OPL->keyboardhandler_r)
- return OPL->keyboardhandler_r(OPL->keyboard_param);
- else {
- LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n"));
- }
- }
return 0;
#if 0
case 0x0f: /* ADPCM-DATA */
return 0;
#endif
case 0x19: /* I/O DATA */
- if(OPL->type&OPL_TYPE_IO)
- {
- if(OPL->porthandler_r)
- return OPL->porthandler_r(OPL->port_param);
- else {
- LOG(LOG_WAR,("OPL:read unmapped I/O port\n"));
- }
- }
return 0;
case 0x1a: /* PCM-DATA */
return 0;
@@ -1380,7 +1192,6 @@ int OPLTimerOver(FM_OPL *OPL,int c)
if( OPL->mode & 0x80 )
{ /* CSM mode total level latch and auto key on */
int ch;
- if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
for(ch=0;ch<9;ch++)
CSMKeyControll( &OPL->P_CH[ch] );
}
diff --git a/hw/audio/fmopl.h b/hw/audio/fmopl.h
index fdda7f9f51..fc9f16b58a 100644
--- a/hw/audio/fmopl.h
+++ b/hw/audio/fmopl.h
@@ -1,174 +1,103 @@
#ifndef FMOPL_H
#define FMOPL_H
-/* --- select emulation chips --- */
-#define BUILD_YM3812 (HAS_YM3812)
-//#define BUILD_YM3526 (HAS_YM3526)
-//#define BUILD_Y8950 (HAS_Y8950)
-
-/* --- system optimize --- */
-/* select bit size of output : 8 or 16 */
-#define OPL_OUTPUT_BIT 16
-
-/* compiler dependence */
-#ifndef OSD_CPU_H
-#define OSD_CPU_H
-typedef unsigned char UINT8; /* unsigned 8bit */
-typedef unsigned short UINT16; /* unsigned 16bit */
-typedef unsigned int UINT32; /* unsigned 32bit */
-typedef signed char INT8; /* signed 8bit */
-typedef signed short INT16; /* signed 16bit */
-typedef signed int INT32; /* signed 32bit */
-#endif
-
-#if (OPL_OUTPUT_BIT==16)
-typedef INT16 OPLSAMPLE;
-#endif
-#if (OPL_OUTPUT_BIT==8)
-typedef unsigned char OPLSAMPLE;
-#endif
-
-
-#if BUILD_Y8950
-#include "ymdeltat.h"
-#endif
+#include <stdint.h>
typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
-typedef void (*OPL_IRQHANDLER)(int param,int irq);
-typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
-typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data);
-typedef unsigned char (*OPL_PORTHANDLER_R)(int param);
/* !!!!! here is private section , do not access there member direct !!!!! */
-#define OPL_TYPE_WAVESEL 0x01 /* waveform select */
-#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */
-#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */
-#define OPL_TYPE_IO 0x08 /* I/O port */
-
/* Saving is necessary for member of the 'R' mark for suspend/resume */
/* ---------- OPL one of slot ---------- */
typedef struct fm_opl_slot {
- INT32 TL; /* total level :TL << 8 */
- INT32 TLL; /* adjusted now TL */
- UINT8 KSR; /* key scale rate :(shift down bit) */
- INT32 *AR; /* attack rate :&AR_TABLE[AR<<2] */
- INT32 *DR; /* decay rate :&DR_TALBE[DR<<2] */
- INT32 SL; /* sustin level :SL_TALBE[SL] */
- INT32 *RR; /* release rate :&DR_TABLE[RR<<2] */
- UINT8 ksl; /* keyscale level :(shift down bits) */
- UINT8 ksr; /* key scale rate :kcode>>KSR */
- UINT32 mul; /* multiple :ML_TABLE[ML] */
- UINT32 Cnt; /* frequency count : */
- UINT32 Incr; /* frequency step : */
+ int32_t TL; /* total level :TL << 8 */
+ int32_t TLL; /* adjusted now TL */
+ uint8_t KSR; /* key scale rate :(shift down bit) */
+ int32_t *AR; /* attack rate :&AR_TABLE[AR<<2] */
+ int32_t *DR; /* decay rate :&DR_TALBE[DR<<2] */
+ int32_t SL; /* sustin level :SL_TALBE[SL] */
+ int32_t *RR; /* release rate :&DR_TABLE[RR<<2] */
+ uint8_t ksl; /* keyscale level :(shift down bits) */
+ uint8_t ksr; /* key scale rate :kcode>>KSR */
+ uint32_t mul; /* multiple :ML_TABLE[ML] */
+ uint32_t Cnt; /* frequency count : */
+ uint32_t Incr; /* frequency step : */
/* envelope generator state */
- UINT8 eg_typ; /* envelope type flag */
- UINT8 evm; /* envelope phase */
- INT32 evc; /* envelope counter */
- INT32 eve; /* envelope counter end point */
- INT32 evs; /* envelope counter step */
- INT32 evsa; /* envelope step for AR :AR[ksr] */
- INT32 evsd; /* envelope step for DR :DR[ksr] */
- INT32 evsr; /* envelope step for RR :RR[ksr] */
+ uint8_t eg_typ; /* envelope type flag */
+ uint8_t evm; /* envelope phase */
+ int32_t evc; /* envelope counter */
+ int32_t eve; /* envelope counter end point */
+ int32_t evs; /* envelope counter step */
+ int32_t evsa; /* envelope step for AR :AR[ksr] */
+ int32_t evsd; /* envelope step for DR :DR[ksr] */
+ int32_t evsr; /* envelope step for RR :RR[ksr] */
/* LFO */
- UINT8 ams; /* ams flag */
- UINT8 vib; /* vibrate flag */
+ uint8_t ams; /* ams flag */
+ uint8_t vib; /* vibrate flag */
/* wave selector */
- INT32 **wavetable;
+ int32_t **wavetable;
}OPL_SLOT;
/* ---------- OPL one of channel ---------- */
typedef struct fm_opl_channel {
OPL_SLOT SLOT[2];
- UINT8 CON; /* connection type */
- UINT8 FB; /* feed back :(shift down bit) */
- INT32 *connect1; /* slot1 output pointer */
- INT32 *connect2; /* slot2 output pointer */
- INT32 op1_out[2]; /* slot1 output for selfeedback */
+ uint8_t CON; /* connection type */
+ uint8_t FB; /* feed back :(shift down bit) */
+ int32_t *connect1; /* slot1 output pointer */
+ int32_t *connect2; /* slot2 output pointer */
+ int32_t op1_out[2]; /* slot1 output for selfeedback */
/* phase generator state */
- UINT32 block_fnum; /* block+fnum : */
- UINT8 kcode; /* key code : KeyScaleCode */
- UINT32 fc; /* Freq. Increment base */
- UINT32 ksl_base; /* KeyScaleLevel Base step */
- UINT8 keyon; /* key on/off flag */
+ uint32_t block_fnum; /* block+fnum : */
+ uint8_t kcode; /* key code : KeyScaleCode */
+ uint32_t fc; /* Freq. Increment base */
+ uint32_t ksl_base; /* KeyScaleLevel Base step */
+ uint8_t keyon; /* key on/off flag */
} OPL_CH;
/* OPL state */
typedef struct fm_opl_f {
- UINT8 type; /* chip type */
int clock; /* master clock (Hz) */
int rate; /* sampling rate (Hz) */
double freqbase; /* frequency base */
double TimerBase; /* Timer base time (==sampling time) */
- UINT8 address; /* address register */
- UINT8 status; /* status flag */
- UINT8 statusmask; /* status mask */
- UINT32 mode; /* Reg.08 : CSM , notesel,etc. */
+ uint8_t address; /* address register */
+ uint8_t status; /* status flag */
+ uint8_t statusmask; /* status mask */
+ uint32_t mode; /* Reg.08 : CSM , notesel,etc. */
/* Timer */
int T[2]; /* timer counter */
- UINT8 st[2]; /* timer enable */
+ uint8_t st[2]; /* timer enable */
/* FM channel slots */
OPL_CH *P_CH; /* pointer of CH */
int max_ch; /* maximum channel */
/* Rhythm sention */
- UINT8 rhythm; /* Rhythm mode , key flag */
-#if BUILD_Y8950
- /* Delta-T ADPCM unit (Y8950) */
- YM_DELTAT *deltat; /* DELTA-T ADPCM */
-#endif
- /* Keyboard / I/O interface unit (Y8950) */
- UINT8 portDirection;
- UINT8 portLatch;
- OPL_PORTHANDLER_R porthandler_r;
- OPL_PORTHANDLER_W porthandler_w;
- int port_param;
- OPL_PORTHANDLER_R keyboardhandler_r;
- OPL_PORTHANDLER_W keyboardhandler_w;
- int keyboard_param;
+ uint8_t rhythm; /* Rhythm mode , key flag */
/* time tables */
- INT32 AR_TABLE[75]; /* atttack rate tables */
- INT32 DR_TABLE[75]; /* decay rate tables */
- UINT32 FN_TABLE[1024]; /* fnumber -> increment counter */
+ int32_t AR_TABLE[75]; /* atttack rate tables */
+ int32_t DR_TABLE[75]; /* decay rate tables */
+ uint32_t FN_TABLE[1024]; /* fnumber -> increment counter */
/* LFO */
- INT32 *ams_table;
- INT32 *vib_table;
- INT32 amsCnt;
- INT32 amsIncr;
- INT32 vibCnt;
- INT32 vibIncr;
+ int32_t *ams_table;
+ int32_t *vib_table;
+ int32_t amsCnt;
+ int32_t amsIncr;
+ int32_t vibCnt;
+ int32_t vibIncr;
/* wave selector enable flag */
- UINT8 wavesel;
+ uint8_t wavesel;
/* external event callback handler */
OPL_TIMERHANDLER TimerHandler; /* TIMER handler */
int TimerParam; /* TIMER parameter */
- OPL_IRQHANDLER IRQHandler; /* IRQ handler */
- int IRQParam; /* IRQ parameter */
- OPL_UPDATEHANDLER UpdateHandler; /* stream update handler */
- int UpdateParam; /* stream update parameter */
} FM_OPL;
/* ---------- Generic interface section ---------- */
-#define OPL_TYPE_YM3526 (0)
-#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL)
-#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO)
-
-FM_OPL *OPLCreate(int type, int clock, int rate);
+FM_OPL *OPLCreate(int clock, int rate);
void OPLDestroy(FM_OPL *OPL);
void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset);
-void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param);
-void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param);
-/* Y8950 port handlers */
-void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param);
-void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param);
-void OPLResetChip(FM_OPL *OPL);
int OPLWrite(FM_OPL *OPL,int a,int v);
unsigned char OPLRead(FM_OPL *OPL,int a);
int OPLTimerOver(FM_OPL *OPL,int c);
-/* YM3626/YM3812 local section */
-void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
-
-void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
-
+void YM3812UpdateOne(FM_OPL *OPL, int16_t *buffer, int length);
#endif
diff --git a/hw/audio/gus.c b/hw/audio/gus.c
index 3d08a6576a..ec103a4db9 100644
--- a/hw/audio/gus.c
+++ b/hw/audio/gus.c
@@ -53,7 +53,7 @@ typedef struct GUSState {
uint32_t freq;
uint32_t port;
int pos, left, shift, irqs;
- GUSsample *mixbuf;
+ int16_t *mixbuf;
uint8_t himem[1024 * 1024 + 32 + 4096];
int samples;
SWVoiceOut *voice;
diff --git a/hw/audio/gusemu.h b/hw/audio/gusemu.h
index 9aec7bf8e7..ab591eefb7 100644
--- a/hw/audio/gusemu.h
+++ b/hw/audio/gusemu.h
@@ -25,26 +25,10 @@
#ifndef GUSEMU_H
#define GUSEMU_H
-/* data types (need to be adjusted if neither a VC6 nor a C99 compatible compiler is used) */
-
-#if defined _WIN32 && defined _MSC_VER /* doesn't support other win32 compilers yet, do it yourself... */
- typedef unsigned char GUSbyte;
- typedef unsigned short GUSword;
- typedef unsigned int GUSdword;
- typedef signed char GUSchar;
- typedef signed short GUSsample;
-#else
- typedef int8_t GUSchar;
- typedef uint8_t GUSbyte;
- typedef uint16_t GUSword;
- typedef uint32_t GUSdword;
- typedef int16_t GUSsample;
-#endif
-
typedef struct _GUSEmuState
{
- GUSbyte *himemaddr; /* 1024*1024 bytes used for storing uploaded samples (+32 additional bytes for read padding) */
- GUSbyte *gusdatapos; /* (gusdataend-gusdata) bytes used for storing emulated GF1/mixer register states (32*32+4 bytes in initial GUSemu32 version) */
+ uint8_t *himemaddr; /* 1024*1024 bytes used for storing uploaded samples (+32 additional bytes for read padding) */
+ uint8_t *gusdatapos; /* (gusdataend-gusdata) bytes used for storing emulated GF1/mixer register states (32*32+4 bytes in initial GUSemu32 version) */
uint32_t gusirq;
uint32_t gusdma;
unsigned int timer1fraction;
@@ -92,7 +76,7 @@ void gus_dma_transferdata(GUSEmuState *state, char *dma_addr, unsigned int count
/* If the interrupts are asynchronous, it may be needed to use a separate thread mixing into a temporary */
/* audio buffer in order to avoid quality loss caused by large numsamples and elapsed_time values. */
-void gus_mixvoices(GUSEmuState *state, unsigned int playback_freq, unsigned int numsamples, GUSsample *bufferpos);
+void gus_mixvoices(GUSEmuState *state, unsigned int playback_freq, unsigned int numsamples, int16_t *bufferpos);
/* recommended range: 10 < numsamples < 100 */
/* lower values may result in increased rounding error, higher values often cause audible timing delays */
diff --git a/hw/audio/gusemu_hal.c b/hw/audio/gusemu_hal.c
index 973d6b9f4f..1150fc4426 100644
--- a/hw/audio/gusemu_hal.c
+++ b/hw/audio/gusemu_hal.c
@@ -31,15 +31,15 @@
#include "gusemu.h"
#define GUSregb(position) (* (gusptr+(position)))
-#define GUSregw(position) (*(GUSword *) (gusptr+(position)))
-#define GUSregd(position) (*(GUSdword *)(gusptr+(position)))
+#define GUSregw(position) (*(uint16_t *) (gusptr+(position)))
+#define GUSregd(position) (*(uint16_t *)(gusptr+(position)))
/* size given in bytes */
unsigned int gus_read(GUSEmuState * state, int port, int size)
{
int value_read = 0;
- GUSbyte *gusptr;
+ uint8_t *gusptr;
gusptr = state->gusdatapos;
GUSregd(portaccesses)++;
@@ -125,7 +125,7 @@ unsigned int gus_read(GUSEmuState * state, int port, int size)
if (!GUSregb(IRQStatReg2x6))
GUS_irqclear(state, state->gusirq);
}
- return (GUSbyte) value_read;
+ return (uint8_t) value_read;
/* DramDMAmemPosReg */
/* case 0x42: value_read=GUSregw(GUS42DMAStart); break;*/
/* 43h+44h write only */
@@ -173,12 +173,12 @@ unsigned int gus_read(GUSEmuState * state, int port, int size)
value_read = value_read >> 8;
value_read &= 0xff;
}
- return (GUSword) value_read;
+ return (uint16_t) value_read;
/* case 0x306: */ /* Mixer/Version info */
/* return 0xff; */ /* Pre 3.6 boards, ICS mixer NOT present */
case 0x307: /* DRAMaccess */
{
- GUSbyte *adr;
+ uint8_t *adr;
adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
return *adr;
}
@@ -189,14 +189,14 @@ unsigned int gus_read(GUSEmuState * state, int port, int size)
void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
{
- GUSbyte *gusptr;
+ uint8_t *gusptr;
gusptr = state->gusdatapos;
GUSregd(portaccesses)++;
switch (port & 0xff0f)
{
case 0x200: /* MixerCtrlReg */
- GUSregb(MixerCtrlReg2x0) = (GUSbyte) data;
+ GUSregb(MixerCtrlReg2x0) = (uint8_t) data;
break;
case 0x206: /* IRQstatReg / SB2x6IRQ */
if (GUSregb(GUS45TimerCtrl) & 0x20) /* SB IRQ enabled? -> set 2x6IRQ bit */
@@ -208,7 +208,7 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
break;
case 0x308: /* AdLib 388h */
case 0x208: /* AdLibCommandReg */
- GUSregb(AdLibCommand2xA) = (GUSbyte) data;
+ GUSregb(AdLibCommand2xA) = (uint8_t) data;
break;
case 0x309: /* AdLib 389h */
case 0x209: /* AdLibDataReg */
@@ -217,11 +217,11 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
if (data & 0x80)
GUSregb(TimerStatus2x8) &= 0x1f; /* AdLib IRQ reset? -> clear maskable adl. timer int regs */
else
- GUSregb(TimerDataReg2x9) = (GUSbyte) data;
+ GUSregb(TimerDataReg2x9) = (uint8_t) data;
}
else
{
- GUSregb(AdLibData2x9) = (GUSbyte) data;
+ GUSregb(AdLibData2x9) = (uint8_t) data;
if (GUSregb(GUS45TimerCtrl) & 0x02)
{
GUSregb(TimerStatus2x8) |= 0x01;
@@ -231,16 +231,16 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
}
break;
case 0x20A:
- GUSregb(AdLibStatus2x8) = (GUSbyte) data;
+ GUSregb(AdLibStatus2x8) = (uint8_t) data;
break; /* AdLibStatus2x8 */
case 0x20B: /* GUS hidden registers */
switch (GUSregb(RegCtrl_2xF) & 0x7)
{
case 0:
if (GUSregb(MixerCtrlReg2x0) & 0x40)
- GUSregb(IRQ_2xB) = (GUSbyte) data; /* control register select bit */
+ GUSregb(IRQ_2xB) = (uint8_t) data; /* control register select bit */
else
- GUSregb(DMA_2xB) = (GUSbyte) data;
+ GUSregb(DMA_2xB) = (uint8_t) data;
break;
/* case 1-4: general purpose emulation regs */
case 5: /* clear stat reg 2xF */
@@ -249,7 +249,7 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
GUS_irqclear(state, state->gusirq);
break;
case 6: /* Jumper reg (Joystick/MIDI enable) */
- GUSregb(Jumper_2xB) = (GUSbyte) data;
+ GUSregb(Jumper_2xB) = (uint8_t) data;
break;
default:;
}
@@ -262,20 +262,20 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
GUS_irqrequest(state, state->gusirq, 1);
}
case 0x20D: /* SB2xCd no IRQ */
- GUSregb(SB2xCd) = (GUSbyte) data;
+ GUSregb(SB2xCd) = (uint8_t) data;
break;
case 0x20E: /* SB2xE */
- GUSregb(SB2xE) = (GUSbyte) data;
+ GUSregb(SB2xE) = (uint8_t) data;
break;
case 0x20F:
- GUSregb(RegCtrl_2xF) = (GUSbyte) data;
+ GUSregb(RegCtrl_2xF) = (uint8_t) data;
break; /* CtrlReg2xF */
case 0x302: /* VoiceSelReg */
- GUSregb(VoiceSelReg3x2) = (GUSbyte) data;
+ GUSregb(VoiceSelReg3x2) = (uint8_t) data;
break;
case 0x303: /* FunkSelReg */
- GUSregb(FunkSelReg3x3) = (GUSbyte) data;
- if ((GUSbyte) data == 0x8f) /* set irqstatreg, get voicereg and clear IRQ */
+ GUSregb(FunkSelReg3x3) = (uint8_t) data;
+ if ((uint8_t) data == 0x8f) /* set irqstatreg, get voicereg and clear IRQ */
{
int voice;
if (GUSregd(voicewavetableirq)) /* WavetableIRQ */
@@ -318,15 +318,15 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
case 0x304:
case 0x305:
{
- GUSword writedata = (GUSword) data;
- GUSword readmask = 0x0000;
+ uint16_t writedata = (uint16_t) data;
+ uint16_t readmask = 0x0000;
if (size == 1)
{
readmask = 0xff00;
writedata &= 0xff;
if ((port & 0xff0f) == 0x305)
{
- writedata = (GUSword) (writedata << 8);
+ writedata = (uint16_t) (writedata << 8);
readmask = 0x00ff;
}
}
@@ -353,17 +353,17 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
break; /* reset flag active? */
offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f);
offset += (GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /* = Voice*32 + Funktion*2 */
- GUSregw(offset) = (GUSword) ((GUSregw(offset) & readmask) | writedata);
+ GUSregw(offset) = (uint16_t) ((GUSregw(offset) & readmask) | writedata);
}
break;
/* voice unspecific functions */
case 0x0e: /* NumVoices */
- GUSregb(NumVoices) = (GUSbyte) data;
+ GUSregb(NumVoices) = (uint8_t) data;
break;
/* case 0x0f: */ /* read only */
/* common functions */
case 0x41: /* DramDMAContrReg */
- GUSregb(GUS41DMACtrl) = (GUSbyte) data;
+ GUSregb(GUS41DMACtrl) = (uint8_t) data;
if (data & 0x01)
GUS_dmarequest(state);
break;
@@ -380,7 +380,7 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
(GUSregd(GUSDRAMPOS24bit) & 0xffff) | ((data & 0x0f) << 16);
break;
case 0x45: /* TCtrlReg */
- GUSregb(GUS45TimerCtrl) = (GUSbyte) data;
+ GUSregb(GUS45TimerCtrl) = (uint8_t) data;
if (!(data & 0x20))
GUSregb(TimerStatus2x8) &= 0xe7; /* sb IRQ dis? -> clear 2x8/2xC sb IRQ flags */
if (!(data & 0x02))
@@ -434,18 +434,18 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
GUS_irqclear(state, state->gusirq);
break;
case 0x46: /* Counter1 */
- GUSregb(GUS46Counter1) = (GUSbyte) data;
+ GUSregb(GUS46Counter1) = (uint8_t) data;
break;
case 0x47: /* Counter2 */
- GUSregb(GUS47Counter2) = (GUSbyte) data;
+ GUSregb(GUS47Counter2) = (uint8_t) data;
break;
/* case 0x48: */ /* sampling freq reg not emulated (same as interwave) */
case 0x49: /* SampCtrlReg */
- GUSregb(GUS49SampCtrl) = (GUSbyte) data;
+ GUSregb(GUS49SampCtrl) = (uint8_t) data;
break;
/* case 0x4b: */ /* joystick trim not emulated */
case 0x4c: /* GUSreset */
- GUSregb(GUS4cReset) = (GUSbyte) data;
+ GUSregb(GUS4cReset) = (uint8_t) data;
if (!(GUSregb(GUS4cReset) & 1)) /* reset... */
{
GUSregd(voicewavetableirq) = 0;
@@ -471,9 +471,9 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
break;
case 0x307: /* DRAMaccess */
{
- GUSbyte *adr;
+ uint8_t *adr;
adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
- *adr = (GUSbyte) data;
+ *adr = (uint8_t) data;
}
break;
}
@@ -510,7 +510,7 @@ void gus_dma_transferdata(GUSEmuState * state, char *dma_addr, unsigned int coun
char *srcaddr;
char *destaddr;
char msbmask = 0;
- GUSbyte *gusptr;
+ uint8_t *gusptr;
gusptr = state->gusdatapos;
srcaddr = dma_addr; /* system memory address */
@@ -521,8 +521,8 @@ void gus_dma_transferdata(GUSEmuState * state, char *dma_addr, unsigned int coun
destaddr = (char *) state->himemaddr + offset; /* wavetable RAM address */
}
- GUSregw(GUS42DMAStart) += (GUSword) (count >> 4); /* ToDo: add 16bit GUS page limit? */
- GUSregb(GUS50DMAHigh) = (GUSbyte) ((count + GUSregb(GUS50DMAHigh)) & 0xf); /* ToDo: add 16bit GUS page limit? */
+ GUSregw(GUS42DMAStart) += (uint16_t) (count >> 4); /* ToDo: add 16bit GUS page limit? */
+ GUSregb(GUS50DMAHigh) = (uint8_t) ((count + GUSregb(GUS50DMAHigh)) & 0xf); /* ToDo: add 16bit GUS page limit? */
if (GUSregb(GUS41DMACtrl) & 0x02) /* direction, 0 := sysram->gusram */
{
diff --git a/hw/audio/gusemu_mixer.c b/hw/audio/gusemu_mixer.c
index 701e8fb0ed..00b9861b92 100644
--- a/hw/audio/gusemu_mixer.c
+++ b/hw/audio/gusemu_mixer.c
@@ -27,26 +27,26 @@
#include "gustate.h"
#define GUSregb(position) (* (gusptr+(position)))
-#define GUSregw(position) (*(GUSword *) (gusptr+(position)))
-#define GUSregd(position) (*(GUSdword *)(gusptr+(position)))
+#define GUSregw(position) (*(uint16_t *) (gusptr+(position)))
+#define GUSregd(position) (*(uint16_t *)(gusptr+(position)))
-#define GUSvoice(position) (*(GUSword *)(voiceptr+(position)))
+#define GUSvoice(position) (*(uint16_t *)(voiceptr+(position)))
/* samples are always 16bit stereo (4 bytes each, first right then left interleaved) */
void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int numsamples,
- GUSsample *bufferpos)
+ int16_t *bufferpos)
{
/* note that byte registers are stored in the upper half of each voice register! */
- GUSbyte *gusptr;
+ uint8_t *gusptr;
int Voice;
- GUSword *voiceptr;
+ uint16_t *voiceptr;
unsigned int count;
for (count = 0; count < numsamples * 2; count++)
*(bufferpos + count) = 0; /* clear */
gusptr = state->gusdatapos;
- voiceptr = (GUSword *) gusptr;
+ voiceptr = (uint16_t *) gusptr;
if (!(GUSregb(GUS4cReset) & 0x01)) /* reset flag active? */
return;
@@ -85,16 +85,16 @@ void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int
if (GUSvoice(wVSRControl) & 0x400) /* 16bit */
{
int offset = ((CurrPos >> 9) & 0xc0000) + (((CurrPos >> 9) & 0x1ffff) << 1);
- GUSchar *adr;
- adr = (GUSchar *) state->himemaddr + offset;
+ int8_t *adr;
+ adr = (int8_t *) state->himemaddr + offset;
sample1 = (*adr & 0xff) + (*(adr + 1) * 256);
sample2 = (*(adr + 2) & 0xff) + (*(adr + 2 + 1) * 256);
}
else /* 8bit */
{
int offset = (CurrPos >> 9) & 0xfffff;
- GUSchar *adr;
- adr = (GUSchar *) state->himemaddr + offset;
+ int8_t *adr;
+ adr = (int8_t *) state->himemaddr + offset;
sample1 = (*adr) * 256;
sample2 = (*(adr + 1)) * 256;
}
@@ -171,8 +171,8 @@ void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int
}
/* mix samples into buffer */
- *(bufferpos + 2 * sample) += (GUSsample) ((sample1 * PanningPos) >> 4); /* right */
- *(bufferpos + 2 * sample + 1) += (GUSsample) ((sample1 * (15 - PanningPos)) >> 4); /* left */
+ *(bufferpos + 2 * sample) += (int16_t) ((sample1 * PanningPos) >> 4); /* right */
+ *(bufferpos + 2 * sample + 1) += (int16_t) ((sample1 * (15 - PanningPos)) >> 4); /* left */
}
/* write back voice and volume */
GUSvoice(wVSRCurrVol) = Volume32 / 32;
@@ -187,7 +187,7 @@ void gus_irqgen(GUSEmuState * state, unsigned int elapsed_time)
/* time given in microseconds */
{
int requestedIRQs = 0;
- GUSbyte *gusptr;
+ uint8_t *gusptr;
gusptr = state->gusdatapos;
if (GUSregb(TimerDataReg2x9) & 1) /* start timer 1 (80us decrement rate) */
{
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c
index 52d4640e60..5402cd196c 100644
--- a/hw/audio/hda-codec.c
+++ b/hw/audio/hda-codec.c
@@ -520,7 +520,7 @@ static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc)
return 0;
}
-static int hda_audio_exit(HDACodecDevice *hda)
+static void hda_audio_exit(HDACodecDevice *hda)
{
HDAAudioState *a = HDA_AUDIO(hda);
HDAAudioStream *st;
@@ -539,7 +539,6 @@ static int hda_audio_exit(HDACodecDevice *hda)
}
}
AUD_remove_card(&a->card);
- return 0;
}
static int hda_audio_post_load(void *opaque, int version)
diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c
index 537face94d..2c497eb174 100644
--- a/hw/audio/intel-hda.c
+++ b/hw/audio/intel-hda.c
@@ -70,7 +70,7 @@ static void hda_codec_dev_realize(DeviceState *qdev, Error **errp)
}
}
-static int hda_codec_dev_exit(DeviceState *qdev)
+static void hda_codec_dev_unrealize(DeviceState *qdev, Error **errp)
{
HDACodecDevice *dev = HDA_CODEC_DEVICE(qdev);
HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev);
@@ -78,7 +78,6 @@ static int hda_codec_dev_exit(DeviceState *qdev)
if (cdc->exit) {
cdc->exit(dev);
}
- return 0;
}
HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
@@ -1318,7 +1317,7 @@ static void hda_codec_device_class_init(ObjectClass *klass, void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
k->realize = hda_codec_dev_realize;
- k->exit = hda_codec_dev_exit;
+ k->unrealize = hda_codec_dev_unrealize;
set_bit(DEVICE_CATEGORY_SOUND, k->categories);
k->bus_type = TYPE_HDA_BUS;
k->props = hda_props;
diff --git a/hw/audio/intel-hda.h b/hw/audio/intel-hda.h
index d784bcf5fc..53b78da4df 100644
--- a/hw/audio/intel-hda.h
+++ b/hw/audio/intel-hda.h
@@ -38,7 +38,7 @@ typedef struct HDACodecDeviceClass
DeviceClass parent_class;
int (*init)(HDACodecDevice *dev);
- int (*exit)(HDACodecDevice *dev);
+ void (*exit)(HDACodecDevice *dev);
void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data);
void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running, bool output);
} HDACodecDeviceClass;
diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
index 725fdc46f4..55fcb68fd2 100644
--- a/hw/char/Makefile.objs
+++ b/hw/char/Makefile.objs
@@ -29,3 +29,4 @@ common-obj-$(CONFIG_MILKYMIST) += milkymist-uart.o
common-obj-$(CONFIG_SCLPCONSOLE) += sclpconsole.o sclpconsole-lm.o
obj-$(CONFIG_VIRTIO) += virtio-serial-bus.o
+obj-$(CONFIG_TERMINAL3270) += terminal3270.o
diff --git a/hw/char/terminal3270.c b/hw/char/terminal3270.c
new file mode 100644
index 0000000000..b2dda01baa
--- /dev/null
+++ b/hw/char/terminal3270.c
@@ -0,0 +1,293 @@
+/*
+ * Terminal 3270 implementation
+ *
+ * Copyright 2017 IBM Corp.
+ *
+ * Authors: Yang Chen <bjcyang@linux.vnet.ibm.com>
+ * Jing Liu <liujbjl@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "sysemu/char.h"
+#include "hw/s390x/3270-ccw.h"
+
+/* Enough spaces for different window sizes. */
+#define INPUT_BUFFER_SIZE 1000
+/*
+ * 1 for header, 1024*2 for datastream, 2 for tail
+ * Reserve enough spaces for telnet IAC escape.
+ */
+#define OUTPUT_BUFFER_SIZE 2051
+
+typedef struct Terminal3270 {
+ EmulatedCcw3270Device cdev;
+ CharBackend chr;
+ uint8_t inv[INPUT_BUFFER_SIZE];
+ uint8_t outv[OUTPUT_BUFFER_SIZE];
+ int in_len;
+ int out_len;
+ bool handshake_done;
+ guint timer_tag;
+} Terminal3270;
+
+#define TYPE_TERMINAL_3270 "x-terminal3270"
+#define TERMINAL_3270(obj) \
+ OBJECT_CHECK(Terminal3270, (obj), TYPE_TERMINAL_3270)
+
+static int terminal_can_read(void *opaque)
+{
+ Terminal3270 *t = opaque;
+
+ return INPUT_BUFFER_SIZE - t->in_len;
+}
+
+/*
+ * Protocol handshake done,
+ * signal guest by an unsolicited DE irq.
+ */
+static void TN3270_handshake_done(Terminal3270 *t)
+{
+ CcwDevice *ccw_dev = CCW_DEVICE(t);
+ SubchDev *sch = ccw_dev->sch;
+
+ t->handshake_done = true;
+ sch->curr_status.scsw.dstat = SCSW_DSTAT_DEVICE_END;
+ css_conditional_io_interrupt(sch);
+}
+
+/*
+ * Called when the interval is timeout to detect
+ * if the client is still alive by Timing Mark.
+ */
+static gboolean send_timing_mark_cb(gpointer opaque)
+{
+ Terminal3270 *t = opaque;
+ const uint8_t timing[] = {0xff, 0xfd, 0x06};
+
+ qemu_chr_fe_write_all(&t->chr, timing, sizeof(timing));
+ return true;
+}
+
+/*
+ * Receive inbound data from socket.
+ * For data given to guest, drop the data boundary IAC, IAC_EOR.
+ * TODO:
+ * Using "Reset" key on x3270 may result multiple commands in one packet.
+ * This usually happens when the user meets a poor traffic of the network.
+ * As of now, for such case, we simply terminate the connection,
+ * and we should come back here later with a better solution.
+ */
+static void terminal_read(void *opaque, const uint8_t *buf, int size)
+{
+ Terminal3270 *t = opaque;
+ CcwDevice *ccw_dev = CCW_DEVICE(t);
+ SubchDev *sch = ccw_dev->sch;
+ int end;
+
+ assert(size <= (INPUT_BUFFER_SIZE - t->in_len));
+
+ if (t->timer_tag) {
+ g_source_remove(t->timer_tag);
+ t->timer_tag = 0;
+ }
+ t->timer_tag = g_timeout_add_seconds(600, send_timing_mark_cb, t);
+
+ memcpy(&t->inv[t->in_len], buf, size);
+ t->in_len += size;
+ if (t->in_len < 2) {
+ return;
+ }
+
+ if (!t->handshake_done) {
+ /*
+ * Receiving Terminal Type is the last step of handshake.
+ * The data format: IAC SB Terminal-Type IS <terminal type> IAC SE
+ * The code for Terminal-Type is 0x18, for IS is 0.
+ * Simply check the data format and mark handshake_done.
+ */
+ if (t->in_len > 6 && t->inv[2] == 0x18 && t->inv[3] == 0x0 &&
+ t->inv[t->in_len - 2] == IAC && t->inv[t->in_len - 1] == IAC_SE) {
+ TN3270_handshake_done(t);
+ t->in_len = 0;
+ }
+ return;
+ }
+
+ for (end = 0; end < t->in_len - 1; end++) {
+ if (t->inv[end] == IAC && t->inv[end + 1] == IAC_EOR) {
+ break;
+ }
+ }
+ if (end == t->in_len - 2) {
+ /* Data is valid for consuming. */
+ t->in_len -= 2;
+ sch->curr_status.scsw.dstat = SCSW_DSTAT_ATTENTION;
+ css_conditional_io_interrupt(sch);
+ } else if (end < t->in_len - 2) {
+ /* "Reset" key is used. */
+ qemu_chr_fe_disconnect(&t->chr);
+ } else {
+ /* Gathering data. */
+ return;
+ }
+}
+
+static void chr_event(void *opaque, int event)
+{
+ Terminal3270 *t = opaque;
+ CcwDevice *ccw_dev = CCW_DEVICE(t);
+ SubchDev *sch = ccw_dev->sch;
+
+ /* Ensure the initial status correct, always reset them. */
+ t->in_len = 0;
+ t->out_len = 0;
+ t->handshake_done = false;
+ if (t->timer_tag) {
+ g_source_remove(t->timer_tag);
+ t->timer_tag = 0;
+ }
+
+ switch (event) {
+ case CHR_EVENT_OPENED:
+ /*
+ * 3270 does handshake firstly by the negotiate options in
+ * char-socket.c. Once qemu receives the terminal-type of the
+ * client, mark handshake done and trigger everything rolling again.
+ */
+ t->timer_tag = g_timeout_add_seconds(600, send_timing_mark_cb, t);
+ break;
+ case CHR_EVENT_CLOSED:
+ sch->curr_status.scsw.dstat = SCSW_DSTAT_DEVICE_END;
+ css_conditional_io_interrupt(sch);
+ break;
+ }
+}
+
+static void terminal_init(EmulatedCcw3270Device *dev, Error **errp)
+{
+ Terminal3270 *t = TERMINAL_3270(dev);
+ static bool terminal_available;
+
+ if (terminal_available) {
+ error_setg(errp, "Multiple 3270 terminals are not supported.");
+ return;
+ }
+ terminal_available = true;
+ qemu_chr_fe_set_handlers(&t->chr, terminal_can_read,
+ terminal_read, chr_event, t, NULL, true);
+}
+
+static int read_payload_3270(EmulatedCcw3270Device *dev, uint32_t cda,
+ uint16_t count)
+{
+ Terminal3270 *t = TERMINAL_3270(dev);
+ int len;
+
+ len = MIN(count, t->in_len);
+ cpu_physical_memory_write(cda, t->inv, len);
+ t->in_len -= len;
+
+ return len;
+}
+
+/* TN3270 uses binary transmission, which needs escape IAC to IAC IAC */
+static int insert_IAC_escape_char(uint8_t *outv, int out_len)
+{
+ int IAC_num = 0, new_out_len, i, j;
+
+ for (i = 0; i < out_len; i++) {
+ if (outv[i] == IAC) {
+ IAC_num++;
+ }
+ }
+ if (IAC_num == 0) {
+ return out_len;
+ }
+ new_out_len = out_len + IAC_num;
+ for (i = out_len - 1, j = new_out_len - 1; j > i && i >= 0; i--, j--) {
+ outv[j] = outv[i];
+ if (outv[i] == IAC) {
+ outv[--j] = IAC;
+ }
+ }
+ return new_out_len;
+}
+
+/*
+ * Write 3270 outbound to socket.
+ * Return the count of 3270 data field if succeeded, zero if failed.
+ */
+static int write_payload_3270(EmulatedCcw3270Device *dev, uint8_t cmd,
+ uint32_t cda, uint16_t count)
+{
+ Terminal3270 *t = TERMINAL_3270(dev);
+ int retval = 0;
+
+ assert(count <= (OUTPUT_BUFFER_SIZE - 3) / 2);
+
+ if (!t->handshake_done) {
+ if (!(t->outv[0] == IAC && t->outv[1] != IAC)) {
+ /*
+ * Before having finished 3270 negotiation,
+ * sending outbound data except protocol options is prohibited.
+ */
+ return 0;
+ }
+ }
+ if (!qemu_chr_fe_get_driver(&t->chr)) {
+ /* We just say we consumed all data if there's no backend. */
+ return count;
+ }
+ t->outv[0] = cmd;
+ cpu_physical_memory_read(cda, &t->outv[1], count);
+ t->out_len = count + 1;
+
+ t->out_len = insert_IAC_escape_char(t->outv, t->out_len);
+ t->outv[t->out_len++] = IAC;
+ t->outv[t->out_len++] = IAC_EOR;
+
+ retval = qemu_chr_fe_write_all(&t->chr, t->outv, t->out_len);
+ return (retval <= 0) ? 0 : (retval - 3);
+}
+
+static Property terminal_properties[] = {
+ DEFINE_PROP_CHR("chardev", Terminal3270, chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static const VMStateDescription terminal3270_vmstate = {
+ .name = TYPE_TERMINAL_3270,
+ .unmigratable = 1,
+};
+
+static void terminal_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ EmulatedCcw3270Class *ck = EMULATED_CCW_3270_CLASS(klass);
+
+ dc->props = terminal_properties;
+ dc->vmsd = &terminal3270_vmstate;
+ ck->init = terminal_init;
+ ck->read_payload_3270 = read_payload_3270;
+ ck->write_payload_3270 = write_payload_3270;
+}
+
+static const TypeInfo ccw_terminal_info = {
+ .name = TYPE_TERMINAL_3270,
+ .parent = TYPE_EMULATED_CCW_3270,
+ .instance_size = sizeof(Terminal3270),
+ .class_init = terminal_class_init,
+ .class_size = sizeof(EmulatedCcw3270Class),
+};
+
+static void register_types(void)
+{
+ type_register_static(&ccw_terminal_info);
+}
+
+type_init(register_types)
diff --git a/hw/input/hid.c b/hw/input/hid.c
index fa9cc4c616..93887ecc43 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -256,6 +256,10 @@ static void hid_keyboard_process_keycode(HIDState *hs)
slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
keycode = hs->kbd.keycodes[slot];
+ if (!hs->n) {
+ trace_hid_kbd_queue_empty();
+ }
+
key = keycode & 0x7f;
index = key | ((hs->kbd.modifiers & (1 << 8)) >> 1);
hid_code = hid_usage_keys[index];
diff --git a/hw/input/trace-events b/hw/input/trace-events
index f3bfbede5c..5a87818b49 100644
--- a/hw/input/trace-events
+++ b/hw/input/trace-events
@@ -24,6 +24,7 @@ milkymist_softusb_pulse_irq(void) "Pulse IRQ"
# hw/input/hid.c
hid_kbd_queue_full(void) "queue full"
+hid_kbd_queue_empty(void) "queue empty"
# hw/input/virtio
virtio_input_queue_full(void) "queue full"
diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c
index a98c799de6..febc469170 100644
--- a/hw/openrisc/cputimer.c
+++ b/hw/openrisc/cputimer.c
@@ -61,6 +61,7 @@ void cpu_openrisc_timer_update(OpenRISCCPU *cpu)
}
next = now + (uint64_t)wait * TIMER_PERIOD;
timer_mod(cpu->env.timer, next);
+ qemu_cpu_kick(CPU(cpu));
}
void cpu_openrisc_count_start(OpenRISCCPU *cpu)
diff --git a/hw/s390x/3270-ccw.c b/hw/s390x/3270-ccw.c
new file mode 100644
index 0000000000..a7a5b412e4
--- /dev/null
+++ b/hw/s390x/3270-ccw.c
@@ -0,0 +1,174 @@
+/*
+ * Emulated ccw-attached 3270 implementation
+ *
+ * Copyright 2017 IBM Corp.
+ * Author(s): Yang Chen <bjcyang@linux.vnet.ibm.com>
+ * Jing Liu <liujbjl@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/module.h"
+#include "cpu.h"
+#include "hw/s390x/css.h"
+#include "hw/s390x/css-bridge.h"
+#include "hw/s390x/3270-ccw.h"
+
+/* Handle READ ccw commands from guest */
+static int handle_payload_3270_read(EmulatedCcw3270Device *dev, CCW1 *ccw)
+{
+ EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev);
+ CcwDevice *ccw_dev = CCW_DEVICE(dev);
+ int len;
+
+ if (!ccw->cda) {
+ return -EFAULT;
+ }
+
+ len = ck->read_payload_3270(dev, ccw->cda, ccw->count);
+ ccw_dev->sch->curr_status.scsw.count = ccw->count - len;
+
+ return 0;
+}
+
+/* Handle WRITE ccw commands to write data to client */
+static int handle_payload_3270_write(EmulatedCcw3270Device *dev, CCW1 *ccw)
+{
+ EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev);
+ CcwDevice *ccw_dev = CCW_DEVICE(dev);
+ int len;
+
+ if (!ccw->cda) {
+ return -EFAULT;
+ }
+
+ len = ck->write_payload_3270(dev, ccw->cmd_code, ccw->cda, ccw->count);
+
+ if (len <= 0) {
+ return -EIO;
+ }
+
+ ccw_dev->sch->curr_status.scsw.count = ccw->count - len;
+ return 0;
+}
+
+static int emulated_ccw_3270_cb(SubchDev *sch, CCW1 ccw)
+{
+ int rc = 0;
+ EmulatedCcw3270Device *dev = sch->driver_data;
+
+ switch (ccw.cmd_code) {
+ case TC_WRITESF:
+ case TC_WRITE:
+ case TC_EWRITE:
+ case TC_EWRITEA:
+ rc = handle_payload_3270_write(dev, &ccw);
+ break;
+ case TC_RDBUF:
+ case TC_READMOD:
+ rc = handle_payload_3270_read(dev, &ccw);
+ break;
+ default:
+ rc = -ENOSYS;
+ break;
+ }
+
+ if (rc == -EIO) {
+ /* I/O error, specific devices generate specific conditions */
+ SCSW *s = &sch->curr_status.scsw;
+
+ sch->curr_status.scsw.dstat = SCSW_DSTAT_UNIT_CHECK;
+ sch->sense_data[0] = 0x40; /* intervention-req */
+ s->ctrl &= ~SCSW_ACTL_START_PEND;
+ s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
+ s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
+ SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
+ }
+
+ return rc;
+}
+
+static void emulated_ccw_3270_realize(DeviceState *ds, Error **errp)
+{
+ uint16_t chpid;
+ EmulatedCcw3270Device *dev = EMULATED_CCW_3270(ds);
+ EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev);
+ CcwDevice *cdev = CCW_DEVICE(ds);
+ CCWDeviceClass *cdk = CCW_DEVICE_GET_CLASS(cdev);
+ SubchDev *sch = css_create_virtual_sch(cdev->devno, errp);
+ Error *err = NULL;
+
+ if (!sch) {
+ return;
+ }
+
+ if (!ck->init) {
+ goto out_err;
+ }
+
+ sch->driver_data = dev;
+ cdev->sch = sch;
+ chpid = css_find_free_chpid(sch->cssid);
+
+ if (chpid > MAX_CHPID) {
+ error_setg(&err, "No available chpid to use.");
+ goto out_err;
+ }
+
+ sch->id.reserved = 0xff;
+ sch->id.cu_type = EMULATED_CCW_3270_CU_TYPE;
+ css_sch_build_virtual_schib(sch, (uint8_t)chpid,
+ EMULATED_CCW_3270_CHPID_TYPE);
+ sch->ccw_cb = emulated_ccw_3270_cb;
+
+ ck->init(dev, &err);
+ if (err) {
+ goto out_err;
+ }
+
+ cdk->realize(cdev, &err);
+ if (err) {
+ goto out_err;
+ }
+
+ return;
+
+out_err:
+ error_propagate(errp, err);
+ css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
+ cdev->sch = NULL;
+ g_free(sch);
+}
+
+static Property emulated_ccw_3270_properties[] = {
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void emulated_ccw_3270_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->props = emulated_ccw_3270_properties;
+ dc->bus_type = TYPE_VIRTUAL_CSS_BUS;
+ dc->realize = emulated_ccw_3270_realize;
+ dc->hotpluggable = false;
+}
+
+static const TypeInfo emulated_ccw_3270_info = {
+ .name = TYPE_EMULATED_CCW_3270,
+ .parent = TYPE_CCW_DEVICE,
+ .instance_size = sizeof(EmulatedCcw3270Device),
+ .class_init = emulated_ccw_3270_class_init,
+ .class_size = sizeof(EmulatedCcw3270Class),
+ .abstract = true,
+};
+
+static void emulated_ccw_register(void)
+{
+ type_register_static(&emulated_ccw_3270_info);
+}
+
+type_init(emulated_ccw_register)
diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs
index 41ac4ec325..36bd4b1645 100644
--- a/hw/s390x/Makefile.objs
+++ b/hw/s390x/Makefile.objs
@@ -7,6 +7,7 @@ obj-y += sclpcpu.o
obj-y += ipl.o
obj-y += css.o
obj-y += s390-virtio-ccw.o
+obj-y += 3270-ccw.o
obj-y += virtio-ccw.o
obj-y += css-bridge.o
obj-y += ccw-device.o
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index c03bb20bc9..15c4f4b249 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -576,6 +576,9 @@ static void sch_handle_start_func(SubchDev *sch, ORB *orb)
s->dstat = SCSW_DSTAT_CHANNEL_END | SCSW_DSTAT_DEVICE_END;
s->cpa = sch->channel_prog + 8;
break;
+ case -EIO:
+ /* I/O errors, status depends on specific devices */
+ break;
case -ENOSYS:
/* unsupported command, generate unit check (command reject) */
s->ctrl &= ~SCSW_ACTL_START_PEND;
@@ -1302,6 +1305,27 @@ bool css_schid_final(int m, uint8_t cssid, uint8_t ssid, uint16_t schid)
(MAX_SCHID + 1) / sizeof(unsigned long));
}
+unsigned int css_find_free_chpid(uint8_t cssid)
+{
+ CssImage *css = channel_subsys.css[cssid];
+ unsigned int chpid;
+
+ if (!css) {
+ return MAX_CHPID + 1;
+ }
+
+ for (chpid = 0; chpid <= MAX_CHPID; chpid++) {
+ /* skip reserved chpid */
+ if (chpid == VIRTIO_CCW_CHPID) {
+ continue;
+ }
+ if (!css->chpids[chpid].in_use) {
+ return chpid;
+ }
+ }
+ return MAX_CHPID + 1;
+}
+
static int css_add_virtual_chpid(uint8_t cssid, uint8_t chpid, uint8_t type)
{
CssImage *css;
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 7978c7d52a..75d3c681a4 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -17,8 +17,10 @@
#include "cpu.h"
#include "elf.h"
#include "hw/loader.h"
+#include "hw/boards.h"
#include "hw/s390x/virtio-ccw.h"
#include "hw/s390x/css.h"
+#include "hw/s390x/ebcdic.h"
#include "ipl.h"
#include "qemu/error-report.h"
@@ -243,12 +245,17 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
ipl->iplb.pbt = S390_IPL_TYPE_CCW;
ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
- return true;
} else if (sd) {
SCSIBus *bus = scsi_bus_from_device(sd);
VirtIOSCSI *vdev = container_of(bus, VirtIOSCSI, bus);
VirtIOSCSICcw *scsi_ccw = container_of(vdev, VirtIOSCSICcw, vdev);
- CcwDevice *ccw_dev = CCW_DEVICE(scsi_ccw);
+ CcwDevice *ccw_dev;
+
+ ccw_dev = (CcwDevice *)object_dynamic_cast(OBJECT(scsi_ccw),
+ TYPE_CCW_DEVICE);
+ if (!ccw_dev) { /* It might be a PCI device instead */
+ return false;
+ }
ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN);
ipl->iplb.blk0_len =
@@ -259,13 +266,39 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
ipl->iplb.scsi.channel = cpu_to_be16(sd->channel);
ipl->iplb.scsi.devno = cpu_to_be16(ccw_dev->sch->devno);
ipl->iplb.scsi.ssid = ccw_dev->sch->ssid & 3;
- return true;
+ } else {
+ return false; /* unknown device */
}
+
+ if (!s390_ipl_set_loadparm(ipl->iplb.loadparm)) {
+ ipl->iplb.flags |= DIAG308_FLAGS_LP_VALID;
+ }
+ return true;
}
return false;
}
+int s390_ipl_set_loadparm(uint8_t *loadparm)
+{
+ MachineState *machine = MACHINE(qdev_get_machine());
+ char *lp = object_property_get_str(OBJECT(machine), "loadparm", NULL);
+
+ if (lp) {
+ int i;
+
+ /* lp is an uppercase string without leading/embedded spaces */
+ for (i = 0; i < 8 && lp[i]; i++) {
+ loadparm[i] = ascii2ebcdic[(uint8_t) lp[i]];
+ }
+
+ g_free(lp);
+ return 0;
+ }
+
+ return -1;
+}
+
static int load_netboot_image(Error **errp)
{
S390IPLState *ipl = get_ipl_device();
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 46930e4c64..8a705e0428 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -57,6 +57,8 @@ struct IplBlockQemuScsi {
} QEMU_PACKED;
typedef struct IplBlockQemuScsi IplBlockQemuScsi;
+#define DIAG308_FLAGS_LP_VALID 0x80
+
union IplParameterBlock {
struct {
uint32_t len;
@@ -82,6 +84,7 @@ union IplParameterBlock {
} QEMU_PACKED;
typedef union IplParameterBlock IplParameterBlock;
+int s390_ipl_set_loadparm(uint8_t *loadparm);
void s390_ipl_update_diag308(IplParameterBlock *iplb);
void s390_ipl_prepare_cpu(S390CPU *cpu);
IplParameterBlock *s390_ipl_get_iplb(void);
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 04bd0ebe40..fdd4384ff0 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -274,6 +274,36 @@ bool cpu_model_allowed(void)
return true;
}
+static char *machine_get_loadparm(Object *obj, Error **errp)
+{
+ S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
+
+ return g_memdup(ms->loadparm, sizeof(ms->loadparm));
+}
+
+static void machine_set_loadparm(Object *obj, const char *val, Error **errp)
+{
+ S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
+ int i;
+
+ for (i = 0; i < sizeof(ms->loadparm) && val[i]; i++) {
+ uint8_t c = toupper(val[i]); /* mimic HMC */
+
+ if (('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || (c == '.') ||
+ (c == ' ')) {
+ ms->loadparm[i] = c;
+ } else {
+ error_setg(errp, "LOADPARM: invalid character '%c' (ASCII 0x%02x)",
+ c, c);
+ return;
+ }
+ }
+
+ for (; i < sizeof(ms->loadparm); i++) {
+ ms->loadparm[i] = ' '; /* pad right with spaces */
+ }
+}
+
static inline void s390_machine_initfn(Object *obj)
{
object_property_add_bool(obj, "aes-key-wrap",
@@ -291,6 +321,13 @@ static inline void s390_machine_initfn(Object *obj)
"enable/disable DEA key wrapping using the CPACF wrapping key",
NULL);
object_property_set_bool(obj, true, "dea-key-wrap", NULL);
+ object_property_add_str(obj, "loadparm",
+ machine_get_loadparm, machine_set_loadparm, NULL);
+ object_property_set_description(obj, "loadparm",
+ "Up to 8 chars in set of [A-Za-z0-9. ] (lower case chars converted"
+ " to upper case) to pass to machine loader, boot manager,"
+ " and guest kernel",
+ NULL);
}
static const TypeInfo ccw_machine_info = {
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
index e741da1141..b4f6dd58dd 100644
--- a/hw/s390x/sclp.c
+++ b/hw/s390x/sclp.c
@@ -23,6 +23,7 @@
#include "hw/s390x/sclp.h"
#include "hw/s390x/event-facility.h"
#include "hw/s390x/s390-pci-bus.h"
+#include "hw/s390x/ipl.h"
static inline SCLPDevice *get_sclp_device(void)
{
@@ -57,6 +58,7 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
int cpu_count = 0;
int rnsize, rnmax;
int slots = MIN(machine->ram_slots, s390_get_memslot_count(kvm_state));
+ IplParameterBlock *ipib = s390_ipl_get_iplb();
CPU_FOREACH(cpu) {
cpu_count++;
@@ -129,6 +131,13 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
read_info->rnmax2 = cpu_to_be64(rnmax);
}
+ if (ipib && ipib->flags & DIAG308_FLAGS_LP_VALID) {
+ memcpy(&read_info->loadparm, &ipib->loadparm,
+ sizeof(read_info->loadparm));
+ } else {
+ s390_ipl_set_loadparm(read_info->loadparm);
+ }
+
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
}
diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c
index daab0d56cf..a41b0d6ec5 100644
--- a/hw/usb/ccid-card-passthru.c
+++ b/hw/usb/ccid-card-passthru.c
@@ -267,7 +267,7 @@ static void ccid_card_vscard_drop_connection(PassthruState *card)
Chardev *chr = qemu_chr_fe_get_driver(&card->cs);
qemu_chr_fe_deinit(&card->cs);
- qemu_chr_delete(chr);
+ object_unparent(OBJECT(chr));
card->vscard_in_pos = card->vscard_in_hdr = 0;
}
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 0efe62f725..b001a27f05 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -1433,7 +1433,7 @@ static void usbredir_unrealize(USBDevice *udev, Error **errp)
Chardev *chr = qemu_chr_fe_get_driver(&dev->cs);
qemu_chr_fe_deinit(&dev->cs);
- qemu_chr_delete(chr);
+ object_unparent(OBJECT(chr));
/* Note must be done after qemu_chr_close, as that causes a close event */
qemu_bh_delete(dev->chardev_close_bh);
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 6b33b9f55d..a8f12eeb35 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -119,6 +119,9 @@ void vfio_region_write(void *opaque, hwaddr addr,
case 4:
buf.dword = cpu_to_le32(data);
break;
+ case 8:
+ buf.qword = cpu_to_le64(data);
+ break;
default:
hw_error("vfio: unsupported write size, %d bytes", size);
break;
@@ -173,6 +176,9 @@ uint64_t vfio_region_read(void *opaque,
case 4:
data = le32_to_cpu(buf.dword);
break;
+ case 8:
+ data = le64_to_cpu(buf.qword);
+ break;
default:
hw_error("vfio: unsupported read size, %d bytes", size);
break;
@@ -190,6 +196,14 @@ const MemoryRegionOps vfio_region_ops = {
.read = vfio_region_read,
.write = vfio_region_write,
.endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 8,
+ },
};
/*
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 03a3d01549..32aca77701 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -2625,8 +2625,8 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
if (!(~vdev->host.domain || ~vdev->host.bus ||
~vdev->host.slot || ~vdev->host.function)) {
error_setg(errp, "No provided host device");
- error_append_hint(errp, "Use -vfio-pci,host=DDDD:BB:DD.F "
- "or -vfio-pci,sysfsdev=PATH_TO_DEVICE\n");
+ error_append_hint(errp, "Use -device vfio-pci,host=DDDD:BB:DD.F "
+ "or -device vfio-pci,sysfsdev=PATH_TO_DEVICE\n");
return;
}
vdev->vbasedev.sysfsdev =
diff --git a/hw/xen/xen-common.c b/hw/xen/xen-common.c
index ae76150e8a..a9055e9eba 100644
--- a/hw/xen/xen-common.c
+++ b/hw/xen/xen-common.c
@@ -38,7 +38,7 @@ static int store_dev_info(int domid, Chardev *cs, const char *string)
int ret = -1;
/* Only continue if we're talking to a pty. */
- if (strncmp(cs->filename, "pty:", 4)) {
+ if (!CHARDEV_IS_PTY(cs)) {
return 0;
}
pts = cs->filename + 4;