Commit 6a0f4021469727675b83d85ac91d106bfae0e2c3

Authored by Takashi Iwai

Merge branch 'topic/dummy' into for-linus

* topic/dummy:
  ALSA: dummy - Increase MAX_PCM_SUBSTREAMS to 128
  ALSA: dummy - Add debug proc file
  ALSA: Add const prefix to proc helper functions
  ALSA: Re-export snd_pcm_format_name() function
  ALSA: dummy - Fake buffer allocations
  ALSA: dummy - Fix the timer calculation in systimer mode
  ALSA: dummy - Add more description
  ALSA: dummy - Better jiffies handling
  ALSA: dummy - Support high-res timer mode

Showing 9 changed files Side-by-side Diff

Documentation/sound/alsa/ALSA-Configuration.txt
... ... @@ -513,6 +513,26 @@
513 513 or input, but you may use this module for any application which
514 514 requires a sound card (like RealPlayer).
515 515  
  516 + pcm_devs - Number of PCM devices assigned to each card
  517 + (default = 1, up to 4)
  518 + pcm_substreams - Number of PCM substreams assigned to each PCM
  519 + (default = 8, up to 16)
  520 + hrtimer - Use hrtimer (=1, default) or system timer (=0)
  521 + fake_buffer - Fake buffer allocations (default = 1)
  522 +
  523 + When multiple PCM devices are created, snd-dummy gives different
  524 + behavior to each PCM device:
  525 + 0 = interleaved with mmap support
  526 + 1 = non-interleaved with mmap support
  527 + 2 = interleaved without mmap
  528 + 3 = non-interleaved without mmap
  529 +
  530 + As default, snd-dummy drivers doesn't allocate the real buffers
  531 + but either ignores read/write or mmap a single dummy page to all
  532 + buffer pages, in order to save the resouces. If your apps need
  533 + the read/ written buffer data to be consistent, pass fake_buffer=0
  534 + option.
  535 +
516 536 The power-management is supported.
517 537  
518 538 Module snd-echo3g
include/sound/info.h
... ... @@ -110,13 +110,13 @@
110 110 static inline void snd_card_info_read_oss(struct snd_info_buffer *buffer) {}
111 111 #endif
112 112  
113   -int snd_iprintf(struct snd_info_buffer *buffer, char *fmt, ...) \
  113 +int snd_iprintf(struct snd_info_buffer *buffer, const char *fmt, ...) \
114 114 __attribute__ ((format (printf, 2, 3)));
115 115 int snd_info_init(void);
116 116 int snd_info_done(void);
117 117  
118 118 int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len);
119   -char *snd_info_get_str(char *dest, char *src, int len);
  119 +const char *snd_info_get_str(char *dest, const char *src, int len);
120 120 struct snd_info_entry *snd_info_create_module_entry(struct module *module,
121 121 const char *name,
122 122 struct snd_info_entry *parent);
... ... @@ -988,5 +988,7 @@
988 988  
989 989 #define PCM_RUNTIME_CHECK(sub) snd_BUG_ON(!(sub) || !(sub)->runtime)
990 990  
  991 +const char *snd_pcm_format_name(snd_pcm_format_t format);
  992 +
991 993 #endif /* __SOUND_PCM_H */
... ... @@ -106,7 +106,7 @@
106 106 *
107 107 * Returns the size of output string.
108 108 */
109   -int snd_iprintf(struct snd_info_buffer *buffer, char *fmt,...)
  109 +int snd_iprintf(struct snd_info_buffer *buffer, const char *fmt, ...)
