]> git.alsa-project.org Git - alsa-lib.git/commitdiff
New hw_params implementation
authorAbramo Bagnara <abramo@alsa-project.org>
Thu, 21 Dec 2000 20:44:10 +0000 (20:44 +0000)
committerAbramo Bagnara <abramo@alsa-project.org>
Thu, 21 Dec 2000 20:44:10 +0000 (20:44 +0000)
28 files changed:
aserver/aserver.c
include/aserver.h
include/pcm.h
src/pcm/Makefile.am
src/pcm/interval.c [new file with mode: 0644]
src/pcm/interval.h [new file with mode: 0644]
src/pcm/interval_inline.h [new file with mode: 0644]
src/pcm/mask.c [new file with mode: 0644]
src/pcm/mask.h [new file with mode: 0644]
src/pcm/mask_inline.h [new file with mode: 0644]
src/pcm/pcm.c
src/pcm/pcm_adpcm.c
src/pcm/pcm_alaw.c
src/pcm/pcm_copy.c
src/pcm/pcm_file.c
src/pcm/pcm_hw.c
src/pcm/pcm_linear.c
src/pcm/pcm_local.h
src/pcm/pcm_mulaw.c
src/pcm/pcm_multi.c
src/pcm/pcm_null.c
src/pcm/pcm_params.c [new file with mode: 0644]
src/pcm/pcm_plug.c
src/pcm/pcm_plugin.h
src/pcm/pcm_rate.c
src/pcm/pcm_route.c
src/pcm/pcm_share.c
src/pcm/pcm_shm.c

index 8c07a8dce88acb4ba5d961c4c0a7f0da916de9a9..cf8119ce976870e141d0168922c19b5eb0d0e56f 100644 (file)
@@ -379,8 +379,8 @@ int pcm_shm_cmd(client_t *client)
        case SND_PCM_IOCTL_INFO:
                ctrl->result = snd_pcm_info(pcm, (snd_pcm_info_t *) &ctrl->u.info);
                break;
-       case SND_PCM_IOCTL_HW_INFO:
-               ctrl->result = snd_pcm_hw_info(pcm, (snd_pcm_hw_info_t *) &ctrl->u.hw_info);
+       case SND_PCM_IOCTL_HW_REFINE:
+               ctrl->result = snd_pcm_hw_refine(pcm, (snd_pcm_hw_params_t *) &ctrl->u.hw_refine);
                break;
        case SND_PCM_IOCTL_HW_PARAMS:
                ctrl->result = snd_pcm_hw_params(pcm, (snd_pcm_hw_params_t *) &ctrl->u.hw_params);
index db8439e62d8b1db6a87498c235b7b88b2a44e493..f66944c7b9e99b4948517fa7180c3cb1b8739e18 100644 (file)
@@ -42,7 +42,7 @@ typedef struct {
                        pid_t pid;
                } async;
                snd_pcm_info_t info;
-               snd_pcm_hw_info_t hw_info;
+               snd_pcm_hw_params_t hw_refine;
                snd_pcm_hw_params_t hw_params;
                snd_pcm_sw_params_t sw_params;
                snd_pcm_dig_params_t dig_params;
index 9203e4e5a87a7a051bbdb4f5098291172007e73e..01ba31497bc059bff29f3ca688e7ae2dc39d8813 100644 (file)
@@ -35,18 +35,6 @@ typedef enum _snd_pcm_type {
        SND_PCM_TYPE_LBSERVER,
 } snd_pcm_type_t;
 
-enum {
-       SND_PCM_RULE_PAR_MASK = 0x00ff,
-       SND_PCM_RULE_REL_LT = 0x100,
-       SND_PCM_RULE_REL_GT = 0x200,
-       SND_PCM_RULE_REL_EQ = 0x300,
-       SND_PCM_RULE_REL_LE = 0x400,
-       SND_PCM_RULE_REL_GE = 0x500,
-       SND_PCM_RULE_REL_NEAR = 0x600,
-       SND_PCM_RULE_REL_BITS = 0x700,
-       SND_PCM_RULE_REL_MASK = 0xff00
-};
-
 typedef struct _snd_pcm_channel_area {
        void *addr;                     /* base address of channel samples */
        unsigned int first;             /* offset to first sample in bits */
@@ -69,8 +57,7 @@ int snd_pcm_poll_descriptor(snd_pcm_t *pcm);
 int snd_pcm_nonblock(snd_pcm_t *pcm, int nonblock);
 int snd_pcm_async(snd_pcm_t *pcm, int sig, pid_t pid);
 int snd_pcm_info(snd_pcm_t *pcm, snd_pcm_info_t *info);
-int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info);
-int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
+int snd_pcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
 int snd_pcm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params);
 int snd_pcm_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t *info);
 int snd_pcm_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t *params);
@@ -92,7 +79,7 @@ ssize_t snd_pcm_readn(snd_pcm_t *pcm, void **bufs, size_t size);
 int snd_pcm_dump_hw_setup(snd_pcm_t *pcm, FILE *fp);
 int snd_pcm_dump_sw_setup(snd_pcm_t *pcm, FILE *fp);
 int snd_pcm_dump_setup(snd_pcm_t *pcm, FILE *fp);
-int snd_pcm_dump_hw_info(snd_pcm_hw_info_t *info, FILE *fp);
+int snd_pcm_dump_hw_params(snd_pcm_hw_params_t *params, FILE *fp);
 int snd_pcm_dump_hw_params_fail(snd_pcm_hw_params_t *params, FILE *fp);
 int snd_pcm_dump_sw_params_fail(snd_pcm_sw_params_t *params, FILE *fp);
 int snd_pcm_dump(snd_pcm_t *pcm, FILE *fp);
@@ -103,8 +90,58 @@ int snd_pcm_unlink(snd_pcm_t *pcm);
 int snd_pcm_wait(snd_pcm_t *pcm, int timeout);
 ssize_t snd_pcm_avail_update(snd_pcm_t *pcm);
 int snd_pcm_set_avail_min(snd_pcm_t *pcm, size_t size);
-void snd_pcm_hw_info_any(snd_pcm_hw_info_t *info);
-int snd_pcm_hw_params_info(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_hw_info_t *info);
+
+typedef struct _mask mask_t;
+size_t mask_sizeof();
+void mask_none(mask_t *mask);
+void mask_all(mask_t *mask);
+void mask_load(mask_t *mask, unsigned int msk);
+int mask_empty(const mask_t *mask);
+void mask_set(mask_t *mask, unsigned int val);
+void mask_reset(mask_t *mask, unsigned int val);
+void mask_copy(mask_t *mask, const mask_t *v);
+int mask_test(const mask_t *mask, unsigned int val);
+void mask_intersect(mask_t *mask, const mask_t *v);
+int mask_eq(const mask_t *a, const mask_t *b);
+int mask_single(const mask_t *mask);
+
+int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
+int snd_pcm_hw_params_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                          unsigned int par, unsigned int val);
+int snd_pcm_hw_params_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                         unsigned int par, unsigned int val);
+int snd_pcm_hw_params_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                         unsigned int par, unsigned int val);
+int snd_pcm_hw_params_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                            unsigned int par, unsigned int min, unsigned int max);
+int snd_pcm_hw_params_first(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                           unsigned int par);
+int snd_pcm_hw_params_last(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                          unsigned int par);
+int snd_pcm_hw_params_set(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                         unsigned int par, unsigned int val);
+int snd_pcm_hw_params_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                          unsigned int par, const mask_t *mask);
+int snd_pcm_hw_params_info_rate(const snd_pcm_hw_params_t *params,
+                               unsigned int *rate_num,
+                               unsigned int *rate_den);
+int snd_pcm_hw_params_info_msbits(const snd_pcm_hw_params_t *params);
+int snd_pcm_hw_params_info_flags(const snd_pcm_hw_params_t *params);
+int snd_pcm_hw_params_info_fifo_size(const snd_pcm_hw_params_t *params);
+int snd_pcm_hw_params_info_dig_groups(const snd_pcm_hw_params_t *params);
+int snd_pcm_hw_params_value(const snd_pcm_hw_params_t *params,
+                           unsigned int var);
+const mask_t *snd_pcm_hw_params_value_mask(const snd_pcm_hw_params_t *params,
+                                          unsigned int var);
+const interval_t *snd_pcm_hw_params_value_interval(const snd_pcm_hw_params_t *params,
+                                                  unsigned int var);
+unsigned int snd_pcm_hw_params_value_min(const snd_pcm_hw_params_t *params,
+                                        unsigned int var);
+unsigned int snd_pcm_hw_params_value_max(const snd_pcm_hw_params_t *params,
+                                        unsigned int var);
+int snd_pcm_hw_params_test(const snd_pcm_hw_params_t *params,
+                          unsigned int var, unsigned int val);
+int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
 
 typedef struct _snd_pcm_strategy snd_pcm_strategy_t;
 
@@ -114,7 +151,7 @@ typedef struct _snd_pcm_strategy_simple_choices_list {
        unsigned int badness;
 } snd_pcm_strategy_simple_choices_list_t;
 
