VirtualBox

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

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

Audio: Included "TimerHz" in CFGMR3AreValuesValid checks.

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