110 110 {
111 111 va_list args;
112 112 int len, res;
... ... @@ -725,7 +725,7 @@
725 725 * Returns the updated pointer of the original string so that
726 726 * it can be used for the next call.
727 727 */
728   -char *snd_info_get_str(char *dest, char *src, int len)
  728 +const char *snd_info_get_str(char *dest, const char *src, int len)
729 729 {
730 730 int c;
731 731  
sound/core/oss/mixer_oss.c
... ... @@ -1154,7 +1154,8 @@
1154 1154 struct snd_info_buffer *buffer)
1155 1155 {
1156 1156 struct snd_mixer_oss *mixer = entry->private_data;
1157   - char line[128], str[32], idxstr[16], *cptr;
  1157 + char line[128], str[32], idxstr[16];
  1158 + const char *cptr;
1158 1159 int ch, idx;
1159 1160 struct snd_mixer_oss_assign_table *tbl;
1160 1161 struct slot *slot;
sound/core/oss/pcm_oss.c
... ... @@ -2836,7 +2836,8 @@
2836 2836 struct snd_info_buffer *buffer)
2837 2837 {
2838 2838 struct snd_pcm_str *pstr = entry->private_data;
2839   - char line[128], str[32], task_name[32], *ptr;
  2839 + char line[128], str[32], task_name[32];
  2840 + const char *ptr;
2840 2841 int idx1;
2841 2842 struct snd_pcm_oss_setup *setup, *setup1, template;
2842 2843  
... ... @@ -162,18 +162,7 @@
162 162 return -ENOIOCTLCMD;
163 163 }
164 164  
165   -#ifdef CONFIG_SND_VERBOSE_PROCFS
166   -
167   -#define STATE(v) [SNDRV_PCM_STATE_##v] = #v
168   -#define STREAM(v) [SNDRV_PCM_STREAM_##v] = #v
169   -#define READY(v) [SNDRV_PCM_READY_##v] = #v
170   -#define XRUN(v) [SNDRV_PCM_XRUN_##v] = #v
171   -#define SILENCE(v) [SNDRV_PCM_SILENCE_##v] = #v
172   -#define TSTAMP(v) [SNDRV_PCM_TSTAMP_##v] = #v
173   -#define ACCESS(v) [SNDRV_PCM_ACCESS_##v] = #v
174   -#define START(v) [SNDRV_PCM_START_##v] = #v
175 165 #define FORMAT(v) [SNDRV_PCM_FORMAT_##v] = #v
176   -#define SUBFORMAT(v) [SNDRV_PCM_SUBFORMAT_##v] = #v
177 166  
178 167 static char *snd_pcm_format_names[] = {
179 168 FORMAT(S8),
180 169  
... ... @@ -216,10 +205,23 @@
216 205 FORMAT(U18_3BE),
217 206 };
218 207  
219   -static const char *snd_pcm_format_name(snd_pcm_format_t format)
  208 +const char *snd_pcm_format_name(snd_pcm_format_t format)
220 209 {
221 210 return snd_pcm_format_names[format];
222 211 }
  212 +EXPORT_SYMBOL_GPL(snd_pcm_format_name);
  213 +
  214 +#ifdef CONFIG_SND_VERBOSE_PROCFS
  215 +
  216 +#define STATE(v) [SNDRV_PCM_STATE_##v] = #v
  217 +#define STREAM(v) [SNDRV_PCM_STREAM_##v] = #v
  218 +#define READY(v) [SNDRV_PCM_READY_##v] = #v
  219 +#define XRUN(v) [SNDRV_PCM_XRUN_##v] = #v
  220 +#define SILENCE(v) [SNDRV_PCM_SILENCE_##v] = #v
  221 +#define TSTAMP(v) [SNDRV_PCM_TSTAMP_##v] = #v
  222 +#define ACCESS(v) [SNDRV_PCM_ACCESS_##v] = #v
  223 +#define START(v) [SNDRV_PCM_START_##v] = #v
  224 +#define SUBFORMAT(v) [SNDRV_PCM_SUBFORMAT_##v] = #v
223 225  
224 226 static char *snd_pcm_stream_names[] = {
225 227 STREAM(PLAYBACK),
sound/drivers/dummy.c
... ... @@ -25,12 +25,15 @@
25 25 #include <linux/slab.h>
26 26 #include <linux/time.h>
27 27 #include <linux/wait.h>
  28 +#include <linux/hrtimer.h>
  29 +#include <linux/math64.h>
28 30 #include <linux/moduleparam.h>
29 31 #include <sound/core.h>
30 32 #include <sound/control.h>
31 33 #include <sound/tlv.h>
32 34 #include <sound/pcm.h>
33 35 #include <sound/rawmidi.h>
  36 +#include <sound/info.h>
34 37 #include <sound/initval.h>
35 38  
36 39 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
... ... @@ -39,7 +42,7 @@
39 42 MODULE_SUPPORTED_DEVICE("{{ALSA,Dummy soundcard}}");
40 43  
41 44 #define MAX_PCM_DEVICES 4
42   -#define MAX_PCM_SUBSTREAMS 16
  45 +#define MAX_PCM_SUBSTREAMS 128
43 46 #define MAX_MIDI_DEVICES 2
44 47  
45 48 #if 0 /* emu10k1 emulation */
... ... @@ -148,6 +151,10 @@
148 151 static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
149 152 static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};
150 153 //static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
  154 +#ifdef CONFIG_HIGH_RES_TIMERS
  155 +static int hrtimer = 1;
  156 +#endif
  157 +static int fake_buffer = 1;
151 158  
152 159 module_param_array(index, int, NULL, 0444);
153 160 MODULE_PARM_DESC(index, "Index value for dummy soundcard.");
... ... @@ -161,6 +168,12 @@
161 168 MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-16) for dummy driver.");
162 169 //module_param_array(midi_devs, int, NULL, 0444);
163 170 //MODULE_PARM_DESC(midi_devs, "MIDI devices # (0-2) for dummy driver.");
  171 +module_param(fake_buffer, bool, 0444);
  172 +MODULE_PARM_DESC(fake_buffer, "Fake buffer allocations.");
  173 +#ifdef CONFIG_HIGH_RES_TIMERS
  174 +module_param(hrtimer, bool, 0644);
  175 +MODULE_PARM_DESC(hrtimer, "Use hrtimer as the timer source.");
  176 +#endif
164 177  
165 178 static struct platform_device *devices[SNDRV_CARDS];
166 179  
167 180  
168 181  
169 182  
170 183  
171 184  
172 185  
173 186  
174 187  
175 188  
176 189  
177 190  
178 191  
179 192  
180 193  
181 194  
182 195  
183 196  
184 197  
185 198  
186 199  
187 200  
188 201  
189 202  
190 203  
191 204  
192 205  
193 206  
194 207  
... ... @@ -171,137 +184,324 @@
171 184 #define MIXER_ADDR_CD 4
172 185 #define MIXER_ADDR_LAST 4
173 186  
  187 +struct dummy_timer_ops {
  188 + int (*create)(struct snd_pcm_substream *);
  189 + void (*free)(struct snd_pcm_substream *);
  190 + int (*prepare)(struct snd_pcm_substream *);
  191 + int (*start)(struct snd_pcm_substream *);
  192 + int (*stop)(struct snd_pcm_substream *);
  193 + snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *);
  194 +};
  195 +
