149ab747fSPaolo Bonzini /* 249ab747fSPaolo Bonzini * QEMU Crystal CS4231 audio chip emulation 349ab747fSPaolo Bonzini * 449ab747fSPaolo Bonzini * Copyright (c) 2006 Fabrice Bellard 549ab747fSPaolo Bonzini * 649ab747fSPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy 749ab747fSPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal 849ab747fSPaolo Bonzini * in the Software without restriction, including without limitation the rights 949ab747fSPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1049ab747fSPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is 1149ab747fSPaolo Bonzini * furnished to do so, subject to the following conditions: 1249ab747fSPaolo Bonzini * 1349ab747fSPaolo Bonzini * The above copyright notice and this permission notice shall be included in 1449ab747fSPaolo Bonzini * all copies or substantial portions of the Software. 1549ab747fSPaolo Bonzini * 1649ab747fSPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1749ab747fSPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1849ab747fSPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1949ab747fSPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2049ab747fSPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2149ab747fSPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 2249ab747fSPaolo Bonzini * THE SOFTWARE. 2349ab747fSPaolo Bonzini */ 24*6086a565SPeter Maydell #include "qemu/osdep.h" 2549ab747fSPaolo Bonzini #include "hw/hw.h" 2649ab747fSPaolo Bonzini #include "hw/audio/audio.h" 2749ab747fSPaolo Bonzini #include "audio/audio.h" 2849ab747fSPaolo Bonzini #include "hw/isa/isa.h" 2949ab747fSPaolo Bonzini #include "hw/qdev.h" 3049ab747fSPaolo Bonzini #include "qemu/timer.h" 3149ab747fSPaolo Bonzini 3249ab747fSPaolo Bonzini /* 3349ab747fSPaolo Bonzini Missing features: 3449ab747fSPaolo Bonzini ADC 3549ab747fSPaolo Bonzini Loopback 3649ab747fSPaolo Bonzini Timer 3749ab747fSPaolo Bonzini ADPCM 3849ab747fSPaolo Bonzini More... 3949ab747fSPaolo Bonzini */ 4049ab747fSPaolo Bonzini 4149ab747fSPaolo Bonzini /* #define DEBUG */ 4249ab747fSPaolo Bonzini /* #define DEBUG_XLAW */ 4349ab747fSPaolo Bonzini 4449ab747fSPaolo Bonzini static struct { 4549ab747fSPaolo Bonzini int aci_counter; 4649ab747fSPaolo Bonzini } conf = {1}; 4749ab747fSPaolo Bonzini 4849ab747fSPaolo Bonzini #ifdef DEBUG 4949ab747fSPaolo Bonzini #define dolog(...) AUD_log ("cs4231a", __VA_ARGS__) 5049ab747fSPaolo Bonzini #else 5149ab747fSPaolo Bonzini #define dolog(...) 5249ab747fSPaolo Bonzini #endif 5349ab747fSPaolo Bonzini 5449ab747fSPaolo Bonzini #define lwarn(...) AUD_log ("cs4231a", "warning: " __VA_ARGS__) 5549ab747fSPaolo Bonzini #define lerr(...) AUD_log ("cs4231a", "error: " __VA_ARGS__) 5649ab747fSPaolo Bonzini 5749ab747fSPaolo Bonzini #define CS_REGS 16 5849ab747fSPaolo Bonzini #define CS_DREGS 32 5949ab747fSPaolo Bonzini 60a3dcca56SAndreas Färber #define TYPE_CS4231A "cs4231a" 61a3dcca56SAndreas Färber #define CS4231A(obj) OBJECT_CHECK (CSState, (obj), TYPE_CS4231A) 62a3dcca56SAndreas Färber 6349ab747fSPaolo Bonzini typedef struct CSState { 6449ab747fSPaolo Bonzini ISADevice dev; 6549ab747fSPaolo Bonzini QEMUSoundCard card; 6649ab747fSPaolo Bonzini MemoryRegion ioports; 6749ab747fSPaolo Bonzini qemu_irq pic; 6849ab747fSPaolo Bonzini uint32_t regs[CS_REGS]; 6949ab747fSPaolo Bonzini uint8_t dregs[CS_DREGS]; 7049ab747fSPaolo Bonzini uint32_t irq; 7149ab747fSPaolo Bonzini uint32_t dma; 7249ab747fSPaolo Bonzini uint32_t port; 7349ab747fSPaolo Bonzini int shift; 7449ab747fSPaolo Bonzini int dma_running; 7549ab747fSPaolo Bonzini int audio_free; 7649ab747fSPaolo Bonzini int transferred; 7749ab747fSPaolo Bonzini int aci_counter; 7849ab747fSPaolo Bonzini SWVoiceOut *voice; 7949ab747fSPaolo Bonzini int16_t *tab; 8049ab747fSPaolo Bonzini } CSState; 8149ab747fSPaolo Bonzini 8249ab747fSPaolo Bonzini #define MODE2 (1 << 6) 8349ab747fSPaolo Bonzini #define MCE (1 << 6) 8449ab747fSPaolo Bonzini #define PMCE (1 << 4) 8549ab747fSPaolo Bonzini #define CMCE (1 << 5) 8649ab747fSPaolo Bonzini #define TE (1 << 6) 8749ab747fSPaolo Bonzini #define PEN (1 << 0) 8849ab747fSPaolo Bonzini #define INT (1 << 0) 8949ab747fSPaolo Bonzini #define IEN (1 << 1) 9049ab747fSPaolo Bonzini #define PPIO (1 << 6) 9149ab747fSPaolo Bonzini #define PI (1 << 4) 9249ab747fSPaolo Bonzini #define CI (1 << 5) 9349ab747fSPaolo Bonzini #define TI (1 << 6) 9449ab747fSPaolo Bonzini 9549ab747fSPaolo Bonzini enum { 9649ab747fSPaolo Bonzini Index_Address, 9749ab747fSPaolo Bonzini Index_Data, 9849ab747fSPaolo Bonzini Status, 9949ab747fSPaolo Bonzini PIO_Data 10049ab747fSPaolo Bonzini }; 10149ab747fSPaolo Bonzini 10249ab747fSPaolo Bonzini enum { 10349ab747fSPaolo Bonzini Left_ADC_Input_Control, 10449ab747fSPaolo Bonzini Right_ADC_Input_Control, 10549ab747fSPaolo Bonzini Left_AUX1_Input_Control, 10649ab747fSPaolo Bonzini Right_AUX1_Input_Control, 10749ab747fSPaolo Bonzini Left_AUX2_Input_Control, 10849ab747fSPaolo Bonzini Right_AUX2_Input_Control, 10949ab747fSPaolo Bonzini Left_DAC_Output_Control, 11049ab747fSPaolo Bonzini Right_DAC_Output_Control, 11149ab747fSPaolo Bonzini FS_And_Playback_Data_Format, 11249ab747fSPaolo Bonzini Interface_Configuration, 11349ab747fSPaolo Bonzini Pin_Control, 11449ab747fSPaolo Bonzini Error_Status_And_Initialization, 11549ab747fSPaolo Bonzini MODE_And_ID, 11649ab747fSPaolo Bonzini Loopback_Control, 11749ab747fSPaolo Bonzini Playback_Upper_Base_Count, 11849ab747fSPaolo Bonzini Playback_Lower_Base_Count, 11949ab747fSPaolo Bonzini Alternate_Feature_Enable_I, 12049ab747fSPaolo Bonzini Alternate_Feature_Enable_II, 12149ab747fSPaolo Bonzini Left_Line_Input_Control, 12249ab747fSPaolo Bonzini Right_Line_Input_Control, 12349ab747fSPaolo Bonzini Timer_Low_Base, 12449ab747fSPaolo Bonzini Timer_High_Base, 12549ab747fSPaolo Bonzini RESERVED, 12649ab747fSPaolo Bonzini Alternate_Feature_Enable_III, 12749ab747fSPaolo Bonzini Alternate_Feature_Status, 12849ab747fSPaolo Bonzini Version_Chip_ID, 12949ab747fSPaolo Bonzini Mono_Input_And_Output_Control, 13049ab747fSPaolo Bonzini RESERVED_2, 13149ab747fSPaolo Bonzini Capture_Data_Format, 13249ab747fSPaolo Bonzini RESERVED_3, 13349ab747fSPaolo Bonzini Capture_Upper_Base_Count, 13449ab747fSPaolo Bonzini Capture_Lower_Base_Count 13549ab747fSPaolo Bonzini }; 13649ab747fSPaolo Bonzini 13749ab747fSPaolo Bonzini static int freqs[2][8] = { 13849ab747fSPaolo Bonzini { 8000, 16000, 27420, 32000, -1, -1, 48000, 9000 }, 13949ab747fSPaolo Bonzini { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 } 14049ab747fSPaolo Bonzini }; 14149ab747fSPaolo Bonzini 14249ab747fSPaolo Bonzini /* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */ 14349ab747fSPaolo Bonzini static int16_t MuLawDecompressTable[256] = 14449ab747fSPaolo Bonzini { 14549ab747fSPaolo Bonzini -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956, 14649ab747fSPaolo Bonzini -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764, 14749ab747fSPaolo Bonzini -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412, 14849ab747fSPaolo Bonzini -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316, 14949ab747fSPaolo Bonzini -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, 15049ab747fSPaolo Bonzini -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, 15149ab747fSPaolo Bonzini -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, 15249ab747fSPaolo Bonzini -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, 15349ab747fSPaolo Bonzini -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, 15449ab747fSPaolo Bonzini -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, 15549ab747fSPaolo Bonzini -876, -844, -812, -780, -748, -716, -684, -652, 15649ab747fSPaolo Bonzini -620, -588, -556, -524, -492, -460, -428, -396, 15749ab747fSPaolo Bonzini -372, -356, -340, -324, -308, -292, -276, -260, 15849ab747fSPaolo Bonzini -244, -228, -212, -196, -180, -164, -148, -132, 15949ab747fSPaolo Bonzini -120, -112, -104, -96, -88, -80, -72, -64, 16049ab747fSPaolo Bonzini -56, -48, -40, -32, -24, -16, -8, 0, 16149ab747fSPaolo Bonzini 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, 16249ab747fSPaolo Bonzini 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, 16349ab747fSPaolo Bonzini 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, 16449ab747fSPaolo Bonzini 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, 16549ab747fSPaolo Bonzini 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, 16649ab747fSPaolo Bonzini 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, 16749ab747fSPaolo Bonzini 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, 16849ab747fSPaolo Bonzini 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, 16949ab747fSPaolo Bonzini 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, 17049ab747fSPaolo Bonzini 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, 17149ab747fSPaolo Bonzini 876, 844, 812, 780, 748, 716, 684, 652, 17249ab747fSPaolo Bonzini 620, 588, 556, 524, 492, 460, 428, 396, 17349ab747fSPaolo Bonzini 372, 356, 340, 324, 308, 292, 276, 260, 17449ab747fSPaolo Bonzini 244, 228, 212, 196, 180, 164, 148, 132, 17549ab747fSPaolo Bonzini 120, 112, 104, 96, 88, 80, 72, 64, 17649ab747fSPaolo Bonzini 56, 48, 40, 32, 24, 16, 8, 0 17749ab747fSPaolo Bonzini }; 17849ab747fSPaolo Bonzini 17949ab747fSPaolo Bonzini static int16_t ALawDecompressTable[256] = 18049ab747fSPaolo Bonzini { 18149ab747fSPaolo Bonzini -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, 18249ab747fSPaolo Bonzini -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, 18349ab747fSPaolo Bonzini -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, 18449ab747fSPaolo Bonzini -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, 18549ab747fSPaolo Bonzini -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944, 18649ab747fSPaolo Bonzini -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136, 18749ab747fSPaolo Bonzini -11008,-10496,-12032,-11520,-8960, -8448, -9984, -9472, 18849ab747fSPaolo Bonzini -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568, 18949ab747fSPaolo Bonzini -344, -328, -376, -360, -280, -264, -312, -296, 19049ab747fSPaolo Bonzini -472, -456, -504, -488, -408, -392, -440, -424, 19149ab747fSPaolo Bonzini -88, -72, -120, -104, -24, -8, -56, -40, 19249ab747fSPaolo Bonzini -216, -200, -248, -232, -152, -136, -184, -168, 19349ab747fSPaolo Bonzini -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, 19449ab747fSPaolo Bonzini -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, 19549ab747fSPaolo Bonzini -688, -656, -752, -720, -560, -528, -624, -592, 19649ab747fSPaolo Bonzini -944, -912, -1008, -976, -816, -784, -880, -848, 19749ab747fSPaolo Bonzini 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, 19849ab747fSPaolo Bonzini 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, 19949ab747fSPaolo Bonzini 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, 20049ab747fSPaolo Bonzini 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, 20149ab747fSPaolo Bonzini 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, 20249ab747fSPaolo Bonzini 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, 20349ab747fSPaolo Bonzini 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, 20449ab747fSPaolo Bonzini 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, 20549ab747fSPaolo Bonzini 344, 328, 376, 360, 280, 264, 312, 296, 20649ab747fSPaolo Bonzini 472, 456, 504, 488, 408, 392, 440, 424, 20749ab747fSPaolo Bonzini 88, 72, 120, 104, 24, 8, 56, 40, 20849ab747fSPaolo Bonzini 216, 200, 248, 232, 152, 136, 184, 168, 20949ab747fSPaolo Bonzini 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, 21049ab747fSPaolo Bonzini 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, 21149ab747fSPaolo Bonzini 688, 656, 752, 720, 560, 528, 624, 592, 21249ab747fSPaolo Bonzini 944, 912, 1008, 976, 816, 784, 880, 848 21349ab747fSPaolo Bonzini }; 21449ab747fSPaolo Bonzini 215a3dcca56SAndreas Färber static void cs4231a_reset (DeviceState *dev) 21649ab747fSPaolo Bonzini { 217a3dcca56SAndreas Färber CSState *s = CS4231A (dev); 21849ab747fSPaolo Bonzini 21949ab747fSPaolo Bonzini s->regs[Index_Address] = 0x40; 22049ab747fSPaolo Bonzini s->regs[Index_Data] = 0x00; 22149ab747fSPaolo Bonzini s->regs[Status] = 0x00; 22249ab747fSPaolo Bonzini s->regs[PIO_Data] = 0x00; 22349ab747fSPaolo Bonzini 22449ab747fSPaolo Bonzini s->dregs[Left_ADC_Input_Control] = 0x00; 22549ab747fSPaolo Bonzini s->dregs[Right_ADC_Input_Control] = 0x00; 22649ab747fSPaolo Bonzini s->dregs[Left_AUX1_Input_Control] = 0x88; 22749ab747fSPaolo Bonzini s->dregs[Right_AUX1_Input_Control] = 0x88; 22849ab747fSPaolo Bonzini s->dregs[Left_AUX2_Input_Control] = 0x88; 22949ab747fSPaolo Bonzini s->dregs[Right_AUX2_Input_Control] = 0x88; 23049ab747fSPaolo Bonzini s->dregs[Left_DAC_Output_Control] = 0x80; 23149ab747fSPaolo Bonzini s->dregs[Right_DAC_Output_Control] = 0x80; 23249ab747fSPaolo Bonzini s->dregs[FS_And_Playback_Data_Format] = 0x00; 23349ab747fSPaolo Bonzini s->dregs[Interface_Configuration] = 0x08; 23449ab747fSPaolo Bonzini s->dregs[Pin_Control] = 0x00; 23549ab747fSPaolo Bonzini s->dregs[Error_Status_And_Initialization] = 0x00; 23649ab747fSPaolo Bonzini s->dregs[MODE_And_ID] = 0x8a; 23749ab747fSPaolo Bonzini s->dregs[Loopback_Control] = 0x00; 23849ab747fSPaolo Bonzini s->dregs[Playback_Upper_Base_Count] = 0x00; 23949ab747fSPaolo Bonzini s->dregs[Playback_Lower_Base_Count] = 0x00; 24049ab747fSPaolo Bonzini s->dregs[Alternate_Feature_Enable_I] = 0x00; 24149ab747fSPaolo Bonzini s->dregs[Alternate_Feature_Enable_II] = 0x00; 24249ab747fSPaolo Bonzini s->dregs[Left_Line_Input_Control] = 0x88; 24349ab747fSPaolo Bonzini s->dregs[Right_Line_Input_Control] = 0x88; 24449ab747fSPaolo Bonzini s->dregs[Timer_Low_Base] = 0x00; 24549ab747fSPaolo Bonzini s->dregs[Timer_High_Base] = 0x00; 24649ab747fSPaolo Bonzini s->dregs[RESERVED] = 0x00; 24749ab747fSPaolo Bonzini s->dregs[Alternate_Feature_Enable_III] = 0x00; 24849ab747fSPaolo Bonzini s->dregs[Alternate_Feature_Status] = 0x00; 24949ab747fSPaolo Bonzini s->dregs[Version_Chip_ID] = 0xa0; 25049ab747fSPaolo Bonzini s->dregs[Mono_Input_And_Output_Control] = 0xa0; 25149ab747fSPaolo Bonzini s->dregs[RESERVED_2] = 0x00; 25249ab747fSPaolo Bonzini s->dregs[Capture_Data_Format] = 0x00; 25349ab747fSPaolo Bonzini s->dregs[RESERVED_3] = 0x00; 25449ab747fSPaolo Bonzini s->dregs[Capture_Upper_Base_Count] = 0x00; 25549ab747fSPaolo Bonzini s->dregs[Capture_Lower_Base_Count] = 0x00; 25649ab747fSPaolo Bonzini } 25749ab747fSPaolo Bonzini 25849ab747fSPaolo Bonzini static void cs_audio_callback (void *opaque, int free) 25949ab747fSPaolo Bonzini { 26049ab747fSPaolo Bonzini CSState *s = opaque; 26149ab747fSPaolo Bonzini s->audio_free = free; 26249ab747fSPaolo Bonzini } 26349ab747fSPaolo Bonzini 26449ab747fSPaolo Bonzini static void cs_reset_voices (CSState *s, uint32_t val) 26549ab747fSPaolo Bonzini { 26649ab747fSPaolo Bonzini int xtal; 26749ab747fSPaolo Bonzini struct audsettings as; 26849ab747fSPaolo Bonzini 26949ab747fSPaolo Bonzini #ifdef DEBUG_XLAW 27049ab747fSPaolo Bonzini if (val == 0 || val == 32) 27149ab747fSPaolo Bonzini val = (1 << 4) | (1 << 5); 27249ab747fSPaolo Bonzini #endif 27349ab747fSPaolo Bonzini 27449ab747fSPaolo Bonzini xtal = val & 1; 27549ab747fSPaolo Bonzini as.freq = freqs[xtal][(val >> 1) & 7]; 27649ab747fSPaolo Bonzini 27749ab747fSPaolo Bonzini if (as.freq == -1) { 27849ab747fSPaolo Bonzini lerr ("unsupported frequency (val=%#x)\n", val); 27949ab747fSPaolo Bonzini goto error; 28049ab747fSPaolo Bonzini } 28149ab747fSPaolo Bonzini 28249ab747fSPaolo Bonzini as.nchannels = (val & (1 << 4)) ? 2 : 1; 28349ab747fSPaolo Bonzini as.endianness = 0; 28449ab747fSPaolo Bonzini s->tab = NULL; 28549ab747fSPaolo Bonzini 28649ab747fSPaolo Bonzini switch ((val >> 5) & ((s->dregs[MODE_And_ID] & MODE2) ? 7 : 3)) { 28749ab747fSPaolo Bonzini case 0: 28849ab747fSPaolo Bonzini as.fmt = AUD_FMT_U8; 28949ab747fSPaolo Bonzini s->shift = as.nchannels == 2; 29049ab747fSPaolo Bonzini break; 29149ab747fSPaolo Bonzini 29249ab747fSPaolo Bonzini case 1: 29349ab747fSPaolo Bonzini s->tab = MuLawDecompressTable; 29449ab747fSPaolo Bonzini goto x_law; 29549ab747fSPaolo Bonzini case 3: 29649ab747fSPaolo Bonzini s->tab = ALawDecompressTable; 29749ab747fSPaolo Bonzini x_law: 29849ab747fSPaolo Bonzini as.fmt = AUD_FMT_S16; 29949ab747fSPaolo Bonzini as.endianness = AUDIO_HOST_ENDIANNESS; 30049ab747fSPaolo Bonzini s->shift = as.nchannels == 2; 30149ab747fSPaolo Bonzini break; 30249ab747fSPaolo Bonzini 30349ab747fSPaolo Bonzini case 6: 30449ab747fSPaolo Bonzini as.endianness = 1; 30549ab747fSPaolo Bonzini case 2: 30649ab747fSPaolo Bonzini as.fmt = AUD_FMT_S16; 30749ab747fSPaolo Bonzini s->shift = as.nchannels; 30849ab747fSPaolo Bonzini break; 30949ab747fSPaolo Bonzini 31049ab747fSPaolo Bonzini case 7: 31149ab747fSPaolo Bonzini case 4: 31249ab747fSPaolo Bonzini lerr ("attempt to use reserved format value (%#x)\n", val); 31349ab747fSPaolo Bonzini goto error; 31449ab747fSPaolo Bonzini 31549ab747fSPaolo Bonzini case 5: 31649ab747fSPaolo Bonzini lerr ("ADPCM 4 bit IMA compatible format is not supported\n"); 31749ab747fSPaolo Bonzini goto error; 31849ab747fSPaolo Bonzini } 31949ab747fSPaolo Bonzini 32049ab747fSPaolo Bonzini s->voice = AUD_open_out ( 32149ab747fSPaolo Bonzini &s->card, 32249ab747fSPaolo Bonzini s->voice, 32349ab747fSPaolo Bonzini "cs4231a", 32449ab747fSPaolo Bonzini s, 32549ab747fSPaolo Bonzini cs_audio_callback, 32649ab747fSPaolo Bonzini &as 32749ab747fSPaolo Bonzini ); 32849ab747fSPaolo Bonzini 32949ab747fSPaolo Bonzini if (s->dregs[Interface_Configuration] & PEN) { 33049ab747fSPaolo Bonzini if (!s->dma_running) { 33149ab747fSPaolo Bonzini DMA_hold_DREQ (s->dma); 33249ab747fSPaolo Bonzini AUD_set_active_out (s->voice, 1); 33349ab747fSPaolo Bonzini s->transferred = 0; 33449ab747fSPaolo Bonzini } 33549ab747fSPaolo Bonzini s->dma_running = 1; 33649ab747fSPaolo Bonzini } 33749ab747fSPaolo Bonzini else { 33849ab747fSPaolo Bonzini if (s->dma_running) { 33949ab747fSPaolo Bonzini DMA_release_DREQ (s->dma); 34049ab747fSPaolo Bonzini AUD_set_active_out (s->voice, 0); 34149ab747fSPaolo Bonzini } 34249ab747fSPaolo Bonzini s->dma_running = 0; 34349ab747fSPaolo Bonzini } 34449ab747fSPaolo Bonzini return; 34549ab747fSPaolo Bonzini 34649ab747fSPaolo Bonzini error: 34749ab747fSPaolo Bonzini if (s->dma_running) { 34849ab747fSPaolo Bonzini DMA_release_DREQ (s->dma); 34949ab747fSPaolo Bonzini AUD_set_active_out (s->voice, 0); 35049ab747fSPaolo Bonzini } 35149ab747fSPaolo Bonzini } 35249ab747fSPaolo Bonzini 35349ab747fSPaolo Bonzini static uint64_t cs_read (void *opaque, hwaddr addr, unsigned size) 35449ab747fSPaolo Bonzini { 35549ab747fSPaolo Bonzini CSState *s = opaque; 35649ab747fSPaolo Bonzini uint32_t saddr, iaddr, ret; 35749ab747fSPaolo Bonzini 35849ab747fSPaolo Bonzini saddr = addr; 35949ab747fSPaolo Bonzini iaddr = ~0U; 36049ab747fSPaolo Bonzini 36149ab747fSPaolo Bonzini switch (saddr) { 36249ab747fSPaolo Bonzini case Index_Address: 36349ab747fSPaolo Bonzini ret = s->regs[saddr] & ~0x80; 36449ab747fSPaolo Bonzini break; 36549ab747fSPaolo Bonzini 36649ab747fSPaolo Bonzini case Index_Data: 36749ab747fSPaolo Bonzini if (!(s->dregs[MODE_And_ID] & MODE2)) 36849ab747fSPaolo Bonzini iaddr = s->regs[Index_Address] & 0x0f; 36949ab747fSPaolo Bonzini else 37049ab747fSPaolo Bonzini iaddr = s->regs[Index_Address] & 0x1f; 37149ab747fSPaolo Bonzini 37249ab747fSPaolo Bonzini ret = s->dregs[iaddr]; 37349ab747fSPaolo Bonzini if (iaddr == Error_Status_And_Initialization) { 37449ab747fSPaolo Bonzini /* keep SEAL happy */ 37549ab747fSPaolo Bonzini if (s->aci_counter) { 37649ab747fSPaolo Bonzini ret |= 1 << 5; 37749ab747fSPaolo Bonzini s->aci_counter -= 1; 37849ab747fSPaolo Bonzini } 37949ab747fSPaolo Bonzini } 38049ab747fSPaolo Bonzini break; 38149ab747fSPaolo Bonzini 38249ab747fSPaolo Bonzini default: 38349ab747fSPaolo Bonzini ret = s->regs[saddr]; 38449ab747fSPaolo Bonzini break; 38549ab747fSPaolo Bonzini } 38649ab747fSPaolo Bonzini dolog ("read %d:%d -> %d\n", saddr, iaddr, ret); 38749ab747fSPaolo Bonzini return ret; 38849ab747fSPaolo Bonzini } 38949ab747fSPaolo Bonzini 39049ab747fSPaolo Bonzini static void cs_write (void *opaque, hwaddr addr, 39149ab747fSPaolo Bonzini uint64_t val64, unsigned size) 39249ab747fSPaolo Bonzini { 39349ab747fSPaolo Bonzini CSState *s = opaque; 39449ab747fSPaolo Bonzini uint32_t saddr, iaddr, val; 39549ab747fSPaolo Bonzini 39649ab747fSPaolo Bonzini saddr = addr; 39749ab747fSPaolo Bonzini val = val64; 39849ab747fSPaolo Bonzini 39949ab747fSPaolo Bonzini switch (saddr) { 40049ab747fSPaolo Bonzini case Index_Address: 40149ab747fSPaolo Bonzini if (!(s->regs[Index_Address] & MCE) && (val & MCE) 40249ab747fSPaolo Bonzini && (s->dregs[Interface_Configuration] & (3 << 3))) 40349ab747fSPaolo Bonzini s->aci_counter = conf.aci_counter; 40449ab747fSPaolo Bonzini 40549ab747fSPaolo Bonzini s->regs[Index_Address] = val & ~(1 << 7); 40649ab747fSPaolo Bonzini break; 40749ab747fSPaolo Bonzini 40849ab747fSPaolo Bonzini case Index_Data: 40949ab747fSPaolo Bonzini if (!(s->dregs[MODE_And_ID] & MODE2)) 41049ab747fSPaolo Bonzini iaddr = s->regs[Index_Address] & 0x0f; 41149ab747fSPaolo Bonzini else 41249ab747fSPaolo Bonzini iaddr = s->regs[Index_Address] & 0x1f; 41349ab747fSPaolo Bonzini 41449ab747fSPaolo Bonzini switch (iaddr) { 41549ab747fSPaolo Bonzini case RESERVED: 41649ab747fSPaolo Bonzini case RESERVED_2: 41749ab747fSPaolo Bonzini case RESERVED_3: 41849ab747fSPaolo Bonzini lwarn ("attempt to write %#x to reserved indirect register %d\n", 41949ab747fSPaolo Bonzini val, iaddr); 42049ab747fSPaolo Bonzini break; 42149ab747fSPaolo Bonzini 42249ab747fSPaolo Bonzini case FS_And_Playback_Data_Format: 42349ab747fSPaolo Bonzini if (s->regs[Index_Address] & MCE) { 42449ab747fSPaolo Bonzini cs_reset_voices (s, val); 42549ab747fSPaolo Bonzini } 42649ab747fSPaolo Bonzini else { 42749ab747fSPaolo Bonzini if (s->dregs[Alternate_Feature_Status] & PMCE) { 42849ab747fSPaolo Bonzini val = (val & ~0x0f) | (s->dregs[iaddr] & 0x0f); 42949ab747fSPaolo Bonzini cs_reset_voices (s, val); 43049ab747fSPaolo Bonzini } 43149ab747fSPaolo Bonzini else { 43249ab747fSPaolo Bonzini lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n", 43349ab747fSPaolo Bonzini s->regs[Index_Address], 43449ab747fSPaolo Bonzini s->dregs[Alternate_Feature_Status], 43549ab747fSPaolo Bonzini val); 43649ab747fSPaolo Bonzini break; 43749ab747fSPaolo Bonzini } 43849ab747fSPaolo Bonzini } 43949ab747fSPaolo Bonzini s->dregs[iaddr] = val; 44049ab747fSPaolo Bonzini break; 44149ab747fSPaolo Bonzini 44249ab747fSPaolo Bonzini case Interface_Configuration: 44349ab747fSPaolo Bonzini val &= ~(1 << 5); /* D5 is reserved */ 44449ab747fSPaolo Bonzini s->dregs[iaddr] = val; 44549ab747fSPaolo Bonzini if (val & PPIO) { 44649ab747fSPaolo Bonzini lwarn ("PIO is not supported (%#x)\n", val); 44749ab747fSPaolo Bonzini break; 44849ab747fSPaolo Bonzini } 44949ab747fSPaolo Bonzini if (val & PEN) { 45049ab747fSPaolo Bonzini if (!s->dma_running) { 45149ab747fSPaolo Bonzini cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]); 45249ab747fSPaolo Bonzini } 45349ab747fSPaolo Bonzini } 45449ab747fSPaolo Bonzini else { 45549ab747fSPaolo Bonzini if (s->dma_running) { 45649ab747fSPaolo Bonzini DMA_release_DREQ (s->dma); 45749ab747fSPaolo Bonzini AUD_set_active_out (s->voice, 0); 45849ab747fSPaolo Bonzini s->dma_running = 0; 45949ab747fSPaolo Bonzini } 46049ab747fSPaolo Bonzini } 46149ab747fSPaolo Bonzini break; 46249ab747fSPaolo Bonzini 46349ab747fSPaolo Bonzini case Error_Status_And_Initialization: 46449ab747fSPaolo Bonzini lwarn ("attempt to write to read only register %d\n", iaddr); 46549ab747fSPaolo Bonzini break; 46649ab747fSPaolo Bonzini 46749ab747fSPaolo Bonzini case MODE_And_ID: 46849ab747fSPaolo Bonzini dolog ("val=%#x\n", val); 46949ab747fSPaolo Bonzini if (val & MODE2) 47049ab747fSPaolo Bonzini s->dregs[iaddr] |= MODE2; 47149ab747fSPaolo Bonzini else 47249ab747fSPaolo Bonzini s->dregs[iaddr] &= ~MODE2; 47349ab747fSPaolo Bonzini break; 47449ab747fSPaolo Bonzini 47549ab747fSPaolo Bonzini case Alternate_Feature_Enable_I: 47649ab747fSPaolo Bonzini if (val & TE) 47749ab747fSPaolo Bonzini lerr ("timer is not yet supported\n"); 47849ab747fSPaolo Bonzini s->dregs[iaddr] = val; 47949ab747fSPaolo Bonzini break; 48049ab747fSPaolo Bonzini 48149ab747fSPaolo Bonzini case Alternate_Feature_Status: 48249ab747fSPaolo Bonzini if ((s->dregs[iaddr] & PI) && !(val & PI)) { 48349ab747fSPaolo Bonzini /* XXX: TI CI */ 48449ab747fSPaolo Bonzini qemu_irq_lower (s->pic); 48549ab747fSPaolo Bonzini s->regs[Status] &= ~INT; 48649ab747fSPaolo Bonzini } 48749ab747fSPaolo Bonzini s->dregs[iaddr] = val; 48849ab747fSPaolo Bonzini break; 48949ab747fSPaolo Bonzini 49049ab747fSPaolo Bonzini case Version_Chip_ID: 49149ab747fSPaolo Bonzini lwarn ("write to Version_Chip_ID register %#x\n", val); 49249ab747fSPaolo Bonzini s->dregs[iaddr] = val; 49349ab747fSPaolo Bonzini break; 49449ab747fSPaolo Bonzini 49549ab747fSPaolo Bonzini default: 49649ab747fSPaolo Bonzini s->dregs[iaddr] = val; 49749ab747fSPaolo Bonzini break; 49849ab747fSPaolo Bonzini } 49949ab747fSPaolo Bonzini dolog ("written value %#x to indirect register %d\n", val, iaddr); 50049ab747fSPaolo Bonzini break; 50149ab747fSPaolo Bonzini 50249ab747fSPaolo Bonzini case Status: 50349ab747fSPaolo Bonzini if (s->regs[Status] & INT) { 50449ab747fSPaolo Bonzini qemu_irq_lower (s->pic); 50549ab747fSPaolo Bonzini } 50649ab747fSPaolo Bonzini s->regs[Status] &= ~INT; 50749ab747fSPaolo Bonzini s->dregs[Alternate_Feature_Status] &= ~(PI | CI | TI); 50849ab747fSPaolo Bonzini break; 50949ab747fSPaolo Bonzini 51049ab747fSPaolo Bonzini case PIO_Data: 51149ab747fSPaolo Bonzini lwarn ("attempt to write value %#x to PIO register\n", val); 51249ab747fSPaolo Bonzini break; 51349ab747fSPaolo Bonzini } 51449ab747fSPaolo Bonzini } 51549ab747fSPaolo Bonzini 51649ab747fSPaolo Bonzini static int cs_write_audio (CSState *s, int nchan, int dma_pos, 51749ab747fSPaolo Bonzini int dma_len, int len) 51849ab747fSPaolo Bonzini { 51949ab747fSPaolo Bonzini int temp, net; 52049ab747fSPaolo Bonzini uint8_t tmpbuf[4096]; 52149ab747fSPaolo Bonzini 52249ab747fSPaolo Bonzini temp = len; 52349ab747fSPaolo Bonzini net = 0; 52449ab747fSPaolo Bonzini 52549ab747fSPaolo Bonzini while (temp) { 52649ab747fSPaolo Bonzini int left = dma_len - dma_pos; 52749ab747fSPaolo Bonzini int copied; 52849ab747fSPaolo Bonzini size_t to_copy; 52949ab747fSPaolo Bonzini 53049ab747fSPaolo Bonzini to_copy = audio_MIN (temp, left); 53149ab747fSPaolo Bonzini if (to_copy > sizeof (tmpbuf)) { 53249ab747fSPaolo Bonzini to_copy = sizeof (tmpbuf); 53349ab747fSPaolo Bonzini } 53449ab747fSPaolo Bonzini 53549ab747fSPaolo Bonzini copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy); 53649ab747fSPaolo Bonzini if (s->tab) { 53749ab747fSPaolo Bonzini int i; 53849ab747fSPaolo Bonzini int16_t linbuf[4096]; 53949ab747fSPaolo Bonzini 54049ab747fSPaolo Bonzini for (i = 0; i < copied; ++i) 54149ab747fSPaolo Bonzini linbuf[i] = s->tab[tmpbuf[i]]; 54249ab747fSPaolo Bonzini copied = AUD_write (s->voice, linbuf, copied << 1); 54349ab747fSPaolo Bonzini copied >>= 1; 54449ab747fSPaolo Bonzini } 54549ab747fSPaolo Bonzini else { 54649ab747fSPaolo Bonzini copied = AUD_write (s->voice, tmpbuf, copied); 54749ab747fSPaolo Bonzini } 54849ab747fSPaolo Bonzini 54949ab747fSPaolo Bonzini temp -= copied; 55049ab747fSPaolo Bonzini dma_pos = (dma_pos + copied) % dma_len; 55149ab747fSPaolo Bonzini net += copied; 55249ab747fSPaolo Bonzini 55349ab747fSPaolo Bonzini if (!copied) { 55449ab747fSPaolo Bonzini break; 55549ab747fSPaolo Bonzini } 55649ab747fSPaolo Bonzini } 55749ab747fSPaolo Bonzini 55849ab747fSPaolo Bonzini return net; 55949ab747fSPaolo Bonzini } 56049ab747fSPaolo Bonzini 56149ab747fSPaolo Bonzini static int cs_dma_read (void *opaque, int nchan, int dma_pos, int dma_len) 56249ab747fSPaolo Bonzini { 56349ab747fSPaolo Bonzini CSState *s = opaque; 56449ab747fSPaolo Bonzini int copy, written; 56549ab747fSPaolo Bonzini int till = -1; 56649ab747fSPaolo Bonzini 56749ab747fSPaolo Bonzini copy = s->voice ? (s->audio_free >> (s->tab != NULL)) : dma_len; 56849ab747fSPaolo Bonzini 56949ab747fSPaolo Bonzini if (s->dregs[Pin_Control] & IEN) { 57049ab747fSPaolo Bonzini till = (s->dregs[Playback_Lower_Base_Count] 57149ab747fSPaolo Bonzini | (s->dregs[Playback_Upper_Base_Count] << 8)) << s->shift; 57249ab747fSPaolo Bonzini till -= s->transferred; 57349ab747fSPaolo Bonzini copy = audio_MIN (till, copy); 57449ab747fSPaolo Bonzini } 57549ab747fSPaolo Bonzini 57649ab747fSPaolo Bonzini if ((copy <= 0) || (dma_len <= 0)) { 57749ab747fSPaolo Bonzini return dma_pos; 57849ab747fSPaolo Bonzini } 57949ab747fSPaolo Bonzini 58049ab747fSPaolo Bonzini written = cs_write_audio (s, nchan, dma_pos, dma_len, copy); 58149ab747fSPaolo Bonzini 58249ab747fSPaolo Bonzini dma_pos = (dma_pos + written) % dma_len; 58349ab747fSPaolo Bonzini s->audio_free -= (written << (s->tab != NULL)); 58449ab747fSPaolo Bonzini 58549ab747fSPaolo Bonzini if (written == till) { 58649ab747fSPaolo Bonzini s->regs[Status] |= INT; 58749ab747fSPaolo Bonzini s->dregs[Alternate_Feature_Status] |= PI; 58849ab747fSPaolo Bonzini s->transferred = 0; 58949ab747fSPaolo Bonzini qemu_irq_raise (s->pic); 59049ab747fSPaolo Bonzini } 59149ab747fSPaolo Bonzini else { 59249ab747fSPaolo Bonzini s->transferred += written; 59349ab747fSPaolo Bonzini } 59449ab747fSPaolo Bonzini 59549ab747fSPaolo Bonzini return dma_pos; 59649ab747fSPaolo Bonzini } 59749ab747fSPaolo Bonzini 59849ab747fSPaolo Bonzini static int cs4231a_pre_load (void *opaque) 59949ab747fSPaolo Bonzini { 60049ab747fSPaolo Bonzini CSState *s = opaque; 60149ab747fSPaolo Bonzini 60249ab747fSPaolo Bonzini if (s->dma_running) { 60349ab747fSPaolo Bonzini DMA_release_DREQ (s->dma); 60449ab747fSPaolo Bonzini AUD_set_active_out (s->voice, 0); 60549ab747fSPaolo Bonzini } 60649ab747fSPaolo Bonzini s->dma_running = 0; 60749ab747fSPaolo Bonzini return 0; 60849ab747fSPaolo Bonzini } 60949ab747fSPaolo Bonzini 61049ab747fSPaolo Bonzini static int cs4231a_post_load (void *opaque, int version_id) 61149ab747fSPaolo Bonzini { 61249ab747fSPaolo Bonzini CSState *s = opaque; 61349ab747fSPaolo Bonzini 61449ab747fSPaolo Bonzini if (s->dma_running && (s->dregs[Interface_Configuration] & PEN)) { 61549ab747fSPaolo Bonzini s->dma_running = 0; 61649ab747fSPaolo Bonzini cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]); 61749ab747fSPaolo Bonzini } 61849ab747fSPaolo Bonzini return 0; 61949ab747fSPaolo Bonzini } 62049ab747fSPaolo Bonzini 62149ab747fSPaolo Bonzini static const VMStateDescription vmstate_cs4231a = { 62249ab747fSPaolo Bonzini .name = "cs4231a", 62349ab747fSPaolo Bonzini .version_id = 1, 62449ab747fSPaolo Bonzini .minimum_version_id = 1, 62549ab747fSPaolo Bonzini .pre_load = cs4231a_pre_load, 62649ab747fSPaolo Bonzini .post_load = cs4231a_post_load, 62749ab747fSPaolo Bonzini .fields = (VMStateField[]) { 62849ab747fSPaolo Bonzini VMSTATE_UINT32_ARRAY (regs, CSState, CS_REGS), 62949ab747fSPaolo Bonzini VMSTATE_BUFFER (dregs, CSState), 63049ab747fSPaolo Bonzini VMSTATE_INT32 (dma_running, CSState), 63149ab747fSPaolo Bonzini VMSTATE_INT32 (audio_free, CSState), 63249ab747fSPaolo Bonzini VMSTATE_INT32 (transferred, CSState), 63349ab747fSPaolo Bonzini VMSTATE_INT32 (aci_counter, CSState), 63449ab747fSPaolo Bonzini VMSTATE_END_OF_LIST () 63549ab747fSPaolo Bonzini } 63649ab747fSPaolo Bonzini }; 63749ab747fSPaolo Bonzini 63849ab747fSPaolo Bonzini static const MemoryRegionOps cs_ioport_ops = { 63949ab747fSPaolo Bonzini .read = cs_read, 64049ab747fSPaolo Bonzini .write = cs_write, 64149ab747fSPaolo Bonzini .impl = { 64249ab747fSPaolo Bonzini .min_access_size = 1, 64349ab747fSPaolo Bonzini .max_access_size = 1, 64449ab747fSPaolo Bonzini } 64549ab747fSPaolo Bonzini }; 64649ab747fSPaolo Bonzini 647db895a1eSAndreas Färber static void cs4231a_initfn (Object *obj) 64849ab747fSPaolo Bonzini { 649db895a1eSAndreas Färber CSState *s = CS4231A (obj); 65049ab747fSPaolo Bonzini 65164bde0f3SPaolo Bonzini memory_region_init_io (&s->ioports, OBJECT(s), &cs_ioport_ops, s, 65264bde0f3SPaolo Bonzini "cs4231a", 4); 653db895a1eSAndreas Färber } 654db895a1eSAndreas Färber 655db895a1eSAndreas Färber static void cs4231a_realizefn (DeviceState *dev, Error **errp) 656db895a1eSAndreas Färber { 657db895a1eSAndreas Färber ISADevice *d = ISA_DEVICE (dev); 658db895a1eSAndreas Färber CSState *s = CS4231A (dev); 659db895a1eSAndreas Färber 660db895a1eSAndreas Färber isa_init_irq (d, &s->pic, s->irq); 661db895a1eSAndreas Färber 662db895a1eSAndreas Färber isa_register_ioport (d, &s->ioports, s->port); 66349ab747fSPaolo Bonzini 66449ab747fSPaolo Bonzini DMA_register_channel (s->dma, cs_dma_read, s); 66549ab747fSPaolo Bonzini 66649ab747fSPaolo Bonzini AUD_register_card ("cs4231a", &s->card); 66749ab747fSPaolo Bonzini } 66849ab747fSPaolo Bonzini 66936cd6f6fSPaolo Bonzini static int cs4231a_init (ISABus *bus) 67049ab747fSPaolo Bonzini { 671a3dcca56SAndreas Färber isa_create_simple (bus, TYPE_CS4231A); 67249ab747fSPaolo Bonzini return 0; 67349ab747fSPaolo Bonzini } 67449ab747fSPaolo Bonzini 67549ab747fSPaolo Bonzini static Property cs4231a_properties[] = { 676c7bcc85dSPaolo Bonzini DEFINE_PROP_UINT32 ("iobase", CSState, port, 0x534), 67749ab747fSPaolo Bonzini DEFINE_PROP_UINT32 ("irq", CSState, irq, 9), 67849ab747fSPaolo Bonzini DEFINE_PROP_UINT32 ("dma", CSState, dma, 3), 67949ab747fSPaolo Bonzini DEFINE_PROP_END_OF_LIST (), 68049ab747fSPaolo Bonzini }; 68149ab747fSPaolo Bonzini 68249ab747fSPaolo Bonzini static void cs4231a_class_initfn (ObjectClass *klass, void *data) 68349ab747fSPaolo Bonzini { 68449ab747fSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS (klass); 685db895a1eSAndreas Färber 686db895a1eSAndreas Färber dc->realize = cs4231a_realizefn; 687a3dcca56SAndreas Färber dc->reset = cs4231a_reset; 688125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_SOUND, dc->categories); 68949ab747fSPaolo Bonzini dc->desc = "Crystal Semiconductor CS4231A"; 69049ab747fSPaolo Bonzini dc->vmsd = &vmstate_cs4231a; 69149ab747fSPaolo Bonzini dc->props = cs4231a_properties; 69249ab747fSPaolo Bonzini } 69349ab747fSPaolo Bonzini 69449ab747fSPaolo Bonzini static const TypeInfo cs4231a_info = { 695a3dcca56SAndreas Färber .name = TYPE_CS4231A, 69649ab747fSPaolo Bonzini .parent = TYPE_ISA_DEVICE, 69749ab747fSPaolo Bonzini .instance_size = sizeof (CSState), 698db895a1eSAndreas Färber .instance_init = cs4231a_initfn, 69949ab747fSPaolo Bonzini .class_init = cs4231a_class_initfn, 70049ab747fSPaolo Bonzini }; 70149ab747fSPaolo Bonzini 70249ab747fSPaolo Bonzini static void cs4231a_register_types (void) 70349ab747fSPaolo Bonzini { 70449ab747fSPaolo Bonzini type_register_static (&cs4231a_info); 70536cd6f6fSPaolo Bonzini isa_register_soundhw("cs4231a", "CS4231A", cs4231a_init); 70649ab747fSPaolo Bonzini } 70749ab747fSPaolo Bonzini 70849ab747fSPaolo Bonzini type_init (cs4231a_register_types) 709