Home | History | Annotate | Download | only in pcm
      1 /**
      2  * \file pcm/pcm_ioplug.c
      3  * \ingroup Plugin_SDK
      4  * \brief I/O Plugin SDK
      5  * \author Takashi Iwai <tiwai (at) suse.de>
      6  * \date 2005
      7  */
      8 /*
      9  *  PCM - External I/O Plugin SDK
     10  *  Copyright (c) 2005 by Takashi Iwai <tiwai (at) 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_iplug_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 }
   1073