Google
 

Open Sound System
The Hitchhiker's Guide to OSS 4.1 Internals

Do you have problems with sound/audio application development? Don't panic! Click here for help!

ac97/ac97_ext.inc

AC97 chip specific Mixer extension handlers

Description




This file is included from ac97.c and it implements codec specific extensions such as S/PDIF control.


This file is part of Open Sound System.

Copyright (C) 4Front Technologies 1996-2008.

This this source file is released under GPL v2 license (no other versions). See the COPYING file included in the main directory of this source distribution for the license terms and conditions.


extern int ac97_recselect;

void
ac97_enable_spdif (ac97_devc * devc)
{
  switch (devc->spdifout_support)
    {
    case CS_SPDIFOUT:
      codec_write (devc, 0x68, codec_read (devc, 0x68) | 0x8000);
      break;
    case CX_SPDIFOUT:
      codec_write (devc, 0x5c, codec_read (devc, 0x5c) | 0x08);
      break;
    case AD_SPDIFOUT:
    case ALC_SPDIFOUT:
    case VIA_SPDIFOUT:
    case STAC_SPDIFOUT:
    case CMI_SPDIFOUT:
    case YMF_SPDIFOUT:
      codec_write (devc, 0x2a,
		   (codec_read (devc, 0x2a) & 0xffc3) | 0x4 | devc->
		   spdif_slot);
      break;
    default:
      break;
    }
}

void
ac97_disable_spdif (ac97_devc * devc)
{
  switch (devc->spdifout_support)
    {
    case CS_SPDIFOUT:
      codec_write (devc, 0x68, codec_read (devc, 0x68) & ~0x8000);
      break;
    case AD_SPDIFOUT:
    case ALC_SPDIFOUT:
    case VIA_SPDIFOUT:
    case STAC_SPDIFOUT:
    case CMI_SPDIFOUT:
    case YMF_SPDIFOUT:
      codec_write (devc, 0x2a, (codec_read (devc, 0x2a) & 0xffc3) & ~0x4);
      break;
    case CX_SPDIFOUT:
      codec_write (devc, 0x5c, codec_read (devc, 0x5c) & ~0x8);
      break;
    default:
      break;
    }
}

/********************AC97 SPDIFIN Control *************************/
int
ac97_spdifin_ctl (int dev, int ctrl, unsigned int cmd, int value)
{
  ac97_devc *devc = mixer_devs[dev]->devc;


  if (cmd == SNDCTL_MIX_READ)
    {
      value = 0;
      switch (ctrl)
	{
	case SPDIFIN_ENABLE:	/* Enable/disable SPDIF IN */
	  if (devc->spdifin_support == ALC_SPDIFIN)
	    value = (codec_read (devc, 0x7A) & 0x8000) ? 1 : 0;
	  if (devc->spdifin_support == CMI_SPDIFIN)
	    value = (codec_read (devc, 0x6c) & 0x1) ? 1 : 0;
	  break;
	case SPDIFIN_PRO:	/* Pro */
	  if (devc->spdifin_support == ALC_SPDIFIN)
	    value = (codec_read (devc, 0x60) & 0x1) ? 1 : 0;
	  if (devc->spdifin_support == CMI_SPDIFIN)
	    value = (codec_read (devc, 0x68) & 0x1) ? 1 : 0;
	  break;
	case SPDIFIN_AUDIO:	/* /Audio */
	  if (devc->spdifin_support == ALC_SPDIFIN)
	    value = (codec_read (devc, 0x60) & 0x2) ? 1 : 0;
	  if (devc->spdifin_support == CMI_SPDIFIN)
	    value = (codec_read (devc, 0x68) & 0x1) ? 1 : 0;
	  break;
	case SPDIFIN_COPY:	/* Copy */
	  if (devc->spdifin_support == ALC_SPDIFIN)
	    value = (codec_read (devc, 0x60) & 0x4) ? 1 : 0;
	  if (devc->spdifin_support == CMI_SPDIFIN)
	    value = (codec_read (devc, 0x68) & 0x4) ? 1 : 0;
	  break;
	case SPDIFIN_PREEMPH:	/* Pre */
	  if (devc->spdifin_support == ALC_SPDIFIN)
	    value = (codec_read (devc, 0x60) & 0x38) >> 3;
	  if (devc->spdifin_support == CMI_SPDIFIN)
	    value = (codec_read (devc, 0x68) & 0x38) >> 3;
	  break;
	case SPDIFIN_MODE:	/* Mode */
	  if (devc->spdifin_support == ALC_SPDIFIN)
	    value = (codec_read (devc, 0x60) & 0xc0) ? 1 : 0;
	  if (devc->spdifin_support == CMI_SPDIFIN)
	    value = (codec_read (devc, 0x68) & 0xc0) ? 1 : 0;
	  break;
	case SPDIFIN_CATEGORY:	/* Category */
	  if (devc->spdifin_support == ALC_SPDIFIN)
	    value = (codec_read (devc, 0x60) & 0x7f00) >> 8;
	  if (devc->spdifin_support == CMI_SPDIFIN)
	    value = (codec_read (devc, 0x68) & 0x7f00) >> 8;
	  break;
	case SPDIFIN_GENERATION:	/* Level */
	  if (devc->spdifin_support == ALC_SPDIFIN)
	    value = (codec_read (devc, 0x60) & 0x8000) ? 1 : 0;
	  if (devc->spdifin_support == CMI_SPDIFIN)
	    value = (codec_read (devc, 0x68) & 0x8000) ? 1 : 0;
	  break;
	case SPDIFIN_SOURCE:	/* Source */
	  if (devc->spdifin_support == ALC_SPDIFIN)
	    value = codec_read (devc, 0x62) & 0xf;
	  if (devc->spdifin_support == CMI_SPDIFIN)
	    value = codec_read (devc, 0x6a) & 0xf;
	  break;
	case SPDIFIN_CHAN:	/* Channel */
	  if (devc->spdifin_support == ALC_SPDIFIN)
	    value = (codec_read (devc, 0x62) & 0xf0) >> 4;
	  if (devc->spdifin_support == CMI_SPDIFIN)
	    value = (codec_read (devc, 0x6a) & 0xf0) >> 4;
	  break;
	case SPDIFIN_RATE:	/* Sampling Rate */
	  if (devc->spdifin_support == ALC_SPDIFIN)
	    value = (codec_read (devc, 0x62) & 0xf00) >> 8;
	  if (devc->spdifin_support == CMI_SPDIFIN)
	    value = (codec_read (devc, 0x6a) & 0xf00) >> 8;
	  switch (value)
	    {
	    case 0:
	      value = 44100;
	      break;
	    case 2:
	      value = 48000;
	      break;
	    case 3:
	      value = 32000;
	      break;
	    }
	  break;
	case SPDIFIN_CLOCK:	/* Clock Accuracy */
	  if (devc->spdifin_support == ALC_SPDIFIN)
	    value = (codec_read (devc, 0x62) & 0x3000) >> 12;
	  if (devc->spdifin_support == CMI_SPDIFIN)
	    value = (codec_read (devc, 0x6a) & 0x3000) >> 12;
	  break;
	case SPDIFIN_SIGNAL:	/* Lock */
	  if (devc->spdifin_support == ALC_SPDIFIN)
	    value = (codec_read (devc, 0x62) & 0x4000) ? 1 : 0;
	  break;
	case SPDIFIN_VBIT:	/* VBit */
	  if (devc->spdifin_support == ALC_SPDIFIN)
	    value = (codec_read (devc, 0x62) & 0x8000) ? 1 : 0;
	  break;

	case SPDIFIN_MON:	/* SPDIF Input Mon */
	  if (devc->spdifin_support == ALC_SPDIFIN)
	    value = codec_read (devc, 0x6A) & (1 << 13) ? 1 : 0;
	  if (devc->spdifin_support == CMI_SPDIFIN)
	    value = codec_read (devc, 0x6c) & 0x8 ? 1 : 0;
	  break;

	default:
	  break;
	}
    }
  if (cmd == SNDCTL_MIX_WRITE)
    {
      switch (ctrl)
	{
	case SPDIFIN_ENABLE:	/* SPDIF Record Enable */
	  if (devc->spdifin_support == ALC_SPDIFIN)
	    {
	      if (value)
		{
		  /* Set 0x7a enable SPDIF Input                      */
		  /* set 0x6a: PCM Input from SPDIFIN                 */
		  codec_write (devc, 0x7a, codec_read (devc, 0x7a) | 0x2);
		  codec_write (devc, 0x6a, codec_read (devc, 0x6a) | 0x8000);
		}
	      else
		{
		  codec_write (devc, 0x7a, codec_read (devc, 0x7a) & ~0x2);
		  codec_write (devc, 0x6a, codec_read (devc, 0x6a) & ~0x8000);
		}
	    }

	  if (devc->spdifin_support == CMI_SPDIFIN)
	    {
	      if (value)
		{
		  codec_write (devc, 0x6c, codec_read (devc, 0x6c) | 1);
		  codec_write (devc, 0x6c, codec_read (devc, 0x6c) | 0x10);
		}
	      else
		{
		  codec_write (devc, 0x6c, codec_read (devc, 0x6c) & ~1);
		  codec_write (devc, 0x6c, codec_read (devc, 0x6c) & ~0x10);
		}
	    }
	  break;

	case SPDIFIN_MON:	/* SPDIF input monitor on analog DAC */
	  if (devc->spdifin_support == ALC_SPDIFIN)
	    {
	      if (value)
		codec_write (devc, 0x6a, codec_read (devc, 0x6a) | (1 << 13));
	      else
		codec_write (devc, 0x6a,
			     codec_read (devc, 0x6a) & ~(1 << 13));
	    }

	  if (devc->spdifin_support == CMI_SPDIFIN)
	    {
	      if (value)
		codec_write (devc, 0x6c, codec_read (devc, 0x6c) | 0x8);
	      else
		codec_write (devc, 0x6c, codec_read (devc, 0x6c) & ~0x8);
	    }
	  break;

	}
    }
  return value;
}

