diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/audio/Makefile.objs | 2 | ||||
-rw-r--r-- | hw/audio/adlib.c | 47 | ||||
-rw-r--r-- | hw/audio/fmopl.c | 277 | ||||
-rw-r--r-- | hw/audio/fmopl.h | 175 | ||||
-rw-r--r-- | hw/audio/gus.c | 2 | ||||
-rw-r--r-- | hw/audio/gusemu.h | 22 | ||||
-rw-r--r-- | hw/audio/gusemu_hal.c | 74 | ||||
-rw-r--r-- | hw/audio/gusemu_mixer.c | 28 | ||||
-rw-r--r-- | hw/audio/hda-codec.c | 3 | ||||
-rw-r--r-- | hw/audio/intel-hda.c | 5 | ||||
-rw-r--r-- | hw/audio/intel-hda.h | 2 | ||||
-rw-r--r-- | hw/char/Makefile.objs | 1 | ||||
-rw-r--r-- | hw/char/terminal3270.c | 293 | ||||
-rw-r--r-- | hw/input/hid.c | 4 | ||||
-rw-r--r-- | hw/input/trace-events | 1 | ||||
-rw-r--r-- | hw/openrisc/cputimer.c | 1 | ||||
-rw-r--r-- | hw/s390x/3270-ccw.c | 174 | ||||
-rw-r--r-- | hw/s390x/Makefile.objs | 1 | ||||
-rw-r--r-- | hw/s390x/css.c | 24 | ||||
-rw-r--r-- | hw/s390x/ipl.c | 39 | ||||
-rw-r--r-- | hw/s390x/ipl.h | 3 | ||||
-rw-r--r-- | hw/s390x/s390-virtio-ccw.c | 37 | ||||
-rw-r--r-- | hw/s390x/sclp.c | 9 | ||||
-rw-r--r-- | hw/usb/ccid-card-passthru.c | 2 | ||||
-rw-r--r-- | hw/usb/redirect.c | 2 | ||||
-rw-r--r-- | hw/vfio/common.c | 14 | ||||
-rw-r--r-- | hw/vfio/pci.c | 4 | ||||
-rw-r--r-- | hw/xen/xen-common.c | 2 |
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; |