1<html><head><meta http-equiv="Content-Type" content="text/html; charset=ANSI_X3.4-1968"><title>Chapter&#160;13.&#160;Power Management</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="index.html" title="Writing an ALSA Driver"><link rel="prev" href="proc-interface.html" title="Chapter&#160;12.&#160;Proc Interface"><link rel="next" href="module-parameters.html" title="Chapter&#160;14.&#160;Module Parameters"></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">Chapter&#160;13.&#160;Power Management</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="proc-interface.html">Prev</a>&#160;</td><th width="60%" align="center">&#160;</th><td width="20%" align="right">&#160;<a accesskey="n" href="module-parameters.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="power-management"></a>Chapter&#160;13.&#160;Power Management</h1></div></div></div><p>
2      If the chip is supposed to work with suspend/resume
3      functions, you need to add power-management code to the
4      driver. The additional code for power-management should be
5      <code class="function">ifdef</code>'ed with
6      <code class="constant">CONFIG_PM</code>. 
7    </p><p>
8	If the driver <span class="emphasis"><em>fully</em></span> supports suspend/resume
9	that is, the device can be
10	properly resumed to its state when suspend was called,
11	you can set the <code class="constant">SNDRV_PCM_INFO_RESUME</code> flag
12	in the pcm info field.  Usually, this is possible when the
13	registers of the chip can be safely saved and restored to
14	RAM. If this is set, the trigger callback is called with
15	<code class="constant">SNDRV_PCM_TRIGGER_RESUME</code> after the resume
16	callback completes. 
17	</p><p>
18	Even if the driver doesn't support PM fully but 
19	partial suspend/resume is still possible, it's still worthy to
20	implement suspend/resume callbacks. In such a case, applications
21	would reset the status by calling
22	<code class="function">snd_pcm_prepare()</code> and restart the stream
23	appropriately.  Hence, you can define suspend/resume callbacks
24	below but don't set <code class="constant">SNDRV_PCM_INFO_RESUME</code>
25	info flag to the PCM.
26	</p><p>
27	Note that the trigger with SUSPEND can always be called when
28	<code class="function">snd_pcm_suspend_all</code> is called,
29	regardless of the <code class="constant">SNDRV_PCM_INFO_RESUME</code> flag.
30	The <code class="constant">RESUME</code> flag affects only the behavior
31	of <code class="function">snd_pcm_resume()</code>.
32	(Thus, in theory,
33	<code class="constant">SNDRV_PCM_TRIGGER_RESUME</code> isn't needed
34	to be handled in the trigger callback when no
35	<code class="constant">SNDRV_PCM_INFO_RESUME</code> flag is set.  But,
36	it's better to keep it for compatibility reasons.)
37	</p><p>
38      In the earlier version of ALSA drivers, a common
39      power-management layer was provided, but it has been removed.
40      The driver needs to define the suspend/resume hooks according to
41      the bus the device is connected to.  In the case of PCI drivers, the
42      callbacks look like below:
43
44      </p><div class="informalexample"><pre class="programlisting">
45
46  #ifdef CONFIG_PM
47  static int snd_my_suspend(struct pci_dev *pci, pm_message_t state)
48  {
49          .... /* do things for suspend */
50          return 0;
51  }
52  static int snd_my_resume(struct pci_dev *pci)
53  {
54          .... /* do things for suspend */
55          return 0;
56  }
57  #endif
58
59        </pre></div><p>
60    </p><p>
61      The scheme of the real suspend job is as follows.
62
63      </p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>Retrieve the card and the chip data.</p></li><li class="listitem"><p>Call <code class="function">snd_power_change_state()</code> with
64	  <code class="constant">SNDRV_CTL_POWER_D3hot</code> to change the
65	  power status.</p></li><li class="listitem"><p>Call <code class="function">snd_pcm_suspend_all()</code> to suspend the running PCM streams.</p></li><li class="listitem"><p>If AC97 codecs are used, call
66	<code class="function">snd_ac97_suspend()</code> for each codec.</p></li><li class="listitem"><p>Save the register values if necessary.</p></li><li class="listitem"><p>Stop the hardware if necessary.</p></li><li class="listitem"><p>Disable the PCI device by calling
67	  <code class="function">pci_disable_device()</code>.  Then, call
68          <code class="function">pci_save_state()</code> at last.</p></li></ol></div><p>
69    </p><p>
70      A typical code would be like:
71
72      </p><div class="informalexample"><pre class="programlisting">
73
74  static int mychip_suspend(struct pci_dev *pci, pm_message_t state)
75  {
76          /* (1) */
77          struct snd_card *card = pci_get_drvdata(pci);
78          struct mychip *chip = card-&gt;private_data;
79          /* (2) */
80          snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
81          /* (3) */
82          snd_pcm_suspend_all(chip-&gt;pcm);
83          /* (4) */
84          snd_ac97_suspend(chip-&gt;ac97);
85          /* (5) */
86          snd_mychip_save_registers(chip);
87          /* (6) */
88          snd_mychip_stop_hardware(chip);
89          /* (7) */
90          pci_disable_device(pci);
91          pci_save_state(pci);
92          return 0;
93  }
94
95        </pre></div><p>
96    </p><p>
97    The scheme of the real resume job is as follows.
98
99    </p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>Retrieve the card and the chip data.</p></li><li class="listitem"><p>Set up PCI. First, call <code class="function">pci_restore_state()</code>.
100    	Then enable the pci device again by calling <code class="function">pci_enable_device()</code>.
101	Call <code class="function">pci_set_master()</code> if necessary, too.</p></li><li class="listitem"><p>Re-initialize the chip.</p></li><li class="listitem"><p>Restore the saved registers if necessary.</p></li><li class="listitem"><p>Resume the mixer, e.g. calling
102    <code class="function">snd_ac97_resume()</code>.</p></li><li class="listitem"><p>Restart the hardware (if any).</p></li><li class="listitem"><p>Call <code class="function">snd_power_change_state()</code> with
103	<code class="constant">SNDRV_CTL_POWER_D0</code> to notify the processes.</p></li></ol></div><p>
104    </p><p>
105    A typical code would be like:
106
107      </p><div class="informalexample"><pre class="programlisting">
108
109  static int mychip_resume(struct pci_dev *pci)
110  {
111          /* (1) */
112          struct snd_card *card = pci_get_drvdata(pci);
113          struct mychip *chip = card-&gt;private_data;
114          /* (2) */
115          pci_restore_state(pci);
116          pci_enable_device(pci);
117          pci_set_master(pci);
118          /* (3) */
119          snd_mychip_reinit_chip(chip);
120          /* (4) */
121          snd_mychip_restore_registers(chip);
122          /* (5) */
123          snd_ac97_resume(chip-&gt;ac97);
124          /* (6) */
125          snd_mychip_restart_chip(chip);
126          /* (7) */
127          snd_power_change_state(card, SNDRV_CTL_POWER_D0);
128          return 0;
129  }
130
131        </pre></div><p>
132    </p><p>
133	As shown in the above, it's better to save registers after
134	suspending the PCM operations via
135	<code class="function">snd_pcm_suspend_all()</code> or
136	<code class="function">snd_pcm_suspend()</code>.  It means that the PCM
137	streams are already stopped when the register snapshot is
138	taken.  But, remember that you don't have to restart the PCM
139	stream in the resume callback. It'll be restarted via 
140	trigger call with <code class="constant">SNDRV_PCM_TRIGGER_RESUME</code>
141	when necessary.
142    </p><p>
143      OK, we have all callbacks now. Let's set them up. In the
144      initialization of the card, make sure that you can get the chip
145      data from the card instance, typically via
146      <em class="structfield"><code>private_data</code></em> field, in case you
147      created the chip data individually.
148
149      </p><div class="informalexample"><pre class="programlisting">
150
151  static int snd_mychip_probe(struct pci_dev *pci,
152                              const struct pci_device_id *pci_id)
153  {
154          ....
155          struct snd_card *card;
156          struct mychip *chip;
157          int err;
158          ....
159          err = snd_card_new(&amp;pci-&gt;dev, index[dev], id[dev], THIS_MODULE,
160                             0, &amp;card);
161          ....
162          chip = kzalloc(sizeof(*chip), GFP_KERNEL);
163          ....
164          card-&gt;private_data = chip;
165          ....
166  }
167
168        </pre></div><p>
169
170	When you created the chip data with
171	<code class="function">snd_card_new()</code>, it's anyway accessible
172	via <em class="structfield"><code>private_data</code></em> field.
173
174      </p><div class="informalexample"><pre class="programlisting">
175
176  static int snd_mychip_probe(struct pci_dev *pci,
177                              const struct pci_device_id *pci_id)
178  {
179          ....
180          struct snd_card *card;
181          struct mychip *chip;
182          int err;
183          ....
184          err = snd_card_new(&amp;pci-&gt;dev, index[dev], id[dev], THIS_MODULE,
185                             sizeof(struct mychip), &amp;card);
186          ....
187          chip = card-&gt;private_data;
188          ....
189  }
190
191        </pre></div><p>
192
193    </p><p>
194      If you need a space to save the registers, allocate the
195	buffer for it here, too, since it would be fatal
196    if you cannot allocate a memory in the suspend phase.
197    The allocated buffer should be released in the corresponding
198    destructor.
199    </p><p>
200      And next, set suspend/resume callbacks to the pci_driver.
201
202      </p><div class="informalexample"><pre class="programlisting">
203
204  static struct pci_driver driver = {
205          .name = KBUILD_MODNAME,
206          .id_table = snd_my_ids,
207          .probe = snd_my_probe,
208          .remove = snd_my_remove,
209  #ifdef CONFIG_PM
210          .suspend = snd_my_suspend,
211          .resume = snd_my_resume,
212  #endif
213  };
214
215        </pre></div><p>
216    </p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="proc-interface.html">Prev</a>&#160;</td><td width="20%" align="center">&#160;</td><td width="40%" align="right">&#160;<a accesskey="n" href="module-parameters.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter&#160;12.&#160;Proc Interface&#160;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&#160;Chapter&#160;14.&#160;Module Parameters</td></tr></table></div></body></html>
217