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

66
14. AC 97 14. AC 97 디디디디 디디디디 디디디디 디디디디

description

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. - PowerPoint PPT Presentation

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

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

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

Page 2: 14. AC 97  디바이스 드라이버

www.huins.com 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

Page 3: 14. AC 97  디바이스 드라이버

www.huins.com 3

14.1.1 CS420214.1.1 CS4202

Page 4: 14. AC 97  디바이스 드라이버

www.huins.com 4

14.1.2 AC’97 Controller Unit14.1.2 AC’97 Controller Unit AC-Link

Page 5: 14. AC 97  디바이스 드라이버

www.huins.com 5

14.1.2 AC’97 Controller Unit14.1.2 AC’97 Controller Unit Audio Frame

Page 6: 14. AC 97  디바이스 드라이버

www.huins.com 6

14.1.2 AC’97 Controller Unit14.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.

Page 7: 14. AC 97  디바이스 드라이버

www.huins.com 7

14.1.2 AC’97 Controller Unit14.1.2 AC’97 Controller Unit Start of Audio Output Frame

Page 8: 14. AC 97  디바이스 드라이버

www.huins.com 8

14.1.2 AC’97 Controller Unit14.1.2 AC’97 Controller Unit AC-link Audio Input Frame (SDATA_IN)

Page 9: 14. AC 97  디바이스 드라이버

www.huins.com 9

14.1.2 AC’97 Controller Unit14.1.2 AC’97 Controller Unit Start of an Audio Input Frame

Page 10: 14. AC 97  디바이스 드라이버

www.huins.com 10

14.1.2 AC’97 Controller Unit14.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, mode

m-in and mono mic-in. All of the above channels support only 16-bit samples in hardware. Samples l

ess than 16 bits are supported through software.

Page 11: 14. AC 97  디바이스 드라이버

www.huins.com 11

14.1.2 AC’97 Controller Unit14.1.2 AC’97 Controller Unit

Page 12: 14. AC 97  디바이스 드라이버

www.huins.com 12

14.1.2 AC’97 Controller Unit14.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.

Page 13: 14. AC 97  디바이스 드라이버

www.huins.com 13

14.1.2 AC’97 Controller Unit14.1.2 AC’97 Controller Unit Signal Configuration Steps(Cont’)

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

www.huins.com 14

14.1.2 AC’97 Controller Unit14.1.2 AC’97 Controller Unit Waking up the AC-link

Page 15: 14. AC 97  디바이스 드라이버

www.huins.com 15

14.1.2 AC’97 Controller Unit14.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 se

quence. 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.

Page 16: 14. AC 97  디바이스 드라이버

www.huins.com 16

14.1.2 AC’97 Controller Unit14.1.2 AC’97 Controller Unit Codec Access Register

Page 17: 14. AC 97  디바이스 드라이버

www.huins.com 17

14.2 Sound Device Driver14.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

Page 18: 14. AC 97  디바이스 드라이버

www.huins.com 18

14.2 Sound Device Driver14.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)

Page 19: 14. AC 97  디바이스 드라이버

www.huins.com 19

14.2 Sound Device Driver14.2 Sound Device Driver 의 원리의 원리 Global Status Register(GSR)

Page 20: 14. AC 97  디바이스 드라이버

www.huins.com 20

14.2 Sound Device Driver14.2 Sound Device Driver 의 원리의 원리 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;

}

cleared by software writing a ‘1’ to this location

Page 21: 14. AC 97  디바이스 드라이버

www.huins.com 21

14.2 Sound Device Driver14.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

Page 22: 14. AC 97  디바이스 드라이버

www.huins.com 22

14.2 Sound Device Driver14.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

Page 23: 14. AC 97  디바이스 드라이버

www.huins.com 23

14.2 Sound Device Driver14.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;

Page 24: 14. AC 97  디바이스 드라이버

www.huins.com 24

14.2 Sound Device Driver14.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;

Page 25: 14. AC 97  디바이스 드라이버

www.huins.com 25

14.2 Sound Device Driver14.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();

}

Page 26: 14. AC 97  디바이스 드라이버

www.huins.com 26

14.2 Sound Device Driver14.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;

}

Page 27: 14. AC 97  디바이스 드라이버

www.huins.com 27

14.2 Sound Device Driver14.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);

Page 28: 14. AC 97  디바이스 드라이버

www.huins.com 28

14.2 Sound Device Driver14.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

};

Page 29: 14. AC 97  디바이스 드라이버

www.huins.com 29

14.2 Sound Device Driver14.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 를 자동으로 잡아준다 .

Page 30: 14. AC 97  디바이스 드라이버

www.huins.com 30

14.2 Sound Device Driver14.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 시 호출

Page 31: 14. AC 97  디바이스 드라이버

www.huins.com 31

14.2 Sound Device Driver14.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

dma chnnel number

Stop interrupt enbale(read/write)

Page 32: 14. AC 97  디바이스 드라이버

www.huins.com 32

14.2 Sound Device Driver14.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 한다 .

Page 33: 14. AC 97  디바이스 드라이버

www.huins.com 33

14.2 Sound Device Driver14.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

Number of fragments

19

Page 34: 14. AC 97  디바이스 드라이버

www.huins.com 34

14.2 Sound Device Driver14.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);

}

Page 35: 14. AC 97  디바이스 드라이버

www.huins.com 35

14.2 Sound Device Driver14.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

Page 36: 14. AC 97  디바이스 드라이버

www.huins.com 36

14.2 Sound Device Driver14.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

Page 37: 14. AC 97  디바이스 드라이버

www.huins.com 37

14.2 Sound Device Driver14.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.

Page 38: 14. AC 97  디바이스 드라이버

www.huins.com 38

14.2 Sound Device Driver14.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;

}

Page 39: 14. AC 97  디바이스 드라이버

www.huins.com 39

14.2 Sound Device Driver14.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;

Page 40: 14. AC 97  디바이스 드라이버

www.huins.com 40

14.2 Sound Device Driver14.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;}

Page 41: 14. AC 97  디바이스 드라이버

www.huins.com 41

14.2 Sound Device Driver14.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;

}

Page 42: 14. AC 97  디바이스 드라이버

www.huins.com 42

14.2 Sound Device Driver14.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;

}

Page 43: 14. AC 97  디바이스 드라이버

www.huins.com 43

14.2 Sound Device Driver14.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

Page 44: 14. AC 97  디바이스 드라이버

www.huins.com 44

14.2 Sound Device Driver14.2 Sound Device Driver 의 원리의 원리 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;

}

2

Page 45: 14. AC 97  디바이스 드라이버

www.huins.com 45

14.2 Sound Device Driver14.2 Sound Device Driver 의 원리의 원리 pxa-audio.c source 분석 (cont’d)

int pxa_audio_attach(struct inode *inode, struct file *file, audio_state_t *stat

e){

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

Page 46: 14. AC 97  디바이스 드라이버

www.huins.com 46

14.2 Sound Device Driver14.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

Page 47: 14. AC 97  디바이스 드라이버

www.huins.com 47

14.2 Sound Device Driver14.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;

Page 48: 14. AC 97  디바이스 드라이버

www.huins.com 48

14.2 Sound Device Driver14.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

Page 49: 14. AC 97  디바이스 드라이버

www.huins.com 49

14.2 Sound Device Driver14.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);

Page 50: 14. AC 97  디바이스 드라이버

www.huins.com 50

14.3 Audio 14.3 Audio 구동구동 mixer

/dev 디렉토리에 가면 mixer 가 있음을 확인할 수 있다 .

Page 51: 14. AC 97  디바이스 드라이버

www.huins.com 51

14.3 Audio 14.3 Audio 구동구동 mixer

$ mixer vol 100 이라고 입력하면 volume 을 설정할 수 있다 .

Page 52: 14. AC 97  디바이스 드라이버

www.huins.com 52

14.3 Audio 14.3 Audio 구동구동 mixer

pcm 볼륨를 설정할 수 있다 .

Page 53: 14. AC 97  디바이스 드라이버

www.huins.com 53

14.3 Audio 14.3 Audio 구동구동 mixer

/usr/bin 디렉토리 밑에 madplay 가 있음을 확인할 수 있다 .

Page 54: 14. AC 97  디바이스 드라이버

www.huins.com 54