-int snd_pcm_hw_info_strategy(snd_pcm_t *pcm, snd_pcm_hw_info_t *info,
+int snd_pcm_hw_info_strategy(snd_pcm_t *pcm, snd_pcm_hw_params_t *info,
                             const snd_pcm_strategy_t *strategy);
 
 int snd_pcm_strategy_free(snd_pcm_strategy_t *strategy);
@@ -129,9 +166,9 @@ int snd_pcm_strategy_simple_choices(snd_pcm_strategy_t *strategy, int order,
                                    unsigned int param,
                                    unsigned int count,
                                    snd_pcm_strategy_simple_choices_list_t *choices);
-int snd_pcm_hw_info_try_explain_failure(snd_pcm_t *pcm,
-                                       snd_pcm_hw_info_t *fail,
-                                       snd_pcm_hw_info_t *success,
+int snd_pcm_hw_params_try_explain_failure(snd_pcm_t *pcm,
+                                       snd_pcm_hw_params_t *fail,
+                                       snd_pcm_hw_params_t *success,
                                        unsigned int depth,
                                        FILE *fp);
 
@@ -147,7 +184,12 @@ ssize_t snd_pcm_mmap_readi(snd_pcm_t *pcm, void *buffer, size_t size);
 ssize_t snd_pcm_mmap_writen(snd_pcm_t *pcm, void **bufs, size_t size);
 ssize_t snd_pcm_mmap_readn(snd_pcm_t *pcm, void **bufs, size_t size);
 
+const char *snd_pcm_access_name(unsigned int access);
 const char *snd_pcm_format_name(unsigned int format);
+const char *snd_pcm_subformat_name(unsigned int subformat);
+const char *snd_pcm_hw_param_name(unsigned int params);
+const char *snd_pcm_sw_param_name(unsigned int params);
+
 const char *snd_pcm_format_description(unsigned int format);
 int snd_pcm_format_value(const char* name);
 
index 351a378378957e60fcb084eae02cfabf0b785954..38e3892f11cb7845f89f63226be662a6062d6b91 100644 (file)
@@ -1,11 +1,13 @@
 
 EXTRA_LTLIBRARIES = libpcm.la
 
-libpcm_la_SOURCES = pcm.c pcm_hw.c pcm_plugin.c pcm_copy.c pcm_linear.c \
+libpcm_la_SOURCES = mask.c interval.c \
+                   pcm.c pcm_hw.c pcm_plugin.c pcm_copy.c pcm_linear.c \
                    pcm_route.c pcm_mulaw.c pcm_alaw.c pcm_adpcm.c \
                    pcm_rate.c pcm_plug.c pcm_misc.c pcm_mmap.c pcm_multi.c \
-                   pcm_shm.c pcm_file.c pcm_share.c pcm_null.c
-noinst_HEADERS = pcm_local.h pcm_plugin.h
+                   pcm_shm.c pcm_file.c pcm_share.c pcm_null.c pcm_params.c
+noinst_HEADERS = pcm_local.h pcm_plugin.h mask.h mask_inline.h \
+                interval.h interval_inline.h
 
 all: libpcm.la
 
diff --git a/src/pcm/interval.c b/src/pcm/interval.c
new file mode 100644 (file)
index 0000000..bd3982c
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ *  Interval functions
+ *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Library General Public License as
+ *   published by the Free Software Foundation; either version 2 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Library General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Library General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+  
+#define INTERVAL_C
+
+#include <sys/types.h>
+#include <limits.h>
+#include <errno.h>
+#include <assert.h>
+#include <linux/asound.h>
+#include "interval.h"
+
+static inline void div64_32(u_int64_t *n, u_int32_t div, u_int32_t *rem)
+{
+       *rem = *n % div;
+       *n /= div;
+}
+
+static inline unsigned int div32(unsigned int a, unsigned int b, 
+                                unsigned int *r)
+{
+       *r = a % b;
+       return a / b;
+}
+
+static inline unsigned int div_down(unsigned int a, unsigned int b)
+{
+       return a / b;
+}
+
+static inline unsigned int div_up(unsigned int a, unsigned int b)
+{
+       unsigned int r;
+       unsigned int q = div32(a, b, &r);
+       if (r)
+               ++q;
+       return q;
+}
+
+static inline unsigned int mul(unsigned int a, unsigned int b)
+{
+       if (div_down(UINT_MAX, a) < b)
+               return UINT_MAX;
+       return a * b;
+}
+
+static inline unsigned int add(unsigned int a, unsigned int b)
+{
+       if (a >= UINT_MAX - b)
+               return UINT_MAX;
+       return a + b;
+}
+
+static inline unsigned int sub(unsigned int a, unsigned int b)
+{
+       if (a > b)
+               return a - b;
+       return 0;
+}
+
+static inline unsigned int muldiv32(unsigned int a, unsigned int b,
+                                   unsigned int c, unsigned int *r)
+{
+       u_int64_t n = (u_int64_t) a * b;
+       div64_32(&n, c, r);
+       if (n >= UINT_MAX) {
+               *r = 0;
+               return UINT_MAX;
+       }
+       return n;
+}
+
+int interval_refine_min(interval_t *i, unsigned int min)
+{
+       int changed = 0;
+       int openmin = 0;
+       assert(!interval_empty(i));
+       if (i->min < min) {
+               i->min = min;
+               i->openmin = openmin;
+               changed = 1;
+       } else if (i->min == min && !i->openmin && openmin) {
+               i->openmin = 1;
+               changed = 1;
+       }
+       if (!i->real) {
+               if (i->openmin) {
+                       i->min++;
+                       i->openmin = 0;
+               }
+       }
+       if (i->min > i->max ||
+           (i->min == i->max && (i->openmin || i->openmax))) {
+               i->empty = 1;
+               return -EINVAL;
+       }
+       return changed;
+}
+
+int interval_refine_max(interval_t *i, unsigned int max)
+{
+       int changed = 0;
+       int openmax = 1;
+       max = add(max, 1);
+       assert(!interval_empty(i));
+       if (i->max > max) {
+               i->max = max;
+               i->openmax = openmax;
+               changed = 1;
+       } else if (i->max == max && !i->openmax && openmax) {
+               i->openmax = 1;
+               changed = 1;
+       }
+       if (!i->real) {
+               if (i->openmax) {
+                       i->max--;
+                       i->openmax = 0;
+               }
+       }
+       if (i->min > i->max ||
+           (i->min == i->max && (i->openmin || i->openmax))) {
+               i->empty = 1;
+               return -EINVAL;
+       }
+       return changed;
+}
+
+/* r <- v */
+int interval_refine(interval_t *i, const interval_t *v)
+{
+       int changed = 0;
+       assert(!interval_empty(i));
+       if (i->min < v->min) {
+               i->min = v->min;
+               i->openmin = v->openmin;
+               changed = 1;
+       } else if (i->min == v->min && !i->openmin && v->openmin) {
+               i->openmin = 1;
+               changed = 1;
+       }
+       if (i->max > v->max) {
+               i->max = v->max;
+               i->openmax = v->openmax;
+               changed = 1;
+       } else if (i->max == v->max && !i->openmax && v->openmax) {
+               i->openmax = 1;
+               changed = 1;
+       }
+       if (!i->real) {
+               if (i->openmin) {
+                       i->min++;
+                       i->openmin = 0;
+               }
+               if (i->openmax) {
+                       i->max--;
+                       i->openmax = 0;
+               }
+       }
+       if (i->min > i->max ||
+           (i->min == i->max && (i->openmin || i->openmax))) {
+               i->empty = 1;
+               return -EINVAL;
+       }
+       return changed;
+}
+
+int interval_refine_first(interval_t *i)
+{
+       assert(!interval_empty(i));
+       if (i->min == i->max ||
+               (i->min + 1 == i->max && i->openmin && i->openmax))
+               return 0;
+       i->max = i->min;
+       i->openmax = i->openmin;
+       if (i->openmax)
+               i->max++;
+       return 1;
+}
+
+int interval_refine_last(interval_t *i)
+{
+       assert(!interval_empty(i));
+       if (i->min == i->max ||
+               (i->min + 1 == i->max && i->openmin && i->openmax))
+               return 0;
+       i->min = i->max;
+       i->openmin = i->openmax;
+       if (i->openmin)
+               i->min--;
+       return 1;
+}
+
+int interval_refine_set(interval_t *i, unsigned int val)
+{
+       interval_t t;
+       t.min = val;
+       t.openmin = 0;
+       t.max = add(val, 1);
+       t.openmax = 1;
+       return interval_refine(i, &t);
+}
+
+/* a <- b * c */
+int interval_mul(interval_t *a, const interval_t *b, const interval_t *c)
+{
+       interval_t t;
+       assert(!a->empty && !b->empty && !c->empty);
+       t.min = mul(b->min, c->min);
+       t.openmin = (b->openmin || c->openmin);
+       t.max = mul(b->max,  c->max);
+       t.openmax = (b->openmax || c->openmax);
+       return interval_refine(a, &t);
+}
+
+/* a <- b / c */
+int interval_div(interval_t *a, const interval_t *b, const interval_t *c)
+{
+       interval_t t;
+       unsigned int r;
+       assert(!a->empty && !b->empty && !c->empty);
+       t.min = div32(b->min, c->max, &r);
+       t.openmin = (r || b->openmin || c->openmax);
+       t.max = div32(b->max, c->min, &r);
+       if (r) {
+               t.max++;
+               t.openmax = 1;
+       } else
+               t.openmax = (b->openmax || c->openmin);
+       return interval_refine(a, &t);
+}
+
+
+/* a <- b * c / k */
+int interval_muldivk(interval_t *a, unsigned int k,
+                   const interval_t *b, const interval_t *c)
+{
+       interval_t t;
+       unsigned int r;
+       assert(!a->empty && !b->empty && !c->empty);
+       t.min = muldiv32(b->min, c->min, k, &r);
+       t.openmin = (r || b->openmin || c->openmin);
+       t.max = muldiv32(b->max, c->max, k, &r);
+       if (r) {
+               t.max++;
+               t.openmax = 1;
+       } else
+               t.openmax = (b->openmax || c->openmax);
+       return interval_refine(a, &t);
+}
+
+/* a <- b * k / c */
+int interval_mulkdiv(interval_t *a, unsigned int k,
+                    const interval_t *b, const interval_t *c)
+{
+       interval_t t;
+       unsigned int r;
+       assert(!a->empty && !b->empty && !c->empty);
+       t.min = muldiv32(b->min, k, c->max, &r);
+       t.openmin = (r || b->openmin || c->openmax);
+       t.max = muldiv32(b->max, k, c->min, &r);
+       if (r) {
+               t.max++;
+               t.openmax = 1;
+       } else
+               t.openmax = (b->openmax || c->openmin);
+       return interval_refine(a, &t);
+}
+
+void interval_print(const interval_t *i, FILE *fp)
+{
+       if (interval_single(i)) {
+               fprintf(fp, "%u", interval_value(i));
+       } else {
+               fprintf(fp, "%c%u %u%c",
+                       i->openmin ? '(' : '[',
+                       i->min, i->max,
+                       i->openmax ? ')' : ']');
+       }
+}
diff --git a/src/pcm/interval.h b/src/pcm/interval.h
new file mode 100644 (file)
index 0000000..6fd91f7
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *  Interval header
+ *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Library General Public License as
+ *   published by the Free Software Foundation; either version 2 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Library General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Library General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+  
+#include <stdio.h>
+
+#ifdef INTERVAL_C
+#include "interval_inline.h"
+#endif
+
+void interval_all(interval_t *i);
+void interval_setreal(interval_t *i);
+int interval_empty(const interval_t *i);
+int interval_single(const interval_t *i);
+int interval_value(const interval_t *i);
+int interval_min(const interval_t *i);
+int interval_max(const interval_t *i);
+int interval_test(const interval_t *i, unsigned int val);
+int interval_refine_min(interval_t *i, unsigned int min);
+int interval_refine_max(interval_t *i, unsigned int max);
+int interval_refine(interval_t *i, const interval_t *v);
+int interval_refine_first(interval_t *i);
+int interval_refine_last(interval_t *i);
+int interval_refine_set(interval_t *i, unsigned int val);
+int interval_mul(interval_t *a, const interval_t *b, const interval_t *c);
+int interval_div(interval_t *a, const interval_t *b, const interval_t *c);
+int interval_muldivk(interval_t *a, unsigned int k,
+                    const interval_t *b, const interval_t *c);
+int interval_mulkdiv(interval_t *a, unsigned int k,
+                    const interval_t *b, const interval_t *c);
+void interval_copy(interval_t *dst, const interval_t *src);
+void interval_print(const interval_t *i, FILE *fp);
+int interval_eq(const interval_t *i1, const interval_t *i2);
diff --git a/src/pcm/interval_inline.h b/src/pcm/interval_inline.h
new file mode 100644 (file)
index 0000000..845fec8
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ *  Interval inlines
+ *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Library General Public License as
+ *   published by the Free Software Foundation; either version 2 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Library General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Library General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+  
+#ifdef INTERVAL_C
+#define INLINE inline
+#else
+#define INLINE static inline
+#endif
+
+INLINE void interval_all(interval_t *i)
+{
+       i->min = 1;
+       i->max = UINT_MAX;
+}
+
+INLINE int interval_empty(const interval_t *i)
+{
+       return i->empty;
+}
+
+INLINE int interval_single(const interval_t *i)
+{
+       assert(!interval_empty(i));
+       return (i->min == i->max || 
+               (i->min + 1 == i->max && i->openmax));
+}
+
+INLINE int interval_value(const interval_t *i)
+{
+       assert(interval_single(i));
+       return i->min;
+}
+
+INLINE int interval_min(const interval_t *i)
+{
+       assert(!interval_empty(i));
+       return i->min;
+}
+
+INLINE int interval_max(const interval_t *i)
+{
+       unsigned int v;
+       assert(!interval_empty(i));
+       v = i->max;
+       if (i->openmax)
+               v--;
+       return v;
+}
+
+INLINE int interval_test(const interval_t *i, unsigned int val)
+{
+       return !((i->min > val || (i->min == val && i->openmin) ||
+                 i->max < val || (i->max == val && i->openmax)));
+}
+
+INLINE void interval_copy(interval_t *d, const interval_t *s)
+{
+       *d = *s;
+}
+
+INLINE void interval_setreal(interval_t *i)
+{
+       i->real = 1;
+}
+
+INLINE int interval_eq(const interval_t *i1, const interval_t *i2)
+{
+       if (i1->empty)
+               return i2->empty;
+       if (i2->empty)
+               return i1->empty;
+       return i1->min == i2->min && i1->openmin == i2->openmin &&
+               i1->max == i2->max && i1->openmax == i2->openmax;
+}
+
diff --git a/src/pcm/mask.c b/src/pcm/mask.c
new file mode 100644 (file)
index 0000000..124ea7e
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *  Mask functions
+ *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Library General Public License as
+ *   published by the Free Software Foundation; either version 2 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Library General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Library General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+  
+#define MASK_C
+
+#include <sys/types.h>
+#include <limits.h>
+#include <errno.h>
+#include <assert.h>
+#include "asoundlib.h"
+#include "mask.h"
+
diff --git a/src/pcm/mask.h b/src/pcm/mask.h
new file mode 100644 (file)
index 0000000..8324bbd
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ *  Mask header
+ *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Library General Public License as
+ *   published by the Free Software Foundation; either version 2 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Library General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Library General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+  
+#include <sys/types.h>
+#include <limits.h>
+#include <errno.h>
+#include <assert.h>
+#include "asoundlib.h"
+
+#define MASK_MAX 32
+
+#ifdef MASK_C
+#include "mask_inline.h"
+#endif
+
+void mask_none(mask_t *mask);
+void mask_all(mask_t *mask);
+void mask_load(mask_t *mask, unsigned int msk);
+int mask_empty(const mask_t *mask);
+void mask_set(mask_t *mask, unsigned int val);
+void mask_reset(mask_t *mask, unsigned int val);
+void mask_copy(mask_t *mask, const mask_t *v);
+int mask_test(const mask_t *mask, unsigned int val);
+void mask_intersect(mask_t *mask, const mask_t *v);
+unsigned int mask_count(const mask_t *mask);
+unsigned int mask_min(const mask_t *mask);
+unsigned int mask_max(const mask_t *mask);
+void mask_set_range(mask_t *mask, unsigned int from, unsigned int to);
+void mask_reset_range(mask_t *mask, unsigned int from, unsigned int to);
+void mask_leave(mask_t *mask, unsigned int val);
+int mask_eq(const mask_t *mask, const mask_t *v);
+int mask_single(const mask_t *mask);
+int mask_refine(mask_t *mask, const mask_t *v);
+int mask_refine_first(mask_t *mask);
+int mask_refine_last(mask_t *mask);
+int mask_refine_min(mask_t *mask, unsigned int val);
+int mask_refine_max(mask_t *mask, unsigned int val);
+int mask_refine_set(mask_t *mask, unsigned int val);
+int mask_value(const mask_t *mask);
diff --git a/src/pcm/mask_inline.h b/src/pcm/mask_inline.h
new file mode 100644 (file)
index 0000000..abfbfa4
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ *  Mask inlines
+ *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Library General Public License as
+ *   published by the Free Software Foundation; either version 2 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Library General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Library General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+  
+#ifdef MASK_C
+#define INLINE inline
+#else
+#define INLINE static inline
+#endif
+
+struct _mask {
+       unsigned int bits;
+};
+
+#define mask_bits(mask) ((mask)->bits)
+
+INLINE unsigned int ld2(u_int32_t v)
+{
+        unsigned r = 0;
+
+        if (v >= 0x10000) {
+                v >>= 16;
+                r += 16;
+        }
+        if (v >= 0x100) {
+                v >>= 8;
+                r += 8;
+        }
+        if (v >= 0x10) {
+                v >>= 4;
+                r += 4;
+        }
+        if (v >= 4) {
+                v >>= 2;
+                r += 2;
+        }
+        if (v >= 2)
+                r++;
+        return r;
+}
+
+INLINE unsigned int hweight32(u_int32_t v)
+{
+        v = (v & 0x55555555) + ((v >> 1) & 0x55555555);
+        v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
+        v = (v & 0x0F0F0F0F) + ((v >> 4) & 0x0F0F0F0F);
+        v = (v & 0x00FF00FF) + ((v >> 8) & 0x00FF00FF);
+        return (v & 0x0000FFFF) + ((v >> 16) & 0x0000FFFF);
+}
+
+INLINE size_t mask_sizeof(void)
+{
+       return sizeof(mask_t);
+}
+
+INLINE void mask_none(mask_t *mask)
+{
+       mask_bits(mask) = 0;
+}
+
+INLINE void mask_all(mask_t *mask)
+{
+       mask_bits(mask) = ~0U;
+}
+
+INLINE void mask_load(mask_t *mask, unsigned int msk)
+{
+       mask_bits(mask) = msk;
+}
+
+INLINE int mask_empty(const mask_t *mask)
+{
+       return mask_bits(mask) == 0;
+}
+
+INLINE unsigned int mask_count(const mask_t *mask)
+{
+       return hweight32(mask_bits(mask));
+}
+
+INLINE unsigned int mask_min(const mask_t *mask)
+{
+       assert(!mask_empty(mask));
+       return ffs(mask_bits(mask)) - 1;
+}
+
+INLINE unsigned int mask_max(const mask_t *mask)
+{
+       assert(!mask_empty(mask));
+       return ld2(mask_bits(mask));
+}
+
+INLINE void mask_set(mask_t *mask, unsigned int val)
+{
+       assert(val <= MASK_MAX);
+       mask_bits(mask) |= (1U << val);
+}
+
+INLINE void mask_reset(mask_t *mask, unsigned int val)
+{
+       assert(val <= MASK_MAX);
+       mask_bits(mask) &= ~(1U << val);
+}
+
+INLINE void mask_set_range(mask_t *mask, unsigned int from, unsigned int to)
+{
+       assert(to <= MASK_MAX && from <= to);
+       mask_bits(mask) |= ((1U << (from - to + 1)) - 1) << from;
+}
+
+INLINE void mask_reset_range(mask_t *mask, unsigned int from, unsigned int to)
+{
+       assert(to <= MASK_MAX && from <= to);
+       mask_bits(mask) &= ~(((1U << (from - to + 1)) - 1) << from);
+}
+
+INLINE void mask_leave(mask_t *mask, unsigned int val)
+{
+       assert(val <= MASK_MAX);
+       mask_bits(mask) &= 1U << val;
+}
+
+INLINE void mask_intersect(mask_t *mask, const mask_t *v)
+{
+       mask_bits(mask) &= mask_bits(v);
+}
+
+INLINE int mask_eq(const mask_t *mask, const mask_t *v)
+{
+       return mask_bits(mask) == mask_bits(v);
+}
+
+INLINE void mask_copy(mask_t *mask, const mask_t *v)
+{
+       mask_bits(mask) = mask_bits(v);
+}
+
+INLINE int mask_test(const mask_t *mask, unsigned int val)
+{
+       assert(val <= MASK_MAX);
+       return mask_bits(mask) & (1U << val);
+}
+
+INLINE int mask_single(const mask_t *mask)
+{
+       assert(!mask_empty(mask));
+       return !(mask_bits(mask) & (mask_bits(mask) - 1));
+}
+
+INLINE int mask_refine(mask_t *mask, const mask_t *v)
+{
+       mask_t old;
+       assert(!mask_empty(mask));
+       mask_copy(&old, mask);
+       mask_intersect(mask, v);
+       if (mask_empty(mask))
+               return -EINVAL;
+       return !mask_eq(mask, &old);
+}
+
+INLINE int mask_refine_first(mask_t *mask)
+{
+       assert(!mask_empty(mask));
+       if (mask_single(mask))
+               return 0;
+       mask_leave(mask, mask_min(mask));
+       return 1;
+}
+
+INLINE int mask_refine_last(mask_t *mask)
+{
+       assert(!mask_empty(mask));
+       if (mask_single(mask))
+               return 0;
+       mask_leave(mask, mask_max(mask));
+       return 1;
+}
+
+INLINE int mask_refine_min(mask_t *mask, unsigned int val)
+{
+       assert(!mask_empty(mask));
+       if (mask_min(mask) >= val)
+               return 0;
+       mask_reset_range(mask, 0, val - 1);
+       if (mask_empty(mask))
+               return -EINVAL;
+       return 1;
+}
+
+INLINE int mask_refine_max(mask_t *mask, unsigned int val)
+{
+       assert(!mask_empty(mask));
+       if (mask_max(mask) <= val)
+               return 0;
+       mask_reset_range(mask, val + 1, MASK_MAX);
+       if (mask_empty(mask))
+               return -EINVAL;
+       return 1;
+}
+
+INLINE int mask_refine_set(mask_t *mask, unsigned int val)
+{
+       int changed;
+       assert(!mask_empty(mask));
+       changed = !mask_single(mask);
+       mask_leave(mask, val);
+       if (mask_empty(mask))
+               return -EINVAL;
+       return changed;
+}
+
+INLINE int mask_value(const mask_t *mask)
+{
+       assert(!mask_empty(mask));
+       return mask_min(mask);
+}
index 2b87359389981518e882f0d0fa38b43c6473d655..7de083cb1b816efc57ac9e9cd585b8e38b463b27 100644 (file)
@@ -94,64 +94,6 @@ int snd_pcm_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
        return pcm->ops->info(pcm->op_arg, info);
 }
 
-int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info)
-{
-       int err;
-       assert(pcm && info);
-#if 0
-       fprintf(stderr, "hw_info entered:\n");
-       snd_pcm_dump_hw_info(info, stderr);
-       fprintf(stderr, "\n");
-#endif
-       err = pcm->ops->hw_info(pcm->op_arg, info);
-#if 0
-       fprintf(stderr, "hw_info return %d:\n", err);
-       snd_pcm_dump_hw_info(info, stderr);
-       fprintf(stderr, "\n");
-#endif
-       return err;
-}
-
-void snd_pcm_hw_info_any(snd_pcm_hw_info_t *info)
-{
-       assert(info);
-       info->flags = 0;
-       info->access_mask = ~0;
-       info->format_mask = ~0;
-       info->subformat_mask = ~0;
-       info->channels_min = 1;
-       info->channels_max = UINT_MAX;
-       info->rate_min = 1;
-       info->rate_max = UINT_MAX;
-       info->fragment_length_min = 0;
-       info->fragment_length_max = UINT_MAX;
-       info->fragments_min = 1;
-       info->fragments_max = UINT_MAX;
-       info->buffer_length_min = 1;
-       info->buffer_length_max = UINT_MAX;
-}
-
-void snd_pcm_hw_params_to_info(snd_pcm_hw_params_t *params, snd_pcm_hw_info_t *info)
-{
-       int r;
-       assert(info && params);
-       info->flags = 0;
-       info->access_mask = 1U << params->access;
-       info->format_mask = 1U << params->format;
-       info->subformat_mask = 1U << params->subformat;
-       info->channels_min = info->channels_max = params->channels;
-       info->rate_min = info->rate_max = params->rate;
-       info->fragment_length_min = muldiv_down(params->fragment_size, 1000000, params->rate);
-       info->fragment_length_max = muldiv(params->fragment_size + 1, 1000000, params->rate, &r);
-       if (r == 0)
-               info->fragment_length_max--;
-       info->fragments_min = info->fragments_max = params->fragments;
-       info->buffer_length_min = muldiv_down(params->fragment_size * params->fragments, 1000000, params->rate);
-       info->buffer_length_max = muldiv((params->fragment_size + 1) * params->fragments, 1000000, params->rate, &r);
-       if (r  == 0)
-               info->buffer_length_max--;
-}
-
 int snd_pcm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
 {
        int err;
@@ -377,7 +319,6 @@ int snd_pcm_poll_descriptor(snd_pcm_t *pcm)
 #define XRUN(v) [SND_PCM_XRUN_##v] = #v
 #define ACCESS(v) [SND_PCM_ACCESS_##v] = #v
 #define START(v) [SND_PCM_START_##v] = #v
-#define HW_INFO(v) [SND_PCM_HW_INFO_##v] = #v
 #define HW_PARAM(v) [SND_PCM_HW_PARAM_##v] = #v
 #define SW_PARAM(v) [SND_PCM_SW_PARAM_##v] = #v
 #define FORMAT(v) [SND_PCM_FORMAT_##v] = #v
@@ -400,25 +341,21 @@ char *snd_pcm_state_names[] = {
        STATE(PAUSED),
 };
 
-char *snd_pcm_hw_info_names[] = {
-       HW_INFO(ACCESS),
-       HW_INFO(FORMAT),
-       HW_INFO(SUBFORMAT),
-       HW_INFO(CHANNELS),
-       HW_INFO(RATE),
-       HW_INFO(FRAGMENT_LENGTH),
-       HW_INFO(FRAGMENTS),
-       HW_INFO(BUFFER_LENGTH),
-};
-
 char *snd_pcm_hw_param_names[] = {
        HW_PARAM(ACCESS),
        HW_PARAM(FORMAT),
        HW_PARAM(SUBFORMAT),
        HW_PARAM(CHANNELS),
        HW_PARAM(RATE),
+       HW_PARAM(FRAGMENT_LENGTH),
        HW_PARAM(FRAGMENT_SIZE),
        HW_PARAM(FRAGMENTS),
+       HW_PARAM(BUFFER_LENGTH),
+       HW_PARAM(BUFFER_SIZE),
+       HW_PARAM(SAMPLE_BITS),
+       HW_PARAM(FRAME_BITS),
+       HW_PARAM(FRAGMENT_BYTES),
+       HW_PARAM(BUFFER_BYTES),
 };
 
 char *snd_pcm_sw_param_names[] = {
@@ -574,47 +511,6 @@ int snd_pcm_dump_setup(snd_pcm_t *pcm, FILE *fp)
        return 0;
 }
 
-int snd_pcm_dump_hw_params_fail(snd_pcm_hw_params_t *params, FILE *fp)
-{
-       int k;
-       if (params->fail_mask == 0) {
-               fprintf(fp, "unknown hw_params failure reason\n");
-               return 0;
-       }
-       fprintf(fp, "hw_params failed on the following field value(s):\n");
-       for (k = 0; k <= SND_PCM_HW_PARAM_LAST; ++k) {
-               if (!(params->fail_mask & (1U << k)))
-                       continue;
-               switch (k) {
-               case SND_PCM_HW_PARAM_ACCESS:
-                       fprintf(fp, "access: %s\n", assoc(params->access, snd_pcm_access_names));
-                       break;
-               case SND_PCM_HW_PARAM_FORMAT:
-                       fprintf(fp, "format: %s\n", assoc(params->format, snd_pcm_format_names));
-                       break;
-               case SND_PCM_HW_PARAM_SUBFORMAT:
-                       fprintf(fp, "subformat: %s\n", assoc(params->subformat, snd_pcm_subformat_names));
-                       break;
-               case SND_PCM_HW_PARAM_CHANNELS:
-                       fprintf(fp, "channels: %u\n", params->channels);
-                       break;
-               case SND_PCM_HW_PARAM_RATE:
-                       fprintf(fp, "rate: %u\n", params->rate);
-                       break;
-               case SND_PCM_HW_PARAM_FRAGMENT_SIZE:
-                       fprintf(fp, "fragment_size: %lu\n", (long)params->fragment_size);
-                       break;
-               case SND_PCM_HW_PARAM_FRAGMENTS:
-                       fprintf(fp, "fragments: %u\n", params->fragments);
-                       break;
-               default:
-                       assert(0);
-                       break;
-               }
-       }
-       return 0;
-}
-
 int snd_pcm_dump_sw_params_fail(snd_pcm_sw_params_t *params, FILE *fp)
 {
        int k;
@@ -678,6 +574,12 @@ int snd_pcm_dump(snd_pcm_t *pcm, FILE *fp)
        return 0;
 }
 
+const char *snd_pcm_access_name(unsigned int access)
+{
+       assert(access <= SND_PCM_ACCESS_LAST);
+       return snd_pcm_access_names[access];
+}
+
 const char *snd_pcm_format_name(unsigned int format)
 {
        assert(format <= SND_PCM_FORMAT_LAST);
@@ -700,6 +602,18 @@ int snd_pcm_format_value(const char* name)
        return -1;
 }
 
+const char *snd_pcm_subformat_name(unsigned int subformat)
+{
+       assert(subformat <= SND_PCM_SUBFORMAT_LAST);
+       return snd_pcm_subformat_names[subformat];
+}
+
+const char *snd_pcm_hw_param_name(unsigned int param)
+{
+       assert(param <= SND_PCM_HW_PARAM_LAST);
+       return snd_pcm_hw_param_names[param];
+}
+
 ssize_t snd_pcm_bytes_to_frames(snd_pcm_t *pcm, ssize_t bytes)
 {
        assert(pcm);
@@ -1291,1124 +1205,6 @@ ssize_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_t *areas,
        return err;
 }
 
-#if 0
-int snd_pcm_alloc_user_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i)
-{
-       i->type = SND_PCM_MMAP_USER;
-       i->size = snd_pcm_frames_to_bytes(pcm, pcm->buffer_size);
-       i->u.user.shmid = shmget(IPC_PRIVATE, i->size, 0666);
-       if (i->u.user.shmid < 0) {
-               SYSERR("shmget failed");
-               return -errno;
-       }
-       i->addr = shmat(i->u.user.shmid, 0, 0);
-       if (i->addr == (void*) -1) {
-               SYSERR("shmat failed");
-               return -errno;
-       }
-       return 0;
-}
-
-int snd_pcm_alloc_kernel_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i, int fd)
-{
-       i->type = SND_PCM_MMAP_KERNEL;
-       /* FIXME */
-       i->size = PAGE_ALIGN(snd_pcm_frames_to_bytes(pcm, pcm->buffer_size));
-       i->addr = mmap(NULL, i->size,
-                      PROT_WRITE | PROT_READ,
-                      MAP_FILE|MAP_SHARED, 
-                      fd, SND_PCM_MMAP_OFFSET_DATA);
-       if (i->addr == MAP_FAILED ||
-           i->addr == NULL) {
-               SYSERR("data mmap failed");
-               return -errno;
-       }
-       i->u.kernel.fd = fd;
-       return 0;
-}
-
-int snd_pcm_free_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i)
-{
-       if (i->type == SND_PCM_MMAP_USER) {
-               if (shmdt(i->addr) < 0) {
-                       SYSERR("shmdt failed");
-                       return -errno;
-               }
-               if (shmctl(i->u.user.shmid, IPC_RMID, 0) < 0) {
-                       SYSERR("shmctl IPC_RMID failed");
-                       return -errno;
-               }
-       } else {
-               if (munmap(pcm->mmap_info->addr, pcm->mmap_info->size) < 0) {
-                       SYSERR("data munmap failed");
-                       return -errno;
-               }
-       }
-       return 0;
-}
-#endif
-
-int snd_pcm_hw_info_bits_per_sample(snd_pcm_hw_info_t *info,
-                                   unsigned int *min, unsigned int *max)
-{
-       int k;
-       unsigned int bits_min = UINT_MAX, bits_max = 0;
-       int changed = 0;
-       for (k = 0; k <= SND_PCM_FORMAT_LAST; ++k) {
-               int bits;
-               if (!(info->format_mask & (1U << k)))
-                       continue;
-               bits = snd_pcm_format_physical_width(k);
-               assert(bits > 0);
-               if ((unsigned) bits < *min || (unsigned)bits > *max) {
-                       info->format_mask &= ~(1U << k);
-                       changed++;
-                       continue;
-               }
-               if ((unsigned)bits < bits_min)
-                       bits_min = bits;
-               if ((unsigned)bits > bits_max)
-                       bits_max = bits;
-       }
-       *min = bits_min;
-       *max = bits_max;
-       if (info->format_mask == 0)
-               return -EINVAL;
-       return changed;
-}
-
-
-int snd_pcm_hw_info_complete(snd_pcm_hw_info_t *info)
-{
-       if (info->msbits == 0) {
-               unsigned int bits_min = 0, bits_max = UINT_MAX;
-               snd_pcm_hw_info_bits_per_sample(info, &bits_min, &bits_max);
-               if (bits_min == bits_max)
-                       info->msbits = bits_min;
-       }
-       if (info->rate_den == 0 &&
-           info->rate_min == info->rate_max) {
-               info->rate_num = info->rate_min;
-               info->rate_den = 1;
-       }
-       return 0;
-}
-
-struct _snd_pcm_strategy {
-       unsigned int badness_min, badness_max;
-       int (*choose_param)(const snd_pcm_hw_info_t *info,
-                           snd_pcm_t *pcm,
-                           const snd_pcm_strategy_t *strategy);
-       int (*next_value)(const snd_pcm_hw_info_t *info,
-                          unsigned int param,
-                          int value,
-                          snd_pcm_t *pcm,
-                          const snd_pcm_strategy_t *strategy);
-       int (*min_badness)(const snd_pcm_hw_info_t *info,
-                          unsigned int max_badness,
-                          snd_pcm_t *pcm,
-                          const snd_pcm_strategy_t *strategy);
-       void *private;
-       void (*free)(snd_pcm_strategy_t *strategy);
-};
-
-/* Independent badness */
-typedef struct _snd_pcm_strategy_simple snd_pcm_strategy_simple_t;
-
-struct _snd_pcm_strategy_simple {
-       int valid;
-       unsigned int order;
-       int (*next_value)(const snd_pcm_hw_info_t *info,
-                          unsigned int param,
-                          int value,
-                          snd_pcm_t *pcm,
-                          const snd_pcm_strategy_simple_t *par);
-       unsigned int (*min_badness)(const snd_pcm_hw_info_t *info,
-                                   unsigned int param,
-                                   snd_pcm_t *pcm,
-                                   const snd_pcm_strategy_simple_t *par);
-       void *private;
-       void (*free)(snd_pcm_strategy_simple_t *strategy);
-};
-
-typedef struct _snd_pcm_strategy_simple_near {
-       int best;
-       unsigned int mul;
-} snd_pcm_strategy_simple_near_t;
-
-typedef struct _snd_pcm_strategy_simple_choices {
-       unsigned int count;
-       /* choices need to be sorted on ascending badness */
-       snd_pcm_strategy_simple_choices_list_t *choices;
-} snd_pcm_strategy_simple_choices_t;
-
-static inline unsigned int hweight32(u_int32_t v)
-{
-        v = (v & 0x55555555) + ((v >> 1) & 0x55555555);
-        v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
-        v = (v & 0x0F0F0F0F) + ((v >> 4) & 0x0F0F0F0F);
-        v = (v & 0x00FF00FF) + ((v >> 8) & 0x00FF00FF);
-        return (v & 0x0000FFFF) + ((v >> 16) & 0x0000FFFF);
-}
-
-static inline unsigned int ld2(u_int32_t v)
-{
-        unsigned r = 0;
-
-        if (v >= 0x10000) {
-                v >>= 16;
-                r += 16;
-        }
-        if (v >= 0x100) {
-                v >>= 8;
-                r += 8;
-        }
-        if (v >= 0x10) {
-                v >>= 4;
-                r += 4;
-        }
-        if (v >= 4) {
-                v >>= 2;
-                r += 2;
-        }
-        if (v >= 2)
-                r++;
-        return r;
-}
-
-typedef struct {
-       enum { MASK, MINMAX } type;
-       char **names;
-       unsigned int last;
-} par_desc_t;
-
-par_desc_t hw_infos[SND_PCM_HW_INFO_LAST + 1] = {
-       [SND_PCM_HW_INFO_ACCESS] = {
-               type: MASK,
-               names: snd_pcm_access_names,
-               last: SND_PCM_ACCESS_LAST,
-       },
-       [SND_PCM_HW_INFO_FORMAT] = {
-               type: MASK,
-               names: snd_pcm_format_names,
-               last: SND_PCM_FORMAT_LAST,
-       },
-       [SND_PCM_HW_INFO_SUBFORMAT] = {
-               type: MASK,
-               names: snd_pcm_subformat_names,
-               last: SND_PCM_SUBFORMAT_LAST,
-       },
-       [SND_PCM_HW_INFO_CHANNELS] = {
-               type: MINMAX,
-               names: 0,
-               last: 0,
-       },
-       [SND_PCM_HW_INFO_RATE] = {
-               type: MINMAX,
-               names: 0,
-               last: 0,
-       },
-       [SND_PCM_HW_INFO_FRAGMENT_LENGTH] = {
-               type: MINMAX,
-               names: 0,
-               last: 0,
-       },
-       [SND_PCM_HW_INFO_FRAGMENTS] = {
-               type: MINMAX,
-               names: 0,
-               last: 0,
-       },
-       [SND_PCM_HW_INFO_BUFFER_LENGTH] = {
-               type: MINMAX,
-               names: 0,
-               last: 0,
-       },
-};
-
-unsigned int snd_pcm_hw_info_par_get_mask(const snd_pcm_hw_info_t *info,
-                                         unsigned int param)
-{
-       switch (param) {
-       case SND_PCM_HW_INFO_ACCESS:
-               return info->access_mask;
-       case SND_PCM_HW_INFO_FORMAT:
-               return info->format_mask;
-       case SND_PCM_HW_INFO_SUBFORMAT:
-               return info->subformat_mask;
-       default:
-               assert(0);
-               return 0;
-       }
-}
-       
-void snd_pcm_hw_info_par_get_minmax(const snd_pcm_hw_info_t *info,
-                                   unsigned int param,
-                                   unsigned int *min, unsigned int *max)
-{
-       switch (param) {
-       case SND_PCM_HW_INFO_ACCESS:
-       case SND_PCM_HW_INFO_FORMAT:
-       case SND_PCM_HW_INFO_SUBFORMAT:
-       {
-               unsigned int mask = snd_pcm_hw_info_par_get_mask(info, param);
-               if (!mask) {
-                       *min = 32;
-                       *max = 0;
-               } else {
-                       *min = ffs(mask) - 1;
-                       *max = ld2(mask);
-               }
-               break;
-       }
-       case SND_PCM_HW_INFO_CHANNELS:
-               *min = info->channels_min;
-               *max = info->channels_max;
-               break;
-       case SND_PCM_HW_INFO_RATE:
-               *min = info->rate_min;
-               *max = info->rate_max;
-               break;
-       case SND_PCM_HW_INFO_FRAGMENT_LENGTH:
-               *min = info->fragment_length_min;
-               *max = info->fragment_length_max;
-               break;
-       case SND_PCM_HW_INFO_FRAGMENTS:
-               *min = info->fragments_min;
-               *max = info->fragments_max;
-               break;
-       case SND_PCM_HW_INFO_BUFFER_LENGTH:
-               *min = info->buffer_length_min;
-               *max = info->buffer_length_max;
-               break;
-       default:
-               assert(0);
-       }
-}
-
-void snd_pcm_hw_info_par_set_mask(snd_pcm_hw_info_t *info, unsigned int param,
-                                 unsigned int v)
-{
-       switch (param) {
-       case SND_PCM_HW_INFO_ACCESS:
-               info->access_mask = v;
-               break;
-       case SND_PCM_HW_INFO_FORMAT:
-               info->format_mask = v;
-               break;
-       case SND_PCM_HW_INFO_SUBFORMAT:
-               info->subformat_mask = v;
-               break;
-       default:
-               assert(0);
-       }
-}
-
-void snd_pcm_hw_info_par_set_minmax(snd_pcm_hw_info_t *info,
-                                   unsigned int param,
-                                   unsigned int min, unsigned int max)
-{
-       switch (param) {
-       case SND_PCM_HW_INFO_ACCESS:
-       case SND_PCM_HW_INFO_FORMAT:
-       case SND_PCM_HW_INFO_SUBFORMAT:
-       {
-               unsigned int mask;
-               if (min >= 32 || max <= 0 || min > max) {
-                       snd_pcm_hw_info_par_set_mask(info, param, 0);
-                       break;
-               }
-               if (max >= 31) {
-                       max = 31;
-                       if (min <= 0)
-                               break;
-               }
-               mask = snd_pcm_hw_info_par_get_mask(info, param);
-               mask &= ((1U << (max - min + 1)) - 1) << min;
-               snd_pcm_hw_info_par_set_mask(info, param, mask);
-               break;
-       }
-       case SND_PCM_HW_INFO_CHANNELS:
-               info->channels_min = min;
-               info->channels_max = max;
-               break;
-       case SND_PCM_HW_INFO_RATE:
-               info->rate_min = min;
-               info->rate_max = max;
-               break;
-       case SND_PCM_HW_INFO_FRAGMENT_LENGTH:
-               info->fragment_length_min = min;
-               info->fragment_length_max = max;
-               break;
-       case SND_PCM_HW_INFO_FRAGMENTS:
-               info->fragments_min = min;
-               info->fragments_max = max;
-               break;
-       case SND_PCM_HW_INFO_BUFFER_LENGTH:
-               info->buffer_length_min = min;
-               info->buffer_length_max = max;
-               break;
-       default:
-               assert(0);
-       }
-}
-
-void snd_pcm_hw_info_par_copy(snd_pcm_hw_info_t *info, unsigned int param,
-                             snd_pcm_hw_info_t *src)
-{
-       switch (param) {
-       case SND_PCM_HW_INFO_ACCESS:
-               info->access_mask = src->access_mask;
-               break;
-       case SND_PCM_HW_INFO_FORMAT:
-               info->format_mask = src->format_mask;
-               break;
-       case SND_PCM_HW_INFO_SUBFORMAT:
-               info->subformat_mask = src->subformat_mask;
-               break;
-       case SND_PCM_HW_INFO_CHANNELS:
-               info->channels_min = src->channels_min;
-               info->channels_max = src->channels_max;
-               break;
-       case SND_PCM_HW_INFO_RATE:
-               info->rate_min = src->rate_min;
-               info->rate_max = src->rate_max;
-               break;
-       case SND_PCM_HW_INFO_FRAGMENT_LENGTH:
-               info->fragment_length_min = src->fragment_length_min;
-               info->fragment_length_max = src->fragment_length_max;
-               break;
-       case SND_PCM_HW_INFO_FRAGMENTS:
-               info->fragments_min = src->fragments_min;
-               info->fragments_max = src->fragments_max;
-               break;
-       case SND_PCM_HW_INFO_BUFFER_LENGTH:
-               info->buffer_length_min = src->buffer_length_min;
-               info->buffer_length_max = src->buffer_length_max;
-               break;
-       default:
-               assert(0);
-               break;
-       }
-}
-
-unsigned int snd_pcm_hw_info_par_choices(const snd_pcm_hw_info_t *info,
-                                         unsigned int param)
-{
-       par_desc_t *p;
-       assert(param <= SND_PCM_HW_INFO_LAST);
-       p = &hw_infos[param];
-       switch (p->type) {
-       case MASK:
-               return hweight32(snd_pcm_hw_info_par_get_mask(info, param));
-       case MINMAX:
-       {
-               unsigned int min, max;
-               snd_pcm_hw_info_par_get_minmax(info, param, &min, &max);
-               return max - min + 1;
-       }
-       default:
-               assert(0);
-               return 0;
-       }
-}
-
-unsigned int snd_pcm_hw_info_par_refine_min(snd_pcm_hw_info_t *info,
-                                            unsigned int param,
-                                            unsigned int value)
-{
-       unsigned int min, max;
-       snd_pcm_hw_info_par_get_minmax(info, param, &min, &max);
-       if (min < value) {
-               min = value;
-               snd_pcm_hw_info_par_set_minmax(info, param, min, max);
-       }
-       return min;
-}
-
-unsigned int snd_pcm_hw_info_par_refine_max(snd_pcm_hw_info_t *info,
-                                            unsigned int param,
-                                            unsigned int value)
-{
-       unsigned int min, max;
-       snd_pcm_hw_info_par_get_minmax(info, param, &min, &max);
-       if (max > value) {
-               max = value;
-               snd_pcm_hw_info_par_set_minmax(info, param, min, max);
-       }
-       return max;
-}
-
-int snd_pcm_hw_info_par_check(const snd_pcm_hw_info_t *info, 
-                             unsigned int param,
-                             unsigned int value)
-{
-       par_desc_t *p;
-       assert(param <= SND_PCM_HW_INFO_LAST);
-       p = &hw_infos[param];
-       switch (p->type) {
-       case MASK:
-               return snd_pcm_hw_info_par_get_mask(info, param) & (1 << value);
-       case MINMAX:
-       {
-               unsigned int min, max;
-               snd_pcm_hw_info_par_get_minmax(info, param, &min, &max);
-               return value >= min && value <= max;
-       }
-       default:
-               assert(0);
-               return 0;
-       }
-}
-
-int snd_pcm_hw_info_par_nearest_next(const snd_pcm_hw_info_t *info,
-                                     unsigned int param,
-                                     unsigned int best, int value,
-                                     snd_pcm_t *pcm)
-{
-       unsigned int min, max;
-       unsigned int max1, min2;
-       snd_pcm_hw_info_t i1, i2;
-       int err1 = -EINVAL;
-       int err2 = -EINVAL;
-       
-       snd_pcm_hw_info_par_get_minmax(info, param, &min, &max);
-       i1 = *info;
-       i2 = *info;
-       if (value < 0) {
-               max1 = best;
-               min2 = best + 1;
-       } else {
-               int diff = value - best;
-               if (diff < 0) {
-                       if (value > 1)
-                               max1 = value - 1;
-                       else
-                               max1 = 0;
-                       min2 = best - diff;
-               } else {
-                       if (best > (unsigned int) diff)
-                               max1 = best - diff - 1;
-                       else
-                               max1 = 0;
-                       min2 = value + 1;
-               }
-       }
-       max1 = snd_pcm_hw_info_par_refine_max(&i1, param, max1);
-       min2 = snd_pcm_hw_info_par_refine_min(&i2, param, min2);
-       if (min <= max1) {
-               err1 = snd_pcm_hw_info(pcm, &i1);
-               if (err1 >= 0)
-                       max1 = snd_pcm_hw_info_par_refine_max(&i1, param, max1);
-       }
-       if (min2 <= max && (err1 < 0 || best - max1 > min2 - best)) {
-               err2 = snd_pcm_hw_info(pcm, &i2);
-               if (err2 >= 0)
-                       min2 = snd_pcm_hw_info_par_refine_min(&i2, param, min2);
-       }
-       if (err1 < 0) {
-               if (err2 < 0)
-                       return -1;
-               return min2;
-       } else if (err2 < 0)
-               return max1;
-       if (best - max1 <= min2 - best)
-               return max1;
-       return min2;
-}
-
-void snd_pcm_hw_info_par_dump(snd_pcm_hw_info_t *info, unsigned int param, FILE *fp)
-{
-       par_desc_t *p;
-       assert(param <= SND_PCM_HW_INFO_LAST);
-       p = &hw_infos[param];
-       switch (p->type) {
-       case MASK:
-       {
-               unsigned int mask = snd_pcm_hw_info_par_get_mask(info, param);
-               if (mask == ~0U)
-                       fputs(" ALL", fp);
-               else if (mask) {
-                       unsigned int k;
-                       for (k = 0; k <= p->last; ++k)
-                               if (mask & (1U << k)) {
-                                       putc(' ', fp);
-                                       fputs(p->names[k], fp);
-                               }
-               } else
-                       fputs(" NONE", fp);
-               break;
-       }
-       case MINMAX:
-       {
-               unsigned int min, max;
-               snd_pcm_hw_info_par_get_minmax(info, param, &min, &max);
-               if (min == max)
-                       printf("%u", min);
-               else
-                       printf("%u - %u", min, max);
-               break;
-       }
-       default:
-               assert(0);
-               break;
-       }
-}
-
-int snd_pcm_hw_info_par_empty(snd_pcm_hw_info_t *info, unsigned int param)
-{
-       par_desc_t *p;
-       assert(param <= SND_PCM_HW_INFO_LAST);
-       p = &hw_infos[param];
-       switch (p->type) {
-       case MASK:
-               return !snd_pcm_hw_info_par_get_mask(info, param);
-       case MINMAX:
-       {
-               unsigned int min, max;
-               snd_pcm_hw_info_par_get_minmax(info, param, &min, &max);
-               return min > max;
-       }
-       default:
-               assert(0);
-               return 0;;
-       }
-}
-
-unsigned int snd_pcm_hw_info_fail_mask(snd_pcm_hw_info_t *info)
-{
-       unsigned int k, mask = 0;
-       for (k = 0; k <= SND_PCM_HW_INFO_LAST; ++k) {
-               if (snd_pcm_hw_info_par_empty(info, k))
-                       mask |= 1 << k;
-       }
-       return mask;
-}
-
-int snd_pcm_hw_info_to_params(snd_pcm_t *pcm, snd_pcm_hw_info_t *info, snd_pcm_hw_params_t *params)
-{
-       int err;
-       err = snd_pcm_hw_info(pcm, info);
-       if (err < 0) {
-               params->fail_mask = snd_pcm_hw_info_fail_mask(info);
-               return err;
-       }
-
-       assert(info->access_mask);
-       if (info->access_mask & (info->access_mask - 1)) {
-               info->access_mask = 1 << (ffs(info->access_mask) - 1);
-               err = snd_pcm_hw_info(pcm, info);
-               assert(err >= 0);
-       }
-       assert(info->format_mask);
-       if (info->format_mask & (info->format_mask - 1)) {
-               info->format_mask = 1 << (ffs(info->format_mask) - 1);
-               err = snd_pcm_hw_info(pcm, info);
-               assert(err >= 0);
-       }
-       assert(info->subformat_mask);
-       if (info->subformat_mask & (info->subformat_mask - 1)) {
-               info->subformat_mask = 1 << (ffs(info->subformat_mask) - 1);
-               err = snd_pcm_hw_info(pcm, info);
-               assert(err >= 0);
-       }
-       assert(info->channels_min <= info->channels_max);
-       if (info->channels_min < info->channels_max) {
-               info->channels_max = info->channels_min;
-               err = snd_pcm_hw_info(pcm, info);
-               assert(err >= 0);
-       }
-       assert(info->rate_min <= info->rate_max);
-       if (info->rate_min < info->rate_max) {
-               info->rate_max = info->rate_min;
-               err = snd_pcm_hw_info(pcm, info);
-               assert(err >= 0);
-       }
-       assert(info->fragment_length_min <= info->fragment_length_max);
-       if (info->fragment_length_min < info->fragment_length_max) {
-               info->fragment_length_max = info->fragment_length_min;
-               err = snd_pcm_hw_info(pcm, info);
-               assert(err >= 0);
-       }
-       assert(info->fragments_min <= info->fragments_max);
-       if (info->fragments_min < info->fragments_max) {
-               /* Defaults to maximum use of buffer */
-               info->fragments_min = info->fragments_max;
-               err = snd_pcm_hw_info(pcm, info);
-               assert(err >= 0);
-       }
-       params->access = ffs(info->access_mask) - 1;
-       params->format = ffs(info->format_mask) - 1;
-       params->subformat = ffs(info->subformat_mask) - 1;
-       params->channels = info->channels_min;
-       params->rate = info->rate_min;
-       params->fragment_size = muldiv_near(info->fragment_length_min, info->rate_min, 1000000);
-       params->fragments = info->fragments_min;
-       return 0;
-}
-
-int _snd_pcm_hw_params_info(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_hw_info_t *info)
-{
-       int err;
-       params->fail_mask = 0;
-       
-       if (pcm->mmap_channels) {
-               err = snd_pcm_munmap(pcm);
-               if (err < 0)
-                       return err;
-       }
-       err = pcm->ops->hw_params(pcm->op_arg, params);
-       if (err < 0)
-               goto _mmap;
-
-       pcm->setup = 1;
-       pcm->access = params->access;
-       pcm->format = params->format;
-       pcm->subformat = params->subformat;
-       pcm->rate = params->rate;
-       pcm->channels = params->channels;
-       pcm->fragment_size = params->fragment_size;
-       pcm->fragments = params->fragments;
-       pcm->bits_per_sample = snd_pcm_format_physical_width(params->format);
-       pcm->bits_per_frame = pcm->bits_per_sample * params->channels;
-       pcm->buffer_size = params->fragment_size * params->fragments;
-       
-       pcm->info = info->info;
-       pcm->msbits = info->msbits;
-       pcm->rate_num = info->rate_num;
-       pcm->rate_den = info->rate_den;
-       pcm->fifo_size = info->fifo_size;
-       
-       /* Default sw params */
-       pcm->start_mode = SND_PCM_START_DATA;
-       pcm->ready_mode = SND_PCM_READY_FRAGMENT;
-       pcm->xrun_mode = SND_PCM_XRUN_FRAGMENT;
-       pcm->avail_min = pcm->fragment_size;
-       pcm->xfer_min = pcm->fragment_size;
-       pcm->xfer_align = pcm->fragment_size;
-       pcm->time = 0;
-       pcm->boundary = LONG_MAX - pcm->buffer_size * 2 - LONG_MAX % pcm->buffer_size;
-
- _mmap:
-       if (pcm->setup &&
-           (pcm->mmap_rw || 
-            (pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED ||
-             pcm->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED ||
-             pcm->access == SND_PCM_ACCESS_MMAP_COMPLEX))) {
-               int err;
-               err = snd_pcm_mmap(pcm);
-               if (err < 0)
-                       return err;
-       }
-       return err;
-}
-
-int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
-{
-       snd_pcm_hw_info_t info;
-       int err;
-       assert(pcm && params);
-       snd_pcm_hw_params_to_info(params, &info);
-       err = snd_pcm_hw_info(pcm, &info);
-       if (err < 0) {
-               params->fail_mask = snd_pcm_hw_info_fail_mask(&info);
-               return err;
-       }
-       return _snd_pcm_hw_params_info(pcm, params, &info);
-}
-
-int snd_pcm_hw_params_info(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
-                          snd_pcm_hw_info_t *info)
-{
-       int err = snd_pcm_hw_info_to_params(pcm, info, params);
-       if (err < 0)
-               return err;
-       return _snd_pcm_hw_params_info(pcm, params, info);
-}
-
-
-int snd_pcm_hw_info_strategy1(snd_pcm_t *pcm, snd_pcm_hw_info_t *info,
-                             const snd_pcm_strategy_t *strategy,
-                             unsigned int badness_min, unsigned int badness_max)
-{
-       snd_pcm_hw_info_t best_info;
-       int param;
-       int value;
-       unsigned int best_badness;
-       unsigned int mask = ~0;
-       int badness = strategy->min_badness(info, badness_max, pcm, strategy);
-       snd_pcm_hw_info_t info1;
-#if 0
-       printf("\nBadness: %d\n", badness);
-       snd_pcm_dump_hw_info(info, stdout);
-#endif
-       if (badness < 0)
-               return badness;
-       if ((unsigned int)badness > badness_min)
-               badness_min = badness_min;
-       param = strategy->choose_param(info, pcm, strategy);
-       if (param < 0)
-               return badness;
-       best_badness = UINT_MAX;
-       value = -1;
-       while (1) {
-               int err;
-               value = strategy->next_value(info, param, value, pcm, strategy);
-               if (value < 0)
-                       break;
-               info1 = *info;
-               snd_pcm_hw_info_par_set_minmax(&info1, param, value, value);
-               err = snd_pcm_hw_info(pcm, &info1);
-               if (err >= 0) {
-                       badness = snd_pcm_hw_info_strategy1(pcm, &info1, strategy, badness_min, badness_max);
-                       if (badness >= 0) {
-                               
-                               if ((unsigned int) badness <= badness_min) {
-                                       *info = info1;
-                                       return badness;
-                               }
-                               best_badness = badness;
-                               best_info = info1;
-                               badness_max = badness - 1;
-                               continue;
-                       }
-                       if (badness != -EINVAL)
-                               continue;
-               }
-               mask &= snd_pcm_hw_info_fail_mask(&info1);
-       }
-       if (best_badness == UINT_MAX) {
-               for (param = 0; param <= SND_PCM_HW_INFO_LAST; param++) {
-                       if (!(mask & (1 << param)))
-                               continue;
-                       snd_pcm_hw_info_par_copy(info, param, &info1);
-               }
-               return -EINVAL;
-       }
-       *info = best_info;
-       return best_badness;
-}
-
-int snd_pcm_hw_info_strategy(snd_pcm_t *pcm, snd_pcm_hw_info_t *info,
-                            const snd_pcm_strategy_t *strategy)
-{
-       int err;
-       err = snd_pcm_hw_info(pcm, info);
-       if (err < 0)
-               return err;
-       return snd_pcm_hw_info_strategy1(pcm, info, strategy,
-                                        strategy->badness_min,
-                                        strategy->badness_max);
-}
-
-
-void snd_pcm_strategy_simple_free(snd_pcm_strategy_t *strategy)
-{
-       snd_pcm_strategy_simple_t *pars = strategy->private;
-       int k;
-       for (k = 0; k <= SND_PCM_HW_INFO_LAST; ++k) {
-               if (pars[k].valid && pars[k].free)
-                       pars[k].free(&pars[k]);
-       }
-       free(pars);
-}
-
-int snd_pcm_strategy_simple_choose_param(const snd_pcm_hw_info_t *info,
-                                        snd_pcm_t *pcm ATTRIBUTE_UNUSED,
-                                        const snd_pcm_strategy_t *strategy)
-{
-       unsigned int param;
-       int best_param = -1;
-       const snd_pcm_strategy_simple_t *pars = strategy->private;
-       unsigned int min_choices = UINT_MAX;
-       unsigned int min_order = UINT_MAX;
-       for (param = 0; param <= SND_PCM_HW_INFO_LAST; ++param) {
-               const snd_pcm_strategy_simple_t *p = &pars[param];
-               unsigned int choices;
-               if (!p->valid)
-                       continue;
-               choices = snd_pcm_hw_info_par_choices(info, param);
-               if (choices == 1)
-                       continue;
-               assert(choices != 0);
-               if (p->order < min_order ||
-                   (p->order == min_order &&
-                    choices < min_choices)) {
-                       min_order = p->order;
-                       min_choices = choices;
-                       best_param = param;
-               }
-       }
-       return best_param;
-}
-
-int snd_pcm_strategy_simple_next_value(const snd_pcm_hw_info_t *info,
-                                       unsigned int param,
-                                       int value,
-                                       snd_pcm_t *pcm,
-                                       const snd_pcm_strategy_t *strategy)
-{
-       const snd_pcm_strategy_simple_t *pars = strategy->private;
-       assert(pars[param].valid);
-       return pars[param].next_value(info, param, value, pcm, &pars[param]);
-}
-
-
-int snd_pcm_strategy_simple_min_badness(const snd_pcm_hw_info_t *info,
-                                       unsigned int max_badness,
-                                       snd_pcm_t *pcm,
-                                       const snd_pcm_strategy_t *strategy)
-{
-       unsigned int param;
-       unsigned int badness = 0;
-       const snd_pcm_strategy_simple_t *pars = strategy->private;
-       for (param = 0; param <= SND_PCM_HW_INFO_LAST; ++param) {
-               unsigned int b;
-               if (!pars[param].valid)
-                       continue;
-               b = pars[param].min_badness(info, param, pcm, &pars[param]);
-               if (b > max_badness || max_badness - b < badness)
-                       return -E2BIG;
-               badness += b;
-       }
-       return badness;
-}
-
-
-void snd_pcm_strategy_simple_near_free(snd_pcm_strategy_simple_t *par)
-{
-       snd_pcm_strategy_simple_near_t *p = par->private;
-       free(p);
-}
-
-unsigned int snd_pcm_strategy_simple_near_min_badness(const snd_pcm_hw_info_t *info,
-                                                     unsigned int param,
-                                                     snd_pcm_t *pcm,
-                                                     const snd_pcm_strategy_simple_t *par)
-{
-       const snd_pcm_strategy_simple_near_t *p = par->private;
-       int value = snd_pcm_hw_info_par_nearest_next(info, param, p->best, -1, pcm);
-       int diff;
-       assert(value >= 0);
-       diff = p->best - value;
-       if (diff < 0)
-               diff = -diff;
-       return diff * p->mul;
-}
-       
-int snd_pcm_strategy_simple_near_next_value(const snd_pcm_hw_info_t *info,
-                                            unsigned int param,
-                                            int value,
-                                            snd_pcm_t *pcm,
-                                            const snd_pcm_strategy_simple_t *par)
-{
-       const snd_pcm_strategy_simple_near_t *p = par->private;
-       return snd_pcm_hw_info_par_nearest_next(info, param, p->best, value, pcm);
-}
-
-void snd_pcm_strategy_simple_choices_free(snd_pcm_strategy_simple_t *par)
-{
-       snd_pcm_strategy_simple_choices_t *p = par->private;
-//     free(p->choices);
-       free(p);
-}
-
-unsigned int snd_pcm_strategy_simple_choices_min_badness(const snd_pcm_hw_info_t *info,
-                                                        unsigned int param,
-                                                        snd_pcm_t *pcm ATTRIBUTE_UNUSED,
-                                                        const snd_pcm_strategy_simple_t *par)
-{
-       const snd_pcm_strategy_simple_choices_t *p = par->private;
-       unsigned int k;
-       for (k = 0; k < p->count; ++k) {
-               if (snd_pcm_hw_info_par_check(info, param, p->choices[k].value))
-                       return p->choices[k].badness;
-       }
-       assert(0);
-       return UINT_MAX;
-}
-       
-int snd_pcm_strategy_simple_choices_next_value(const snd_pcm_hw_info_t *info,
-                                               unsigned int param,
-                                               int value,
-                                               snd_pcm_t *pcm ATTRIBUTE_UNUSED,
-                                               const snd_pcm_strategy_simple_t *par)
-{
-       const snd_pcm_strategy_simple_choices_t *p = par->private;
-       unsigned int k = 0;
-       if (value >= 0) {
-               for (; k < p->count; ++k) {
-                       if (p->choices[k].value == (unsigned int) value) {
-                               k++;
-                               break;
-                       }
-               }
-       }
-       for (; k < p->count; ++k) {
-               unsigned int v = p->choices[k].value;
-               if (snd_pcm_hw_info_par_check(info, param, v))
-                       return v;
-       }
-       return -1;
-}
-
-int snd_pcm_strategy_free(snd_pcm_strategy_t *strategy)
-{
-       if (strategy->free)
-               strategy->free(strategy);
-       free(strategy);
-       return 0;
-}
-
-int snd_pcm_strategy_simple(snd_pcm_strategy_t **strategyp,
-                           unsigned int badness_min,
-                           unsigned int badness_max)
-{
-       snd_pcm_strategy_simple_t *data;
-       snd_pcm_strategy_t *s;
-       assert(strategyp);
-       data = calloc(SND_PCM_HW_INFO_LAST + 1, sizeof(*data));
-       if (!data)
-               return -ENOMEM;
-       s = calloc(1, sizeof(*s));
-       if (!s) {
-               free(data);
-               return -ENOMEM;
-       }
-       s->choose_param = snd_pcm_strategy_simple_choose_param;
-       s->next_value = snd_pcm_strategy_simple_next_value;
-       s->min_badness = snd_pcm_strategy_simple_min_badness;
-       s->badness_min = badness_min;
-       s->badness_max = badness_max;
-       s->private = data;
-       s->free = snd_pcm_strategy_simple_free;
-       *strategyp = s;
-       return 0;
-}
-
-int snd_pcm_strategy_simple_near(snd_pcm_strategy_t *strategy,
-                                int order,
-                                unsigned int param,
-                                unsigned int best,
-                                unsigned int mul)
-{
-       snd_pcm_strategy_simple_t *s = strategy->private;
-       snd_pcm_strategy_simple_near_t *data;
-       assert(strategy);
-       assert(param <= SND_PCM_HW_INFO_LAST);
-       assert(!s->valid);
-       data = calloc(1, sizeof(*data));
-       if (!data)
-               return -ENOMEM;
-       data->best = best;
-       data->mul = mul;
-       s += param;
-       s->order = order;
-       s->valid = 1;
-       s->next_value = snd_pcm_strategy_simple_near_next_value;
-       s->min_badness = snd_pcm_strategy_simple_near_min_badness;
-       s->private = data;
-       s->free = snd_pcm_strategy_simple_near_free;
-       return 0;
-}
-
-int snd_pcm_strategy_simple_choices(snd_pcm_strategy_t *strategy,
-                                   int order,
-                                   unsigned int param,
-                                   unsigned int count,
-                                   snd_pcm_strategy_simple_choices_list_t *choices)
-{
-       snd_pcm_strategy_simple_t *s = strategy->private;
-       snd_pcm_strategy_simple_choices_t *data;
-       assert(strategy);
-       assert(param <= SND_PCM_HW_INFO_LAST);
-       assert(!s->valid);
-       data = calloc(1, sizeof(*data));
-       if (!data)
-               return -ENOMEM;
-       data->count = count;
-       data->choices = choices;
-       s += param;
-       s->valid = 1;
-       s->order = order;
-       s->next_value = snd_pcm_strategy_simple_choices_next_value;
-       s->min_badness = snd_pcm_strategy_simple_choices_min_badness;
-       s->private = data;
-       s->free = snd_pcm_strategy_simple_choices_free;
-       return 0;
-}
-
-int snd_pcm_dump_hw_info(snd_pcm_hw_info_t *info, FILE *fp)
-{
-       unsigned int param;
-       for (param = 0; param <= SND_PCM_HW_INFO_LAST; param++) {
-               fprintf(fp, "%s: ", snd_pcm_hw_info_names[param]);
-               snd_pcm_hw_info_par_dump(info, param, fp);
-               putc('\n', fp);
-       }
-       return 0;
-}
-
-int snd_pcm_hw_info_try_explain_failure1(snd_pcm_t *pcm,
-                                        snd_pcm_hw_info_t *fail,
-                                        snd_pcm_hw_info_t *success,
-                                        unsigned int depth,
-                                        FILE *fp)
-{
-       unsigned int param;
-       snd_pcm_hw_info_t i;
-       if (depth < 1)
-               return -ENOENT;
-       for (param = 0; param <= SND_PCM_HW_INFO_LAST; param++) {
-               int err;
-               i = *success;
-               snd_pcm_hw_info_par_copy(&i, param, fail);
-               err = snd_pcm_hw_info(pcm, &i);
-               if (err == 0 && 
-                   snd_pcm_hw_info_try_explain_failure1(pcm, fail, &i, depth - 1, fp) < 0)
-                       continue;
-               fprintf(fp, "%s: ", snd_pcm_hw_info_names[param]);
-               snd_pcm_hw_info_par_dump(fail, param, fp);
-               putc('\n', fp);
-               return 0;
-       }
-       return -ENOENT;
-}
-
-int snd_pcm_hw_info_try_explain_failure(snd_pcm_t *pcm,
-                                       snd_pcm_hw_info_t *fail,
-                                       snd_pcm_hw_info_t *success,
-                                       unsigned int depth,
-                                       FILE *fp)
-{
-       snd_pcm_hw_info_t i, any;
-       int err;
-       unsigned int fail_mask;
-       assert(pcm && fail);
-        fail_mask = snd_pcm_hw_info_fail_mask(fail);
-       if (fail_mask) {
-               unsigned int param;
-               for (param = 0; param <= SND_PCM_HW_INFO_LAST; param++) {
-                       if (!(fail_mask & (1 << param)))
-                               continue;
-                       fprintf(fp, "%s: ", snd_pcm_hw_info_names[param]);
-                       snd_pcm_hw_info_par_dump(fail, param, fp);
-                       putc('\n', fp);
-               }
-               return 0;
-       }
-       i = *fail;
-       err = snd_pcm_hw_info(pcm, &i);
-       if (err == 0) {
-               fprintf(fp, "Too low max badness or configuration temporarily unavailable\n");
-               return 0;
-       }
-       if (!success) {
-               snd_pcm_hw_info_any(&any);
-               success = &any;
-       }
-       return snd_pcm_hw_info_try_explain_failure1(pcm, fail, success, depth, fp);
-}
-
 size_t _snd_pcm_mmap_hw_ptr(snd_pcm_t *pcm)
 {
        return *pcm->hw_ptr;
index dd32c5ad9dc864b85598f13da8e16b08bff55a82..2946b48ec786c92cf99a67f3562eb1ff9901c578 100644 (file)
@@ -329,35 +329,59 @@ static int snd_pcm_adpcm_close(snd_pcm_t *pcm)
        return 0;
 }
 
