VirtualBox

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

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

Audio/SB16: Lowered I/O timer frequency from 200Hz to 25Hz.

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