14.3 Audio 14.3 Audio 구동구동 mixer

위와 같이 입력하면 PXA255 보드에 있는 sample.mp3 파일을 실행 할 수 있다 . 실행시키면 ‘연애 소설 OST’ 를 들을 수 있다 .

Page 55: 14. AC 97  디바이스 드라이버

www.huins.com 55

14.4 OSS(Open Sound System) Interface14.4 OSS(Open Sound System) Interface 를 를 이용한 이용한 Sound ProgrammingSound Programming

/* www.opensound.com */

#define DEFAULT_DSP_SPEED 8000

#define RECORD 0

#define PLAY 1

#define AUDIO "/dev/dsp"

int prof = APF_NORMAL;

int timelimit=0, dsp_speed = DEFAULT_DSP_SPEED, dsp_stereo=0;

int samplesize = 8;

int quiet_mode = 0;

int audio, abuf_size;

int direction, omode;

int blksize=0;

int fragsize=0;

char *audiobuf;

int c;

char audio_name[20] = AUDIO;

Page 56: 14. AC 97  디바이스 드라이버

www.huins.com 56

14.4 OSS(Open Sound System) Interface14.4 OSS(Open Sound System) Interface 를 를 이용한 이용한 Sound ProgrammingSound Programming

void recplay (char *name);extern void describe_error(void);

Int main (int argc, char *argv[]){

char *command; int tmp;

command = argv[0]; if (strstr (argv[0], "srec")) { direction = RECORD; omode = O_RDONLY; } else if (strstr (argv[0], "splay")) { direction = PLAY; omode = O_WRONLY; }

Page 57: 14. AC 97  디바이스 드라이버

www.huins.com 57

14.4 OSS(Open Sound System) Interface14.4 OSS(Open Sound System) Interface 를 를 이용한 이용한 Sound ProgrammingSound Programming

else

{

fprintf (stderr,

"Error: command should be named either srec or splay\n");

exit (1);

}

while ((c = getopt (argc, argv, "pqs:St:b:d:B:f:")) != -1)

switch (c){

case 'S': dsp_stereo = 1;

break;

case 'q': quiet_mode = 1;

break;

case 's': dsp_speed = atoi (optarg);

if (dsp_speed < 300)

dsp_speed *= 1000;

break;

Command 가 없을 경우 error 메세지 출력

Page 58: 14. AC 97  디바이스 드라이버

www.huins.com 58

14.4 OSS(Open Sound System) Interface14.4 OSS(Open Sound System) Interface 를 를 이용한 이용한 Sound ProgrammingSound Programming

case 't': timelimit = atoi (optarg); break;

case 'b': samplesize = atoi (optarg); break;

case 'B': blksize = atoi (optarg); break;

case 'd': strncpy(audio_name, optarg, 20); break;

case 'f': fragsize = 0xffff0000 | atoi (optarg); break;

case 'p': prof = APF_CPUINTENS; break;

default: fprintf (stderr, "Usage: %s [-qS] [-t secs] [-s Hz] [-b 8|12|16] [-d device] [filename]\n", command);

exit (-1); }

Page 59: 14. AC 97  디바이스 드라이버

www.huins.com 59

14.4 OSS(Open Sound System) Interface14.4 OSS(Open Sound System) Interface 를 를 이용한 이용한 Sound ProgrammingSound Programming

audio = open (audio_name, omode, 0); if (audio == -1) { perror (audio_name); describe_error(); exit (-1); }

if (fragsize != 0) if (ioctl(audio, SNDCTL_DSP_SETFRAGMENT, &fragsize)== -1) {

perror("SETFRAGMENT");exit(-1);

}

tmp = samplesize; ioctl(audio, SNDCTL_DSP_SAMPLESIZE, &samplesize); if (tmp != samplesize) { fprintf(stderr, "Unable to set the sample size\n"); exit(-1); }

Open device fail

Page 60: 14. AC 97  디바이스 드라이버

www.huins.com 60

14.4 OSS(Open Sound System) Interface14.4 OSS(Open Sound System) Interface 를 를 이용한 이용한 Sound ProgrammingSound Programming

ioctl(audio, SNDCTL_DSP_PROFILE, &prof);

if (ioctl (audio, SNDCTL_DSP_STEREO, &dsp_stereo)==-1) { fprintf (stderr, "%s: Unable to set mono/stereo\n", command); perror (audio_name); exit (-1); }

if (ioctl (audio, SNDCTL_DSP_SPEED, &dsp_speed) == -1) { fprintf (stderr, "%s: Unable to set audio speed\n", command); perror (audio_name); exit (-1); } if (!quiet_mode) { fprintf (stderr, "Speed %d Hz ", dsp_speed); if (dsp_stereo)

fprintf (stderr, "(stereo)\n"); else

fprintf (stderr, "(mono)\n"); if (samplesize != 8) fprintf(stderr, "%d bits per sample\n", samplesize); }

Page 61: 14. AC 97  디바이스 드라이버

www.huins.com 61

14.4 OSS(Open Sound System) Interface14.4 OSS(Open Sound System) Interface 를 를 이용한 이용한 Sound ProgrammingSound Programming

if (blksize > 0) abuf_size = blksize; else {

ioctl (audio, SNDCTL_DSP_GETBLKSIZE, &abuf_size); if (abuf_size < 1) { perror ("GETBLKSIZE"); exit (-1); }

} if ((audiobuf = malloc (abuf_size)) == NULL) { fprintf (stderr, "Unable to allocate input/output buffer\n"); exit (-1); } if (optind > argc - 1) recplay (NULL); else while (optind <= argc - 1) {

recplay (argv[optind++]); } close (audio); return 0;} //main() 끝

