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

📄 em8300_audio.c

📁 linux TV 源码
💻 C
📖 第 1 页 / 共 2 页
字号:
#define __NO_VERSION__#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/version.h>#include <linux/string.h>#include <linux/pci.h>#include <linux/soundcard.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/i2c-algo-bit.h>#include "em8300_reg.h"#include <linux/em8300.h>#include "em8300_fifo.h"#ifndef AFMT_AC3#define AFMT_AC3 0x00000400#endif#include <endian.h>__inline__ uint32_t my_abs(int32_t v) {	return v < 0 ? -v : v;}int em8300_audio_calcbuffered(struct em8300_s *em);static int set_audiomode(struct em8300_s *em, int mode);/* C decompilation of sub_prepare_SPDIF by *  Anton Altaparmakov <antona@bigfoot.com>** Notes:*  local1 = "in" = current inblock position pointer.*  local3 = "i" = for loop counter.*  Need unsigned everywhere, otherwise get into trouble with signed shift rights!*/void sub_prepare_SPDIF(struct em8300_s *em, unsigned char *outblock, unsigned char *inblock, unsigned int inlength){	// 	ebp-4 = local1 = in	ebp-8 = local2	//	ebp-0ch = local3 = i	ebp-10h = local4	unsigned char *in; // 32 bit points to array of 8 bit chars	unsigned short int local2; // 16 bit, unsigned	unsigned int i; // 32 bit, signed	unsigned char local4; // 8 bit, unsigned	in = inblock;	for (i = 0; i < (inlength >> 2); i++) {		if (em->dword_DB4 == 0xc0) {			em->dword_DB4 = 0;		}				{			register int ebx;			if (em->dword_DB4 < 0) {				ebx = em->byte_D90[(em->dword_DB4 + 7) >> 3] & 0xff << (!((!em->dword_DB4 + 1) & 7) + 1) & 0xff;			} else {				ebx = (em->byte_D90[em->dword_DB4 >> 3] & 0xff) << (em->dword_DB4 & 7);			}			local4 = (unsigned char)((ebx & 0x80) >> 1);		}		local2 = in[0] << 8 | in[1];		in += 2;		if (em->dword_DB4 != 0) {			outblock[i*8+3] = 2;		} else {			outblock[i*8+3] = 0;		}		outblock[i*8+2] = local2 << 4;		outblock[i*8+1] = local2 >> 4;		outblock[i*8] = local2 >> 12 | local4;       		local2 = in[0] << 8 | in[1];		in += 2;		outblock[i*8+7] = 1;		outblock[i*8+6] = local2 << 4;		outblock[i*8+5] = local2 >> 4;		outblock[i*8+4] = local2 >> 12 | local4;		++em->dword_DB4;	}		return;}static void preprocess_analog(struct em8300_s *em, unsigned char *outbuf, const unsigned char *inbuf_user, int inlength){	int i;	#if BYTE_ORDER == BIG_ENDIAN	if (em->audio.format == AFMT_S16_BE) {#else /* BYTE_ORDER == LITTLE_ENDIAN */	if (em->audio.format == AFMT_S16_LE ||	    em->audio_mode == EM8300_AUDIOMODE_DIGITALAC3) {#endif		if (em->audio.channels == 2) {			for (i=0; i < inlength; i+=4) {				get_user(outbuf[i+3], inbuf_user++);				get_user(outbuf[i+2], inbuf_user++);				get_user(outbuf[i+1], inbuf_user++);				get_user(outbuf[i], inbuf_user++);			}		} else {			for (i=0; i < inlength; i+=2) {				get_user(outbuf[2*i+1], inbuf_user++);				get_user(outbuf[2*i], inbuf_user++);				outbuf[2*i+3] = outbuf[2*i+1];				outbuf[2*i+2] = outbuf[2*i];			}		}	} else {		for (i=0; i<inlength/2; i++) {			outbuf[2*i] = inbuf_user[i];			outbuf[2*i+1] = inbuf_user[i];		}		}}static void preprocess_digital(struct em8300_s *em, unsigned char *outbuf,			       const unsigned char *inbuf_user, int inlength){	int i;	unsigned char tmpbuf[0x600];#if BYTE_ORDER == BIG_ENDIAN	if (em->audio.format == AFMT_S16_BE) {#else /* BYTE_ORDER == LITTLE_ENDIAN */        if (em->audio.format == AFMT_S16_LE ||	    em->audio_mode == EM8300_AUDIOMODE_DIGITALAC3) {#endif		for(i=0; i < inlength; i+=2) {			get_user(tmpbuf[i+1], inbuf_user++);			get_user(tmpbuf[i], inbuf_user++);		}	} else {		copy_from_user(tmpbuf, inbuf_user, inlength);	}	sub_prepare_SPDIF(em,outbuf, tmpbuf, inlength);}static void setup_mafifo(struct em8300_s *em) {	if (em->audio_mode == EM8300_AUDIOMODE_ANALOG) {		em->mafifo->preprocess_ratio = ((em->audio.channels == 2) ? 1 : 2);		em->mafifo->preprocess_cb = &preprocess_analog;#if 0 /* fix 1/2 second delay */		em->mafifo->preprocess_maxbufsize = -1;#else		em->mafifo->preprocess_maxbufsize = 3070;#endif	} else {		em->mafifo->preprocess_ratio = 2;		em->mafifo->preprocess_maxbufsize = 0x600;		em->mafifo->preprocess_cb = &preprocess_digital;	}}int mpegaudio_command(struct em8300_s *em, int cmd) {	em8300_waitfor(em,ucregister(MA_Command), 0xffff, 0xffff);	if (cmd == 2) {		em->audio_sync = 0;		em->audio_ptsvalid = 0;		em->audio_lag = 0;		em->audio_lastpts = 0;	}	pr_debug("MA_Command: %d\n",cmd);	write_ucregister(MA_Command,cmd);	return em8300_waitfor(em, ucregister(MA_Status), cmd, 0xffff);}static int audio_start(struct em8300_s *em) {	em->irqmask |= IRQSTATUS_AUDIO_FIFO;	write_ucregister(Q_IrqMask, em->irqmask);	em->audio.enable_bits = PCM_ENABLE_OUTPUT;	return mpegaudio_command(em, MACOMMAND_PLAY);}static int audio_stop(struct em8300_s *em) {	em->irqmask &= ~IRQSTATUS_AUDIO_FIFO;	write_ucregister(Q_IrqMask, em->irqmask);	em->audio.enable_bits = 0;	return mpegaudio_command(em, MACOMMAND_STOP);}static int set_speed(struct em8300_s *em, int speed){	em->clockgen &= ~CLOCKGEN_SAMPFREQ_MASK;	switch(speed) {	case 48000:		em->clockgen |= CLOCKGEN_SAMPFREQ_48;		speed = 48000;		break;	case 44100:		em->clockgen |= CLOCKGEN_SAMPFREQ_44;		speed = 44100;		break;	case 66000:		em->clockgen |= CLOCKGEN_SAMPFREQ_66;		speed = 66000;		break;	case 32000:		em->clockgen |= CLOCKGEN_SAMPFREQ_32;		speed = 32000;		break;	default:		em->clockgen |= CLOCKGEN_SAMPFREQ_48;		speed = 48000;	}		em->audio.speed = speed;	em8300_clockgen_write(em, em->clockgen);		return speed;}static int set_channels(struct em8300_s *em, int val) {	if (val > 2) val = 2;	em->audio.channels = val;	setup_mafifo(em);	return val;}static int set_format(struct em8300_s *em, int fmt){	if (fmt != AFMT_QUERY) {		switch (fmt) {#ifdef AFMT_AC3		case AFMT_AC3:			if (em->audio_mode != EM8300_AUDIOMODE_DIGITALAC3)				set_audiomode(em, EM8300_AUDIOMODE_DIGITALAC3);			set_speed(em, 48000);			em->audio.format = fmt;			break;#endif		case AFMT_S16_BE:		case AFMT_S16_LE:			if (em->audio_mode == EM8300_AUDIOMODE_DIGITALAC3)				set_audiomode(em, em->pcm_mode);			em->audio.format = fmt;			break;		default:			if (em->audio_mode == EM8300_AUDIOMODE_DIGITALAC3)				set_audiomode(em, em->pcm_mode);			fmt = AFMT_S16_BE;			break;		}	}	return em->audio.format;}int em8300_audio_ioctl(struct em8300_s *em,unsigned int cmd, unsigned long arg){	int err, len = 0;	int val = 0;	if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0) {		/*		 * Have to validate the address given by the process.		 */		len = _SIOC_SIZE(cmd);		if (len < 1 || len > 65536 || arg == 0) {			return -EFAULT;		}		if (_SIOC_DIR(cmd) & _SIOC_WRITE) {			if ((err = verify_area(VERIFY_READ, (void *)arg, len)) < 0) {				return err;			}		}		if (_SIOC_DIR(cmd) & _SIOC_READ) {			if ((err = verify_area(VERIFY_WRITE, (void *)arg, len)) < 0) {				return err;			}		}	}	switch(cmd) { 	case SNDCTL_DSP_RESET: /* reset device */		pr_debug("em8300_audio.o: SNDCTL_DSP_RESET\n");		em8300_fifo_sync(em->mafifo);		return 0;		break;	case SNDCTL_DSP_SYNC:  /* wait until last byte is played and reset device */		pr_debug("em8300_audio.o: SNDCTL_DSP_SYNC\n");		em8300_fifo_sync(em->mafifo);		val = 0;		break;	case SNDCTL_DSP_SPEED: /* set sample rate */		if (get_user(val, (int *)arg)) {			return -EFAULT;		}		pr_debug("em8300_audio.o: SNDCTL_DSP_SPEED %i ", val);		val = set_speed(em, val);		pr_debug("%i\n", val);		break;	case SOUND_PCM_READ_RATE: /* read sample rate */		pr_debug("em8300_audio.o: SNDCTL_DSP_RATE %i ", val);		val = em->audio.speed;		pr_debug("%i\n", val);		break;	case SNDCTL_DSP_STEREO: /* set stereo or mono mode */		if (get_user(val, (int *)arg)) {			return -EFAULT;		}		if (val > 1 || val < 0) {			return -EINVAL;		}		pr_debug("em8300_audio.o: SNDCTL_DSP_STEREO %i\n", val);		set_channels(em, val + 1);		break;	case SNDCTL_DSP_GETBLKSIZE: /* get fragment size */		val = em->audio.slotsize;		pr_debug("em8300_audio.o: SNDCTL_DSP_GETBLKSIZE %i\n", val);		break;	case SNDCTL_DSP_CHANNELS: /* set number of channels */		if (get_user(val, (int *)arg)) {			return -EFAULT;		}		if (val > 2 || val < 1) {			return -EINVAL;		}		pr_debug("em8300_audio.o: SNDCTL_DSP_CHANNELS %i\n", val);		set_channels(em, val);		break;	case SOUND_PCM_READ_CHANNELS: /* read number of channels */		val = em->audio.channels;		pr_debug("em8300_audio.o: SOUND_PCM_READ_CHANNELS %i\n", val);		break;	case SNDCTL_DSP_POST: /* "there is likely to be a pause in the output" */		pr_debug("em8300_audio.o: SNDCTL_DSP_POST\n");		pr_info("em8300_audio.o: SNDCTL_DSP_GETPOST not implemented yet\n");

⌨️ 快捷键说明

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