149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini * QEMU ES1370 emulation
349ab747fSPaolo Bonzini *
449ab747fSPaolo Bonzini * Copyright (c) 2005 Vassili Karpov (malc)
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 */
2449ab747fSPaolo Bonzini
25480e4c7aSVolker Rümelin #define DEBUG_ES1370 0
26a4b342a3SVolker Rümelin #define VERBOSE_ES1370 0
2749ab747fSPaolo Bonzini
286086a565SPeter Maydell #include "qemu/osdep.h"
298a824e4dSEduardo Habkost #include "hw/audio/soundhw.h"
3049ab747fSPaolo Bonzini #include "audio/audio.h"
31edf5ca5dSMarkus Armbruster #include "hw/pci/pci_device.h"
32d6454270SMarkus Armbruster #include "migration/vmstate.h"
33480e4c7aSVolker Rümelin #include "qemu/cutils.h"
340b8fa32fSMarkus Armbruster #include "qemu/module.h"
3549ab747fSPaolo Bonzini #include "sysemu/dma.h"
36db1015e9SEduardo Habkost #include "qom/object.h"
370116f746SVolker Rümelin #include "trace.h"
3849ab747fSPaolo Bonzini
3949ab747fSPaolo Bonzini /* Missing stuff:
4049ab747fSPaolo Bonzini SCTRL_P[12](END|ST)INC
4149ab747fSPaolo Bonzini SCTRL_P1SCTRLD
4249ab747fSPaolo Bonzini SCTRL_P2DACSEN
4349ab747fSPaolo Bonzini CTRL_DAC_SYNC
4449ab747fSPaolo Bonzini MIDI
4549ab747fSPaolo Bonzini non looped mode
4649ab747fSPaolo Bonzini surely more
4749ab747fSPaolo Bonzini */
4849ab747fSPaolo Bonzini
4949ab747fSPaolo Bonzini /*
5049ab747fSPaolo Bonzini Following macros and samplerate array were copied verbatim from
5149ab747fSPaolo Bonzini Linux kernel 2.4.30: drivers/sound/es1370.c
5249ab747fSPaolo Bonzini
5349ab747fSPaolo Bonzini Copyright (C) 1998-2001, 2003 Thomas Sailer (t.sailer@alumni.ethz.ch)
5449ab747fSPaolo Bonzini */
5549ab747fSPaolo Bonzini
5649ab747fSPaolo Bonzini /* Start blatant GPL violation */
5749ab747fSPaolo Bonzini
5849ab747fSPaolo Bonzini #define ES1370_REG_CONTROL 0x00
5949ab747fSPaolo Bonzini #define ES1370_REG_STATUS 0x04
6049ab747fSPaolo Bonzini #define ES1370_REG_UART_DATA 0x08
6149ab747fSPaolo Bonzini #define ES1370_REG_UART_STATUS 0x09
6249ab747fSPaolo Bonzini #define ES1370_REG_UART_CONTROL 0x09
6349ab747fSPaolo Bonzini #define ES1370_REG_UART_TEST 0x0a
6449ab747fSPaolo Bonzini #define ES1370_REG_MEMPAGE 0x0c
6549ab747fSPaolo Bonzini #define ES1370_REG_CODEC 0x10
6649ab747fSPaolo Bonzini #define ES1370_REG_SERIAL_CONTROL 0x20
6749ab747fSPaolo Bonzini #define ES1370_REG_DAC1_SCOUNT 0x24
6849ab747fSPaolo Bonzini #define ES1370_REG_DAC2_SCOUNT 0x28
6949ab747fSPaolo Bonzini #define ES1370_REG_ADC_SCOUNT 0x2c
7049ab747fSPaolo Bonzini
7149ab747fSPaolo Bonzini #define ES1370_REG_DAC1_FRAMEADR 0xc30
7249ab747fSPaolo Bonzini #define ES1370_REG_DAC1_FRAMECNT 0xc34
7349ab747fSPaolo Bonzini #define ES1370_REG_DAC2_FRAMEADR 0xc38
7449ab747fSPaolo Bonzini #define ES1370_REG_DAC2_FRAMECNT 0xc3c
7549ab747fSPaolo Bonzini #define ES1370_REG_ADC_FRAMEADR 0xd30
7649ab747fSPaolo Bonzini #define ES1370_REG_ADC_FRAMECNT 0xd34
7749ab747fSPaolo Bonzini #define ES1370_REG_PHANTOM_FRAMEADR 0xd38
7849ab747fSPaolo Bonzini #define ES1370_REG_PHANTOM_FRAMECNT 0xd3c
7949ab747fSPaolo Bonzini
8049ab747fSPaolo Bonzini static const unsigned dac1_samplerate[] = { 5512, 11025, 22050, 44100 };
8149ab747fSPaolo Bonzini
8249ab747fSPaolo Bonzini #define DAC2_SRTODIV(x) (((1411200+(x)/2)/(x))-2)
8349ab747fSPaolo Bonzini #define DAC2_DIVTOSR(x) (1411200/((x)+2))
8449ab747fSPaolo Bonzini
8549ab747fSPaolo Bonzini #define CTRL_ADC_STOP 0x80000000 /* 1 = ADC stopped */
8649ab747fSPaolo Bonzini #define CTRL_XCTL1 0x40000000 /* electret mic bias */
8749ab747fSPaolo Bonzini #define CTRL_OPEN 0x20000000 /* no function, can be read and written */
8849ab747fSPaolo Bonzini #define CTRL_PCLKDIV 0x1fff0000 /* ADC/DAC2 clock divider */
8949ab747fSPaolo Bonzini #define CTRL_SH_PCLKDIV 16
9049ab747fSPaolo Bonzini #define CTRL_MSFMTSEL 0x00008000 /* MPEG serial data fmt: 0 = Sony, 1 = I2S */
9149ab747fSPaolo Bonzini #define CTRL_M_SBB 0x00004000 /* DAC2 clock: 0 = PCLKDIV, 1 = MPEG */
9249ab747fSPaolo Bonzini #define CTRL_WTSRSEL 0x00003000 /* DAC1 clock freq: 0=5512, 1=11025, 2=22050, 3=44100 */
9349ab747fSPaolo Bonzini #define CTRL_SH_WTSRSEL 12
9449ab747fSPaolo Bonzini #define CTRL_DAC_SYNC 0x00000800 /* 1 = DAC2 runs off DAC1 clock */
9549ab747fSPaolo Bonzini #define CTRL_CCB_INTRM 0x00000400 /* 1 = CCB "voice" ints enabled */
9649ab747fSPaolo Bonzini #define CTRL_M_CB 0x00000200 /* recording source: 0 = ADC, 1 = MPEG */
9749ab747fSPaolo Bonzini #define CTRL_XCTL0 0x00000100 /* 0 = Line in, 1 = Line out */
9849ab747fSPaolo Bonzini #define CTRL_BREQ 0x00000080 /* 1 = test mode (internal mem test) */
9949ab747fSPaolo Bonzini #define CTRL_DAC1_EN 0x00000040 /* enable DAC1 */
10049ab747fSPaolo Bonzini #define CTRL_DAC2_EN 0x00000020 /* enable DAC2 */
10149ab747fSPaolo Bonzini #define CTRL_ADC_EN 0x00000010 /* enable ADC */
10249ab747fSPaolo Bonzini #define CTRL_UART_EN 0x00000008 /* enable MIDI uart */
10349ab747fSPaolo Bonzini #define CTRL_JYSTK_EN 0x00000004 /* enable Joystick port (presumably at address 0x200) */
10449ab747fSPaolo Bonzini #define CTRL_CDC_EN 0x00000002 /* enable serial (CODEC) interface */
10549ab747fSPaolo Bonzini #define CTRL_SERR_DIS 0x00000001 /* 1 = disable PCI SERR signal */
10649ab747fSPaolo Bonzini
10749ab747fSPaolo Bonzini #define STAT_INTR 0x80000000 /* wired or of all interrupt bits */
10849ab747fSPaolo Bonzini #define STAT_CSTAT 0x00000400 /* 1 = codec busy or codec write in progress */
10949ab747fSPaolo Bonzini #define STAT_CBUSY 0x00000200 /* 1 = codec busy */
11049ab747fSPaolo Bonzini #define STAT_CWRIP 0x00000100 /* 1 = codec write in progress */
11149ab747fSPaolo Bonzini #define STAT_VC 0x00000060 /* CCB int source, 0=DAC1, 1=DAC2, 2=ADC, 3=undef */
11249ab747fSPaolo Bonzini #define STAT_SH_VC 5
11349ab747fSPaolo Bonzini #define STAT_MCCB 0x00000010 /* CCB int pending */
11449ab747fSPaolo Bonzini #define STAT_UART 0x00000008 /* UART int pending */
11549ab747fSPaolo Bonzini #define STAT_DAC1 0x00000004 /* DAC1 int pending */
11649ab747fSPaolo Bonzini #define STAT_DAC2 0x00000002 /* DAC2 int pending */
11749ab747fSPaolo Bonzini #define STAT_ADC 0x00000001 /* ADC int pending */
11849ab747fSPaolo Bonzini
11949ab747fSPaolo Bonzini #define USTAT_RXINT 0x80 /* UART rx int pending */
12049ab747fSPaolo Bonzini #define USTAT_TXINT 0x04 /* UART tx int pending */
12149ab747fSPaolo Bonzini #define USTAT_TXRDY 0x02 /* UART tx ready */
12249ab747fSPaolo Bonzini #define USTAT_RXRDY 0x01 /* UART rx ready */
12349ab747fSPaolo Bonzini
12449ab747fSPaolo Bonzini #define UCTRL_RXINTEN 0x80 /* 1 = enable RX ints */
12549ab747fSPaolo Bonzini #define UCTRL_TXINTEN 0x60 /* TX int enable field mask */
12649ab747fSPaolo Bonzini #define UCTRL_ENA_TXINT 0x20 /* enable TX int */
12749ab747fSPaolo Bonzini #define UCTRL_CNTRL 0x03 /* control field */
12849ab747fSPaolo Bonzini #define UCTRL_CNTRL_SWR 0x03 /* software reset command */
12949ab747fSPaolo Bonzini
13049ab747fSPaolo Bonzini #define SCTRL_P2ENDINC 0x00380000 /* */
13149ab747fSPaolo Bonzini #define SCTRL_SH_P2ENDINC 19
13249ab747fSPaolo Bonzini #define SCTRL_P2STINC 0x00070000 /* */
13349ab747fSPaolo Bonzini #define SCTRL_SH_P2STINC 16
13449ab747fSPaolo Bonzini #define SCTRL_R1LOOPSEL 0x00008000 /* 0 = loop mode */
13549ab747fSPaolo Bonzini #define SCTRL_P2LOOPSEL 0x00004000 /* 0 = loop mode */
13649ab747fSPaolo Bonzini #define SCTRL_P1LOOPSEL 0x00002000 /* 0 = loop mode */
13749ab747fSPaolo Bonzini #define SCTRL_P2PAUSE 0x00001000 /* 1 = pause mode */
13849ab747fSPaolo Bonzini #define SCTRL_P1PAUSE 0x00000800 /* 1 = pause mode */
13949ab747fSPaolo Bonzini #define SCTRL_R1INTEN 0x00000400 /* enable interrupt */
14049ab747fSPaolo Bonzini #define SCTRL_P2INTEN 0x00000200 /* enable interrupt */
14149ab747fSPaolo Bonzini #define SCTRL_P1INTEN 0x00000100 /* enable interrupt */
14249ab747fSPaolo Bonzini #define SCTRL_P1SCTRLD 0x00000080 /* reload sample count register for DAC1 */
14349ab747fSPaolo Bonzini #define SCTRL_P2DACSEN 0x00000040 /* 1 = DAC2 play back last sample when disabled */
14449ab747fSPaolo Bonzini #define SCTRL_R1SEB 0x00000020 /* 1 = 16bit */
14549ab747fSPaolo Bonzini #define SCTRL_R1SMB 0x00000010 /* 1 = stereo */
14649ab747fSPaolo Bonzini #define SCTRL_R1FMT 0x00000030 /* format mask */
14749ab747fSPaolo Bonzini #define SCTRL_SH_R1FMT 4
14849ab747fSPaolo Bonzini #define SCTRL_P2SEB 0x00000008 /* 1 = 16bit */
14949ab747fSPaolo Bonzini #define SCTRL_P2SMB 0x00000004 /* 1 = stereo */
15049ab747fSPaolo Bonzini #define SCTRL_P2FMT 0x0000000c /* format mask */
15149ab747fSPaolo Bonzini #define SCTRL_SH_P2FMT 2
15249ab747fSPaolo Bonzini #define SCTRL_P1SEB 0x00000002 /* 1 = 16bit */
15349ab747fSPaolo Bonzini #define SCTRL_P1SMB 0x00000001 /* 1 = stereo */
15449ab747fSPaolo Bonzini #define SCTRL_P1FMT 0x00000003 /* format mask */
15549ab747fSPaolo Bonzini #define SCTRL_SH_P1FMT 0
15649ab747fSPaolo Bonzini
15749ab747fSPaolo Bonzini /* End blatant GPL violation */
15849ab747fSPaolo Bonzini
15949ab747fSPaolo Bonzini #define NB_CHANNELS 3
16049ab747fSPaolo Bonzini #define DAC1_CHANNEL 0
16149ab747fSPaolo Bonzini #define DAC2_CHANNEL 1
16249ab747fSPaolo Bonzini #define ADC_CHANNEL 2
16349ab747fSPaolo Bonzini
16449ab747fSPaolo Bonzini static void es1370_dac1_callback (void *opaque, int free);
16549ab747fSPaolo Bonzini static void es1370_dac2_callback (void *opaque, int free);
16649ab747fSPaolo Bonzini static void es1370_adc_callback (void *opaque, int avail);
16749ab747fSPaolo Bonzini
print_ctl(uint32_t val)16849ab747fSPaolo Bonzini static void print_ctl(uint32_t val)
16949ab747fSPaolo Bonzini {
170480e4c7aSVolker Rümelin if (DEBUG_ES1370) {
17149ab747fSPaolo Bonzini char buf[1024];
17249ab747fSPaolo Bonzini
17349ab747fSPaolo Bonzini buf[0] = '\0';
174480e4c7aSVolker Rümelin #define a(n) if (val & CTRL_##n) pstrcat(buf, sizeof(buf), " "#n)
17549ab747fSPaolo Bonzini a(ADC_STOP);
17649ab747fSPaolo Bonzini a(XCTL1);
17749ab747fSPaolo Bonzini a(OPEN);
17849ab747fSPaolo Bonzini a(MSFMTSEL);
17949ab747fSPaolo Bonzini a(M_SBB);
18049ab747fSPaolo Bonzini a(DAC_SYNC);
18149ab747fSPaolo Bonzini a(CCB_INTRM);
18249ab747fSPaolo Bonzini a(M_CB);
18349ab747fSPaolo Bonzini a(XCTL0);
18449ab747fSPaolo Bonzini a(BREQ);
18549ab747fSPaolo Bonzini a(DAC1_EN);
18649ab747fSPaolo Bonzini a(DAC2_EN);
18749ab747fSPaolo Bonzini a(ADC_EN);
18849ab747fSPaolo Bonzini a(UART_EN);
18949ab747fSPaolo Bonzini a(JYSTK_EN);
19049ab747fSPaolo Bonzini a(CDC_EN);
19149ab747fSPaolo Bonzini a(SERR_DIS);
19249ab747fSPaolo Bonzini #undef a
19349ab747fSPaolo Bonzini AUD_log("es1370", "ctl - PCLKDIV %d(DAC2 freq %d), freq %d,%s\n",
19449ab747fSPaolo Bonzini (val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV,
19549ab747fSPaolo Bonzini DAC2_DIVTOSR((val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV),
19649ab747fSPaolo Bonzini dac1_samplerate[(val & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL],
19749ab747fSPaolo Bonzini buf);
19849ab747fSPaolo Bonzini }
199480e4c7aSVolker Rümelin }
20049ab747fSPaolo Bonzini
print_sctl(uint32_t val)20149ab747fSPaolo Bonzini static void print_sctl(uint32_t val)
20249ab747fSPaolo Bonzini {
203480e4c7aSVolker Rümelin if (DEBUG_ES1370) {
20449ab747fSPaolo Bonzini static const char *fmt_names[] = {"8M", "8S", "16M", "16S"};
20549ab747fSPaolo Bonzini char buf[1024];
20649ab747fSPaolo Bonzini
20749ab747fSPaolo Bonzini buf[0] = '\0';
20849ab747fSPaolo Bonzini
209480e4c7aSVolker Rümelin #define a(n) if (val & SCTRL_##n) pstrcat(buf, sizeof(buf), " "#n)
210480e4c7aSVolker Rümelin #define b(n) if (!(val & SCTRL_##n)) pstrcat(buf, sizeof(buf), " "#n)
21149ab747fSPaolo Bonzini b(R1LOOPSEL);
21249ab747fSPaolo Bonzini b(P2LOOPSEL);
21349ab747fSPaolo Bonzini b(P1LOOPSEL);
21449ab747fSPaolo Bonzini a(P2PAUSE);
21549ab747fSPaolo Bonzini a(P1PAUSE);
21649ab747fSPaolo Bonzini a(R1INTEN);
21749ab747fSPaolo Bonzini a(P2INTEN);
21849ab747fSPaolo Bonzini a(P1INTEN);
21949ab747fSPaolo Bonzini a(P1SCTRLD);
22049ab747fSPaolo Bonzini a(P2DACSEN);
22149ab747fSPaolo Bonzini if (buf[0]) {
222480e4c7aSVolker Rümelin pstrcat(buf, sizeof(buf), "\n ");
223480e4c7aSVolker Rümelin } else {
22449ab747fSPaolo Bonzini buf[0] = ' ';
22549ab747fSPaolo Bonzini buf[1] = '\0';
22649ab747fSPaolo Bonzini }
22749ab747fSPaolo Bonzini #undef b
22849ab747fSPaolo Bonzini #undef a
22949ab747fSPaolo Bonzini AUD_log("es1370",
230480e4c7aSVolker Rümelin "%s p2_end_inc %d, p2_st_inc %d,"
231480e4c7aSVolker Rümelin " r1_fmt %s, p2_fmt %s, p1_fmt %s\n",
23249ab747fSPaolo Bonzini buf,
23349ab747fSPaolo Bonzini (val & SCTRL_P2ENDINC) >> SCTRL_SH_P2ENDINC,
23449ab747fSPaolo Bonzini (val & SCTRL_P2STINC) >> SCTRL_SH_P2STINC,
23549ab747fSPaolo Bonzini fmt_names[(val >> SCTRL_SH_R1FMT) & 3],
23649ab747fSPaolo Bonzini fmt_names[(val >> SCTRL_SH_P2FMT) & 3],
237480e4c7aSVolker Rümelin fmt_names[(val >> SCTRL_SH_P1FMT) & 3]);
23849ab747fSPaolo Bonzini }
239480e4c7aSVolker Rümelin }
24049ab747fSPaolo Bonzini
241a4b342a3SVolker Rümelin #define lwarn(...) \
242a4b342a3SVolker Rümelin do { \
243a4b342a3SVolker Rümelin if (VERBOSE_ES1370) { \
244a4b342a3SVolker Rümelin AUD_log("es1370: warning", __VA_ARGS__); \
245a4b342a3SVolker Rümelin } \
246a4b342a3SVolker Rümelin } while (0)
24749ab747fSPaolo Bonzini
248d9c214d7SPhilippe Mathieu-Daudé #define TYPE_ES1370 "ES1370"
249d9c214d7SPhilippe Mathieu-Daudé OBJECT_DECLARE_SIMPLE_TYPE(ES1370State, ES1370)
250d9c214d7SPhilippe Mathieu-Daudé
25149ab747fSPaolo Bonzini struct chan {
25249ab747fSPaolo Bonzini uint32_t shift;
25349ab747fSPaolo Bonzini uint32_t leftover;
25449ab747fSPaolo Bonzini uint32_t scount;
25549ab747fSPaolo Bonzini uint32_t frame_addr;
25649ab747fSPaolo Bonzini uint32_t frame_cnt;
25749ab747fSPaolo Bonzini };
25849ab747fSPaolo Bonzini
259db1015e9SEduardo Habkost struct ES1370State {
26049ab747fSPaolo Bonzini PCIDevice dev;
26149ab747fSPaolo Bonzini QEMUSoundCard card;
26249ab747fSPaolo Bonzini MemoryRegion io;
26349ab747fSPaolo Bonzini struct chan chan[NB_CHANNELS];
26449ab747fSPaolo Bonzini SWVoiceOut *dac_voice[2];
26549ab747fSPaolo Bonzini SWVoiceIn *adc_voice;
26649ab747fSPaolo Bonzini
26749ab747fSPaolo Bonzini uint32_t ctl;
26849ab747fSPaolo Bonzini uint32_t status;
26949ab747fSPaolo Bonzini uint32_t mempage;
27049ab747fSPaolo Bonzini uint32_t codec;
27149ab747fSPaolo Bonzini uint32_t sctl;
272db1015e9SEduardo Habkost };
27349ab747fSPaolo Bonzini
27449ab747fSPaolo Bonzini struct chan_bits {
27549ab747fSPaolo Bonzini uint32_t ctl_en;
27649ab747fSPaolo Bonzini uint32_t stat_int;
27749ab747fSPaolo Bonzini uint32_t sctl_pause;
27849ab747fSPaolo Bonzini uint32_t sctl_inten;
27949ab747fSPaolo Bonzini uint32_t sctl_fmt;
28049ab747fSPaolo Bonzini uint32_t sctl_sh_fmt;
28149ab747fSPaolo Bonzini uint32_t sctl_loopsel;
28249ab747fSPaolo Bonzini void (*calc_freq) (ES1370State *s, uint32_t ctl,
28349ab747fSPaolo Bonzini uint32_t *old_freq, uint32_t *new_freq);
28449ab747fSPaolo Bonzini };
28549ab747fSPaolo Bonzini
28649ab747fSPaolo Bonzini static void es1370_dac1_calc_freq (ES1370State *s, uint32_t ctl,
28749ab747fSPaolo Bonzini uint32_t *old_freq, uint32_t *new_freq);
28849ab747fSPaolo Bonzini static void es1370_dac2_and_adc_calc_freq (ES1370State *s, uint32_t ctl,
28949ab747fSPaolo Bonzini uint32_t *old_freq,
29049ab747fSPaolo Bonzini uint32_t *new_freq);
29149ab747fSPaolo Bonzini
29249ab747fSPaolo Bonzini static const struct chan_bits es1370_chan_bits[] = {
29349ab747fSPaolo Bonzini {CTRL_DAC1_EN, STAT_DAC1, SCTRL_P1PAUSE, SCTRL_P1INTEN,
29449ab747fSPaolo Bonzini SCTRL_P1FMT, SCTRL_SH_P1FMT, SCTRL_P1LOOPSEL,
29549ab747fSPaolo Bonzini es1370_dac1_calc_freq},
29649ab747fSPaolo Bonzini
29749ab747fSPaolo Bonzini {CTRL_DAC2_EN, STAT_DAC2, SCTRL_P2PAUSE, SCTRL_P2INTEN,
29849ab747fSPaolo Bonzini SCTRL_P2FMT, SCTRL_SH_P2FMT, SCTRL_P2LOOPSEL,
29949ab747fSPaolo Bonzini es1370_dac2_and_adc_calc_freq},
30049ab747fSPaolo Bonzini
30149ab747fSPaolo Bonzini {CTRL_ADC_EN, STAT_ADC, 0, SCTRL_R1INTEN,
30249ab747fSPaolo Bonzini SCTRL_R1FMT, SCTRL_SH_R1FMT, SCTRL_R1LOOPSEL,
30349ab747fSPaolo Bonzini es1370_dac2_and_adc_calc_freq}
30449ab747fSPaolo Bonzini };
30549ab747fSPaolo Bonzini
es1370_update_status(ES1370State * s,uint32_t new_status)30649ab747fSPaolo Bonzini static void es1370_update_status (ES1370State *s, uint32_t new_status)
30749ab747fSPaolo Bonzini {
30849ab747fSPaolo Bonzini uint32_t level = new_status & (STAT_DAC1 | STAT_DAC2 | STAT_ADC);
30949ab747fSPaolo Bonzini
31049ab747fSPaolo Bonzini if (level) {
31149ab747fSPaolo Bonzini s->status = new_status | STAT_INTR;
31202e7de68SVolker Rümelin } else {
31349ab747fSPaolo Bonzini s->status = new_status & ~STAT_INTR;
31449ab747fSPaolo Bonzini }
3159e64f8a3SMarcel Apfelbaum pci_set_irq(&s->dev, !!level);
31649ab747fSPaolo Bonzini }
31749ab747fSPaolo Bonzini
es1370_reset(ES1370State * s)31849ab747fSPaolo Bonzini static void es1370_reset (ES1370State *s)
31949ab747fSPaolo Bonzini {
32049ab747fSPaolo Bonzini size_t i;
32149ab747fSPaolo Bonzini
32249ab747fSPaolo Bonzini s->ctl = 1;
32349ab747fSPaolo Bonzini s->status = 0x60;
32449ab747fSPaolo Bonzini s->mempage = 0;
32549ab747fSPaolo Bonzini s->codec = 0;
32649ab747fSPaolo Bonzini s->sctl = 0;
32749ab747fSPaolo Bonzini
32849ab747fSPaolo Bonzini for (i = 0; i < NB_CHANNELS; ++i) {
32949ab747fSPaolo Bonzini struct chan *d = &s->chan[i];
33049ab747fSPaolo Bonzini d->scount = 0;
33149ab747fSPaolo Bonzini d->leftover = 0;
33249ab747fSPaolo Bonzini if (i == ADC_CHANNEL) {
33349ab747fSPaolo Bonzini AUD_close_in (&s->card, s->adc_voice);
33449ab747fSPaolo Bonzini s->adc_voice = NULL;
33502e7de68SVolker Rümelin } else {
33649ab747fSPaolo Bonzini AUD_close_out (&s->card, s->dac_voice[i]);
33749ab747fSPaolo Bonzini s->dac_voice[i] = NULL;
33849ab747fSPaolo Bonzini }
33949ab747fSPaolo Bonzini }
3409e64f8a3SMarcel Apfelbaum pci_irq_deassert(&s->dev);
34149ab747fSPaolo Bonzini }
34249ab747fSPaolo Bonzini
es1370_maybe_lower_irq(ES1370State * s,uint32_t sctl)34349ab747fSPaolo Bonzini static void es1370_maybe_lower_irq (ES1370State *s, uint32_t sctl)
34449ab747fSPaolo Bonzini {
34549ab747fSPaolo Bonzini uint32_t new_status = s->status;
34649ab747fSPaolo Bonzini
34749ab747fSPaolo Bonzini if (!(sctl & SCTRL_P1INTEN) && (s->sctl & SCTRL_P1INTEN)) {
34849ab747fSPaolo Bonzini new_status &= ~STAT_DAC1;
34949ab747fSPaolo Bonzini }
35049ab747fSPaolo Bonzini
35149ab747fSPaolo Bonzini if (!(sctl & SCTRL_P2INTEN) && (s->sctl & SCTRL_P2INTEN)) {
35249ab747fSPaolo Bonzini new_status &= ~STAT_DAC2;
35349ab747fSPaolo Bonzini }
35449ab747fSPaolo Bonzini
35549ab747fSPaolo Bonzini if (!(sctl & SCTRL_R1INTEN) && (s->sctl & SCTRL_R1INTEN)) {
35649ab747fSPaolo Bonzini new_status &= ~STAT_ADC;
35749ab747fSPaolo Bonzini }
35849ab747fSPaolo Bonzini
35949ab747fSPaolo Bonzini if (new_status != s->status) {
36049ab747fSPaolo Bonzini es1370_update_status (s, new_status);
36149ab747fSPaolo Bonzini }
36249ab747fSPaolo Bonzini }
36349ab747fSPaolo Bonzini
es1370_dac1_calc_freq(ES1370State * s,uint32_t ctl,uint32_t * old_freq,uint32_t * new_freq)36449ab747fSPaolo Bonzini static void es1370_dac1_calc_freq (ES1370State *s, uint32_t ctl,
36549ab747fSPaolo Bonzini uint32_t *old_freq, uint32_t *new_freq)
36649ab747fSPaolo Bonzini
36749ab747fSPaolo Bonzini {
36849ab747fSPaolo Bonzini *old_freq = dac1_samplerate[(s->ctl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
36949ab747fSPaolo Bonzini *new_freq = dac1_samplerate[(ctl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
37049ab747fSPaolo Bonzini }
37149ab747fSPaolo Bonzini
es1370_dac2_and_adc_calc_freq(ES1370State * s,uint32_t ctl,uint32_t * old_freq,uint32_t * new_freq)37249ab747fSPaolo Bonzini static void es1370_dac2_and_adc_calc_freq (ES1370State *s, uint32_t ctl,
37349ab747fSPaolo Bonzini uint32_t *old_freq,
37449ab747fSPaolo Bonzini uint32_t *new_freq)
37549ab747fSPaolo Bonzini
37649ab747fSPaolo Bonzini {
37749ab747fSPaolo Bonzini uint32_t old_pclkdiv, new_pclkdiv;
37849ab747fSPaolo Bonzini
37949ab747fSPaolo Bonzini new_pclkdiv = (ctl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV;
38049ab747fSPaolo Bonzini old_pclkdiv = (s->ctl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV;
38149ab747fSPaolo Bonzini *new_freq = DAC2_DIVTOSR (new_pclkdiv);
38249ab747fSPaolo Bonzini *old_freq = DAC2_DIVTOSR (old_pclkdiv);
38349ab747fSPaolo Bonzini }
38449ab747fSPaolo Bonzini
es1370_update_voices(ES1370State * s,uint32_t ctl,uint32_t sctl)38549ab747fSPaolo Bonzini static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl)
38649ab747fSPaolo Bonzini {
38749ab747fSPaolo Bonzini size_t i;
38849ab747fSPaolo Bonzini uint32_t old_freq, new_freq, old_fmt, new_fmt;
38949ab747fSPaolo Bonzini
39049ab747fSPaolo Bonzini for (i = 0; i < NB_CHANNELS; ++i) {
39149ab747fSPaolo Bonzini struct chan *d = &s->chan[i];
39249ab747fSPaolo Bonzini const struct chan_bits *b = &es1370_chan_bits[i];
39349ab747fSPaolo Bonzini
39449ab747fSPaolo Bonzini new_fmt = (sctl & b->sctl_fmt) >> b->sctl_sh_fmt;
39549ab747fSPaolo Bonzini old_fmt = (s->sctl & b->sctl_fmt) >> b->sctl_sh_fmt;
39649ab747fSPaolo Bonzini
39749ab747fSPaolo Bonzini b->calc_freq (s, ctl, &old_freq, &new_freq);
39849ab747fSPaolo Bonzini
39949ab747fSPaolo Bonzini if ((old_fmt != new_fmt) || (old_freq != new_freq)) {
40049ab747fSPaolo Bonzini d->shift = (new_fmt & 1) + (new_fmt >> 1);
4010116f746SVolker Rümelin trace_es1370_stream_format(i, new_freq,
4020116f746SVolker Rümelin new_fmt & 2 ? "s16" : "u8", new_fmt & 1 ? "stereo" : "mono",
40349ab747fSPaolo Bonzini d->shift);
40449ab747fSPaolo Bonzini if (new_freq) {
40549ab747fSPaolo Bonzini struct audsettings as;
40649ab747fSPaolo Bonzini
40749ab747fSPaolo Bonzini as.freq = new_freq;
40849ab747fSPaolo Bonzini as.nchannels = 1 << (new_fmt & 1);
40985bc5852SKővágó, Zoltán as.fmt = (new_fmt & 2) ? AUDIO_FORMAT_S16 : AUDIO_FORMAT_U8;
41049ab747fSPaolo Bonzini as.endianness = 0;
41149ab747fSPaolo Bonzini
41249ab747fSPaolo Bonzini if (i == ADC_CHANNEL) {
41349ab747fSPaolo Bonzini s->adc_voice =
41449ab747fSPaolo Bonzini AUD_open_in (
41549ab747fSPaolo Bonzini &s->card,
41649ab747fSPaolo Bonzini s->adc_voice,
41749ab747fSPaolo Bonzini "es1370.adc",
41849ab747fSPaolo Bonzini s,
41949ab747fSPaolo Bonzini es1370_adc_callback,
42049ab747fSPaolo Bonzini &as
42149ab747fSPaolo Bonzini );
42202e7de68SVolker Rümelin } else {
42349ab747fSPaolo Bonzini s->dac_voice[i] =
42449ab747fSPaolo Bonzini AUD_open_out (
42549ab747fSPaolo Bonzini &s->card,
42649ab747fSPaolo Bonzini s->dac_voice[i],
42749ab747fSPaolo Bonzini i ? "es1370.dac2" : "es1370.dac1",
42849ab747fSPaolo Bonzini s,
42949ab747fSPaolo Bonzini i ? es1370_dac2_callback : es1370_dac1_callback,
43049ab747fSPaolo Bonzini &as
43149ab747fSPaolo Bonzini );
43249ab747fSPaolo Bonzini }
43349ab747fSPaolo Bonzini }
43449ab747fSPaolo Bonzini }
43549ab747fSPaolo Bonzini
43649ab747fSPaolo Bonzini if (((ctl ^ s->ctl) & b->ctl_en)
43749ab747fSPaolo Bonzini || ((sctl ^ s->sctl) & b->sctl_pause)) {
43849ab747fSPaolo Bonzini int on = (ctl & b->ctl_en) && !(sctl & b->sctl_pause);
43949ab747fSPaolo Bonzini
44049ab747fSPaolo Bonzini if (i == ADC_CHANNEL) {
44149ab747fSPaolo Bonzini AUD_set_active_in (s->adc_voice, on);
44202e7de68SVolker Rümelin } else {
44349ab747fSPaolo Bonzini AUD_set_active_out (s->dac_voice[i], on);
44449ab747fSPaolo Bonzini }
44549ab747fSPaolo Bonzini }
44649ab747fSPaolo Bonzini }
44749ab747fSPaolo Bonzini
44849ab747fSPaolo Bonzini s->ctl = ctl;
44949ab747fSPaolo Bonzini s->sctl = sctl;
45049ab747fSPaolo Bonzini }
45149ab747fSPaolo Bonzini
es1370_fixup(ES1370State * s,uint32_t addr)45249ab747fSPaolo Bonzini static inline uint32_t es1370_fixup (ES1370State *s, uint32_t addr)
45349ab747fSPaolo Bonzini {
45449ab747fSPaolo Bonzini addr &= 0xff;
45502e7de68SVolker Rümelin if (addr >= 0x30 && addr <= 0x3f) {
45649ab747fSPaolo Bonzini addr |= s->mempage << 8;
45702e7de68SVolker Rümelin }
45849ab747fSPaolo Bonzini return addr;
45949ab747fSPaolo Bonzini }
46049ab747fSPaolo Bonzini
es1370_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)461154c1d1fSPaolo Bonzini static void es1370_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
46249ab747fSPaolo Bonzini {
46349ab747fSPaolo Bonzini ES1370State *s = opaque;
46449ab747fSPaolo Bonzini struct chan *d = &s->chan[0];
46549ab747fSPaolo Bonzini
46649ab747fSPaolo Bonzini addr = es1370_fixup (s, addr);
46749ab747fSPaolo Bonzini
46849ab747fSPaolo Bonzini switch (addr) {
46949ab747fSPaolo Bonzini case ES1370_REG_CONTROL:
47049ab747fSPaolo Bonzini es1370_update_voices (s, val, s->sctl);
47149ab747fSPaolo Bonzini print_ctl (val);
47249ab747fSPaolo Bonzini break;
47349ab747fSPaolo Bonzini
47449ab747fSPaolo Bonzini case ES1370_REG_MEMPAGE:
47549ab747fSPaolo Bonzini s->mempage = val & 0xf;
47649ab747fSPaolo Bonzini break;
47749ab747fSPaolo Bonzini
47849ab747fSPaolo Bonzini case ES1370_REG_SERIAL_CONTROL:
47949ab747fSPaolo Bonzini es1370_maybe_lower_irq (s, val);
48049ab747fSPaolo Bonzini es1370_update_voices (s, s->ctl, val);
48149ab747fSPaolo Bonzini print_sctl (val);
48249ab747fSPaolo Bonzini break;
48349ab747fSPaolo Bonzini
48449ab747fSPaolo Bonzini case ES1370_REG_DAC1_SCOUNT:
485154c1d1fSPaolo Bonzini case ES1370_REG_DAC2_SCOUNT:
486154c1d1fSPaolo Bonzini case ES1370_REG_ADC_SCOUNT:
487154c1d1fSPaolo Bonzini d += (addr - ES1370_REG_DAC1_SCOUNT) >> 2;
48800e3b29dSVolker Rümelin d->scount = (val & 0xffff) << 16 | (val & 0xffff);
4890116f746SVolker Rümelin trace_es1370_sample_count_wr(d - &s->chan[0],
4900116f746SVolker Rümelin d->scount >> 16, d->scount & 0xffff);
49149ab747fSPaolo Bonzini break;
49249ab747fSPaolo Bonzini
493cf9270e5SPaolo Bonzini case ES1370_REG_ADC_FRAMEADR:
494cf9270e5SPaolo Bonzini d += 2;
495cf9270e5SPaolo Bonzini goto frameadr;
49649ab747fSPaolo Bonzini case ES1370_REG_DAC1_FRAMEADR:
497154c1d1fSPaolo Bonzini case ES1370_REG_DAC2_FRAMEADR:
498154c1d1fSPaolo Bonzini d += (addr - ES1370_REG_DAC1_FRAMEADR) >> 3;
499cf9270e5SPaolo Bonzini frameadr:
50049ab747fSPaolo Bonzini d->frame_addr = val;
5010116f746SVolker Rümelin trace_es1370_frame_address_wr(d - &s->chan[0], d->frame_addr);
50249ab747fSPaolo Bonzini break;
50349ab747fSPaolo Bonzini
50449ab747fSPaolo Bonzini case ES1370_REG_PHANTOM_FRAMECNT:
505a4b342a3SVolker Rümelin lwarn("writing to phantom frame count 0x%" PRIx64 "\n", val);
50649ab747fSPaolo Bonzini break;
50749ab747fSPaolo Bonzini case ES1370_REG_PHANTOM_FRAMEADR:
508a4b342a3SVolker Rümelin lwarn("writing to phantom frame address 0x%" PRIx64 "\n", val);
50949ab747fSPaolo Bonzini break;
51049ab747fSPaolo Bonzini
511cf9270e5SPaolo Bonzini case ES1370_REG_ADC_FRAMECNT:
512cf9270e5SPaolo Bonzini d += 2;
513cf9270e5SPaolo Bonzini goto framecnt;
51449ab747fSPaolo Bonzini case ES1370_REG_DAC1_FRAMECNT:
515154c1d1fSPaolo Bonzini case ES1370_REG_DAC2_FRAMECNT:
516154c1d1fSPaolo Bonzini d += (addr - ES1370_REG_DAC1_FRAMECNT) >> 3;
517cf9270e5SPaolo Bonzini framecnt:
51849ab747fSPaolo Bonzini d->frame_cnt = val;
51949ab747fSPaolo Bonzini d->leftover = 0;
5200116f746SVolker Rümelin trace_es1370_frame_count_wr(d - &s->chan[0],
5210116f746SVolker Rümelin d->frame_cnt >> 16, d->frame_cnt & 0xffff);
52249ab747fSPaolo Bonzini break;
52349ab747fSPaolo Bonzini
52449ab747fSPaolo Bonzini default:
525a4b342a3SVolker Rümelin lwarn("writel 0x%" PRIx64 " <- 0x%" PRIx64 "\n", addr, val);
52649ab747fSPaolo Bonzini break;
52749ab747fSPaolo Bonzini }
52849ab747fSPaolo Bonzini }
52949ab747fSPaolo Bonzini
es1370_read(void * opaque,hwaddr addr,unsigned size)530154c1d1fSPaolo Bonzini static uint64_t es1370_read(void *opaque, hwaddr addr, unsigned size)
53149ab747fSPaolo Bonzini {
53249ab747fSPaolo Bonzini ES1370State *s = opaque;
53349ab747fSPaolo Bonzini uint32_t val;
53449ab747fSPaolo Bonzini struct chan *d = &s->chan[0];
53549ab747fSPaolo Bonzini
53649ab747fSPaolo Bonzini addr = es1370_fixup (s, addr);
53749ab747fSPaolo Bonzini
53849ab747fSPaolo Bonzini switch (addr) {
53949ab747fSPaolo Bonzini case ES1370_REG_CONTROL:
54049ab747fSPaolo Bonzini val = s->ctl;
54149ab747fSPaolo Bonzini break;
54249ab747fSPaolo Bonzini case ES1370_REG_STATUS:
54349ab747fSPaolo Bonzini val = s->status;
54449ab747fSPaolo Bonzini break;
54549ab747fSPaolo Bonzini case ES1370_REG_MEMPAGE:
54649ab747fSPaolo Bonzini val = s->mempage;
54749ab747fSPaolo Bonzini break;
54849ab747fSPaolo Bonzini case ES1370_REG_CODEC:
54949ab747fSPaolo Bonzini val = s->codec;
55049ab747fSPaolo Bonzini break;
55149ab747fSPaolo Bonzini case ES1370_REG_SERIAL_CONTROL:
55249ab747fSPaolo Bonzini val = s->sctl;
55349ab747fSPaolo Bonzini break;
55449ab747fSPaolo Bonzini
55549ab747fSPaolo Bonzini case ES1370_REG_DAC1_SCOUNT:
556154c1d1fSPaolo Bonzini case ES1370_REG_DAC2_SCOUNT:
557154c1d1fSPaolo Bonzini case ES1370_REG_ADC_SCOUNT:
558154c1d1fSPaolo Bonzini d += (addr - ES1370_REG_DAC1_SCOUNT) >> 2;
5590116f746SVolker Rümelin trace_es1370_sample_count_rd(d - &s->chan[0],
5600116f746SVolker Rümelin d->scount >> 16, d->scount & 0xffff);
56149ab747fSPaolo Bonzini val = d->scount;
56249ab747fSPaolo Bonzini break;
56349ab747fSPaolo Bonzini
56424f7973bSPaolo Bonzini case ES1370_REG_ADC_FRAMECNT:
56524f7973bSPaolo Bonzini d += 2;
56624f7973bSPaolo Bonzini goto framecnt;
56749ab747fSPaolo Bonzini case ES1370_REG_DAC1_FRAMECNT:
568154c1d1fSPaolo Bonzini case ES1370_REG_DAC2_FRAMECNT:
569154c1d1fSPaolo Bonzini d += (addr - ES1370_REG_DAC1_FRAMECNT) >> 3;
57024f7973bSPaolo Bonzini framecnt:
5710116f746SVolker Rümelin trace_es1370_frame_count_rd(d - &s->chan[0],
5720116f746SVolker Rümelin d->frame_cnt >> 16, d->frame_cnt & 0xffff);
57349ab747fSPaolo Bonzini val = d->frame_cnt;
57449ab747fSPaolo Bonzini break;
57549ab747fSPaolo Bonzini
57624f7973bSPaolo Bonzini case ES1370_REG_ADC_FRAMEADR:
57724f7973bSPaolo Bonzini d += 2;
57824f7973bSPaolo Bonzini goto frameadr;
57949ab747fSPaolo Bonzini case ES1370_REG_DAC1_FRAMEADR:
580154c1d1fSPaolo Bonzini case ES1370_REG_DAC2_FRAMEADR:
581154c1d1fSPaolo Bonzini d += (addr - ES1370_REG_DAC1_FRAMEADR) >> 3;
58224f7973bSPaolo Bonzini frameadr:
5830116f746SVolker Rümelin trace_es1370_frame_address_rd(d - &s->chan[0], d->frame_addr);
58449ab747fSPaolo Bonzini val = d->frame_addr;
58549ab747fSPaolo Bonzini break;
58649ab747fSPaolo Bonzini
58749ab747fSPaolo Bonzini case ES1370_REG_PHANTOM_FRAMECNT:
58849ab747fSPaolo Bonzini val = ~0U;
58949ab747fSPaolo Bonzini lwarn("reading from phantom frame count\n");
59049ab747fSPaolo Bonzini break;
59149ab747fSPaolo Bonzini case ES1370_REG_PHANTOM_FRAMEADR:
59249ab747fSPaolo Bonzini val = ~0U;
59349ab747fSPaolo Bonzini lwarn("reading from phantom frame address\n");
59449ab747fSPaolo Bonzini break;
59549ab747fSPaolo Bonzini
59649ab747fSPaolo Bonzini default:
59749ab747fSPaolo Bonzini val = ~0U;
598a4b342a3SVolker Rümelin lwarn("readl 0x%" PRIx64 " -> 0x%x\n", addr, val);
59949ab747fSPaolo Bonzini break;
60049ab747fSPaolo Bonzini }
60149ab747fSPaolo Bonzini return val;
60249ab747fSPaolo Bonzini }
60349ab747fSPaolo Bonzini
es1370_transfer_audio(ES1370State * s,struct chan * d,int loop_sel,int max,bool * irq)60449ab747fSPaolo Bonzini static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
6055bf1a71cSVolker Rümelin int max, bool *irq)
60649ab747fSPaolo Bonzini {
60749ab747fSPaolo Bonzini uint8_t tmpbuf[4096];
608ca988518SVolker Rümelin size_t to_transfer;
60949ab747fSPaolo Bonzini uint32_t addr = d->frame_addr;
61049ab747fSPaolo Bonzini int sc = d->scount & 0xffff;
61149ab747fSPaolo Bonzini int csc = d->scount >> 16;
61249ab747fSPaolo Bonzini int csc_bytes = (csc + 1) << d->shift;
61349ab747fSPaolo Bonzini int cnt = d->frame_cnt >> 16;
61449ab747fSPaolo Bonzini int size = d->frame_cnt & 0xffff;
615369ff955SPrasad J Pandit if (size < cnt) {
616369ff955SPrasad J Pandit return;
617369ff955SPrasad J Pandit }
61849ab747fSPaolo Bonzini int left = ((size - cnt + 1) << 2) + d->leftover;
61949ab747fSPaolo Bonzini int transferred = 0;
62049ab747fSPaolo Bonzini int index = d - &s->chan[0];
62149ab747fSPaolo Bonzini
622ca988518SVolker Rümelin to_transfer = MIN(max, MIN(left, csc_bytes));
62349ab747fSPaolo Bonzini addr += (cnt << 2) + d->leftover;
62449ab747fSPaolo Bonzini
62549ab747fSPaolo Bonzini if (index == ADC_CHANNEL) {
626ca988518SVolker Rümelin while (to_transfer > 0) {
62749ab747fSPaolo Bonzini int acquired, to_copy;
62849ab747fSPaolo Bonzini
629ca988518SVolker Rümelin to_copy = MIN(to_transfer, sizeof(tmpbuf));
63049ab747fSPaolo Bonzini acquired = AUD_read (s->adc_voice, tmpbuf, to_copy);
63102e7de68SVolker Rümelin if (!acquired) {
63249ab747fSPaolo Bonzini break;
63302e7de68SVolker Rümelin }
63449ab747fSPaolo Bonzini
63549ab747fSPaolo Bonzini pci_dma_write (&s->dev, addr, tmpbuf, acquired);
63649ab747fSPaolo Bonzini
637ca988518SVolker Rümelin to_transfer -= acquired;
63849ab747fSPaolo Bonzini addr += acquired;
63949ab747fSPaolo Bonzini transferred += acquired;
64049ab747fSPaolo Bonzini }
64102e7de68SVolker Rümelin } else {
64249ab747fSPaolo Bonzini SWVoiceOut *voice = s->dac_voice[index];
64349ab747fSPaolo Bonzini
644ca988518SVolker Rümelin while (to_transfer > 0) {
64549ab747fSPaolo Bonzini int copied, to_copy;
64649ab747fSPaolo Bonzini
647ca988518SVolker Rümelin to_copy = MIN(to_transfer, sizeof(tmpbuf));
64849ab747fSPaolo Bonzini pci_dma_read (&s->dev, addr, tmpbuf, to_copy);
64949ab747fSPaolo Bonzini copied = AUD_write (voice, tmpbuf, to_copy);
65002e7de68SVolker Rümelin if (!copied) {
65149ab747fSPaolo Bonzini break;
65202e7de68SVolker Rümelin }
653ca988518SVolker Rümelin to_transfer -= copied;
65449ab747fSPaolo Bonzini addr += copied;
65549ab747fSPaolo Bonzini transferred += copied;
65649ab747fSPaolo Bonzini }
65749ab747fSPaolo Bonzini }
65849ab747fSPaolo Bonzini
65949ab747fSPaolo Bonzini if (csc_bytes == transferred) {
6605bf1a71cSVolker Rümelin if (*irq) {
6615bf1a71cSVolker Rümelin trace_es1370_lost_interrupt(index);
6625bf1a71cSVolker Rümelin }
6635bf1a71cSVolker Rümelin *irq = true;
66449ab747fSPaolo Bonzini d->scount = sc | (sc << 16);
66502e7de68SVolker Rümelin } else {
6665bf1a71cSVolker Rümelin *irq = false;
66749ab747fSPaolo Bonzini d->scount = sc | (((csc_bytes - transferred - 1) >> d->shift) << 16);
66849ab747fSPaolo Bonzini }
66949ab747fSPaolo Bonzini
67049ab747fSPaolo Bonzini cnt += (transferred + d->leftover) >> 2;
67149ab747fSPaolo Bonzini
67249ab747fSPaolo Bonzini if (s->sctl & loop_sel) {
6734409a6d8SPeter Maydell /*
6744409a6d8SPeter Maydell * loop_sel tells us which bit in the SCTL register to look at
6754409a6d8SPeter Maydell * (either P1_LOOP_SEL, P2_LOOP_SEL or R1_LOOP_SEL). The sense
6764409a6d8SPeter Maydell * of these bits is 0 for loop mode (set interrupt and keep recording
6774409a6d8SPeter Maydell * when the sample count reaches zero) or 1 for stop mode (set
6784409a6d8SPeter Maydell * interrupt and stop recording).
6794409a6d8SPeter Maydell */
68049ab747fSPaolo Bonzini AUD_log ("es1370: warning", "non looping mode\n");
68102e7de68SVolker Rümelin } else {
68249ab747fSPaolo Bonzini d->frame_cnt = size;
68349ab747fSPaolo Bonzini
68402e7de68SVolker Rümelin if ((uint32_t) cnt <= d->frame_cnt) {
68549ab747fSPaolo Bonzini d->frame_cnt |= cnt << 16;
68649ab747fSPaolo Bonzini }
68702e7de68SVolker Rümelin }
68849ab747fSPaolo Bonzini
68949ab747fSPaolo Bonzini d->leftover = (transferred + d->leftover) & 3;
6900116f746SVolker Rümelin trace_es1370_transfer_audio(index,
6910116f746SVolker Rümelin d->frame_cnt >> 16, d->frame_cnt & 0xffff,
6920116f746SVolker Rümelin d->scount >> 16, d->scount & 0xffff,
6930116f746SVolker Rümelin d->leftover, *irq);
69449ab747fSPaolo Bonzini }
69549ab747fSPaolo Bonzini
es1370_run_channel(ES1370State * s,size_t chan,int free_or_avail)69649ab747fSPaolo Bonzini static void es1370_run_channel (ES1370State *s, size_t chan, int free_or_avail)
69749ab747fSPaolo Bonzini {
69849ab747fSPaolo Bonzini uint32_t new_status = s->status;
6995bf1a71cSVolker Rümelin int max_bytes;
7005bf1a71cSVolker Rümelin bool irq;
70149ab747fSPaolo Bonzini struct chan *d = &s->chan[chan];
70249ab747fSPaolo Bonzini const struct chan_bits *b = &es1370_chan_bits[chan];
70349ab747fSPaolo Bonzini
70449ab747fSPaolo Bonzini if (!(s->ctl & b->ctl_en) || (s->sctl & b->sctl_pause)) {
70549ab747fSPaolo Bonzini return;
70649ab747fSPaolo Bonzini }
70749ab747fSPaolo Bonzini
70849ab747fSPaolo Bonzini max_bytes = free_or_avail;
70949ab747fSPaolo Bonzini max_bytes &= ~((1 << d->shift) - 1);
71049ab747fSPaolo Bonzini if (!max_bytes) {
71149ab747fSPaolo Bonzini return;
71249ab747fSPaolo Bonzini }
71349ab747fSPaolo Bonzini
7145bf1a71cSVolker Rümelin irq = s->sctl & b->sctl_inten && s->status & b->stat_int;
7155bf1a71cSVolker Rümelin
71649ab747fSPaolo Bonzini es1370_transfer_audio (s, d, b->sctl_loopsel, max_bytes, &irq);
71749ab747fSPaolo Bonzini
71849ab747fSPaolo Bonzini if (irq) {
71949ab747fSPaolo Bonzini if (s->sctl & b->sctl_inten) {
72049ab747fSPaolo Bonzini new_status |= b->stat_int;
72149ab747fSPaolo Bonzini }
72249ab747fSPaolo Bonzini }
72349ab747fSPaolo Bonzini
72449ab747fSPaolo Bonzini if (new_status != s->status) {
72549ab747fSPaolo Bonzini es1370_update_status (s, new_status);
72649ab747fSPaolo Bonzini }
72749ab747fSPaolo Bonzini }
72849ab747fSPaolo Bonzini
es1370_dac1_callback(void * opaque,int free)72949ab747fSPaolo Bonzini static void es1370_dac1_callback (void *opaque, int free)
73049ab747fSPaolo Bonzini {
73149ab747fSPaolo Bonzini ES1370State *s = opaque;
73249ab747fSPaolo Bonzini
73349ab747fSPaolo Bonzini es1370_run_channel (s, DAC1_CHANNEL, free);
73449ab747fSPaolo Bonzini }
73549ab747fSPaolo Bonzini
es1370_dac2_callback(void * opaque,int free)73649ab747fSPaolo Bonzini static void es1370_dac2_callback (void *opaque, int free)
73749ab747fSPaolo Bonzini {
73849ab747fSPaolo Bonzini ES1370State *s = opaque;
73949ab747fSPaolo Bonzini
74049ab747fSPaolo Bonzini es1370_run_channel (s, DAC2_CHANNEL, free);
74149ab747fSPaolo Bonzini }
74249ab747fSPaolo Bonzini
es1370_adc_callback(void * opaque,int avail)74349ab747fSPaolo Bonzini static void es1370_adc_callback (void *opaque, int avail)
74449ab747fSPaolo Bonzini {
74549ab747fSPaolo Bonzini ES1370State *s = opaque;
74649ab747fSPaolo Bonzini
74749ab747fSPaolo Bonzini es1370_run_channel (s, ADC_CHANNEL, avail);
74849ab747fSPaolo Bonzini }
74949ab747fSPaolo Bonzini
75049ab747fSPaolo Bonzini static const MemoryRegionOps es1370_io_ops = {
75149ab747fSPaolo Bonzini .read = es1370_read,
75249ab747fSPaolo Bonzini .write = es1370_write,
753154c1d1fSPaolo Bonzini .valid = {
75449ab747fSPaolo Bonzini .min_access_size = 1,
75549ab747fSPaolo Bonzini .max_access_size = 4,
75649ab747fSPaolo Bonzini },
757154c1d1fSPaolo Bonzini .impl = {
758154c1d1fSPaolo Bonzini .min_access_size = 4,
759154c1d1fSPaolo Bonzini .max_access_size = 4,
760154c1d1fSPaolo Bonzini },
76149ab747fSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN,
76249ab747fSPaolo Bonzini };
76349ab747fSPaolo Bonzini
76449ab747fSPaolo Bonzini static const VMStateDescription vmstate_es1370_channel = {
76549ab747fSPaolo Bonzini .name = "es1370_channel",
76649ab747fSPaolo Bonzini .version_id = 2,
76749ab747fSPaolo Bonzini .minimum_version_id = 2,
768856a6fe4SRichard Henderson .fields = (const VMStateField[]) {
76949ab747fSPaolo Bonzini VMSTATE_UINT32 (shift, struct chan),
77049ab747fSPaolo Bonzini VMSTATE_UINT32 (leftover, struct chan),
77149ab747fSPaolo Bonzini VMSTATE_UINT32 (scount, struct chan),
77249ab747fSPaolo Bonzini VMSTATE_UINT32 (frame_addr, struct chan),
77349ab747fSPaolo Bonzini VMSTATE_UINT32 (frame_cnt, struct chan),
77449ab747fSPaolo Bonzini VMSTATE_END_OF_LIST ()
77549ab747fSPaolo Bonzini }
77649ab747fSPaolo Bonzini };
77749ab747fSPaolo Bonzini
es1370_post_load(void * opaque,int version_id)77849ab747fSPaolo Bonzini static int es1370_post_load (void *opaque, int version_id)
77949ab747fSPaolo Bonzini {
78049ab747fSPaolo Bonzini uint32_t ctl, sctl;
78149ab747fSPaolo Bonzini ES1370State *s = opaque;
78249ab747fSPaolo Bonzini size_t i;
78349ab747fSPaolo Bonzini
78449ab747fSPaolo Bonzini for (i = 0; i < NB_CHANNELS; ++i) {
78549ab747fSPaolo Bonzini if (i == ADC_CHANNEL) {
78649ab747fSPaolo Bonzini if (s->adc_voice) {
78749ab747fSPaolo Bonzini AUD_close_in (&s->card, s->adc_voice);
78849ab747fSPaolo Bonzini s->adc_voice = NULL;
78949ab747fSPaolo Bonzini }
79002e7de68SVolker Rümelin } else {
79149ab747fSPaolo Bonzini if (s->dac_voice[i]) {
79249ab747fSPaolo Bonzini AUD_close_out (&s->card, s->dac_voice[i]);
79349ab747fSPaolo Bonzini s->dac_voice[i] = NULL;
79449ab747fSPaolo Bonzini }
79549ab747fSPaolo Bonzini }
79649ab747fSPaolo Bonzini }
79749ab747fSPaolo Bonzini
79849ab747fSPaolo Bonzini ctl = s->ctl;
79949ab747fSPaolo Bonzini sctl = s->sctl;
80049ab747fSPaolo Bonzini s->ctl = 0;
80149ab747fSPaolo Bonzini s->sctl = 0;
80249ab747fSPaolo Bonzini es1370_update_voices (s, ctl, sctl);
80349ab747fSPaolo Bonzini return 0;
80449ab747fSPaolo Bonzini }
80549ab747fSPaolo Bonzini
80649ab747fSPaolo Bonzini static const VMStateDescription vmstate_es1370 = {
80749ab747fSPaolo Bonzini .name = "es1370",
80849ab747fSPaolo Bonzini .version_id = 2,
80949ab747fSPaolo Bonzini .minimum_version_id = 2,
81049ab747fSPaolo Bonzini .post_load = es1370_post_load,
811856a6fe4SRichard Henderson .fields = (const VMStateField[]) {
81249ab747fSPaolo Bonzini VMSTATE_PCI_DEVICE (dev, ES1370State),
81349ab747fSPaolo Bonzini VMSTATE_STRUCT_ARRAY (chan, ES1370State, NB_CHANNELS, 2,
81449ab747fSPaolo Bonzini vmstate_es1370_channel, struct chan),
81549ab747fSPaolo Bonzini VMSTATE_UINT32 (ctl, ES1370State),
81649ab747fSPaolo Bonzini VMSTATE_UINT32 (status, ES1370State),
81749ab747fSPaolo Bonzini VMSTATE_UINT32 (mempage, ES1370State),
81849ab747fSPaolo Bonzini VMSTATE_UINT32 (codec, ES1370State),
81949ab747fSPaolo Bonzini VMSTATE_UINT32 (sctl, ES1370State),
82049ab747fSPaolo Bonzini VMSTATE_END_OF_LIST ()
82149ab747fSPaolo Bonzini }
82249ab747fSPaolo Bonzini };
82349ab747fSPaolo Bonzini
es1370_on_reset(DeviceState * dev)82411f547e5SGerd Hoffmann static void es1370_on_reset(DeviceState *dev)
82549ab747fSPaolo Bonzini {
826721d8f25SPhilippe Mathieu-Daudé ES1370State *s = ES1370(dev);
827721d8f25SPhilippe Mathieu-Daudé
82849ab747fSPaolo Bonzini es1370_reset (s);
82949ab747fSPaolo Bonzini }
83049ab747fSPaolo Bonzini
es1370_realize(PCIDevice * dev,Error ** errp)8319af21dbeSMarkus Armbruster static void es1370_realize(PCIDevice *dev, Error **errp)
83249ab747fSPaolo Bonzini {
8330d769044SCao jin ES1370State *s = ES1370(dev);
83449ab747fSPaolo Bonzini uint8_t *c = s->dev.config;
83549ab747fSPaolo Bonzini
836cb94ff5fSMartin Kletzander if (!AUD_register_card ("es1370", &s->card, errp)) {
837cb94ff5fSMartin Kletzander return;
838cb94ff5fSMartin Kletzander }
839cb94ff5fSMartin Kletzander
84049ab747fSPaolo Bonzini c[PCI_STATUS + 1] = PCI_STATUS_DEVSEL_SLOW >> 8;
84149ab747fSPaolo Bonzini
84249ab747fSPaolo Bonzini #if 0
84349ab747fSPaolo Bonzini c[PCI_CAPABILITY_LIST] = 0xdc;
84449ab747fSPaolo Bonzini c[PCI_INTERRUPT_LINE] = 10;
84549ab747fSPaolo Bonzini c[0xdc] = 0x00;
84649ab747fSPaolo Bonzini #endif
84749ab747fSPaolo Bonzini
84849ab747fSPaolo Bonzini c[PCI_INTERRUPT_PIN] = 1;
84949ab747fSPaolo Bonzini c[PCI_MIN_GNT] = 0x0c;
85049ab747fSPaolo Bonzini c[PCI_MAX_LAT] = 0x80;
85149ab747fSPaolo Bonzini
85264bde0f3SPaolo Bonzini memory_region_init_io (&s->io, OBJECT(s), &es1370_io_ops, s, "es1370", 256);
85349ab747fSPaolo Bonzini pci_register_bar (&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
85449ab747fSPaolo Bonzini
85549ab747fSPaolo Bonzini es1370_reset (s);
85649ab747fSPaolo Bonzini }
85749ab747fSPaolo Bonzini
es1370_exit(PCIDevice * dev)858069eb7b2SLi Qiang static void es1370_exit(PCIDevice *dev)
859069eb7b2SLi Qiang {
860069eb7b2SLi Qiang ES1370State *s = ES1370(dev);
861069eb7b2SLi Qiang int i;
862069eb7b2SLi Qiang
863069eb7b2SLi Qiang for (i = 0; i < 2; ++i) {
864069eb7b2SLi Qiang AUD_close_out(&s->card, s->dac_voice[i]);
865069eb7b2SLi Qiang }
866069eb7b2SLi Qiang
867069eb7b2SLi Qiang AUD_close_in(&s->card, s->adc_voice);
868069eb7b2SLi Qiang AUD_remove_card(&s->card);
869069eb7b2SLi Qiang }
870069eb7b2SLi Qiang
87188e47b9aSKővágó, Zoltán static Property es1370_properties[] = {
87288e47b9aSKővágó, Zoltán DEFINE_AUDIO_PROPERTIES(ES1370State, card),
87388e47b9aSKővágó, Zoltán DEFINE_PROP_END_OF_LIST(),
87488e47b9aSKővágó, Zoltán };
87588e47b9aSKővágó, Zoltán
es1370_class_init(ObjectClass * klass,void * data)87649ab747fSPaolo Bonzini static void es1370_class_init (ObjectClass *klass, void *data)
87749ab747fSPaolo Bonzini {
87849ab747fSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS (klass);
87949ab747fSPaolo Bonzini PCIDeviceClass *k = PCI_DEVICE_CLASS (klass);
88049ab747fSPaolo Bonzini
8819af21dbeSMarkus Armbruster k->realize = es1370_realize;
882069eb7b2SLi Qiang k->exit = es1370_exit;
88349ab747fSPaolo Bonzini k->vendor_id = PCI_VENDOR_ID_ENSONIQ;
88449ab747fSPaolo Bonzini k->device_id = PCI_DEVICE_ID_ENSONIQ_ES1370;
88549ab747fSPaolo Bonzini k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
88649ab747fSPaolo Bonzini k->subsystem_vendor_id = 0x4942;
88749ab747fSPaolo Bonzini k->subsystem_id = 0x4c4c;
888125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_SOUND, dc->categories);
88949ab747fSPaolo Bonzini dc->desc = "ENSONIQ AudioPCI ES1370";
89049ab747fSPaolo Bonzini dc->vmsd = &vmstate_es1370;
891*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, es1370_on_reset);
8924f67d30bSMarc-André Lureau device_class_set_props(dc, es1370_properties);
89349ab747fSPaolo Bonzini }
89449ab747fSPaolo Bonzini
89549ab747fSPaolo Bonzini static const TypeInfo es1370_info = {
8960d769044SCao jin .name = TYPE_ES1370,
89749ab747fSPaolo Bonzini .parent = TYPE_PCI_DEVICE,
89849ab747fSPaolo Bonzini .instance_size = sizeof (ES1370State),
89949ab747fSPaolo Bonzini .class_init = es1370_class_init,
900fd3b02c8SEduardo Habkost .interfaces = (InterfaceInfo[]) {
901fd3b02c8SEduardo Habkost { INTERFACE_CONVENTIONAL_PCI_DEVICE },
902fd3b02c8SEduardo Habkost { },
903fd3b02c8SEduardo Habkost },
90449ab747fSPaolo Bonzini };
90549ab747fSPaolo Bonzini
es1370_register_types(void)90649ab747fSPaolo Bonzini static void es1370_register_types (void)
90749ab747fSPaolo Bonzini {
90849ab747fSPaolo Bonzini type_register_static (&es1370_info);
9090e933febSGerd Hoffmann deprecated_register_soundhw("es1370", "ENSONIQ AudioPCI ES1370",
9100e933febSGerd Hoffmann 0, TYPE_ES1370);
91149ab747fSPaolo Bonzini }
91249ab747fSPaolo Bonzini
91349ab747fSPaolo Bonzini type_init (es1370_register_types)
914