symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/cs4231a.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * QEMU Crystal CS4231 audio chip emulation
       
     3  *
       
     4  * Copyright (c) 2006 Fabrice Bellard
       
     5  *
       
     6  * Permission is hereby granted, free of charge, to any person obtaining a copy
       
     7  * of this software and associated documentation files (the "Software"), to deal
       
     8  * in the Software without restriction, including without limitation the rights
       
     9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       
    10  * copies of the Software, and to permit persons to whom the Software is
       
    11  * furnished to do so, subject to the following conditions:
       
    12  *
       
    13  * The above copyright notice and this permission notice shall be included in
       
    14  * all copies or substantial portions of the Software.
       
    15  *
       
    16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       
    17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       
    18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
       
    19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       
    20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       
    21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
       
    22  * THE SOFTWARE.
       
    23  */
       
    24 #include "hw.h"
       
    25 #include "audiodev.h"
       
    26 #include "audio/audio.h"
       
    27 #include "isa.h"
       
    28 #include "qemu-timer.h"
       
    29 
       
    30 /*
       
    31   Missing features:
       
    32   ADC
       
    33   Loopback
       
    34   Timer
       
    35   ADPCM
       
    36   More...
       
    37 */
       
    38 
       
    39 /* #define DEBUG */
       
    40 /* #define DEBUG_XLAW */
       
    41 
       
    42 static struct {
       
    43     int irq;
       
    44     int dma;
       
    45     int port;
       
    46     int aci_counter;
       
    47 } conf = {9, 3, 0x534, 1};
       
    48 
       
    49 #ifdef DEBUG
       
    50 #define dolog(...) AUD_log ("cs4231a", __VA_ARGS__)
       
    51 #else
       
    52 #define dolog(...)
       
    53 #endif
       
    54 
       
    55 #define lwarn(...) AUD_log ("cs4231a", "warning: " __VA_ARGS__)
       
    56 #define lerr(...) AUD_log ("cs4231a", "error: " __VA_ARGS__)
       
    57 
       
    58 #define CS_REGS 16
       
    59 #define CS_DREGS 32
       
    60 
       
    61 typedef struct CSState {
       
    62     QEMUSoundCard card;
       
    63     qemu_irq *pic;
       
    64     uint32_t regs[CS_REGS];
       
    65     uint8_t dregs[CS_DREGS];
       
    66     int irq;
       
    67     int dma;
       
    68     int port;
       
    69     int shift;
       
    70     int dma_running;
       
    71     int audio_free;
       
    72     int transferred;
       
    73     int aci_counter;
       
    74     SWVoiceOut *voice;
       
    75     int16_t *tab;
       
    76 } CSState;
       
    77 
       
    78 #define IO_READ_PROTO(name)                             \
       
    79     static uint32_t name (void *opaque, uint32_t addr)
       
    80 
       
    81 #define IO_WRITE_PROTO(name)                                            \
       
    82     static void name (void *opaque, uint32_t addr, uint32_t val)
       
    83 
       
    84 #define GET_SADDR(addr) (addr & 3)
       
    85 
       
    86 #define MODE2 (1 << 6)
       
    87 #define MCE (1 << 6)
       
    88 #define PMCE (1 << 4)
       
    89 #define CMCE (1 << 5)
       
    90 #define TE (1 << 6)
       
    91 #define PEN (1 << 0)
       
    92 #define INT (1 << 0)
       
    93 #define IEN (1 << 1)
       
    94 #define PPIO (1 << 6)
       
    95 #define PI (1 << 4)
       
    96 #define CI (1 << 5)
       
    97 #define TI (1 << 6)
       
    98 
       
    99 enum {
       
   100     Index_Address,
       
   101     Index_Data,
       
   102     Status,
       
   103     PIO_Data
       
   104 };
       
   105 
       
   106 enum {
       
   107     Left_ADC_Input_Control,
       
   108     Right_ADC_Input_Control,
       
   109     Left_AUX1_Input_Control,
       
   110     Right_AUX1_Input_Control,
       
   111     Left_AUX2_Input_Control,
       
   112     Right_AUX2_Input_Control,
       
   113     Left_DAC_Output_Control,
       
   114     Right_DAC_Output_Control,
       
   115     FS_And_Playback_Data_Format,
       
   116     Interface_Configuration,
       
   117     Pin_Control,
       
   118     Error_Status_And_Initialization,
       
   119     MODE_And_ID,
       
   120     Loopback_Control,
       
   121     Playback_Upper_Base_Count,
       
   122     Playback_Lower_Base_Count,
       
   123     Alternate_Feature_Enable_I,
       
   124     Alternate_Feature_Enable_II,
       
   125     Left_Line_Input_Control,
       
   126     Right_Line_Input_Control,
       
   127     Timer_Low_Base,
       
   128     Timer_High_Base,
       
   129     RESERVED,
       
   130     Alternate_Feature_Enable_III,
       
   131     Alternate_Feature_Status,
       
   132     Version_Chip_ID,
       
   133     Mono_Input_And_Output_Control,
       
   134     RESERVED_2,
       
   135     Capture_Data_Format,
       
   136     RESERVED_3,
       
   137     Capture_Upper_Base_Count,
       
   138     Capture_Lower_Base_Count
       
   139 };
       
   140 
       
   141 static int freqs[2][8] = {
       
   142     { 8000, 16000, 27420, 32000,    -1,    -1, 48000, 9000 },
       
   143     { 5510, 11025, 18900, 22050, 37800, 44100, 33075, 6620 }
       
   144 };
       
   145 
       
   146 /* Tables courtesy http://hazelware.luggle.com/tutorials/mulawcompression.html */
       
   147 static int16_t MuLawDecompressTable[256] =
       
   148 {
       
   149      -32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
       
   150      -23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
       
   151      -15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
       
   152      -11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
       
   153       -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
       
   154       -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
       
   155       -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
       
   156       -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
       
   157       -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
       
   158       -1372, -1308, -1244, -1180, -1116, -1052,  -988,  -924,
       
   159        -876,  -844,  -812,  -780,  -748,  -716,  -684,  -652,
       
   160        -620,  -588,  -556,  -524,  -492,  -460,  -428,  -396,
       
   161        -372,  -356,  -340,  -324,  -308,  -292,  -276,  -260,
       
   162        -244,  -228,  -212,  -196,  -180,  -164,  -148,  -132,
       
   163        -120,  -112,  -104,   -96,   -88,   -80,   -72,   -64,
       
   164         -56,   -48,   -40,   -32,   -24,   -16,    -8,     0,
       
   165       32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
       
   166       23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
       
   167       15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
       
   168       11900, 11388, 10876, 10364,  9852,  9340,  8828,  8316,
       
   169        7932,  7676,  7420,  7164,  6908,  6652,  6396,  6140,
       
   170        5884,  5628,  5372,  5116,  4860,  4604,  4348,  4092,
       
   171        3900,  3772,  3644,  3516,  3388,  3260,  3132,  3004,
       
   172        2876,  2748,  2620,  2492,  2364,  2236,  2108,  1980,
       
   173        1884,  1820,  1756,  1692,  1628,  1564,  1500,  1436,
       
   174        1372,  1308,  1244,  1180,  1116,  1052,   988,   924,
       
   175         876,   844,   812,   780,   748,   716,   684,   652,
       
   176         620,   588,   556,   524,   492,   460,   428,   396,
       
   177         372,   356,   340,   324,   308,   292,   276,   260,
       
   178         244,   228,   212,   196,   180,   164,   148,   132,
       
   179         120,   112,   104,    96,    88,    80,    72,    64,
       
   180          56,    48,    40,    32,    24,    16,     8,     0
       
   181 };
       
   182 
       
   183 static int16_t ALawDecompressTable[256] =
       
   184 {
       
   185      -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
       
   186      -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
       
   187      -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
       
   188      -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
       
   189      -22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
       
   190      -30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
       
   191      -11008,-10496,-12032,-11520,-8960, -8448, -9984, -9472,
       
   192      -15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
       
   193      -344,  -328,  -376,  -360,  -280,  -264,  -312,  -296,
       
   194      -472,  -456,  -504,  -488,  -408,  -392,  -440,  -424,
       
   195      -88,   -72,   -120,  -104,  -24,   -8,    -56,   -40,
       
   196      -216,  -200,  -248,  -232,  -152,  -136,  -184,  -168,
       
   197      -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
       
   198      -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
       
   199      -688,  -656,  -752,  -720,  -560,  -528,  -624,  -592,
       
   200      -944,  -912,  -1008, -976,  -816,  -784,  -880,  -848,
       
   201       5504,  5248,  6016,  5760,  4480,  4224,  4992,  4736,
       
   202       7552,  7296,  8064,  7808,  6528,  6272,  7040,  6784,
       
   203       2752,  2624,  3008,  2880,  2240,  2112,  2496,  2368,
       
   204       3776,  3648,  4032,  3904,  3264,  3136,  3520,  3392,
       
   205       22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
       
   206       30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
       
   207       11008, 10496, 12032, 11520, 8960,  8448,  9984,  9472,
       
   208       15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
       
   209       344,   328,   376,   360,   280,   264,   312,   296,
       
   210       472,   456,   504,   488,   408,   392,   440,   424,
       
   211       88,    72,   120,   104,    24,     8,    56,    40,
       
   212       216,   200,   248,   232,   152,   136,   184,   168,
       
   213       1376,  1312,  1504,  1440,  1120,  1056,  1248,  1184,
       
   214       1888,  1824,  2016,  1952,  1632,  1568,  1760,  1696,
       
   215       688,   656,   752,   720,   560,   528,   624,   592,
       
   216       944,   912,  1008,   976,   816,   784,   880,   848
       
   217 };
       
   218 
       
   219 static void cs_reset(void *opaque)
       
   220 {
       
   221     CSState *s = opaque;
       
   222 
       
   223     s->regs[Index_Address] = 0x40;
       
   224     s->regs[Index_Data]    = 0x00;
       
   225     s->regs[Status]        = 0x00;
       
   226     s->regs[PIO_Data]      = 0x00;
       
   227 
       
   228     s->dregs[Left_ADC_Input_Control]          = 0x00;
       
   229     s->dregs[Right_ADC_Input_Control]         = 0x00;
       
   230     s->dregs[Left_AUX1_Input_Control]         = 0x88;
       
   231     s->dregs[Right_AUX1_Input_Control]        = 0x88;
       
   232     s->dregs[Left_AUX2_Input_Control]         = 0x88;
       
   233     s->dregs[Right_AUX2_Input_Control]        = 0x88;
       
   234     s->dregs[Left_DAC_Output_Control]         = 0x80;
       
   235     s->dregs[Right_DAC_Output_Control]        = 0x80;
       
   236     s->dregs[FS_And_Playback_Data_Format]     = 0x00;
       
   237     s->dregs[Interface_Configuration]         = 0x08;
       
   238     s->dregs[Pin_Control]                     = 0x00;
       
   239     s->dregs[Error_Status_And_Initialization] = 0x00;
       
   240     s->dregs[MODE_And_ID]                     = 0x8a;
       
   241     s->dregs[Loopback_Control]                = 0x00;
       
   242     s->dregs[Playback_Upper_Base_Count]       = 0x00;
       
   243     s->dregs[Playback_Lower_Base_Count]       = 0x00;
       
   244     s->dregs[Alternate_Feature_Enable_I]      = 0x00;
       
   245     s->dregs[Alternate_Feature_Enable_II]     = 0x00;
       
   246     s->dregs[Left_Line_Input_Control]         = 0x88;
       
   247     s->dregs[Right_Line_Input_Control]        = 0x88;
       
   248     s->dregs[Timer_Low_Base]                  = 0x00;
       
   249     s->dregs[Timer_High_Base]                 = 0x00;
       
   250     s->dregs[RESERVED]                        = 0x00;
       
   251     s->dregs[Alternate_Feature_Enable_III]    = 0x00;
       
   252     s->dregs[Alternate_Feature_Status]        = 0x00;
       
   253     s->dregs[Version_Chip_ID]                 = 0xa0;
       
   254     s->dregs[Mono_Input_And_Output_Control]   = 0xa0;
       
   255     s->dregs[RESERVED_2]                      = 0x00;
       
   256     s->dregs[Capture_Data_Format]             = 0x00;
       
   257     s->dregs[RESERVED_3]                      = 0x00;
       
   258     s->dregs[Capture_Upper_Base_Count]        = 0x00;
       
   259     s->dregs[Capture_Lower_Base_Count]        = 0x00;
       
   260 }
       
   261 
       
   262 static void cs_audio_callback (void *opaque, int free)
       
   263 {
       
   264     CSState *s = opaque;
       
   265     s->audio_free = free;
       
   266 }
       
   267 
       
   268 static void cs_reset_voices (CSState *s, uint32_t val)
       
   269 {
       
   270     int xtal;
       
   271     struct audsettings as;
       
   272 
       
   273 #ifdef DEBUG_XLAW
       
   274     if (val == 0 || val == 32)
       
   275         val = (1 << 4) | (1 << 5);
       
   276 #endif
       
   277 
       
   278     xtal = val & 1;
       
   279     as.freq = freqs[xtal][(val >> 1) & 7];
       
   280 
       
   281     if (as.freq == -1) {
       
   282         lerr ("unsupported frequency (val=%#x)\n", val);
       
   283         goto error;
       
   284     }
       
   285 
       
   286     as.nchannels = (val & (1 << 4)) ? 2 : 1;
       
   287     as.endianness = 0;
       
   288     s->tab = NULL;
       
   289 
       
   290     switch ((val >> 5) & ((s->dregs[MODE_And_ID] & MODE2) ? 7 : 3)) {
       
   291     case 0:
       
   292         as.fmt = AUD_FMT_U8;
       
   293         s->shift = as.nchannels == 2;
       
   294         break;
       
   295 
       
   296     case 1:
       
   297         s->tab = MuLawDecompressTable;
       
   298         goto x_law;
       
   299     case 3:
       
   300         s->tab = ALawDecompressTable;
       
   301     x_law:
       
   302         as.fmt = AUD_FMT_S16;
       
   303         as.endianness = AUDIO_HOST_ENDIANNESS;
       
   304         s->shift = as.nchannels == 2;
       
   305         break;
       
   306 
       
   307     case 6:
       
   308         as.endianness = 1;
       
   309     case 2:
       
   310         as.fmt = AUD_FMT_S16;
       
   311         s->shift = as.nchannels;
       
   312         break;
       
   313 
       
   314     case 7:
       
   315     case 4:
       
   316         lerr ("attempt to use reserved format value (%#x)\n", val);
       
   317         goto error;
       
   318 
       
   319     case 5:
       
   320         lerr ("ADPCM 4 bit IMA compatible format is not supported\n");
       
   321         goto error;
       
   322     }
       
   323 
       
   324     s->voice = AUD_open_out (
       
   325         &s->card,
       
   326         s->voice,
       
   327         "cs4231a",
       
   328         s,
       
   329         cs_audio_callback,
       
   330         &as
       
   331         );
       
   332 
       
   333     if (s->dregs[Interface_Configuration] & PEN) {
       
   334         if (!s->dma_running) {
       
   335             DMA_hold_DREQ (s->dma);
       
   336             AUD_set_active_out (s->voice, 1);
       
   337             s->transferred = 0;
       
   338         }
       
   339         s->dma_running = 1;
       
   340     }
       
   341     else {
       
   342         if (s->dma_running) {
       
   343             DMA_release_DREQ (s->dma);
       
   344             AUD_set_active_out (s->voice, 0);
       
   345         }
       
   346         s->dma_running = 0;
       
   347     }
       
   348     return;
       
   349 
       
   350  error:
       
   351     if (s->dma_running) {
       
   352         DMA_release_DREQ (s->dma);
       
   353         AUD_set_active_out (s->voice, 0);
       
   354     }
       
   355 }
       
   356 
       
   357 IO_READ_PROTO (cs_read)
       
   358 {
       
   359     CSState *s = opaque;
       
   360     uint32_t saddr, iaddr, ret;
       
   361 
       
   362     saddr = GET_SADDR (addr);
       
   363     iaddr = ~0U;
       
   364 
       
   365     switch (saddr) {
       
   366     case Index_Address:
       
   367         ret = s->regs[saddr] & ~0x80;
       
   368         break;
       
   369 
       
   370     case Index_Data:
       
   371         if (!(s->dregs[MODE_And_ID] & MODE2))
       
   372             iaddr = s->regs[Index_Address] & 0x0f;
       
   373         else
       
   374             iaddr = s->regs[Index_Address] & 0x1f;
       
   375 
       
   376         ret = s->dregs[iaddr];
       
   377         if (iaddr == Error_Status_And_Initialization) {
       
   378             /* keep SEAL happy */
       
   379             if (s->aci_counter) {
       
   380                 ret |= 1 << 5;
       
   381                 s->aci_counter -= 1;
       
   382             }
       
   383         }
       
   384         break;
       
   385 
       
   386     default:
       
   387         ret = s->regs[saddr];
       
   388         break;
       
   389     }
       
   390     dolog ("read %d:%d -> %d\n", saddr, iaddr, ret);
       
   391     return ret;
       
   392 }
       
   393 
       
   394 IO_WRITE_PROTO (cs_write)
       
   395 {
       
   396     CSState *s = opaque;
       
   397     uint32_t saddr, iaddr;
       
   398 
       
   399     saddr = GET_SADDR (addr);
       
   400 
       
   401     switch (saddr) {
       
   402     case Index_Address:
       
   403         if (!(s->regs[Index_Address] & MCE) && (val & MCE)
       
   404             && (s->dregs[Interface_Configuration] & (3 << 3)))
       
   405             s->aci_counter = conf.aci_counter;
       
   406 
       
   407         s->regs[Index_Address] = val & ~(1 << 7);
       
   408         break;
       
   409 
       
   410     case Index_Data:
       
   411         if (!(s->dregs[MODE_And_ID] & MODE2))
       
   412             iaddr = s->regs[Index_Address] & 0x0f;
       
   413         else
       
   414             iaddr = s->regs[Index_Address] & 0x1f;
       
   415 
       
   416         switch (iaddr) {
       
   417         case RESERVED:
       
   418         case RESERVED_2:
       
   419         case RESERVED_3:
       
   420             lwarn ("attempt to write %#x to reserved indirect register %d\n",
       
   421                    val, iaddr);
       
   422             break;
       
   423 
       
   424         case FS_And_Playback_Data_Format:
       
   425             if (s->regs[Index_Address] & MCE) {
       
   426                 cs_reset_voices (s, val);
       
   427             }
       
   428             else {
       
   429                 if (s->dregs[Alternate_Feature_Status] & PMCE) {
       
   430                     val = (val & ~0x0f) | (s->dregs[iaddr] & 0x0f);
       
   431                     cs_reset_voices (s, val);
       
   432                 }
       
   433                 else {
       
   434                     lwarn ("[P]MCE(%#x, %#x) is not set, val=%#x\n",
       
   435                            s->regs[Index_Address],
       
   436                            s->dregs[Alternate_Feature_Status],
       
   437                            val);
       
   438                     break;
       
   439                 }
       
   440             }
       
   441             s->dregs[iaddr] = val;
       
   442             break;
       
   443 
       
   444         case Interface_Configuration:
       
   445             val &= ~(1 << 5);   /* D5 is reserved */
       
   446             s->dregs[iaddr] = val;
       
   447             if (val & PPIO) {
       
   448                 lwarn ("PIO is not supported (%#x)\n", val);
       
   449                 break;
       
   450             }
       
   451             if (val & PEN) {
       
   452                 if (!s->dma_running) {
       
   453                     cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
       
   454                 }
       
   455             }
       
   456             else {
       
   457                 if (s->dma_running) {
       
   458                     DMA_release_DREQ (s->dma);
       
   459                     AUD_set_active_out (s->voice, 0);
       
   460                     s->dma_running = 0;
       
   461                 }
       
   462             }
       
   463             break;
       
   464 
       
   465         case Error_Status_And_Initialization:
       
   466             lwarn ("attempt to write to read only register %d\n", iaddr);
       
   467             break;
       
   468 
       
   469         case MODE_And_ID:
       
   470             dolog ("val=%#x\n", val);
       
   471             if (val & MODE2)
       
   472                 s->dregs[iaddr] |= MODE2;
       
   473             else
       
   474                 s->dregs[iaddr] &= ~MODE2;
       
   475             break;
       
   476 
       
   477         case Alternate_Feature_Enable_I:
       
   478             if (val & TE)
       
   479                 lerr ("timer is not yet supported\n");
       
   480             s->dregs[iaddr] = val;
       
   481             break;
       
   482 
       
   483         case Alternate_Feature_Status:
       
   484             if ((s->dregs[iaddr] & PI) && !(val & PI)) {
       
   485                 /* XXX: TI CI */
       
   486                 qemu_irq_lower (s->pic[s->irq]);
       
   487                 s->regs[Status] &= ~INT;
       
   488             }
       
   489             s->dregs[iaddr] = val;
       
   490             break;
       
   491 
       
   492         case Version_Chip_ID:
       
   493             lwarn ("write to Version_Chip_ID register %#x\n", val);
       
   494             s->dregs[iaddr] = val;
       
   495             break;
       
   496 
       
   497         default:
       
   498             s->dregs[iaddr] = val;
       
   499             break;
       
   500         }
       
   501         dolog ("written value %#x to indirect register %d\n", val, iaddr);
       
   502         break;
       
   503 
       
   504     case Status:
       
   505         if (s->regs[Status] & INT) {
       
   506             qemu_irq_lower (s->pic[s->irq]);
       
   507         }
       
   508         s->regs[Status] &= ~INT;
       
   509         s->dregs[Alternate_Feature_Status] &= ~(PI | CI | TI);
       
   510         break;
       
   511 
       
   512     case PIO_Data:
       
   513         lwarn ("attempt to write value %#x to PIO register\n", val);
       
   514         break;
       
   515     }
       
   516 }
       
   517 
       
   518 static int cs_write_audio (CSState *s, int nchan, int dma_pos,
       
   519                            int dma_len, int len)
       
   520 {
       
   521     int temp, net;
       
   522     uint8_t tmpbuf[4096];
       
   523 
       
   524     temp = len;
       
   525     net = 0;
       
   526 
       
   527     while (temp) {
       
   528         int left = dma_len - dma_pos;
       
   529         int copied;
       
   530         size_t to_copy;
       
   531 
       
   532         to_copy = audio_MIN (temp, left);
       
   533         if (to_copy > sizeof (tmpbuf)) {
       
   534             to_copy = sizeof (tmpbuf);
       
   535         }
       
   536 
       
   537         copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
       
   538         if (s->tab) {
       
   539             int i;
       
   540             int16_t linbuf[4096];
       
   541 
       
   542             for (i = 0; i < copied; ++i)
       
   543                 linbuf[i] = s->tab[tmpbuf[i]];
       
   544             copied = AUD_write (s->voice, linbuf, copied << 1);
       
   545             copied >>= 1;
       
   546         }
       
   547         else {
       
   548             copied = AUD_write (s->voice, tmpbuf, copied);
       
   549         }
       
   550 
       
   551         temp -= copied;
       
   552         dma_pos = (dma_pos + copied) % dma_len;
       
   553         net += copied;
       
   554 
       
   555         if (!copied) {
       
   556             break;
       
   557         }
       
   558     }
       
   559 
       
   560     return net;
       
   561 }
       
   562 
       
   563 static int cs_dma_read (void *opaque, int nchan, int dma_pos, int dma_len)
       
   564 {
       
   565     CSState *s = opaque;
       
   566     int copy, written;
       
   567     int till = -1;
       
   568 
       
   569     copy = s->voice ? (s->audio_free >> (s->tab != NULL)) : dma_len;
       
   570 
       
   571     if (s->dregs[Pin_Control] & IEN) {
       
   572         till = (s->dregs[Playback_Lower_Base_Count]
       
   573             | (s->dregs[Playback_Upper_Base_Count] << 8)) << s->shift;
       
   574         till -= s->transferred;
       
   575         copy = audio_MIN (till, copy);
       
   576     }
       
   577 
       
   578     if ((copy <= 0) || (dma_len <= 0)) {
       
   579         return dma_pos;
       
   580     }
       
   581 
       
   582     written = cs_write_audio (s, nchan, dma_pos, dma_len, copy);
       
   583 
       
   584     dma_pos = (dma_pos + written) % dma_len;
       
   585     s->audio_free -= (written << (s->tab != NULL));
       
   586 
       
   587     if (written == till) {
       
   588         s->regs[Status] |= INT;
       
   589         s->dregs[Alternate_Feature_Status] |= PI;
       
   590         s->transferred = 0;
       
   591         qemu_irq_raise (s->pic[s->irq]);
       
   592     }
       
   593     else {
       
   594         s->transferred += written;
       
   595     }
       
   596 
       
   597     return dma_pos;
       
   598 }
       
   599 
       
   600 static void cs_save(QEMUFile *f, void *opaque)
       
   601 {
       
   602     CSState *s = opaque;
       
   603     unsigned int i;
       
   604     uint32_t val;
       
   605 
       
   606     for (i = 0; i < CS_REGS; i++)
       
   607         qemu_put_be32s(f, &s->regs[i]);
       
   608 
       
   609     qemu_put_buffer(f, s->dregs, CS_DREGS);
       
   610     val = s->dma_running; qemu_put_be32s(f, &val);
       
   611     val = s->audio_free;  qemu_put_be32s(f, &val);
       
   612     val = s->transferred; qemu_put_be32s(f, &val);
       
   613     val = s->aci_counter; qemu_put_be32s(f, &val);
       
   614 }
       
   615 
       
   616 static int cs_load(QEMUFile *f, void *opaque, int version_id)
       
   617 {
       
   618     CSState *s = opaque;
       
   619     unsigned int i;
       
   620     uint32_t val, dma_running;
       
   621 
       
   622     if (version_id > 1)
       
   623         return -EINVAL;
       
   624 
       
   625     for (i = 0; i < CS_REGS; i++)
       
   626         qemu_get_be32s(f, &s->regs[i]);
       
   627 
       
   628     qemu_get_buffer(f, s->dregs, CS_DREGS);
       
   629 
       
   630     qemu_get_be32s(f, &dma_running);
       
   631     qemu_get_be32s(f, &val); s->audio_free  = val;
       
   632     qemu_get_be32s(f, &val); s->transferred = val;
       
   633     qemu_get_be32s(f, &val); s->aci_counter = val;
       
   634     if (dma_running && (s->dregs[Interface_Configuration] & PEN))
       
   635         cs_reset_voices (s, s->dregs[FS_And_Playback_Data_Format]);
       
   636     return 0;
       
   637 }
       
   638 
       
   639 int cs4231a_init (AudioState *audio, qemu_irq *pic)
       
   640 {
       
   641     int i;
       
   642     CSState *s;
       
   643 
       
   644     if (!audio) {
       
   645         lerr ("No audio state\n");
       
   646         return -1;
       
   647     }
       
   648 
       
   649     s = qemu_mallocz (sizeof (*s));
       
   650     if (!s) {
       
   651         lerr ("Could not allocate memory for cs4231a (%zu bytes)\n",
       
   652                sizeof (*s));
       
   653         return -1;
       
   654     }
       
   655 
       
   656     s->pic = pic;
       
   657     s->irq = conf.irq;
       
   658     s->dma = conf.dma;
       
   659     s->port = conf.port;
       
   660 
       
   661     for (i = 0; i < 4; i++) {
       
   662         register_ioport_write (s->port + i, 1, 1, cs_write, s);
       
   663         register_ioport_read (s->port + i, 1, 1, cs_read, s);
       
   664     }
       
   665 
       
   666     DMA_register_channel (s->dma, cs_dma_read, s);
       
   667 
       
   668     register_savevm ("cs4231a", 0, 1, cs_save, cs_load, s);
       
   669     qemu_register_reset (cs_reset, s);
       
   670     cs_reset (s);
       
   671 
       
   672     AUD_register_card (audio,"cs4231a", &s->card);
       
   673     return 0;
       
   674 }