static int
spdifin_ext_init (int dev)
{
  int group, err;

  if ((group = mixer_ext_create_group_flags (dev, 0, "SPDIN", MIXF_FLAT)) < 0)
    return group;

  if ((err =
       mixer_ext_create_control (dev, group, SPDIFIN_ENABLE, ac97_spdifin_ctl,
				 MIXT_ONOFF, "SPDIN_Enable", 1,
				 MIXF_READABLE | MIXF_WRITEABLE)) < 0)
    return err;

  if ((err =
       mixer_ext_create_control (dev, group, SPDIFIN_MON, ac97_spdifin_ctl,
				 MIXT_ONOFF, "SPDIN_Monitor", 1,
				 MIXF_READABLE | MIXF_WRITEABLE)) < 0)
    return err;

#if 1
  if ((err =
       mixer_ext_create_control (dev, group, SPDIFIN_PRO, ac97_spdifin_ctl,
				 MIXT_VALUE, "SPDIN_Pro", 1,
				 MIXF_READABLE)) < 0)
    return err;

  if ((err =
       mixer_ext_create_control (dev, group, SPDIFIN_AUDIO, ac97_spdifin_ctl,
				 MIXT_VALUE, "SPDIN_Audio", 1,
				 MIXF_READABLE)) < 0)
    return err;

  if ((err =
       mixer_ext_create_control (dev, group, SPDIFIN_COPY, ac97_spdifin_ctl,
				 MIXT_VALUE, "SPDIN_Copy", 1,
				 MIXF_READABLE)) < 0)
    return err;

  if ((err =
       mixer_ext_create_control (dev, group, SPDIFIN_PREEMPH,
				 ac97_spdifin_ctl, MIXT_VALUE,
				 "SPDIN_Pre-emph", 1, MIXF_READABLE)) < 0)
    return err;

  if ((err =
       mixer_ext_create_control (dev, group, SPDIFIN_MODE, ac97_spdifin_ctl,
				 MIXT_VALUE, "SPDIN_Mode", 1,
				 MIXF_READABLE)) < 0)
    return err;

  if ((err =
       mixer_ext_create_control (dev, group, SPDIFIN_CATEGORY,
				 ac97_spdifin_ctl, MIXT_VALUE,
				 "SPDIN_CATEGORY", 1, MIXF_READABLE)) < 0)
    return err;

  if ((err =
       mixer_ext_create_control (dev, group, SPDIFIN_GENERATION,
				 ac97_spdifin_ctl, MIXT_VALUE,
				 "SPDIN_GenLevel", 1, MIXF_READABLE)) < 0)
    return err;
  if ((err =
       mixer_ext_create_control (dev, group, SPDIFIN_SOURCE, ac97_spdifin_ctl,
				 MIXT_VALUE, "SPDIN_Source", 1,
				 MIXF_READABLE)) < 0)
    return err;
  if ((err =
       mixer_ext_create_control (dev, group, SPDIFIN_CHAN, ac97_spdifin_ctl,
				 MIXT_VALUE, "SPDIN_Channel", 1,
				 MIXF_READABLE)) < 0)
    return err;
  if ((err =
       mixer_ext_create_control (dev, group, SPDIFIN_RATE, ac97_spdifin_ctl,
				 MIXT_VALUE, "SPDIN_Rate", 1,
				 MIXF_READABLE)) < 0)
    return err;
  if ((err =
       mixer_ext_create_control (dev, group, SPDIFIN_CLOCK, ac97_spdifin_ctl,
				 MIXT_VALUE, "SPDIN_Clock", 1,
				 MIXF_READABLE)) < 0)
    return err;
  if ((err =
       mixer_ext_create_control (dev, group, SPDIFIN_SIGNAL, ac97_spdifin_ctl,
				 MIXT_VALUE, "SPDIN_Signal", 1,
				 MIXF_READABLE)) < 0)
    return err;
  if ((err =
       mixer_ext_create_control (dev, group, SPDIFIN_VBIT, ac97_spdifin_ctl,
				 MIXT_VALUE, "SPDIN_VBit", 1,
				 MIXF_READABLE)) < 0)
    return err;
#endif
  return 0;
}

