Home | History | Annotate | Download | only in pcm
      1 /**
      2  * \file pcm/pcm_lfloat.c
      3  * \ingroup PCM_Plugins
      4  * \brief PCM Linear<->Float Conversion Plugin Interface
      5  * \author Jaroslav Kysela <perex (at) perex.cz>
      6  * \date 2001
      7  */
      8 /*
      9  *  PCM - Linear Integer <-> Linear Float conversion
     10  *  Copyright (c) 2001 by Jaroslav Kysela <perex (at) perex.cz>
     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 <byteswap.h>
     30 #include "pcm_local.h"
     31 #include "pcm_plugin.h"
     32 
     33 #include "plugin_ops.h"
     34 
     35 #ifndef DOC_HIDDEN
     36 
     37 typedef float float_t;
     38 typedef double double_t;
     39 
     40 #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ <= 91)
     41 #define BUGGY_GCC
     42 #endif
     43 
     44 #ifndef PIC
     45 /* entry for static linking */
     46 const char *_snd_module_pcm_lfloat = "";
     47 #endif
     48 
     49 typedef struct {
     50 	/* This field need to be the first */
     51 	snd_pcm_plugin_t plug;
     52 	unsigned int int32_idx;
     53 	unsigned int float32_idx;
     54 	snd_pcm_format_t sformat;
     55 	void (*func)(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset,
     56 		     const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset,
     57 		     unsigned int channels, snd_pcm_uframes_t frames,
     58 		     unsigned int get32idx, unsigned int put32floatidx);
     59 } snd_pcm_lfloat_t;
     60 
     61 int snd_pcm_lfloat_get_s32_index(snd_pcm_format_t format)
     62 {
     63 	int width, endian;
     64 
     65 	switch (format) {
     66 	case SND_PCM_FORMAT_FLOAT_LE:
     67 	case SND_PCM_FORMAT_FLOAT_BE:
     68 		width = 32;
     69 		break;
     70 	case SND_PCM_FORMAT_FLOAT64_LE:
     71 	case SND_PCM_FORMAT_FLOAT64_BE:
     72 		width = 64;
     73 		break;
     74 	default:
     75 		return -EINVAL;
     76 	}
     77 #ifdef SND_LITTLE_ENDIAN
     78 	endian = snd_pcm_format_big_endian(format);
     79 #else
     80 	endian = snd_pcm_format_little_endian(format);
     81 #endif
     82 	return ((width / 32)-1) * 2 + endian;
     83 }
     84 
     85 int snd_pcm_lfloat_put_s32_index(snd_pcm_format_t format)
     86 {
     87 	return snd_pcm_lfloat_get_s32_index(format);
     88 }
     89 
     90 #endif /* DOC_HIDDEN */
     91 
     92 #ifndef BUGGY_GCC
     93 
     94 #ifndef DOC_HIDDEN
     95 
     96 void snd_pcm_lfloat_convert_integer_float(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset,
     97 					  const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset,
     98 					  unsigned int channels, snd_pcm_uframes_t frames,
     99 					  unsigned int get32idx, unsigned int put32floatidx)
    100 {
    101 #define GET32_LABELS
    102 #define PUT32F_LABELS
    103 #include "plugin_ops.h"
    104 #undef PUT32F_LABELS
    105 #undef GET32_LABELS
    106 	void *get32 = get32_labels[get32idx];
    107 	void *put32float = put32float_labels[put32floatidx];
    108 	unsigned int channel;
    109 	for (channel = 0; channel < channels; ++channel) {
    110 		const char *src;
    111 		char *dst;
    112 		int src_step, dst_step;
    113 		snd_pcm_uframes_t frames1;
    114 		int32_t sample = 0;
    115 		snd_tmp_float_t tmp_float;
    116 		snd_tmp_double_t tmp_double;
    117 		const snd_pcm_channel_area_t *src_area = &src_areas[channel];
    118 		const snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
    119 		src = snd_pcm_channel_area_addr(src_area, src_offset);
    120 		dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
    121 		src_step = snd_pcm_channel_area_step(src_area);
    122 		dst_step = snd_pcm_channel_area_step(dst_area);
    123 		frames1 = frames;
    124 		while (frames1-- > 0) {
    125 			goto *get32;
    126 #define GET32_END sample_loaded
    127 #include "plugin_ops.h"
    128 #undef GET32_END
    129 		sample_loaded:
    130 			goto *put32float;
    131 #define PUT32F_END sample_put
    132 #include "plugin_ops.h"
    133 #undef PUT32F_END
    134 		sample_put:
    135 			src += src_step;
    136 			dst += dst_step;
    137 		}
    138 	}
    139 }
    140 
    141 void snd_pcm_lfloat_convert_float_integer(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset,
    142 					  const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset,
    143 					  unsigned int channels, snd_pcm_uframes_t frames,
    144 					  unsigned int put32idx, unsigned int get32floatidx)
    145 {
    146 #define PUT32_LABELS
    147 #define GET32F_LABELS
    148 #include "plugin_ops.h"
    149 #undef GET32F_LABELS
    150 #undef PUT32_LABELS
    151 	void *put32 = put32_labels[put32idx];
    152 	void *get32float = get32float_labels[get32floatidx];
    153 	unsigned int channel;
    154 	for (channel = 0; channel < channels; ++channel) {
    155 		const char *src;
    156 		char *dst;
    157 		int src_step, dst_step;
    158 		snd_pcm_uframes_t frames1;
    159 		int32_t sample = 0;
    160 		snd_tmp_float_t tmp_float;
    161 		snd_tmp_double_t tmp_double;
    162 		const snd_pcm_channel_area_t *src_area = &src_areas[channel];
    163 		const snd_pcm_channel_area_t *dst_area = &dst_areas[channel];
    164 		src = snd_pcm_channel_area_addr(src_area, src_offset);
    165 		dst = snd_pcm_channel_area_addr(dst_area, dst_offset);
    166 		src_step = snd_pcm_channel_area_step(src_area);
    167 		dst_step = snd_pcm_channel_area_step(dst_area);
    168 		frames1 = frames;
    169 		while (frames1-- > 0) {
    170 			goto *get32float;
    171 #define GET32F_END sample_loaded
    172 #include "plugin_ops.h"
    173 #undef GET32F_END
    174 		sample_loaded:
    175 			goto *put32;
    176 #define PUT32_END sample_put
    177 #include "plugin_ops.h"
    178 #undef PUT32_END
    179 		sample_put:
    180 			src += src_step;
    181 			dst += dst_step;
    182 		}
    183 	}
    184 }
    185 
    186 #endif /* DOC_HIDDEN */
    187 
    188 static int snd_pcm_lfloat_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
    189 {
    190 	snd_pcm_lfloat_t *lfloat = pcm->private_data;
    191 	int err;
    192 	snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM };
    193 	snd_pcm_format_mask_t lformat_mask = { SND_PCM_FMTBIT_LINEAR };
    194 	snd_pcm_format_mask_t fformat_mask = { SND_PCM_FMTBIT_FLOAT };
    195 	err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS,
    196 					 &access_mask);
    197 	if (err < 0)
    198 		return err;
    199 	err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_FORMAT,
    200 					 snd_pcm_format_linear(lfloat->sformat) ?
    201 					 &fformat_mask : &lformat_mask);
    202 	if (err < 0)
    203 		return err;
    204 	err = _snd_pcm_hw_params_set_subformat(params, SND_PCM_SUBFORMAT_STD);
    205 	if (err < 0)
    206 		return err;
    207 	params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
    208 	return 0;
    209 }
    210 
    211 static int snd_pcm_lfloat_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams)
    212 {
    213 	snd_pcm_lfloat_t *lfloat = pcm->private_data;
    214 	snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP };
    215 	_snd_pcm_hw_params_any(sparams);
    216 	_snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS,
    217 				   &saccess_mask);
    218 	_snd_pcm_hw_params_set_format(sparams, lfloat->sformat);
    219 	_snd_pcm_hw_params_set_subformat(sparams, SND_PCM_SUBFORMAT_STD);
    220 	return 0;
    221 }
    222 
    223 static int snd_pcm_lfloat_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
    224 					    snd_pcm_hw_params_t *sparams)
    225 {
    226 	int err;
    227 	unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
    228 			      SND_PCM_HW_PARBIT_RATE |
    229 			      SND_PCM_HW_PARBIT_PERIOD_SIZE |
    230 			      SND_PCM_HW_PARBIT_BUFFER_SIZE |
    231 			      SND_PCM_HW_PARBIT_PERIODS |
    232 			      SND_PCM_HW_PARBIT_PERIOD_TIME |
    233 			      SND_PCM_HW_PARBIT_BUFFER_TIME |
    234 			      SND_PCM_HW_PARBIT_TICK_TIME);
    235 	err = _snd_pcm_hw_params_refine(sparams, links, params);
    236 	if (err < 0)
    237 		return err;
    238 	return 0;
    239 }
    240 
    241 static int snd_pcm_lfloat_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params,
    242 					    snd_pcm_hw_params_t *sparams)
    243 {
    244 	int err;
    245 	unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
    246 			      SND_PCM_HW_PARBIT_RATE |
    247 			      SND_PCM_HW_PARBIT_PERIOD_SIZE |
    248 			      SND_PCM_HW_PARBIT_BUFFER_SIZE |
    249 			      SND_PCM_HW_PARBIT_PERIODS |
    250 			      SND_PCM_HW_PARBIT_PERIOD_TIME |
    251 			      SND_PCM_HW_PARBIT_BUFFER_TIME |
    252 			      SND_PCM_HW_PARBIT_TICK_TIME);
    253 	err = _snd_pcm_hw_params_refine(params, links, sparams);
    254 	if (err < 0)
    255 		return err;
    256 	return 0;
    257 }
    258 
    259 static int snd_pcm_lfloat_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
    260 {
    261 	return snd_pcm_hw_refine_slave(pcm, params,
    262 				       snd_pcm_lfloat_hw_refine_cprepare,
    263 				       snd_pcm_lfloat_hw_refine_cchange,
    264 				       snd_pcm_lfloat_hw_refine_sprepare,
    265 				       snd_pcm_lfloat_hw_refine_schange,
    266 				       snd_pcm_generic_hw_refine);
    267 }
    268 
    269 static int snd_pcm_lfloat_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
    270 {
    271 	snd_pcm_lfloat_t *lfloat = pcm->private_data;
    272 	snd_pcm_t *slave = lfloat->plug.gen.slave;
    273 	snd_pcm_format_t src_format, dst_format;
    274 	int err = snd_pcm_hw_params_slave(pcm, params,
    275 					  snd_pcm_lfloat_hw_refine_cchange,
    276 					  snd_pcm_lfloat_hw_refine_sprepare,
    277 					  snd_pcm_lfloat_hw_refine_schange,
    278 					  snd_pcm_generic_hw_params);
    279 	if (err < 0)
    280 		return err;
    281 	if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
    282 		err = INTERNAL(snd_pcm_hw_params_get_format)(params, &src_format);
    283 		dst_format = slave->format;
    284 	} else {
    285 		src_format = slave->format;
    286 		err = INTERNAL(snd_pcm_hw_params_get_format)(params, &dst_format);
    287 	}
    288 	if (snd_pcm_format_linear(src_format)) {
    289 		lfloat->int32_idx = snd_pcm_linear_get32_index(src_format, SND_PCM_FORMAT_S32);
    290 		lfloat->float32_idx = snd_pcm_lfloat_put_s32_index(dst_format);
    291 		lfloat->func = snd_pcm_lfloat_convert_integer_float;
    292 	} else {
    293 		lfloat->int32_idx = snd_pcm_linear_put32_index(SND_PCM_FORMAT_S32, dst_format);
    294 		lfloat->float32_idx = snd_pcm_lfloat_get_s32_index(src_format);
    295 		lfloat->func = snd_pcm_lfloat_convert_float_integer;
    296 	}
    297 	return 0;
    298 }
    299 
    300 static snd_pcm_uframes_t
    301 snd_pcm_lfloat_write_areas(snd_pcm_t *pcm,
    302 			   const snd_pcm_channel_area_t *areas,
    303 			   snd_pcm_uframes_t offset,
    304 			   snd_pcm_uframes_t size,
    305 			   const snd_pcm_channel_area_t *slave_areas,
    306 			   snd_pcm_uframes_t slave_offset,
    307 			   snd_pcm_uframes_t *slave_sizep)
    308 {
    309 	snd_pcm_lfloat_t *lfloat = pcm->private_data;
    310 	if (size > *slave_sizep)
    311 		size = *slave_sizep;
    312 	lfloat->func(slave_areas, slave_offset,
    313 		     areas, offset,
    314 		     pcm->channels, size,
    315 		     lfloat->int32_idx, lfloat->float32_idx);
    316 	*slave_sizep = size;
    317 	return size;
    318 }
    319 
    320 static snd_pcm_uframes_t
    321 snd_pcm_lfloat_read_areas(snd_pcm_t *pcm,
    322 			  const snd_pcm_channel_area_t *areas,
    323 			  snd_pcm_uframes_t offset,
    324 			  snd_pcm_uframes_t size,
    325 			  const snd_pcm_channel_area_t *slave_areas,
    326 			  snd_pcm_uframes_t slave_offset,
    327 			  snd_pcm_uframes_t *slave_sizep)
    328 {
    329 	snd_pcm_lfloat_t *lfloat = pcm->private_data;
    330 	if (size > *slave_sizep)
    331 		size = *slave_sizep;
    332 	lfloat->func(areas, offset,
    333 		     slave_areas, slave_offset,
    334 		     pcm->channels, size,
    335 		     lfloat->int32_idx, lfloat->float32_idx);
    336 	*slave_sizep = size;
    337 	return size;
    338 }
    339 
    340 static void snd_pcm_lfloat_dump(snd_pcm_t *pcm, snd_output_t *out)
    341 {
    342 	snd_pcm_lfloat_t *lfloat = pcm->private_data;
    343 	snd_output_printf(out, "Linear Integer <-> Linear Float conversion PCM (%s)\n",
    344 		snd_pcm_format_name(lfloat->sformat));
    345 	if (pcm->setup) {
    346 		snd_output_printf(out, "Its setup is:\n");
    347 		snd_pcm_dump_setup(pcm, out);
    348 	}
    349 	snd_output_printf(out, "Slave: ");
    350 	snd_pcm_dump(lfloat->plug.gen.slave, out);
    351 }
    352 
    353 static const snd_pcm_ops_t snd_pcm_lfloat_ops = {
    354 	.close = snd_pcm_generic_close,
    355 	.info = snd_pcm_generic_info,
    356 	.hw_refine = snd_pcm_lfloat_hw_refine,
    357 	.hw_params = snd_pcm_lfloat_hw_params,
    358 	.hw_free = snd_pcm_generic_hw_free,
    359 	.sw_params = snd_pcm_generic_sw_params,
    360 	.channel_info = snd_pcm_generic_channel_info,
    361 	.dump = snd_pcm_lfloat_dump,
    362 	.nonblock = snd_pcm_generic_nonblock,
    363 	.async = snd_pcm_generic_async,
    364 	.mmap = snd_pcm_generic_mmap,
    365 	.munmap = snd_pcm_generic_munmap,
    366 };
    367 
    368 /**
    369  * \brief Creates a new linear conversion PCM
    370  * \param pcmp Returns created PCM handle
    371  * \param name Name of PCM
    372  * \param sformat Slave (destination) format
    373  * \param slave Slave PCM handle
    374  * \param close_slave When set, the slave PCM handle is closed with copy PCM
    375  * \retval zero on success otherwise a negative error code
    376  * \warning Using of this function might be dangerous in the sense
    377  *          of compatibility reasons. The prototype might be freely
    378  *          changed in future.
    379  */
    380 int snd_pcm_lfloat_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sformat, snd_pcm_t *slave, int close_slave)
    381 {
    382 	snd_pcm_t *pcm;
    383 	snd_pcm_lfloat_t *lfloat;
    384 	int err;
    385 	assert(pcmp && slave);
    386 	if (snd_pcm_format_linear(sformat) != 1 &&
    387 	    snd_pcm_format_float(sformat) != 1)
    388 		return -EINVAL;
    389 	lfloat = calloc(1, sizeof(snd_pcm_lfloat_t));
    390 	if (!lfloat) {
    391 		return -ENOMEM;
    392 	}
    393 	snd_pcm_plugin_init(&lfloat->plug);
    394 	lfloat->sformat = sformat;
    395 	lfloat->plug.read = snd_pcm_lfloat_read_areas;
    396 	lfloat->plug.write = snd_pcm_lfloat_write_areas;
    397 	lfloat->plug.undo_read = snd_pcm_plugin_undo_read_generic;
    398 	lfloat->plug.undo_write = snd_pcm_plugin_undo_write_generic;
    399 	lfloat->plug.gen.slave = slave;
    400 	lfloat->plug.gen.close_slave = close_slave;
    401 
    402 	err = snd_pcm_new(&pcm, SND_PCM_TYPE_LINEAR_FLOAT, name, slave->stream, slave->mode);
    403 	if (err < 0) {
    404 		free(lfloat);
    405 		return err;
    406 	}
    407 	pcm->ops = &snd_pcm_lfloat_ops;
    408 	pcm->fast_ops = &snd_pcm_plugin_fast_ops;
    409 	pcm->private_data = lfloat;
    410 	pcm->poll_fd = slave->poll_fd;
    411 	pcm->poll_events = slave->poll_events;
    412 	pcm->monotonic = slave->monotonic;
    413 	snd_pcm_set_hw_ptr(pcm, &lfloat->plug.hw_ptr, -1, 0);
    414 	snd_pcm_set_appl_ptr(pcm, &lfloat->plug.appl_ptr, -1, 0);
    415 	*pcmp = pcm;
    416 
    417 	return 0;
    418 }
    419 
    420 /*! \page pcm_plugins
    421 
    422 \section pcm_plugins_lfloat Plugin: linear<->float
    423 
    424 This plugin converts linear to float samples and float to linear samples from master
    425 linear<->float conversion PCM to given slave PCM. The channel count, format and rate must
    426 match for both of them.
    427 
    428 \code
    429 pcm.name {
    430         type lfloat             # Linear<->Float conversion PCM
    431         slave STR               # Slave name
    432         # or
    433         slave {                 # Slave definition
    434                 pcm STR         # Slave PCM name
    435                 # or
    436                 pcm { }         # Slave PCM definition
    437                 format STR      # Slave format
    438         }
    439 }
    440 \endcode
    441 
    442 \subsection pcm_plugins_lfloat_funcref Function reference
    443 
    444 <UL>
    445   <LI>snd_pcm_lfloat_open()
    446   <LI>_snd_pcm_lfloat_open()
    447 </UL>
    448 
    449 */
    450 
    451 /**
    452  * \brief Creates a new linear<->float conversion PCM
    453  * \param pcmp Returns created PCM handle
    454  * \param name Name of PCM
    455  * \param root Root configuration node
    456  * \param conf Configuration node with copy PCM description
    457  * \param stream Stream type
    458  * \param mode Stream mode
    459  * \retval zero on success otherwise a negative error code
    460  * \warning Using of this function might be dangerous in the sense
    461  *          of compatibility reasons. The prototype might be freely
    462  *          changed in future.
    463  */
    464 int _snd_pcm_lfloat_open(snd_pcm_t **pcmp, const char *name,
    465 			 snd_config_t *root, snd_config_t *conf,
    466 			 snd_pcm_stream_t stream, int mode)
    467 {
    468 	snd_config_iterator_t i, next;
    469 	int err;
    470 	snd_pcm_t *spcm;
    471 	snd_config_t *slave = NULL, *sconf;
    472 	snd_pcm_format_t sformat;
    473 	snd_config_for_each(i, next, conf) {
    474 		snd_config_t *n = snd_config_iterator_entry(i);
    475 		const char *id;
    476 		if (snd_config_get_id(n, &id) < 0)
    477 			continue;
    478 		if (snd_pcm_conf_generic_id(id))
    479 			continue;
    480 		if (strcmp(id, "slave") == 0) {
    481 			slave = n;
    482 			continue;
    483 		}
    484 		SNDERR("Unknown field %s", id);
    485 		return -EINVAL;
    486 	}
    487 	if (!slave) {
    488 		SNDERR("slave is not defined");
    489 		return -EINVAL;
    490 	}
    491 	err = snd_pcm_slave_conf(root, slave, &sconf, 1,
    492 				 SND_PCM_HW_PARAM_FORMAT, SCONF_MANDATORY, &sformat);
    493 	if (err < 0)
    494 		return err;
    495 	if (snd_pcm_format_linear(sformat) != 1 &&
    496 	    snd_pcm_format_float(sformat) != 1) {
    497 		snd_config_delete(sconf);
    498 		SNDERR("slave format is not linear integer or linear float");
    499 		return -EINVAL;
    500 	}
    501 	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
    502 	snd_config_delete(sconf);
    503 	if (err < 0)
    504 		return err;
    505 	err = snd_pcm_lfloat_open(pcmp, name, sformat, spcm, 1);
    506 	if (err < 0)
    507 		snd_pcm_close(spcm);
    508 	return err;
    509 }
    510 #ifndef DOC_HIDDEN
    511 SND_DLSYM_BUILD_VERSION(_snd_pcm_lfloat_open, SND_PCM_DLSYM_VERSION);
    512 #endif
    513 
    514 #else /* BUGGY_GCC */
    515 
    516 int snd_pcm_lfloat_open(snd_pcm_t **pcmp ATTRIBUTE_UNUSED,
    517 			const char *name ATTRIBUTE_UNUSED,
    518 			snd_pcm_format_t sformat ATTRIBUTE_UNUSED,
    519 			snd_pcm_t *slave ATTRIBUTE_UNUSED,
    520 			int close_slave ATTRIBUTE_UNUSED)
    521 {
    522 	SNDERR("please, upgrade your GCC to use lfloat plugin");
    523 	return -EINVAL;
    524 }
    525 
    526 int _snd_pcm_lfloat_open(snd_pcm_t **pcmp ATTRIBUTE_UNUSED,
    527 			 const char *name ATTRIBUTE_UNUSED,
    528 			 snd_config_t *root ATTRIBUTE_UNUSED,
    529 			 snd_config_t *conf ATTRIBUTE_UNUSED,
    530 			 snd_pcm_stream_t stream ATTRIBUTE_UNUSED,
    531 			 int mode ATTRIBUTE_UNUSED)
    532 {
    533 	SNDERR("please, upgrade your GCC to use lfloat plugin");
    534 	return -EINVAL;
    535 }
    536 
    537 #endif /* BUGGY_GCC */
    538