VirtualBox

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

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

SB16: Implemented reset handler (finally).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 70.7 KB
Line 
1/* $Id: DevSB16.cpp 55445 2015-04-27 12:40:15Z 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
1436static IO_WRITE_PROTO(mixer_write_datab)
1437{
1438 PSB16STATE pThis = (PSB16STATE)opaque;
1439 bool fUpdateMaster = false;
1440 bool fUpdateStream = false;
1441
1442 (void) nport;
1443 LogFlowFunc(("mixer_write [%#x] <- %#x\n", pThis->mixer_nreg, val));
1444
1445 switch (pThis->mixer_nreg)
1446 {
1447 case 0x00:
1448 sb16MixerReset(pThis);
1449 /* And update the actual volume, too. */
1450 fUpdateMaster = true;
1451 fUpdateStream = true;
1452 break;
1453
1454 case 0x04:
1455 /* Translate from old style stream volume (L/R). */
1456 pThis->mixer_regs[0x32] = val & 0xff;
1457 pThis->mixer_regs[0x33] = val << 4;
1458 fUpdateStream = true;
1459 break;
1460
1461 case 0x22:
1462 /* Translate from old style master volume (L/R). */
1463 pThis->mixer_regs[0x30] = val & 0xff;
1464 pThis->mixer_regs[0x31] = val << 4;
1465 fUpdateMaster = true;
1466 break;
1467
1468 case 0x30:
1469 /* Translate to old style master volume (L). */
1470 pThis->mixer_regs[0x22] = (pThis->mixer_regs[0x22] & 0x0f) | val;
1471 fUpdateMaster = true;
1472 break;
1473
1474 case 0x31:
1475 /* Translate to old style master volume (R). */
1476 pThis->mixer_regs[0x22] = (pThis->mixer_regs[0x22] & 0xf0) | (val >> 4);
1477 fUpdateMaster = true;
1478 break;
1479
1480 case 0x32:
1481 /* Translate to old style stream volume (L). */
1482 pThis->mixer_regs[0x04] = (pThis->mixer_regs[0x04] & 0x0f) | val;
1483 fUpdateStream = true;
1484 break;
1485
1486 case 0x33:
1487 /* Translate to old style stream volume (R). */
1488 pThis->mixer_regs[0x04] = (pThis->mixer_regs[0x04] & 0xf0) | (val >> 4);
1489 fUpdateStream = true;
1490 break;
1491
1492 case 0x80:
1493 {
1494 int irq = irq_of_magic(val);
1495 LogFlowFunc(("setting irq to %d (val=%#x)\n", irq, val));
1496 if (irq > 0)
1497 pThis->irq = irq;
1498 break;
1499 }
1500
1501 case 0x81:
1502 {
1503 int dma, hdma;
1504
1505 dma = lsbindex (val & 0xf);
1506 hdma = lsbindex (val & 0xf0);
1507 if (dma != pThis->dma || hdma != pThis->hdma)
1508 LogFlow(("SB16: attempt to change DMA 8bit %d(%d), 16bit %d(%d) (val=%#x)\n",
1509 dma, pThis->dma, hdma, pThis->hdma, val));
1510#if 0
1511 pThis->dma = dma;
1512 pThis->hdma = hdma;
1513#endif
1514 break;
1515 }
1516
1517 case 0x82:
1518 LogFlowFunc(("attempt to write into IRQ status register (val=%#x)\n", val));
1519 return VINF_SUCCESS;
1520
1521 default:
1522 if (pThis->mixer_nreg >= 0x80)
1523 LogFlowFunc(("attempt to write mixer[%#x] <- %#x\n", pThis->mixer_nreg, val));
1524 break;
1525 }
1526
1527 pThis->mixer_regs[pThis->mixer_nreg] = val;
1528
1529 /* Update the master (mixer) volume. */
1530 if (fUpdateMaster)
1531 sb16SetMasterVolume(pThis);
1532
1533 /* Update the stream (PCM) volume. */
1534 if (fUpdateStream)
1535 sb16SetPcmOutVolume(pThis);
1536
1537 return VINF_SUCCESS;
1538}
1539
1540static IO_WRITE_PROTO(mixer_write)
1541{
1542 PSB16STATE pThis = (PSB16STATE)opaque;
1543 int iport = nport - pThis->port;
1544 switch (cb)
1545 {
1546 case 1:
1547 switch (iport)
1548 {
1549 case 4:
1550 mixer_write_indexb (pDevIns, opaque, nport, val, 1);
1551 break;
1552 case 5:
1553 mixer_write_datab (pDevIns, opaque, nport, val, 1);
1554 break;
1555 }
1556 break;
1557 case 2:
1558 mixer_write_indexb (pDevIns, opaque, nport, val & 0xff, 1);
1559 mixer_write_datab (pDevIns, opaque, nport, (val >> 8) & 0xff, 1);
1560 break;
1561 default:
1562 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", nport, cb, val));
1563 break;
1564 }
1565 return VINF_SUCCESS;
1566}
1567
1568static IO_READ_PROTO(mixer_read)
1569{
1570 PSB16STATE pThis = (PSB16STATE)opaque;
1571
1572 (void) nport;
1573#ifndef DEBUG_SB16_MOST
1574 if (pThis->mixer_nreg != 0x82) {
1575 LogFlowFunc(("mixer_read[%#x] -> %#x\n",
1576 pThis->mixer_nreg, pThis->mixer_regs[pThis->mixer_nreg]));
1577 }
1578#else
1579 LogFlowFunc(("mixer_read[%#x] -> %#x\n",
1580 pThis->mixer_nreg, pThis->mixer_regs[pThis->mixer_nreg]));
1581#endif
1582 *pu32 = pThis->mixer_regs[pThis->mixer_nreg];
1583 return VINF_SUCCESS;
1584}
1585
1586static int sb16WriteAudio(PSB16STATE pThis, int nchan, uint32_t dma_pos,
1587 uint32_t dma_len, int len)
1588{
1589 uint8_t tmpbuf[_4K]; /** @todo Have a buffer on the heap. */
1590 uint32_t cbToWrite = len;
1591 uint32_t cbWrittenTotal = 0;
1592
1593 while (cbToWrite)
1594 {
1595 uint32_t cbWrittenMin = UINT32_MAX;
1596 uint32_t cbToRead;
1597 uint32_t cbRead;
1598
1599 cbToRead = RT_MIN(dma_len - dma_pos, cbToWrite);
1600 if (cbToRead > sizeof(tmpbuf))
1601 cbToRead = sizeof(tmpbuf);
1602
1603 int rc = PDMDevHlpDMAReadMemory(pThis->pDevIns, nchan, tmpbuf, dma_pos, cbToRead, &cbRead);
1604 AssertMsgRC(rc, ("DMAReadMemory -> %Rrc\n", rc));
1605
1606#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1607 uint32_t cbWritten;
1608
1609 /* Just multiplex the output to the connected backends.
1610 * No need to utilize the virtual mixer here (yet). */
1611 PSB16DRIVER pDrv;
1612 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1613 {
1614 int rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
1615 tmpbuf, cbToRead, &cbWritten);
1616 AssertRCBreak(rc);
1617 if (RT_FAILURE(rc2))
1618 continue;
1619
1620 cbWrittenMin = RT_MIN(cbWrittenMin, cbWritten);
1621 LogFlowFunc(("\tLUN#%RU8: cbWritten=%RU32, cWrittenMin=%RU32\n", pDrv->uLUN, cbWritten, cbWrittenMin));
1622 }
1623#else
1624 cbWrittenMin = AUD_write (pThis->voice, tmpbuf, cbToRead);
1625#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1626
1627 Assert(cbToWrite >= cbWrittenMin);
1628 cbToWrite -= cbWrittenMin;
1629 dma_pos = (dma_pos + cbWrittenMin) % dma_len;
1630 cbWrittenTotal += cbWrittenMin;
1631
1632 if (!cbRead || !cbWrittenMin)
1633 break;
1634 }
1635
1636 return cbWrittenTotal;
1637}
1638
1639static DECLCALLBACK(uint32_t) sb16DMARead(PPDMDEVINS pDevIns, void *opaque, unsigned nchan, uint32_t dma_pos, uint32_t dma_len)
1640{
1641 PSB16STATE pThis = (PSB16STATE)opaque;
1642 int till, copy, written, free;
1643
1644 if (pThis->block_size <= 0)
1645 {
1646 LogFlowFunc(("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n",
1647 pThis->block_size, nchan, dma_pos, dma_len));
1648 return dma_pos;
1649 }
1650
1651 if (pThis->left_till_irq < 0)
1652 pThis->left_till_irq = pThis->block_size;
1653
1654#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1655 PSB16DRIVER pDrv;
1656
1657 uint32_t cbOutMin = UINT32_MAX;
1658 uint32_t cbOut;
1659 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1660 {
1661 int rc2 = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
1662 NULL /* pcbIn */, &cbOut, NULL /* pcSamplesLive */);
1663 if (RT_SUCCESS(rc2))
1664 cbOutMin = RT_MIN(cbOutMin, cbOut);
1665 }
1666
1667 LogFlowFunc(("cbOutMin=%RU32\n", cbOutMin));
1668 if (cbOutMin == UINT32_MAX)
1669 {
1670 free = dma_len;
1671 }
1672 else
1673 {
1674 free = cbOutMin & ~pThis->align; /** @todo int vs. uint32. */
1675 if ((free <= 0) || !dma_len)
1676 return dma_pos;
1677 }
1678#else
1679 if (pThis->voice)
1680 {
1681 free = pThis->audio_free & ~pThis->align;
1682 if ((free <= 0) || !dma_len)
1683 return dma_pos;
1684 }
1685 else
1686 free = dma_len;
1687#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1688
1689 copy = free;
1690 till = pThis->left_till_irq;
1691
1692#ifdef DEBUG_SB16_MOST
1693 LogFlowFunc(("pos:%06d %d till:%d len:%d\n", dma_pos, free, till, dma_len));
1694#endif
1695
1696 if (copy >= till)
1697 {
1698 if (0 == pThis->dma_auto)
1699 {
1700 copy = till;
1701 }
1702 else
1703 {
1704 if (copy >= till + pThis->block_size)
1705 copy = till; /* Make sure we won't skip IRQs. */
1706 }
1707 }
1708
1709 written = sb16WriteAudio(pThis, nchan, dma_pos, dma_len, copy);
1710 dma_pos = (dma_pos + written) % dma_len;
1711 pThis->left_till_irq -= written;
1712
1713 if (pThis->left_till_irq <= 0)
1714 {
1715 pThis->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
1716 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 1);
1717 if (0 == pThis->dma_auto)
1718 {
1719 sb16Control(pThis, 0);
1720 sb16SpeakerControl(pThis, 0);
1721 }
1722 }
1723
1724#ifdef DEBUG_SB16_MOST
1725 LogFlowFunc(("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n",
1726 dma_pos, free, dma_len, pThis->left_till_irq, copy, written,
1727 pThis->block_size));
1728#endif
1729
1730 while (pThis->left_till_irq <= 0)
1731 pThis->left_till_irq += pThis->block_size;
1732
1733 return dma_pos;
1734}
1735
1736#ifndef VBOX_WITH_PDM_AUDIO_DRIVER
1737static void sb16AudioCallback(void *pvContext, int cbFree)
1738{
1739 PSB16STATE pState = (PSB16STATE)pvContext;
1740 AssertPtrReturnVoid(pState);
1741 pState->audio_free = cbFree;
1742 /* New space available, see if we can transfer more. There is no cyclic DMA timer in VBox. */
1743 PDMDevHlpDMASchedule(pState->pDevIns);
1744}
1745#else
1746static DECLCALLBACK(void) sb16TimerIO(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1747{
1748 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
1749 AssertPtrReturnVoid(pThis);
1750
1751 int rc = VINF_SUCCESS;
1752
1753 uint32_t cbInMax = 0;
1754 uint32_t cbOutMin = UINT32_MAX;
1755
1756 PSB16DRIVER pDrv;
1757
1758 uint32_t cbIn, cbOut, cSamplesLive;
1759 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1760 {
1761 rc = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
1762 &cbIn, &cbOut, &cSamplesLive);
1763 if (RT_SUCCESS(rc))
1764 {
1765 LogFlowFunc(("\tLUN#%RU8: [1] cbIn=%RU32, cbOut=%RU32\n", pDrv->uLUN, cbIn, cbOut));
1766
1767 if (cSamplesLive)
1768 {
1769 uint32_t cSamplesPlayed;
1770 int rc2 = pDrv->pConnector->pfnPlayOut(pDrv->pConnector, &cSamplesPlayed);
1771 if (RT_SUCCESS(rc2))
1772 LogFlowFunc(("LUN#%RU8: cSamplesLive=%RU32, cSamplesPlayed=%RU32\n",
1773 pDrv->uLUN, cSamplesLive, cSamplesPlayed));
1774
1775 if (cSamplesPlayed)
1776 {
1777 rc = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
1778 &cbIn, &cbOut, &cSamplesLive);
1779 if (RT_SUCCESS(rc))
1780 LogFlowFunc(("\tLUN#%RU8: [2] cbIn=%RU32, cbOut=%RU32\n", pDrv->uLUN, cbIn, cbOut));
1781 }
1782 }
1783
1784 cbInMax = RT_MAX(cbInMax, cbIn);
1785 cbOutMin = RT_MIN(cbOutMin, cbOut);
1786 }
1787 }
1788
1789 LogFlowFunc(("cbInMax=%RU32, cbOutMin=%RU32\n", cbInMax, cbOutMin));
1790
1791 if (cbOutMin == UINT32_MAX)
1792 cbOutMin = 0;
1793
1794 /*
1795 * Playback.
1796 */
1797 if (cbOutMin)
1798 {
1799 Assert(cbOutMin != UINT32_MAX);
1800
1801 /* New space available, see if we can transfer more. */
1802 PDMDevHlpDMASchedule(pThis->pDevIns);
1803 }
1804
1805 /*
1806 * Recording.
1807 */
1808 /** @todo Implement recording. */
1809
1810 TMTimerSet(pThis->pTimerIO, TMTimerGet(pThis->pTimerIO) + pThis->uTicksIO);
1811}
1812#endif /* !VBOX_WITH_PDM_AUDIO_DRIVER */
1813
1814static void sb16Save(PSSMHANDLE pSSM, PSB16STATE pThis)
1815{
1816 SSMR3PutS32(pSSM, pThis->irq);
1817 SSMR3PutS32(pSSM, pThis->dma);
1818 SSMR3PutS32(pSSM, pThis->hdma);
1819 SSMR3PutS32(pSSM, pThis->port);
1820 SSMR3PutS32(pSSM, pThis->ver);
1821 SSMR3PutS32(pSSM, pThis->in_index);
1822 SSMR3PutS32(pSSM, pThis->out_data_len);
1823 SSMR3PutS32(pSSM, pThis->fmt_stereo);
1824 SSMR3PutS32(pSSM, pThis->fmt_signed);
1825 SSMR3PutS32(pSSM, pThis->fmt_bits);
1826
1827 SSMR3PutU32(pSSM, pThis->fmt);
1828
1829 SSMR3PutS32(pSSM, pThis->dma_auto);
1830 SSMR3PutS32(pSSM, pThis->block_size);
1831 SSMR3PutS32(pSSM, pThis->fifo);
1832 SSMR3PutS32(pSSM, pThis->freq);
1833 SSMR3PutS32(pSSM, pThis->time_const);
1834 SSMR3PutS32(pSSM, pThis->speaker);
1835 SSMR3PutS32(pSSM, pThis->needed_bytes);
1836 SSMR3PutS32(pSSM, pThis->cmd);
1837 SSMR3PutS32(pSSM, pThis->use_hdma);
1838 SSMR3PutS32(pSSM, pThis->highspeed);
1839 SSMR3PutS32(pSSM, pThis->can_write);
1840 SSMR3PutS32(pSSM, pThis->v2x6);
1841
1842 SSMR3PutU8 (pSSM, pThis->csp_param);
1843 SSMR3PutU8 (pSSM, pThis->csp_value);
1844 SSMR3PutU8 (pSSM, pThis->csp_mode);
1845 SSMR3PutU8 (pSSM, pThis->csp_param); /* Bug compatible! */
1846 SSMR3PutMem(pSSM, pThis->csp_regs, 256);
1847 SSMR3PutU8 (pSSM, pThis->csp_index);
1848 SSMR3PutMem(pSSM, pThis->csp_reg83, 4);
1849 SSMR3PutS32(pSSM, pThis->csp_reg83r);
1850 SSMR3PutS32(pSSM, pThis->csp_reg83w);
1851
1852 SSMR3PutMem(pSSM, pThis->in2_data, sizeof (pThis->in2_data));
1853 SSMR3PutMem(pSSM, pThis->out_data, sizeof (pThis->out_data));
1854 SSMR3PutU8 (pSSM, pThis->test_reg);
1855 SSMR3PutU8 (pSSM, pThis->last_read_byte);
1856
1857 SSMR3PutS32(pSSM, pThis->nzero);
1858 SSMR3PutS32(pSSM, pThis->left_till_irq);
1859 SSMR3PutS32(pSSM, pThis->dma_running);
1860 SSMR3PutS32(pSSM, pThis->bytes_per_second);
1861 SSMR3PutS32(pSSM, pThis->align);
1862
1863 SSMR3PutS32(pSSM, pThis->mixer_nreg);
1864 SSMR3PutMem(pSSM, pThis->mixer_regs, 256);
1865
1866}
1867
1868static int sb16Load(PSSMHANDLE pSSM, PSB16STATE pThis, int version_id)
1869{
1870 SSMR3GetS32(pSSM, &pThis->irq);
1871 SSMR3GetS32(pSSM, &pThis->dma);
1872 SSMR3GetS32(pSSM, &pThis->hdma);
1873 SSMR3GetS32(pSSM, &pThis->port);
1874 SSMR3GetS32(pSSM, &pThis->ver);
1875 SSMR3GetS32(pSSM, &pThis->in_index);
1876 SSMR3GetS32(pSSM, &pThis->out_data_len);
1877 SSMR3GetS32(pSSM, &pThis->fmt_stereo);
1878 SSMR3GetS32(pSSM, &pThis->fmt_signed);
1879 SSMR3GetS32(pSSM, &pThis->fmt_bits);
1880
1881 SSMR3GetU32(pSSM, (uint32_t *)&pThis->fmt);
1882
1883 SSMR3GetS32(pSSM, &pThis->dma_auto);
1884 SSMR3GetS32(pSSM, &pThis->block_size);
1885 SSMR3GetS32(pSSM, &pThis->fifo);
1886 SSMR3GetS32(pSSM, &pThis->freq);
1887 SSMR3GetS32(pSSM, &pThis->time_const);
1888 SSMR3GetS32(pSSM, &pThis->speaker);
1889 SSMR3GetS32(pSSM, &pThis->needed_bytes);
1890 SSMR3GetS32(pSSM, &pThis->cmd);
1891 SSMR3GetS32(pSSM, &pThis->use_hdma);
1892 SSMR3GetS32(pSSM, &pThis->highspeed);
1893 SSMR3GetS32(pSSM, &pThis->can_write);
1894 SSMR3GetS32(pSSM, &pThis->v2x6);
1895
1896 SSMR3GetU8 (pSSM, &pThis->csp_param);
1897 SSMR3GetU8 (pSSM, &pThis->csp_value);
1898 SSMR3GetU8 (pSSM, &pThis->csp_mode);
1899 SSMR3GetU8 (pSSM, &pThis->csp_param); /* Bug compatible! */
1900 SSMR3GetMem(pSSM, pThis->csp_regs, 256);
1901 SSMR3GetU8 (pSSM, &pThis->csp_index);
1902 SSMR3GetMem(pSSM, pThis->csp_reg83, 4);
1903 SSMR3GetS32(pSSM, &pThis->csp_reg83r);
1904 SSMR3GetS32(pSSM, &pThis->csp_reg83w);
1905
1906 SSMR3GetMem(pSSM, pThis->in2_data, sizeof (pThis->in2_data));
1907 SSMR3GetMem(pSSM, pThis->out_data, sizeof (pThis->out_data));
1908 SSMR3GetU8 (pSSM, &pThis->test_reg);
1909 SSMR3GetU8 (pSSM, &pThis->last_read_byte);
1910
1911 SSMR3GetS32(pSSM, &pThis->nzero);
1912 SSMR3GetS32(pSSM, &pThis->left_till_irq);
1913 SSMR3GetS32(pSSM, &pThis->dma_running);
1914 SSMR3GetS32(pSSM, &pThis->bytes_per_second);
1915 SSMR3GetS32(pSSM, &pThis->align);
1916
1917 SSMR3GetS32(pSSM, &pThis->mixer_nreg);
1918 SSMR3GetMem(pSSM, pThis->mixer_regs, 256);
1919
1920#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1921 PSB16DRIVER pDrv;
1922 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1923 {
1924 if (pDrv->Out.pStrmOut)
1925 {
1926 pDrv->pConnector->pfnCloseOut(pThis->pDrv, pDrv->Out.pStrmOut);
1927 pDrv->Out.pStrmOut = NULL;
1928 }
1929 }
1930#else
1931 AUD_close_out (&pThis->card, pThis->voice);
1932 pThis->voice = NULL;
1933#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1934
1935 if (pThis->dma_running)
1936 {
1937 if (pThis->freq)
1938 {
1939#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1940 PDMAUDIOSTREAMCFG streamCfg;
1941 streamCfg.uHz = pThis->freq;
1942 streamCfg.cChannels = 1 << pThis->fmt_stereo;
1943 streamCfg.enmFormat = pThis->fmt;
1944 streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
1945
1946 int rc = sb16OpenOut(pThis, &streamCfg);
1947 AssertRC(rc);
1948#else
1949 pThis->audio_free = 0;
1950
1951 audsettings_t as;
1952 as.freq = pThis->freq;
1953 as.nchannels = 1 << pThis->fmt_stereo;
1954 as.fmt = pThis->fmt;
1955 as.endianness = 0;
1956 pThis->voice = AUD_open_out (
1957 &pThis->card,
1958 pThis->voice,
1959 "sb16",
1960 pThis,
1961 sb16AudioCallback,
1962 &as
1963 );
1964#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1965 }
1966
1967 sb16Control(pThis, 1);
1968 sb16SpeakerControl(pThis, pThis->speaker);
1969 }
1970
1971 return VINF_SUCCESS;
1972}
1973
1974static DECLCALLBACK(int) sb16LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
1975{
1976 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
1977
1978 SSMR3PutS32(pSSM, pThis->irqCfg);
1979 SSMR3PutS32(pSSM, pThis->dmaCfg);
1980 SSMR3PutS32(pSSM, pThis->hdmaCfg);
1981 SSMR3PutS32(pSSM, pThis->portCfg);
1982 SSMR3PutS32(pSSM, pThis->verCfg);
1983 return VINF_SSM_DONT_CALL_AGAIN;
1984}
1985
1986static DECLCALLBACK(int) sb16SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1987{
1988 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
1989
1990 sb16LiveExec(pDevIns, pSSM, 0);
1991 sb16Save(pSSM, pThis);
1992 return VINF_SUCCESS;
1993}
1994
1995static DECLCALLBACK(int) sb16LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1996{
1997 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
1998
1999 AssertMsgReturn( uVersion == SB16_SAVE_STATE_VERSION
2000 || uVersion == SB16_SAVE_STATE_VERSION_VBOX_30,
2001 ("%u\n", uVersion),
2002 VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
2003 if (uVersion > SB16_SAVE_STATE_VERSION_VBOX_30)
2004 {
2005 int32_t irq;
2006 SSMR3GetS32 (pSSM, &irq);
2007 int32_t dma;
2008 SSMR3GetS32 (pSSM, &dma);
2009 int32_t hdma;
2010 SSMR3GetS32 (pSSM, &hdma);
2011 int32_t port;
2012 SSMR3GetS32 (pSSM, &port);
2013 int32_t ver;
2014 int rc = SSMR3GetS32 (pSSM, &ver);
2015 AssertRCReturn (rc, rc);
2016
2017 if ( irq != pThis->irqCfg
2018 || dma != pThis->dmaCfg
2019 || hdma != pThis->hdmaCfg
2020 || port != pThis->portCfg
2021 || ver != pThis->verCfg)
2022 {
2023 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
2024 N_("config changed: irq=%x/%x dma=%x/%x hdma=%x/%x port=%x/%x ver=%x/%x (saved/config)"),
2025 irq, pThis->irqCfg,
2026 dma, pThis->dmaCfg,
2027 hdma, pThis->hdmaCfg,
2028 port, pThis->portCfg,
2029 ver, pThis->verCfg);
2030 }
2031 }
2032
2033 if (uPass != SSM_PASS_FINAL)
2034 return VINF_SUCCESS;
2035
2036 sb16Load(pSSM, pThis, uVersion);
2037 return VINF_SUCCESS;
2038}
2039
2040#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
2041static int sb16OpenOut(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg)
2042{
2043 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2044 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
2045
2046 int rc = VINF_SUCCESS;
2047
2048 PSB16DRIVER pDrv;
2049 uint8_t uLUN = 0;
2050 char *pszDesc;
2051 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2052 {
2053 if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] sb16.po", uLUN) <= 0)
2054 {
2055 rc = VERR_NO_MEMORY;
2056 break;
2057 }
2058
2059 int rc2 = pDrv->pConnector->pfnOpenOut(pDrv->pConnector, pszDesc, pCfg, &pDrv->Out.pStrmOut);
2060 LogFlowFunc(("LUN#%RU8: Opened output with rc=%Rrc\n", uLUN, rc));
2061 if (rc2 == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
2062 {
2063 audioMixerRemoveStream(pThis->pSinkOutput, pDrv->Out.phStrmOut);
2064 rc = audioMixerAddStreamOut(pThis->pSinkOutput,
2065 pDrv->pConnector, pDrv->Out.pStrmOut,
2066 0 /* uFlags */,
2067 &pDrv->Out.phStrmOut);
2068 }
2069
2070 RTStrFree(pszDesc);
2071
2072 if (RT_FAILURE(rc2))
2073 {
2074 if (RT_SUCCESS(rc))
2075 rc = rc2;
2076 break;
2077 }
2078
2079 uLUN++;
2080 }
2081 /* Ensure volume gets propagated. */
2082 audioMixerInvalidate(pThis->pMixer);
2083
2084 return rc;
2085}
2086#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
2087
2088/**
2089 * @interface_method_impl{PDMDEVREG,pfnReset}
2090 */
2091static DECLCALLBACK(void) sb16DevReset(PPDMDEVINS pDevIns)
2092{
2093 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2094
2095 /* Bring back the device to initial state, and especially make
2096 * sure there's no interrupt or DMA activity.
2097 */
2098 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 0);
2099
2100 pThis->mixer_regs[0x82] = 0;
2101 pThis->csp_regs[5] = 1;
2102 pThis->csp_regs[9] = 0xf8;
2103
2104 pThis->dma_auto = 0;
2105 pThis->in_index = 0;
2106 pThis->out_data_len = 0;
2107 pThis->left_till_irq = 0;
2108 pThis->needed_bytes = 0;
2109 pThis->block_size = -1;
2110 pThis->nzero = 0;
2111 pThis->highspeed = 0;
2112 pThis->v2x6 = 0;
2113 pThis->cmd = -1;
2114
2115 sb16MixerReset(pThis);
2116 sb16SpeakerControl(pThis, 0);
2117 sb16Control(pThis, 0);
2118 sb16ResetLegacy(pThis);
2119}
2120
2121/**
2122 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2123 */
2124static DECLCALLBACK(void *) sb16QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
2125{
2126 PSB16STATE pThis = RT_FROM_MEMBER(pInterface, SB16STATE, IBase);
2127 Assert(&pThis->IBase == pInterface);
2128
2129 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
2130 return NULL;
2131}
2132
2133/**
2134 * @interface_method_impl{PDMDEVREG,pfnDestruct}
2135 */
2136static DECLCALLBACK(int) sb16Destruct(PPDMDEVINS pDevIns)
2137{
2138 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2139
2140#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
2141 PSB16DRIVER pDrv;
2142
2143 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2144 pDrv->Out.phStrmOut = NULL;
2145
2146 pThis->pSinkOutput = NULL;
2147
2148 if (pThis->pMixer)
2149 {
2150 audioMixerDestroy(pThis->pMixer);
2151 pThis->pMixer = NULL;
2152 }
2153#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
2154
2155 return VINF_SUCCESS;
2156}
2157
2158static DECLCALLBACK(int) sb16Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
2159{
2160 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2161 int rc;
2162
2163 /*
2164 * Validations.
2165 */
2166 Assert(iInstance == 0);
2167 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2168 if (!CFGMR3AreValuesValid(pCfgHandle,
2169 "IRQ\0"
2170 "DMA\0"
2171 "DMA16\0"
2172 "Port\0"
2173 "Version\0"))
2174 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
2175 N_("Invalid configuration for sb16 device"));
2176
2177 /*
2178 * Read config data.
2179 */
2180 rc = CFGMR3QuerySIntDef(pCfgHandle, "IRQ", &pThis->irq, 5);
2181 if (RT_FAILURE(rc))
2182 return PDMDEV_SET_ERROR(pDevIns, rc,
2183 N_("Configuration error: Failed to get the \"IRQ\" value"));
2184 pThis->irqCfg = pThis->irq;
2185
2186 rc = CFGMR3QuerySIntDef(pCfgHandle, "DMA", &pThis->dma, 1);
2187 if (RT_FAILURE(rc))
2188 return PDMDEV_SET_ERROR(pDevIns, rc,
2189 N_("Configuration error: Failed to get the \"DMA\" value"));
2190 pThis->dmaCfg = pThis->dma;
2191
2192 rc = CFGMR3QuerySIntDef(pCfgHandle, "DMA16", &pThis->hdma, 5);
2193 if (RT_FAILURE(rc))
2194 return PDMDEV_SET_ERROR(pDevIns, rc,
2195 N_("Configuration error: Failed to get the \"DMA16\" value"));
2196 pThis->hdmaCfg = pThis->hdma;
2197
2198 RTIOPORT Port;
2199 rc = CFGMR3QueryPortDef(pCfgHandle, "Port", &Port, 0x220);
2200 if (RT_FAILURE(rc))
2201 return PDMDEV_SET_ERROR(pDevIns, rc,
2202 N_("Configuration error: Failed to get the \"Port\" value"));
2203 pThis->port = Port;
2204 pThis->portCfg = Port;
2205
2206 uint16_t u16Version;
2207 rc = CFGMR3QueryU16Def(pCfgHandle, "Version", &u16Version, 0x0405);
2208 if (RT_FAILURE(rc))
2209 return PDMDEV_SET_ERROR(pDevIns, rc,
2210 N_("Configuration error: Failed to get the \"Version\" value"));
2211 pThis->ver = u16Version;
2212 pThis->verCfg = u16Version;
2213
2214 /*
2215 * Init instance data.
2216 */
2217 pThis->pDevIns = pDevIns;
2218 pThis->IBase.pfnQueryInterface = sb16QueryInterface;
2219 pThis->cmd = -1;
2220
2221 pThis->mixer_regs[0x80] = magic_of_irq (pThis->irq);
2222 pThis->mixer_regs[0x81] = (1 << pThis->dma) | (1 << pThis->hdma);
2223 pThis->mixer_regs[0x82] = 2 << 5;
2224
2225 pThis->csp_regs[5] = 1;
2226 pThis->csp_regs[9] = 0xf8;
2227
2228#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
2229 RTListInit(&pThis->lstDrv);
2230#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
2231
2232 sb16MixerReset(pThis);
2233
2234 /*
2235 * Create timer(s), register & attach stuff.
2236 */
2237 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16TimerIRQ, pThis,
2238 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 IRQ timer", &pThis->pTimerIRQ);
2239 if (RT_FAILURE(rc))
2240 AssertMsgFailedReturn(("Error creating IRQ timer, rc=%Rrc\n", rc), rc);
2241
2242 rc = PDMDevHlpIOPortRegister(pDevIns, pThis->port + 0x04, 2, pThis,
2243 mixer_write, mixer_read, NULL, NULL, "SB16");
2244 if (RT_FAILURE(rc))
2245 return rc;
2246 rc = PDMDevHlpIOPortRegister(pDevIns, pThis->port + 0x06, 10, pThis,
2247 dsp_write, dsp_read, NULL, NULL, "SB16");
2248 if (RT_FAILURE(rc))
2249 return rc;
2250
2251 rc = PDMDevHlpDMARegister(pDevIns, pThis->hdma, sb16DMARead, pThis);
2252 if (RT_FAILURE(rc))
2253 return rc;
2254 rc = PDMDevHlpDMARegister(pDevIns, pThis->dma, sb16DMARead, pThis);
2255 if (RT_FAILURE(rc))
2256 return rc;
2257
2258 pThis->can_write = 1;
2259
2260 rc = PDMDevHlpSSMRegister3(pDevIns, SB16_SAVE_STATE_VERSION, sizeof(SB16STATE), sb16LiveExec, sb16SaveExec, sb16LoadExec);
2261 if (RT_FAILURE(rc))
2262 return rc;
2263
2264 /*
2265 * Attach driver.
2266 */
2267#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
2268 uint8_t uLUN;
2269 for (uLUN = 0; uLUN < UINT8_MAX; uLUN)
2270 {
2271 LogFunc(("Trying to attach driver for LUN #%RU8 ...\n", uLUN));
2272 rc = sb16Attach(pDevIns, uLUN, PDM_TACH_FLAGS_NOT_HOT_PLUG);
2273 if (RT_FAILURE(rc))
2274 {
2275 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2276 rc = VINF_SUCCESS;
2277 break;
2278 }
2279
2280 uLUN++;
2281 }
2282
2283 LogFunc(("cLUNs=%RU8, rc=%Rrc\n", uLUN, rc));
2284#else
2285 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Audio Driver Port");
2286 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2287 LogFunc(("SB16: No attached driver!\n"));
2288 else if (RT_FAILURE(rc))
2289 {
2290 AssertMsgFailed(("Failed to attach SB16 LUN #0! rc=%Rrc\n", rc));
2291 return rc;
2292 }
2293#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
2294
2295#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
2296 sb16ResetLegacy(pThis);
2297
2298 PSB16DRIVER pDrv;
2299 uLUN = 0;
2300 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2301 {
2302 PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
2303 AssertPtr(pCon);
2304
2305 bool fIsOK = pCon->pfnIsOutputOK(pCon, pDrv->Out.pStrmOut);
2306 if (fIsOK)
2307 {
2308 rc = pCon->pfnEnableOut(pCon, pDrv->Out.pStrmOut, true /* fEnable */);
2309 fIsOK = RT_SUCCESS(rc);
2310 }
2311
2312 if (!fIsOK)
2313 {
2314 /*
2315 * Only primary drivers are critical for the VM to run. Everything else
2316 * might not worth showing an own error message box in the GUI.
2317 */
2318 if (!(pDrv->Flags & PDMAUDIODRVFLAG_PRIMARY))
2319 continue;
2320
2321 LogRel(("SB16: Warning: Unable to enable/use output for LUN#%RU8\n", uLUN));
2322
2323 pCon->pfnCloseOut(pCon, pDrv->Out.pStrmOut);
2324 pDrv->Out.pStrmOut = NULL;
2325
2326 pThis->pDrv->pfnInitNull(pThis->pDrv);
2327
2328 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
2329 N_("No audio devices could be opened. Selecting the NULL audio backend "
2330 "with the consequence that no sound is audible"));
2331 }
2332
2333 uLUN++;
2334 }
2335
2336 if (RT_SUCCESS(rc))
2337 {
2338 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16TimerIO, pThis,
2339 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 IO timer", &pThis->pTimerIO);
2340 if (RT_FAILURE(rc))
2341 AssertMsgFailedReturn(("Error creating I/O timer, rc=%Rrc\n", rc), rc);
2342 else
2343 {
2344 pThis->uTicksIO = PDMDevHlpTMTimeVirtGetFreq(pDevIns) / 200; /** Hz. @todo Make this configurable! */
2345 if (pThis->uTicksIO < 100)
2346 pThis->uTicksIO = 100;
2347 LogFunc(("I/O timer ticks=%RU64\n", pThis->uTicksIO));
2348
2349 /* Fire off timer. */
2350 TMTimerSet(pThis->pTimerIO, TMTimerGet(pThis->pTimerIO) + pThis->uTicksIO);
2351 }
2352 }
2353#else
2354 AUD_register_card("sb16", &pThis->card);
2355 sb16ResetLegacy(pThis);
2356
2357 if (!AUD_is_host_voice_out_ok(pThis->voice))
2358 {
2359 LogRel (("SB16: WARNING: Unable to open PCM OUT!\n"));
2360 AUD_close_out (&pThis->card, pThis->voice);
2361 pThis->voice = NULL;
2362
2363 AUD_init_null();
2364
2365 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
2366 N_("No audio devices could be opened. Selecting the NULL audio backend "
2367 "with the consequence that no sound is audible"));
2368 }
2369#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
2370
2371 return VINF_SUCCESS;
2372}
2373
2374const PDMDEVREG g_DeviceSB16 =
2375{
2376 /* u32Version */
2377 PDM_DEVREG_VERSION,
2378 /* szName */
2379 "sb16",
2380 /* szRCMod */
2381 "",
2382 /* szR0Mod */
2383 "",
2384 /* pszDescription */
2385 "Sound Blaster 16 Controller",
2386 /* fFlags */
2387 PDM_DEVREG_FLAGS_DEFAULT_BITS,
2388 /* fClass */
2389 PDM_DEVREG_CLASS_AUDIO,
2390 /* cMaxInstances */
2391 1,
2392 /* cbInstance */
2393 sizeof(SB16STATE),
2394 /* pfnConstruct */
2395 sb16Construct,
2396 /* pfnDestruct */
2397 sb16Destruct,
2398 /* pfnRelocate */
2399 NULL,
2400 /* pfnMemSetup */
2401 NULL,
2402 /* pfnPowerOn */
2403 NULL,
2404 /* pfnReset */
2405 sb16DevReset,
2406 /* pfnSuspend */
2407 NULL,
2408 /* pfnResume */
2409 NULL,
2410 /* pfnAttach */
2411 NULL,
2412 /* pfnDetach */
2413 NULL,
2414 /* pfnQueryInterface */
2415 NULL,
2416 /* pfnInitComplete */
2417 NULL,
2418 /* pfnPowerOff */
2419 NULL,
2420 /* pfnSoftReset */
2421 NULL,
2422 /* u32VersionEnd */
2423 PDM_DEVREG_VERSION
2424};
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