/********************AC97 SPDIFOUT Control *************************/
int
ac97_spdifout_ctl (int dev, int ctrl, unsigned int cmd, int value)
{
  int tmp = 0;
  static int flag;
  ac97_devc *devc = mixer_devs[dev]->devc;
  if (cmd == SNDCTL_MIX_READ)
    {
      value = 0;
      switch (ctrl)
	{
	case SPDIFOUT_ENABLE:	/* SPDIF OUT */
	  switch (devc->spdifout_support)
	    {
	    case CS_SPDIFOUT:
	      value = (codec_read (devc, 0x68) & 0x8000) ? 1 : 0;
	      break;
	    case CX_SPDIFOUT:
	      value = (codec_read (devc, 0x5c) & 0x08) ? 1 : 0;
	      break;
	    case AD_SPDIFOUT:
	    case ALC_SPDIFOUT:
	    case VIA_SPDIFOUT:
	    case STAC_SPDIFOUT:
	    case CMI_SPDIFOUT:
	    case YMF_SPDIFOUT:
	      value = (codec_read (devc, 0x2a) & 0x4) ? 1 : 0;
	      break;
	    }
	  break;

	case SPDIFOUT_PRO:	/* Consumer/PRO */
	  switch (devc->spdifout_support)
	    {
	    case CS_SPDIFOUT:
	      value = (codec_read (devc, 0x68) & 0x1) ? 1 : 0;
	      break;
	    case CX_SPDIFOUT:
	      value = (codec_read (devc, 0x5c) & 0x1) ? 1 : 0;
	      break;
	    case AD_SPDIFOUT:
	    case ALC_SPDIFOUT:
	    case VIA_SPDIFOUT:
	    case STAC_SPDIFOUT:
	    case CMI_SPDIFOUT:
	    case YMF_SPDIFOUT:
	      value = (codec_read (devc, 0x3a) & 0x1) ? 1 : 0;
	      break;
	    }
	  break;

	case SPDIFOUT_AUDIO:	/* PCM/AC3 */
	  switch (devc->spdifout_support)
	    {
	    case CS_SPDIFOUT:
	      value = (codec_read (devc, 0x68) & 0x2) ? 1 : 0;
	      break;
	    case CX_SPDIFOUT:
	      value = (codec_read (devc, 0x5c) & 0x2) ? 1 : 0;
	      break;
	    case AD_SPDIFOUT:
	    case ALC_SPDIFOUT:
	    case VIA_SPDIFOUT:
	    case STAC_SPDIFOUT:
	    case CMI_SPDIFOUT:
	    case YMF_SPDIFOUT:
	      value = (codec_read (devc, 0x3a) & 0x2) ? 1 : 0;
	      break;
	    }
	  break;

	case SPDIFOUT_COPY:	/* Copy Prot */
	  switch (devc->spdifout_support)
	    {
	    case CS_SPDIFOUT:
	      value = (codec_read (devc, 0x68) & 0x4) ? 1 : 0;
	      break;
	    case CX_SPDIFOUT:
	      value = (codec_read (devc, 0x5c) & 0x4) ? 1 : 0;
	      break;
	    case AD_SPDIFOUT:
	    case ALC_SPDIFOUT:
	    case VIA_SPDIFOUT:
	    case STAC_SPDIFOUT:
	    case CMI_SPDIFOUT:
	    case YMF_SPDIFOUT:
	      value = (codec_read (devc, 0x3a) & 0x4) ? 1 : 0;
	      break;
	    }
	  break;

	case SPDIFOUT_PREEMPH:	/* Pre emphasis */
	  switch (devc->spdifout_support)
	    {
	    case CS_SPDIFOUT:
	      value = codec_read (devc, 0x68) & 0x8 ? 1 : 0;
	      break;
	    case AD_SPDIFOUT:
	    case ALC_SPDIFOUT:
	    case VIA_SPDIFOUT:
	    case STAC_SPDIFOUT:
	    case CMI_SPDIFOUT:
	    case YMF_SPDIFOUT:
	      value = (codec_read (devc, 0x3a) & 0x8) ? 1 : 0;
	      break;
	    }
	  break;

	case SPDIFOUT_RATE:	/* Sampling Rate */
	  switch (devc->spdifout_support)
	    {
	    case CS_SPDIFOUT:
	      {
		tmp = codec_read (devc, 0x68) & 0x1000;
		switch (tmp)
		  {
		  case 0x1000:
		    value = 0;
		    break;
		  case 0x0000:
		    value = 1;
		    break;
		  default:
		    cmn_err (CE_NOTE, "unsupported SPDIF F/S rate\n");
		    break;
		  }

	      }
	      break;
	    case AD_SPDIFOUT:
	    case ALC_SPDIFOUT:
	    case VIA_SPDIFOUT:
	    case STAC_SPDIFOUT:
	    case CMI_SPDIFOUT:
	    case YMF_SPDIFOUT:
	      {
		tmp = codec_read (devc, 0x3a) & 0x3000;
		switch (tmp)
		  {
		  case 0x2000:
		    value = 0;
		    break;
		  case 0x0000:
		    value = 1;
		    break;
		  case 0x3000:
		    value = 2;
		    break;
		  default:
		    cmn_err (CE_NOTE, "unsupported SPDIF F/S rate\n");
		    value = 0;
		    break;
		  }
	      }
	      break;
	    }
	  break;

	case SPDIFOUT_VBIT:	/* V Bit */
	  switch (devc->spdifout_support)
	    {
	    case CS_SPDIFOUT:
	      value = codec_read (devc, 0x68) & 0x4000 ? 1 : 0;
	      break;
	    case AD_SPDIFOUT:
	    case ALC_SPDIFOUT:
	    case VIA_SPDIFOUT:
	    case STAC_SPDIFOUT:
	    case CMI_SPDIFOUT:
	    case YMF_SPDIFOUT:
	      value = codec_read (devc, 0x3a) & 0x8000 ? 1 : 0;
	      break;
	    }
	  break;

	case SPDIFOUT_ADC:	/* Analog In to SPDIF Out */
	  switch (devc->spdifout_support)
	    {
	    case ALC_SPDIFOUT:
	      value = codec_read (devc, 0x6a) & (1 << 12) ? 1 : 0;
	      break;

	    case AD_SPDIFOUT:
	      value = codec_read (devc, 0x74) & 0x4 ? 1 : 0;
	      break;

	    case CS_SPDIFOUT:
	      value = codec_read (devc, 0x5e) & (1 << 11) ? 1 : 0;
	      break;

	    case STAC_SPDIFOUT:
	      value = codec_read (devc, 0x6a) & 0x2 ? 1 : 0;
	      break;

	    case YMF_SPDIFOUT:
	      value = codec_read (devc, 0x66) & 0x2 ? 1 : 0;
	      break;

	    default:
	      break;
	    }
	}
    }
  if (cmd == SNDCTL_MIX_WRITE)
    {
      ac97_disable_spdif (devc);
      switch (ctrl)
	{
	case SPDIFOUT_ENABLE:	/* Enable SPDIF OUT */
	  if (value)
	    {
	      ac97_enable_spdif (devc);
	      flag = 1;
	    }
	  else
	    {
	      ac97_disable_spdif (devc);
	      flag = 0;
	    }
	  break;

	case SPDIFOUT_PRO:	/* consumer/pro audio */
	  switch (devc->spdifout_support)
	    {
	    case CS_SPDIFOUT:
	      if (value)
		codec_write (devc, 0x68, codec_read (devc, 0x68) | 1);
	      else
		codec_write (devc, 0x68, codec_read (devc, 0x68) & ~1);
	      break;
	    case CX_SPDIFOUT:
	      if (value)
		codec_write (devc, 0x5c, codec_read (devc, 0x5c) | 1);
	      else
		codec_write (devc, 0x5c, codec_read (devc, 0x5c) & ~1);
	      break;
	    case AD_SPDIFOUT:
	    case ALC_SPDIFOUT:
	    case VIA_SPDIFOUT:
	    case STAC_SPDIFOUT:
	    case CMI_SPDIFOUT:
	    case YMF_SPDIFOUT:
	      if (value)
		codec_write (devc, 0x3a, codec_read (devc, 0x3a) | 1);
	      else
		codec_write (devc, 0x3a, codec_read (devc, 0x3a) & ~1);
	      break;
	    }
	  break;

	case SPDIFOUT_AUDIO:	/* PCM/AC3 */
	  switch (devc->spdifout_support)
	    {
	    case CS_SPDIFOUT:
	      if (value)
		codec_write (devc, 0x68, codec_read (devc, 0x68) | 0x2);
	      else
		codec_write (devc, 0x68, codec_read (devc, 0x68) & ~2);
	      break;
	    case CX_SPDIFOUT:
	      if (value)
		codec_write (devc, 0x5c, codec_read (devc, 0x5c) | 0x2);
	      else
		codec_write (devc, 0x5c, codec_read (devc, 0x5c) & ~2);
	      break;
	    case AD_SPDIFOUT:
	    case ALC_SPDIFOUT:
	    case VIA_SPDIFOUT:
	    case STAC_SPDIFOUT:
	    case CMI_SPDIFOUT:
	    case YMF_SPDIFOUT:
	      if (value)
		codec_write (devc, 0x3a, codec_read (devc, 0x3a) | 0x2);
	      else
		codec_write (devc, 0x3a, codec_read (devc, 0x3a) & ~2);
	      break;
	    }
	  break;

	case SPDIFOUT_COPY:	/* copy prot */
	  switch (devc->spdifout_support)
	    {
	    case CS_SPDIFOUT:
	      if (value)
		codec_write (devc, 0x68, codec_read (devc, 0x68) | 4);
	      else
		codec_write (devc, 0x68, codec_read (devc, 0x68) & ~4);
	      break;
	    case CX_SPDIFOUT:
	      if (value)
		codec_write (devc, 0x5c, codec_read (devc, 0x5c) | 4);
	      else
		codec_write (devc, 0x5c, codec_read (devc, 0x5c) & ~4);
	      break;
	    case AD_SPDIFOUT:
	    case ALC_SPDIFOUT:
	    case VIA_SPDIFOUT:
	    case STAC_SPDIFOUT:
	    case CMI_SPDIFOUT:
	    case YMF_SPDIFOUT:
	      if (value)
		codec_write (devc, 0x3a, codec_read (devc, 0x3a) | 4);
	      else
		codec_write (devc, 0x3a, codec_read (devc, 0x3a) & ~4);
	      break;
	    }
	  break;

	case SPDIFOUT_PREEMPH:	/* preemphasis */
	  switch (devc->spdifout_support)
	    {
	    case CS_SPDIFOUT:
	      if (value)
		codec_write (devc, 0x68, codec_read (devc, 0x68) | 8);
	      else
		codec_write (devc, 0x68, codec_read (devc, 0x68) & ~8);
	      break;
	    case AD_SPDIFOUT:
	    case ALC_SPDIFOUT:
	    case VIA_SPDIFOUT:
	    case STAC_SPDIFOUT:
	    case CMI_SPDIFOUT:
	    case YMF_SPDIFOUT:
	      if (value)
		codec_write (devc, 0x3a, codec_read (devc, 0x3a) | 8);
	      else
		codec_write (devc, 0x3a, codec_read (devc, 0x3a) & ~8);
	      break;
	    }
	  break;

	case SPDIFOUT_RATE:	/* Frequency */
	  switch (devc->spdifout_support)
	    {
	    case CS_SPDIFOUT:
	      switch (value)
		{
		case 0:
		  codec_write (devc, 0x68,
			       (codec_read (devc, 0x68) & 0xEFFF) | 0x1000);
		  break;
		case 1:
		  codec_write (devc, 0x68,
			       (codec_read (devc, 0x68) & 0xEFFF) | 0);
		  break;
		default:
		  break;
		}
	      break;

	    case AD_SPDIFOUT:
	    case ALC_SPDIFOUT:
	    case VIA_SPDIFOUT:
	    case STAC_SPDIFOUT:
	    case CMI_SPDIFOUT:
	    case YMF_SPDIFOUT:
	      switch (value)
		{
		case 0:	/* 48000 */
		  codec_write (devc, 0x3a,
			       (codec_read (devc, 0x3a) & 0xcfff) | 0x2000);
		  break;
		case 1:	/* 44100 */
		  codec_write (devc, 0x3a,
			       (codec_read (devc, 0x3a) & 0xcfff) | 0x0);
		  break;
		case 2:	/* 32000 */
		  codec_write (devc, 0x3a,
			       (codec_read (devc, 0x3a) & 0xcfff) | 0x3000);
		  break;

		default:
		  break;
		}
	      break;
	    }
	  break;

	case SPDIFOUT_VBIT:	/* V Bit */
	  switch (devc->spdifout_support)
	    {
	    case CS_SPDIFOUT:
	      if (value)
		codec_write (devc, 0x68, codec_read (devc, 0x68) | 0x4000);
	      else
		codec_write (devc, 0x68, codec_read (devc, 0x68) & ~0x4000);
	      break;
	    case AD_SPDIFOUT:
	    case ALC_SPDIFOUT:
	    case VIA_SPDIFOUT:
	    case STAC_SPDIFOUT:
	    case CMI_SPDIFOUT:
	    case YMF_SPDIFOUT:
	      if (value)
		codec_write (devc, 0x3a, codec_read (devc, 0x3a) | 0x8000);
	      else
		codec_write (devc, 0x3a, codec_read (devc, 0x3a) & ~0x8000);
	      break;
	    }
	  break;

	case SPDIFOUT_ADC:	/* Analog In to SPDIF Out */
	  switch (devc->spdifout_support)
	    {
	    case ALC_SPDIFOUT:
	      if (value)
		codec_write (devc, 0x6a, codec_read (devc, 0x6a) | (1 << 12));
	      else
		codec_write (devc, 0x6a,
			     codec_read (devc, 0x6a) & ~(1 << 12));
	      break;

	    case AD_SPDIFOUT:
	      if (value)
		codec_write (devc, 0x74, codec_read (devc, 0x74) | 0x4);
	      else
		codec_write (devc, 0x74, codec_read (devc, 0x74) & ~0x4);
	      break;

	    case CS_SPDIFOUT:
	      if (value)
		codec_write (devc, 0x5e, codec_read (devc, 0x5e) | (1 << 11));
	      else
		codec_write (devc, 0x5e,
			     codec_read (devc, 0x5e) & ~(1 << 11));
	      break;

	    case STAC_SPDIFOUT:
	      if (value)
		codec_write (devc, 0x6a, codec_read (devc, 0x6a) | 0x2);
	      else
		codec_write (devc, 0x6a, codec_read (devc, 0x6a) & ~0x2);
	      break;

	    case CMI_SPDIFOUT:
	      if (value)
		codec_write (devc, 0x6c, codec_read (devc, 0x6c) | 0x2);
	      else
		codec_write (devc, 0x6c, codec_read (devc, 0x6c) & ~0x2);
	      break;

	    case YMF_SPDIFOUT:
	      if (value)
		codec_write (devc, 0x66, codec_read (devc, 0x66) | 0x2);
	      else
		codec_write (devc, 0x66, codec_read (devc, 0x66) & ~0x2);
	      break;
	    }
	  break;

	default:
	  break;
	}
      if (flag)
	ac97_enable_spdif (devc);
    }

  return value;
}

