VirtualBox

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

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

Audio: Reattaching fixes.

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