174 196 struct snd_dummy {
175 197 struct snd_card *card;
176 198 struct snd_pcm *pcm;
177 199 spinlock_t mixer_lock;
178 200 int mixer_volume[MIXER_ADDR_LAST+1][2];
179 201 int capture_source[MIXER_ADDR_LAST+1][2];
  202 + const struct dummy_timer_ops *timer_ops;
180 203 };
181 204  
182   -struct snd_dummy_pcm {
183   - struct snd_dummy *dummy;
  205 +/*
  206 + * system timer interface
  207 + */
  208 +
  209 +struct dummy_systimer_pcm {
184 210 spinlock_t lock;
185 211 struct timer_list timer;
186   - unsigned int pcm_buffer_size;
187   - unsigned int pcm_period_size;
188   - unsigned int pcm_bps; /* bytes per second */
189   - unsigned int pcm_hz; /* HZ */
190   - unsigned int pcm_irq_pos; /* IRQ position */
191   - unsigned int pcm_buf_pos; /* position in buffer */
  212 + unsigned long base_time;
  213 + unsigned int frac_pos; /* fractional sample position (based HZ) */
  214 + unsigned int frac_period_rest;
  215 + unsigned int frac_buffer_size; /* buffer_size * HZ */
  216 + unsigned int frac_period_size; /* period_size * HZ */
  217 + unsigned int rate;
  218 + int elapsed;
192 219 struct snd_pcm_substream *substream;
193 220 };
194 221  
195   -
196   -static inline void snd_card_dummy_pcm_timer_start(struct snd_dummy_pcm *dpcm)
  222 +static void dummy_systimer_rearm(struct dummy_systimer_pcm *dpcm)
197 223 {
198   - dpcm->timer.expires = 1 + jiffies;
  224 + dpcm->timer.expires = jiffies +
  225 + (dpcm->frac_period_rest + dpcm->rate - 1) / dpcm->rate;
199 226 add_timer(&dpcm->timer);
200 227 }
201 228  
202   -static inline void snd_card_dummy_pcm_timer_stop(struct snd_dummy_pcm *dpcm)
  229 +static void dummy_systimer_update(struct dummy_systimer_pcm *dpcm)
203 230 {
204   - del_timer(&dpcm->timer);
  231 + unsigned long delta;
  232 +
  233 + delta = jiffies - dpcm->base_time;
  234 + if (!delta)
  235 + return;
  236 + dpcm->base_time += delta;
  237 + delta *= dpcm->rate;
  238 + dpcm->frac_pos += delta;
  239 + while (dpcm->frac_pos >= dpcm->frac_buffer_size)
  240 + dpcm->frac_pos -= dpcm->frac_buffer_size;
  241 + while (dpcm->frac_period_rest <= delta) {
  242 + dpcm->elapsed++;
  243 + dpcm->frac_period_rest += dpcm->frac_period_size;
  244 + }
  245 + dpcm->frac_period_rest -= delta;
205 246 }
206 247  
207   -static int snd_card_dummy_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
  248 +static int dummy_systimer_start(struct snd_pcm_substream *substream)
208 249 {
209   - struct snd_pcm_runtime *runtime = substream->runtime;
210   - struct snd_dummy_pcm *dpcm = runtime->private_data;
211   - int err = 0;
  250 + struct dummy_systimer_pcm *dpcm = substream->runtime->private_data;
  251 + spin_lock(&dpcm->lock);
  252 + dpcm->base_time = jiffies;
  253 + dummy_systimer_rearm(dpcm);
  254 + spin_unlock(&dpcm->lock);
  255 + return 0;
  256 +}
212 257  
  258 +static int dummy_systimer_stop(struct snd_pcm_substream *substream)
  259 +{
  260 + struct dummy_systimer_pcm *dpcm = substream->runtime->private_data;
213 261 spin_lock(&dpcm->lock);
214   - switch (cmd) {
215   - case SNDRV_PCM_TRIGGER_START:
216   - case SNDRV_PCM_TRIGGER_RESUME:
217   - snd_card_dummy_pcm_timer_start(dpcm);
218   - break;
219   - case SNDRV_PCM_TRIGGER_STOP:
220   - case SNDRV_PCM_TRIGGER_SUSPEND:
221   - snd_card_dummy_pcm_timer_stop(dpcm);
222   - break;
223   - default:
224   - err = -EINVAL;
225   - break;
226   - }
  262 + del_timer(&dpcm->timer);
227 263 spin_unlock(&dpcm->lock);
228 264 return 0;
229 265 }
230 266  
231   -static int snd_card_dummy_pcm_prepare(struct snd_pcm_substream *substream)
  267 +static int dummy_systimer_prepare(struct snd_pcm_substream *substream)
232 268 {
233 269 struct snd_pcm_runtime *runtime = substream->runtime;
234   - struct snd_dummy_pcm *dpcm = runtime->private_data;
235   - int bps;
  270 + struct dummy_systimer_pcm *dpcm = runtime->private_data;
236 271  
237   - bps = snd_pcm_format_width(runtime->format) * runtime->rate *
238   - runtime->channels / 8;
  272 + dpcm->frac_pos = 0;
  273 + dpcm->rate = runtime->rate;
  274 + dpcm->frac_buffer_size = runtime->buffer_size * HZ;
  275 + dpcm->frac_period_size = runtime->period_size * HZ;
  276 + dpcm->frac_period_rest = dpcm->frac_period_size;
  277 + dpcm->elapsed = 0;
239 278  
240   - if (bps <= 0)
241   - return -EINVAL;
242   -
243   - dpcm->pcm_bps = bps;
244   - dpcm->pcm_hz = HZ;
245   - dpcm->pcm_buffer_size = snd_pcm_lib_buffer_bytes(substream);
246   - dpcm->pcm_period_size = snd_pcm_lib_period_bytes(substream);
247   - dpcm->pcm_irq_pos = 0;
248   - dpcm->pcm_buf_pos = 0;
249   -
250   - snd_pcm_format_set_silence(runtime->format, runtime->dma_area,
251   - bytes_to_samples(runtime, runtime->dma_bytes));
252   -
253 279 return 0;
254 280 }
255 281  
256   -static void snd_card_dummy_pcm_timer_function(unsigned long data)
  282 +static void dummy_systimer_callback(unsigned long data)
257 283 {
258   - struct snd_dummy_pcm *dpcm = (struct snd_dummy_pcm *)data;
  284 + struct dummy_systimer_pcm *dpcm = (struct dummy_systimer_pcm *)data;
259 285 unsigned long flags;
  286 + int elapsed = 0;
260 287  
261 288 spin_lock_irqsave(&dpcm->lock, flags);
262   - dpcm->timer.expires = 1 + jiffies;
263   - add_timer(&dpcm->timer);
264   - dpcm->pcm_irq_pos += dpcm->pcm_bps;
265   - dpcm->pcm_buf_pos += dpcm->pcm_bps;
266   - dpcm->pcm_buf_pos %= dpcm->pcm_buffer_size * dpcm->pcm_hz;
267   - if (dpcm->pcm_irq_pos >= dpcm->pcm_period_size * dpcm->pcm_hz) {
268   - dpcm->pcm_irq_pos %= dpcm->pcm_period_size * dpcm->pcm_hz;
269   - spin_unlock_irqrestore(&dpcm->lock, flags);
  289 + dummy_systimer_update(dpcm);
  290 + dummy_systimer_rearm(dpcm);
  291 + elapsed = dpcm->elapsed;
  292 + dpcm->elapsed = 0;
  293 + spin_unlock_irqrestore(&dpcm->lock, flags);
  294 + if (elapsed)
270 295 snd_pcm_period_elapsed(dpcm->substream);
271   - } else
272   - spin_unlock_irqrestore(&dpcm->lock, flags);
273 296 }
274 297  
275   -static snd_pcm_uframes_t snd_card_dummy_pcm_pointer(struct snd_pcm_substream *substream)
  298 +static snd_pcm_uframes_t
  299 +dummy_systimer_pointer(struct snd_pcm_substream *substream)
276 300 {
  301 + struct dummy_systimer_pcm *dpcm = substream->runtime->private_data;
  302 + snd_pcm_uframes_t pos;
  303 +
  304 + spin_lock(&dpcm->lock);
  305 + dummy_systimer_update(dpcm);
  306 + pos = dpcm->frac_pos / HZ;
  307 + spin_unlock(&dpcm->lock);
  308 + return pos;
  309 +}
  310 +
  311 +static int dummy_systimer_create(struct snd_pcm_substream *substream)
  312 +{
  313 + struct dummy_systimer_pcm *dpcm;
  314 +
  315 + dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
  316 + if (!dpcm)
  317 + return -ENOMEM;
  318 + substream->runtime->private_data = dpcm;
  319 + init_timer(&dpcm->timer);
  320 + dpcm->timer.data = (unsigned long) dpcm;
  321 + dpcm->timer.function = dummy_systimer_callback;
  322 + spin_lock_init(&dpcm->lock);
  323 + dpcm->substream = substream;
  324 + return 0;
  325 +}
  326 +
  327 +static void dummy_systimer_free(struct snd_pcm_substream *substream)
  328 +{
  329 + kfree(substream->runtime->private_data);
  330 +}
  331 +
  332 +static struct dummy_timer_ops dummy_systimer_ops = {
  333 + .create = dummy_systimer_create,
  334 + .free = dummy_systimer_free,
  335 + .prepare = dummy_systimer_prepare,
  336 + .start = dummy_systimer_start,
  337 + .stop = dummy_systimer_stop,
  338 + .pointer = dummy_systimer_pointer,
  339 +};
  340 +
  341 +#ifdef CONFIG_HIGH_RES_TIMERS
  342 +/*
  343 + * hrtimer interface
  344 + */
  345 +
  346 +struct dummy_hrtimer_pcm {
  347 + ktime_t base_time;
  348 + ktime_t period_time;
  349 + atomic_t running;
  350 + struct hrtimer timer;
  351 + struct tasklet_struct tasklet;
  352 + struct snd_pcm_substream *substream;
  353 +};
  354 +
  355 +static void dummy_hrtimer_pcm_elapsed(unsigned long priv)
  356 +{
  357 + struct dummy_hrtimer_pcm *dpcm = (struct dummy_hrtimer_pcm *)priv;
  358 + if (atomic_read(&dpcm->running))
  359 + snd_pcm_period_elapsed(dpcm->substream);
  360 +}
  361 +
  362 +static enum hrtimer_restart dummy_hrtimer_callback(struct hrtimer *timer)
  363 +{
  364 + struct dummy_hrtimer_pcm *dpcm;
  365 +
  366 + dpcm = container_of(timer, struct dummy_hrtimer_pcm, timer);
  367 + if (!atomic_read(&dpcm->running))
  368 + return HRTIMER_NORESTART;
  369 + tasklet_schedule(&dpcm->tasklet);
  370 + hrtimer_forward_now(timer, dpcm->period_time);
  371 + return HRTIMER_RESTART;
  372 +}
  373 +
  374 +static int dummy_hrtimer_start(struct snd_pcm_substream *substream)
  375 +{
  376 + struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data;
  377 +
  378 + dpcm->base_time = hrtimer_cb_get_time(&dpcm->timer);
  379 + hrtimer_start(&dpcm->timer, dpcm->period_time, HRTIMER_MODE_REL);
  380 + atomic_set(&dpcm->running, 1);
  381 + return 0;
  382 +}
  383 +
  384 +static int dummy_hrtimer_stop(struct snd_pcm_substream *substream)
  385 +{
  386 + struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data;
  387 +
  388 + atomic_set(&dpcm->running, 0);
  389 + hrtimer_cancel(&dpcm->timer);
  390 + return 0;
  391 +}
  392 +
  393 +static inline void dummy_hrtimer_sync(struct dummy_hrtimer_pcm *dpcm)
  394 +{
  395 + tasklet_kill(&dpcm->tasklet);
  396 +}
  397 +
  398 +static snd_pcm_uframes_t
  399 +dummy_hrtimer_pointer(struct snd_pcm_substream *substream)
  400 +{
277 401 struct snd_pcm_runtime *runtime = substream->runtime;
278   - struct snd_dummy_pcm *dpcm = runtime->private_data;
  402 + struct dummy_hrtimer_pcm *dpcm = runtime->private_data;
  403 + u64 delta;
  404 + u32 pos;
279 405  
280   - return bytes_to_frames(runtime, dpcm->pcm_buf_pos / dpcm->pcm_hz);
  406 + delta = ktime_us_delta(hrtimer_cb_get_time(&dpcm->timer),
  407 + dpcm->base_time);
  408 + delta = div_u64(delta * runtime->rate + 999999, 1000000);
  409 + div_u64_rem(delta, runtime->buffer_size, &pos);
  410 + return pos;
281 411 }
282 412  
283   -static struct snd_pcm_hardware snd_card_dummy_playback =
  413 +static int dummy_hrtimer_prepare(struct snd_pcm_substream *substream)
284 414 {
285   - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
286   - SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID),
287   - .formats = USE_FORMATS,
288   - .rates = USE_RATE,
289   - .rate_min = USE_RATE_MIN,
290   - .rate_max = USE_RATE_MAX,
291   - .channels_min = USE_CHANNELS_MIN,
292   - .channels_max = USE_CHANNELS_MAX,
293   - .buffer_bytes_max = MAX_BUFFER_SIZE,
294   - .period_bytes_min = 64,
295   - .period_bytes_max = MAX_PERIOD_SIZE,
296   - .periods_min = USE_PERIODS_MIN,
297   - .periods_max = USE_PERIODS_MAX,
298   - .fifo_size = 0,
  415 + struct snd_pcm_runtime *runtime = substream->runtime;
  416 + struct dummy_hrtimer_pcm *dpcm = runtime->private_data;
  417 + unsigned int period, rate;
  418 + long sec;
  419 + unsigned long nsecs;
  420 +
  421 + dummy_hrtimer_sync(dpcm);
  422 + period = runtime->period_size;
  423 + rate = runtime->rate;
  424 + sec = period / rate;
  425 + period %= rate;
  426 + nsecs = div_u64((u64)period * 1000000000UL + rate - 1, rate);
  427 + dpcm->period_time = ktime_set(sec, nsecs);
  428 +
  429 + return 0;
  430 +}
  431 +
  432 +static int dummy_hrtimer_create(struct snd_pcm_substream *substream)
  433 +{
  434 + struct dummy_hrtimer_pcm *dpcm;
  435 +
  436 + dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
  437 + if (!dpcm)
  438 + return -ENOMEM;
  439 + substream->runtime->private_data = dpcm;
  440 + hrtimer_init(&dpcm->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
  441 + dpcm->timer.function = dummy_hrtimer_callback;
  442 + dpcm->substream = substream;
  443 + atomic_set(&dpcm->running, 0);
  444 + tasklet_init(&dpcm->tasklet, dummy_hrtimer_pcm_elapsed,
  445 + (unsigned long)dpcm);
  446 + return 0;
  447 +}
  448 +
  449 +static void dummy_hrtimer_free(struct snd_pcm_substream *substream)
  450 +{
  451 + struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data;
  452 + dummy_hrtimer_sync(dpcm);
  453 + kfree(dpcm);
  454 +}
  455 +
  456 +static struct dummy_timer_ops dummy_hrtimer_ops = {
  457 + .create = dummy_hrtimer_create,
  458 + .free = dummy_hrtimer_free,
  459 + .prepare = dummy_hrtimer_prepare,
  460 + .start = dummy_hrtimer_start,
  461 + .stop = dummy_hrtimer_stop,
  462 + .pointer = dummy_hrtimer_pointer,
299 463 };
300 464  
301   -static struct snd_pcm_hardware snd_card_dummy_capture =
  465 +#endif /* CONFIG_HIGH_RES_TIMERS */
  466 +
  467 +/*
  468 + * PCM interface
  469 + */
  470 +
  471 +static int dummy_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
302 472 {
303   - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
304   - SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID),
  473 + struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
  474 +
  475 + switch (cmd) {
  476 + case SNDRV_PCM_TRIGGER_START:
  477 + case SNDRV_PCM_TRIGGER_RESUME:
  478 + return dummy->timer_ops->start(substream);
  479 + case SNDRV_PCM_TRIGGER_STOP:
  480 + case SNDRV_PCM_TRIGGER_SUSPEND:
  481 + return dummy->timer_ops->stop(substream);
  482 + }
  483 + return -EINVAL;
  484 +}
  485 +
  486 +static int dummy_pcm_prepare(struct snd_pcm_substream *substream)
  487 +{
  488 + struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
  489 +
  490 + return dummy->timer_ops->prepare(substream);
  491 +}
  492 +
  493 +static snd_pcm_uframes_t dummy_pcm_pointer(struct snd_pcm_substream *substream)
  494 +{
  495 + struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
  496 +
  497 + return dummy->timer_ops->pointer(substream);
  498 +}
  499 +
  500 +static struct snd_pcm_hardware dummy_pcm_hardware = {
  501 + .info = (SNDRV_PCM_INFO_MMAP |
  502 + SNDRV_PCM_INFO_INTERLEAVED |
  503 + SNDRV_PCM_INFO_RESUME |
  504 + SNDRV_PCM_INFO_MMAP_VALID),
305 505 .formats = USE_FORMATS,
306 506 .rates = USE_RATE,
307 507 .rate_min = USE_RATE_MIN,
308 508  
309 509  
310 510  
311 511  
312 512  
313 513  
314 514  
315 515  
316 516  
317 517  
318 518  
319 519  
320 520  
321 521  
322 522  
323 523  
324 524  
325 525  
326 526  
327 527  
328 528  
... ... @@ -316,123 +516,152 @@
316 516 .fifo_size = 0,
317 517 };
318 518  
319   -static void snd_card_dummy_runtime_free(struct snd_pcm_runtime *runtime)
  519 +static int dummy_pcm_hw_params(struct snd_pcm_substream *substream,
  520 + struct snd_pcm_hw_params *hw_params)
320 521 {
321   - kfree(runtime->private_data);
  522 + if (fake_buffer) {
  523 + /* runtime->dma_bytes has to be set manually to allow mmap */
  524 + substream->runtime->dma_bytes = params_buffer_bytes(hw_params);
  525 + return 0;
  526 + }
  527 + return snd_pcm_lib_malloc_pages(substream,
  528 + params_buffer_bytes(hw_params));
322 529 }
323 530  
324   -static int snd_card_dummy_hw_params(struct snd_pcm_substream *substream,
325   - struct snd_pcm_hw_params *hw_params)
  531 +static int dummy_pcm_hw_free(struct snd_pcm_substream *substream)
326 532 {
327   - return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
328   -}
329   -
330   -static int snd_card_dummy_hw_free(struct snd_pcm_substream *substream)
331   -{
  533 + if (fake_buffer)
  534 + return 0;
332 535 return snd_pcm_lib_free_pages(substream);
333 536 }
334 537  
335   -static struct snd_dummy_pcm *new_pcm_stream(struct snd_pcm_substream *substream)
  538 +static int dummy_pcm_open(struct snd_pcm_substream *substream)
336 539 {
337   - struct snd_dummy_pcm *dpcm;
338   -
339   - dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
340   - if (! dpcm)
341   - return dpcm;
342   - init_timer(&dpcm->timer);
343   - dpcm->timer.data = (unsigned long) dpcm;
344   - dpcm->timer.function = snd_card_dummy_pcm_timer_function;
345   - spin_lock_init(&dpcm->lock);
346   - dpcm->substream = substream;
347   - return dpcm;
348   -}
349   -
350   -static int snd_card_dummy_playback_open(struct snd_pcm_substream *substream)
351   -{
  540 + struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
352 541 struct snd_pcm_runtime *runtime = substream->runtime;
353   - struct snd_dummy_pcm *dpcm;
354 542 int err;
355 543  
356   - if ((dpcm = new_pcm_stream(substream)) == NULL)
357   - return -ENOMEM;
358   - runtime->private_data = dpcm;
359   - /* makes the infrastructure responsible for freeing dpcm */
360   - runtime->private_free = snd_card_dummy_runtime_free;
361   - runtime->hw = snd_card_dummy_playback;
  544 + dummy->timer_ops = &dummy_systimer_ops;
  545 +#ifdef CONFIG_HIGH_RES_TIMERS
  546 + if (hrtimer)
  547 + dummy->timer_ops = &dummy_hrtimer_ops;
  548 +#endif
  549 +
  550 + err = dummy->timer_ops->create(substream);
  551 + if (err < 0)
  552 + return err;
  553 +
  554 + runtime->hw = dummy_pcm_hardware;
362 555 if (substream->pcm->device & 1) {
363 556 runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
364 557 runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
365 558 }
366 559 if (substream->pcm->device & 2)
367   - runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID);
368   - err = add_playback_constraints(runtime);
369   - if (err < 0)
370   - return err;
  560 + runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP |
  561 + SNDRV_PCM_INFO_MMAP_VALID);
371 562  
  563 + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  564 + err = add_playback_constraints(substream->runtime);
  565 + else
  566 + err = add_capture_constraints(substream->runtime);
  567 + if (err < 0) {
  568 + dummy->timer_ops->free(substream);
  569 + return err;
  570 + }
372 571 return 0;
373 572 }
374 573  
375   -static int snd_card_dummy_capture_open(struct snd_pcm_substream *substream)
  574 +static int dummy_pcm_close(struct snd_pcm_substream *substream)
376 575 {
377   - struct snd_pcm_runtime *runtime = substream->runtime;
378   - struct snd_dummy_pcm *dpcm;
379   - int err;
  576 + struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
  577 + dummy->timer_ops->free(substream);
  578 + return 0;
  579 +}
380 580  
381   - if ((dpcm = new_pcm_stream(substream)) == NULL)
382   - return -ENOMEM;
383   - runtime->private_data = dpcm;
384   - /* makes the infrastructure responsible for freeing dpcm */
385   - runtime->private_free = snd_card_dummy_runtime_free;
386   - runtime->hw = snd_card_dummy_capture;
387   - if (substream->pcm->device == 1) {
388   - runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
389   - runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
  581 +/*
  582 + * dummy buffer handling
  583 + */
  584 +
  585 +static void *dummy_page[2];
  586 +
  587 +static void free_fake_buffer(void)
  588 +{
  589 + if (fake_buffer) {
  590 + int i;
  591 + for (i = 0; i < 2; i++)
  592 + if (dummy_page[i]) {
  593 + free_page((unsigned long)dummy_page[i]);
  594 + dummy_page[i] = NULL;
  595 + }
390 596 }
391   - if (substream->pcm->device & 2)
392   - runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID);
393   - err = add_capture_constraints(runtime);
394   - if (err < 0)
395   - return err;
  597 +}
396 598  
  599 +static int alloc_fake_buffer(void)
  600 +{
  601 + int i;
  602 +
  603 + if (!fake_buffer)
  604 + return 0;
  605 + for (i = 0; i < 2; i++) {
  606 + dummy_page[i] = (void *)get_zeroed_page(GFP_KERNEL);
  607 + if (!dummy_page[i]) {
  608 + free_fake_buffer();
  609 + return -ENOMEM;
  610 + }
  611 + }
397 612 return 0;
398 613 }
399 614  
400   -static int snd_card_dummy_playback_close(struct snd_pcm_substream *substream)
  615 +static int dummy_pcm_copy(struct snd_pcm_substream *substream,
  616 + int channel, snd_pcm_uframes_t pos,
  617 + void __user *dst, snd_pcm_uframes_t count)
401 618 {
402   - return 0;
  619 + return 0; /* do nothing */
403 620 }
404 621  
405   -static int snd_card_dummy_capture_close(struct snd_pcm_substream *substream)
  622 +static int dummy_pcm_silence(struct snd_pcm_substream *substream,
  623 + int channel, snd_pcm_uframes_t pos,
  624 + snd_pcm_uframes_t count)
406 625 {
407   - return 0;
  626 + return 0; /* do nothing */
408 627 }
409 628  
410   -static struct snd_pcm_ops snd_card_dummy_playback_ops = {
411   - .open = snd_card_dummy_playback_open,
412   - .close = snd_card_dummy_playback_close,
413   - .ioctl = snd_pcm_lib_ioctl,
414   - .hw_params = snd_card_dummy_hw_params,
415   - .hw_free = snd_card_dummy_hw_free,
416   - .prepare = snd_card_dummy_pcm_prepare,
417   - .trigger = snd_card_dummy_pcm_trigger,
418   - .pointer = snd_card_dummy_pcm_pointer,
  629 +static struct page *dummy_pcm_page(struct snd_pcm_substream *substream,
  630 + unsigned long offset)
  631 +{
  632 + return virt_to_page(dummy_page[substream->stream]); /* the same page */
  633 +}
  634 +
  635 +static struct snd_pcm_ops dummy_pcm_ops = {
  636 + .open = dummy_pcm_open,
  637 + .close = dummy_pcm_close,
  638 + .ioctl = snd_pcm_lib_ioctl,
  639 + .hw_params = dummy_pcm_hw_params,
  640 + .hw_free = dummy_pcm_hw_free,
  641 + .prepare = dummy_pcm_prepare,
  642 + .trigger = dummy_pcm_trigger,
  643 + .pointer = dummy_pcm_pointer,
419 644 };
420 645  
421   -static struct snd_pcm_ops snd_card_dummy_capture_ops = {
422   - .open = snd_card_dummy_capture_open,
423   - .close = snd_card_dummy_capture_close,
424   - .ioctl = snd_pcm_lib_ioctl,
425   - .hw_params = snd_card_dummy_hw_params,
426   - .hw_free = snd_card_dummy_hw_free,
427   - .prepare = snd_card_dummy_pcm_prepare,
428   - .trigger = snd_card_dummy_pcm_trigger,
429   - .pointer = snd_card_dummy_pcm_pointer,
  646 +static struct snd_pcm_ops dummy_pcm_ops_no_buf = {
  647 + .open = dummy_pcm_open,
  648 + .close = dummy_pcm_close,
  649 + .ioctl = snd_pcm_lib_ioctl,
  650 + .hw_params = dummy_pcm_hw_params,
  651 + .hw_free = dummy_pcm_hw_free,
  652 + .prepare = dummy_pcm_prepare,
  653 + .trigger = dummy_pcm_trigger,
  654 + .pointer = dummy_pcm_pointer,
  655 + .copy = dummy_pcm_copy,
  656 + .silence = dummy_pcm_silence,
  657 + .page = dummy_pcm_page,
430 658 };
431 659  
432 660 static int __devinit snd_card_dummy_pcm(struct snd_dummy *dummy, int device,
433 661 int substreams)
434 662 {
435 663 struct snd_pcm *pcm;
  664 + struct snd_pcm_ops *ops;
436 665 int err;
437 666  
438 667 err = snd_pcm_new(dummy->card, "Dummy PCM", device,
439 668  
440 669  
... ... @@ -440,17 +669,28 @@
440 669 if (err < 0)
441 670 return err;
442 671 dummy->pcm = pcm;
443   - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_dummy_playback_ops);
444   - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_dummy_capture_ops);
  672 + if (fake_buffer)
  673 + ops = &dummy_pcm_ops_no_buf;
  674 + else
  675 + ops = &dummy_pcm_ops;
  676 + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, ops);
  677 + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, ops);
