📄 em8300_audio.c
字号:
return -EINVAL; break; case SNDCTL_DSP_SETFRAGMENT: /* set fragment size */ pr_debug("em8300_audio.o: SNDCTL_DSP_SETFRAGMENT %i\n", val); pr_info("em8300_audio.o: SNDCTL_DSP_SETFRAGMENT not implemented yet\n"); return -EINVAL; break; case SNDCTL_DSP_GETFMTS: /* get possible formats */#ifdef AFMT_AC3 val = AFMT_AC3 | AFMT_S16_BE | AFMT_S16_LE;#else val = AFMT_S16_BE | AFMT_S16_LE;#endif pr_debug("em8300_audio.o: SNDCTL_DSP_GETFMTS\n"); break; case SNDCTL_DSP_SETFMT: /* set sample format */ if (get_user(val, (int *)arg)) { return -EFAULT; } pr_debug("em8300_audio.o: SNDCTL_DSP_SETFMT %i ", val); val = set_format(em, val); pr_debug("%i\n", val); break; case SOUND_PCM_READ_BITS: /* read sample format */ val = em->audio.format; pr_debug("em8300_audio.o: SOUND_PCM_READ_BITS\n"); break; case SNDCTL_DSP_GETOSPACE: { audio_buf_info buf_info; buf_info.fragments = ((*em->mafifo->readptr - *em->mafifo->writeptr)/em->mafifo->slotptrsize+em->mafifo->nslots-1)%em->mafifo->nslots; buf_info.fragstotal = em->mafifo->nslots; buf_info.fragsize = em->mafifo->slotsize; buf_info.bytes = em->mafifo->nslots*em->mafifo->slotsize; pr_debug("em8300_audio.o: SNDCTL_DSP_GETOSPACE\n"); return copy_to_user((void *)arg, &buf_info, sizeof(audio_buf_info)); } case SNDCTL_DSP_GETISPACE: pr_debug("em8300_audio.o: SNDCTL_DSP_GETISPACE\n"); return -EINVAL; break; case SNDCTL_DSP_GETCAPS: val = DSP_CAP_REALTIME | DSP_CAP_BATCH | DSP_CAP_TRIGGER; pr_debug("em8300_audio.o: SNDCTL_DSP_GETCAPS\n"); break; case SNDCTL_DSP_GETTRIGGER: val = em->audio.enable_bits; pr_debug("em8300_audio.o: SNDCTL_DSP_GETTRIGGER\n"); break; case SNDCTL_DSP_SETTRIGGER: if (val & PCM_ENABLE_OUTPUT) { if (em->audio.enable_bits & PCM_ENABLE_OUTPUT) { em->audio.enable_bits |= PCM_ENABLE_OUTPUT; mpegaudio_command(em, MACOMMAND_PLAY); } } pr_debug("em8300_audio.o: SNDCTL_DSP_SETTRIGGER\n"); pr_info("em8300_audio.o: SNDCTL_DSP_SETTRIGGER not implemented properly yet\n"); break; case SNDCTL_DSP_GETIPTR: pr_debug("em8300_audio.o: SNDCTL_DSP_GETIPTR\n"); return -EINVAL; break; case SNDCTL_DSP_GETOPTR: { count_info ci; ci.bytes = em->mafifo->bytes - (em8300_audio_calcbuffered(em) / em->mafifo->preprocess_ratio); if (ci.bytes < 0) ci.bytes = 0; ci.blocks = 0; ci.ptr = 0; pr_debug("em8300_audio.o: SNDCTL_DSP_GETOPTR %i\n", ci.bytes); return copy_to_user((void *)arg, &ci, sizeof(count_info)); } case SNDCTL_DSP_GETODELAY: val = em8300_audio_calcbuffered(em) / em->mafifo->preprocess_ratio; pr_debug("em8300_audio.o: SNDCTL_DSP_GETODELAY %i\n", val); break;#if 0 case SOUND_DSP_GETERROR: return -EINVAL; break;#endif case EM8300_IOCTL_AUDIO_SETPTS: if (get_user(em->audio_pts, (int *)arg)) return -EFAULT; em->audio_pts >>= 1; em->audio_ptsvalid=1; em->audio_sync = 1; break; default: pr_info("em8300_audio.o: unknown ioctl called\n"); return -EINVAL; } return put_user(val, (int *)arg);}int em8300_audio_flush(struct em8300_s *em){ int audiobuf, audiobufsize; mpegaudio_command(em, MACOMMAND_STOP); /* Zero audio buffer */ audiobuf = read_ucregister(MA_BuffStart_Lo) | (read_ucregister(MA_BuffStart_Hi) << 16); audiobufsize = read_ucregister(MA_BuffSize) | (read_ucregister(MA_BuffSize_Hi) << 16); mpegaudio_command(em, MACOMMAND_PAUSE); return em8300_setregblock(em, audiobuf, 0, audiobufsize);}int em8300_audio_open(struct em8300_s *em){ if (!em->ucodeloaded) { return -ENODEV; } em->audio_lastpts = 0; em->audio_lag = 0; em->last_calcbuf = 0; em->mafifo->bytes = 0; return audio_start(em);}int em8300_audio_release(struct em8300_s *em){ return audio_stop(em); }static int set_audiomode(struct em8300_s *em, int mode){ unsigned char mutepattern_src[0x300]; unsigned char mutepattern[0x600]; em->audio_mode = mode; em->clockgen &= ~CLOCKGEN_OUTMASK; if (em->audio_mode == EM8300_AUDIOMODE_ANALOG) { em->clockgen |= CLOCKGEN_ANALOGOUT; } else { em->clockgen |= CLOCKGEN_DIGITALOUT; } em8300_clockgen_write(em, em->clockgen); memset(mutepattern_src, 0, sizeof(mutepattern_src)); memset(em->byte_D90, 0, sizeof(em->byte_D90)); em->byte_D90[1]=0x98; switch (em->audio.speed) { case 32000: em->byte_D90[3] = 0xc0; break; case 44100: em->byte_D90[3] = 0; break; case 48000: em->byte_D90[3] = 0x40; break; } switch (em->audio_mode) { case EM8300_AUDIOMODE_ANALOG: em->pcm_mode = EM8300_AUDIOMODE_ANALOG; write_register(EM8300_AUDIO_RATE, 0x62); em8300_setregblock(em, 2*ucregister(Mute_Pattern), 0, 0x600); printk(KERN_NOTICE "em8300_audio.o: Analog audio enabled\n"); break; case EM8300_AUDIOMODE_DIGITALPCM: em->pcm_mode = EM8300_AUDIOMODE_DIGITALPCM; write_register(EM8300_AUDIO_RATE, 0x3a0); em->byte_D90[0]=0x0; sub_prepare_SPDIF(em, mutepattern, mutepattern_src, 0x300); em8300_writeregblock(em, 2*ucregister(Mute_Pattern), (unsigned *)mutepattern, 0x600); printk(KERN_NOTICE "em8300_audio.o: Digital PCM audio enabled\n"); break; case EM8300_AUDIOMODE_DIGITALAC3: write_register(EM8300_AUDIO_RATE, 0x3a0); em->byte_D90[0]=0x40; sub_prepare_SPDIF(em, mutepattern, mutepattern_src, 0x300); em8300_writeregblock(em, 2*ucregister(Mute_Pattern), (unsigned *)mutepattern, 0x600); printk(KERN_NOTICE "em8300_audio.o: Digital AC3 audio enabled\n"); break; } return 0;}int em8300_audio_setup(struct em8300_s *em){ int ret; em->audio.channels = 2; em->audio.format = AFMT_S16_NE; em->audio.slotsize = 0x1000; em->clockgen = em->clockgen_tvmode; set_speed(em, 48000); set_audiomode(em, EM8300_AUDIOMODE_DEFAULT); ret = em8300_audio_flush(em); setup_mafifo(em); if (ret) { printk(KERN_ERR "em8300_audio.o: Couldn't zero audio buffer\n"); return ret; } write_ucregister(MA_Threshold, 6); mpegaudio_command(em, MACOMMAND_PLAY); mpegaudio_command(em, MACOMMAND_PAUSE); em->audio.enable_bits = 0; return 0;}int em8300_audio_calcbuffered(struct em8300_s *em){ int readptr, writeptr, bufsize, n; readptr = read_ucregister(MA_Rdptr) | (read_ucregister(MA_Rdptr_Hi) << 16); writeptr = read_ucregister(MA_Wrptr) | (read_ucregister(MA_Wrptr_Hi) << 16); bufsize = read_ucregister(MA_BuffSize) | (read_ucregister(MA_BuffSize_Hi) << 16); n = (bufsize+writeptr-readptr) % bufsize; return em8300_fifo_calcbuffered(em->mafifo) + n;}int em8300_audio_write(struct em8300_s *em, const char * buf, size_t count, loff_t *ppos){ int32_t diff; uint32_t vpts, master_vpts; uint32_t calcbuf; if (em->audio_sync) { if (em->audio_ptsvalid) { em->audio_ptsvalid=0; if (em->audio_lastpts == 0) { em->audio_lastpts = em->audio_pts; } if (em->rollover) { em->rollover_lastpts += (em->audio_pts - em->audio_lastpts); em->audio_lag -= (em->audio_pts - em->audio_lastpts); em->audio_lastpts = em->audio_pts; } /* rollover detected */ if (em->audio_pts < em->audio_lastpts) { pr_debug("em8300_audio.o: ROLLOVER DETECTED! lastpts: %u pts: %u\n", em->audio_lastpts, em->audio_pts); em->rollover = 1; em->rollover_pts = 0; em->rollover_startpts = em->audio_pts; em->rollover_lastpts = em->audio_lastpts + em->lastpts_count; em->audio_lastpts = em->audio_pts; em->audio_lag -= em->lastpts_count; } else { em->audio_lag -= (em->audio_pts - em->audio_lastpts); em->audio_lastpts = em->audio_pts; } em->lastpts_count = 0; } if (!em->rollover) { em->basepts = em->audio_pts; } else { em->basepts = em->rollover_lastpts; } calcbuf = em8300_audio_calcbuffered(em);#ifdef DEBUG_SYNC pr_debug("em8300_audio.o: calcbuf: %u since_last_pts: %i\n", calcbuf, em->audio_lag);#endif vpts = em->basepts + em->audio_lag - (calcbuf * 45000/4 / em->audio.speed); master_vpts = read_ucregister(MV_SCRlo) | (read_ucregister(MV_SCRhi) << 16); if (em->rollover && (em->rollover_pts == 0)) { /* I'm not sure if there's any significance to this 45000/4 */ /* I had to add some pts, so I just picked it -RH */ em->rollover_pts = em->basepts + em->audio_lag + 45000/4; } if (em->rollover && (vpts > em->rollover_pts)) { em->rollover = 0; vpts -= em->rollover_startpts; }#ifdef DEBUG_SYNC pr_debug("em8300_audio.o: pts: %u vpts: %u scr: %u bpts: %u\n", em->audio_pts, vpts, master_vpts, basepts);#endif diff = vpts - master_vpts; if (my_abs(diff) > 3600) { pr_info("em8300_audio.o: resyncing\n"); pr_debug("em8300_audio.o: master clock adjust time %d -> %d\n", master_vpts, vpts); write_ucregister(MV_SCRlo, vpts & 0xffff); write_ucregister(MV_SCRhi, (vpts >> 16) & 0xffff); pr_debug("Setting SCR: %d\n", vpts); } em->audio_lag += (count * 45000/4 / em->audio.speed); em->last_calcbuf = calcbuf + count; em->lastpts_count += (count * 45000/4 / em->audio.speed); } return em8300_fifo_writeblocking(em->mafifo, count, buf,0);}/* 18-09-2000 - Ze'ev Maor - added these two ioctls to set and get audio mode. */int em8300_ioctl_setaudiomode(struct em8300_s *em, int mode){ em8300_audio_flush(em); set_audiomode(em, mode); setup_mafifo(em); mpegaudio_command(em, MACOMMAND_PLAY); em->audio.enable_bits = PCM_ENABLE_OUTPUT; return 0;}int em8300_ioctl_getaudiomode(struct em8300_s *em, int mode){ int a=em->audio_mode; copy_to_user((void *)mode, &a, sizeof(int)); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -