OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [sound/] [ics2101.c] - Rev 1765

Compare with Previous | Blame | View Log

/*
 * sound/ics2101.c
 *
 * Driver for the ICS2101 mixer of GUS v3.7.
 *
 *
 * Copyright (C) by Hannu Savolainen 1993-1997
 *
 * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
 * Version 2 (June 1991). See the "COPYING" file distributed with this software
 * for more info.
 *
 *
 * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
 * Bartlomiej Zolnierkiewicz : added __init to ics2101_mixer_init()
 */
#include <linux/init.h>
#include "sound_config.h"
 
#include <linux/ultrasound.h>
 
#include "gus.h"
#include "gus_hw.h"
 
#define MIX_DEVS	(SOUND_MASK_MIC|SOUND_MASK_LINE| \
			 SOUND_MASK_SYNTH| \
  			 SOUND_MASK_CD | SOUND_MASK_VOLUME)
 
extern int     *gus_osp;
extern int      gus_base;
static int      volumes[ICS_MIXDEVS];
static int      left_fix[ICS_MIXDEVS] =
{1, 1, 1, 2, 1, 2};
static int      right_fix[ICS_MIXDEVS] =
{2, 2, 2, 1, 2, 1};
 
static int scale_vol(int vol)
{
	/*
	 *  Experimental volume scaling by Risto Kankkunen.
	 *  This should give smoother volume response than just
	 *  a plain multiplication.
	 */
 
	int e;
 
	if (vol < 0)
		vol = 0;
	if (vol > 100)
		vol = 100;
	vol = (31 * vol + 50) / 100;
	e = 0;
	if (vol)
	{
		while (vol < 16)
		{
			vol <<= 1;
			e--;
		}
		vol -= 16;
		e += 7;
	}
	return ((e << 4) + vol);
}
 
static void write_mix(int dev, int chn, int vol)
{
	int *selector;
	unsigned long flags;
	int ctrl_addr = dev << 3;
	int attn_addr = dev << 3;
 
	vol = scale_vol(vol);
 
	if (chn == CHN_LEFT)
	{
		selector = left_fix;
		ctrl_addr |= 0x00;
		attn_addr |= 0x02;
	}
	else
	{
		selector = right_fix;
		ctrl_addr |= 0x01;
		attn_addr |= 0x03;
	}
 
	save_flags(flags);
	cli();
	outb((ctrl_addr), u_MixSelect);
	outb((selector[dev]), u_MixData);
	outb((attn_addr), u_MixSelect);
	outb(((unsigned char) vol), u_MixData);
	restore_flags(flags);
}
 
static int set_volumes(int dev, int vol)
{
	int left = vol & 0x00ff;
	int right = (vol >> 8) & 0x00ff;
 
	if (left < 0)
		left = 0;
	if (left > 100)
		left = 100;
	if (right < 0)
		right = 0;
	if (right > 100)
		right = 100;
 
	write_mix(dev, CHN_LEFT, left);
	write_mix(dev, CHN_RIGHT, right);
 
	vol = left + (right << 8);
	volumes[dev] = vol;
	return vol;
}
 
static int ics2101_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
{
	int val;
 
	if (((cmd >> 8) & 0xff) == 'M') {
		if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
 
			if (get_user(val, (int *)arg))
				return -EFAULT;
			switch (cmd & 0xff) {
			case SOUND_MIXER_RECSRC:
				return gus_default_mixer_ioctl(dev, cmd, arg);
 
			case SOUND_MIXER_MIC:
				val = set_volumes(DEV_MIC, val);
				break;
 
			case SOUND_MIXER_CD:
				val = set_volumes(DEV_CD, val);
				break;
 
			case SOUND_MIXER_LINE:
				val = set_volumes(DEV_LINE, val);
				break;
 
			case SOUND_MIXER_SYNTH:
				val = set_volumes(DEV_GF1, val);
				break;
 
			case SOUND_MIXER_VOLUME:
				val = set_volumes(DEV_VOL, val);
				break;
 
			default:
				return -EINVAL;
			}
			return put_user(val, (int *)arg);
		} else {
			switch (cmd & 0xff) {
				/*
				 * Return parameters
				 */
			case SOUND_MIXER_RECSRC:
				return gus_default_mixer_ioctl(dev, cmd, arg);
 
			case SOUND_MIXER_DEVMASK:
				val = MIX_DEVS; 
				break;
 
			case SOUND_MIXER_STEREODEVS:
				val = SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_SYNTH | SOUND_MASK_VOLUME | SOUND_MASK_MIC; 
				break;
 
			case SOUND_MIXER_RECMASK:
				val = SOUND_MASK_MIC | SOUND_MASK_LINE; 
				break;
 
			case SOUND_MIXER_CAPS:
				val = 0; 
				break;
 
			case SOUND_MIXER_MIC:
				val = volumes[DEV_MIC];
				break;
 
			case SOUND_MIXER_LINE:
				val = volumes[DEV_LINE];
				break;
 
			case SOUND_MIXER_CD:
				val = volumes[DEV_CD];
				break;
 
			case SOUND_MIXER_VOLUME:
				val = volumes[DEV_VOL];
				break;
 
			case SOUND_MIXER_SYNTH:
				val = volumes[DEV_GF1]; 
				break;
 
			default:
				return -EINVAL;
			}
			return put_user(val, (int *)arg);
		}
	}
	return -EINVAL;
}
 
static struct mixer_operations ics2101_mixer_operations =
{
	owner:	THIS_MODULE,
	id:	"ICS2101",
	name:	"ICS2101 Multimedia Mixer",
	ioctl:	ics2101_mixer_ioctl
};
 
int __init ics2101_mixer_init(void)
{
	int i;
	int n;
 
	if ((n = sound_alloc_mixerdev()) != -1)
	{
		mixer_devs[n] = &ics2101_mixer_operations;
 
		/*
		 * Some GUS v3.7 cards had some channels flipped. Disable
		 * the flipping feature if the model id is other than 5.
		 */
 
		if (inb(u_MixSelect) != 5)
		{
			for (i = 0; i < ICS_MIXDEVS; i++)
				left_fix[i] = 1;
			for (i = 0; i < ICS_MIXDEVS; i++)
				right_fix[i] = 2;
		}
		set_volumes(DEV_GF1, 0x5a5a);
		set_volumes(DEV_CD, 0x5a5a);
		set_volumes(DEV_MIC, 0x0000);
		set_volumes(DEV_LINE, 0x5a5a);
		set_volumes(DEV_VOL, 0x5a5a);
		set_volumes(DEV_UNUSED, 0x0000);
	}
	return n;
}
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.