디바이스 드라이버 개발 도구 동향 - ETRI · 임채덕 외 / 디바이스 드라이버 개발 도구 동향 45 I. 서론 임베디드 소프트웨어(embedded software)에서
14. AC 97 디바이스 드라이버
description
Transcript of 14. AC 97 디바이스 드라이버
14. AC 97 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
www.huins.com 3
14.1.1 CS420214.1.1 CS4202
www.huins.com 4
14.1.2 AC’97 Controller Unit14.1.2 AC’97 Controller Unit AC-Link
www.huins.com 5
14.1.2 AC’97 Controller Unit14.1.2 AC’97 Controller Unit Audio Frame
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.
www.huins.com 7
14.1.2 AC’97 Controller Unit14.1.2 AC’97 Controller Unit Start of Audio Output Frame
www.huins.com 8
14.1.2 AC’97 Controller Unit14.1.2 AC’97 Controller Unit AC-link Audio Input Frame (SDATA_IN)
www.huins.com 9
14.1.2 AC’97 Controller Unit14.1.2 AC’97 Controller Unit Start of an Audio Input Frame
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.
www.huins.com 11
14.1.2 AC’97 Controller Unit14.1.2 AC’97 Controller Unit
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.
www.huins.com 13
14.1.2 AC’97 Controller Unit14.1.2 AC’97 Controller Unit Signal Configuration Steps(Cont’)
www.huins.com 14
14.1.2 AC’97 Controller Unit14.1.2 AC’97 Controller Unit Waking up the AC-link
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.
www.huins.com 16
14.1.2 AC’97 Controller Unit14.1.2 AC’97 Controller Unit Codec Access Register
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
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)
www.huins.com 19
14.2 Sound Device Driver14.2 Sound Device Driver 의 원리의 원리 Global Status Register(GSR)
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
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
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
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;
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;
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();
}
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;
}
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);
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
};
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 를 자동으로 잡아준다 .
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 시 호출
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)
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 한다 .
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
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);
}
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
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
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.
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;
}
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;
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;}
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;
}
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;
}
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
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
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
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
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;
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
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);
www.huins.com 50
14.3 Audio 14.3 Audio 구동구동 mixer
/dev 디렉토리에 가면 mixer 가 있음을 확인할 수 있다 .
www.huins.com 51
14.3 Audio 14.3 Audio 구동구동 mixer
$ mixer vol 100 이라고 입력하면 volume 을 설정할 수 있다 .
www.huins.com 52
14.3 Audio 14.3 Audio 구동구동 mixer
pcm 볼륨를 설정할 수 있다 .
www.huins.com 53
14.3 Audio 14.3 Audio 구동구동 mixer
/usr/bin 디렉토리 밑에 madplay 가 있음을 확인할 수 있다 .
www.huins.com 54
14.3 Audio 14.3 Audio 구동구동 mixer
위와 같이 입력하면 PXA255 보드에 있는 sample.mp3 파일을 실행 할 수 있다 . 실행시키면 ‘연애 소설 OST’ 를 들을 수 있다 .
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;
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; }
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 메세지 출력
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); }
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
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); }
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() 끝
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
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 보다 반드시 같거나 작아야
한다 .
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);}
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; }
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);
}
}