zoukankan      html  css  js  c++  java
  • ALSA driver--PCM Interrupt handle

    PCM 中断处理函数的主要作用是用来更新buffer position.

    在PCM的interrupt handle里面通过snd_pcm_period_elapsed来通知alsa-core buffer position随着peroid的变化。

    在声卡中可以有几种类型的中断产生方式:

    1.每隔peroid就产生interupt

    在这种中断模式下,可以在每次中断是调用snd_pcm_peroid_elapsed. snd_pcm_peroid_elapsed以substream作为参数,因此我们必须要能够在芯片专用数据chip中能够访问到substream,在chip中保存当前正在running的substream.可以在PCM的open 函数中将substream保存到chip(chip作为PCM的private_data)中.

    典型的中断处理函数如下:

    static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id)
      {
              struct mychip *chip = dev_id;
              spin_lock(&chip->lock);
              ....
              if (pcm_irq_invoked(chip)) {
                      /* call updater, unlock before it */
                      spin_unlock(&chip->lock);
                      snd_pcm_period_elapsed(chip->substream);
                      spin_lock(&chip->lock);
                      /* acknowledge the interrupt if necessary */
              }
              ....
              spin_unlock(&chip->lock);
              return IRQ_HANDLED;
      }

    2.高频率时间中断(High frequency timer interrupts)

    高频率时间中断用在当硬件每隔固定的时间产生中断,而不是每隔peroid产生中断。我们必须在产生中断时检测hardware position,并计算处理的数据长度,当处理的数据长度超过peroid size时,就调用snd_pcm_peroid_elapsed。

      static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id)
      {
              struct mychip *chip = dev_id;
              spin_lock(&chip->lock);
              ....
              if (pcm_irq_invoked(chip)) {
                      unsigned int last_ptr, size;
                      /* get the current hardware pointer (in frames) */
                      last_ptr = get_hw_ptr(chip);
                      /* calculate the processed frames since the
                       * last update
                       */
                      if (last_ptr < chip->last_ptr)
                              size = runtime->buffer_size + last_ptr 
                                       - chip->last_ptr; 
                      else
                              size = last_ptr - chip->last_ptr;
                      /* remember the last updated point */
                      chip->last_ptr = last_ptr;
                      /* accumulate the size */
                      chip->size += size;
                      /* over the period boundary? */
                      if (chip->size >= runtime->period_size) {
                              /* reset the accumulator */
                              chip->size %= runtime->period_size;
                              /* call updater */
                              spin_unlock(&chip->lock);
                              snd_pcm_period_elapsed(substream);
                              spin_lock(&chip->lock);
                      }
                      /* acknowledge the interrupt if necessary */
              }
              ....
              spin_unlock(&chip->lock);
              return IRQ_HANDLED;
      }
    

    在上面两种中断方式中,如果硬件已经处理了多个peroid size的数据,我们只需要调用一次snd_pcm_peroid_elapsed,alsa core就会去检查hardware position 并更新到最新状态。

  • 相关阅读:
    [NOI2009]管道取珠 DP + 递推
    poj3207 Ikki's Story IV
    NOIP2016Day1T2天天爱跑步(LCA+桶)
    NOIP2016Day2T3愤怒的小鸟(状压dp) O(2^n*n^2)再优化
    NOIP2016Day1T3换教室(floyd+期望dp)
    bzoj1854: [Scoi2010]游戏(匈牙利) / GDKOI Day2 T2(最大流)
    [CodeVs4927]线段树练习5
    基数排序的奇技淫巧
    bzoj2724: [Violet 6]蒲公英(离散化+分块)
    bzoj1483: [HNOI2009]梦幻布丁(链表+启发式合并)
  • 原文地址:https://www.cnblogs.com/fellow1988/p/6200936.html
Copyright © 2011-2022 走看看