Android音频驱动-ASOC之PCM Open

来源:互联网 发布:象棋软件排行 编辑:程序博客网 时间:2024/05/20 02:23
status_t AudioALSAPlaybackHandlerBase::openPcmDriver(const unsigned int device){    mPcm = pcm_open(AudioALSADeviceParser::getInstance()->GetCardIndex(),                    device, PCM_OUT | PCM_MONOTONIC, &mConfig);    return NO_ERROR;}struct pcm *pcm_open(unsigned int card, unsigned int device,                     unsigned int flags, struct pcm_config *config){    struct pcm *pcm;    struct snd_pcm_info info;    struct snd_pcm_hw_params params;    struct snd_pcm_sw_params sparams;    char fn[256];    int rc;    pcm = calloc(1, sizeof(struct pcm));    pcm->config = *config;    snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device,             flags & PCM_IN ? 'c' : 'p');    pcm->flags = flags;    pcm->fd = open(fn, O_RDWR);    ......}//在创建alsa主设备时设置了文件操作对象,PCM设备都是alsa的从设备,共享一个驱动,打开次设备时会调用主设备的open函数/*static const struct file_operations snd_fops ={    .owner =    THIS_MODULE,    .open =     snd_open,    .llseek =   noop_llseek,};*/static int snd_open(struct inode *inode, struct file *file){    unsigned int minor = iminor(inode);    struct snd_minor *mptr = NULL;    const struct file_operations *new_fops;    int err = 0;    mptr = snd_minors[minor];    new_fops = fops_get(mptr->f_ops);    replace_fops(file, new_fops);    if (file->f_op->open)        err = file->f_op->open(inode, file);    return err;}//注册PCM设备时设置了PCM设备的文件操作对象/*const struct file_operations snd_pcm_f_ops[2] = {    {        .owner =        THIS_MODULE,        .write =        snd_pcm_write,        .aio_write =        snd_pcm_aio_write,        .open =         snd_pcm_playback_open,        .release =      snd_pcm_release,        .llseek =       no_llseek,        .poll =         snd_pcm_playback_poll,        .unlocked_ioctl =   snd_pcm_playback_ioctl,        .compat_ioctl =     snd_pcm_ioctl_compat,        .mmap =         snd_pcm_mmap,        .fasync =       snd_pcm_fasync,        .get_unmapped_area =    snd_pcm_get_unmapped_area,    },    {        .owner =        THIS_MODULE,        .read =         snd_pcm_read,        .aio_read =     snd_pcm_aio_read,        .open =         snd_pcm_capture_open,        .release =      snd_pcm_release,        .llseek =       no_llseek,        .poll =         snd_pcm_capture_poll,        .unlocked_ioctl =   snd_pcm_capture_ioctl,        .compat_ioctl =     snd_pcm_ioctl_compat,        .mmap =         snd_pcm_mmap,        .fasync =       snd_pcm_fasync,        .get_unmapped_area =    snd_pcm_get_unmapped_area,    }};*/static int snd_pcm_playback_open(struct inode *inode, struct file *file){    struct snd_pcm *pcm;    int err = nonseekable_open(inode, file);    pcm = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_PCM_PLAYBACK);    err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);    return err;}void *snd_lookup_minor_data(unsigned int minor, int type){    struct snd_minor *mreg;    void *private_data;    if (minor >= ARRAY_SIZE(snd_minors))        return NULL;    mreg = snd_minors[minor];    if (mreg && mreg->type == type) {        private_data = mreg->private_data;        if (private_data && mreg->card_ptr)            get_device(&mreg->card_ptr->card_dev);    } else        private_data = NULL;    return private_data;}static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream){    int err;    err = snd_card_file_add(pcm->card, file);//将file加入到card的files链表进行管理    while (1) {        err = snd_pcm_open_file(file, pcm, stream);    }    return err;}static int snd_pcm_open_file(struct file *file,                 struct snd_pcm *pcm,                 int stream){    struct snd_pcm_file *pcm_file;    struct snd_pcm_substream *substream;    int err;    err = snd_pcm_open_substream(pcm, stream, file, &substream);    pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);    pcm_file->substream = substream;//将打开的substream保存在pcm_file中    if (substream->ref_count == 1) {        substream->file = pcm_file;        substream->pcm_release = pcm_release_private;    }    file->private_data = pcm_file;//file获得打开的substream    return 0;}//打开pcm所属的substream,需要使用substream->ops操作函数int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,               struct file *file,               struct snd_pcm_substream **rsubstream){    struct snd_pcm_substream *substream;    int err;    err = snd_pcm_attach_substream(pcm, stream, file, &substream);//获取pcm的substream    err = snd_pcm_hw_constraints_init(substream);//初始化pcm硬件约束    if ((err = substream->ops->open(substream)) < 0)//调用substream的回调函数open        goto error;    substream->hw_opened = 1;    err = snd_pcm_hw_constraints_complete(substream);//设置pcm硬件约束    *rsubstream = substream;    return 0;}int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,                 struct file *file,                 struct snd_pcm_substream **rsubstream){    struct snd_pcm_str * pstr;    struct snd_pcm_substream *substream;    struct snd_pcm_runtime *runtime;    struct snd_ctl_file *kctl;    struct snd_card *card;    int prefer_subdevice = -1;    size_t size;    *rsubstream = NULL;    pstr = &pcm->streams[stream];    card = pcm->card;    list_for_each_entry(kctl, &card->ctl_files, list) {        if (kctl->pid == task_pid(current)) {            prefer_subdevice = kctl->prefer_pcm_subdevice;            if (prefer_subdevice != -1)                break;        }    }    switch (stream) {    case SNDRV_PCM_STREAM_PLAYBACK:        if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {            for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream;                  substream = substream->next) {                if (SUBSTREAM_BUSY(substream))                    return -EAGAIN;            }        }        break;    case SNDRV_PCM_STREAM_CAPTURE:        if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {            for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream;                  substream = substream->next) {                if (SUBSTREAM_BUSY(substream))                    return -EAGAIN;            }        }        break;    default:        return -EINVAL;    }    if (file->f_flags & O_APPEND) {        if (prefer_subdevice < 0) {            if (pstr->substream_count > 1)                return -EINVAL; /* must be unique */            substream = pstr->substream;        } else {            for (substream = pstr->substream; substream;                 substream = substream->next)                if (substream->number == prefer_subdevice)                    break;        }        substream->ref_count++;        *rsubstream = substream;        return 0;    }    if (prefer_subdevice >= 0) {        for (substream = pstr->substream; substream; substream = substream->next)            if (!SUBSTREAM_BUSY(substream) && substream->number == prefer_subdevice)                goto __ok;    }    for (substream = pstr->substream; substream; substream = substream->next)        if (!SUBSTREAM_BUSY(substream))            break;      __ok:    runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);    size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status));    runtime->status = snd_malloc_pages(size, GFP_KERNEL);    memset((void*)runtime->status, 0, size);    size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control));    runtime->control = snd_malloc_pages(size, GFP_KERNEL);    memset((void*)runtime->control, 0, size);    runtime->status->state = SNDRV_PCM_STATE_OPEN;    substream->runtime = runtime;    substream->private_data = pcm->private_data;    substream->ref_count = 1;    substream->pid = get_pid(task_pid(current));    pstr->substream_opened++;    *rsubstream = substream;    return 0;}