-static int snd_pcm_adpcm_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
+static int snd_pcm_adpcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_adpcm_t *adpcm = pcm->private;
-       unsigned int format_mask, access_mask;
+       snd_pcm_t *slave = adpcm->plug.slave;
        int err;
-       info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED | 
-                             SND_PCM_ACCBIT_RW_INTERLEAVED |
-                             SND_PCM_ACCBIT_MMAP_NONINTERLEAVED | 
-                             SND_PCM_ACCBIT_RW_NONINTERLEAVED);
-       access_mask = info->access_mask;
-       if (access_mask == 0)
-               return -EINVAL;
-       if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM)
-               info->format_mask &= SND_PCM_FMTBIT_LINEAR;
-       else
-               info->format_mask &= SND_PCM_FMTBIT_IMA_ADPCM;
-       format_mask = info->format_mask;
-       if (format_mask == 0)
-               return -EINVAL;
+       snd_pcm_hw_params_t sparams;
+       mask_t *access_mask = alloca(mask_sizeof());
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+       err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_ACCESS,
+                                     access_mask);
+       if (err < 0)
+               return err;
+       if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) {
+               mask_t *format_mask = alloca(mask_sizeof());
+               mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
+               err = _snd_pcm_hw_params_mask(params, 1,
+                                             SND_PCM_HW_PARAM_FORMAT,
+                                             format_mask);
+               if (err < 0)
+                       return err;
+       } else {
+               err = _snd_pcm_hw_params_set(params, 1,
+                                            SND_PCM_HW_PARAM_FORMAT,
+                                            SND_PCM_FORMAT_IMA_ADPCM);
+               if (err < 0)
+                       return err;
+       }
+       err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_SUBFORMAT,
+                                    SND_PCM_SUBFORMAT_STD);
+       if (err < 0)
+               return err;
 
-       info->format_mask = 1U << adpcm->sformat;
-       info->access_mask = SND_PCM_ACCBIT_MMAP;
-       err = snd_pcm_hw_info(adpcm->plug.slave, info);
-       info->format_mask = format_mask;
-       info->access_mask = access_mask;
+       _snd_pcm_hw_params_any(&sparams);
+       _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+                               saccess_mask);
+       _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+                              adpcm->sformat);
+       _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+                              SND_PCM_SUBFORMAT_STD);
+       err = snd_pcm_hw_refine2(params, &sparams,
+                                snd_pcm_hw_refine, slave,
+                                SND_PCM_HW_PARBIT_CHANNELS |
+                                SND_PCM_HW_PARBIT_RATE |
+                                SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+                                SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                                SND_PCM_HW_PARBIT_FRAGMENTS |
+                                SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+                                SND_PCM_HW_PARBIT_BUFFER_LENGTH);
        if (err < 0)
                return err;
-       info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
-       snd_pcm_hw_info_complete(info);
+       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
        return 0;
 }
 
@@ -365,19 +389,33 @@ static int snd_pcm_adpcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
 {
        snd_pcm_adpcm_t *adpcm = pcm->private;
        snd_pcm_t *slave = adpcm->plug.slave;
-       snd_pcm_hw_info_t sinfo;
-       snd_pcm_hw_params_t sparams;
        int err;
-       snd_pcm_hw_params_to_info(params, &sinfo);
-       sinfo.format_mask = 1 << adpcm->sformat;
-       sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
-       err = snd_pcm_hw_params_info(slave, &sparams, &sinfo);
-       params->fail_mask = sparams.fail_mask;
+       snd_pcm_hw_params_t sparams;
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+
+       _snd_pcm_hw_params_any(&sparams);
+       _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+                               saccess_mask);
+       _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+                              adpcm->sformat);
+       _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+                              SND_PCM_SUBFORMAT_STD);
+       err = snd_pcm_hw_params2(params, &sparams,
+                                snd_pcm_hw_params, slave,
+                                SND_PCM_HW_PARBIT_CHANNELS |
+                                SND_PCM_HW_PARBIT_RATE |
+                                SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+                                SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                                SND_PCM_HW_PARBIT_FRAGMENTS |
+                                SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+                                SND_PCM_HW_PARBIT_BUFFER_LENGTH);
        if (err < 0)
                return err;
+       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
                if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) {
-                       adpcm->getput_idx = get_index(params->format, SND_PCM_FORMAT_S16);
+                       adpcm->getput_idx = get_index(snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT), SND_PCM_FORMAT_S16);
                        adpcm->func = adpcm_encode;
                } else {
                        adpcm->getput_idx = put_index(SND_PCM_FORMAT_S16, adpcm->sformat);
@@ -385,7 +423,7 @@ static int snd_pcm_adpcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
                }
        } else {
                if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) {
-                       adpcm->getput_idx = put_index(SND_PCM_FORMAT_S16, params->format);
+                       adpcm->getput_idx = put_index(SND_PCM_FORMAT_S16, snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT));
                        adpcm->func = adpcm_decode;
                } else {
                        adpcm->getput_idx = get_index(adpcm->sformat, SND_PCM_FORMAT_S16);
@@ -394,7 +432,7 @@ static int snd_pcm_adpcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
        }
        if (adpcm->states)
                free(adpcm->states);
-       adpcm->states = malloc(params->channels * sizeof(*adpcm->states));
+       adpcm->states = malloc(snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_CHANNELS) * sizeof(*adpcm->states));
        return 0;
 }
 
@@ -495,7 +533,7 @@ static void snd_pcm_adpcm_dump(snd_pcm_t *pcm, FILE *fp)
 snd_pcm_ops_t snd_pcm_adpcm_ops = {
        close: snd_pcm_adpcm_close,
        info: snd_pcm_plugin_info,
-       hw_info: snd_pcm_adpcm_hw_info,
+       hw_refine: snd_pcm_adpcm_hw_refine,
        hw_params: snd_pcm_adpcm_hw_params,
        sw_params: snd_pcm_plugin_sw_params,
        dig_info: snd_pcm_plugin_dig_info,
index a6428775e5fd0123c23895b8f1e4a1d1d005d6d2..d29dab8f742fe503852def417714fb01d8bb1d47 100644 (file)
@@ -211,35 +211,59 @@ static void alaw_encode(const snd_pcm_channel_area_t *src_areas,
        }
 }
 
-static int snd_pcm_alaw_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
+static int snd_pcm_alaw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_alaw_t *alaw = pcm->private;
-       unsigned int format_mask, access_mask;
+       snd_pcm_t *slave = alaw->plug.slave;
        int err;
-       info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED | 
-                             SND_PCM_ACCBIT_RW_INTERLEAVED |
-                             SND_PCM_ACCBIT_MMAP_NONINTERLEAVED | 
-                             SND_PCM_ACCBIT_RW_NONINTERLEAVED);
-       access_mask = info->access_mask;
-       if (access_mask == 0)
-               return -EINVAL;
-       if (alaw->sformat == SND_PCM_FORMAT_MU_LAW)
-               info->format_mask &= SND_PCM_FMTBIT_LINEAR;
-       else
-               info->format_mask &= SND_PCM_FMTBIT_MU_LAW;
-       format_mask = info->format_mask;
-       if (format_mask == 0)
-               return -EINVAL;
+       snd_pcm_hw_params_t sparams;
+       mask_t *access_mask = alloca(mask_sizeof());
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+       err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_ACCESS,
+                                     access_mask);
+       if (err < 0)
+               return err;
+       if (alaw->sformat == SND_PCM_FORMAT_A_LAW) {
+               mask_t *format_mask = alloca(mask_sizeof());
+               mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
+               err = _snd_pcm_hw_params_mask(params, 1,
+                                             SND_PCM_HW_PARAM_FORMAT,
+                                             format_mask);
+               if (err < 0)
+                       return err;
+       } else {
+               err = _snd_pcm_hw_params_set(params, 1, 
+                                            SND_PCM_HW_PARAM_FORMAT,
+                                            SND_PCM_FORMAT_A_LAW);
+               if (err < 0)
+                       return err;
+       }
+       err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_SUBFORMAT,
+                                    SND_PCM_SUBFORMAT_STD);
+       if (err < 0)
+               return err;
 
-       info->format_mask = 1U << alaw->sformat;
-       info->access_mask = SND_PCM_ACCBIT_MMAP;
-       err = snd_pcm_hw_info(alaw->plug.slave, info);
-       info->format_mask = format_mask;
-       info->access_mask = access_mask;
+       _snd_pcm_hw_params_any(&sparams);
+       _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+                               saccess_mask);
+       _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+                              alaw->sformat);
+       _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+                              SND_PCM_SUBFORMAT_STD);
+       err = snd_pcm_hw_refine2(params, &sparams,
+                                snd_pcm_hw_refine, slave,
+                                SND_PCM_HW_PARBIT_CHANNELS |
+                                SND_PCM_HW_PARBIT_RATE |
+                                SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+                                SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                                SND_PCM_HW_PARBIT_FRAGMENTS |
+                                SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+                                SND_PCM_HW_PARBIT_BUFFER_LENGTH);
        if (err < 0)
                return err;
