OSDN Git Service

fix doc errors
[android-x86/external-alsa-lib.git] / src / pcm / pcm_ioplug.c
1 /**
2  * \file pcm/pcm_ioplug.c
3  * \ingroup Plugin_SDK
4  * \brief I/O Plugin SDK
5  * \author Takashi Iwai <tiwai@suse.de>
6  * \date 2005
7  */
8 /*
9  *  PCM - External I/O Plugin SDK
10  *  Copyright (c) 2005 by Takashi Iwai <tiwai@suse.de>
11  *
12  *
13  *   This library is free software; you can redistribute it and/or modify
14  *   it under the terms of the GNU Lesser General Public License as
15  *   published by the Free Software Foundation; either version 2.1 of
16  *   the License, or (at your option) any later version.
17  *
18  *   This program is distributed in the hope that it will be useful,
19  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  *   GNU Lesser General Public License for more details.
22  *
23  *   You should have received a copy of the GNU Lesser General Public
24  *   License along with this library; if not, write to the Free Software
25  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
26  *
27  */
28   
29 #include "pcm_local.h"
30 #include "pcm_ioplug.h"
31 #include "pcm_ext_parm.h"
32 #include "pcm_generic.h"
33
34 #ifndef PIC
35 /* entry for static linking */
36 const char *_snd_module_pcm_ioplug = "";
37 #endif
38
39 #ifndef DOC_HIDDEN
40
41 /* hw_params */
42 typedef struct snd_pcm_ioplug_priv {
43         snd_pcm_ioplug_t *data;
44         struct snd_ext_parm params[SND_PCM_IOPLUG_HW_PARAMS];
45         unsigned int last_hw;
46         snd_pcm_uframes_t avail_max;
47         snd_htimestamp_t trigger_tstamp;
48 } ioplug_priv_t;
49
50 /* update the hw pointer */
51 static void snd_pcm_ioplug_hw_ptr_update(snd_pcm_t *pcm)
52 {
53         ioplug_priv_t *io = pcm->private_data;
54         snd_pcm_sframes_t hw;
55
56         hw = io->data->callback->pointer(io->data);
57         if (hw >= 0) {
58                 unsigned int delta;
59                 if ((unsigned int)hw >= io->last_hw)
60                         delta = hw - io->last_hw;
61                 else
62                         delta = pcm->buffer_size + hw - io->last_hw;
63                 io->data->hw_ptr += delta;
64                 io->last_hw = hw;
65         } else
66                 io->data->state = SNDRV_PCM_STATE_XRUN;
67 }
68
69 static int snd_pcm_ioplug_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
70 {
71         memset(info, 0, sizeof(*info));
72         info->stream = pcm->stream;
73         info->card = -1;
74         if (pcm->name) {
75                 strncpy((char *)info->id, pcm->name, sizeof(info->id));
76                 strncpy((char *)info->name, pcm->name, sizeof(info->name));
77                 strncpy((char *)info->subname, pcm->name, sizeof(info->subname));
78         }
79         info->subdevices_count = 1;
80         return 0;
81 }
82
83 static int snd_pcm_ioplug_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
84 {
85         return snd_pcm_channel_info_shm(pcm, info, -1);
86 }
87
88 static int snd_pcm_ioplug_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
89 {
90         ioplug_priv_t *io = pcm->private_data;
91
92         memset(status, 0, sizeof(*status));
93         snd_pcm_ioplug_hw_ptr_update(pcm);
94         status->state = io->data->state;
95         status->trigger_tstamp = io->trigger_tstamp;
96         status->avail = snd_pcm_mmap_avail(pcm);
97         status->avail_max = io->avail_max;
98         return 0;
99 }
100
101 static snd_pcm_state_t snd_pcm_ioplug_state(snd_pcm_t *pcm)
102 {
103         ioplug_priv_t *io = pcm->private_data;
104         return io->data->state;
105 }
106
107 static int snd_pcm_ioplug_hwsync(snd_pcm_t *pcm)
108 {
109         snd_pcm_ioplug_hw_ptr_update(pcm);
110         return 0;
111 }
112
113 static int snd_pcm_ioplug_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
114 {
115         ioplug_priv_t *io = pcm->private_data;
116
117         if (io->data->version >= 0x010001 &&
118             io->data->callback->delay)
119                 return io->data->callback->delay(io->data, delayp);
120         else {
121                 snd_pcm_ioplug_hw_ptr_update(pcm);
122                 *delayp = snd_pcm_mmap_hw_avail(pcm);
123         }
124         return 0;
125 }
126
127 static int snd_pcm_ioplug_reset(snd_pcm_t *pcm)
128 {
129         ioplug_priv_t *io = pcm->private_data;
130
131         io->data->appl_ptr = 0;
132         io->data->hw_ptr = 0;
133         io->last_hw = 0;
134         io->avail_max = 0;
135         return 0;
136 }
137
138 static int snd_pcm_ioplug_prepare(snd_pcm_t *pcm)
139 {
140         ioplug_priv_t *io = pcm->private_data;
141
142         io->data->state = SND_PCM_STATE_PREPARED;
143         snd_pcm_ioplug_reset(pcm);
144         if (io->data->callback->prepare)
145                 return io->data->callback->prepare(io->data);
146         return 0;
147 }
148
149 static const int hw_params_type[SND_PCM_IOPLUG_HW_PARAMS] = {
150         [SND_PCM_IOPLUG_HW_ACCESS] = SND_PCM_HW_PARAM_ACCESS,
151         [SND_PCM_IOPLUG_HW_FORMAT] = SND_PCM_HW_PARAM_FORMAT,
152         [SND_PCM_IOPLUG_HW_CHANNELS] = SND_PCM_HW_PARAM_CHANNELS,
153         [SND_PCM_IOPLUG_HW_RATE] = SND_PCM_HW_PARAM_RATE,
154         [SND_PCM_IOPLUG_HW_PERIOD_BYTES] = SND_PCM_HW_PARAM_PERIOD_BYTES,
155         [SND_PCM_IOPLUG_HW_BUFFER_BYTES] = SND_PCM_HW_PARAM_BUFFER_BYTES,
156         [SND_PCM_IOPLUG_HW_PERIODS] = SND_PCM_HW_PARAM_PERIODS,
157 };
158
159 /* x = a * b */
160 static int rule_mul(snd_pcm_hw_params_t *params, int x, int a, int b)
161 {
162         snd_interval_t t;
163
164         snd_interval_mul(hw_param_interval(params, a),
165                          hw_param_interval(params, b), &t);
166         return snd_interval_refine(hw_param_interval(params, x), &t);
167 }
168
169 /* x = a / b */
170 static int rule_div(snd_pcm_hw_params_t *params, int x, int a, int b)
171 {
172         snd_interval_t t;
173
174         snd_interval_div(hw_param_interval(params, a),
175                          hw_param_interval(params, b), &t);
176         return snd_interval_refine(hw_param_interval(params, x), &t);
177 }
178
179 /* x = a * b / k */
180 static int rule_muldivk(snd_pcm_hw_params_t *params, int x, int a, int b, int k)
181 {
182         snd_interval_t t;
183
184         snd_interval_muldivk(hw_param_interval(params, a),
185                              hw_param_interval(params, b), k, &t);
186         return snd_interval_refine(hw_param_interval(params, x), &t);
187 }
188
189 /* x = a * k / b */
190 static int rule_mulkdiv(snd_pcm_hw_params_t *params, int x, int a, int k, int b)
191 {
192         snd_interval_t t;
193
194         snd_interval_mulkdiv(hw_param_interval(params, a), k,
195                              hw_param_interval(params, b), &t);
196         return snd_interval_refine(hw_param_interval(params, x), &t);
197 }
198
199 #if 0
200 static void dump_parm(snd_pcm_hw_params_t *params)
201 {
202         snd_output_t *log;
203         snd_output_stdio_attach(&log, stderr, 0);
204         snd_pcm_hw_params_dump(params, log);
205         snd_output_close(log);
206 }
207 #endif
208
209 /* refine *_TIME and *_SIZE, then update *_BYTES */
210 static int refine_time_and_size(snd_pcm_hw_params_t *params,
211                                 int time, int size, int bytes)
212 {
213         int err, change1 = 0;
214
215         /* size = time * rate / 1000000 */
216         err = rule_muldivk(params, size, time,
217                            SND_PCM_HW_PARAM_RATE, 1000000);
218         if (err < 0)
219                 return err;
220         change1 |= err;
221
222         /* bytes = size * framebits / 8 */
223         err = rule_muldivk(params, bytes, size,
224                            SND_PCM_HW_PARAM_FRAME_BITS, 8);
225         if (err < 0)
226                 return err;
227         change1 |= err;
228         return change1;
229 }
230
231 /* refine *_TIME and *_SIZE from *_BYTES */
232 static int refine_back_time_and_size(snd_pcm_hw_params_t *params,
233                                      int time, int size, int bytes)
234 {
235         int err;
236
237         /* size = bytes * 8 / framebits */
238         err = rule_mulkdiv(params, size, bytes, 8, SND_PCM_HW_PARAM_FRAME_BITS);
239         if (err < 0)
240                 return err;
241         /* time = size * 1000000 / rate */
242         err = rule_mulkdiv(params, time, size, 1000000, SND_PCM_HW_PARAM_RATE);
243         if (err < 0)
244                 return err;
245         return 0;
246 }
247
248
249 static int snd_pcm_ioplug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
250 {
251         int change = 0, change1, change2, err;
252         ioplug_priv_t *io = pcm->private_data;
253         struct snd_ext_parm *p;
254         unsigned int i;
255
256         /* access, format */
257         for (i = SND_PCM_IOPLUG_HW_ACCESS; i <= SND_PCM_IOPLUG_HW_FORMAT; i++) {
258                 err = snd_ext_parm_mask_refine(hw_param_mask(params, hw_params_type[i]),
259                                                io->params, i);
260                 if (err < 0)
261                         return err;
262                 change |= err;
263         }
264         /* channels, rate */
265         for (; i <= SND_PCM_IOPLUG_HW_RATE; i++) {
266                 err = snd_ext_parm_interval_refine(hw_param_interval(params, hw_params_type[i]),
267                                                    io->params, i);
268                 if (err < 0)
269                         return err;
270                 change |= err;
271         }
272
273         if (params->rmask & ((1 << SND_PCM_HW_PARAM_ACCESS) |
274                              (1 << SND_PCM_HW_PARAM_FORMAT) |
275                              (1 << SND_PCM_HW_PARAM_SUBFORMAT) |
276                              (1 << SND_PCM_HW_PARAM_CHANNELS) |
277                              (1 << SND_PCM_HW_PARAM_RATE))) {
278                 err = snd_pcm_hw_refine_soft(pcm, params);
279                 if (err < 0)
280                         return err;
281                 change |= err;
282         }
283
284         change1 = refine_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME,
285                                        SND_PCM_HW_PARAM_PERIOD_SIZE,
286                                        SND_PCM_HW_PARAM_PERIOD_BYTES);
287         if (change1 < 0)
288                 return change1;
289         err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_BYTES),
290                                            io->params, SND_PCM_IOPLUG_HW_PERIOD_BYTES);
291         if (err < 0)
292                 return err;
293         change1 |= err;
294         if (change1) {
295                 change |= change1;
296                 err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME,
297                                                 SND_PCM_HW_PARAM_PERIOD_SIZE,
298                                                 SND_PCM_HW_PARAM_PERIOD_BYTES);
299                 if (err < 0)
300                         return err;
301         }
302
303         change1 = refine_time_and_size(params, SND_PCM_HW_PARAM_BUFFER_TIME,
304                                        SND_PCM_HW_PARAM_BUFFER_SIZE,
305                                        SND_PCM_HW_PARAM_BUFFER_BYTES);
306         if (change1 < 0)
307                 return change1;
308         change |= change1;
309
310         do {
311                 change2 = 0;
312                 err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_BUFFER_BYTES),
313                                                    io->params, SND_PCM_IOPLUG_HW_BUFFER_BYTES);
314                 if (err < 0)
315                         return err;
316                 change2 |= err;
317                 /* periods = buffer_bytes / period_bytes */
318                 err = rule_div(params, SND_PCM_HW_PARAM_PERIODS,
319                                SND_PCM_HW_PARAM_BUFFER_BYTES,
320                                SND_PCM_HW_PARAM_PERIOD_BYTES);
321                 if (err < 0)
322                         return err;
323                 change2 |= err;
324                 err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIODS),
325                                                    io->params, SND_PCM_IOPLUG_HW_PERIODS);
326                 if (err < 0)
327                         return err;
328                 change2 |= err;
329                 /* buffer_bytes = periods * period_bytes */
330                 err = rule_mul(params, SND_PCM_HW_PARAM_BUFFER_BYTES,
331                                SND_PCM_HW_PARAM_PERIOD_BYTES,
332                                SND_PCM_HW_PARAM_PERIODS);
333                 if (err < 0)
334                         return err;
335                 change2 |= err;
336                 change1 |= change2;
337         } while (change2);
338         change |= change1;
339
340         if (change1) {
341                 err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_BUFFER_TIME,
342                                                 SND_PCM_HW_PARAM_BUFFER_SIZE,
343                                                 SND_PCM_HW_PARAM_BUFFER_BYTES);
344                 if (err < 0)
345                         return err;
346         }
347
348         /* period_bytes = buffer_bytes / periods */
349         err = rule_div(params, SND_PCM_HW_PARAM_PERIOD_BYTES,
350                        SND_PCM_HW_PARAM_BUFFER_BYTES,
351                        SND_PCM_HW_PARAM_PERIODS);
352         if (err < 0)
353                 return err;
354         if (err) {
355                 /* update period_size and period_time */
356                 change |= err;
357                 err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_BYTES),
358                                                    io->params, SND_PCM_IOPLUG_HW_PERIOD_BYTES);
359                 if (err < 0)
360                         return err;
361                 err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME,
362                                                 SND_PCM_HW_PARAM_PERIOD_SIZE,
363                                                 SND_PCM_HW_PARAM_PERIOD_BYTES);
364                 if (err < 0)
365                         return err;
366         }
367
368         params->info = SND_PCM_INFO_BLOCK_TRANSFER;
369         p = &io->params[SND_PCM_IOPLUG_HW_ACCESS];
370         if (p->active) {
371                 for (i = 0; i < p->num_list; i++)
372                         switch (p->list[i]) {
373                         case SND_PCM_ACCESS_MMAP_INTERLEAVED:
374                         case SND_PCM_ACCESS_RW_INTERLEAVED:
375                                 params->info |= SND_PCM_INFO_INTERLEAVED;
376                                 break;
377                         case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
378                         case SND_PCM_ACCESS_RW_NONINTERLEAVED:
379                                 params->info |= SND_PCM_INFO_NONINTERLEAVED;
380                                 break;
381                         }
382         }
383         if (io->data->callback->pause)
384                 params->info |= SND_PCM_INFO_PAUSE;
385         if (io->data->callback->resume)
386                 params->info |= SND_PCM_INFO_RESUME;
387
388 #if 0
389         fprintf(stderr, "XXX\n");
390         dump_parm(params);
391 #endif
392         return change;
393 }
394
395 static int snd_pcm_ioplug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
396 {
397         ioplug_priv_t *io = pcm->private_data;
398         int err;
399
400         INTERNAL(snd_pcm_hw_params_get_access)(params, &io->data->access);
401         INTERNAL(snd_pcm_hw_params_get_format)(params, &io->data->format);
402         INTERNAL(snd_pcm_hw_params_get_channels)(params, &io->data->channels);
403         INTERNAL(snd_pcm_hw_params_get_rate)(params, &io->data->rate, 0);
404         INTERNAL(snd_pcm_hw_params_get_period_size)(params, &io->data->period_size, 0);
405         INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &io->data->buffer_size);
406         if (io->data->callback->hw_params) {
407                 err = io->data->callback->hw_params(io->data, params);
408                 if (err < 0)
409                         return err;
410                 INTERNAL(snd_pcm_hw_params_get_access)(params, &io->data->access);
411                 INTERNAL(snd_pcm_hw_params_get_format)(params, &io->data->format);
412                 INTERNAL(snd_pcm_hw_params_get_channels)(params, &io->data->channels);
413                 INTERNAL(snd_pcm_hw_params_get_rate)(params, &io->data->rate, 0);
414                 INTERNAL(snd_pcm_hw_params_get_period_size)(params, &io->data->period_size, 0);
415                 INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &io->data->buffer_size);
416         }
417         return 0;
418 }
419
420 static int snd_pcm_ioplug_hw_free(snd_pcm_t *pcm)
421 {
422         ioplug_priv_t *io = pcm->private_data;
423
424         if (io->data->callback->hw_free)
425                 return io->data->callback->hw_free(io->data);
426         return 0;
427 }
428
429 static int snd_pcm_ioplug_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
430 {
431         ioplug_priv_t *io = pcm->private_data;
432
433         if (io->data->callback->sw_params)
434                 return io->data->callback->sw_params(io->data, params);
435         return 0;
436 }
437
438
439 static int snd_pcm_ioplug_start(snd_pcm_t *pcm)
440 {
441         ioplug_priv_t *io = pcm->private_data;
442         int err;
443         
444         if (io->data->state != SND_PCM_STATE_PREPARED)
445                 return -EBUSY;
446
447         err = io->data->callback->start(io->data);
448         if (err < 0)
449                 return err;
450
451         gettimestamp(&io->trigger_tstamp, pcm->monotonic);
452         io->data->state = SND_PCM_STATE_RUNNING;
453
454         return 0;
455 }
456
457 static int snd_pcm_ioplug_drop(snd_pcm_t *pcm)
458 {
459         ioplug_priv_t *io = pcm->private_data;
460
461         if (io->data->state == SND_PCM_STATE_OPEN)
462                 return -EBADFD;
463
464         io->data->callback->stop(io->data);
465
466         gettimestamp(&io->trigger_tstamp, pcm->monotonic);
467         io->data->state = SND_PCM_STATE_SETUP;
468
469         return 0;
470 }
471
472 static int snd_pcm_ioplug_drain(snd_pcm_t *pcm)
473 {
474         ioplug_priv_t *io = pcm->private_data;
475
476         if (io->data->state == SND_PCM_STATE_OPEN)
477                 return -EBADFD;
478         if (io->data->callback->drain)
479                 io->data->callback->drain(io->data);
480         return snd_pcm_ioplug_drop(pcm);
481 }
482
483 static int snd_pcm_ioplug_pause(snd_pcm_t *pcm, int enable)
484 {
485         ioplug_priv_t *io = pcm->private_data;
486         static const snd_pcm_state_t states[2] = {
487                 SND_PCM_STATE_RUNNING, SND_PCM_STATE_PAUSED
488         };
489         int prev, err;
490
491         prev = !enable;
492         enable = !prev;
493         if (io->data->state != states[prev])
494                 return -EBADFD;
495         if (io->data->callback->pause) {
496                 err = io->data->callback->pause(io->data, enable);
497                 if (err < 0)
498                         return err;
499         }
500         io->data->state = states[enable];
501         return 0;
502 }
503
504 static snd_pcm_sframes_t snd_pcm_ioplug_rewindable(snd_pcm_t *pcm)
505 {
506         return snd_pcm_mmap_hw_avail(pcm);
507 }
508
509 static snd_pcm_sframes_t snd_pcm_ioplug_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
510 {
511         snd_pcm_mmap_appl_backward(pcm, frames);
512         return frames;
513 }
514
515 static snd_pcm_sframes_t snd_pcm_ioplug_forwardable(snd_pcm_t *pcm)
516 {
517         return snd_pcm_mmap_avail(pcm);
518 }
519
520 static snd_pcm_sframes_t snd_pcm_ioplug_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
521 {
522         snd_pcm_mmap_appl_forward(pcm, frames);
523         return frames;
524 }
525
526 static int snd_pcm_ioplug_resume(snd_pcm_t *pcm)
527 {
528         ioplug_priv_t *io = pcm->private_data;
529
530         if (io->data->callback->resume)
531                 io->data->callback->resume(io->data);
532         return 0;
533 }
534
535 static snd_pcm_sframes_t ioplug_priv_transfer_areas(snd_pcm_t *pcm,
536                                                        const snd_pcm_channel_area_t *areas,
537                                                        snd_pcm_uframes_t offset,
538                                                        snd_pcm_uframes_t size)
539 {
540         ioplug_priv_t *io = pcm->private_data;
541         snd_pcm_sframes_t result;
542                 
543         if (! size)
544                 return 0;
545         if (io->data->callback->transfer)
546                 result = io->data->callback->transfer(io->data, areas, offset, size);
547         else
548                 result = size;
549         if (result > 0)
550                 snd_pcm_mmap_appl_forward(pcm, result);
551         return result;
552 }
553
554 static snd_pcm_sframes_t snd_pcm_ioplug_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)
555 {
556         if (pcm->mmap_rw)
557                 return snd_pcm_mmap_writei(pcm, buffer, size);
558         else {
559                 snd_pcm_channel_area_t areas[pcm->channels];
560                 snd_pcm_areas_from_buf(pcm, areas, (void*)buffer);
561                 return snd_pcm_write_areas(pcm, areas, 0, size, 
562                                            ioplug_priv_transfer_areas);
563         }
564 }
565
566 static snd_pcm_sframes_t snd_pcm_ioplug_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
567 {
568         if (pcm->mmap_rw)
569                 return snd_pcm_mmap_writen(pcm, bufs, size);
570         else {
571                 snd_pcm_channel_area_t areas[pcm->channels];
572                 snd_pcm_areas_from_bufs(pcm, areas, bufs);
573                 return snd_pcm_write_areas(pcm, areas, 0, size,
574                                            ioplug_priv_transfer_areas);
575         }
576 }
577
578 static snd_pcm_sframes_t snd_pcm_ioplug_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)
579 {
580         if (pcm->mmap_rw)
581                 return snd_pcm_mmap_readi(pcm, buffer, size);
582         else {
583                 snd_pcm_channel_area_t areas[pcm->channels];
584                 snd_pcm_areas_from_buf(pcm, areas, buffer);
585                 return snd_pcm_read_areas(pcm, areas, 0, size,
586                                           ioplug_priv_transfer_areas);
587         }
588 }
589
590 static snd_pcm_sframes_t snd_pcm_ioplug_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
591 {
592         if (pcm->mmap_rw)
593                 return snd_pcm_mmap_readn(pcm, bufs, size);
594         else {
595                 snd_pcm_channel_area_t areas[pcm->channels];
596                 snd_pcm_areas_from_bufs(pcm, areas, bufs);
597                 return snd_pcm_read_areas(pcm, areas, 0, size,
598                                           ioplug_priv_transfer_areas);
599         }
600 }
601
602 static snd_pcm_sframes_t snd_pcm_ioplug_mmap_commit(snd_pcm_t *pcm,
603                                                     snd_pcm_uframes_t offset,
604                                                     snd_pcm_uframes_t size)
605 {
606         if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
607             pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED &&
608             pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) {
609                 const snd_pcm_channel_area_t *areas;
610                 snd_pcm_uframes_t ofs, frames = size;
611
612                 snd_pcm_mmap_begin(pcm, &areas, &ofs, &frames);
613                 if (ofs != offset)
614                         return -EIO;
615                 return ioplug_priv_transfer_areas(pcm, areas, offset, frames);
616         }
617
618         snd_pcm_mmap_appl_forward(pcm, size);
619         return size;
620 }
621
622 static snd_pcm_sframes_t snd_pcm_ioplug_avail_update(snd_pcm_t *pcm)
623 {
624         ioplug_priv_t *io = pcm->private_data;
625         snd_pcm_uframes_t avail;
626
627         snd_pcm_ioplug_hw_ptr_update(pcm);
628         if (io->data->state == SNDRV_PCM_STATE_XRUN)
629                 return -EPIPE;
630         if (pcm->stream == SND_PCM_STREAM_CAPTURE &&
631             pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED &&
632             pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) {
633                 if (io->data->callback->transfer) {
634                         const snd_pcm_channel_area_t *areas;
635                         snd_pcm_uframes_t offset, size = UINT_MAX;
636                         snd_pcm_sframes_t result;
637
638                         snd_pcm_mmap_begin(pcm, &areas, &offset, &size);
639                         result = io->data->callback->transfer(io->data, areas, offset, size);
640                         if (result < 0)
641                                 return result;
642                 }
643         }
644         avail = snd_pcm_mmap_avail(pcm);
645         if (avail > io->avail_max)
646                 io->avail_max = avail;
647         return (snd_pcm_sframes_t)avail;
648 }
649
650 static int snd_pcm_ioplug_nonblock(snd_pcm_t *pcm, int nonblock)
651 {
652         ioplug_priv_t *io = pcm->private_data;
653
654         io->data->nonblock = nonblock;
655         return 0;
656 }
657
658 static int snd_pcm_ioplug_poll_descriptors_count(snd_pcm_t *pcm)
659 {
660         ioplug_priv_t *io = pcm->private_data;
661
662         if (io->data->callback->poll_descriptors_count)
663                 return io->data->callback->poll_descriptors_count(io->data);
664         else
665                 return 1;
666 }
667
668 static int snd_pcm_ioplug_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space)
669 {
670         ioplug_priv_t *io = pcm->private_data;
671
672         if (io->data->callback->poll_descriptors)
673                 return io->data->callback->poll_descriptors(io->data, pfds, space);
674         if (pcm->poll_fd < 0)
675                 return -EIO;
676         if (space >= 1 && pfds) {
677                 pfds->fd = pcm->poll_fd;
678                 pfds->events = pcm->poll_events | POLLERR | POLLNVAL;
679         } else {
680                 return 0;
681         }
682         return 1;
683 }
684
685 static int snd_pcm_ioplug_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
686 {
687         ioplug_priv_t *io = pcm->private_data;
688
689         if (io->data->callback->poll_revents)
690                 return io->data->callback->poll_revents(io->data, pfds, nfds, revents);
691         else
692                 *revents = pfds->revents;
693         return 0;
694 }
695
696 static int snd_pcm_ioplug_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
697 {
698         return 0;
699 }
700
701 static int snd_pcm_ioplug_async(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
702                                 int sig ATTRIBUTE_UNUSED,
703                                 pid_t pid ATTRIBUTE_UNUSED)
704 {
705         return -ENOSYS;
706 }
707
708 static int snd_pcm_ioplug_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
709 {
710         return 0;
711 }
712
713 static void snd_pcm_ioplug_dump(snd_pcm_t *pcm, snd_output_t *out)
714 {
715         ioplug_priv_t *io = pcm->private_data;
716
717         if (io->data->callback->dump)
718                 io->data->callback->dump(io->data, out);
719         else {
720                 if (io->data->name)
721                         snd_output_printf(out, "%s\n", io->data->name);
722                 else
723                         snd_output_printf(out, "IO-PCM Plugin\n");
724                 if (pcm->setup) {
725                         snd_output_printf(out, "Its setup is:\n");
726                         snd_pcm_dump_setup(pcm, out);
727                 }
728         }
729 }
730
731 static void clear_io_params(ioplug_priv_t *io)
732 {
733         int i;
734         for (i = 0; i < SND_PCM_IOPLUG_HW_PARAMS; i++)
735                 snd_ext_parm_clear(&io->params[i]);
736 }
737
738 static int snd_pcm_ioplug_close(snd_pcm_t *pcm)
739 {
740         ioplug_priv_t *io = pcm->private_data;
741
742         clear_io_params(io);
743         if (io->data->callback->close)
744                 io->data->callback->close(io->data);
745         free(io);
746
747         return 0;
748 }
749
750 static const snd_pcm_ops_t snd_pcm_ioplug_ops = {
751         .close = snd_pcm_ioplug_close,
752         .nonblock = snd_pcm_ioplug_nonblock,
753         .async = snd_pcm_ioplug_async,
754         .info = snd_pcm_ioplug_info,
755         .hw_refine = snd_pcm_ioplug_hw_refine,
756         .hw_params = snd_pcm_ioplug_hw_params,
757         .hw_free = snd_pcm_ioplug_hw_free,
758         .sw_params = snd_pcm_ioplug_sw_params,
759         .channel_info = snd_pcm_ioplug_channel_info,
760         .dump = snd_pcm_ioplug_dump,
761         .mmap = snd_pcm_ioplug_mmap,
762         .munmap = snd_pcm_ioplug_munmap,
763 };
764
765 static const snd_pcm_fast_ops_t snd_pcm_ioplug_fast_ops = {
766         .status = snd_pcm_ioplug_status,
767         .prepare = snd_pcm_ioplug_prepare,
768         .reset = snd_pcm_ioplug_reset,
769         .start = snd_pcm_ioplug_start,
770         .drop = snd_pcm_ioplug_drop,
771         .drain = snd_pcm_ioplug_drain,
772         .pause = snd_pcm_ioplug_pause,
773         .state = snd_pcm_ioplug_state,
774         .hwsync = snd_pcm_ioplug_hwsync,
775         .delay = snd_pcm_ioplug_delay,
776         .resume = snd_pcm_ioplug_resume,
777         .link = NULL,
778         .link_slaves = NULL,
779         .unlink = NULL,
780         .rewindable = snd_pcm_ioplug_rewindable,
781         .rewind = snd_pcm_ioplug_rewind,
782         .forwardable = snd_pcm_ioplug_forwardable,
783         .forward = snd_pcm_ioplug_forward,
784         .writei = snd_pcm_ioplug_writei,
785         .writen = snd_pcm_ioplug_writen,
786         .readi = snd_pcm_ioplug_readi,
787         .readn = snd_pcm_ioplug_readn,
788         .avail_update = snd_pcm_ioplug_avail_update,
789         .mmap_commit = snd_pcm_ioplug_mmap_commit,
790         .htimestamp = snd_pcm_generic_real_htimestamp,
791         .poll_descriptors_count = snd_pcm_ioplug_poll_descriptors_count,
792         .poll_descriptors = snd_pcm_ioplug_poll_descriptors,
793         .poll_revents = snd_pcm_ioplug_poll_revents,
794 };
795
796 #endif /* !DOC_HIDDEN */
797
798 /*
799  * Exported functions
800  */
801
802 /*! \page pcm_external_plugins PCM External Plugin SDK
803
804 \section pcm_ioplug External Plugin: I/O Plugin
805
806 The I/O-type plugin is a PCM plugin to work as the input or output terminal point,
807 i.e. as a user-space PCM driver.
808
809 The new plugin is created via #snd_pcm_ioplug_create() function.
810 The first argument is a pointer of the pluging information.  Some of
811 this struct must be initialized in prior to call
812 #snd_pcm_ioplug_create().  Then the function fills other fields in
813 return.  The rest arguments, name, stream and mode, are usually
814 identical with the values passed from the ALSA plugin constructor.
815
816 The following fields are mandatory: version, name, callback.
817 Otherfields are optional and should be initialized with zero.
818
819 The constant #SND_PCM_IOPLUG_VERSION must be passed to the version
820 field for the version check in alsa-lib.  A non-NULL ASCII string
821 has to be passed to the name field.  The callback field contains the 
822 table of callback functions for this plugin (defined as
823 #snd_pcm_ioplug_callback_t).
824
825 flags field specifies the optional bit-flags.  poll_fd and poll_events
826 specify the poll file descriptor and the corresponding poll events
827 (POLLIN, POLLOUT) for the plugin.  If the plugin requires multiple
828 poll descriptors or poll descriptor(s) dynamically varying, set
829 poll_descriptors and poll_descriptors_count callbacks to the callback
830 table.  Then the poll_fd and poll_events field are ignored.
831
832 mmap_rw specifies whether the plugin behaves in the pseudo mmap mode.
833 When this value is set to 1, the plugin creates always a local buffer
834 and performs read/write calls using this buffer as if it's mmapped.
835 The address of local buffer can be obtained via
836 #snd_pcm_ioplug_mmap_areas() function.
837 When poll_fd, poll_events and mmap_rw fields are changed after
838 #snd_pcm_ioplug_create(), call #snd_pcm_ioplug_reinit_status() to
839 reflect the changes.
840
841 The driver can set an arbitrary value (pointer) to private_data
842 field to refer its own data in the callbacks.
843
844 The rest fields are filled by #snd_pcm_ioplug_create().  The pcm field
845 is the resultant PCM handle.  The others are the current status of the
846 PCM.
847
848 The callback functions in #snd_pcm_ioplug_callback_t define the real
849 behavior of the driver.
850 At least, start, stop and pointer callbacks must be given.  Other
851 callbacks are optional.  The start and stop callbacks are called when
852 the PCM stream is started and stopped, repsectively.  The pointer
853 callback returns the current DMA position, which may be called at any
854 time.
855
856 The transfer callback is called when any data transfer happens.  It
857 receives the area array, offset and the size to transfer.  The area
858 array contains the array of snd_pcm_channel_area_t with the elements
859 of number of channels.
860
861 When the PCM is closed, close callback is called.  If the driver
862 allocates any internal buffers, they should be released in this
863 callback.  The hw_params and hw_free callbacks are called when
864 hw_params are set and reset, respectively.  Note that they may be
865 called multiple times according to the application.  Similarly,
866 sw_params callback is called when sw_params is set or changed.
867
868 The prepare, drain, pause and resume callbacks are called when
869 #snd_pcm_prepare(), #snd_pcm_drain(), #snd_pcm_pause(), and
870 #snd_pcm_resume() are called.  The poll_descriptors_count and
871 poll_descriptors callbacks are used to return the multiple or dynamic
872 poll descriptors as mentioned above.  The poll_revents callback is
873 used to modify poll events.  If the driver needs to mangle the native
874 poll events to proper poll events for PCM, you can do it in this
875 callback.
876
877 Finally, the dump callback is used to print the status of the plugin.
878
879 The hw_params constraints can be defined via either
880 #snd_pcm_ioplug_set_param_minmax() and #snd_pcm_ioplug_set_param_list()
881 functions after calling #snd_pcm_ioplug_create().
882 The former defines the minimal and maximal acceptable values for the
883 given hw_params parameter (SND_PCM_IOPLUG_HW_XXX).
884 This function can't be used for the format parameter.  The latter
885 function specifies the available parameter values as the list.
886
887 To clear the parameter constraints, call #snd_pcm_ioplug_params_reset() function.
888
889 */
890
891 /**
892  * \brief Create an ioplug instance
893  * \param ioplug the ioplug handle
894  * \param name name of PCM
895  * \param stream stream direction
896  * \param mode PCM open mode
897  * \return 0 if successful, or a negative error code
898  *
899  * Creates the ioplug instance.
900  *
901  * The callback is the mandatory field of ioplug handle.  At least, start, stop and
902  * pointer callbacks must be set before calling this function.
903  *
904  */
905 int snd_pcm_ioplug_create(snd_pcm_ioplug_t *ioplug, const char *name,
906                           snd_pcm_stream_t stream, int mode)
907 {
908         ioplug_priv_t *io;
909         int err;
910         snd_pcm_t *pcm;
911
912         assert(ioplug && ioplug->callback);
913         assert(ioplug->callback->start &&
914                ioplug->callback->stop &&
915                ioplug->callback->pointer);
916
917         /* We support 1.0.0 to current */
918         if (ioplug->version < 0x010000 ||
919             ioplug->version > SND_PCM_IOPLUG_VERSION) {
920                 SNDERR("ioplug: Plugin version mismatch\n");
921                 return -ENXIO;
922         }
923
924         io = calloc(1, sizeof(*io));
925         if (! io)
926                 return -ENOMEM;
927
928         io->data = ioplug;
929         ioplug->state = SND_PCM_STATE_OPEN;
930         ioplug->stream = stream;
931
932         err = snd_pcm_new(&pcm, SND_PCM_TYPE_IOPLUG, name, stream, mode);
933         if (err < 0) {
934                 free(io);
935                 return err;
936         }
937
938         ioplug->pcm = pcm;
939         pcm->ops = &snd_pcm_ioplug_ops;
940         pcm->fast_ops = &snd_pcm_ioplug_fast_ops;
941         pcm->private_data = io;
942
943         snd_pcm_set_hw_ptr(pcm, &ioplug->hw_ptr, -1, 0);
944         snd_pcm_set_appl_ptr(pcm, &ioplug->appl_ptr, -1, 0);
945
946         snd_pcm_ioplug_reinit_status(ioplug);
947
948         return 0;
949 }
950
951 /**
952  * \brief Delete the ioplug instance
953  * \param ioplug the ioplug handle
954  * \return 0 if successful, or a negative error code
955  */
956 int snd_pcm_ioplug_delete(snd_pcm_ioplug_t *ioplug)
957 {
958         return snd_pcm_close(ioplug->pcm);
959 }
960
961
962 /**
963  * \brief Reset ioplug parameters
964  * \param ioplug the ioplug handle
965  *
966  * Resets the all parameters for the given ioplug handle.
967  */
968 void snd_pcm_ioplug_params_reset(snd_pcm_ioplug_t *ioplug)
969 {
970         ioplug_priv_t *io = ioplug->pcm->private_data;
971         clear_io_params(io);
972 }
973
974 /**
975  * \brief Set parameter as the list
976  * \param ioplug the ioplug handle
977  * \param type parameter type
978  * \param num_list number of available values
979  * \param list the list of available values
980  * \return 0 if successful, or a negative error code
981  *
982  * Sets the parameter as the list.
983  * The available values of the given parameter type is restricted to the ones of the given list.
984  */
985 int snd_pcm_ioplug_set_param_list(snd_pcm_ioplug_t *ioplug, int type, unsigned int num_list, const unsigned int *list)
986 {
987         ioplug_priv_t *io = ioplug->pcm->private_data;
988         if (type < 0 && type >= SND_PCM_IOPLUG_HW_PARAMS) {
989                 SNDERR("IOPLUG: invalid parameter type %d", type);
990                 return -EINVAL;
991         }
992         if (type == SND_PCM_IOPLUG_HW_PERIODS)
993                 io->params[type].integer = 1;
994         return snd_ext_parm_set_list(&io->params[type], num_list, list);
995 }
996
997 /**
998  * \brief Set parameter as the min/max values
999  * \param ioplug the ioplug handle
1000  * \param type parameter type
1001  * \param min the minimum value
1002  * \param max the maximum value
1003  * \return 0 if successful, or a negative error code
1004  *
1005  * Sets the parameter as the min/max values.
1006  * The available values of the given parameter type is restricted between the given
1007  * minimum and maximum values.
1008  */
1009 int snd_pcm_ioplug_set_param_minmax(snd_pcm_ioplug_t *ioplug, int type, unsigned int min, unsigned int max)
1010 {
1011         ioplug_priv_t *io = ioplug->pcm->private_data;
1012         if (type < 0 && type >= SND_PCM_IOPLUG_HW_PARAMS) {
1013                 SNDERR("IOPLUG: invalid parameter type %d", type);
1014                 return -EINVAL;
1015         }
1016         if (type == SND_PCM_IOPLUG_HW_ACCESS || type == SND_PCM_IOPLUG_HW_FORMAT) {
1017                 SNDERR("IOPLUG: invalid parameter type %d", type);
1018                 return -EINVAL;
1019         }
1020         if (type == SND_PCM_IOPLUG_HW_PERIODS)
1021                 io->params[type].integer = 1;
1022         return snd_ext_parm_set_minmax(&io->params[type], min, max);
1023 }
1024
1025 /**
1026  * \brief Reinitialize the poll and mmap status
1027  * \param ioplug the ioplug handle
1028  * \return 0 if successful, or a negative error code
1029  *
1030  * Reinitializes the poll and the mmap status of the PCM.
1031  * Call this function to propagate the status change in the ioplug instance to
1032  * its PCM internals.
1033  */
1034 int snd_pcm_ioplug_reinit_status(snd_pcm_ioplug_t *ioplug)
1035 {
1036         ioplug->pcm->poll_fd = ioplug->poll_fd;
1037         ioplug->pcm->poll_events = ioplug->poll_events;
1038         ioplug->pcm->monotonic = (ioplug->flags & SND_PCM_IOPLUG_FLAG_MONOTONIC) != 0;
1039         ioplug->pcm->mmap_rw = ioplug->mmap_rw;
1040         return 0;
1041 }
1042
1043 /**
1044  * \brief Get mmap area of ioplug
1045  * \param ioplug the ioplug handle
1046  * \return the mmap channel areas if available, or NULL
1047  *
1048  * Returns the mmap channel areas if available.  When mmap_rw field is not set,
1049  * this function always returns NULL.
1050  */
1051 const snd_pcm_channel_area_t *snd_pcm_ioplug_mmap_areas(snd_pcm_ioplug_t *ioplug)
1052 {
1053         if (ioplug->mmap_rw)
1054                 return snd_pcm_mmap_areas(ioplug->pcm);
1055         return NULL;
1056 }
1057
1058 /**
1059  * \brief Change the ioplug PCM status
1060  * \param ioplug the ioplug handle
1061  * \param state the PCM status
1062  * \return zero if successful or a negative error code
1063  *
1064  * Changes the PCM status of the ioplug to the given value.
1065  * This function can be used for external plugins to notify the status
1066  * change, e.g. XRUN.
1067  */
1068 int snd_pcm_ioplug_set_state(snd_pcm_ioplug_t *ioplug, snd_pcm_state_t state)
1069 {
1070         ioplug->state = state;
1071         return 0;
1072 }