445 678 pcm->private_data = dummy;
446 679 pcm->info_flags = 0;
447 680 strcpy(pcm->name, "Dummy PCM");
448   - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
449   - snd_dma_continuous_data(GFP_KERNEL),
450   - 0, 64*1024);
  681 + if (!fake_buffer) {
  682 + snd_pcm_lib_preallocate_pages_for_all(pcm,
  683 + SNDRV_DMA_TYPE_CONTINUOUS,
  684 + snd_dma_continuous_data(GFP_KERNEL),
  685 + 0, 64*1024);
  686 + }
451 687 return 0;
452 688 }
453 689  
  690 +/*
  691 + * mixer interface
  692 + */
  693 +
454 694 #define DUMMY_VOLUME(xname, xindex, addr) \
455 695 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
456 696 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
... ... @@ -581,6 +821,131 @@
581 821 return 0;
582 822 }
583 823  
  824 +#if defined(CONFIG_SND_DEBUG) && defined(CONFIG_PROC_FS)
  825 +/*
  826 + * proc interface
  827 + */
  828 +static void print_formats(struct snd_info_buffer *buffer)
  829 +{
  830 + int i;
  831 +
  832 + for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) {
  833 + if (dummy_pcm_hardware.formats & (1ULL << i))
  834 + snd_iprintf(buffer, " %s", snd_pcm_format_name(i));
  835 + }
  836 +}
  837 +
  838 +static void print_rates(struct snd_info_buffer *buffer)
  839 +{
  840 + static int rates[] = {
  841 + 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000,
  842 + 64000, 88200, 96000, 176400, 192000,
  843 + };
  844 + int i;
  845 +
  846 + if (dummy_pcm_hardware.rates & SNDRV_PCM_RATE_CONTINUOUS)
  847 + snd_iprintf(buffer, " continuous");
  848 + if (dummy_pcm_hardware.rates & SNDRV_PCM_RATE_KNOT)
  849 + snd_iprintf(buffer, " knot");
  850 + for (i = 0; i < ARRAY_SIZE(rates); i++)
  851 + if (dummy_pcm_hardware.rates & (1 << i))
  852 + snd_iprintf(buffer, " %d", rates[i]);
  853 +}
  854 +
  855 +#define get_dummy_int_ptr(ofs) \
  856 + (unsigned int *)((char *)&dummy_pcm_hardware + (ofs))
  857 +#define get_dummy_ll_ptr(ofs) \
  858 + (unsigned long long *)((char *)&dummy_pcm_hardware + (ofs))
  859 +
  860 +struct dummy_hw_field {
  861 + const char *name;
  862 + const char *format;
  863 + unsigned int offset;
  864 + unsigned int size;
  865 +};
  866 +#define FIELD_ENTRY(item, fmt) { \
  867 + .name = #item, \
  868 + .format = fmt, \
  869 + .offset = offsetof(struct snd_pcm_hardware, item), \
  870 + .size = sizeof(dummy_pcm_hardware.item) }
  871 +
  872 +static struct dummy_hw_field fields[] = {
  873 + FIELD_ENTRY(formats, "%#llx"),
  874 + FIELD_ENTRY(rates, "%#x"),
  875 + FIELD_ENTRY(rate_min, "%d"),
  876 + FIELD_ENTRY(rate_max, "%d"),
  877 + FIELD_ENTRY(channels_min, "%d"),
  878 + FIELD_ENTRY(channels_max, "%d"),
  879 + FIELD_ENTRY(buffer_bytes_max, "%ld"),
  880 + FIELD_ENTRY(period_bytes_min, "%ld"),
  881 + FIELD_ENTRY(period_bytes_max, "%ld"),
  882 + FIELD_ENTRY(periods_min, "%d"),
  883 + FIELD_ENTRY(periods_max, "%d"),
  884 +};
  885 +
  886 +static void dummy_proc_read(struct snd_info_entry *entry,
  887 + struct snd_info_buffer *buffer)
  888 +{
  889 + int i;
  890 +
  891 + for (i = 0; i < ARRAY_SIZE(fields); i++) {
  892 + snd_iprintf(buffer, "%s ", fields[i].name);
  893 + if (fields[i].size == sizeof(int))
  894 + snd_iprintf(buffer, fields[i].format,
  895 + *get_dummy_int_ptr(fields[i].offset));
  896 + else
  897 + snd_iprintf(buffer, fields[i].format,
  898 + *get_dummy_ll_ptr(fields[i].offset));
  899 + if (!strcmp(fields[i].name, "formats"))
  900 + print_formats(buffer);
  901 + else if (!strcmp(fields[i].name, "rates"))
  902 + print_rates(buffer);
  903 + snd_iprintf(buffer, "\n");
  904 + }
  905 +}
  906 +
  907 +static void dummy_proc_write(struct snd_info_entry *entry,
  908 + struct snd_info_buffer *buffer)
  909 +{
  910 + char line[64];
  911 +
  912 + while (!snd_info_get_line(buffer, line, sizeof(line))) {
  913 + char item[20];
  914 + const char *ptr;
  915 + unsigned long long val;
  916 + int i;
  917 +
  918 + ptr = snd_info_get_str(item, line, sizeof(item));
  919 + for (i = 0; i < ARRAY_SIZE(fields); i++) {
  920 + if (!strcmp(item, fields[i].name))
  921 + break;
  922 + }
  923 + if (i >= ARRAY_SIZE(fields))
  924 + continue;
  925 + snd_info_get_str(item, ptr, sizeof(item));
  926 + if (strict_strtoull(item, 0, &val))
  927 + continue;
  928 + if (fields[i].size == sizeof(int))
  929 + *get_dummy_int_ptr(fields[i].offset) = val;
  930 + else
  931 + *get_dummy_ll_ptr(fields[i].offset) = val;
  932 + }
  933 +}
  934 +
  935 +static void __devinit dummy_proc_init(struct snd_dummy *chip)
  936 +{
  937 + struct snd_info_entry *entry;
  938 +
  939 + if (!snd_card_proc_new(chip->card, "dummy_pcm", &entry)) {
  940 + snd_info_set_text_ops(entry, chip, dummy_proc_read);
  941 + entry->c.text.write = dummy_proc_write;
  942 + entry->mode |= S_IWUSR;
  943 + }
  944 +}
  945 +#else
  946 +#define dummy_proc_init(x)
  947 +#endif /* CONFIG_SND_DEBUG && CONFIG_PROC_FS */
  948 +