-       info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
-       snd_pcm_hw_info_complete(info);
+       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
        return 0;
 }
 
@@ -247,27 +271,41 @@ static int snd_pcm_alaw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
 {
        snd_pcm_alaw_t *alaw = pcm->private;
        snd_pcm_t *slave = alaw->plug.slave;
-       snd_pcm_hw_info_t sinfo;
-       snd_pcm_hw_params_t sparams;
        int err;
-       snd_pcm_hw_params_to_info(params, &sinfo);
-       sinfo.format_mask = 1 << alaw->sformat;
-       sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
-       err = snd_pcm_hw_params_info(slave, &sparams, &sinfo);
-       params->fail_mask = sparams.fail_mask;
+       snd_pcm_hw_params_t sparams;
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+
+       _snd_pcm_hw_params_any(&sparams);
+       _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+                               saccess_mask);
+       _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+                              alaw->sformat);
+       _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+                              SND_PCM_SUBFORMAT_STD);
+       err = snd_pcm_hw_params2(params, &sparams,
+                                snd_pcm_hw_params, slave,
+                                SND_PCM_HW_PARBIT_CHANNELS |
+                                SND_PCM_HW_PARBIT_RATE |
+                                SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+                                SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                                SND_PCM_HW_PARBIT_FRAGMENTS |
+                                SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+                                SND_PCM_HW_PARBIT_BUFFER_LENGTH);
        if (err < 0)
                return err;
+       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
-               if (alaw->sformat == SND_PCM_FORMAT_MU_LAW) {
-                       alaw->getput_idx = get_index(params->format, SND_PCM_FORMAT_S16);
+               if (alaw->sformat == SND_PCM_FORMAT_A_LAW) {
+                       alaw->getput_idx = get_index(snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT), SND_PCM_FORMAT_S16);
                        alaw->func = alaw_encode;
                } else {
                        alaw->getput_idx = put_index(SND_PCM_FORMAT_S16, alaw->sformat);
                        alaw->func = alaw_decode;
                }
        } else {
-               if (alaw->sformat == SND_PCM_FORMAT_MU_LAW) {
-                       alaw->getput_idx = put_index(SND_PCM_FORMAT_S16, params->format);
+               if (alaw->sformat == SND_PCM_FORMAT_A_LAW) {
+                       alaw->getput_idx = put_index(SND_PCM_FORMAT_S16, snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT));
                        alaw->func = alaw_decode;
                } else {
                        alaw->getput_idx = get_index(alaw->sformat, SND_PCM_FORMAT_S16);
@@ -363,7 +401,7 @@ static void snd_pcm_alaw_dump(snd_pcm_t *pcm, FILE *fp)
 snd_pcm_ops_t snd_pcm_alaw_ops = {
        close: snd_pcm_plugin_close,
        info: snd_pcm_plugin_info,
-       hw_info: snd_pcm_alaw_hw_info,
+       hw_refine: snd_pcm_alaw_hw_refine,
        hw_params: snd_pcm_alaw_hw_params,
        sw_params: snd_pcm_plugin_sw_params,
        dig_info: snd_pcm_plugin_dig_info,
index b699883dc877cf87fd63a360c09ba8f5060718b8..4a9ea503efb5ae283bc01813dddb0327e7be3326 100644 (file)
@@ -28,40 +28,50 @@ typedef struct {
        snd_pcm_plugin_t plug;
 } snd_pcm_copy_t;
 
-static int snd_pcm_copy_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
+static int snd_pcm_copy_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_copy_t *copy = pcm->private;
-       unsigned int access_mask;
+       snd_pcm_t *slave = copy->plug.slave;
        int err;
-       info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED | 
-                             SND_PCM_ACCBIT_RW_INTERLEAVED |
-                             SND_PCM_ACCBIT_MMAP_NONINTERLEAVED | 
-                             SND_PCM_ACCBIT_RW_NONINTERLEAVED);
-       access_mask = info->access_mask;
-       if (access_mask == 0)
-               return -EINVAL;
-
-       info->access_mask = SND_PCM_ACCBIT_MMAP;
-       err = snd_pcm_hw_info(copy->plug.slave, info);
-       info->access_mask = access_mask;
+       snd_pcm_hw_params_t sparams;
+       mask_t *access_mask = alloca(mask_sizeof());
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+       err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_ACCESS,
+                                     access_mask);
        if (err < 0)
                return err;
-       info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
-       snd_pcm_hw_info_complete(info);
-       return 0;
+       _snd_pcm_hw_params_any(&sparams);
+       _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+                               saccess_mask);
+       err = snd_pcm_hw_refine2(params, &sparams,
+                                snd_pcm_hw_refine, slave, 
+                                ~SND_PCM_HW_PARBIT_ACCESS);
+       if (err < 0)
+               return err;
+       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+       return err;
 }
 
 static int snd_pcm_copy_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_copy_t *copy = pcm->private;
        snd_pcm_t *slave = copy->plug.slave;
-       snd_pcm_hw_info_t sinfo;
-       snd_pcm_hw_params_t sparams;
        int err;
-       snd_pcm_hw_params_to_info(params, &sinfo);
-       sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
-       err = snd_pcm_hw_params_info(slave, &sparams, &sinfo);
-       params->fail_mask = sparams.fail_mask;
+       snd_pcm_hw_params_t sparams;
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+
+       _snd_pcm_hw_params_any(&sparams);
+       _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+                               saccess_mask);
+       err = snd_pcm_hw_params2(params, &sparams,
+                                snd_pcm_hw_params, slave, 
+                                ~SND_PCM_HW_PARBIT_ACCESS);
+       if (err < 0)
+               return err;
+       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
        return err;
 }
 
@@ -149,7 +159,7 @@ static void snd_pcm_copy_dump(snd_pcm_t *pcm, FILE *fp)
 snd_pcm_ops_t snd_pcm_copy_ops = {
        close: snd_pcm_plugin_close,
        info: snd_pcm_plugin_info,
-       hw_info: snd_pcm_copy_hw_info,
+       hw_refine: snd_pcm_copy_hw_refine,
        hw_params: snd_pcm_copy_hw_params,
        sw_params: snd_pcm_plugin_sw_params,
        dig_info: snd_pcm_plugin_dig_info,
index 2b563c396870ffc530bca9b8200b370a3bda8acf..bd464cb71a060596f09332e5a9b23a4ad48711c6 100644 (file)
@@ -254,10 +254,10 @@ static int snd_pcm_file_set_avail_min(snd_pcm_t *pcm, size_t frames)
        return snd_pcm_set_avail_min(file->slave, frames);
 }
 
-static int snd_pcm_file_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
+static int snd_pcm_file_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_file_t *file = pcm->private;
-       return snd_pcm_hw_info(file->slave, info);
+       return snd_pcm_hw_refine(file->slave, params);
 }
 
 static int snd_pcm_file_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
@@ -314,7 +314,7 @@ static void snd_pcm_file_dump(snd_pcm_t *pcm, FILE *fp)
 snd_pcm_ops_t snd_pcm_file_ops = {
        close: snd_pcm_file_close,
        info: snd_pcm_file_info,
-       hw_info: snd_pcm_file_hw_info,
+       hw_refine: snd_pcm_file_hw_refine,
        hw_params: snd_pcm_file_hw_params,
        sw_params: snd_pcm_file_sw_params,
        dig_info: snd_pcm_file_dig_info,
index c874634e3873863a8c5903fbeb7a4482006ecc08..78e1ecf372fdd56526cc44ce56bb2b418fedfdea 100644 (file)
@@ -109,7 +109,7 @@ static int snd_pcm_hw_async(snd_pcm_t *pcm, int sig, pid_t pid)
        return 0;
 }
 
-static int _snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
+static int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
 {
        snd_pcm_hw_t *hw = pcm->private;
        int fd = hw->fd;
@@ -120,12 +120,12 @@ static int _snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
        return 0;
 }
 
-static int snd_pcm_hw_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
+static int snd_pcm_hw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_hw_t *hw = pcm->private;
        int fd = hw->fd;
-       if (ioctl(fd, SND_PCM_IOCTL_HW_INFO, info) < 0) {
-               // SYSERR("SND_PCM_IOCTL_HW_INFO failed");
+       if (ioctl(fd, SND_PCM_IOCTL_HW_REFINE, params) < 0) {
+               // SYSERR("SND_PCM_IOCTL_HW_REFINE failed");
                return -errno;
        }
        return 0;
@@ -521,8 +521,8 @@ static void snd_pcm_hw_dump(snd_pcm_t *pcm, FILE *fp)
 
 snd_pcm_ops_t snd_pcm_hw_ops = {
        close: snd_pcm_hw_close,
-       info: _snd_pcm_hw_info,
-       hw_info: snd_pcm_hw_hw_info,
+       info: snd_pcm_hw_info,
+       hw_refine: snd_pcm_hw_hw_refine,
        hw_params: snd_pcm_hw_hw_params,
        sw_params: snd_pcm_hw_sw_params,
        dig_info: snd_pcm_hw_dig_info,
index 50c3e603c495202c5b34c4847a612a1beeec98b2..0647ee0755a2d783289463ac79c3b516ad865c7f 100644 (file)
@@ -72,32 +72,50 @@ static void linear_transfer(const snd_pcm_channel_area_t *src_areas, size_t src_
        }
 }
 
-static int snd_pcm_linear_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
+static int snd_pcm_linear_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_linear_t *linear = pcm->private;
-       unsigned int format_mask, access_mask;
+       snd_pcm_t *slave = linear->plug.slave;
        int err;
-       info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED | 
-                             SND_PCM_ACCBIT_RW_INTERLEAVED |
-                             SND_PCM_ACCBIT_MMAP_NONINTERLEAVED | 
-                             SND_PCM_ACCBIT_RW_NONINTERLEAVED);
-       access_mask = info->access_mask;
-       if (access_mask == 0)
-               return -EINVAL;
-       info->format_mask &= SND_PCM_FMTBIT_LINEAR;
-       format_mask = info->format_mask;
-       if (format_mask == 0)
-               return -EINVAL;
+       snd_pcm_hw_params_t sparams;
+       mask_t *access_mask = alloca(mask_sizeof());
+       mask_t *format_mask = alloca(mask_sizeof());
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
+       mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+       err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_ACCESS,
+                                     access_mask);
+       if (err < 0)
+               return err;
+       err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_FORMAT,
+                                     format_mask);
+       if (err < 0)
+               return err;
+       err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_SUBFORMAT,
+                                    SND_PCM_SUBFORMAT_STD);
+       if (err < 0)
+               return err;
 
-       info->format_mask = 1U << linear->sformat;
-       info->access_mask = SND_PCM_ACCBIT_MMAP;
-       err = snd_pcm_hw_info(linear->plug.slave, info);
-       info->format_mask = format_mask;
-       info->access_mask = access_mask;
+       _snd_pcm_hw_params_any(&sparams);
+       _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+                               saccess_mask);
+       _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+                              linear->sformat);
+       _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+                              SND_PCM_SUBFORMAT_STD);
+       err = snd_pcm_hw_refine2(params, &sparams,
+                                snd_pcm_hw_refine, slave,
+                                SND_PCM_HW_PARBIT_CHANNELS |
+                                SND_PCM_HW_PARBIT_RATE |
+                                SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+                                SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                                SND_PCM_HW_PARBIT_FRAGMENTS |
+                                SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+                                SND_PCM_HW_PARBIT_BUFFER_LENGTH);
        if (err < 0)
                return err;
-       info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
-       snd_pcm_hw_info_complete(info);
+       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
        return 0;
 }
 
@@ -105,22 +123,36 @@ static int snd_pcm_linear_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_linear_t *linear = pcm->private;
        snd_pcm_t *slave = linear->plug.slave;
-       snd_pcm_hw_info_t sinfo;
-       snd_pcm_hw_params_t sparams;
        int err;
-       snd_pcm_hw_params_to_info(params, &sinfo);
-       sinfo.format_mask = 1 << linear->sformat;
-       sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
-       err = snd_pcm_hw_params_info(slave, &sparams, &sinfo);
-       params->fail_mask = sparams.fail_mask;
+       snd_pcm_hw_params_t sparams;
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+
+       _snd_pcm_hw_params_any(&sparams);
+       _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+                               saccess_mask);
+       _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+                              linear->sformat);
+       _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+                              SND_PCM_SUBFORMAT_STD);
+       err = snd_pcm_hw_params2(params, &sparams,
+                                snd_pcm_hw_params, slave,
+                                SND_PCM_HW_PARBIT_CHANNELS |
+                                SND_PCM_HW_PARBIT_RATE |
+                                SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+                                SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                                SND_PCM_HW_PARBIT_FRAGMENTS |
+                                SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+                                SND_PCM_HW_PARBIT_BUFFER_LENGTH);
        if (err < 0)
                return err;
+       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
-               linear->conv_idx = conv_index(params->format,
+               linear->conv_idx = conv_index(snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT),
                                              linear->sformat);
        else
                linear->conv_idx = conv_index(linear->sformat,
-                                             params->format);
+                                             snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT));
        return 0;
 }
 
@@ -208,7 +240,7 @@ static void snd_pcm_linear_dump(snd_pcm_t *pcm, FILE *fp)
 snd_pcm_ops_t snd_pcm_linear_ops = {
        close: snd_pcm_plugin_close,
        info: snd_pcm_plugin_info,
-       hw_info: snd_pcm_linear_hw_info,
+       hw_refine: snd_pcm_linear_hw_refine,
        hw_params: snd_pcm_linear_hw_params,
        sw_params: snd_pcm_plugin_sw_params,
        dig_info: snd_pcm_plugin_dig_info,
index ecb671b6a093fc8ad54b00ba620ea4a1310e0176..0bf9796bb075a5ff5dc0ed18eee7d74a188421ae 100644 (file)
@@ -1,6 +1,7 @@
 /*
  *  PCM Interface - local header file
- *  Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
+ *  Copyright (c) 2000 by Jaroslav Kysela <perex@suse.cz>
+ *                        Abramo Bagnara <abramo@alsa-project.org>
  *
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -58,7 +59,7 @@ typedef struct {
        int (*nonblock)(snd_pcm_t *pcm, int nonblock);
        int (*async)(snd_pcm_t *pcm, int sig, pid_t pid);
        int (*info)(snd_pcm_t *pcm, snd_pcm_info_t *info);
-       int (*hw_info)(snd_pcm_t *pcm, snd_pcm_hw_info_t *info);
+       int (*hw_refine)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
        int (*hw_params)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
        int (*sw_params)(snd_pcm_t *pcm, snd_pcm_sw_params_t *params);
        int (*dig_info)(snd_pcm_t *pcm, snd_pcm_dig_info_t *info);
@@ -168,15 +169,9 @@ ssize_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area_t *areas,
                            snd_pcm_xfer_areas_func_t func);
 ssize_t snd_pcm_read_mmap(snd_pcm_t *pcm, size_t size);
 ssize_t snd_pcm_write_mmap(snd_pcm_t *pcm, size_t size);
-int snd_pcm_hw_info_complete(snd_pcm_hw_info_t *info);
-void snd_pcm_hw_params_to_info(snd_pcm_hw_params_t *params, snd_pcm_hw_info_t *info);
-int snd_pcm_hw_info_to_params(snd_pcm_t *pcm, snd_pcm_hw_info_t *info, snd_pcm_hw_params_t *params);
+int snd_pcm_hw_info_complete(snd_pcm_hw_params_t *info);
 int snd_pcm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info);
 int snd_pcm_channel_info_shm(snd_pcm_t *pcm, snd_pcm_channel_info_t *info, int shmid);
-int snd_pcm_hw_info_par_nearest_next(const snd_pcm_hw_info_t *info,
-                                    unsigned int param,
-                                    unsigned int best, int value,
-                                    snd_pcm_t *pcm);
 
 static inline size_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm)
 {
@@ -316,3 +311,50 @@ static inline int muldiv_near(int a, int b, int c)
                n++;
        return n;
 }
+
+int _snd_pcm_hw_refine(snd_pcm_hw_params_t *params);
+void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params);
+int _snd_pcm_hw_params_mask(snd_pcm_hw_params_t *params, int hw,
+                           unsigned int var, const mask_t *mask);
+int _snd_pcm_hw_params_first(snd_pcm_hw_params_t *params, int hw,
+                            unsigned int var);
+int _snd_pcm_hw_params_last(snd_pcm_hw_params_t *params, int hw,
+                           unsigned int var);
+int _snd_pcm_hw_params_set(snd_pcm_hw_params_t *params, int hw,
+                          unsigned int var, unsigned int val);
+int _snd_pcm_hw_params_min(snd_pcm_hw_params_t *params, int hw,
+                          unsigned int var, unsigned int val);
+int _snd_pcm_hw_params_max(snd_pcm_hw_params_t *params, int hw,
+                          unsigned int var, unsigned int val);
+int snd_pcm_hw_refine2(snd_pcm_hw_params_t *params,
+                      snd_pcm_hw_params_t *sparams,
+                      int (*func)(snd_pcm_t *slave,
+                                  snd_pcm_hw_params_t *params),
+                      snd_pcm_t *slave,
+                      unsigned int links);
+int snd_pcm_hw_params2(snd_pcm_hw_params_t *params,
+                      snd_pcm_hw_params_t *sparams,
+                      int (*func)(snd_pcm_t *slave, 
+                                  snd_pcm_hw_params_t *sparams),
+                      snd_pcm_t *slave,
+                      unsigned int links);
+
+#define SND_PCM_HW_PARBIT_ACCESS       (1 << SND_PCM_HW_PARAM_ACCESS)
+#define SND_PCM_HW_PARBIT_FORMAT       (1 << SND_PCM_HW_PARAM_FORMAT)
+#define SND_PCM_HW_PARBIT_SUBFORMAT    (1 << SND_PCM_HW_PARAM_SUBFORMAT)
+#define SND_PCM_HW_PARBIT_CHANNELS     (1 << SND_PCM_HW_PARAM_CHANNELS)
+#define SND_PCM_HW_PARBIT_RATE         (1 << SND_PCM_HW_PARAM_RATE)
+#define SND_PCM_HW_PARBIT_FRAGMENT_LENGTH (1 << SND_PCM_HW_PARAM_FRAGMENT_LENGTH)
+#define SND_PCM_HW_PARBIT_FRAGMENT_SIZE        (1 << SND_PCM_HW_PARAM_FRAGMENT_SIZE)
+#define SND_PCM_HW_PARBIT_FRAGMENTS    (1 << SND_PCM_HW_PARAM_FRAGMENTS)
+#define SND_PCM_HW_PARBIT_BUFFER_LENGTH        (1 << SND_PCM_HW_PARAM_BUFFER_LENGTH)
+#define SND_PCM_HW_PARBIT_BUFFER_SIZE  (1 << SND_PCM_HW_PARAM_BUFFER_SIZE)
+#define SND_PCM_HW_PARBIT_SAMPLE_BITS  (1 << SND_PCM_HW_PARAM_SAMPLE_BITS)
+#define SND_PCM_HW_PARBIT_FRAME_BITS   (1 << SND_PCM_HW_PARAM_FRAME_BITS)
+#define SND_PCM_HW_PARBIT_FRAGMENT_BYTES (1 << SND_PCM_HW_PARAM_FRAGMENT_BYTES)
+#define SND_PCM_HW_PARBIT_BUFFER_BYTES (1 << SND_PCM_HW_PARAM_BUFFER_BYTES)
+
+
+#define SND_PCM_ACCBIT_MMAP ((1 << SND_PCM_ACCESS_MMAP_INTERLEAVED) | \
+                            (1 << SND_PCM_ACCESS_MMAP_NONINTERLEAVED) | \
+                            (1 << SND_PCM_ACCESS_MMAP_COMPLEX))
index abefeacb601f1c57e416de6a2b0c7c4b557b48a5..4b937911310c53d3600038677d91a2c9c739906e 100644 (file)
@@ -228,35 +228,59 @@ static void mulaw_encode(const snd_pcm_channel_area_t *src_areas,
        }
 }
 
-static int snd_pcm_mulaw_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
+static int snd_pcm_mulaw_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_mulaw_t *mulaw = pcm->private;
-       unsigned int format_mask, access_mask;
+       snd_pcm_t *slave = mulaw->plug.slave;
        int err;
-       info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED | 
-                             SND_PCM_ACCBIT_RW_INTERLEAVED |
-                             SND_PCM_ACCBIT_MMAP_NONINTERLEAVED | 
-                             SND_PCM_ACCBIT_RW_NONINTERLEAVED);
-       access_mask = info->access_mask;
-       if (access_mask == 0)
-               return -EINVAL;
-       if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW)
-               info->format_mask &= SND_PCM_FMTBIT_LINEAR;
-       else
-               info->format_mask &= SND_PCM_FMTBIT_MU_LAW;
-       format_mask = info->format_mask;
-       if (format_mask == 0)
-               return -EINVAL;
+       snd_pcm_hw_params_t sparams;
+       mask_t *access_mask = alloca(mask_sizeof());
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+       err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_ACCESS,
+                                     access_mask);
+       if (err < 0)
+               return err;
+       if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) {
+               mask_t *format_mask = alloca(mask_sizeof());
+               mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
+               err = _snd_pcm_hw_params_mask(params, 1, 
+                                             SND_PCM_HW_PARAM_FORMAT,
+                                             format_mask);
+               if (err < 0)
+                       return err;
+       } else {
+               err = _snd_pcm_hw_params_set(params, 1,
+                                            SND_PCM_HW_PARAM_FORMAT,
+                                            SND_PCM_FORMAT_MU_LAW);
+               if (err < 0)
+                       return err;
+       }
+       err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_SUBFORMAT,
+                                    SND_PCM_SUBFORMAT_STD);
+       if (err < 0)
+               return err;
 
-       info->format_mask = 1U << mulaw->sformat;
-       info->access_mask = SND_PCM_ACCBIT_MMAP;
-       err = snd_pcm_hw_info(mulaw->plug.slave, info);
-       info->format_mask = format_mask;
-       info->access_mask = access_mask;
+       _snd_pcm_hw_params_any(&sparams);
+       _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+                               saccess_mask);
+       _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+                              mulaw->sformat);
+       _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+                              SND_PCM_SUBFORMAT_STD);
+       err = snd_pcm_hw_refine2(params, &sparams,
+                                snd_pcm_hw_refine, slave,
+                                SND_PCM_HW_PARBIT_CHANNELS |
+                                SND_PCM_HW_PARBIT_RATE |
+                                SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+                                SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                                SND_PCM_HW_PARBIT_FRAGMENTS |
+                                SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+                                SND_PCM_HW_PARBIT_BUFFER_LENGTH);
        if (err < 0)
                return err;
-       info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
-       snd_pcm_hw_info_complete(info);
+       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
        return 0;
 }
 
@@ -264,19 +288,33 @@ static int snd_pcm_mulaw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
 {
        snd_pcm_mulaw_t *mulaw = pcm->private;
        snd_pcm_t *slave = mulaw->plug.slave;
-       snd_pcm_hw_info_t sinfo;
-       snd_pcm_hw_params_t sparams;
        int err;
-       snd_pcm_hw_params_to_info(params, &sinfo);
-       sinfo.format_mask = 1 << mulaw->sformat;
-       sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
-       err = snd_pcm_hw_params_info(slave, &sparams, &sinfo);
-       params->fail_mask = sparams.fail_mask;
+       snd_pcm_hw_params_t sparams;
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+
+       _snd_pcm_hw_params_any(&sparams);
+       _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+                               saccess_mask);
+       _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+                              mulaw->sformat);
+       _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+                              SND_PCM_SUBFORMAT_STD);
+       err = snd_pcm_hw_params2(params, &sparams,
+                                snd_pcm_hw_params, slave,
+                                SND_PCM_HW_PARBIT_CHANNELS |
+                                SND_PCM_HW_PARBIT_RATE |
+                                SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+                                SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                                SND_PCM_HW_PARBIT_FRAGMENTS |
+                                SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+                                SND_PCM_HW_PARBIT_BUFFER_LENGTH);
        if (err < 0)
                return err;
+       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
                if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) {
-                       mulaw->getput_idx = get_index(params->format, SND_PCM_FORMAT_S16);
+                       mulaw->getput_idx = get_index(snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT), SND_PCM_FORMAT_S16);
                        mulaw->func = mulaw_encode;
                } else {
                        mulaw->getput_idx = put_index(SND_PCM_FORMAT_S16, mulaw->sformat);
@@ -284,7 +322,7 @@ static int snd_pcm_mulaw_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
                }
        } else {
                if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) {
-                       mulaw->getput_idx = put_index(SND_PCM_FORMAT_S16, params->format);
+                       mulaw->getput_idx = put_index(SND_PCM_FORMAT_S16, snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT));
                        mulaw->func = mulaw_decode;
                } else {
                        mulaw->getput_idx = get_index(mulaw->sformat, SND_PCM_FORMAT_S16);
@@ -380,7 +418,7 @@ static void snd_pcm_mulaw_dump(snd_pcm_t *pcm, FILE *fp)
 snd_pcm_ops_t snd_pcm_mulaw_ops = {
        close: snd_pcm_plugin_close,
        info: snd_pcm_plugin_info,
-       hw_info: snd_pcm_mulaw_hw_info,
+       hw_refine: snd_pcm_mulaw_hw_refine,
        hw_params: snd_pcm_mulaw_hw_params,
        sw_params: snd_pcm_plugin_sw_params,
        dig_info: snd_pcm_plugin_dig_info,
index 82c50cc0e3be1d8792bc4ecf63b246e6762bbb96..57578a3ef9816e5da794a4f369504b5554f5184a 100644 (file)
@@ -26,6 +26,7 @@
 #include <errno.h>
 #include <math.h>
 #include "pcm_local.h"
+#include "interval.h"
 
 typedef struct {
        snd_pcm_t *pcm;
@@ -90,83 +91,109 @@ static int snd_pcm_multi_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
        return 0;
 }
 
-static int snd_pcm_multi_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info)
+static int snd_pcm_multi_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_multi_t *multi = pcm->private;
        unsigned int k;
-       snd_pcm_hw_info_t i;
-       unsigned int access_mask, saccess_mask;
+       snd_pcm_hw_params_t sparams;
        int changed = 0;
-       int err = 0;
-       if (info->channels_min < multi->channels_count)
-               info->channels_min = multi->channels_count;
-       if (info->channels_max > multi->channels_count)
-               info->channels_max = multi->channels_count;
-       if (info->channels_min > info->channels_max)
-               return -EINVAL;
-       i = *info;
-       saccess_mask = ~0;
+       int err;
+       const mask_t *access_mask = snd_pcm_hw_params_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       if (mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) ||
+           mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED))
+               mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+       else {
+               mask_none(saccess_mask);
+               if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED) &&
+                   multi->slaves_count == 1)
+                       mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
+               if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED))
+                       mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
+               if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_COMPLEX)) {
+                       mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX);
+                       if (multi->slaves_count > 1)
+                               mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
+               }
+       }
+               
+       err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_CHANNELS,
+                                    multi->channels_count);
+       if (err < 0)
+               return err;
        changed = 0;
        do {
                for (k = 0; k < multi->slaves_count; ++k) {
                        snd_pcm_t *slave = multi->slaves[k].pcm;
-                       snd_pcm_hw_info_t sinfo = i;
-                       sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
-                       sinfo.channels_min = sinfo.channels_max = multi->slaves[k].channels_count;
-                       err = snd_pcm_hw_info(slave, &sinfo);
-                       if (err < 0) {
-                               sinfo.access_mask = info->access_mask;
-                               sinfo.channels_min = multi->channels_count;
-                               sinfo.channels_max = multi->channels_count;
-                               *info = sinfo;
+                       _snd_pcm_hw_params_any(&sparams);
+                       _snd_pcm_hw_params_mask(&sparams, 0,
+                                               SND_PCM_HW_PARAM_ACCESS,
+                                               saccess_mask);
+                       _snd_pcm_hw_params_set(&sparams, 0,
+                                              SND_PCM_HW_PARAM_CHANNELS,
+                                              multi->slaves[k].channels_count);
+                       err = snd_pcm_hw_refine2(params, &sparams,
+                                                snd_pcm_hw_refine, slave,
+                                                SND_PCM_HW_PARBIT_FORMAT |
+                                                SND_PCM_HW_PARBIT_SUBFORMAT |
+                                                SND_PCM_HW_PARBIT_RATE |
+                                                SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+                                                SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+                                                SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                                                SND_PCM_HW_PARBIT_BUFFER_LENGTH |
+                                                SND_PCM_HW_PARBIT_FRAGMENTS);
+                       if (err < 0)
                                return err;
-                       }
-                       if (i.format_mask != sinfo.format_mask ||
-                           i.subformat_mask != sinfo.subformat_mask ||
-                           i.rate_min != sinfo.rate_min ||
-                           i.rate_max != sinfo.rate_max ||
-                           i.fragment_length_min != sinfo.fragment_length_min ||
-                           i.fragment_length_max != sinfo.fragment_length_max ||
-                           i.fragments_min != sinfo.fragments_min ||
-                           i.fragments_max != sinfo.fragments_max ||
-                           i.buffer_length_min != sinfo.buffer_length_min ||
-                           i.buffer_length_max != sinfo.buffer_length_max)
+                       if (params->hw_cmask)
                                changed++;
-                       saccess_mask &= sinfo.access_mask;
-                       i = sinfo;
                }
        } while (changed && multi->slaves_count > 1);
-       access_mask = info->access_mask;
-       *info = i;
-       info->access_mask = access_mask;
-       if (!(saccess_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED) ||
-           multi->slaves_count > 1)
-               info->access_mask &= ~SND_PCM_ACCBIT_MMAP_INTERLEAVED;
-       if (!(saccess_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED))
-               info->access_mask &= ~SND_PCM_ACCBIT_MMAP_NONINTERLEAVED;
-       if (!info->access_mask)
-               return -EINVAL;
-       info->channels_min = info->channels_max = multi->channels_count;
        return 0;
 }
 
 static int snd_pcm_multi_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_multi_t *multi = pcm->private;
-       unsigned int i;
+       unsigned int k;
        int err;
-       for (i = 0; i < multi->slaves_count; ++i) {
-               snd_pcm_t *slave = multi->slaves[i].pcm;
-               snd_pcm_hw_info_t sinfo;
+       const mask_t *access_mask = snd_pcm_hw_params_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       if (mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) ||
+           mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED))
+               mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+       else {
+               mask_none(saccess_mask);
+               if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED) &&
+                   multi->slaves_count == 1)
+                       mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
+               if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED))
+                       mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
+               if (mask_test(access_mask, SND_PCM_ACCESS_MMAP_COMPLEX)) {
+                       mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX);
+                       if (multi->slaves_count > 1)
+                               mask_set(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
+               }
+       }
+       for (k = 0; k < multi->slaves_count; ++k) {
+               snd_pcm_t *slave = multi->slaves[k].pcm;
                snd_pcm_hw_params_t sparams;
-               snd_pcm_hw_params_to_info(params, &sinfo);
-               sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
-               sinfo.channels_min = sinfo.channels_max = multi->slaves[i].channels_count;
-               err = snd_pcm_hw_params_info(slave, &sparams, &sinfo);
-               if (err < 0) {
-                       params->fail_mask = sparams.fail_mask;
+               _snd_pcm_hw_params_any(&sparams);
+               _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+                                       saccess_mask);
+               _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_CHANNELS,
+                                      multi->slaves[k].channels_count);
+               err = snd_pcm_hw_params2(params, &sparams,
+                                        snd_pcm_hw_params, slave,
+                                        SND_PCM_HW_PARBIT_FORMAT |
+                                        SND_PCM_HW_PARBIT_SUBFORMAT |
+                                        SND_PCM_HW_PARBIT_RATE |
+                                        SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+                                        SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+                                        SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                                        SND_PCM_HW_PARBIT_BUFFER_LENGTH |
+                                        SND_PCM_HW_PARBIT_FRAGMENTS);
+               if (err < 0)
                        return err;
-               }
                err = snd_pcm_areas_silence(slave->running_areas, 0, slave->channels, slave->buffer_size, slave->format);
                if (err < 0)
                        return err;
@@ -376,7 +403,7 @@ static void snd_pcm_multi_dump(snd_pcm_t *pcm, FILE *fp)
 snd_pcm_ops_t snd_pcm_multi_ops = {
        close: snd_pcm_multi_close,
        info: snd_pcm_multi_info,
-       hw_info: snd_pcm_multi_hw_info,
+       hw_refine: snd_pcm_multi_hw_refine,
        hw_params: snd_pcm_multi_hw_params,
        sw_params: snd_pcm_multi_sw_params,
        dig_info: snd_pcm_multi_dig_info,
index abaa06ad08af60fc6494a8fa5d99c12ef4e34eeb..bdedd22f1bd7c292f976d5e8be339f179ef1fc74 100644 (file)
@@ -230,10 +230,11 @@ static int snd_pcm_null_set_avail_min(snd_pcm_t *pcm, size_t frames)
        return 0;
 }
 
-static int snd_pcm_null_hw_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_info_t * info)
+static int snd_pcm_null_hw_refine(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params)
 {
-       snd_pcm_hw_info_complete(info);
-       info->fifo_size = 0;
+       _snd_pcm_hw_refine(params);
+       params->fifo_size = 0;
+       params->dig_groups = 0;
        return 0;
 }
 
@@ -245,15 +246,15 @@ static int snd_pcm_null_hw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_pa
 static int snd_pcm_null_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t * params)
 {
        if (params->start_mode > SND_PCM_START_LAST) {
-               params->fail_mask = SND_PCM_SW_PARBIT_START_MODE;
+               params->fail_mask = 1 << SND_PCM_SW_PARAM_START_MODE;
                return -EINVAL;
        }
        if (params->ready_mode > SND_PCM_READY_LAST) {
-               params->fail_mask = SND_PCM_SW_PARBIT_READY_MODE;
+               params->fail_mask = 1 << SND_PCM_SW_PARAM_READY_MODE;
                return -EINVAL;
        }
        if (params->xrun_mode > SND_PCM_XRUN_LAST) {
-               params->fail_mask = SND_PCM_SW_PARBIT_XRUN_MODE;
+               params->fail_mask = 1 << SND_PCM_SW_PARAM_XRUN_MODE;
                return -EINVAL;
        }
        return 0;
@@ -306,7 +307,7 @@ static void snd_pcm_null_dump(snd_pcm_t *pcm, FILE *fp)
 snd_pcm_ops_t snd_pcm_null_ops = {
        close: snd_pcm_null_close,
        info: snd_pcm_null_info,
-       hw_info: snd_pcm_null_hw_info,
+       hw_refine: snd_pcm_null_hw_refine,
        hw_params: snd_pcm_null_hw_params,
        sw_params: snd_pcm_null_sw_params,
        dig_params: snd_pcm_null_dig_params,
diff --git a/src/pcm/pcm_params.c b/src/pcm/pcm_params.c
new file mode 100644 (file)
index 0000000..b944ed9
--- /dev/null
@@ -0,0 +1,1689 @@
+/*
+ *  PCM - Params functions
+ *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
+ *
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Library General Public License as
+ *   published by the Free Software Foundation; either version 2 of
+ *   the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Library General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Library General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+  
+#include "pcm_local.h"
+#include "interval_inline.h"
+#include "interval.h"
+#include "mask.h"
+
+static inline unsigned int add(unsigned int a, unsigned int b)
+{
+       if (a >= UINT_MAX - b)
+               return UINT_MAX;
+       return a + b;
+}
+
+static inline unsigned int sub(unsigned int a, unsigned int b)
+{
+       if (a > b)
+               return a - b;
+       return 0;
+}
+
+static inline int is_mask(int var)
+{
+       return var >= SND_PCM_HW_PARAM_FIRST_MASK &&
+               var <= SND_PCM_HW_PARAM_LAST_MASK;
+}
+
+static inline int is_interval(int var)
+{
+       return var >= SND_PCM_HW_PARAM_FIRST_INTERVAL &&
+               var <= SND_PCM_HW_PARAM_LAST_INTERVAL;
+}
+
+static inline mask_t *params_mask(snd_pcm_hw_params_t *params,
+                                 unsigned int var)
+{
+       assert(is_mask(var));
+       return (mask_t*)&params->masks[var - SND_PCM_HW_PARAM_FIRST_MASK];
+}
+
+static inline interval_t *params_interval(snd_pcm_hw_params_t *params,
+                                         unsigned int var)
+{
+       assert(is_interval(var));
+       return &params->intervals[var - SND_PCM_HW_PARAM_FIRST_INTERVAL];
+}
+
+static inline const mask_t *params_mask_c(const snd_pcm_hw_params_t *params,
+                                         unsigned int var)
+{
+       return (const mask_t *)params_mask((snd_pcm_hw_params_t*) params, var);
+}
+
+static inline const interval_t *params_interval_c(const snd_pcm_hw_params_t *params,
+                                                 unsigned int var)
+{
+       return (const interval_t *)params_interval((snd_pcm_hw_params_t*) params, var);
+}
+
+void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params)
+{
+       unsigned int k;
+       memset(params, 0, sizeof(*params));
+       for (k = SND_PCM_HW_PARAM_FIRST_MASK; k <= SND_PCM_HW_PARAM_LAST_MASK; k++) {
+               mask_all(params_mask(params, k));
+               params->appl_cmask |= 1 << k;
+       }
+
+       for (k = SND_PCM_HW_PARAM_FIRST_INTERVAL; k <= SND_PCM_HW_PARAM_LAST_INTERVAL; k++) {
+               interval_all(params_interval(params, k));
+               params->appl_cmask |= 1 << k;
+       }
+       interval_setreal(params_interval(params, SND_PCM_HW_PARAM_RATE));
+       interval_setreal(params_interval(params, SND_PCM_HW_PARAM_FRAGMENT_LENGTH));
+       interval_setreal(params_interval(params, SND_PCM_HW_PARAM_BUFFER_LENGTH));
+       params->info = ~0U;
+       params->dig_groups = UINT_MAX;
+}
+
+/* Fill PARAMS with full configuration space boundaries */
+int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+       _snd_pcm_hw_params_any(params);
+       return snd_pcm_hw_refine(pcm, params);
+}
+
+/* Return the value for field PAR if it's fixed in configuration space 
+   defined by PARAMS. Return -EINVAL otherwise
+*/
+int snd_pcm_hw_params_value(const snd_pcm_hw_params_t *params,
+                           unsigned int var)
+{
+       if (is_mask(var)) {
+               const mask_t *mask = params_mask_c(params, var);
+               if (!mask_single(mask))
+                       return -EINVAL;
+               return mask_value(mask);
+       }
+       if (is_interval(var)) {
+               const interval_t *i = params_interval_c(params, var);
+               if (!interval_single(i))
+                       return -EINVAL;
+               return interval_value(i);
+       }
+       assert(0);
+       return -EINVAL;
+}
+
+/* Return the minimum value for field PAR. */
+unsigned int snd_pcm_hw_params_value_min(const snd_pcm_hw_params_t *params,
+                                        unsigned int var)
+{
+       if (is_mask(var)) {
+               return mask_min(params_mask_c(params, var));
+       }
+       if (is_interval(var)) {
+               return interval_min(params_interval_c(params, var));
+       }
+       assert(0);
+       return -EINVAL;
+}
+
+/* Return the maximum value for field PAR. */
+unsigned int snd_pcm_hw_params_value_max(const snd_pcm_hw_params_t *params,
+                                        unsigned int var)
+{
+       if (is_mask(var)) {
+               return mask_max(params_mask_c(params, var));
+       }
+       if (is_interval(var)) {
+               return interval_max(params_interval_c(params, var));
+       }
+       assert(0);
+       return -EINVAL;
+}
+
+/* Return the mask for field PAR.
+   This function can be called only for SND_PCM_HW_PARAM_ACCESS,
+   SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT. */
+const mask_t *snd_pcm_hw_params_value_mask(const snd_pcm_hw_params_t *params,
+                                          unsigned int var)
+{
+       assert(is_mask(var));
+       return params_mask_c(params, var);
+}
+
+/* Return the interval for field PAR.
+   This function cannot be called for SND_PCM_HW_PARAM_ACCESS,
+   SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT. */
+const interval_t *snd_pcm_hw_params_value_interval(const snd_pcm_hw_params_t *params,
+                                                  unsigned int var)
+{
+       assert(is_interval(var));
+       return params_interval_c(params, var);
+}
+
+
+/* --- Refinement functions --- */
+
+int _snd_pcm_hw_params_first(snd_pcm_hw_params_t *params, int hw,
+                            unsigned int var)
+{
+       int changed;
+       if (is_mask(var))
+               changed = mask_refine_first(params_mask(params, var));
+       else if (is_interval(var))
+               changed = interval_refine_first(params_interval(params, var));
+       else {
+               assert(0);
+               return -EINVAL;
+       }
+       if (changed) {
+               if (hw)
+                       params->hw_cmask |= 1 << var;
+               else
+                       params->appl_cmask |= 1 << var;
+       }
+       return changed;
+}
+
+
+/* Inside configuration space defined by PARAMS remove from PAR all 
+   values > minimum. Reduce configuration space accordingly.
+   Return the minimum.
+*/
+int snd_pcm_hw_params_first(snd_pcm_t *pcm, 
+                           snd_pcm_hw_params_t *params, unsigned int var)
+{
+       int changed = _snd_pcm_hw_params_first(params, 0, var);
+       if (changed < 0)
+               return changed;
+       if (changed) {
+               int err = snd_pcm_hw_refine(pcm, params);
+               assert(err >= 0);
+       }
+       return snd_pcm_hw_params_value(params, var);
+}
+
+int _snd_pcm_hw_params_last(snd_pcm_hw_params_t *params, int hw,
+                           unsigned int var)
+{
+       int changed;
+       if (is_mask(var))
+               changed = mask_refine_last(params_mask(params, var));
+       else if (is_interval(var))
+               changed = interval_refine_last(params_interval(params, var));
+       else {
+               assert(0);
+               return -EINVAL;
+       }
+       if (changed) {
+               if (hw)
+                       params->hw_cmask |= 1 << var;
+               else
+                       params->appl_cmask |= 1 << var;
+       }
+       return changed;
+}
+
+
+/* Inside configuration space defined by PARAMS remove from PAR all 
+   values < maximum. Reduce configuration space accordingly.
+   Return the maximum.
+*/
+int snd_pcm_hw_params_last(snd_pcm_t *pcm, 
+                           snd_pcm_hw_params_t *params, unsigned int var)
+{
+       int changed = _snd_pcm_hw_params_last(params, 0, var);
+       if (changed < 0)
+               return changed;
+       if (changed) {
+               int err = snd_pcm_hw_refine(pcm, params);
+               assert(err >= 0);
+       }
+       return snd_pcm_hw_params_value(params, var);
+}
+
+int _snd_pcm_hw_params_min(snd_pcm_hw_params_t *params, int hw,
+                          unsigned int var, unsigned int val)
+{
+       int changed;
+       if (is_mask(var))
+               changed = mask_refine_min(params_mask(params, var), val);
+       else if (is_interval(var))
+               changed = interval_refine_min(params_interval(params, var), val);
+       else {
+               assert(0);
+               return -EINVAL;
+       }
+       if (changed) {
+               if (hw)
+                       params->hw_cmask |= 1 << var;
+               else
+                       params->appl_cmask |= 1 << var;
+       }
+       return changed;
+}
+
+/* Inside configuration space defined by PARAMS remove from PAR all 
+   values < VAL. Reduce configuration space accordingly.
+   Return new minimum or -EINVAL if the configuration space is empty
+*/
+int snd_pcm_hw_params_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                         unsigned int var, unsigned int val)
+{
+       int changed = _snd_pcm_hw_params_min(params, 0, var, val);
+       if (changed < 0)
+               return changed;
+       if (changed) {
+               int err = snd_pcm_hw_refine(pcm, params);
+               if (err < 0)
+                       return err;
+       }
+       return snd_pcm_hw_params_value_min(params, var);
+}
+
+int _snd_pcm_hw_params_max(snd_pcm_hw_params_t *params, int hw,
+                          unsigned int var, unsigned int val)
+{
+       int changed;
+       if (is_mask(var))
+               changed = mask_refine_max(params_mask(params, var), val);
+       else if (is_interval(var))
+               changed = interval_refine_max(params_interval(params, var), val);
+       else {
+               assert(0);
+               return -EINVAL;
+       }
+       if (changed) {
+               if (hw)
+                       params->hw_cmask |= 1 << var;
+               else
+                       params->appl_cmask |= 1 << var;
+       }
+       return changed;
+}
+
+/* Inside configuration space defined by PARAMS remove from PAR all 
+   values >= VAL + 1. Reduce configuration space accordingly.
+   Return new maximum or -EINVAL if the configuration space is empty
+*/
+int snd_pcm_hw_params_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                         unsigned int var, unsigned int val)
+{
+       int changed = _snd_pcm_hw_params_max(params, 0, var, val);
+       if (changed < 0)
+               return changed;
+       if (changed) {
+               int err = snd_pcm_hw_refine(pcm, params);
+               if (err < 0)
+                       return err;
+       }
+       return snd_pcm_hw_params_value_max(params, var);
+}
+
+int _snd_pcm_hw_params_minmax(snd_pcm_hw_params_t *params, int hw,
+                             unsigned int var,
+                             unsigned int min, unsigned int max)
+{
+       int changed, c1, c2;
+       if (is_mask(var)) {
+               mask_t *mask = params_mask(params, var);
+               c1 = mask_refine_min(mask, min);
+               if (c1 < 0)
+                       changed = c1;
+               else {
+                       c2 = mask_refine_max(mask, max);
+                       if (c2 < 0)
+                               changed = c2;
+                       else
+                               changed = (c1 || c2);
+               }
+       }
+       else if (is_interval(var)) {
+               interval_t *i = params_interval(params, var);
+               c1 = interval_refine_min(i, min);
+               if (c1 < 0)
+                       changed = c1;
+               else {
+                       c2 = interval_refine_max(i, max);
+                       if (c2 < 0)
+                               changed = c2;
+                       else
+                               changed = (c1 || c2);
+               }
+       } else {
+               assert(0);
+               return -EINVAL;
+       }
+       if (changed) {
+               if (hw)
+                       params->hw_cmask |= 1 << var;
+               else
+                       params->appl_cmask |= 1 << var;
+       }
+       return changed;
+}
+
+/* Inside configuration space defined by PARAMS remove from PAR all 
+   values < MIN and all values > MAX. Reduce configuration space accordingly.
+   Return 0 or -EINVAL if the configuration space is empty
+*/
+int snd_pcm_hw_params_minmax(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                            unsigned int var,
+                            unsigned int min, unsigned int max)
+{
+       int changed = _snd_pcm_hw_params_minmax(params, 0, var, min, max);
+       if (changed < 0)
+               return changed;
+       if (changed) {
+               int err = snd_pcm_hw_refine(pcm, params);
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+int _snd_pcm_hw_params_set(snd_pcm_hw_params_t *params, int hw,
+                          unsigned int var, unsigned int val)
+{
+       int changed;
+       if (is_mask(var))
+               changed = mask_refine_set(params_mask(params, var), val);
+       else if (is_interval(var))
+               changed = interval_refine_set(params_interval(params, var), val);
+       else {
+               assert(0);
+               return -EINVAL;
+       }
+       if (changed) {
+               if (hw)
+                       params->hw_cmask |= 1 << var;
+               else
+                       params->appl_cmask |= 1 << var;
+       }
+       return changed;
+}
+
+/* Inside configuration space defined by PARAMS remove from PAR all 
+   values < VAL and >= VAL +1. Reduce configuration space accordingly.
+   Return VAL or -EINVAL if the configuration space is empty
+*/
+int snd_pcm_hw_params_set(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                         unsigned int var, unsigned int val)
+{
+       int changed = _snd_pcm_hw_params_set(params, 0, var, val);
+       if (changed < 0)
+               return changed;
+       if (changed) {
+               int err = snd_pcm_hw_refine(pcm, params);
+               if (err < 0)
+                       return err;
+       }
+       return snd_pcm_hw_params_value(params, var);
+}
+
+int _snd_pcm_hw_params_mask(snd_pcm_hw_params_t *params, int hw,
+                           unsigned int var, const mask_t *val)
+{
+       int changed;
+       assert(is_mask(var));
+       changed = mask_refine(params_mask(params, var), val);
+       if (changed) {
+               if (hw)
+                       params->hw_cmask |= 1 << var;
+               else
+                       params->appl_cmask |= 1 << var;
+       }
+       return changed;
+}
+
+/* Inside configuration space defined by PARAMS remove from PAR all values
+   not contained in MASK. Reduce configuration space accordingly.
+   This function can be called only for SND_PCM_HW_PARAM_ACCESS,
+   SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT.
+   Return 0 on success or -EINVAL
+   if the configuration space is empty
+*/
+int snd_pcm_hw_params_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                          unsigned int var, const mask_t *val)
+{
+       int changed = _snd_pcm_hw_params_mask(params, 0, var, val);
+       if (changed < 0)
+               return changed;
+       if (changed) {
+               int err = snd_pcm_hw_refine(pcm, params);
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+/* Inside configuration space defined by PARAMS set PAR to the available value
+   nearest to VAL. Reduce configuration space accordingly.
+   This function cannot be called for SND_PCM_HW_PARAM_ACCESS,
+   SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT.
+   Return the value found.
+ */
+int snd_pcm_hw_params_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                          unsigned int var, unsigned int val)
+{
+       snd_pcm_hw_params_t save;
+       int v;
+       unsigned int max1 = val, min2 = add(val, 1);
+       save = *params;
+       v = snd_pcm_hw_params_max(pcm, params, var, max1);
+       if (v >= 0) {
+               int v1;
+               snd_pcm_hw_params_t params1;
+               if (val == (unsigned int)v)
+                       goto _end;
+               params1 = save;
+               v1 = snd_pcm_hw_params_min(pcm, &params1, var, min2);
+               if (v1 < 0)
+                       goto _end;
+               if (val - v > v1 - val) {
+                       *params = params1;
+                       v = v1;
+               }
+       } else {
+               *params = save;
+               v = snd_pcm_hw_params_min(pcm, params, var, min2);
+               assert(v >= 0);
+       }
+ _end:
+       v = snd_pcm_hw_params_set(pcm, params, var, v);
+       assert(v >= 0);
+       return v;
+}
+
+/* Inside configuration space defined by PARAMS set PAR to the available value
+   nearest to VAL after OLD (values less than VAL are returned first).
+   Reduce configuration space accordingly.
+   This function cannot be called for SND_PCM_HW_PARAM_ACCESS,
+   SND_PCM_HW_PARAM_FORMAT, SND_PCM_HW_PARAM_SUBFORMAT.
+   Return the value found.
+ */
+int snd_pcm_hw_params_next(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                          unsigned int var, unsigned int val,
+                          unsigned int old)
+{
+       snd_pcm_hw_params_t save;
+       int v;
+       unsigned int max1, min2;
+       int diff = old - val;
+       if (diff < 0) {
+               max1 = sub(old, 1);
+               min2 = add(val, -diff);
+       } else {
+               max1 = sub(val, diff + 1);
+               min2 = add(old, 1);
+       }
+       save = *params;
+       v = snd_pcm_hw_params_max(pcm, params, var, max1);
+       if (v >= 0) {
+               int v1;
+               snd_pcm_hw_params_t params1;
+               if (val == (unsigned int)v)
+                       goto _end;
+               params1 = save;
+               v1 = snd_pcm_hw_params_min(pcm, &params1, var, min2);
+               if (v1 < 0)
+                       goto _end;
+               if (val - v > v1 - val) {
+                       *params = params1;
+                       v = v1;
+               }
+       } else {
+               *params = save;
+               v = snd_pcm_hw_params_min(pcm, params, var, min2);
+               if (v < 0)
+                       return v;
+       }
+ _end:
+       v = snd_pcm_hw_params_set(pcm, params, var, v);
+       return v;
+}
+
+
+/* ---- end of refinement functions ---- */
+
+int snd_pcm_hw_params_empty(const snd_pcm_hw_params_t *params,
+                           unsigned int var)
+{
+       if (is_mask(var))
+               return mask_empty(params_mask_c(params, var));
+       if (is_interval(var))
+               return interval_empty(params_interval_c(params, var));
+       assert(0);
+       return -EINVAL;
+}
+
+/* Return rate numerator/denumerator obtainable for configuration space defined
+   by PARAMS */
+int snd_pcm_hw_params_info_rate(const snd_pcm_hw_params_t *params,
+                               unsigned int *rate_num, unsigned int *rate_den)
+{
+       if (params->rate_den == 0)
+               return -EINVAL;
+       *rate_num = params->rate_num;
+       *rate_den = params->rate_den;
+       return 0;
+}
+
+/* Return significative bits in sample for configuration space defined
+   by PARAMS */
+int snd_pcm_hw_params_info_msbits(const snd_pcm_hw_params_t *params)
+{
+       if (params->msbits == 0)
+               return -EINVAL;
+       return params->msbits;
+}
+
+/* Return info for configuration space defined by PARAMS */
+int snd_pcm_hw_params_info_flags(const snd_pcm_hw_params_t *params)
+{
+       if (params->info == ~0U)
+               return -EINVAL;
+       return params->info;
+}
+
+/* Return fifo size for configuration space defined by PARAMS */
+int snd_pcm_hw_params_info_fifo_size(const snd_pcm_hw_params_t *params)
+{
+       if (params->fifo_size == 0)
+               return -EINVAL;
+       return params->fifo_size;
+}
+
+/* Return count of digital groups for configuration space defined by PARAMS */
+int snd_pcm_hw_params_info_dig_groups(const snd_pcm_hw_params_t *params)
+{
+       if (params->dig_groups == UINT_MAX)
+               return -EINVAL;
+       return params->dig_groups;
+}
+
+/* Choose one configuration from configuration space defined by PARAMS
+   The configuration choosen is that obtained fixing in this order:
+   first access
+   first format
+   first subformat
+   min channels
+   min rate
+   min fragment size
+   max fragments
+*/
+void snd_pcm_hw_params_choose(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+       int err;
+       unsigned int hw_cmask = 0;
+
+       err = snd_pcm_hw_params_first(pcm, params, SND_PCM_HW_PARAM_ACCESS);
+       assert(err >= 0);
+       hw_cmask |= params->hw_cmask;
+
+       err = snd_pcm_hw_params_first(pcm, params, SND_PCM_HW_PARAM_FORMAT);
+       assert(err >= 0);
+       hw_cmask |= params->hw_cmask;
+
+       err = snd_pcm_hw_params_first(pcm, params, SND_PCM_HW_PARAM_SUBFORMAT);
+       assert(err >= 0);
+       hw_cmask |= params->hw_cmask;
+
+       err = snd_pcm_hw_params_first(pcm, params, SND_PCM_HW_PARAM_CHANNELS);
+       assert(err >= 0);
+       hw_cmask |= params->hw_cmask;
+
+       err = snd_pcm_hw_params_first(pcm, params, SND_PCM_HW_PARAM_RATE);
+       assert(err >= 0);
+       hw_cmask |= params->hw_cmask;
+
+       err = snd_pcm_hw_params_first(pcm, params, SND_PCM_HW_PARAM_FRAGMENT_SIZE);
+       assert(err >= 0);
+       hw_cmask |= params->hw_cmask;
+
+       err = snd_pcm_hw_params_last(pcm, params, SND_PCM_HW_PARAM_FRAGMENTS);
+       assert(err >= 0);
+       hw_cmask |= params->hw_cmask;
+
+       params->hw_cmask = hw_cmask;
+}
+
+int snd_pcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+       int err;
+       assert(pcm && params);
+       params->hw_cmask = 0;
+       err = pcm->ops->hw_refine(pcm->op_arg, params);
+       params->appl_cmask = 0;
+       return err;
+}
+
+/* Install one of the configurations present in configuration
+   space defined by PARAMS.
+   The configuration choosen is that obtained fixing in this order:
+   first access
+   first format
+   first subformat
+   min channels
+   min rate
+   min fragment_size
+   max fragments
+   Return 0 on success or a negative number expressing the error.
+*/
+int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+       int err;
+       params->hw_cmask = 0;
+       snd_pcm_hw_params_choose(pcm, params);
+       if (pcm->mmap_channels) {
+               err = snd_pcm_munmap(pcm);
+               if (err < 0)
+                       return err;
+       }
+       err = pcm->ops->hw_params(pcm->op_arg, params);
+       if (err < 0)
+               goto _mmap;
+
+       pcm->setup = 1;
+       pcm->access = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_ACCESS);
+       pcm->format = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT);
+       pcm->subformat = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_SUBFORMAT);
+       pcm->channels = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_CHANNELS);
+       pcm->rate = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_RATE);
+       pcm->fragment_size = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FRAGMENT_SIZE);
+       pcm->fragments = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FRAGMENTS);
+       pcm->bits_per_sample = snd_pcm_format_physical_width(pcm->format);
+       pcm->bits_per_frame = pcm->bits_per_sample * pcm->channels;
+       pcm->buffer_size = pcm->fragment_size * pcm->fragments;
+       
+       pcm->info = params->info;
+       pcm->msbits = params->msbits;
+       pcm->rate_num = params->rate_num;
+       pcm->rate_den = params->rate_den;
+       pcm->fifo_size = params->fifo_size;
+       
+       /* Default sw params */
+       pcm->start_mode = SND_PCM_START_DATA;
+       pcm->ready_mode = SND_PCM_READY_FRAGMENT;
+       pcm->xrun_mode = SND_PCM_XRUN_FRAGMENT;
+       pcm->avail_min = pcm->fragment_size;
+       pcm->xfer_min = pcm->fragment_size;
+       pcm->xfer_align = pcm->fragment_size;
+       pcm->time = 0;
+       pcm->boundary = LONG_MAX - pcm->buffer_size * 2 - LONG_MAX % pcm->buffer_size;
+
+ _mmap:
+       if (pcm->setup &&
+           (pcm->mmap_rw || 
+            (pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED ||
+             pcm->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED ||
+             pcm->access == SND_PCM_ACCESS_MMAP_COMPLEX))) {
+               int err;
+               err = snd_pcm_mmap(pcm);
+               if (err < 0)
+                       return err;
+       }
+       if (err >= 0)
+               snd_pcm_prepare(pcm);
+       return err;
+}
+
+/* Strategies */
+
+struct _snd_pcm_strategy {
+       unsigned int badness_min, badness_max;
+       int (*choose_param)(const snd_pcm_hw_params_t *params,
+                           snd_pcm_t *pcm,
+                           const snd_pcm_strategy_t *strategy);
+       int (*next_value)(snd_pcm_hw_params_t *params,
+                         unsigned int param,
+                         int value,
+                         snd_pcm_t *pcm,
+                         const snd_pcm_strategy_t *strategy);
+       int (*min_badness)(const snd_pcm_hw_params_t *params,
+                          unsigned int max_badness,
+                          snd_pcm_t *pcm,
+                          const snd_pcm_strategy_t *strategy);
+       void *private;
+       void (*free)(snd_pcm_strategy_t *strategy);
+};
+
+/* Independent badness */
+typedef struct _snd_pcm_strategy_simple snd_pcm_strategy_simple_t;
+
+struct _snd_pcm_strategy_simple {
+       int valid;
+       unsigned int order;
+       int (*next_value)(snd_pcm_hw_params_t *params,
+                         unsigned int param,
+                         int value,
+                         snd_pcm_t *pcm,
+                         const snd_pcm_strategy_simple_t *par);
+       unsigned int (*min_badness)(const snd_pcm_hw_params_t *params,
+                                   unsigned int param,
+                                   snd_pcm_t *pcm,
+                                   const snd_pcm_strategy_simple_t *par);
+       void *private;
+       void (*free)(snd_pcm_strategy_simple_t *strategy);
+};
+
+typedef struct _snd_pcm_strategy_simple_near {
+       int best;
+       unsigned int mul;
+} snd_pcm_strategy_simple_near_t;
+
+typedef struct _snd_pcm_strategy_simple_choices {
+       unsigned int count;
+       /* choices need to be sorted on ascending badness */
+       snd_pcm_strategy_simple_choices_list_t *choices;
+} snd_pcm_strategy_simple_choices_t;
+
+int snd_pcm_hw_params_test(const snd_pcm_hw_params_t *params,
+                          unsigned int var, unsigned int val)
+{
+       if (is_mask(var)) {
+               const mask_t *mask = params_mask_c(params, var);
+               return mask_test(mask, val);
+       }
+       if (is_interval(var)) {
+               const interval_t *i = params_interval_c(params, var);
+               return interval_test(i, val);
+       }
+       assert(0);
+       return -EINVAL;
+}
+
+unsigned int snd_pcm_hw_params_count(const snd_pcm_hw_params_t *params,
+                                    unsigned int var)
+{
+       if (is_mask(var)) {
+               const mask_t *mask = params_mask_c(params, var);
+               return mask_count(mask);
+       }
+       if (is_interval(var)) {
+               const interval_t *i = params_interval_c(params, var);
+               return interval_max(i) - interval_min(i) + 1;
+       }
+       assert(0);
+       return 0;
+}
+
+void snd_pcm_hw_params_copy(snd_pcm_hw_params_t *params, unsigned int var,
+                           const snd_pcm_hw_params_t *src)
+{
+       if (is_mask(var)) {
+               mask_t *d = params_mask(params, var);
+               const mask_t *s = params_mask_c(src, var);
+               mask_copy(d, s);
+       }
+       if (is_interval(var)) {
+               interval_t *d = params_interval(params, var);
+               const interval_t *s = params_interval_c(src, var);
+               interval_copy(d, s);
+       }
+       assert(0);
+}
+
+void snd_pcm_hw_params_dump(const snd_pcm_hw_params_t *params,
+                           unsigned int var, FILE *fp)
+{
+       if (is_mask(var)) {
+               const mask_t *mask = params_mask_c(params, var);
+               if (mask_empty(mask))
+                       fputs(" NONE", fp);
+               else {
+                       unsigned int k;
+                       for (k = 0; k <= MASK_MAX; ++k) {
+                               if (mask_test(mask, k)) {
+                                       putc(' ', fp);
+                                       switch (var) {
+                                       case SND_PCM_HW_PARAM_ACCESS:
+                                               fputs(snd_pcm_access_name(k), fp);
+                                               break;
+                                       case SND_PCM_HW_PARAM_FORMAT:
+                                               fputs(snd_pcm_format_name(k), fp);
+                                               break;
+                                       case SND_PCM_HW_PARAM_SUBFORMAT:
+                                               fputs(snd_pcm_subformat_name(k), fp);
+                                               break;
+                                       default:
+                                               assert(0);
+                                       }
+                               }
+                       }
+               }
+               return;
+       }
+       if (is_interval(var)) {
+               interval_print(params_interval_c(params, var), fp);
+               return;
+       }
+       assert(0);
+}
+
+int snd_pcm_dump_hw_params(snd_pcm_hw_params_t *params, FILE *fp)
+{
+       unsigned int k;
+       for (k = 0; k <= SND_PCM_HW_PARAM_LAST; k++) {
+               fprintf(fp, "%s: ", snd_pcm_hw_param_name(k));
+               snd_pcm_hw_params_dump(params, k, fp);
+               putc('\n', fp);
+       }
+       return 0;
+}
+
+int snd_pcm_hw_params_strategy(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                               const snd_pcm_strategy_t *strategy,
+                               unsigned int badness_min,
+                               unsigned int badness_max)
+{
+       snd_pcm_hw_params_t best_params;
+       int var;
+       int value;
+       unsigned int best_badness;
+       int badness = strategy->min_badness(params, badness_max, pcm, strategy);
+       snd_pcm_hw_params_t params1;
+#if 0
+       printf("\nBadness: %d\n", badness);
+       snd_pcm_dump_hw_params(params, stdout);
+#endif
+       if (badness < 0)
+               return badness;
+       if ((unsigned int)badness > badness_min)
+               badness_min = badness_min;
+       var = strategy->choose_param(params, pcm, strategy);
+       if (var < 0)
+               return badness;
+       best_badness = UINT_MAX;
+       value = -1;
+       while (1) {
+               unsigned int hw_cmask;
+               params1 = *params;
+               value = strategy->next_value(&params1, var, value, pcm, strategy);
+               if (value < 0)
+                       break;
+               hw_cmask = params1.hw_cmask;
+               badness = snd_pcm_hw_params_strategy(pcm, &params1, strategy, badness_min, badness_max);
+               params1.hw_cmask |= hw_cmask;
+               if (badness >= 0) {
+                       if ((unsigned int) badness <= badness_min) {
+                               *params = params1;
+                               return badness;
+                       }
+                       best_badness = badness;
+                       best_params = params1;
+                       badness_max = badness - 1;
+               }
+       }
+       if (best_badness == UINT_MAX) {
+               return -EINVAL;
+       }
+       *params = best_params;
+       return best_badness;
+}
+
+void snd_pcm_strategy_simple_free(snd_pcm_strategy_t *strategy)
+{
+       snd_pcm_strategy_simple_t *pars = strategy->private;
+       int k;
+       for (k = 0; k <= SND_PCM_HW_PARAM_LAST; ++k) {
+               if (pars[k].valid && pars[k].free)
+                       pars[k].free(&pars[k]);
+       }
+       free(pars);
+}
+
+int snd_pcm_strategy_simple_choose_param(const snd_pcm_hw_params_t *params,
+                                        snd_pcm_t *pcm ATTRIBUTE_UNUSED,
+                                        const snd_pcm_strategy_t *strategy)
+{
+       unsigned int var;
+       int best_var = -1;
+       const snd_pcm_strategy_simple_t *pars = strategy->private;
+       unsigned int min_choices = UINT_MAX;
+       unsigned int min_order = UINT_MAX;
+       for (var = 0; var <= SND_PCM_HW_PARAM_LAST; ++var) {
+               const snd_pcm_strategy_simple_t *p = &pars[var];
+               unsigned int choices;
+               if (!p->valid)
+                       continue;
+               choices = snd_pcm_hw_params_count(params, var);
+               if (choices == 1)
+                       continue;
+               assert(choices != 0);
+               if (p->order < min_order ||
+                   (p->order == min_order &&
+                    choices < min_choices)) {
+                       min_order = p->order;
+                       min_choices = choices;
+                       best_var = var;
+               }
+       }
+       return best_var;
+}
+
+int snd_pcm_strategy_simple_next_value(snd_pcm_hw_params_t *params,
+                                      unsigned int var,
+                                      int value,
+                                      snd_pcm_t *pcm,
+                                      const snd_pcm_strategy_t *strategy)
+{
+       const snd_pcm_strategy_simple_t *pars = strategy->private;
+       assert(pars[var].valid);
+       return pars[var].next_value(params, var, value, pcm, &pars[var]);
+}
+
+
+int snd_pcm_strategy_simple_min_badness(const snd_pcm_hw_params_t *params,
+                                       unsigned int max_badness,
+                                       snd_pcm_t *pcm,
+                                       const snd_pcm_strategy_t *strategy)
+{
+       unsigned int var;
+       unsigned int badness = 0;
+       const snd_pcm_strategy_simple_t *pars = strategy->private;
+       for (var = 0; var <= SND_PCM_HW_PARAM_LAST; ++var) {
+               unsigned int b;
+               if (!pars[var].valid)
+                       continue;
+               b = pars[var].min_badness(params, var, pcm, &pars[var]);
+               if (b > max_badness || max_badness - b < badness)
+                       return -E2BIG;
+               badness += b;
+       }
+       return badness;
+}
+
+
+void snd_pcm_strategy_simple_near_free(snd_pcm_strategy_simple_t *par)
+{
+       snd_pcm_strategy_simple_near_t *p = par->private;
+       free(p);
+}
+
+unsigned int snd_pcm_strategy_simple_near_min_badness(const snd_pcm_hw_params_t *params,
+                                                     unsigned int var,
+                                                     snd_pcm_t *pcm,
+                                                     const snd_pcm_strategy_simple_t *par)
+{
+       const snd_pcm_strategy_simple_near_t *p = par->private;
+       snd_pcm_hw_params_t params1 = *params;
+       int value = snd_pcm_hw_params_near(pcm, &params1, var, p->best);
+       int diff;
+       assert(value >= 0);
+       diff = p->best - value;
+       if (diff < 0)
+               diff = -diff;
+       return diff * p->mul;
+}
+       
+int snd_pcm_strategy_simple_near_next_value(snd_pcm_hw_params_t *params,
+                                           unsigned int var,
+                                           int value,
+                                           snd_pcm_t *pcm,
+                                           const snd_pcm_strategy_simple_t *par)
+{
+       const snd_pcm_strategy_simple_near_t *p = par->private;
+       if (value < 0) 
+               return snd_pcm_hw_params_near(pcm, params, var, p->best);
+       else
+               return snd_pcm_hw_params_next(pcm, params, var, p->best, value);
+}
+
+void snd_pcm_strategy_simple_choices_free(snd_pcm_strategy_simple_t *par)
+{
+       snd_pcm_strategy_simple_choices_t *p = par->private;
+//     free(p->choices);
+       free(p);
+}
+
+unsigned int snd_pcm_strategy_simple_choices_min_badness(const snd_pcm_hw_params_t *params,
+                                                        unsigned int var,
+                                                        snd_pcm_t *pcm ATTRIBUTE_UNUSED,
+                                                        const snd_pcm_strategy_simple_t *par)
+{
+       const snd_pcm_strategy_simple_choices_t *p = par->private;
+       unsigned int k;
+       for (k = 0; k < p->count; ++k) {
+               if (snd_pcm_hw_params_test(params, var, p->choices[k].value))
+                       return p->choices[k].badness;
+       }
+       assert(0);
+       return UINT_MAX;
+}
+       
+int snd_pcm_strategy_simple_choices_next_value(snd_pcm_hw_params_t *params,
+                                              unsigned int var,
+                                              int value,
+                                              snd_pcm_t *pcm,
+                                              const snd_pcm_strategy_simple_t *par)
+{
+       const snd_pcm_strategy_simple_choices_t *p = par->private;
+       unsigned int k = 0;
+       if (value >= 0) {
+               for (; k < p->count; ++k) {
+                       if (p->choices[k].value == (unsigned int) value) {
+                               k++;
+                               break;
+                       }
+               }
+       }
+       for (; k < p->count; ++k) {
+               unsigned int v = p->choices[k].value;
+               if (snd_pcm_hw_params_test(params, var, v)) {
+                       snd_pcm_hw_params_t save = *params;
+                       int err = snd_pcm_hw_params_set(pcm, params, var, v);
+                       if (err < 0) {
+                               *params = save;
+                               continue;
+                       }
+                       return v;
+               }
+       }
+       return -1;
+}
+
+int snd_pcm_strategy_free(snd_pcm_strategy_t *strategy)
+{
+       if (strategy->free)
+               strategy->free(strategy);
+       free(strategy);
+       return 0;
+}
+
+int snd_pcm_strategy_simple(snd_pcm_strategy_t **strategyp,
+                           unsigned int badness_min,
+                           unsigned int badness_max)
+{
+       snd_pcm_strategy_simple_t *data;
+       snd_pcm_strategy_t *s;
+       assert(strategyp);
+       data = calloc(SND_PCM_HW_PARAM_LAST + 1, sizeof(*data));
+       if (!data)
+               return -ENOMEM;
+       s = calloc(1, sizeof(*s));
+       if (!s) {
+               free(data);
+               return -ENOMEM;
+       }
+       s->choose_param = snd_pcm_strategy_simple_choose_param;
+       s->next_value = snd_pcm_strategy_simple_next_value;
+       s->min_badness = snd_pcm_strategy_simple_min_badness;
+       s->badness_min = badness_min;
+       s->badness_max = badness_max;
+       s->private = data;
+       s->free = snd_pcm_strategy_simple_free;
+       *strategyp = s;
+       return 0;
+}
+
+int snd_pcm_strategy_simple_near(snd_pcm_strategy_t *strategy,
+                                int order,
+                                unsigned int var,
+                                unsigned int best,
+                                unsigned int mul)
+{
+       snd_pcm_strategy_simple_t *s = strategy->private;
+       snd_pcm_strategy_simple_near_t *data;
+       assert(strategy);
+       assert(var <= SND_PCM_HW_PARAM_LAST);
+       assert(!s->valid);
+       data = calloc(1, sizeof(*data));
+       if (!data)
+               return -ENOMEM;
+       data->best = best;
+       data->mul = mul;
+       s += var;
+       s->order = order;
+       s->valid = 1;
+       s->next_value = snd_pcm_strategy_simple_near_next_value;
+       s->min_badness = snd_pcm_strategy_simple_near_min_badness;
+       s->private = data;
+       s->free = snd_pcm_strategy_simple_near_free;
+       return 0;
+}
+
+int snd_pcm_strategy_simple_choices(snd_pcm_strategy_t *strategy,
+                                   int order,
+                                   unsigned int var,
+                                   unsigned int count,
+                                   snd_pcm_strategy_simple_choices_list_t *choices)
+{
+       snd_pcm_strategy_simple_t *s = strategy->private;
+       snd_pcm_strategy_simple_choices_t *data;
+       assert(strategy);
+       assert(var <= SND_PCM_HW_PARAM_LAST);
+       assert(!s->valid);
+       data = calloc(1, sizeof(*data));
+       if (!data)
+               return -ENOMEM;
+       data->count = count;
+       data->choices = choices;
+       s += var;
+       s->valid = 1;
+       s->order = order;
+       s->next_value = snd_pcm_strategy_simple_choices_next_value;
+       s->min_badness = snd_pcm_strategy_simple_choices_min_badness;
+       s->private = data;
+       s->free = snd_pcm_strategy_simple_choices_free;
+       return 0;
+}
+
+int snd_pcm_hw_params_try_explain_failure1(snd_pcm_t *pcm,
+                                          snd_pcm_hw_params_t *fail,
+                                          snd_pcm_hw_params_t *success,
+                                          unsigned int depth,
+                                          FILE *fp)
+{
+       unsigned int var;
+       snd_pcm_hw_params_t i;
+       if (depth < 1)
+               return -ENOENT;
+       for (var = 0; var <= SND_PCM_HW_PARAM_LAST; var++) {
+               int err;
+               i = *success;
+               snd_pcm_hw_params_copy(&i, var, fail);
+               err = snd_pcm_hw_refine(pcm, &i);
+               if (err == 0 && 
+                   snd_pcm_hw_params_try_explain_failure1(pcm, fail, &i, depth - 1, fp) < 0)
+                       continue;
+               fprintf(fp, "%s: ", snd_pcm_hw_param_name(var));
+               snd_pcm_hw_params_dump(fail, var, fp);
+               putc('\n', fp);
+               return 0;
+       }
+       return -ENOENT;
+}
+
+int snd_pcm_hw_params_try_explain_failure(snd_pcm_t *pcm,
+                                         snd_pcm_hw_params_t *fail,
+                                         snd_pcm_hw_params_t *success,
+                                         unsigned int depth,
+                                         FILE *fp)
+{
+       snd_pcm_hw_params_t i, any;
+       int err;
+       unsigned int var;
+       int done = 0;
+       assert(pcm && fail);
+       for (var = 0; var <= SND_PCM_HW_PARAM_LAST; var++) {
+               if (!snd_pcm_hw_params_empty(fail, var))
+                       continue;
+               fprintf(fp, "%s is empty\n", snd_pcm_hw_param_name(var));
+               done = 1;
+       }
+       if (done)
+               return 0;
+       i = *fail;
+       err = snd_pcm_hw_refine(pcm, &i);
+       if (err == 0) {
+               fprintf(fp, "Configuration is virtually correct\n");
+               return 0;
+       }
+       if (!success) {
+               snd_pcm_hw_params_any(pcm, &any);
+               success = &any;
+       }
+       return snd_pcm_hw_params_try_explain_failure1(pcm, fail, success, depth, fp);
+}
+
+typedef struct _snd_pcm_hw_rule snd_pcm_hw_rule_t;
+
+typedef int (*snd_pcm_hw_rule_func_t)(snd_pcm_hw_params_t *params,
+                                     snd_pcm_hw_rule_t *rule);
+
+struct _snd_pcm_hw_rule {
+       int var;
+       snd_pcm_hw_rule_func_t func;
+       int deps[4];
+       void *private;
+};
+
+int snd_pcm_hw_rule_mul(snd_pcm_hw_params_t *params,
+                       snd_pcm_hw_rule_t *rule)
+{
+       return interval_mul(params_interval(params, rule->var),
+                           params_interval(params, rule->deps[0]),
+                           params_interval(params, rule->deps[1]));
+}
+
+int snd_pcm_hw_rule_div(snd_pcm_hw_params_t *params,
+                       snd_pcm_hw_rule_t *rule)
+{
+       return interval_div(params_interval(params, rule->var),
+                           params_interval(params, rule->deps[0]),
+                           params_interval(params, rule->deps[1]));
+}
+
+int snd_pcm_hw_rule_muldivk(snd_pcm_hw_params_t *params,
+                           snd_pcm_hw_rule_t *rule)
+{
+       return interval_muldivk(params_interval(params, rule->var),
+                               (unsigned long) rule->private,
+                               params_interval(params, rule->deps[0]),
+                               params_interval(params, rule->deps[1]));
+}
+
+int snd_pcm_hw_rule_mulkdiv(snd_pcm_hw_params_t *params,
+                           snd_pcm_hw_rule_t *rule)
+{
+       return interval_mulkdiv(params_interval(params, rule->var),
+                               (unsigned long) rule->private,
+                               params_interval(params, rule->deps[0]),
+                               params_interval(params, rule->deps[1]));
+}
+
+int snd_pcm_hw_rule_format(snd_pcm_hw_params_t *params,
+                          snd_pcm_hw_rule_t *rule)
+{
+       int changed = 0;
+       unsigned int k;
+       mask_t *mask = params_mask(params, rule->var);
+       interval_t *i = params_interval(params, rule->deps[0]);
+       for (k = 0; k <= SND_PCM_FORMAT_LAST; ++k) {
+               int bits;
+               if (!mask_test(mask, k))
+                       continue;
+               bits = snd_pcm_format_physical_width(k);
+               if (bits < 0)
+                       continue;
+               if (!interval_test(i, bits)) {
+                       mask_reset(mask, k);
+                       if (mask_empty(mask))
+                               return -EINVAL;
+                       changed = 1;
+               }
+       }
+       return changed;
+}
+
+
+int snd_pcm_hw_rule_sample_bits(snd_pcm_hw_params_t *params,
+                               snd_pcm_hw_rule_t *rule)
+{
+       unsigned int min, max;
+       unsigned int k;
+       interval_t *i = params_interval(params, rule->var);
+       mask_t *mask = params_mask(params, rule->deps[0]);
+       int c, changed = 0;
+       min = UINT_MAX;
+       max = 0;
+       for (k = 0; k <= SND_PCM_FORMAT_LAST; ++k) {
+               int bits;
+               if (!mask_test(mask, k))
+                       continue;
+               bits = snd_pcm_format_physical_width(k);
+               if (bits < 0)
+                       continue;
+               if (min > (unsigned)bits)
+                       min = bits;
+               if (max < (unsigned)bits)
+                       max = bits;
+       }
+       c = interval_refine_min(i, min);
+       if (c < 0)
+               return c;
+       if (c)
+               changed = 1;
+       c = interval_refine_max(i, max);
+       if (c < 0)
+               return c;
+       if (c)
+               changed = 1;
+       return changed;
+}
+
+snd_pcm_hw_rule_t snd_pcm_hw_rules[] = {
+       {
+               var: SND_PCM_HW_PARAM_FORMAT,
+               func: snd_pcm_hw_rule_format,
+               deps: { SND_PCM_HW_PARAM_SAMPLE_BITS, -1 },
+               private: 0,
+       },
+       {
+               var: SND_PCM_HW_PARAM_SAMPLE_BITS, 
+               func: snd_pcm_hw_rule_sample_bits,
+               deps: { SND_PCM_HW_PARAM_FORMAT, -1 },
+               private: 0,
+       },
+       {
+               var: SND_PCM_HW_PARAM_SAMPLE_BITS, 
+               func: snd_pcm_hw_rule_div,
+               deps: { SND_PCM_HW_PARAM_FRAME_BITS,
+                       SND_PCM_HW_PARAM_CHANNELS, -1 },
+               private: 0,
+       },
+       {
+               var: SND_PCM_HW_PARAM_FRAME_BITS, 
+               func: snd_pcm_hw_rule_mul,
+               deps: { SND_PCM_HW_PARAM_SAMPLE_BITS,
+                       SND_PCM_HW_PARAM_CHANNELS, -1 },
+               private: 0,
+       },
+       {
+               var: SND_PCM_HW_PARAM_FRAME_BITS, 
+               func: snd_pcm_hw_rule_mulkdiv,
+               deps: { SND_PCM_HW_PARAM_FRAGMENT_BYTES,
+                       SND_PCM_HW_PARAM_FRAGMENT_SIZE, -1 },
+               private: (void*) 8,
+       },
+       {
+               var: SND_PCM_HW_PARAM_FRAME_BITS, 
+               func: snd_pcm_hw_rule_mulkdiv,
+               deps: { SND_PCM_HW_PARAM_BUFFER_BYTES,
+                       SND_PCM_HW_PARAM_BUFFER_SIZE, -1 },
+               private: (void*) 8,
+       },
+       {
+               var: SND_PCM_HW_PARAM_CHANNELS, 
+               func: snd_pcm_hw_rule_div,
+               deps: { SND_PCM_HW_PARAM_FRAME_BITS,
+                       SND_PCM_HW_PARAM_SAMPLE_BITS, -1 },
+               private: 0,
+       },
+       {
+               var: SND_PCM_HW_PARAM_RATE, 
+               func: snd_pcm_hw_rule_mulkdiv,
+               deps: { SND_PCM_HW_PARAM_FRAGMENT_SIZE,
+                       SND_PCM_HW_PARAM_FRAGMENT_LENGTH, -1 },
+               private: (void*) 1000000,
+       },
+       {
+               var: SND_PCM_HW_PARAM_RATE, 
+               func: snd_pcm_hw_rule_mulkdiv,
+               deps: { SND_PCM_HW_PARAM_BUFFER_SIZE,
+                       SND_PCM_HW_PARAM_BUFFER_LENGTH, -1 },
+               private: (void*) 1000000,
+       },
+       {
+               var: SND_PCM_HW_PARAM_FRAGMENTS, 
+               func: snd_pcm_hw_rule_div,
+               deps: { SND_PCM_HW_PARAM_BUFFER_SIZE,
+                       SND_PCM_HW_PARAM_FRAGMENT_SIZE, -1 },
+               private: 0,
+       },
+       {
+               var: SND_PCM_HW_PARAM_FRAGMENT_SIZE, 
+               func: snd_pcm_hw_rule_div,
+               deps: { SND_PCM_HW_PARAM_BUFFER_SIZE,
+                       SND_PCM_HW_PARAM_FRAGMENTS, -1 },
+               private: 0,
+       },
+       {
+               var: SND_PCM_HW_PARAM_FRAGMENT_SIZE, 
+               func: snd_pcm_hw_rule_mulkdiv,
+               deps: { SND_PCM_HW_PARAM_FRAGMENT_BYTES,
+                       SND_PCM_HW_PARAM_FRAME_BITS, -1 },
+               private: (void*) 8,
+       },
+       {
+               var: SND_PCM_HW_PARAM_FRAGMENT_SIZE, 
+               func: snd_pcm_hw_rule_muldivk,
+               deps: { SND_PCM_HW_PARAM_FRAGMENT_LENGTH,
+                       SND_PCM_HW_PARAM_RATE, -1 },
+               private: (void*) 1000000,
+       },
+       {
+               var: SND_PCM_HW_PARAM_BUFFER_SIZE, 
+               func: snd_pcm_hw_rule_mul,
+               deps: { SND_PCM_HW_PARAM_FRAGMENT_SIZE,
+                       SND_PCM_HW_PARAM_FRAGMENTS, -1 },
+               private: 0,
+       },
+       {
+               var: SND_PCM_HW_PARAM_BUFFER_SIZE, 
+               func: snd_pcm_hw_rule_mulkdiv,
+               deps: { SND_PCM_HW_PARAM_BUFFER_BYTES,
+                       SND_PCM_HW_PARAM_FRAME_BITS, -1 },
+               private: (void*) 8,
+       },
+       {
+               var: SND_PCM_HW_PARAM_BUFFER_SIZE, 
+               func: snd_pcm_hw_rule_muldivk,
+               deps: { SND_PCM_HW_PARAM_BUFFER_LENGTH,
+                       SND_PCM_HW_PARAM_RATE, -1 },
+               private: (void*) 1000000,
+       },
+       {
+               var: SND_PCM_HW_PARAM_FRAGMENT_BYTES, 
+               func: snd_pcm_hw_rule_muldivk,
+               deps: { SND_PCM_HW_PARAM_FRAGMENT_SIZE,
+                       SND_PCM_HW_PARAM_FRAME_BITS, -1 },
+               private: (void*) 8,
+       },
+       {
+               var: SND_PCM_HW_PARAM_BUFFER_BYTES, 
+               func: snd_pcm_hw_rule_muldivk,
+               deps: { SND_PCM_HW_PARAM_BUFFER_SIZE,
+                       SND_PCM_HW_PARAM_FRAME_BITS, -1 },
+               private: (void*) 8,
+       },
+       {
+               var: SND_PCM_HW_PARAM_FRAGMENT_LENGTH, 
+               func: snd_pcm_hw_rule_mulkdiv,
+               deps: { SND_PCM_HW_PARAM_FRAGMENT_SIZE,
+                       SND_PCM_HW_PARAM_RATE, -1 },
+               private: (void*) 1000000,
+       },
+       {
+               var: SND_PCM_HW_PARAM_BUFFER_LENGTH, 
+               func: snd_pcm_hw_rule_mulkdiv,
+               deps: { SND_PCM_HW_PARAM_BUFFER_SIZE,
+                       SND_PCM_HW_PARAM_RATE, -1 },
+               private: (void*) 1000000,
+       },
+};
+
+#define RULES (sizeof(snd_pcm_hw_rules) / sizeof(snd_pcm_hw_rules[0]))
+
+int _snd_pcm_hw_refine(snd_pcm_hw_params_t *params)
+{
+       unsigned int k;
+       interval_t *i;
+       snd_pcm_hw_rule_t *rules = snd_pcm_hw_rules;
+       unsigned int rstamps[RULES];
+       unsigned int vstamps[SND_PCM_HW_PARAM_LAST + 1];
+       unsigned int stamp = 2;
+       int err, changed;
+
+       for (k = 0; k < RULES; k++)
+               rstamps[k] = 0;
+       for (k = 0; k <= SND_PCM_HW_PARAM_LAST; k++)
+               vstamps[k] = (params->appl_cmask & (1 << k)) ? 1 : 0;
+       params->appl_cmask = 0;
+       params->hw_cmask = 0;
+       changed = 1;
+       while (changed) {
+               changed = 0;
+               for (k = 0; k < RULES; k++) {
+                       snd_pcm_hw_rule_t *r = &rules[k];
+                       unsigned int d;
+                       int doit = 0;
+#ifdef RULES_DEBUG
+                       interval_t *i;
+#endif
+                       for (d = 0; r->deps[d] >= 0; d++) {
+                               if (vstamps[r->deps[d]] > rstamps[k]) {
+                                       doit = 1;
+                                       break;
+                               }
+                       }
+                       if (!doit)
+                               continue;
+#ifdef RULES_DEBUG
+                       i = params_interval(params, r->var);
+                       fprintf(stderr, "Rule %d: %u ", k, r->var);
+                       interval_print(i, stderr);
+#endif
+                       err = r->func(params, r);
+#ifdef RULES_DEBUG
+                       interval_print(i, stderr);
+                       putc('\n', stderr);
+#endif
+                       rstamps[k] = stamp;
+                       if (err && r->var >= 0) {
+                               params->hw_cmask |= 1 << r->var;
+                               vstamps[r->var] = stamp;
+                               changed = 1;
+                       }
+                       if (err < 0)
+                               return err;
+                       stamp++;
+               }
+       }
+       if (!params->msbits) {
+               i = params_interval(params, SND_PCM_HW_PARAM_SAMPLE_BITS);
+               if (interval_single(i))
+                       params->msbits = interval_value(i);
+       }
+
+       if (!params->rate_den) {
+               i = params_interval(params, SND_PCM_HW_PARAM_RATE);
+               if (interval_single(i)) {
+                       params->rate_num = interval_value(i);
+                       params->rate_den = 1;
+               }
+       }
+       return 0;
+}
+
+int snd_pcm_hw_params_refine(snd_pcm_hw_params_t *params, unsigned int var,
+                            const snd_pcm_hw_params_t *src)
+{
+       if (is_mask(var)) {
+               mask_t *d = params_mask(params, var);
+               const mask_t *s = params_mask_c(src, var);
+               return mask_refine(d, s);
+       }
+       if (is_interval(var)) {
+               interval_t *d = params_interval(params, var);
+               const interval_t *s = params_interval_c(src, var);
+               return interval_refine(d, s);
+       }
+       assert(0);
+       return -EINVAL;
+}
+                            
+int snd_pcm_hw_refine2(snd_pcm_hw_params_t *params,
+                      snd_pcm_hw_params_t *sparams,
+                      int (*func)(snd_pcm_t *slave,
+                                  snd_pcm_hw_params_t *sparams),
+                      snd_pcm_t *slave, 
+                      unsigned int links)
+{
+       unsigned int k;
+       int err, error = 0;
+       unsigned int client_from_slave = ~0U;
+       unsigned int client_refine = ~0U;
+       unsigned int slave_from_client = ~0U;
+       unsigned int slave_refine = ~0U;
+       unsigned int hw_cmask = params->hw_cmask;
+
+       while (client_from_slave || client_refine) {
+               for (k = 0; k <= SND_PCM_HW_PARAM_LAST; ++k) {
+                       int changed;
+                       if (!(links & (1 << k)))
+                               continue;
+                       if (!(client_from_slave & (1 << k)))
+                               continue;
+                       changed = snd_pcm_hw_params_refine(params, k, sparams);
+                       if (changed) {
+                               hw_cmask |= 1 << k;
+                               slave_from_client |= 1 << k;
+                               client_refine |= 1 << k;
+                       }
+                       if (changed < 0)
+                               error = changed;
+               }
+               client_from_slave = 0;
+               if (error)
+                       break;
+               if (client_refine) {
+                       params->appl_cmask = client_refine;
+                       client_refine = 0;
+                       err = _snd_pcm_hw_refine(params);
+                       hw_cmask |= params->hw_cmask;
+                       slave_from_client |= params->hw_cmask;
+                       if (err < 0) {
+                               error = err;
+                               break;
+                       }
+               }
+       
+               for (k = 0; k <= SND_PCM_HW_PARAM_LAST; ++k) {
+                       int changed;
+                       if (!(links & (1 << k)))
+                               continue;
+                       if (!(slave_from_client & (1 << k)))
+                               continue;
+                       changed = snd_pcm_hw_params_refine(sparams, k, params);
+                       if (changed) {
+                               slave_refine |= 1 << k;
+                               client_from_slave |= 1 << k;
+                       }
+                       if (changed < 0)
+                               error = changed;
+               }
+               slave_from_client = 0;
+               if (error)
+                       continue;
+               if (slave_refine) {
+                       sparams->appl_cmask = slave_refine;
+                       slave_refine = 0;
+                       error = func(slave, sparams);
+                       client_from_slave |= sparams->hw_cmask;
+               }
+       }
+       params->appl_cmask = 0;
+       params->hw_cmask = hw_cmask;
+       return error;
+}
+
+int snd_pcm_hw_params2(snd_pcm_hw_params_t *params,
+                      snd_pcm_hw_params_t *sparams,
+                      int (*func)(snd_pcm_t *slave,
+                                  snd_pcm_hw_params_t *sparams),
+                      snd_pcm_t *slave, 
+                      unsigned int links)
+{
+       unsigned int k;
+       int err;
+       for (k = 0; k <= SND_PCM_HW_PARAM_LAST; ++k) {
+               int changed;
+               if (!(links & (1 << k)))
+                       continue;
+               changed = snd_pcm_hw_params_refine(sparams, k, params);
+               if (changed < 0)
+                       return changed;
+       }
+       sparams->appl_cmask = ~0U;
+       err = func(slave, sparams);
+       if (err >= 0)
+               return err;
+
+       for (k = 0; k <= SND_PCM_HW_PARAM_LAST; ++k) {
+               int changed;
+               if (!(links & (1 << k)))
+                       continue;
+               if (!(sparams->hw_cmask & (1 << k)))
+                       continue;
+               changed = snd_pcm_hw_params_refine(params, k, sparams);
+               if (changed)
+                       params->hw_cmask |= 1 << k;
+       
+       }
+       return err;
+}
+
index 9c6c14260f1bfe2ff5b56522d89695c06543b1f7..1a833f5b8cd45274afc9a0c998ab225d9e8a6686 100644 (file)
@@ -118,12 +118,14 @@ static unsigned int nonlinear_preferred_formats[] = {
        SND_PCM_FORMAT_IMA_ADPCM,
 };
 
-static int snd_pcm_plug_slave_format(int format, unsigned int format_mask)
+static int snd_pcm_plug_slave_format(int format, const mask_t *format_mask)
 {
        int w, u, e, wid, w1, dw;
-       if (format_mask & (1 << format))
+       mask_t *lin = alloca(mask_sizeof());
+       if (mask_test(format_mask, format))
                return format;
-       if (!((1 << format) & SND_PCM_FMTBIT_LINEAR)) {
+       mask_load(lin, SND_PCM_FMTBIT_LINEAR);
+       if (!mask_test(lin, format)) {
                unsigned int i;
                switch (format) {
                case SND_PCM_FORMAT_MU_LAW:
@@ -131,7 +133,7 @@ static int snd_pcm_plug_slave_format(int format, unsigned int format_mask)
                case SND_PCM_FORMAT_IMA_ADPCM:
                        for (i = 0; i < sizeof(linear_preferred_formats) / sizeof(linear_preferred_formats[0]); ++i) {
                                unsigned int f = linear_preferred_formats[i];
-                               if (format_mask & (1 << f))
+                               if (mask_test(format_mask, f))
                                        return f;
                        }
                        /* Fall through */
@@ -140,11 +142,12 @@ static int snd_pcm_plug_slave_format(int format, unsigned int format_mask)
                }
 
        }
-       if (!(format_mask & SND_PCM_FMTBIT_LINEAR)) {
+       mask_intersect(lin, format_mask);
+       if (mask_empty(lin)) {
                unsigned int i;
                for (i = 0; i < sizeof(nonlinear_preferred_formats) / sizeof(nonlinear_preferred_formats[0]); ++i) {
                        unsigned int f = nonlinear_preferred_formats[i];
-                       if (format_mask & (1 << f))
+                       if (mask_test(format_mask, f))
                                return f;
                }
                return -EINVAL;
@@ -161,7 +164,7 @@ static int snd_pcm_plug_slave_format(int format, unsigned int format_mask)
                        for (sgn = 0; sgn < 2; ++sgn) {
                                int f;
                                f = snd_pcm_build_linear_format(w1, u1, e1);
-                               if (f >= 0 && format_mask & (1 << f))
+                               if (f >= 0 && mask_test(format_mask, f))
                                        return f;
                                u1 = !u1;
                        }
@@ -177,125 +180,181 @@ static int snd_pcm_plug_slave_format(int format, unsigned int format_mask)
        return -EINVAL;
 }
 
-static int snd_pcm_plug_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info)
+#define SND_PCM_FMTBIT_PLUG (SND_PCM_FMTBIT_LINEAR | \
+                            (1 << SND_PCM_FORMAT_MU_LAW) | \
+                            (1 << SND_PCM_FORMAT_A_LAW) | \
+                            (1 << SND_PCM_FORMAT_IMA_ADPCM))
+
+static int snd_pcm_plug_hw_refine1(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                                  snd_pcm_hw_params_t *sparams)
 {
        snd_pcm_plug_t *plug = pcm->private;
        snd_pcm_t *slave = plug->req_slave;
-       snd_pcm_hw_info_t sinfo;
-       int rate_min, rate_max;
-       int channels_min, channels_max;
-       unsigned int format, format_mask;
        int err;
+       const mask_t *format_mask, *sformat_mask;
+       unsigned int rate_min, rate_max, srate_min, srate_max;
+       unsigned int channels_min, channels_max, schannels_min, schannels_max;
+       unsigned int format;
+       int same_rate, same_channels, same_format;
+       snd_pcm_hw_params_t tmp;
+       unsigned int links = (SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+                             SND_PCM_HW_PARBIT_FRAGMENTS |
+                             SND_PCM_HW_PARBIT_BUFFER_LENGTH);
+       mask_t *tmp_mask = alloca(mask_sizeof());
+       mask_t *accplug_mask = alloca(mask_sizeof());
+       mask_t *mmap_mask = alloca(mask_sizeof());
+       mask_t *fmtplug_mask = alloca(mask_sizeof());
+       mask_load(accplug_mask, SND_PCM_ACCBIT_PLUGIN);
+       mask_load(mmap_mask, SND_PCM_ACCBIT_MMAP);
+       mask_load(fmtplug_mask, SND_PCM_FMTBIT_PLUG);
        
-       info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED | 
-                             SND_PCM_ACCBIT_RW_INTERLEAVED |
-                             SND_PCM_ACCBIT_MMAP_NONINTERLEAVED | 
-                             SND_PCM_ACCBIT_RW_NONINTERLEAVED);
-       if (info->access_mask == 0)
-               return -EINVAL;
-
-       info->format_mask &= (SND_PCM_FMTBIT_LINEAR | SND_PCM_FMTBIT_MU_LAW |
-                             SND_PCM_FMTBIT_A_LAW | SND_PCM_FMTBIT_IMA_ADPCM);
-       if (info->format_mask == 0)
-               return -EINVAL;
-
-       info->subformat_mask &= SND_PCM_SUBFMTBIT_STD;
-       if (info->subformat_mask == 0)
-               return -EINVAL;
-
-       if (info->rate_min < RATE_MIN)
-               info->rate_min = RATE_MIN;
-       if (info->rate_max > RATE_MAX)
-               info->rate_max = RATE_MAX;
-       if (info->rate_max < info->rate_min)
-               return -EINVAL;
-
-       if (info->channels_min < 1)
-               info->channels_min = 1;
-       if (info->channels_max < info->channels_min)
-               return -EINVAL;
-
-       sinfo = *info;
-       sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
-       sinfo.format_mask = (SND_PCM_FMTBIT_LINEAR | SND_PCM_FMTBIT_MU_LAW |
-                            SND_PCM_FMTBIT_A_LAW | SND_PCM_FMTBIT_IMA_ADPCM);
-       sinfo.channels_min = 1;
-       sinfo.channels_max = UINT_MAX;
-       sinfo.rate_min = RATE_MIN;
-       sinfo.rate_max = RATE_MAX;
+       err = _snd_pcm_hw_params_min(params, 1, SND_PCM_HW_PARAM_CHANNELS, 1);
+       if (err < 0)
+               return err;
+       err = _snd_pcm_hw_params_min(params, 1, SND_PCM_HW_PARAM_RATE, RATE_MIN);
+       if (err < 0)
+               return err;
+       err = _snd_pcm_hw_params_max(params, 1, SND_PCM_HW_PARAM_RATE, RATE_MAX);
+       if (err < 0)
+               return err;
 
-       err = snd_pcm_hw_info(slave, &sinfo);
+       _snd_pcm_hw_params_any(sparams);
+       err = snd_pcm_hw_refine2(params, sparams,
+                                snd_pcm_hw_refine, slave, links);
        if (err < 0)
-               goto _err;
+               return err;
        
-       rate_min = snd_pcm_hw_info_par_nearest_next(&sinfo,
-                                                   SND_PCM_HW_INFO_RATE,
-                                                   info->rate_min, -1,
-                                                   slave);
-       assert(rate_min >= 0);
-       if ((int)info->rate_max - rate_min > 1) {
-               rate_max = snd_pcm_hw_info_par_nearest_next(&sinfo,
-                                                           SND_PCM_HW_INFO_RATE,
-                                                           info->rate_max, -1,
-                                                           slave);
-               assert(rate_max >= 0);
-       } else
-               rate_max = rate_min;
-       sinfo.rate_min = rate_min;
-       sinfo.rate_max = rate_max;
-
-       err = snd_pcm_hw_info(slave, &sinfo);
+       rate_min = snd_pcm_hw_params_value_min(params, SND_PCM_HW_PARAM_RATE);
+       rate_max = snd_pcm_hw_params_value_max(params, SND_PCM_HW_PARAM_RATE);
+       tmp = *sparams;
+       srate_min = snd_pcm_hw_params_near(slave, &tmp,
+                                          SND_PCM_HW_PARAM_RATE, rate_min);
+       if (srate_min < rate_max) {
+               tmp = *sparams;
+               srate_max = snd_pcm_hw_params_near(slave, &tmp,
+                                                  SND_PCM_HW_PARAM_RATE, rate_max);
+       } else 
+               srate_max = srate_min;
+       err = snd_pcm_hw_params_minmax(slave, sparams,
+                                      SND_PCM_HW_PARAM_RATE,
+                                      srate_min, srate_max);
        assert(err >= 0);
 
-       channels_min = snd_pcm_hw_info_par_nearest_next(&sinfo,
-                                                   SND_PCM_HW_INFO_CHANNELS,
-                                                   info->channels_min, -1,
-                                                   slave);
-       assert(channels_min >= 0);
-       if ((int)info->channels_max - channels_min > 1) {
-               channels_max = snd_pcm_hw_info_par_nearest_next(&sinfo,
-                                                           SND_PCM_HW_INFO_CHANNELS,
-                                                           info->channels_max, -1,
-                                                           slave);
-               assert(channels_max >= 0);
-       } else
-               channels_max = channels_min;
-       sinfo.channels_min = channels_min;
-       sinfo.channels_max = channels_max;
-
-       err = snd_pcm_hw_info(slave, &sinfo);
+       channels_min = snd_pcm_hw_params_value_min(params, SND_PCM_HW_PARAM_CHANNELS);
+       channels_max = snd_pcm_hw_params_value_max(params, SND_PCM_HW_PARAM_CHANNELS);
+       tmp = *sparams;
+       schannels_min = snd_pcm_hw_params_near(slave, &tmp,
+                                              SND_PCM_HW_PARAM_CHANNELS, channels_min);
+       if (schannels_min < channels_max) {
+               tmp = *sparams;
+               schannels_max = snd_pcm_hw_params_near(slave, &tmp,
+                                                      SND_PCM_HW_PARAM_CHANNELS, channels_max);
+       } else 
+               schannels_max = schannels_min;
+       err = snd_pcm_hw_params_minmax(slave, sparams,
+                                      SND_PCM_HW_PARAM_CHANNELS,
+                                      schannels_min, schannels_max);
        assert(err >= 0);
 
-       format_mask = 0;
+       format_mask = snd_pcm_hw_params_value_mask(params,
+                                                  SND_PCM_HW_PARAM_FORMAT);
+       sformat_mask = snd_pcm_hw_params_value_mask(sparams,
+                                                   SND_PCM_HW_PARAM_FORMAT);
+       mask_none(tmp_mask);
        for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) {
                int f;
-               if (!(info->format_mask & (1 << format)))
+               if (!mask_test(format_mask, format))
                        continue;
-               f = snd_pcm_plug_slave_format(format, sinfo.format_mask);
-               assert(f >= 0);
-               format_mask |= (1 << f);
+               if (mask_test(sformat_mask, format))
+                       f = format;
+               else {
+                       f = snd_pcm_plug_slave_format(format, sformat_mask);
+                       if (f < 0) {
+                               mask_t *m = alloca(mask_sizeof());
+                               mask_all(m);
+                               mask_reset(m, format);
+                               err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_FORMAT, m);
+                               if (err < 0)
+                                       return err;
+                               continue;
+                       }
+               }
+               mask_set(tmp_mask, f);
        }
