⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pss.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * sound/pss.c * * The low level driver for the Personal Sound System (ECHO ESC614). * * * 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) * Alan Cox		modularisation, clean up. * * 98-02-21: Vladimir Michl <vladimir.michl@upol.cz> *          Added mixer device for Beethoven ADSP-16 (master volume, *	    bass, treble, synth), only for speakers. *          Fixed bug in pss_write (exchange parameters) *          Fixed config port of SB *          Requested two regions for PSS (PSS mixer, PSS config) *          Modified pss_download_boot *          To probe_pss_mss added test for initialize AD1848 * 98-05-28: Vladimir Michl <vladimir.michl@upol.cz> *          Fixed computation of mixer volumes * 04-05-1999: Anthony Barbachan <barbcode@xmen.cis.fordham.edu> *          Added code that allows the user to enable his cdrom and/or  *          joystick through the module parameters pss_cdrom_port and  *          pss_enable_joystick.  pss_cdrom_port takes a port address as its *          argument.  pss_enable_joystick takes either a 0 or a non-0 as its *          argument. * 04-06-1999: Anthony Barbachan <barbcode@xmen.cis.fordham.edu> *          Separated some code into new functions for easier reuse.   *          Cleaned up and streamlined new code.  Added code to allow a user  *          to only use this driver for enabling non-sound components  *          through the new module parameter pss_no_sound (flag).  Added  *          code that would allow a user to decide whether the driver should  *          reset the configured hardware settings for the PSS board through  *          the module parameter pss_keep_settings (flag).   This flag will  *          allow a user to free up resources in use by this card if needbe,  *          furthermore it allows him to use this driver to just enable the  *          emulations and then be unloaded as it is no longer needed.  Both  *          new settings are only available to this driver if compiled as a  *          module.  The default settings of all new parameters are set to  *          load the driver as it did in previous versions. * 04-07-1999: Anthony Barbachan <barbcode@xmen.cis.fordham.edu> *          Added module parameter pss_firmware to allow the user to tell  *          the driver where the fireware file is located.  The default  *          setting is the previous hardcoded setting "/etc/sound/pss_synth". * 00-03-03: Christoph Hellwig <chhellwig@gmx.net> *	    Adapted to module_init/module_exit * 11-10-2000: Bartlomiej Zolnierkiewicz <bkz@linux-ide.org> *	    Added __init to probe_pss(), attach_pss() and probe_pss_mpu() */#include <linux/config.h>#include <linux/init.h>#include <linux/module.h>#include "sound_config.h"#include "sound_firmware.h"#include "ad1848.h"#include "mpu401.h"/* * PSS registers. */#define REG(x)	(devc->base+x)#define	PSS_DATA	0#define	PSS_STATUS	2#define PSS_CONTROL	2#define	PSS_ID		4#define	PSS_IRQACK	4#define	PSS_PIO		0x1a/* * Config registers */#define CONF_PSS	0x10#define CONF_WSS	0x12#define CONF_SB		0x14#define CONF_CDROM	0x16#define CONF_MIDI	0x18/* * Status bits. */#define PSS_FLAG3     0x0800#define PSS_FLAG2     0x0400#define PSS_FLAG1     0x1000#define PSS_FLAG0     0x0800#define PSS_WRITE_EMPTY  0x8000#define PSS_READ_FULL    0x4000/* * WSS registers */#define WSS_INDEX 4#define WSS_DATA 5/* * WSS status bits */#define WSS_INITIALIZING 0x80#define WSS_AUTOCALIBRATION 0x20#define NO_WSS_MIXER	-1#include "coproc.h"#include "pss_boot.h"/* If compiled into kernel, it enable or disable pss mixer */#ifdef CONFIG_PSS_MIXERstatic unsigned char pss_mixer = 1;#elsestatic unsigned char pss_mixer = 0;#endiftypedef struct pss_mixerdata {	unsigned int volume_l;	unsigned int volume_r;	unsigned int bass;	unsigned int treble;	unsigned int synth;} pss_mixerdata;typedef struct pss_confdata {	int             base;	int             irq;	int             dma;	int            *osp;	pss_mixerdata   mixer;	int             ad_mixer_dev;} pss_confdata;  static pss_confdata pss_data;static pss_confdata *devc = &pss_data;static int      pss_initialized = 0;static int      nonstandard_microcode = 0;static int	pss_cdrom_port = -1;	/* Parameter for the PSS cdrom port */static int	pss_enable_joystick = 0;/* Parameter for enabling the joystick */static void pss_write(pss_confdata *devc, int data){	int i, limit;	limit = jiffies + HZ/10;	/* The timeout is 0.1 seconds */	/*	 * Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes	 * called while interrupts are disabled. This means that the timer is	 * disabled also. However the timeout situation is a abnormal condition.	 * Normally the DSP should be ready to accept commands after just couple of	 * loops.	 */	for (i = 0; i < 5000000 && time_before(jiffies, limit); i++) 	{ 		if (inw(REG(PSS_STATUS)) & PSS_WRITE_EMPTY) 		{ 			outw(data, REG(PSS_DATA)); 			return; 		} 	} 	printk(KERN_WARNING "PSS: DSP Command (%04x) Timeout.\n", data);}int __init probe_pss(struct address_info *hw_config){	unsigned short id;	int irq, dma;	devc->base = hw_config->io_base;	irq = devc->irq = hw_config->irq;	dma = devc->dma = hw_config->dma;	devc->osp = hw_config->osp;	if (devc->base != 0x220 && devc->base != 0x240)		if (devc->base != 0x230 && devc->base != 0x250)		/* Some cards use these */			return 0;	if (check_region(devc->base, 0x19 /*16*/)) { 		printk(KERN_ERR "PSS: I/O port conflict\n");		return 0;	}	id = inw(REG(PSS_ID));	if ((id >> 8) != 'E') {		printk(KERN_ERR "No PSS signature detected at 0x%x (0x%x)\n",  devc->base,  id); 		return 0;	}	return 1;}static int set_irq(pss_confdata * devc, int dev, int irq){	static unsigned short irq_bits[16] =	{		0x0000, 0x0000, 0x0000, 0x0008,		0x0000, 0x0010, 0x0000, 0x0018,		0x0000, 0x0020, 0x0028, 0x0030,		0x0038, 0x0000, 0x0000, 0x0000	};	unsigned short  tmp, bits;	if (irq < 0 || irq > 15)		return 0;	tmp = inw(REG(dev)) & ~0x38;	/* Load confreg, mask IRQ bits out */	if ((bits = irq_bits[irq]) == 0 && irq != 0)	{		printk(KERN_ERR "PSS: Invalid IRQ %d\n", irq);		return 0;	}	outw(tmp | bits, REG(dev));	return 1;}static int set_io_base(pss_confdata * devc, int dev, int base){	unsigned short  tmp = inw(REG(dev)) & 0x003f;	unsigned short  bits = (base & 0x0ffc) << 4;	outw(bits | tmp, REG(dev));	return 1;}static int set_dma(pss_confdata * devc, int dev, int dma){	static unsigned short dma_bits[8] =	{		0x0001, 0x0002, 0x0000, 0x0003,		0x0000, 0x0005, 0x0006, 0x0007	};	unsigned short  tmp, bits;	if (dma < 0 || dma > 7)		return 0;	tmp = inw(REG(dev)) & ~0x07;	/* Load confreg, mask DMA bits out */	if ((bits = dma_bits[dma]) == 0 && dma != 4)	{		  printk(KERN_ERR "PSS: Invalid DMA %d\n", dma);		  return 0;	}	outw(tmp | bits, REG(dev));	return 1;}static int pss_reset_dsp(pss_confdata * devc){	unsigned long   i, limit = jiffies + HZ/10;	outw(0x2000, REG(PSS_CONTROL));	for (i = 0; i < 32768 && (limit-jiffies >= 0); i++)		inw(REG(PSS_CONTROL));	outw(0x0000, REG(PSS_CONTROL));	return 1;}static int pss_put_dspword(pss_confdata * devc, unsigned short word){	int i, val;	for (i = 0; i < 327680; i++)	{		val = inw(REG(PSS_STATUS));		if (val & PSS_WRITE_EMPTY)		{			outw(word, REG(PSS_DATA));			return 1;		}	}	return 0;}static int pss_get_dspword(pss_confdata * devc, unsigned short *word){	int i, val;	for (i = 0; i < 327680; i++)	{		val = inw(REG(PSS_STATUS));		if (val & PSS_READ_FULL)		{			*word = inw(REG(PSS_DATA));			return 1;		}	}	return 0;}static int pss_download_boot(pss_confdata * devc, unsigned char *block, int size, int flags){	int i, limit, val, count;	if (flags & CPF_FIRST)	{/*_____ Warn DSP software that a boot is coming */		outw(0x00fe, REG(PSS_DATA));		limit = jiffies + HZ/10;		for (i = 0; i < 32768 && time_before(jiffies, limit); i++)			if (inw(REG(PSS_DATA)) == 0x5500)				break;		outw(*block++, REG(PSS_DATA));		pss_reset_dsp(devc);	}	count = 1;	while ((flags&CPF_LAST) || count<size )	{		int j;		for (j = 0; j < 327670; j++)		{/*_____ Wait for BG to appear */			if (inw(REG(PSS_STATUS)) & PSS_FLAG3)				break;		}		if (j == 327670)		{			/* It's ok we timed out when the file was empty */			if (count >= size && flags & CPF_LAST)				break;			else			{				printk("\n");				printk(KERN_ERR "PSS: Download timeout problems, byte %d=%d\n", count, size);				return 0;			}		}/*_____ Send the next byte */		if (count >= size) 		{			/* If not data in block send 0xffff */			outw (0xffff, REG (PSS_DATA));		}		else		{			/*_____ Send the next byte */			outw (*block++, REG (PSS_DATA));		};		count++;	}	if (flags & CPF_LAST)	{/*_____ Why */		outw(0, REG(PSS_DATA));		limit = jiffies + HZ/10;		for (i = 0; i < 32768 && (limit - jiffies >= 0); i++)			val = inw(REG(PSS_STATUS));		limit = jiffies + HZ/10;		for (i = 0; i < 32768 && (limit-jiffies >= 0); i++)		{			val = inw(REG(PSS_STATUS));			if (val & 0x4000)				break;		}		/* now read the version */		for (i = 0; i < 32000; i++)		{			val = inw(REG(PSS_STATUS));			if (val & PSS_READ_FULL)				break;		}		if (i == 32000)			return 0;		val = inw(REG(PSS_DATA));		/* printk( "<PSS: microcode version %d.%d loaded>",  val/16,  val % 16); */	}	return 1;}/* Mixer */static void set_master_volume(pss_confdata *devc, int left, int right){	static unsigned char log_scale[101] =  {		0xdb, 0xe0, 0xe3, 0xe5, 0xe7, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xed, 0xee,		0xef, 0xef, 0xf0, 0xf0, 0xf1, 0xf1, 0xf2, 0xf2, 0xf2, 0xf3, 0xf3, 0xf3,		0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf6, 0xf7,		0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9,		0xf9, 0xf9, 0xf9, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb,		0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc,		0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd,		0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,		0xfe, 0xfe, 0xff, 0xff, 0xff	};	pss_write(devc, 0x0010);	pss_write(devc, log_scale[left] | 0x0000);	pss_write(devc, 0x0010);	pss_write(devc, log_scale[right] | 0x0100);}static void set_synth_volume(pss_confdata *devc, int volume){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -