VirtualBox

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

Last change on this file since 58600 was 58600, checked in by vboxsync, 9 years ago

Audio: Introduced reference counting for guest audio streams; this should prevent that the audio connector interface is destroying streams which still are being used by other parties, e.g. the audio mixer (bugref:8054).

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