📄 em8300_audio.c
字号:
#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 + -