static int
spdifout_ext_init (int dev)
{
  int group, err;
  if ((group =
       mixer_ext_create_group_flags (dev, 0, "SPDOUT", MIXF_FLAT)) < 0)
    return group;
  if ((err =
       mixer_ext_create_control (dev, group, SPDIFOUT_ENABLE,
				 ac97_spdifout_ctl, MIXT_ONOFF,
				 "SPDOUT_ENABLE", 1,
				 MIXF_READABLE | MIXF_WRITEABLE)) < 0)
    return err;

  if ((err =
       mixer_ext_create_control (dev, group, SPDIFOUT_ADC,
				 ac97_spdifout_ctl, MIXT_ONOFF,
				 "SPDOUT_ADC/DAC", 1,
				 MIXF_READABLE | MIXF_WRITEABLE)) < 0)
    return err;

  if ((err =
       mixer_ext_create_control (dev, group, SPDIFOUT_PRO,
				 ac97_spdifout_ctl, MIXT_ENUM,
				 "SPDOUT_Pro", 2,
				 MIXF_READABLE | MIXF_WRITEABLE)) < 0)
    return err;

  if ((err =
       mixer_ext_create_control (dev, group, SPDIFOUT_AUDIO,
				 ac97_spdifout_ctl, MIXT_ENUM,
				 "SPDOUT_Audio", 2,
				 MIXF_READABLE | MIXF_WRITEABLE)) < 0)
    return err;

  if ((err =
       mixer_ext_create_control (dev, group, SPDIFOUT_COPY,
				 ac97_spdifout_ctl, MIXT_ONOFF,
				 "SPDOUT_Copy", 1,
				 MIXF_READABLE | MIXF_WRITEABLE)) < 0)
    return err;

  if ((err =
       mixer_ext_create_control (dev, group, SPDIFOUT_PREEMPH,
				 ac97_spdifout_ctl, MIXT_ONOFF,
				 "SPDOUT_Pre-emph", 1,
				 MIXF_READABLE | MIXF_WRITEABLE)) < 0)
    return err;

  if ((err =
       mixer_ext_create_control (dev, group, SPDIFOUT_RATE,
				 ac97_spdifout_ctl, MIXT_ENUM,
				 "SPDOUT_Rate", 3,
				 MIXF_READABLE | MIXF_WRITEABLE)) < 0)
    return err;

  if ((err =
       mixer_ext_create_control (dev, group, SPDIFOUT_VBIT,
				 ac97_spdifout_ctl, MIXT_ONOFF,
				 "SPDOUT_VBit", 1,
				 MIXF_READABLE | MIXF_WRITEABLE)) < 0)
    return err;

  return 0;
}

/**********************Mixer Extensions ********************/
int
ac97_mixext_ctl (int dev, int ctrl, unsigned int cmd, int value)
{
  int left, right;
  ac97_devc *devc = mixer_devs[dev]->devc;

  if (cmd == SNDCTL_MIX_READ)
    {
      value = 0;
      switch (ctrl)
	{
	case VOL_CENTER:	/* Left line in to output connection */
	  value = devc->extmixlevels[CENTER_VOL];	/* LFE/Center */
	  break;

	case VOL_REAR:
	  value = devc->extmixlevels[REAR_VOL];	/* Rear/Surround */
	  break;

	case VOL_SIDE:
	  value = devc->extmixlevels[SIDE_VOL];	/* Side Surround */
	  break;

	case REAR2LINE:	/* Rear to Line In */
	  if (devc->mixer_ext == ALC650_MIXER_EXT)
	    value = (codec_read (devc, 0x6A) & 0x200) ? 1 : 0;
	  if (devc->mixer_ext == CMI9739_MIXER_EXT)
	    value = (codec_read (devc, 0x64) & 0x400) ? 1 : 0;
	  if (devc->mixer_ext == STAC9758_MIXER_EXT)
	    value = (codec_read (devc, 0x64) & 0x50) ? 1 : 0;
	  if (devc->mixer_ext == AD1980_MIXER_EXT)
	    value = (codec_read (devc, 0x76) & (1 << 11)) ? 0 : 1;
	  break;

	case CENTER2MIC:	/* Center to Mic */
	  if (devc->mixer_ext == ALC650_MIXER_EXT)
	    value = (codec_read (devc, 0x6A) & 0x400) ? 1 : 0;
	  if (devc->mixer_ext == CMI9739_MIXER_EXT)
	    value = (codec_read (devc, 0x64) & 0x1000) ? 1 : 0;
	  if (devc->mixer_ext == STAC9758_MIXER_EXT)
	    value = (codec_read (devc, 0x64) & 0x0C) ? 1 : 0;
	  if (devc->mixer_ext == AD1980_MIXER_EXT)
	    value = (codec_read (devc, 0x76) & (1 << 12)) ? 0 : 1;
	  break;

	case SPREAD:		/* Duplicate front on lfe/rear */
	  if (devc->mixer_ext == ALC650_MIXER_EXT)
	    value = (codec_read (devc, 0x6A) & 0x1) ? 1 : 0;
	  if (devc->mixer_ext == AD1980_MIXER_EXT)
	    value = (codec_read (devc, 0x76) & 0x80) ? 1 : 0;
	  if (devc->mixer_ext == VIA1616_MIXER_EXT)
	    value = (codec_read (devc, 0x5a) & 0x8000) ? 1 : 0;
	  break;

	case MICBOOST:		/* 30db Mic boost */
	  if (devc->mixer_ext == AD1980_MIXER_EXT)
	    value = (codec_read (devc, 0x76) & 0x2) ? 1 : 0;
	  if (devc->mixer_ext == CMI9739_MIXER_EXT)
	    value = (codec_read (devc, 0x64) & 0x1) ? 1 : 0;
	  break;

	case DOWNMIX_LFE:	/* Downmix LFE to Front */
	  if (devc->mixer_ext == ALC650_MIXER_EXT)
	    value = (codec_read (devc, 0x6A) & 0x4) ? 1 : 0;
	  if (devc->mixer_ext == AD1980_MIXER_EXT)
	    value = (codec_read (devc, 0x76) & 0x100) ? 1 : 0;
	  if (devc->mixer_ext == VIA1616_MIXER_EXT)
	    value = (codec_read (devc, 0x5a) & 0x1000) ? 1 : 0;
	  break;

	case DOWNMIX_REAR:	/* Downmix Rear to Front */
	  if (devc->mixer_ext == ALC650_MIXER_EXT)
	    value = (codec_read (devc, 0x6A) & 0x2) ? 1 : 0;
	  if (devc->mixer_ext == VIA1616_MIXER_EXT)
	    value = (codec_read (devc, 0x5a) & 0x800) ? 1 : 0;
	  break;
	}
    }

  if (cmd == SNDCTL_MIX_WRITE)
    {
      switch (ctrl)
	{
	case VOL_CENTER:	/* Center/LFE volume */
	  left = value & 0xff;
	  right = (value >> 8) & 0xff;
	  if (left > 100)
	    left = 100;
	  if (right > 100)
	    right = 100;
	  value = left | (right << 8);
	  if (devc->mixer_ext == ALC650_MIXER_EXT)
	    codec_write (devc, 0x66,
			 mix_scale (left, right, devc->centervol_bits));
	  devc->extmixlevels[CENTER_VOL] = value;
	  break;

	case VOL_REAR:		/* Rear/Surround volume */
	  left = value & 0xff;
	  right = (value >> 8) & 0xff;
	  if (left > 100)
	    left = 100;
	  if (right > 100)
	    right = 100;
	  value = left | (right << 8);
	  if (devc->mixer_ext == ALC650_MIXER_EXT)
	    codec_write (devc, 0x64,
			 mix_scale (left, right, devc->rearvol_bits));
	  devc->extmixlevels[REAR_VOL] = value;
	  break;

	case VOL_SIDE:		/* Side Surround volume */
	  left = value & 0xff;
	  right = (value >> 8) & 0xff;
	  if (left > 100)
	    left = 100;
	  if (right > 100)
	    right = 100;
	  value = left | (right << 8);
	  if (devc->mixer_ext == CMI9780_MIXER_EXT)
	    codec_write (devc, 0x60,
			 mix_scale (left, right, devc->sidevol_bits));
	  devc->extmixlevels[SIDE_VOL] = value;
	  break;

	case REAR2LINE:	/* Surround to Line In */
	  if (devc->mixer_ext == ALC650_MIXER_EXT)
	    {
	      if (value)
		codec_write (devc, 0x6a, codec_read (devc, 0x6a) | 0x200);
	      else
		codec_write (devc, 0x6a, codec_read (devc, 0x6a) & ~0x200);
	    }

	  if ((devc->mixer_ext == CMI9739_MIXER_EXT)
	      || (devc->mixer_ext == CMI9780_MIXER_EXT))
	    {
	      if (value)
		codec_write (devc, 0x64, codec_read (devc, 0x64) | 0x400);
	      else
		codec_write (devc, 0x64, codec_read (devc, 0x64) & ~0x400);
	    }

	  if (devc->mixer_ext == STAC9758_MIXER_EXT)
	    {
	      if (value)
		codec_write (devc, 0x64, codec_read (devc, 0x64) | 0x50);
	      else
		codec_write (devc, 0x64, codec_read (devc, 0x64) & ~0x50);
	    }

	  if (devc->mixer_ext == AD1980_MIXER_EXT)
	    {
	      if (value)
		codec_write (devc, 0x76,
			     codec_read (devc, 0x76) & ~(1 << 11));
	      else
		codec_write (devc, 0x76, codec_read (devc, 0x76) | (1 << 11));
	    }

	  break;

	case CENTER2MIC:	/* Center/LFE to Mic In */
	  if (devc->mixer_ext == ALC650_MIXER_EXT)
	    {
	      if (value)
		codec_write (devc, 0x6a, codec_read (devc, 0x6a) | 0x400);
	      else
		codec_write (devc, 0x6a, codec_read (devc, 0x6a) & ~0x400);
	    }

	  if ((devc->mixer_ext == CMI9739_MIXER_EXT)
	      || (devc->mixer_ext == CMI9780_MIXER_EXT))
	    {
	      if (value)
		codec_write (devc, 0x64, codec_read (devc, 0x64) | 0x1000);
	      else
		codec_write (devc, 0x64, codec_read (devc, 0x64) & ~0x1000);
	    }

	  if (devc->mixer_ext == STAC9758_MIXER_EXT)
	    {
	      if (value)
		codec_write (devc, 0x64, codec_read (devc, 0x64) | 0xC);
	      else
		codec_write (devc, 0x64, codec_read (devc, 0x64) & ~0xC);
	    }

	  if (devc->mixer_ext == AD1980_MIXER_EXT)
	    {
	      if (value)
		codec_write (devc, 0x76,
			     codec_read (devc, 0x76) & ~(1 << 12));
	      else
		codec_write (devc, 0x76, codec_read (devc, 0x76) | (1 << 12));
	    }
	  break;

	case SPREAD:		/* 4 Speaker output - LF/RF duplicate on Rear */
	  if (devc->mixer_ext == ALC650_MIXER_EXT)
	    {
	      if (value)
		{
		  /* enable Line-In jack to play Surround out */
		  codec_write (devc, 0x6a, codec_read (devc, 0x6a) | 0x200);
		  codec_write (devc, 0x6a, codec_read (devc, 0x6a) | 1);
		}
	      else
		{
		  /* disable Line-In jack to play Surround out */
		  codec_write (devc, 0x6a, codec_read (devc, 0x6a) & ~0x200);
		  codec_write (devc, 0x6a, codec_read (devc, 0x6a) & ~1);
		}
	    }

	  if (devc->mixer_ext == AD1980_MIXER_EXT)
	    {
	      if (value)
		codec_write (devc, 0x76, codec_read (devc, 0x76) | 0x80);
	      else
		codec_write (devc, 0x76, codec_read (devc, 0x76) & ~0x80);
	    }

	  if (devc->mixer_ext == VIA1616_MIXER_EXT)
	    {
	      if (value)
		codec_write (devc, 0x5a, codec_read (devc, 0x5a) | 0x8000);
	      else
		codec_write (devc, 0x5a, codec_read (devc, 0x5a) & ~0x8000);
	    }
	  break;

	case MICBOOST:
	  if (devc->mixer_ext == AD1980_MIXER_EXT)
	    {
	      if (value)
		codec_write (devc, 0x76, codec_read (devc, 0x76) | 0x2);
	      else
		codec_write (devc, 0x76, codec_read (devc, 0x76) & ~0x2);
	    }

	  if ((devc->mixer_ext == CMI9739_MIXER_EXT)
	      || (devc->mixer_ext == CMI9780_MIXER_EXT))
	    {
	      if (value)
		codec_write (devc, 0x64, codec_read (devc, 0x64) | 0x1);
	      else
		codec_write (devc, 0x64, codec_read (devc, 0x64) & ~0x1);
	    }
	  break;

	case DOWNMIX_LFE:	/* Downmix LFE to Front */
	  if (devc->mixer_ext == ALC650_MIXER_EXT)
	    {
	      if (value)
		codec_write (devc, 0x6a, codec_read (devc, 0x6a) | 0x4);
	      else
		codec_write (devc, 0x6a, codec_read (devc, 0x6a) & ~0x4);
	    }

	  if (devc->mixer_ext == AD1980_MIXER_EXT)
	    {
	      if (value)
		codec_write (devc, 0x76, codec_read (devc, 0x76) | 0x300);
	      else
		codec_write (devc, 0x76, codec_read (devc, 0x76) & ~0x300);
	    }

	  if (devc->mixer_ext == VIA1616_MIXER_EXT)
	    {
	      if (value)
		codec_write (devc, 0x5a, codec_read (devc, 0x5a) | 0x1000);
	      else
		codec_write (devc, 0x5a, codec_read (devc, 0x5a) & ~0x1000);
	    }
	  break;

	case DOWNMIX_REAR:	/* Downmix Rear to Front */
	  if (devc->mixer_ext == ALC650_MIXER_EXT)
	    {
	      if (value)
		codec_write (devc, 0x6a, codec_read (devc, 0x6a) | 0x2);
	      else
		codec_write (devc, 0x6a, codec_read (devc, 0x6a) & ~0x2);
	    }

	  if (devc->mixer_ext == VIA1616_MIXER_EXT)
	    {
	      if (value)
		codec_write (devc, 0x5a, codec_read (devc, 0x5a) | 0x800);
	      else
		codec_write (devc, 0x5a, codec_read (devc, 0x5a) & ~0x800);
	    }
	  break;
	}
    }
  return value;
}

static int
ac97_micboost_ctl (int dev, int ctrl, unsigned int cmd, int value)
{
  ac97_devc *devc = mixer_devs[dev]->devc;
  int tmp;

  if (cmd == SNDCTL_MIX_READ)
    {
	return !!devc->micboost;
    }

  if (cmd == SNDCTL_MIX_WRITE)
    {
	value = !!value;

	tmp = codec_read (devc, 0x0e);

	if (value)
	  devc->micboost = 0x40;
	else
	  devc->micboost = 0x00;

	codec_write (devc, 0x0e, (tmp & ~0x40) | devc->micboost);

	return value;
    }

  return OSS_EINVAL;
}

static int
ac97_recselect_ctl (int dev, int ctrl, unsigned int cmd, int value)
{
  int tmp;
  ac97_devc *devc = mixer_devs[dev]->devc;

  if (ctrl < 0 || ctrl > 1)
    return OSS_EINVAL;

  tmp = codec_read (devc, 0x1a);

  if (cmd == SNDCTL_MIX_READ)
    {
      return (tmp >> (ctrl * 8)) & 0x07;
    }

  if (cmd == SNDCTL_MIX_WRITE)
    {
      if (value < 0 || value > 7)
	return OSS_EINVAL;

      tmp &= ~(0x7 << (ctrl * 8));
      tmp |= (value << (ctrl * 8));
      codec_write (devc, 0x1a, tmp);
      return value;
    }

  return OSS_EINVAL;
}

