VirtualBox

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

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

SB16: Iproved mixer volume SBP<->SB16 conversion.

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