VirtualBox

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

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

SB16/Audio: VBoxized.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 68.8 KB
Line 
1/* $Id: DevSB16.cpp 55355 2015-04-21 14:14:26Z 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 void sb16ResetLegacy(PSB16STATE pThis)
1060{
1061 pThis->freq = 11025;
1062 pThis->fmt_signed = 0;
1063 pThis->fmt_bits = 8;
1064 pThis->fmt_stereo = 0;
1065
1066#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1067 PDMAUDIOSTREAMCFG streamCfg;
1068 streamCfg.uHz = pThis->freq;
1069 streamCfg.cChannels = 1; /* Mono */
1070 streamCfg.enmFormat = AUD_FMT_U8;
1071 streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
1072
1073 int rc = sb16OpenOut(pThis, &streamCfg);
1074 AssertRC(rc);
1075#else
1076 audsettings_t streamCfg;
1077 streamCfg.freq = pThis->freq;
1078 streamCfg.nchannels = 1;
1079 streamCfg.fmt = AUD_FMT_U8;
1080 streamCfg.endianness = 0;
1081 pThis->voice = AUD_open_out (
1082 &pThis->card,
1083 pThis->voice,
1084 "sb16",
1085 pThis,
1086 sb16AudioCallback,
1087 &streamCfg
1088 );
1089#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1090
1091 /* Not sure about that... */
1092 /* AUD_set_active_out (pThis->voice, 1); */
1093}
1094
1095static void sb16Reset(PSB16STATE pThis)
1096{
1097 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 0);
1098 if (pThis->dma_auto)
1099 {
1100 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 1);
1101 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 0);
1102 }
1103
1104 pThis->mixer_regs[0x82] = 0;
1105 pThis->dma_auto = 0;
1106 pThis->in_index = 0;
1107 pThis->out_data_len = 0;
1108 pThis->left_till_irq = 0;
1109 pThis->needed_bytes = 0;
1110 pThis->block_size = -1;
1111 pThis->nzero = 0;
1112 pThis->highspeed = 0;
1113 pThis->v2x6 = 0;
1114 pThis->cmd = -1;
1115
1116 dsp_out_data(pThis, 0xaa);
1117 sb16SpeakerControl(pThis, 0);
1118 sb16Control(pThis, 0);
1119 sb16ResetLegacy(pThis);
1120}
1121
1122static IO_WRITE_PROTO(dsp_write)
1123{
1124 PSB16STATE pThis = (PSB16STATE)opaque;
1125 int iport = nport - pThis->port;
1126
1127 LogFlowFunc(("write %#x <- %#x\n", nport, val));
1128 switch (iport)
1129 {
1130 case 0x06:
1131 switch (val)
1132 {
1133 case 0x00:
1134 {
1135 if (pThis->v2x6 == 1)
1136 {
1137 if (0 && pThis->highspeed)
1138 {
1139 pThis->highspeed = 0;
1140 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 0);
1141 sb16Control(pThis, 0);
1142 }
1143 else
1144 sb16Reset(pThis);
1145 }
1146 pThis->v2x6 = 0;
1147 break;
1148 }
1149
1150 case 0x01:
1151 case 0x03: /* FreeBSD kludge */
1152 pThis->v2x6 = 1;
1153 break;
1154
1155 case 0xc6:
1156 pThis->v2x6 = 0; /* Prince of Persia, csp.sys, diagnose.exe */
1157 break;
1158
1159 case 0xb8: /* Panic */
1160 sb16Reset(pThis);
1161 break;
1162
1163 case 0x39:
1164 dsp_out_data(pThis, 0x38);
1165 sb16Reset(pThis);
1166 pThis->v2x6 = 0x39;
1167 break;
1168
1169 default:
1170 pThis->v2x6 = val;
1171 break;
1172 }
1173 break;
1174
1175 case 0x0c: /* Write data or command | write status */
1176#if 0
1177 if (pThis->highspeed)
1178 break;
1179#endif
1180 if (0 == pThis->needed_bytes)
1181 {
1182 sb16HandleCommand(pThis, val);
1183#if 0
1184 if (0 == pThis->needed_bytes) {
1185 log_dsp (pThis);
1186 }
1187#endif
1188 }
1189 else
1190 {
1191 if (pThis->in_index == sizeof (pThis->in2_data))
1192 {
1193 LogFlowFunc(("in data overrun\n"));
1194 }
1195 else
1196 {
1197 pThis->in2_data[pThis->in_index++] = val;
1198 if (pThis->in_index == pThis->needed_bytes)
1199 {
1200 pThis->needed_bytes = 0;
1201 complete (pThis);
1202#if 0
1203 log_dsp (pThis);
1204#endif
1205 }
1206 }
1207 }
1208 break;
1209
1210 default:
1211 LogFlowFunc(("nport=%#x, val=%#x)\n", nport, val));
1212 break;
1213 }
1214
1215 return VINF_SUCCESS;
1216}
1217
1218static IO_READ_PROTO(dsp_read)
1219{
1220 PSB16STATE pThis = (PSB16STATE)opaque;
1221 int iport, retval, ack = 0;
1222
1223 iport = nport - pThis->port;
1224
1225 /** @todo reject non-byte access?
1226 * The spec does not mention a non-byte access so we should check how real hardware behaves. */
1227
1228 switch (iport)
1229 {
1230 case 0x06: /* reset */
1231 retval = 0xff;
1232 break;
1233
1234 case 0x0a: /* read data */
1235 if (pThis->out_data_len)
1236 {
1237 retval = pThis->out_data[--pThis->out_data_len];
1238 pThis->last_read_byte = retval;
1239 }
1240 else
1241 {
1242 if (pThis->cmd != -1)
1243 LogFlowFunc(("empty output buffer for command %#x\n", pThis->cmd));
1244 retval = pThis->last_read_byte;
1245 /* goto error; */
1246 }
1247 break;
1248
1249 case 0x0c: /* 0 can write */
1250 retval = pThis->can_write ? 0 : 0x80;
1251 break;
1252
1253 case 0x0d: /* timer interrupt clear */
1254 /* LogFlowFunc(("timer interrupt clear\n")); */
1255 retval = 0;
1256 break;
1257
1258 case 0x0e: /* data available status | irq 8 ack */
1259 retval = (!pThis->out_data_len || pThis->highspeed) ? 0 : 0x80;
1260 if (pThis->mixer_regs[0x82] & 1)
1261 {
1262 ack = 1;
1263 pThis->mixer_regs[0x82] &= ~1;
1264 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 0);
1265 }
1266 break;
1267
1268 case 0x0f: /* irq 16 ack */
1269 retval = 0xff;
1270 if (pThis->mixer_regs[0x82] & 2)
1271 {
1272 ack = 1;
1273 pThis->mixer_regs[0x82] &= ~2;
1274 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 0);
1275 }
1276 break;
1277
1278 default:
1279 goto error;
1280 }
1281
1282 if (!ack)
1283 LogFlowFunc(("read %#x -> %#x\n", nport, retval));
1284
1285 *pu32 = retval;
1286 return VINF_SUCCESS;
1287
1288 error:
1289 LogFlowFunc(("warning: dsp_read %#x error\n", nport));
1290 return VERR_IOM_IOPORT_UNUSED;
1291}
1292
1293static void sb16MixerReset(PSB16STATE pThis)
1294{
1295#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1296 PSB16DRIVER pDrv;
1297
1298 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1299 pDrv->Out.phStrmOut = NULL;
1300
1301 pThis->pSinkOutput = NULL;
1302
1303 if (pThis->pMixer)
1304 {
1305 audioMixerDestroy(pThis->pMixer);
1306 pThis->pMixer = NULL;
1307 }
1308#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1309
1310 memset (pThis->mixer_regs, 0xff, 0x7f);
1311 memset (pThis->mixer_regs + 0x83, 0xff, sizeof (pThis->mixer_regs) - 0x83);
1312
1313 pThis->mixer_regs[0x02] = 4; /* master volume 3bits */
1314 pThis->mixer_regs[0x06] = 4; /* MIDI volume 3bits */
1315 pThis->mixer_regs[0x08] = 0; /* CD volume 3bits */
1316 pThis->mixer_regs[0x0a] = 0; /* voice volume 2bits */
1317
1318 /* d5=input filt, d3=lowpass filt, d1,d2=input source */
1319 pThis->mixer_regs[0x0c] = 0;
1320
1321 /* d5=output filt, d1=stereo switch */
1322 pThis->mixer_regs[0x0e] = 0;
1323
1324 /* voice volume L d5,d7, R d1,d3 */
1325 pThis->mixer_regs[0x04] = (4 << 5) | (4 << 1);
1326 /* master ... */
1327 pThis->mixer_regs[0x22] = (4 << 5) | (4 << 1);
1328 /* MIDI ... */
1329 pThis->mixer_regs[0x26] = (4 << 5) | (4 << 1);
1330
1331 for (int i = 0x30; i < 0x48; i++)
1332 pThis->mixer_regs[i] = 0x20;
1333
1334#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1335 int rc2 = audioMixerCreate("SB16 Mixer", 0 /* uFlags */, &pThis->pMixer);
1336 if (RT_SUCCESS(rc2))
1337 {
1338 /* Set a default audio format for our mixer. */
1339 PDMAUDIOSTREAMCFG streamCfg;
1340 streamCfg.uHz = 41000;
1341 streamCfg.cChannels = 2;
1342 streamCfg.enmFormat = AUD_FMT_S16;
1343 streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
1344
1345 rc2 = audioMixerSetDeviceFormat(pThis->pMixer, &streamCfg);
1346 AssertRC(rc2);
1347
1348 /* Add all required audio sinks. */
1349 rc2 = audioMixerAddSink(pThis->pMixer, "[Playback] PCM Output",
1350 AUDMIXSINKDIR_OUTPUT, &pThis->pSinkOutput);
1351 AssertRC(rc2);
1352 }
1353#endif
1354}
1355
1356static IO_WRITE_PROTO(mixer_write_indexb)
1357{
1358 PSB16STATE pThis = (PSB16STATE)opaque;
1359 (void) nport;
1360 pThis->mixer_nreg = val;
1361
1362 return VINF_SUCCESS;
1363}
1364
1365#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1366uint32_t popcount (uint32_t u) /** @todo r=andy WTF? */
1367{
1368 u = ((u&0x55555555) + ((u>>1)&0x55555555));
1369 u = ((u&0x33333333) + ((u>>2)&0x33333333));
1370 u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
1371 u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
1372 u = ( u&0x0000ffff) + (u>>16);
1373 return u;
1374}
1375
1376uint32_t lsbindex (uint32_t u)
1377{
1378 return popcount ((u & -(int32_t)u) - 1);
1379}
1380#endif
1381
1382static IO_WRITE_PROTO(mixer_write_datab)
1383{
1384 PSB16STATE pThis = (PSB16STATE)opaque;
1385 bool fUpdateMaster = false;
1386 bool fUpdateStream = false;
1387
1388 (void) nport;
1389 LogFlowFunc(("mixer_write [%#x] <- %#x\n", pThis->mixer_nreg, val));
1390
1391 switch (pThis->mixer_nreg)
1392 {
1393 case 0x00:
1394 sb16MixerReset(pThis);
1395 /* And update the actual volume, too. */
1396 fUpdateMaster = true;
1397 fUpdateStream = true;
1398 break;
1399
1400 case 0x04:
1401 /* Translate from old style stream volume (L/R). */
1402 pThis->mixer_regs[0x32] = val & 0xff;
1403 pThis->mixer_regs[0x33] = val << 4;
1404 fUpdateStream = true;
1405 break;
1406
1407 case 0x22:
1408 /* Translate from old style master volume (L/R). */
1409 pThis->mixer_regs[0x30] = val & 0xff;
1410 pThis->mixer_regs[0x31] = val << 4;
1411 fUpdateMaster = true;
1412 break;
1413
1414 case 0x30:
1415 /* Translate to old style master volume (L). */
1416 pThis->mixer_regs[0x22] = (pThis->mixer_regs[0x22] & 0x0f) | val;
1417 fUpdateMaster = true;
1418 break;
1419
1420 case 0x31:
1421 /* Translate to old style master volume (R). */
1422 pThis->mixer_regs[0x22] = (pThis->mixer_regs[0x22] & 0xf0) | (val >> 4);
1423 fUpdateMaster = true;
1424 break;
1425
1426 case 0x32:
1427 /* Translate to old style stream volume (L). */
1428 pThis->mixer_regs[0x04] = (pThis->mixer_regs[0x04] & 0x0f) | val;
1429 fUpdateStream = true;
1430 break;
1431
1432 case 0x33:
1433 /* Translate to old style stream volume (R). */
1434 pThis->mixer_regs[0x04] = (pThis->mixer_regs[0x04] & 0xf0) | (val >> 4);
1435 fUpdateStream = true;
1436 break;
1437
1438 case 0x80:
1439 {
1440 int irq = irq_of_magic(val);
1441 LogFlowFunc(("setting irq to %d (val=%#x)\n", irq, val));
1442 if (irq > 0)
1443 pThis->irq = irq;
1444 break;
1445 }
1446
1447 case 0x81:
1448 {
1449 int dma, hdma;
1450
1451 dma = lsbindex (val & 0xf);
1452 hdma = lsbindex (val & 0xf0);
1453 if (dma != pThis->dma || hdma != pThis->hdma)
1454 LogFlow(("SB16: attempt to change DMA 8bit %d(%d), 16bit %d(%d) (val=%#x)\n",
1455 dma, pThis->dma, hdma, pThis->hdma, val));
1456#if 0
1457 pThis->dma = dma;
1458 pThis->hdma = hdma;
1459#endif
1460 break;
1461 }
1462
1463 case 0x82:
1464 LogFlowFunc(("attempt to write into IRQ status register (val=%#x)\n", val));
1465 return VINF_SUCCESS;
1466
1467 default:
1468 if (pThis->mixer_nreg >= 0x80)
1469 LogFlowFunc(("attempt to write mixer[%#x] <- %#x\n", pThis->mixer_nreg, val));
1470 break;
1471 }
1472
1473 pThis->mixer_regs[pThis->mixer_nreg] = val;
1474
1475 /* Update the master (mixer) volume. */
1476 if (fUpdateMaster)
1477 {
1478 int mute = 0; /** @todo Handle (un)muting. */
1479 uint8_t lvol = pThis->mixer_regs[0x30];
1480 uint8_t rvol = pThis->mixer_regs[0x31];
1481
1482#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1483 PDMAUDIOVOLUME vol = { RT_BOOL(mute), lvol, rvol };
1484 audioMixerSetMasterVolume(pThis->pMixer, &vol);
1485#else
1486 AUD_set_volume(AUD_MIXER_VOLUME, &mute, &lvol, &rvol);
1487#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1488 }
1489
1490 /* Update the stream (PCM) volume. */
1491 if (fUpdateStream)
1492 {
1493 int mute = 0; /** @todo Handle (un)muting. */
1494 uint8_t lvol = pThis->mixer_regs[0x32];
1495 uint8_t rvol = pThis->mixer_regs[0x33];
1496
1497#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1498 PDMAUDIOVOLUME vol = { RT_BOOL(mute), lvol, rvol };
1499 audioMixerSetSinkVolume(pThis->pSinkOutput, &vol);
1500#else
1501 AUD_set_volume(AUD_MIXER_PCM, &mute, &lvol, &rvol);
1502#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1503 }
1504
1505 return VINF_SUCCESS;
1506}
1507
1508static IO_WRITE_PROTO(mixer_write)
1509{
1510 PSB16STATE pThis = (PSB16STATE)opaque;
1511 int iport = nport - pThis->port;
1512 switch (cb)
1513 {
1514 case 1:
1515 switch (iport)
1516 {
1517 case 4:
1518 mixer_write_indexb (pDevIns, opaque, nport, val, 1);
1519 break;
1520 case 5:
1521 mixer_write_datab (pDevIns, opaque, nport, val, 1);
1522 break;
1523 }
1524 break;
1525 case 2:
1526 mixer_write_indexb (pDevIns, opaque, nport, val & 0xff, 1);
1527 mixer_write_datab (pDevIns, opaque, nport, (val >> 8) & 0xff, 1);
1528 break;
1529 default:
1530 AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", nport, cb, val));
1531 break;
1532 }
1533 return VINF_SUCCESS;
1534}
1535
1536static IO_READ_PROTO(mixer_read)
1537{
1538 PSB16STATE pThis = (PSB16STATE)opaque;
1539
1540 (void) nport;
1541#ifndef DEBUG_SB16_MOST
1542 if (pThis->mixer_nreg != 0x82) {
1543 LogFlowFunc(("mixer_read[%#x] -> %#x\n",
1544 pThis->mixer_nreg, pThis->mixer_regs[pThis->mixer_nreg]));
1545 }
1546#else
1547 LogFlowFunc(("mixer_read[%#x] -> %#x\n",
1548 pThis->mixer_nreg, pThis->mixer_regs[pThis->mixer_nreg]));
1549#endif
1550 *pu32 = pThis->mixer_regs[pThis->mixer_nreg];
1551 return VINF_SUCCESS;
1552}
1553
1554static int sb16WriteAudio(PSB16STATE pThis, int nchan, uint32_t dma_pos,
1555 uint32_t dma_len, int len)
1556{
1557 uint8_t tmpbuf[_4K]; /** @todo Have a buffer on the heap. */
1558 uint32_t cbToWrite = len;
1559 uint32_t cbWrittenTotal = 0;
1560
1561 while (cbToWrite)
1562 {
1563 uint32_t cbWrittenMin = UINT32_MAX;
1564 uint32_t cbToRead;
1565 uint32_t cbRead;
1566
1567 cbToRead = RT_MIN(dma_len - dma_pos, cbToWrite);
1568 if (cbToRead > sizeof(tmpbuf))
1569 cbToRead = sizeof(tmpbuf);
1570
1571 int rc = PDMDevHlpDMAReadMemory(pThis->pDevIns, nchan, tmpbuf, dma_pos, cbToRead, &cbRead);
1572 AssertMsgRC(rc, ("DMAReadMemory -> %Rrc\n", rc));
1573
1574#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1575 uint32_t cbWritten;
1576
1577 /* Just multiplex the output to the connected backends.
1578 * No need to utilize the virtual mixer here (yet). */
1579 PSB16DRIVER pDrv;
1580 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1581 {
1582 int rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
1583 tmpbuf, cbToRead, &cbWritten);
1584 AssertRCBreak(rc);
1585 if (RT_FAILURE(rc2))
1586 continue;
1587
1588 cbWrittenMin = RT_MIN(cbWrittenMin, cbWritten);
1589 LogFlowFunc(("\tLUN#%RU8: cbWritten=%RU32, cWrittenMin=%RU32\n", pDrv->uLUN, cbWritten, cbWrittenMin));
1590 }
1591#else
1592 cbWrittenMin = AUD_write (pThis->voice, tmpbuf, cbToRead);
1593#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1594
1595 Assert(cbToWrite >= cbWrittenMin);
1596 cbToWrite -= cbWrittenMin;
1597 dma_pos = (dma_pos + cbWrittenMin) % dma_len;
1598 cbWrittenTotal += cbWrittenMin;
1599
1600 if (!cbRead || !cbWrittenMin)
1601 break;
1602 }
1603
1604 return cbWrittenTotal;
1605}
1606
1607static DECLCALLBACK(uint32_t) sb16DMARead(PPDMDEVINS pDevIns, void *opaque, unsigned nchan, uint32_t dma_pos, uint32_t dma_len)
1608{
1609 PSB16STATE pThis = (PSB16STATE)opaque;
1610 int till, copy, written, free;
1611
1612 if (pThis->block_size <= 0)
1613 {
1614 LogFlowFunc(("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n",
1615 pThis->block_size, nchan, dma_pos, dma_len));
1616 return dma_pos;
1617 }
1618
1619 if (pThis->left_till_irq < 0)
1620 pThis->left_till_irq = pThis->block_size;
1621
1622#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1623 PSB16DRIVER pDrv;
1624
1625 uint32_t cbOutMin = UINT32_MAX;
1626 uint32_t cbOut;
1627 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1628 {
1629 int rc2 = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
1630 NULL /* pcbIn */, &cbOut, NULL /* pcSamplesLive */);
1631 if (RT_SUCCESS(rc2))
1632 cbOutMin = RT_MIN(cbOutMin, cbOut);
1633 }
1634
1635 LogFlowFunc(("cbOutMin=%RU32\n", cbOutMin));
1636 if (cbOutMin == UINT32_MAX)
1637 {
1638 free = dma_len;
1639 }
1640 else
1641 {
1642 free = cbOutMin & ~pThis->align; /** @todo int vs. uint32. */
1643 if ((free <= 0) || !dma_len)
1644 return dma_pos;
1645 }
1646#else
1647 if (pThis->voice)
1648 {
1649 free = pThis->audio_free & ~pThis->align;
1650 if ((free <= 0) || !dma_len)
1651 return dma_pos;
1652 }
1653 else
1654 free = dma_len;
1655#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1656
1657 copy = free;
1658 till = pThis->left_till_irq;
1659
1660#ifdef DEBUG_SB16_MOST
1661 LogFlowFunc(("pos:%06d %d till:%d len:%d\n", dma_pos, free, till, dma_len));
1662#endif
1663
1664 if (copy >= till)
1665 {
1666 if (0 == pThis->dma_auto)
1667 {
1668 copy = till;
1669 }
1670 else
1671 {
1672 if (copy >= till + pThis->block_size)
1673 copy = till; /* Make sure we won't skip IRQs. */
1674 }
1675 }
1676
1677 written = sb16WriteAudio(pThis, nchan, dma_pos, dma_len, copy);
1678 dma_pos = (dma_pos + written) % dma_len;
1679 pThis->left_till_irq -= written;
1680
1681 if (pThis->left_till_irq <= 0)
1682 {
1683 pThis->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
1684 PDMDevHlpISASetIrq(pThis->pDevIns, pThis->irq, 1);
1685 if (0 == pThis->dma_auto)
1686 {
1687 sb16Control(pThis, 0);
1688 sb16SpeakerControl(pThis, 0);
1689 }
1690 }
1691
1692#ifdef DEBUG_SB16_MOST
1693 LogFlowFunc(("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n",
1694 dma_pos, free, dma_len, pThis->left_till_irq, copy, written,
1695 pThis->block_size));
1696#endif
1697
1698 while (pThis->left_till_irq <= 0)
1699 pThis->left_till_irq += pThis->block_size;
1700
1701 return dma_pos;
1702}
1703
1704#ifndef VBOX_WITH_PDM_AUDIO_DRIVER
1705static void sb16AudioCallback(void *pvContext, int cbFree)
1706{
1707 PSB16STATE pState = (PSB16STATE)pvContext;
1708 AssertPtrReturnVoid(pState);
1709 pState->audio_free = cbFree;
1710 /* New space available, see if we can transfer more. There is no cyclic DMA timer in VBox. */
1711 PDMDevHlpDMASchedule(pState->pDevIns);
1712}
1713#else
1714static DECLCALLBACK(void) sb16TimerIO(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
1715{
1716 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
1717 AssertPtrReturnVoid(pThis);
1718
1719 int rc = VINF_SUCCESS;
1720
1721 uint32_t cbInMax = 0;
1722 uint32_t cbOutMin = UINT32_MAX;
1723
1724 PSB16DRIVER pDrv;
1725
1726 uint32_t cbIn, cbOut, cSamplesLive;
1727 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1728 {
1729 rc = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
1730 &cbIn, &cbOut, &cSamplesLive);
1731 if (RT_SUCCESS(rc))
1732 {
1733 LogFlowFunc(("\tLUN#%RU8: [1] cbIn=%RU32, cbOut=%RU32\n", pDrv->uLUN, cbIn, cbOut));
1734
1735 if (cSamplesLive)
1736 {
1737 uint32_t cSamplesPlayed;
1738 int rc2 = pDrv->pConnector->pfnPlayOut(pDrv->pConnector, &cSamplesPlayed);
1739 if (RT_SUCCESS(rc2))
1740 LogFlowFunc(("LUN#%RU8: cSamplesLive=%RU32, cSamplesPlayed=%RU32\n",
1741 pDrv->uLUN, cSamplesLive, cSamplesPlayed));
1742
1743 if (cSamplesPlayed)
1744 {
1745 rc = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
1746 &cbIn, &cbOut, &cSamplesLive);
1747 if (RT_SUCCESS(rc))
1748 LogFlowFunc(("\tLUN#%RU8: [2] cbIn=%RU32, cbOut=%RU32\n", pDrv->uLUN, cbIn, cbOut));
1749 }
1750 }
1751
1752 cbInMax = RT_MAX(cbInMax, cbIn);
1753 cbOutMin = RT_MIN(cbOutMin, cbOut);
1754 }
1755 }
1756
1757 LogFlowFunc(("cbInMax=%RU32, cbOutMin=%RU32\n", cbInMax, cbOutMin));
1758
1759 if (cbOutMin == UINT32_MAX)
1760 cbOutMin = 0;
1761
1762 /*
1763 * Playback.
1764 */
1765 if (cbOutMin)
1766 {
1767 Assert(cbOutMin != UINT32_MAX);
1768
1769 /* New space available, see if we can transfer more. */
1770 PDMDevHlpDMASchedule(pThis->pDevIns);
1771 }
1772
1773 /*
1774 * Recording.
1775 */
1776 /** @todo Implement recording. */
1777
1778 TMTimerSet(pThis->pTimerIO, TMTimerGet(pThis->pTimerIO) + pThis->uTicksIO);
1779}
1780#endif /* !VBOX_WITH_PDM_AUDIO_DRIVER */
1781
1782static void sb16Save(PSSMHANDLE pSSM, PSB16STATE pThis)
1783{
1784 SSMR3PutS32(pSSM, pThis->irq);
1785 SSMR3PutS32(pSSM, pThis->dma);
1786 SSMR3PutS32(pSSM, pThis->hdma);
1787 SSMR3PutS32(pSSM, pThis->port);
1788 SSMR3PutS32(pSSM, pThis->ver);
1789 SSMR3PutS32(pSSM, pThis->in_index);
1790 SSMR3PutS32(pSSM, pThis->out_data_len);
1791 SSMR3PutS32(pSSM, pThis->fmt_stereo);
1792 SSMR3PutS32(pSSM, pThis->fmt_signed);
1793 SSMR3PutS32(pSSM, pThis->fmt_bits);
1794
1795 SSMR3PutU32(pSSM, pThis->fmt);
1796
1797 SSMR3PutS32(pSSM, pThis->dma_auto);
1798 SSMR3PutS32(pSSM, pThis->block_size);
1799 SSMR3PutS32(pSSM, pThis->fifo);
1800 SSMR3PutS32(pSSM, pThis->freq);
1801 SSMR3PutS32(pSSM, pThis->time_const);
1802 SSMR3PutS32(pSSM, pThis->speaker);
1803 SSMR3PutS32(pSSM, pThis->needed_bytes);
1804 SSMR3PutS32(pSSM, pThis->cmd);
1805 SSMR3PutS32(pSSM, pThis->use_hdma);
1806 SSMR3PutS32(pSSM, pThis->highspeed);
1807 SSMR3PutS32(pSSM, pThis->can_write);
1808 SSMR3PutS32(pSSM, pThis->v2x6);
1809
1810 SSMR3PutU8 (pSSM, pThis->csp_param);
1811 SSMR3PutU8 (pSSM, pThis->csp_value);
1812 SSMR3PutU8 (pSSM, pThis->csp_mode);
1813 SSMR3PutU8 (pSSM, pThis->csp_param); /* Bug compatible! */
1814 SSMR3PutMem(pSSM, pThis->csp_regs, 256);
1815 SSMR3PutU8 (pSSM, pThis->csp_index);
1816 SSMR3PutMem(pSSM, pThis->csp_reg83, 4);
1817 SSMR3PutS32(pSSM, pThis->csp_reg83r);
1818 SSMR3PutS32(pSSM, pThis->csp_reg83w);
1819
1820 SSMR3PutMem(pSSM, pThis->in2_data, sizeof (pThis->in2_data));
1821 SSMR3PutMem(pSSM, pThis->out_data, sizeof (pThis->out_data));
1822 SSMR3PutU8 (pSSM, pThis->test_reg);
1823 SSMR3PutU8 (pSSM, pThis->last_read_byte);
1824
1825 SSMR3PutS32(pSSM, pThis->nzero);
1826 SSMR3PutS32(pSSM, pThis->left_till_irq);
1827 SSMR3PutS32(pSSM, pThis->dma_running);
1828 SSMR3PutS32(pSSM, pThis->bytes_per_second);
1829 SSMR3PutS32(pSSM, pThis->align);
1830
1831 SSMR3PutS32(pSSM, pThis->mixer_nreg);
1832 SSMR3PutMem(pSSM, pThis->mixer_regs, 256);
1833
1834}
1835
1836static int sb16Load(PSSMHANDLE pSSM, PSB16STATE pThis, int version_id)
1837{
1838 SSMR3GetS32(pSSM, &pThis->irq);
1839 SSMR3GetS32(pSSM, &pThis->dma);
1840 SSMR3GetS32(pSSM, &pThis->hdma);
1841 SSMR3GetS32(pSSM, &pThis->port);
1842 SSMR3GetS32(pSSM, &pThis->ver);
1843 SSMR3GetS32(pSSM, &pThis->in_index);
1844 SSMR3GetS32(pSSM, &pThis->out_data_len);
1845 SSMR3GetS32(pSSM, &pThis->fmt_stereo);
1846 SSMR3GetS32(pSSM, &pThis->fmt_signed);
1847 SSMR3GetS32(pSSM, &pThis->fmt_bits);
1848
1849 SSMR3GetU32(pSSM, (uint32_t *)&pThis->fmt);
1850
1851 SSMR3GetS32(pSSM, &pThis->dma_auto);
1852 SSMR3GetS32(pSSM, &pThis->block_size);
1853 SSMR3GetS32(pSSM, &pThis->fifo);
1854 SSMR3GetS32(pSSM, &pThis->freq);
1855 SSMR3GetS32(pSSM, &pThis->time_const);
1856 SSMR3GetS32(pSSM, &pThis->speaker);
1857 SSMR3GetS32(pSSM, &pThis->needed_bytes);
1858 SSMR3GetS32(pSSM, &pThis->cmd);
1859 SSMR3GetS32(pSSM, &pThis->use_hdma);
1860 SSMR3GetS32(pSSM, &pThis->highspeed);
1861 SSMR3GetS32(pSSM, &pThis->can_write);
1862 SSMR3GetS32(pSSM, &pThis->v2x6);
1863
1864 SSMR3GetU8 (pSSM, &pThis->csp_param);
1865 SSMR3GetU8 (pSSM, &pThis->csp_value);
1866 SSMR3GetU8 (pSSM, &pThis->csp_mode);
1867 SSMR3GetU8 (pSSM, &pThis->csp_param); /* Bug compatible! */
1868 SSMR3GetMem(pSSM, pThis->csp_regs, 256);
1869 SSMR3GetU8 (pSSM, &pThis->csp_index);
1870 SSMR3GetMem(pSSM, pThis->csp_reg83, 4);
1871 SSMR3GetS32(pSSM, &pThis->csp_reg83r);
1872 SSMR3GetS32(pSSM, &pThis->csp_reg83w);
1873
1874 SSMR3GetMem(pSSM, pThis->in2_data, sizeof (pThis->in2_data));
1875 SSMR3GetMem(pSSM, pThis->out_data, sizeof (pThis->out_data));
1876 SSMR3GetU8 (pSSM, &pThis->test_reg);
1877 SSMR3GetU8 (pSSM, &pThis->last_read_byte);
1878
1879 SSMR3GetS32(pSSM, &pThis->nzero);
1880 SSMR3GetS32(pSSM, &pThis->left_till_irq);
1881 SSMR3GetS32(pSSM, &pThis->dma_running);
1882 SSMR3GetS32(pSSM, &pThis->bytes_per_second);
1883 SSMR3GetS32(pSSM, &pThis->align);
1884
1885 SSMR3GetS32(pSSM, &pThis->mixer_nreg);
1886 SSMR3GetMem(pSSM, pThis->mixer_regs, 256);
1887
1888#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1889 PSB16DRIVER pDrv;
1890 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
1891 {
1892 if (pDrv->Out.pStrmOut)
1893 {
1894 pDrv->pConnector->pfnCloseOut(pThis->pDrv, pDrv->Out.pStrmOut);
1895 pDrv->Out.pStrmOut = NULL;
1896 }
1897 }
1898#else
1899 AUD_close_out (&pThis->card, pThis->voice);
1900 pThis->voice = NULL;
1901#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1902
1903 if (pThis->dma_running)
1904 {
1905 if (pThis->freq)
1906 {
1907#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
1908 PDMAUDIOSTREAMCFG streamCfg;
1909 streamCfg.uHz = pThis->freq;
1910 streamCfg.cChannels = 1 << pThis->fmt_stereo;
1911 streamCfg.enmFormat = pThis->fmt;
1912 streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
1913
1914 int rc = sb16OpenOut(pThis, &streamCfg);
1915 AssertRC(rc);
1916#else
1917 pThis->audio_free = 0;
1918
1919 audsettings_t as;
1920 as.freq = pThis->freq;
1921 as.nchannels = 1 << pThis->fmt_stereo;
1922 as.fmt = pThis->fmt;
1923 as.endianness = 0;
1924 pThis->voice = AUD_open_out (
1925 &pThis->card,
1926 pThis->voice,
1927 "sb16",
1928 pThis,
1929 sb16AudioCallback,
1930 &as
1931 );
1932#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
1933 }
1934
1935 sb16Control(pThis, 1);
1936 sb16SpeakerControl(pThis, pThis->speaker);
1937 }
1938
1939 return VINF_SUCCESS;
1940}
1941
1942static DECLCALLBACK(int) sb16LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
1943{
1944 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
1945
1946 SSMR3PutS32(pSSM, pThis->irqCfg);
1947 SSMR3PutS32(pSSM, pThis->dmaCfg);
1948 SSMR3PutS32(pSSM, pThis->hdmaCfg);
1949 SSMR3PutS32(pSSM, pThis->portCfg);
1950 SSMR3PutS32(pSSM, pThis->verCfg);
1951 return VINF_SSM_DONT_CALL_AGAIN;
1952}
1953
1954static DECLCALLBACK(int) sb16SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1955{
1956 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
1957
1958 sb16LiveExec(pDevIns, pSSM, 0);
1959 sb16Save(pSSM, pThis);
1960 return VINF_SUCCESS;
1961}
1962
1963static DECLCALLBACK(int) sb16LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1964{
1965 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
1966
1967 AssertMsgReturn( uVersion == SB16_SAVE_STATE_VERSION
1968 || uVersion == SB16_SAVE_STATE_VERSION_VBOX_30,
1969 ("%u\n", uVersion),
1970 VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
1971 if (uVersion > SB16_SAVE_STATE_VERSION_VBOX_30)
1972 {
1973 int32_t irq;
1974 SSMR3GetS32 (pSSM, &irq);
1975 int32_t dma;
1976 SSMR3GetS32 (pSSM, &dma);
1977 int32_t hdma;
1978 SSMR3GetS32 (pSSM, &hdma);
1979 int32_t port;
1980 SSMR3GetS32 (pSSM, &port);
1981 int32_t ver;
1982 int rc = SSMR3GetS32 (pSSM, &ver);
1983 AssertRCReturn (rc, rc);
1984
1985 if ( irq != pThis->irqCfg
1986 || dma != pThis->dmaCfg
1987 || hdma != pThis->hdmaCfg
1988 || port != pThis->portCfg
1989 || ver != pThis->verCfg)
1990 {
1991 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
1992 N_("config changed: irq=%x/%x dma=%x/%x hdma=%x/%x port=%x/%x ver=%x/%x (saved/config)"),
1993 irq, pThis->irqCfg,
1994 dma, pThis->dmaCfg,
1995 hdma, pThis->hdmaCfg,
1996 port, pThis->portCfg,
1997 ver, pThis->verCfg);
1998 }
1999 }
2000
2001 if (uPass != SSM_PASS_FINAL)
2002 return VINF_SUCCESS;
2003
2004 sb16Load(pSSM, pThis, uVersion);
2005 return VINF_SUCCESS;
2006}
2007
2008#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
2009static int sb16OpenOut(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg)
2010{
2011 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2012 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
2013
2014 int rc = VINF_SUCCESS;
2015
2016 PSB16DRIVER pDrv;
2017 uint8_t uLUN = 0;
2018 char *pszDesc;
2019 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2020 {
2021 if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] sb16.po", uLUN) <= 0)
2022 {
2023 rc = VERR_NO_MEMORY;
2024 break;
2025 }
2026
2027 int rc2 = pDrv->pConnector->pfnOpenOut(pDrv->pConnector, pszDesc, pCfg, &pDrv->Out.pStrmOut);
2028 LogFlowFunc(("LUN#%RU8: Opened output with rc=%Rrc\n", uLUN, rc));
2029 if (rc2 == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
2030 {
2031 audioMixerRemoveStream(pThis->pSinkOutput, pDrv->Out.phStrmOut);
2032 rc = audioMixerAddStreamOut(pThis->pSinkOutput,
2033 pDrv->pConnector, pDrv->Out.pStrmOut,
2034 0 /* uFlags */,
2035 &pDrv->Out.phStrmOut);
2036 }
2037
2038 RTStrFree(pszDesc);
2039
2040 if (RT_FAILURE(rc2))
2041 {
2042 if (RT_SUCCESS(rc))
2043 rc = rc2;
2044 break;
2045 }
2046
2047 uLUN++;
2048 }
2049
2050 return rc;
2051}
2052#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
2053
2054/**
2055 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2056 */
2057static DECLCALLBACK(void *) sb16QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
2058{
2059 PSB16STATE pThis = RT_FROM_MEMBER(pInterface, SB16STATE, IBase);
2060 Assert(&pThis->IBase == pInterface);
2061
2062 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
2063 return NULL;
2064}
2065
2066/**
2067 * @interface_method_impl{PDMDEVREG,pfnDestruct}
2068 */
2069static DECLCALLBACK(int) sb16Destruct(PPDMDEVINS pDevIns)
2070{
2071 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2072
2073#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
2074 PSB16DRIVER pDrv;
2075
2076 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2077 pDrv->Out.phStrmOut = NULL;
2078
2079 pThis->pSinkOutput = NULL;
2080
2081 if (pThis->pMixer)
2082 {
2083 audioMixerDestroy(pThis->pMixer);
2084 pThis->pMixer = NULL;
2085 }
2086#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
2087
2088 return VINF_SUCCESS;
2089}
2090
2091static DECLCALLBACK(int) sb16Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
2092{
2093 PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
2094 int rc;
2095
2096 /*
2097 * Validations.
2098 */
2099 Assert(iInstance == 0);
2100 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2101 if (!CFGMR3AreValuesValid(pCfgHandle,
2102 "IRQ\0"
2103 "DMA\0"
2104 "DMA16\0"
2105 "Port\0"
2106 "Version\0"))
2107 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
2108 N_("Invalid configuration for sb16 device"));
2109
2110 /*
2111 * Read config data.
2112 */
2113 rc = CFGMR3QuerySIntDef(pCfgHandle, "IRQ", &pThis->irq, 5);
2114 if (RT_FAILURE(rc))
2115 return PDMDEV_SET_ERROR(pDevIns, rc,
2116 N_("Configuration error: Failed to get the \"IRQ\" value"));
2117 pThis->irqCfg = pThis->irq;
2118
2119 rc = CFGMR3QuerySIntDef(pCfgHandle, "DMA", &pThis->dma, 1);
2120 if (RT_FAILURE(rc))
2121 return PDMDEV_SET_ERROR(pDevIns, rc,
2122 N_("Configuration error: Failed to get the \"DMA\" value"));
2123 pThis->dmaCfg = pThis->dma;
2124
2125 rc = CFGMR3QuerySIntDef(pCfgHandle, "DMA16", &pThis->hdma, 5);
2126 if (RT_FAILURE(rc))
2127 return PDMDEV_SET_ERROR(pDevIns, rc,
2128 N_("Configuration error: Failed to get the \"DMA16\" value"));
2129 pThis->hdmaCfg = pThis->hdma;
2130
2131 RTIOPORT Port;
2132 rc = CFGMR3QueryPortDef(pCfgHandle, "Port", &Port, 0x220);
2133 if (RT_FAILURE(rc))
2134 return PDMDEV_SET_ERROR(pDevIns, rc,
2135 N_("Configuration error: Failed to get the \"Port\" value"));
2136 pThis->port = Port;
2137 pThis->portCfg = Port;
2138
2139 uint16_t u16Version;
2140 rc = CFGMR3QueryU16Def(pCfgHandle, "Version", &u16Version, 0x0405);
2141 if (RT_FAILURE(rc))
2142 return PDMDEV_SET_ERROR(pDevIns, rc,
2143 N_("Configuration error: Failed to get the \"Version\" value"));
2144 pThis->ver = u16Version;
2145 pThis->verCfg = u16Version;
2146
2147 /*
2148 * Init instance data.
2149 */
2150 pThis->pDevIns = pDevIns;
2151 pThis->IBase.pfnQueryInterface = sb16QueryInterface;
2152 pThis->cmd = -1;
2153
2154 pThis->mixer_regs[0x80] = magic_of_irq (pThis->irq);
2155 pThis->mixer_regs[0x81] = (1 << pThis->dma) | (1 << pThis->hdma);
2156 pThis->mixer_regs[0x82] = 2 << 5;
2157
2158 pThis->csp_regs[5] = 1;
2159 pThis->csp_regs[9] = 0xf8;
2160
2161#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
2162 RTListInit(&pThis->lstDrv);
2163#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
2164
2165 sb16MixerReset(pThis);
2166
2167 /*
2168 * Create timer(s), register & attach stuff.
2169 */
2170 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16TimerIRQ, pThis,
2171 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 IRQ timer", &pThis->pTimerIRQ);
2172 if (RT_FAILURE(rc))
2173 AssertMsgFailedReturn(("Error creating IRQ timer, rc=%Rrc\n", rc), rc);
2174
2175 rc = PDMDevHlpIOPortRegister(pDevIns, pThis->port + 0x04, 2, pThis,
2176 mixer_write, mixer_read, NULL, NULL, "SB16");
2177 if (RT_FAILURE(rc))
2178 return rc;
2179 rc = PDMDevHlpIOPortRegister(pDevIns, pThis->port + 0x06, 10, pThis,
2180 dsp_write, dsp_read, NULL, NULL, "SB16");
2181 if (RT_FAILURE(rc))
2182 return rc;
2183
2184 rc = PDMDevHlpDMARegister(pDevIns, pThis->hdma, sb16DMARead, pThis);
2185 if (RT_FAILURE(rc))
2186 return rc;
2187 rc = PDMDevHlpDMARegister(pDevIns, pThis->dma, sb16DMARead, pThis);
2188 if (RT_FAILURE(rc))
2189 return rc;
2190
2191 pThis->can_write = 1;
2192
2193 rc = PDMDevHlpSSMRegister3(pDevIns, SB16_SAVE_STATE_VERSION, sizeof(SB16STATE), sb16LiveExec, sb16SaveExec, sb16LoadExec);
2194 if (RT_FAILURE(rc))
2195 return rc;
2196
2197 /*
2198 * Attach driver.
2199 */
2200#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
2201 uint8_t uLUN;
2202 for (uLUN = 0; uLUN < UINT8_MAX; uLUN)
2203 {
2204 LogFunc(("Trying to attach driver for LUN #%RU8 ...\n", uLUN));
2205 rc = sb16Attach(pDevIns, uLUN, PDM_TACH_FLAGS_NOT_HOT_PLUG);
2206 if (RT_FAILURE(rc))
2207 {
2208 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2209 rc = VINF_SUCCESS;
2210 break;
2211 }
2212
2213 uLUN++;
2214 }
2215
2216 LogFunc(("cLUNs=%RU8, rc=%Rrc\n", uLUN, rc));
2217#else
2218 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Audio Driver Port");
2219 if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2220 LogFunc(("SB16: No attached driver!\n"));
2221 else if (RT_FAILURE(rc))
2222 {
2223 AssertMsgFailed(("Failed to attach SB16 LUN #0! rc=%Rrc\n", rc));
2224 return rc;
2225 }
2226#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
2227
2228#ifdef VBOX_WITH_PDM_AUDIO_DRIVER
2229 sb16ResetLegacy(pThis);
2230
2231 PSB16DRIVER pDrv;
2232 uLUN = 0;
2233 RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
2234 {
2235 PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
2236 AssertPtr(pCon);
2237
2238 bool fIsOK = pCon->pfnIsOutputOK(pCon, pDrv->Out.pStrmOut);
2239 if (fIsOK)
2240 {
2241 rc = pCon->pfnEnableOut(pCon, pDrv->Out.pStrmOut, true /* fEnable */);
2242 fIsOK = RT_SUCCESS(rc);
2243 }
2244
2245 if (!fIsOK)
2246 {
2247 /*
2248 * Only primary drivers are critical for the VM to run. Everything else
2249 * might not worth showing an own error message box in the GUI.
2250 */
2251 if (!(pDrv->Flags & PDMAUDIODRVFLAG_PRIMARY))
2252 continue;
2253
2254 LogRel(("SB16: Warning: Unable to enable/use output for LUN#%RU8\n", uLUN));
2255
2256 pCon->pfnCloseOut(pCon, pDrv->Out.pStrmOut);
2257 pDrv->Out.pStrmOut = NULL;
2258
2259 pThis->pDrv->pfnInitNull(pThis->pDrv);
2260
2261 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
2262 N_("No audio devices could be opened. Selecting the NULL audio backend "
2263 "with the consequence that no sound is audible"));
2264 }
2265
2266 uLUN++;
2267 }
2268
2269 if (RT_SUCCESS(rc))
2270 {
2271 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16TimerIO, pThis,
2272 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 IO timer", &pThis->pTimerIO);
2273 if (RT_FAILURE(rc))
2274 AssertMsgFailedReturn(("Error creating I/O timer, rc=%Rrc\n", rc), rc);
2275 else
2276 {
2277 pThis->uTicksIO = PDMDevHlpTMTimeVirtGetFreq(pDevIns) / 200; /** Hz. @todo Make this configurable! */
2278 if (pThis->uTicksIO < 100)
2279 pThis->uTicksIO = 100;
2280 LogFunc(("I/O timer ticks=%RU64\n", pThis->uTicksIO));
2281
2282 /* Fire off timer. */
2283 TMTimerSet(pThis->pTimerIO, TMTimerGet(pThis->pTimerIO) + pThis->uTicksIO);
2284 }
2285 }
2286#else
2287 AUD_register_card("sb16", &pThis->card);
2288 sb16ResetLegacy(pThis);
2289
2290 if (!AUD_is_host_voice_out_ok(pThis->voice))
2291 {
2292 LogRel (("SB16: WARNING: Unable to open PCM OUT!\n"));
2293 AUD_close_out (&pThis->card, pThis->voice);
2294 pThis->voice = NULL;
2295
2296 AUD_init_null();
2297
2298 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
2299 N_("No audio devices could be opened. Selecting the NULL audio backend "
2300 "with the consequence that no sound is audible"));
2301 }
2302#endif /* VBOX_WITH_PDM_AUDIO_DRIVER */
2303
2304 return VINF_SUCCESS;
2305}
2306
2307const PDMDEVREG g_DeviceSB16 =
2308{
2309 /* u32Version */
2310 PDM_DEVREG_VERSION,
2311 /* szName */
2312 "sb16",
2313 /* szRCMod */
2314 "",
2315 /* szR0Mod */
2316 "",
2317 /* pszDescription */
2318 "Sound Blaster 16 Controller",
2319 /* fFlags */
2320 PDM_DEVREG_FLAGS_DEFAULT_BITS,
2321 /* fClass */
2322 PDM_DEVREG_CLASS_AUDIO,
2323 /* cMaxInstances */
2324 1,
2325 /* cbInstance */
2326 sizeof(SB16STATE),
2327 /* pfnConstruct */
2328 sb16Construct,
2329 /* pfnDestruct */
2330 sb16Destruct,
2331 /* pfnRelocate */
2332 NULL,
2333 /* pfnMemSetup */
2334 NULL,
2335 /* pfnPowerOn */
2336 NULL,
2337 /* pfnReset */
2338 NULL,
2339 /* pfnSuspend */
2340 NULL,
2341 /* pfnResume */
2342 NULL,
2343 /* pfnAttach */
2344 NULL,
2345 /* pfnDetach */
2346 NULL,
2347 /* pfnQueryInterface */
2348 NULL,
2349 /* pfnInitComplete */
2350 NULL,
2351 /* pfnPowerOff */
2352 NULL,
2353 /* pfnSoftReset */
2354 NULL,
2355 /* u32VersionEnd */
2356 PDM_DEVREG_VERSION
2357};
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