VirtualBox

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

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

SB16: Corrected SBP->SB16 volume conversion.

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