1<html><head><meta http-equiv="Content-Type" content="text/html; charset=ANSI_X3.4-1968"><title>Interrupt Handler</title><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="index.html" title="Writing an ALSA Driver"><link rel="up" href="pcm-interface.html" title="Chapter 5. PCM Interface"><link rel="prev" href="pcm-interface-operators.html" title="Operators"><link rel="next" href="pcm-interface-atomicity.html" title="Atomicity"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Interrupt Handler</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="pcm-interface-operators.html">Prev</a> </td><th width="60%" align="center">Chapter 5. PCM Interface</th><td width="20%" align="right"> <a accesskey="n" href="pcm-interface-atomicity.html">Next</a></td></tr></table><hr></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="pcm-interface-interrupt-handler"></a>Interrupt Handler</h2></div></div></div><div class="toc"><dl class="toc"><dt><span class="section"><a href="pcm-interface-interrupt-handler.html#pcm-interface-interrupt-handler-boundary">Interrupts at the period (fragment) boundary</a></span></dt><dt><span class="section"><a href="pcm-interface-interrupt-handler.html#pcm-interface-interrupt-handler-timer">High frequency timer interrupts</a></span></dt><dt><span class="section"><a href="pcm-interface-interrupt-handler.html#pcm-interface-interrupt-handler-both">On calling <code class="function">snd_pcm_period_elapsed()</code></a></span></dt></dl></div><p> 2 The rest of pcm stuff is the PCM interrupt handler. The 3 role of PCM interrupt handler in the sound driver is to update 4 the buffer position and to tell the PCM middle layer when the 5 buffer position goes across the prescribed period size. To 6 inform this, call the <code class="function">snd_pcm_period_elapsed()</code> 7 function. 8 </p><p> 9 There are several types of sound chips to generate the interrupts. 10 </p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="pcm-interface-interrupt-handler-boundary"></a>Interrupts at the period (fragment) boundary</h3></div></div></div><p> 11 This is the most frequently found type: the hardware 12 generates an interrupt at each period boundary. 13 In this case, you can call 14 <code class="function">snd_pcm_period_elapsed()</code> at each 15 interrupt. 16 </p><p> 17 <code class="function">snd_pcm_period_elapsed()</code> takes the 18 substream pointer as its argument. Thus, you need to keep the 19 substream pointer accessible from the chip instance. For 20 example, define substream field in the chip record to hold the 21 current running substream pointer, and set the pointer value 22 at open callback (and reset at close callback). 23 </p><p> 24 If you acquire a spinlock in the interrupt handler, and the 25 lock is used in other pcm callbacks, too, then you have to 26 release the lock before calling 27 <code class="function">snd_pcm_period_elapsed()</code>, because 28 <code class="function">snd_pcm_period_elapsed()</code> calls other pcm 29 callbacks inside. 30 </p><p> 31 Typical code would be like: 32 33 </p><div class="example"><a name="idp1094132124"></a><p class="title"><b>Example 5.3. Interrupt Handler Case #1</b></p><div class="example-contents"><pre class="programlisting"> 34 35 static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id) 36 { 37 struct mychip *chip = dev_id; 38 spin_lock(&chip->lock); 39 .... 40 if (pcm_irq_invoked(chip)) { 41 /* call updater, unlock before it */ 42 spin_unlock(&chip->lock); 43 snd_pcm_period_elapsed(chip->substream); 44 spin_lock(&chip->lock); 45 /* acknowledge the interrupt if necessary */ 46 } 47 .... 48 spin_unlock(&chip->lock); 49 return IRQ_HANDLED; 50 } 51 52 </pre></div></div><p><br class="example-break"> 53 </p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="pcm-interface-interrupt-handler-timer"></a>High frequency timer interrupts</h3></div></div></div><p> 54 This happens when the hardware doesn't generate interrupts 55 at the period boundary but issues timer interrupts at a fixed 56 timer rate (e.g. es1968 or ymfpci drivers). 57 In this case, you need to check the current hardware 58 position and accumulate the processed sample length at each 59 interrupt. When the accumulated size exceeds the period 60 size, call 61 <code class="function">snd_pcm_period_elapsed()</code> and reset the 62 accumulator. 63 </p><p> 64 Typical code would be like the following. 65 66 </p><div class="example"><a name="idp1094135868"></a><p class="title"><b>Example 5.4. Interrupt Handler Case #2</b></p><div class="example-contents"><pre class="programlisting"> 67 68 static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id) 69 { 70 struct mychip *chip = dev_id; 71 spin_lock(&chip->lock); 72 .... 73 if (pcm_irq_invoked(chip)) { 74 unsigned int last_ptr, size; 75 /* get the current hardware pointer (in frames) */ 76 last_ptr = get_hw_ptr(chip); 77 /* calculate the processed frames since the 78 * last update 79 */ 80 if (last_ptr < chip->last_ptr) 81 size = runtime->buffer_size + last_ptr 82 - chip->last_ptr; 83 else 84 size = last_ptr - chip->last_ptr; 85 /* remember the last updated point */ 86 chip->last_ptr = last_ptr; 87 /* accumulate the size */ 88 chip->size += size; 89 /* over the period boundary? */ 90 if (chip->size >= runtime->period_size) { 91 /* reset the accumulator */ 92 chip->size %= runtime->period_size; 93 /* call updater */ 94 spin_unlock(&chip->lock); 95 snd_pcm_period_elapsed(substream); 96 spin_lock(&chip->lock); 97 } 98 /* acknowledge the interrupt if necessary */ 99 } 100 .... 101 spin_unlock(&chip->lock); 102 return IRQ_HANDLED; 103 } 104 105 </pre></div></div><p><br class="example-break"> 106 </p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="pcm-interface-interrupt-handler-both"></a>On calling <code class="function">snd_pcm_period_elapsed()</code></h3></div></div></div><p> 107 In both cases, even if more than one period are elapsed, you 108 don't have to call 109 <code class="function">snd_pcm_period_elapsed()</code> many times. Call 110 only once. And the pcm layer will check the current hardware 111 pointer and update to the latest status. 112 </p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="pcm-interface-operators.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="pcm-interface.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="pcm-interface-atomicity.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Operators </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Atomicity</td></tr></table></div></body></html> 113