亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 1261 | 回復: 0
打印 上一主題 下一主題

writing-an-alsa-driver(編寫一個ALSA驅(qū)動)翻譯稿 第五章(1) [復制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2008-06-20 13:59 |只看該作者 |倒序瀏覽

       
       
翻譯:creator

sz111@126.com

       
       
第五章
PCM[color="#000000"]接口
[color="#000000"]概述
   
PCM[color="#000000"]中間層是ALSA[color="#000000"]中作用非常大的。它是唯一需要在每個驅(qū)動中都需要實現(xiàn)的low-level[color="#000000"]的硬件接口。
   
為了訪問PCM[color="#000000"]層,你需要包含[color="#000000"]。除此之外,如果你要操作hw_param[color="#000000"]相關的函數(shù),還需要包含[color="#000000"]。
   
每個card[color="#000000"]設備可以最多擁有4[color="#000000"]個pcm[color="#000000"]實例。一個pcm[color="#000000"]實例對應予一個pcm[color="#000000"]設備文件。組件的號碼限制主要是和Linux[color="#000000"]的可用的設備號多少有關。假如允許64bit[color="#000000"]的設備號,我們可以擁有更多的pcm[color="#000000"]實例。
[color="#000000"]    一個pcm[color="#000000"]實例包含pcm
[color="#000000"]放音和錄音流,而每個pcm[color="#000000"]流由一個或多個pcm[color="#000000"]子流組成。一些聲卡支持多重播放的功能。例如:emu10k1[color="#000000"]就包含一個32[color="#000000"]個立體聲子流的PCM[color="#000000"]放音設備。事實上,每次被打開的時候,一個可用的子流會自動的被選中和打開。同時,當一個子流已經(jīng)存在,并且已經(jīng)被打開,當再次被打開的時候,會被阻塞,或者根據(jù)打開文件的模式不同返回一個EAGAIND[color="#000000"]的錯誤信息。你也不需要知道你的驅(qū)動細節(jié)部分,PCM[color="#000000"]中間層會處理那些工作。
[color="#000000"]代碼示例
   
下面的代碼沒有包含硬件接口程序,主要顯示一個如何構建一個PCM[color="#000000"]接口的骨架。
[color="#000000"]Example5-1.PCM[color="#000000"]示例代碼
    #include
[color="#000000"]    ....
[color="#000000"]    /*[color="#000000"]硬件定義*/
    static
struct snd_pcm_hardware snd_mychip_playback_hw = {
        .info
= (SNDRV_PCM_INFO_MMAP |
               
SNDRV_PCM_INFO_INTERLEAVED
|
               
SNDRV_PCM_INFO_BLOCK_TRANSFER
|
               
SNDRV_PCM_INFO_MMAP_VALID),
        .formats
= SNDRV_PCM_FORMAT_S16_LE,
        .rates
= SNDRV_PCM_RATE_8000_48000[color="#000000"],
        .rate_min
= 8000,
        .rate_max
= 48000,
      
.channels_min
= 2,
      
.channels_max
= 2,
      
.buffer_bytes_max
= 32768,
      
.period_bytes_min
= 4096,
      
.period_bytes_max
= 32768,
      
.periods_min
= 1,
      
.periods_max
= 1024,
[color="#000000"]    };
[color="#000000"]    /*[color="#000000"]硬件定義*/
    static
struct snd_pcm_hardware snd_mychip_capture_hw = {
        .info
= (SNDRV_PCM_INFO_MMAP |
               
SNDRV_PCM_INFO_INTERLEAVED
|
               
SNDRV_PCM_INFO_BLOCK_TRANSFER
|
               
SNDRV_PCM_INFO_MMAP_VALID),
        .formats
= SNDRV_PCM_FORMAT_S16_LE,
        .rates
= SNDRV_PCM_RATE_8000_48000[color="#000000"],
        .rate_min
= 8000,
        .rate_max
= 48000,
      
.channels_min
= 2,
      
.channels_max
= 2,
      
.buffer_bytes_max
= 32768,
      
.period_bytes_min
= 4096,
      
.period_bytes_max
= 32768,
      
.periods_min
= 1,
      
.periods_max
= 1024,
[color="#000000"]    };
[color="#000000"]   
[color="#000000"]    /*[color="#000000"]播放open[color="#000000"]函數(shù)*/
    static
int snd_mychip_playback_open(struct snd_pcm_substream *substream)
[color="#000000"]    {
        struct
mychip *chip = snd_pcm_substream_chip(substream);
        struct
snd_pcm_runtime *runtime = substream->runtime;
[color="#000000"]   
      
runtime->hw
= snd_mychip_playback_hw;
      
/*[color="#000000"]其他硬件初始化的部分在這里完成*/
        return
0;
[color="#000000"]    }
[color="#000000"]    /*[color="#000000"]播放close[color="#000000"]函數(shù)*/
    static
int snd_mychip_playback_close(struct snd_pcm_substream *substream)
[color="#000000"]    {
         struct
mychip *chip = snd_pcm_substream_chip(substream);
        
//[color="#000000"]硬件相關代碼寫在這
         return
0;
[color="#000000"]     }
[color="#000000"]     /*[color="#000000"]錄音open[color="#000000"]函數(shù)*/
     static
int snd_mychip_capture_open(struct snd_pcm_substream *substream)
[color="#000000"]     {
         struct
mychip *chip = snd_pcm_substream_chip(substream);
         struct
snd_pcm_runtime *runtime = substream->runtime;
   

        
runtime->hw
= snd_mychip_capture_hw;
        
/*[color="#000000"]其他硬件初始化的部分在這里完成*/
         return
0;
[color="#000000"]     }
   
/*[color="#000000"]錄音close[color="#000000"]函數(shù)*/
     static
int snd_mychip_capture_close(struct snd_pcm_substream *substream)
[color="#000000"]     {
         struct
mychip *chip = snd_pcm_substream_chip(substream);
        
//[color="#000000"]硬件相關代碼寫在這
         return
0;
[color="#000000"]     }
   

   
/*hw_params[color="#000000"]函數(shù)*/
    static
int snd_mychip_pcm_hw_params(struct snd_pcm_substream *substream,
                 
                      struct
snd_pcm_hw_params *hw_params)
[color="#000000"]    {
        return
snd_pcm_lib_malloc_pages(substream,
                 
                      params_buffer_bytes(hw_params));
[color="#000000"]    }
[color="#000000"]    /*hw_free[color="#000000"]函數(shù)*/
    static
int snd_mychip_pcm_hw_free(struct snd_pcm_substream *substream)
[color="#000000"]    {
        return
snd_pcm_lib_free_pages(substream);
[color="#000000"]    }
    /*prepare函數(shù)*/
    static
int snd_mychip_pcm_prepare(struct snd_pcm_substream *substream)
    {
        struct
mychip *chip = snd_pcm_substream_chip(substream);
        struct
snd_pcm_runtime *runtime = substream->runtime;
        /*在此做設定一些硬件配置
         *例如....
         */
        mychip_set_sample_format(chip,
runtime->format);
        mychip_set_sample_rate(chip,
runtime->rate);
        mychip_set_channels(chip,
runtime->channels);
        mychip_set_dma_setup(chip,
runtime->dma_addr,
                           
chip->buffer_size,
                           
chip->period_size);
        return
0;
    }
    /*trigger函數(shù)*/
    static
int snd_mychip_pcm_trigger(struct snd_pcm_substream *substream,
                                    
int cmd)
    {
        switch(cmd){
        case
SNDRV_PCM_TRIGGER_START:
            //啟動一個PCM引擎
            break;
        case
SNDRV_PCM_TRIGGER_STOP:
            //停止一個PCM引擎
            break;
        default:
            return
-EINVAL;
        }
    }
    /*pointer函數(shù)*/
    static
snd_pcm_uframes_t
    snd_mychip_pcm_pointer(struct
snd_pcm_substream *substream)
    {
        struct
mychip *chip = snd_pcm_substream_chip(substream)
        unsigned
int current_ptr;
        /*得到當前緩沖區(qū)的硬件位置*/
        current_ptr
= mychip_get_hw_pointer(chip);
        return
current_ptr;
    }
    /*操作函數(shù)*/
    static
struct snd_pcm_ops snd_mychip_playback_ops = {
        .open
= snd_mychip_playback_open,
        .close
= snd_mychip_playback_close,
.ioctl
= snd_pcm_lib_ioctl,
        .hw_params
= snd_mychip_pcm_hw_params,
        .hw_free
= snd_mychip_pcm_hw_free,
        .prepare
= snd_mychip_pcm_prepare,
        .trigger
= snd_mychip_pcm_trigger,
        .pointer
= snd_mychip_pcm_pointer,
    };
    /*操作函數(shù)*/
    static
struct snd_pcm_ops snd_mychip_capture_ops = {
        .open
= snd_mychip_capture_open,
        .close
= snd_mychip_capture_close,
.ioctl
= snd_pcm_lib_ioctl,
        .hw_params
= snd_mychip_pcm_hw_params,
        .hw_free
= snd_mychip_pcm_hw_free,
        .prepare
= snd_mychip_pcm_prepare,
        .trigger
= snd_mychip_pcm_trigger,
        .pointer
= snd_mychip_pcm_pointer,
    };
    /*關于錄音的定義在這里省略....*/
    /*創(chuàng)建一個pcm設備*/
    static
int __devinit snd_mychip_new_pcm(struct mychip *chip)
    {
        struct
snd_pcm *pcm;
        int
err;
        if
((err = snd_pcm_new(chip->card, “My Chip”, 0 , 1, 1,&pcm)
            return
err;
        pcm->private_data
= chip;
        strcpy(pcm->name,”My
Chip”);
        chip->pcm
= pcm;
        /*設定操作函數(shù)*/
      
snd_pcm_set_ops(pcm,SNDRV_PCM_STREAM_PLAYBACK,
                       
&snd_mychip_playback_ops);

         
        
snd_pcm_set_ops(pcm,SNDRV_PCM_STREAM_CAPTURE,
                       
&snd_mychip_capture_ops);
         /*預分配緩沖區(qū)
          *注意:可能會失敗
          */
        
snd_pcm_lib_preallocate_pages_for_all(pcm,SNDRV_DMA_TYPE_DEV,
                                       
       snd_dma_pci_data(chip->pci),
                                       
       64*1024,64*1024);
         return
0;         
     }
構造函數(shù)
   
通過snd_pcm_new()來分配一個pcm實例。更好的方式是為pcm創(chuàng)建一個構造函數(shù)。
    static
int __devinit snd_mychip_new_pcm(struct mychip *chip)
    {
        struct
snd_pcm *pcm;
        int
err;
        if
((err = snd_pcm_new(chip->card, “My Chip”, 0 , 1, 1,&pcm)
            return
err;
        pcm->private_data
= chip;
        strcpy(pcm->name,”My
Chip”);
        chip->pcm
= pcm;
        ....
        return
0;         
     }
   
snd_pcm_new()需要4個參數(shù)。第一個是card指針,第二個是標識符字符串,第三個是PCM設備索引。假如你創(chuàng)建了超過一個pcm實例,通過設備索引參數(shù)來區(qū)分pcm設備。例如:索引為1代表是第二個PCM設備。
   
第四個和第五個參數(shù)是表示播放和錄音的子流的數(shù)目。上面的示例都是為1。當沒有播放或錄音可以用的時候,可以設定對應的參數(shù)為0。
   
假如聲卡支持多個播放和錄音子流,你可以分配更多的號碼,但是它們必須可以在open()和close()函數(shù)中被正確處理。你可以通過snd_pcm_substream的成員變量number來知道那用到的是那個子流。如:
    struct
snd_pcm_substream *substream;
    int
index = substream->number;
  
    pcm創(chuàng)建之后,必須設定pcm流的操作函數(shù)。
   
snd_pcm_set_ops(pcm,SNDRV_PCM_STREAM_PLAYBACK,
                  
&snd_mychip_playback_ops);

         
   
snd_pcm_set_ops(pcm,SNDRV_PCM_STREAM_CAPTURE,
                  
&snd_mychip_capture_ops);
    操作函數(shù)類似如下:
    /*操作函數(shù)*/
    static
struct snd_pcm_ops snd_mychip_playback_ops = {
        .open
= snd_mychip_playback_open,
        .close
= snd_mychip_playback_close,
.ioctl
= snd_pcm_lib_ioctl,
        .hw_params
= snd_mychip_pcm_hw_params,
        .hw_free
= snd_mychip_pcm_hw_free,
        .prepare
= snd_mychip_pcm_prepare,
        .trigger
= snd_mychip_pcm_trigger,
        .pointer
= snd_mychip_pcm_pointer,
    };
    每一個回調(diào)函數(shù)都會在“操作函數(shù)”一節(jié)中詳細介紹。
   
設定完操作函數(shù)之后,大部分情況要預分配緩沖區(qū)。一般情況采用如下方式分配:
      
snd_pcm_lib_preallocate_pages_for_all(pcm,
SNDRV_DMA_TYPE_DEV,
                                       
      snd_dma_pci_data(chip->pci),
                                       
      64*1024,64*1024);
   
默認它會分配64KB的緩沖。關于緩沖區(qū)的管理會在“緩沖區(qū)和內(nèi)存管理”一章詳細描述。
   
除此之外,你還可以為這個pcm設定一些附加的信息保存在pcm->info_flags變量中。一些可用的變量定義例如SNDRV_PCM_INFO_XXX都在中,這些主要是為了硬件定義的(稍后會詳細描述)。假如你的聲卡僅僅支持半雙工,你要指定如下:
     pcm->info_flags
= SNDDRV_PCM_INFO_HALF_DUPLEX;
到了析構部分?
   
一個pcm實例不是總是要求析構的。既然pcm中間層會自動的把pcm設備是否,你就不用特別的在調(diào)用析構函數(shù)了。
   
析構函數(shù)在一種情況下是必須的,就是你在內(nèi)部創(chuàng)建了一個特殊的的記錄,需要自己去釋放他們。這種情況下,你可以把pcm->private_free指向你的析構函數(shù)。
    Example5-2.含有一個析構函數(shù)的PCM實例
    static
void mychip_pcm_free(struct snd_pcm *pcm)
    {
         struct
mychip *chip = snd_pcm_chip(pcm);
         /*釋放你自己的數(shù)據(jù)*/
        
kfree(chip->my_private_pcm_data);
         //做其他事情
    }
    static
int __devinit snd_mychip_new_pcm(struct mychip *chip)
    {
        struct
snd_pcm *pcm;
        /*分配你自己的數(shù)據(jù)*/
        chip->myprivate_pcm_data
= kmalloc(..);
        /*設定析構函數(shù)*/
        pcm->private_data
= chip;
        pcm->private_free
= mychip_pcm_free;
        ....
    }


本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u1/49088/showart_1006030.html
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復

  

北京盛拓優(yōu)訊信息技術有限公司. 版權所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP