= ALSA = -- [김도집] [[DateTime(2005-08-23T04:41:42)]] [[TableOfContents]] == ALSA란? == ALSA는 Advanced Linux Sound Architecture의 약어이다. 이는 리눅스 운영체제에서 오디오와 미디 기능을 제공하기 위한 아키텍처이다. ALSA의 공식 사이트는 다음과 같다. [http://www.alsa-project.org/] == 드라이버 개발을 위한 문서 == * Writing an ALSA Driver [http://www.alsa-project.org/~iwai/writing-an-alsa-driver/index.html HTML] [http://www.alsa-project.org/~iwai/writing-an-alsa-driver.pdf PDF] == 드라이버 API == === 자료 구조 === snd_card_t는 에 정의 되어 있다. 이는 strcut _snd_card 의 typedef형이다. {{{ struct _snd_card { char driver[16]; /* 드라이버 이름 */ char shortname[32]; /* 사운드 카드의 짧은 이름 */ char longname[80]; /* 사운드 카드의 이름 */ void *private_data; /* 사운드 카드에 대한 추가 정보 */ void (*private_free) (snd_card_t *card); /* 추가 정보을 위해 할당받은 자원 */ /* 반환을 위한 콜백 */ }}} /!\ 위 구조체의 필드는 위 명시된 내용 외에도 무수히 많다. 사용자가 꼭 알아야 하는 것들만 나열했다. === snd_card_new === 사운드 카드의 구조체를 할당 받는다. {{{ snd_card_t *snd_card_new(int idx, const char *xid, struct module *module, int extra_size) }}} ||매개변수||설명|| ||idx||카드의 인덱스(주소),0에서 (SNDRV_CARDS-1)|| ||xid||카드 이름 (문자열)|| ||module||locking을 소유한 상위 모듈|| ||extra_size||사운드카드 구조체 이후 추가 할당받을 메모리 크기|| 성공하면 snd_card_t형의 포인터를 반환하고 실패하면 NULL을 반환한다. {{{ snd_card_t *card; card = snd_card_new(-1, id, THIS_MODULE, sizeof(foo_bar)); if (card == NULL) return -ENOMEM; }}} === snd_card_register === 사운드 카드를 등록한다. {{{ int snd_card_register(snd_card_t *card) }}} 성공하면 0을 반환하고, 실패하면 0이 아닌 값을 반환한다. 관련함수: snd_card_free === snd_card_free === 사운드카드 구조체의 자원을 반환한다. {{{ int snd_card_free(snd_card_t *card) }}} 성공하면 0을 반환하고, 실패하면 0이 아닌 값을 반환한다. 관련함수: snd_card_new, snd_card_register === 전원 관리 === 전원 관리 함수는 CONFIG_PM 이 정의된 경우에만 유효 하도록 작성한다. {{{ #ifdef CONFIG_PM static int snd_foo_suspend(...) { ... } #endif }}} snd_card_set_pm_callback() snd_power_change_state() snd_pcm_suspend_all() ||전원 상태 매크로||설명|| ||SNDRV_CTRL_POWER_D0||Full On 상태|| ||SNDRV_CTRL_POWER_D1||일부만 On 상태|| ||SNDRV_CTRL_POWER_D2||일부만 On 상태|| ||SNDRV_CTRL_POWER_D3||Off 상태|| ||SNDRV_CTRL_POWER_D3hot||전원은 공급되지만 Off 상태|| ||SNDRV_CTRL_POWER_D3cold||전원 공급도 없는 Off 상태|| ==== snd_card_set_pm_callback ==== 전원 관리를 위한 콜백을 등록한다. {{{ int snd_card_set_pm_callback(snd_card_t *card, int (*suspend)(snd_card_t *, pm_message_t), int (*resume)(snd_card_t *), void *private_data) }}} ||필드||설명|| ||card||사운드카드 구조체|| ||suspend||절전 모드 진입시 호출되는 콜백|| ||resume||절전 모드 해제시 호출되는 콜백|| ||private_data||콜백에 넘길 매개 변수의 포인터|| 항상 0을 반환한다. 이 함수는 매개변수 card의 필드 중 pm_suspend, pm_resume, pm_private_data 를 넘겨주는 매개 변수의 값으로 설정한다. {{{ snd_card_set_pm_callback(card, snd_foo_suspend, snd_foo_resume, foo); }}} ==== snd_power_change_state ==== ==== snd_pcm_suspend_all ==== === PCM === ==== 자료 구조 ==== ==== PCM 연산 ==== 다음의 자료형은 파일에 정의되어 있다. {{{ typedef struct _snd_pcm_ops { int (*open)(snd_pcm_substream_t *substream); int (*close)(snd_pcm_substream_t *substream); int (*ioctl)(snd_pcm_substream_t *substream, unsigned int cmd, void *arg); int (*hw_params)(snd_pcm_substream_t *substream, snd_pcm_hw_params_t *params); int (*hw_free)(snd_pcm_substream_t *substream); int (*prepare)(snd_pcm_substream_t *substream); int (*trigger)(snd_pcm_substream_t *substream, int cmd); snd_pcm_uframes_t (*pointer)(snd_pcm_substream_t *substream); int (*copy)(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t pos, void __user *buf, snd_pcm_ufreams_t count); struct page *(*page)(snd_pcm_substream_t *substream, unsigned long offset); int (*mmap)(snd_pcm_substream_t *substream, struct vm_area_struct *vma); int (*ack)(snd_pcm_substream_t *substream); } snd_pcm_ops_t; }}} ||필드||설명|| ||open|||| ||close|||| ||ioctl|||| ||hw_parames|||| ||hw_free|||| ||prepare|||| ||trigger|||| ||pointer|||| ===== open ===== 어떤 스트림인지를 결정한다. 함수 원형은 다음과 같다: {{{ static int xxx_open(snd_pcm_substream_t *substream) }}} ===== close ===== ===== ioctl ===== ===== hw_params ===== ===== hw_free ===== ===== prepare ===== 스트림의 처리 전에 초기값을 설정한다. 예를 들면, sample rate등이 있다. 함수 원형은 다음과 같다: {{{ static int xxx_prepare(snd_pcm_substream_t *substream) }}} ===== trigger ===== 스트림의 중단 및 시작을 처리한다. 함수 원형은 다음과 같다: {{{ static int xxx_trigger(snd_pcm_substream_t *substream, int cmd) }}} cmd는 에 정의된 매크로이다. ||cmd||설명|| ||SNDRV_PCM_TRIGGER_STOP||스트림을 종료한다.|| ||SNDRV_PCM_TRIGGER_START||스트림을 시작한다.|| ===== pointer ===== 현 스트림의 위치를 가져온다. 함수 원형은 다음과 같다: {{{ static snd_pcm_uframes_t xxx_pointer(snd_pcm_substream_t *substream) }}} ==== snd_pcm_new ==== 새로운 PCM 디바이스를 위한 자원을 할당받는다. 이러한 역할을 하는 함수가 snd_pcm_new 함수이다. 함수의 원형은 다음과 같다: {{{ int snd_pcm_new(snd_card_t *card, char *id, int device, int playback_count, int capture_count, snd_pcm_t **rpcm) }}} ||매개변수||설명|| ||card||사운드 카드 데이터의 포인터|| ||id||ID 문자열|| ||device||장치 인덱스 (0부터 시작한다)|| ||playback_count||재생할 때 스트림의 개수|| ||capture_count||녹음할 때 스트림의 개수|| ||rpcm||새 pcm 디바이스를 위한 자원을 저장하기 위한 포인터|| 성공하면 0을 반환하고, 실패하면 음의 에러 코드 값을 반환한다. 사용 예를 보면 다음과 같다: {{{ int err; snd_pcm_t *pcm; if ((err = snd_pcm_new(foo->card, "FOO ACM", device, 1, 1, &pcm)) < 0) return err; } }}}==== snd_pcm_lib_preallocate_pages_for_all ==== 스트림을 위한 연속된 메모리를 할당받기 위한 사전 작업을 처리한다. 함수의 원형은 다음과 같다: {{{ int snd_pcm_lib_preallocate_pages_for_all(snd_pcm_t *pcm, int type, void *data, size_t size, size_t max) }}} ||매개변수||설명|| ||pcm||pcm 디바이스 포인터|| ||type||SNDRV_DMA_TYPE_로 시작하는 DMA 타입|| ||data||DMA 타입에 따른 데이터|| ||size||사전 할당을 받아야 하는 메모리의 바이트 단위의 크기|| ||max||허용하는 최대 메모리 크기|| 성공하면 0을 반환하고 실패하면 에러코드인 음수를 반환한다. type 필드에 사용할 수 있는 것들은 다음과 같다: ||type||설명|| ||SNDRV_DMA_TYPE_UNKNOWN||정의 되지 않은 타입|| ||SNDRV_DMA_TYPE_CONTINUOUS||DMA가 아닌 연속된 메모리|| ||SNDRV_DMA_TYPE_DEV||디바이스 내의 연속된 메모리|| ||SNDRV_DMA_TYPE_DEV_SG||디바이스 내의 연속된 SG-버퍼|| ||SNDRV_DMA_TYPE_SBUS||연속된 SBUS|| 다음은 사용예이다: {{{ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINOUS, snd_dma_continues_data(GFP_KERNEL), 128 * 1024, 128 * 1024); }}} ==== snd_pcm_set_ops ==== PCM의 동작을 위한 연산 테이블을 등록한다. {{{ void snd_pcm_set_ops(snd_pcm_t *pcm, int direction, snd_pcm_ops_t *ops) }}} ||direction||설명|| ||SNDRV_PCM_STREAM_PLAYBACK|||| ||SNDRV_PCM_STREAM_CAPTURE|||| === MIXER === 믹서는 사운드 카드를 제어하는 인터페이스이다. 여러 개의 제어기가 존재할 수 있다. 이들을 믹서에 추가하는 것은 snd_ctl_new함수가 처리한다. ==== snd_ctl_new ==== 믹서에 제어기를 등록한다. 함수 원형은 다음과 같다: {{{ int snd_ctl_add(snd_card_t *card, snd_kcontrl_t *kcontrol) }}} 성공하면 0을 반환하고, 실패하면 0이 아닌 에러코드를 반환한다. 사용예는 다음과 같다: {{{ if ((err = snd_ctl_add(card, snd_ctl_new1(&xxx_contols[idx], chip))) < 0) return err; }}}==== snd_ctl_new1 ==== 제어기에 대한 정보를 쉽게 생성시킬 수 있도록 도와주는 함수이다. 함수의 원형은 다음과 같다: {{{ snd_kctonrol_t *snd_ctl_new1(const snd_kcontol_new_t *ncontrol, void *private_data) }}} 사용예는 다음과 같다: {{{ if ((err = snd_ctl_add(card, snd_ctl_new1(&xxx_contols[idx], chip))) < 0) return err; }}}