-       sinfo.format_mask = format_mask;
 
-       err = snd_pcm_hw_info(slave, &sinfo);
+       err = _snd_pcm_hw_params_mask(sparams, 0, 
+                                     SND_PCM_HW_PARAM_FORMAT, tmp_mask);
        assert(err >= 0);
-
- _err:
-       info->subformat_mask = sinfo.subformat_mask;
-       info->fragment_length_min = sinfo.fragment_length_min;
-       info->fragment_length_max = sinfo.fragment_length_max;
-       info->fragments_min = sinfo.fragments_min;
-       info->fragments_max = sinfo.fragments_max;
-       info->buffer_length_min = sinfo.buffer_length_min;
-       info->buffer_length_max = sinfo.buffer_length_max;
-       
+       sformat_mask = snd_pcm_hw_params_value_mask(sparams,
+                                                   SND_PCM_HW_PARAM_FORMAT);
+
+       same_rate = (rate_min == rate_max && 
+                    rate_min == srate_min &&
+                    rate_min == srate_max);
+       same_channels = (channels_min == channels_max && 
+                        channels_min == schannels_min &&
+                        channels_min == schannels_max);
+       same_format = (mask_single(format_mask) && 
+                      mask_eq(format_mask, sformat_mask));
+       if (same_rate)
+               links |= (SND_PCM_HW_PARBIT_RATE |
+                         SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+                         SND_PCM_HW_PARBIT_BUFFER_SIZE);
+       if (same_channels) {
+               links |= SND_PCM_HW_PARBIT_CHANNELS;
+               if (same_format)
+                       links |= (SND_PCM_HW_PARBIT_FRAME_BITS |
+                                 SND_PCM_HW_PARBIT_FRAGMENT_BYTES |
+                                 SND_PCM_HW_PARBIT_BUFFER_BYTES);
+       }
+       if (same_format)
+               links |= (SND_PCM_HW_PARBIT_FORMAT |
+                         SND_PCM_HW_PARBIT_SUBFORMAT |
+                         SND_PCM_HW_PARBIT_SAMPLE_BITS);
+
+       if (same_rate && same_channels && same_format) {
+               const mask_t *access_mask = snd_pcm_hw_params_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
+               mask_copy(tmp_mask, snd_pcm_hw_params_value_mask(sparams, SND_PCM_HW_PARAM_ACCESS));
+               mask_intersect(tmp_mask, access_mask);
+               if (!mask_empty(tmp_mask))
+                       _snd_pcm_hw_params_mask(sparams, 0,
+                                               SND_PCM_HW_PARAM_ACCESS,
+                                               access_mask);
+               else
+                 _snd_pcm_hw_params_mask(sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+                                         mmap_mask);
+       } else {
+               err = _snd_pcm_hw_params_mask(params, 1,
+                                             SND_PCM_HW_PARAM_ACCESS,
+                                             accplug_mask);
+               if (err < 0)
+                       return err;
+               err = _snd_pcm_hw_params_mask(params, 1,
+                                             SND_PCM_HW_PARAM_FORMAT,
+                                             fmtplug_mask);
+               if (err < 0)
+                       return err;
+               _snd_pcm_hw_params_mask(sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+                                       mmap_mask);
+               _snd_pcm_hw_params_mask(sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+                                       fmtplug_mask);
+       }
+       err = snd_pcm_hw_refine2(params, sparams,
+                                snd_pcm_hw_refine, slave, links);
        if (err < 0)
                return err;
-       info->info = sinfo.info & ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
-       snd_pcm_hw_info_complete(info);
+       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
        return 0;
 }
 
+
+
+static int snd_pcm_plug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+       snd_pcm_hw_params_t sparams;
+       return snd_pcm_plug_hw_refine1(pcm, params, &sparams);
+}
+
 static void snd_pcm_plug_clear(snd_pcm_t *pcm)
 {
        snd_pcm_plug_t *plug = pcm->private;
@@ -309,7 +368,14 @@ static void snd_pcm_plug_clear(snd_pcm_t *pcm)
        }
 }
 
-static int snd_pcm_plug_change_rate(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_hw_params_t *clt, snd_pcm_hw_params_t *slv)
+typedef struct {
+       unsigned int access;
+       unsigned int format;
+       unsigned int channels;
+       unsigned int rate;
+} snd_pcm_plug_params_t;
+
+static int snd_pcm_plug_change_rate(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_plug_params_t *clt, snd_pcm_plug_params_t *slv)
 {
        snd_pcm_plug_t *plug = pcm->private;
        int err;
@@ -326,7 +392,7 @@ static int snd_pcm_plug_change_rate(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_hw_
        return 1;
 }
 
-static int snd_pcm_plug_change_channels(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_hw_params_t *clt, snd_pcm_hw_params_t *slv)
+static int snd_pcm_plug_change_channels(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_plug_params_t *clt, snd_pcm_plug_params_t *slv)
 {
        snd_pcm_plug_t *plug = pcm->private;
        unsigned int tt_ssize, tt_cused, tt_sused;
@@ -391,7 +457,7 @@ static int snd_pcm_plug_change_channels(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm
        return 1;
 }
 
-static int snd_pcm_plug_change_format(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_hw_params_t *clt, snd_pcm_hw_params_t *slv)
+static int snd_pcm_plug_change_format(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_plug_params_t *clt, snd_pcm_plug_params_t *slv)
 {
        snd_pcm_plug_t *plug = pcm->private;
        int err, cfmt;
@@ -451,7 +517,7 @@ static int snd_pcm_plug_change_format(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_h
        return 1;
 }
 
-static int snd_pcm_plug_change_access(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_hw_params_t *clt, snd_pcm_hw_params_t *slv)
+static int snd_pcm_plug_change_access(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_plug_params_t *clt, snd_pcm_plug_params_t *slv)
 {
        snd_pcm_plug_t *plug = pcm->private;
        int err;
@@ -465,11 +531,11 @@ static int snd_pcm_plug_change_access(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_h
 }
 
 static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm,
-                                      snd_pcm_hw_params_t *client,
-                                      snd_pcm_hw_params_t *slave)
+                                      snd_pcm_plug_params_t *client,
+                                      snd_pcm_plug_params_t *slave)
 {
        snd_pcm_plug_t *plug = pcm->private;
-       int (*funcs[])(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_hw_params_t *s, snd_pcm_hw_params_t *d) = {
+       int (*funcs[])(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_plug_params_t *s, snd_pcm_plug_params_t *d) = {
                snd_pcm_plug_change_format,
                snd_pcm_plug_change_channels,
                snd_pcm_plug_change_rate,
@@ -477,7 +543,7 @@ static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm,
                snd_pcm_plug_change_format,
                snd_pcm_plug_change_access
        };
-       snd_pcm_hw_params_t p = *slave;
+       snd_pcm_plug_params_t p = *slave;
        unsigned int k = 0;
        while (client->format != p.format ||
               client->channels != p.channels ||
@@ -505,70 +571,25 @@ static int snd_pcm_plug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_plug_t *plug = pcm->private;
        snd_pcm_t *slave = plug->req_slave;
-       snd_pcm_hw_info_t sinfo;
+       snd_pcm_plug_params_t clt_params, slv_params;
        snd_pcm_hw_params_t sparams;
-       int format;
-       int err;
-
-       sparams = *params;
-       snd_pcm_hw_params_to_info(&sparams, &sinfo);
-       sinfo.access_mask = ~0U;
-       sinfo.format_mask = (SND_PCM_FMTBIT_LINEAR | SND_PCM_FMTBIT_MU_LAW |
-                            SND_PCM_FMTBIT_A_LAW | SND_PCM_FMTBIT_IMA_ADPCM);
-       sinfo.subformat_mask = SND_PCM_SUBFMTBIT_STD;
-       sinfo.channels_min = 1;
-       sinfo.channels_max = UINT_MAX;
-       sinfo.rate_min = RATE_MIN;
-       sinfo.rate_max = RATE_MAX;
-
-       err = snd_pcm_hw_info(slave, &sinfo);
-       if (err < 0)
-               return err;
-
-       err = snd_pcm_hw_info_par_nearest_next(&sinfo,
-                                              SND_PCM_HW_INFO_RATE,
-                                              params->rate, -1,
-                                              slave);
-       if (err < 0)
-               return err;
-       sinfo.rate_min = sinfo.rate_max = err;
-
-       err = snd_pcm_hw_info(slave, &sinfo);
-       assert(err >= 0);
-
-       err = snd_pcm_hw_info_par_nearest_next(&sinfo,
-                                              SND_PCM_HW_INFO_CHANNELS,
-                                              params->channels, -1,
-                                              slave);
-       if (err < 0)
-               return err;
-       sinfo.channels_min = sinfo.channels_max = err;
-
-       err = snd_pcm_hw_info(slave, &sinfo);
+       int err = snd_pcm_plug_hw_refine1(pcm, params, &sparams);
        assert(err >= 0);
 
-       format = snd_pcm_plug_slave_format(params->format, sinfo.format_mask);
-       assert(format >= 0);
+       clt_params.access = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_ACCESS);
+       clt_params.format = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT);
+       clt_params.channels = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_CHANNELS);
+       clt_params.rate = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_RATE);
 
-       sparams.format = format;
-       assert(sinfo.rate_min == sinfo.rate_max);
-       sparams.rate = sinfo.rate_min;
-       assert(sinfo.channels_min == sinfo.channels_max);
-       sparams.channels = sinfo.channels_min;
+       slv_params.access = snd_pcm_hw_params_first(slave, &sparams, SND_PCM_HW_PARAM_ACCESS);
+       slv_params.format = snd_pcm_hw_params_value(&sparams, SND_PCM_HW_PARAM_FORMAT);
+       slv_params.channels = snd_pcm_hw_params_value(&sparams, SND_PCM_HW_PARAM_CHANNELS);
+       slv_params.rate = snd_pcm_hw_params_value(&sparams, SND_PCM_HW_PARAM_RATE);
 
        snd_pcm_plug_clear(pcm);
-       if (params->format != sparams.format ||
-           params->channels != sparams.channels ||
-           params->rate != sparams.rate ||
-           !(sinfo.access_mask & (1 << params->access))) {
-               sinfo.access_mask &= SND_PCM_ACCBIT_MMAP;
-               assert(sinfo.access_mask);
-               sparams.access = ffs(sinfo.access_mask) - 1;
-               err = snd_pcm_plug_insert_plugins(pcm, params, &sparams);
-               if (err < 0)
-                       return err;
-       }
-
+       err = snd_pcm_plug_insert_plugins(pcm, &clt_params, &slv_params);
+       if (err < 0)
+               return err;
        err = snd_pcm_hw_params(plug->slave, params);
        if (err < 0) {
                snd_pcm_plug_clear(pcm);
@@ -638,7 +659,7 @@ static void snd_pcm_plug_dump(snd_pcm_t *pcm, FILE *fp)
 snd_pcm_ops_t snd_pcm_plug_ops = {
        close: snd_pcm_plug_close,
        info: snd_pcm_plug_info,
-       hw_info: snd_pcm_plug_hw_info,
+       hw_refine: snd_pcm_plug_hw_refine,
        hw_params: snd_pcm_plug_hw_params,
        sw_params: snd_pcm_plug_sw_params,
        dig_info: snd_pcm_plug_dig_info,
index e5029f2ad439e8c741b131e5707030f86a62af30..1cab1044b03a6ab9b7d6d5d02de99961f38539d1 100644 (file)
@@ -64,13 +64,14 @@ int get_index(int src_format, int dst_format);
 int put_index(int src_format, int dst_format);
 int conv_index(int src_format, int dst_format);
 
-#define SND_PCM_FMTBIT_LINEAR (SND_PCM_FMTBIT_S8     |SND_PCM_FMTBIT_U8 | \
-                               SND_PCM_FMTBIT_S16_LE|SND_PCM_FMTBIT_S16_BE | \
-                               SND_PCM_FMTBIT_U16_LE|SND_PCM_FMTBIT_U16_BE | \
-                               SND_PCM_FMTBIT_S24_LE|SND_PCM_FMTBIT_S24_BE | \
-                               SND_PCM_FMTBIT_U24_LE|SND_PCM_FMTBIT_U24_BE | \
-                               SND_PCM_FMTBIT_S32_LE|SND_PCM_FMTBIT_S32_BE | \
-                               SND_PCM_FMTBIT_U32_LE|SND_PCM_FMTBIT_U32_BE)
+#define SND_PCM_FMTBIT_LINEAR \
+       ((1 << SND_PCM_FORMAT_S8    ) | (1 << SND_PCM_FORMAT_U8) | \
+        (1 << SND_PCM_FORMAT_S16_LE) | (1 << SND_PCM_FORMAT_S16_BE) | \
+        (1 << SND_PCM_FORMAT_U16_LE) | (1 << SND_PCM_FORMAT_U16_BE) | \
+        (1 << SND_PCM_FORMAT_S24_LE) | (1 << SND_PCM_FORMAT_S24_BE) | \
+        (1 << SND_PCM_FORMAT_U24_LE) | (1 << SND_PCM_FORMAT_U24_BE) | \
+        (1 << SND_PCM_FORMAT_S32_LE) | (1 << SND_PCM_FORMAT_S32_BE) | \
+        (1 << SND_PCM_FORMAT_U32_LE) | (1 << SND_PCM_FORMAT_U32_BE))
 
 extern snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops;
 
@@ -107,3 +108,9 @@ int snd_pcm_route_open(snd_pcm_t **pcmp, char *name,
                       snd_pcm_t *slave, int close_slave);
 int snd_pcm_rate_open(snd_pcm_t **pcmp, char *name, int sformat, int srate, snd_pcm_t *slave, int close_slave);
 
+
+#define SND_PCM_ACCBIT_PLUGIN ((1 << SND_PCM_ACCESS_MMAP_INTERLEAVED) | \
+                              (1 << SND_PCM_ACCESS_RW_INTERLEAVED) | \
+                              (1 << SND_PCM_ACCESS_MMAP_NONINTERLEAVED) | \
+                              (1 << SND_PCM_ACCESS_RW_NONINTERLEAVED))
+
index 231c83c8b0cdeb206d57b31848125aed102fa530..74dfbdb3dc8381ea9e460cd3febe7609806613ef 100644 (file)
@@ -233,50 +233,60 @@ static int snd_pcm_rate_close(snd_pcm_t *pcm)
        return 0;
 }
 