584 949 static int __devinit snd_dummy_probe(struct platform_device *devptr)
585 950 {
586 951 struct snd_card *card;
... ... @@ -610,6 +975,8 @@
610 975 strcpy(card->shortname, "Dummy");
611 976 sprintf(card->longname, "Dummy %i", dev + 1);
612 977  
  978 + dummy_proc_init(dummy);
  979 +
613 980 snd_card_set_dev(card, &devptr->dev);
614 981  
615 982 err = snd_card_register(card);
... ... @@ -670,6 +1037,7 @@
670 1037 for (i = 0; i < ARRAY_SIZE(devices); ++i)
671 1038 platform_device_unregister(devices[i]);
672 1039 platform_driver_unregister(&snd_dummy_driver);
  1040 + free_fake_buffer();
673 1041 }
674 1042  
675 1043 static int __init alsa_card_dummy_init(void)
... ... @@ -679,6 +1047,12 @@
679 1047 err = platform_driver_register(&snd_dummy_driver);
680 1048 if (err < 0)
681 1049 return err;
  1050 +
  1051 + err = alloc_fake_buffer();
  1052 + if (err < 0) {
  1053 + platform_driver_unregister(&snd_dummy_driver);
  1054 + return err;
  1055 + }
682 1056  
683 1057 cards = 0;
684 1058 for (i = 0; i < SNDRV_CARDS; i++) {
sound/usb/usbaudio.c
... ... @@ -2124,8 +2124,8 @@
2124 2124 fp = list_entry(p, struct audioformat, list);
2125 2125 snd_iprintf(buffer, " Interface %d\n", fp->iface);
2126 2126 snd_iprintf(buffer, " Altset %d\n", fp->altsetting);
2127   - snd_iprintf(buffer, " Format: %#x (%d bits)\n",
2128   - fp->format, snd_pcm_format_width(fp->format));
  2127 + snd_iprintf(buffer, " Format: %s\n",
  2128 + snd_pcm_format_name(fp->format));
2129 2129 snd_iprintf(buffer, " Channels: %d\n", fp->channels);
2130 2130 snd_iprintf(buffer, " Endpoint: %d %s (%s)\n",
2131 2131 fp->endpoint & USB_ENDPOINT_NUMBER_MASK,