xref: /openbmc/qemu/hw/audio/es1370.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
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