-static int snd_pcm_rate_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
+static int snd_pcm_rate_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_rate_t *rate = pcm->private;
-       unsigned int access_mask, format_mask;
-       unsigned int rate_min, rate_max;
+       snd_pcm_t *slave = rate->plug.slave;
        int err;
-       info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED | 
-                             SND_PCM_ACCBIT_RW_INTERLEAVED |
-                             SND_PCM_ACCBIT_MMAP_NONINTERLEAVED | 
-                             SND_PCM_ACCBIT_RW_NONINTERLEAVED);
-       access_mask = info->access_mask;
-       if (access_mask == 0)
-               return -EINVAL;
-
-       info->format_mask &= SND_PCM_FMTBIT_LINEAR;
-       format_mask = info->format_mask;
-       if (format_mask == 0)
-               return -EINVAL;
+       snd_pcm_hw_params_t sparams;
+       unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
+                             SND_PCM_HW_PARBIT_FRAGMENTS |
+                             SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+                             SND_PCM_HW_PARBIT_BUFFER_LENGTH);
+       mask_t *access_mask = alloca(mask_sizeof());
+       mask_t *format_mask = alloca(mask_sizeof());
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
+       mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+       err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_ACCESS,
+                                     access_mask);
+       if (err < 0)
+               return err;
+       err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_FORMAT,
+                                     format_mask);
+       if (err < 0)
+               return err;
+       err = _snd_pcm_hw_params_min(params, 1,
+                                    SND_PCM_HW_PARAM_RATE, RATE_MIN);
+       if (err < 0)
+               return err;
+       err = _snd_pcm_hw_params_max(params, 1,
+                                    SND_PCM_HW_PARAM_RATE, RATE_MAX);
+       if (err < 0)
+               return err;
 
-       if (info->rate_min < RATE_MIN)
-               info->rate_min = RATE_MIN;
-       if (info->rate_max > RATE_MAX)
-               info->rate_max = RATE_MAX;
-       rate_min = info->rate_min;
-       rate_max = info->rate_max;
-       if (rate_max < rate_min)
-               return -EINVAL;
-       
-       info->access_mask = SND_PCM_ACCBIT_MMAP;
-       if (rate->sformat >= 0)
-               info->format_mask = 1U << rate->sformat;
-       info->rate_min = rate->srate;
-       info->rate_max = rate->srate;
+       _snd_pcm_hw_params_any(&sparams);
+       _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+                               saccess_mask);
+       if (rate->sformat >= 0) {
+               _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+                                      rate->sformat);
+               _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+                                      SND_PCM_SUBFORMAT_STD);
+       } else
+               links |= (SND_PCM_HW_PARBIT_FORMAT |
+                         SND_PCM_HW_PARBIT_SUBFORMAT |
+                         SND_PCM_HW_PARBIT_SAMPLE_BITS |
+                         SND_PCM_HW_PARBIT_FRAME_BITS);
+       _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_RATE,
+                              rate->srate);
                
-       err = snd_pcm_hw_info(rate->plug.slave, info);
-       if (rate->sformat >= 0)
-               info->format_mask = format_mask;
-       info->rate_min = rate_min;
-       info->rate_max = rate_max;
-
+       err = snd_pcm_hw_refine2(params, &sparams,
+                                snd_pcm_hw_refine, slave, links);
        if (err < 0)
                return err;
-       info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
-       snd_pcm_hw_info_complete(info);
+       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
        return 0;
 }
 
@@ -284,32 +294,48 @@ static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
 {
        snd_pcm_rate_t *rate = pcm->private;
        snd_pcm_t *slave = rate->plug.slave;
-       snd_pcm_hw_info_t sinfo;
+       int err;
        snd_pcm_hw_params_t sparams;
+       unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
+                             SND_PCM_HW_PARBIT_FRAGMENTS |
+                             SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+                             SND_PCM_HW_PARBIT_BUFFER_LENGTH);
        unsigned int src_format, dst_format;
        unsigned int src_rate, dst_rate;
-       int mul, div;
-       int err;
-       snd_pcm_hw_params_to_info(params, &sinfo);
-       if (rate->sformat >= 0)
-               sinfo.format_mask = 1 << rate->sformat;
-       sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
-       sinfo.rate_min = rate->srate;
-       sinfo.rate_max = rate->srate;
-       err = snd_pcm_hw_params_info(slave, &sparams, &sinfo);
-       params->fail_mask = sparams.fail_mask;
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+
+       _snd_pcm_hw_params_any(&sparams);
+       _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+                               saccess_mask);
+       if (rate->sformat >= 0) {
+               _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+                                      rate->sformat);
+               _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+                                      SND_PCM_SUBFORMAT_STD);
+       } else
+               links |= (SND_PCM_HW_PARBIT_FORMAT |
+                         SND_PCM_HW_PARBIT_SUBFORMAT |
+                         SND_PCM_HW_PARBIT_SAMPLE_BITS |
+                         SND_PCM_HW_PARBIT_FRAME_BITS);
+       _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_RATE,
+                              rate->srate);
+               
+       err = snd_pcm_hw_params2(params, &sparams,
+                                snd_pcm_hw_params, slave, links);
        if (err < 0)
                return err;
+       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
-               src_format = params->format;
+               src_format = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT);
                dst_format = slave->format;
-               src_rate = params->rate;
+               src_rate = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_RATE);
                dst_rate = slave->rate;
        } else {
                src_format = slave->format;
-               dst_format = params->format;
+               dst_format = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT);
                src_rate = slave->rate;
-               dst_rate = params->rate;
+               dst_rate = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_RATE);
        }
        rate->get_idx = get_index(src_format, SND_PCM_FORMAT_S16);
        rate->put_idx = put_index(SND_PCM_FORMAT_S16, dst_format);
@@ -321,16 +347,9 @@ static int snd_pcm_rate_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
                /* pitch is get_increment */
        }
        rate->pitch = (((u_int64_t)dst_rate * DIV) + src_rate / 2) / src_rate;
-       if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
-               mul = DIV;
-               div = rate->pitch;
-       } else {
-               mul = rate->pitch;
-               div = DIV;
-       }
        if (rate->states)
                free(rate->states);
-       rate->states = malloc(params->channels * sizeof(*rate->states));
+       rate->states = malloc(snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_CHANNELS) * sizeof(*rate->states));
        return 0;
 }
 
@@ -493,7 +512,7 @@ static void snd_pcm_rate_dump(snd_pcm_t *pcm, FILE *fp)
 snd_pcm_ops_t snd_pcm_rate_ops = {
        close: snd_pcm_rate_close,
        info: snd_pcm_plugin_info,
-       hw_info: snd_pcm_rate_hw_info,
+       hw_refine: snd_pcm_rate_hw_refine,
        hw_params: snd_pcm_rate_hw_params,
        sw_params: snd_pcm_rate_sw_params,
        dig_info: snd_pcm_plugin_dig_info,
index d9eb379cd150d1a6d9c98e587d14d610b835ad6e..cbebad8bb07c737798bbc5bbccf120e90235c663 100644 (file)
@@ -425,50 +425,64 @@ static int snd_pcm_route_close(snd_pcm_t *pcm)
        return 0;
 }
 
-static int snd_pcm_route_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info)
+static int snd_pcm_route_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_route_t *route = pcm->private;
-       unsigned int format_mask, access_mask;
-       unsigned int channels_min, channels_max;
+       snd_pcm_t *slave = route->plug.slave;
        int err;
-       info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED | 
-                             SND_PCM_ACCBIT_RW_INTERLEAVED |
-                             SND_PCM_ACCBIT_MMAP_NONINTERLEAVED | 
-                             SND_PCM_ACCBIT_RW_NONINTERLEAVED);
-       access_mask = info->access_mask;
-       if (access_mask == 0)
-               return -EINVAL;
-
-       info->format_mask &= SND_PCM_FMTBIT_LINEAR;
-       format_mask = info->format_mask;
-       if (format_mask == 0)
-               return -EINVAL;
-
-       if (info->channels_min < 1)
-               info->channels_min = 1;
-       channels_min = info->channels_min;
-       channels_max = info->channels_max;
-       if (channels_min > channels_max)
-               return -EINVAL;
+       snd_pcm_hw_params_t sparams;
+       unsigned int links = (SND_PCM_HW_PARBIT_CHANNELS |
+                             SND_PCM_HW_PARBIT_FRAGMENTS |
+                             SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+                             SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+                             SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                             SND_PCM_HW_PARBIT_BUFFER_LENGTH);
+       mask_t *access_mask = alloca(mask_sizeof());
+       mask_t *format_mask = alloca(mask_sizeof());
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(access_mask, SND_PCM_ACCBIT_PLUGIN);
+       mask_load(format_mask, SND_PCM_FMTBIT_LINEAR);
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+       err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_ACCESS,
+                                     access_mask);
+       if (err < 0)
+               return err;
+       err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_FORMAT,
+                                     format_mask);
+       if (err < 0)
+               return err;
+       err = _snd_pcm_hw_params_min(params, 1, SND_PCM_HW_PARAM_CHANNELS, 1);
+       if (err < 0)
+               return err;
 
-       if (route->sformat >= 0)
-               info->format_mask = 1U << route->sformat;
-       if (route->schannels >= 0)
-               info->channels_min = info->channels_max = route->schannels;
-               
-       info->access_mask = SND_PCM_ACCBIT_MMAP;
-       err = snd_pcm_hw_info(route->plug.slave, info);
-       info->access_mask = access_mask;
-       if (route->sformat >= 0)
-               info->format_mask = format_mask;
+       _snd_pcm_hw_params_any(&sparams);
+       _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+                               saccess_mask);
+       if (route->sformat >= 0) {
+               _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+                                      route->sformat);
+               _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+                                      SND_PCM_SUBFORMAT_STD);
+       } else
+               links |= (SND_PCM_HW_PARBIT_FORMAT | 
+                         SND_PCM_HW_PARBIT_SUBFORMAT |
+                         SND_PCM_HW_PARBIT_SAMPLE_BITS);
        if (route->schannels >= 0) {
-               info->channels_min = channels_min;
-               info->channels_max = channels_max;
+               _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_CHANNELS,
+                                      route->schannels);
+       } else {
+               links |= SND_PCM_HW_PARBIT_CHANNELS;
+               if (route->sformat < 0)
+                       links |= (SND_PCM_HW_PARBIT_FRAME_BITS |
+                                 SND_PCM_HW_PARBIT_FRAGMENT_BYTES |
+                                 SND_PCM_HW_PARBIT_BUFFER_BYTES);
        }
+               
+       err = snd_pcm_hw_refine2(params, &sparams,
+                                snd_pcm_hw_refine, slave, links);
        if (err < 0)
                return err;
-       info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
-       snd_pcm_hw_info_complete(info);
+       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
        return 0;
 }
 
@@ -476,26 +490,51 @@ static int snd_pcm_route_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
 {
        snd_pcm_route_t *route = pcm->private;
        snd_pcm_t *slave = route->plug.slave;
-       unsigned int src_format, dst_format;
-       snd_pcm_hw_info_t sinfo;
-       snd_pcm_hw_params_t sparams;
        int err;
-       snd_pcm_hw_params_to_info(params, &sinfo);
-       if (route->sformat >= 0)
-               sinfo.format_mask = 1 << route->sformat;
-       if (route->schannels >= 0)
-               sinfo.channels_min = sinfo.channels_max = route->schannels;
-       sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
-       err = snd_pcm_hw_params_info(slave, &sparams, &sinfo);
-       params->fail_mask = sparams.fail_mask;
+       snd_pcm_hw_params_t sparams;
+       unsigned int links = (SND_PCM_HW_PARBIT_FRAGMENTS |
+                             SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+                             SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+                             SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                             SND_PCM_HW_PARBIT_BUFFER_LENGTH);
+       unsigned int src_format, dst_format;
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+
+       _snd_pcm_hw_params_any(&sparams);
+       _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+                               saccess_mask);
+       if (route->sformat >= 0) {
+               _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_FORMAT,
+                                      route->sformat);
+               _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_SUBFORMAT,
+                                      SND_PCM_SUBFORMAT_STD);
+       } else
+               links |= (SND_PCM_HW_PARBIT_FORMAT | 
+                         SND_PCM_HW_PARBIT_SUBFORMAT |
+                         SND_PCM_HW_PARBIT_SAMPLE_BITS);
+       if (route->schannels >= 0) {
+               _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_CHANNELS,
+                                      route->schannels);
+       } else {
+               links |= SND_PCM_HW_PARBIT_CHANNELS;
+               if (route->sformat < 0)
+                       links |= (SND_PCM_HW_PARBIT_FRAME_BITS |
+                                 SND_PCM_HW_PARBIT_FRAGMENT_BYTES |
+                                 SND_PCM_HW_PARBIT_BUFFER_BYTES);
+       }
+
+       err = snd_pcm_hw_params2(params, &sparams, 
+                                snd_pcm_hw_params, slave, links);
        if (err < 0)
                return err;
+       params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
-               src_format = params->format;
+               src_format = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT);
                dst_format = slave->format;
        } else {
                src_format = slave->format;
-               dst_format = params->format;
+               dst_format = snd_pcm_hw_params_value(params, SND_PCM_HW_PARAM_FORMAT);
        }
        route->params.get_idx = get_index(src_format, SND_PCM_FORMAT_U16);
        route->params.put_idx = put_index(SND_PCM_FORMAT_U32, dst_format);
@@ -622,7 +661,7 @@ static void snd_pcm_route_dump(snd_pcm_t *pcm, FILE *fp)
 snd_pcm_ops_t snd_pcm_route_ops = {
        close: snd_pcm_route_close,
        info: snd_pcm_plugin_info,
-       hw_info: snd_pcm_route_hw_info,
+       hw_refine: snd_pcm_route_hw_refine,
        hw_params: snd_pcm_route_hw_params,
        sw_params: snd_pcm_plugin_sw_params,
        dig_info: snd_pcm_plugin_dig_info,
index 8c55c9ad15409bcf44cecf1f4aa1397708782dd2..0bf9d664fe0f33716c1a9371548f0215595fdc3f 100644 (file)
@@ -442,50 +442,66 @@ static int snd_pcm_share_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
        return snd_pcm_info(share->slave->pcm, info);
 }
 
-static int snd_pcm_share_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info)
+static int snd_pcm_share_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        snd_pcm_share_t *share = pcm->private;
        snd_pcm_share_slave_t *slave = share->slave;
-       unsigned int access_mask;
-       int err = 0;
-       info->access_mask &= (SND_PCM_ACCBIT_MMAP_INTERLEAVED | 
-                             SND_PCM_ACCBIT_RW_INTERLEAVED |
-                             SND_PCM_ACCBIT_MMAP_NONINTERLEAVED | 
-                             SND_PCM_ACCBIT_RW_NONINTERLEAVED);
-       access_mask = info->access_mask;
-       if (access_mask == 0)
-               return -EINVAL;
+       snd_pcm_hw_params_t sparams;
+       int err;
+       mask_t *access_mask = alloca(mask_sizeof());
+       const mask_t *mmap_mask;
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+
+       err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_CHANNELS,
+                                    share->channels_count);
+       if (err < 0)
+               return err;
 
        if (slave->format >= 0) {
-               info->format_mask &= 1U << slave->format;
-               if (!info->format_mask)
-                       return -EINVAL;
+               err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_FORMAT,
+                                            slave->format);
+               if (err < 0)
+                       return err;
        }
 
-       if (info->channels_min < share->channels_count)
-               info->channels_min = share->channels_count;
-       if (info->channels_max > share->channels_count)
-               info->channels_max = share->channels_count;
-       if (info->channels_min > info->channels_max)
-               return -EINVAL;
-
        if (slave->rate >= 0) {
-               if (info->rate_min < (unsigned)slave->rate)
-                       info->rate_min = slave->rate;
-               if (info->rate_max > (unsigned)slave->rate)
-                       info->rate_max = slave->rate;
-               if (info->rate_min > info->rate_max)
-                       return -EINVAL;
+               err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_RATE,
+                                            slave->rate);
+               if (err < 0)
+                       return err;
        }
 
-       info->access_mask = SND_PCM_ACCBIT_MMAP;
-       info->channels_min = info->channels_max = slave->channels_count;
-       err = snd_pcm_hw_info(slave->pcm, info);
-       info->access_mask = access_mask;
-       info->channels_min = info->channels_max = share->channels_count;
+       _snd_pcm_hw_params_any(&sparams);
+       _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+                               saccess_mask);
+       _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_CHANNELS,
+                              slave->channels_count);
+       err = snd_pcm_hw_refine2(params, &sparams,
+                                snd_pcm_hw_refine, slave->pcm,
+                                SND_PCM_HW_PARBIT_FORMAT |
+                                SND_PCM_HW_PARBIT_SUBFORMAT |
+                                SND_PCM_HW_PARBIT_RATE |
+                                SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+                                SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+                                SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                                SND_PCM_HW_PARBIT_BUFFER_LENGTH |
+                                SND_PCM_HW_PARBIT_FRAGMENTS);
+       if (err < 0)
+               return err;
+       mmap_mask = snd_pcm_hw_params_value_mask(&sparams, SND_PCM_HW_PARAM_ACCESS);
+       mask_all(access_mask);
+       mask_reset(access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
+       if (!mask_test(mmap_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED))
+               mask_reset(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
+       if (!mask_test(mmap_mask, SND_PCM_ACCESS_MMAP_COMPLEX) &&
+           !mask_test(mmap_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED))
+               mask_reset(access_mask, SND_PCM_ACCESS_MMAP_COMPLEX);
+       err = _snd_pcm_hw_params_mask(params, 1, SND_PCM_HW_PARAM_ACCESS,
+                                     access_mask);
        if (err < 0)
                return err;
-       info->info |= SND_PCM_INFO_DOUBLE;
+       params->info |= SND_PCM_INFO_DOUBLE;
        return 0;
 }
 
@@ -498,31 +514,55 @@ static int snd_pcm_share_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
        Pthread_mutex_lock(&slave->mutex);
        if (slave->setup_count > 1 || 
            (slave->setup_count == 1 && !pcm->setup)) {
-               if (params->format != spcm->format)
-                       params->fail_mask |= SND_PCM_HW_PARBIT_FORMAT;
-               if (params->subformat != spcm->subformat)
-                       params->fail_mask |= SND_PCM_HW_PARBIT_SUBFORMAT;
-               if (params->rate != spcm->rate)
-                       params->fail_mask |= SND_PCM_HW_PARBIT_RATE;
-               if (params->fragments != spcm->fragments)
-                       params->fail_mask |= SND_PCM_HW_PARBIT_FRAGMENTS;
-               if (params->fragment_size != spcm->fragment_size)
-                       params->fail_mask |= SND_PCM_HW_PARBIT_FRAGMENT_SIZE;
-               if (params->fail_mask) {
+               err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_FORMAT,
+                                            spcm->format);
+               if (err < 0)
+                       goto _err;
+               err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_SUBFORMAT,
+                                            spcm->subformat);
+               if (err < 0)
+                       goto _err;
+               err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_RATE,
+                                            spcm->rate);
+               if (err < 0)
+                       goto _err;
+               err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_FRAGMENT_SIZE,
+                                            spcm->fragment_size);
+               if (err < 0)
+                       goto _err;
+               err = _snd_pcm_hw_params_set(params, 1, SND_PCM_HW_PARAM_FRAGMENTS,
+                                                  spcm->fragments);
+       _err:
+               if (err < 0) {
                        ERR("slave is already running with different setup");
                        err = -EBUSY;
                        goto _end;
                }
        } else {
-               snd_pcm_hw_params_t sparams = *params;
-               sparams.channels = slave->channels_count;
-               err = snd_pcm_hw_params(slave->pcm, &sparams);
+               snd_pcm_hw_params_t sparams;
+               mask_t *saccess_mask = alloca(mask_sizeof());
+               mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+               _snd_pcm_hw_params_any(&sparams);
+               _snd_pcm_hw_params_mask(&sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+                                       saccess_mask);
+               _snd_pcm_hw_params_set(&sparams, 0, SND_PCM_HW_PARAM_CHANNELS,
+                                      share->channels_count);
+               err = snd_pcm_hw_params2(params, &sparams,
+                                        snd_pcm_hw_params, slave->pcm,
+                                        SND_PCM_HW_PARBIT_FORMAT |
+                                        SND_PCM_HW_PARBIT_SUBFORMAT |
+                                        SND_PCM_HW_PARBIT_RATE |
+                                        SND_PCM_HW_PARBIT_FRAGMENT_SIZE |
+                                        SND_PCM_HW_PARBIT_FRAGMENT_LENGTH |
+                                        SND_PCM_HW_PARBIT_BUFFER_SIZE |
+                                        SND_PCM_HW_PARBIT_BUFFER_LENGTH |
+                                        SND_PCM_HW_PARBIT_FRAGMENTS);
                if (err < 0)
                        goto _end;
                /* >= 30 ms */
-               slave->safety_threshold = sparams.rate * 30 / 1000;
-               slave->safety_threshold += sparams.fragment_size - 1;
-               slave->safety_threshold -= slave->safety_threshold % sparams.fragment_size;
+               slave->safety_threshold = slave->pcm->rate * 30 / 1000;
+               slave->safety_threshold += slave->pcm->fragment_size - 1;
+               slave->safety_threshold -= slave->safety_threshold % slave->pcm->fragment_size;
                slave->silence_frames = slave->safety_threshold;
                if (slave->pcm->stream == SND_PCM_STREAM_PLAYBACK)
                        snd_pcm_areas_silence(slave->pcm->running_areas, 0, slave->pcm->channels, slave->pcm->buffer_size, slave->pcm->format);
@@ -537,15 +577,15 @@ static int snd_pcm_share_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 static int snd_pcm_share_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params)
 {
        if (params->start_mode > SND_PCM_START_LAST) {
-               params->fail_mask = SND_PCM_SW_PARBIT_START_MODE;
+               params->fail_mask = 1 << SND_PCM_SW_PARAM_START_MODE;
                return -EINVAL;
        }
        if (params->ready_mode > SND_PCM_READY_LAST) {
-               params->fail_mask = SND_PCM_SW_PARBIT_READY_MODE;
+               params->fail_mask = 1 << SND_PCM_SW_PARAM_READY_MODE;
                return -EINVAL;
        }
        if (params->xrun_mode > SND_PCM_XRUN_LAST) {
-               params->fail_mask = SND_PCM_SW_PARBIT_XRUN_MODE;
+               params->fail_mask = 1 << SND_PCM_SW_PARAM_XRUN_MODE;
                return -EINVAL;
        }
        return 0;
@@ -1067,7 +1107,7 @@ static void snd_pcm_share_dump(snd_pcm_t *pcm, FILE *fp)
 snd_pcm_ops_t snd_pcm_share_ops = {
        close: snd_pcm_share_close,
        info: snd_pcm_share_info,
-       hw_info: snd_pcm_share_hw_info,
+       hw_refine: snd_pcm_share_hw_refine,
        hw_params: snd_pcm_share_hw_params,
        sw_params: snd_pcm_share_sw_params,
        dig_info: snd_pcm_share_dig_info,
index 885d72e0791169e18511bfb061eb43a22964b10b..cac1108d96d97a004de26f33a126a9130872ccb9 100644 (file)
@@ -42,7 +42,6 @@
 typedef struct {
        int socket;
        volatile snd_pcm_shm_ctrl_t *ctrl;
-       unsigned int access_mask;
 } snd_pcm_shm_t;
 
 int receive_fd(int socket, void *data, size_t len, int *fd)
@@ -148,49 +147,60 @@ static int snd_pcm_shm_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
        return err;
 }
 
-static int snd_pcm_shm_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
+static int _snd_pcm_shm_hw_refine(snd_pcm_t *pcm,
+                                 snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED)
 {
        snd_pcm_shm_t *shm = pcm->private;
        volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
-       int err;
-       unsigned int access_mask = info->access_mask;
-       ctrl->cmd = SND_PCM_IOCTL_HW_INFO;
-       ctrl->u.hw_info = *info;
-       ctrl->u.hw_info.access_mask = SND_PCM_ACCBIT_MMAP;
-       err = snd_pcm_shm_action(pcm);
-       if (err < 0)
-               return err;
-       access_mask &= (SND_PCM_ACCESS_RW_INTERLEAVED |
-                       SND_PCM_ACCESS_RW_NONINTERLEAVED |
-                       ctrl->u.hw_info.access_mask);
-       if (!access_mask)
-               return -EINVAL;
-       *info = ctrl->u.hw_info;
-       shm->access_mask = info->access_mask;
-       info->access_mask = access_mask;
-       return 0;
+       ctrl->cmd = SND_PCM_IOCTL_HW_REFINE;
+       return snd_pcm_shm_action(pcm);
 }
 
-static int snd_pcm_shm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
+static int snd_pcm_shm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
+{
+       snd_pcm_shm_t *shm = pcm->private;
+       volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
+       snd_pcm_hw_params_t *sparams = (snd_pcm_hw_params_t *) &ctrl->u.hw_refine;
+       const mask_t *access_mask = snd_pcm_hw_params_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+       if (!mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) &&
+           !mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED))
+               mask_intersect(saccess_mask, access_mask);
+       _snd_pcm_hw_params_any(sparams);
+       _snd_pcm_hw_params_mask(sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+                               saccess_mask);
+       return snd_pcm_hw_refine2(params, sparams,
+                                 _snd_pcm_shm_hw_refine, pcm,
+                                 ~SND_PCM_HW_PARBIT_ACCESS);
+}
+
+static int _snd_pcm_shm_hw_params(snd_pcm_t *pcm, 
+                                 snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED)
 {
        snd_pcm_shm_t *shm = pcm->private;
        volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
-       unsigned int access = params->access;
-       int err;
        ctrl->cmd = SND_PCM_IOCTL_HW_PARAMS;
-       ctrl->u.hw_params = *params;
-       if (shm->access_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
-               ctrl->u.hw_params.access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
-       else if (shm->access_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
-               ctrl->u.hw_params.access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
-       else
-               assert(0);
-       err = snd_pcm_shm_action(pcm);
-       params->access = access;
-       *params = ctrl->u.hw_params;
-       if (err < 0)
-               return err;
-       return err;
+       return snd_pcm_shm_action(pcm);
+}
+
+static int snd_pcm_shm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
+{
+       snd_pcm_shm_t *shm = pcm->private;
+       volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
+       snd_pcm_hw_params_t *sparams = (snd_pcm_hw_params_t *) &ctrl->u.hw_refine;
+       const mask_t *access_mask = snd_pcm_hw_params_value_mask(params, SND_PCM_HW_PARAM_ACCESS);
+       mask_t *saccess_mask = alloca(mask_sizeof());
+       mask_load(saccess_mask, SND_PCM_ACCBIT_MMAP);
+       if (!mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) &&
+           !mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED))
+               mask_intersect(saccess_mask, access_mask);
+       _snd_pcm_hw_params_any(sparams);
+       _snd_pcm_hw_params_mask(sparams, 0, SND_PCM_HW_PARAM_ACCESS,
+                               saccess_mask);
+       return snd_pcm_hw_params2(params, sparams,
+                                 _snd_pcm_shm_hw_params, pcm,
+                                 ~SND_PCM_HW_PARBIT_ACCESS);
 }
 
 static int snd_pcm_shm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
@@ -461,7 +471,7 @@ static void snd_pcm_shm_dump(snd_pcm_t *pcm, FILE *fp)
 snd_pcm_ops_t snd_pcm_shm_ops = {
        close: snd_pcm_shm_close,
        info: snd_pcm_shm_info,
-       hw_info: snd_pcm_shm_hw_info,
+       hw_refine: snd_pcm_shm_hw_refine,
        hw_params: snd_pcm_shm_hw_params,
        sw_params: snd_pcm_shm_sw_params,
        dig_info: snd_pcm_shm_dig_info,