1 / 66

14. AC 97 디바이스 드라이버

14. AC 97 디바이스 드라이버. 목차. 14.1 Sound 용 Codec chip architecture 14.1.1 CS4202 14.1.2 AC’97 Controller Unit 14.2 Sound Device Driver 의 원리 14.3 Audio 구동 13.3.1 Mixer 13.3.2 madplayer 14.4 OSS(Open Sound System) Interface 를 이용한 Sound Programming. 14.1.1 CS4202.

kyria
Télécharger la présentation

14. AC 97 디바이스 드라이버

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 14. AC 97 디바이스 드라이버

  2. 목차 14.1 Sound 용 Codec chip architecture 14.1.1 CS4202 14.1.2 AC’97 Controller Unit 14.2 Sound Device Driver의 원리 14.3 Audio 구동 13.3.1 Mixer 13.3.2 madplayer 14.4 OSS(Open Sound System) Interface를 이용한 Sound Programming www.huins.com

  3. 14.1.1 CS4202 www.huins.com

  4. 14.1.2 AC’97 Controller Unit • AC-Link www.huins.com

  5. 14.1.2 AC’97 Controller Unit • Audio Frame www.huins.com

  6. 14.1.2 AC’97 Controller Unit • AC-link Audio Output Frame(SDATA_OUT) A new audio output frame begins with a low-to-high SYNC transition synchronous to BITCLK’s rising edge. BITCLK’s falling edge immediately follows and AC’97 samples SYNC’s assertion. BITCLK’s falling edge marks the instance that AC-link’s sides are each aware that a new audio frame has started. On BITCLK’s next rising edge, the ACUNIT transitions SDATA_OUT into the slot 0’s first bit position (valid frame bit). Each new bit position is presented to AC-link on a BITCLK rising edge and then sampled by AC’97 on the following BITCLK falling edge. This sequence ensures that data transitions and subsequent sample points for both incoming and outgoing data streams are time aligned. www.huins.com

  7. 14.1.2 AC’97 Controller Unit • Start of Audio Output Frame www.huins.com

  8. 14.1.2 AC’97 Controller Unit • AC-link Audio Input Frame (SDATA_IN) www.huins.com

  9. 14.1.2 AC’97 Controller Unit • Start of an Audio Input Frame www.huins.com

  10. 14.1.2 AC’97 Controller Unit • Feature List The processor ACUNIT supports the following AC’97 features: • Independent channels for Stereo PCM In, Stereo PCM out, modem-out, modem-in and mono mic-in. • All of the above channels support only 16-bit samples in hardware. Samples less than 16 bits are supported through software. www.huins.com

  11. 14.1.2 AC’97 Controller Unit www.huins.com

  12. 14.1.2 AC’97 Controller Unit • Signal Configuration Steps 1. Configure SYNC and SDATA_OUT as outputs. 2. Configure BITCLK, SDATA_IN_0, and SDATA_IN_1 as inputs. 3. nACRESET is a dedicated output. It remains asserted on power-up. Complete these steps to deassert nACRESET: a. Configure the other AC’97 signals as previously described. b. In the Global Control Register(GCR), Set the GCR[COLD_RST]bit. www.huins.com

  13. 14.1.2 AC’97 Controller Unit • Signal Configuration Steps(Cont’) www.huins.com

  14. 14.1.2 AC’97 Controller Unit • Waking up the AC-link www.huins.com

  15. 14.1.2 AC’97 Controller Unit • Waking up the AC-link(Cont’) • To wake up the AC-link, a CODEC drives SDATA_IN to a logic high level. The rising edge triggers the Resume Interrupt if that CODEC’s resume enable bit is set to a one. • The CPU then wakes up the CODEC using the cold or warm reset sequence. The ACUNIT uses a warm reset to wake up the primary CODEC. The CODEC detects a warm reset when SYNC is driven high for a minimum of one microsecond and the BITCLK is absent. • The CODEC must wait until it samples SYNC low before it can start BITCLK. The CODEC that signaled the wake event must keep its SDATA_IN high until it detects that a warm reset has been completed. The CODEC can then transition its SDATA_IN low. www.huins.com

  16. 14.1.2 AC’97 Controller Unit • Codec Access Register www.huins.com

  17. 14.2 Sound Device Driver의 원리 • pxa-ac97.c source 분석 static u16 pxa_ac97_read(struct ac97_codec *codec, u8 reg) { u16 val = -1; down(&CAR_mutex); if (!(CAR & CAR_CAIP)) { volatile u32 *reg_addr = (u32 *)&PAC_REG_BASE + (reg >> 1); waitingForMask=GSR_SDONE; init_completion(&CAR_completion); //start read access across the ac97 link (void)*reg_addr; wait_for_completion(&CAR_completion); 0x40500200 : primary audio codec 1 << 18 done = 0 wait = null www.huins.com

  18. 14.2 Sound Device Driver의 원리 • pxa-ac97.c source 분석 (Cont’) • Each CODEC has up to sixty-four 16-bit registers that are addressable internal to the CODEC at half-word boundaries(16-bit boundaries). Because the processor only supports internal register accesses at word boundaries (32-bit boundaries), software must select the one of the following formulas to translate a 7-bit CODEC address into a 32-bit processor address: • Processor physical address for a Primary Audio CODEC = 0x4050-0200 + Shift_Left_Once(Internal 7-bit CODEC Register Address) • Processor physical address for a Secondary Audio CODEC = 0x4050-0300 + Shift_Left_Once(Internal 7-bit CODEC Register Address) • Processor physical address for a Primary Modem CODEC = 0x4050-0400 + Shift_Left_Once(Internal 7-bit CODEC Register Address) • Processor physical address for a Secondary Modem CODEC = 0x4050-0500 + Shift_Left_Once(Internal 7-bit CODEC Register Address) www.huins.com

  19. 14.2 Sound Device Driver의 원리 • Global Status Register(GSR) www.huins.com

  20. 14.2 Sound Device Driver의 원리 cleared by software writing a ‘1’ to this location • pxa-ac97.c source 분석 (Cont’) if (GSR & GSR_RDCS) { GSR |= GSR_RDCS; printk(KERN_CRIT __FUNCTION__": read codec register timeout.\n"); } init_completion(&CAR_completion); val = *reg_addr; wait_for_completion(&CAR_completion); } else { printk(KERN_CRIT __FUNCTION__": CAR_CAIP already set\n"); } up(&CAR_mutex); return val; } www.huins.com

  21. 14.2 Sound Device Driver의 원리 • pxa-ac97.c source 분석 (Cont’) static void pxa_ac97_write(struct ac97_codec *codec, u8 reg, u16 val) { down(&CAR_mutex); if (!(CAR & CAR_CAIP)) { volatile u32 *reg_addr= (u32 *)&PAC_REG_BASE + reg >>1); waitingForMask=GSR_CDONE; init_completion(&CAR_completion); *reg_addr = val; wait_for_completion(&CAR_completion); } else { printk(KERN_CRIT __FUNCTION__": CAR_CAIP already set\n"); } up(&CAR_mutex); } 0x40500200 : primary audio codec 1 << 19 www.huins.com

  22. 14.2 Sound Device Driver의 원리 • pxa-ac97.c source 분석 (Cont’) static void pxa_ac97_irq(int irq, void *dev_id, struct pt_regs *regs) { int gsr = GSR; GSR = gsr & (GSR_SDONE|GSR_CDONE); if (gsr & waitingForMask) { complete(&CAR_completion); } } 0x4050001C GSCI = 1 www.huins.com

  23. 14.2 Sound Device Driver의 원리 • pxa-ac97.c source 분석 (Cont’) static struct ac97_codec pxa_ac97_codec = { codec_read: pxa_ac97_read, codec_write: pxa_ac97_write, }; static DECLARE_MUTEX(pxa_ac97_mutex); static int pxa_ac97_refcount; www.huins.com

  24. 14.2 Sound Device Driver의 원리 • pxa-ac97.c source 분석 (Cont’) int pxa_ac97_get(struct ac97_codec **codec) { int ret; *codec = NULL; down(&pxa_ac97_mutex); if (!pxa_ac97_refcount) { ret = request_irq(IRQ_AC97, pxa_ac97_irq, 0, "AC97", NULL); if (ret) return ret; www.huins.com

  25. 14.2 Sound Device Driver의 원리 • pxa-ac97.c source 분석 (Cont’) CKEN |= CKEN2_AC97; set_GPIO_mode(GPIO31_SYNC_AC97_MD); set_GPIO_mode(GPIO30_SDATA_OUT_AC97_MD); set_GPIO_mode(GPIO28_BITCLK_AC97_MD); set_GPIO_mode(GPIO29_SDATA_IN_AC97_MD); GCR = 0; udelay(10); GCR = GCR_COLD_RST|GCR_CDONE_IE|GCR_SDONE_IE; while (!(GSR & GSR_PCR)) { schedule(); } www.huins.com

  26. 14.2 Sound Device Driver의 원리 • pxa-ac97.c source 분석 (Cont’) ret = ac97_probe_codec(&pxa_ac97_codec); if (ret != 1) { free_irq(IRQ_AC97, NULL); GCR = GCR_ACLINK_OFF; CKEN &= ~CKEN2_AC97; return ret; } pxa_ac97_write(&pxa_ac97_codec,AC97_EXTENDED_STATUS,1); pxa_ac97_write(&pxa_ac97_codec, 0x6a, 0x0050); pxa_ac97_write(&pxa_ac97_codec, 0x6c, 0x0030); } pxa_ac97_refcount++; up(&pxa_ac97_mutex); *codec = &pxa_ac97_codec; return 0; } www.huins.com

  27. 14.2 Sound Device Driver의 원리 • pxa-ac97.c source 분석 (Cont’) void pxa_ac97_put(void) { down(&pxa_ac97_mutex); pxa_ac97_refcount--; if (!pxa_ac97_refcount) { GCR = GCR_ACLINK_OFF; CKEN &= ~CKEN2_AC97; free_irq(IRQ_AC97, NULL); } up(&pxa_ac97_mutex); } EXPORT_SYMBOL(pxa_ac97_get); EXPORT_SYMBOL(pxa_ac97_put); www.huins.com

  28. 14.2 Sound Device Driver의 원리 • pxa-ac97.c source 분석 (Cont’) static int ac97_audio_open(struct inode *inode, struct file *file) { return pxa_audio_attach(inode, file, &ac97_audio_state); } static struct file_operations ac97_audio_fops = { open: ac97_audio_open, owner: THIS_MODULE }; www.huins.com

  29. 14.2 Sound Device Driver의 원리 • pxa-ac97.c source 분석 (Cont’) static int __init pxa_ac97_init(void) { int ret; struct ac97_codec *dummy; ret = pxa_ac97_get(&dummy); if (ret) return ret; ac97_audio_state.dev_dsp = register_sound_dsp(&ac97_audio_fops, -1); pxa_ac97_codec.dev_mixer = register_sound_mixer(&mixer_fops, -1); return 0; } Minor number를 자동으로 잡아준다. www.huins.com

  30. 14.2 Sound Device Driver의 원리 • pxa-ac97.c source 분석 (Cont’) static void __exit pxa_ac97_exit(void) { unregister_sound_dsp(ac97_audio_state.dev_dsp); unregister_sound_mixer(pxa_ac97_codec.dev_mixer); pxa_ac97_put(); } module_init(pxa_ac97_init); module_exit(pxa_ac97_exit); Insmod실행 시 호출 : 모듈을 커널에 등록 rmmod시 호출 www.huins.com

  31. 14.2 Sound Device Driver의 원리 • pxa-audio.c source 분석 void pxa_audio_clear_buf(audio_stream_t * s) { DECLARE_WAITQUEUE(wait, current); int frag; if (!s->buffers) return; /* Ensure DMA isn't running */ set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&s->stop_wq, &wait); DCSR(s->dma_ch) = DCSR_STOPIRQEN; schedule(); remove_wait_queue(&s->stop_wq, &wait); Set to true whe thread is in WaitForSingleObject Audio buffer array Stop interrupt enbale(read/write) dma chnnel number www.huins.com

  32. 14.2 Sound Device Driver의 원리 • pxa-audio.c source 분석(cont’d) /* free DMA buffers */ for (frag = 0; frag < s->nbfrags; frag++) { audio_buf_t *b = &s->buffers[frag]; if (!b->master) continue; consistent_free(b->data, b->master, b->dma_desc->dsadr); } /* free descriptor ring */ if (s->buffers->dma_desc) consistent_free(s->buffers->dma_desc, s->nbfrags * s->descs_per_frag * DMA_DESC_SIZE, s->dma_desc_phys); /* free buffer structure array */ kfree(s->buffers); s->buffers = NULL; } Buffer를 clear 한다는 메시지와 함께 buffer를 free한다. www.huins.com

  33. 14.2 Sound Device Driver의 원리 • pxa-audio.c source 분석(cont’d) static int audio_set_fragments(audio_stream_t *s, int val) { if (s->mapped || DCSR(s->dma_ch) & DCSR_RUN) return -EBUSY; if (s->buffers) audio_clear_buf(s); s->nbfrags = (val >> 16) & 0x7FFF; val &= 0xffff; if (val < 5) val = 5; if (val > 15) val = 15; Device or resource is busy 19 Number of fragments www.huins.com

  34. 14.2 Sound Device Driver의 원리 • pxa-audio.c source 분석(cont’d) s->fragsize = 1 << val; if (s->nbfrags < 2) s->nbfrags = 2; if (s->nbfrags * s->fragsize > 256 * 1024) s->nbfrags = 256 * 1024 / s->fragsize; if (audio_setup_buf(s)) return -ENOMEM; return val|(s->nbfrags << 16); } www.huins.com

  35. 14.2 Sound Device Driver의 원리 • pxa-audio.c source 분석(cont’d) static int audio_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) { const char *buffer0 = buffer; audio_state_t *state = (audio_state_t *)file->private_data; audio_stream_t *s = state->output_stream; int chunksize, ret = 0; if (ppos != &file->f_pos) return -ESPIPE; if (s->mapped) return -ENXIO; if (!s->buffers && audio_setup_buf(s)) return -ENOMEM; Illegal seek No such device or address Out of memory www.huins.com

  36. 14.2 Sound Device Driver의 원리 • pxa-audio.c source 분석(cont’d) while (count > 0) { audio_buf_t *b = &s->buffers[s->usr_frag]; /* Grab a fragment */ if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; if (down_trylock(&s->sem)) break; } else { ret = -ERESTARTSYS; if (down_interruptible(&s->sem)) break; } /* Feed the current buffer */ chunksize = s->fragsize - b->offset; if (chunksize > count) chunksize = count; 00004 Try again : 35 www.huins.com

  37. 14.2 Sound Device Driver의 원리 • pxa-audio.c source 분석(cont’d) if (copy_from_user(b->data + b->offset, buffer, chunksize)) { up(&s->sem); return -EFAULT; } b->offset += chunksize; buffer += chunksize; count -= chunksize; if (b->offset < s->fragsize) { up(&s->sem); break; } /*activate DMA on current buffer*/ b->offset = 0; b->dma_desc->ddadr &= ~DDADR_STOP; if (DCSR(s->dma_ch) & DCSR_STOPSTATE) { DDADR(s->dma_ch) = b->dma_desc->ddadr; DCSR(s->dma_ch) = DCSR_RUN; } Bad address Unlock this fragment’s checkpoint descriptor and kick DMA if it is idle. Using checkpoint descriptors allows for control operations without the need for stopping the DMA channel if it is already running. www.huins.com

  38. 14.2 Sound Device Driver의 원리 • pxa-audio.c source 분석(cont’d) /* move the index to the next fragment */ if (++s->usr_frag >= s->nbfrags) s->usr_frag = 0; } if ((buffer - buffer0)) ret = buffer - buffer0; return ret; } www.huins.com

  39. 14.2 Sound Device Driver의 원리 • pxa-audio.c source 분석(cont’d) static int audio_read(struct file *file, char *buffer, size_t count, loff_t * ppos) { char *buffer0 = buffer; audio_state_t *state = file->private_data; audio_stream_t *s = state->input_stream; int chunksize, ret = 0; if (ppos != &file->f_pos) return -ESPIPE; if (s->mapped) return -ENXIO; if (!s->buffers && audio_setup_buf(s)) return -ENOMEM; www.huins.com

  40. 14.2 Sound Device Driver의 원리 • pxa-audio.c source 분석(cont’d) while (count > 0) { audio_buf_t *b = &s->buffers[s->usr_frag]; /* prime DMA */ if (DCSR(s->dma_ch) & DCSR_STOPSTATE) { DDADR(s->dma_ch) = s->buffers[s->dma_frag].dma_desc->ddadr; DCSR(s->dma_ch) = DCSR_RUN; } /* Wait for a buffer to become full */ if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; if (down_trylock(&s->sem)) break; } else { ret = -ERESTARTSYS; if (down_interruptible(&s->sem)) break; } www.huins.com

  41. 14.2 Sound Device Driver의 원리 • pxa-audio.c source 분석(cont’d) /* Grab data from current buffer */ chunksize = s->fragsize - b->offset; if (chunksize > count) chunksize = count; if (copy_to_user(buffer, b->data + b->offset, chunksize)) { up(&s->sem); return -EFAULT; } b->offset += chunksize; buffer += chunksize; count -= chunksize; if (b->offset < s->fragsize) { up(&s->sem); break; } www.huins.com

  42. 14.2 Sound Device Driver의 원리 • pxa-audio.c source 분석(cont’d) b->offset = 0; b->dma_desc->ddadr &= ~DDADR_STOP; /* move the index to the next fragment */ if (++s->usr_frag >= s->nbfrags) s->usr_frag = 0; } if ((buffer - buffer0)) ret = buffer - buffer0; return ret; } www.huins.com

  43. 14.2 Sound Device Driver의 원리 • pxa-audio.c source 분석(cont’d) static int audio_release(struct inode *inode, struct file *file) { audio_state_t *state = file->private_data; down(&state->sem); if (file->f_mode & FMODE_READ) { audio_clear_buf(state->input_stream); *state->input_stream->drcmr = 0; pxa_free_dma(state->input_stream->dma_ch); state->rd_ref = 0; } 1 DMA request channel to use DMA channel number www.huins.com

  44. 14.2 Sound Device Driver의 원리 2 • pxa-audio.c source 분석(cont’d) if (file->f_mode & FMODE_WRITE) { audio_sync(file); audio_clear_buf(state->output_stream); *state->output_stream->drcmr = 0; pxa_free_dma(state->output_stream->dma_ch); state->wr_ref = 0; } up(&state->sem); return 0; } www.huins.com

  45. 14.2 Sound Device Driver의 원리 • pxa-audio.c source 분석(cont’d) int pxa_audio_attach(struct inode *inode, struct file *file, audio_state_t *state) { audio_stream_t *is = state->input_stream; audio_stream_t *os = state->output_stream; int err; down(&state->sem); /* access control */ err = -ENODEV; if ((file->f_mode & FMODE_WRITE) && !os) goto out; if ((file->f_mode & FMODE_READ) && !is) goto out; No such device www.huins.com

  46. 14.2 Sound Device Driver의 원리 • pxa-audio.c source 분석(cont’d) err = -EBUSY; if ((file->f_mode & FMODE_WRITE) && state->wr_ref) goto out; if ((file->f_mode & FMODE_READ) && state->rd_ref) goto out; /* request DMA channels */ if (file->f_mode & FMODE_WRITE) { err = pxa_request_dma(os->name, DMA_PRIO_LOW, audio_dma_irq, os); if (err < 0) goto out; os->dma_ch = err; } 8 www.huins.com

  47. 14.2 Sound Device Driver의 원리 • pxa-audio.c source 분석(cont’d) if (file->f_mode & FMODE_READ) { err = pxa_request_dma(is->name, DMA_PRIO_LOW, audio_dma_irq, is); if (err < 0) { if (file->f_mode & FMODE_WRITE) { *os->drcmr = 0; pxa_free_dma(os->dma_ch); } goto out; } is->dma_ch = err; } file->private_data = state; file->f_op->release = audio_release; file->f_op->write = audio_write; file->f_op->read = audio_read; file->f_op->mmap = audio_mmap; file->f_op->poll = audio_poll; file->f_op->ioctl = audio_ioctl; file->f_op->llseek = no_llseek; www.huins.com

  48. 14.2 Sound Device Driver의 원리 • pxa-audio.c source 분석(cont’d) if ((file->f_mode & FMODE_WRITE)) { state->wr_ref = 1; os->fragsize = AUDIO_FRAGSIZE_DEFAULT; os->nbfrags = AUDIO_NBFRAGS_DEFAULT; os->output = 1; os->mapped = 0; init_waitqueue_head(&os->frag_wq); init_waitqueue_head(&os->stop_wq); *os->drcmr = os->dma_ch | DRCMR_MAPVLD; } if (file->f_mode & FMODE_READ) { state->rd_ref = 1; is->fragsize = AUDIO_FRAGSIZE_DEFAULT; is->nbfrags = AUDIO_NBFRAGS_DEFAULT; is->output = 0; is->mapped = 0; init_waitqueue_head(&is->frag_wq); init_waitqueue_head(&is->stop_wq); *is->drcmr = is->dma_ch | DRCMR_MAPVLD; } 8192 8 www.huins.com

  49. 14.2 Sound Device Driver의 원리 • pxa-audio.c source 분석(cont’d) err = 0; out: up(&state->sem); return err; } EXPORT_SYMBOL(pxa_audio_attach); EXPORT_SYMBOL(pxa_audio_clear_buf); www.huins.com

  50. 14.3 Audio 구동 • mixer • /dev 디렉토리에 가면 mixer가 있음을 확인할 수 있다. www.huins.com

More Related