VirtualBox

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

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

SB16: Typo.

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