VirtualBox

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

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

Audio: Added support for dynamically enabling/disabling host audio backends, more code for audio callback support (still disabled).

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

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