/* This program is public domain. Note that VIA has a nice VIAAUDIO.COM  */
/* which does the un-mute AND the Windows support but is < 600 bytes :-) */

/* Note: VIAFMTSR.COM is only needed if you want Adlib/OPL3 simulation.  */
/* It's a software synthesizer. The SB16 DSP is done by hardware / BIOS. */


#define VERIFYENABLE 1	/* only needed if you tend to misconfig your CMOS */
#define SCANFORDEVICE 1	/* only needed if you do not know pcisel already  */
#define VERBOSE 1	/* only needed if you want to see some messages   */


/*
    Summary: Minimal "un-mute sound" code in Assembly language is...
	mov al,0x39	; for "enter Win" 0x19, for "leave Win" 0x29
	out 0x80,al
	mov eax,0x80003d48	; <--- adjust to YOUR pcisel here!
	mov dx,0xcf8
	out dx,eax
	mov dx,0xcfc
	in eax,dx	; in al,dx would be enough
	and al,0xfe	; same for "leave Win", for "enter Win" or al,1
	out dx,eax	; out dx,al would be enough
	int 0x20	; exit to DOS (optional ;-))
    Quite short, huh? Less than 32 bytes.
*/


/* The PCI bus location of the AC97 function of the VT82C686: */
unsigned int pcisel = 0x80003d00U;  /* <--- bus 0 slot 7 function 5 */


void mute (int muted)
{
    outl(0xcf8, pcisel | 0x48); /* registers 0x40 ... are vendor specific */
    outb(0xcfc, (inb(0xcfc) & ~1) | (muted ? 1 : 0));
    return;
} /* mute */


/* Scan the system for the VIA (0x1106) VT82C686 AC97 controller (0x3058) */
/* and disable the muting (enable the sound) of the SB16 mode then...     */
int main (void)
{
    unsigned int slot;


    outb(0x80, 0x39); /* "state 3" (initial access) */
    /* (VIA abuses "DMA extra page register, temporary storage" here...) */


#if SCANFORDEVICE
    /* Search is simple: sub-function is always 5, bus is always 0 */
    for (slot = 0; slot < 32; slot++) {
	outl(0xcf8, (0x80000500U | (slot << 11))); /* read device ID register */
	if (inl(0xcfc) != 0x30581106) continue; /* no VIA VT82C686, search on */
	pcisel = (pcisel & 0xffff07ff) | (slot << 11);
	break; /* we found it :-) */
    };

    if (slot == 0x1f) { /* bad luck for people with 32 PCI slots */
#if VERBOSE
	printf ("No VIA VT82c686a/b (VT8231) AC97 southbridge function found!\n");
#endif
	return 1;
    }
#endif


#if VERIFYENABLE
    outl(0xcf8, pcisel | 0x40); /* registers 0x40 ... are vendor specific */
    if (!(inb(0xcfe) & 1)) { /* ... more elegant: inl(0xcfc) & 0x10000 ... */
#if VERBOSE
	printf ("VIA VT82c686a/b (VT8231) 'SoundBlaster' not enabled in BIOS\n");
#endif
	return 2;
    }
#endif


    mute (0); /* unmute the device. *** rest is done by BIOS already! *** */


#if VERBOSE
    printf ("VIA VT82c686a/b (VT8231) 'SoundBlaster' at 'slot' %x un-muted.\n",
	(pcisel >> 11) & 0x1f);
#endif

    return 0;
} /* main */


  /* if you have Wind*ws: call mute(1) for int 2f.1605, init broadcast */
  /* (win /s AND /3) and call mute(0) for int 2f.1606, exit broadcast. */
  /* DOSX/Win386 exit broadcast means: system is now back in real mode */
  /* Do outb(0x80, 0x19) before mute(1) at Wind*ws start */
  /* Do outb(0x80, 0x29) before mute(0) at return to DOS */


/* Volume control 00..63 -> set 32bit register to 0 - (volume << 14) */
/* See: http://mobokive.dyndns.org/Archive/Clayton/drivers/Intel#20Chipset/ */
/*      Ac97sound/cs4299/Win98SE/cwawdm.inf ... and probably more useful:   */
/* "PCI Configuration Data", table 00878, in Ralf Brown's Interrupt List 61 */


/* You can also check register 0x08: bytes are class:sub:interface:revision */
/* RBIL 61 table F0085 Plug-and-Play device type: class 4, sub 1 -->  audio */
/* (EISA-PnP: device id "PNPB002" would mean SBPro. Same class, sub as PCI) */

