VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DevSB16.cpp@ 56146

Last change on this file since 56146 was 56085, checked in by vboxsync, 10 years ago

PDM/Audio: Removed old audio architecture.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 67.0 KB
Line 
1/* $Id: DevSB16.cpp 56085 2015-05-26 16:39:58Z vboxsync $ */
2/** @file
3 * DevSB16 - VBox SB16 Audio Controller.
4 *
5 * @todo hiccups on NT4 and Win98.
6 */
7
8/*
9 * Copyright (C) 2015 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 * --------------------------------------------------------------------
19 *
20 * This code is based on: sb16.c from QEMU AUDIO subsystem (r3917).
21 * QEMU Soundblaster 16 emulation
22 *
23 * Copyright (c) 2003-2005 Vassili Karpov (malc)
24 *
25 * Permission is hereby granted, free of charge, to any person obtaining a copy
26 * of this software and associated documentation files (the "Software"), to deal
27 * in the Software without restriction, including without limitation the rights
28 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29 * copies of the Software, and to permit persons to whom the Software is
30 * furnished to do so, subject to the following conditions:
31 *
32 * The above copyright notice and this permission notice shall be included in
33 * all copies or substantial portions of the Software.
34 *
35 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
38 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
41 * THE SOFTWARE.
42 */
43
44#include <iprt/assert.h>
45#ifdef IN_RING3
46# include <iprt/mem.h>
47# include <iprt/string.h>
48# include <iprt/uuid.h>
49#endif
50
51#include <VBox/vmm/pdmdev.h>
52#include <VBox/vmm/pdmaudioifs.h>
53
54#include "VBoxDD.h"
55
56#ifdef LOG_GROUP
57 #undef LOG_GROUP
58#endif
59#define LOG_GROUP LOG_GROUP_DEV_AUDIO
60#include <VBox/log.h>
61
62#include "AudioMixer.h"
63
64/** Current saved state version. */
65#define SB16_SAVE_STATE_VERSION 2
66/** The version used in VirtualBox version 3.0 and earlier. This didn't include the config dump. */
67#define SB16_SAVE_STATE_VERSION_VBOX_30 1
68
69#define IO_READ_PROTO(name) \
70 DECLCALLBACK(int) name (PPDMDEVINS pDevIns, void *opaque, \
71 RTIOPORT nport, uint32_t *pu32, unsigned cb)
72
73#define IO_WRITE_PROTO(name) \
74 DECLCALLBACK(int) name (PPDMDEVINS pDevIns, void *opaque, \
75 RTIOPORT nport, uint32_t val, unsigned cb)
76
77static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
78
79typedef struct SB16OUTPUTSTREAM
80{
81 /** PCM output stream. */
82 R3PTRTYPE(PPDMAUDIOGSTSTRMOUT) pStrmOut;
83 /** Mixer handle for output stream. */
84 R3PTRTYPE(PAUDMIXSTREAM) phStrmOut;
85} SB16OUTPUTSTREAM, *PSB16OUTPUTSTREAM;
86
87/**
88 * Struct for maintaining a host backend driver.
89 */
90typedef struct SB16STATE *PSB16STATE;
91typedef struct SB16DRIVER
92{
93 union
94 {
95 /** Node for storing this driver in our device driver
96 * list of SB16STATE. */
97 RTLISTNODE Node;
98 struct
99 {
100 R3PTRTYPE(void *) dummy1;
101 R3PTRTYPE(void *) dummy2;
102 } dummy;
103 };
104
105 /** Pointer to SB16 controller (state). */
106 R3PTRTYPE(PSB16STATE) pSB16State;
107 /** Driver flags. */
108 PDMAUDIODRVFLAGS Flags;
109 uint32_t PaddingFlags;
110 /** LUN # to which this driver has been assigned. */
111 uint8_t uLUN;
112 uint8_t Padding[5];
113 /** Audio connector interface to the underlying
114 * host backend. */
115 R3PTRTYPE(PPDMIAUDIOCONNECTOR) pConnector;
116 /** Stream for output. */
117 SB16OUTPUTSTREAM Out;
118} SB16DRIVER, *PSB16DRIVER;
119
120typedef struct SB16STATE
121{
122#ifdef VBOX
123 /** Pointer to the device instance. */
124 PPDMDEVINSR3 pDevIns;
125 /** Pointer to the connector of the attached audio driver. */
126 PPDMIAUDIOCONNECTOR pDrv;
127 int irqCfg;
128 int dmaCfg;
129 int hdmaCfg;
130 int portCfg;
131 int verCfg;
132#endif
133 int irq;
134 int dma;
135 int hdma;
136 int port;
137 int ver;
138
139 int in_index;
140 int out_data_len;
141 int fmt_stereo;
142 int fmt_signed;
143 int fmt_bits;
144 PDMAUDIOFMT fmt;
145 int dma_auto;
146 int block_size;
147 int fifo;
148 int freq;
149 int time_const;
150 int speaker;
151 int needed_bytes;
152 int cmd;
153 int use_hdma;
154 int highspeed;
155 int can_write; /** @todo Value never gets 0? */
156
157 int v2x6;
158
159 uint8_t csp_param;
160 uint8_t csp_value;
161 uint8_t csp_mode;
162 uint8_t csp_regs[256];
163 uint8_t csp_index;
164 uint8_t csp_reg83[4];
165 int csp_reg83r;
166 int csp_reg83w;
167
168 uint8_t in2_data[10];
169 uint8_t out_data[50];
170 uint8_t test_reg;
171 uint8_t last_read_byte;
172 int nzero;
173
174 int left_till_irq; /** Note: Can be < 0. */
175
176 int dma_running;
177 int bytes_per_second;
178 int align;
179
180 RTLISTANCHOR lstDrv;
181 /** The device' software mixer. */
182 R3PTRTYPE(PAUDIOMIXER) pMixer;
183 /** Audio sink for PCM output. */
184 R3PTRTYPE(PAUDMIXSINK) pSinkOutput;
185 /** The emulation timer for handling I/O of the attached LUN drivers. */
186 PTMTIMERR3 pTimerIO;
187 /** Timer ticks for handling the LUN drivers. */
188 uint64_t uTicksIO;
189
190 PTMTIMER pTimerIRQ;
191 PPDMIBASE pDrvBase;
192 /** LUN\#0: Base interface. */
193 PDMIBASE IBase;
194
195 /* mixer state */
196 int mixer_nreg;
197 uint8_t mixer_regs[256];
198} SB16STATE, *PSB16STATE;
199
200static int sb16OpenOut(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg);
201
202/**
203 * Attach command.
204 *
205 * This is called to let the device attach to a driver for a specified LUN
206 * during runtime. This is not called during VM construction, the device
207 * constructor have to attach to all the available drivers.
208 *
209 * @returns VBox status code.
210 * @param pDevIns The device instance.
211 * @param uLUN The logical unit which is being detached.
212 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
213 */
214static DECLCALLBACK(int) sb16Attach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
215{
216 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
217
218 AssertMsgReturn(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
219 ("AC'97 device does not support hotplugging\n"),
220 VERR_INVALID_PARAMETER);
221
222 /*
223 * Attach driver.
224 */
225 char *pszDesc = NULL;
226 if (RTStrAPrintf(&pszDesc, "Audio driver port (SB16) for LUN #%u", uLUN) <= 0)
227 AssertMsgReturn(pszDesc,
228 ("Not enough memory for SB16 driver port description of LUN #%u\n", uLUN),
229 VERR_NO_MEMORY);
230
231 int rc = PDMDevHlpDriverAttach(pDevIns, uLUN,
232 &pThis->IBase, &pThis->pDrvBase, pszDesc);
233 if (RT_SUCCESS(rc))
234 {
235 PSB16DRIVER pDrv = (PSB16DRIVER)RTMemAllocZ(sizeof(SB16DRIVER));
236 if (pDrv)
237 {
238 pDrv->pConnector = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIAUDIOCONNECTOR);
239 AssertMsg(pDrv->pConnector != NULL,
240 ("Configuration error: LUN #%u has no host audio interface, rc=%Rrc\n",
241 uLUN, rc));
242 pDrv->pSB16State = pThis;
243 pDrv->uLUN = uLUN;
244
245 /*
246 * For now we always set the driver at LUN 0 as our primary
247 * host backend. This might change in the future.
248 */
249 if (pDrv->uLUN == 0)
250 pDrv->Flags |= PDMAUDIODRVFLAG_PRIMARY;
251
252 LogFunc(("LUN#%RU8: pCon=%p, drvFlags=0x%x\n", uLUN, pDrv->pConnector, pDrv->Flags));
253
254 /* Attach to driver list. */
255 RTListAppend(&pThis->lstDrv, &pDrv->Node);
256 }
257 else
258 rc = VERR_NO_MEMORY;
259 }
260 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
261 {
262 LogFunc(("No attached driver for LUN #%u\n", uLUN));
263 }
264 else if (RT_FAILURE(rc))
265 AssertMsgFailed(("Failed to attach SB16 LUN #%u (\"%s\"), rc=%Rrc\n",
266 uLUN, pszDesc, rc));
267
268 RTStrFree(pszDesc);
269
270 LogFunc(("iLUN=%u, fFlags=0x%x, rc=%Rrc\n", uLUN, fFlags, rc));
271 return rc;
272}
273
274static void sb16AudioCallback(void *pvContext, uint32_t cbFree);
275
276static int magic_of_irq(int irq)
277{
278 switch (irq)
279 {
280 case 5:
281 return 2;
282 case 7:
283 return 4;
284 case 9:
285 return 1;
286 case 10:
287 return 8;
288 default:
289 break;
290 }
291
292 LogFlowFunc(("bad irq %d\n", irq));
293 return 2;
294}
295
296static int irq_of_magic(int magic)
297{
298 switch (magic)
299 {
300 case 1:
301 return 9;
302 case 2:
303 return 5;
304 case 4:
305 return 7;
306 case 8:
307 return 10;
308 default:
309 break;
310 }
311
312 LogFlowFunc(("bad irq magic %d\n", magic));
313 return -1;
314}
315
316#ifdef DEBUG
317static inline void log_dsp(PSB16STATE pThis)
318{
319 LogFlowFunc(("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n",
320 pThis->fmt_stereo ? "Stereo" : "Mono",
321 pThis->fmt_signed ? "Signed" : "Unsigned",
322 pThis->fmt_bits,
323 pThis->dma_auto ? "Auto" : "Single",
324 pThis->block_size,
325 pThis->freq,
326 pThis->time_const,
327 pThis->speaker));
328}
329#endif
330
331static void sb16SpeakerControl(PSB16STATE pThis, int on)
332{
333 pThis->speaker = on;
334 /* AUD_enable (pThis->voice, on); */
335}
336
337static void sb16Control(PSB16STATE pThis, int hold)
338{
339 int dma = pThis->use_hdma ? pThis->hdma : pThis->dma;
340 pThis->dma_running = hold;
341
342 LogFlowFunc(("hold %d high %d dma %d\n", hold, pThis->use_hdma, dma));
343
344 PSB16DRIVER pDrv;
345 if (hold)
346 {
347 PDMDevHlpDMASetDREQ (pThis->pDevIns, dma, 1);
348 PDMDevHlpDMASchedule (pThis->pDevIns);
349 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
350 pDrv->pConnector->pfnEnableOut(pDrv->pConnector,
351 pDrv->Out.pStrmOut, true /* fEnable */);
352 }
353 else
354 {
355 PDMDevHlpDMASetDREQ (pThis->pDevIns, dma, 0);
356 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
357 pDrv->pConnector->pfnEnableOut(pDrv->pConnector,
358 pDrv->Out.pStrmOut, false /* fEnable */);
359 }
360}
361
362static DECLCALLBACK(void) sb16TimerIRQ(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvThis)
363{
364 PSB16STATE pThis = (PSB16STATE)pvThis;
365 pThis->can_write = 1;
366 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 1);
367}
368
369#define DMA8_AUTO 1
370#define DMA8_HIGH 2
371
372static void continue_dma8(PSB16STATE pThis)
373{
374 if (pThis->freq > 0)
375 {
376 PDMAUDIOSTREAMCFG streamCfg;
377 streamCfg.uHz = pThis->freq;
378 streamCfg.cChannels = 1 << pThis->fmt_stereo;
379 streamCfg.enmFormat = pThis->fmt;
380 streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
381
382 int rc = sb16OpenOut(pThis, &streamCfg);
383 AssertRC(rc);
384 }
385
386 sb16Control(pThis, 1);
387}
388
389static void dma_cmd8(PSB16STATE pThis, int mask, int dma_len)
390{
391 pThis->fmt = AUD_FMT_U8;
392 pThis->use_hdma = 0;
393 pThis->fmt_bits = 8;
394 pThis->fmt_signed = 0;
395 pThis->fmt_stereo = (pThis->mixer_regs[0x0e] & 2) != 0;
396
397 if (-1 == pThis->time_const)
398 {
399 if (pThis->freq <= 0)
400 pThis->freq = 11025;
401 }
402 else
403 {
404 int tmp = (256 - pThis->time_const);
405 pThis->freq = (1000000 + (tmp / 2)) / tmp;
406 }
407
408 if (dma_len != -1)
409 {
410 pThis->block_size = dma_len << pThis->fmt_stereo;
411 }
412 else
413 {
414 /* This is apparently the only way to make both Act1/PL
415 and SecondReality/FC work
416
417 r=andy Wow, actually someone who remembers Future Crew :-)
418
419 Act1 sets block size via command 0x48 and it's an odd number
420 SR does the same with even number
421 Both use stereo, and Creatives own documentation states that
422 0x48 sets block size in bytes less one.. go figure */
423 pThis->block_size &= ~pThis->fmt_stereo;
424 }
425
426 pThis->freq >>= pThis->fmt_stereo;
427 pThis->left_till_irq = pThis->block_size;
428 pThis->bytes_per_second = (pThis->freq << pThis->fmt_stereo);
429 /* pThis->highspeed = (mask & DMA8_HIGH) != 0; */
430 pThis->dma_auto = (mask & DMA8_AUTO) != 0;
431 pThis->align = (1 << pThis->fmt_stereo) - 1;
432
433 if (pThis->block_size & pThis->align)
434 LogFlowFunc(("warning: misaligned block size %d, alignment %d\n",
435 pThis->block_size, pThis->align + 1));
436
437 LogFlowFunc(("freq %d, stereo %d, sign %d, bits %d, dma %d, auto %d, fifo %d, high %d\n",
438 pThis->freq, pThis->fmt_stereo, pThis->fmt_signed, pThis->fmt_bits,
439 pThis->block_size, pThis->dma_auto, pThis->fifo, pThis->highspeed));
440
441 continue_dma8(pThis);
442 sb16SpeakerControl(pThis, 1);
443}
444
445static void dma_cmd(PSB16STATE pThis, uint8_t cmd, uint8_t d0, int dma_len)
446{
447 pThis->use_hdma = cmd < 0xc0;
448 pThis->fifo = (cmd >> 1) & 1;
449 pThis->dma_auto = (cmd >> 2) & 1;
450 pThis->fmt_signed = (d0 >> 4) & 1;
451 pThis->fmt_stereo = (d0 >> 5) & 1;
452
453 switch (cmd >> 4)
454 {
455 case 11:
456 pThis->fmt_bits = 16;
457 break;
458
459 case 12:
460 pThis->fmt_bits = 8;
461 break;
462 }
463
464 if (-1 != pThis->time_const)
465 {
466#if 1
467 int tmp = 256 - pThis->time_const;
468 pThis->freq = (1000000 + (tmp / 2)) / tmp;
469#else
470 /* pThis->freq = 1000000 / ((255 - pThis->time_const) << pThis->fmt_stereo); */
471 pThis->freq = 1000000 / ((255 - pThis->time_const));
472#endif
473 pThis->time_const = -1;
474 }
475
476 pThis->block_size = dma_len + 1;
477 pThis->block_size <<= ((pThis->fmt_bits == 16) ? 1 : 0);
478 if (!pThis->dma_auto)
479 {
480 /*
481 * It is clear that for DOOM and auto-init this value
482 * shouldn't take stereo into account, while Miles Sound Systems
483 * setsound.exe with single transfer mode wouldn't work without it
484 * wonders of SB16 yet again.
485 */
486 pThis->block_size <<= pThis->fmt_stereo;
487 }
488
489 LogFlowFunc(("freq %d, stereo %d, sign %d, bits %d, dma %d, auto %d, fifo %d, high %d\n",
490 pThis->freq, pThis->fmt_stereo, pThis->fmt_signed, pThis->fmt_bits,
491 pThis->block_size, pThis->dma_auto, pThis->fifo, pThis->highspeed));
492
493 if (16 == pThis->fmt_bits)
494 pThis->fmt = pThis->fmt_signed ? AUD_FMT_S16 : AUD_FMT_U16;
495 else
496 pThis->fmt = pThis->fmt_signed ? AUD_FMT_S8 : AUD_FMT_U8;
497
498 pThis->left_till_irq = pThis->block_size;
499
500 pThis->bytes_per_second = (pThis->freq << pThis->fmt_stereo) << ((pThis->fmt_bits == 16) ? 1 : 0);
501 pThis->highspeed = 0;
502 pThis->align = (1 << (pThis->fmt_stereo + (pThis->fmt_bits == 16))) - 1;
503 if (pThis->block_size & pThis->align)
504 {
505 LogFlowFunc(("warning: misaligned block size %d, alignment %d\n",
506 pThis->block_size, pThis->align + 1));
507 }
508
509 if (pThis->freq)
510 {
511 PDMAUDIOSTREAMCFG streamCfg;
512 streamCfg.uHz = pThis->freq;
513 streamCfg.cChannels = 1 << pThis->fmt_stereo;
514 streamCfg.enmFormat = pThis->fmt;
515 streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
516
517 int rc = sb16OpenOut(pThis, &streamCfg);
518 AssertRC(rc);
519 }
520
521 sb16Control(pThis, 1);
522 sb16SpeakerControl(pThis, 1);
523}
524
525static inline void dsp_out_data (PSB16STATE pThis, uint8_t val)
526{
527 LogFlowFunc(("outdata %#x\n", val));
528 if ((size_t) pThis->out_data_len < sizeof (pThis->out_data)) {
529 pThis->out_data[pThis->out_data_len++] = val;
530 }
531}
532
533static inline uint8_t dsp_get_data (PSB16STATE pThis)
534{
535 if (pThis->in_index) {
536 return pThis->in2_data[--pThis->in_index];
537 }
538 else {
539 LogFlowFunc(("buffer underflow\n"));
540 return 0;
541 }
542}
543
544static void sb16HandleCommand(PSB16STATE pThis, uint8_t cmd)
545{
546 LogFlowFunc(("command %#x\n", cmd));
547
548 if (cmd > 0xaf && cmd < 0xd0)
549 {
550 if (cmd & 8) /** @todo Handle recording. */
551 LogFlowFunc(("ADC not yet supported (command %#x)\n", cmd));
552
553 switch (cmd >> 4)
554 {
555 case 11:
556 case 12:
557 break;
558 default:
559 LogFlowFunc(("%#x wrong bits\n", cmd));
560 }
561
562 pThis->needed_bytes = 3;
563 }
564 else
565 {
566 pThis->needed_bytes = 0;
567
568 switch (cmd)
569 {
570 case 0x03:
571 dsp_out_data(pThis, 0x10); /* pThis->csp_param); */
572 goto warn;
573
574 case 0x04:
575 pThis->needed_bytes = 1;
576 goto warn;
577
578 case 0x05:
579 pThis->needed_bytes = 2;
580 goto warn;
581
582 case 0x08:
583 /* __asm__ ("int3"); */
584 goto warn;
585
586 case 0x0e:
587 pThis->needed_bytes = 2;
588 goto warn;
589
590 case 0x09:
591 dsp_out_data(pThis, 0xf8);
592 goto warn;
593
594 case 0x0f:
595 pThis->needed_bytes = 1;
596 goto warn;
597
598 case 0x10:
599 pThis->needed_bytes = 1;
600 goto warn;
601
602 case 0x14:
603 pThis->needed_bytes = 2;
604 pThis->block_size = 0;
605 break;
606
607 case 0x1c: /* Auto-Initialize DMA DAC, 8-bit */
608 dma_cmd8(pThis, DMA8_AUTO, -1);
609 break;
610
611 case 0x20: /* Direct ADC, Juice/PL */
612 dsp_out_data(pThis, 0xff);
613 goto warn;
614
615 case 0x35:
616 LogFlowFunc(("0x35 - MIDI command not implemented\n"));
617 break;
618
619 case 0x40:
620 pThis->freq = -1;
621 pThis->time_const = -1;
622 pThis->needed_bytes = 1;
623 break;
624
625 case 0x41:
626 pThis->freq = -1;
627 pThis->time_const = -1;
628 pThis->needed_bytes = 2;
629 break;
630
631 case 0x42:
632 pThis->freq = -1;
633 pThis->time_const = -1;
634 pThis->needed_bytes = 2;
635 goto warn;
636
637 case 0x45:
638 dsp_out_data(pThis, 0xaa);
639 goto warn;
640
641 case 0x47: /* Continue Auto-Initialize DMA 16bit */
642 break;
643
644 case 0x48:
645 pThis->needed_bytes = 2;
646 break;
647
648 case 0x74:
649 pThis->needed_bytes = 2; /* DMA DAC, 4-bit ADPCM */
650 LogFlowFunc(("0x75 - DMA DAC, 4-bit ADPCM not implemented\n"));
651 break;
652
653 case 0x75: /* DMA DAC, 4-bit ADPCM Reference */
654 pThis->needed_bytes = 2;
655 LogFlowFunc(("0x74 - DMA DAC, 4-bit ADPCM Reference not implemented\n"));
656 break;
657
658 case 0x76: /* DMA DAC, 2.6-bit ADPCM */
659 pThis->needed_bytes = 2;
660 LogFlowFunc(("0x74 - DMA DAC, 2.6-bit ADPCM not implemented\n"));
661 break;
662
663 case 0x77: /* DMA DAC, 2.6-bit ADPCM Reference */
664 pThis->needed_bytes = 2;
665 LogFlowFunc(("0x74 - DMA DAC, 2.6-bit ADPCM Reference not implemented\n"));
666 break;
667
668 case 0x7d:
669 LogFlowFunc(("0x7d - Autio-Initialize DMA DAC, 4-bit ADPCM Reference\n"));
670 LogFlowFunc(("not implemented\n"));
671 break;
672
673 case 0x7f:
674 LogFlowFunc(("0x7d - Autio-Initialize DMA DAC, 2.6-bit ADPCM Reference\n"));
675 LogFlowFunc(("not implemented\n"));
676 break;
677
678 case 0x80:
679 pThis->needed_bytes = 2;
680 break;
681
682 case 0x90:
683 case 0x91:
684 dma_cmd8(pThis, (((cmd & 1) == 0) ? 1 : 0) | DMA8_HIGH, -1);
685 break;
686
687 case 0xd0: /* halt DMA operation. 8bit */
688 sb16Control(pThis, 0);
689 break;
690
691 case 0xd1: /* speaker on */
692 sb16SpeakerControl(pThis, 1);
693 break;
694
695 case 0xd3: /* speaker off */
696 sb16SpeakerControl(pThis, 0);
697 break;
698
699 case 0xd4: /* continue DMA operation. 8bit */
700 /* KQ6 (or maybe Sierras audblst.drv in general) resets
701 the frequency between halt/continue */
702 continue_dma8(pThis);
703 break;
704
705 case 0xd5: /* halt DMA operation. 16bit */
706 sb16Control(pThis, 0);
707 break;
708
709 case 0xd6: /* continue DMA operation. 16bit */
710 sb16Control(pThis, 1);
711 break;
712
713 case 0xd9: /* exit auto-init DMA after this block. 16bit */
714 pThis->dma_auto = 0;
715 break;
716
717 case 0xda: /* exit auto-init DMA after this block. 8bit */
718 pThis->dma_auto = 0;
719 break;
720
721 case 0xe0: /* DSP identification */
722 pThis->needed_bytes = 1;
723 break;
724
725 case 0xe1:
726 dsp_out_data(pThis, pThis->ver & 0xff);
727 dsp_out_data(pThis, pThis->ver >> 8);
728 break;
729
730 case 0xe2:
731 pThis->needed_bytes = 1;
732 goto warn;
733
734 case 0xe3:
735 {
736 for (int i = sizeof (e3) - 1; i >= 0; --i)
737 dsp_out_data(pThis, e3[i]);
738
739 break;
740 }
741
742 case 0xe4: /* write test reg */
743 pThis->needed_bytes = 1;
744 break;
745
746 case 0xe7:
747 LogFlowFunc(("Attempt to probe for ESS (0xe7)?\n"));
748 break;
749
750 case 0xe8: /* read test reg */
751 dsp_out_data(pThis, pThis->test_reg);
752 break;
753
754 case 0xf2:
755 case 0xf3:
756 dsp_out_data(pThis, 0xaa);
757 pThis->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2;
758 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 1);
759 break;
760
761 case 0xf8:
762 /* Undocumented, used by old Creative diagnostic programs. */
763 dsp_out_data (pThis, 0);
764 goto warn;
765
766 case 0xf9:
767 pThis->needed_bytes = 1;
768 goto warn;
769
770 case 0xfa:
771 dsp_out_data (pThis, 0);
772 goto warn;
773
774 case 0xfc: /* FIXME */
775 dsp_out_data (pThis, 0);
776 goto warn;
777
778 default:
779 LogFlowFunc(("Unrecognized command %#x\n", cmd));
780 break;
781 }
782 }
783
784 if (!pThis->needed_bytes)
785 LogFlow(("\n"));
786
787exit:
788
789 if (!pThis->needed_bytes)
790 pThis->cmd = -1;
791 else
792 pThis->cmd = cmd;
793
794 return;
795
796warn:
797 LogFlowFunc(("warning: command %#x,%d is not truly understood yet\n",
798 cmd, pThis->needed_bytes));
799 goto exit;
800}
801
802static uint16_t dsp_get_lohi (PSB16STATE pThis)
803{
804 uint8_t hi = dsp_get_data (pThis);
805 uint8_t lo = dsp_get_data (pThis);
806 return (hi << 8) | lo;
807}
808
809static uint16_t dsp_get_hilo (PSB16STATE pThis)
810{
811 uint8_t lo = dsp_get_data (pThis);
812 uint8_t hi = dsp_get_data (pThis);
813 return (hi << 8) | lo;
814}
815
816static void complete(PSB16STATE pThis)
817{
818 int d0, d1, d2;
819 LogFlowFunc(("complete command %#x, in_index %d, needed_bytes %d\n",
820 pThis->cmd, pThis->in_index, pThis->needed_bytes));
821
822 if (pThis->cmd > 0xaf && pThis->cmd < 0xd0)
823 {
824 d2 = dsp_get_data (pThis);
825 d1 = dsp_get_data (pThis);
826 d0 = dsp_get_data (pThis);
827
828 if (pThis->cmd & 8)
829 LogFlowFunc(("ADC params cmd = %#x d0 = %d, d1 = %d, d2 = %d\n", pThis->cmd, d0, d1, d2));
830 else
831 {
832 LogFlowFunc(("cmd = %#x d0 = %d, d1 = %d, d2 = %d\n", pThis->cmd, d0, d1, d2));
833 dma_cmd(pThis, pThis->cmd, d0, d1 + (d2 << 8));
834 }
835 }
836 else
837 {
838 switch (pThis->cmd)
839 {
840 case 0x04:
841 pThis->csp_mode = dsp_get_data (pThis);
842 pThis->csp_reg83r = 0;
843 pThis->csp_reg83w = 0;
844 LogFlowFunc(("CSP command 0x04: mode=%#x\n", pThis->csp_mode));
845 break;
846
847 case 0x05:
848 pThis->csp_param = dsp_get_data (pThis);
849 pThis->csp_value = dsp_get_data (pThis);
850 LogFlowFunc(("CSP command 0x05: param=%#x value=%#x\n",
851 pThis->csp_param,
852 pThis->csp_value));
853 break;
854
855 case 0x0e:
856 {
857 d0 = dsp_get_data(pThis);
858 d1 = dsp_get_data(pThis);
859 LogFlowFunc(("write CSP register %d <- %#x\n", d1, d0));
860 if (d1 == 0x83)
861 {
862 LogFlowFunc(("0x83[%d] <- %#x\n", pThis->csp_reg83r, d0));
863 pThis->csp_reg83[pThis->csp_reg83r % 4] = d0;
864 pThis->csp_reg83r += 1;
865 }
866 else
867 pThis->csp_regs[d1] = d0;
868 break;
869 }
870
871 case 0x0f:
872 d0 = dsp_get_data(pThis);
873 LogFlowFunc(("read CSP register %#x -> %#x, mode=%#x\n", d0, pThis->csp_regs[d0], pThis->csp_mode));
874 if (d0 == 0x83)
875 {
876 LogFlowFunc(("0x83[%d] -> %#x\n",
877 pThis->csp_reg83w,
878 pThis->csp_reg83[pThis->csp_reg83w % 4]));
879 dsp_out_data (pThis, pThis->csp_reg83[pThis->csp_reg83w % 4]);
880 pThis->csp_reg83w += 1;
881 }
882 else
883 dsp_out_data(pThis, pThis->csp_regs[d0]);
884 break;
885
886 case 0x10:
887 d0 = dsp_get_data(pThis);
888 LogFlowFunc(("cmd 0x10 d0=%#x\n", d0));
889 break;
890
891 case 0x14:
892 dma_cmd8(pThis, 0, dsp_get_lohi (pThis) + 1);
893 break;
894
895 case 0x40:
896 pThis->time_const = dsp_get_data(pThis);
897 LogFlowFunc(("set time const %d\n", pThis->time_const));
898 break;
899
900 case 0x42: /* FT2 sets output freq with this, go figure */
901#if 0
902 LogFlowFunc(("cmd 0x42 might not do what it think it should\n"));
903#endif
904 case 0x41:
905 pThis->freq = dsp_get_hilo(pThis);
906 LogFlowFunc(("set freq %d\n", pThis->freq));
907 break;
908
909 case 0x48:
910 pThis->block_size = dsp_get_lohi(pThis) + 1;
911 LogFlowFunc(("set dma block len %d\n", pThis->block_size));
912 break;
913
914 case 0x74:
915 case 0x75:
916 case 0x76:
917 case 0x77:
918 /* ADPCM stuff, ignore */
919 break;
920
921 case 0x80:
922 {
923 int freq, samples, bytes;
924 uint64_t ticks;
925
926 freq = pThis->freq > 0 ? pThis->freq : 11025;
927 samples = dsp_get_lohi (pThis) + 1;
928 bytes = samples << pThis->fmt_stereo << ((pThis->fmt_bits == 16) ? 1 : 0);
929 ticks = (bytes * TMTimerGetFreq(pThis->pTimerIRQ)) / freq;
930 if (ticks < TMTimerGetFreq(pThis->pTimerIRQ) / 1024)
931 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 1);
932 else
933 TMTimerSet(pThis->pTimerIRQ, TMTimerGet(pThis->pTimerIRQ) + ticks);
934 LogFlowFunc(("mix silence %d %d % %RU64\n", samples, bytes, ticks));
935 break;
936 }
937
938 case 0xe0:
939 d0 = dsp_get_data(pThis);
940 pThis->out_data_len = 0;
941 LogFlowFunc(("E0 data = %#x\n", d0));
942 dsp_out_data(pThis, ~d0);
943 break;
944
945 case 0xe2:
946 d0 = dsp_get_data(pThis);
947 LogFlow(("SB16:E2 = %#x\n", d0));
948 break;
949
950 case 0xe4:
951 pThis->test_reg = dsp_get_data(pThis);
952 break;
953
954 case 0xf9:
955 d0 = dsp_get_data(pThis);
956 LogFlowFunc(("command 0xf9 with %#x\n", d0));
957 switch (d0) {
958 case 0x0e:
959 dsp_out_data(pThis, 0xff);
960 break;
961
962 case 0x0f:
963 dsp_out_data(pThis, 0x07);
964 break;
965
966 case 0x37:
967 dsp_out_data(pThis, 0x38);
968 break;
969
970 default:
971 dsp_out_data(pThis, 0x00);
972 break;
973 }
974 break;
975
976 default:
977 LogFlowFunc(("complete: unrecognized command %#x\n", pThis->cmd));
978 return;
979 }
980 }
981
982 LogFlow(("\n"));
983 pThis->cmd = -1;
984 return;
985}
986
987static uint8_t sb16MixRegToVol(PSB16STATE pThis, int reg)
988{
989 /* The SB16 mixer has a 0 to -62dB range in 32 levels (2dB each step).
990 * We use a 0 to -96dB range in 256 levels (0.375dB each step).
991 * Only the top 5 bits of a mixer register are used.
992 */
993 uint8_t steps = 31 - (pThis->mixer_regs[reg] >> 3);
994 uint8_t vol = 255 - steps * 16 / 3; /* (2dB*8) / (0.375dB*8) */
995 return vol;
996}
997
998static void sb16SetMasterVolume(PSB16STATE pThis)
999{
1000 /* There's no mute switch, only volume controls. */
1001 uint8_t lvol = sb16MixRegToVol(pThis, 0x30);
1002 uint8_t rvol = sb16MixRegToVol(pThis, 0x31);
1003 PDMAUDIOVOLUME vol = { false, lvol, rvol };
1004 AudioMixerSetMasterVolume(pThis->pMixer, &vol);
1005}
1006
1007static void sb16SetPcmOutVolume(PSB16STATE pThis)
1008{
1009 /* There's no mute switch, only volume controls. */
1010 uint8_t lvol = sb16MixRegToVol(pThis, 0x32);
1011 uint8_t rvol = sb16MixRegToVol(pThis, 0x33);
1012 PDMAUDIOVOLUME vol = { false, lvol, rvol };
1013 AudioMixerSetSinkVolume(pThis->pSinkOutput, &vol);
1014}
1015
1016static void sb16ResetLegacy(PSB16STATE pThis)
1017{
1018 pThis->freq = 11025;
1019 pThis->fmt_signed = 0;
1020 pThis->fmt_bits = 8;
1021 pThis->fmt_stereo = 0;
1022
1023 PDMAUDIOSTREAMCFG streamCfg;
1024 streamCfg.uHz = pThis->freq;
1025 streamCfg.cChannels = 1; /* Mono */
1026 streamCfg.enmFormat = AUD_FMT_U8;
1027 streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
1028
1029 int rc2 = sb16OpenOut(pThis, &streamCfg);
1030 AssertRC(rc2);
1031}
1032
1033static void sb16Reset(PSB16STATE pThis)
1034{
1035 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 0);
1036 if (pThis->dma_auto)
1037 {
1038 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 1);
1039 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 0);
1040 }
1041
1042 pThis->mixer_regs[0x82] = 0;
1043 pThis->dma_auto = 0;
1044 pThis->in_index = 0;
1045 pThis->out_data_len = 0;
1046 pThis->left_till_irq = 0;
1047 pThis->needed_bytes = 0;
1048 pThis->block_size = -1;
1049 pThis->nzero = 0;
1050 pThis->highspeed = 0;
1051 pThis->v2x6 = 0;
1052 pThis->cmd = -1;
1053
1054 dsp_out_data(pThis, 0xaa);
1055 sb16SpeakerControl(pThis, 0);
1056 sb16Control(pThis, 0);
1057 sb16ResetLegacy(pThis);
1058}
1059
1060static IO_WRITE_PROTO(dsp_write)
1061{
1062 PSB16STATE pThis = (PSB16STATE)opaque;
1063 int iport = nport - pThis->port;
1064
1065 LogFlowFunc(("write %#x <- %#x\n", nport, val));
1066 switch (iport)
1067 {
1068 case 0x06:
1069 switch (val)
1070 {
1071 case 0x00:
1072 {
1073 if (pThis->v2x6 == 1)
1074 {
1075 if (0 && pThis->highspeed)
1076 {
1077 pThis->highspeed = 0;
1078 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 0);
1079 sb16Control(pThis, 0);
1080 }
1081 else
1082 sb16Reset(pThis);
1083 }
1084 pThis->v2x6 = 0;
1085 break;
1086 }
1087
1088 case 0x01:
1089 case 0x03: /* FreeBSD kludge */
1090 pThis->v2x6 = 1;
1091 break;
1092
1093 case 0xc6:
1094 pThis->v2x6 = 0; /* Prince of Persia, csp.sys, diagnose.exe */
1095 break;
1096
1097 case 0xb8: /* Panic */
1098 sb16Reset(pThis);
1099 break;
1100
1101 case 0x39:
1102 dsp_out_data(pThis, 0x38);
1103 sb16Reset(pThis);
1104 pThis->v2x6 = 0x39;
1105 break;
1106
1107 default:
1108 pThis->v2x6 = val;
1109 break;
1110 }
1111 break;
1112
1113 case 0x0c: /* Write data or command | write status */
1114#if 0
1115 if (pThis->highspeed)
1116 break;
1117#endif
1118 if (0 == pThis->needed_bytes)
1119 {
1120 sb16HandleCommand(pThis, val);
1121#if 0
1122 if (0 == pThis->needed_bytes) {
1123 log_dsp (pThis);
1124 }
1125#endif
1126 }
1127 else
1128 {
1129 if (pThis->in_index == sizeof (pThis->in2_data))
1130 {
1131 LogFlowFunc(("in data overrun\n"));
1132 }
1133 else
1134 {
1135 pThis->in2_data[pThis->in_index++] = val;
1136 if (pThis->in_index == pThis->needed_bytes)
1137 {
1138 pThis->needed_bytes = 0;
1139 complete (pThis);
1140#if 0
1141 log_dsp (pThis);
1142#endif
1143 }
1144 }
1145 }
1146 break;
1147
1148 default:
1149 LogFlowFunc(("nport=%#x, val=%#x)\n", nport, val));
1150 break;
1151 }
1152
1153 return VINF_SUCCESS;
1154}
1155
1156static IO_READ_PROTO(dsp_read)
1157{
1158 PSB16STATE pThis = (PSB16STATE)opaque;
1159 int iport, retval, ack = 0;
1160
1161 iport = nport - pThis->port;
1162
1163 /** @todo reject non-byte access?
1164 * The spec does not mention a non-byte access so we should check how real hardware behaves. */
1165
1166 switch (iport)
1167 {
1168 case 0x06: /* reset */
1169 retval = 0xff;
1170 break;
1171
1172 case 0x0a: /* read data */
1173 if (pThis->out_data_len)
1174 {
1175 retval = pThis->out_data[--pThis->out_data_len];
1176 pThis->last_read_byte = retval;
1177 }
1178 else
1179 {
1180 if (pThis->cmd != -1)
1181 LogFlowFunc(("empty output buffer for command %#x\n", pThis->cmd));
1182 retval = pThis->last_read_byte;
1183 /* goto error; */
1184 }
1185 break;
1186
1187 case 0x0c: /* 0 can write */
1188 retval = pThis->can_write ? 0 : 0x80;
1189 break;
1190
1191 case 0x0d: /* timer interrupt clear */
1192 /* LogFlowFunc(("timer interrupt clear\n")); */
1193 retval = 0;
1194 break;
1195
1196 case 0x0e: /* data available status | irq 8 ack */
1197 retval = (!pThis->out_data_len || pThis->highspeed) ? 0 : 0x80;
1198 if (pThis->mixer_regs[0x82] & 1)
1199 {
1200 ack = 1;
1201 pThis->mixer_regs[0x82] &= ~1;
1202 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 0);
1203 }
1204 break;
1205
1206 case 0x0f: /* irq 16 ack */
1207 retval = 0xff;
1208 if (pThis->mixer_regs[0x82] & 2)
1209 {
1210 ack = 1;
1211 pThis->mixer_regs[0x82] &= ~2;
1212 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 0);
1213 }
1214 break;
1215
1216 default:
1217 goto error;
1218 }
1219
1220 if (!ack)
1221 LogFlowFunc(("read %#x -> %#x\n", nport, retval));
1222
1223 *pu32 = retval;
1224 return VINF_SUCCESS;
1225
1226 error:
1227 LogFlowFunc(("warning: dsp_read %#x error\n", nport));
1228 return VERR_IOM_IOPORT_UNUSED;
1229}
1230
1231static void sb16MixerReset(PSB16STATE pThis)
1232{
1233 PSB16DRIVER pDrv;
1234
1235 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1236 pDrv->Out.phStrmOut = NULL;
1237
1238 pThis->pSinkOutput = NULL;
1239
1240 if (pThis->pMixer)
1241 {
1242 AudioMixerDestroy(pThis->pMixer);
1243 pThis->pMixer = NULL;
1244 }
1245
1246 memset(pThis->mixer_regs, 0xff, 0x7f);
1247 memset(pThis->mixer_regs + 0x83, 0xff, sizeof (pThis->mixer_regs) - 0x83);
1248
1249 pThis->mixer_regs[0x02] = 4; /* master volume 3bits */
1250 pThis->mixer_regs[0x06] = 4; /* MIDI volume 3bits */
1251 pThis->mixer_regs[0x08] = 0; /* CD volume 3bits */
1252 pThis->mixer_regs[0x0a] = 0; /* voice volume 2bits */
1253
1254 /* d5=input filt, d3=lowpass filt, d1,d2=input source */
1255 pThis->mixer_regs[0x0c] = 0;
1256
1257 /* d5=output filt, d1=stereo switch */
1258 pThis->mixer_regs[0x0e] = 0;
1259
1260 /* voice volume L d5,d7, R d1,d3 */
1261 pThis->mixer_regs[0x04] = (12 << 4) | 12;
1262 /* master ... */
1263 pThis->mixer_regs[0x22] = (12 << 4) | 12;
1264 /* MIDI ... */
1265 pThis->mixer_regs[0x26] = (12 << 4) | 12;
1266
1267 /* master/voice/MIDI L/R volume */
1268 for (int i = 0x30; i < 0x36; i++)
1269 pThis->mixer_regs[i] = 24 << 3; /* -14 dB */
1270
1271 /* treble/bass */
1272 for (int i = 0x44; i < 0x48; i++)
1273 pThis->mixer_regs[i] = 0x80;
1274
1275 int rc2 = AudioMixerCreate("SB16 Mixer", 0 /* uFlags */, &pThis->pMixer);
1276 if (RT_SUCCESS(rc2))
1277 {
1278 /* Set a default audio format for our mixer. */
1279 PDMAUDIOSTREAMCFG streamCfg;
1280 streamCfg.uHz = 41000;
1281 streamCfg.cChannels = 2;
1282 streamCfg.enmFormat = AUD_FMT_S16;
1283 streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
1284
1285 rc2 = AudioMixerSetDeviceFormat(pThis->pMixer, &streamCfg);
1286 AssertRC(rc2);
1287
1288 /* Add all required audio sinks. */
1289 rc2 = AudioMixerAddSink(pThis->pMixer, "[Playback] PCM Output",
1290 AUDMIXSINKDIR_OUTPUT, &pThis->pSinkOutput);
1291 AssertRC(rc2);
1292 }
1293
1294 /* Update the master (mixer) and PCM out volumes. */
1295 sb16SetMasterVolume(pThis);
1296 sb16SetPcmOutVolume(pThis);
1297}
1298
1299static IO_WRITE_PROTO(mixer_write_indexb)
1300{
1301 PSB16STATE pThis = (PSB16STATE)opaque;
1302 (void) nport;
1303 pThis->mixer_nreg = val;
1304
1305 return VINF_SUCCESS;
1306}
1307
1308uint32_t popcount(uint32_t u) /** @todo r=andy WTF? */
1309{
1310 u = ((u&0x55555555) + ((u>>1)&0x55555555));
1311 u = ((u&0x33333333) + ((u>>2)&0x33333333));
1312 u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
1313 u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
1314 u = ( u&0x0000ffff) + (u>>16);
1315 return u;
1316}
1317
1318uint32_t lsbindex(uint32_t u)
1319{
1320 return popcount((u & -(int32_t)u) - 1);
1321}
1322
1323/* Convert SB16 to SB Pro mixer volume (left). */
1324static inline void sb16ConvVolumeL(PSB16STATE pThis, unsigned reg, uint8_t val)
1325{
1326 /* High nibble in SBP mixer. */
1327 pThis->mixer_regs[reg] = (pThis->mixer_regs[reg] & 0x0f) | (val & 0xf0);
1328}
1329
1330/* Convert SB16 to SB Pro mixer volume (right). */
1331static inline void sb16ConvVolumeR(PSB16STATE pThis, unsigned reg, uint8_t val)
1332{
1333 /* Low nibble in SBP mixer. */
1334 pThis->mixer_regs[reg] = (pThis->mixer_regs[reg] & 0xf0) | (val >> 4);
1335}
1336
1337static IO_WRITE_PROTO(mixer_write_datab)
1338{
1339 PSB16STATE pThis = (PSB16STATE)opaque;
1340 bool fUpdateMaster = false;
1341 bool fUpdateStream = false;
1342
1343 (void) nport;
1344 LogFlowFunc(("mixer_write [%#x] <- %#x\n", pThis->mixer_nreg, val));
1345
1346 switch (pThis->mixer_nreg)
1347 {
1348 case 0x00:
1349 sb16MixerReset(pThis);
1350 /* And update the actual volume, too. */
1351 fUpdateMaster = true;
1352 fUpdateStream = true;
1353 break;
1354
1355 case 0x04:
1356 /* Translate from old style stream volume (L/R). */
1357 pThis->mixer_regs[0x32] = (val & 0xf0) >> 3;
1358 pThis->mixer_regs[0x33] = (val & 0x0f) << 1;
1359 fUpdateStream = true;
1360 break;
1361
1362 case 0x22:
1363 /* Translate from old style master volume (L/R). */
1364 pThis->mixer_regs[0x30] = (val & 0xf0) >> 3;
1365 pThis->mixer_regs[0x31] = (val & 0x0f) << 1;
1366 fUpdateMaster = true;
1367 break;
1368
1369 case 0x26:
1370 /* Translate from old style MIDI volume (L/R). */
1371 pThis->mixer_regs[0x34] = (val & 0xf0) >> 3;
1372 pThis->mixer_regs[0x35] = (val & 0x0f) << 1;
1373 break;
1374
1375 case 0x28:
1376 /* Translate from old style CD volume (L/R). */
1377 pThis->mixer_regs[0x36] = (val & 0xf0) >> 3;
1378 pThis->mixer_regs[0x37] = (val & 0x0f) << 1;
1379 break;
1380
1381 case 0x2E:
1382 /* Translate from old style line volume (L/R). */
1383 pThis->mixer_regs[0x38] = (val & 0xf0) >> 3;
1384 pThis->mixer_regs[0x39] = (val & 0x0f) << 1;
1385 break;
1386
1387 case 0x30: /* Translate to old style master volume (L). */
1388 sb16ConvVolumeL(pThis, 0x22, val);
1389 fUpdateMaster = true;
1390 break;
1391
1392 case 0x31: /* Translate to old style master volume (R). */
1393 sb16ConvVolumeR(pThis, 0x22, val);
1394 fUpdateMaster = true;
1395 break;
1396
1397 case 0x32: /* Translate to old style voice volume (L). */
1398 sb16ConvVolumeL(pThis, 0x04, val);
1399 fUpdateStream = true;
1400 break;
1401
1402 case 0x33: /* Translate to old style voice volume (R). */
1403 sb16ConvVolumeR(pThis, 0x04, val);
1404 fUpdateStream = true;
1405 break;
1406
1407 case 0x34: /* Translate to old style MIDI volume (L). */
1408 sb16ConvVolumeL(pThis, 0x26, val);
1409 break;
1410
1411 case 0x35: /* Translate to old style MIDI volume (R). */
1412 sb16ConvVolumeR(pThis, 0x26, val);
1413 break;
1414
1415 case 0x36: /* Translate to old style CD volume (L). */
1416 sb16ConvVolumeL(pThis, 0x28, val);
1417 break;
1418
1419 case 0x37: /* Translate to old style CD volume (R). */
1420 sb16ConvVolumeR(pThis, 0x28, val);
1421 break;
1422
1423 case 0x38: /* Translate to old style line volume (L). */
1424 sb16ConvVolumeL(pThis, 0x2E, val);
1425 break;
1426
1427 case 0x39: /* Translate to old style line volume (R). */
1428 sb16ConvVolumeR(pThis, 0x2E, val);
1429 break;
1430
1431 case 0x80:
1432 {
1433 int irq = irq_of_magic(val);
1434 LogFlowFunc(("setting irq to %d (val=%#x)\n", irq, val));
1435 if (irq > 0)
1436 pThis->irq = irq;
1437 break;
1438 }
1439
1440 case 0x81:
1441 {
1442 int dma, hdma;
1443
1444 dma = lsbindex (val & 0xf);
1445 hdma = lsbindex (val & 0xf0);
1446 if (dma != pThis->dma || hdma != pThis->hdma)
1447 LogFlow(("SB16: attempt to change DMA 8bit %d(%d), 16bit %d(%d) (val=%#x)\n",
1448 dma, pThis->dma, hdma, pThis->hdma, val));
1449#if 0
1450 pThis->dma = dma;
1451 pThis->hdma = hdma;
1452#endif
1453 break;
1454 }
1455
1456 case 0x82:
1457 LogFlowFunc(("attempt to write into IRQ status register (val=%#x)\n", val));
1458 return VINF_SUCCESS;
1459
1460 default:
1461 if (pThis->mixer_nreg >= 0x80)
1462 LogFlowFunc(("attempt to write mixer[%#x] <- %#x\n", pThis->mixer_nreg, val));
1463 break;
1464 }
1465
1466 pThis->mixer_regs[pThis->mixer_nreg] = val;
1467
1468 /* Update the master (mixer) volume. */
1469 if (fUpdateMaster)
1470 sb16SetMasterVolume(pThis);
1471
1472 /* Update the stream (PCM) volume. */
1473 if (fUpdateStream)
1474 sb16SetPcmOutVolume(pThis);
1475
1476 return VINF_SUCCESS;
1477}
1478
1479static IO_WRITE_PROTO(mixer_write)
1480{
1481 PSB16STATE pThis = (PSB16STATE)opaque;
1482 int iport = nport - pThis->port;
1483 switch (cb)
1484 {
1485 case 1:
1486 switch (iport)
1487 {
1488 case 4:
1489 mixer_write_indexb (pDevIns, opaque, nport, val, 1);
1490 break;
1491 case 5:
1492 mixer_write_datab (pDevIns, opaque, nport, val, 1);
1493 break;
1494 }
1495 break;
1496 case 2:
1497 mixer_write_indexb (pDevIns, opaque, nport, val & 0xff, 1);
1498 mixer_write_datab (pDevIns, opaque, nport, (val >> 8) & 0xff, 1);
1499 break;
1500 default:
1501 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", nport, cb, val));
1502 break;
1503 }
1504 return VINF_SUCCESS;
1505}
1506
1507static IO_READ_PROTO(mixer_read)
1508{
1509 PSB16STATE pThis = (PSB16STATE)opaque;
1510
1511 (void) nport;
1512#ifndef DEBUG_SB16_MOST
1513 if (pThis->mixer_nreg != 0x82) {
1514 LogFlowFunc(("mixer_read[%#x] -> %#x\n",
1515 pThis->mixer_nreg, pThis->mixer_regs[pThis->mixer_nreg]));
1516 }
1517#else
1518 LogFlowFunc(("mixer_read[%#x] -> %#x\n",
1519 pThis->mixer_nreg, pThis->mixer_regs[pThis->mixer_nreg]));
1520#endif
1521 *pu32 = pThis->mixer_regs[pThis->mixer_nreg];
1522 return VINF_SUCCESS;
1523}
1524
1525static int sb16WriteAudio(PSB16STATE pThis, int nchan, uint32_t dma_pos,
1526 uint32_t dma_len, int len)
1527{
1528 uint8_t tmpbuf[_4K]; /** @todo Have a buffer on the heap. */
1529 uint32_t cbToWrite = len;
1530 uint32_t cbWrittenTotal = 0;
1531
1532 while (cbToWrite)
1533 {
1534 uint32_t cbWrittenMin = UINT32_MAX;
1535 uint32_t cbToRead;
1536 uint32_t cbRead;
1537
1538 cbToRead = RT_MIN(dma_len - dma_pos, cbToWrite);
1539 if (cbToRead > sizeof(tmpbuf))
1540 cbToRead = sizeof(tmpbuf);
1541
1542 int rc = PDMDevHlpDMAReadMemory(pThis->pDevIns, nchan, tmpbuf, dma_pos, cbToRead, &cbRead);
1543 AssertMsgRC(rc, ("DMAReadMemory -> %Rrc\n", rc));
1544
1545 uint32_t cbWritten;
1546
1547 /* Just multiplex the output to the connected backends.
1548 * No need to utilize the virtual mixer here (yet). */
1549 PSB16DRIVER pDrv;
1550 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1551 {
1552 int rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
1553 tmpbuf, cbToRead, &cbWritten);
1554 AssertRCBreak(rc);
1555 if (RT_FAILURE(rc2))
1556 continue;
1557
1558 cbWrittenMin = RT_MIN(cbWrittenMin, cbWritten);
1559 LogFlowFunc(("\tLUN#%RU8: cbWritten=%RU32, cWrittenMin=%RU32\n", pDrv->uLUN, cbWritten, cbWrittenMin));
1560 }
1561
1562 Assert(cbToWrite >= cbWrittenMin);
1563 cbToWrite -= cbWrittenMin;
1564 dma_pos = (dma_pos + cbWrittenMin) % dma_len;
1565 cbWrittenTotal += cbWrittenMin;
1566
1567 if (!cbRead || !cbWrittenMin)
1568 break;
1569 }
1570
1571 return cbWrittenTotal;
1572}
1573
1574static DECLCALLBACK(uint32_t) sb16DMARead(PPDMDEVINS pDevIns, void *opaque, unsigned nchan, uint32_t dma_pos, uint32_t dma_len)
1575{
1576 PSB16STATE pThis = (PSB16STATE)opaque;
1577 int till, copy, written, free;
1578
1579 if (pThis->block_size <= 0)
1580 {
1581 LogFlowFunc(("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n",
1582 pThis->block_size, nchan, dma_pos, dma_len));
1583 return dma_pos;
1584 }
1585
1586 if (pThis->left_till_irq < 0)
1587 pThis->left_till_irq = pThis->block_size;
1588
1589 PSB16DRIVER pDrv;
1590
1591 uint32_t cbOutMin = UINT32_MAX;
1592 uint32_t cbOut;
1593 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1594 {
1595 int rc2 = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
1596 NULL /* pcbIn */, &cbOut, NULL /* pcSamplesLive */);
1597 if (RT_SUCCESS(rc2))
1598 cbOutMin = RT_MIN(cbOutMin, cbOut);
1599 }
1600
1601 LogFlowFunc(("cbOutMin=%RU32\n", cbOutMin));
1602 if (cbOutMin == UINT32_MAX)
1603 {
1604 free = dma_len;
1605 }
1606 else
1607 {
1608 free = cbOutMin & ~pThis->align; /** @todo int vs. uint32. */
1609 if ((free <= 0) || !dma_len)
1610 return dma_pos;
1611 }
1612
1613 copy = free;
1614 till = pThis->left_till_irq;
1615
1616#ifdef DEBUG_SB16_MOST
1617 LogFlowFunc(("pos:%06d %d till:%d len:%d\n", dma_pos, free, till, dma_len));
1618#endif
1619
1620 if (copy >= till)
1621 {
1622 if (0 == pThis->dma_auto)
1623 {
1624 copy = till;
1625 }
1626 else
1627 {
1628 if (copy >= till + pThis->block_size)
1629 copy = till; /* Make sure we won't skip IRQs. */
1630 }
1631 }
1632
1633 written = sb16WriteAudio(pThis, nchan, dma_pos, dma_len, copy);
1634 dma_pos = (dma_pos + written) % dma_len;
1635 pThis->left_till_irq -= written;
1636
1637 if (pThis->left_till_irq <= 0)
1638 {
1639 pThis->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
1640 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 1);
1641 if (0 == pThis->dma_auto)
1642 {
1643 sb16Control(pThis, 0);
1644 sb16SpeakerControl(pThis, 0);
1645 }
1646 }
1647
1648#ifdef DEBUG_SB16_MOST
1649 LogFlowFunc(("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n",
1650 dma_pos, free, dma_len, pThis->left_till_irq, copy, written,
1651 pThis->block_size));
1652#endif
1653
1654 while (pThis->left_till_irq <= 0)
1655 pThis->left_till_irq += pThis->block_size;
1656
1657 return dma_pos;
1658}
1659
1660static DECLCALLBACK(void) sb16TimerIO(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1661{
1662 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
1663 AssertPtrReturnVoid(pThis);
1664
1665 int rc = VINF_SUCCESS;
1666
1667 uint32_t cbInMax = 0;
1668 uint32_t cbOutMin = UINT32_MAX;
1669
1670 PSB16DRIVER pDrv;
1671
1672 uint32_t cbIn, cbOut, cSamplesLive;
1673 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1674 {
1675 rc = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
1676 &cbIn, &cbOut, &cSamplesLive);
1677 if (RT_SUCCESS(rc))
1678 {
1679 LogFlowFunc(("\tLUN#%RU8: [1] cbIn=%RU32, cbOut=%RU32\n", pDrv->uLUN, cbIn, cbOut));
1680
1681 if (cSamplesLive)
1682 {
1683 uint32_t cSamplesPlayed;
1684 int rc2 = pDrv->pConnector->pfnPlayOut(pDrv->pConnector, &cSamplesPlayed);
1685 if (RT_SUCCESS(rc2))
1686 LogFlowFunc(("LUN#%RU8: cSamplesLive=%RU32, cSamplesPlayed=%RU32\n",
1687 pDrv->uLUN, cSamplesLive, cSamplesPlayed));
1688
1689 if (cSamplesPlayed)
1690 {
1691 rc = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
1692 &cbIn, &cbOut, &cSamplesLive);
1693 if (RT_SUCCESS(rc))
1694 LogFlowFunc(("\tLUN#%RU8: [2] cbIn=%RU32, cbOut=%RU32\n", pDrv->uLUN, cbIn, cbOut));
1695 }
1696 }
1697
1698 cbInMax = RT_MAX(cbInMax, cbIn);
1699 cbOutMin = RT_MIN(cbOutMin, cbOut);
1700 }
1701 }
1702
1703 LogFlowFunc(("cbInMax=%RU32, cbOutMin=%RU32\n", cbInMax, cbOutMin));
1704
1705 if (cbOutMin == UINT32_MAX)
1706 cbOutMin = 0;
1707
1708 /*
1709 * Playback.
1710 */
1711 if (cbOutMin)
1712 {
1713 Assert(cbOutMin != UINT32_MAX);
1714
1715 /* New space available, see if we can transfer more. */
1716 PDMDevHlpDMASchedule(pThis->pDevIns);
1717 }
1718
1719 /*
1720 * Recording.
1721 */
1722 /** @todo Implement recording. */
1723
1724 TMTimerSet(pThis->pTimerIO, TMTimerGet(pThis->pTimerIO) + pThis->uTicksIO);
1725}
1726
1727static void sb16Save(PSSMHANDLE pSSM, PSB16STATE pThis)
1728{
1729 SSMR3PutS32(pSSM, pThis->irq);
1730 SSMR3PutS32(pSSM, pThis->dma);
1731 SSMR3PutS32(pSSM, pThis->hdma);
1732 SSMR3PutS32(pSSM, pThis->port);
1733 SSMR3PutS32(pSSM, pThis->ver);
1734 SSMR3PutS32(pSSM, pThis->in_index);
1735 SSMR3PutS32(pSSM, pThis->out_data_len);
1736 SSMR3PutS32(pSSM, pThis->fmt_stereo);
1737 SSMR3PutS32(pSSM, pThis->fmt_signed);
1738 SSMR3PutS32(pSSM, pThis->fmt_bits);
1739
1740 SSMR3PutU32(pSSM, pThis->fmt);
1741
1742 SSMR3PutS32(pSSM, pThis->dma_auto);
1743 SSMR3PutS32(pSSM, pThis->block_size);
1744 SSMR3PutS32(pSSM, pThis->fifo);
1745 SSMR3PutS32(pSSM, pThis->freq);
1746 SSMR3PutS32(pSSM, pThis->time_const);
1747 SSMR3PutS32(pSSM, pThis->speaker);
1748 SSMR3PutS32(pSSM, pThis->needed_bytes);
1749 SSMR3PutS32(pSSM, pThis->cmd);
1750 SSMR3PutS32(pSSM, pThis->use_hdma);
1751 SSMR3PutS32(pSSM, pThis->highspeed);
1752 SSMR3PutS32(pSSM, pThis->can_write);
1753 SSMR3PutS32(pSSM, pThis->v2x6);
1754
1755 SSMR3PutU8 (pSSM, pThis->csp_param);
1756 SSMR3PutU8 (pSSM, pThis->csp_value);
1757 SSMR3PutU8 (pSSM, pThis->csp_mode);
1758 SSMR3PutU8 (pSSM, pThis->csp_param); /* Bug compatible! */
1759 SSMR3PutMem(pSSM, pThis->csp_regs, 256);
1760 SSMR3PutU8 (pSSM, pThis->csp_index);
1761 SSMR3PutMem(pSSM, pThis->csp_reg83, 4);
1762 SSMR3PutS32(pSSM, pThis->csp_reg83r);
1763 SSMR3PutS32(pSSM, pThis->csp_reg83w);
1764
1765 SSMR3PutMem(pSSM, pThis->in2_data, sizeof (pThis->in2_data));
1766 SSMR3PutMem(pSSM, pThis->out_data, sizeof (pThis->out_data));
1767 SSMR3PutU8 (pSSM, pThis->test_reg);
1768 SSMR3PutU8 (pSSM, pThis->last_read_byte);
1769
1770 SSMR3PutS32(pSSM, pThis->nzero);
1771 SSMR3PutS32(pSSM, pThis->left_till_irq);
1772 SSMR3PutS32(pSSM, pThis->dma_running);
1773 SSMR3PutS32(pSSM, pThis->bytes_per_second);
1774 SSMR3PutS32(pSSM, pThis->align);
1775
1776 SSMR3PutS32(pSSM, pThis->mixer_nreg);
1777 SSMR3PutMem(pSSM, pThis->mixer_regs, 256);
1778
1779}
1780
1781static int sb16Load(PSSMHANDLE pSSM, PSB16STATE pThis, int version_id)
1782{
1783 SSMR3GetS32(pSSM, &pThis->irq);
1784 SSMR3GetS32(pSSM, &pThis->dma);
1785 SSMR3GetS32(pSSM, &pThis->hdma);
1786 SSMR3GetS32(pSSM, &pThis->port);
1787 SSMR3GetS32(pSSM, &pThis->ver);
1788 SSMR3GetS32(pSSM, &pThis->in_index);
1789 SSMR3GetS32(pSSM, &pThis->out_data_len);
1790 SSMR3GetS32(pSSM, &pThis->fmt_stereo);
1791 SSMR3GetS32(pSSM, &pThis->fmt_signed);
1792 SSMR3GetS32(pSSM, &pThis->fmt_bits);
1793
1794 SSMR3GetU32(pSSM, (uint32_t *)&pThis->fmt);
1795
1796 SSMR3GetS32(pSSM, &pThis->dma_auto);
1797 SSMR3GetS32(pSSM, &pThis->block_size);
1798 SSMR3GetS32(pSSM, &pThis->fifo);
1799 SSMR3GetS32(pSSM, &pThis->freq);
1800 SSMR3GetS32(pSSM, &pThis->time_const);
1801 SSMR3GetS32(pSSM, &pThis->speaker);
1802 SSMR3GetS32(pSSM, &pThis->needed_bytes);
1803 SSMR3GetS32(pSSM, &pThis->cmd);
1804 SSMR3GetS32(pSSM, &pThis->use_hdma);
1805 SSMR3GetS32(pSSM, &pThis->highspeed);
1806 SSMR3GetS32(pSSM, &pThis->can_write);
1807 SSMR3GetS32(pSSM, &pThis->v2x6);
1808
1809 SSMR3GetU8 (pSSM, &pThis->csp_param);
1810 SSMR3GetU8 (pSSM, &pThis->csp_value);
1811 SSMR3GetU8 (pSSM, &pThis->csp_mode);
1812 SSMR3GetU8 (pSSM, &pThis->csp_param); /* Bug compatible! */
1813 SSMR3GetMem(pSSM, pThis->csp_regs, 256);
1814 SSMR3GetU8 (pSSM, &pThis->csp_index);
1815 SSMR3GetMem(pSSM, pThis->csp_reg83, 4);
1816 SSMR3GetS32(pSSM, &pThis->csp_reg83r);
1817 SSMR3GetS32(pSSM, &pThis->csp_reg83w);
1818
1819 SSMR3GetMem(pSSM, pThis->in2_data, sizeof (pThis->in2_data));
1820 SSMR3GetMem(pSSM, pThis->out_data, sizeof (pThis->out_data));
1821 SSMR3GetU8 (pSSM, &pThis->test_reg);
1822 SSMR3GetU8 (pSSM, &pThis->last_read_byte);
1823
1824 SSMR3GetS32(pSSM, &pThis->nzero);
1825 SSMR3GetS32(pSSM, &pThis->left_till_irq);
1826 SSMR3GetS32(pSSM, &pThis->dma_running);
1827 SSMR3GetS32(pSSM, &pThis->bytes_per_second);
1828 SSMR3GetS32(pSSM, &pThis->align);
1829
1830 SSMR3GetS32(pSSM, &pThis->mixer_nreg);
1831 SSMR3GetMem(pSSM, pThis->mixer_regs, 256);
1832
1833#if 0
1834 PSB16DRIVER pDrv;
1835 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1836 {
1837 if (pDrv->Out.pStrmOut)
1838 {
1839 pDrv->pConnector->pfnCloseOut(pThis->pDrv, pDrv->Out.pStrmOut);
1840 pDrv->Out.pStrmOut = NULL;
1841 }
1842 }
1843#endif
1844
1845 if (pThis->dma_running)
1846 {
1847 if (pThis->freq)
1848 {
1849 PDMAUDIOSTREAMCFG streamCfg;
1850 streamCfg.uHz = pThis->freq;
1851 streamCfg.cChannels = 1 << pThis->fmt_stereo;
1852 streamCfg.enmFormat = pThis->fmt;
1853 streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
1854
1855 int rc = sb16OpenOut(pThis, &streamCfg);
1856 AssertRC(rc);
1857 }
1858
1859 sb16Control(pThis, 1);
1860 sb16SpeakerControl(pThis, pThis->speaker);
1861 }
1862
1863 /* Update the master (mixer) and PCM out volumes. */
1864 sb16SetMasterVolume(pThis);
1865 sb16SetPcmOutVolume(pThis);
1866
1867 return VINF_SUCCESS;
1868}
1869
1870static DECLCALLBACK(int) sb16LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
1871{
1872 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
1873
1874 SSMR3PutS32(pSSM, pThis->irqCfg);
1875 SSMR3PutS32(pSSM, pThis->dmaCfg);
1876 SSMR3PutS32(pSSM, pThis->hdmaCfg);
1877 SSMR3PutS32(pSSM, pThis->portCfg);
1878 SSMR3PutS32(pSSM, pThis->verCfg);
1879 return VINF_SSM_DONT_CALL_AGAIN;
1880}
1881
1882static DECLCALLBACK(int) sb16SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1883{
1884 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
1885
1886 sb16LiveExec(pDevIns, pSSM, 0);
1887 sb16Save(pSSM, pThis);
1888 return VINF_SUCCESS;
1889}
1890
1891static DECLCALLBACK(int) sb16LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1892{
1893 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
1894
1895 AssertMsgReturn( uVersion == SB16_SAVE_STATE_VERSION
1896 || uVersion == SB16_SAVE_STATE_VERSION_VBOX_30,
1897 ("%u\n", uVersion),
1898 VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
1899 if (uVersion > SB16_SAVE_STATE_VERSION_VBOX_30)
1900 {
1901 int32_t irq;
1902 SSMR3GetS32 (pSSM, &irq);
1903 int32_t dma;
1904 SSMR3GetS32 (pSSM, &dma);
1905 int32_t hdma;
1906 SSMR3GetS32 (pSSM, &hdma);
1907 int32_t port;
1908 SSMR3GetS32 (pSSM, &port);
1909 int32_t ver;
1910 int rc = SSMR3GetS32 (pSSM, &ver);
1911 AssertRCReturn (rc, rc);
1912
1913 if ( irq != pThis->irqCfg
1914 || dma != pThis->dmaCfg
1915 || hdma != pThis->hdmaCfg
1916 || port != pThis->portCfg
1917 || ver != pThis->verCfg)
1918 {
1919 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
1920 N_("config changed: irq=%x/%x dma=%x/%x hdma=%x/%x port=%x/%x ver=%x/%x (saved/config)"),
1921 irq, pThis->irqCfg,
1922 dma, pThis->dmaCfg,
1923 hdma, pThis->hdmaCfg,
1924 port, pThis->portCfg,
1925 ver, pThis->verCfg);
1926 }
1927 }
1928
1929 if (uPass != SSM_PASS_FINAL)
1930 return VINF_SUCCESS;
1931
1932 sb16Load(pSSM, pThis, uVersion);
1933 return VINF_SUCCESS;
1934}
1935
1936static int sb16OpenOut(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg)
1937{
1938 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1939 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
1940
1941 int rc = VINF_SUCCESS;
1942
1943 PSB16DRIVER pDrv;
1944 uint8_t uLUN = 0;
1945 char *pszDesc;
1946 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1947 {
1948 if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] sb16.po", uLUN) <= 0)
1949 {
1950 rc = VERR_NO_MEMORY;
1951 break;
1952 }
1953
1954 int rc2 = pDrv->pConnector->pfnOpenOut(pDrv->pConnector, pszDesc, pCfg, &pDrv->Out.pStrmOut);
1955 LogFlowFunc(("LUN#%RU8: Opened output with rc=%Rrc\n", uLUN, rc));
1956 if (rc2 == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
1957 {
1958 AudioMixerRemoveStream(pThis->pSinkOutput, pDrv->Out.phStrmOut);
1959 rc = AudioMixerAddStreamOut(pThis->pSinkOutput,
1960 pDrv->pConnector, pDrv->Out.pStrmOut,
1961 0 /* uFlags */,
1962 &pDrv->Out.phStrmOut);
1963 }
1964
1965 RTStrFree(pszDesc);
1966
1967 if (RT_FAILURE(rc2))
1968 {
1969 if (RT_SUCCESS(rc))
1970 rc = rc2;
1971 break;
1972 }
1973
1974 uLUN++;
1975 }
1976 /* Ensure volume gets propagated. */
1977 AudioMixerInvalidate(pThis->pMixer);
1978
1979 return rc;
1980}
1981
1982/**
1983 * @interface_method_impl{PDMDEVREG,pfnReset}
1984 */
1985static DECLCALLBACK(void) sb16DevReset(PPDMDEVINS pDevIns)
1986{
1987 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
1988
1989 /* Bring back the device to initial state, and especially make
1990 * sure there's no interrupt or DMA activity.
1991 */
1992 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 0);
1993
1994 pThis->mixer_regs[0x82] = 0;
1995 pThis->csp_regs[5] = 1;
1996 pThis->csp_regs[9] = 0xf8;
1997
1998 pThis->dma_auto = 0;
1999 pThis->in_index = 0;
2000 pThis->out_data_len = 0;
2001 pThis->left_till_irq = 0;
2002 pThis->needed_bytes = 0;
2003 pThis->block_size = -1;
2004 pThis->nzero = 0;
2005 pThis->highspeed = 0;
2006 pThis->v2x6 = 0;
2007 pThis->cmd = -1;
2008
2009 sb16MixerReset(pThis);
2010 sb16SpeakerControl(pThis, 0);
2011 sb16Control(pThis, 0);
2012 sb16ResetLegacy(pThis);
2013}
2014
2015/**
2016 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2017 */
2018static DECLCALLBACK(void *) sb16QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
2019{
2020 PSB16STATE pThis = RT_FROM_MEMBER(pInterface, SB16STATE, IBase);
2021 Assert(&pThis->IBase == pInterface);
2022
2023 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
2024 return NULL;
2025}
2026
2027/**
2028 * @interface_method_impl{PDMDEVREG,pfnDestruct}
2029 */
2030static DECLCALLBACK(int) sb16Destruct(PPDMDEVINS pDevIns)
2031{
2032 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2033
2034 PSB16DRIVER pDrv;
2035
2036 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2037 pDrv->Out.phStrmOut = NULL;
2038
2039 pThis->pSinkOutput = NULL;
2040
2041 if (pThis->pMixer)
2042 {
2043 AudioMixerDestroy(pThis->pMixer);
2044 pThis->pMixer = NULL;
2045 }
2046
2047 return VINF_SUCCESS;
2048}
2049
2050static DECLCALLBACK(int) sb16Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
2051{
2052 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2053 int rc;
2054
2055 /*
2056 * Validations.
2057 */
2058 Assert(iInstance == 0);
2059 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2060 if (!CFGMR3AreValuesValid(pCfgHandle,
2061 "IRQ\0"
2062 "DMA\0"
2063 "DMA16\0"
2064 "Port\0"
2065 "Version\0"))
2066 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
2067 N_("Invalid configuration for sb16 device"));
2068
2069 /*
2070 * Read config data.
2071 */
2072 rc = CFGMR3QuerySIntDef(pCfgHandle, "IRQ", &pThis->irq, 5);
2073 if (RT_FAILURE(rc))
2074 return PDMDEV_SET_ERROR(pDevIns, rc,
2075 N_("Configuration error: Failed to get the \"IRQ\" value"));
2076 pThis->irqCfg = pThis->irq;
2077
2078 rc = CFGMR3QuerySIntDef(pCfgHandle, "DMA", &pThis->dma, 1);
2079 if (RT_FAILURE(rc))
2080 return PDMDEV_SET_ERROR(pDevIns, rc,
2081 N_("Configuration error: Failed to get the \"DMA\" value"));
2082 pThis->dmaCfg = pThis->dma;
2083
2084 rc = CFGMR3QuerySIntDef(pCfgHandle, "DMA16", &pThis->hdma, 5);
2085 if (RT_FAILURE(rc))
2086 return PDMDEV_SET_ERROR(pDevIns, rc,
2087 N_("Configuration error: Failed to get the \"DMA16\" value"));
2088 pThis->hdmaCfg = pThis->hdma;
2089
2090 RTIOPORT Port;
2091 rc = CFGMR3QueryPortDef(pCfgHandle, "Port", &Port, 0x220);
2092 if (RT_FAILURE(rc))
2093 return PDMDEV_SET_ERROR(pDevIns, rc,
2094 N_("Configuration error: Failed to get the \"Port\" value"));
2095 pThis->port = Port;
2096 pThis->portCfg = Port;
2097
2098 uint16_t u16Version;
2099 rc = CFGMR3QueryU16Def(pCfgHandle, "Version", &u16Version, 0x0405);
2100 if (RT_FAILURE(rc))
2101 return PDMDEV_SET_ERROR(pDevIns, rc,
2102 N_("Configuration error: Failed to get the \"Version\" value"));
2103 pThis->ver = u16Version;
2104 pThis->verCfg = u16Version;
2105
2106 /*
2107 * Init instance data.
2108 */
2109 pThis->pDevIns = pDevIns;
2110 pThis->IBase.pfnQueryInterface = sb16QueryInterface;
2111 pThis->cmd = -1;
2112
2113 pThis->mixer_regs[0x80] = magic_of_irq (pThis->irq);
2114 pThis->mixer_regs[0x81] = (1 << pThis->dma) | (1 << pThis->hdma);
2115 pThis->mixer_regs[0x82] = 2 << 5;
2116
2117 pThis->csp_regs[5] = 1;
2118 pThis->csp_regs[9] = 0xf8;
2119
2120 RTListInit(&pThis->lstDrv);
2121
2122 sb16MixerReset(pThis);
2123
2124 /*
2125 * Create timer(s), register & attach stuff.
2126 */
2127 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16TimerIRQ, pThis,
2128 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 IRQ timer", &pThis->pTimerIRQ);
2129 if (RT_FAILURE(rc))
2130 AssertMsgFailedReturn(("Error creating IRQ timer, rc=%Rrc\n", rc), rc);
2131
2132 rc = PDMDevHlpIOPortRegister(pDevIns, pThis->port + 0x04, 2, pThis,
2133 mixer_write, mixer_read, NULL, NULL, "SB16");
2134 if (RT_FAILURE(rc))
2135 return rc;
2136 rc = PDMDevHlpIOPortRegister(pDevIns, pThis->port + 0x06, 10, pThis,
2137 dsp_write, dsp_read, NULL, NULL, "SB16");
2138 if (RT_FAILURE(rc))
2139 return rc;
2140
2141 rc = PDMDevHlpDMARegister(pDevIns, pThis->hdma, sb16DMARead, pThis);
2142 if (RT_FAILURE(rc))
2143 return rc;
2144 rc = PDMDevHlpDMARegister(pDevIns, pThis->dma, sb16DMARead, pThis);
2145 if (RT_FAILURE(rc))
2146 return rc;
2147
2148 pThis->can_write = 1;
2149
2150 rc = PDMDevHlpSSMRegister3(pDevIns, SB16_SAVE_STATE_VERSION, sizeof(SB16STATE), sb16LiveExec, sb16SaveExec, sb16LoadExec);
2151 if (RT_FAILURE(rc))
2152 return rc;
2153
2154 /*
2155 * Attach driver.
2156 */
2157 uint8_t uLUN;
2158 for (uLUN = 0; uLUN < UINT8_MAX; uLUN)
2159 {
2160 LogFunc(("Trying to attach driver for LUN #%RU8 ...\n", uLUN));
2161 rc = sb16Attach(pDevIns, uLUN, PDM_TACH_FLAGS_NOT_HOT_PLUG);
2162 if (RT_FAILURE(rc))
2163 {
2164 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2165 rc = VINF_SUCCESS;
2166 break;
2167 }
2168
2169 uLUN++;
2170 }
2171
2172 LogFunc(("cLUNs=%RU8, rc=%Rrc\n", uLUN, rc));
2173
2174 sb16ResetLegacy(pThis);
2175
2176 PSB16DRIVER pDrv;
2177 uLUN = 0;
2178 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2179 {
2180 PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
2181 AssertPtr(pCon);
2182
2183 bool fIsOK = pCon->pfnIsOutputOK(pCon, pDrv->Out.pStrmOut);
2184 if (fIsOK)
2185 {
2186 rc = pCon->pfnEnableOut(pCon, pDrv->Out.pStrmOut, true /* fEnable */);
2187 fIsOK = RT_SUCCESS(rc);
2188 }
2189
2190 if (!fIsOK)
2191 {
2192 /*
2193 * Only primary drivers are critical for the VM to run. Everything else
2194 * might not worth showing an own error message box in the GUI.
2195 */
2196 if (!(pDrv->Flags & PDMAUDIODRVFLAG_PRIMARY))
2197 continue;
2198
2199 LogRel(("SB16: Warning: Unable to enable/use output for LUN#%RU8\n", uLUN));
2200
2201 pCon->pfnCloseOut(pCon, pDrv->Out.pStrmOut);
2202 pDrv->Out.pStrmOut = NULL;
2203
2204 pThis->pDrv->pfnInitNull(pThis->pDrv);
2205
2206 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
2207 N_("No audio devices could be opened. Selecting the NULL audio backend "
2208 "with the consequence that no sound is audible"));
2209 }
2210
2211 uLUN++;
2212 }
2213
2214 if (RT_SUCCESS(rc))
2215 {
2216 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16TimerIO, pThis,
2217 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 IO timer", &pThis->pTimerIO);
2218 if (RT_FAILURE(rc))
2219 AssertMsgFailedReturn(("Error creating I/O timer, rc=%Rrc\n", rc), rc);
2220 else
2221 {
2222 pThis->uTicksIO = PDMDevHlpTMTimeVirtGetFreq(pDevIns) / 200; /** Hz. @todo Make this configurable! */
2223 if (pThis->uTicksIO < 100)
2224 pThis->uTicksIO = 100;
2225 LogFunc(("I/O timer ticks=%RU64\n", pThis->uTicksIO));
2226
2227 /* Fire off timer. */
2228 TMTimerSet(pThis->pTimerIO, TMTimerGet(pThis->pTimerIO) + pThis->uTicksIO);
2229 }
2230 }
2231
2232 return VINF_SUCCESS;
2233}
2234
2235const PDMDEVREG g_DeviceSB16 =
2236{
2237 /* u32Version */
2238 PDM_DEVREG_VERSION,
2239 /* szName */
2240 "sb16",
2241 /* szRCMod */
2242 "",
2243 /* szR0Mod */
2244 "",
2245 /* pszDescription */
2246 "Sound Blaster 16 Controller",
2247 /* fFlags */
2248 PDM_DEVREG_FLAGS_DEFAULT_BITS,
2249 /* fClass */
2250 PDM_DEVREG_CLASS_AUDIO,
2251 /* cMaxInstances */
2252 1,
2253 /* cbInstance */
2254 sizeof(SB16STATE),
2255 /* pfnConstruct */
2256 sb16Construct,
2257 /* pfnDestruct */
2258 sb16Destruct,
2259 /* pfnRelocate */
2260 NULL,
2261 /* pfnMemSetup */
2262 NULL,
2263 /* pfnPowerOn */
2264 NULL,
2265 /* pfnReset */
2266 sb16DevReset,
2267 /* pfnSuspend */
2268 NULL,
2269 /* pfnResume */
2270 NULL,
2271 /* pfnAttach */
2272 NULL,
2273 /* pfnDetach */
2274 NULL,
2275 /* pfnQueryInterface */
2276 NULL,
2277 /* pfnInitComplete */
2278 NULL,
2279 /* pfnPowerOff */
2280 NULL,
2281 /* pfnSoftReset */
2282 NULL,
2283 /* u32VersionEnd */
2284 PDM_DEVREG_VERSION
2285};
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette