root / hw / lm4549.c @ be62a2eb
History | View | Annotate | Download (9 kB)
1 | d028d02d | Mathieu Sonet | /*
|
---|---|---|---|
2 | d028d02d | Mathieu Sonet | * LM4549 Audio Codec Interface
|
3 | d028d02d | Mathieu Sonet | *
|
4 | d028d02d | Mathieu Sonet | * Copyright (c) 2011
|
5 | d028d02d | Mathieu Sonet | * Written by Mathieu Sonet - www.elasticsheep.com
|
6 | d028d02d | Mathieu Sonet | *
|
7 | 4d8db4e4 | Stefan Weil | * This code is licensed under the GPL.
|
8 | d028d02d | Mathieu Sonet | *
|
9 | d028d02d | Mathieu Sonet | * *****************************************************************
|
10 | d028d02d | Mathieu Sonet | *
|
11 | d028d02d | Mathieu Sonet | * This driver emulates the LM4549 codec.
|
12 | d028d02d | Mathieu Sonet | *
|
13 | d028d02d | Mathieu Sonet | * It supports only one playback voice and no record voice.
|
14 | d028d02d | Mathieu Sonet | */
|
15 | d028d02d | Mathieu Sonet | |
16 | d028d02d | Mathieu Sonet | #include "hw.h" |
17 | d028d02d | Mathieu Sonet | #include "audio/audio.h" |
18 | d028d02d | Mathieu Sonet | #include "lm4549.h" |
19 | d028d02d | Mathieu Sonet | |
20 | d028d02d | Mathieu Sonet | #if 0
|
21 | d028d02d | Mathieu Sonet | #define LM4549_DEBUG 1
|
22 | d028d02d | Mathieu Sonet | #endif
|
23 | d028d02d | Mathieu Sonet | |
24 | d028d02d | Mathieu Sonet | #if 0
|
25 | d028d02d | Mathieu Sonet | #define LM4549_DUMP_DAC_INPUT 1
|
26 | d028d02d | Mathieu Sonet | #endif
|
27 | d028d02d | Mathieu Sonet | |
28 | d028d02d | Mathieu Sonet | #ifdef LM4549_DEBUG
|
29 | d028d02d | Mathieu Sonet | #define DPRINTF(fmt, ...) \
|
30 | d028d02d | Mathieu Sonet | do { printf("lm4549: " fmt , ## __VA_ARGS__); } while (0) |
31 | d028d02d | Mathieu Sonet | #else
|
32 | d028d02d | Mathieu Sonet | #define DPRINTF(fmt, ...) do {} while (0) |
33 | d028d02d | Mathieu Sonet | #endif
|
34 | d028d02d | Mathieu Sonet | |
35 | d028d02d | Mathieu Sonet | #if defined(LM4549_DUMP_DAC_INPUT)
|
36 | d028d02d | Mathieu Sonet | #include <stdio.h> |
37 | d028d02d | Mathieu Sonet | static FILE *fp_dac_input;
|
38 | d028d02d | Mathieu Sonet | #endif
|
39 | d028d02d | Mathieu Sonet | |
40 | d028d02d | Mathieu Sonet | /* LM4549 register list */
|
41 | d028d02d | Mathieu Sonet | enum {
|
42 | d028d02d | Mathieu Sonet | LM4549_Reset = 0x00,
|
43 | d028d02d | Mathieu Sonet | LM4549_Master_Volume = 0x02,
|
44 | d028d02d | Mathieu Sonet | LM4549_Line_Out_Volume = 0x04,
|
45 | d028d02d | Mathieu Sonet | LM4549_Master_Volume_Mono = 0x06,
|
46 | d028d02d | Mathieu Sonet | LM4549_PC_Beep_Volume = 0x0A,
|
47 | d028d02d | Mathieu Sonet | LM4549_Phone_Volume = 0x0C,
|
48 | d028d02d | Mathieu Sonet | LM4549_Mic_Volume = 0x0E,
|
49 | d028d02d | Mathieu Sonet | LM4549_Line_In_Volume = 0x10,
|
50 | d028d02d | Mathieu Sonet | LM4549_CD_Volume = 0x12,
|
51 | d028d02d | Mathieu Sonet | LM4549_Video_Volume = 0x14,
|
52 | d028d02d | Mathieu Sonet | LM4549_Aux_Volume = 0x16,
|
53 | d028d02d | Mathieu Sonet | LM4549_PCM_Out_Volume = 0x18,
|
54 | d028d02d | Mathieu Sonet | LM4549_Record_Select = 0x1A,
|
55 | d028d02d | Mathieu Sonet | LM4549_Record_Gain = 0x1C,
|
56 | d028d02d | Mathieu Sonet | LM4549_General_Purpose = 0x20,
|
57 | d028d02d | Mathieu Sonet | LM4549_3D_Control = 0x22,
|
58 | d028d02d | Mathieu Sonet | LM4549_Powerdown_Ctrl_Stat = 0x26,
|
59 | d028d02d | Mathieu Sonet | LM4549_Ext_Audio_ID = 0x28,
|
60 | d028d02d | Mathieu Sonet | LM4549_Ext_Audio_Stat_Ctrl = 0x2A,
|
61 | d028d02d | Mathieu Sonet | LM4549_PCM_Front_DAC_Rate = 0x2C,
|
62 | d028d02d | Mathieu Sonet | LM4549_PCM_ADC_Rate = 0x32,
|
63 | d028d02d | Mathieu Sonet | LM4549_Vendor_ID1 = 0x7C,
|
64 | d028d02d | Mathieu Sonet | LM4549_Vendor_ID2 = 0x7E
|
65 | d028d02d | Mathieu Sonet | }; |
66 | d028d02d | Mathieu Sonet | |
67 | d028d02d | Mathieu Sonet | static void lm4549_reset(lm4549_state *s) |
68 | d028d02d | Mathieu Sonet | { |
69 | d028d02d | Mathieu Sonet | uint16_t *regfile = s->regfile; |
70 | d028d02d | Mathieu Sonet | |
71 | d028d02d | Mathieu Sonet | regfile[LM4549_Reset] = 0x0d50;
|
72 | d028d02d | Mathieu Sonet | regfile[LM4549_Master_Volume] = 0x8008;
|
73 | d028d02d | Mathieu Sonet | regfile[LM4549_Line_Out_Volume] = 0x8000;
|
74 | d028d02d | Mathieu Sonet | regfile[LM4549_Master_Volume_Mono] = 0x8000;
|
75 | d028d02d | Mathieu Sonet | regfile[LM4549_PC_Beep_Volume] = 0x0000;
|
76 | d028d02d | Mathieu Sonet | regfile[LM4549_Phone_Volume] = 0x8008;
|
77 | d028d02d | Mathieu Sonet | regfile[LM4549_Mic_Volume] = 0x8008;
|
78 | d028d02d | Mathieu Sonet | regfile[LM4549_Line_In_Volume] = 0x8808;
|
79 | d028d02d | Mathieu Sonet | regfile[LM4549_CD_Volume] = 0x8808;
|
80 | d028d02d | Mathieu Sonet | regfile[LM4549_Video_Volume] = 0x8808;
|
81 | d028d02d | Mathieu Sonet | regfile[LM4549_Aux_Volume] = 0x8808;
|
82 | d028d02d | Mathieu Sonet | regfile[LM4549_PCM_Out_Volume] = 0x8808;
|
83 | d028d02d | Mathieu Sonet | regfile[LM4549_Record_Select] = 0x0000;
|
84 | d028d02d | Mathieu Sonet | regfile[LM4549_Record_Gain] = 0x8000;
|
85 | d028d02d | Mathieu Sonet | regfile[LM4549_General_Purpose] = 0x0000;
|
86 | d028d02d | Mathieu Sonet | regfile[LM4549_3D_Control] = 0x0101;
|
87 | d028d02d | Mathieu Sonet | regfile[LM4549_Powerdown_Ctrl_Stat] = 0x000f;
|
88 | d028d02d | Mathieu Sonet | regfile[LM4549_Ext_Audio_ID] = 0x0001;
|
89 | d028d02d | Mathieu Sonet | regfile[LM4549_Ext_Audio_Stat_Ctrl] = 0x0000;
|
90 | d028d02d | Mathieu Sonet | regfile[LM4549_PCM_Front_DAC_Rate] = 0xbb80;
|
91 | d028d02d | Mathieu Sonet | regfile[LM4549_PCM_ADC_Rate] = 0xbb80;
|
92 | d028d02d | Mathieu Sonet | regfile[LM4549_Vendor_ID1] = 0x4e53;
|
93 | d028d02d | Mathieu Sonet | regfile[LM4549_Vendor_ID2] = 0x4331;
|
94 | d028d02d | Mathieu Sonet | } |
95 | d028d02d | Mathieu Sonet | |
96 | d028d02d | Mathieu Sonet | static void lm4549_audio_transfer(lm4549_state *s) |
97 | d028d02d | Mathieu Sonet | { |
98 | d028d02d | Mathieu Sonet | uint32_t written_bytes, written_samples; |
99 | d028d02d | Mathieu Sonet | uint32_t i; |
100 | d028d02d | Mathieu Sonet | |
101 | d028d02d | Mathieu Sonet | /* Activate the voice */
|
102 | d028d02d | Mathieu Sonet | AUD_set_active_out(s->voice, 1);
|
103 | d028d02d | Mathieu Sonet | s->voice_is_active = 1;
|
104 | d028d02d | Mathieu Sonet | |
105 | d028d02d | Mathieu Sonet | /* Try to write the buffer content */
|
106 | d028d02d | Mathieu Sonet | written_bytes = AUD_write(s->voice, s->buffer, |
107 | d028d02d | Mathieu Sonet | s->buffer_level * sizeof(uint16_t));
|
108 | d028d02d | Mathieu Sonet | written_samples = written_bytes >> 1;
|
109 | d028d02d | Mathieu Sonet | |
110 | d028d02d | Mathieu Sonet | #if defined(LM4549_DUMP_DAC_INPUT)
|
111 | d028d02d | Mathieu Sonet | fwrite(s->buffer, sizeof(uint8_t), written_bytes, fp_dac_input);
|
112 | d028d02d | Mathieu Sonet | #endif
|
113 | d028d02d | Mathieu Sonet | |
114 | d028d02d | Mathieu Sonet | s->buffer_level -= written_samples; |
115 | d028d02d | Mathieu Sonet | |
116 | d028d02d | Mathieu Sonet | if (s->buffer_level > 0) { |
117 | d028d02d | Mathieu Sonet | /* Move the data back to the start of the buffer */
|
118 | d028d02d | Mathieu Sonet | for (i = 0; i < s->buffer_level; i++) { |
119 | d028d02d | Mathieu Sonet | s->buffer[i] = s->buffer[i + written_samples]; |
120 | d028d02d | Mathieu Sonet | } |
121 | d028d02d | Mathieu Sonet | } |
122 | d028d02d | Mathieu Sonet | } |
123 | d028d02d | Mathieu Sonet | |
124 | d028d02d | Mathieu Sonet | static void lm4549_audio_out_callback(void *opaque, int free) |
125 | d028d02d | Mathieu Sonet | { |
126 | d028d02d | Mathieu Sonet | lm4549_state *s = (lm4549_state *)opaque; |
127 | d028d02d | Mathieu Sonet | static uint32_t prev_buffer_level;
|
128 | d028d02d | Mathieu Sonet | |
129 | d028d02d | Mathieu Sonet | #ifdef LM4549_DEBUG
|
130 | d028d02d | Mathieu Sonet | int size = AUD_get_buffer_size_out(s->voice);
|
131 | d028d02d | Mathieu Sonet | DPRINTF("audio_out_callback size = %i free = %i\n", size, free);
|
132 | d028d02d | Mathieu Sonet | #endif
|
133 | d028d02d | Mathieu Sonet | |
134 | d028d02d | Mathieu Sonet | /* Detect that no data are consumed
|
135 | d028d02d | Mathieu Sonet | => disable the voice */
|
136 | d028d02d | Mathieu Sonet | if (s->buffer_level == prev_buffer_level) {
|
137 | d028d02d | Mathieu Sonet | AUD_set_active_out(s->voice, 0);
|
138 | d028d02d | Mathieu Sonet | s->voice_is_active = 0;
|
139 | d028d02d | Mathieu Sonet | } |
140 | d028d02d | Mathieu Sonet | prev_buffer_level = s->buffer_level; |
141 | d028d02d | Mathieu Sonet | |
142 | d028d02d | Mathieu Sonet | /* Check if a buffer transfer is pending */
|
143 | d028d02d | Mathieu Sonet | if (s->buffer_level == LM4549_BUFFER_SIZE) {
|
144 | d028d02d | Mathieu Sonet | lm4549_audio_transfer(s); |
145 | d028d02d | Mathieu Sonet | |
146 | d028d02d | Mathieu Sonet | /* Request more data */
|
147 | d028d02d | Mathieu Sonet | if (s->data_req_cb != NULL) { |
148 | d028d02d | Mathieu Sonet | (s->data_req_cb)(s->opaque); |
149 | d028d02d | Mathieu Sonet | } |
150 | d028d02d | Mathieu Sonet | } |
151 | d028d02d | Mathieu Sonet | } |
152 | d028d02d | Mathieu Sonet | |
153 | d028d02d | Mathieu Sonet | uint32_t lm4549_read(lm4549_state *s, target_phys_addr_t offset) |
154 | d028d02d | Mathieu Sonet | { |
155 | d028d02d | Mathieu Sonet | uint16_t *regfile = s->regfile; |
156 | d028d02d | Mathieu Sonet | uint32_t value = 0;
|
157 | d028d02d | Mathieu Sonet | |
158 | d028d02d | Mathieu Sonet | /* Read the stored value */
|
159 | d028d02d | Mathieu Sonet | assert(offset < 128);
|
160 | d028d02d | Mathieu Sonet | value = regfile[offset]; |
161 | d028d02d | Mathieu Sonet | |
162 | d028d02d | Mathieu Sonet | DPRINTF("read [0x%02x] = 0x%04x\n", offset, value);
|
163 | d028d02d | Mathieu Sonet | |
164 | d028d02d | Mathieu Sonet | return value;
|
165 | d028d02d | Mathieu Sonet | } |
166 | d028d02d | Mathieu Sonet | |
167 | d028d02d | Mathieu Sonet | void lm4549_write(lm4549_state *s,
|
168 | d028d02d | Mathieu Sonet | target_phys_addr_t offset, uint32_t value) |
169 | d028d02d | Mathieu Sonet | { |
170 | d028d02d | Mathieu Sonet | uint16_t *regfile = s->regfile; |
171 | d028d02d | Mathieu Sonet | |
172 | d028d02d | Mathieu Sonet | assert(offset < 128);
|
173 | d028d02d | Mathieu Sonet | DPRINTF("write [0x%02x] = 0x%04x\n", offset, value);
|
174 | d028d02d | Mathieu Sonet | |
175 | d028d02d | Mathieu Sonet | switch (offset) {
|
176 | d028d02d | Mathieu Sonet | case LM4549_Reset:
|
177 | d028d02d | Mathieu Sonet | lm4549_reset(s); |
178 | d028d02d | Mathieu Sonet | break;
|
179 | d028d02d | Mathieu Sonet | |
180 | d028d02d | Mathieu Sonet | case LM4549_PCM_Front_DAC_Rate:
|
181 | d028d02d | Mathieu Sonet | regfile[LM4549_PCM_Front_DAC_Rate] = value; |
182 | d028d02d | Mathieu Sonet | DPRINTF("DAC rate change = %i\n", value);
|
183 | d028d02d | Mathieu Sonet | |
184 | d028d02d | Mathieu Sonet | /* Re-open a voice with the new sample rate */
|
185 | d028d02d | Mathieu Sonet | struct audsettings as;
|
186 | d028d02d | Mathieu Sonet | as.freq = value; |
187 | d028d02d | Mathieu Sonet | as.nchannels = 2;
|
188 | d028d02d | Mathieu Sonet | as.fmt = AUD_FMT_S16; |
189 | d028d02d | Mathieu Sonet | as.endianness = 0;
|
190 | d028d02d | Mathieu Sonet | |
191 | d028d02d | Mathieu Sonet | s->voice = AUD_open_out( |
192 | d028d02d | Mathieu Sonet | &s->card, |
193 | d028d02d | Mathieu Sonet | s->voice, |
194 | d028d02d | Mathieu Sonet | "lm4549.out",
|
195 | d028d02d | Mathieu Sonet | s, |
196 | d028d02d | Mathieu Sonet | lm4549_audio_out_callback, |
197 | d028d02d | Mathieu Sonet | &as |
198 | d028d02d | Mathieu Sonet | ); |
199 | d028d02d | Mathieu Sonet | break;
|
200 | d028d02d | Mathieu Sonet | |
201 | d028d02d | Mathieu Sonet | case LM4549_Powerdown_Ctrl_Stat:
|
202 | d028d02d | Mathieu Sonet | value &= ~0xf;
|
203 | d028d02d | Mathieu Sonet | value |= regfile[LM4549_Powerdown_Ctrl_Stat] & 0xf;
|
204 | d028d02d | Mathieu Sonet | regfile[LM4549_Powerdown_Ctrl_Stat] = value; |
205 | d028d02d | Mathieu Sonet | break;
|
206 | d028d02d | Mathieu Sonet | |
207 | d028d02d | Mathieu Sonet | case LM4549_Ext_Audio_ID:
|
208 | d028d02d | Mathieu Sonet | case LM4549_Vendor_ID1:
|
209 | d028d02d | Mathieu Sonet | case LM4549_Vendor_ID2:
|
210 | d028d02d | Mathieu Sonet | DPRINTF("Write to read-only register 0x%x\n", (int)offset); |
211 | d028d02d | Mathieu Sonet | break;
|
212 | d028d02d | Mathieu Sonet | |
213 | d028d02d | Mathieu Sonet | default:
|
214 | d028d02d | Mathieu Sonet | /* Store the new value */
|
215 | d028d02d | Mathieu Sonet | regfile[offset] = value; |
216 | d028d02d | Mathieu Sonet | break;
|
217 | d028d02d | Mathieu Sonet | } |
218 | d028d02d | Mathieu Sonet | } |
219 | d028d02d | Mathieu Sonet | |
220 | d028d02d | Mathieu Sonet | uint32_t lm4549_write_samples(lm4549_state *s, uint32_t left, uint32_t right) |
221 | d028d02d | Mathieu Sonet | { |
222 | d028d02d | Mathieu Sonet | /* The left and right samples are in 20-bit resolution.
|
223 | d028d02d | Mathieu Sonet | The LM4549 has 18-bit resolution and only uses the bits [19:2].
|
224 | d028d02d | Mathieu Sonet | This model supports 16-bit playback.
|
225 | d028d02d | Mathieu Sonet | */
|
226 | d028d02d | Mathieu Sonet | |
227 | d028d02d | Mathieu Sonet | if (s->buffer_level >= LM4549_BUFFER_SIZE) {
|
228 | d028d02d | Mathieu Sonet | DPRINTF("write_sample Buffer full\n");
|
229 | d028d02d | Mathieu Sonet | return 0; |
230 | d028d02d | Mathieu Sonet | } |
231 | d028d02d | Mathieu Sonet | |
232 | d028d02d | Mathieu Sonet | /* Store 16-bit samples in the buffer */
|
233 | d028d02d | Mathieu Sonet | s->buffer[s->buffer_level++] = (left >> 4);
|
234 | d028d02d | Mathieu Sonet | s->buffer[s->buffer_level++] = (right >> 4);
|
235 | d028d02d | Mathieu Sonet | |
236 | d028d02d | Mathieu Sonet | if (s->buffer_level == LM4549_BUFFER_SIZE) {
|
237 | d028d02d | Mathieu Sonet | /* Trigger the transfer of the buffer to the audio host */
|
238 | d028d02d | Mathieu Sonet | lm4549_audio_transfer(s); |
239 | d028d02d | Mathieu Sonet | } |
240 | d028d02d | Mathieu Sonet | |
241 | d028d02d | Mathieu Sonet | return 1; |
242 | d028d02d | Mathieu Sonet | } |
243 | d028d02d | Mathieu Sonet | |
244 | d028d02d | Mathieu Sonet | static int lm4549_post_load(void *opaque, int version_id) |
245 | d028d02d | Mathieu Sonet | { |
246 | d028d02d | Mathieu Sonet | lm4549_state *s = (lm4549_state *)opaque; |
247 | d028d02d | Mathieu Sonet | uint16_t *regfile = s->regfile; |
248 | d028d02d | Mathieu Sonet | |
249 | d028d02d | Mathieu Sonet | /* Re-open a voice with the current sample rate */
|
250 | d028d02d | Mathieu Sonet | uint32_t freq = regfile[LM4549_PCM_Front_DAC_Rate]; |
251 | d028d02d | Mathieu Sonet | |
252 | d028d02d | Mathieu Sonet | DPRINTF("post_load freq = %i\n", freq);
|
253 | d028d02d | Mathieu Sonet | DPRINTF("post_load voice_is_active = %i\n", s->voice_is_active);
|
254 | d028d02d | Mathieu Sonet | |
255 | d028d02d | Mathieu Sonet | struct audsettings as;
|
256 | d028d02d | Mathieu Sonet | as.freq = freq; |
257 | d028d02d | Mathieu Sonet | as.nchannels = 2;
|
258 | d028d02d | Mathieu Sonet | as.fmt = AUD_FMT_S16; |
259 | d028d02d | Mathieu Sonet | as.endianness = 0;
|
260 | d028d02d | Mathieu Sonet | |
261 | d028d02d | Mathieu Sonet | s->voice = AUD_open_out( |
262 | d028d02d | Mathieu Sonet | &s->card, |
263 | d028d02d | Mathieu Sonet | s->voice, |
264 | d028d02d | Mathieu Sonet | "lm4549.out",
|
265 | d028d02d | Mathieu Sonet | s, |
266 | d028d02d | Mathieu Sonet | lm4549_audio_out_callback, |
267 | d028d02d | Mathieu Sonet | &as |
268 | d028d02d | Mathieu Sonet | ); |
269 | d028d02d | Mathieu Sonet | |
270 | d028d02d | Mathieu Sonet | /* Request data */
|
271 | d028d02d | Mathieu Sonet | if (s->voice_is_active == 1) { |
272 | d028d02d | Mathieu Sonet | lm4549_audio_out_callback(s, AUD_get_buffer_size_out(s->voice)); |
273 | d028d02d | Mathieu Sonet | } |
274 | d028d02d | Mathieu Sonet | |
275 | d028d02d | Mathieu Sonet | return 0; |
276 | d028d02d | Mathieu Sonet | } |
277 | d028d02d | Mathieu Sonet | |
278 | d028d02d | Mathieu Sonet | void lm4549_init(lm4549_state *s, lm4549_callback data_req_cb, void* opaque) |
279 | d028d02d | Mathieu Sonet | { |
280 | d028d02d | Mathieu Sonet | struct audsettings as;
|
281 | d028d02d | Mathieu Sonet | |
282 | d028d02d | Mathieu Sonet | /* Store the callback and opaque pointer */
|
283 | d028d02d | Mathieu Sonet | s->data_req_cb = data_req_cb; |
284 | d028d02d | Mathieu Sonet | s->opaque = opaque; |
285 | d028d02d | Mathieu Sonet | |
286 | d028d02d | Mathieu Sonet | /* Init the registers */
|
287 | d028d02d | Mathieu Sonet | lm4549_reset(s); |
288 | d028d02d | Mathieu Sonet | |
289 | d028d02d | Mathieu Sonet | /* Register an audio card */
|
290 | d028d02d | Mathieu Sonet | AUD_register_card("lm4549", &s->card);
|
291 | d028d02d | Mathieu Sonet | |
292 | d028d02d | Mathieu Sonet | /* Open a default voice */
|
293 | d028d02d | Mathieu Sonet | as.freq = 48000;
|
294 | d028d02d | Mathieu Sonet | as.nchannels = 2;
|
295 | d028d02d | Mathieu Sonet | as.fmt = AUD_FMT_S16; |
296 | d028d02d | Mathieu Sonet | as.endianness = 0;
|
297 | d028d02d | Mathieu Sonet | |
298 | d028d02d | Mathieu Sonet | s->voice = AUD_open_out( |
299 | d028d02d | Mathieu Sonet | &s->card, |
300 | d028d02d | Mathieu Sonet | s->voice, |
301 | d028d02d | Mathieu Sonet | "lm4549.out",
|
302 | d028d02d | Mathieu Sonet | s, |
303 | d028d02d | Mathieu Sonet | lm4549_audio_out_callback, |
304 | d028d02d | Mathieu Sonet | &as |
305 | d028d02d | Mathieu Sonet | ); |
306 | d028d02d | Mathieu Sonet | |
307 | d028d02d | Mathieu Sonet | AUD_set_volume_out(s->voice, 0, 255, 255); |
308 | d028d02d | Mathieu Sonet | |
309 | d028d02d | Mathieu Sonet | s->voice_is_active = 0;
|
310 | d028d02d | Mathieu Sonet | |
311 | d028d02d | Mathieu Sonet | /* Reset the input buffer */
|
312 | d028d02d | Mathieu Sonet | memset(s->buffer, 0x00, sizeof(s->buffer)); |
313 | d028d02d | Mathieu Sonet | s->buffer_level = 0;
|
314 | d028d02d | Mathieu Sonet | |
315 | d028d02d | Mathieu Sonet | #if defined(LM4549_DUMP_DAC_INPUT)
|
316 | d028d02d | Mathieu Sonet | fp_dac_input = fopen("lm4549_dac_input.pcm", "wb"); |
317 | d028d02d | Mathieu Sonet | if (!fp_dac_input) {
|
318 | d028d02d | Mathieu Sonet | hw_error("Unable to open lm4549_dac_input.pcm for writing\n");
|
319 | d028d02d | Mathieu Sonet | } |
320 | d028d02d | Mathieu Sonet | #endif
|
321 | d028d02d | Mathieu Sonet | } |
322 | d028d02d | Mathieu Sonet | |
323 | d028d02d | Mathieu Sonet | const VMStateDescription vmstate_lm4549_state = {
|
324 | d028d02d | Mathieu Sonet | .name = "lm4549_state",
|
325 | d028d02d | Mathieu Sonet | .version_id = 1,
|
326 | d028d02d | Mathieu Sonet | .minimum_version_id = 1,
|
327 | d028d02d | Mathieu Sonet | .minimum_version_id_old = 1,
|
328 | d028d02d | Mathieu Sonet | .post_load = &lm4549_post_load, |
329 | d028d02d | Mathieu Sonet | .fields = (VMStateField[]) { |
330 | d028d02d | Mathieu Sonet | VMSTATE_UINT32(voice_is_active, lm4549_state), |
331 | d028d02d | Mathieu Sonet | VMSTATE_UINT16_ARRAY(regfile, lm4549_state, 128),
|
332 | d028d02d | Mathieu Sonet | VMSTATE_UINT16_ARRAY(buffer, lm4549_state, LM4549_BUFFER_SIZE), |
333 | d028d02d | Mathieu Sonet | VMSTATE_UINT32(buffer_level, lm4549_state), |
334 | d028d02d | Mathieu Sonet | VMSTATE_END_OF_LIST() |
335 | d028d02d | Mathieu Sonet | } |
336 | d028d02d | Mathieu Sonet | }; |