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 */
240b8fa32fSMarkus Armbruster
256086a565SPeter Maydell #include "qemu/osdep.h"
268a824e4dSEduardo Habkost #include "hw/audio/soundhw.h"
2749ab747fSPaolo Bonzini #include "audio/audio.h"
2864552b6bSMarkus Armbruster #include "hw/irq.h"
2949ab747fSPaolo Bonzini #include "hw/isa/isa.h"
30a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
31d6454270SMarkus Armbruster #include "migration/vmstate.h"
320b8fa32fSMarkus Armbruster #include "qemu/module.h"
3349ab747fSPaolo Bonzini #include "qemu/timer.h"
34c9073238SThomas Huth #include "qapi/error.h"
35db1015e9SEduardo Habkost #include "qom/object.h"
3649ab747fSPaolo Bonzini
3749ab747fSPaolo Bonzini /*
3849ab747fSPaolo Bonzini Missing features:
3949ab747fSPaolo Bonzini ADC
4049ab747fSPaolo Bonzini Loopback
4149ab747fSPaolo Bonzini Timer
4249ab747fSPaolo Bonzini ADPCM
4349ab747fSPaolo Bonzini More...
4449ab747fSPaolo Bonzini */
4549ab747fSPaolo Bonzini
4649ab747fSPaolo Bonzini /* #define DEBUG */
4749ab747fSPaolo Bonzini /* #define DEBUG_XLAW */
4849ab747fSPaolo Bonzini
4949ab747fSPaolo Bonzini static struct {
5049ab747fSPaolo Bonzini int aci_counter;
5149ab747fSPaolo Bonzini } conf = {1};
5249ab747fSPaolo Bonzini
5349ab747fSPaolo Bonzini #ifdef DEBUG
5449ab747fSPaolo Bonzini #define dolog(...) AUD_log ("cs4231a", __VA_ARGS__)
5549ab747fSPaolo Bonzini #else
5649ab747fSPaolo Bonzini #define dolog(...)
5749ab747fSPaolo Bonzini #endif
5849ab747fSPaolo Bonzini
5949ab747fSPaolo Bonzini #define lwarn(...) AUD_log ("cs4231a", "warning: " __VA_ARGS__)
6049ab747fSPaolo Bonzini #define lerr(...) AUD_log ("cs4231a", "error: " __VA_ARGS__)
6149ab747fSPaolo Bonzini
6249ab747fSPaolo Bonzini #define CS_REGS 16
6349ab747fSPaolo Bonzini #define CS_DREGS 32
6449ab747fSPaolo Bonzini
65a3dcca56SAndreas Färber #define TYPE_CS4231A "cs4231a"
66db1015e9SEduardo Habkost typedef struct CSState CSState;
678110fa1dSEduardo Habkost DECLARE_INSTANCE_CHECKER(CSState, CS4231A,
688110fa1dSEduardo Habkost TYPE_CS4231A)
69a3dcca56SAndreas Färber
70db1015e9SEduardo Habkost struct CSState {
7149ab747fSPaolo Bonzini ISADevice dev;
7249ab747fSPaolo Bonzini QEMUSoundCard card;
7349ab747fSPaolo Bonzini MemoryRegion ioports;
7449ab747fSPaolo Bonzini qemu_irq pic;
7549ab747fSPaolo Bonzini uint32_t regs[CS_REGS];
7649ab747fSPaolo Bonzini uint8_t dregs[CS_DREGS];
7749ab747fSPaolo Bonzini uint32_t irq;
7849ab747fSPaolo Bonzini uint32_t dma;
7949ab747fSPaolo Bonzini uint32_t port;
802d011091SHervé Poussineau IsaDma *isa_dma;
8149ab747fSPaolo Bonzini int shift;
8249ab747fSPaolo Bonzini int dma_running;
8349ab747fSPaolo Bonzini int audio_free;
8449ab747fSPaolo Bonzini int transferred;
8549ab747fSPaolo Bonzini int aci_counter;
8649ab747fSPaolo Bonzini SWVoiceOut *voice;
87bae17e74SBernhard Beschow const int16_t *tab;
88db1015e9SEduardo Habkost };
8949ab747fSPaolo Bonzini
9049ab747fSPaolo Bonzini #define MODE2 (1 << 6)
9149ab747fSPaolo Bonzini #define MCE (1 << 6)
9249ab747fSPaolo Bonzini #define PMCE (1 << 4)
9349ab747fSPaolo Bonzini #define CMCE (1 << 5)
9449ab747fSPaolo Bonzini #define TE (1 << 6)
9549ab747fSPaolo Bonzini #define PEN (1 << 0)
9649ab747fSPaolo Bonzini #define INT (1 << 0)
9749ab747fSPaolo Bonzini #define IEN (1 << 1)
9849ab747fSPaolo Bonzini #define PPIO (1 << 6)
9949ab747fSPaolo Bonzini #define PI (1 << 4)
10049ab747fSPaolo Bonzini #define CI (1 << 5)
10149ab747fSPaolo Bonzini #define TI (1 << 6)
10249ab747fSPaolo Bonzini
10349ab747fSPaolo Bonzini enum {
10449ab747fSPaolo Bonzini Index_Address,
10549ab747fSPaolo Bonzini Index_Data,
10649ab747fSPaolo Bonzini Status,
10749ab747fSPaolo Bonzini PIO_Data
10849ab747fSPaolo Bonzini };
10949ab747fSPaolo Bonzini
11049ab747fSPaolo Bonzini enum {
11149ab747fSPaolo Bonzini Left_ADC_Input_Control,
11249ab747fSPaolo Bonzini Right_ADC_Input_Control,
11349ab747fSPaolo Bonzini Left_AUX1_Input_Control,
11449ab747fSPaolo Bonzini Right_AUX1_Input_Control,
11549ab747fSPaolo Bonzini Left_AUX2_Input_Control,
11649ab747fSPaolo Bonzini Right_AUX2_Input_Control,
11749ab747fSPaolo Bonzini Left_DAC_Output_Control,
11849ab747fSPaolo Bonzini Right_DAC_Output_Control,
11949ab747fSPaolo Bonzini FS_And_Playback_Data_Format,
12049ab747fSPaolo Bonzini Interface_Configuration,
12149ab747fSPaolo Bonzini Pin_Control,
12249ab747fSPaolo Bonzini Error_Status_And_Initialization,
12349ab747fSPaolo Bonzini MODE_And_ID,
12449ab747fSPaolo Bonzini Loopback_Control,
12549ab747fSPaolo Bonzini Playback_Upper_Base_Count,
12649ab747fSPaolo Bonzini Playback_Lower_Base_Count,
12749ab747fSPaolo Bonzini Alternate_Feature_Enable_I,
12849ab747fSPaolo Bonzini Alternate_Feature_Enable_II,
12949ab747fSPaolo Bonzini Left_Line_Input_Control,
13049ab747fSPaolo Bonzini Right_Line_Input_Control,
13149ab747fSPaolo Bonzini Timer_Low_Base,
13249ab747fSPaolo Bonzini Timer_High_Base,
13349ab747fSPaolo Bonzini RESERVED,
13449ab747fSPaolo Bonzini Alternate_Feature_Enable_III,
13549ab747fSPaolo Bonzini Alternate_Feature_Status,
13649ab747fSPaolo Bonzini Version_Chip_ID,
13749ab747fSPaolo Bonzini Mono_Input_And_Output_Control,
13849ab747fSPaolo Bonzini RESERVED_2,
13949ab747fSPaolo Bonzini Capture_Data_Format,
14049ab747fSPaolo Bonzini RESERVED_3,
14149ab747fSPaolo Bonzini Capture_Upper_Base_Count,
14249ab747fSPaolo Bonzini Capture_Lower_Base_Count
14349ab747fSPaolo Bonzini };
14449ab747fSPaolo Bonzini
145bae17e74SBernhard Beschow static const int freqs[2][8] = {
14649ab747fSPaolo Bonzini { 8000, 16000, 27420, 32000, -1, -1, 48000, 9000 },
14749ab747fSPaolo Bonzini { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 }
14849ab747fSPaolo Bonzini };
14949ab747fSPaolo Bonzini
15049ab747fSPaolo Bonzini /* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */
151bae17e74SBernhard Beschow static const int16_t MuLawDecompressTable[256] =
15249ab747fSPaolo Bonzini {
15349ab747fSPaolo Bonzini -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
15449ab747fSPaolo Bonzini -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
15549ab747fSPaolo Bonzini -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
15649ab747fSPaolo Bonzini -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
15749ab747fSPaolo Bonzini -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
15849ab747fSPaolo Bonzini -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
15949ab747fSPaolo Bonzini -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
16049ab747fSPaolo Bonzini -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
16149ab747fSPaolo Bonzini -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
16249ab747fSPaolo Bonzini -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
16349ab747fSPaolo Bonzini -876, -844, -812, -780, -748, -716, -684, -652,
16449ab747fSPaolo Bonzini -620, -588, -556, -524, -492, -460, -428, -396,
16549ab747fSPaolo Bonzini -372, -356, -340, -324, -308, -292, -276, -260,
16649ab747fSPaolo Bonzini -244, -228, -212, -196, -180, -164, -148, -132,
16749ab747fSPaolo Bonzini -120, -112, -104, -96, -88, -80, -72, -64,
16849ab747fSPaolo Bonzini -56, -48, -40, -32, -24, -16, -8, 0,
16949ab747fSPaolo Bonzini 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
17049ab747fSPaolo Bonzini 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
17149ab747fSPaolo Bonzini 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
17249ab747fSPaolo Bonzini 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
17349ab747fSPaolo Bonzini 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
17449ab747fSPaolo Bonzini 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
17549ab747fSPaolo Bonzini 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
17649ab747fSPaolo Bonzini 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
17749ab747fSPaolo Bonzini 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
17849ab747fSPaolo Bonzini 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
17949ab747fSPaolo Bonzini 876, 844, 812, 780, 748, 716, 684, 652,
18049ab747fSPaolo Bonzini 620, 588, 556, 524, 492, 460, 428, 396,
18149ab747fSPaolo Bonzini 372, 356, 340, 324, 308, 292, 276, 260,
18249ab747fSPaolo Bonzini 244, 228, 212, 196, 180, 164, 148, 132,
18349ab747fSPaolo Bonzini 120, 112, 104, 96, 88, 80, 72, 64,
18449ab747fSPaolo Bonzini 56, 48, 40, 32, 24, 16, 8, 0
18549ab747fSPaolo Bonzini };
18649ab747fSPaolo Bonzini
187bae17e74SBernhard Beschow static const int16_t ALawDecompressTable[256] =
18849ab747fSPaolo Bonzini {
18949ab747fSPaolo Bonzini -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
19049ab747fSPaolo Bonzini -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
19149ab747fSPaolo Bonzini -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
19249ab747fSPaolo Bonzini -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
19349ab747fSPaolo Bonzini -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
19449ab747fSPaolo Bonzini -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
19549ab747fSPaolo Bonzini -11008,-10496,-12032,-11520,-8960, -8448, -9984, -9472,
19649ab747fSPaolo Bonzini -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
19749ab747fSPaolo Bonzini -344, -328, -376, -360, -280, -264, -312, -296,
19849ab747fSPaolo Bonzini -472, -456, -504, -488, -408, -392, -440, -424,
19949ab747fSPaolo Bonzini -88, -72, -120, -104, -24, -8, -56, -40,
20049ab747fSPaolo Bonzini -216, -200, -248, -232, -152, -136, -184, -168,
20149ab747fSPaolo Bonzini -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
20249ab747fSPaolo Bonzini -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
20349ab747fSPaolo Bonzini -688, -656, -752, -720, -560, -528, -624, -592,
20449ab747fSPaolo Bonzini -944, -912, -1008, -976, -816, -784, -880, -848,
20549ab747fSPaolo Bonzini 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
20649ab747fSPaolo Bonzini 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
20749ab747fSPaolo Bonzini 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
20849ab747fSPaolo Bonzini 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
20949ab747fSPaolo Bonzini 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
21049ab747fSPaolo Bonzini 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
21149ab747fSPaolo Bonzini 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
21249ab747fSPaolo Bonzini 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
21349ab747fSPaolo Bonzini 344, 328, 376, 360, 280, 264, 312, 296,
21449ab747fSPaolo Bonzini 472, 456, 504, 488, 408, 392, 440, 424,
21549ab747fSPaolo Bonzini 88, 72, 120, 104, 24, 8, 56, 40,
21649ab747fSPaolo Bonzini 216, 200, 248, 232, 152, 136, 184, 168,
21749ab747fSPaolo Bonzini 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
21849ab747fSPaolo Bonzini 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
21949ab747fSPaolo Bonzini 688, 656, 752, 720, 560, 528, 624, 592,
22049ab747fSPaolo Bonzini 944, 912, 1008, 976, 816, 784, 880, 848
22149ab747fSPaolo Bonzini };
22249ab747fSPaolo Bonzini
cs4231a_reset(DeviceState * dev)223a3dcca56SAndreas Färber static void cs4231a_reset (DeviceState *dev)
22449ab747fSPaolo Bonzini {
225a3dcca56SAndreas Färber CSState *s = CS4231A (dev);
22649ab747fSPaolo Bonzini
22749ab747fSPaolo Bonzini s->regs[Index_Address] = 0x40;
22849ab747fSPaolo Bonzini s->regs[Index_Data] = 0x00;
22949ab747fSPaolo Bonzini s->regs[Status] = 0x00;
23049ab747fSPaolo Bonzini s->regs[PIO_Data] = 0x00;
23149ab747fSPaolo Bonzini
23249ab747fSPaolo Bonzini s->dregs[Left_ADC_Input_Control] = 0x00;
23349ab747fSPaolo Bonzini s->dregs[Right_ADC_Input_Control] = 0x00;
23449ab747fSPaolo Bonzini s->dregs[Left_AUX1_Input_Control] = 0x88;
23549ab747fSPaolo Bonzini s->dregs[Right_AUX1_Input_Control] = 0x88;
23649ab747fSPaolo Bonzini s->dregs[Left_AUX2_Input_Control] = 0x88;
23749ab747fSPaolo Bonzini s->dregs[Right_AUX2_Input_Control] = 0x88;
23849ab747fSPaolo Bonzini s->dregs[Left_DAC_Output_Control] = 0x80;
23949ab747fSPaolo Bonzini s->dregs[Right_DAC_Output_Control] = 0x80;
24049ab747fSPaolo Bonzini s->dregs[FS_And_Playback_Data_Format] = 0x00;
24149ab747fSPaolo Bonzini s->dregs[Interface_Configuration] = 0x08;
24249ab747fSPaolo Bonzini s->dregs[Pin_Control] = 0x00;
24349ab747fSPaolo Bonzini s->dregs[Error_Status_And_Initialization] = 0x00;
24449ab747fSPaolo Bonzini s->dregs[MODE_And_ID] = 0x8a;
24549ab747fSPaolo Bonzini s->dregs[Loopback_Control] = 0x00;
24649ab747fSPaolo Bonzini s->dregs[Playback_Upper_Base_Count] = 0x00;
24749ab747fSPaolo Bonzini s->dregs[Playback_Lower_Base_Count] = 0x00;
24849ab747fSPaolo Bonzini s->dregs[Alternate_Feature_Enable_I] = 0x00;
24949ab747fSPaolo Bonzini s->dregs[Alternate_Feature_Enable_II] = 0x00;
25049ab747fSPaolo Bonzini s->dregs[Left_Line_Input_Control] = 0x88;
25149ab747fSPaolo Bonzini s->dregs[Right_Line_Input_Control] = 0x88;
25249ab747fSPaolo Bonzini s->dregs[Timer_Low_Base] = 0x00;
25349ab747fSPaolo Bonzini s->dregs[Timer_High_Base] = 0x00;
25449ab747fSPaolo Bonzini s->dregs[RESERVED] = 0x00;
25549ab747fSPaolo Bonzini s->dregs[Alternate_Feature_Enable_III] = 0x00;
25649ab747fSPaolo Bonzini s->dregs[Alternate_Feature_Status] = 0x00;
25749ab747fSPaolo Bonzini s->dregs[Version_Chip_ID] = 0xa0;
25849ab747fSPaolo Bonzini s->dregs[Mono_Input_And_Output_Control] = 0xa0;
25949ab747fSPaolo Bonzini s->dregs[RESERVED_2] = 0x00;
26049ab747fSPaolo Bonzini s->dregs[Capture_Data_Format] = 0x00;
26149ab747fSPaolo Bonzini s->dregs[RESERVED_3] = 0x00;
26249ab747fSPaolo Bonzini s->dregs[Capture_Upper_Base_Count] = 0x00;
26349ab747fSPaolo Bonzini s->dregs[Capture_Lower_Base_Count] = 0x00;
26449ab747fSPaolo Bonzini }
26549ab747fSPaolo Bonzini
cs_audio_callback(void * opaque,int free)26649ab747fSPaolo Bonzini static void cs_audio_callback (void *opaque, int free)
26749ab747fSPaolo Bonzini {
26849ab747fSPaolo Bonzini CSState *s = opaque;
26949ab747fSPaolo Bonzini s->audio_free = free;
27049ab747fSPaolo Bonzini }
27149ab747fSPaolo Bonzini
cs_reset_voices(CSState * s,uint32_t val)27249ab747fSPaolo Bonzini static void cs_reset_voices (CSState *s, uint32_t val)
27349ab747fSPaolo Bonzini {
27449ab747fSPaolo Bonzini int xtal;
27549ab747fSPaolo Bonzini struct audsettings as;
2762d011091SHervé Poussineau IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
27749ab747fSPaolo Bonzini
27849ab747fSPaolo Bonzini #ifdef DEBUG_XLAW
27949ab747fSPaolo Bonzini if (val == 0 || val == 32)
28049ab747fSPaolo Bonzini val = (1 << 4) | (1 << 5);
28149ab747fSPaolo Bonzini #endif
28249ab747fSPaolo Bonzini
28349ab747fSPaolo Bonzini xtal = val & 1;
28449ab747fSPaolo Bonzini as.freq = freqs[xtal][(val >> 1) & 7];
28549ab747fSPaolo Bonzini
28649ab747fSPaolo Bonzini if (as.freq == -1) {
28749ab747fSPaolo Bonzini lerr ("unsupported frequency (val=%#x)\n", val);
28849ab747fSPaolo Bonzini goto error;
28949ab747fSPaolo Bonzini }
29049ab747fSPaolo Bonzini
29149ab747fSPaolo Bonzini as.nchannels = (val & (1 << 4)) ? 2 : 1;
29249ab747fSPaolo Bonzini as.endianness = 0;
29349ab747fSPaolo Bonzini s->tab = NULL;
29449ab747fSPaolo Bonzini
29549ab747fSPaolo Bonzini switch ((val >> 5) & ((s->dregs[MODE_And_ID] & MODE2) ? 7 : 3)) {
29649ab747fSPaolo Bonzini case 0:
29785bc5852SKővágó, Zoltán as.fmt = AUDIO_FORMAT_U8;
29849ab747fSPaolo Bonzini s->shift = as.nchannels == 2;
29949ab747fSPaolo Bonzini break;
30049ab747fSPaolo Bonzini
30149ab747fSPaolo Bonzini case 1:
30249ab747fSPaolo Bonzini s->tab = MuLawDecompressTable;
30349ab747fSPaolo Bonzini goto x_law;
30449ab747fSPaolo Bonzini case 3:
30549ab747fSPaolo Bonzini s->tab = ALawDecompressTable;
30649ab747fSPaolo Bonzini x_law:
30785bc5852SKővágó, Zoltán as.fmt = AUDIO_FORMAT_S16;
30849ab747fSPaolo Bonzini as.endianness = AUDIO_HOST_ENDIANNESS;
30949ab747fSPaolo Bonzini s->shift = as.nchannels == 2;
31049ab747fSPaolo Bonzini break;
31149ab747fSPaolo Bonzini
31249ab747fSPaolo Bonzini case 6:
31349ab747fSPaolo Bonzini as.endianness = 1;
314edd7541bSPaolo Bonzini /* fall through */
31549ab747fSPaolo Bonzini case 2:
31685bc5852SKővágó, Zoltán as.fmt = AUDIO_FORMAT_S16;
31749ab747fSPaolo Bonzini s->shift = as.nchannels;
31849ab747fSPaolo Bonzini break;
31949ab747fSPaolo Bonzini
32049ab747fSPaolo Bonzini case 7:
32149ab747fSPaolo Bonzini case 4:
32249ab747fSPaolo Bonzini lerr ("attempt to use reserved format value (%#x)\n", val);
32349ab747fSPaolo Bonzini goto error;
32449ab747fSPaolo Bonzini
32549ab747fSPaolo Bonzini case 5:
32649ab747fSPaolo Bonzini lerr ("ADPCM 4 bit IMA compatible format is not supported\n");
32749ab747fSPaolo Bonzini goto error;
32849ab747fSPaolo Bonzini }
32949ab747fSPaolo Bonzini
33049ab747fSPaolo Bonzini s->voice = AUD_open_out (
33149ab747fSPaolo Bonzini &s->card,
33249ab747fSPaolo Bonzini s->voice,
33349ab747fSPaolo Bonzini "cs4231a",
33449ab747fSPaolo Bonzini s,
33549ab747fSPaolo Bonzini cs_audio_callback,
33649ab747fSPaolo Bonzini &as
33749ab747fSPaolo Bonzini );
33849ab747fSPaolo Bonzini
33949ab747fSPaolo Bonzini if (s->dregs[Interface_Configuration] & PEN) {
34049ab747fSPaolo Bonzini if (!s->dma_running) {
3412d011091SHervé Poussineau k->hold_DREQ(s->isa_dma, s->dma);
34249ab747fSPaolo Bonzini AUD_set_active_out (s->voice, 1);
34349ab747fSPaolo Bonzini s->transferred = 0;
34449ab747fSPaolo Bonzini }
34549ab747fSPaolo Bonzini s->dma_running = 1;
34649ab747fSPaolo Bonzini }
34749ab747fSPaolo Bonzini else {
34849ab747fSPaolo Bonzini if (s->dma_running) {
3492d011091SHervé Poussineau k->release_DREQ(s->isa_dma, s->dma);
35049ab747fSPaolo Bonzini AUD_set_active_out (s->voice, 0);
35149ab747fSPaolo Bonzini }
35249ab747fSPaolo Bonzini s->dma_running = 0;
35349ab747fSPaolo Bonzini }
35449ab747fSPaolo Bonzini return;
35549ab747fSPaolo Bonzini
35649ab747fSPaolo Bonzini error:
35749ab747fSPaolo Bonzini if (s->dma_running) {
3582d011091SHervé Poussineau k->release_DREQ(s->isa_dma, s->dma);
35949ab747fSPaolo Bonzini AUD_set_active_out (s->voice, 0);
36049ab747fSPaolo Bonzini }
36149ab747fSPaolo Bonzini }
36249ab747fSPaolo Bonzini
cs_read(void * opaque,hwaddr addr,unsigned size)36349ab747fSPaolo Bonzini static uint64_t cs_read (void *opaque, hwaddr addr, unsigned size)
36449ab747fSPaolo Bonzini {
36549ab747fSPaolo Bonzini CSState *s = opaque;
36649ab747fSPaolo Bonzini uint32_t saddr, iaddr, ret;
36749ab747fSPaolo Bonzini
36849ab747fSPaolo Bonzini saddr = addr;
36949ab747fSPaolo Bonzini iaddr = ~0U;
37049ab747fSPaolo Bonzini
37149ab747fSPaolo Bonzini switch (saddr) {
37249ab747fSPaolo Bonzini case Index_Address:
37349ab747fSPaolo Bonzini ret = s->regs[saddr] & ~0x80;
37449ab747fSPaolo Bonzini break;
37549ab747fSPaolo Bonzini
37649ab747fSPaolo Bonzini case Index_Data:
37749ab747fSPaolo Bonzini if (!(s->dregs[MODE_And_ID] & MODE2))
37849ab747fSPaolo Bonzini iaddr = s->regs[Index_Address] & 0x0f;
37949ab747fSPaolo Bonzini else
38049ab747fSPaolo Bonzini iaddr = s->regs[Index_Address] & 0x1f;
38149ab747fSPaolo Bonzini
38249ab747fSPaolo Bonzini ret = s->dregs[iaddr];
38349ab747fSPaolo Bonzini if (iaddr == Error_Status_And_Initialization) {
38449ab747fSPaolo Bonzini /* keep SEAL happy */
38549ab747fSPaolo Bonzini if (s->aci_counter) {
38649ab747fSPaolo Bonzini ret |= 1 << 5;
38749ab747fSPaolo Bonzini s->aci_counter -= 1;
38849ab747fSPaolo Bonzini }
38949ab747fSPaolo Bonzini }
39049ab747fSPaolo Bonzini break;
39149ab747fSPaolo Bonzini
39249ab747fSPaolo Bonzini default:
39349ab747fSPaolo Bonzini ret = s->regs[saddr];
39449ab747fSPaolo Bonzini break;
39549ab747fSPaolo Bonzini }
39649ab747fSPaolo Bonzini dolog ("read %d:%d -> %d\n", saddr, iaddr, ret);
39749ab747fSPaolo Bonzini return ret;
39849ab747fSPaolo Bonzini }
39949ab747fSPaolo Bonzini
cs_write(void * opaque,hwaddr addr,uint64_t val64,unsigned size)40049ab747fSPaolo Bonzini static void cs_write (void *opaque, hwaddr addr,
40149ab747fSPaolo Bonzini uint64_t val64, unsigned size)
40249ab747fSPaolo Bonzini {
40349ab747fSPaolo Bonzini CSState *s = opaque;
40449ab747fSPaolo Bonzini uint32_t saddr, iaddr, val;
40549ab747fSPaolo Bonzini
40649ab747fSPaolo Bonzini saddr = addr;
40749ab747fSPaolo Bonzini val = val64;
40849ab747fSPaolo Bonzini
40949ab747fSPaolo Bonzini switch (saddr) {
41049ab747fSPaolo Bonzini case Index_Address:
41149ab747fSPaolo Bonzini if (!(s->regs[Index_Address] & MCE) && (val & MCE)
41249ab747fSPaolo Bonzini && (s->dregs[Interface_Configuration] & (3 << 3)))
41349ab747fSPaolo Bonzini s->aci_counter = conf.aci_counter;
41449ab747fSPaolo Bonzini
41549ab747fSPaolo Bonzini s->regs[Index_Address] = val & ~(1 << 7);
41649ab747fSPaolo Bonzini break;
41749ab747fSPaolo Bonzini
41849ab747fSPaolo Bonzini case Index_Data:
41949ab747fSPaolo Bonzini if (!(s->dregs[MODE_And_ID] & MODE2))
42049ab747fSPaolo Bonzini iaddr = s->regs[Index_Address] & 0x0f;
42149ab747fSPaolo Bonzini else
42249ab747fSPaolo Bonzini iaddr = s->regs[Index_Address] & 0x1f;
42349ab747fSPaolo Bonzini
42449ab747fSPaolo Bonzini switch (iaddr) {
42549ab747fSPaolo Bonzini case RESERVED:
42649ab747fSPaolo Bonzini case RESERVED_2:
42749ab747fSPaolo Bonzini case RESERVED_3:
42849ab747fSPaolo Bonzini lwarn ("attempt to write %#x to reserved indirect register %d\n",
42949ab747fSPaolo Bonzini val, iaddr);
43049ab747fSPaolo Bonzini break;
43149ab747fSPaolo Bonzini
43249ab747fSPaolo Bonzini case FS_And_Playback_Data_Format:
43349ab747fSPaolo Bonzini if (s->regs[Index_Address] & MCE) {
43449ab747fSPaolo Bonzini cs_reset_voices (s, val);
43549ab747fSPaolo Bonzini }
43649ab747fSPaolo Bonzini else {
43749ab747fSPaolo Bonzini if (s->dregs[Alternate_Feature_Status] & PMCE) {
43849ab747fSPaolo Bonzini val = (val & ~0x0f) | (s->dregs[iaddr] & 0x0f);
43949ab747fSPaolo Bonzini cs_reset_voices (s, val);
44049ab747fSPaolo Bonzini }
44149ab747fSPaolo Bonzini else {
44249ab747fSPaolo Bonzini lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n",
44349ab747fSPaolo Bonzini s->regs[Index_Address],
44449ab747fSPaolo Bonzini s->dregs[Alternate_Feature_Status],
44549ab747fSPaolo Bonzini val);
44649ab747fSPaolo Bonzini break;
44749ab747fSPaolo Bonzini }
44849ab747fSPaolo Bonzini }
44949ab747fSPaolo Bonzini s->dregs[iaddr] = val;
45049ab747fSPaolo Bonzini break;
45149ab747fSPaolo Bonzini
45249ab747fSPaolo Bonzini case Interface_Configuration:
45349ab747fSPaolo Bonzini val &= ~(1 << 5); /* D5 is reserved */
45449ab747fSPaolo Bonzini s->dregs[iaddr] = val;
45549ab747fSPaolo Bonzini if (val & PPIO) {
45649ab747fSPaolo Bonzini lwarn ("PIO is not supported (%#x)\n", val);
45749ab747fSPaolo Bonzini break;
45849ab747fSPaolo Bonzini }
45949ab747fSPaolo Bonzini if (val & PEN) {
46049ab747fSPaolo Bonzini if (!s->dma_running) {
46149ab747fSPaolo Bonzini cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
46249ab747fSPaolo Bonzini }
46349ab747fSPaolo Bonzini }
46449ab747fSPaolo Bonzini else {
46549ab747fSPaolo Bonzini if (s->dma_running) {
4662d011091SHervé Poussineau IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
4672d011091SHervé Poussineau k->release_DREQ(s->isa_dma, s->dma);
46849ab747fSPaolo Bonzini AUD_set_active_out (s->voice, 0);
46949ab747fSPaolo Bonzini s->dma_running = 0;
47049ab747fSPaolo Bonzini }
47149ab747fSPaolo Bonzini }
47249ab747fSPaolo Bonzini break;
47349ab747fSPaolo Bonzini
47449ab747fSPaolo Bonzini case Error_Status_And_Initialization:
47549ab747fSPaolo Bonzini lwarn ("attempt to write to read only register %d\n", iaddr);
47649ab747fSPaolo Bonzini break;
47749ab747fSPaolo Bonzini
47849ab747fSPaolo Bonzini case MODE_And_ID:
47949ab747fSPaolo Bonzini dolog ("val=%#x\n", val);
48049ab747fSPaolo Bonzini if (val & MODE2)
48149ab747fSPaolo Bonzini s->dregs[iaddr] |= MODE2;
48249ab747fSPaolo Bonzini else
48349ab747fSPaolo Bonzini s->dregs[iaddr] &= ~MODE2;
48449ab747fSPaolo Bonzini break;
48549ab747fSPaolo Bonzini
48649ab747fSPaolo Bonzini case Alternate_Feature_Enable_I:
48749ab747fSPaolo Bonzini if (val & TE)
48849ab747fSPaolo Bonzini lerr ("timer is not yet supported\n");
48949ab747fSPaolo Bonzini s->dregs[iaddr] = val;
49049ab747fSPaolo Bonzini break;
49149ab747fSPaolo Bonzini
49249ab747fSPaolo Bonzini case Alternate_Feature_Status:
49349ab747fSPaolo Bonzini if ((s->dregs[iaddr] & PI) && !(val & PI)) {
49449ab747fSPaolo Bonzini /* XXX: TI CI */
49549ab747fSPaolo Bonzini qemu_irq_lower (s->pic);
49649ab747fSPaolo Bonzini s->regs[Status] &= ~INT;
49749ab747fSPaolo Bonzini }
49849ab747fSPaolo Bonzini s->dregs[iaddr] = val;
49949ab747fSPaolo Bonzini break;
50049ab747fSPaolo Bonzini
50149ab747fSPaolo Bonzini case Version_Chip_ID:
50249ab747fSPaolo Bonzini lwarn ("write to Version_Chip_ID register %#x\n", val);
50349ab747fSPaolo Bonzini s->dregs[iaddr] = val;
50449ab747fSPaolo Bonzini break;
50549ab747fSPaolo Bonzini
50649ab747fSPaolo Bonzini default:
50749ab747fSPaolo Bonzini s->dregs[iaddr] = val;
50849ab747fSPaolo Bonzini break;
50949ab747fSPaolo Bonzini }
51049ab747fSPaolo Bonzini dolog ("written value %#x to indirect register %d\n", val, iaddr);
51149ab747fSPaolo Bonzini break;
51249ab747fSPaolo Bonzini
51349ab747fSPaolo Bonzini case Status:
51449ab747fSPaolo Bonzini if (s->regs[Status] & INT) {
51549ab747fSPaolo Bonzini qemu_irq_lower (s->pic);
51649ab747fSPaolo Bonzini }
51749ab747fSPaolo Bonzini s->regs[Status] &= ~INT;
51849ab747fSPaolo Bonzini s->dregs[Alternate_Feature_Status] &= ~(PI | CI | TI);
51949ab747fSPaolo Bonzini break;
52049ab747fSPaolo Bonzini
52149ab747fSPaolo Bonzini case PIO_Data:
52249ab747fSPaolo Bonzini lwarn ("attempt to write value %#x to PIO register\n", val);
52349ab747fSPaolo Bonzini break;
52449ab747fSPaolo Bonzini }
52549ab747fSPaolo Bonzini }
52649ab747fSPaolo Bonzini
cs_write_audio(CSState * s,int nchan,int dma_pos,int dma_len,int len)52749ab747fSPaolo Bonzini static int cs_write_audio (CSState *s, int nchan, int dma_pos,
52849ab747fSPaolo Bonzini int dma_len, int len)
52949ab747fSPaolo Bonzini {
53049ab747fSPaolo Bonzini int temp, net;
53149ab747fSPaolo Bonzini uint8_t tmpbuf[4096];
5322d011091SHervé Poussineau IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
53349ab747fSPaolo Bonzini
53449ab747fSPaolo Bonzini temp = len;
53549ab747fSPaolo Bonzini net = 0;
53649ab747fSPaolo Bonzini
53749ab747fSPaolo Bonzini while (temp) {
53849ab747fSPaolo Bonzini int left = dma_len - dma_pos;
53949ab747fSPaolo Bonzini int copied;
54049ab747fSPaolo Bonzini size_t to_copy;
54149ab747fSPaolo Bonzini
54258935915SKővágó, Zoltán to_copy = MIN (temp, left);
54349ab747fSPaolo Bonzini if (to_copy > sizeof (tmpbuf)) {
54449ab747fSPaolo Bonzini to_copy = sizeof (tmpbuf);
54549ab747fSPaolo Bonzini }
54649ab747fSPaolo Bonzini
5472d011091SHervé Poussineau copied = k->read_memory(s->isa_dma, nchan, tmpbuf, dma_pos, to_copy);
54849ab747fSPaolo Bonzini if (s->tab) {
54949ab747fSPaolo Bonzini int i;
55049ab747fSPaolo Bonzini int16_t linbuf[4096];
55149ab747fSPaolo Bonzini
55249ab747fSPaolo Bonzini for (i = 0; i < copied; ++i)
55349ab747fSPaolo Bonzini linbuf[i] = s->tab[tmpbuf[i]];
55449ab747fSPaolo Bonzini copied = AUD_write (s->voice, linbuf, copied << 1);
55549ab747fSPaolo Bonzini copied >>= 1;
55649ab747fSPaolo Bonzini }
55749ab747fSPaolo Bonzini else {
55849ab747fSPaolo Bonzini copied = AUD_write (s->voice, tmpbuf, copied);
55949ab747fSPaolo Bonzini }
56049ab747fSPaolo Bonzini
56149ab747fSPaolo Bonzini temp -= copied;
56249ab747fSPaolo Bonzini dma_pos = (dma_pos + copied) % dma_len;
56349ab747fSPaolo Bonzini net += copied;
56449ab747fSPaolo Bonzini
56549ab747fSPaolo Bonzini if (!copied) {
56649ab747fSPaolo Bonzini break;
56749ab747fSPaolo Bonzini }
56849ab747fSPaolo Bonzini }
56949ab747fSPaolo Bonzini
57049ab747fSPaolo Bonzini return net;
57149ab747fSPaolo Bonzini }
57249ab747fSPaolo Bonzini
cs_dma_read(void * opaque,int nchan,int dma_pos,int dma_len)57349ab747fSPaolo Bonzini static int cs_dma_read (void *opaque, int nchan, int dma_pos, int dma_len)
57449ab747fSPaolo Bonzini {
57549ab747fSPaolo Bonzini CSState *s = opaque;
57649ab747fSPaolo Bonzini int copy, written;
57749ab747fSPaolo Bonzini int till = -1;
57849ab747fSPaolo Bonzini
57949ab747fSPaolo Bonzini copy = s->voice ? (s->audio_free >> (s->tab != NULL)) : dma_len;
58049ab747fSPaolo Bonzini
58149ab747fSPaolo Bonzini if (s->dregs[Pin_Control] & IEN) {
58249ab747fSPaolo Bonzini till = (s->dregs[Playback_Lower_Base_Count]
58349ab747fSPaolo Bonzini | (s->dregs[Playback_Upper_Base_Count] << 8)) << s->shift;
58449ab747fSPaolo Bonzini till -= s->transferred;
58558935915SKővágó, Zoltán copy = MIN (till, copy);
58649ab747fSPaolo Bonzini }
58749ab747fSPaolo Bonzini
58849ab747fSPaolo Bonzini if ((copy <= 0) || (dma_len <= 0)) {
58949ab747fSPaolo Bonzini return dma_pos;
59049ab747fSPaolo Bonzini }
59149ab747fSPaolo Bonzini
59249ab747fSPaolo Bonzini written = cs_write_audio (s, nchan, dma_pos, dma_len, copy);
59349ab747fSPaolo Bonzini
59449ab747fSPaolo Bonzini dma_pos = (dma_pos + written) % dma_len;
59549ab747fSPaolo Bonzini s->audio_free -= (written << (s->tab != NULL));
59649ab747fSPaolo Bonzini
59749ab747fSPaolo Bonzini if (written == till) {
59849ab747fSPaolo Bonzini s->regs[Status] |= INT;
59949ab747fSPaolo Bonzini s->dregs[Alternate_Feature_Status] |= PI;
60049ab747fSPaolo Bonzini s->transferred = 0;
60149ab747fSPaolo Bonzini qemu_irq_raise (s->pic);
60249ab747fSPaolo Bonzini }
60349ab747fSPaolo Bonzini else {
60449ab747fSPaolo Bonzini s->transferred += written;
60549ab747fSPaolo Bonzini }
60649ab747fSPaolo Bonzini
60749ab747fSPaolo Bonzini return dma_pos;
60849ab747fSPaolo Bonzini }
60949ab747fSPaolo Bonzini
cs4231a_pre_load(void * opaque)61049ab747fSPaolo Bonzini static int cs4231a_pre_load (void *opaque)
61149ab747fSPaolo Bonzini {
61249ab747fSPaolo Bonzini CSState *s = opaque;
61349ab747fSPaolo Bonzini
61449ab747fSPaolo Bonzini if (s->dma_running) {
6152d011091SHervé Poussineau IsaDmaClass *k = ISADMA_GET_CLASS(s->isa_dma);
6162d011091SHervé Poussineau k->release_DREQ(s->isa_dma, s->dma);
61749ab747fSPaolo Bonzini AUD_set_active_out (s->voice, 0);
61849ab747fSPaolo Bonzini }
61949ab747fSPaolo Bonzini s->dma_running = 0;
62049ab747fSPaolo Bonzini return 0;
62149ab747fSPaolo Bonzini }
62249ab747fSPaolo Bonzini
cs4231a_post_load(void * opaque,int version_id)62349ab747fSPaolo Bonzini static int cs4231a_post_load (void *opaque, int version_id)
62449ab747fSPaolo Bonzini {
62549ab747fSPaolo Bonzini CSState *s = opaque;
62649ab747fSPaolo Bonzini
62749ab747fSPaolo Bonzini if (s->dma_running && (s->dregs[Interface_Configuration] & PEN)) {
62849ab747fSPaolo Bonzini s->dma_running = 0;
62949ab747fSPaolo Bonzini cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
63049ab747fSPaolo Bonzini }
63149ab747fSPaolo Bonzini return 0;
63249ab747fSPaolo Bonzini }
63349ab747fSPaolo Bonzini
63449ab747fSPaolo Bonzini static const VMStateDescription vmstate_cs4231a = {
63549ab747fSPaolo Bonzini .name = "cs4231a",
63649ab747fSPaolo Bonzini .version_id = 1,
63749ab747fSPaolo Bonzini .minimum_version_id = 1,
63849ab747fSPaolo Bonzini .pre_load = cs4231a_pre_load,
63949ab747fSPaolo Bonzini .post_load = cs4231a_post_load,
640856a6fe4SRichard Henderson .fields = (const VMStateField[]) {
64149ab747fSPaolo Bonzini VMSTATE_UINT32_ARRAY (regs, CSState, CS_REGS),
64249ab747fSPaolo Bonzini VMSTATE_BUFFER (dregs, CSState),
64349ab747fSPaolo Bonzini VMSTATE_INT32 (dma_running, CSState),
64449ab747fSPaolo Bonzini VMSTATE_INT32 (audio_free, CSState),
64549ab747fSPaolo Bonzini VMSTATE_INT32 (transferred, CSState),
64649ab747fSPaolo Bonzini VMSTATE_INT32 (aci_counter, CSState),
64749ab747fSPaolo Bonzini VMSTATE_END_OF_LIST ()
64849ab747fSPaolo Bonzini }
64949ab747fSPaolo Bonzini };
65049ab747fSPaolo Bonzini
65149ab747fSPaolo Bonzini static const MemoryRegionOps cs_ioport_ops = {
65249ab747fSPaolo Bonzini .read = cs_read,
65349ab747fSPaolo Bonzini .write = cs_write,
65449ab747fSPaolo Bonzini .impl = {
65549ab747fSPaolo Bonzini .min_access_size = 1,
65649ab747fSPaolo Bonzini .max_access_size = 1,
65749ab747fSPaolo Bonzini }
65849ab747fSPaolo Bonzini };
65949ab747fSPaolo Bonzini
cs4231a_initfn(Object * obj)660db895a1eSAndreas Färber static void cs4231a_initfn (Object *obj)
66149ab747fSPaolo Bonzini {
662db895a1eSAndreas Färber CSState *s = CS4231A (obj);
66349ab747fSPaolo Bonzini
66464bde0f3SPaolo Bonzini memory_region_init_io (&s->ioports, OBJECT(s), &cs_ioport_ops, s,
66564bde0f3SPaolo Bonzini "cs4231a", 4);
666db895a1eSAndreas Färber }
667db895a1eSAndreas Färber
cs4231a_realizefn(DeviceState * dev,Error ** errp)668db895a1eSAndreas Färber static void cs4231a_realizefn (DeviceState *dev, Error **errp)
669db895a1eSAndreas Färber {
670db895a1eSAndreas Färber ISADevice *d = ISA_DEVICE (dev);
6718e7db8abSPhilippe Mathieu-Daudé ISABus *bus = isa_bus_from_device(d);
672db895a1eSAndreas Färber CSState *s = CS4231A (dev);
6732d011091SHervé Poussineau IsaDmaClass *k;
674db895a1eSAndreas Färber
6758e7db8abSPhilippe Mathieu-Daudé s->isa_dma = isa_bus_get_dma(bus, s->dma);
676c9073238SThomas Huth if (!s->isa_dma) {
677c9073238SThomas Huth error_setg(errp, "ISA controller does not support DMA");
678c9073238SThomas Huth return;
679c9073238SThomas Huth }
680c9073238SThomas Huth
681cb94ff5fSMartin Kletzander if (!AUD_register_card ("cs4231a", &s->card, errp)) {
682cb94ff5fSMartin Kletzander return;
683cb94ff5fSMartin Kletzander }
684cb94ff5fSMartin Kletzander
6858e7db8abSPhilippe Mathieu-Daudé s->pic = isa_bus_get_irq(bus, s->irq);
6862d011091SHervé Poussineau k = ISADMA_GET_CLASS(s->isa_dma);
6872d011091SHervé Poussineau k->register_channel(s->isa_dma, s->dma, cs_dma_read, s);
688db895a1eSAndreas Färber
689db895a1eSAndreas Färber isa_register_ioport (d, &s->ioports, s->port);
69049ab747fSPaolo Bonzini }
69149ab747fSPaolo Bonzini
69249ab747fSPaolo Bonzini static Property cs4231a_properties[] = {
69388e47b9aSKővágó, Zoltán DEFINE_AUDIO_PROPERTIES(CSState, card),
694c7bcc85dSPaolo Bonzini DEFINE_PROP_UINT32 ("iobase", CSState, port, 0x534),
69549ab747fSPaolo Bonzini DEFINE_PROP_UINT32 ("irq", CSState, irq, 9),
69649ab747fSPaolo Bonzini DEFINE_PROP_UINT32 ("dma", CSState, dma, 3),
69749ab747fSPaolo Bonzini DEFINE_PROP_END_OF_LIST (),
69849ab747fSPaolo Bonzini };
69949ab747fSPaolo Bonzini
cs4231a_class_initfn(ObjectClass * klass,void * data)70049ab747fSPaolo Bonzini static void cs4231a_class_initfn (ObjectClass *klass, void *data)
70149ab747fSPaolo Bonzini {
70249ab747fSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS (klass);
703db895a1eSAndreas Färber
704db895a1eSAndreas Färber dc->realize = cs4231a_realizefn;
705*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, cs4231a_reset);
706125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
70749ab747fSPaolo Bonzini dc->desc = "Crystal Semiconductor CS4231A";
70849ab747fSPaolo Bonzini dc->vmsd = &vmstate_cs4231a;
7094f67d30bSMarc-André Lureau device_class_set_props(dc, cs4231a_properties);
71049ab747fSPaolo Bonzini }
71149ab747fSPaolo Bonzini
71249ab747fSPaolo Bonzini static const TypeInfo cs4231a_info = {
713a3dcca56SAndreas Färber .name = TYPE_CS4231A,
71449ab747fSPaolo Bonzini .parent = TYPE_ISA_DEVICE,
71549ab747fSPaolo Bonzini .instance_size = sizeof (CSState),
716db895a1eSAndreas Färber .instance_init = cs4231a_initfn,
71749ab747fSPaolo Bonzini .class_init = cs4231a_class_initfn,
71849ab747fSPaolo Bonzini };
71949ab747fSPaolo Bonzini
cs4231a_register_types(void)72049ab747fSPaolo Bonzini static void cs4231a_register_types (void)
72149ab747fSPaolo Bonzini {
72249ab747fSPaolo Bonzini type_register_static (&cs4231a_info);
7236497a636SGerd Hoffmann deprecated_register_soundhw("cs4231a", "CS4231A", 1, TYPE_CS4231A);
72449ab747fSPaolo Bonzini }
72549ab747fSPaolo Bonzini
72649ab747fSPaolo Bonzini type_init (cs4231a_register_types)
727