static int
ac97_mixext_init (int dev)
{
  ac97_devc *devc = mixer_devs[dev]->devc;
  unsigned int mixflags = 0;

  int group, err, ctl;

  if ((ctl =
     mixer_ext_create_control (dev, 0, 0,
			     ac97_micboost_ctl, MIXT_ONOFF,
			     "micboost", 1,
			     MIXF_READABLE | MIXF_WRITEABLE)) < 0)
     return ctl;

  if (ac97_recselect)
    {
      if ((group =
	   mixer_ext_create_group_flags (dev, 0, "AC97_RECSEL",
					 MIXF_FLAT)) < 0)
	return group;

      if ((ctl =
	   mixer_ext_create_control (dev, group, 1,
				     ac97_recselect_ctl, MIXT_ENUM,
				     "LEFT", 8,
				     MIXF_READABLE | MIXF_WRITEABLE)) < 0)
	return ctl;
      mixer_ext_set_strings (dev, ctl,
			     "MIC CD VIDEO AUX LINE STEREOMIX MONOMIX PHONE",
			     0);

      if ((ctl =
	   mixer_ext_create_control (dev, group, 0,
				     ac97_recselect_ctl, MIXT_ENUM,
				     "RIGHT", 8,
				     MIXF_READABLE | MIXF_WRITEABLE)) < 0)
	return ctl;
      mixer_ext_set_strings (dev, ctl,
			     "MIC CD VIDEO AUX LINE STEREOMIX MONOMIX PHONE",
			     0);
    }


Don't use flat groups with AC97 chips that have slider controls (ALC650 at this moment)

  if (devc->mixer_ext != ALC650_MIXER_EXT)
    mixflags = MIXF_FLAT;

  if ((group =
       mixer_ext_create_group_flags (dev, 0, "AC97_MIXEXT", mixflags)) < 0)
    return group;

  if ((devc->mixer_ext == ALC650_MIXER_EXT)
      || (devc->mixer_ext == CMI9780_MIXER_EXT))
    {
      if ((err =
	   mixer_ext_create_control (dev, group, VOL_CENTER,
				     ac97_mixext_ctl, MIXT_STEREOSLIDER,
				     "CENTERVOL", 100,
				     MIXF_READABLE | MIXF_WRITEABLE)) < 0)
	return err;
      ac97_mixext_ctl (dev, VOL_CENTER, SNDCTL_MIX_WRITE, 100 | (100 << 8));

      if ((err =
	   mixer_ext_create_control (dev, group, VOL_REAR, ac97_mixext_ctl,
				     MIXT_STEREOSLIDER, "REARVOL", 100,
				     MIXF_READABLE | MIXF_WRITEABLE)) < 0)
	return err;
      ac97_mixext_ctl (dev, VOL_REAR, SNDCTL_MIX_WRITE, 100 | (100 << 8));

      if ((err =
	   mixer_ext_create_control (dev, group, VOL_SIDE, ac97_mixext_ctl,
				     MIXT_STEREOSLIDER, "SIDEVOL", 100,
				     MIXF_READABLE | MIXF_WRITEABLE)) < 0)
	return err;
      ac97_mixext_ctl (dev, VOL_SIDE, SNDCTL_MIX_WRITE, 100 | (100 << 8));
    }


  if ((devc->mixer_ext == CMI9739_MIXER_EXT)
      || (devc->mixer_ext == CMI9780_MIXER_EXT)
      || (devc->mixer_ext == ALC650_MIXER_EXT)
      || (devc->mixer_ext == AD1980_MIXER_EXT)
      || (devc->mixer_ext == STAC9758_MIXER_EXT))
    {
      if ((err =
	   mixer_ext_create_control (dev, group, REAR2LINE,
				     ac97_mixext_ctl, MIXT_ONOFF,
				     "REAR2LINEJACK", 1,
				     MIXF_READABLE | MIXF_WRITEABLE)) < 0)
	return err;
    }

  if ((devc->mixer_ext == CMI9739_MIXER_EXT)
      || (devc->mixer_ext == CMI9780_MIXER_EXT)
      || (devc->mixer_ext == ALC650_MIXER_EXT)
      || (devc->mixer_ext == AD1980_MIXER_EXT)
      || (devc->mixer_ext == STAC9758_MIXER_EXT))
    {

      if ((err =
	   mixer_ext_create_control (dev, group, CENTER2MIC,
				     ac97_mixext_ctl, MIXT_ONOFF,
				     "CENTER2MICJACK", 1,
				     MIXF_READABLE | MIXF_WRITEABLE)) < 0)
	return err;
    }

  if ((devc->mixer_ext == AD1980_MIXER_EXT)
      || (devc->mixer_ext == VIA1616_MIXER_EXT)
      || (devc->mixer_ext == ALC650_MIXER_EXT))
    {

      if ((err =
	   mixer_ext_create_control (dev, group, SPREAD,
				     ac97_mixext_ctl, MIXT_ENUM,
				     "SPKMODE", 2,
				     MIXF_READABLE | MIXF_WRITEABLE)) < 0)
	return err;
    }

  if ((devc->mixer_ext == AD1980_MIXER_EXT)
      || (devc->mixer_ext == VIA1616_MIXER_EXT)
      || (devc->mixer_ext == ALC650_MIXER_EXT))
    {
      if ((err =
	   mixer_ext_create_control (dev, group, DOWNMIX_LFE,
				     ac97_mixext_ctl, MIXT_ONOFF,
				     "MIX-LFE2FRONT", 1,
				     MIXF_READABLE | MIXF_WRITEABLE)) < 0)
	return err;
    }

  if ((devc->mixer_ext == VIA1616_MIXER_EXT)
      || (devc->mixer_ext == ALC650_MIXER_EXT))
    {
      if ((err =
	   mixer_ext_create_control (dev, group, DOWNMIX_REAR,
				     ac97_mixext_ctl, MIXT_ONOFF,
				     "MIX-REAR2FRONT", 1,
				     MIXF_READABLE | MIXF_WRITEABLE)) < 0)
	return err;
    }

  if ((devc->mixer_ext == AD1980_MIXER_EXT)
      || (devc->mixer_ext == CMI9739_MIXER_EXT)
      || (devc->mixer_ext == CMI9780_MIXER_EXT))
    {
      if ((err =
	   mixer_ext_create_control (dev, group, MICBOOST,
				     ac97_mixext_ctl, MIXT_ONOFF,
				     "MICBOOST", 1,
				     MIXF_READABLE | MIXF_WRITEABLE)) < 0)
	return err;
    }
  return 0;
}

/********************END of Mixer Extensions **************/

/* AC97 Mixer Extensions */

static int
ac97mixer_ext_init (int dev)
{
  ac97_devc *devc = mixer_devs[dev]->devc;
  int err;

  if (devc->client_mixer_init != NULL)
    if ((err = devc->client_mixer_init (dev)) < 0)
      return err;

  if ((devc->mixer_ext > 0) || ac97_recselect)
    if ((err = ac97_mixext_init (dev)) < 0)
      return err;

  if (devc->spdifout_support)
    if ((err = spdifout_ext_init (dev)) < 0)
      return err;

  if (devc->spdifin_support)
    if ((err = spdifin_ext_init (dev)) < 0)
      return err;
  return 0;
}

void
ac97_spdif_setup (int dev, int speed, int bits)
{
  int val;

  val = ac97_spdifout_ctl (dev, SPDIFOUT_RATE, SNDCTL_MIX_READ, 0);

  mixer_devs[dev]->modify_counter++;

  switch (speed)
    {
    case 48000:
      if (val != 0)
	ac97_spdifout_ctl (dev, SPDIFOUT_RATE, SNDCTL_MIX_WRITE, 0);
      break;

    case 44100:
      if (val != 1)
	ac97_spdifout_ctl (dev, SPDIFOUT_RATE, SNDCTL_MIX_WRITE, 1);
      break;

    case 32000:
      if (val != 2)
	ac97_spdifout_ctl (dev, SPDIFOUT_RATE, SNDCTL_MIX_WRITE, 2);
      break;

    default:
      break;
    }

  if (bits == AFMT_AC3)
     ac97_spdifout_ctl (dev, SPDIFOUT_AUDIO, SNDCTL_MIX_WRITE, 1);
  else
     ac97_spdifout_ctl (dev, SPDIFOUT_AUDIO, SNDCTL_MIX_WRITE, 0);
}

Copyright (C) 4Front Technologies, 2007. All rights reserved.

Back to index OSS web site


Copyright (C) 4Front Technologies, 2007. All rights reserved.
Back to index OSS web site