Page 62: 14. AC 97  디바이스 드라이버

www.huins.com 62

14.4 OSS(Open Sound System) Interface14.4 OSS(Open Sound System) Interface 를를 이용한 이용한 Sound ProgrammingSound Programming

void recplay (char *name){ int fd, l;

int count, c;

if (!timelimit) count = 0x7fffffff; else { count = timelimit * dsp_speed; if (dsp_stereo)

count *= 2; if (samplesize != 8) count *= 2; }

Number of byte the program wants to read from the device.

Using an integer power of 2

Page 63: 14. AC 97  디바이스 드라이버

www.huins.com 63

14.4 OSS(Open Sound System) Interface14.4 OSS(Open Sound System) Interface 를 를 이용한 이용한 Sound ProgrammingSound Programming

if (direction == PLAY) { if (!name){

fd = 0; name = "stdin"; }

else { if ((fd = open (name, O_RDONLY, 0)) == -1) { perror (name); exit (-1); } }

while (count) { c = count;

if (c > abuf_size) c = abuf_size;

c 값은 abuf_size 보다 반드시 같거나 작아야

한다 .

Page 64: 14. AC 97  디바이스 드라이버

www.huins.com 64

14.4 OSS(Open Sound System) Interface14.4 OSS(Open Sound System) Interface 를 를 이용한 이용한 Sound ProgrammingSound Programming

if ((l = read (fd, audiobuf, c)) > 0) { if (write (audio, audiobuf, l) != l) {

perror (audio_name); exit (-1);}

count -= l; } else { if (l == -1) {

perror (name); exit (-1);}

count = 0; /* Stop */ }

} /* while (count) */ if (fd != 0) close (fd);}

Page 65: 14. AC 97  디바이스 드라이버

www.huins.com 65

14.4 OSS(Open Sound System) Interface14.4 OSS(Open Sound System) Interface 를 를 이용한 이용한 Sound ProgrammingSound Programming

else { if (!name) {

fd = 1; name = "stdout";}

else { if ((fd = open (name, O_WRONLY | O_CREAT, 0666)) == -1) { perror (name); exit (-1); }}

while (count) { c = count; if (c > abuf_size) c = abuf_size; if ((l = read (audio, audiobuf, c)) > 0) { if (write (fd, audiobuf, l) != l) {

perror (name); exit (-1);}

count -= l; }

Page 66: 14. AC 97  디바이스 드라이버

www.huins.com 66

14.4 OSS(Open Sound System) Interface14.4 OSS(Open Sound System) Interface 를 를 이용한 이용한 Sound ProgrammingSound Programming

if (l == -1)

{

perror (audio_name);

exit (-1);

}

} /* While count */

if (fd != 1)

close (fd);

}

}