在创建pcm设备时已经调用snd_pcm_set_ops函数设置了substream->ops,在打开pcm的时候需要调用substream的ops->open函数

static int soc_pcm_open(struct snd_pcm_substream *substream){    struct snd_soc_pcm_runtime *rtd = substream->private_data;    struct snd_pcm_runtime *runtime = substream->runtime;    struct snd_soc_platform *platform = rtd->platform;    struct snd_soc_dai *cpu_dai = rtd->cpu_dai;    struct snd_soc_dai *codec_dai;    const char *codec_dai_name = "multicodec";    int i, ret = 0;    /* startup the audio subsystem */    if (cpu_dai->driver->ops && cpu_dai->driver->ops->startup) {        ret = cpu_dai->driver->ops->startup(substream, cpu_dai);//调用cpu dai driver的startup    }    if (platform->driver->ops && platform->driver->ops->open) {        ret = platform->driver->ops->open(substream);//调用platform driver的open    }    for (i = 0; i < rtd->num_codecs; i++) {        codec_dai = rtd->codec_dais[i];        if (codec_dai->driver->ops && codec_dai->driver->ops->startup) {            ret = codec_dai->driver->ops->startup(substream, codec_dai);//调用codec dai driver的startup        }    }    if (rtd->dai_link->ops && rtd->dai_link->ops->startup) {        ret = rtd->dai_link->ops->startup(substream);//调用dai link的startup,没有实现    }    /* Check that the codec and cpu DAIs are compatible */    soc_pcm_init_runtime_hw(substream);//检测codec和cup dai的兼容性    return ret;}

cpu dai driver、platform driver、codec dai driver的具体实现

static int multimedia_startup(struct snd_pcm_substream *substream,                  struct snd_soc_dai *dai){    snd_pcm_hw_constraint_list(substream->runtime, 0,                   SNDRV_PCM_HW_PARAM_RATE,                   &constraints_sample_rates);    return 0;}static int mtk_pcm_I2S0dl1_open(struct snd_pcm_substream *substream){    int ret = 0;    struct snd_pcm_runtime *runtime = substream->runtime;    AfeControlSramLock();    if (GetSramState() == SRAM_STATE_FREE) {        mtk_I2S0dl1_hardware.buffer_bytes_max = GetPLaybackSramFullSize();        mPlaybackSramState = SRAM_STATE_PLAYBACKFULL;        SetSramState(mPlaybackSramState);    } else {        mtk_I2S0dl1_hardware.buffer_bytes_max = GetPLaybackDramSize();        mPlaybackSramState = SRAM_STATE_PLAYBACKDRAM;    }    AfeControlSramUnLock();    if (mPlaybackSramState == SRAM_STATE_PLAYBACKDRAM)        AudDrv_Emi_Clk_On();    runtime->hw = mtk_I2S0dl1_hardware;    AudDrv_Clk_On();    memcpy((void *)(&(runtime->hw)), (void *)&mtk_I2S0dl1_hardware ,           sizeof(struct snd_pcm_hardware));    pI2S0dl1MemControl = Get_Mem_ControlT(Soc_Aud_Digital_Block_MEM_DL1);    ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,                     &constraints_sample_rates);    return 0;}static int mt63xx_codec_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *Daiport){    if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && substream->runtime->rate) {        mBlockSampleRate[AUDIO_ANALOG_DEVICE_IN_ADC] = substream->runtime->rate;    } else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && substream->runtime->rate) {        mBlockSampleRate[AUDIO_ANALOG_DEVICE_OUT_DAC] = substream->runtime->rate;    }    return 0;}
原创粉丝点击