/*
 * ddksample_audio.c -  OSS DDK sample driver - misc routines
 *
 * Description:
 * This file contains routines that are not related with the
 * OSS DDK interface. To understand how OSS DDK works you don't need to
 * pay any attention on these routines. They are here just to produce
 * some data for the mixer routines (ddksample_mixer.c).
 *
 * ddksample_misc.c emulates some arbitrary audio device. It does
 * volume scaling to the output data and computes the peak meters from the
 * result of the scaling.
 */


/*
 * Solaris DDI includes
 */
#include <sys/types.h>
#include <sys/modctl.h>
#include <sys/kmem.h>
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>

/*
 * OSS specific includes
 */
#include <sys/soundcard.h>
#include <sys/ossddk/ossddk.h>

#include "ddksample.h"

/**************************************************/
void
ddksample_do_math(ddksample_portc *portc, void *buf, int len)
{
	int i;
	ddksample_devc *devc = ossddk_adev_get_devc(portc->dev);

	switch (portc->bits + portc->channels)
	{
	case 16+1: /* 16 bits / mono */
		{
			int val;
			int peak=0;
			short *p = buf;

			len /= sizeof(*p);

			for (i=0;i<len;i++)
			{
			/* Do volume computations */

				val = *p++ << 8; /* Scale up to 24 bits */

				val = (val * portc->left_volume) / DDKSAMPLE_MAX_VOL;

				/*
				 * Note that legacy mixer volume max is always
				 * 100.
				 */
				val = (val * devc->mainvol_left) / 100;

			/*
			 * Now we have the sample value after volume control.
			 * This driver doesn't store this value anywhere but
			 * if necessary this functionality can be added here.

			/*
			 * Next compute the peak value
			 */

			 if (val<0) val=-val; /* Absolute value */

			 if (val > peak)
		            peak=val;
			}

			if (peak > portc->left_peak)
			   portc->left_peak=peak;
			if (peak > portc->right_peak)
			   portc->right_peak=peak;
		}
		break;

	case 16+2: /* 16 bits / stereo */
		{
			int val;
			int left_peak=0, right_peak=0;
			short *p = buf;

			len /= sizeof(*p);

			for (i=0;i<len;i += 2) /* Each stereo sa,ple pair */
			{
			/*
			 * Left channel
			 */

			/* Do volume computations */

				val = (*p++) << 8; /* Scale up to 24 bits */

				val = (val * portc->left_volume) / DDKSAMPLE_MAX_VOL;

				/*
				 * Note that legacy mixer volume max is always
				 * 100.
				 */
				val = (val * devc->mainvol_left) / 100;

			/*
			 * Now we have the sample value after volume control.
			 * This driver doesn't store this value anywhere but
			 * if necessary this functionality can be added here.

			/*
			 * Next compute the peak value
			 */

			 if (val<0) val=-val; /* Absolute value */

			 if (val > left_peak)
		            left_peak=val;

			/*
			 * Right channel
			 */

			/* Do volume computations */

				val = (*p++) << 8; /* Scale up to 24 bits */

				val = (val * portc->left_volume) / DDKSAMPLE_MAX_VOL;

				/*
				 * Note that legacy mixer volume max is always
				 * 100.
				 */
				val = (val * devc->mainvol_left) / 100;

			/*
			 * Now we have the sample value after volume control.
			 * This driver doesn't store this value anywhere but
			 * if necessary this functionality can be added here.

			/*
			 * Next compute the peak value
			 */

			 if (val<0) val=-val; /* Absolute value */

			 if (val > right_peak)
		            right_peak=val;
			}

			if (left_peak > portc->left_peak)
			   portc->left_peak=left_peak;
			if (right_peak > portc->right_peak)
			   portc->right_peak=right_peak;
		}
		break;
	}
}
