]> git.alsa-project.org Git - alsa-lib.git/commitdiff
Merged pcmfinal branch.
authorJaroslav Kysela <perex@perex.cz>
Mon, 20 Nov 2000 20:10:46 +0000 (20:10 +0000)
committerJaroslav Kysela <perex@perex.cz>
Mon, 20 Nov 2000 20:10:46 +0000 (20:10 +0000)
57 files changed:
TODO
aserver/aserver.c
include/aserver.h
include/conf.h
include/control.h
include/header.h
include/hwdep.h
include/instr.h
include/mixer.h
include/pcm.h
include/rawmidi.h
include/seq.h
include/timer.h
src/control/cards.c
src/control/control.c
src/control/control_hw.c
src/control/control_local.h
src/control/control_shm.c
src/error.c
src/hwdep/hwdep.c
src/instr/iwffff.c
src/mixer/mixer_local.h
src/pcm/pcm.c
src/pcm/pcm_adpcm.c
src/pcm/pcm_alaw.c
src/pcm/pcm_file.c
src/pcm/pcm_hw.c
src/pcm/pcm_linear.c
src/pcm/pcm_local.h
src/pcm/pcm_misc.c
src/pcm/pcm_mmap.c
src/pcm/pcm_mulaw.c
src/pcm/pcm_multi.c
src/pcm/pcm_null.c
src/pcm/pcm_plug.c
src/pcm/pcm_plugin.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
src/rawmidi/Makefile.am
src/rawmidi/rawmidi.c
src/rawmidi/rawmidi_hw.c [new file with mode: 0644]
src/rawmidi/rawmidi_local.h [new file with mode: 0644]
src/seq/Makefile.am
src/seq/seq.c
src/seq/seq_hw.c [new file with mode: 0644]
src/seq/seq_local.h [new file with mode: 0644]
src/seq/seq_priv.h [deleted file]
src/seq/seqmid.c
src/timer/timer.c
test/latency.c
test/pause.c
test/pcm.c
test/pcmtest.c
test/seq-sender.c

diff --git a/TODO b/TODO
index ecf105a49686bbeda48d46ec9786902c992e92bf..d89b590999cac64d5835ddc4d7796dd3066984f8 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,3 +1,3 @@
 M think about xrun recovery helpers
-M add abstraction layer to timer, rawmidi, hwdep, seq
+M add abstraction layer to timer, hwdep
 L move OSS emulation to user space? (pseudo device driver and daemon)
index 5e54d0b012792990700d9333c05e576129904958..3b326ff8ae9a74d82e18802a4dd59ccef9f1b309 100644 (file)
@@ -379,14 +379,20 @@ 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_PARAMS:
-               ctrl->result = snd_pcm_params(pcm, (snd_pcm_params_t *) &ctrl->u.params);
+       case SND_PCM_IOCTL_HW_INFO:
+               ctrl->result = snd_pcm_hw_info(pcm, (snd_pcm_hw_info_t *) &ctrl->u.hw_info);
                break;
-       case SND_PCM_IOCTL_PARAMS_INFO:
-               ctrl->result = snd_pcm_params_info(pcm, (snd_pcm_params_info_t *) &ctrl->u.params_info);
+       case SND_PCM_IOCTL_HW_PARAMS:
+               ctrl->result = snd_pcm_hw_params(pcm, (snd_pcm_hw_params_t *) &ctrl->u.hw_params);
                break;
-       case SND_PCM_IOCTL_SETUP:
-               ctrl->result = snd_pcm_setup(pcm, (snd_pcm_setup_t *) &ctrl->u.setup);
+       case SND_PCM_IOCTL_SW_PARAMS:
+               ctrl->result = snd_pcm_sw_params(pcm, (snd_pcm_sw_params_t *) &ctrl->u.sw_params);
+               break;
+       case SND_PCM_IOCTL_DIG_PARAMS:
+               ctrl->result = snd_pcm_dig_params(pcm, (snd_pcm_dig_params_t *) &ctrl->u.dig_params);
+               break;
+       case SND_PCM_IOCTL_DIG_INFO:
+               ctrl->result = snd_pcm_dig_info(pcm, (snd_pcm_dig_info_t *) &ctrl->u.dig_info);
                break;
        case SND_PCM_IOCTL_STATUS:
                ctrl->result = snd_pcm_status(pcm, (snd_pcm_status_t *) &ctrl->u.status);
@@ -422,12 +428,9 @@ int pcm_shm_cmd(client_t *client)
                break;
        case SND_PCM_IOCTL_CHANNEL_INFO:
                ctrl->result = snd_pcm_channel_info(pcm, (snd_pcm_channel_info_t *) &ctrl->u.channel_info);
-               break;
-       case SND_PCM_IOCTL_CHANNEL_PARAMS:
-               ctrl->result = snd_pcm_channel_params(pcm, (snd_pcm_channel_params_t *) &ctrl->u.channel_params);
-               break;
-       case SND_PCM_IOCTL_CHANNEL_SETUP:
-               ctrl->result = snd_pcm_channel_setup(pcm, (snd_pcm_channel_setup_t *) &ctrl->u.channel_setup);
+               if (ctrl->result >= 0 &&
+                   ctrl->u.channel_info.type == SND_PCM_AREA_MMAP)
+                       return shm_ack_fd(client, ctrl->u.channel_info.u.mmap.fd);
                break;
        case SND_PCM_IOCTL_REWIND:
                ctrl->result = snd_pcm_rewind(pcm, ctrl->u.rewind.frames);
@@ -444,27 +447,7 @@ int pcm_shm_cmd(client_t *client)
                break;
        case SND_PCM_IOCTL_MMAP:
        {
-               err = snd_pcm_mmap(pcm);
-               if (err < 0)
-                       ctrl->result = err;
-               else
-                       ctrl->result = pcm->mmap_info_count;
-               break;
-       }
-       case SND_PCM_IOCTL_MMAP_INFO:
-       {
-               unsigned int index = ctrl->u.mmap_info.index;
-               snd_pcm_mmap_info_t *i = &pcm->mmap_info[index];
-               if (index >= pcm->mmap_info_count) {
-                       ctrl->result = -EINVAL;
-                       break;
-               }
-               ctrl->u.mmap_info = *i;
-               ctrl->u.mmap_info.index = index;
-               ctrl->result = 0;
-               if (i->type == SND_PCM_MMAP_USER)
-                       break;
-               return shm_ack_fd(client, i->u.kernel.fd);
+               ctrl->result = snd_pcm_mmap(pcm);
        }
        case SND_PCM_IOCTL_MUNMAP:
        {
index 85823fd8dbe89de3f841803a70bf55a0e202aafe..6106d43a87eef30aad29e73e940ad69bea17c920 100644 (file)
@@ -28,7 +28,6 @@
 #define SND_PCM_IOCTL_AVAIL_UPDATE     _IO ('A', 0xf8)
 #define SND_PCM_IOCTL_ASYNC            _IO ('A', 0xf9)
 #define SND_PCM_IOCTL_CLOSE            _IO ('A', 0xfa)
-#define SND_PCM_IOCTL_MMAP_INFO                _IO ('A', 0xfb)
 #define SND_PCM_IOCTL_POLL_DESCRIPTOR  _IO ('A', 0xfc)
 #define SND_PCM_IOCTL_SET_AVAIL_MIN    _IO ('A', 0xfd)
 
@@ -42,11 +41,12 @@ typedef struct {
                        int sig;
                        pid_t pid;
                } async;
-               snd_pcm_mmap_info_t mmap_info;
                snd_pcm_info_t info;
-               snd_pcm_params_t params;
-               snd_pcm_params_info_t params_info;
-               snd_pcm_setup_t setup;
+               snd_pcm_hw_info_t hw_info;
+               snd_pcm_hw_params_t hw_params;
+               snd_pcm_sw_params_t sw_params;
+               snd_pcm_dig_params_t dig_params;
+               snd_pcm_dig_info_t dig_info;
                snd_pcm_status_t status;
                struct {
                        ssize_t frames;
@@ -55,8 +55,6 @@ typedef struct {
                        int enable;
                } pause;
                snd_pcm_channel_info_t channel_info;
-               snd_pcm_channel_params_t channel_params;
-               snd_pcm_channel_setup_t channel_setup;
                struct {
                        ssize_t frames;
                } rewind;
index d2858380f63e903264dda079be18532e7d9ec0a0..00ae6f99493427bc8863d8cadc3513d067b10b7c 100644 (file)
@@ -1,14 +1,14 @@
 
-typedef enum {
+typedef enum _snd_config_type {
         SND_CONFIG_TYPE_INTEGER,
         SND_CONFIG_TYPE_REAL,
         SND_CONFIG_TYPE_STRING,
        SND_CONFIG_TYPE_COMPOUND,
 } snd_config_type_t;
 
-typedef struct snd_config snd_config_t;
+typedef struct _snd_config snd_config_t;
 
-struct snd_config {
+struct _snd_config {
        char *id;
        snd_config_type_t type;
        union {
index 864a39e4c5b5651e9ed6cc76cb568f8972d2cf50..f786b014d902a847556e858e975ceebeaf628ef4 100644 (file)
@@ -5,14 +5,14 @@
  *                                                                          *
  ****************************************************************************/
 
-typedef struct snd_ctl snd_ctl_t;
+typedef struct _snd_ctl snd_ctl_t;
 
-typedef enum { SND_CTL_TYPE_HW,
+typedef enum _snd_ctl_type { SND_CTL_TYPE_HW,
               SND_CTL_TYPE_SHM,
               SND_CTL_TYPE_INET
  } snd_ctl_type_t;
 
-typedef struct snd_ctl_callbacks {
+typedef struct _snd_ctl_callbacks {
        void *private_data;     /* may be used by an application */
        void (*rebuild) (snd_ctl_t *handle, void *private_data);
        void (*value) (snd_ctl_t *handle, void *private_data, snd_control_id_t * id);
@@ -40,8 +40,6 @@ int snd_defaults_pcm_device(void);
 int snd_defaults_rawmidi_card(void);
 int snd_defaults_rawmidi_device(void);
 
-int snd_ctl_hw_open(snd_ctl_t **handle, char *name, int card);
-int snd_ctl_shm_open(snd_ctl_t **handlep, char *name, char *socket, char *sname);
 snd_ctl_type_t snd_ctl_type(snd_ctl_t *handle);
 int snd_ctl_open(snd_ctl_t **handle, char *name);
 int snd_ctl_close(snd_ctl_t *handle);
@@ -82,10 +80,10 @@ struct list_head {
        ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
 
 
-typedef struct snd_hcontrol_list_stru snd_hcontrol_list_t;
-typedef struct snd_hcontrol_stru snd_hcontrol_t;
+typedef struct _snd_hcontrol_list snd_hcontrol_list_t;
+typedef struct _snd_hcontrol snd_hcontrol_t;
 
-struct snd_hcontrol_list_stru {
+struct _snd_hcontrol_list {
        unsigned int controls_offset;   /* W: first control ID to get */
        unsigned int controls_request;  /* W: count of control IDs to get */
        unsigned int controls_count;    /* R: count of available (set) controls */
@@ -93,7 +91,7 @@ struct snd_hcontrol_list_stru {
        snd_control_id_t *pids;         /* W: IDs */
 };
 
-struct snd_hcontrol_stru {
+struct _snd_hcontrol {
        snd_control_id_t id;    /* must be always on top */
        struct list_head list;  /* links for list of all hcontrols */
        int change: 1,          /* structure change */
index 6875e256890fb3b5e5b972a06ec412e7f5f40224..8ce91f67f94e989462bf967ad148d9a534b3cd9f 100644 (file)
@@ -46,3 +46,5 @@
 #define SND_TRANSPORT_TYPE_SHM 0
 #define SND_TRANSPORT_TYPE_TCP 1
 
+extern void snd_lib_error(const char *file, int line, const char *function, int err, const char *fmt, ...)  __attribute__ ((weak, format (printf, 5, 6)));
+
index 6446543b1b729c872844264b3693eb0eda4a9b22..ecd7958197195c3272e84ce6dbbaa73ac0eb747b 100644 (file)
@@ -14,7 +14,7 @@
 extern "C" {
 #endif
 
-typedef struct snd_hwdep snd_hwdep_t;
+typedef struct _snd_hwdep snd_hwdep_t;
 
 int snd_hwdep_open(snd_hwdep_t **handle, int card, int device, int mode);
 int snd_hwdep_close(snd_hwdep_t *handle);
index a9922d76ca14bbd7e945f045875249f27355bfb8..c1c29315b7e3111562ae83633d103c0a6c478a1b 100644 (file)
@@ -40,7 +40,7 @@ int snd_instr_simple_free(snd_instr_simple_t *simple);
 /* InterWave FFFF support */
 
 typedef void snd_instr_iwffff_t;
-typedef struct snd_iwffff_handle snd_iwffff_handle_t;
+typedef struct _snd_iwffff_handle snd_iwffff_handle_t;
 
 #ifdef __cplusplus
 extern "C" {
index f7eab69b29427352700e5b90f272db0dbff5caa3..c53de78c5812547f0b24d340ec7a1e0a5280b97a 100644 (file)
@@ -5,7 +5,7 @@
  *                                                                          *
  ****************************************************************************/
 
-typedef struct snd_mixer snd_mixer_t;
+typedef struct _snd_mixer snd_mixer_t;
 
 #ifdef __cplusplus
 extern "C" {
@@ -23,7 +23,7 @@ int snd_mixer_poll_descriptor(snd_mixer_t *handle);
  *  Simple (legacy) mixer API
  */
 
-typedef enum {
+typedef enum _snd_mixer_channel_id {
        SND_MIXER_CHN_FRONT_LEFT = 0,
        SND_MIXER_CHN_FRONT_RIGHT,
        SND_MIXER_CHN_FRONT_CENTER,
@@ -51,12 +51,12 @@ typedef enum {
 #define SND_MIXER_SCTCAP_JOINTLY_CAPTURE (1<<5)
 #define SND_MIXER_SCTCAP_EXCL_CAPTURE   (1<<6)
 
-typedef struct snd_mixer_sid {
+typedef struct _snd_mixer_sid {
        unsigned char name[60];
        unsigned int index;
 } snd_mixer_sid_t;
 
-typedef struct snd_mixer_simple_control_list {
+typedef struct _snd_mixer_simple_control_list {
        unsigned int controls_offset;   /* W: first control ID to get */
        unsigned int controls_request;  /* W: count of control IDs to get */
        unsigned int controls_count;    /* R: count of available (set) IDs */
@@ -65,7 +65,7 @@ typedef struct snd_mixer_simple_control_list {
         char reserved[50];
 } snd_mixer_simple_control_list_t;
 
-typedef struct snd_mixer_simple_control {
+typedef struct _snd_mixer_simple_control {
        snd_mixer_sid_t sid;            /* WR: simple control identification */
        unsigned int caps;              /* RO: capabilities */
        unsigned int channels;          /* RO: bitmap of active channels */
@@ -88,7 +88,7 @@ typedef struct snd_mixer_simple_control {
        } volume;                       /* RW */
 } snd_mixer_simple_control_t;
 
-typedef struct snd_mixer_simple_callbacks {
+typedef struct _snd_mixer_simple_callbacks {
        void *private_data;     /* may be used by an application */
        void (*rebuild) (snd_mixer_t *handle, void *private_data);
        void (*value) (snd_mixer_t *handle, void *private_data, snd_mixer_sid_t *id);
index 364ec5c4853222dfef5ad276a444a61e8e7fa4a7..c0ecee92aea3ad7cef9cd7c8e8d4de65e1c2eaf0 100644 (file)
 extern "C" {
 #endif
 
-typedef unsigned int bitset_t;
+typedef struct _snd_pcm snd_pcm_t;
 
-static inline size_t bitset_size(size_t nbits)
-{
-       return (nbits + sizeof(bitset_t) * 8 - 1) / (sizeof(bitset_t) * 8);
-}
-
-static inline bitset_t *bitset_alloc(size_t nbits)
-{
-       return (bitset_t*) calloc(bitset_size(nbits), sizeof(bitset_t));
-}
-       
-static inline void bitset_set(bitset_t *bitmap, unsigned int pos)
-{
-       size_t bits = sizeof(*bitmap) * 8;
-       bitmap[pos / bits] |= 1U << (pos % bits);
-}
-
-static inline void bitset_reset(bitset_t *bitmap, unsigned int pos)
-{
-       size_t bits = sizeof(*bitmap) * 8;
-       bitmap[pos / bits] &= ~(1U << (pos % bits));
-}
-
-static inline int bitset_get(bitset_t *bitmap, unsigned int pos)
-{
-       size_t bits = sizeof(*bitmap) * 8;
-       return !!(bitmap[pos / bits] & (1U << (pos % bits)));
-}
-
-static inline void bitset_copy(bitset_t *dst, bitset_t *src, size_t nbits)
-{
-       memcpy(dst, src, bitset_size(nbits) * sizeof(bitset_t));
-}
-
-static inline void bitset_and(bitset_t *dst, bitset_t *bs, size_t nbits)
-{
-       bitset_t *end = dst + bitset_size(nbits);
-       while (dst < end)
-               *dst++ &= *bs++;
-}
-
-static inline void bitset_or(bitset_t *dst, bitset_t *bs, size_t nbits)
-{
-       bitset_t *end = dst + bitset_size(nbits);
-       while (dst < end)
-               *dst++ |= *bs++;
-}
-
-static inline void bitset_zero(bitset_t *dst, size_t nbits)
-{
-       bitset_t *end = dst + bitset_size(nbits);
-       while (dst < end)
-               *dst++ = 0;
-}
-
-static inline void bitset_one(bitset_t *dst, size_t nbits)
-{
-       bitset_t *end = dst + bitset_size(nbits);
-       while (dst < end)
-               *dst++ = ~(bitset_t)0;
-}
-
-static inline size_t hweight32(bitset_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);
-}
-
-/* Count bits set */
-static inline size_t bitset_count(bitset_t *bitset, size_t nbits)
-{
-       bitset_t *end = bitset + bitset_size(nbits) - 1;
-       size_t bits = sizeof(*bitset) * 8;
-       size_t count = 0;
-       while (bitset < end)
-               count += hweight32(*bitset++);
-       count += hweight32(*bitset & ((1U << (nbits % bits)) - 1));
-       return count;
-}
-
-typedef struct snd_pcm snd_pcm_t;
-typedef struct snd_pcm_loopback snd_pcm_loopback_t;
-
-typedef enum {
+typedef enum _snd_pcm_type {
        SND_PCM_TYPE_HW,
        SND_PCM_TYPE_MULTI,
        SND_PCM_TYPE_FILE,
@@ -119,16 +34,28 @@ typedef enum {
        SND_PCM_TYPE_LBSERVER,
 } snd_pcm_type_t;
 
-extern void snd_pcm_error(const char *file, int line, const char *function, int err, const char *fmt, ...)  __attribute__ ((weak, format (printf, 5, 6)));
+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 */
+       unsigned int step;              /* samples distance in bits */
+} snd_pcm_channel_area_t;
 
 int snd_pcm_open(snd_pcm_t **pcm, char *name, 
                 int stream, int mode);
 
 /* Obsolete functions */
-int snd_pcm_hw_open_subdevice(snd_pcm_t **pcm, int card, int device, int subdevice, int stream, int mode);
-int snd_pcm_hw_open_device(snd_pcm_t **pcm, int card, int device, int stream, int mode);
-int snd_pcm_plug_open_subdevice(snd_pcm_t **pcm, int card, int device, int subdevice, int stream, int mode);
-int snd_pcm_plug_open_device(snd_pcm_t **pcm, int card, int device, int stream, int mode);
 #define snd_pcm_write snd_pcm_writei
 #define snd_pcm_read snd_pcm_readi
 ssize_t snd_pcm_writev(snd_pcm_t *pcm, const struct iovec *vector, int count);
@@ -141,12 +68,11 @@ 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_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info);
-int snd_pcm_params(snd_pcm_t *pcm, snd_pcm_params_t *params);
-int snd_pcm_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup);
-int snd_pcm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info);
-int snd_pcm_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params);
-int snd_pcm_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup);
+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_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);
 int snd_pcm_status(snd_pcm_t *pcm, snd_pcm_status_t *status);
 int snd_pcm_prepare(snd_pcm_t *pcm);
 int snd_pcm_start(snd_pcm_t *pcm);
@@ -160,23 +86,35 @@ ssize_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, size_t size);
 ssize_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, size_t size);
 ssize_t snd_pcm_writen(snd_pcm_t *pcm, void **bufs, size_t size);
 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_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);
 int snd_pcm_dump_status(snd_pcm_status_t *status, FILE *fp);
 int snd_pcm_link(snd_pcm_t *pcm1, snd_pcm_t *pcm2);
 int snd_pcm_unlink(snd_pcm_t *pcm);
 
-int snd_pcm_channels_mask(snd_pcm_t *pcm, bitset_t *cmask);
 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);
-
+int snd_pcm_hw_params_rules(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                           unsigned int count, int *rules);
+int snd_pcm_hw_params_rulesv(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, ...);
+int snd_pcm_hw_info_rules(snd_pcm_t *pcm, 
+                         snd_pcm_hw_info_t *info,
+                         snd_pcm_hw_params_t *params,
+                         unsigned int count, int *rules);
+int snd_pcm_hw_info_rulesv(snd_pcm_t *pcm, 
+                          snd_pcm_hw_info_t *info,
+                          snd_pcm_hw_params_t *params, ...);
 
 /* mmap */
-int snd_pcm_mmap(snd_pcm_t *pcm);
-int snd_pcm_munmap(snd_pcm_t *pcm);
 snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm);
-int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *stopped_areas, snd_pcm_channel_area_t *running_areas);
+snd_pcm_channel_area_t *snd_pcm_mmap_running_areas(snd_pcm_t *pcm);
+snd_pcm_channel_area_t *snd_pcm_mmap_stopped_areas(snd_pcm_t *pcm);
 ssize_t snd_pcm_mmap_forward(snd_pcm_t *pcm, size_t size);
 size_t snd_pcm_mmap_offset(snd_pcm_t *pcm);
 size_t snd_pcm_mmap_xfer(snd_pcm_t *pcm, size_t size);
index 2d4a65b785d04f72650dab3cfaa299cce9b0bcba..f75ef0c28f70196a60ce2ea7dbc638310e8546ee 100644 (file)
@@ -5,31 +5,37 @@
  *                                                                          *
  ****************************************************************************/
 
-#define SND_RAWMIDI_OPEN_OUTPUT                (O_WRONLY)
-#define SND_RAWMIDI_OPEN_OUTPUT_APPEND (O_WRONLY|O_APPEND|O_NONBLOCK)
-#define SND_RAWMIDI_OPEN_INPUT         (O_RDONLY)
-#define SND_RAWMIDI_OPEN_DUPLEX                (O_RDWR)
-#define SND_RAWMIDI_OPEN_DUPLEX_APPEND (O_RDWR|O_APPEND|O_NONBLOCK)
-#define SND_RAWMIDI_OPEN_NONBLOCK      (O_NONBLOCK)
+#define SND_RAWMIDI_OPEN_OUTPUT        (1<<SND_RAWMIDI_STREAM_OUTPUT)
+#define SND_RAWMIDI_OPEN_INPUT (1<<SND_RAWMIDI_STREAM_INPUT)
+#define SND_RAWMIDI_OPEN_DUPLEX        (SND_RAWMIDI_OPEN_OUTPUT|SND_RAWMIDI_OPEN_INPUT)
+
+#define SND_RAWMIDI_APPEND     1
+#define SND_RAWMIDI_NONBLOCK   2
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-typedef struct snd_rawmidi snd_rawmidi_t;
+typedef struct _snd_rawmidi snd_rawmidi_t;
+
+typedef enum _snd_rawmidi_type {
+       SND_RAWMIDI_TYPE_HW,
+       SND_RAWMIDI_TYPE_SHM,
+       SND_RAWMIDI_TYPE_INET,
+} snd_rawmidi_type_t;
 
-int snd_rawmidi_open_subdevice(snd_rawmidi_t **handle, int card, int device, int subdevice, int mode);
-int snd_rawmidi_open(snd_rawmidi_t **handle, int card, int device, int mode);
+int snd_rawmidi_open(snd_rawmidi_t **handle, char *name, int streams, int mode);
 int snd_rawmidi_close(snd_rawmidi_t *handle);
 int snd_rawmidi_poll_descriptor(snd_rawmidi_t *handle);
-int snd_rawmidi_block_mode(snd_rawmidi_t *handle, int enable);
+int snd_rawmidi_nonblock(snd_rawmidi_t *handle, int nonblock);
 int snd_rawmidi_info(snd_rawmidi_t *handle, snd_rawmidi_info_t * info);
 int snd_rawmidi_params(snd_rawmidi_t *handle, snd_rawmidi_params_t * params);
 int snd_rawmidi_status(snd_rawmidi_t *handle, snd_rawmidi_status_t * status);
 int snd_rawmidi_output_drop(snd_rawmidi_t *handle);
 int snd_rawmidi_output_drain(snd_rawmidi_t *handle);
 int snd_rawmidi_input_drain(snd_rawmidi_t *handle);
-int snd_rawmidi_stream_drain(snd_rawmidi_t *handle, int channel);
+int snd_rawmidi_drain(snd_rawmidi_t *handle, int channel);
+int snd_rawmidi_drop(snd_rawmidi_t *handle, int channel);
 ssize_t snd_rawmidi_write(snd_rawmidi_t *handle, const void *buffer, size_t size);
 ssize_t snd_rawmidi_read(snd_rawmidi_t *handle, void *buffer, size_t size);
 
index 2ba07c6c569383a0dff1338585741408bc68afdc..b2a566f5803e07519430b3a3f865d824325f5c3a 100644 (file)
@@ -5,20 +5,28 @@
  *                                                                          *
  ****************************************************************************/
 
-#define SND_SEQ_OPEN_OUT       (O_WRONLY)
-#define SND_SEQ_OPEN_IN                (O_RDONLY)
-#define SND_SEQ_OPEN           (O_RDWR)
+#define SND_SEQ_OPEN_OUTPUT    1
+#define SND_SEQ_OPEN_INPUT     2
+#define SND_SEQ_OPEN_DUPLEX    (SND_SEQ_OPEN_OUTPUT|SND_SEQ_OPEN_INPUT)
+
+#define SND_SEQ_NONBLOCK       1
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-typedef struct snd_seq snd_seq_t;
+typedef enum _snd_seq_type {
+       SND_SEQ_TYPE_HW,
+       SND_SEQ_TYPE_SHM,
+       SND_SEQ_TYPE_INET,
+} snd_seq_type_t;
+
+typedef struct _snd_seq snd_seq_t;
 
-int snd_seq_open(snd_seq_t **handle, int mode);
+int snd_seq_open(snd_seq_t **handle, char *name, int streams, int mode);
 int snd_seq_close(snd_seq_t *handle);
 int snd_seq_poll_descriptor(snd_seq_t *handle);
-int snd_seq_block_mode(snd_seq_t *handle, int enable);
+int snd_seq_nonblock(snd_seq_t *handle, int nonblock);
 int snd_seq_client_id(snd_seq_t *handle);
 int snd_seq_output_buffer_size(snd_seq_t *handle);
 int snd_seq_input_buffer_size(snd_seq_t *handle);
index a406d9c00d5c72091b6ca904bb47c5a8991e2568..d01c57ebce3ee9a2dc8cef1b36f81a927f1e0377 100644 (file)
@@ -9,7 +9,7 @@
 extern "C" {
 #endif
 
-typedef struct snd_timer snd_timer_t;
+typedef struct _snd_timer snd_timer_t;
 
 int snd_timer_open(snd_timer_t **handle);
 int snd_timer_close(snd_timer_t *handle);
@@ -18,7 +18,6 @@ int snd_timer_general_info(snd_timer_t *handle, snd_timer_general_info_t * info)
 int snd_timer_select(snd_timer_t *handle, snd_timer_select_t *tselect);
 int snd_timer_info(snd_timer_t *handle, snd_timer_info_t *timer);
 int snd_timer_params(snd_timer_t *handle, snd_timer_params_t *params);
-int snd_timer_setup(snd_timer_t *handle, snd_timer_setup_t *setup);
 int snd_timer_status(snd_timer_t *handle, snd_timer_status_t *status);
 int snd_timer_start(snd_timer_t *handle);
 int snd_timer_stop(snd_timer_t *handle);
index b139e0c89b2d9348e92cca1ce0a31df521ba6f8c..064e6dbf292f5875db1c03763dd50973183c46dc 100644 (file)
@@ -27,6 +27,7 @@
 #include <ctype.h>
 #include <fcntl.h>
 #include <sys/ioctl.h>
+#include "control_local.h"
 #include "asoundlib.h"
 
 #define SND_FILE_CONTROL       "/dev/snd/controlC%i"
index 40c900759552cc4ad3f70dadc5b40514865c95e5..2aa84f2e894e31d83a25c715843f430d774e5fd0 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdarg.h>
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
@@ -170,8 +171,16 @@ int snd_ctl_open(snd_ctl_t **ctlp, char *name)
                return err;
        err = snd_config_searchv(snd_config, &ctl_conf, "ctl", name, 0);
        if (err < 0) {
-               int cardno = snd_card_get_index(name);
-               return snd_ctl_hw_open(ctlp, name, cardno);
+               int card;
+               char socket[256], sname[256];
+               err = sscanf(name, "hw:%d", &card);
+               if (err == 1)
+                       return snd_ctl_hw_open(ctlp, NULL, card);
+               err = sscanf(name, "shm:%256s,%256s", socket, sname);
+               if (err == 2)
+                       return snd_ctl_shm_open(ctlp, NULL, socket, sname);
+               ERR("Unknown control %s", name);
+               return -ENOENT;
        }
        if (snd_config_type(ctl_conf) != SND_CONFIG_TYPE_COMPOUND)
                return -EINVAL;
@@ -182,8 +191,6 @@ int snd_ctl_open(snd_ctl_t **ctlp, char *name)
        if (err < 0)
                return err;
        err = snd_config_searchv(snd_config, &type_conf, "ctltype", str, 0);
-       if (err < 0)
-               return err;
        snd_config_foreach(i, type_conf) {
                snd_config_t *n = snd_config_entry(i);
                if (strcmp(n->id, "comment") == 0)
@@ -215,3 +222,4 @@ int snd_ctl_open(snd_ctl_t **ctlp, char *name)
                return -ENXIO;
        return open_func(ctlp, name, ctl_conf);
 }
+
index eb805ae98415d02c30480d523ea6901d5d2baf7e..152e99c771efa974eaf96558c5ba9d5f65ddb14c 100644 (file)
@@ -140,7 +140,7 @@ static int snd_ctl_hw_read(snd_ctl_t *handle, snd_ctl_event_t *event)
        return read(hw->fd, event, sizeof(*event));
 }
 
-struct snd_ctl_ops snd_ctl_hw_ops = {
+snd_ctl_ops_t snd_ctl_hw_ops = {
        close: snd_ctl_hw_close,
        poll_descriptor: snd_ctl_hw_poll_descriptor,
        hw_info: snd_ctl_hw_hw_info,
index 8f912ccb7a6745db9a68688cb997dd42e2a8d9fb..3cfb7f55a2ddf7c7f065bc15d1cb3c5f691ce33d 100644 (file)
 #include "asoundlib.h"
 #include "list.h"
 
-struct snd_ctl_ops {
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
+#define ERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, __VA_ARGS__)
+#define SYSERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, __VA_ARGS__)
+#else
+#define ERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, ##args)
+#define SYSERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, ##args)
+#endif
+
+typedef struct {
        int (*close)(snd_ctl_t *handle);
        int (*poll_descriptor)(snd_ctl_t *handle);
        int (*hw_info)(snd_ctl_t *handle, snd_ctl_hw_info_t *info);
@@ -37,13 +45,13 @@ struct snd_ctl_ops {
        int (*rawmidi_info)(snd_ctl_t *handle, snd_rawmidi_info_t * info);
        int (*rawmidi_prefer_subdevice)(snd_ctl_t *handle, int subdev);
        int (*read)(snd_ctl_t *handle, snd_ctl_event_t *event);
-};
+} snd_ctl_ops_t;
 
 
-struct snd_ctl {
+struct _snd_ctl {
        char *name;
        snd_ctl_type_t type;
-       struct snd_ctl_ops *ops;
+       snd_ctl_ops_t *ops;
        void *private;
        int hcount;
        int herr;
@@ -56,3 +64,6 @@ struct snd_ctl {
        snd_ctl_hcallback_add_t *callback_add;
        void *callback_add_private_data;
 };
+
+int snd_ctl_hw_open(snd_ctl_t **handle, char *name, int card);
+int snd_ctl_shm_open(snd_ctl_t **handlep, char *name, char *socket, char *sname);
index 02210c748aa294fb9cd6ad00dd3b5164c7c87726..e8086f1933126eefacec4fdf2a5d3c79334cfdc4 100644 (file)
@@ -266,7 +266,7 @@ static int snd_ctl_shm_read(snd_ctl_t *ctl, snd_ctl_event_t *event)
        return err;
 }
 
-struct snd_ctl_ops snd_ctl_shm_ops = {
+snd_ctl_ops_t snd_ctl_shm_ops = {
        close: snd_ctl_shm_close,
        poll_descriptor: snd_ctl_shm_poll_descriptor,
        hw_info: snd_ctl_shm_hw_info,
index 47fb5ec899532bfe96d3657a9002ff29fa7b5c76..b5871f9a4689a172d47dcbdcecffa98f9ef4ba7e 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdarg.h>
 #include <string.h>
 #include "asoundlib.h"
 
@@ -42,3 +43,16 @@ const char *snd_strerror(int errnum)
                 return "Unknown error";
        return snd_error_codes[errnum];
 }
+
+void snd_lib_error(const char *file, int line, const char *function, int err, const char *fmt, ...)
+{
+       va_list arg;
+       va_start(arg, fmt);
+       fprintf(stderr, "ALSA lib %s:%i:(%s) ", file, line, function);
+       vfprintf(stderr, fmt, arg);
+       if (err)
+               fprintf(stderr, ": %s", snd_strerror(err));
+       putc('\n', stderr);
+       va_end(arg);
+}
+
index e644053666e2256c5b0245ed6de153d1eb5ce44b..d8e428f9c843ea091740ee19b0f318e547e88604 100644 (file)
@@ -31,7 +31,7 @@
 #define SND_FILE_HWDEP "/dev/snd/hwC%iD%i"
 #define SND_HWDEP_VERSION_MAX  SND_PROTOCOL_VERSION(1, 0, 0)
 
-struct snd_hwdep {
+struct _snd_hwdep {
        int card;
        int device;
        int fd;
index 90b3f5856b0b58fa00a42f02b35688832bae15bc..383b40ac21e3fc386a89a9768e09c052641966af 100644 (file)
@@ -171,7 +171,7 @@ struct envelope_record {
 #define copyright_header IW_ID_VALUE('C', 'P', 'R', 'T')
 #endif
 
-struct snd_iwffff_handle {
+struct _snd_iwffff_handle {
        int rom;
        unsigned char *fff_data;
        size_t fff_size;
index 956be64e1fbc68fe7f6ececc2b8cc34431637ffd..a5eb3adb2fd261f36ff417f7298a7721bdd03d34 100644 (file)
@@ -23,8 +23,8 @@
 #include "asoundlib.h"
 #include "list.h"
 
-typedef struct mixer_simple mixer_simple_t;
-typedef struct mixer_simple_hcontrol_private mixer_simple_hcontrol_private_t;
+typedef struct _mixer_simple mixer_simple_t;
+typedef struct _mixer_simple_hcontrol_private mixer_simple_hcontrol_private_t;
 
 typedef int (mixer_simple_get_t) (snd_mixer_t *handle, mixer_simple_t *simple, snd_mixer_simple_control_t *control);
 typedef int (mixer_simple_put_t) (snd_mixer_t *handle, mixer_simple_t *simple, snd_mixer_simple_control_t *control);
@@ -43,7 +43,7 @@ typedef int (mixer_simple_event_add_t) (snd_mixer_t *handle, snd_hcontrol_t *hco
 #define MIXER_PRESENT_CAPTURE_ROUTE    (1<<10)
 #define MIXER_PRESENT_CAPTURE_SOURCE   (1<<11)
 
-struct mixer_simple {
+struct _mixer_simple {
        /* this may be moved to a private area */
        unsigned int present;           /* present controls */
        unsigned int global_values;
@@ -74,11 +74,11 @@ struct mixer_simple {
        unsigned long private_value;
 };
 
-struct mixer_simple_hcontrol_private {
+struct _mixer_simple_hcontrol_private {
        void *simples;                  /* list of associated hcontrols */
 };
   
-struct snd_mixer {
+struct _snd_mixer {
        snd_ctl_t *ctl_handle;
        int simple_valid;
        int simple_changes;             /* total number of changes */
index 71fd88279b5d4bfb105671539e3a8f757cb6e79e..b8285fa8944221d0a0998bfcee724b73dd4f3ddc 100644 (file)
@@ -28,6 +28,7 @@
 #include <sys/poll.h>
 #include <sys/shm.h>
 #include <sys/mman.h>
+#include <limits.h>
 #include <dlfcn.h>
 #include "pcm_local.h"
 #include "list.h"
@@ -38,7 +39,7 @@ snd_pcm_type_t snd_pcm_type(snd_pcm_t *pcm)
        return pcm->type;
 }
 
-snd_pcm_type_t snd_pcm(snd_pcm_t *pcm)
+snd_pcm_type_t snd_pcm_stream(snd_pcm_t *pcm)
 {
        assert(pcm);
        return pcm->stream;
@@ -49,23 +50,23 @@ int snd_pcm_close(snd_pcm_t *pcm)
        int ret = 0;
        int err;
        assert(pcm);
-       if (pcm->valid_setup) {
+       if (pcm->setup) {
                if (pcm->mode & SND_PCM_NONBLOCK)
                        snd_pcm_drop(pcm);
                else
                        snd_pcm_drain(pcm);
        }
-       if (pcm->mmap_info) {
+       if (pcm->mmap_channels) {
                if ((err = snd_pcm_munmap(pcm)) < 0)
                        ret = err;
        }
        if ((err = pcm->ops->close(pcm->op_arg)) < 0)
                ret = err;
-       pcm->valid_setup = 0;
+       pcm->setup = 0;
        if (pcm->name)
                free(pcm->name);
        free(pcm);
-       return ret;
+       return 0;
 }      
 
 int snd_pcm_nonblock(snd_pcm_t *pcm, int nonblock)
@@ -93,84 +94,176 @@ int snd_pcm_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
        return pcm->ops->info(pcm->op_arg, info);
 }
 
-int snd_pcm_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info)
-{
-       assert(pcm && info);
-       return pcm->ops->params_info(pcm->op_arg, info);
-}
-
-int snd_pcm_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup)
+int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info)
 {
        int err;
-       assert(pcm && setup);
-       if (pcm->valid_setup) {
-               *setup = pcm->setup;
-               return 0;
-       }
-       if ((err = pcm->ops->setup(pcm->op_arg, &pcm->setup)) < 0)
-               return err;
-       *setup = pcm->setup;
-       pcm->bits_per_sample = snd_pcm_format_physical_width(setup->format.sfmt);
-        pcm->bits_per_frame = pcm->bits_per_sample * setup->format.channels;
-       pcm->valid_setup = 1;
-       return 0;
+       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;
 }
 
-int snd_pcm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
+void snd_pcm_hw_params_to_info(snd_pcm_hw_params_t *params, snd_pcm_hw_info_t *info)
 {
-       assert(pcm && info);
-       assert(pcm->valid_setup);
-       assert(info->channel < pcm->setup.format.channels);
-       return pcm->ops->channel_info(pcm->op_arg, info);
+       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_size_min = info->fragment_size_max = params->fragment_size;
+       info->fragments_min = info->fragments_max = params->fragments;
 }
 
-int snd_pcm_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
+void snd_pcm_hw_info_to_params(snd_pcm_hw_info_t *info, snd_pcm_hw_params_t *params)
 {
-       assert(pcm && params);
-       assert(pcm->valid_setup);
-       assert(params->channel < pcm->setup.format.channels);
-       return pcm->ops->channel_params(pcm->op_arg, params);
+       assert(info->access_mask && 
+              !(info->access_mask & (info->access_mask - 1)));
+       params->access = ffs(info->access_mask) - 1;
+       assert(info->format_mask && 
+              !(info->format_mask & (info->format_mask - 1)));
+       params->format = ffs(info->format_mask) - 1;
+       assert(info->subformat_mask && 
+              !(info->subformat_mask & (info->subformat_mask - 1)));
+       params->subformat = ffs(info->subformat_mask) - 1;
+       assert(info->channels_min == info->channels_max);
+       params->channels = info->channels_min;
+       assert(info->rate_min == info->rate_max);
+       params->rate = info->rate_min;
+       assert(info->fragment_size_min == info->fragment_size_max);
+       params->fragment_size = info->fragment_size_min;
+       assert(info->fragments_min == info->fragments_max);
+       params->fragments = info->fragments_min;
 }
 
-int snd_pcm_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
+void snd_pcm_hw_info_to_params_fail(snd_pcm_hw_info_t *info, snd_pcm_hw_params_t *params)
 {
-       assert(pcm && setup);
-       assert(pcm->valid_setup);
-       assert(setup->channel < pcm->setup.format.channels);
-       return pcm->ops->channel_setup(pcm->op_arg, setup);
+       unsigned int f = 0;
+       if (info->access_mask == 0)
+               f |= SND_PCM_HW_PARBIT_ACCESS;
+       if (info->format_mask == 0)
+               f |= SND_PCM_HW_PARBIT_FORMAT;
+       if (info->subformat_mask == 0)
+               f |= SND_PCM_HW_PARBIT_SUBFORMAT;
+       if (info->channels_min > info->channels_max)
+               f |= SND_PCM_HW_PARBIT_CHANNELS;
+       if (info->rate_min > info->rate_max)
+               f |= SND_PCM_HW_PARBIT_RATE;
+       if (info->fragment_size_min > info->fragment_size_max)
+               f |= SND_PCM_HW_PARBIT_FRAGMENT_SIZE;
+       if (info->fragments_min > info->fragments_max)
+               f |= SND_PCM_HW_PARBIT_FRAGMENTS;
+       assert(f);
+       params->fail_mask = f;
 }
 
-int _snd_pcm_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
+int _snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        int err;
-       snd_pcm_setup_t setup;
-       if ((err = pcm->ops->params(pcm->op_arg, params)) < 0)
+       snd_pcm_hw_info_t info;
+       
+       snd_pcm_hw_params_to_info(params, &info);
+       err = snd_pcm_hw_info(pcm, &info);
+       if (err < 0) {
+               snd_pcm_hw_info_to_params_fail(&info, params);
                return err;
-       pcm->valid_setup = 0;
-       return snd_pcm_setup(pcm, &setup);
+       }
+       snd_pcm_hw_info_to_params(&info, params);
+       if ((err = pcm->ops->hw_params(pcm->op_arg, params)) < 0)
+               return err;
+       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_master = info.rate_master;
+       pcm->rate_divisor = info.rate_divisor;
+       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;
+       return 0;
 }
 
-int snd_pcm_params_mmap(snd_pcm_t *pcm, snd_pcm_params_t *params)
+int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
 {
        int err;
-       if (pcm->mmap_info) {
+       assert(pcm && params);
+       if (pcm->setup && pcm->mmap_channels && 
+           (pcm->mmap_rw || 
+            (pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED ||
+             pcm->access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED ||
+             pcm->access == SND_PCM_ACCESS_MMAP_COMPLEX))) {
                err = snd_pcm_munmap(pcm);
                if (err < 0)
                        return err;
        }
-       err = _snd_pcm_params(pcm, params);
-       if (pcm->valid_setup)
-               snd_pcm_mmap(pcm);
+       err = _snd_pcm_hw_params(pcm, params);
+       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_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
+int snd_pcm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
 {
+       int err;
        assert(pcm && params);
-       if (pcm->mmap_auto)
-               return snd_pcm_params_mmap(pcm, params);
-       assert(!pcm->mmap_info);
-       return _snd_pcm_params(pcm, params);
+       assert(pcm->setup);
+       if ((err = pcm->ops->sw_params(pcm->op_arg, params)) < 0)
+               return err;
+       pcm->start_mode = params->start_mode;
+       pcm->ready_mode = params->ready_mode;
+       pcm->xrun_mode = params->xrun_mode;
+       pcm->avail_min = params->avail_min;
+       pcm->xfer_min = params->xfer_min;
+       pcm->xfer_align = params->xfer_align;
+       pcm->time = params->time;
+       pcm->boundary = params->boundary;
+       return 0;
+}
+
+int snd_pcm_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t *params)
+{
+       assert(pcm && params);
+       return pcm->ops->dig_params(pcm->op_arg, params);
+}
+
+int snd_pcm_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t *info)
+{
+       assert(pcm && info);
+       return pcm->ops->dig_info(pcm->op_arg, info);
 }
 
 int snd_pcm_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
@@ -188,44 +281,42 @@ int snd_pcm_state(snd_pcm_t *pcm)
 int snd_pcm_delay(snd_pcm_t *pcm, ssize_t *delayp)
 {
        assert(pcm);
-       assert(pcm->valid_setup);
+       assert(pcm->setup);
        return pcm->fast_ops->delay(pcm->fast_op_arg, delayp);
 }
 
 int snd_pcm_prepare(snd_pcm_t *pcm)
 {
        assert(pcm);
-       assert(pcm->valid_setup);
+       assert(pcm->setup);
        return pcm->fast_ops->prepare(pcm->fast_op_arg);
 }
 
 int snd_pcm_start(snd_pcm_t *pcm)
 {
        assert(pcm);
-       assert(pcm->valid_setup);
-       assert(pcm->stream != SND_PCM_STREAM_PLAYBACK ||
-              snd_pcm_mmap_playback_hw_avail(pcm) > 0);
+       assert(pcm->setup);
        return pcm->fast_ops->start(pcm->fast_op_arg);
 }
 
 int snd_pcm_drop(snd_pcm_t *pcm)
 {
        assert(pcm);
-       assert(pcm->valid_setup);
+       assert(pcm->setup);
        return pcm->fast_ops->drop(pcm->fast_op_arg);
 }
 
 int snd_pcm_drain(snd_pcm_t *pcm)
 {
        assert(pcm);
-       assert(pcm->valid_setup);
+       assert(pcm->setup);
        return pcm->fast_ops->drain(pcm->fast_op_arg);
 }
 
 int snd_pcm_pause(snd_pcm_t *pcm, int enable)
 {
        assert(pcm);
-       assert(pcm->valid_setup);
+       assert(pcm->setup);
        return pcm->fast_ops->pause(pcm->fast_op_arg, enable);
 }
 
@@ -233,7 +324,7 @@ int snd_pcm_pause(snd_pcm_t *pcm, int enable)
 ssize_t snd_pcm_rewind(snd_pcm_t *pcm, size_t frames)
 {
        assert(pcm);
-       assert(pcm->valid_setup);
+       assert(pcm->setup);
        assert(frames > 0);
        return pcm->fast_ops->rewind(pcm->fast_op_arg, frames);
 }
@@ -242,12 +333,12 @@ int snd_pcm_set_avail_min(snd_pcm_t *pcm, size_t frames)
 {
        int err;
        assert(pcm);
-       assert(pcm->valid_setup);
+       assert(pcm->setup);
        assert(frames > 0);
        err = pcm->fast_ops->set_avail_min(pcm->fast_op_arg, frames);
        if (err < 0)
                return err;
-       pcm->setup.avail_min = frames;
+       pcm->avail_min = frames;
        return 0;
 }
 
@@ -255,9 +346,8 @@ ssize_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, size_t size)
 {
        assert(pcm);
        assert(size == 0 || buffer);
-       assert(pcm->valid_setup);
-       assert(pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED);
-       assert(!pcm->mmap_info || pcm->mmap_auto);
+       assert(pcm->setup);
+       assert(pcm->access == SND_PCM_ACCESS_RW_INTERLEAVED);
        return _snd_pcm_writei(pcm, buffer, size);
 }
 
@@ -265,9 +355,8 @@ ssize_t snd_pcm_writen(snd_pcm_t *pcm, void **bufs, size_t size)
 {
        assert(pcm);
        assert(size == 0 || bufs);
-       assert(pcm->valid_setup);
-       assert(pcm->setup.xfer_mode == SND_PCM_XFER_NONINTERLEAVED);
-       assert(!pcm->mmap_info || pcm->mmap_auto);
+       assert(pcm->setup);
+       assert(pcm->access == SND_PCM_ACCESS_RW_NONINTERLEAVED);
        return _snd_pcm_writen(pcm, bufs, size);
 }
 
@@ -275,9 +364,8 @@ ssize_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, size_t size)
 {
        assert(pcm);
        assert(size == 0 || buffer);
-       assert(pcm->valid_setup);
-       assert(pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED);
-       assert(!pcm->mmap_info || pcm->mmap_auto);
+       assert(pcm->setup);
+       assert(pcm->access == SND_PCM_ACCESS_RW_INTERLEAVED);
        return _snd_pcm_readi(pcm, buffer, size);
 }
 
@@ -285,9 +373,8 @@ ssize_t snd_pcm_readn(snd_pcm_t *pcm, void **bufs, size_t size)
 {
        assert(pcm);
        assert(size == 0 || bufs);
-       assert(pcm->valid_setup);
-       assert(pcm->setup.xfer_mode == SND_PCM_XFER_NONINTERLEAVED);
-       assert(!pcm->mmap_info || pcm->mmap_auto);
+       assert(pcm->setup);
+       assert(pcm->access == SND_PCM_ACCESS_RW_NONINTERLEAVED);
        return _snd_pcm_readn(pcm, bufs, size);
 }
 
@@ -296,8 +383,8 @@ ssize_t snd_pcm_writev(snd_pcm_t *pcm, const struct iovec *vector, int count)
        void **bufs;
        int k;
        assert(pcm);
-       assert(pcm->valid_setup);
-       assert((int)pcm->setup.format.channels == count);
+       assert(pcm->setup);
+       assert((int)pcm->channels == count);
        bufs = alloca(sizeof(*bufs) * count);
        for (k = 0; k < count; ++k) {
                bufs[k] = vector[k].iov_base;
@@ -311,8 +398,8 @@ ssize_t snd_pcm_readv(snd_pcm_t *pcm, const struct iovec *vector, int count)
        void **bufs;
        int k;
        assert(pcm);
-       assert(pcm->valid_setup);
-       assert((int)pcm->setup.format.channels == count);
+       assert(pcm->setup);
+       assert((int)pcm->channels == count);
        bufs = alloca(sizeof(*bufs) * count);
        for (k = 0; k < count; ++k) {
                bufs[k] = vector[k].iov_base;
@@ -400,80 +487,329 @@ static const char *assoc(int value, assoc_t *alist)
 #define STREAM(v) { SND_PCM_STREAM_##v, #v, #v }
 #define READY(v) { SND_PCM_READY_##v, #v, #v }
 #define XRUN(v) { SND_PCM_XRUN_##v, #v, #v }
-#define XFER(v) { SND_PCM_XFER_##v, #v, #v }
-#define MMAP(v) { SND_PCM_MMAP_##v, #v, #v }
-#define SFMT(v, d) { SND_PCM_SFMT_##v, #v, d }
+#define ACCESS(v) { SND_PCM_ACCESS_##v, #v, #v }
+#define FORMAT(v, d) { SND_PCM_FORMAT_##v, #v, d }
+#define SUBFORMAT(v, d) { SND_PCM_SUBFORMAT_##v, #v, d }
 #define XRUN_ACT(v) { SND_PCM_XRUN_ACT_##v, #v, #v }
 #define START(v) { SND_PCM_START_##v, #v, #v }
 #define FILL(v) { SND_PCM_FILL_##v, #v, #v }
+#define HW_PARAM(v) { SND_PCM_HW_PARAM_##v, #v, #v }
+#define SW_PARAM(v) { SND_PCM_SW_PARAM_##v, #v, #v }
 #define END { 0, NULL, NULL }
 
-static assoc_t states[] = { STATE(OPEN), STATE(SETUP), STATE(PREPARED),
-                           STATE(RUNNING), STATE(XRUN), STATE(PAUSED), END };
-static assoc_t streams[] = { STREAM(PLAYBACK), STREAM(CAPTURE), END };
-static assoc_t xruns[] = { XRUN(ASAP), XRUN(FRAGMENT), XRUN(NONE), END };
-static assoc_t fmts[] = {
-       SFMT(S8, "Signed 8-bit"), 
-       SFMT(U8, "Unsigned 8-bit"),
-       SFMT(S16_LE, "Signed 16-bit Little Endian"),
-       SFMT(S16_BE, "Signed 16-bit Big Endian"),
-       SFMT(U16_LE, "Unsigned 16-bit Little Endian"),
-       SFMT(U16_BE, "Unsigned 16-bit Big Endian"),
-       SFMT(S24_LE, "Signed 24-bit Little Endian"),
-       SFMT(S24_BE, "Signed 24-bit Big Endian"),
-       SFMT(U24_LE, "Unsigned 24-bit Little Endian"),
-       SFMT(U24_BE, "Unsigned 24-bit Big Endian"),
-       SFMT(S32_LE, "Signed 32-bit Little Endian"),
-       SFMT(S32_BE, "Signed 32-bit Big Endian"),
-       SFMT(U32_LE, "Unsigned 32-bit Little Endian"),
-       SFMT(U32_BE, "Unsigned 32-bit Big Endian"),
-       SFMT(FLOAT_LE, "Float Little Endian"),
-       SFMT(FLOAT_BE, "Float Big Endian"),
-       SFMT(FLOAT64_LE, "Float64 Little Endian"),
-       SFMT(FLOAT64_BE, "Float64 Big Endian"),
-       SFMT(IEC958_SUBFRAME_LE, "IEC-958 Little Endian"),
-       SFMT(IEC958_SUBFRAME_BE, "IEC-958 Big Endian"),
-       SFMT(MU_LAW, "Mu-Law"),
-       SFMT(A_LAW, "A-Law"),
-       SFMT(IMA_ADPCM, "Ima-ADPCM"),
-       SFMT(MPEG, "MPEG"),
-       SFMT(GSM, "GSM"),
-       SFMT(SPECIAL, "Special"),
+static assoc_t streams[] = {
+       STREAM(PLAYBACK),
+       STREAM(CAPTURE),
+       END
+};
+
+static assoc_t states[] = {
+       STATE(OPEN),
+       STATE(SETUP),
+       STATE(PREPARED),
+       STATE(RUNNING),
+       STATE(XRUN),
+       STATE(PAUSED),
+       END
+};
+
+#if 0
+static assoc_t hw_params[] = {
+       HW_PARAM(ACCESS),
+       HW_PARAM(FORMAT),
+       HW_PARAM(SUBFORMAT),
+       HW_PARAM(CHANNELS),
+       HW_PARAM(RATE),
+       HW_PARAM(FRAGMENT_SIZE),
+       HW_PARAM(FRAGMENTS),
+       END
+};
+
+static assoc_t sw_params[] = {
+       SW_PARAM(START_MODE),
+       SW_PARAM(READY_MODE),
+       SW_PARAM(AVAIL_MIN),
+       SW_PARAM(XFER_MIN),
+       SW_PARAM(XFER_ALIGN),
+       SW_PARAM(XRUN_MODE),
+       SW_PARAM(TIME),
+       END
+};
+#endif
+
+static assoc_t accesses[] = {
+       ACCESS(MMAP_INTERLEAVED), 
+       ACCESS(MMAP_NONINTERLEAVED),
+       ACCESS(MMAP_COMPLEX),
+       ACCESS(RW_INTERLEAVED),
+       ACCESS(RW_NONINTERLEAVED),
+       END
+};
+
+static assoc_t formats[] = {
+       FORMAT(S8, "Signed 8-bit"), 
+       FORMAT(U8, "Unsigned 8-bit"),
+       FORMAT(S16_LE, "Signed 16-bit Little Endian"),
+       FORMAT(S16_BE, "Signed 16-bit Big Endian"),
+       FORMAT(U16_LE, "Unsigned 16-bit Little Endian"),
+       FORMAT(U16_BE, "Unsigned 16-bit Big Endian"),
+       FORMAT(S24_LE, "Signed 24-bit Little Endian"),
+       FORMAT(S24_BE, "Signed 24-bit Big Endian"),
+       FORMAT(U24_LE, "Unsigned 24-bit Little Endian"),
+       FORMAT(U24_BE, "Unsigned 24-bit Big Endian"),
+       FORMAT(S32_LE, "Signed 32-bit Little Endian"),
+       FORMAT(S32_BE, "Signed 32-bit Big Endian"),
+       FORMAT(U32_LE, "Unsigned 32-bit Little Endian"),
+       FORMAT(U32_BE, "Unsigned 32-bit Big Endian"),
+       FORMAT(FLOAT_LE, "Float Little Endian"),
+       FORMAT(FLOAT_BE, "Float Big Endian"),
+       FORMAT(FLOAT64_LE, "Float64 Little Endian"),
+       FORMAT(FLOAT64_BE, "Float64 Big Endian"),
+       FORMAT(IEC958_SUBFRAME_LE, "IEC-958 Little Endian"),
+       FORMAT(IEC958_SUBFRAME_BE, "IEC-958 Big Endian"),
+       FORMAT(MU_LAW, "Mu-Law"),
+       FORMAT(A_LAW, "A-Law"),
+       FORMAT(IMA_ADPCM, "Ima-ADPCM"),
+       FORMAT(MPEG, "MPEG"),
+       FORMAT(GSM, "GSM"),
+       FORMAT(SPECIAL, "Special"),
        END 
 };
 
-static assoc_t starts[] = { START(EXPLICIT), START(DATA), END };
-static assoc_t readys[] = { READY(FRAGMENT), READY(ASAP), END };
-static assoc_t xfers[] = { XFER(INTERLEAVED), XFER(NONINTERLEAVED), END };
-static assoc_t mmaps[] = { MMAP(INTERLEAVED), MMAP(NONINTERLEAVED), END };
-static assoc_t onoff[] = { {0, "OFF", NULL}, {1, "ON", NULL}, {-1, "ON", NULL}, END };
+static assoc_t subformats[] = {
+       SUBFORMAT(STD, "Standard"), 
+       END
+};
 
-int snd_pcm_dump_setup(snd_pcm_t *pcm, FILE *fp)
+static assoc_t starts[] = {
+       START(EXPLICIT),
+       START(DATA),
+       END
+};
+static assoc_t readys[] = {
+       READY(FRAGMENT),
+       READY(ASAP),
+       END
+};
+
+static assoc_t xruns[] = {
+       XRUN(ASAP),
+       XRUN(FRAGMENT),
+       XRUN(NONE),
+       END
+};
+
+static assoc_t onoff[] = {
+       {0, "OFF", NULL},
+       {1, "ON", NULL},
+       {-1, "ON", NULL},
+       END
+};
+
+int snd_pcm_dump_hw_setup(snd_pcm_t *pcm, FILE *fp)
+{
+       assert(pcm);
+       assert(fp);
+       assert(pcm->setup);
+        fprintf(fp, "stream       : %s\n", assoc(pcm->stream, streams));
+       fprintf(fp, "access       : %s\n", assoc(pcm->access, accesses));
+       fprintf(fp, "format       : %s\n", assoc(pcm->format, formats));
+       fprintf(fp, "subformat    : %s\n", assoc(pcm->subformat, subformats));
+       fprintf(fp, "channels     : %d\n", pcm->channels);
+       fprintf(fp, "rate         : %d\n", pcm->rate);
+       fprintf(fp, "rate         : %g (%d/%d)\n", (double) pcm->rate_master / pcm->rate_divisor, pcm->rate_master, pcm->rate_divisor);
+       fprintf(fp, "msbits       : %d\n", pcm->msbits);
+       fprintf(fp, "fragment_size: %ld\n", (long)pcm->fragment_size);
+       fprintf(fp, "fragments    : %d\n", pcm->fragments);
+       return 0;
+}
+
+int snd_pcm_dump_sw_setup(snd_pcm_t *pcm, FILE *fp)
 {
-       snd_pcm_setup_t *setup;
        assert(pcm);
        assert(fp);
-       assert(pcm->valid_setup);
-       setup = &pcm->setup;
-        fprintf(fp, "stream     : %s\n", assoc(pcm->stream, streams));
-       fprintf(fp, "format     : %s\n", assoc(setup->format.sfmt, fmts));
-       fprintf(fp, "channels   : %d\n", setup->format.channels);
-       fprintf(fp, "rate       : %d (%d/%d=%g)\n", setup->format.rate, setup->rate_master, setup->rate_divisor, (double) setup->rate_master / setup->rate_divisor);
-       // digital
-       fprintf(fp, "start_mode : %s\n", assoc(setup->start_mode, starts));
-       fprintf(fp, "ready_mode : %s\n", assoc(setup->ready_mode, readys));
-       fprintf(fp, "avail_min  : %ld\n", (long)setup->avail_min);
-       fprintf(fp, "xfer_mode  : %s\n", assoc(setup->xfer_mode, xfers));
-       fprintf(fp, "xfer_min   : %ld\n", (long)setup->xfer_min);
-       fprintf(fp, "xfer_align : %ld\n", (long)setup->xfer_align);
-       fprintf(fp, "xrun_mode  : %s\n", assoc(setup->xrun_mode, xruns));
-       fprintf(fp, "mmap_shape : %s\n", assoc(setup->mmap_shape, mmaps));
-       fprintf(fp, "buffer_size: %ld\n", (long)setup->buffer_size);
-       fprintf(fp, "frag_size  : %ld\n", (long)setup->frag_size);
-       fprintf(fp, "boundary   : %ld\n", (long)setup->boundary);
-       fprintf(fp, "time       : %s\n", assoc(setup->time, onoff));
-       fprintf(fp, "frags      : %ld\n", (long)setup->frags);
-       fprintf(fp, "msbits     : %d\n", setup->msbits);
+       assert(pcm->setup);
+       fprintf(fp, "start_mode   : %s\n", assoc(pcm->start_mode, starts));
+       fprintf(fp, "ready_mode   : %s\n", assoc(pcm->ready_mode, readys));
+       fprintf(fp, "xrun_mode    : %s\n", assoc(pcm->xrun_mode, xruns));
+       fprintf(fp, "avail_min    : %ld\n", (long)pcm->avail_min);
+       fprintf(fp, "xfer_min     : %ld\n", (long)pcm->xfer_min);
+       fprintf(fp, "xfer_align   : %ld\n", (long)pcm->xfer_align);
+       fprintf(fp, "time         : %s\n", assoc(pcm->time, onoff));
+       fprintf(fp, "boundary     : %ld\n", (long)pcm->boundary);
+       return 0;
+}
+
+int snd_pcm_dump_setup(snd_pcm_t *pcm, FILE *fp)
+{
+       snd_pcm_dump_hw_setup(pcm, fp);
+       snd_pcm_dump_sw_setup(pcm, fp);
+       return 0;
+}
+
+int snd_pcm_dump_hw_info(snd_pcm_hw_info_t *info,
+                        FILE *fp)
+{
+       unsigned int k;
+       fputs("access:", fp);
+       if (info->access_mask) {
+               for (k = 0; k <= SND_PCM_ACCESS_LAST; ++k)
+                       if (info->access_mask & (1U << k)) {
+                               putc(' ', fp);
+                               fputs(assoc(k, accesses), fp);
+                       }
+       } else
+               fputs(" NONE", fp);
+       putc('\n', fp);
+
+       fputs("format:", fp);
+       if (info->format_mask) {
+               for (k = 0; k <= SND_PCM_FORMAT_LAST; ++k)
+                       if (info->format_mask & (1U << k)) {
+                               putc(' ', fp);
+                               fputs(assoc(k, formats), fp);
+                       }
+       } else
+               fputs(" NONE", fp);
+       putc('\n', fp);
+       
+       fputs("subformat:", fp);
+       if (info->subformat_mask) {
+               for (k = 0; k <= SND_PCM_SUBFORMAT_LAST; ++k)
+                       if (info->subformat_mask & (1U << k)) {
+                               putc(' ', fp);
+                               fputs(assoc(k, subformats), fp);
+                       }
+       } else
+               fputs(" NONE", fp);
+       putc('\n', fp);
+
+       fputs("channels: ", fp);
+       if (info->channels_min == 0 && info->channels_max == UINT_MAX)
+               fputs("ALL", fp);
+       else if (info->channels_min > info->channels_max)
+               fputs("NONE", fp);
+       else {
+               fprintf(fp, "%u", info->channels_min);
+               if (info->channels_min < info->channels_max)
+                       fprintf(fp, " - %u", info->channels_max);
+       }
+       putc('\n', fp);
+
+       fputs("rate: ", fp);
+       if (info->rate_min == 0 && info->rate_max == UINT_MAX)
+               fputs("ALL", fp);
+       else if (info->rate_min > info->rate_max)
+               fputs("NONE", fp);
+       else {
+               fprintf(fp, "%u", info->rate_min);
+               if (info->rate_min < info->rate_max)
+                       fprintf(fp, " - %u", info->rate_max);
+       }
+       putc('\n', fp);
+
+       fputs("fragment_size: ", fp);
+       if (info->fragment_size_min <= 1 && 
+           info->fragment_size_max == ULONG_MAX)
+               fputs("ALL", fp);
+       else if (info->fragment_size_min > info->fragment_size_max)
+               fputs("NONE", fp);
+       else {
+               fprintf(fp, "%lu", (unsigned long)info->fragment_size_min);
+               if (info->fragment_size_min < info->fragment_size_max)
+                       fprintf(fp, " - %lu", (unsigned long)info->fragment_size_max);
+       }
+       putc('\n', fp);
+
+       fputs("fragments: ", fp);
+       if (info->fragments_min <= 1 && info->fragments_max == UINT_MAX)
+               fputs("ALL", fp);
+       else if (info->fragments_min > info->fragments_max)
+               fputs("NONE", fp);
+       else {
+               fprintf(fp, "%u", info->fragments_min);
+               if (info->fragments_min < info->fragments_max)
+                       fprintf(fp, " - %u", info->fragments_max);
+       }
+       putc('\n', 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)
+               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, accesses));
+                       break;
+               case SND_PCM_HW_PARAM_FORMAT:
+                       fprintf(fp, "format: %s\n", assoc(params->format, formats));
+                       break;
+               case SND_PCM_HW_PARAM_SUBFORMAT:
+                       fprintf(fp, "subformat: %s\n", assoc(params->subformat, subformats));
+                       break;
+               case SND_PCM_HW_PARAM_CHANNELS:
+                       fprintf(fp, "channels: %d\n", params->channels);
+                       break;
+               case SND_PCM_HW_PARAM_RATE:
+                       fprintf(fp, "rate: %d\n", params->rate);
+                       break;
+               case SND_PCM_HW_PARAM_FRAGMENT_SIZE:
+                       fprintf(fp, "fragment_size: %ld\n", (long)params->fragment_size);
+                       break;
+               case SND_PCM_HW_PARAM_FRAGMENTS:
+                       fprintf(fp, "fragments: %d\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;
+       if (params->fail_mask == 0)
+               return 0;
+       fprintf(fp, "sw_params failed on the following field value(s):\n");
+       for (k = 0; k <= SND_PCM_SW_PARAM_LAST; ++k) {
+               if (!(params->fail_mask & (1U << k)))
+                       continue;
+               switch (k) {
+               case SND_PCM_SW_PARAM_START_MODE:
+                       fprintf(fp, "start_mode: %s\n", assoc(params->start_mode, starts));
+                       break;
+               case SND_PCM_SW_PARAM_READY_MODE:
+                       fprintf(fp, "ready_mode: %s\n", assoc(params->ready_mode, readys));
+                       break;
+               case SND_PCM_SW_PARAM_XRUN_MODE:
+                       fprintf(fp, "xrun_mode: %s\n", assoc(params->xrun_mode, xruns));
+                       break;
+               case SND_PCM_SW_PARAM_AVAIL_MIN:
+                       fprintf(fp, "avail_min: %ld\n", (long)params->avail_min);
+                       break;
+               case SND_PCM_SW_PARAM_XFER_MIN:
+                       fprintf(fp, "xfer_min: %ld\n", (long)params->xfer_min);
+                       break;
+               case SND_PCM_SW_PARAM_XFER_ALIGN:
+                       fprintf(fp, "xfer_align: %ld\n", (long)params->xfer_align);
+                       break;
+               case SND_PCM_SW_PARAM_TIME:
+                       fprintf(fp, "time: %d\n", params->time);
+                       break;
+               default:
+                       assert(0);
+                       break;
+               }
+       }
        return 0;
 }
 
@@ -501,7 +837,7 @@ int snd_pcm_dump(snd_pcm_t *pcm, FILE *fp)
 
 const char *snd_pcm_format_name(int format)
 {
-       assoc_t *a = assoc_value(format, fmts);
+       assoc_t *a = assoc_value(format, formats);
        if (a)
                return a->name;
        return 0;
@@ -509,7 +845,7 @@ const char *snd_pcm_format_name(int format)
 
 const char *snd_pcm_format_description(int format)
 {
-       assoc_t *a = assoc_value(format, fmts);
+       assoc_t *a = assoc_value(format, formats);
        if (a)
                return a->desc;
        return "Unknown";
@@ -517,7 +853,7 @@ const char *snd_pcm_format_description(int format)
 
 int snd_pcm_format_value(const char* name)
 {
-       assoc_t *a = assoc_name(name, fmts);
+       assoc_t *a = assoc_name(name, formats);
        if (a)
                return a->value;
        return -1;
@@ -526,28 +862,28 @@ int snd_pcm_format_value(const char* name)
 ssize_t snd_pcm_bytes_to_frames(snd_pcm_t *pcm, ssize_t bytes)
 {
        assert(pcm);
-       assert(pcm->valid_setup);
+       assert(pcm->setup);
        return bytes * 8 / pcm->bits_per_frame;
 }
 
 ssize_t snd_pcm_frames_to_bytes(snd_pcm_t *pcm, ssize_t frames)
 {
        assert(pcm);
-       assert(pcm->valid_setup);
+       assert(pcm->setup);
        return frames * pcm->bits_per_frame / 8;
 }
 
 ssize_t snd_pcm_bytes_to_samples(snd_pcm_t *pcm, ssize_t bytes)
 {
        assert(pcm);
-       assert(pcm->valid_setup);
+       assert(pcm->setup);
        return bytes * 8 / pcm->bits_per_sample;
 }
 
 ssize_t snd_pcm_samples_to_bytes(snd_pcm_t *pcm, ssize_t samples)
 {
        assert(pcm);
-       assert(pcm->valid_setup);
+       assert(pcm->setup);
        return samples * pcm->bits_per_sample / 8;
 }
 
@@ -568,8 +904,44 @@ int snd_pcm_open(snd_pcm_t **pcmp, char *name,
                return err;
        err = snd_config_searchv(snd_config, &pcm_conf, "pcm", name, 0);
        if (err < 0) {
+               int card, dev, subdev;
+               char socket[256], sname[256];
+               char format[16], file[256];
+               err = sscanf(name, "hw:%d,%d,%d", &card, &dev, &subdev);
+               if (err == 3)
+                       return snd_pcm_hw_open(pcmp, name, card, dev, subdev, stream, mode);
+               err = sscanf(name, "hw:%d,%d", &card, &dev);
+               if (err == 2)
+                       return snd_pcm_hw_open(pcmp, name, card, dev, -1, stream, mode);
+               err = sscanf(name, "plug:%d,%d,%d", &card, &dev, &subdev);
+               if (err == 3)
+                       return snd_pcm_plug_open_hw(pcmp, name, card, dev, subdev, stream, mode);
+               err = sscanf(name, "plug:%d,%d", &card, &dev);
+               if (err == 2)
+                       return snd_pcm_plug_open_hw(pcmp, name, card, dev, -1, stream, mode);
+               err = sscanf(name, "shm:%256s,%256s", socket, sname);
+               if (err == 2)
+                       return snd_pcm_shm_open(pcmp, NULL, socket, sname, stream, mode);
+               err = sscanf(name, "file:%256s,%16s", file, format);
+               if (err == 2) {
+                       snd_pcm_t *slave;
+                       err = snd_pcm_null_open(&slave, NULL, stream, mode);
+                       if (err < 0)
+                               return err;
+                       return snd_pcm_file_open(pcmp, NULL, file, -1, format, slave, 1);
+               }
+               err = sscanf(name, "file:%256s", file);
+               if (err == 1) {
+                       snd_pcm_t *slave;
+                       err = snd_pcm_null_open(&slave, NULL, stream, mode);
+                       if (err < 0)
+                               return err;
+                       return snd_pcm_file_open(pcmp, NULL, file, -1, "raw", slave, 1);
+               }
+               if (strcmp(name, "null") == 0)
+                       return snd_pcm_null_open(pcmp, NULL, stream, mode);
                ERR("Unknown PCM %s", name);
-               return err;
+               return -ENOENT;
        }
        if (snd_config_type(pcm_conf) != SND_CONFIG_TYPE_COMPOUND) {
                ERR("Invalid type for PCM definition");
@@ -655,7 +1027,7 @@ void snd_pcm_areas_from_buf(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
                            void *buf)
 {
        unsigned int channel;
-       unsigned int channels = pcm->setup.format.channels;
+       unsigned int channels = pcm->channels;
        for (channel = 0; channel < channels; ++channel, ++areas) {
                areas->addr = buf;
                areas->first = channel * pcm->bits_per_sample;
@@ -667,7 +1039,7 @@ void snd_pcm_areas_from_bufs(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
                             void **bufs)
 {
        unsigned int channel;
-       unsigned int channels = pcm->setup.format.channels;
+       unsigned int channels = pcm->channels;
        for (channel = 0; channel < channels; ++channel, ++areas, ++bufs) {
                areas->addr = *bufs;
                areas->first = 0;
@@ -974,7 +1346,7 @@ ssize_t snd_pcm_read_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
        assert(size > 0);
        assert(state >= SND_PCM_STATE_PREPARED);
        if (state == SND_PCM_STATE_PREPARED &&
-           pcm->setup.start_mode != SND_PCM_START_EXPLICIT) {
+           pcm->start_mode != SND_PCM_START_EXPLICIT) {
                err = snd_pcm_start(pcm);
                if (err < 0)
                        return err;
@@ -989,7 +1361,7 @@ ssize_t snd_pcm_read_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
                        err = avail;
                        break;
                }
-               if ((size_t)avail < pcm->setup.avail_min) {
+               if ((size_t)avail < pcm->avail_min) {
                        if (state != SND_PCM_STATE_RUNNING) {
                                err = -EPIPE;
                                break;
@@ -1041,7 +1413,7 @@ ssize_t snd_pcm_write_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
                        err = avail;
                        break;
                }
-               if ((size_t)avail < pcm->setup.avail_min) {
+               if ((size_t)avail < pcm->avail_min) {
                        if (state != SND_PCM_STATE_RUNNING) {
                                err = -EPIPE;
                                break;
@@ -1066,7 +1438,7 @@ ssize_t snd_pcm_write_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
                xfer += err;
                offset += err;
                if (state == SND_PCM_STATE_PREPARED &&
-                   pcm->setup.start_mode != SND_PCM_START_EXPLICIT) {
+                   pcm->start_mode != SND_PCM_START_EXPLICIT) {
                        err = snd_pcm_start(pcm);
                        if (err < 0)
                                break;
@@ -1078,10 +1450,11 @@ ssize_t snd_pcm_write_areas(snd_pcm_t *pcm, 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->setup.buffer_size);
+       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");
@@ -1098,8 +1471,9 @@ int snd_pcm_alloc_user_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i)
 int snd_pcm_alloc_kernel_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i, int fd)
 {
        i->type = SND_PCM_MMAP_KERNEL;
-       i->size = pcm->setup.mmap_bytes;
-       i->addr = mmap(NULL, pcm->setup.mmap_bytes,
+       /* 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);
@@ -1131,15 +1505,1176 @@ int snd_pcm_free_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i)
        }
        return 0;
 }
+#endif
 
-void snd_pcm_error(const char *file, int line, const char *function, int err, const char *fmt, ...)
+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_divisor == 0 &&
+           info->rate_min == info->rate_max) {
+               info->rate_master = info->rate_min;
+               info->rate_divisor = 1;
+       }
+       return 0;
+}
+
+struct {
+       unsigned int rate;
+       unsigned int flag;
+} snd_pcm_rates[] = {
+       { 5512, SND_PCM_RATE_5512 },
+       { 8000, SND_PCM_RATE_8000 },
+       { 11025, SND_PCM_RATE_11025 },
+       { 16000, SND_PCM_RATE_16000 },
+       { 22050, SND_PCM_RATE_22050 },
+       { 32000, SND_PCM_RATE_32000 },
+       { 44100, SND_PCM_RATE_44100 },
+       { 48000, SND_PCM_RATE_48000 },
+       { 64000, SND_PCM_RATE_64000 },
+       { 88200, SND_PCM_RATE_88200 },
+       { 96000, SND_PCM_RATE_96000 },
+       { 176400, SND_PCM_RATE_176400 },
+       { 192000, SND_PCM_RATE_192000 }
+};
+
+#define SND_PCM_RATES (sizeof(snd_pcm_rates) / sizeof(snd_pcm_rates[0]))
+
+int snd_pcm_hw_info_rules_access(snd_pcm_t *pcm, 
+                                snd_pcm_hw_info_t *info,
+                                snd_pcm_hw_params_t *params,
+                                unsigned int count, int *rules)
+{
+       int k;
+       unsigned int rel, mask;
+       snd_pcm_hw_info_t i;
+       rel = *rules & SND_PCM_RULE_REL_MASK;
+       switch (rel) {
+       case SND_PCM_RULE_REL_LT:
+               mask = (1U << params->access) - 1;
+               break;
+       case SND_PCM_RULE_REL_LE:
+               mask = (1U << (params->access + 1)) - 1;
+               break;
+       case SND_PCM_RULE_REL_GT:
+               mask = ~((1U << (params->access + 1)) - 1);
+               break;
+       case SND_PCM_RULE_REL_GE:
+               mask = ~((1U << params->access) - 1);
+               break;
+       case SND_PCM_RULE_REL_EQ:
+               mask = 1U << params->access;
+               break;
+       case SND_PCM_RULE_REL_NEAR:
+       {
+               unsigned int diff = 0;
+               int n;
+               for (diff = 0; diff < 32; ++diff) {
+                       n = (int)params->access - (int)diff;
+                       if (n >= 0) {
+                               unsigned int bit = 1U << n;
+                               if (info->access_mask & bit) {
+                                       i = *info;
+                                       i.access_mask = bit;
+                                       if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+                                           snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                                               *info = i;
+                                               return 0;
+                                       }
+                               }
+                       } else if (params->access + diff > SND_PCM_ACCESS_LAST)
+                               break;
+                       if (diff == 0)
+                               continue;
+                       n = params->access + diff;
+                       if (n <= SND_PCM_ACCESS_LAST) {
+                               unsigned int bit = 1U << n;
+                               if (info->access_mask & bit) {
+                                       i = *info;
+                                       i.access_mask = bit;
+                                       if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+                                           snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                                               *info = i;
+                                               return 0;
+                                       }
+                               }
+                       }
+               }
+               info->access_mask = 0;
+               return -EINVAL;
+       }
+       case SND_PCM_RULE_REL_BITS:
+               mask = params->access;
+               break;
+       default:
+               assert(0);
+               return -EINVAL;
+       }
+       info->access_mask &= mask;
+       if (info->access_mask == 0)
+               return -EINVAL;
+       switch (rel) {
+       case SND_PCM_RULE_REL_LE:
+       case SND_PCM_RULE_REL_LT:
+               for (k = SND_PCM_ACCESS_LAST; k >= 0; --k) {
+                       if (!(info->access_mask & (1U << k)))
+                               continue;
+                       i = *info;
+                       i.access_mask = 1U << k;
+                       if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+                           snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                               *info = i;
+                               return 0;
+                       }
+               }
+               info->access_mask = 0;
+               return -EINVAL;
+       default:
+               for (k = 0; k <= SND_PCM_ACCESS_LAST; ++k) {
+                       if (!(info->access_mask & (1U << k)))
+                               continue;
+                       i = *info;
+                       i.access_mask = 1U << k;
+                       if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+                           snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                               *info = i;
+                               return 0;
+                       }
+               }
+               info->access_mask = 0;
+               return -EINVAL;
+       }               
+       return 0;
+}
+
+int snd_pcm_hw_info_rules_format(snd_pcm_t *pcm, 
+                                snd_pcm_hw_info_t *info,
+                                snd_pcm_hw_params_t *params,
+                                unsigned int count, int *rules)
+{
+       int k;
+       unsigned int rel, mask;
+       snd_pcm_hw_info_t i;
+       rel = *rules & SND_PCM_RULE_REL_MASK;
+       switch (rel) {
+       case SND_PCM_RULE_REL_LT:
+               mask = (1U << params->format) - 1;
+               break;
+       case SND_PCM_RULE_REL_LE:
+               mask = (1U << (params->format + 1)) - 1;
+               break;
+       case SND_PCM_RULE_REL_GT:
+               mask = ~((1U << (params->format + 1)) - 1);
+               break;
+       case SND_PCM_RULE_REL_GE:
+               mask = ~((1U << params->format) - 1);
+               break;
+       case SND_PCM_RULE_REL_EQ:
+               mask = 1U << params->format;
+               break;
+       case SND_PCM_RULE_REL_NEAR:
+       {
+               unsigned int diff = 0;
+               int n;
+               for (diff = 0; diff < 32; ++diff) {
+                       n = (int)params->format - (int)diff;
+                       if (n >= 0) {
+                               unsigned int bit = 1U << n;
+                               if (info->format_mask & bit) {
+                                       i = *info;
+                                       i.format_mask = bit;
+                                       if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+                                           snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                                               *info = i;
+                                               return 0;
+                                       }
+                               }
+                       } else if (params->format + diff > SND_PCM_FORMAT_LAST)
+                               break;
+                       if (diff == 0)
+                               continue;
+                       n = params->format + diff;
+                       if (n <= SND_PCM_FORMAT_LAST) {
+                               unsigned int bit = 1U << n;
+                               if (info->format_mask & bit) {
+                                       i = *info;
+                                       i.format_mask = bit;
+                                       if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+                                           snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                                               *info = i;
+                                               return 0;
+                                       }
+                               }
+                       }
+               }
+               info->format_mask = 0;
+               return -EINVAL;
+       }
+       case SND_PCM_RULE_REL_BITS:
+               mask = params->format;
+               break;
+       default:
+               assert(0);
+               return -EINVAL;
+       }
+       info->format_mask &= mask;
+       if (info->format_mask == 0)
+               return -EINVAL;
+       switch (rel) {
+       case SND_PCM_RULE_REL_LE:
+       case SND_PCM_RULE_REL_LT:
+               for (k = SND_PCM_FORMAT_LAST; k >= 0; --k) {
+                       if (!(info->format_mask & (1U << k)))
+                               continue;
+                       i = *info;
+                       i.format_mask = 1U << k;
+                       if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+                           snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                               *info = i;
+                               return 0;
+                       }
+               }
+               info->format_mask = 0;
+               return -EINVAL;
+       default:
+               for (k = 0; k <= SND_PCM_FORMAT_LAST; ++k) {
+                       if (!(info->format_mask & (1U << k)))
+                               continue;
+                       i = *info;
+                       i.format_mask = 1U << k;
+                       if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+                           snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                               *info = i;
+                               return 0;
+                       }
+               }
+               info->format_mask = 0;
+               return -EINVAL;
+       }               
+       return 0;
+}
+
+int snd_pcm_hw_info_rules_subformat(snd_pcm_t *pcm, 
+                                   snd_pcm_hw_info_t *info,
+                                   snd_pcm_hw_params_t *params,
+                                   unsigned int count, int *rules)
+{
+       int k;
+       unsigned int rel, mask;
+       snd_pcm_hw_info_t i;
+       rel = *rules & SND_PCM_RULE_REL_MASK;
+       switch (rel) {
+       case SND_PCM_RULE_REL_LT:
+               mask = (1U << params->subformat) - 1;
+               break;
+       case SND_PCM_RULE_REL_LE:
+               mask = (1U << (params->subformat + 1)) - 1;
+               break;
+       case SND_PCM_RULE_REL_GT:
+               mask = ~((1U << (params->subformat + 1)) - 1);
+               break;
+       case SND_PCM_RULE_REL_GE:
+               mask = ~((1U << params->subformat) - 1);
+               break;
+       case SND_PCM_RULE_REL_EQ:
+               mask = 1U << params->subformat;
+               break;
+       case SND_PCM_RULE_REL_NEAR:
+       {
+               unsigned int diff = 0;
+               int n;
+               for (diff = 0; diff < 32; ++diff) {
+                       n = (int)params->subformat - (int)diff;
+                       if (n >= 0) {
+                               unsigned int bit = 1U << n;
+                               if (info->subformat_mask & bit) {
+                                       i = *info;
+                                       i.subformat_mask = bit;
+                                       if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+                                           snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                                               *info = i;
+                                               return 0;
+                                       }
+                               }
+                       } else if (params->subformat + diff > SND_PCM_SUBFORMAT_LAST)
+                               break;
+                       if (diff == 0)
+                               continue;
+                       n = params->subformat + diff;
+                       if (n <= SND_PCM_SUBFORMAT_LAST) {
+                               unsigned int bit = 1U << n;
+                               if (info->subformat_mask & bit) {
+                                       i = *info;
+                                       i.subformat_mask = bit;
+                                       if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+                                           snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                                               *info = i;
+                                               return 0;
+                                       }
+                               }
+                       }
+               }
+               info->subformat_mask = 0;
+               return -EINVAL;
+       }
+       case SND_PCM_RULE_REL_BITS:
+               mask = params->subformat;
+               break;
+       default:
+               assert(0);
+               return -EINVAL;
+       }
+       info->subformat_mask &= mask;
+       if (info->subformat_mask == 0)
+               return -EINVAL;
+       switch (rel) {
+       case SND_PCM_RULE_REL_LE:
+       case SND_PCM_RULE_REL_LT:
+               for (k = SND_PCM_SUBFORMAT_LAST; k >= 0; --k) {
+                       if (!(info->subformat_mask & (1U << k)))
+                               continue;
+                       i = *info;
+                       i.subformat_mask = 1U << k;
+                       if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+                           snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                               *info = i;
+                               return 0;
+                       }
+               }
+               info->subformat_mask = 0;
+               return -EINVAL;
+       default:
+               for (k = 0; k <= SND_PCM_SUBFORMAT_LAST; ++k) {
+                       if (!(info->subformat_mask & (1U << k)))
+                               continue;
+                       i = *info;
+                       i.subformat_mask = 1U << k;
+                       if (snd_pcm_hw_info(pcm, &i) >= 0 &&
+                           snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                               *info = i;
+                               return 0;
+                       }
+               }
+               info->subformat_mask = 0;
+               return -EINVAL;
+       }               
+       return 0;
+}
+
+int snd_pcm_hw_info_rules_channels(snd_pcm_t *pcm, 
+                                  snd_pcm_hw_info_t *info,
+                                  snd_pcm_hw_params_t *params,
+                                  unsigned int count, int *rules)
+{
+       int err;
+       unsigned int rel;
+       snd_pcm_hw_info_t i;
+       rel = *rules & SND_PCM_RULE_REL_MASK;
+       switch (rel) {
+       case SND_PCM_RULE_REL_LT:
+               if (info->channels_max > params->channels - 1)
+                       info->channels_max = params->channels - 1;
+               goto _le;
+       case SND_PCM_RULE_REL_LE:
+               if (info->channels_max > params->channels)
+                       info->channels_max = params->channels;
+       _le:
+               while (1) {
+                       if (info->channels_min > info->channels_max)
+                               return -EINVAL;
+                       i = *info;
+                       err = snd_pcm_hw_info(pcm, &i);
+                       if (err < 0) {
+                               info->channels_min = i.channels_min;
+                               info->channels_max = i.channels_max;
+                               return err;
+                       }
+                       i.channels_min = i.channels_max;
+                       if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                               *info = i;
+                               return 0;
+                       }
+                       info->channels_max--;
+               }
+               break;
+       case SND_PCM_RULE_REL_GT:
+               if (info->channels_min < params->channels + 1)
+                       info->channels_min = params->channels + 1;
+               goto _ge;
+       case SND_PCM_RULE_REL_GE:
+               if (info->channels_min < params->channels)
+                       info->channels_min = params->channels;
+       _ge:
+               while (1) {
+                       if (info->channels_min > info->channels_max)
+                               return -EINVAL;
+                       i = *info;
+                       err = snd_pcm_hw_info(pcm, &i);
+                       if (err < 0) {
+                               info->channels_min = i.channels_min;
+                               info->channels_max = i.channels_max;
+                               return err;
+                       }
+                       i.channels_max = i.channels_min;
+                       if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                               *info = i;
+                               return 0;
+                       }
+                       info->channels_min++;
+               }
+               break;
+       case SND_PCM_RULE_REL_EQ:
+               info->channels_min = params->channels;
+               info->channels_max = params->channels;
+               return snd_pcm_hw_info_rules(pcm, info, params, count - 1, rules + 1);
+               break;
+       case SND_PCM_RULE_REL_NEAR:
+       {
+               unsigned int max1, min2;
+               int err1 = -EINVAL, err2 = -EINVAL;
+               max1 = params->channels;
+               min2 = params->channels+1;
+               if (info->channels_min <= max1) {
+                       i = *info;
+                       i.channels_max = max1;
+                       err1 = snd_pcm_hw_info(pcm, &i);
+                       /* shortcut for common case */
+                       if (err1 >= 0 && max1 == i.channels_max) {
+                               i.channels_min = max1;
+                               if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                                       *info = i;
+                                       return 0;
+                               }
+                               i.channels_max = max1 - 1;
+                               err1 = snd_pcm_hw_info(pcm, &i);
+                       }
+                       max1 = i.channels_max;
+               }
+               if (min2 <= info->channels_max) {
+                       i = *info;
+                       i.channels_min = min2;
+                       err2 = snd_pcm_hw_info(pcm, &i);
+                       min2 = i.channels_min;
+               }
+               while (1) {
+                       unsigned int channels;
+                       if (err1 >= 0) {
+                               if (err2 >= 0) {
+                                       if (params->channels - max1 < 
+                                           min2 - params->channels)
+                                               channels = max1;
+                                       else
+                                               channels = min2;
+                               } else
+                                       channels = max1;
+                       } else if (err2 >= 0)
+                               channels = min2;
+                       else {
+                               info->channels_min = UINT_MAX;
+                               info->channels_max = 0;
+                               return -EINVAL;
+                       }
+                       i = *info;
+                       i.channels_min = i.channels_max = channels;
+                       if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                               *info = i;
+                               return 0;
+                       }
+                       if (channels == max1) {
+                               max1--;
+                               i = *info;
+                               i.channels_max = max1;
+                               err1 = snd_pcm_hw_info(pcm, &i);
+                               max1 = i.channels_max;
+                       } else {
+                               min2++;
+                               i = *info;
+                               i.channels_min = min2;
+                               err2 = snd_pcm_hw_info(pcm, &i);
+                               min2 = i.channels_min;
+                       }
+                               
+               }
+               break;
+       }
+       case SND_PCM_RULE_REL_BITS:
+       {
+               unsigned int k;
+               for (k = info->channels_min; k < 32; ++k) {
+                       if (!(params->channels & (1U << k)))
+                               continue;
+                       info->channels_min = k;
+                       if (info->channels_min > info->channels_max)
+                               return -EINVAL;
+                       i = *info;
+                       err = snd_pcm_hw_info(pcm, &i);
+                       if (err < 0) {
+                               info->channels_min = i.channels_min;
+                               info->channels_max = i.channels_max;
+                               return err;
+                       }
+                       i.channels_max = i.channels_min;
+                       if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                               *info = i;
+                               return 0;
+                       }
+               }
+               break;
+       }
+       default:
+               assert(0);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int snd_pcm_hw_info_rules_rate(snd_pcm_t *pcm, 
+                              snd_pcm_hw_info_t *info,
+                              snd_pcm_hw_params_t *params,
+                              unsigned int count, int *rules)
+{
+       int err;
+       unsigned int rel;
+       snd_pcm_hw_info_t i;
+       rel = *rules & SND_PCM_RULE_REL_MASK;
+       switch (rel) {
+       case SND_PCM_RULE_REL_LT:
+               if (info->rate_max > params->rate - 1)
+                       info->rate_max = params->rate - 1;
+               goto _le;
+       case SND_PCM_RULE_REL_LE:
+               if (info->rate_max > params->rate)
+                       info->rate_max = params->rate;
+       _le:
+               while (1) {
+                       if (info->rate_min > info->rate_max)
+                               return -EINVAL;
+                       i = *info;
+                       err = snd_pcm_hw_info(pcm, &i);
+                       if (err < 0) {
+                               info->rate_min = i.rate_min;
+                               info->rate_max = i.rate_max;
+                               return err;
+                       }
+                       i.rate_min = i.rate_max;
+                       if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                               *info = i;
+                               return 0;
+                       }
+                       info->rate_max--;
+               }
+               break;
+       case SND_PCM_RULE_REL_GT:
+               if (info->rate_min < params->rate + 1)
+                       info->rate_min = params->rate + 1;
+               goto _ge;
+       case SND_PCM_RULE_REL_GE:
+               if (info->rate_min < params->rate)
+                       info->rate_min = params->rate;
+       _ge:
+               while (1) {
+                       if (info->rate_min > info->rate_max)
+                               return -EINVAL;
+                       i = *info;
+                       err = snd_pcm_hw_info(pcm, &i);
+                       if (err < 0) {
+                               info->rate_min = i.rate_min;
+                               info->rate_max = i.rate_max;
+                               return err;
+                       }
+                       i.rate_max = i.rate_min;
+                       if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                               *info = i;
+                               return 0;
+                       }
+                       info->rate_min++;
+               }
+               break;
+       case SND_PCM_RULE_REL_EQ:
+               info->rate_min = params->rate;
+               info->rate_max = params->rate;
+               return snd_pcm_hw_info_rules(pcm, info, params, count - 1, rules + 1);
+               break;
+       case SND_PCM_RULE_REL_NEAR:
+       {
+               unsigned int max1, min2;
+               int err1 = -EINVAL, err2 = -EINVAL;
+               max1 = params->rate;
+               min2 = params->rate+1;
+               if (info->rate_min <= max1) {
+                       i = *info;
+                       i.rate_max = max1;
+                       err1 = snd_pcm_hw_info(pcm, &i);
+                       /* shortcut for common case */
+                       if (err1 >= 0 && max1 == i.rate_max) {
+                               i.rate_min = max1;
+                               if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                                       *info = i;
+                                       return 0;
+                               }
+                               i.rate_max = max1 - 1;
+                               err1 = snd_pcm_hw_info(pcm, &i);
+                       }
+                       max1 = i.rate_max;
+               }
+               if (min2 <= info->rate_max) {
+                       i = *info;
+                       i.rate_min = min2;
+                       err2 = snd_pcm_hw_info(pcm, &i);
+                       min2 = i.rate_min;
+               }
+               while (1) {
+                       unsigned int rate;
+                       if (err1 >= 0) {
+                               if (err2 >= 0) {
+                                       if (params->rate - max1 < 
+                                           min2 - params->rate)
+                                               rate = max1;
+                                       else
+                                               rate = min2;
+                               } else
+                                       rate = max1;
+                       } else if (err2 >= 0)
+                               rate = min2;
+                       else {
+                               info->rate_min = UINT_MAX;
+                               info->rate_max = 0;
+                               return -EINVAL;
+                       }
+                       i = *info;
+                       i.rate_min = i.rate_max = rate;
+                       if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                               *info = i;
+                               return 0;
+                       }
+                       if (rate == max1) {
+                               max1--;
+                               i = *info;
+                               i.rate_max = max1;
+                               err1 = snd_pcm_hw_info(pcm, &i);
+                               max1 = i.rate_max;
+                       } else {
+                               min2++;
+                               i = *info;
+                               i.rate_min = min2;
+                               err2 = snd_pcm_hw_info(pcm, &i);
+                               min2 = i.rate_min;
+                       }
+                               
+               }
+               break;
+       }
+       case SND_PCM_RULE_REL_BITS:
+       {
+               unsigned int k;
+               for (k = 0; k < SND_PCM_RATES; ++k) {
+                       if (snd_pcm_rates[k].rate < info->rate_min)
+                               continue;
+                       if (!(params->rate & snd_pcm_rates[k].flag))
+                               continue;
+                       info->rate_min = snd_pcm_rates[k].rate;
+                       if (info->rate_min > info->rate_max)
+                               return -EINVAL;
+                       i = *info;
+                       err = snd_pcm_hw_info(pcm, &i);
+                       if (err < 0) {
+                               info->rate_min = i.rate_min;
+                               info->rate_max = i.rate_max;
+                               return err;
+                       }
+                       i.rate_max = i.rate_min;
+                       if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                               *info = i;
+                               return 0;
+                       }
+               }
+               break;
+       }
+       default:
+               assert(0);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int snd_pcm_hw_info_rules_fragment_size(snd_pcm_t *pcm, 
+                                       snd_pcm_hw_info_t *info,
+                                       snd_pcm_hw_params_t *params,
+                                       unsigned int count, int *rules)
+{
+       int err;
+       unsigned int rel;
+       snd_pcm_hw_info_t i;
+       rel = *rules & SND_PCM_RULE_REL_MASK;
+       switch (rel) {
+       case SND_PCM_RULE_REL_LT:
+               if (info->fragment_size_max > params->fragment_size - 1)
+                       info->fragment_size_max = params->fragment_size - 1;
+               goto _le;
+       case SND_PCM_RULE_REL_LE:
+               if (info->fragment_size_max > params->fragment_size)
+                       info->fragment_size_max = params->fragment_size;
+       _le:
+               while (1) {
+                       if (info->fragment_size_min > info->fragment_size_max)
+                               return -EINVAL;
+                       i = *info;
+                       err = snd_pcm_hw_info(pcm, &i);
+                       if (err < 0) {
+                               info->fragment_size_min = i.fragment_size_min;
+                               info->fragment_size_max = i.fragment_size_max;
+                               return err;
+                       }
+                       i.fragment_size_min = i.fragment_size_max;
+                       if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                               *info = i;
+                               return 0;
+                       }
+                       info->fragment_size_max--;
+               }
+               break;
+       case SND_PCM_RULE_REL_GT:
+               if (info->fragment_size_min < params->fragment_size + 1)
+                       info->fragment_size_min = params->fragment_size + 1;
+               goto _ge;
+       case SND_PCM_RULE_REL_GE:
+               if (info->fragment_size_min < params->fragment_size)
+                       info->fragment_size_min = params->fragment_size;
+       _ge:
+               while (1) {
+                       if (info->fragment_size_min > info->fragment_size_max)
+                               return -EINVAL;
+                       i = *info;
+                       err = snd_pcm_hw_info(pcm, &i);
+                       if (err < 0) {
+                               info->fragment_size_min = i.fragment_size_min;
+                               info->fragment_size_max = i.fragment_size_max;
+                               return err;
+                       }
+                       i.fragment_size_max = i.fragment_size_min;
+                       if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                               *info = i;
+                               return 0;
+                       }
+                       info->fragment_size_min++;
+               }
+               break;
+       case SND_PCM_RULE_REL_EQ:
+               info->fragment_size_min = params->fragment_size;
+               info->fragment_size_max = params->fragment_size;
+               return snd_pcm_hw_info_rules(pcm, info, params, count - 1, rules + 1);
+               break;
+       case SND_PCM_RULE_REL_NEAR:
+       {
+               size_t max1, min2;
+               int err1 = -EINVAL, err2 = -EINVAL;
+               max1 = params->fragment_size;
+               min2 = params->fragment_size+1;
+               if (info->fragment_size_min <= max1) {
+                       i = *info;
+                       i.fragment_size_max = max1;
+                       err1 = snd_pcm_hw_info(pcm, &i);
+                       /* shortcut for common case */
+                       if (err1 >= 0 && max1 == i.fragment_size_max) {
+                               i.fragment_size_min = max1;
+                               if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                                       *info = i;
+                                       return 0;
+                               }
+                               i.fragment_size_max = max1 - 1;
+                               err1 = snd_pcm_hw_info(pcm, &i);
+                       }
+                       max1 = i.fragment_size_max;
+               }
+               if (min2 <= info->fragment_size_max) {
+                       i = *info;
+                       i.fragment_size_min = min2;
+                       err2 = snd_pcm_hw_info(pcm, &i);
+                       min2 = i.fragment_size_min;
+               }
+               while (1) {
+                       size_t fragment_size;
+                       if (err1 >= 0) {
+                               if (err2 >= 0) {
+                                       if (params->fragment_size - max1 < 
+                                           min2 - params->fragment_size)
+                                               fragment_size = max1;
+                                       else
+                                               fragment_size = min2;
+                               } else
+                                       fragment_size = max1;
+                       } else if (err2 >= 0)
+                               fragment_size = min2;
+                       else {
+                               info->fragment_size_min = ULONG_MAX;
+                               info->fragment_size_max = 0;
+                               return -EINVAL;
+                       }
+                       i = *info;
+                       i.fragment_size_min = i.fragment_size_max = fragment_size;
+                       if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                               *info = i;
+                               return 0;
+                       }
+                       if (fragment_size == max1) {
+                               max1--;
+                               i = *info;
+                               i.fragment_size_max = max1;
+                               err1 = snd_pcm_hw_info(pcm, &i);
+                               max1 = i.fragment_size_max;
+                       } else {
+                               min2++;
+                               i = *info;
+                               i.fragment_size_min = min2;
+                               err2 = snd_pcm_hw_info(pcm, &i);
+                               min2 = i.fragment_size_min;
+                       }
+                               
+               }
+               break;
+       }
+       case SND_PCM_RULE_REL_BITS:
+       {
+               unsigned int k;
+               for (k = info->fragment_size_min; k < 32; ++k) {
+                       if (!(params->fragment_size & (1U << k)))
+                               continue;
+                       info->fragment_size_min = 1U << k;
+                       if (info->fragment_size_min > info->fragment_size_max)
+                               return -EINVAL;
+                       i = *info;
+                       err = snd_pcm_hw_info(pcm, &i);
+                       if (err < 0) {
+                               info->fragment_size_min = i.fragment_size_min;
+                               info->fragment_size_max = i.fragment_size_max;
+                               return err;
+                       }
+                       i.fragment_size_max = i.fragment_size_min;
+                       if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                               *info = i;
+                               return 0;
+                       }
+               }
+               break;
+       }
+       default:
+               assert(0);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int snd_pcm_hw_info_rules_fragments(snd_pcm_t *pcm, 
+                                   snd_pcm_hw_info_t *info,
+                                   snd_pcm_hw_params_t *params,
+                                   unsigned int count, int *rules)
+{
+       int err;
+       unsigned int rel;
+       snd_pcm_hw_info_t i;
+       rel = *rules & SND_PCM_RULE_REL_MASK;
+       switch (rel) {
+       case SND_PCM_RULE_REL_LT:
+               if (info->fragments_max > params->fragments - 1)
+                       info->fragments_max = params->fragments - 1;
+               goto _le;
+       case SND_PCM_RULE_REL_LE:
+               if (info->fragments_max > params->fragments)
+                       info->fragments_max = params->fragments;
+       _le:
+               while (1) {
+                       if (info->fragments_min > info->fragments_max)
+                               return -EINVAL;
+                       i = *info;
+                       err = snd_pcm_hw_info(pcm, &i);
+                       if (err < 0) {
+                               info->fragments_min = i.fragments_min;
+                               info->fragments_max = i.fragments_max;
+                               return err;
+                       }
+                       i.fragments_min = i.fragments_max;
+                       if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                               *info = i;
+                               return 0;
+                       }
+                       info->fragments_max--;
+               }
+               break;
+       case SND_PCM_RULE_REL_GT:
+               if (info->fragments_min < params->fragments + 1)
+                       info->fragments_min = params->fragments + 1;
+               goto _ge;
+       case SND_PCM_RULE_REL_GE:
+               if (info->fragments_min < params->fragments)
+                       info->fragments_min = params->fragments;
+       _ge:
+               while (1) {
+                       if (info->fragments_min > info->fragments_max)
+                               return -EINVAL;
+                       i = *info;
+                       err = snd_pcm_hw_info(pcm, &i);
+                       if (err < 0) {
+                               info->fragments_min = i.fragments_min;
+                               info->fragments_max = i.fragments_max;
+                               return err;
+                       }
+                       i.fragments_max = i.fragments_min;
+                       if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                               *info = i;
+                               return 0;
+                       }
+                       info->fragments_min++;
+               }
+               break;
+       case SND_PCM_RULE_REL_EQ:
+               info->fragments_min = params->fragments;
+               info->fragments_max = params->fragments;
+               return snd_pcm_hw_info_rules(pcm, info, params, count - 1, rules + 1);
+               break;
+       case SND_PCM_RULE_REL_NEAR:
+       {
+               unsigned int max1, min2;
+               int err1 = -EINVAL, err2 = -EINVAL;
+               max1 = params->fragments;
+               min2 = params->fragments+1;
+               if (info->fragments_min <= max1) {
+                       i = *info;
+                       i.fragments_max = max1;
+                       err1 = snd_pcm_hw_info(pcm, &i);
+                       /* shortcut for common case */
+                       if (err1 >= 0 && max1 == i.fragments_max) {
+                               i.fragments_min = max1;
+                               if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                                       *info = i;
+                                       return 0;
+                               }
+                               i.fragments_max = max1 - 1;
+                               err1 = snd_pcm_hw_info(pcm, &i);
+                       }
+                       max1 = i.fragments_max;
+               }
+               if (min2 <= info->fragments_max) {
+                       i = *info;
+                       i.fragments_min = min2;
+                       err2 = snd_pcm_hw_info(pcm, &i);
+                       min2 = i.fragments_min;
+               }
+               while (1) {
+                       unsigned int fragments;
+                       if (err1 >= 0) {
+                               if (err2 >= 0) {
+                                       if (params->fragments - max1 < 
+                                           min2 - params->fragments)
+                                               fragments = max1;
+                                       else
+                                               fragments = min2;
+                               } else
+                                       fragments = max1;
+                       } else if (err2 >= 0)
+                               fragments = min2;
+                       else {
+                               info->fragments_min = UINT_MAX;
+                               info->fragments_max = 0;
+                               return -EINVAL;
+                       }
+                       i = *info;
+                       i.fragments_min = i.fragments_max = fragments;
+                       if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                               *info = i;
+                               return 0;
+                       }
+                       if (fragments == max1) {
+                               max1--;
+                               i = *info;
+                               i.fragments_max = max1;
+                               err1 = snd_pcm_hw_info(pcm, &i);
+                               max1 = i.fragments_max;
+                       } else {
+                               min2++;
+                               i = *info;
+                               i.fragments_min = min2;
+                               err2 = snd_pcm_hw_info(pcm, &i);
+                               min2 = i.fragments_min;
+                       }
+                               
+               }
+               break;
+       }
+       case SND_PCM_RULE_REL_BITS:
+       {
+               unsigned int k;
+               for (k = info->fragments_min; k < 32; ++k) {
+                       if (!(params->fragments & (1U << k)))
+                               continue;
+                       info->fragments_min = k;
+                       if (info->fragments_min > info->fragments_max)
+                               return -EINVAL;
+                       i = *info;
+                       err = snd_pcm_hw_info(pcm, &i);
+                       if (err < 0) {
+                               info->fragments_min = i.fragments_min;
+                               info->fragments_max = i.fragments_max;
+                               return err;
+                       }
+                       i.fragments_max = i.fragments_min;
+                       if (snd_pcm_hw_info_rules(pcm, &i, params, count - 1, rules + 1) >= 0) {
+                               *info = i;
+                               return 0;
+                       }
+               }
+               break;
+       }
+       default:
+               assert(0);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int snd_pcm_hw_info_rules(snd_pcm_t *pcm, 
+                         snd_pcm_hw_info_t *info,
+                         snd_pcm_hw_params_t *params,
+                         unsigned int count, int *rules)
+{
+       unsigned int par;
+       if (count == 0)
+               return snd_pcm_hw_info(pcm, info);
+       par = rules[0] & SND_PCM_RULE_PAR_MASK;
+       switch (par) {
+       case SND_PCM_HW_PARAM_ACCESS:
+               return snd_pcm_hw_info_rules_access(pcm, info, params, count, rules);
+       case SND_PCM_HW_PARAM_FORMAT:
+               return snd_pcm_hw_info_rules_format(pcm, info, params, count, rules);
+       case SND_PCM_HW_PARAM_SUBFORMAT:
+               return snd_pcm_hw_info_rules_subformat(pcm, info, params, count, rules);
+       case SND_PCM_HW_PARAM_CHANNELS:
+               return snd_pcm_hw_info_rules_channels(pcm, info, params, count, rules);
+       case SND_PCM_HW_PARAM_RATE:
+               return snd_pcm_hw_info_rules_rate(pcm, info, params, count, rules);
+       case SND_PCM_HW_PARAM_FRAGMENT_SIZE:
+               return snd_pcm_hw_info_rules_fragment_size(pcm, info, params, count, rules);
+       case SND_PCM_HW_PARAM_FRAGMENTS:
+               return snd_pcm_hw_info_rules_fragments(pcm, info, params, count, rules);
+       default:
+               assert(0);
+               return -EINVAL;
+       }
+}
+
+int snd_pcm_hw_info_rulesv(snd_pcm_t *pcm, 
+                          snd_pcm_hw_info_t *info,
+                          snd_pcm_hw_params_t *params, ...)
+{
+       va_list arg;
+       unsigned int count = 0;
+       int rules[32];
+       va_start(arg, params);
+       while (1) {
+               int i = va_arg(arg, int);
+               if (i == -1)
+                       break;
+               rules[count++] = i;
+       }
+       va_end(arg);
+       return snd_pcm_hw_info_rules(pcm, info, params, count, rules);
+}
+
+int snd_pcm_hw_params_rules(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
+                           unsigned int count, int *rules)
+{
+       int err;
+       snd_pcm_hw_info_t info;
+       unsigned int k;
+       snd_pcm_hw_params_to_info(params, &info);
+       for (k = 0; k < count; ++k) {
+               switch (rules[k] & SND_PCM_RULE_PAR_MASK) {
+               case SND_PCM_HW_PARAM_ACCESS:
+                       info.access_mask = ~0;
+                       break;
+               case SND_PCM_HW_PARAM_FORMAT:
+                       info.format_mask = ~0;
+                       break;
+               case SND_PCM_HW_PARAM_SUBFORMAT:
+                       info.subformat_mask = ~0;
+                       break;
+               case SND_PCM_HW_PARAM_CHANNELS:
+                       info.channels_min = 0;
+                       info.channels_max = UINT_MAX;
+                       break;
+               case SND_PCM_HW_PARAM_RATE:
+                       info.rate_min = 0;
+                       info.rate_max = UINT_MAX;
+                       break;
+               case SND_PCM_HW_PARAM_FRAGMENT_SIZE:
+                       info.fragment_size_min = 0;
+                       info.fragment_size_max = ULONG_MAX;
+                       break;
+               case SND_PCM_HW_PARAM_FRAGMENTS:
+                       info.fragments_min = 0;
+                       info.fragments_max = UINT_MAX;
+                       break;
+               default:
+                       assert(0);
+                       break;
+               }
+       }
+       err = snd_pcm_hw_info_rules(pcm, &info, params, count, rules);
+       if (err < 0) {
+               snd_pcm_hw_info_to_params_fail(&info, params);
+               return err;
+       }
+       snd_pcm_hw_info_to_params(&info, params);
+       return snd_pcm_hw_params(pcm, params);
+}
+
+int snd_pcm_hw_params_rulesv(snd_pcm_t *pcm, 
+                            snd_pcm_hw_params_t *params, ...)
 {
        va_list arg;
-       va_start(arg, fmt);
-       fprintf(stderr, "ALSA PCM lib %s:%i:(%s) ", file, line, function);
-       vfprintf(stderr, fmt, arg);
-       if (err)
-               fprintf(stderr, ": %s", snd_strerror(err));
-       putc('\n', stderr);
+       unsigned int count = 0;
+       int rules[32];
+       va_start(arg, params);
+       while (1) {
+               int i = va_arg(arg, int);
+               if (i == -1)
+                       break;
+               rules[count++] = i;
+       }
        va_end(arg);
+       return snd_pcm_hw_params_rules(pcm, params, count, rules);
 }
+
index 2c58b1da9bfa8f68bb0de408084a7203458f24b5..d6be0e576627ad9dc4d7685addf8cc7550814773 100644 (file)
@@ -69,8 +69,6 @@ typedef struct {
        int getput_idx;
        adpcm_f func;
        int sformat;
-       int cformat;
-       int cxfer_mode, cmmap_shape;
        adpcm_state_t *states;
 } snd_pcm_adpcm_t;
 
@@ -331,102 +329,82 @@ static int snd_pcm_adpcm_close(snd_pcm_t *pcm)
        return 0;
 }
 
-static int snd_pcm_adpcm_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+static int snd_pcm_adpcm_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
 {
        snd_pcm_adpcm_t *adpcm = pcm->private;
-       unsigned int req_mask = info->req_mask;
-       unsigned int sfmt = info->req.format.sfmt;
+       unsigned int format_mask, access_mask;
        int err;
-       if (req_mask & SND_PCM_PARAMS_SFMT) {
-               if (adpcm->sformat == SND_PCM_SFMT_IMA_ADPCM ?
-                   !snd_pcm_format_linear(sfmt) :
-                   sfmt != SND_PCM_SFMT_IMA_ADPCM) {
-                       info->req.fail_mask = SND_PCM_PARAMS_SFMT;
-                       info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
-                       return -EINVAL;
-               }
+       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;
+
+       info->format_mask = 1U << adpcm->sformat;
+       info->access_mask = SND_PCM_ACCBIT_MMAP;
+       err = snd_pcm_hw_info(adpcm->plug.slave, info);
+       if (info->format_mask)
+               info->format_mask = format_mask;
+       if (info->access_mask) {
+               adpcm->plug.saccess_mask = info->access_mask;
+               info->access_mask = access_mask;
        }
-       info->req_mask |= SND_PCM_PARAMS_SFMT;
-       info->req_mask &= ~(SND_PCM_PARAMS_MMAP_SHAPE | 
-                           SND_PCM_PARAMS_XFER_MODE);
-       info->req.format.sfmt = adpcm->sformat;
-       err = snd_pcm_params_info(adpcm->plug.slave, info);
-       info->req_mask = req_mask;
-       info->req.format.sfmt = sfmt;
        if (err < 0)
                return err;
-       if (req_mask & SND_PCM_PARAMS_SFMT)
-               info->formats = 1 << sfmt;
-       else
-               info->formats = adpcm->sformat == SND_PCM_SFMT_IMA_ADPCM ?
-                       SND_PCM_LINEAR_FORMATS : 1 << SND_PCM_SFMT_IMA_ADPCM;
-       info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
-       info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
-       return err;
+       info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+       snd_pcm_hw_info_complete(info);
+       return 0;
 }
 
-static int snd_pcm_adpcm_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+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;
+       unsigned int format, access;
        int err;
-       if (adpcm->sformat == SND_PCM_SFMT_IMA_ADPCM ?
-           !snd_pcm_format_linear(params->format.sfmt) :
-           params->format.sfmt != SND_PCM_SFMT_IMA_ADPCM) {
-               params->fail_mask = SND_PCM_PARAMS_SFMT;
-               params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
-               return -EINVAL;
-       }
-       adpcm->cformat = params->format.sfmt;
-       adpcm->cxfer_mode = params->xfer_mode;
-       adpcm->cmmap_shape = params->mmap_shape;
-       params->format.sfmt = adpcm->sformat;
-       params->xfer_mode = SND_PCM_XFER_UNSPECIFIED;
-       params->mmap_shape = SND_PCM_MMAP_UNSPECIFIED;
-       err = snd_pcm_params_mmap(slave, params);
-       params->format.sfmt = adpcm->cformat;
-       params->xfer_mode = adpcm->cxfer_mode;
-       params->mmap_shape = adpcm->cmmap_shape;
-       return err;
-}
-
-static int snd_pcm_adpcm_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
-{
-       snd_pcm_adpcm_t *adpcm = pcm->private;
-       int err = snd_pcm_setup(adpcm->plug.slave, setup);
+       format = params->format;
+       access = params->access;
+       params->format = adpcm->sformat;
+       if (adpcm->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
+               params->access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
+       else if (adpcm->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
+               params->access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
+       else
+               assert(0);
+       err = snd_pcm_hw_params(slave, params);
+       params->format = format;
+       params->access = access;
        if (err < 0)
                return err;
-       assert(adpcm->sformat == setup->format.sfmt);
-       if (adpcm->cxfer_mode == SND_PCM_XFER_UNSPECIFIED)
-               setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
-       else
-               setup->xfer_mode = adpcm->cxfer_mode;
-       if (adpcm->cmmap_shape == SND_PCM_MMAP_UNSPECIFIED)
-               setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
-       else
-               setup->mmap_shape = adpcm->cmmap_shape;
-       setup->format.sfmt = adpcm->cformat;
-       setup->mmap_bytes = 0;
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
-               if (adpcm->sformat == SND_PCM_SFMT_IMA_ADPCM) {
-                       adpcm->getput_idx = get_index(adpcm->cformat, SND_PCM_SFMT_S16);
+               if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) {
+                       adpcm->getput_idx = get_index(format, SND_PCM_FORMAT_S16);
                        adpcm->func = adpcm_encode;
                } else {
-                       adpcm->getput_idx = put_index(SND_PCM_SFMT_S16, adpcm->sformat);
+                       adpcm->getput_idx = put_index(SND_PCM_FORMAT_S16, adpcm->sformat);
                        adpcm->func = adpcm_decode;
                }
        } else {
-               if (adpcm->sformat == SND_PCM_SFMT_IMA_ADPCM) {
-                       adpcm->getput_idx = put_index(SND_PCM_SFMT_S16, adpcm->cformat);
+               if (adpcm->sformat == SND_PCM_FORMAT_IMA_ADPCM) {
+                       adpcm->getput_idx = put_index(SND_PCM_FORMAT_S16, format);
                        adpcm->func = adpcm_decode;
                } else {
-                       adpcm->getput_idx = get_index(adpcm->sformat, SND_PCM_SFMT_S16);
+                       adpcm->getput_idx = get_index(adpcm->sformat, SND_PCM_FORMAT_S16);
                        adpcm->func = adpcm_encode;
                }
        }
        if (adpcm->states)
                free(adpcm->states);
-       adpcm->states = malloc(setup->format.channels * sizeof(*adpcm->states));
+       adpcm->states = malloc(params->channels * sizeof(*adpcm->states));
        return 0;
 }
 
@@ -434,7 +412,7 @@ static int snd_pcm_adpcm_init(snd_pcm_t *pcm)
 {
        snd_pcm_adpcm_t *adpcm = pcm->private;
        unsigned int k;
-       for (k = 0; k < pcm->setup.format.channels; ++k) {
+       for (k = 0; k < pcm->channels; ++k) {
                adpcm->states[k].pred_val = 0;
                adpcm->states[k].step_idx = 0;
        }
@@ -458,7 +436,7 @@ static ssize_t snd_pcm_adpcm_write_areas(snd_pcm_t *pcm,
                size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
                adpcm->func(areas, offset, 
                            snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
-                           frames, pcm->setup.format.channels,
+                           frames, pcm->channels,
                            adpcm->getput_idx, adpcm->states);
                err = snd_pcm_mmap_forward(slave, frames);
                if (err < 0)
@@ -493,7 +471,7 @@ static ssize_t snd_pcm_adpcm_read_areas(snd_pcm_t *pcm,
                size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
                adpcm->func(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
                            areas, offset, 
-                           frames, pcm->setup.format.channels,
+                           frames, pcm->channels,
                            adpcm->getput_idx, adpcm->states);
                err = snd_pcm_mmap_forward(slave, frames);
                if (err < 0)
@@ -516,7 +494,7 @@ static void snd_pcm_adpcm_dump(snd_pcm_t *pcm, FILE *fp)
        snd_pcm_adpcm_t *adpcm = pcm->private;
        fprintf(fp, "Ima-ADPCM conversion PCM (%s)\n", 
                snd_pcm_format_name(adpcm->sformat));
-       if (pcm->valid_setup) {
+       if (pcm->setup) {
                fprintf(fp, "Its setup is:\n");
                snd_pcm_dump_setup(pcm, fp);
        }
@@ -527,12 +505,12 @@ 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,
-       params_info: snd_pcm_adpcm_params_info,
-       params: snd_pcm_adpcm_params,
-       setup: snd_pcm_adpcm_setup,
+       hw_info: snd_pcm_adpcm_hw_info,
+       hw_params: snd_pcm_adpcm_hw_params,
+       sw_params: snd_pcm_plugin_sw_params,
+       dig_info: snd_pcm_plugin_dig_info,
+       dig_params: snd_pcm_plugin_dig_params,
        channel_info: snd_pcm_plugin_channel_info,
-       channel_params: snd_pcm_plugin_channel_params,
-       channel_setup: snd_pcm_plugin_channel_setup,
        dump: snd_pcm_adpcm_dump,
        nonblock: snd_pcm_plugin_nonblock,
        async: snd_pcm_plugin_async,
@@ -546,7 +524,7 @@ int snd_pcm_adpcm_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *sla
        snd_pcm_adpcm_t *adpcm;
        assert(pcmp && slave);
        if (snd_pcm_format_linear(sformat) != 1 &&
-           sformat != SND_PCM_SFMT_IMA_ADPCM)
+           sformat != SND_PCM_FORMAT_IMA_ADPCM)
                return -EINVAL;
        adpcm = calloc(1, sizeof(snd_pcm_adpcm_t));
        if (!adpcm) {
@@ -614,7 +592,7 @@ int _snd_pcm_adpcm_open(snd_pcm_t **pcmp, char *name,
                        if (sformat < 0)
                                return -EINVAL;
                        if (snd_pcm_format_linear(sformat) != 1 &&
-                           sformat != SND_PCM_SFMT_IMA_ADPCM)
+                           sformat != SND_PCM_FORMAT_IMA_ADPCM)
                                return -EINVAL;
                        continue;
                }
index de8f944ed8dfa2fcd93b77197cafaaf0794b753e..fd5f619ccc660ad0f6150861113df37f4be01a35 100644 (file)
@@ -35,8 +35,6 @@ typedef struct {
        int getput_idx;
        alaw_f func;
        int sformat;
-       int cformat;
-       int cxfer_mode, cmmap_shape;
 } snd_pcm_alaw_t;
 
 static inline int val_seg(int val)
@@ -213,96 +211,76 @@ static void alaw_encode(snd_pcm_channel_area_t *src_areas,
        }
 }
 
-static int snd_pcm_alaw_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+static int snd_pcm_alaw_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
 {
        snd_pcm_alaw_t *alaw = pcm->private;
-       unsigned int req_mask = info->req_mask;
-       unsigned int sfmt = info->req.format.sfmt;
+       unsigned int format_mask, access_mask;
        int err;
-       if (req_mask & SND_PCM_PARAMS_SFMT) {
-               if (alaw->sformat == SND_PCM_SFMT_A_LAW ?
-                   !snd_pcm_format_linear(sfmt) :
-                   sfmt != SND_PCM_SFMT_A_LAW) {
-                       info->req.fail_mask = SND_PCM_PARAMS_SFMT;
-                       info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
-                       return -EINVAL;
-               }
+       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;
+
+       info->format_mask = 1U << alaw->sformat;
+       info->access_mask = SND_PCM_ACCBIT_MMAP;
+       err = snd_pcm_hw_info(alaw->plug.slave, info);
+       if (info->format_mask)
+               info->format_mask = format_mask;
+       if (info->access_mask) {
+               alaw->plug.saccess_mask = info->access_mask;
+               info->access_mask = access_mask;
        }
-       info->req_mask |= SND_PCM_PARAMS_SFMT;
-       info->req_mask &= ~(SND_PCM_PARAMS_MMAP_SHAPE | 
-                           SND_PCM_PARAMS_XFER_MODE);
-       info->req.format.sfmt = alaw->sformat;
-       err = snd_pcm_params_info(alaw->plug.slave, info);
-       info->req_mask = req_mask;
-       info->req.format.sfmt = sfmt;
        if (err < 0)
                return err;
-       if (req_mask & SND_PCM_PARAMS_SFMT)
-               info->formats = 1 << sfmt;
-       else
-               info->formats = alaw->sformat == SND_PCM_SFMT_A_LAW ?
-                       SND_PCM_LINEAR_FORMATS : 1 << SND_PCM_SFMT_A_LAW;
-       info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
-       info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
-       return err;
+       info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+       snd_pcm_hw_info_complete(info);
+       return 0;
 }
 
-static int snd_pcm_alaw_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+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;
+       unsigned int format, access;
        int err;
-       if (alaw->sformat == SND_PCM_SFMT_A_LAW ?
-           !snd_pcm_format_linear(params->format.sfmt) :
-           params->format.sfmt != SND_PCM_SFMT_A_LAW) {
-               params->fail_mask = SND_PCM_PARAMS_SFMT;
-               params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
-               return -EINVAL;
-       }
-       alaw->cformat = params->format.sfmt;
-       alaw->cxfer_mode = params->xfer_mode;
-       alaw->cmmap_shape = params->mmap_shape;
-       params->format.sfmt = alaw->sformat;
-       params->xfer_mode = SND_PCM_XFER_UNSPECIFIED;
-       params->mmap_shape = SND_PCM_MMAP_UNSPECIFIED;
-       err = snd_pcm_params_mmap(slave, params);
-       params->format.sfmt = alaw->cformat;
-       params->xfer_mode = alaw->cxfer_mode;
-       params->mmap_shape = alaw->cmmap_shape;
-       return err;
-}
-
-static int snd_pcm_alaw_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
-{
-       snd_pcm_alaw_t *alaw = pcm->private;
-       int err = snd_pcm_setup(alaw->plug.slave, setup);
+       format = params->format;
+       access = params->access;
+       params->format = alaw->sformat;
+       if (alaw->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
+               params->access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
+       else if (alaw->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
+               params->access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
+       else
+               assert(0);
+       err = snd_pcm_hw_params(slave, params);
+       params->format = format;
+       params->access = access;
        if (err < 0)
                return err;
-       assert(alaw->sformat == setup->format.sfmt);
-       if (alaw->cxfer_mode == SND_PCM_XFER_UNSPECIFIED)
-               setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
-       else
-               setup->xfer_mode = alaw->cxfer_mode;
-       if (alaw->cmmap_shape == SND_PCM_MMAP_UNSPECIFIED)
-               setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
-       else
-               setup->mmap_shape = alaw->cmmap_shape;
-       setup->format.sfmt = alaw->cformat;
-       setup->mmap_bytes = 0;
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
-               if (alaw->sformat == SND_PCM_SFMT_A_LAW) {
-                       alaw->getput_idx = get_index(alaw->cformat, SND_PCM_SFMT_S16);
+               if (alaw->sformat == SND_PCM_FORMAT_MU_LAW) {
+                       alaw->getput_idx = get_index(format, SND_PCM_FORMAT_S16);
                        alaw->func = alaw_encode;
                } else {
-                       alaw->getput_idx = put_index(SND_PCM_SFMT_S16, alaw->sformat);
+                       alaw->getput_idx = put_index(SND_PCM_FORMAT_S16, alaw->sformat);
                        alaw->func = alaw_decode;
                }
        } else {
-               if (alaw->sformat == SND_PCM_SFMT_A_LAW) {
-                       alaw->getput_idx = put_index(SND_PCM_SFMT_S16, alaw->cformat);
+               if (alaw->sformat == SND_PCM_FORMAT_MU_LAW) {
+                       alaw->getput_idx = put_index(SND_PCM_FORMAT_S16, format);
                        alaw->func = alaw_decode;
                } else {
-                       alaw->getput_idx = get_index(alaw->sformat, SND_PCM_SFMT_S16);
+                       alaw->getput_idx = get_index(alaw->sformat, SND_PCM_FORMAT_S16);
                        alaw->func = alaw_encode;
                }
        }
@@ -326,7 +304,7 @@ static ssize_t snd_pcm_alaw_write_areas(snd_pcm_t *pcm,
                size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
                alaw->func(areas, offset, 
                            snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
-                           frames, pcm->setup.format.channels,
+                           frames, pcm->channels,
                            alaw->getput_idx);
                err = snd_pcm_mmap_forward(slave, frames);
                if (err < 0)
@@ -361,7 +339,7 @@ static ssize_t snd_pcm_alaw_read_areas(snd_pcm_t *pcm,
                size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
                alaw->func(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
                           areas, offset, 
-                          frames, pcm->setup.format.channels,
+                          frames, pcm->channels,
                           alaw->getput_idx);
                err = snd_pcm_mmap_forward(slave, frames);
                if (err < 0)
@@ -384,7 +362,7 @@ static void snd_pcm_alaw_dump(snd_pcm_t *pcm, FILE *fp)
        snd_pcm_alaw_t *alaw = pcm->private;
        fprintf(fp, "A-Law conversion PCM (%s)\n", 
                snd_pcm_format_name(alaw->sformat));
-       if (pcm->valid_setup) {
+       if (pcm->setup) {
                fprintf(fp, "Its setup is:\n");
                snd_pcm_dump_setup(pcm, fp);
        }
@@ -395,12 +373,12 @@ 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,
-       params_info: snd_pcm_alaw_params_info,
-       params: snd_pcm_alaw_params,
-       setup: snd_pcm_alaw_setup,
+       hw_info: snd_pcm_alaw_hw_info,
+       hw_params: snd_pcm_alaw_hw_params,
+       sw_params: snd_pcm_plugin_sw_params,
+       dig_info: snd_pcm_plugin_dig_info,
+       dig_params: snd_pcm_plugin_dig_params,
        channel_info: snd_pcm_plugin_channel_info,
-       channel_params: snd_pcm_plugin_channel_params,
-       channel_setup: snd_pcm_plugin_channel_setup,
        dump: snd_pcm_alaw_dump,
        nonblock: snd_pcm_plugin_nonblock,
        async: snd_pcm_plugin_async,
@@ -414,7 +392,7 @@ int snd_pcm_alaw_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slav
        snd_pcm_alaw_t *alaw;
        assert(pcmp && slave);
        if (snd_pcm_format_linear(sformat) != 1 &&
-           sformat != SND_PCM_SFMT_A_LAW)
+           sformat != SND_PCM_FORMAT_A_LAW)
                return -EINVAL;
        alaw = calloc(1, sizeof(snd_pcm_alaw_t));
        if (!alaw) {
@@ -481,7 +459,7 @@ int _snd_pcm_alaw_open(snd_pcm_t **pcmp, char *name,
                        if (sformat < 0)
                                return -EINVAL;
                        if (snd_pcm_format_linear(sformat) != 1 &&
-                           sformat != SND_PCM_SFMT_A_LAW)
+                           sformat != SND_PCM_FORMAT_A_LAW)
                                return -EINVAL;
                        continue;
                }
index 192bccc616b902b0bc9beb208961bf45546357aa..4130812e1a39ca333aa3e4609e67254960d626d3 100644 (file)
 #include "pcm_local.h"
 #include "pcm_plugin.h"
 
+enum {
+       SND_PCM_FILE_FORMAT_RAW
+};
+
 typedef struct {
        snd_pcm_t *slave;
        int close_slave;
        char *fname;
        int fd;
+       int format;
 } snd_pcm_file_t;
 
 static int snd_pcm_file_close(snd_pcm_t *pcm)
@@ -68,18 +73,6 @@ static int snd_pcm_file_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * in
        return snd_pcm_channel_info(file->slave, info);
 }
 
-static int snd_pcm_file_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t * params)
-{
-       snd_pcm_file_t *file = pcm->private;
-       return snd_pcm_channel_params(file->slave, params);
-}
-
-static int snd_pcm_file_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
-{
-       snd_pcm_file_t *file = pcm->private;
-       return snd_pcm_channel_setup(file->slave, setup);
-}
-
 static int snd_pcm_file_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
 {
        snd_pcm_file_t *file = pcm->private;
@@ -148,11 +141,16 @@ static void snd_pcm_file_write_areas(snd_pcm_t *pcm,
        snd_pcm_file_t *file = pcm->private;
        size_t bytes = snd_pcm_frames_to_bytes(pcm, frames);
        char *buf;
-       size_t channels = pcm->setup.format.channels;
+       size_t channels = pcm->channels;
        snd_pcm_channel_area_t buf_areas[channels];
        size_t channel;
        ssize_t r;
-       if (pcm->setup.mmap_shape != SND_PCM_MMAP_INTERLEAVED) {
+       switch (pcm->access) {
+       case SND_PCM_ACCESS_MMAP_INTERLEAVED:
+       case SND_PCM_ACCESS_RW_INTERLEAVED:
+               buf = snd_pcm_channel_area_addr(areas, offset);
+               break;
+       default:
                buf = alloca(bytes);
                for (channel = 0; channel < channels; ++channel) {
                        snd_pcm_channel_area_t *a = &buf_areas[channel];
@@ -161,9 +159,8 @@ static void snd_pcm_file_write_areas(snd_pcm_t *pcm,
                        a->step = pcm->bits_per_frame;
                }
                snd_pcm_areas_copy(areas, offset, buf_areas, 0, 
-                                  channels, frames, pcm->setup.format.sfmt);
-       } else
-               buf = snd_pcm_channel_area_addr(areas, offset);
+                                  channels, frames, pcm->format);
+       }
        r = write(file->fd, buf, bytes);
        assert(r == (ssize_t)bytes);
 }
@@ -183,7 +180,7 @@ static ssize_t snd_pcm_file_writei(snd_pcm_t *pcm, const void *buffer, size_t si
 static ssize_t snd_pcm_file_writen(snd_pcm_t *pcm, void **bufs, size_t size)
 {
        snd_pcm_file_t *file = pcm->private;
-       snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+       snd_pcm_channel_area_t areas[pcm->channels];
        ssize_t n = snd_pcm_writen(file->slave, bufs, size);
        if (n > 0) {
                snd_pcm_areas_from_bufs(pcm, areas, bufs);
@@ -207,7 +204,7 @@ static ssize_t snd_pcm_file_readi(snd_pcm_t *pcm, void *buffer, size_t size)
 static ssize_t snd_pcm_file_readn(snd_pcm_t *pcm, void **bufs, size_t size)
 {
        snd_pcm_file_t *file = pcm->private;
-       snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+       snd_pcm_channel_area_t areas[pcm->channels];
        ssize_t n = snd_pcm_writen(file->slave, bufs, size);
        if (n > 0) {
                snd_pcm_areas_from_bufs(pcm, areas, bufs);
@@ -226,12 +223,12 @@ static ssize_t snd_pcm_file_mmap_forward(snd_pcm_t *pcm, size_t size)
                return n;
        while (xfer < (size_t)n) {
                size_t frames = size - xfer;
-               size_t cont = pcm->setup.buffer_size - ofs;
+               size_t cont = pcm->buffer_size - ofs;
                if (cont < frames)
                        frames = cont;
                snd_pcm_file_write_areas(pcm, snd_pcm_mmap_areas(file->slave), ofs, frames);
                ofs += frames;
-               if (ofs == pcm->setup.buffer_size)
+               if (ofs == pcm->buffer_size)
                        ofs = 0;
                xfer += frames;
        }
@@ -250,44 +247,46 @@ 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_mmap(snd_pcm_t *pcm)
+static int snd_pcm_file_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
 {
        snd_pcm_file_t *file = pcm->private;
-       int err = snd_pcm_mmap(file->slave);
-       if (err < 0)
-               return err;
-       pcm->mmap_info_count = file->slave->mmap_info_count;
-       pcm->mmap_info = file->slave->mmap_info;
-       return 0;
+       return snd_pcm_hw_info(file->slave, info);
 }
 
-static int snd_pcm_file_munmap(snd_pcm_t *pcm)
+static int snd_pcm_file_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params)
 {
        snd_pcm_file_t *file = pcm->private;
-       int err = snd_pcm_munmap(file->slave);
-       if (err < 0)
-               return err;
-       pcm->mmap_info_count = 0;
-       pcm->mmap_info = 0;
-       return 0;
+       return snd_pcm_hw_params(file->slave, params);
+}
+
+static int snd_pcm_file_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
+{
+       snd_pcm_file_t *file = pcm->private;
+       return snd_pcm_sw_params(file->slave, params);
+}
+
+static int snd_pcm_file_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t * info)
+{
+       snd_pcm_file_t *file = pcm->private;
+       return snd_pcm_dig_info(file->slave, info);
 }
 
-static int snd_pcm_file_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+static int snd_pcm_file_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t * params)
 {
        snd_pcm_file_t *file = pcm->private;
-       return snd_pcm_params_info(file->slave, info);
+       return snd_pcm_dig_params(file->slave, params);
 }
 
-static int snd_pcm_file_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+static int snd_pcm_file_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
 {
        snd_pcm_file_t *file = pcm->private;
-       return snd_pcm_params(file->slave, params);
+       return snd_pcm_mmap(file->slave);
 }
 
-static int snd_pcm_file_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
+static int snd_pcm_file_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
 {
        snd_pcm_file_t *file = pcm->private;
-       return snd_pcm_setup(file->slave, setup);
+       return snd_pcm_munmap(file->slave);
 }
 
 static void snd_pcm_file_dump(snd_pcm_t *pcm, FILE *fp)
@@ -297,7 +296,7 @@ static void snd_pcm_file_dump(snd_pcm_t *pcm, FILE *fp)
                fprintf(fp, "File PCM (file=%s)\n", file->fname);
        else
                fprintf(fp, "File PCM (fd=%d)\n", file->fd);
-       if (pcm->valid_setup) {
+       if (pcm->setup) {
                fprintf(fp, "Its setup is:\n");
                snd_pcm_dump_setup(pcm, fp);
        }
@@ -308,12 +307,12 @@ 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,
-       params_info: snd_pcm_file_params_info,
-       params: snd_pcm_file_params,
-       setup: snd_pcm_file_setup,
+       hw_info: snd_pcm_file_hw_info,
+       hw_params: snd_pcm_file_hw_params,
+       sw_params: snd_pcm_file_sw_params,
+       dig_info: snd_pcm_file_dig_info,
+       dig_params: snd_pcm_file_dig_params,
        channel_info: snd_pcm_file_channel_info,
-       channel_params: snd_pcm_file_channel_params,
-       channel_setup: snd_pcm_file_channel_setup,
        dump: snd_pcm_file_dump,
        nonblock: snd_pcm_file_nonblock,
        async: snd_pcm_file_async,
@@ -340,11 +339,11 @@ snd_pcm_fast_ops_t snd_pcm_file_fast_ops = {
        set_avail_min: snd_pcm_file_set_avail_min,
 };
 
-int snd_pcm_file_open(snd_pcm_t **pcmp, char *name, char *fname, int fd, snd_pcm_t *slave, int close_slave)
+int snd_pcm_file_open(snd_pcm_t **pcmp, char *name, char *fname, int fd, char *fmt, snd_pcm_t *slave, int close_slave)
 {
        snd_pcm_t *pcm;
        snd_pcm_file_t *file;
-       assert(pcmp && slave);
+       assert(pcmp);
        if (fname) {
                fd = open(fname, O_WRONLY|O_CREAT, 0666);
                if (fd < 0) {
@@ -354,8 +353,16 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, char *name, char *fname, int fd, snd_pcm
        }
        file = calloc(1, sizeof(snd_pcm_file_t));
        if (!file) {
+               if (fname)
+                       close(fd);
                return -ENOMEM;
        }
+       if (fmt == NULL ||
+           strcmp(fmt, "raw") == 0)
+               file->format = SND_PCM_FILE_FORMAT_RAW;
+       else
+               ERR("file format %s is unknown", fmt);
+
        file->fname = fname;
        file->fd = fd;
        file->slave = slave;
@@ -393,6 +400,7 @@ int _snd_pcm_file_open(snd_pcm_t **pcmp, char *name,
        int err;
        snd_pcm_t *spcm;
        char *fname = NULL;
+       char *format = NULL;
        long fd = -1;
        snd_config_foreach(i, conf) {
                snd_config_t *n = snd_config_entry(i);
@@ -408,6 +416,12 @@ int _snd_pcm_file_open(snd_pcm_t **pcmp, char *name,
                                return -EINVAL;
                        continue;
                }
+               if (strcmp(n->id, "format") == 0) {
+                       err = snd_config_string_get(n, &format);
+                       if (err < 0)
+                               return -EINVAL;
+                       continue;
+               }
                if (strcmp(n->id, "file") == 0) {
                        err = snd_config_string_get(n, &fname);
                        if (err < 0) {
@@ -434,7 +448,7 @@ int _snd_pcm_file_open(snd_pcm_t **pcmp, char *name,
        free(sname);
        if (err < 0)
                return err;
-       err = snd_pcm_file_open(pcmp, name, fname, fd, spcm, 1);
+       err = snd_pcm_file_open(pcmp, name, fname, fd, format, spcm, 1);
        if (err < 0)
                snd_pcm_close(spcm);
        return err;
index 63eb82bb848bd1ad1dfca12e149bf527b9c9939d..f9bf3ba24528f6baa4530e6f284d62281b3bac86 100644 (file)
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <sys/shm.h>
+#include <asm/page.h>
 #include "pcm_local.h"
+#include "../control/control_local.h"
 
 #ifndef F_SETSIG
 #define F_SETSIG 10
 #endif
 
+#ifndef PAGE_ALIGN
+#define PAGE_ALIGN(addr)        (((addr)+PAGE_SIZE-1)&PAGE_MASK)
+#endif
+
 typedef struct {
        int fd;
        int card, device, subdevice;
        volatile snd_pcm_mmap_status_t *mmap_status;
        snd_pcm_mmap_control_t *mmap_control;
+       int shmid;
 } snd_pcm_hw_t;
 
 #define SND_FILE_PCM_STREAM_PLAYBACK           "/dev/snd/pcmC%iD%ip"
@@ -102,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;
@@ -113,93 +120,82 @@ static int snd_pcm_hw_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
        return 0;
 }
 
-static int snd_pcm_hw_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+static int snd_pcm_hw_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
 {
        snd_pcm_hw_t *hw = pcm->private;
        int fd = hw->fd;
-       if (ioctl(fd, SND_PCM_IOCTL_PARAMS_INFO, info) < 0) {
-               SYSERR("SND_PCM_IOCTL_PARAMS_INFO failed");
+       if (ioctl(fd, SND_PCM_IOCTL_HW_INFO, info) < 0) {
+               // SYSERR("SND_PCM_IOCTL_HW_INFO failed");
                return -errno;
        }
        return 0;
 }
 
-static int snd_pcm_hw_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+static int snd_pcm_hw_hw_params(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_PARAMS, params) < 0) {
-               SYSERR("SND_PCM_IOCTL_PARAMS failed");
+       if (ioctl(fd, SND_PCM_IOCTL_HW_PARAMS, params) < 0) {
+               SYSERR("SND_PCM_IOCTL_HW_PARAMS failed");
                return -errno;
        }
        return 0;
 }
 
-static int snd_pcm_hw_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
+static int snd_pcm_hw_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
 {
        snd_pcm_hw_t *hw = pcm->private;
        int fd = hw->fd;
-       if (ioctl(fd, SND_PCM_IOCTL_SETUP, setup) < 0) {
-               SYSERR("SND_PCM_IOCTL_SETUP failed");
+       if (ioctl(fd, SND_PCM_IOCTL_SW_PARAMS, params) < 0) {
+               SYSERR("SND_PCM_IOCTL_SW_PARAMS failed");
                return -errno;
        }
-       if (setup->mmap_shape == SND_PCM_MMAP_UNSPECIFIED) {
-               if (setup->xfer_mode == SND_PCM_XFER_INTERLEAVED)
-                       setup->mmap_shape = SND_PCM_MMAP_INTERLEAVED;
-               else
-                       setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
-       }
        return 0;
 }
 
-static int snd_pcm_hw_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
+static int snd_pcm_hw_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t * info)
 {
        snd_pcm_hw_t *hw = pcm->private;
        int fd = hw->fd;
-       if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_INFO, info) < 0) {
-               SYSERR("SND_PCM_IOCTL_CHANNEL_INFO failed");
+       if (ioctl(fd, SND_PCM_IOCTL_DIG_INFO, info) < 0) {
+               SYSERR("SND_PCM_IOCTL_DIG_INFO failed");
                return -errno;
        }
        return 0;
 }
 
-static int snd_pcm_hw_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t * params)
+static int snd_pcm_hw_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t * params)
 {
        snd_pcm_hw_t *hw = pcm->private;
        int fd = hw->fd;
-       if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_PARAMS, params) < 0) {
-               SYSERR("SND_PCM_IOCTL_CHANNEL_PARAMS failed");
+       if (ioctl(fd, SND_PCM_IOCTL_DIG_PARAMS, params) < 0) {
+               SYSERR("SND_PCM_IOCTL_DIG_PARAMS failed");
                return -errno;
        }
        return 0;
 }
 
-static int snd_pcm_hw_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
+static int snd_pcm_hw_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
 {
        snd_pcm_hw_t *hw = pcm->private;
+       snd_pcm_hw_channel_info_t hw_info;
        int fd = hw->fd;
-       if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_SETUP, setup) < 0) {
-               SYSERR("SND_PCM_IOCTL_CHANNEL_SETUP failed");
+       hw_info.channel = info->channel;
+       if (ioctl(fd, SND_PCM_IOCTL_CHANNEL_INFO, &hw_info) < 0) {
+               SYSERR("SND_PCM_IOCTL_CHANNEL_INFO failed");
                return -errno;
        }
-       if (!pcm->mmap_info)
+       info->channel = hw_info.channel;
+       if (pcm->info & SND_PCM_INFO_MMAP) {
+               info->addr = 0;
+               info->first = hw_info.first;
+               info->step = hw_info.step;
+               info->type = SND_PCM_AREA_MMAP;
+               info->u.mmap.fd = fd;
+               info->u.mmap.offset = hw_info.offset;
                return 0;
-       if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) {
-               if (pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED) {
-                       setup->running_area.addr = pcm->mmap_info->addr;
-                       setup->running_area.first = setup->channel * pcm->bits_per_sample;
-                       setup->running_area.step = pcm->bits_per_frame;
-               } else {
-                       setup->running_area.addr = pcm->mmap_info->addr + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
-                       setup->running_area.first = 0;
-                       setup->running_area.step = pcm->bits_per_sample;
-               }
-               setup->stopped_area = setup->running_area;
-       } else {
-               setup->running_area.addr = pcm->mmap_info->addr + (long)setup->running_area.addr;
-               setup->stopped_area.addr = setup->running_area.addr;
        }
-       return 0;
+       return snd_pcm_channel_info_shm(pcm, info, hw->shmid);
 }
 
 static int snd_pcm_hw_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
@@ -245,6 +241,8 @@ static int snd_pcm_hw_start(snd_pcm_t *pcm)
 {
        snd_pcm_hw_t *hw = pcm->private;
        int fd = hw->fd;
+       assert(pcm->stream != SND_PCM_STREAM_PLAYBACK ||
+              snd_pcm_mmap_playback_hw_avail(pcm) > 0);
        if (ioctl(fd, SND_PCM_IOCTL_START) < 0) {
                SYSERR("SND_PCM_IOCTL_START failed");
                return -errno;
@@ -288,7 +286,7 @@ static int snd_pcm_hw_pause(snd_pcm_t *pcm, int enable)
 static ssize_t snd_pcm_hw_rewind(snd_pcm_t *pcm, size_t frames)
 {
        ssize_t hw_avail;
-       if (pcm->setup.xrun_mode == SND_PCM_XRUN_ASAP) {
+       if (pcm->xrun_mode == SND_PCM_XRUN_ASAP) {
                ssize_t d;
                int err = snd_pcm_hw_delay(pcm, &d);
                if (err < 0)
@@ -363,7 +361,7 @@ static int snd_pcm_hw_mmap_status(snd_pcm_t *pcm)
 {
        snd_pcm_hw_t *hw = pcm->private;
        void *ptr;
-       ptr = mmap(NULL, sizeof(snd_pcm_mmap_status_t), PROT_READ, MAP_FILE|MAP_SHARED, 
+       ptr = mmap(NULL, PAGE_ALIGN(sizeof(snd_pcm_mmap_status_t)), PROT_READ, MAP_FILE|MAP_SHARED, 
                   hw->fd, SND_PCM_MMAP_OFFSET_STATUS);
        if (ptr == MAP_FAILED || ptr == NULL) {
                SYSERR("status mmap failed");
@@ -378,7 +376,7 @@ static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm)
 {
        snd_pcm_hw_t *hw = pcm->private;
        void *ptr;
-       ptr = mmap(NULL, sizeof(snd_pcm_mmap_control_t), PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, 
+       ptr = mmap(NULL, PAGE_ALIGN(sizeof(snd_pcm_mmap_control_t)), PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, 
                   hw->fd, SND_PCM_MMAP_OFFSET_CONTROL);
        if (ptr == MAP_FAILED || ptr == NULL) {
                SYSERR("control mmap failed");
@@ -389,31 +387,6 @@ static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm)
        return 0;
 }
 
-static int snd_pcm_hw_mmap(snd_pcm_t *pcm)
-{
-       snd_pcm_hw_t *hw = pcm->private;
-       snd_pcm_mmap_info_t *i = calloc(1, sizeof(*i));
-       int err;
-       if (!i)
-               return -ENOMEM;
-       if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) {
-               err = snd_pcm_alloc_user_mmap(pcm, i);
-               if (err < 0) {
-                       free(i);
-                       return err;
-               }
-       } else {
-               err = snd_pcm_alloc_kernel_mmap(pcm, i, hw->fd);
-               if (err < 0) {
-                       free(i);
-                       return err;
-               }
-       }
-       pcm->mmap_info = i;
-       pcm->mmap_info_count = 1;
-       return 0;
-}
-
 static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm)
 {
        snd_pcm_hw_t *hw = pcm->private;
@@ -434,34 +407,50 @@ static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm)
        return 0;
 }
 
+static int snd_pcm_hw_mmap(snd_pcm_t *pcm)
+{
+       snd_pcm_hw_t *hw = pcm->private;
+       if (!(pcm->info & SND_PCM_INFO_MMAP)) {
+               size_t size = snd_pcm_frames_to_bytes(pcm, pcm->buffer_size);
+               int id = shmget(IPC_PRIVATE, size, 0666);
+               if (id < 0) {
+                       SYSERR("shmget failed");
+                       return -errno;
+               }
+               hw->shmid = id;
+       }
+       return 0;
+}
+
 static int snd_pcm_hw_munmap(snd_pcm_t *pcm)
 {
-       int err = snd_pcm_free_mmap(pcm, pcm->mmap_info);
-       if (err < 0)
-               return err;
-       pcm->mmap_info_count = 0;
-       free(pcm->mmap_info);
-       pcm->mmap_info = 0;
+       snd_pcm_hw_t *hw = pcm->private;
+       if (!(pcm->info & SND_PCM_INFO_MMAP)) {
+               if (shmctl(hw->shmid, IPC_RMID, 0) < 0) {
+                       SYSERR("shmctl IPC_RMID failed");
+                       return -errno;
+               }
+       }
        return 0;
 }
 
 static int snd_pcm_hw_close(snd_pcm_t *pcm)
 {
        snd_pcm_hw_t *hw = pcm->private;
-       int fd = hw->fd;
-       free(hw);
-       if (close(fd)) {
+       if (close(hw->fd)) {
                SYSERR("close failed\n");
                return -errno;
        }
        snd_pcm_hw_munmap_status(pcm);
        snd_pcm_hw_munmap_control(pcm);
+       free(hw);
        return 0;
 }
 
 static ssize_t snd_pcm_hw_mmap_forward(snd_pcm_t *pcm, size_t size)
 {
-       if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED && pcm->stream == SND_PCM_STREAM_PLAYBACK)
+       if (!(pcm->info & SND_PCM_INFO_MMAP) && 
+           pcm->stream == SND_PCM_STREAM_PLAYBACK)
                return snd_pcm_write_mmap(pcm, size);
        snd_pcm_mmap_appl_forward(pcm, size);
        return size;
@@ -471,8 +460,8 @@ static ssize_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
 {
        size_t avail;
        ssize_t err;
-       if (pcm->setup.ready_mode == SND_PCM_READY_ASAP ||
-           pcm->setup.xrun_mode == SND_PCM_XRUN_ASAP) {
+       if (pcm->ready_mode == SND_PCM_READY_ASAP ||
+           pcm->xrun_mode == SND_PCM_XRUN_ASAP) {
                ssize_t d;
                int err = snd_pcm_hw_delay(pcm, &d);
                if (err < 0)
@@ -482,7 +471,8 @@ static ssize_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
                avail = snd_pcm_mmap_playback_avail(pcm);
        } else {
                avail = snd_pcm_mmap_capture_avail(pcm);
-               if (avail > 0 && pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) {
+               if (avail > 0 && 
+                   !(pcm->info & SND_PCM_INFO_MMAP)) {
                        err = snd_pcm_read_mmap(pcm, avail);
                        if (err < 0)
                                return err;
@@ -490,7 +480,7 @@ static ssize_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
                        return err;
                }
        }
-       if (avail > pcm->setup.buffer_size)
+       if (avail > pcm->buffer_size)
                return -EPIPE;
        return avail;
 }
@@ -510,7 +500,7 @@ static void snd_pcm_hw_dump(snd_pcm_t *pcm, FILE *fp)
        fprintf(fp, "Hardware PCM card %d '%s' device %d subdevice %d\n",
                hw->card, name, hw->device, hw->subdevice);
        free(name);
-       if (pcm->valid_setup) {
+       if (pcm->setup) {
                fprintf(fp, "\nIts setup is:\n");
                snd_pcm_dump_setup(pcm, fp);
        }
@@ -518,13 +508,13 @@ 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,
-       params_info: snd_pcm_hw_params_info,
-       params: snd_pcm_hw_params,
-       setup: snd_pcm_hw_setup,
+       info: _snd_pcm_hw_info,
+       hw_info: snd_pcm_hw_hw_info,
+       hw_params: snd_pcm_hw_hw_params,
+       sw_params: snd_pcm_hw_sw_params,
+       dig_info: snd_pcm_hw_dig_info,
+       dig_params: snd_pcm_hw_dig_params,
        channel_info: snd_pcm_hw_channel_info,
-       channel_params: snd_pcm_hw_channel_params,
-       channel_setup: snd_pcm_hw_channel_setup,
        dump: snd_pcm_hw_dump,
        nonblock: snd_pcm_hw_nonblock,
        async: snd_pcm_hw_async,
index b0cc2393da585c579100723871668470056588ab..74ada49cfae9da9c1d0f964671d5ab2a64336220 100644 (file)
@@ -28,8 +28,6 @@ typedef struct {
        snd_pcm_plugin_t plug;
        int conv_idx;
        int sformat;
-       int cformat;
-       int cxfer_mode, cmmap_shape;
 } snd_pcm_linear_t;
 
 static void linear_transfer(snd_pcm_channel_area_t *src_areas, size_t src_offset,
@@ -74,83 +72,65 @@ static void linear_transfer(snd_pcm_channel_area_t *src_areas, size_t src_offset
        }
 }
 
-static int snd_pcm_linear_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+static int snd_pcm_linear_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
 {
        snd_pcm_linear_t *linear = pcm->private;
-       unsigned int req_mask = info->req_mask;
-       unsigned int sfmt = info->req.format.sfmt;
+       unsigned int format_mask, access_mask;
        int err;
-       if (req_mask & SND_PCM_PARAMS_SFMT &&
-           !snd_pcm_format_linear(sfmt)) {
-               info->req.fail_mask = SND_PCM_PARAMS_SFMT;
-               info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+       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;
+
+       info->format_mask = 1U << linear->sformat;
+       info->access_mask = SND_PCM_ACCBIT_MMAP;
+       err = snd_pcm_hw_info(linear->plug.slave, info);
+       if (info->format_mask)
+               info->format_mask = format_mask;
+       if (info->access_mask) {
+               linear->plug.saccess_mask = info->access_mask;
+               info->access_mask = access_mask;
        }
-       info->req_mask |= SND_PCM_PARAMS_SFMT;
-       info->req_mask &= ~(SND_PCM_PARAMS_MMAP_SHAPE | 
-                           SND_PCM_PARAMS_XFER_MODE);
-       info->req.format.sfmt = linear->sformat;
-       err = snd_pcm_params_info(linear->plug.slave, info);
-       info->req_mask = req_mask;
-       info->req.format.sfmt = sfmt;
        if (err < 0)
                return err;
-       if (req_mask & SND_PCM_PARAMS_SFMT)
-               info->formats = 1 << sfmt;
-       else
-               info->formats = SND_PCM_LINEAR_FORMATS;
-       info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
-       info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
-       return err;
+       info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+       snd_pcm_hw_info_complete(info);
+       return 0;
 }
 
-static int snd_pcm_linear_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+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;
+       unsigned int format, access;
        int err;
-       if (!snd_pcm_format_linear(params->format.sfmt)) {
-               params->fail_mask = SND_PCM_PARAMS_SFMT;
-               params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
-               return -EINVAL;
-       }
-       linear->cformat = params->format.sfmt;
-       linear->cxfer_mode = params->xfer_mode;
-       linear->cmmap_shape = params->mmap_shape;
-       params->format.sfmt = linear->sformat;
-       params->xfer_mode = SND_PCM_XFER_UNSPECIFIED;
-       params->mmap_shape = SND_PCM_MMAP_UNSPECIFIED;
-       err = snd_pcm_params_mmap(slave, params);
-       params->format.sfmt = linear->cformat;
-       params->xfer_mode = linear->cxfer_mode;
-       params->mmap_shape = linear->cmmap_shape;
-       return err;
-}
-
-static int snd_pcm_linear_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
-{
-       snd_pcm_linear_t *linear = pcm->private;
-       int err = snd_pcm_setup(linear->plug.slave, setup);
+       format = params->format;
+       access = params->access;
+       params->format = linear->sformat;
+       if (linear->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
+               params->access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
+       else if (linear->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
+               params->access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
+       else
+               assert(0);
+       err = snd_pcm_hw_params(slave, params);
+       params->format = format;
+       params->access = access;
        if (err < 0)
                return err;
-       assert(linear->sformat == setup->format.sfmt);
-       
-       if (linear->cxfer_mode == SND_PCM_XFER_UNSPECIFIED)
-               setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
-       else
-               setup->xfer_mode = linear->cxfer_mode;
-       if (linear->cmmap_shape == SND_PCM_MMAP_UNSPECIFIED)
-               setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
-       else
-               setup->mmap_shape = linear->cmmap_shape;
-       setup->format.sfmt = linear->cformat;
-       setup->mmap_bytes = 0;
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
-               linear->conv_idx = conv_index(linear->cformat,
+               linear->conv_idx = conv_index(format,
                                              linear->sformat);
        else
                linear->conv_idx = conv_index(linear->sformat,
-                                             linear->cformat);
+                                             format);
        return 0;
 }
 
@@ -171,7 +151,7 @@ static ssize_t snd_pcm_linear_write_areas(snd_pcm_t *pcm,
                size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
                linear_transfer(areas, offset, 
                                snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
-                               frames, pcm->setup.format.channels, linear->conv_idx);
+                               frames, pcm->channels, linear->conv_idx);
                err = snd_pcm_mmap_forward(slave, frames);
                if (err < 0)
                        break;
@@ -205,7 +185,7 @@ static ssize_t snd_pcm_linear_read_areas(snd_pcm_t *pcm,
                size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
                linear_transfer(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
                                areas, offset, 
-                               frames, pcm->setup.format.channels, linear->conv_idx);
+                               frames, pcm->channels, linear->conv_idx);
                err = snd_pcm_mmap_forward(slave, frames);
                if (err < 0)
                        break;
@@ -227,7 +207,7 @@ static void snd_pcm_linear_dump(snd_pcm_t *pcm, FILE *fp)
        snd_pcm_linear_t *linear = pcm->private;
        fprintf(fp, "Linear conversion PCM (%s)\n", 
                snd_pcm_format_name(linear->sformat));
-       if (pcm->valid_setup) {
+       if (pcm->setup) {
                fprintf(fp, "Its setup is:\n");
                snd_pcm_dump_setup(pcm, fp);
        }
@@ -238,12 +218,12 @@ 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,
-       params_info: snd_pcm_linear_params_info,
-       params: snd_pcm_linear_params,
-       setup: snd_pcm_linear_setup,
+       hw_info: snd_pcm_linear_hw_info,
+       hw_params: snd_pcm_linear_hw_params,
+       sw_params: snd_pcm_plugin_sw_params,
+       dig_info: snd_pcm_plugin_dig_info,
+       dig_params: snd_pcm_plugin_dig_params,
        channel_info: snd_pcm_plugin_channel_info,
-       channel_params: snd_pcm_plugin_channel_params,
-       channel_setup: snd_pcm_plugin_channel_setup,
        dump: snd_pcm_linear_dump,
        nonblock: snd_pcm_plugin_nonblock,
        async: snd_pcm_plugin_async,
index 8d70ace1ba228277218cd073261b5b15bdd7be6a..d3b4bb105a8c6416ac4f21016648bf00836d8e2b 100644 (file)
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <limits.h>
 #include <sys/uio.h>
 #include <errno.h>
 #include "asoundlib.h"
 
 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
-#define ERR(...) snd_pcm_error(__FILE__, __LINE__, __FUNCTION__, 0, __VA_ARGS__)
-#define SYSERR(...) snd_pcm_error(__FILE__, __LINE__, __FUNCTION__, errno, __VA_ARGS__)
+#define ERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, __VA_ARGS__)
+#define SYSERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, __VA_ARGS__)
 #else
-#define ERR(args...) snd_pcm_error(__FILE__, __LINE__, __FUNCTION__, 0, ##args)
-#define SYSERR(args...) snd_pcm_error(__FILE__, __LINE__, __FUNCTION__, errno, ##args)
+#define ERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, ##args)
+#define SYSERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, ##args)
 #endif
 
+typedef struct _snd_pcm_channel_info {
+       unsigned int channel;
+       void *addr;                     /* base address of channel samples */
+       unsigned int first;             /* offset to first sample in bits */
+       unsigned int step;              /* samples distance in bits */
+       enum { SND_PCM_AREA_SHM, SND_PCM_AREA_MMAP } type;
+       union {
+               struct {
+                       int shmid;
+               } shm;
+               struct {
+                       int fd;
+                       off_t offset;
+               } mmap;
+       } u;
+       char reserved[64];
+} snd_pcm_channel_info_t;
+
 typedef struct {
        int (*close)(snd_pcm_t *pcm);
        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 (*params_info)(snd_pcm_t *pcm, snd_pcm_params_info_t *info);
-       int (*params)(snd_pcm_t *pcm, snd_pcm_params_t *params);
-       int (*setup)(snd_pcm_t *pcm, snd_pcm_setup_t *setup);
+       int (*hw_info)(snd_pcm_t *pcm, snd_pcm_hw_info_t *info);
+       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);
+       int (*dig_params)(snd_pcm_t *pcm, snd_pcm_dig_params_t *params);
        int (*channel_info)(snd_pcm_t *pcm, snd_pcm_channel_info_t *info);
-       int (*channel_params)(snd_pcm_t *pcm, snd_pcm_channel_params_t *params);
-       int (*channel_setup)(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup);
        void (*dump)(snd_pcm_t *pcm, FILE *fp);
        int (*mmap)(snd_pcm_t *pcm);
        int (*munmap)(snd_pcm_t *pcm);
@@ -69,38 +88,43 @@ typedef struct {
        int (*set_avail_min)(snd_pcm_t *pcm, size_t frames);
 } snd_pcm_fast_ops_t;
 
-typedef struct {
-       unsigned int index;
-       enum { SND_PCM_MMAP_KERNEL, SND_PCM_MMAP_USER } type;
-       void *addr;
-       size_t size;
-       union {
-               struct {
-                       int shmid;
-               } user;
-               struct {
-                       int fd;
-               } kernel;
-       } u;
-} snd_pcm_mmap_info_t;
-
-struct snd_pcm {
+struct _snd_pcm {
        char *name;
        snd_pcm_type_t type;
        int stream;
        int mode;
        int poll_fd;
-       int valid_setup;
-       snd_pcm_setup_t setup;
+       int setup;
+       unsigned int access;            /* access mode */
+       unsigned int format;            /* SND_PCM_FORMAT_* */
+       unsigned int subformat;         /* subformat */
+       unsigned int rate;              /* rate in Hz */
+       unsigned int channels;          /* channels */
+       size_t fragment_size;           /* fragment size */
+       unsigned int fragments;         /* fragments */
+       unsigned int start_mode;        /* start mode */
+       unsigned int ready_mode;        /* ready detection mode */
+       unsigned int xrun_mode;         /* xrun detection mode */
+       size_t avail_min;               /* min avail frames for wakeup */
+       size_t xfer_min;                /* xfer min size */
+       size_t xfer_align;              /* xfer size need to be a multiple */
+       unsigned int time: 1;           /* timestamp switch */
+       size_t boundary;                /* pointers wrap point */
+       unsigned int info;              /* Info for returned setup */
+       unsigned int msbits;            /* used most significant bits */
+       unsigned int rate_master;       /* Exact rate is rate_master / */
+       unsigned int rate_divisor;      /* rate_divisor */
+       size_t fifo_size;               /* chip FIFO size in frames */
+       size_t buffer_size;
        size_t bits_per_sample;
        size_t bits_per_frame;
        size_t *appl_ptr;
        volatile size_t *hw_ptr;
-       int mmap_auto;
-       size_t mmap_info_count;
-       snd_pcm_mmap_info_t *mmap_info;
+       int mmap_rw;
+       snd_pcm_channel_info_t *mmap_channels;
        snd_pcm_channel_area_t *running_areas;
        snd_pcm_channel_area_t *stopped_areas;
+       void *stopped;
        snd_pcm_ops_t *ops;
        snd_pcm_fast_ops_t *fast_ops;
        snd_pcm_t *op_arg;
@@ -108,10 +132,18 @@ struct snd_pcm {
        void *private;
 };
 
+int snd_pcm_hw_open(snd_pcm_t **pcm, char *name, int card, int device, int subdevice, int stream, int mode);
+int snd_pcm_plug_open_hw(snd_pcm_t **pcm, char *name, int card, int device, int subdevice, int stream, int mode);
+int snd_pcm_shm_open(snd_pcm_t **pcmp, char *name, char *socket, char *sname, int stream, int mode);
+int snd_pcm_file_open(snd_pcm_t **pcmp, char *name, char *fname, int fd, char *fmt, snd_pcm_t *slave, int close_slave);
+int snd_pcm_null_open(snd_pcm_t **pcmp, char *name, int stream, int mode);
+
+
 void snd_pcm_areas_from_buf(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void *buf);
 void snd_pcm_areas_from_bufs(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void **bufs);
 
-int snd_pcm_params_mmap(snd_pcm_t *pcm, snd_pcm_params_t *params);
+int snd_pcm_mmap(snd_pcm_t *pcm);
+int snd_pcm_munmap(snd_pcm_t *pcm);
 int snd_pcm_mmap_ready(snd_pcm_t *pcm);
 ssize_t snd_pcm_mmap_appl_ptr(snd_pcm_t *pcm, off_t offset);
 void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, size_t frames);
@@ -135,16 +167,19 @@ ssize_t snd_pcm_write_areas(snd_pcm_t *pcm, 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_alloc_user_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i);
-int snd_pcm_alloc_kernel_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i, int fd);
-int snd_pcm_free_mmap(snd_pcm_t *pcm, snd_pcm_mmap_info_t *i);
+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);
+void snd_pcm_hw_info_to_params(snd_pcm_hw_info_t *info, snd_pcm_hw_params_t *params);
+void snd_pcm_hw_info_to_params_fail(snd_pcm_hw_info_t *info, snd_pcm_hw_params_t *params);
+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);
 
 static inline size_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm)
 {
        ssize_t avail;
-       avail = *pcm->hw_ptr + pcm->setup.buffer_size - *pcm->appl_ptr;
+       avail = *pcm->hw_ptr + pcm->buffer_size - *pcm->appl_ptr;
        if (avail < 0)
-               avail += pcm->setup.boundary;
+               avail += pcm->boundary;
        return avail;
 }
 
@@ -153,7 +188,7 @@ static inline size_t snd_pcm_mmap_capture_avail(snd_pcm_t *pcm)
        ssize_t avail;
        avail = *pcm->hw_ptr - *pcm->appl_ptr;
        if (avail < 0)
-               avail += pcm->setup.boundary;
+               avail += pcm->boundary;
        return avail;
 }
 
@@ -162,19 +197,19 @@ static inline size_t snd_pcm_mmap_avail(snd_pcm_t *pcm)
        ssize_t avail;
        avail = *pcm->hw_ptr - *pcm->appl_ptr;
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
-               avail += pcm->setup.buffer_size;
+               avail += pcm->buffer_size;
        if (avail < 0)
-               avail += pcm->setup.boundary;
+               avail += pcm->boundary;
        return avail;
 }
 
 static inline ssize_t snd_pcm_mmap_playback_hw_avail(snd_pcm_t *pcm)
 {
        ssize_t avail;
-       avail = *pcm->hw_ptr + pcm->setup.buffer_size - *pcm->appl_ptr;
+       avail = *pcm->hw_ptr + pcm->buffer_size - *pcm->appl_ptr;
        if (avail < 0)
-               avail += pcm->setup.boundary;
-       return pcm->setup.buffer_size - avail;
+               avail += pcm->boundary;
+       return pcm->buffer_size - avail;
 }
 
 static inline ssize_t snd_pcm_mmap_capture_hw_avail(snd_pcm_t *pcm)
@@ -182,8 +217,8 @@ static inline ssize_t snd_pcm_mmap_capture_hw_avail(snd_pcm_t *pcm)
        ssize_t avail;
        avail = *pcm->hw_ptr - *pcm->appl_ptr;
        if (avail < 0)
-               avail += pcm->setup.boundary;
-       return pcm->setup.buffer_size - avail;
+               avail += pcm->boundary;
+       return pcm->buffer_size - avail;
 }
 
 static inline ssize_t snd_pcm_mmap_hw_avail(snd_pcm_t *pcm)
@@ -191,10 +226,10 @@ static inline ssize_t snd_pcm_mmap_hw_avail(snd_pcm_t *pcm)
        ssize_t avail;
        avail = *pcm->hw_ptr - *pcm->appl_ptr;
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
-               avail += pcm->setup.buffer_size;
+               avail += pcm->buffer_size;
        if (avail < 0)
-               avail += pcm->setup.boundary;
-       return pcm->setup.buffer_size - avail;
+               avail += pcm->boundary;
+       return pcm->buffer_size - avail;
 }
 
 #define snd_pcm_mmap_playback_delay snd_pcm_mmap_playback_hw_avail
index 57bfcf21aac7782cc8559f7e98996c8e6a7f91fe..a67902154c8bf1c1bd6c79570d75d6d7f0a41702 100644 (file)
 int snd_pcm_format_signed(int format)
 {
        switch (format) {
-       case SND_PCM_SFMT_S8:
-       case SND_PCM_SFMT_S16_LE:
-       case SND_PCM_SFMT_S16_BE:
-       case SND_PCM_SFMT_S24_LE:
-       case SND_PCM_SFMT_S24_BE:
-       case SND_PCM_SFMT_S32_LE:
-       case SND_PCM_SFMT_S32_BE:
+       case SND_PCM_FORMAT_S8:
+       case SND_PCM_FORMAT_S16_LE:
+       case SND_PCM_FORMAT_S16_BE:
+       case SND_PCM_FORMAT_S24_LE:
+       case SND_PCM_FORMAT_S24_BE:
+       case SND_PCM_FORMAT_S32_LE:
+       case SND_PCM_FORMAT_S32_BE:
                return 1;
-       case SND_PCM_SFMT_U8:
-       case SND_PCM_SFMT_U16_LE:
-       case SND_PCM_SFMT_U16_BE:
-       case SND_PCM_SFMT_U24_LE:
-       case SND_PCM_SFMT_U24_BE:
-       case SND_PCM_SFMT_U32_LE:
-       case SND_PCM_SFMT_U32_BE:
+       case SND_PCM_FORMAT_U8:
+       case SND_PCM_FORMAT_U16_LE:
+       case SND_PCM_FORMAT_U16_BE:
+       case SND_PCM_FORMAT_U24_LE:
+       case SND_PCM_FORMAT_U24_BE:
+       case SND_PCM_FORMAT_U32_LE:
+       case SND_PCM_FORMAT_U32_BE:
                return 0;
        default:
                return -EINVAL;
@@ -78,25 +78,25 @@ int snd_pcm_format_linear(int format)
 int snd_pcm_format_little_endian(int format)
 {
        switch (format) {
-       case SND_PCM_SFMT_S16_LE:
-       case SND_PCM_SFMT_U16_LE:
-       case SND_PCM_SFMT_S24_LE:
-       case SND_PCM_SFMT_U24_LE:
-       case SND_PCM_SFMT_S32_LE:
-       case SND_PCM_SFMT_U32_LE:
-       case SND_PCM_SFMT_FLOAT_LE:
-       case SND_PCM_SFMT_FLOAT64_LE:
-       case SND_PCM_SFMT_IEC958_SUBFRAME_LE:
+       case SND_PCM_FORMAT_S16_LE:
+       case SND_PCM_FORMAT_U16_LE:
+       case SND_PCM_FORMAT_S24_LE:
+       case SND_PCM_FORMAT_U24_LE:
+       case SND_PCM_FORMAT_S32_LE:
+       case SND_PCM_FORMAT_U32_LE:
+       case SND_PCM_FORMAT_FLOAT_LE:
+       case SND_PCM_FORMAT_FLOAT64_LE:
+       case SND_PCM_FORMAT_IEC958_SUBFRAME_LE:
                return 1;
-       case SND_PCM_SFMT_S16_BE:
-       case SND_PCM_SFMT_U16_BE:
-       case SND_PCM_SFMT_S24_BE:
-       case SND_PCM_SFMT_U24_BE:
-       case SND_PCM_SFMT_S32_BE:
-       case SND_PCM_SFMT_U32_BE:
-       case SND_PCM_SFMT_FLOAT_BE:
-       case SND_PCM_SFMT_FLOAT64_BE:
-       case SND_PCM_SFMT_IEC958_SUBFRAME_BE:
+       case SND_PCM_FORMAT_S16_BE:
+       case SND_PCM_FORMAT_U16_BE:
+       case SND_PCM_FORMAT_S24_BE:
+       case SND_PCM_FORMAT_U24_BE:
+       case SND_PCM_FORMAT_S32_BE:
+       case SND_PCM_FORMAT_U32_BE:
+       case SND_PCM_FORMAT_FLOAT_BE:
+       case SND_PCM_FORMAT_FLOAT64_BE:
+       case SND_PCM_FORMAT_IEC958_SUBFRAME_BE:
                return 0;
        default:
                return -EINVAL;
@@ -116,36 +116,36 @@ int snd_pcm_format_big_endian(int format)
 int snd_pcm_format_width(int format)
 {
        switch (format) {
-       case SND_PCM_SFMT_S8:
-       case SND_PCM_SFMT_U8:
+       case SND_PCM_FORMAT_S8:
+       case SND_PCM_FORMAT_U8:
                return 8;
-       case SND_PCM_SFMT_S16_LE:
-       case SND_PCM_SFMT_S16_BE:
-       case SND_PCM_SFMT_U16_LE:
-       case SND_PCM_SFMT_U16_BE:
+       case SND_PCM_FORMAT_S16_LE:
+       case SND_PCM_FORMAT_S16_BE:
+       case SND_PCM_FORMAT_U16_LE:
+       case SND_PCM_FORMAT_U16_BE:
                return 16;
-       case SND_PCM_SFMT_S24_LE:
-       case SND_PCM_SFMT_S24_BE:
-       case SND_PCM_SFMT_U24_LE:
-       case SND_PCM_SFMT_U24_BE:
+       case SND_PCM_FORMAT_S24_LE:
+       case SND_PCM_FORMAT_S24_BE:
+       case SND_PCM_FORMAT_U24_LE:
+       case SND_PCM_FORMAT_U24_BE:
                return 24;
-       case SND_PCM_SFMT_S32_LE:
-       case SND_PCM_SFMT_S32_BE:
-       case SND_PCM_SFMT_U32_LE:
-       case SND_PCM_SFMT_U32_BE:
-       case SND_PCM_SFMT_FLOAT_LE:
-       case SND_PCM_SFMT_FLOAT_BE:
+       case SND_PCM_FORMAT_S32_LE:
+       case SND_PCM_FORMAT_S32_BE:
+       case SND_PCM_FORMAT_U32_LE:
+       case SND_PCM_FORMAT_U32_BE:
+       case SND_PCM_FORMAT_FLOAT_LE:
+       case SND_PCM_FORMAT_FLOAT_BE:
                return 32;
-       case SND_PCM_SFMT_FLOAT64_LE:
-       case SND_PCM_SFMT_FLOAT64_BE:
+       case SND_PCM_FORMAT_FLOAT64_LE:
+       case SND_PCM_FORMAT_FLOAT64_BE:
                return 64;
-       case SND_PCM_SFMT_IEC958_SUBFRAME_LE:
-       case SND_PCM_SFMT_IEC958_SUBFRAME_BE:
+       case SND_PCM_FORMAT_IEC958_SUBFRAME_LE:
+       case SND_PCM_FORMAT_IEC958_SUBFRAME_BE:
                return 24;
-       case SND_PCM_SFMT_MU_LAW:
-       case SND_PCM_SFMT_A_LAW:
+       case SND_PCM_FORMAT_MU_LAW:
+       case SND_PCM_FORMAT_A_LAW:
                return 8;
-       case SND_PCM_SFMT_IMA_ADPCM:
+       case SND_PCM_FORMAT_IMA_ADPCM:
                return 4;
        default:
                return -EINVAL;
@@ -155,34 +155,34 @@ int snd_pcm_format_width(int format)
 int snd_pcm_format_physical_width(int format)
 {
        switch (format) {
-       case SND_PCM_SFMT_S8:
-       case SND_PCM_SFMT_U8:
+       case SND_PCM_FORMAT_S8:
+       case SND_PCM_FORMAT_U8:
                return 8;
-       case SND_PCM_SFMT_S16_LE:
-       case SND_PCM_SFMT_S16_BE:
-       case SND_PCM_SFMT_U16_LE:
-       case SND_PCM_SFMT_U16_BE:
+       case SND_PCM_FORMAT_S16_LE:
+       case SND_PCM_FORMAT_S16_BE:
+       case SND_PCM_FORMAT_U16_LE:
+       case SND_PCM_FORMAT_U16_BE:
                return 16;
-       case SND_PCM_SFMT_S24_LE:
-       case SND_PCM_SFMT_S24_BE:
-       case SND_PCM_SFMT_U24_LE:
-       case SND_PCM_SFMT_U24_BE:
-       case SND_PCM_SFMT_S32_LE:
-       case SND_PCM_SFMT_S32_BE:
-       case SND_PCM_SFMT_U32_LE:
-       case SND_PCM_SFMT_U32_BE:
-       case SND_PCM_SFMT_FLOAT_LE:
-       case SND_PCM_SFMT_FLOAT_BE:
-       case SND_PCM_SFMT_IEC958_SUBFRAME_LE:
-       case SND_PCM_SFMT_IEC958_SUBFRAME_BE:
+       case SND_PCM_FORMAT_S24_LE:
+       case SND_PCM_FORMAT_S24_BE:
+       case SND_PCM_FORMAT_U24_LE:
+       case SND_PCM_FORMAT_U24_BE:
+       case SND_PCM_FORMAT_S32_LE:
+       case SND_PCM_FORMAT_S32_BE:
+       case SND_PCM_FORMAT_U32_LE:
+       case SND_PCM_FORMAT_U32_BE:
+       case SND_PCM_FORMAT_FLOAT_LE:
+       case SND_PCM_FORMAT_FLOAT_BE:
+       case SND_PCM_FORMAT_IEC958_SUBFRAME_LE:
+       case SND_PCM_FORMAT_IEC958_SUBFRAME_BE:
                return 32;
-       case SND_PCM_SFMT_FLOAT64_LE:
-       case SND_PCM_SFMT_FLOAT64_BE:
+       case SND_PCM_FORMAT_FLOAT64_LE:
+       case SND_PCM_FORMAT_FLOAT64_BE:
                return 64;
-       case SND_PCM_SFMT_MU_LAW:
-       case SND_PCM_SFMT_A_LAW:
+       case SND_PCM_FORMAT_MU_LAW:
+       case SND_PCM_FORMAT_A_LAW:
                return 8;
-       case SND_PCM_SFMT_IMA_ADPCM:
+       case SND_PCM_FORMAT_IMA_ADPCM:
                return 4;
        default:
                return -EINVAL;
@@ -192,35 +192,35 @@ int snd_pcm_format_physical_width(int format)
 ssize_t snd_pcm_format_size(int format, size_t samples)
 {
        switch (format) {
-       case SND_PCM_SFMT_S8:
-       case SND_PCM_SFMT_U8:
+       case SND_PCM_FORMAT_S8:
+       case SND_PCM_FORMAT_U8:
                return samples;
-       case SND_PCM_SFMT_S16_LE:
-       case SND_PCM_SFMT_S16_BE:
-       case SND_PCM_SFMT_U16_LE:
-       case SND_PCM_SFMT_U16_BE:
+       case SND_PCM_FORMAT_S16_LE:
+       case SND_PCM_FORMAT_S16_BE:
+       case SND_PCM_FORMAT_U16_LE:
+       case SND_PCM_FORMAT_U16_BE:
                return samples * 2;
-       case SND_PCM_SFMT_S24_LE:
-       case SND_PCM_SFMT_S24_BE:
-       case SND_PCM_SFMT_U24_LE:
-       case SND_PCM_SFMT_U24_BE:
-       case SND_PCM_SFMT_S32_LE:
-       case SND_PCM_SFMT_S32_BE:
-       case SND_PCM_SFMT_U32_LE:
-       case SND_PCM_SFMT_U32_BE:
-       case SND_PCM_SFMT_FLOAT_LE:
-       case SND_PCM_SFMT_FLOAT_BE:
+       case SND_PCM_FORMAT_S24_LE:
+       case SND_PCM_FORMAT_S24_BE:
+       case SND_PCM_FORMAT_U24_LE:
+       case SND_PCM_FORMAT_U24_BE:
+       case SND_PCM_FORMAT_S32_LE:
+       case SND_PCM_FORMAT_S32_BE:
+       case SND_PCM_FORMAT_U32_LE:
+       case SND_PCM_FORMAT_U32_BE:
+       case SND_PCM_FORMAT_FLOAT_LE:
+       case SND_PCM_FORMAT_FLOAT_BE:
                return samples * 4;
-       case SND_PCM_SFMT_FLOAT64_LE:
-       case SND_PCM_SFMT_FLOAT64_BE:
+       case SND_PCM_FORMAT_FLOAT64_LE:
+       case SND_PCM_FORMAT_FLOAT64_BE:
                return samples * 8;
-       case SND_PCM_SFMT_IEC958_SUBFRAME_LE:
-       case SND_PCM_SFMT_IEC958_SUBFRAME_BE:
+       case SND_PCM_FORMAT_IEC958_SUBFRAME_LE:
+       case SND_PCM_FORMAT_IEC958_SUBFRAME_BE:
                return samples * 4;
-       case SND_PCM_SFMT_MU_LAW:
-       case SND_PCM_SFMT_A_LAW:
+       case SND_PCM_FORMAT_MU_LAW:
+       case SND_PCM_FORMAT_A_LAW:
                return samples;
-       case SND_PCM_SFMT_IMA_ADPCM:
+       case SND_PCM_FORMAT_IMA_ADPCM:
                if (samples & 1)
                        return -EINVAL;
                return samples / 2;
@@ -232,44 +232,44 @@ ssize_t snd_pcm_format_size(int format, size_t samples)
 u_int64_t snd_pcm_format_silence_64(int format)
 {
        switch (format) {
-       case SND_PCM_SFMT_S8:
-       case SND_PCM_SFMT_S16_LE:
-       case SND_PCM_SFMT_S16_BE:
-       case SND_PCM_SFMT_S24_LE:
-       case SND_PCM_SFMT_S24_BE:
-       case SND_PCM_SFMT_S32_LE:
-       case SND_PCM_SFMT_S32_BE:
+       case SND_PCM_FORMAT_S8:
+       case SND_PCM_FORMAT_S16_LE:
+       case SND_PCM_FORMAT_S16_BE:
+       case SND_PCM_FORMAT_S24_LE:
+       case SND_PCM_FORMAT_S24_BE:
+       case SND_PCM_FORMAT_S32_LE:
+       case SND_PCM_FORMAT_S32_BE:
                return 0;
-       case SND_PCM_SFMT_U8:
+       case SND_PCM_FORMAT_U8:
                return 0x8080808080808080ULL;
 #ifdef SND_LITTLE_ENDIAN
-       case SND_PCM_SFMT_U16_LE:
+       case SND_PCM_FORMAT_U16_LE:
                return 0x8000800080008000ULL;
-       case SND_PCM_SFMT_U24_LE:
+       case SND_PCM_FORMAT_U24_LE:
                return 0x0080000000800000ULL;
-       case SND_PCM_SFMT_U32_LE:
+       case SND_PCM_FORMAT_U32_LE:
                return 0x8000000080000000ULL;
-       case SND_PCM_SFMT_U16_BE:
+       case SND_PCM_FORMAT_U16_BE:
                return 0x0080008000800080ULL;
-       case SND_PCM_SFMT_U24_BE:
+       case SND_PCM_FORMAT_U24_BE:
                return 0x0000800000008000ULL;
-       case SND_PCM_SFMT_U32_BE:
+       case SND_PCM_FORMAT_U32_BE:
                return 0x0000008000000080ULL;
 #else
-       case SND_PCM_SFMT_U16_LE:
+       case SND_PCM_FORMAT_U16_LE:
                return 0x0080008000800080ULL;
-       case SND_PCM_SFMT_U24_LE:
+       case SND_PCM_FORMAT_U24_LE:
                return 0x0000800000008000ULL;
-       case SND_PCM_SFMT_U32_LE:
+       case SND_PCM_FORMAT_U32_LE:
                return 0x0000008000000080ULL;
-       case SND_PCM_SFMT_U16_BE:
+       case SND_PCM_FORMAT_U16_BE:
                return 0x8000800080008000ULL;
-       case SND_PCM_SFMT_U24_BE:
+       case SND_PCM_FORMAT_U24_BE:
                return 0x0080000000800000ULL;
-       case SND_PCM_SFMT_U32_BE:
+       case SND_PCM_FORMAT_U32_BE:
                return 0x8000000080000000ULL;
 #endif
-       case SND_PCM_SFMT_FLOAT_LE:
+       case SND_PCM_FORMAT_FLOAT_LE:
        {
                union {
                        float f;
@@ -282,7 +282,7 @@ u_int64_t snd_pcm_format_silence_64(int format)
                return bswap_32(u.i);
 #endif
        }
-       case SND_PCM_SFMT_FLOAT64_LE:
+       case SND_PCM_FORMAT_FLOAT64_LE:
        {
                union {
                        double f;
@@ -295,7 +295,7 @@ u_int64_t snd_pcm_format_silence_64(int format)
                return bswap_64(u.i);
 #endif
        }
-       case SND_PCM_SFMT_FLOAT_BE:             
+       case SND_PCM_FORMAT_FLOAT_BE:           
        {
                union {
                        float f;
@@ -308,7 +308,7 @@ u_int64_t snd_pcm_format_silence_64(int format)
                return u.i;
 #endif
        }
-       case SND_PCM_SFMT_FLOAT64_BE:
+       case SND_PCM_FORMAT_FLOAT64_BE:
        {
                union {
                        double f;
@@ -321,16 +321,16 @@ u_int64_t snd_pcm_format_silence_64(int format)
                return u.i;
 #endif
        }
-       case SND_PCM_SFMT_IEC958_SUBFRAME_LE:
-       case SND_PCM_SFMT_IEC958_SUBFRAME_BE:
+       case SND_PCM_FORMAT_IEC958_SUBFRAME_LE:
+       case SND_PCM_FORMAT_IEC958_SUBFRAME_BE:
                return 0;       
-       case SND_PCM_SFMT_MU_LAW:
+       case SND_PCM_FORMAT_MU_LAW:
                return 0x7f7f7f7f7f7f7f7fULL;
-       case SND_PCM_SFMT_A_LAW:
+       case SND_PCM_FORMAT_A_LAW:
                return 0x5555555555555555ULL;
-       case SND_PCM_SFMT_IMA_ADPCM:    /* special case */
-       case SND_PCM_SFMT_MPEG:
-       case SND_PCM_SFMT_GSM:
+       case SND_PCM_FORMAT_IMA_ADPCM:  /* special case */
+       case SND_PCM_FORMAT_MPEG:
+       case SND_PCM_FORMAT_GSM:
                return 0;
        }
        return 0;
@@ -395,22 +395,22 @@ ssize_t snd_pcm_format_set_silence(int format, void *data, size_t samples)
 }
 
 static int linear_formats[4*2*2] = {
-       SND_PCM_SFMT_S8,
-       SND_PCM_SFMT_U8,
-       SND_PCM_SFMT_S8,
-       SND_PCM_SFMT_U8,
-       SND_PCM_SFMT_S16_LE,
-       SND_PCM_SFMT_S16_BE,
-       SND_PCM_SFMT_U16_LE,
-       SND_PCM_SFMT_U16_BE,
-       SND_PCM_SFMT_S24_LE,
-       SND_PCM_SFMT_S24_BE,
-       SND_PCM_SFMT_U24_LE,
-       SND_PCM_SFMT_U24_BE,
-       SND_PCM_SFMT_S32_LE,
-       SND_PCM_SFMT_S32_BE,
-       SND_PCM_SFMT_U32_LE,
-       SND_PCM_SFMT_U32_BE
+       SND_PCM_FORMAT_S8,
+       SND_PCM_FORMAT_U8,
+       SND_PCM_FORMAT_S8,
+       SND_PCM_FORMAT_U8,
+       SND_PCM_FORMAT_S16_LE,
+       SND_PCM_FORMAT_S16_BE,
+       SND_PCM_FORMAT_U16_LE,
+       SND_PCM_FORMAT_U16_BE,
+       SND_PCM_FORMAT_S24_LE,
+       SND_PCM_FORMAT_S24_BE,
+       SND_PCM_FORMAT_U24_LE,
+       SND_PCM_FORMAT_U24_BE,
+       SND_PCM_FORMAT_S32_LE,
+       SND_PCM_FORMAT_S32_BE,
+       SND_PCM_FORMAT_U32_LE,
+       SND_PCM_FORMAT_U32_BE
 };
 
 int snd_pcm_build_linear_format(int width, int unsignd, int big_endian)
index 4eb51d4f77c508091a0c2db3d26eb91bd8bc98f2..1a754c72b83285c0c26b6739ca0dd672044c20e5 100644 (file)
 #include <string.h>
 #include <errno.h>
 #include <sys/poll.h>
+#include <sys/mman.h>
+#include <sys/shm.h>
+#include <asm/page.h>
 #include "pcm_local.h"
 
+
+#ifndef PAGE_ALIGN
+#define PAGE_ALIGN(addr)        (((addr)+PAGE_SIZE-1)&PAGE_MASK)
+#endif
+
+
 snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm)
 {
-  int state = snd_pcm_state(pcm);
-  if (state == SND_PCM_STATE_RUNNING)
-         return pcm->running_areas;
-  else
-         return pcm->stopped_areas;
+       if (pcm->stopped_areas &&
+           snd_pcm_state(pcm) != SND_PCM_STATE_RUNNING) 
+               return pcm->stopped_areas;
+       return pcm->running_areas;
 }
 
 size_t snd_pcm_mmap_playback_xfer(snd_pcm_t *pcm, size_t frames)
@@ -40,7 +48,7 @@ size_t snd_pcm_mmap_playback_xfer(snd_pcm_t *pcm, size_t frames)
        size_t avail = snd_pcm_mmap_playback_avail(pcm);
        if (avail < frames)
                frames = avail;
-       cont = pcm->setup.buffer_size - *pcm->appl_ptr % pcm->setup.buffer_size;
+       cont = pcm->buffer_size - *pcm->appl_ptr % pcm->buffer_size;
        if (cont < frames)
                frames = cont;
        return frames;
@@ -52,7 +60,7 @@ size_t snd_pcm_mmap_capture_xfer(snd_pcm_t *pcm, size_t frames)
        size_t avail = snd_pcm_mmap_capture_avail(pcm);
        if (avail < frames)
                frames = avail;
-       cont = pcm->setup.buffer_size - *pcm->appl_ptr % pcm->setup.buffer_size;
+       cont = pcm->buffer_size - *pcm->appl_ptr % pcm->buffer_size;
        if (cont < frames)
                frames = cont;
        return frames;
@@ -70,13 +78,13 @@ size_t snd_pcm_mmap_xfer(snd_pcm_t *pcm, size_t frames)
 size_t snd_pcm_mmap_offset(snd_pcm_t *pcm)
 {
         assert(pcm);
-       return *pcm->appl_ptr % pcm->setup.buffer_size;
+       return *pcm->appl_ptr % pcm->buffer_size;
 }
 
 size_t snd_pcm_mmap_hw_offset(snd_pcm_t *pcm)
 {
         assert(pcm);
-       return *pcm->hw_ptr % pcm->setup.buffer_size;
+       return *pcm->hw_ptr % pcm->buffer_size;
 }
 
 void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, size_t frames)
@@ -84,7 +92,7 @@ void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, size_t frames)
        ssize_t appl_ptr = *pcm->appl_ptr;
        appl_ptr -= frames;
        if (appl_ptr < 0)
-               appl_ptr += pcm->setup.boundary;
+               appl_ptr += pcm->boundary;
        *pcm->appl_ptr = appl_ptr;
 }
 
@@ -92,8 +100,8 @@ void snd_pcm_mmap_appl_forward(snd_pcm_t *pcm, size_t frames)
 {
        size_t appl_ptr = *pcm->appl_ptr;
        appl_ptr += frames;
-       if (appl_ptr >= pcm->setup.boundary)
-               appl_ptr -= pcm->setup.boundary;
+       if (appl_ptr >= pcm->boundary)
+               appl_ptr -= pcm->boundary;
        *pcm->appl_ptr = appl_ptr;
 }
 
@@ -102,7 +110,7 @@ void snd_pcm_mmap_hw_backward(snd_pcm_t *pcm, size_t frames)
        ssize_t hw_ptr = *pcm->hw_ptr;
        hw_ptr -= frames;
        if (hw_ptr < 0)
-               hw_ptr += pcm->setup.boundary;
+               hw_ptr += pcm->boundary;
        *pcm->hw_ptr = hw_ptr;
 }
 
@@ -110,8 +118,8 @@ void snd_pcm_mmap_hw_forward(snd_pcm_t *pcm, size_t frames)
 {
        size_t hw_ptr = *pcm->hw_ptr;
        hw_ptr += frames;
-       if (hw_ptr >= pcm->setup.boundary)
-               hw_ptr -= pcm->setup.boundary;
+       if (hw_ptr >= pcm->boundary)
+               hw_ptr -= pcm->boundary;
        *pcm->hw_ptr = hw_ptr;
 }
 
@@ -127,11 +135,13 @@ ssize_t snd_pcm_mmap_write_areas(snd_pcm_t *pcm,
        xfer = 0;
        while (xfer < size) {
                size_t frames = snd_pcm_mmap_playback_xfer(pcm, size - xfer);
+               ssize_t err;
                snd_pcm_areas_copy(areas, offset, 
                                   snd_pcm_mmap_areas(pcm), snd_pcm_mmap_offset(pcm),
-                                  pcm->setup.format.channels, 
-                                  frames, pcm->setup.format.sfmt);
-               snd_pcm_mmap_forward(pcm, frames);
+                                  pcm->channels, 
+                                  frames, pcm->format);
+               err = snd_pcm_mmap_forward(pcm, frames);
+               assert(err == (ssize_t)frames);
                offset += frames;
                xfer += frames;
        }
@@ -152,11 +162,13 @@ ssize_t snd_pcm_mmap_read_areas(snd_pcm_t *pcm,
        xfer = 0;
        while (xfer < size) {
                size_t frames = snd_pcm_mmap_capture_xfer(pcm, size - xfer);
+               ssize_t err;
                snd_pcm_areas_copy(snd_pcm_mmap_areas(pcm), snd_pcm_mmap_offset(pcm),
                                   areas, offset, 
-                                  pcm->setup.format.channels, 
-                                  frames, pcm->setup.format.sfmt);
-               snd_pcm_mmap_forward(pcm, frames);
+                                  pcm->channels, 
+                                  frames, pcm->format);
+               err = snd_pcm_mmap_forward(pcm, frames);
+               assert(err == (ssize_t)frames);
                offset += frames;
                xfer += frames;
        }
@@ -167,7 +179,7 @@ ssize_t snd_pcm_mmap_read_areas(snd_pcm_t *pcm,
 
 ssize_t snd_pcm_mmap_writei(snd_pcm_t *pcm, const void *buffer, size_t size)
 {
-       snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+       snd_pcm_channel_area_t areas[pcm->channels];
        snd_pcm_areas_from_buf(pcm, areas, (void*)buffer);
        return snd_pcm_write_areas(pcm, areas, 0, size,
                                   snd_pcm_mmap_write_areas);
@@ -175,7 +187,7 @@ ssize_t snd_pcm_mmap_writei(snd_pcm_t *pcm, const void *buffer, size_t size)
 
 ssize_t snd_pcm_mmap_writen(snd_pcm_t *pcm, void **bufs, size_t size)
 {
-       snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+       snd_pcm_channel_area_t areas[pcm->channels];
        snd_pcm_areas_from_bufs(pcm, areas, bufs);
        return snd_pcm_write_areas(pcm, areas, 0, size,
                                   snd_pcm_mmap_write_areas);
@@ -183,7 +195,7 @@ ssize_t snd_pcm_mmap_writen(snd_pcm_t *pcm, void **bufs, size_t size)
 
 ssize_t snd_pcm_mmap_readi(snd_pcm_t *pcm, void *buffer, size_t size)
 {
-       snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+       snd_pcm_channel_area_t areas[pcm->channels];
        snd_pcm_areas_from_buf(pcm, areas, buffer);
        return snd_pcm_read_areas(pcm, areas, 0, size,
                                  snd_pcm_mmap_read_areas);
@@ -191,71 +203,204 @@ ssize_t snd_pcm_mmap_readi(snd_pcm_t *pcm, void *buffer, size_t size)
 
 ssize_t snd_pcm_mmap_readn(snd_pcm_t *pcm, void **bufs, size_t size)
 {
-       snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+       snd_pcm_channel_area_t areas[pcm->channels];
        snd_pcm_areas_from_bufs(pcm, areas, bufs);
        return snd_pcm_read_areas(pcm, areas, 0, size,
                                  snd_pcm_mmap_read_areas);
 }
 
-int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *stopped_areas, snd_pcm_channel_area_t *running_areas)
+int snd_pcm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
 {
-       snd_pcm_channel_setup_t setup;
-       snd_pcm_channel_area_t *r, *rp, *s, *sp;
-       unsigned int channel;
-       int err;
-       assert(pcm);
-       assert(pcm->mmap_info);
-       if (!pcm->running_areas) {
-               r = calloc(pcm->setup.format.channels, sizeof(*r));
-               s = calloc(pcm->setup.format.channels, sizeof(*s));
-               for (channel = 0, rp = r, sp = s; channel < pcm->setup.format.channels; ++channel, ++rp, ++sp) {
-                       setup.channel = channel;
-                       err = snd_pcm_channel_setup(pcm, &setup);
-                       if (err < 0) {
-                               free(r);
-                               free(s);
-                               return err;
-                       }
-                       *rp = setup.running_area;
-                       *sp = setup.stopped_area;
-               }
-               pcm->running_areas = r;
-               pcm->stopped_areas = s;
+       return pcm->ops->channel_info(pcm, info);
+}
+
+int snd_pcm_channel_info_shm(snd_pcm_t *pcm, snd_pcm_channel_info_t *info,
+                            int shmid)
+{
+       switch (pcm->access) {
+       case SND_PCM_ACCESS_MMAP_INTERLEAVED:
+       case SND_PCM_ACCESS_RW_INTERLEAVED:
+               info->first = info->channel * pcm->bits_per_sample;
+               info->step = pcm->bits_per_frame;
+               break;
+       case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
+       case SND_PCM_ACCESS_RW_NONINTERLEAVED:
+               info->first = 0;
+               info->step = pcm->bits_per_sample;
+               break;
+       default:
+               assert(0);
+               break;
        }
-       if (running_areas)
-               memcpy(running_areas, pcm->running_areas, pcm->setup.format.channels * sizeof(*running_areas));
-       if (stopped_areas)
-               memcpy(stopped_areas, pcm->stopped_areas, pcm->setup.format.channels * sizeof(*stopped_areas));
+       info->addr = 0;
+       info->type = SND_PCM_AREA_SHM;
+       info->u.shm.shmid = shmid;
        return 0;
-}
+}      
 
 int snd_pcm_mmap(snd_pcm_t *pcm)
 {
        int err;
+       unsigned int c;
        assert(pcm);
-       assert(pcm->valid_setup);
-       if (pcm->mmap_info)
-               return 0;
-
-       if ((err = pcm->ops->mmap(pcm->op_arg)) < 0)
-               return err;
-       err = snd_pcm_mmap_get_areas(pcm, NULL, NULL);
+       assert(pcm->setup);
+       assert(!pcm->mmap_channels);
+       err = pcm->ops->mmap(pcm);
        if (err < 0)
                return err;
+       pcm->mmap_channels = calloc(pcm->channels, sizeof(pcm->mmap_channels[0]));
+       if (!pcm->mmap_channels)
+               return -ENOMEM;
+       assert(!pcm->running_areas);
+       pcm->running_areas = calloc(pcm->channels, sizeof(pcm->running_areas[0]));
+       if (!pcm->running_areas) {
+               free(pcm->mmap_channels);
+               pcm->mmap_channels = NULL;
+               return -ENOMEM;
+       }
+       for (c = 0; c < pcm->channels; ++c) {
+               snd_pcm_channel_info_t *i = &pcm->mmap_channels[c];
+               i->channel = c;
+               err = snd_pcm_channel_info(pcm, i);
+               if (err < 0)
+                       return err;
+       }
+       for (c = 0; c < pcm->channels; ++c) {
+               snd_pcm_channel_info_t *i = &pcm->mmap_channels[c];
+               snd_pcm_channel_area_t *a = &pcm->running_areas[c];
+               unsigned int c1;
+               if (!i->addr) {
+                       char *ptr;
+                       size_t size = i->first + i->step * pcm->buffer_size;
+                       for (c1 = c + 1; c1 < pcm->channels; ++c1) {
+                               snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
+                               size_t s;
+                               if (i1->type != i->type)
+                                       continue;
+                               switch (i1->type) {
+                               case SND_PCM_AREA_MMAP:
+                                       if (i1->u.mmap.fd != i->u.mmap.fd ||
+                                           i1->u.mmap.offset != i->u.mmap.offset)
+                                               continue;
+                                       break;
+                               case SND_PCM_AREA_SHM:
+                                       if (i1->u.shm.shmid != i->u.shm.shmid)
+                                               continue;
+                                       break;
+                               default:
+                                       assert(0);
+                               }
+                               s = i1->first + i1->step * pcm->buffer_size;
+                               if (s > size)
+                                       size = s;
+                       }
+                       size = (size + 7) / 8;
+                       size = PAGE_ALIGN(size);
+                       switch (i->type) {
+                       case SND_PCM_AREA_MMAP:
+                               ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, i->u.mmap.fd, i->u.mmap.offset);
+                               if (ptr == MAP_FAILED) {
+                                       SYSERR("mmap failed");
+                                       return -errno;
+                               }
+                               i->addr = ptr;
+                               break;
+                       case SND_PCM_AREA_SHM:
+                               if (i->u.shm.shmid < 0) {
+                                       int id;
+                                       id = shmget(IPC_PRIVATE, size, 0666);
+                                       if (id < 0) {
+                                               SYSERR("shmget failed");
+                                               return -errno;
+                                       }
+                                       i->u.shm.shmid = id;
+                               }
+                               ptr = shmat(i->u.shm.shmid, 0, 0);
+                               if (ptr == (void*) -1) {
+                                       SYSERR("shmat failed");
+                                       return -errno;
+                               }
+                               i->addr = ptr;
+                               break;
+                       default:
+                               assert(0);
+                       }
+               }
+               for (c1 = c + 1; c1 < pcm->channels; ++c1) {
+                       snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
+                       if (i1->type != i->type)
+                               continue;
+                       switch (i1->type) {
+                       case SND_PCM_AREA_MMAP:
+                               if (i1->u.mmap.fd != i->u.mmap.fd ||
+                                   i1->u.mmap.offset != i->u.mmap.offset)
+                                       continue;
+                               break;
+                       case SND_PCM_AREA_SHM:
+                               if (i1->u.shm.shmid != i->u.shm.shmid)
+                                       continue;
+                               break;
+                       default:
+                               assert(0);
+                       }
+                       i1->addr = i->addr;
+               }
+               a->addr = i->addr;
+               a->first = i->first;
+               a->step = i->step;
+       }
        return 0;
 }
 
 int snd_pcm_munmap(snd_pcm_t *pcm)
 {
        int err;
+       unsigned int c;
        assert(pcm);
-       assert(pcm->mmap_info);
-       if ((err = pcm->ops->munmap(pcm->op_arg)) < 0)
+       assert(pcm->mmap_channels);
+       for (c = 0; c < pcm->channels; ++c) {
+               snd_pcm_channel_info_t *i = &pcm->mmap_channels[c];
+               unsigned int c1;
+               size_t size = i->first + i->step * pcm->buffer_size;
+               if (!i->addr)
+                       continue;
+               for (c1 = c + 1; c1 < pcm->channels; ++c1) {
+                       snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
+                       size_t s;
+                       if (i1->addr != i->addr)
+                               continue;
+                       i1->addr = NULL;
+                       s = i1->first + i1->step * pcm->buffer_size;
+                       if (s > size)
+                               size = s;
+               }
+               size = (size + 7) / 8;
+               size = PAGE_ALIGN(size);
+               switch (i->type) {
+               case SND_PCM_AREA_MMAP:
+                       err = munmap(i->addr, size);
+                       if (err < 0) {
+                               SYSERR("mmap failed");
+                               return -errno;
+                       }
+                       break;
+               case SND_PCM_AREA_SHM:
+                       err = shmdt(i->addr);
+                       if (err < 0) {
+                               SYSERR("shmdt failed");
+                               return -errno;
+                       }
+                       break;
+               default:
+                       assert(0);
+               }
+               i->addr = NULL;
+       }
+       err = pcm->ops->munmap(pcm);
+       if (err < 0)
                return err;
-       free(pcm->stopped_areas);
-       free(pcm->running_areas);
-       pcm->stopped_areas = 0;
-       pcm->running_areas = 0;
+       free(pcm->mmap_channels);
+       pcm->mmap_channels = 0;
        return 0;
 }
 
@@ -267,25 +412,34 @@ ssize_t snd_pcm_write_mmap(snd_pcm_t *pcm, size_t size)
        while (xfer < size) {
                size_t frames = size - xfer;
                size_t offset = snd_pcm_mmap_hw_offset(pcm);
-               size_t cont = pcm->setup.buffer_size - offset;
+               size_t cont = pcm->buffer_size - offset;
                if (cont < frames)
                        frames = cont;
-               if (pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED) {
+               switch (pcm->access) {
+               case SND_PCM_ACCESS_MMAP_INTERLEAVED:
+               {
                        snd_pcm_channel_area_t *a = snd_pcm_mmap_areas(pcm);
                        char *buf = snd_pcm_channel_area_addr(a, offset);
-                       assert(pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED);
                        err = _snd_pcm_writei(pcm, buf, size);
-               } else {
-                       size_t channels = pcm->setup.format.channels;
+                       break;
+               }
+               case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
+               {
+                       size_t channels = pcm->channels;
                        unsigned int c;
                        void *bufs[channels];
                        snd_pcm_channel_area_t *areas = snd_pcm_mmap_areas(pcm);
-                       assert(pcm->setup.mmap_shape == SND_PCM_MMAP_NONINTERLEAVED);
                        for (c = 0; c < channels; ++c) {
                                snd_pcm_channel_area_t *a = &areas[c];
                                bufs[c] = snd_pcm_channel_area_addr(a, offset);
                        }
                        err = _snd_pcm_writen(pcm, bufs, size);
+                       break;
+               }
+               default:
+                       assert(0);
+                       err = -EINVAL;
+                       break;
                }
                if (err < 0)
                        break;
@@ -304,26 +458,34 @@ ssize_t snd_pcm_read_mmap(snd_pcm_t *pcm, size_t size)
        while (xfer < size) {
                size_t frames = size - xfer;
                size_t offset = snd_pcm_mmap_hw_offset(pcm);
-               size_t cont = pcm->setup.buffer_size - offset;
+               size_t cont = pcm->buffer_size - offset;
                if (cont < frames)
                        frames = cont;
-               if (pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED) {
+               switch (pcm->access) {
+               case SND_PCM_ACCESS_MMAP_INTERLEAVED:
+               {
                        snd_pcm_channel_area_t *a = snd_pcm_mmap_areas(pcm);
                        char *buf = snd_pcm_channel_area_addr(a, offset);
-                       assert(pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED);
                        err = _snd_pcm_readi(pcm, buf, size);
-               } else {
-                       size_t channels = pcm->setup.format.channels;
+                       break;
+               }
+               case SND_PCM_ACCESS_MMAP_NONINTERLEAVED:
+               {
+                       size_t channels = pcm->channels;
                        unsigned int c;
                        void *bufs[channels];
                        snd_pcm_channel_area_t *areas = snd_pcm_mmap_areas(pcm);
-                       assert(pcm->setup.mmap_shape == SND_PCM_MMAP_NONINTERLEAVED);
                        for (c = 0; c < channels; ++c) {
                                snd_pcm_channel_area_t *a = &areas[c];
                                bufs[c] = snd_pcm_channel_area_addr(a, offset);
                        }
                        err = _snd_pcm_readn(pcm->fast_op_arg, bufs, size);
                }
+               default:
+                       assert(0);
+                       err = -EINVAL;
+                       break;
+               }
                if (err < 0)
                        break;
                xfer += frames;
index e7ed4802cda7c42fe010a3558f266113315d7d03..01cd202cc9ac235f7bdfadc884884a2e19107b48 100644 (file)
@@ -35,8 +35,6 @@ typedef struct {
        int getput_idx;
        mulaw_f func;
        int sformat;
-       int cformat;
-       int cxfer_mode, cmmap_shape;
 } snd_pcm_mulaw_t;
 
 static inline int val_seg(int val)
@@ -230,96 +228,76 @@ static void mulaw_encode(snd_pcm_channel_area_t *src_areas,
        }
 }
 
-static int snd_pcm_mulaw_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+static int snd_pcm_mulaw_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
 {
        snd_pcm_mulaw_t *mulaw = pcm->private;
-       unsigned int req_mask = info->req_mask;
-       unsigned int sfmt = info->req.format.sfmt;
+       unsigned int format_mask, access_mask;
        int err;
-       if (req_mask & SND_PCM_PARAMS_SFMT) {
-               if (mulaw->sformat == SND_PCM_SFMT_MU_LAW ?
-                   !snd_pcm_format_linear(sfmt) :
-                   sfmt != SND_PCM_SFMT_MU_LAW) {
-                       info->req.fail_mask = SND_PCM_PARAMS_SFMT;
-                       info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
-                       return -EINVAL;
-               }
+       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;
+
+       info->format_mask = 1U << mulaw->sformat;
+       info->access_mask = SND_PCM_ACCBIT_MMAP;
+       err = snd_pcm_hw_info(mulaw->plug.slave, info);
+       if (info->format_mask)
+               info->format_mask = format_mask;
+       if (info->access_mask) {
+               mulaw->plug.saccess_mask = info->access_mask;
+               info->access_mask = access_mask;
        }
-       info->req_mask |= SND_PCM_PARAMS_SFMT;
-       info->req_mask &= ~(SND_PCM_PARAMS_MMAP_SHAPE | 
-                           SND_PCM_PARAMS_XFER_MODE);
-       info->req.format.sfmt = mulaw->sformat;
-       err = snd_pcm_params_info(mulaw->plug.slave, info);
-       info->req_mask = req_mask;
-       info->req.format.sfmt = sfmt;
        if (err < 0)
                return err;
-       if (req_mask & SND_PCM_PARAMS_SFMT)
-               info->formats = 1 << sfmt;
-       else
-               info->formats = mulaw->sformat == SND_PCM_SFMT_MU_LAW ?
-                       SND_PCM_LINEAR_FORMATS : 1 << SND_PCM_SFMT_MU_LAW;
-       info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
-       info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
-       return err;
+       info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+       snd_pcm_hw_info_complete(info);
+       return 0;
 }
 
-static int snd_pcm_mulaw_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+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;
+       unsigned int format, access;
        int err;
-       if (mulaw->sformat == SND_PCM_SFMT_MU_LAW ?
-           !snd_pcm_format_linear(params->format.sfmt) :
-           params->format.sfmt != SND_PCM_SFMT_MU_LAW) {
-               params->fail_mask = SND_PCM_PARAMS_SFMT;
-               params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
-               return -EINVAL;
-       }
-       mulaw->cformat = params->format.sfmt;
-       mulaw->cxfer_mode = params->xfer_mode;
-       mulaw->cmmap_shape = params->mmap_shape;
-       params->format.sfmt = mulaw->sformat;
-       params->xfer_mode = SND_PCM_XFER_UNSPECIFIED;
-       params->mmap_shape = SND_PCM_MMAP_UNSPECIFIED;
-       err = snd_pcm_params_mmap(slave, params);
-       params->format.sfmt = mulaw->cformat;
-       params->xfer_mode = mulaw->cxfer_mode;
-       params->mmap_shape = mulaw->cmmap_shape;
-       return err;
-}
-
-static int snd_pcm_mulaw_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
-{
-       snd_pcm_mulaw_t *mulaw = pcm->private;
-       int err = snd_pcm_setup(mulaw->plug.slave, setup);
+       format = params->format;
+       access = params->access;
+       params->format = mulaw->sformat;
+       if (mulaw->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
+               params->access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
+       else if (mulaw->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
+               params->access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
+       else
+               assert(0);
+       err = snd_pcm_hw_params(slave, params);
+       params->format = format;
+       params->access = access;
        if (err < 0)
                return err;
-       assert(mulaw->sformat == setup->format.sfmt);
-       if (mulaw->cxfer_mode == SND_PCM_XFER_UNSPECIFIED)
-               setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
-       else
-               setup->xfer_mode = mulaw->cxfer_mode;
-       if (mulaw->cmmap_shape == SND_PCM_MMAP_UNSPECIFIED)
-               setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
-       else
-               setup->mmap_shape = mulaw->cmmap_shape;
-       setup->format.sfmt = mulaw->cformat;
-       setup->mmap_bytes = 0;
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
-               if (mulaw->sformat == SND_PCM_SFMT_MU_LAW) {
-                       mulaw->getput_idx = get_index(mulaw->cformat, SND_PCM_SFMT_S16);
+               if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) {
+                       mulaw->getput_idx = get_index(format, SND_PCM_FORMAT_S16);
                        mulaw->func = mulaw_encode;
                } else {
-                       mulaw->getput_idx = put_index(SND_PCM_SFMT_S16, mulaw->sformat);
+                       mulaw->getput_idx = put_index(SND_PCM_FORMAT_S16, mulaw->sformat);
                        mulaw->func = mulaw_decode;
                }
        } else {
-               if (mulaw->sformat == SND_PCM_SFMT_MU_LAW) {
-                       mulaw->getput_idx = put_index(SND_PCM_SFMT_S16, mulaw->cformat);
+               if (mulaw->sformat == SND_PCM_FORMAT_MU_LAW) {
+                       mulaw->getput_idx = put_index(SND_PCM_FORMAT_S16, format);
                        mulaw->func = mulaw_decode;
                } else {
-                       mulaw->getput_idx = get_index(mulaw->sformat, SND_PCM_SFMT_S16);
+                       mulaw->getput_idx = get_index(mulaw->sformat, SND_PCM_FORMAT_S16);
                        mulaw->func = mulaw_encode;
                }
        }
@@ -343,7 +321,7 @@ static ssize_t snd_pcm_mulaw_write_areas(snd_pcm_t *pcm,
                size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
                mulaw->func(areas, offset, 
                            snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
-                           frames, pcm->setup.format.channels,
+                           frames, pcm->channels,
                            mulaw->getput_idx);
                err = snd_pcm_mmap_forward(slave, frames);
                if (err < 0)
@@ -378,7 +356,7 @@ static ssize_t snd_pcm_mulaw_read_areas(snd_pcm_t *pcm,
                size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
                mulaw->func(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
                            areas, offset, 
-                           frames, pcm->setup.format.channels,
+                           frames, pcm->channels,
                            mulaw->getput_idx);
                err = snd_pcm_mmap_forward(slave, frames);
                if (err < 0)
@@ -401,7 +379,7 @@ static void snd_pcm_mulaw_dump(snd_pcm_t *pcm, FILE *fp)
        snd_pcm_mulaw_t *mulaw = pcm->private;
        fprintf(fp, "Mu-Law conversion PCM (%s)\n", 
                snd_pcm_format_name(mulaw->sformat));
-       if (pcm->valid_setup) {
+       if (pcm->setup) {
                fprintf(fp, "Its setup is:\n");
                snd_pcm_dump_setup(pcm, fp);
        }
@@ -412,12 +390,12 @@ 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,
-       params_info: snd_pcm_mulaw_params_info,
-       params: snd_pcm_mulaw_params,
-       setup: snd_pcm_mulaw_setup,
+       hw_info: snd_pcm_mulaw_hw_info,
+       hw_params: snd_pcm_mulaw_hw_params,
+       sw_params: snd_pcm_plugin_sw_params,
+       dig_info: snd_pcm_plugin_dig_info,
+       dig_params: snd_pcm_plugin_dig_params,
        channel_info: snd_pcm_plugin_channel_info,
-       channel_params: snd_pcm_plugin_channel_params,
-       channel_setup: snd_pcm_plugin_channel_setup,
        dump: snd_pcm_mulaw_dump,
        nonblock: snd_pcm_plugin_nonblock,
        async: snd_pcm_plugin_async,
@@ -431,7 +409,7 @@ int snd_pcm_mulaw_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *sla
        snd_pcm_mulaw_t *mulaw;
        assert(pcmp && slave);
        if (snd_pcm_format_linear(sformat) != 1 &&
-           sformat != SND_PCM_SFMT_MU_LAW)
+           sformat != SND_PCM_FORMAT_MU_LAW)
                return -EINVAL;
        mulaw = calloc(1, sizeof(snd_pcm_mulaw_t));
        if (!mulaw) {
@@ -498,7 +476,7 @@ int _snd_pcm_mulaw_open(snd_pcm_t **pcmp, char *name,
                        if (sformat < 0)
                                return -EINVAL;
                        if (snd_pcm_format_linear(sformat) != 1 &&
-                           sformat != SND_PCM_SFMT_MU_LAW)
+                           sformat != SND_PCM_FORMAT_MU_LAW)
                                return -EINVAL;
                        continue;
                }
index 13c9f523a63ee9a29fade06fed3613bda1183b2d..95f634780ab4d883445d98d316f148662100401c 100644 (file)
@@ -31,6 +31,7 @@ typedef struct {
        snd_pcm_t *pcm;
        unsigned int channels_count;
        int close_slave;
+       unsigned int access_mask;
 } snd_pcm_multi_slave_t;
 
 typedef struct {
@@ -43,7 +44,6 @@ typedef struct {
        snd_pcm_multi_slave_t *slaves;
        size_t channels_count;
        snd_pcm_multi_channel_t *channels;
-       int xfer_mode;
 } snd_pcm_multi_t;
 
 static int snd_pcm_multi_close(snd_pcm_t *pcm)
@@ -91,176 +91,104 @@ static int snd_pcm_multi_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
        return 0;
 }
 
-static int snd_pcm_multi_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info)
+static int snd_pcm_multi_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info)
 {
        snd_pcm_multi_t *multi = pcm->private;
-       unsigned int i;
-       int err;
-       snd_pcm_t *slave_0 = multi->slaves[0].pcm;
-       unsigned int req_mask = info->req_mask;
-       unsigned int channels = info->req.format.channels;
-       if ((req_mask & SND_PCM_PARAMS_CHANNELS) &&
-           channels != multi->channels_count) {
-               info->req.fail_mask |= SND_PCM_PARAMS_CHANNELS;
-               info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+       unsigned int k;
+       snd_pcm_hw_info_t i;
+       unsigned int access_mask = ~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_max > info->channels_max)
                return -EINVAL;
-       }
-       info->req_mask |= SND_PCM_PARAMS_CHANNELS;
-       info->req.format.channels = multi->slaves[0].channels_count;
-       err = snd_pcm_params_info(slave_0, info);
-       info->req_mask = req_mask;
-       info->req.format.channels = channels;
-       if (err < 0)
-               return err;
-       info->min_channels = multi->channels_count;
-       info->max_channels = multi->channels_count;
-       for (i = 1; i < multi->slaves_count; ++i) {
-               snd_pcm_t *slave_i = multi->slaves[i].pcm;
-               snd_pcm_params_info_t info_i;
-               info_i = *info;
-               info_i.req_mask |= SND_PCM_PARAMS_CHANNELS;
-               info_i.req.format.channels = multi->slaves[i].channels_count;
-               err = snd_pcm_params_info(slave_i, &info_i);
+       i = *info;
+       for (k = 0; k < multi->slaves_count; ++k) {
+               snd_pcm_t *slave = multi->slaves[k].pcm;
+               i.access_mask = SND_PCM_ACCBIT_MMAP;
+               i.channels_min = i.channels_max = multi->slaves[k].channels_count;
+               err = snd_pcm_hw_info(slave, &i);
+               access_mask &= i.access_mask;
                if (err < 0)
-                       return err;
-               info->formats &= info_i.formats;
-               info->rates &= info_i.rates;
-               if (info_i.min_rate > info->min_rate)
-                       info->min_rate = info_i.min_rate;
-               if (info_i.max_rate < info->max_rate)
-                       info->max_rate = info_i.max_rate;
-               if (info_i.buffer_size < info->buffer_size)
-                       info->buffer_size = info_i.buffer_size;
-               if (info_i.min_fragment_size > info->min_fragment_size)
-                       info->min_fragment_size = info_i.min_fragment_size;
-               if (info_i.max_fragment_size < info->max_fragment_size)
-                       info->max_fragment_size = info_i.max_fragment_size;
-               if (info_i.min_fragments > info->min_fragments)
-                       info->min_fragments = info_i.min_fragments;
-               if (info_i.max_fragments < info->max_fragments)
-                       info->max_fragments = info_i.max_fragments;
-               info->flags &= info_i.flags;
+                       break;
+               multi->slaves[k].access_mask = i.access_mask;
        }
-       if (info->flags & SND_PCM_INFO_INTERLEAVED) {
-               if (multi->slaves_count > 0) {
-                       info->flags &= ~SND_PCM_INFO_INTERLEAVED;
-                       info->flags |= SND_PCM_INFO_COMPLEX;
-               }
-       } else if (!(info->flags & SND_PCM_INFO_NONINTERLEAVED))
-               info->flags |= SND_PCM_INFO_COMPLEX;
-       info->req_mask = req_mask;
-       return 0;
+       *info = i;
+       if (i.channels_min <= i.channels_max) 
+               info->channels_min = info->channels_max = multi->channels_count;
+       if (i.access_mask) {
+               if (!(access_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED) ||
+                   multi->slaves_count > 1)
+                       info->access_mask &= ~SND_PCM_ACCBIT_MMAP_INTERLEAVED;
+               if (!(access_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED))
+                       info->access_mask &= ~SND_PCM_ACCBIT_MMAP_NONINTERLEAVED;
+       }
+       return err;
 }
 
-static int snd_pcm_multi_mmap(snd_pcm_t *pcm)
+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;
-       size_t count = 0;
+       snd_pcm_hw_params_t p;
+       int err;
+       if (params->channels != multi->channels_count) {
+               params->fail_mask = SND_PCM_HW_PARBIT_CHANNELS;
+               return -EINVAL;
+       }
+       p = *params;
        for (i = 0; i < multi->slaves_count; ++i) {
                snd_pcm_t *slave = multi->slaves[i].pcm;
-               snd_pcm_setup_t *setup;
-               int err = snd_pcm_mmap(slave);
+               if (multi->slaves[i].access_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
+                       p.access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
+               else if (multi->slaves[i].access_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
+                       p.access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
+               else
+                       assert(0);
+               p.channels = multi->slaves[i].channels_count;
+               err = snd_pcm_hw_params(slave, &p);
+               if (err < 0) {
+                       params->fail_mask = p.fail_mask;
+                       return err;
+               }
+               err = snd_pcm_areas_silence(slave->running_areas, 0, slave->channels, slave->buffer_size, slave->format);
                if (err < 0)
                        return err;
-               count += slave->mmap_info_count;
-               setup = &slave->setup;
-               if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
-                       snd_pcm_channel_area_t r[setup->format.channels];
-                       snd_pcm_channel_area_t s[setup->format.channels];
-                       err = snd_pcm_mmap_get_areas(slave, s, r);
-                       if (err < 0)
-                               return err;
-                       err = snd_pcm_areas_silence(s, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt);
-                       if (err < 0)
-                               return err;
-                       err = snd_pcm_areas_silence(r, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt);
+               if (slave->stopped_areas) {
+                       err = snd_pcm_areas_silence(slave->stopped_areas, 0, slave->channels, slave->buffer_size, slave->format);
                        if (err < 0)
                                return err;
                }
        }
-       pcm->mmap_info_count = count;
-       pcm->mmap_info = malloc(count * sizeof(*pcm->mmap_info));
-       count = 0;
-       for (i = 0; i < multi->slaves_count; ++i) {
-               snd_pcm_t *slave = multi->slaves[i].pcm;
-               memcpy(&pcm->mmap_info[count], slave->mmap_info, slave->mmap_info_count * sizeof(*pcm->mmap_info));
-               count += slave->mmap_info_count;
-       }
        return 0;
 }
 
-static int snd_pcm_multi_munmap(snd_pcm_t *pcm)
+static int snd_pcm_multi_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
 {
        snd_pcm_multi_t *multi = pcm->private;
        unsigned int i;
+       int err;
        for (i = 0; i < multi->slaves_count; ++i) {
                snd_pcm_t *slave = multi->slaves[i].pcm;
-               int err = snd_pcm_munmap(slave);
+               err = snd_pcm_sw_params(slave, params);
                if (err < 0)
                        return err;
        }
-       pcm->mmap_info_count = 0;
-       free(pcm->mmap_info);
-       pcm->mmap_info = 0;
        return 0;
 }
-               
-static int snd_pcm_multi_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
+
+static int snd_pcm_multi_dig_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_dig_info_t *info ATTRIBUTE_UNUSED)
 {
-       snd_pcm_multi_t *multi = pcm->private;
-       unsigned int i;
-       snd_pcm_params_t p;
-       int err = 0;
-       if (params->format.channels != multi->channels_count) {
-               params->fail_mask = SND_PCM_PARAMS_CHANNELS;
-               params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
-               return -EINVAL;
-       }
-       p = *params;
-       for (i = 0; i < multi->slaves_count; ++i) {
-               snd_pcm_t *slave = multi->slaves[i].pcm;
-               p.format.channels = multi->slaves[i].channels_count;
-               err = snd_pcm_params_mmap(slave, &p);
-               if (err < 0) {
-                       params->fail_mask = p.fail_mask;
-                       params->fail_reason = p.fail_reason;
-                       break;
-               }
-       }
-       if (err == 0)
-               multi->xfer_mode = params->xfer_mode;
-       return err;
+       /* FIXME */
+       return -ENOSYS;
 }
 
-static int snd_pcm_multi_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup)
+static int snd_pcm_multi_dig_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_dig_params_t *params ATTRIBUTE_UNUSED)
 {
-       snd_pcm_multi_t *multi = pcm->private;
-       unsigned int i;
-       int err;
-       err = snd_pcm_setup(multi->slaves[0].pcm, setup);
-       if (err < 0)
-               return err;
-       for (i = 1; i < multi->slaves_count; ++i) {
-               snd_pcm_setup_t s;
-               snd_pcm_t *sh = multi->slaves[i].pcm;
-               err = snd_pcm_setup(sh, &s);
-               if (err < 0)
-                       return err;
-               if (setup->format.rate != s.format.rate)
-                       return -EINVAL;
-               if (setup->buffer_size != s.buffer_size)
-                       return -EINVAL;
-               if (setup->mmap_shape != SND_PCM_MMAP_NONINTERLEAVED ||
-                   s.mmap_shape != SND_PCM_MMAP_NONINTERLEAVED)
-                       setup->mmap_shape = SND_PCM_MMAP_COMPLEX;
-       }
-       setup->format.channels = multi->channels_count;
-       if (multi->xfer_mode == SND_PCM_XFER_UNSPECIFIED)
-               setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
-       else
-               setup->xfer_mode = multi->xfer_mode;
-       return 0;
+       /* FIXME */
+       return -ENOSYS;
 }
 
 static int snd_pcm_multi_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
@@ -335,34 +263,6 @@ static int snd_pcm_multi_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *in
        return err;
 }
 
-static int snd_pcm_multi_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
-{
-       snd_pcm_multi_t *multi = pcm->private;
-       unsigned int channel = params->channel;
-       snd_pcm_multi_channel_t *c = &multi->channels[channel];
-       int err;
-       if (c->slave_idx < 0)
-               return -ENXIO;
-       params->channel = c->slave_channel;
-       err = snd_pcm_channel_params(multi->slaves[c->slave_idx].pcm, params);
-       params->channel = channel;
-       return err;
-}
-
-static int snd_pcm_multi_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
-{
-       snd_pcm_multi_t *multi = pcm->private;
-       unsigned int channel = setup->channel;
-       snd_pcm_multi_channel_t *c = &multi->channels[channel];
-       int err;
-       if (c->slave_idx < 0)
-               return -ENXIO;
-       setup->channel = c->slave_channel;
-       err = snd_pcm_channel_setup(multi->slaves[c->slave_idx].pcm, setup);
-       setup->channel = channel;
-       return err;
-}
-
 static ssize_t snd_pcm_multi_rewind(snd_pcm_t *pcm, size_t frames)
 {
        snd_pcm_multi_t *multi = pcm->private;
@@ -413,6 +313,16 @@ static int snd_pcm_multi_set_avail_min(snd_pcm_t *pcm, size_t frames)
        return snd_pcm_set_avail_min(multi->slaves[0].pcm, frames);
 }
 
+static int snd_pcm_multi_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
+{
+       return 0;
+}
+
+static int snd_pcm_multi_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
+{
+       return 0;
+}
+
 int snd_pcm_multi_poll_descriptor(snd_pcm_t *pcm)
 {
        snd_pcm_multi_t *multi = pcm->private;
@@ -433,7 +343,7 @@ static void snd_pcm_multi_dump(snd_pcm_t *pcm, FILE *fp)
                fprintf(fp, "%d: slave %d, channel %d\n", 
                        k, c->slave_idx, c->slave_channel);
        }
-       if (pcm->valid_setup) {
+       if (pcm->setup) {
                fprintf(fp, "\nIts setup is:\n");
                snd_pcm_dump_setup(pcm, fp);
        }
@@ -446,12 +356,12 @@ 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,
-       params_info: snd_pcm_multi_params_info,
-       params: snd_pcm_multi_params,
-       setup: snd_pcm_multi_setup,
+       hw_info: snd_pcm_multi_hw_info,
+       hw_params: snd_pcm_multi_hw_params,
+       sw_params: snd_pcm_multi_sw_params,
+       dig_info: snd_pcm_multi_dig_info,
+       dig_params: snd_pcm_multi_dig_params,
        channel_info: snd_pcm_multi_channel_info,
-       channel_params: snd_pcm_multi_channel_params,
-       channel_setup: snd_pcm_multi_channel_setup,
        dump: snd_pcm_multi_dump,
        nonblock: snd_pcm_multi_nonblock,
        async: snd_pcm_multi_async,
@@ -538,7 +448,7 @@ int snd_pcm_multi_open(snd_pcm_t **pcmp, char *name,
        pcm->type = SND_PCM_TYPE_MULTI;
        pcm->stream = stream;
        pcm->mode = multi->slaves[0].pcm->mode;
-       pcm->mmap_auto = 1;
+       pcm->mmap_rw = 1;
        pcm->ops = &snd_pcm_multi_ops;
        pcm->op_arg = pcm;
        pcm->fast_ops = &snd_pcm_multi_fast_ops;
index 625c08f9b2c656b9cfd425d950297dbb5efa41c3..2878a17ba6ef995501b777ba98e30eaab522f052 100644 (file)
   
 #include <byteswap.h>
 #include <limits.h>
+#include <sys/shm.h>
 #include "pcm_local.h"
 #include "pcm_plugin.h"
 
 typedef struct {
-       snd_pcm_setup_t setup;
        snd_timestamp_t trigger_time;
        int state;
+       int shmid;
        size_t appl_ptr;
        size_t hw_ptr;
        int poll_fd;
@@ -58,25 +59,10 @@ static int snd_pcm_null_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_info_t * i
        return 0;
 }
 
-static int snd_pcm_null_channel_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_channel_info_t * info)
+static int snd_pcm_null_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
 {
-       int channel = info->channel;
-       memset(info, 0, sizeof(*info));
-       info->channel = channel;
-       return 0;
-}
-
-static int snd_pcm_null_channel_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_channel_params_t * params ATTRIBUTE_UNUSED)
-{
-       return 0;
-}
-
-static int snd_pcm_null_channel_setup(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_channel_setup_t * setup)
-{
-       int channel = setup->channel;
-       memset(setup, 0, sizeof(*setup));
-       setup->channel = channel;
-       return 0;
+       snd_pcm_null_t *null = pcm->private;
+       return snd_pcm_channel_info_shm(pcm, info, null->shmid);
 }
 
 static int snd_pcm_null_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
@@ -86,7 +72,7 @@ static int snd_pcm_null_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
        status->state = null->state;
        status->trigger_time = null->trigger_time;
        gettimeofday(&status->tstamp, 0);
-       status->avail = pcm->setup.buffer_size;
+       status->avail = pcm->buffer_size;
        status->avail_max = status->avail;
        return 0;
 }
@@ -118,7 +104,7 @@ static int snd_pcm_null_start(snd_pcm_t *pcm)
        assert(null->state == SND_PCM_STATE_PREPARED);
        null->state = SND_PCM_STATE_RUNNING;
        if (pcm->stream == SND_PCM_STREAM_CAPTURE)
-               snd_pcm_mmap_appl_forward(pcm, pcm->setup.buffer_size);
+               snd_pcm_mmap_appl_forward(pcm, pcm->buffer_size);
        return 0;
 }
 
@@ -182,7 +168,7 @@ static ssize_t snd_pcm_null_writei(snd_pcm_t *pcm, const void *buffer ATTRIBUTE_
 {
        snd_pcm_null_t *null = pcm->private;
        if (null->state == SND_PCM_STATE_PREPARED &&
-           pcm->setup.start_mode != SND_PCM_START_EXPLICIT) {
+           pcm->start_mode != SND_PCM_START_EXPLICIT) {
                null->state = SND_PCM_STATE_RUNNING;
        }
        return snd_pcm_null_fwd(pcm, size);
@@ -192,7 +178,7 @@ static ssize_t snd_pcm_null_writen(snd_pcm_t *pcm, void **bufs ATTRIBUTE_UNUSED,
 {
        snd_pcm_null_t *null = pcm->private;
        if (null->state == SND_PCM_STATE_PREPARED &&
-           pcm->setup.start_mode != SND_PCM_START_EXPLICIT) {
+           pcm->start_mode != SND_PCM_START_EXPLICIT) {
                null->state = SND_PCM_STATE_RUNNING;
        }
        return snd_pcm_null_fwd(pcm, size);
@@ -202,9 +188,9 @@ static ssize_t snd_pcm_null_readi(snd_pcm_t *pcm, void *buffer ATTRIBUTE_UNUSED,
 {
        snd_pcm_null_t *null = pcm->private;
        if (null->state == SND_PCM_STATE_PREPARED &&
-           pcm->setup.start_mode != SND_PCM_START_EXPLICIT) {
+           pcm->start_mode != SND_PCM_START_EXPLICIT) {
                null->state = SND_PCM_STATE_RUNNING;
-               snd_pcm_mmap_hw_forward(pcm, pcm->setup.buffer_size);
+               snd_pcm_mmap_hw_forward(pcm, pcm->buffer_size);
        }
        return snd_pcm_null_fwd(pcm, size);
 }
@@ -213,9 +199,9 @@ static ssize_t snd_pcm_null_readn(snd_pcm_t *pcm, void **bufs ATTRIBUTE_UNUSED,
 {
        snd_pcm_null_t *null = pcm->private;
        if (null->state == SND_PCM_STATE_PREPARED &&
-           pcm->setup.start_mode != SND_PCM_START_EXPLICIT) {
+           pcm->start_mode != SND_PCM_START_EXPLICIT) {
                null->state = SND_PCM_STATE_RUNNING;
-               snd_pcm_mmap_hw_forward(pcm, pcm->setup.buffer_size);
+               snd_pcm_mmap_hw_forward(pcm, pcm->buffer_size);
        }
        return snd_pcm_null_fwd(pcm, size);
 }
@@ -227,111 +213,83 @@ static ssize_t snd_pcm_null_mmap_forward(snd_pcm_t *pcm, size_t size)
 
 static ssize_t snd_pcm_null_avail_update(snd_pcm_t *pcm)
 {
-       return pcm->setup.buffer_size;
+       return pcm->buffer_size;
 }
 
 static int snd_pcm_null_set_avail_min(snd_pcm_t *pcm, size_t frames)
 {
-       pcm->setup.buffer_size = frames;
+       pcm->avail_min = frames;
        return 0;
 }
 
-static int snd_pcm_null_mmap(snd_pcm_t *pcm)
+static int snd_pcm_null_hw_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_info_t * info)
 {
-       snd_pcm_mmap_info_t *i;
-       int err;
-       i = calloc(1, sizeof(*i));
-       if (!i)
-               return -ENOMEM;
-       err = snd_pcm_alloc_user_mmap(pcm, i);
-       if (err < 0) {
-               free(i);
-               return err;
-       }
-       pcm->mmap_info = i;
-       pcm->mmap_info_count = 1;
+       snd_pcm_hw_info_complete(info);
+       info->fifo_size = 0;
        return 0;
 }
 
-static int snd_pcm_null_munmap(snd_pcm_t *pcm)
+static int snd_pcm_null_hw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t * params ATTRIBUTE_UNUSED)
 {
-       int err = snd_pcm_free_mmap(pcm, pcm->mmap_info);
-       if (err < 0)
-               return err;
-       free(pcm->mmap_info);
-       pcm->mmap_info_count = 0;
-       pcm->mmap_info = 0;
        return 0;
 }
 
-static int snd_pcm_null_params_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_params_info_t * info)
-{
-       int sizes = ((info->req_mask & SND_PCM_PARAMS_SFMT) &&
-                    (info->req_mask & SND_PCM_PARAMS_CHANNELS));
-       info->flags = SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID |
-         SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED |
-         SND_PCM_INFO_PAUSE;
-       info->formats = ~0;
-       info->rates = SND_PCM_RATE_CONTINUOUS | SND_PCM_RATE_8000_192000;
-       info->min_rate = 4000;
-       info->max_rate = 192000;
-       info->min_channels = 1;
-       info->max_channels = 32;
-       info->min_fragments = 1;
-       info->max_fragments = 1024 * 1024;
-       if (sizes) {
-               info->buffer_size = 1024 * 1024;
-               info->min_fragment_size = 1;
-               info->max_fragment_size = 1024 * 1024;
-               info->fragment_align = 1;
+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;
+               return -EINVAL;
+       }
+       if (params->ready_mode > SND_PCM_READY_LAST) {
+               params->fail_mask = SND_PCM_SW_PARBIT_READY_MODE;
+               return -EINVAL;
+       }
+       if (params->xrun_mode > SND_PCM_XRUN_LAST) {
+               params->fail_mask = SND_PCM_SW_PARBIT_XRUN_MODE;
+               return -EINVAL;
        }
        return 0;
 }
 
-static int snd_pcm_null_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+static int snd_pcm_null_dig_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_dig_params_t *params ATTRIBUTE_UNUSED)
+{
+       return 0;
+}
+
+static int snd_pcm_null_dig_info(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_dig_info_t *info ATTRIBUTE_UNUSED)
+{
+       return 0;
+}
+
+static int snd_pcm_null_mmap(snd_pcm_t *pcm)
 {
        snd_pcm_null_t *null = pcm->private;
-       snd_pcm_setup_t *s = &null->setup;
-       int w = snd_pcm_format_width(s->format.sfmt);
-       if (w < 0) {
-               params->fail_mask = SND_PCM_PARAMS_SFMT;
-               return -EINVAL;
+       if (!(pcm->info & SND_PCM_INFO_MMAP)) {
+               size_t size = snd_pcm_frames_to_bytes(pcm, pcm->buffer_size);
+               int id = shmget(IPC_PRIVATE, size, 0666);
+               if (id < 0) {
+                       SYSERR("shmget failed");
+                       return -errno;
+               }
+               null->shmid = id;
        }
-       s->msbits = w;
-       s->format = params->format;
-       s->start_mode = params->start_mode;
-       s->ready_mode = params->ready_mode;
-       s->avail_min = params->avail_min;
-       s->xfer_mode = params->xfer_mode;
-       s->xfer_min = params->xfer_min;
-       s->xfer_align = params->xfer_align;
-       s->xrun_mode = params->xrun_mode;
-       s->mmap_shape = params->mmap_shape;
-       s->frag_size = params->frag_size;
-       s->frags = s->buffer_size / s->frag_size;
-       if (s->frags < 1)
-               s->frags = 1;
-       s->buffer_size = s->frag_size * s->frags;
-       s->boundary = LONG_MAX - LONG_MAX % s->buffer_size;
-       s->time = params->time;
-       s->rate_master = s->format.rate;
-       s->rate_divisor = 1;
-       s->mmap_bytes = 0;
-       s->fifo_size = 1;
        return 0;
 }
 
-static int snd_pcm_null_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
+static int snd_pcm_null_munmap(snd_pcm_t *pcm)
 {
        snd_pcm_null_t *null = pcm->private;
-       *setup = null->setup;
+       if (shmctl(null->shmid, IPC_RMID, 0) < 0) {
+               SYSERR("shmctl IPC_RMID failed");
+                       return -errno;
+       }
        return 0;
 }
 
 static void snd_pcm_null_dump(snd_pcm_t *pcm, FILE *fp)
 {
        fprintf(fp, "Null PCM\n");
-       if (pcm->valid_setup) {
+       if (pcm->setup) {
                fprintf(fp, "Its setup is:\n");
                snd_pcm_dump_setup(pcm, fp);
        }
@@ -340,12 +298,12 @@ 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,
-       params_info: snd_pcm_null_params_info,
-       params: snd_pcm_null_params,
-       setup: snd_pcm_null_setup,
+       hw_info: snd_pcm_null_hw_info,
+       hw_params: snd_pcm_null_hw_params,
+       sw_params: snd_pcm_null_sw_params,
+       dig_params: snd_pcm_null_dig_params,
+       dig_info: snd_pcm_null_dig_info,
        channel_info: snd_pcm_null_channel_info,
-       channel_params: snd_pcm_null_channel_params,
-       channel_setup: snd_pcm_null_channel_setup,
        dump: snd_pcm_null_dump,
        nonblock: snd_pcm_null_nonblock,
        async: snd_pcm_null_async,
index d659ccb5c0b0ecde15ec64f7a0d0a5a21af9698a..cafe1970568bf75ca7e52c21901cdbb099abe0d2 100644 (file)
@@ -32,37 +32,25 @@ typedef struct {
 } snd_pcm_plug_t;
 
 
-unsigned int snd_pcm_plug_formats(unsigned int formats)
-{
-       int fmts = (SND_PCM_LINEAR_FORMATS | SND_PCM_FMT_MU_LAW |
-                   SND_PCM_FMT_A_LAW | SND_PCM_FMT_IMA_ADPCM);
-       if (formats & fmts)
-               formats |= fmts;
-       return formats;
-}
-
 static int preferred_formats[] = {
-       SND_PCM_SFMT_S16_LE,
-       SND_PCM_SFMT_S16_BE,
-       SND_PCM_SFMT_U16_LE,
-       SND_PCM_SFMT_U16_BE,
-       SND_PCM_SFMT_S24_LE,
-       SND_PCM_SFMT_S24_BE,
-       SND_PCM_SFMT_U24_LE,
-       SND_PCM_SFMT_U24_BE,
-       SND_PCM_SFMT_S32_LE,
-       SND_PCM_SFMT_S32_BE,
-       SND_PCM_SFMT_U32_LE,
-       SND_PCM_SFMT_U32_BE,
-       SND_PCM_SFMT_S8,
-       SND_PCM_SFMT_U8
+       SND_PCM_FORMAT_S16_LE,
+       SND_PCM_FORMAT_S16_BE,
+       SND_PCM_FORMAT_U16_LE,
+       SND_PCM_FORMAT_U16_BE,
+       SND_PCM_FORMAT_S24_LE,
+       SND_PCM_FORMAT_S24_BE,
+       SND_PCM_FORMAT_U24_LE,
+       SND_PCM_FORMAT_U24_BE,
+       SND_PCM_FORMAT_S32_LE,
+       SND_PCM_FORMAT_S32_BE,
+       SND_PCM_FORMAT_U32_LE,
+       SND_PCM_FORMAT_U32_BE,
+       SND_PCM_FORMAT_S8,
+       SND_PCM_FORMAT_U8
 };
 
-static int snd_pcm_plug_slave_fmt(int format,
-                                 snd_pcm_params_info_t *slave_info)
+static int snd_pcm_plug_slave_fmt(int format, unsigned int format_mask)
 {
-       if ((snd_pcm_plug_formats(slave_info->formats) & (1 << format)) == 0)
-               return -EINVAL;
        if (snd_pcm_format_linear(format)) {
                int width = snd_pcm_format_width(format);
                int unsignd = snd_pcm_format_unsigned(format);
@@ -77,8 +65,8 @@ static int snd_pcm_plug_slave_fmt(int format,
                                for (sgn = 0; sgn < 2; ++sgn) {
                                        format1 = snd_pcm_build_linear_format(width1, unsignd1, big1);
                                        if (format1 >= 0 &&
-                                           slave_info->formats & (1 << format1))
-                                               goto _found;
+                                           format_mask & (1U << format1))
+                                               return format1;
                                        unsignd1 = !unsignd1;
                                }
                                big1 = !big1;
@@ -89,80 +77,24 @@ static int snd_pcm_plug_slave_fmt(int format,
                        }
                        width1 += dwidth1;
                }
-               return -EINVAL;
-       _found:
-               return format1;
+               return ffs(format_mask) - 1;
        } else {
                unsigned int i;
                switch (format) {
-               case SND_PCM_SFMT_MU_LAW:
-               case SND_PCM_SFMT_A_LAW:
-               case SND_PCM_SFMT_IMA_ADPCM:
+               case SND_PCM_FORMAT_MU_LAW:
+               case SND_PCM_FORMAT_A_LAW:
+               case SND_PCM_FORMAT_IMA_ADPCM:
                        for (i = 0; i < sizeof(preferred_formats) / sizeof(preferred_formats[0]); ++i) {
                                int format1 = preferred_formats[i];
-                               if (slave_info->formats & (1 << format1))
+                               if (format_mask & (1U << format1))
                                        return format1;
                        }
                default:
-                       return -EINVAL;
+                       return ffs(format_mask) - 1;
                }
        }
 }
 
-struct {
-       unsigned int rate;
-       unsigned int flag;
-} snd_pcm_rates[] = {
-       { 8000, SND_PCM_RATE_8000 },
-       { 11025, SND_PCM_RATE_11025 },
-       { 16000, SND_PCM_RATE_16000 },
-       { 22050, SND_PCM_RATE_22050 },
-       { 32000, SND_PCM_RATE_32000 },
-       { 44100, SND_PCM_RATE_44100 },
-       { 48000, SND_PCM_RATE_48000 },
-       { 88200, SND_PCM_RATE_88200 },
-       { 96000, SND_PCM_RATE_96000 },
-       { 176400, SND_PCM_RATE_176400 },
-       { 192000, SND_PCM_RATE_192000 }
-};
-
-static int snd_pcm_plug_slave_rate(unsigned int rate,
-                                  snd_pcm_params_info_t *slave_info)
-{
-        if (rate <= slave_info->min_rate)
-               return slave_info->min_rate;
-       else if (rate >= slave_info->max_rate)
-               return slave_info->max_rate;
-       else if (!(slave_info->rates & (SND_PCM_RATE_CONTINUOUS |
-                                       SND_PCM_RATE_KNOT))) {
-               unsigned int k;
-               unsigned int rate1 = 0, rate2 = 0;
-               int delta1, delta2;
-               for (k = 0; k < sizeof(snd_pcm_rates) / 
-                            sizeof(snd_pcm_rates[0]); ++k) {
-                       if (!(snd_pcm_rates[k].flag & slave_info->rates))
-                               continue;
-                       if (snd_pcm_rates[k].rate < rate) {
-                               rate1 = snd_pcm_rates[k].rate;
-                       } else if (snd_pcm_rates[k].rate >= rate) {
-                               rate2 = snd_pcm_rates[k].rate;
-                               break;
-                       }
-               }
-               if (rate1 == 0)
-                       return rate2;
-               if (rate2 == 0)
-                       return rate1;
-               delta1 = rate - rate1;
-               delta2 = rate2 - rate;
-               if (delta1 < delta2)
-                       return rate1;
-               else
-                       return rate2;
-       }
-       return rate;
-}
-
 static int snd_pcm_plug_close(snd_pcm_t *pcm)
 {
        snd_pcm_plug_t *plug = pcm->private;
@@ -206,97 +138,156 @@ static int snd_pcm_plug_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
        return 0;
 }
 
-static int snd_pcm_plug_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info)
+static int snd_pcm_plug_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info)
 {
        int err;
        snd_pcm_plug_t *plug = pcm->private;
        snd_pcm_t *slave = plug->req_slave;
-       snd_pcm_params_info_t slave_info;
-       int sformat, srate;
-       unsigned int schannels;
-       int crate;
-
-       info->req.fail_reason = 0;
-       info->req.fail_mask = 0;
+       snd_pcm_hw_info_t sinfo, i;
+       snd_pcm_hw_params_t sparams;
+       unsigned int rate_min, rate_max;
+       unsigned int channels_min, channels_max;
+       unsigned int format, format_mask;
+       size_t fragment_size_min, fragment_size_max;
+       
+       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;
 
-       if (info->req_mask & SND_PCM_PARAMS_RATE) {
-               info->min_rate = info->req.format.rate;
-               info->max_rate = info->req.format.rate;
-       } else {
-               info->min_rate = 4000;
-               info->max_rate = 192000;
-       }
-       info->rates = SND_PCM_RATE_CONTINUOUS | SND_PCM_RATE_8000_192000;
+       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;
 
-       if (info->req_mask & SND_PCM_PARAMS_CHANNELS) {
-               info->min_channels = info->req.format.channels;
-               info->max_channels = info->req.format.channels;
-       } else {
-               info->min_channels = 1;
-               info->max_channels = 32;
-       }
+       if (info->rate_min < 4000)
+               info->rate_min = 4000;
+       if (info->rate_max > 192000)
+               info->rate_max = 192000;
+       if (info->rate_max < info->rate_min)
+               return -EINVAL;
 
-       memset(&slave_info, 0, sizeof(slave_info));
-       if ((err = snd_pcm_params_info(slave, &slave_info)) < 0)
-               return err;
+       if (info->channels_min < 1)
+               info->channels_min = 1;
+       if (info->channels_max > 1024)
+               info->channels_max = 1024;
+       if (info->channels_max < info->channels_min)
+               return -EINVAL;
 
-       info->flags = slave_info.flags;
-       info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
+       if (info->fragment_size_max > 1024 * 1024)
+               info->fragment_size_max = 1024 * 1024;
+       if (info->fragment_size_max < info->fragment_size_min)
+               return -EINVAL;
 
-       info->min_fragments = slave_info.min_fragments;
-       info->max_fragments = slave_info.max_fragments;
-       
-       if (info->req_mask & SND_PCM_PARAMS_SFMT) 
-               info->formats = 1 << info->req.format.sfmt;
-       else {
-               info->formats = snd_pcm_plug_formats(slave_info.formats);
-               return 0;
+       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.subformat_mask = SND_PCM_SUBFMTBIT_STD;
+       sinfo.channels_min = 1;
+       sinfo.channels_max = 1024;
+       sinfo.rate_min = 4000;
+       sinfo.rate_max = 192000;
+       sinfo.fragments_min = 1;
+       sinfo.fragments_max = UINT_MAX;
+       sinfo.fragment_size_min = 1;
+       sinfo.fragment_size_max = ULONG_MAX;
+
+       /* Formats */
+       err = snd_pcm_hw_info(slave, &sinfo);
+       if (err < 0) {
+               *info = i;
+               return err;
        }
-
-       sformat = snd_pcm_plug_slave_fmt(info->req.format.sfmt, &slave_info);
-       if (sformat < 0) {
-               info->req.fail_mask = SND_PCM_PARAMS_SFMT;
-               info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
-               return -EINVAL;
+       format_mask = 0;
+       for (format = 0; format < SND_PCM_FORMAT_LAST; ++format) {
+               if (!(info->format_mask & (1 << format)))
+                       continue;
+               err = snd_pcm_plug_slave_fmt(format, sinfo.format_mask);
+               if (err < 0)
+                       info->format_mask &= ~(1 << format);
+               else
+                       format_mask |= (1 << err);
        }
-
-       if (!(info->req_mask & SND_PCM_PARAMS_RATE))
-               return 0;
-       crate = info->req.format.rate;
-       srate = snd_pcm_plug_slave_rate(crate, &slave_info);
-       if (srate < 0) {
-               info->req.fail_mask = SND_PCM_PARAMS_RATE;
-               info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
-               return -EINVAL;
+       sinfo.format_mask = format_mask;
+
+       /* Rate (and fragment_size) */
+       i = sinfo;
+       sparams.rate = info->rate_min;
+       err = snd_pcm_hw_info_rulesv(slave, &i, &sparams,
+                                   SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_RATE,
+                                   -1);
+       if (err < 0) {
+               *info = i;
+               return err;
        }
-
-       if (!(info->req_mask & SND_PCM_PARAMS_CHANNELS))
-               return 0;
-       schannels = info->req.format.channels;
-       if (schannels < info->min_channels)
-               schannels = info->min_channels;
-       else if (schannels > info->max_channels)
-               schannels = info->max_channels;
-
-       slave_info.req_mask = (SND_PCM_PARAMS_SFMT |
-                              SND_PCM_PARAMS_CHANNELS |
-                              SND_PCM_PARAMS_RATE);
-       slave_info.req.format.sfmt = sformat;
-       slave_info.req.format.channels = schannels;
-       slave_info.req.format.rate = srate;
-       if ((err = snd_pcm_params_info(slave, &slave_info)) < 0) {
-               info->req.fail_mask = slave_info.req.fail_mask;
-               info->req.fail_reason = slave_info.req.fail_reason;
+       rate_min = i.rate_min;
+       if (info->rate_max != info->rate_min) {
+               i = sinfo;
+               sparams.rate = info->rate_max;
+               err = snd_pcm_hw_info_rulesv(slave, &i, &sparams,
+                                            SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_RATE,
+                                            -1);
+               if (err < 0) {
+                       *info = i;
+                       return err;
+               }
+               rate_max = i.rate_min;
+       } else
+               rate_max = rate_min;
+       sinfo.rate_min = rate_min;
+       sinfo.rate_max = rate_max;
+
+       /* Channels */
+       i = sinfo;
+       sparams.channels = info->channels_min;
+       err = snd_pcm_hw_info_rulesv(slave, &i, &sparams,
+                                    SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_CHANNELS,
+                                    -1);
+       if (err < 0) {
+               *info = i;
+               return err;
+       }
+       channels_min = i.channels_min;
+       if (info->channels_max != info->channels_min) {
+               i = sinfo;
+               sparams.channels = info->channels_max;
+               err = snd_pcm_hw_info_rulesv(slave, &i, &sparams,
+                                            SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_CHANNELS,
+                                            -1);
+               if (err < 0) {
+                       *info = i;
+                       return err;
+               }
+               channels_max = i.channels_min;
+       } else
+               channels_max = channels_min;
+       sinfo.channels_min = channels_min;
+       sinfo.channels_max = channels_max;
+
+       sinfo.fragments_min = info->fragments_min;
+       sinfo.fragments_max = info->fragments_max;
+       sinfo.fragment_size_min = muldiv_down(info->fragment_size_min, sinfo.rate_min, info->rate_max);
+       sinfo.fragment_size_max = muldiv_up(info->fragment_size_max, sinfo.rate_max, info->rate_min);
+       err = snd_pcm_hw_info(slave, &sinfo);
+       if (err < 0) {
+               *info = sinfo;
                return err;
        }
-       info->buffer_size = muldiv64(slave_info.buffer_size, crate, srate);
-       info->min_fragment_size = muldiv64(slave_info.min_fragment_size, crate, srate);
-       info->max_fragment_size = muldiv64(slave_info.max_fragment_size, crate, srate);
-       info->fragment_align = muldiv64(slave_info.fragment_align, crate, srate);
-       if (sformat != info->req.format.sfmt ||
-           (unsigned int) srate != info->req.format.rate ||
-           schannels != info->req.format.channels)
-               info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+
+       info->subformat_mask = sinfo.subformat_mask;
+       info->fragments_min = sinfo.fragments_min;
+       info->fragments_max = sinfo.fragments_max;
+
+       fragment_size_min = muldiv_down(sinfo.fragment_size_min, info->rate_min, sinfo.rate_max);
+       fragment_size_max = muldiv_up(sinfo.fragment_size_max, info->rate_max, sinfo.rate_min);
+       if (fragment_size_min > info->fragment_size_min)
+               info->fragment_size_min = fragment_size_min;
+       if (fragment_size_max < info->fragment_size_max)
+               info->fragment_size_max = fragment_size_max;
+       info->info = sinfo.info & ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+       snd_pcm_hw_info_complete(info);
        return 0;
 }
 
@@ -313,29 +304,29 @@ 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_format_t *clt, snd_pcm_format_t *slv)
+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)
 {
        snd_pcm_plug_t *plug = pcm->private;
        int err;
-       assert(snd_pcm_format_linear(slv->sfmt));
+       assert(snd_pcm_format_linear(slv->format));
        if (clt->rate == slv->rate)
                return 0;
-       err = snd_pcm_rate_open(new, NULL, slv->sfmt, slv->rate, plug->slave, plug->slave != plug->req_slave);
+       err = snd_pcm_rate_open(new, NULL, slv->format, slv->rate, plug->slave, plug->slave != plug->req_slave);
        if (err < 0)
                return err;
        slv->rate = clt->rate;
-       if (snd_pcm_format_linear(clt->sfmt))
-               slv->sfmt = clt->sfmt;
+       if (snd_pcm_format_linear(clt->format))
+               slv->format = clt->format;
        return 1;
 }
 
-static int snd_pcm_plug_change_channels(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_format_t *clt, snd_pcm_format_t *slv)
+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)
 {
        snd_pcm_plug_t *plug = pcm->private;
        unsigned int tt_ssize, tt_cused, tt_sused;
        ttable_entry_t *ttable;
        int err;
-       assert(snd_pcm_format_linear(slv->sfmt));
+       assert(snd_pcm_format_linear(slv->format));
        if (clt->channels == slv->channels)
                return 0;
        if (clt->rate != slv->rate &&
@@ -384,100 +375,100 @@ static int snd_pcm_plug_change_channels(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm
                                s = 0;
                }
        }
-       err = snd_pcm_route_open(new, NULL, slv->sfmt, slv->channels, ttable, tt_ssize, tt_cused, tt_sused, plug->slave, plug->slave != plug->req_slave);
+       err = snd_pcm_route_open(new, NULL, slv->format, slv->channels, ttable, tt_ssize, tt_cused, tt_sused, plug->slave, plug->slave != plug->req_slave);
        if (err < 0)
                return err;
        slv->channels = clt->channels;
-       if (snd_pcm_format_linear(clt->sfmt))
-               slv->sfmt = clt->sfmt;
+       if (snd_pcm_format_linear(clt->format))
+               slv->format = clt->format;
        return 1;
 }
 
-static int snd_pcm_plug_change_format(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_format_t *clt, snd_pcm_format_t *slv)
+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)
 {
        snd_pcm_plug_t *plug = pcm->private;
        int err, cfmt;
        int (*f)(snd_pcm_t **pcm, char *name, int sformat, snd_pcm_t *slave, int close_slave);
-       if (snd_pcm_format_linear(slv->sfmt)) {
+       if (snd_pcm_format_linear(slv->format)) {
                /* Conversion is done in another plugin */
-               if (clt->sfmt == slv->sfmt ||
+               if (clt->format == slv->format ||
                    clt->rate != slv->rate ||
                    clt->channels != slv->channels)
                        return 0;
        } else {
                /* No conversion is needed */
-               if (clt->sfmt == slv->sfmt &&
+               if (clt->format == slv->format &&
                    clt->rate == slv->rate &&
                    clt->channels == clt->channels)
                        return 0;
        }
-       if (snd_pcm_format_linear(slv->sfmt)) {
-               cfmt = clt->sfmt;
-               switch (clt->sfmt) {
-               case SND_PCM_SFMT_MU_LAW:
+       if (snd_pcm_format_linear(slv->format)) {
+               cfmt = clt->format;
+               switch (clt->format) {
+               case SND_PCM_FORMAT_MU_LAW:
                        f = snd_pcm_mulaw_open;
                        break;
-               case SND_PCM_SFMT_A_LAW:
+               case SND_PCM_FORMAT_A_LAW:
                        f = snd_pcm_alaw_open;
                        break;
-               case SND_PCM_SFMT_IMA_ADPCM:
+               case SND_PCM_FORMAT_IMA_ADPCM:
                        f = snd_pcm_adpcm_open;
                        break;
                default:
-                       assert(snd_pcm_format_linear(clt->sfmt));
+                       assert(snd_pcm_format_linear(clt->format));
                        f = snd_pcm_linear_open;
                        break;
                }
        } else {
-               switch (slv->sfmt) {
-               case SND_PCM_SFMT_MU_LAW:
+               switch (slv->format) {
+               case SND_PCM_FORMAT_MU_LAW:
                        f = snd_pcm_mulaw_open;
                        break;
-               case SND_PCM_SFMT_A_LAW:
+               case SND_PCM_FORMAT_A_LAW:
                        f = snd_pcm_alaw_open;
                        break;
-               case SND_PCM_SFMT_IMA_ADPCM:
+               case SND_PCM_FORMAT_IMA_ADPCM:
                        f = snd_pcm_adpcm_open;
                        break;
                default:
                        assert(0);
                        return -EINVAL;
                }
-               if (snd_pcm_format_linear(clt->sfmt))
-                       cfmt = clt->sfmt;
+               if (snd_pcm_format_linear(clt->format))
+                       cfmt = clt->format;
                else
-                       cfmt = SND_PCM_SFMT_S16;
+                       cfmt = SND_PCM_FORMAT_S16;
        }
-       err = f(new, NULL, slv->sfmt, plug->slave, plug->slave != plug->req_slave);
+       err = f(new, NULL, slv->format, plug->slave, plug->slave != plug->req_slave);
        if (err < 0)
                return err;
-       slv->sfmt = cfmt;
+       slv->format = cfmt;
        return 1;
 }
 
 static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm,
-                                      snd_pcm_format_t *client_fmt,
-                                      snd_pcm_format_t *slave_fmt)
+                                      snd_pcm_hw_params_t *client,
+                                      snd_pcm_hw_params_t *slave)
 {
        snd_pcm_plug_t *plug = pcm->private;
-       int (*funcs[])(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_format_t *s, snd_pcm_format_t *d) = {
+       int (*funcs[])(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_hw_params_t *s, snd_pcm_hw_params_t *d) = {
                snd_pcm_plug_change_format,
                snd_pcm_plug_change_channels,
                snd_pcm_plug_change_rate,
                snd_pcm_plug_change_channels,
                snd_pcm_plug_change_format
        };
-       snd_pcm_format_t sfmt = *slave_fmt;
+       snd_pcm_hw_params_t p = *slave;
        unsigned int k = 0;
        while (1) {
                snd_pcm_t *new;
                int err;
-               if (client_fmt->sfmt == sfmt.sfmt &&
-                   client_fmt->channels == sfmt.channels &&
-                   client_fmt->rate == sfmt.rate)
+               if (client->format == p.format &&
+                   client->channels == p.channels &&
+                   client->rate == p.rate)
                        return 0;
                assert(k < sizeof(funcs)/sizeof(*funcs));
-               err = funcs[k](pcm, &new, client_fmt, &sfmt);
+               err = funcs[k](pcm, &new, client, &p);
                if (err < 0) {
                        snd_pcm_plug_clear(pcm);
                        return err;
@@ -493,134 +484,118 @@ static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm,
        return 0;
 }
 
-static int snd_pcm_plug_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
+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_format_t *slave_format, *format;
-       snd_pcm_params_info_t slave_info;
-       int srate;
+       snd_pcm_hw_info_t sinfo;
+       snd_pcm_hw_params_t sparams;
        int err;
-       
-       memset(&slave_info, 0, sizeof(slave_info));
-       err = snd_pcm_params_info(slave, &slave_info);
-       assert(err >= 0);
-       if (err < 0)
+       sparams = *params;
+       snd_pcm_hw_params_to_info(&sparams, &sinfo);
+       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.subformat_mask = SND_PCM_SUBFMTBIT_STD;
+       sinfo.channels_min = 1;
+       sinfo.channels_max = 1024;
+       sinfo.rate_min = 4000;
+       sinfo.rate_max = 192000;
+       sinfo.fragment_size_min = 1;
+       sinfo.fragment_size_max = ULONG_MAX;
+       err = snd_pcm_hw_info_rulesv(slave, &sinfo, params,
+                                   SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_RATE,
+                                   SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_CHANNELS,
+                                    -1);
+       if (err < 0) {
+               snd_pcm_hw_info_to_params_fail(&sinfo, params);
                return err;
-
-       slave_info.req = *params;
-       format = &params->format;
-       slave_format = &slave_info.req.format;
-
-       srate = snd_pcm_plug_slave_rate(format->rate, &slave_info);
-       if (srate < 0) {
-               params->fail_mask = SND_PCM_PARAMS_RATE;
-               params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
-               return srate;
        }
-       slave_format->rate = srate;
-       slave_info.req_mask |= SND_PCM_PARAMS_RATE;
-       err = snd_pcm_params_info(slave, &slave_info);
-       assert(err >= 0);
+       err = snd_pcm_plug_slave_fmt(sparams.format, sinfo.format_mask);
        if (err < 0)
                return err;
-
-       if (slave_format->rate - slave_info.min_rate < slave_info.max_rate - slave_format->rate)
-               slave_format->rate = slave_info.min_rate;
-       else
-               slave_format->rate = slave_info.max_rate;
-
-       if (format->channels < slave_info.min_channels)
-               slave_format->channels = slave_info.min_channels;
-       else if (format->channels > slave_info.max_channels)
-               slave_format->channels = slave_info.max_channels;
-       slave_info.req_mask |= SND_PCM_PARAMS_CHANNELS;
-       err = snd_pcm_params_info(slave, &slave_info);
-       assert(err >= 0);
-       if (err < 0)
+       sparams.format = err;
+       sinfo.format_mask = 1U << err;
+       sparams.fragment_size = muldiv_near(params->fragment_size, sparams.rate, params->rate);
+       err = snd_pcm_hw_info_rulesv(slave, &sinfo, &sparams,
+                                    SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_FRAGMENT_SIZE,
+                                    -1);
+       if (err < 0) {
+               snd_pcm_hw_info_to_params_fail(&sinfo, params);
                return err;
-
-       if ((slave_info.formats & (1 << format->sfmt)) == 0) {
-               int slave_fmt = snd_pcm_plug_slave_fmt(format->sfmt, &slave_info);
-               if (slave_fmt < 0) {
-                       params->fail_mask = SND_PCM_PARAMS_SFMT;
-                       params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
-                       return slave_fmt;
-               }
-               slave_format->sfmt = slave_fmt;
-       }
-       slave_info.req_mask |= SND_PCM_PARAMS_SFMT;
-
-       if (slave_info.formats != 1U << slave_format->sfmt) {
-               err = snd_pcm_params_info(slave, &slave_info);
-               assert(err >= 0);
-               if (err < 0)
-                       return err;
        }
+       if (sinfo.access_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
+               sparams.access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
+       else if (sinfo.access_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
+               sparams.access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
+       else
+               assert(0);
 
-       err = snd_pcm_plug_insert_plugins(pcm, format, slave_format);
+       err = snd_pcm_plug_insert_plugins(pcm, params, &sparams);
        if (err < 0)
                return err;
 
-       err = snd_pcm_params(plug->slave, params);
+       err = snd_pcm_hw_params(plug->slave, params);
        if (err < 0) {
                snd_pcm_plug_clear(pcm);
                return err;
        }
-       assert(slave->setup.format.sfmt == slave_format->sfmt);
-       assert(slave->setup.format.channels == slave_format->channels);
-       assert(slave->setup.format.rate == slave_format->rate);
        pcm->hw_ptr = slave->hw_ptr;
        pcm->appl_ptr = slave->appl_ptr;
        return 0;
 }
 
-static int snd_pcm_plug_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup)
+static int snd_pcm_plug_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
 {
        snd_pcm_plug_t *plug = pcm->private;
-       return snd_pcm_setup(plug->slave, setup);
+       snd_pcm_t *slave = plug->req_slave;
+       size_t avail_min, xfer_min, xfer_align;
+       int err;
+       avail_min = params->avail_min;
+       xfer_min = params->xfer_min;
+       xfer_align = params->xfer_align;
+       params->avail_min = muldiv_near(params->avail_min, slave->rate, pcm->rate);
+       params->xfer_min = muldiv_near(params->xfer_min, slave->rate, pcm->rate);
+       params->xfer_align = muldiv_near(params->xfer_align, slave->rate, pcm->rate);
+       err = snd_pcm_sw_params(slave, params);
+       params->avail_min = avail_min;
+       params->xfer_min = xfer_min;
+       params->xfer_align = xfer_align;
+       params->boundary = LONG_MAX - pcm->buffer_size * 2 - LONG_MAX % pcm->buffer_size;
+       return err;
 }
 
-static int snd_pcm_plug_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
+static int snd_pcm_plug_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t * info)
 {
        snd_pcm_plug_t *plug = pcm->private;
-       return snd_pcm_channel_info(plug->slave, info);
+       return snd_pcm_dig_info(plug->slave, info);
 }
 
-static int snd_pcm_plug_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
+static int snd_pcm_plug_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t * params)
 {
        snd_pcm_plug_t *plug = pcm->private;
-       return snd_pcm_channel_params(plug->slave, params);
+       return snd_pcm_dig_params(plug->slave, params);
 }
 
-static int snd_pcm_plug_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
+
+static int snd_pcm_plug_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
 {
        snd_pcm_plug_t *plug = pcm->private;
-       return snd_pcm_channel_setup(plug->slave, setup);
+       return snd_pcm_channel_info(plug->slave, info);
 }
 
 static int snd_pcm_plug_mmap(snd_pcm_t *pcm)
 {
-       snd_pcm_plug_t *plug = pcm->private;
-       int err = snd_pcm_mmap(plug->slave);
-       if (err < 0)
-               return err;
-       pcm->mmap_info_count = plug->slave->mmap_info_count;
-       pcm->mmap_info = plug->slave->mmap_info;
-       return 0;
+       snd_pcm_plugin_t *plug = pcm->private;
+       return snd_pcm_mmap(plug->slave);
 }
 
 static int snd_pcm_plug_munmap(snd_pcm_t *pcm)
 {
-       snd_pcm_plug_t *plug = pcm->private;
-       int err = snd_pcm_munmap(plug->slave);
-       if (err < 0)
-               return err;
-       pcm->mmap_info_count = 0;
-       pcm->mmap_info = 0;
-       return 0;
+       snd_pcm_plugin_t *plug = pcm->private;
+       return snd_pcm_munmap(plug->slave);
 }
-               
+
 static void snd_pcm_plug_dump(snd_pcm_t *pcm, FILE *fp)
 {
        snd_pcm_plug_t *plug = pcm->private;
@@ -631,12 +606,12 @@ 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,
-       params_info: snd_pcm_plug_params_info,
-       params: snd_pcm_plug_params,
-       setup: snd_pcm_plug_setup,
+       hw_info: snd_pcm_plug_hw_info,
+       hw_params: snd_pcm_plug_hw_params,
+       sw_params: snd_pcm_plug_sw_params,
+       dig_info: snd_pcm_plug_dig_info,
+       dig_params: snd_pcm_plug_dig_params,
        channel_info: snd_pcm_plug_channel_info,
-       channel_params: snd_pcm_plug_channel_params,
-       channel_setup: snd_pcm_plug_channel_setup,
        dump: snd_pcm_plug_dump,
        nonblock: snd_pcm_plug_nonblock,
        async: snd_pcm_plug_async,
@@ -687,19 +662,14 @@ int snd_pcm_plug_open(snd_pcm_t **pcmp,
        return 0;
 }
 
-int snd_pcm_plug_open_subdevice(snd_pcm_t **pcmp, int card, int device, int subdevice, int stream, int mode)
+int snd_pcm_plug_open_hw(snd_pcm_t **pcmp, char *name, int card, int device, int subdevice, int stream, int mode)
 {
        snd_pcm_t *slave;
        int err;
-       err = snd_pcm_hw_open_subdevice(&slave, card, device, subdevice, stream, mode);
+       err = snd_pcm_hw_open(&slave, NULL, card, device, subdevice, stream, mode);
        if (err < 0)
                return err;
-       return snd_pcm_plug_open(pcmp, NULL, 0, 0, 0, 0, slave, 1);
-}
-
-int snd_pcm_plug_open_device(snd_pcm_t **pcmp, int card, int device, int stream, int mode)
-{
-       return snd_pcm_plug_open_subdevice(pcmp, card, device, -1, stream, mode);
+       return snd_pcm_plug_open(pcmp, name, 0, 0, 0, 0, slave, 1);
 }
 
 #define MAX_CHANNELS 32
index 9929558f52e9abd0f04b6a03f6d7f50fdc62e62b..9dd4e6129f84974ba56639b335236f99d314c197 100644 (file)
@@ -52,38 +52,28 @@ int snd_pcm_plugin_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
        return snd_pcm_info(plugin->slave, info);
 }
 
-int snd_pcm_plugin_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
+int snd_pcm_plugin_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
 {
        snd_pcm_plugin_t *plugin = pcm->private;
-       return snd_pcm_channel_info(plugin->slave, info);
+       return snd_pcm_sw_params(plugin->slave, params);
 }
 
-int snd_pcm_plugin_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t * params)
+int snd_pcm_plugin_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t *info)
 {
        snd_pcm_plugin_t *plugin = pcm->private;
-       return snd_pcm_channel_params(plugin->slave, params);
+       return snd_pcm_dig_info(plugin->slave, info);
 }
 
-int snd_pcm_plugin_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
+int snd_pcm_plugin_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t *params)
 {
        snd_pcm_plugin_t *plugin = pcm->private;
-       int err;
-       err = snd_pcm_channel_setup(plugin->slave, setup);
-       if (err < 0)
-               return err;
-       if (!pcm->mmap_info)
-               return 0;
-       if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) {
-               setup->running_area.addr = pcm->mmap_info->addr;
-               setup->running_area.first = setup->channel * pcm->bits_per_sample;
-               setup->running_area.step = pcm->bits_per_frame;
-       } else {
-               setup->running_area.addr = pcm->mmap_info->addr + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
-               setup->running_area.first = 0;
-               setup->running_area.step = pcm->bits_per_sample;
-       }
-       setup->stopped_area = setup->running_area;
-       return 0;
+       return snd_pcm_dig_params(plugin->slave, params);
+}
+
+int snd_pcm_plugin_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
+{
+       snd_pcm_plugin_t *plugin = pcm->private;
+       return snd_pcm_channel_info_shm(pcm, info, plugin->shmid);
 }
 
 int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
@@ -185,7 +175,7 @@ ssize_t snd_pcm_plugin_rewind(snd_pcm_t *pcm, size_t frames)
 ssize_t snd_pcm_plugin_writei(snd_pcm_t *pcm, const void *buffer, size_t size)
 {
        snd_pcm_plugin_t *plugin = pcm->private;
-       snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+       snd_pcm_channel_area_t areas[pcm->channels];
        ssize_t frames;
        snd_pcm_areas_from_buf(pcm, areas, (void*)buffer);
        frames = snd_pcm_write_areas(pcm, areas, 0, size, plugin->write);
@@ -197,7 +187,7 @@ ssize_t snd_pcm_plugin_writei(snd_pcm_t *pcm, const void *buffer, size_t size)
 ssize_t snd_pcm_plugin_writen(snd_pcm_t *pcm, void **bufs, size_t size)
 {
        snd_pcm_plugin_t *plugin = pcm->private;
-       snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+       snd_pcm_channel_area_t areas[pcm->channels];
        ssize_t frames;
        snd_pcm_areas_from_bufs(pcm, areas, bufs);
        frames = snd_pcm_write_areas(pcm, areas, 0, size, plugin->write);
@@ -209,7 +199,7 @@ ssize_t snd_pcm_plugin_writen(snd_pcm_t *pcm, void **bufs, size_t size)
 ssize_t snd_pcm_plugin_readi(snd_pcm_t *pcm, void *buffer, size_t size)
 {
        snd_pcm_plugin_t *plugin = pcm->private;
-       snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+       snd_pcm_channel_area_t areas[pcm->channels];
        ssize_t frames;
        snd_pcm_areas_from_buf(pcm, areas, buffer);
        frames = snd_pcm_read_areas(pcm, areas, 0, size, plugin->read);
@@ -221,7 +211,7 @@ ssize_t snd_pcm_plugin_readi(snd_pcm_t *pcm, void *buffer, size_t size)
 ssize_t snd_pcm_plugin_readn(snd_pcm_t *pcm, void **bufs, size_t size)
 {
        snd_pcm_plugin_t *plugin = pcm->private;
-       snd_pcm_channel_area_t areas[pcm->setup.format.channels];
+       snd_pcm_channel_area_t areas[pcm->channels];
        ssize_t frames;
        snd_pcm_areas_from_bufs(pcm, areas, bufs);
        frames = snd_pcm_read_areas(pcm, areas, 0, size, plugin->read);
@@ -251,7 +241,7 @@ ssize_t snd_pcm_plugin_mmap_forward(snd_pcm_t *pcm, size_t client_size)
                size_t slave_frames = slave_size - slave_xfer;
                size_t client_frames = client_size - client_xfer;
                size_t offset = snd_pcm_mmap_hw_offset(pcm);
-               size_t cont = pcm->setup.buffer_size - offset;
+               size_t cont = pcm->buffer_size - offset;
                if (cont < client_frames)
                        client_frames = cont;
                err = plugin->write(pcm, pcm->running_areas, offset,
@@ -279,17 +269,18 @@ ssize_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
        if (slave_size <= 0)
                return slave_size;
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK ||
-           !pcm->mmap_info)
+           pcm->access == SND_PCM_ACCESS_RW_INTERLEAVED ||
+           pcm->access == SND_PCM_ACCESS_RW_NONINTERLEAVED)
                return plugin->client_frames ?
                        plugin->client_frames(pcm, slave_size) : slave_size;
        client_xfer = snd_pcm_mmap_capture_avail(pcm);
-       client_size = pcm->setup.buffer_size;
+       client_size = pcm->buffer_size;
        while (slave_xfer < (size_t)slave_size &&
               client_xfer < client_size) {
                size_t slave_frames = slave_size - slave_xfer;
                size_t client_frames = client_size - client_xfer;
                size_t offset = snd_pcm_mmap_hw_offset(pcm);
-               size_t cont = pcm->setup.buffer_size - offset;
+               size_t cont = pcm->buffer_size - offset;
                if (cont < client_frames)
                        client_frames = cont;
                err = plugin->read(pcm, pcm->running_areas, offset,
@@ -313,38 +304,26 @@ int snd_pcm_plugin_set_avail_min(snd_pcm_t *pcm, size_t frames)
 
 int snd_pcm_plugin_mmap(snd_pcm_t *pcm)
 {
-       snd_pcm_plugin_t *plugin = pcm->private;
-       snd_pcm_t *slave = plugin->slave;
-       snd_pcm_mmap_info_t *i;
-       int err = snd_pcm_mmap(slave);
-       if (err < 0)
-               return err;
-       i = calloc(1, sizeof(*i));
-       if (!i)
-               return -ENOMEM;
-       err = snd_pcm_alloc_user_mmap(pcm, i);
-       if (err < 0) {
-               free(i);
-               return err;
+       snd_pcm_plugin_t *plug = pcm->private;
+       if (!(pcm->info & SND_PCM_INFO_MMAP)) {
+               size_t size = snd_pcm_frames_to_bytes(pcm, pcm->buffer_size);
+               int id = shmget(IPC_PRIVATE, size, 0666);
+               if (id < 0) {
+                       SYSERR("shmget failed");
+                       return -errno;
+               }
+               plug->shmid = id;
        }
-       pcm->mmap_info = i;
-       pcm->mmap_info_count = 1;
        return 0;
 }
 
 int snd_pcm_plugin_munmap(snd_pcm_t *pcm)
 {
-       snd_pcm_plugin_t *plugin = pcm->private;
-       snd_pcm_t *slave = plugin->slave;
-       int err = snd_pcm_munmap(slave);
-       if (err < 0)
-               return err;
-       err = snd_pcm_free_mmap(pcm, pcm->mmap_info);
-       if (err < 0)
-               return err;
-       free(pcm->mmap_info);
-       pcm->mmap_info_count = 0;
-       pcm->mmap_info = 0;
+       snd_pcm_plugin_t *plug = pcm->private;
+       if (shmctl(plug->shmid, IPC_RMID, 0) < 0) {
+               SYSERR("shmctl IPC_RMID failed");
+                       return -errno;
+       }
        return 0;
 }
 
index b0275fd80a33b9a48ca80e90e8b5fc7b1c3358ea..4047ffb7c12a64df36a7f09095811998a97d3c91 100644 (file)
@@ -24,18 +24,21 @@ typedef struct {
        int close_slave;
        snd_pcm_xfer_areas_func_t read;
        snd_pcm_xfer_areas_func_t write;
-       size_t (*client_frames)(snd_pcm_t *pcm, size_t frames);
+       ssize_t (*client_frames)(snd_pcm_t *pcm, ssize_t frames);
        int (*init)(snd_pcm_t *pcm);
+       int shmid;
        size_t appl_ptr, hw_ptr;
+       unsigned int saccess_mask;
 } snd_pcm_plugin_t;    
 
 int snd_pcm_plugin_close(snd_pcm_t *pcm);
 int snd_pcm_plugin_nonblock(snd_pcm_t *pcm, int nonblock);
 int snd_pcm_plugin_async(snd_pcm_t *pcm, int sig, pid_t pid);
 int snd_pcm_plugin_info(snd_pcm_t *pcm, snd_pcm_info_t * info);
+int snd_pcm_plugin_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params);
+int snd_pcm_plugin_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t *info);
+int snd_pcm_plugin_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t *params);
 int snd_pcm_plugin_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info);
-int snd_pcm_plugin_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t * params);
-int snd_pcm_plugin_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup);
 int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status);
 int snd_pcm_plugin_state(snd_pcm_t *pcm);
 int snd_pcm_plugin_delay(snd_pcm_t *pcm, ssize_t *delayp);
@@ -58,22 +61,34 @@ int snd_pcm_plugin_munmap_status(snd_pcm_t *pcm);
 int snd_pcm_plugin_munmap_control(snd_pcm_t *pcm);
 int snd_pcm_plugin_munmap(snd_pcm_t *pcm);
 int snd_pcm_plugin_poll_descriptor(snd_pcm_t *pcm);
-int snd_pcm_plugin_channels_mask(snd_pcm_t *pcm, bitset_t *cmask);
 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_LINEAR_FORMATS (SND_PCM_FMT_S8 | SND_PCM_FMT_U8 | \
-                               SND_PCM_FMT_S16_LE | SND_PCM_FMT_S16_BE | \
-                               SND_PCM_FMT_U16_LE | SND_PCM_FMT_U16_BE | \
-                               SND_PCM_FMT_S24_LE | SND_PCM_FMT_S24_BE | \
-                               SND_PCM_FMT_U24_LE | SND_PCM_FMT_U24_BE | \
-                               SND_PCM_FMT_S32_LE | SND_PCM_FMT_S32_BE | \
-                               SND_PCM_FMT_U32_LE | SND_PCM_FMT_U32_BE)
+#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)
 
 extern snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops;
 
-#define muldiv64(a,b,d) (((int64_t)(a) * (b) + (b) / 2) / (d))
+static inline ssize_t muldiv_down(ssize_t a, ssize_t b, ssize_t d)
+{
+       return (int64_t) (a * b) / d;
+}
+
+static inline ssize_t muldiv_up(ssize_t a, ssize_t b, ssize_t d)
+{
+       return (int64_t) (a * b + (d - 1)) / d;
+}
+
+static inline ssize_t muldiv_near(ssize_t a, ssize_t b, ssize_t d)
+{
+       return (int64_t) (a * b + (d / 2)) / d;
+}
 
 #define ROUTE_PLUGIN_FLOAT 1
 #define ROUTE_PLUGIN_RESOLUTION 16
index 8893f2686658ac376dd472b64a16ba317af77594..8684ccec9f830e47962de23962b1d0054af90f1e 100644 (file)
@@ -48,13 +48,8 @@ typedef struct {
        int put_idx;
        unsigned int pitch;
        rate_f func;
-       int req_sformat;
-       int req_srate;
        int sformat;
-       int cformat;
        int srate;
-       int crate;
-       int cxfer_mode, cmmap_shape;
        rate_state_t *states;
 } snd_pcm_rate_t;
 
@@ -93,7 +88,7 @@ static size_t resample_expand(snd_pcm_channel_area_t *src_areas,
 #if 0
                if (!src_area->enabled) {
                        if (dst_area->wanted)
-                               snd_pcm_area_silence(&dst_area->area, 0, dst_frames, plugin->dst_format.sfmt);
+                               snd_pcm_area_silence(&dst_area->area, 0, dst_frames, plugin->dst_format);
                        dst_area->enabled = 0;
                        continue;
                }
@@ -177,7 +172,7 @@ static size_t resample_shrink(snd_pcm_channel_area_t *src_areas,
 #if 0
                if (!src_area->enabled) {
                        if (dst_area->wanted)
-                               snd_pcm_area_silence(&dst_area->area, 0, dst_frames, plugin->dst_format.sfmt);
+                               snd_pcm_area_silence(&dst_area->area, 0, dst_frames, plugin->dst_format);
                        dst_area->enabled = 0;
                        continue;
                }
@@ -238,142 +233,132 @@ static int snd_pcm_rate_close(snd_pcm_t *pcm)
        return 0;
 }
 
-static int snd_pcm_rate_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+static int snd_pcm_rate_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
 {
        snd_pcm_rate_t *rate = pcm->private;
-       unsigned int req_mask = info->req_mask;
-       unsigned int sfmt = info->req.format.sfmt;
-       unsigned int crate = info->req.format.rate;
-       unsigned int srate;
+       snd_pcm_hw_info_t sinfo;
+       unsigned int access_mask;
+       size_t fragment_size_min, fragment_size_max;
        int err;
-       if (req_mask & SND_PCM_PARAMS_SFMT &&
-           !snd_pcm_format_linear(sfmt)) {
-               info->req.fail_mask = SND_PCM_PARAMS_SFMT;
-               info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+       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;
+       if (info->format_mask == 0)
+               return -EINVAL;
+       if (info->rate_min < 4000)
+               info->rate_min = 4000;
+       if (info->rate_max > 192000)
+               info->rate_max = 192000;
+       if (info->rate_max < info->rate_min)
+               return -EINVAL;
+       if (info->fragment_size_max > 1024 * 1024)
+               info->fragment_size_max = 1024 * 1024;
+       if (info->fragment_size_max < info->fragment_size_min)
+               return -EINVAL;
+       sinfo = *info;
+
+       sinfo.rate_min = rate->srate;
+       sinfo.rate_max = rate->srate;
+       if (rate->sformat >= 0)
+               sinfo.format_mask = 1U << rate->sformat;
+       sinfo.fragment_size_min = muldiv_down(info->fragment_size_min, sinfo.rate_min, info->rate_max);
+       sinfo.fragment_size_max = muldiv_up(info->fragment_size_max, sinfo.rate_max, info->rate_min);
+               
+       sinfo.access_mask = SND_PCM_ACCBIT_MMAP;
+       err = snd_pcm_hw_info(rate->plug.slave, &sinfo);
+       info->subformat_mask = sinfo.subformat_mask;
+       info->channels_min = sinfo.channels_min;
+       info->channels_max = sinfo.channels_max;
+       info->fragments_min = sinfo.fragments_min;
+       info->fragments_max = sinfo.fragments_max;
+
+       if (!sinfo.access_mask) {
+               info->access_mask = 0;
        }
-       if (rate->req_sformat >= 0) {
-               info->req_mask |= SND_PCM_PARAMS_SFMT;
-               info->req.format.sfmt = rate->req_sformat;
+       if (!sinfo.format_mask) {
+               info->format_mask = 0;
+       }
+       if (sinfo.rate_min > sinfo.rate_max) {
+               info->rate_min = UINT_MAX;
+               info->rate_max = 0;
+       }
+       if (sinfo.fragment_size_min > sinfo.fragment_size_max) {
+               info->fragment_size_min = ULONG_MAX;
+               info->fragment_size_max = 0;
        }
-       info->req_mask |= SND_PCM_PARAMS_RATE;
-       info->req_mask &= ~(SND_PCM_PARAMS_MMAP_SHAPE | 
-                           SND_PCM_PARAMS_XFER_MODE);
-       info->req.format.rate = rate->req_srate;
-       err = snd_pcm_params_info(rate->plug.slave, info);
-       info->req_mask = req_mask;
-       info->req.format.sfmt = sfmt;
-       info->req.format.rate = crate;
        if (err < 0)
                return err;
-       if (req_mask & SND_PCM_PARAMS_SFMT)
-               info->formats = 1 << sfmt;
-       else
-               info->formats = SND_PCM_LINEAR_FORMATS;
-       if (!(req_mask & SND_PCM_PARAMS_RATE)) {
-               info->min_rate = 4000;
-               info->max_rate = 192000;
-               return 0;
-       }
-       if (rate->req_srate - info->min_rate < info->max_rate - rate->req_srate)
-               srate = info->min_rate;
-       else
-               srate = info->max_rate;
-       info->min_rate = crate;
-       info->max_rate = crate;
-       if (info->buffer_size)
-               info->buffer_size = muldiv64(info->buffer_size, crate, srate);
-       if (info->min_fragment_size)
-               info->min_fragment_size = muldiv64(info->min_fragment_size, crate, srate);
-       if (info->max_fragment_size)
-               info->max_fragment_size = muldiv64(info->max_fragment_size, crate, srate);
-       if (info->fragment_align)
-               info->fragment_align = muldiv64(info->fragment_align, crate, srate);
-       info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
-       info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
+       
+       fragment_size_min = muldiv_down(sinfo.fragment_size_min, info->rate_min, sinfo.rate_max);
+       fragment_size_max = muldiv_up(sinfo.fragment_size_max, info->rate_max, sinfo.rate_min);
+       if (fragment_size_min > info->fragment_size_min)
+               info->fragment_size_min = fragment_size_min;
+       if (fragment_size_max < info->fragment_size_max)
+               info->fragment_size_max = fragment_size_max;
+       rate->plug.saccess_mask = sinfo.access_mask;
+       info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+       snd_pcm_hw_info_complete(info);
        return 0;
 }
 
-static int snd_pcm_rate_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+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_params_t slave_params;
-       snd_pcm_params_info_t slave_info;
-       int srate, crate;
+       snd_pcm_hw_info_t sinfo;
+       unsigned int format, access, crate;
+       unsigned int src_format, dst_format;
+       unsigned int src_rate, dst_rate;
+       size_t fragment_size;
+       int mul, div;
        int err;
-       if (!snd_pcm_format_linear(params->format.sfmt)) {
-               params->fail_mask = SND_PCM_PARAMS_SFMT;
-               params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
-               return -EINVAL;
-       }
-       slave_params = *params;
-       rate->cformat = params->format.sfmt;
-       rate->crate = crate = params->format.rate;
-       rate->cxfer_mode = params->xfer_mode;
-       rate->cmmap_shape = params->mmap_shape;
-
-       memset(&slave_info, 0, sizeof(slave_info));
-       slave_info.req = *params;
-       if (rate->req_sformat >= 0) {
-               slave_info.req.format.sfmt = rate->req_sformat;
-               slave_params.format.sfmt = rate->req_sformat;
-       }
-       slave_info.req.format.rate = rate->req_srate;
-       slave_info.req_mask = ~0;
-       err = snd_pcm_params_info(slave, &slave_info);
-       if (err < 0) {
-               params->fail_mask = slave_info.req.fail_mask;
-               params->fail_reason = slave_info.req.fail_reason;
-               return err;
-       }
-
-       if (rate->req_srate - slave_info.min_rate < slave_info.max_rate - rate->req_srate)
-               srate = slave_info.min_rate;
+       crate = params->rate;
+       format = params->format;
+       fragment_size = params->fragment_size;
+       access = params->access;
+       params->rate = rate->srate;
+       if (rate->sformat >= 0)
+               params->format = rate->sformat;
+       if (rate->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
+               params->access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
+       else if (rate->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
+               params->access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
        else
-               srate = slave_info.max_rate;
-
-       slave_params.format.rate = srate;
-       slave_params.avail_min = muldiv64(params->avail_min, srate, crate);
-       slave_params.xfer_min = muldiv64(params->xfer_min, srate, crate);
-       slave_params.buffer_size = muldiv64(params->buffer_size, srate, crate);
-       slave_params.frag_size = muldiv64(params->frag_size, srate, crate);
-       slave_params.xfer_align = muldiv64(params->xfer_align, srate, crate);
-       /* FIXME: boundary? */
-       slave_params.xfer_mode = SND_PCM_XFER_UNSPECIFIED;
-       slave_params.mmap_shape = SND_PCM_MMAP_UNSPECIFIED;
-       err = snd_pcm_params_mmap(slave, &slave_params);
-       params->fail_mask = slave_params.fail_mask;
-       params->fail_reason = slave_params.fail_reason;
-       return err;
-}
-
-static int snd_pcm_rate_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
-{
-       snd_pcm_rate_t *rate = pcm->private;
-       int src_format, dst_format;
-       int src_rate, dst_rate;
-       int mul, div;
-       int err = snd_pcm_setup(rate->plug.slave, setup);
+               assert(0);
+       params->fragment_size = muldiv_near(params->fragment_size, params->rate, crate);
+       snd_pcm_hw_params_to_info(params, &sinfo);
+       sinfo.fragment_size_min = 0;
+       sinfo.fragment_size_max = ULONG_MAX;
+       err = snd_pcm_hw_info_rulesv(slave, &sinfo, params,
+                                    SND_PCM_RULE_REL_NEAR | SND_PCM_HW_PARAM_FRAGMENT_SIZE,
+                                    -1);
+       snd_pcm_hw_info_to_params(&sinfo, params);
+       if (err >= 0)
+               err = snd_pcm_hw_params(slave, params);
+       params->format = format;
+       params->rate = crate;
+       params->access = access;
+       params->fragment_size = fragment_size;
        if (err < 0)
                return err;
-       if (rate->req_sformat >= 0)
-               assert(rate->req_sformat == setup->format.sfmt);
-       rate->sformat = setup->format.sfmt;
-       rate->srate = setup->format.rate;
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
-               src_format = rate->cformat;
-               dst_format = rate->sformat;
-               src_rate = rate->crate;
-               dst_rate = rate->srate;
+               src_format = format;
+               dst_format = slave->format;
+               src_rate = crate;
+               dst_rate = slave->rate;
        } else {
-               src_format = rate->sformat;
-               dst_format = rate->cformat;
-               src_rate = rate->srate;
-               dst_rate = rate->crate;
+               src_format = slave->format;
+               dst_format = format;
+               src_rate = slave->rate;
+               dst_rate = crate;
        }
-       rate->get_idx = get_index(src_format, SND_PCM_SFMT_S16);
-       rate->put_idx = put_index(SND_PCM_SFMT_S16, dst_format);
+       rate->get_idx = get_index(src_format, SND_PCM_FORMAT_S16);
+       rate->put_idx = put_index(SND_PCM_FORMAT_S16, dst_format);
        if (src_rate < dst_rate) {
                rate->func = resample_expand;
                /* pitch is get_threshold */
@@ -389,43 +374,37 @@ static int snd_pcm_rate_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
                mul = rate->pitch;
                div = DIV;
        }
-       rate->crate = muldiv64(rate->srate, mul, div);
-       if (rate->cxfer_mode == SND_PCM_XFER_UNSPECIFIED)
-               setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
-       else
-               setup->xfer_mode = rate->cxfer_mode;
-       if (rate->cmmap_shape == SND_PCM_MMAP_UNSPECIFIED)
-               setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
-       else
-               setup->mmap_shape = rate->cmmap_shape;
-       setup->format.sfmt = rate->cformat;
-       setup->format.rate = rate->crate;
-       /* FIXME */
-       setup->rate_master = rate->crate;
-       setup->rate_divisor = 1;
-       setup->mmap_bytes = 0;
-       setup->avail_min = muldiv64(setup->avail_min, mul, div);
-       setup->xfer_min = muldiv64(setup->xfer_min, mul, div);
-
-       /* FIXME: the three above are not a lot sensible */
-       setup->buffer_size = muldiv64(setup->buffer_size, mul, div);
-       setup->frag_size = muldiv64(setup->frag_size, mul, div);
-       setup->xfer_align = muldiv64(setup->xfer_align, mul, div);
-
-       /* FIXME */
-       setup->boundary = LONG_MAX - LONG_MAX % setup->buffer_size;
-
        if (rate->states)
                free(rate->states);
-       rate->states = malloc(setup->format.channels * sizeof(*rate->states));
+       rate->states = malloc(params->channels * sizeof(*rate->states));
        return 0;
 }
 
+static int snd_pcm_rate_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
+{
+       snd_pcm_rate_t *rate = pcm->private;
+       snd_pcm_t *slave = rate->plug.slave;
+       size_t avail_min, xfer_min, xfer_align;
+       int err;
+       avail_min = params->avail_min;
+       xfer_min = params->xfer_min;
+       xfer_align = params->xfer_align;
+       params->avail_min = muldiv_near(params->avail_min, slave->rate, pcm->rate);
+       params->xfer_min = muldiv_near(params->xfer_min, slave->rate, pcm->rate);
+       params->xfer_align = muldiv_near(params->xfer_align, slave->rate, pcm->rate);
+       err = snd_pcm_sw_params(slave, params);
+       params->avail_min = avail_min;
+       params->xfer_min = xfer_min;
+       params->xfer_align = xfer_align;
+       params->boundary = LONG_MAX - pcm->buffer_size * 2 - LONG_MAX % pcm->buffer_size;
+       return err;
+}
+
 static int snd_pcm_rate_init(snd_pcm_t *pcm)
 {
        snd_pcm_rate_t *rate = pcm->private;
        unsigned int k;
-       for (k = 0; k < pcm->setup.format.channels; ++k) {
+       for (k = 0; k < pcm->channels; ++k) {
                rate->states[k].sum = 0;
                rate->states[k].sample = 0;
                if (rate->func == resample_expand) {
@@ -463,7 +442,7 @@ static ssize_t snd_pcm_rate_write_areas(snd_pcm_t *pcm,
                src_frames = rate->func(areas, client_offset, src_frames,
                                        snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
                                        &dst_frames, 
-                                       pcm->setup.format.channels,
+                                       pcm->channels,
                                        rate->get_idx, rate->put_idx,
                                        rate->pitch, rate->states);
                err = snd_pcm_mmap_forward(slave, dst_frames);
@@ -509,7 +488,7 @@ static ssize_t snd_pcm_rate_read_areas(snd_pcm_t *pcm,
                src_frames = rate->func(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
                                        src_frames,
                                        areas, client_offset, &dst_frames,
-                                       pcm->setup.format.channels,
+                                       pcm->channels,
                                        rate->get_idx, rate->put_idx,
                                        rate->pitch, rate->states);
                err = snd_pcm_mmap_forward(slave, src_frames);
@@ -529,27 +508,27 @@ static ssize_t snd_pcm_rate_read_areas(snd_pcm_t *pcm,
        return err;
 }
 
-size_t snd_pcm_rate_client_frames(snd_pcm_t *pcm, size_t frames)
+ssize_t snd_pcm_rate_client_frames(snd_pcm_t *pcm, ssize_t frames)
 {
        snd_pcm_rate_t *rate = pcm->private;
        /* Round toward zero */
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
-               return (int64_t)frames * DIV / rate->pitch;
+               return muldiv_down(frames, DIV, rate->pitch);
        else
-               return (int64_t)frames * rate->pitch / DIV;
+               return muldiv_down(frames, rate->pitch, DIV);
 }
 
 static void snd_pcm_rate_dump(snd_pcm_t *pcm, FILE *fp)
 {
        snd_pcm_rate_t *rate = pcm->private;
-       if (rate->req_sformat < 0)
+       if (rate->sformat < 0)
                fprintf(fp, "Rate conversion PCM (%d)\n", 
-                       rate->req_srate);
+                       rate->srate);
        else
                fprintf(fp, "Rate conversion PCM (%d, sformat=%s)\n", 
-                       rate->req_srate,
-                       snd_pcm_format_name(rate->req_sformat));
-       if (pcm->valid_setup) {
+                       rate->srate,
+                       snd_pcm_format_name(rate->sformat));
+       if (pcm->setup) {
                fprintf(fp, "Its setup is:\n");
                snd_pcm_dump_setup(pcm, fp);
        }
@@ -560,12 +539,12 @@ 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,
-       params_info: snd_pcm_rate_params_info,
-       params: snd_pcm_rate_params,
-       setup: snd_pcm_rate_setup,
+       hw_info: snd_pcm_rate_hw_info,
+       hw_params: snd_pcm_rate_hw_params,
+       sw_params: snd_pcm_rate_sw_params,
+       dig_info: snd_pcm_plugin_dig_info,
+       dig_params: snd_pcm_plugin_dig_params,
        channel_info: snd_pcm_plugin_channel_info,
-       channel_params: snd_pcm_plugin_channel_params,
-       channel_setup: snd_pcm_plugin_channel_setup,
        dump: snd_pcm_rate_dump,
        nonblock: snd_pcm_plugin_nonblock,
        async: snd_pcm_plugin_async,
@@ -584,8 +563,8 @@ int snd_pcm_rate_open(snd_pcm_t **pcmp, char *name, int sformat, int srate, snd_
        if (!rate) {
                return -ENOMEM;
        }
-       rate->req_srate = srate;
-       rate->req_sformat = sformat;
+       rate->srate = srate;
+       rate->sformat = sformat;
        rate->plug.read = snd_pcm_rate_read_areas;
        rate->plug.write = snd_pcm_rate_write_areas;
        rate->plug.client_frames = snd_pcm_rate_client_frames;
index 4e84155329846d066714eac6dd06b0f38d3f5f3b..75a4b106d6ecbd97aae5da0ed84e34f1aaed7694 100644 (file)
@@ -81,12 +81,8 @@ typedef union {
 typedef struct {
        /* This field need to be the first */
        snd_pcm_plugin_t plug;
-       int req_sformat, req_schannels;
        int sformat;
-       int cformat;
        int schannels;
-       int cchannels;
-       int cxfer_mode, cmmap_shape;
        route_params_t params;
 } snd_pcm_route_t;
 
@@ -429,110 +425,91 @@ static int snd_pcm_route_close(snd_pcm_t *pcm)
        return 0;
 }
 
-static int snd_pcm_route_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+static int snd_pcm_route_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info)
 {
        snd_pcm_route_t *route = pcm->private;
-       unsigned int req_mask = info->req_mask;
-       unsigned int sfmt = info->req.format.sfmt;
-       unsigned int channels = info->req.format.channels;
+       unsigned int format_mask, access_mask, channels_min, channels_max;
        int err;
-       if (req_mask & SND_PCM_PARAMS_SFMT &&
-           !snd_pcm_format_linear(sfmt)) {
-               info->req.fail_mask = SND_PCM_PARAMS_SFMT;
-               info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+       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;
+       if (info->channels_max > 1024)
+               info->channels_max = 1024;
+       if (info->channels_max < info->channels_min)
+               return -EINVAL;
+       channels_min = info->channels_min;
+       channels_max = info->channels_max;
+       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);
+       if (info->format_mask) 
+               info->format_mask = format_mask;
+       if (info->channels_min <= info->channels_max) {
+               info->channels_min = channels_min;
+               info->channels_max = channels_max;
        }
-       if (route->req_sformat >= 0) {
-               info->req_mask |= SND_PCM_PARAMS_SFMT;
-               info->req.format.sfmt = route->req_sformat;
-       }
-       if (route->req_schannels >= 0) {
-               info->req_mask |= SND_PCM_PARAMS_CHANNELS;
-               info->req.format.channels = route->req_schannels;
+       if (info->access_mask) {
+               route->plug.saccess_mask = info->access_mask;
+               info->access_mask = access_mask;
        }
-       info->req_mask &= ~(SND_PCM_PARAMS_MMAP_SHAPE | 
-                           SND_PCM_PARAMS_XFER_MODE);
-       err = snd_pcm_params_info(route->plug.slave, info);
-       info->req_mask = req_mask;
-       info->req.format.sfmt = sfmt;
-       info->req.format.channels = channels;
+       if (info->format_mask)
+               info->format_mask = format_mask;
        if (err < 0)
                return err;
-       if (req_mask & SND_PCM_PARAMS_SFMT)
-               info->formats = 1 << sfmt;
-       else
-               info->formats = SND_PCM_LINEAR_FORMATS;
-       if (req_mask & SND_PCM_PARAMS_CHANNELS) {
-               info->min_channels = channels;
-               info->max_channels = channels;
-       } else {
-               info->min_channels = 1;
-               info->max_channels = 1024;
-       }
-       info->flags &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
-       info->flags |= SND_PCM_INFO_INTERLEAVED | SND_PCM_INFO_NONINTERLEAVED;
-       return err;
+       info->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID);
+       snd_pcm_hw_info_complete(info);
+       return 0;
 }
 
-static int snd_pcm_route_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+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 format, access, channels;
+       unsigned int src_format, dst_format;
        int err;
-       if (!snd_pcm_format_linear(params->format.sfmt)) {
-               params->fail_mask = SND_PCM_PARAMS_SFMT;
-               params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
-               return -EINVAL;
-       }
-       route->cformat = params->format.sfmt;
-       route->cchannels = params->format.channels;
-       route->cxfer_mode = params->xfer_mode;
-       route->cmmap_shape = params->mmap_shape;
-       if (route->req_sformat >= 0)
-               params->format.sfmt = route->req_sformat;
-       if (route->req_schannels >= 0)
-               params->format.channels = route->req_schannels;
-       params->xfer_mode = SND_PCM_XFER_UNSPECIFIED;
-       params->mmap_shape = SND_PCM_MMAP_UNSPECIFIED;
-       err = snd_pcm_params_mmap(slave, params);
-       params->format.sfmt = route->cformat;
-       params->format.channels = route->cchannels;
-       params->xfer_mode = route->cxfer_mode;
-       params->mmap_shape = route->cmmap_shape;
-       return err;
-}
-
-static int snd_pcm_route_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
-{
-       snd_pcm_route_t *route = pcm->private;
-       int src_format, dst_format;
-       int err = snd_pcm_setup(route->plug.slave, setup);
+       format = params->format;
+       channels = params->channels;
+       access = params->access;
+       if (route->sformat >= 0)
+               params->format = route->sformat;
+       if (route->schannels >= 0)
+               params->channels = route->schannels;
+       if (route->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_INTERLEAVED)
+               params->access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
+       else if (route->plug.saccess_mask & SND_PCM_ACCBIT_MMAP_NONINTERLEAVED)
+               params->access = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
+       else
+               assert(0);
+       err = snd_pcm_hw_params(slave, params);
+       params->format = format;
+       params->channels = channels;
+       params->access = access;
        if (err < 0)
                return err;
-       if (route->req_sformat >= 0)
-               assert(route->req_sformat == setup->format.sfmt);
-       route->sformat = setup->format.sfmt;
-       route->schannels = setup->format.channels;
-       if (route->cxfer_mode == SND_PCM_XFER_UNSPECIFIED)
-               setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
-       else
-               setup->xfer_mode = route->cxfer_mode;
-       if (route->cmmap_shape == SND_PCM_MMAP_UNSPECIFIED)
-               setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
-       else
-               setup->mmap_shape = route->cmmap_shape;
-       setup->format.sfmt = route->cformat;
-       setup->format.channels = route->cchannels;
-       setup->mmap_bytes = 0;
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
-               src_format = route->cformat;
-               dst_format = route->sformat;
+               src_format = format;
+               dst_format = slave->format;
        } else {
-               src_format = route->sformat;
-               dst_format = route->cformat;
+               src_format = slave->format;
+               dst_format = format;
        }
-       route->params.get_idx = get_index(src_format, SND_PCM_SFMT_U16);
-       route->params.put_idx = put_index(SND_PCM_SFMT_U32, dst_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);
        route->params.conv_idx = conv_index(src_format, dst_format);
        route->params.src_size = snd_pcm_format_width(src_format) / 8;
        route->params.dst_sfmt = dst_format;
@@ -547,30 +524,6 @@ static int snd_pcm_route_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
        return 0;
 }
 
-static int snd_pcm_route_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
-{
-#if 0
-       snd_pcm_plugin_t *plugin = pcm->private;
-       int err;
-       err = snd_pcm_channel_setup(plugin->slave, setup);
-       if (err < 0)
-               return err;
-#endif
-       if (!pcm->mmap_info)
-               return 0;
-       if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) {
-               setup->running_area.addr = pcm->mmap_info->addr;
-               setup->running_area.first = setup->channel * pcm->bits_per_sample;
-               setup->running_area.step = pcm->bits_per_frame;
-       } else {
-               setup->running_area.addr = pcm->mmap_info->addr + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
-               setup->running_area.first = 0;
-               setup->running_area.step = pcm->bits_per_sample;
-       }
-       setup->stopped_area = setup->running_area;
-       return 0;
-}
-
 static ssize_t snd_pcm_route_write_areas(snd_pcm_t *pcm,
                                         snd_pcm_channel_area_t *areas,
                                         size_t offset,
@@ -588,7 +541,7 @@ static ssize_t snd_pcm_route_write_areas(snd_pcm_t *pcm,
                size_t frames = snd_pcm_mmap_playback_xfer(slave, size - xfer);
                route_transfer(areas, offset, 
                               snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
-                              frames, route->schannels, &route->params);
+                              frames, slave->channels, &route->params);
                err = snd_pcm_mmap_forward(slave, frames);
                if (err < 0)
                        break;
@@ -622,7 +575,7 @@ static ssize_t snd_pcm_route_read_areas(snd_pcm_t *pcm,
                size_t frames = snd_pcm_mmap_capture_xfer(slave, size - xfer);
                route_transfer(snd_pcm_mmap_areas(slave), snd_pcm_mmap_offset(slave),
                               areas, offset, 
-                              frames, route->cchannels, &route->params);
+                              frames, pcm->channels, &route->params);
                err = snd_pcm_mmap_forward(slave, frames);
                if (err < 0)
                        break;
@@ -643,11 +596,11 @@ static void snd_pcm_route_dump(snd_pcm_t *pcm, FILE *fp)
 {
        snd_pcm_route_t *route = pcm->private;
        unsigned int dst;
-       if (route->req_sformat < 0)
+       if (route->sformat < 0)
                fprintf(fp, "Route conversion PCM\n");
        else
                fprintf(fp, "Route conversion PCM (sformat=%s)\n", 
-                       snd_pcm_format_name(route->req_sformat));
+                       snd_pcm_format_name(route->sformat));
        fputs("Transformation table:\n", fp);
        for (dst = 0; dst < route->params.ndsts; dst++) {
                ttable_dst_t *d = &route->params.dsts[dst];
@@ -669,7 +622,7 @@ static void snd_pcm_route_dump(snd_pcm_t *pcm, FILE *fp)
                }
                putc('\n', fp);
        }
-       if (pcm->valid_setup) {
+       if (pcm->setup) {
                fprintf(fp, "Its setup is:\n");
                snd_pcm_dump_setup(pcm, fp);
        }
@@ -680,12 +633,12 @@ 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,
-       params_info: snd_pcm_route_params_info,
-       params: snd_pcm_route_params,
-       setup: snd_pcm_route_setup,
+       hw_info: snd_pcm_route_hw_info,
+       hw_params: snd_pcm_route_hw_params,
+       sw_params: snd_pcm_plugin_sw_params,
+       dig_info: snd_pcm_plugin_dig_info,
+       dig_params: snd_pcm_plugin_dig_params,
        channel_info: snd_pcm_plugin_channel_info,
-       channel_params: snd_pcm_plugin_channel_params,
-       channel_setup: snd_pcm_route_channel_setup,
        dump: snd_pcm_route_dump,
        nonblock: snd_pcm_plugin_nonblock,
        async: snd_pcm_plugin_async,
@@ -782,8 +735,8 @@ int snd_pcm_route_open(snd_pcm_t **pcmp, char *name,
        if (!route) {
                return -ENOMEM;
        }
-       route->req_sformat = sformat;
-       route->req_schannels = schannels;
+       route->sformat = sformat;
+       route->schannels = schannels;
        route->plug.read = snd_pcm_route_read_areas;
        route->plug.write = snd_pcm_route_write_areas;
        route->plug.slave = slave;
index 85edc923239c2079b574b64171e24f1ab2f4c5d0..898f864745c64510bb0a4a4f1170710aba695380 100644 (file)
@@ -21,6 +21,7 @@
   
 #include <stdio.h>
 #include <stdlib.h>
+#include <limits.h>
 #include <unistd.h>
 #include <string.h>
 #include <signal.h>
@@ -66,8 +67,8 @@ typedef struct {
        struct list_head clients;
        struct list_head list;
        snd_pcm_t *pcm;
-       int sformat;
-       int srate;
+       int format;
+       int rate;
        size_t channels_count;
        size_t open_count;
        size_t setup_count;
@@ -104,7 +105,6 @@ typedef struct {
        int ready;
        int client_socket;
        int slave_socket;
-       void *stopped_data;
 } snd_pcm_share_t;
 
 static void _snd_pcm_share_stop(snd_pcm_t *pcm, int state);
@@ -115,9 +115,9 @@ static size_t snd_pcm_share_slave_avail(snd_pcm_share_slave_t *slave)
        snd_pcm_t *pcm = slave->pcm;
        avail = slave->hw_ptr - *pcm->appl_ptr;
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
-               avail += pcm->setup.buffer_size;
+               avail += pcm->buffer_size;
        if (avail < 0)
-               avail += pcm->setup.boundary;
+               avail += pcm->boundary;
        return avail;
 }
 
@@ -133,8 +133,8 @@ static size_t _snd_pcm_share_slave_forward(snd_pcm_share_slave_t *slave)
        size_t avail, slave_avail;
        size_t slave_hw_avail;
        slave_avail = snd_pcm_share_slave_avail(slave);
-       boundary = slave->pcm->setup.boundary;
-       buffer_size = slave->pcm->setup.buffer_size;
+       boundary = slave->pcm->boundary;
+       buffer_size = slave->pcm->buffer_size;
        min_frames = slave_avail;
        max_frames = 0;
        slave_appl_ptr = *slave->pcm->appl_ptr;
@@ -191,7 +191,7 @@ static size_t _snd_pcm_share_missing(snd_pcm_t *pcm, int slave_xrun)
        snd_pcm_share_t *share = pcm->private;
        snd_pcm_share_slave_t *slave = share->slave;
        snd_pcm_t *spcm = slave->pcm;
-       size_t buffer_size = spcm->setup.buffer_size;
+       size_t buffer_size = spcm->buffer_size;
        int ready = 1, running = 0;
        size_t avail = 0, slave_avail;
        ssize_t hw_avail;
@@ -208,7 +208,7 @@ static size_t _snd_pcm_share_missing(snd_pcm_t *pcm, int slave_xrun)
        default:
                return INT_MAX;
        }
-       if (slave_xrun && pcm->setup.xrun_mode != SND_PCM_XRUN_NONE) {
+       if (slave_xrun && pcm->xrun_mode != SND_PCM_XRUN_NONE) {
                _snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN);
                goto update_poll;
        }
@@ -251,7 +251,7 @@ static size_t _snd_pcm_share_missing(snd_pcm_t *pcm, int slave_xrun)
                }
                break;
        case SND_PCM_STATE_RUNNING:
-               if (pcm->setup.xrun_mode != SND_PCM_XRUN_NONE) {
+               if (pcm->xrun_mode != SND_PCM_XRUN_NONE) {
                        if (hw_avail <= 0) {
                                _snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN);
                                break;
@@ -300,7 +300,7 @@ static size_t _snd_pcm_share_missing(snd_pcm_t *pcm, int slave_xrun)
                                size_t cont = buffer_size - offset;
                                if (cont < frames)
                                        frames = cont;
-                               snd_pcm_areas_silence(pcm->running_areas, offset, pcm->setup.format.channels, frames, pcm->setup.format.sfmt);
+                               snd_pcm_areas_silence(pcm->running_areas, offset, pcm->channels, frames, pcm->format);
                                offset += frames;
                                if (offset >= buffer_size)
                                        offset = 0;
@@ -357,17 +357,17 @@ void *snd_pcm_share_slave_thread(void *data)
                        size_t hw_ptr;
                        ssize_t avail_min;
                        hw_ptr = slave->hw_ptr + missing;
-                       hw_ptr += spcm->setup.frag_size - 1;
-                       if (hw_ptr >= spcm->setup.boundary)
-                               hw_ptr -= spcm->setup.boundary;
-                       hw_ptr -= hw_ptr % spcm->setup.frag_size;
+                       hw_ptr += spcm->fragment_size - 1;
+                       if (hw_ptr >= spcm->boundary)
+                               hw_ptr -= spcm->boundary;
+                       hw_ptr -= hw_ptr % spcm->fragment_size;
                        avail_min = hw_ptr - *spcm->appl_ptr;
                        if (spcm->stream == SND_PCM_STREAM_PLAYBACK)
-                               avail_min += spcm->setup.buffer_size;
+                               avail_min += spcm->buffer_size;
                        if (avail_min < 0)
-                               avail_min += spcm->setup.boundary;
+                               avail_min += spcm->boundary;
                        // printf("avail_min=%d\n", avail_min);
-                       if ((size_t)avail_min != spcm->setup.avail_min)
+                       if ((size_t)avail_min != spcm->avail_min)
                                snd_pcm_set_avail_min(spcm, avail_min);
                        slave->polling = 1;
                        Pthread_mutex_unlock(&slave->mutex);
@@ -403,16 +403,16 @@ static void _snd_pcm_share_update(snd_pcm_t *pcm)
                size_t hw_ptr;
                ssize_t avail_min;
                hw_ptr = slave->hw_ptr + missing;
-               hw_ptr += spcm->setup.frag_size - 1;
-               if (hw_ptr >= spcm->setup.boundary)
-                       hw_ptr -= spcm->setup.boundary;
-               hw_ptr -= hw_ptr % spcm->setup.frag_size;
+               hw_ptr += spcm->fragment_size - 1;
+               if (hw_ptr >= spcm->boundary)
+                       hw_ptr -= spcm->boundary;
+               hw_ptr -= hw_ptr % spcm->fragment_size;
                avail_min = hw_ptr - *spcm->appl_ptr;
                if (spcm->stream == SND_PCM_STREAM_PLAYBACK)
-                       avail_min += spcm->setup.buffer_size;
+                       avail_min += spcm->buffer_size;
                if (avail_min < 0)
-                       avail_min += spcm->setup.boundary;
-               if ((size_t)avail_min < spcm->setup.avail_min)
+                       avail_min += spcm->boundary;
+               if ((size_t)avail_min < spcm->avail_min)
                        snd_pcm_set_avail_min(spcm, avail_min);
        }
 }
@@ -442,211 +442,128 @@ 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_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info)
+static int snd_pcm_share_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t *info)
 {
        snd_pcm_share_t *share = pcm->private;
        snd_pcm_share_slave_t *slave = share->slave;
+       unsigned int access_mask;
        int err = 0;
-       unsigned int req_mask = info->req_mask;
-       unsigned int channels = info->req.format.channels;
-       if ((req_mask & SND_PCM_PARAMS_CHANNELS) &&
-           channels != share->channels_count) {
-               info->req.fail_mask |= SND_PCM_PARAMS_CHANNELS;
-               info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+       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 (slave->sformat >= 0) {
-               if ((req_mask & SND_PCM_PARAMS_SFMT) &&
-                   info->req.format.sfmt != slave->sformat) {
-                       info->req.fail_mask |= SND_PCM_PARAMS_SFMT;
-                       info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
+       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_max > info->channels_max)
+               return -EINVAL;
+       if (slave->format >= 0) {
+               info->format_mask &= 1U << slave->format;
+               if (!info->format_mask)
                        return -EINVAL;
-               }
-               info->req.format.sfmt = slave->sformat;
-               info->req_mask |= SND_PCM_PARAMS_SFMT;
-       }
-       if (slave->srate >= 0) {
-               info->req.format.rate = slave->srate;
-               info->req_mask |= SND_PCM_PARAMS_RATE;
-       }
-
-       info->req_mask |= SND_PCM_PARAMS_CHANNELS;
-       info->req.format.channels = slave->channels_count;
-       err = snd_pcm_params_info(slave->pcm, info);
-       info->req.format.channels = channels;
-       info->req_mask = req_mask;
-       Pthread_mutex_lock(&slave->mutex);
-       if (slave->setup_count > 1 || 
-           (slave->setup_count == 1 && !pcm->valid_setup)) {
-               snd_pcm_setup_t *s = &slave->pcm->setup;
-               if ((req_mask & SND_PCM_PARAMS_SFMT) &&
-                   info->req.format.sfmt != s->format.sfmt) {
-                       info->req.fail_mask |= SND_PCM_PARAMS_SFMT;
-                       info->req.fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
-                       err = -EINVAL;
-                       goto _end;
-               }
-               info->formats = 1 << s->format.sfmt;
-               info->rates = SND_PCM_RATE_CONTINUOUS;
-               info->min_rate = info->max_rate = s->format.rate;
-               info->buffer_size = s->buffer_size;
-               info->min_fragment_size = info->max_fragment_size = s->frag_size;
-               info->min_fragments = info->max_fragments = s->frags;
-               info->fragment_align = s->frag_size;
-               info->req.fail_mask = 0;
        }
-
-       info->min_channels = info->max_channels = share->channels_count;
-       if (info->flags & SND_PCM_INFO_INTERLEAVED) {
-               info->flags &= ~SND_PCM_INFO_INTERLEAVED;
-               info->flags |= SND_PCM_INFO_COMPLEX;
+       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_max > info->rate_max)
+                       return -EINVAL;
        }
- _end:
-       Pthread_mutex_unlock(&slave->mutex);
+       info->access_mask = SND_PCM_ACCBIT_MMAP;
+       info->channels_min = info->channels_max = slave->channels_count;
+       err = snd_pcm_hw_info(slave->pcm, info);
+       if (info->channels_min <= info->channels_max)
+               info->channels_min = info->channels_max = share->channels_count;
+       if (info->access_mask)
+               info->access_mask = access_mask;
+       info->info |= SND_PCM_INFO_DOUBLE;
        return err;
 }
 
-static int snd_pcm_share_mmap(snd_pcm_t *pcm)
+static int snd_pcm_share_hw_params(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;
-       snd_pcm_mmap_info_t *i;
-       size_t count;
+       snd_pcm_t *spcm = slave->pcm;
        int err = 0;
        Pthread_mutex_lock(&slave->mutex);
-       if (slave->mmap_count == 0) {
-               err = snd_pcm_mmap(slave->pcm);
+       if (slave->setup_count > 1 || 
+           (slave->setup_count == 1 && !pcm->setup)) {
+               if (params->access != spcm->access ||
+                   params->format != spcm->format ||
+                   params->subformat != spcm->subformat ||
+                   params->rate != spcm->rate ||
+                   params->fragments != spcm->fragments ||
+                   params->fragment_size != spcm->fragment_size) {
+                       ERR("slave is already running with different setup");
+                       params->fail_mask |= SND_PCM_HW_PARBIT_FORMAT;
+                       return -EBUSY;
+               }
+       } else {
+               snd_pcm_hw_params_t sparams = *params;
+               sparams.channels = slave->channels_count;
+               err = snd_pcm_hw_params(slave->pcm, &sparams);
                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->silence_frames = slave->safety_threshold;
                if (slave->pcm->stream == SND_PCM_STREAM_PLAYBACK)
-                       snd_pcm_areas_silence(slave->pcm->running_areas, 0, slave->pcm->setup.format.channels, slave->pcm->setup.buffer_size, slave->pcm->setup.format.sfmt);
+                       snd_pcm_areas_silence(slave->pcm->running_areas, 0, slave->pcm->channels, slave->pcm->buffer_size, slave->pcm->format);
        }
-       slave->mmap_count++;
-       count = slave->pcm->mmap_info_count;
-       i = malloc((count + 1) * sizeof(*i));
-       if (!i) {
-               err = -ENOMEM;
-               goto _end;
-       }
-       err = snd_pcm_alloc_user_mmap(pcm, i);
-       if (err < 0) {
-               free(i);
-               return err;
-       }
-       share->stopped_data = i->addr;
-       memcpy(i + 1, slave->pcm->mmap_info, count * sizeof(*pcm->mmap_info));
-       pcm->mmap_info_count = count + 1;
-       pcm->mmap_info = i;
+       share->state = SND_PCM_STATE_SETUP;
+       slave->setup_count++;
  _end:
        Pthread_mutex_unlock(&slave->mutex);
-       return 0;
+       return err;
 }
 
-static int snd_pcm_share_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
+static int snd_pcm_share_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params)
 {
-       snd_pcm_share_t *share = pcm->private;
-       snd_pcm_share_slave_t *slave = share->slave;
-       snd_pcm_mmap_info_t *i = pcm->mmap_info;
-       int err = 0;
-       Pthread_mutex_lock(&slave->mutex);
-       slave->mmap_count--;
-       if (slave->mmap_count == 0) {
-               err = snd_pcm_munmap(slave->pcm);
-               if (err < 0)
-                       goto _end;
+       if (params->start_mode > SND_PCM_START_LAST) {
+               params->fail_mask = SND_PCM_SW_PARBIT_START_MODE;
+               return -EINVAL;
        }
-       err = snd_pcm_free_mmap(pcm, i);
-       if (err < 0)
-               goto _end;
-       free(i);
-       pcm->mmap_info_count = 0;
-       pcm->mmap_info = 0;
- _end:
-       Pthread_mutex_unlock(&slave->mutex);
-       return err;
+       if (params->ready_mode > SND_PCM_READY_LAST) {
+               params->fail_mask = SND_PCM_SW_PARBIT_READY_MODE;
+               return -EINVAL;
+       }
+       if (params->xrun_mode > SND_PCM_XRUN_LAST) {
+               params->fail_mask = SND_PCM_SW_PARBIT_XRUN_MODE;
+               return -EINVAL;
+       }
+       return 0;
 }
-               
-static int snd_pcm_share_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
+
+static int snd_pcm_share_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t *info)
 {
        snd_pcm_share_t *share = pcm->private;
        snd_pcm_share_slave_t *slave = share->slave;
-       unsigned int channels = params->format.channels;
-       int err = 0;
-       if (channels != share->channels_count) {
-               params->fail_mask = SND_PCM_PARAMS_CHANNELS;
-               params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
-               ERR("channels requested (%d) differs from configuration (%ld)", channels, (long)share->channels_count);
-               return -EINVAL;
-       }
-       share->xfer_mode = params->xfer_mode;
-       share->xrun_mode = params->xrun_mode;
-       share->avail_min = params->avail_min;
+       int err;
+       /* FIXME */
        Pthread_mutex_lock(&slave->mutex);
-       if (slave->setup_count > 1 || 
-           (slave->setup_count == 1 && !pcm->valid_setup)) {
-               snd_pcm_setup_t *s = &slave->pcm->setup;
-               if (params->format.sfmt != s->format.sfmt) {
-                       ERR("slave is already running with different format");
-                       params->fail_mask |= SND_PCM_PARAMS_SFMT;
-               }
-               if (params->fail_mask) {
-                       params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
-                       err = -EINVAL;
-                       goto _end;
-               }
-       } else {
-               snd_pcm_params_t sp = *params;
-               snd_pcm_setup_t *ss;
-               if (slave->sformat >= 0 &&
-                   params->format.sfmt != slave->sformat) {
-                       params->fail_mask = SND_PCM_PARAMS_SFMT;
-                       params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
-                       ERR("format requested (%d) differs from configuration (%d)", params->format.sfmt, slave->sformat);
-                       err = -EINVAL;
-                       goto _end;
-               }
-               if (slave->srate >= 0)
-                       sp.format.rate = slave->srate;
-               sp.xfer_mode = SND_PCM_XFER_UNSPECIFIED;
-               sp.xrun_mode = SND_PCM_XRUN_NONE;
-               sp.format.channels = slave->channels_count;
-               err = snd_pcm_params_mmap(slave->pcm, &sp);
-               if (err < 0)
-                       goto _end;
-               ss = &slave->pcm->setup;
-               /* >= 30 ms */
-               slave->safety_threshold = ss->format.rate * 30 / 1000;
-               slave->safety_threshold += ss->frag_size - 1;
-               slave->safety_threshold -= slave->safety_threshold % ss->frag_size;
-               slave->silence_frames = slave->safety_threshold;
-       }
-       share->state = SND_PCM_STATE_SETUP;
-       slave->setup_count++;
- _end:
+       err = snd_pcm_dig_info(slave->pcm, info);
        Pthread_mutex_unlock(&slave->mutex);
        return err;
 }
 
-static int snd_pcm_share_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup)
+static int snd_pcm_share_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t *params)
 {
        snd_pcm_share_t *share = pcm->private;
        snd_pcm_share_slave_t *slave = share->slave;
        int err;
-       err = snd_pcm_setup(slave->pcm, setup);
-       if (err < 0)
-               return err;
-       setup->xrun_mode = share->xrun_mode;
-       setup->format.channels = share->channels_count;
-       if (share->avail_min > setup->buffer_size)
-               share->avail_min = setup->buffer_size;
-       setup->avail_min = share->avail_min;
-       if (share->xfer_mode == SND_PCM_XFER_UNSPECIFIED)
-               setup->xfer_mode = SND_PCM_XFER_NONINTERLEAVED;
-       else
-               setup->xfer_mode = share->xfer_mode;
-       if (setup->mmap_shape != SND_PCM_MMAP_INTERLEAVED)
-               setup->mmap_shape = SND_PCM_MMAP_COMPLEX;
-       return 0;
+       /* FIXME */
+       Pthread_mutex_lock(&slave->mutex);
+       err = snd_pcm_dig_params(slave->pcm, params);
+       Pthread_mutex_unlock(&slave->mutex);
+       return err;
 }
 
 static int snd_pcm_share_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
@@ -661,7 +578,7 @@ static int snd_pcm_share_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
                if (share->state != SND_PCM_STATE_RUNNING &&
                    share->state != SND_PCM_STATE_DRAINING)
                        goto _notrunning;
-               d = pcm->setup.buffer_size - status->avail;
+               d = pcm->buffer_size - status->avail;
        } else {
                status->avail = snd_pcm_mmap_capture_avail(pcm);
                if (share->state != SND_PCM_STATE_RUNNING)
@@ -738,7 +655,7 @@ static ssize_t snd_pcm_share_avail_update(snd_pcm_t *pcm)
        }
        Pthread_mutex_unlock(&slave->mutex);
        avail = snd_pcm_mmap_avail(pcm);
-       if ((size_t)avail > pcm->setup.buffer_size)
+       if ((size_t)avail > pcm->buffer_size)
                return -EPIPE;
        return avail;
 }
@@ -753,10 +670,10 @@ static ssize_t _snd_pcm_share_mmap_forward(snd_pcm_t *pcm, size_t size)
        if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
            share->state == SND_PCM_STATE_RUNNING) {
                frames = *slave->pcm->appl_ptr - share->appl_ptr;
-               if (frames > (ssize_t)pcm->setup.buffer_size)
-                       frames -= pcm->setup.boundary;
-               else if (frames < -(ssize_t)pcm->setup.buffer_size)
-                       frames += pcm->setup.boundary;
+               if (frames > (ssize_t)pcm->buffer_size)
+                       frames -= pcm->boundary;
+               else if (frames < -(ssize_t)pcm->buffer_size)
+                       frames += pcm->boundary;
                if (frames > 0) {
                        /* Latecomer PCM */
                        ret = snd_pcm_rewind(slave->pcm, frames);
@@ -839,13 +756,13 @@ static int snd_pcm_share_start(snd_pcm_t *pcm)
                while (xfer < hw_avail) {
                        size_t frames = hw_avail - xfer;
                        size_t offset = snd_pcm_mmap_offset(pcm);
-                       size_t cont = pcm->setup.buffer_size - offset;
+                       size_t cont = pcm->buffer_size - offset;
                        if (cont < frames)
                                frames = cont;
                        snd_pcm_areas_copy(pcm->stopped_areas, xfer,
                                           pcm->running_areas, offset,
-                                          pcm->setup.format.channels, frames,
-                                          pcm->setup.format.sfmt);
+                                          pcm->channels, frames,
+                                          pcm->format);
                        xfer += frames;
                }
                snd_pcm_mmap_appl_forward(pcm, hw_avail);
@@ -883,51 +800,6 @@ static int snd_pcm_share_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *in
        return err;
 }
 
-static int snd_pcm_share_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t *params)
-{
-       snd_pcm_share_t *share = pcm->private;
-       snd_pcm_share_slave_t *slave = share->slave;
-       unsigned int channel = params->channel;
-       int c = share->slave_channels[channel];
-       int err;
-       params->channel = c;
-       err = snd_pcm_channel_params(slave->pcm, params);
-       params->channel = channel;
-       return err;
-}
-
-static int snd_pcm_share_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup)
-{
-       snd_pcm_share_t *share = pcm->private;
-       snd_pcm_share_slave_t *slave = share->slave;
-       unsigned int channel = setup->channel;
-       int c = share->slave_channels[channel];
-       int err;
-       setup->channel = c;
-       err = snd_pcm_channel_setup(slave->pcm, setup);
-       setup->channel = channel;
-       if (err < 0)
-               return err;
-       if (!pcm->mmap_info)
-               return 0;
-       switch (pcm->setup.mmap_shape) {
-       case SND_PCM_MMAP_INTERLEAVED:
-       case SND_PCM_MMAP_COMPLEX:
-               setup->stopped_area.addr = share->stopped_data;
-               setup->stopped_area.first = channel * pcm->bits_per_sample;
-               setup->stopped_area.step = pcm->bits_per_frame;
-               break;
-       case SND_PCM_MMAP_NONINTERLEAVED:
-               setup->stopped_area.addr = share->stopped_data + c * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
-               setup->stopped_area.first = 0;
-               setup->stopped_area.step = pcm->bits_per_sample;
-               break;
-       default:
-               assert(0);
-       }
-       return 0;
-}
-
 static ssize_t _snd_pcm_share_rewind(snd_pcm_t *pcm, size_t frames)
 {
        snd_pcm_share_t *share = pcm->private;
@@ -984,7 +856,7 @@ static int snd_pcm_share_set_avail_min(snd_pcm_t *pcm, size_t frames)
        snd_pcm_share_t *share = pcm->private;
        snd_pcm_share_slave_t *slave = share->slave;
        Pthread_mutex_lock(&slave->mutex);
-       pcm->setup.avail_min = frames;
+       pcm->avail_min = frames;
        share->avail_min = frames;
        _snd_pcm_share_update(pcm);
        Pthread_mutex_unlock(&slave->mutex);
@@ -996,7 +868,7 @@ static void _snd_pcm_share_stop(snd_pcm_t *pcm, int state)
 {
        snd_pcm_share_t *share = pcm->private;
        snd_pcm_share_slave_t *slave = share->slave;
-       if (!pcm->mmap_info) {
+       if (!pcm->mmap_channels) {
                /* PCM closing already begun in the main thread */
                return;
        }
@@ -1004,13 +876,13 @@ static void _snd_pcm_share_stop(snd_pcm_t *pcm, int state)
        if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
                snd_pcm_areas_copy(pcm->running_areas, 0,
                                   pcm->stopped_areas, 0,
-                                  pcm->setup.format.channels, pcm->setup.buffer_size,
-                                  pcm->setup.format.sfmt);
+                                  pcm->channels, pcm->buffer_size,
+                                  pcm->format);
        } else if (slave->running_count > 1) {
                int err;
                ssize_t delay;
-               snd_pcm_areas_silence(pcm->running_areas, 0, pcm->setup.format.channels,
-                                     pcm->setup.buffer_size, pcm->setup.format.sfmt);
+               snd_pcm_areas_silence(pcm->running_areas, 0, pcm->channels,
+                                     pcm->buffer_size, pcm->format);
                err = snd_pcm_delay(slave->pcm, &delay);
                if (err >= 0 && delay > 0)
                        snd_pcm_rewind(slave->pcm, delay);
@@ -1116,7 +988,7 @@ static int snd_pcm_share_close(snd_pcm_t *pcm)
        int err = 0;
        Pthread_mutex_lock(&slaves_mutex);
        Pthread_mutex_lock(&slave->mutex);
-       if (pcm->valid_setup)
+       if (pcm->setup)
                slave->setup_count--;
        slave->open_count--;
        if (slave->open_count == 0) {
@@ -1142,6 +1014,16 @@ static int snd_pcm_share_close(snd_pcm_t *pcm)
        return err;
 }
 
+static int snd_pcm_share_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
+{
+       return 0;
+}
+
+static int snd_pcm_share_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
+{
+       return 0;
+}
+
 static void snd_pcm_share_dump(snd_pcm_t *pcm, FILE *fp)
 {
        snd_pcm_share_t *share = pcm->private;
@@ -1151,7 +1033,7 @@ static void snd_pcm_share_dump(snd_pcm_t *pcm, FILE *fp)
        fprintf(fp, "\nChannel bindings:\n");
        for (k = 0; k < share->channels_count; ++k)
                fprintf(fp, "%d: %d\n", k, share->slave_channels[k]);
-       if (pcm->valid_setup) {
+       if (pcm->setup) {
                fprintf(fp, "\nIts setup is:\n");
                snd_pcm_dump_setup(pcm, fp);
        }
@@ -1162,12 +1044,12 @@ 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,
-       params_info: snd_pcm_share_params_info,
-       params: snd_pcm_share_params,
-       setup: snd_pcm_share_setup,
+       hw_info: snd_pcm_share_hw_info,
+       hw_params: snd_pcm_share_hw_params,
+       sw_params: snd_pcm_share_sw_params,
+       dig_info: snd_pcm_share_dig_info,
+       dig_params: snd_pcm_share_dig_params,
        channel_info: snd_pcm_share_channel_info,
-       channel_params: snd_pcm_share_channel_params,
-       channel_setup: snd_pcm_share_channel_setup,
        dump: snd_pcm_share_dump,
        nonblock: snd_pcm_share_nonblock,
        async: snd_pcm_share_async,
@@ -1311,8 +1193,8 @@ int snd_pcm_share_open(snd_pcm_t **pcmp, char *name, char *sname,
                INIT_LIST_HEAD(&slave->clients);
                slave->pcm = spcm;
                slave->channels_count = schannels_count;
-               slave->sformat = sformat;
-               slave->srate = srate;
+               slave->format = sformat;
+               slave->rate = srate;
                pthread_mutex_init(&slave->mutex, NULL);
                pthread_cond_init(&slave->poll_cond, NULL);
                list_add_tail(&slave->list, &slaves);
@@ -1353,7 +1235,7 @@ int snd_pcm_share_open(snd_pcm_t **pcmp, char *name, char *sname,
        pcm->type = SND_PCM_TYPE_SHARE;
        pcm->stream = stream;
        pcm->mode = mode;
-       pcm->mmap_auto = 1;
+       pcm->mmap_rw = 1;
        pcm->ops = &snd_pcm_share_ops;
        pcm->op_arg = pcm;
        pcm->fast_ops = &snd_pcm_share_fast_ops;
index 0878bc17a1908bdee788e459a7c8159ebec95b3f..d609e7420d9bf6613f4e75b9383518eb97e7ab0e 100644 (file)
@@ -22,6 +22,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stddef.h>
+#include <limits.h>
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
@@ -40,8 +41,8 @@
 
 typedef struct {
        int socket;
+       unsigned int access_mask;
        volatile snd_pcm_shm_ctrl_t *ctrl;
-       snd_pcm_mmap_info_t *slave_mmap_info;
 } snd_pcm_shm_t;
 
 int receive_fd(int socket, void *data, size_t len, int *fd)
@@ -147,108 +148,147 @@ static int snd_pcm_shm_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
        return err;
 }
 
-static int snd_pcm_shm_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
+static int snd_pcm_shm_hw_info(snd_pcm_t *pcm, snd_pcm_hw_info_t * info)
 {
        snd_pcm_shm_t *shm = pcm->private;
        volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
        int err;
-       ctrl->cmd = SND_PCM_IOCTL_PARAMS_INFO;
-       ctrl->u.params_info = *info;
+       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);
+       *info = ctrl->u.hw_info;
+       if (info->access_mask) {
+               shm->access_mask = info->access_mask;
+               info->access_mask |= (SND_PCM_ACCESS_RW_INTERLEAVED |
+                                     SND_PCM_ACCESS_RW_NONINTERLEAVED);
+               info->access_mask &= access_mask;
+       }
        if (err < 0)
                return err;
-       *info = ctrl->u.params_info;
        return err;
 }
 
-static int snd_pcm_shm_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
+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;
+       unsigned int access = params->access;
        int err;
-       ctrl->cmd = SND_PCM_IOCTL_PARAMS;
-       ctrl->u.params = *params;
+       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;
-       *params = ctrl->u.params;
        return err;
 }
 
-static int snd_pcm_shm_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
+static int snd_pcm_shm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params)
 {
        snd_pcm_shm_t *shm = pcm->private;
        volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
        int err;
-       ctrl->cmd = SND_PCM_IOCTL_SETUP;
-       // ctrl->u.setup = *setup;
+       ctrl->cmd = SND_PCM_IOCTL_SW_PARAMS;
+       ctrl->u.sw_params = *params;
        err = snd_pcm_shm_action(pcm);
+       *params = ctrl->u.sw_params;
        if (err < 0)
                return err;
-       *setup = ctrl->u.setup;
        return err;
 }
 
-static int snd_pcm_shm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
+static int snd_pcm_shm_dig_info(snd_pcm_t *pcm, snd_pcm_dig_info_t * info)
 {
        snd_pcm_shm_t *shm = pcm->private;
        volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
        int err;
-       ctrl->cmd = SND_PCM_IOCTL_CHANNEL_INFO;
-       ctrl->u.channel_info = *info;
+       ctrl->cmd = SND_PCM_IOCTL_DIG_INFO;
+       ctrl->u.dig_info = *info;
        err = snd_pcm_shm_action(pcm);
        if (err < 0)
                return err;
-       *info = ctrl->u.channel_info;
+       *info = ctrl->u.dig_info;
        return err;
 }
 
-static int snd_pcm_shm_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t * params)
+static int snd_pcm_shm_dig_params(snd_pcm_t *pcm, snd_pcm_dig_params_t * params)
 {
        snd_pcm_shm_t *shm = pcm->private;
        volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
        int err;
-       ctrl->cmd = SND_PCM_IOCTL_CHANNEL_PARAMS;
-       ctrl->u.channel_params = *params;
+       ctrl->cmd = SND_PCM_IOCTL_DIG_PARAMS;
+       ctrl->u.dig_params = *params;
        err = snd_pcm_shm_action(pcm);
+       *params = ctrl->u.dig_params;
        if (err < 0)
                return err;
-       *params = ctrl->u.channel_params;
        return err;
 }
 
-static void *convert_addr(void *addr, size_t count, snd_pcm_mmap_info_t *old, snd_pcm_mmap_info_t *new)
+static int snd_pcm_shm_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
 {
-       size_t k;
-       size_t mindist = ULONG_MAX;
-       int idx = -1;
-       for (k = 0; k < count; ++k) {
-               if (addr >= old[k].addr) {
-                       size_t dist = addr - old[k].addr;
-                       if (dist < mindist) {
-                               mindist = dist;
-                               idx = k;
-                       }
+       return 0;
+}
+
+static int snd_pcm_shm_munmap(snd_pcm_t *pcm)
+{
+       unsigned int c;
+       for (c = 0; c < pcm->channels; ++c) {
+               snd_pcm_channel_info_t *i = &pcm->mmap_channels[c];
+               unsigned int c1;
+               int err;
+               if (i->type != SND_PCM_AREA_MMAP)
+                       continue;
+               if (i->u.mmap.fd < 0)
+                       continue;
+               for (c1 = c + 1; c1 < pcm->channels; ++c1) {
+                       snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
+                       if (i1->type != SND_PCM_AREA_MMAP)
+                               continue;
+                       if (i1->u.mmap.fd != i->u.mmap.fd)
+                               continue;
+                       i1->u.mmap.fd = -1;
+               }
+               err = close(i->u.mmap.fd);
+               if (err < 0) {
+                       SYSERR("close failed");
+                       return -errno;
                }
        }
-       assert(idx >= 0);
-       return new[idx].addr + mindist;
+       return 0;
 }
 
-static int snd_pcm_shm_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
+static int snd_pcm_shm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
 {
        snd_pcm_shm_t *shm = pcm->private;
        volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
        int err;
-       ctrl->cmd = SND_PCM_IOCTL_CHANNEL_SETUP;
-       ctrl->u.channel_setup = *setup;
-       err = snd_pcm_shm_action(pcm);
+       int fd;
+       ctrl->cmd = SND_PCM_IOCTL_CHANNEL_INFO;
+       ctrl->u.channel_info = *info;
+       err = snd_pcm_shm_action_fd(pcm, &fd);
        if (err < 0)
                return err;
-       *setup = ctrl->u.channel_setup;
-       if (pcm->mmap_info) {
-               setup->running_area.addr = convert_addr(setup->running_area.addr, pcm->mmap_info_count, shm->slave_mmap_info, pcm->mmap_info);
-               setup->stopped_area.addr = convert_addr(setup->stopped_area.addr, pcm->mmap_info_count, shm->slave_mmap_info, pcm->mmap_info);
+       *info = ctrl->u.channel_info;
+       info->addr = 0;
+       switch (info->type) {
+       case SND_PCM_AREA_MMAP:
+               info->u.mmap.fd = fd;
+               break;
+       case SND_PCM_AREA_SHM:
+               break;
+       default:
+               assert(0);
+               break;
        }
        return err;
 }
@@ -356,86 +396,6 @@ static ssize_t snd_pcm_shm_rewind(snd_pcm_t *pcm, size_t frames)
        return snd_pcm_shm_action(pcm);
 }
 
-static int snd_pcm_shm_mmap(snd_pcm_t *pcm)
-{
-       snd_pcm_shm_t *shm = pcm->private;
-       volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
-       int count, k, err, fd;
-       ctrl->cmd = SND_PCM_IOCTL_MMAP;
-       count = snd_pcm_shm_action(pcm);
-       if (count < 0)
-               return count;
-       pcm->mmap_info_count = count;
-       pcm->mmap_info = malloc(count * sizeof(*pcm->mmap_info));
-       shm->slave_mmap_info = malloc(count * sizeof(*shm->slave_mmap_info));
-       for (k = 0; k < count; ++k) {
-               snd_pcm_mmap_info_t *i = &pcm->mmap_info[k];
-               void *ptr;
-               ctrl->cmd = SND_PCM_IOCTL_MMAP_INFO;
-               ctrl->u.mmap_info.index = k;
-               err = snd_pcm_shm_action_fd(pcm, &fd);
-               if (err < 0)
-                       return err;
-               shm->slave_mmap_info[k] = ctrl->u.mmap_info;
-               *i = ctrl->u.mmap_info;
-               if (i->type == SND_PCM_MMAP_KERNEL) {
-                       i->u.kernel.fd = fd;
-                       ptr = mmap(NULL, i->size, PROT_WRITE | PROT_READ,
-                                  MAP_FILE | MAP_SHARED, 
-                                  fd, SND_PCM_MMAP_OFFSET_DATA);
-                       close(fd);
-                       if (ptr == MAP_FAILED || ptr == NULL) {
-                               SYSERR("mmap failed");
-                               free(pcm->mmap_info);
-                               return -errno;
-                       }
-               } else {
-                       ptr = shmat(i->u.user.shmid, 0, 0);
-                       if (ptr == (void*)-1) {
-                               SYSERR("shmat failed");
-                               free(pcm->mmap_info);
-                               return -errno;
-                       }
-               }
-               i->addr = ptr;
-       }
-       return 0;
-}
-
-static int snd_pcm_shm_munmap(snd_pcm_t *pcm)
-{
-       snd_pcm_shm_t *shm = pcm->private;
-       volatile snd_pcm_shm_ctrl_t *ctrl = shm->ctrl;
-       int err;
-       unsigned int k;
-       ctrl->cmd = SND_PCM_IOCTL_MUNMAP;
-       err = snd_pcm_shm_action(pcm);
-       if (err < 0)
-               return err;
-       for (k = 0; k < pcm->mmap_info_count; ++k) {
-               snd_pcm_mmap_info_t *i = &pcm->mmap_info[k];
-               if (i->type == SND_PCM_MMAP_KERNEL) {
-                       err = munmap(i->addr, i->size);
-                       if (err < 0) {
-                               SYSERR("munmap failed");
-                               return -errno;
-                       }
-               } else {
-                       err = shmdt(i->addr);
-                       if (err < 0) {
-                               SYSERR("shmdt failed");
-                               return -errno;
-                       }
-               }
-       }
-       pcm->mmap_info_count = 0;
-       free(pcm->mmap_info);
-       free(shm->slave_mmap_info);
-       pcm->mmap_info = 0;
-       shm->slave_mmap_info = 0;
-       return ctrl->result;
-}
-
 static ssize_t snd_pcm_shm_mmap_forward(snd_pcm_t *pcm, size_t size)
 {
        snd_pcm_shm_t *shm = pcm->private;
@@ -483,7 +443,7 @@ static int snd_pcm_shm_close(snd_pcm_t *pcm)
 static void snd_pcm_shm_dump(snd_pcm_t *pcm, FILE *fp)
 {
        fprintf(fp, "Shm PCM\n");
-       if (pcm->valid_setup) {
+       if (pcm->setup) {
                fprintf(fp, "\nIts setup is:\n");
                snd_pcm_dump_setup(pcm, fp);
        }
@@ -492,12 +452,12 @@ 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,
-       params_info: snd_pcm_shm_params_info,
-       params: snd_pcm_shm_params,
-       setup: snd_pcm_shm_setup,
+       hw_info: snd_pcm_shm_hw_info,
+       hw_params: snd_pcm_shm_hw_params,
+       sw_params: snd_pcm_shm_sw_params,
+       dig_info: snd_pcm_shm_dig_info,
+       dig_params: snd_pcm_shm_dig_params,
        channel_info: snd_pcm_shm_channel_info,
-       channel_params: snd_pcm_shm_channel_params,
-       channel_setup: snd_pcm_shm_channel_setup,
        dump: snd_pcm_shm_dump,
        nonblock: snd_pcm_shm_nonblock,
        async: snd_pcm_shm_async,
@@ -656,7 +616,7 @@ int snd_pcm_shm_open(snd_pcm_t **pcmp, char *name, char *socket, char *sname, in
        pcm->type = SND_PCM_TYPE_SHM;
        pcm->stream = stream;
        pcm->mode = mode;
-       pcm->mmap_auto = 1;
+       pcm->mmap_rw = 1;
        pcm->ops = &snd_pcm_shm_ops;
        pcm->op_arg = pcm;
        pcm->fast_ops = &snd_pcm_shm_fast_ops;
index 1abeadd12d469490ac85aa12506492fea18b36c6..7b374de4d1d3b72b5b82421f337f511c31d9d79d 100644 (file)
@@ -1,6 +1,8 @@
 EXTRA_LTLIBRARIES=librawmidi.la
 
-librawmidi_la_SOURCES = rawmidi.c
+librawmidi_la_SOURCES = rawmidi.c rawmidi_hw.c
+noinst_HEADERS = rawmidi_local.h
+
 all: librawmidi.la
 
 
index f18dc08782cbb7da3727792a50f169c40a667f26..3bebdff9d19bc1647848306274e6a684f08d945a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  RawMIDI Interface - main file
- *  Copyright (c) 1998 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
  *   it under the terms of the GNU Library General Public License as
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdarg.h>
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
+#include <dlfcn.h>
+#include "rawmidi_local.h"
 #include "asoundlib.h"
 
-#define SND_FILE_RAWMIDI       "/dev/snd/midiC%iD%i"
-#define SND_RAWMIDI_VERSION_MAX        SND_PROTOCOL_VERSION(2, 0, 0)
-
-struct snd_rawmidi {
-       int card;
-       int device;
-       int fd;
-       int mode;
-};
-
-int snd_rawmidi_open_subdevice(snd_rawmidi_t **handle, int card, int device, int subdevice, int mode)
-{
-       int fd, ver, ret;
-       int attempt = 0;
-       char filename[32];
-       snd_ctl_t *ctl;
-       snd_rawmidi_t *rmidi;
-       snd_rawmidi_info_t info;
-
-       *handle = NULL;
-       
-       if (card < 0 || card >= SND_CARDS)
-               return -EINVAL;
-
-       if ((ret = snd_ctl_hw_open(&ctl, NULL, card)) < 0)
-               return ret;
-       sprintf(filename, SND_FILE_RAWMIDI, card, device);
-
-      __again:
-       if (attempt++ > 3) {
-               snd_ctl_close(ctl);
-               return -EBUSY;
-       }
-       ret = snd_ctl_rawmidi_prefer_subdevice(ctl, subdevice);
-       if (ret < 0) {
-               snd_ctl_close(ctl);
-               return ret;
-       }
-       if ((fd = open(filename, mode)) < 0) {
-               snd_card_load(card);
-               if ((fd = open(filename, mode)) < 0) {
-                       snd_ctl_close(ctl);
-                       return -errno;
-               }
-       }
-       if (ioctl(fd, SND_RAWMIDI_IOCTL_PVERSION, &ver) < 0) {
-               ret = -errno;
-               close(fd);
-               snd_ctl_close(ctl);
-               return ret;
-       }
-       if (SND_PROTOCOL_INCOMPATIBLE(ver, SND_RAWMIDI_VERSION_MAX)) {
-               close(fd);
-               snd_ctl_close(ctl);
-               return -SND_ERROR_INCOMPATIBLE_VERSION;
-       }
-       if (subdevice >= 0) {
-               memset(&info, 0, sizeof(info));
-               if (ioctl(fd, SND_RAWMIDI_IOCTL_INFO, &info) < 0) {
-                       ret = -errno;
-                       close(fd);
-                       snd_ctl_close(ctl);
-                       return ret;
-               }
-               if (info.subdevice != subdevice) {
-                       close(fd);
-                       goto __again;
-               }
-       }
-       rmidi = (snd_rawmidi_t *) calloc(1, sizeof(snd_rawmidi_t));
-       if (rmidi == NULL) {
-               close(fd);
-               snd_ctl_close(ctl);
-               return -ENOMEM;
-       }
-       rmidi->card = card;
-       rmidi->device = device;
-       rmidi->fd = fd;
-       rmidi->mode = mode;
-       *handle = rmidi;
-       return 0;
-}
-
-int snd_rawmidi_open(snd_rawmidi_t **handle, int card, int device, int mode)
-{
-       return snd_rawmidi_open_subdevice(handle, card, device, -1, mode);
-}
-
 int snd_rawmidi_close(snd_rawmidi_t *rmidi)
 {
-       int res;
-
-       if (!rmidi)
-               return -EINVAL;
-       res = close(rmidi->fd) < 0 ? -errno : 0;
+       int err;
+       assert(rmidi);
+       if ((err = rmidi->ops->close(rmidi)) < 0)
+               return err;
+       if (rmidi->name)
+               free(rmidi->name);
        free(rmidi);
-       return res;
+       return 0;
 }
 
 int snd_rawmidi_poll_descriptor(snd_rawmidi_t *rmidi)
 {
-       if (!rmidi)
-               return -EINVAL;
-       return rmidi->fd;
+       assert(rmidi);
+       return rmidi->poll_fd;
 }
 
-int snd_rawmidi_block_mode(snd_rawmidi_t *rmidi, int enable)
+int snd_rawmidi_nonblock(snd_rawmidi_t *rmidi, int nonblock)
 {
-       long flags;
-
-       if (!rmidi)
-               return -EINVAL;
-       if (rmidi->mode == SND_RAWMIDI_OPEN_OUTPUT_APPEND ||
-           rmidi->mode == SND_RAWMIDI_OPEN_DUPLEX_APPEND)
-               return -EINVAL;
-       if ((flags = fcntl(rmidi->fd, F_GETFL)) < 0)
-               return -errno;
-       if (enable)
-               flags &= ~O_NONBLOCK;
+       int err;
+       assert(rmidi);
+       assert(!(rmidi->mode & SND_RAWMIDI_APPEND));
+       if ((err = rmidi->ops->nonblock(rmidi, nonblock)) < 0)
+               return err;
+       if (nonblock)
+               rmidi->mode |= SND_RAWMIDI_NONBLOCK;
        else
-               flags |= O_NONBLOCK;
-       if (fcntl(rmidi->fd, F_SETFL, flags) < 0)
-               return -errno;
+               rmidi->mode &= ~SND_RAWMIDI_NONBLOCK;
        return 0;
 }
 
 int snd_rawmidi_info(snd_rawmidi_t *rmidi, snd_rawmidi_info_t * info)
 {
-       if (!rmidi || !info)
-               return -EINVAL;
-       if (ioctl(rmidi->fd, SND_RAWMIDI_IOCTL_INFO, info) < 0)
-               return -errno;
-       return 0;
+       assert(rmidi && info);
+       return rmidi->ops->info(rmidi, info);
 }
 
 int snd_rawmidi_params(snd_rawmidi_t *rmidi, snd_rawmidi_params_t * params)
 {
-       if (!rmidi || !params)
-               return -EINVAL;
-       if (params->stream < 0 || params->stream > 1)
-               return -EINVAL;
-       if (ioctl(rmidi->fd, SND_RAWMIDI_IOCTL_PARAMS, params) < 0)
-               return -errno;
-       return 0;
+       assert(rmidi && params);
+       return rmidi->ops->params(rmidi, params);
 }
 
 int snd_rawmidi_status(snd_rawmidi_t *rmidi, snd_rawmidi_status_t * status)
 {
-       if (!rmidi || !status)
-               return -EINVAL;
-       if (status->stream < 0 || status->stream > 1)
-               return -EINVAL;
-       if (ioctl(rmidi->fd, SND_RAWMIDI_IOCTL_STATUS, status) < 0)
-               return -errno;
-       return 0;
+       assert(rmidi && status);
+       return rmidi->ops->status(rmidi, status);
+}
+
+int snd_rawmidi_drop(snd_rawmidi_t *rmidi, int str)
+{
+       assert(rmidi);
+       assert(str >= 0 && str <= 1);
+       assert(rmidi->streams & (1 << str));
+       return rmidi->ops->drop(rmidi, str);
 }
 
 int snd_rawmidi_output_drop(snd_rawmidi_t *rmidi)
 {
-       int str = SND_RAWMIDI_STREAM_OUTPUT;
-       if (!rmidi)
-               return -EINVAL;
-       if (ioctl(rmidi->fd, SND_RAWMIDI_IOCTL_DROP, &str) < 0)
-               return -errno;
-       return 0;
+       return snd_rawmidi_drop(rmidi, SND_RAWMIDI_STREAM_OUTPUT);
 }
 
-int snd_rawmidi_stream_drain(snd_rawmidi_t *rmidi, int str)
+int snd_rawmidi_drain(snd_rawmidi_t *rmidi, int str)
 {
-       if (!rmidi)
-               return -EINVAL;
-       if (str < 0 || str > 1)
-               return -EINVAL;
-       if (ioctl(rmidi->fd, SND_RAWMIDI_IOCTL_DRAIN, &str) < 0)
-               return -errno;
-       return 0;
+       assert(rmidi);
+       assert(str >= 0 && str <= 1);
+       assert(rmidi->streams & (1 << str));
+       return rmidi->ops->drain(rmidi, str);
 }
 
 int snd_rawmidi_output_drain(snd_rawmidi_t *rmidi)
 {
-       return snd_rawmidi_stream_drain(rmidi, SND_RAWMIDI_STREAM_OUTPUT);
+       return snd_rawmidi_drain(rmidi, SND_RAWMIDI_STREAM_OUTPUT);
 }
 
 int snd_rawmidi_input_drain(snd_rawmidi_t *rmidi)
 {
-       return snd_rawmidi_stream_drain(rmidi, SND_RAWMIDI_STREAM_INPUT);
+       return snd_rawmidi_drain(rmidi, SND_RAWMIDI_STREAM_INPUT);
 }
 
 ssize_t snd_rawmidi_write(snd_rawmidi_t *rmidi, const void *buffer, size_t size)
 {
-       ssize_t result;
-
-       if (!rmidi || (!buffer && size > 0))
-               return -EINVAL;
-       result = write(rmidi->fd, buffer, size);
-       if (result < 0)
-               return -errno;
-       return result;
+       assert(rmidi && (buffer || size == 0));
+       return rmidi->ops->write(rmidi, buffer, size);
 }
 
 ssize_t snd_rawmidi_read(snd_rawmidi_t *rmidi, void *buffer, size_t size)
 {
-       ssize_t result;
+       assert(rmidi && (buffer || size == 0));
+       return rmidi->ops->read(rmidi, buffer, size);
+}
 
-       if (!rmidi || (!buffer && size > 0))
+int snd_rawmidi_open(snd_rawmidi_t **rawmidip, char *name, 
+                    int streams, int mode)
+{
+       char *str;
+       int err;
+       snd_config_t *rawmidi_conf, *conf, *type_conf;
+       snd_config_iterator_t i;
+       char *lib = NULL, *open = NULL;
+       int (*open_func)(snd_rawmidi_t **rawmidip, char *name, snd_config_t *conf, 
+                        int streams, int mode);
+       void *h;
+       assert(rawmidip && name);
+       err = snd_config_update();
+       if (err < 0)
+               return err;
+       err = snd_config_searchv(snd_config, &rawmidi_conf, "rawmidi", name, 0);
+       if (err < 0) {
+               int card, dev, subdev;
+               err = sscanf(name, "hw:%d,%d,%d", &card, &dev, &subdev);
+               if (err == 3)
+                       return snd_rawmidi_hw_open(rawmidip, name, card, dev, subdev, streams, mode);
+               err = sscanf(name, "hw:%d,%d", &card, &dev);
+               if (err == 2)
+                       return snd_rawmidi_hw_open(rawmidip, name, card, dev, -1, streams, mode);
+               ERR("Unknown RAWMIDI %s", name);
+               return -ENOENT;
+       }
+       if (snd_config_type(rawmidi_conf) != SND_CONFIG_TYPE_COMPOUND) {
+               ERR("Invalid type for RAWMIDI definition");
+               return -EINVAL;
+       }
+       err = snd_config_search(rawmidi_conf, "streams", &conf);
+       if (err >= 0) {
+               err = snd_config_string_get(conf, &str);
+               if (err < 0) {
+                       ERR("Invalid type for streams");
+                       return err;
+               }
+               if (strcmp(str, "output") == 0) {
+                       if (streams == SND_RAWMIDI_OPEN_INPUT)
+                               return -EINVAL;
+               } else if (strcmp(str, "input") == 0) {
+                       if (streams == SND_RAWMIDI_OPEN_OUTPUT)
+                               return -EINVAL;
+               } else if (strcmp(str, "duplex") == 0) {
+                       if (streams != SND_RAWMIDI_OPEN_DUPLEX)
+                               return -EINVAL;
+               } else {
+                       ERR("Invalid value for streams");
+                       return -EINVAL;
+               }
+       }
+       err = snd_config_search(rawmidi_conf, "type", &conf);
+       if (err < 0) {
+               ERR("type is not defined");
+               return err;
+       }
+       err = snd_config_string_get(conf, &str);
+       if (err < 0) {
+               ERR("Invalid type for type");
+               return err;
+       }
+       err = snd_config_searchv(snd_config, &type_conf, "rawmiditype", str, 0);
+       if (err < 0) {
+               ERR("Unknown RAWMIDI type %s", str);
+               return err;
+       }
+       snd_config_foreach(i, type_conf) {
+               snd_config_t *n = snd_config_entry(i);
+               if (strcmp(n->id, "comment") == 0)
+                       continue;
+               if (strcmp(n->id, "lib") == 0) {
+                       err = snd_config_string_get(n, &lib);
+                       if (err < 0) {
+                               ERR("Invalid type for lib");
+                               return -EINVAL;
+                       }
+                       continue;
+               }
+               if (strcmp(n->id, "open") == 0) {
+                       err = snd_config_string_get(n, &open);
+                       if (err < 0) {
+                               ERR("Invalid type for open");
+                               return -EINVAL;
+                       }
+                       continue;
+                       ERR("Unknown field: %s", n->id);
+                       return -EINVAL;
+               }
+       }
+       if (!open) {
+               ERR("open is not defined");
                return -EINVAL;
-       result = read(rmidi->fd, buffer, size);
-       if (result < 0)
-               return -errno;
-       return result;
+       }
+       if (!lib)
+               lib = "libasound.so";
+       h = dlopen(lib, RTLD_NOW);
+       if (!h) {
+               ERR("Cannot open shared library %s", lib);
+               return -ENOENT;
+       }
+       open_func = dlsym(h, open);
+       dlclose(h);
+       if (!open_func) {
+               ERR("symbol %s is not defined inside %s", open, lib);
+               return -ENXIO;
+       }
+       return open_func(rawmidip, name, rawmidi_conf, streams, mode);
 }
+
diff --git a/src/rawmidi/rawmidi_hw.c b/src/rawmidi/rawmidi_hw.c
new file mode 100644 (file)
index 0000000..4ebe70a
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ *  RawMIDI - Hardware
+ *  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
+ *   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>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "../control/control_local.h"
+#include "rawmidi_local.h"
+#include "asoundlib.h"
+
+#define SND_FILE_RAWMIDI       "/dev/snd/midiC%iD%i"
+#define SND_RAWMIDI_VERSION_MAX        SND_PROTOCOL_VERSION(2, 0, 0)
+
+typedef struct {
+       int fd;
+       int card, device, subdevice;
+} snd_rawmidi_hw_t;
+
+static int snd_rawmidi_hw_close(snd_rawmidi_t *rmidi)
+{
+       snd_rawmidi_hw_t *hw = rmidi->private;
+       if (close(hw->fd)) {
+               SYSERR("close failed\n");
+               return -errno;
+       }
+       free(hw);
+       return 0;
+}
+
+static int snd_rawmidi_hw_nonblock(snd_rawmidi_t *rmidi, int nonblock)
+{
+       snd_rawmidi_hw_t *hw = rmidi->private;
+       long flags;
+
+       if ((flags = fcntl(hw->fd, F_GETFL)) < 0) {
+               SYSERR("F_GETFL failed");
+               return -errno;
+       }
+       if (nonblock)
+               flags &= ~O_NONBLOCK;
+       else
+               flags |= O_NONBLOCK;
+       if (fcntl(hw->fd, F_SETFL, flags) < 0) {
+               SYSERR("F_SETFL for O_NONBLOCK failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_rawmidi_hw_info(snd_rawmidi_t *rmidi, snd_rawmidi_info_t * info)
+{
+       snd_rawmidi_hw_t *hw = rmidi->private;
+       if (ioctl(hw->fd, SND_RAWMIDI_IOCTL_INFO, info) < 0) {
+               SYSERR("SND_RAWMIDI_IOCTL_INFO failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_rawmidi_hw_params(snd_rawmidi_t *rmidi, snd_rawmidi_params_t * params)
+{
+       snd_rawmidi_hw_t *hw = rmidi->private;
+       if (ioctl(hw->fd, SND_RAWMIDI_IOCTL_PARAMS, params) < 0) {
+               SYSERR("SND_RAWMIDI_IOCTL_PARAMS failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_rawmidi_hw_status(snd_rawmidi_t *rmidi, snd_rawmidi_status_t * status)
+{
+       snd_rawmidi_hw_t *hw = rmidi->private;
+       if (ioctl(hw->fd, SND_RAWMIDI_IOCTL_STATUS, status) < 0) {
+               SYSERR("SND_RAWMIDI_IOCTL_STATUS failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_rawmidi_hw_drop(snd_rawmidi_t *rmidi, int stream)
+{
+       snd_rawmidi_hw_t *hw = rmidi->private;
+       if (ioctl(hw->fd, SND_RAWMIDI_IOCTL_DROP, &stream) < 0) {
+               SYSERR("SND_RAWMIDI_IOCTL_DROP failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_rawmidi_hw_drain(snd_rawmidi_t *rmidi, int stream)
+{
+       snd_rawmidi_hw_t *hw = rmidi->private;
+       if (ioctl(hw->fd, SND_RAWMIDI_IOCTL_DRAIN, &stream) < 0) {
+               SYSERR("SND_RAWMIDI_IOCTL_DRAIN failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static ssize_t snd_rawmidi_hw_write(snd_rawmidi_t *rmidi, const void *buffer, size_t size)
+{
+       snd_rawmidi_hw_t *hw = rmidi->private;
+       ssize_t result;
+       result = write(hw->fd, buffer, size);
+       if (result < 0)
+               return -errno;
+       return result;
+}
+
+static ssize_t snd_rawmidi_hw_read(snd_rawmidi_t *rmidi, void *buffer, size_t size)
+{
+       snd_rawmidi_hw_t *hw = rmidi->private;
+       ssize_t result;
+       result = read(hw->fd, buffer, size);
+       if (result < 0)
+               return -errno;
+       return result;
+}
+
+snd_rawmidi_ops_t snd_rawmidi_hw_ops = {
+       close: snd_rawmidi_hw_close,
+       nonblock: snd_rawmidi_hw_nonblock,
+       info: snd_rawmidi_hw_info,
+       params: snd_rawmidi_hw_params,
+       status: snd_rawmidi_hw_status,
+       drop: snd_rawmidi_hw_drop,
+       drain: snd_rawmidi_hw_drain,
+       write: snd_rawmidi_hw_write,
+       read: snd_rawmidi_hw_read,
+};
+
+
+int snd_rawmidi_hw_open(snd_rawmidi_t **handlep, char *name, int card, int device, int subdevice, int streams, int mode)
+{
+       int fd, ver, ret;
+       int attempt = 0;
+       char filename[32];
+       snd_ctl_t *ctl;
+       snd_rawmidi_t *rmidi;
+       snd_rawmidi_hw_t *hw;
+       snd_rawmidi_info_t info;
+       int fmode;
+
+       *handlep = NULL;
+       
+       assert(card >= 0 && card < SND_CARDS);
+
+       if ((ret = snd_ctl_hw_open(&ctl, NULL, card)) < 0)
+               return ret;
+       sprintf(filename, SND_FILE_RAWMIDI, card, device);
+
+      __again:
+       if (attempt++ > 3) {
+               snd_ctl_close(ctl);
+               return -EBUSY;
+       }
+       ret = snd_ctl_rawmidi_prefer_subdevice(ctl, subdevice);
+       if (ret < 0) {
+               snd_ctl_close(ctl);
+               return ret;
+       }
+
+       switch (streams) {
+       case SND_RAWMIDI_OPEN_OUTPUT:
+               fmode = O_WRONLY;
+               break;
+       case SND_RAWMIDI_OPEN_INPUT:
+               fmode = O_RDONLY;
+               break;
+       case SND_RAWMIDI_OPEN_DUPLEX:
+               fmode = O_RDWR;
+               break;
+       default:
+               assert(0);
+               return -EINVAL;
+       }
+
+       if (mode & SND_RAWMIDI_APPEND) {
+               assert(streams & SND_RAWMIDI_OPEN_OUTPUT);
+               fmode |= O_APPEND;
+       }
+
+       if (mode & SND_RAWMIDI_NONBLOCK) {
+               fmode |= O_NONBLOCK;
+       }
+
+       assert(!(mode & ~(SND_RAWMIDI_APPEND|SND_RAWMIDI_NONBLOCK)));
+
+       if ((fd = open(filename, fmode)) < 0) {
+               snd_card_load(card);
+               if ((fd = open(filename, fmode)) < 0) {
+                       snd_ctl_close(ctl);
+                       SYSERR("open %s failed", filename);
+                       return -errno;
+               }
+       }
+       if (ioctl(fd, SND_RAWMIDI_IOCTL_PVERSION, &ver) < 0) {
+               ret = -errno;
+               SYSERR("SND_RAWMIDI_IOCTL_PVERSION failed");
+               close(fd);
+               snd_ctl_close(ctl);
+               return ret;
+       }
+       if (SND_PROTOCOL_INCOMPATIBLE(ver, SND_RAWMIDI_VERSION_MAX)) {
+               close(fd);
+               snd_ctl_close(ctl);
+               return -SND_ERROR_INCOMPATIBLE_VERSION;
+       }
+       if (subdevice >= 0) {
+               memset(&info, 0, sizeof(info));
+               if (ioctl(fd, SND_RAWMIDI_IOCTL_INFO, &info) < 0) {
+                       SYSERR("SND_RAWMIDI_IOCTL_INFO failed");
+                       ret = -errno;
+                       close(fd);
+                       snd_ctl_close(ctl);
+                       return ret;
+               }
+               if (info.subdevice != subdevice) {
+                       close(fd);
+                       goto __again;
+               }
+       }
+       hw = calloc(1, sizeof(snd_rawmidi_hw_t));
+       if (hw == NULL) {
+               close(fd);
+               snd_ctl_close(ctl);
+               return -ENOMEM;
+       }
+       rmidi = calloc(1, sizeof(snd_rawmidi_t));
+       if (rmidi == NULL) {
+               free(hw);
+               close(fd);
+               snd_ctl_close(ctl);
+               return -ENOMEM;
+       }
+       hw->card = card;
+       hw->device = device;
+       hw->subdevice = subdevice;
+       hw->fd = fd;
+       if (name)
+               rmidi->name = strdup(name);
+       rmidi->type = SND_RAWMIDI_TYPE_HW;
+       rmidi->streams = streams;
+       rmidi->mode = mode;
+       rmidi->poll_fd = fd;
+       rmidi->ops = &snd_rawmidi_hw_ops;
+       rmidi->private = hw;
+       *handlep = rmidi;
+       return 0;
+}
+
+int _snd_rawmidi_hw_open(snd_rawmidi_t **handlep, char *name, snd_config_t *conf,
+                        int streams, int mode)
+{
+       snd_config_iterator_t i;
+       long card = -1, device = 0, subdevice = -1;
+       char *str;
+       int err;
+       snd_config_foreach(i, conf) {
+               snd_config_t *n = snd_config_entry(i);
+               if (strcmp(n->id, "comment") == 0)
+                       continue;
+               if (strcmp(n->id, "type") == 0)
+                       continue;
+               if (strcmp(n->id, "streams") == 0)
+                       continue;
+               if (strcmp(n->id, "card") == 0) {
+                       err = snd_config_integer_get(n, &card);
+                       if (err < 0) {
+                               err = snd_config_string_get(n, &str);
+                               if (err < 0)
+                                       return -EINVAL;
+                               card = snd_card_get_index(str);
+                               if (card < 0)
+                                       return card;
+                       }
+                       continue;
+               }
+               if (strcmp(n->id, "device") == 0) {
+                       err = snd_config_integer_get(n, &device);
+                       if (err < 0)
+                               return err;
+                       continue;
+               }
+               if (strcmp(n->id, "subdevice") == 0) {
+                       err = snd_config_integer_get(n, &subdevice);
+                       if (err < 0)
+                               return err;
+                       continue;
+               }
+               return -EINVAL;
+       }
+       if (card < 0)
+               return -EINVAL;
+       return snd_rawmidi_hw_open(handlep, name, card, device, subdevice, streams, mode);
+}
+                               
diff --git a/src/rawmidi/rawmidi_local.h b/src/rawmidi/rawmidi_local.h
new file mode 100644 (file)
index 0000000..81b303d
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ *  Rawmidi interface - local header file
+ *  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 <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include "asoundlib.h"
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
+#define ERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, __VA_ARGS__)
+#define SYSERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, __VA_ARGS__)
+#else
+#define ERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, ##args)
+#define SYSERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, ##args)
+#endif
+
+typedef struct {
+       int (*close)(snd_rawmidi_t *rawmidi);
+       int (*nonblock)(snd_rawmidi_t *rawmidi, int nonblock);
+       int (*info)(snd_rawmidi_t *rawmidi, snd_rawmidi_info_t *info);
+       int (*params)(snd_rawmidi_t *rawmidi, snd_rawmidi_params_t *params);
+       int (*status)(snd_rawmidi_t *rawmidi, snd_rawmidi_status_t *status);
+       int (*drop)(snd_rawmidi_t *rawmidi, int stream);
+       int (*drain)(snd_rawmidi_t *rawmidi, int stream);
+       ssize_t (*write)(snd_rawmidi_t *rawmidi, const void *buffer, size_t size);
+       ssize_t (*read)(snd_rawmidi_t *rawmidi, void *buffer, size_t size);
+} snd_rawmidi_ops_t;
+
+struct _snd_rawmidi {
+       char *name;
+       snd_rawmidi_type_t type;
+       int streams;
+       int mode;
+       int poll_fd;
+       snd_rawmidi_ops_t *ops;
+       void *private;
+};
+
+int snd_rawmidi_hw_open(snd_rawmidi_t **handle, char *name, int card, int device, int subdevice, int streams, int mode);
+
index 637dfec81f20d79629771f589de9c75b6d84d35c..530820e06734c013a91c5c4f7bc7550facdf42ef 100644 (file)
@@ -1,7 +1,7 @@
 EXTRA_LTLIBRARIES=libseq.la
 
-libseq_la_SOURCES = seq.c seqmid.c
-noinst_HEADERS = seq_priv.h
+libseq_la_SOURCES = seq_hw.c seq.c seqmid.c
+noinst_HEADERS = seq_local.h
 
 all: libseq.la
 
index c0774d21b8c34e91a5dda7d6e609934393651ec7..ab4f269f7af3a20a9b9787685e7e508ce068330a 100644 (file)
@@ -1,6 +1,7 @@
 /*
  *  Sequencer Interface - main file
- *  Copyright (c) 1998 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
  *
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
+#include <sys/poll.h>
+#include <dlfcn.h>
+#include "seq_local.h"
 #include "asoundlib.h"
-#include "seq_priv.h"
 
-#define SND_FILE_SEQ           "/dev/snd/seq"
-#define SND_FILE_ALOADSEQ      "/dev/aloadSEQ"
-#define SND_SEQ_VERSION_MAX    SND_PROTOCOL_VERSION(1, 0, 0)
-#define SND_SEQ_OBUF_SIZE      (16*1024)       /* default size */
-#define SND_SEQ_IBUF_SIZE      500             /* in event_size aligned */
-#define DEFAULT_TMPBUF_SIZE    20
-
-/*
- * open a sequencer device so that it creates a user-client.
- */
-int snd_seq_open(snd_seq_t **handle, int mode)
+int snd_seq_open(snd_seq_t **seqp, char *name, 
+                int streams, int mode)
 {
-       int fd, ver, client, flg;
-       char filename[32];
-       snd_seq_t *seq;
-
-       *handle = NULL;
-
-       sprintf(filename, SND_FILE_SEQ);
-       if ((fd = open(filename, mode)) < 0) {
-               close(open(SND_FILE_ALOADSEQ, O_RDWR));
-               if ((fd = open(filename, mode)) < 0)
-                       return -errno;
+       char *str;
+       int err;
+       snd_config_t *seq_conf, *conf, *type_conf;
+       snd_config_iterator_t i;
+       char *lib = NULL, *open = NULL;
+       int (*open_func)(snd_seq_t **seqp, char *name, snd_config_t *conf, 
+                        int streams, int mode);
+       void *h;
+       assert(seqp && name);
+       err = snd_config_update();
+       if (err < 0)
+               return err;
+       err = snd_config_searchv(snd_config, &seq_conf, "seq", name, 0);
+       if (err < 0) {
+               if (strcmp(name, "hw") == 0)
+                       return snd_seq_hw_open(seqp, name, streams, mode);
+               ERR("Unknown SEQ %s", name);
+               return -ENOENT;
        }
-       if (ioctl(fd, SND_SEQ_IOCTL_PVERSION, &ver) < 0) {
-               close(fd);
-               return -errno;
+       if (snd_config_type(seq_conf) != SND_CONFIG_TYPE_COMPOUND) {
+               ERR("Invalid type for SEQ definition");
+               return -EINVAL;
+       }
+       err = snd_config_search(seq_conf, "streams", &conf);
+       if (err >= 0) {
+               err = snd_config_string_get(conf, &str);
+               if (err < 0) {
+                       ERR("Invalid type for streams");
+                       return err;
+               }
+               if (strcmp(str, "output") == 0) {
+                       if (streams == SND_SEQ_OPEN_INPUT)
+                               return -EINVAL;
+               } else if (strcmp(str, "input") == 0) {
+                       if (streams == SND_SEQ_OPEN_OUTPUT)
+                               return -EINVAL;
+               } else if (strcmp(str, "duplex") == 0) {
+                       if (streams != SND_SEQ_OPEN_DUPLEX)
+                               return -EINVAL;
+               } else {
+                       ERR("Invalid value for streams");
+                       return -EINVAL;
+               }
        }
-       if (SND_PROTOCOL_INCOMPATIBLE(ver, SND_SEQ_VERSION_MAX)) {
-               close(fd);
-               return -SND_ERROR_INCOMPATIBLE_VERSION;
+       err = snd_config_search(seq_conf, "type", &conf);
+       if (err < 0) {
+               ERR("type is not defined");
+               return err;
        }
-       if (ioctl(fd, SND_SEQ_IOCTL_CLIENT_ID, &client) < 0) {
-               close(fd);
-               return -errno;
+       err = snd_config_string_get(conf, &str);
+       if (err < 0) {
+               ERR("Invalid type for type");
+               return err;
        }
-       seq = (snd_seq_t *) calloc(1, sizeof(snd_seq_t));
-       if (seq == NULL) {
-               close(fd);
-               return -ENOMEM;
+       err = snd_config_searchv(snd_config, &type_conf, "seqtype", str, 0);
+       if (err < 0) {
+               ERR("Unknown SEQ type %s", str);
+               return err;
        }
-       seq->client = client;
-       seq->fd = fd;
-       flg = 3;
-       if (mode == SND_SEQ_OPEN_OUT || mode == SND_SEQ_OPEN)
-               seq->obuf = (char *) malloc(seq->obufsize = SND_SEQ_OBUF_SIZE);
-       else
-               flg &= ~1;
-       if (mode == SND_SEQ_OPEN_IN || mode == SND_SEQ_OPEN)
-               seq->ibuf = (snd_seq_event_t *) calloc(sizeof(snd_seq_event_t), seq->ibufsize = SND_SEQ_IBUF_SIZE);
-       else
-               flg &= ~2;
-       if ((!seq->obuf && (flg & 1)) || (!seq->ibuf && (flg & 2))) {
-               if (seq->obuf)
-                       free(seq->obuf);
-               if (seq->ibuf)
-                       free(seq->ibuf);
-               free(seq);
-               return -ENOMEM;
+       snd_config_foreach(i, type_conf) {
+               snd_config_t *n = snd_config_entry(i);
+               if (strcmp(n->id, "comment") == 0)
+                       continue;
+               if (strcmp(n->id, "lib") == 0) {
+                       err = snd_config_string_get(n, &lib);
+                       if (err < 0) {
+                               ERR("Invalid type for lib");
+                               return -EINVAL;
+                       }
+                       continue;
+               }
+               if (strcmp(n->id, "open") == 0) {
+                       err = snd_config_string_get(n, &open);
+                       if (err < 0) {
+                               ERR("Invalid type for open");
+                               return -EINVAL;
+                       }
+                       continue;
+                       ERR("Unknown field: %s", n->id);
+                       return -EINVAL;
+               }
        }
-       seq->tmpbuf = NULL;
-       seq->tmpbufsize = 0;
-       *handle = seq;
-       return 0;
+       if (!open) {
+               ERR("open is not defined");
+               return -EINVAL;
+       }
+       if (!lib)
+               lib = "libasound.so";
+       h = dlopen(lib, RTLD_NOW);
+       if (!h) {
+               ERR("Cannot open shared library %s", lib);
+               return -ENOENT;
+       }
+       open_func = dlsym(h, open);
+       dlclose(h);
+       if (!open_func) {
+               ERR("symbol %s is not defined inside %s", open, lib);
+               return -ENXIO;
+       }
+       return open_func(seqp, name, seq_conf, streams, mode);
 }
 
 /*
@@ -101,19 +135,21 @@ int snd_seq_open(snd_seq_t **handle, int mode)
  */
 int snd_seq_close(snd_seq_t *seq)
 {
-       int res;
-
-       if (!seq)
-               return -EINVAL;
-       res = close(seq->fd) < 0 ? -errno : 0;
+       int err;
+       assert(seq);
+       err = seq->ops->close(seq);
+       if (err < 0)
+               return err;
        if (seq->obuf)
                free(seq->obuf);
        if (seq->ibuf)
                free(seq->ibuf);
        if (seq->tmpbuf)
                free(seq->tmpbuf);
+       if (seq->name)
+               free(seq->name);
        free(seq);
-       return res;
+       return 0;
 }
 
 /*
@@ -121,28 +157,24 @@ int snd_seq_close(snd_seq_t *seq)
  */
 int snd_seq_poll_descriptor(snd_seq_t *seq)
 {
-       if (!seq)
-               return -EINVAL;
-       return seq->fd;
+       assert(seq);
+       return seq->poll_fd;
 }
 
 /*
  * set blocking behavior
  */
-int snd_seq_block_mode(snd_seq_t *seq, int enable)
+int snd_seq_nonblock(snd_seq_t *seq, int nonblock)
 {
-       long flags;
-
-       if (!seq)
-               return -EINVAL;
-       if ((flags = fcntl(seq->fd, F_GETFL)) < 0)
-               return -errno;
-       if (enable)
-               flags &= ~O_NONBLOCK;
+       int err;
+       assert(seq);
+       err = seq->ops->nonblock(seq, nonblock);
+       if (err < 0)
+               return err;
+       if (nonblock)
+               seq->mode |= SND_SEQ_NONBLOCK;
        else
-               flags |= O_NONBLOCK;
-       if (fcntl(seq->fd, F_SETFL, flags) < 0)
-               return -errno;
+               seq->mode &= ~SND_SEQ_NONBLOCK;
        return 0;
 }
 
@@ -151,8 +183,7 @@ int snd_seq_block_mode(snd_seq_t *seq, int enable)
  */
 int snd_seq_client_id(snd_seq_t *seq)
 {
-       if (!seq)
-               return -EINVAL;
+       assert(seq);
        return seq->client;
 }
 
@@ -161,8 +192,7 @@ int snd_seq_client_id(snd_seq_t *seq)
  */
 int snd_seq_output_buffer_size(snd_seq_t *seq)
 {
-       if (!seq)
-               return -EINVAL;
+       assert(seq);
        if (!seq->obuf)
                return 0;
        return seq->obufsize;
@@ -173,8 +203,7 @@ int snd_seq_output_buffer_size(snd_seq_t *seq)
  */
 int snd_seq_input_buffer_size(snd_seq_t *seq)
 {
-       if (!seq)
-               return -EINVAL;
+       assert(seq);
        if (!seq->ibuf)
                return 0;
        return seq->ibufsize * sizeof(snd_seq_event_t);
@@ -185,10 +214,8 @@ int snd_seq_input_buffer_size(snd_seq_t *seq)
  */
 int snd_seq_resize_output_buffer(snd_seq_t *seq, size_t size)
 {
-       if (!seq || !seq->obuf)
-               return -EINVAL;
-       if (size < sizeof(snd_seq_event_t))
-               return -EINVAL;
+       assert(seq && seq->obuf);
+       assert(size >= sizeof(snd_seq_event_t));
        snd_seq_drop_output(seq);
        if (size != seq->obufsize) {
                char *newbuf;
@@ -207,10 +234,8 @@ int snd_seq_resize_output_buffer(snd_seq_t *seq, size_t size)
  */
 int snd_seq_resize_input_buffer(snd_seq_t *seq, size_t size)
 {
-       if (!seq || !seq->ibuf)
-               return -EINVAL;
-       if (size < sizeof(snd_seq_event_t))
-               return -EINVAL;
+       assert(seq && seq->ibuf);
+       assert(size >= sizeof(snd_seq_event_t));
        snd_seq_drop_input(seq);
        size = (size + sizeof(snd_seq_event_t) - 1) / sizeof(snd_seq_event_t);
        if (size != seq->ibufsize) {
@@ -230,35 +255,27 @@ int snd_seq_resize_input_buffer(snd_seq_t *seq, size_t size)
  */
 int snd_seq_system_info(snd_seq_t *seq, snd_seq_system_info_t * info)
 {
-       if (!seq || !info)
-               return -EINVAL;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_SYSTEM_INFO, info) < 0)
-               return -errno;
-       return 0;
+       assert(seq && info);
+       return seq->ops->system_info(seq, info);
 }
 
 /*
- * obtain the current client information
+ * obtain the information of given client
  */
-int snd_seq_get_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
+int snd_seq_get_any_client_info(snd_seq_t *seq, int client, snd_seq_client_info_t * info)
 {
-       if (!seq || !info)
-               return -EINVAL;
-       return snd_seq_get_any_client_info(seq, seq->client, info);
+       assert(seq && info && client >= 0);
+       memset(info, 0, sizeof(snd_seq_client_info_t));
+       info->client = client;
+       return seq->ops->get_client_info(seq, info);
 }
 
 /*
- * obtain the information of given client
+ * obtain the current client information
  */
-int snd_seq_get_any_client_info(snd_seq_t *seq, int client, snd_seq_client_info_t * info)
+int snd_seq_get_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
 {
-       if (!seq || !info || client < 0)
-               return -EINVAL;
-       bzero(info, sizeof(snd_seq_client_info_t));
-       info->client = client;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_CLIENT_INFO, info) < 0)
-               return -errno;
-       return 0;
+       return snd_seq_get_any_client_info(seq, seq->client, info);
 }
 
 /*
@@ -266,13 +283,10 @@ int snd_seq_get_any_client_info(snd_seq_t *seq, int client, snd_seq_client_info_
  */
 int snd_seq_set_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
 {
-       if (!seq || !info)
-               return -EINVAL;
+       assert(seq && info);
        info->client = seq->client;
        info->type = USER_CLIENT;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_SET_CLIENT_INFO, info) < 0)
-               return -errno;
-       return 0;
+       return seq->ops->set_client_info(seq, info);
 }
 
 /*----------------------------------------------------------------*/
@@ -283,51 +297,37 @@ int snd_seq_set_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
 
 int snd_seq_create_port(snd_seq_t *seq, snd_seq_port_info_t * port)
 {
-       if (!seq || !port)
-               return -EINVAL;
+       assert(seq && port);
        port->client = seq->client;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_CREATE_PORT, port) < 0)
-               return -errno;
-       return 0;
+       return seq->ops->create_port(seq, port);
 }
 
 int snd_seq_delete_port(snd_seq_t *seq, snd_seq_port_info_t * port)
 {
-       if (!seq || !port)
-               return -EINVAL;
+       assert(seq && port);
        port->client = seq->client;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_DELETE_PORT, port) < 0)
-               return -errno;
-       return 0;
-}
-
-int snd_seq_get_port_info(snd_seq_t *seq, int port, snd_seq_port_info_t * info)
-{
-       if (!seq || !info || port < 0)
-               return -EINVAL;
-       return snd_seq_get_any_port_info(seq, seq->client, port, info);
+       return seq->ops->delete_port(seq, port);
 }
 
 int snd_seq_get_any_port_info(snd_seq_t *seq, int client, int port, snd_seq_port_info_t * info)
 {
-       if (!seq || !info || client < 0 || port < 0)
-               return -EINVAL;
-       bzero(info, sizeof(snd_seq_port_info_t));
+       assert(seq && info && client >= 0 && port >= 0);
+       memset(info, 0, sizeof(snd_seq_port_info_t));
        info->client = client;
        info->port = port;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_PORT_INFO, info) < 0)
-               return -errno;
-       return 0;
+       return seq->ops->get_port_info(seq, info);
+}
+
+int snd_seq_get_port_info(snd_seq_t *seq, int port, snd_seq_port_info_t * info)
+{
+       return snd_seq_get_any_port_info(seq, seq->client, port, info);
 }
 
 int snd_seq_set_port_info(snd_seq_t *seq, int port, snd_seq_port_info_t * info)
 {
-       if (!seq || !info || port < 0)
-               return -EINVAL;
+       assert(seq && info && port >= 0);
        info->port = port;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_SET_PORT_INFO, info) < 0)
-               return -errno;
-       return 0;
+       return seq->ops->set_port_info(seq, info);
 }
 
 /*----------------------------------------------------------------*/
@@ -338,38 +338,26 @@ int snd_seq_set_port_info(snd_seq_t *seq, int port, snd_seq_port_info_t * info)
 
 int snd_seq_get_port_subscription(snd_seq_t *seq, snd_seq_port_subscribe_t * sub)
 {
-       if (!seq || !sub)
-               return -EINVAL;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_SUBSCRIPTION, sub) < 0)
-               return -errno;
-       return 0;
+       assert(seq && sub);
+       return seq->ops->get_port_subscription(seq, sub);
 }
 
 int snd_seq_subscribe_port(snd_seq_t *seq, snd_seq_port_subscribe_t * sub)
 {
-       if (!seq || !sub)
-               return -EINVAL;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_SUBSCRIBE_PORT, sub) < 0)
-               return -errno;
-       return 0;
+       assert(seq && sub);
+       return seq->ops->subscribe_port(seq, sub);
 }
 
 int snd_seq_unsubscribe_port(snd_seq_t *seq, snd_seq_port_subscribe_t * sub)
 {
-       if (!seq || !sub)
-               return -EINVAL;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_UNSUBSCRIBE_PORT, sub) < 0)
-               return -errno;
-       return 0;
+       assert(seq && sub);
+       return seq->ops->unsubscribe_port(seq, sub);
 }
 
 int snd_seq_query_port_subscribers(snd_seq_t *seq, snd_seq_query_subs_t * subs)
 {
-       if (!seq || !subs)
-               return -EINVAL;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_QUERY_SUBS, subs) < 0)
-               return -errno;
-       return 0;
+       assert(seq && subs);
+       return seq->ops->query_port_subscribers(seq, subs);
 }
 
 /*----------------------------------------------------------------*/
@@ -380,118 +368,88 @@ int snd_seq_query_port_subscribers(snd_seq_t *seq, snd_seq_query_subs_t * subs)
 
 int snd_seq_get_queue_status(snd_seq_t *seq, int q, snd_seq_queue_status_t * status)
 {
-       if (!seq || !status)
-               return -EINVAL;
-       bzero(status, sizeof(snd_seq_queue_status_t));
+       assert(seq && status);
+       memset(status, 0, sizeof(snd_seq_queue_status_t));
        status->queue = q;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_QUEUE_STATUS, status) < 0)
-               return -errno;
-       return 0;
+       return seq->ops->get_queue_status(seq, status);
 }
 
 int snd_seq_get_queue_tempo(snd_seq_t *seq, int q, snd_seq_queue_tempo_t * tempo)
 {
-       if (!seq || !tempo)
-               return -EINVAL;
-       bzero(tempo, sizeof(snd_seq_queue_tempo_t));
+       assert(seq && tempo);
+       memset(tempo, 0, sizeof(snd_seq_queue_tempo_t));
        tempo->queue = q;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_QUEUE_TEMPO, tempo) < 0)
-               return -errno;
-       return 0;
+       return seq->ops->get_queue_tempo(seq, tempo);
 }
 
 int snd_seq_set_queue_tempo(snd_seq_t *seq, int q, snd_seq_queue_tempo_t * tempo)
 {
-       if (!seq || !tempo)
-               return -EINVAL;
+       assert(seq && tempo);
        tempo->queue = q;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_SET_QUEUE_TEMPO, tempo) < 0)
-               return -errno;
-       return 0;
+       return seq->ops->set_queue_tempo(seq, tempo);
 }
 
 int snd_seq_get_queue_owner(snd_seq_t *seq, int q, snd_seq_queue_owner_t * owner)
 {
-       if (!seq || !owner)
-               return -EINVAL;
-       bzero(owner, sizeof(snd_seq_queue_owner_t));
+       assert(seq && owner);
+       memset(owner, 0, sizeof(snd_seq_queue_owner_t));
        owner->queue = q;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_QUEUE_OWNER, owner) < 0)
-               return -errno;
-       return 0;
+       return seq->ops->get_queue_owner(seq, owner);
 }
 
 int snd_seq_set_queue_owner(snd_seq_t *seq, int q, snd_seq_queue_owner_t * owner)
 {
-       if (!seq || !owner)
-               return -EINVAL;
+       assert(seq && owner);
        owner->queue = q;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_SET_QUEUE_OWNER, owner) < 0)
-               return -errno;
-       return 0;
+       return seq->ops->set_queue_owner(seq, owner);
 }
 
 int snd_seq_get_queue_timer(snd_seq_t *seq, int q, snd_seq_queue_timer_t * timer)
 {
-       if (!seq || !timer)
-               return -EINVAL;
-       bzero(timer, sizeof(snd_seq_queue_timer_t));
+       assert(seq && timer);
+       memset(timer, 0, sizeof(snd_seq_queue_timer_t));
        timer->queue = q;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_QUEUE_TIMER, timer) < 0)
-               return -errno;
-       return 0;
+       return seq->ops->get_queue_timer(seq, timer);
 }
 
 int snd_seq_set_queue_timer(snd_seq_t *seq, int q, snd_seq_queue_timer_t * timer)
 {
-       if (!seq || !timer)
-               return -EINVAL;
+       assert(seq && timer);
        timer->queue = q;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_SET_QUEUE_TIMER, timer) < 0)
-               return -errno;
-       return 0;
+       return seq->ops->set_queue_timer(seq, timer);
 }
 
 int snd_seq_get_queue_client(snd_seq_t *seq, int q, snd_seq_queue_client_t * info)
 {
-       if (!seq || !info)
-               return -EINVAL;
-       bzero(info, sizeof(snd_seq_queue_client_t));
+       assert(seq && info);
+       memset(info, 0, sizeof(snd_seq_queue_client_t));
        info->queue = q;
        info->client = seq->client;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_QUEUE_CLIENT, info) < 0)
-               return -errno;
-       return 0;
+       return seq->ops->get_queue_client(seq, info);
 }
 
 int snd_seq_set_queue_client(snd_seq_t *seq, int q, snd_seq_queue_client_t * info)
 {
-       if (!seq || !info)
-               return -EINVAL;
+       assert(seq && info);
        info->queue = q;
        info->client = seq->client;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_SET_QUEUE_CLIENT, info) < 0)
-               return -errno;
-       return 0;
+       return seq->ops->set_queue_client(seq, info);
 }
 
 int snd_seq_create_queue(snd_seq_t *seq, snd_seq_queue_info_t *info)
 {
-       if (!seq)
-               return -EINVAL; 
+       int err;
+       assert(seq && info);
        info->owner = seq->client;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_CREATE_QUEUE, info) < 0)
-               return -errno;
+       err = seq->ops->create_queue(seq, info);
+       if (err < 0)
+               return err;
        return info->queue;
 }
 
 int snd_seq_alloc_named_queue(snd_seq_t *seq, char *name)
 {
        snd_seq_queue_info_t info;
-
-       if (!seq)
-               return -EINVAL; 
-
        memset(&info, 0, sizeof(info));
        info.locked = 1;
        if (name)
@@ -508,10 +466,6 @@ int snd_seq_alloc_queue(snd_seq_t *seq)
 int snd_seq_alloc_sync_queue(snd_seq_t *seq, char *name)
 {
        snd_seq_queue_info_t info;
-
-       if (!seq)
-               return -EINVAL; 
-
        memset(&info, 0, sizeof(info));
        info.locked = 1;
        if (name)
@@ -524,47 +478,35 @@ int snd_seq_alloc_sync_queue(snd_seq_t *seq, char *name)
 int snd_seq_free_queue(snd_seq_t *seq, int q)
 {
        snd_seq_queue_info_t info;
-
-       if (!seq)
-               return -EINVAL; 
-
+       assert(seq);
        memset(&info, 0, sizeof(info));
        info.queue = q;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_DELETE_QUEUE, &info) < 0)
-               return -errno;
-
-       return 0;
+       return seq->ops->delete_queue(seq, &info);
 }
 
 int snd_seq_get_queue_info(snd_seq_t *seq, int q, snd_seq_queue_info_t *info)
 {
-       if (!seq || !info)
-               return -EINVAL;
+       assert(seq && info);
        info->queue = q;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_QUEUE_INFO, info) < 0)
-               return -errno;
-       return 0;
+       return seq->ops->get_queue_info(seq, info);
 }
 
 int snd_seq_set_queue_info(snd_seq_t *seq, int q, snd_seq_queue_info_t *info)
 {
-       if (!seq || !info)
-               return -EINVAL;
+       assert(seq && info);
        info->queue = q;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_SET_QUEUE_INFO, info) < 0)
-               return -errno;
-       return 0;
+       return seq->ops->set_queue_info(seq, info);
 }
 
 int snd_seq_get_named_queue(snd_seq_t *seq, char *name)
 {
+       int err;
        snd_seq_queue_info_t info;
-
-       if (!seq)
-               return -EINVAL;
+       assert(seq && name);
        strncpy(info.name, name, sizeof(info.name));
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_NAMED_QUEUE, &info) < 0)
-               return -errno;
+       err = seq->ops->get_named_queue(seq, &info);
+       if (err < 0)
+               return err;
        return info.queue;
 }
 
@@ -687,9 +629,7 @@ int snd_seq_free_event(snd_seq_event_t *ev ATTRIBUTE_UNUSED)
 ssize_t snd_seq_event_length(snd_seq_event_t *ev)
 {
        ssize_t len = sizeof(snd_seq_event_t);
-
-       if (!ev)
-               return -EINVAL;
+       assert(ev);
        if (snd_seq_ev_is_variable(ev))
                len += ev->data.ext.len;
        return len;
@@ -726,9 +666,7 @@ int snd_seq_event_output(snd_seq_t *seq, snd_seq_event_t *ev)
 int snd_seq_event_output_buffer(snd_seq_t *seq, snd_seq_event_t *ev)
 {
        int len;
-
-       if (!seq || !ev)
-               return -EINVAL;
+       assert(seq && ev);
        len = snd_seq_event_length(ev);
        if (len < 0)
                return -EINVAL;
@@ -773,7 +711,7 @@ static int alloc_tmpbuf(snd_seq_t *seq, size_t len)
  */
 int snd_seq_event_output_direct(snd_seq_t *seq, snd_seq_event_t *ev)
 {
-       ssize_t len, result;
+       ssize_t len;
        void *buf;
 
        len = snd_seq_event_length(ev);
@@ -789,9 +727,7 @@ int snd_seq_event_output_direct(snd_seq_t *seq, snd_seq_event_t *ev)
                buf = seq->tmpbuf;
        }
 
-       result = write(seq->fd, buf, len);
-
-       return (result < 0) ? -errno : (int)result;
+       return seq->ops->write(seq, buf, len);
 }
 
 /*
@@ -799,8 +735,7 @@ int snd_seq_event_output_direct(snd_seq_t *seq, snd_seq_event_t *ev)
  */
 int snd_seq_event_output_pending(snd_seq_t *seq)
 {
-       if (!seq)
-               return -EINVAL;
+       assert(seq);
        return seq->obufused;
 }
 
@@ -809,14 +744,12 @@ int snd_seq_event_output_pending(snd_seq_t *seq)
  */
 int snd_seq_drain_output(snd_seq_t *seq)
 {
-       int result;
-
-       if (!seq)
-               return -EINVAL;
+       ssize_t result;
+       assert(seq);
        while (seq->obufused > 0) {
-               result = write(seq->fd, seq->obuf, seq->obufused);
+               result = seq->ops->write(seq, seq->obuf, seq->obufused);
                if (result < 0)
-                       return -errno;
+                       return -result;
                if ((size_t)result < seq->obufused)
                        memmove(seq->obuf, seq->obuf + result, seq->obufused - result);
                seq->obufused -= result;
@@ -832,9 +765,7 @@ int snd_seq_extract_output(snd_seq_t *seq, snd_seq_event_t **ev_res)
 {
        size_t len, olen;
        snd_seq_event_t ev;
-
-       if (!seq)
-               return -EINVAL;
+       assert(seq);
        if (ev_res)
                *ev_res = NULL;
        if ((olen = seq->obufused) < sizeof(snd_seq_event_t))
@@ -865,9 +796,9 @@ int snd_seq_extract_output(snd_seq_t *seq, snd_seq_event_t **ev_res)
 static ssize_t snd_seq_event_read_buffer(snd_seq_t *seq)
 {
        ssize_t len;
-       len = read(seq->fd, seq->ibuf, seq->ibufsize * sizeof(snd_seq_event_t));
+       len = seq->ops->read(seq, seq->ibuf, seq->ibufsize * sizeof(snd_seq_event_t));
        if (len < 0)
-               return -errno;
+               return len;
        seq->ibuflen = len / sizeof(snd_seq_event_t);
        seq->ibufptr = 0;
        return seq->ibuflen;
@@ -901,11 +832,8 @@ static int snd_seq_event_retrieve_buffer(snd_seq_t *seq, snd_seq_event_t **retp)
 int snd_seq_event_input(snd_seq_t *seq, snd_seq_event_t **ev)
 {
        int err;
-
+       assert(seq);
        *ev = NULL;
-       if (!seq)
-               return -EINVAL;
-
        if (seq->ibuflen <= 0) {
                if ((err = snd_seq_event_read_buffer(seq)) < 0)
                        return err;
@@ -917,15 +845,18 @@ int snd_seq_event_input(snd_seq_t *seq, snd_seq_event_t **ev)
 /*
  * read input data from sequencer if available
  */
-static int snd_seq_event_input_feed(snd_seq_t *seq, struct timeval *timeout)
+static int snd_seq_event_input_feed(snd_seq_t *seq, int timeout)
 {
-       fd_set rfds;
-
-       FD_ZERO(&rfds);
-       FD_SET(seq->fd, &rfds);
-       if (select(seq->fd + 1, &rfds, NULL, NULL, timeout) < 0)
+       struct pollfd pfd;
+       int err;
+       pfd.fd = seq->poll_fd;
+       pfd.events = POLLIN;
+       err = poll(&pfd, 1, timeout);
+       if (err < 0) {
+               SYSERR("poll");
                return -errno;
-       if (FD_ISSET(seq->fd, &rfds))
+       }
+       if (pfd.revents & POLLIN) 
                return snd_seq_event_read_buffer(seq);
        return seq->ibuflen;
 }
@@ -936,10 +867,7 @@ static int snd_seq_event_input_feed(snd_seq_t *seq, struct timeval *timeout)
 int snd_seq_event_input_pending(snd_seq_t *seq, int fetch_sequencer)
 {
        if (seq->ibuflen == 0 && fetch_sequencer) {
-               struct timeval tv;
-               tv.tv_sec = 0;
-               tv.tv_usec = 0;
-               return snd_seq_event_input_feed(seq, &tv);
+               return snd_seq_event_input_feed(seq, 0);
        }
        return seq->ibuflen;
 }
@@ -955,8 +883,7 @@ int snd_seq_event_input_pending(snd_seq_t *seq, int fetch_sequencer)
  */
 int snd_seq_drop_output_buffer(snd_seq_t *seq)
 {
-       if (!seq)
-               return -EINVAL;
+       assert(seq);
        seq->obufused = 0;
        return 0;
 }
@@ -966,8 +893,7 @@ int snd_seq_drop_output_buffer(snd_seq_t *seq)
  */
 int snd_seq_drop_input_buffer(snd_seq_t *seq)
 {
-       if (!seq)
-               return -EINVAL;
+       assert(seq);
        seq->ibufptr = 0;
        seq->ibuflen = 0;
        return 0;
@@ -979,10 +905,7 @@ int snd_seq_drop_input_buffer(snd_seq_t *seq)
 int snd_seq_drop_output(snd_seq_t *seq)
 {
        snd_seq_remove_events_t rminfo;
-
-       if (!seq)
-               return -EINVAL;
-
+       assert(seq);
        seq->obufused = 0; /* drain output buffer */
 
        memset(&rminfo, 0, sizeof(rminfo));
@@ -997,9 +920,7 @@ int snd_seq_drop_output(snd_seq_t *seq)
 int snd_seq_drop_input(snd_seq_t *seq)
 {
        snd_seq_remove_events_t rminfo;
-
-       if (!seq)
-               return -EINVAL;
+       assert(seq);
 
        seq->ibufptr = 0;       /* drain input buffer */
        seq->ibuflen = 0;
@@ -1131,10 +1052,7 @@ int snd_seq_remove_events(snd_seq_t *seq, snd_seq_remove_events_t *rmp)
                }
        }
 
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_REMOVE_EVENTS, rmp) < 0)
-               return -errno;
-
-       return 0;
+       return seq->ops->remove_events(seq, rmp);
 }
 
 /*----------------------------------------------------------------*/
@@ -1145,22 +1063,16 @@ int snd_seq_remove_events(snd_seq_t *seq, snd_seq_remove_events_t *rmp)
 
 int snd_seq_get_client_pool(snd_seq_t *seq, snd_seq_client_pool_t *info)
 {
-       if (!seq || !info)
-               return -EINVAL;
+       assert(seq && info);
        info->client = seq->client;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_GET_CLIENT_POOL, info) < 0)
-               return -errno;
-       return 0;
+       return seq->ops->get_client_pool(seq, info);
 }
 
 int snd_seq_set_client_pool(snd_seq_t *seq, snd_seq_client_pool_t *info)
 {
-       if (!seq || !info)
-               return -EINVAL;
+       assert(seq && info);
        info->client = seq->client;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_SET_CLIENT_POOL, info) < 0)
-               return -errno;
-       return 0;
+       return seq->ops->set_client_pool(seq, info);
 }
 
 /*----------------------------------------------------------------*/
@@ -1171,20 +1083,14 @@ int snd_seq_set_client_pool(snd_seq_t *seq, snd_seq_client_pool_t *info)
 
 int snd_seq_query_next_client(snd_seq_t *seq, snd_seq_client_info_t *info)
 {
-       if (!seq || !info)
-               return -EINVAL;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_QUERY_NEXT_CLIENT, info) < 0)
-               return -errno;
-       return 0;
+       assert(seq && info);
+       return seq->ops->query_next_client(seq, info);
 }
 
 int snd_seq_query_next_port(snd_seq_t *seq, snd_seq_port_info_t *info)
 {
-       if (!seq || !info)
-               return -EINVAL;
-       if (ioctl(seq->fd, SND_SEQ_IOCTL_QUERY_NEXT_PORT, info) < 0)
-               return -errno;
-       return 0;
+       assert(seq && info);
+       return seq->ops->query_next_port(seq, info);
 }
 
 /*----------------------------------------------------------------*/
diff --git a/src/seq/seq_hw.c b/src/seq/seq_hw.c
new file mode 100644 (file)
index 0000000..4f7e243
--- /dev/null
@@ -0,0 +1,545 @@
+/*
+ *  Sequencer Interface - main file
+ *  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
+ *   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 <fcntl.h>
+#include <sys/ioctl.h>
+#include "seq_local.h"
+#include "asoundlib.h"
+
+#define SND_FILE_SEQ           "/dev/snd/seq"
+#define SND_FILE_ALOADSEQ      "/dev/aloadSEQ"
+#define SND_SEQ_VERSION_MAX    SND_PROTOCOL_VERSION(1, 0, 0)
+
+typedef struct {
+       int fd;
+} snd_seq_hw_t;
+
+static int snd_seq_hw_close(snd_seq_t *seq)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (close(hw->fd)) {
+               SYSERR("close failed\n");
+               return -errno;
+       }
+       free(hw);
+       return 0;
+}
+
+static int snd_seq_hw_nonblock(snd_seq_t *seq, int nonblock)
+{
+       snd_seq_hw_t *hw = seq->private;
+       long flags;
+
+       if ((flags = fcntl(hw->fd, F_GETFL)) < 0) {
+               SYSERR("F_GETFL failed");
+               return -errno;
+       }
+       if (nonblock)
+               flags &= ~O_NONBLOCK;
+       else
+               flags |= O_NONBLOCK;
+       if (fcntl(hw->fd, F_SETFL, flags) < 0) {
+               SYSERR("F_SETFL for O_NONBLOCK failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_client_id(snd_seq_t *seq)
+{
+       snd_seq_hw_t *hw = seq->private;
+       int client;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_CLIENT_ID, &client) < 0) {
+               SYSERR("SND_SEQ_IOCTL_CLIENT_ID failed");
+               return -errno;
+       }
+       return client;
+}
+
+static int snd_seq_hw_system_info(snd_seq_t *seq, snd_seq_system_info_t * info)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_SYSTEM_INFO, info) < 0) {
+               SYSERR("SND_SEQ_IOCTL_SYSTEM_INFO failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_get_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_CLIENT_INFO, info) < 0) {
+               SYSERR("SND_SEQ_IOCTL_GET_CLIENT_INFO failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_set_client_info(snd_seq_t *seq, snd_seq_client_info_t * info)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_CLIENT_INFO, info) < 0) {
+               SYSERR("SND_SEQ_IOCTL_SET_CLIENT_INFO failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_create_port(snd_seq_t *seq, snd_seq_port_info_t * port)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_CREATE_PORT, port) < 0) {
+               SYSERR("SND_SEQ_IOCTL_CREATE_PORT failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_delete_port(snd_seq_t *seq, snd_seq_port_info_t * port)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_DELETE_PORT, port) < 0) {
+               SYSERR("SND_SEQ_IOCTL_DELETE_PORT failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_get_port_info(snd_seq_t *seq, snd_seq_port_info_t * info)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_PORT_INFO, info) < 0) {
+               SYSERR("SND_SEQ_IOCTL_GET_PORT_INFO failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_set_port_info(snd_seq_t *seq, snd_seq_port_info_t * info)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_PORT_INFO, info) < 0) {
+               SYSERR("SND_SEQ_IOCTL_SET_PORT_INFO failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_get_port_subscription(snd_seq_t *seq, snd_seq_port_subscribe_t * sub)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_SUBSCRIPTION, sub) < 0) {
+               SYSERR("SND_SEQ_IOCTL_GET_SUBSCRIPTION failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_subscribe_port(snd_seq_t *seq, snd_seq_port_subscribe_t * sub)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_SUBSCRIBE_PORT, sub) < 0) {
+               SYSERR("SND_SEQ_IOCTL_SUBSCRIBE_PORT failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_unsubscribe_port(snd_seq_t *seq, snd_seq_port_subscribe_t * sub)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_UNSUBSCRIBE_PORT, sub) < 0) {
+               SYSERR("SND_SEQ_IOCTL_UNSUBSCRIBE_PORT failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_query_port_subscribers(snd_seq_t *seq, snd_seq_query_subs_t * subs)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_QUERY_SUBS, subs) < 0) {
+               SYSERR("SND_SEQ_IOCTL_QUERY_SUBS failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_get_queue_status(snd_seq_t *seq, snd_seq_queue_status_t * status)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_QUEUE_STATUS, status) < 0) {
+               SYSERR("SND_SEQ_IOCTL_GET_QUEUE_STATUS failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_get_queue_tempo(snd_seq_t *seq, snd_seq_queue_tempo_t * tempo)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_QUEUE_TEMPO, tempo) < 0) {
+               SYSERR("SND_SEQ_IOCTL_GET_QUEUE_TEMPO failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_set_queue_tempo(snd_seq_t *seq, snd_seq_queue_tempo_t * tempo)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_QUEUE_TEMPO, tempo) < 0) {
+               SYSERR("SND_SEQ_IOCTL_SET_QUEUE_TEMPO failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_get_queue_owner(snd_seq_t *seq, snd_seq_queue_owner_t * owner)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_QUEUE_OWNER, owner) < 0) {
+               SYSERR("SND_SEQ_IOCTL_GET_QUEUE_OWNER failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_set_queue_owner(snd_seq_t *seq, snd_seq_queue_owner_t * owner)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_QUEUE_OWNER, owner) < 0) {
+               SYSERR("SND_SEQ_IOCTL_SET_QUEUE_OWNER failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_get_queue_timer(snd_seq_t *seq, snd_seq_queue_timer_t * timer)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_QUEUE_TIMER, timer) < 0) {
+               SYSERR("SND_SEQ_IOCTL_GET_QUEUE_TIMER failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_set_queue_timer(snd_seq_t *seq, snd_seq_queue_timer_t * timer)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_QUEUE_TIMER, timer) < 0) {
+               SYSERR("SND_SEQ_IOCTL_SET_QUEUE_TIMER failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_get_queue_client(snd_seq_t *seq, snd_seq_queue_client_t * info)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_QUEUE_CLIENT, info) < 0) {
+               SYSERR("SND_SEQ_IOCTL_GET_QUEUE_CLIENT failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_set_queue_client(snd_seq_t *seq, snd_seq_queue_client_t * info)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_QUEUE_CLIENT, info) < 0) {
+               SYSERR("SND_SEQ_IOCTL_SET_QUEUE_CLIENT failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_create_queue(snd_seq_t *seq, snd_seq_queue_info_t *info)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_CREATE_QUEUE, info) < 0) {
+               SYSERR("SND_SEQ_IOCTL_CREATE_QUEUE failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_delete_queue(snd_seq_t *seq, snd_seq_queue_info_t *info)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_DELETE_QUEUE, info) < 0) {
+               SYSERR("SND_SEQ_IOCTL_DELETE_QUEUE failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_get_queue_info(snd_seq_t *seq, snd_seq_queue_info_t *info)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_QUEUE_INFO, info) < 0) {
+               SYSERR("SND_SEQ_IOCTL_GET_QUEUE_INFO failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_set_queue_info(snd_seq_t *seq, snd_seq_queue_info_t *info)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_QUEUE_INFO, info) < 0) {
+               SYSERR("SND_SEQ_IOCTL_SET_QUEUE_INFO failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_get_named_queue(snd_seq_t *seq, snd_seq_queue_info_t *info)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_NAMED_QUEUE, info) < 0) {
+               SYSERR("SND_SEQ_IOCTL_GET_NAMED_QUEUE failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static ssize_t snd_seq_hw_write(snd_seq_t *seq, void *buf, size_t len)
+{
+       snd_seq_hw_t *hw = seq->private;
+       ssize_t result = write(hw->fd, buf, len);
+       if (result < 0)
+               return -errno;
+       return result;
+}
+
+static ssize_t snd_seq_hw_read(snd_seq_t *seq, void *buf, size_t len)
+{
+       snd_seq_hw_t *hw = seq->private;
+       ssize_t result = read(hw->fd, buf, len);
+       if (result < 0)
+               return -errno;
+       return result;
+}
+
+static int snd_seq_hw_remove_events(snd_seq_t *seq, snd_seq_remove_events_t *rmp)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_REMOVE_EVENTS, rmp) < 0) {
+               SYSERR("SND_SEQ_IOCTL_REMOVE_EVENTS failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_get_client_pool(snd_seq_t *seq, snd_seq_client_pool_t *info)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_GET_CLIENT_POOL, info) < 0) {
+               SYSERR("SND_SEQ_IOCTL_GET_CLIENT_POOL failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_set_client_pool(snd_seq_t *seq, snd_seq_client_pool_t *info)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_SET_CLIENT_POOL, info) < 0) {
+               SYSERR("SND_SEQ_IOCTL_SET_CLIENT_POOL failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_query_next_client(snd_seq_t *seq, snd_seq_client_info_t *info)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_QUERY_NEXT_CLIENT, info) < 0) {
+               SYSERR("SND_SEQ_IOCTL_QUERY_NEXT_CLIENT failed");
+               return -errno;
+       }
+       return 0;
+}
+
+static int snd_seq_hw_query_next_port(snd_seq_t *seq, snd_seq_port_info_t *info)
+{
+       snd_seq_hw_t *hw = seq->private;
+       if (ioctl(hw->fd, SND_SEQ_IOCTL_QUERY_NEXT_PORT, info) < 0) {
+               SYSERR("SND_SEQ_IOCTL_QUERY_NEXT_PORT failed");
+               return -errno;
+       }
+       return 0;
+}
+
+snd_seq_ops_t snd_seq_hw_ops = {
+       close: snd_seq_hw_close,
+       nonblock: snd_seq_hw_nonblock,
+       system_info: snd_seq_hw_system_info,
+       get_client_info: snd_seq_hw_get_client_info,
+       set_client_info: snd_seq_hw_set_client_info,
+       create_port: snd_seq_hw_create_port,
+       delete_port: snd_seq_hw_delete_port,
+       get_port_info: snd_seq_hw_get_port_info,
+       set_port_info: snd_seq_hw_set_port_info,
+       get_port_subscription: snd_seq_hw_get_port_subscription,
+       subscribe_port: snd_seq_hw_subscribe_port,
+       unsubscribe_port: snd_seq_hw_unsubscribe_port,
+       query_port_subscribers: snd_seq_hw_query_port_subscribers,
+       get_queue_status: snd_seq_hw_get_queue_status,
+       get_queue_tempo: snd_seq_hw_get_queue_tempo,
+       set_queue_tempo: snd_seq_hw_set_queue_tempo,
+       get_queue_owner: snd_seq_hw_get_queue_owner,
+       set_queue_owner: snd_seq_hw_set_queue_owner,
+       get_queue_timer: snd_seq_hw_get_queue_timer,
+       set_queue_timer: snd_seq_hw_set_queue_timer,
+       get_queue_client: snd_seq_hw_get_queue_client,
+       set_queue_client: snd_seq_hw_set_queue_client,
+       create_queue: snd_seq_hw_create_queue,
+       delete_queue: snd_seq_hw_delete_queue,
+       get_queue_info: snd_seq_hw_get_queue_info,
+       set_queue_info: snd_seq_hw_set_queue_info,
+       get_named_queue: snd_seq_hw_get_named_queue,
+       write: snd_seq_hw_write,
+       read: snd_seq_hw_read,
+       remove_events: snd_seq_hw_remove_events,
+       get_client_pool: snd_seq_hw_get_client_pool,
+       set_client_pool: snd_seq_hw_set_client_pool,
+       query_next_client: snd_seq_hw_query_next_client,
+       query_next_port: snd_seq_hw_query_next_port,
+};
+
+int snd_seq_hw_open(snd_seq_t **handle, char *name, int streams, int mode)
+{
+       int fd, ver, client, fmode;
+       char filename[32];
+       snd_seq_t *seq;
+       snd_seq_hw_t *hw;
+
+       *handle = NULL;
+
+       switch (streams) {
+       case SND_SEQ_OPEN_OUTPUT:
+               fmode = O_WRONLY;
+               break;
+       case SND_SEQ_OPEN_INPUT:
+               fmode = O_RDONLY;
+               break;
+       case SND_SEQ_OPEN_DUPLEX:
+               fmode = O_RDWR;
+               break;
+       default:
+               assert(0);
+               return -EINVAL;
+       }
+       
+       if (mode & SND_SEQ_NONBLOCK)
+               fmode |= O_NONBLOCK;
+
+       sprintf(filename, SND_FILE_SEQ);
+       if ((fd = open(filename, fmode)) < 0) {
+               close(open(SND_FILE_ALOADSEQ, O_RDWR));
+               if ((fd = open(filename, fmode)) < 0) {
+                       SYSERR("open %s failed", filename);
+                       return -errno;
+               }
+       }
+       if (ioctl(fd, SND_SEQ_IOCTL_PVERSION, &ver) < 0) {
+               SYSERR("SND_SEQ_IOCTL_PVERSION failed");
+               close(fd);
+               return -errno;
+       }
+       if (SND_PROTOCOL_INCOMPATIBLE(ver, SND_SEQ_VERSION_MAX)) {
+               close(fd);
+               return -SND_ERROR_INCOMPATIBLE_VERSION;
+       }
+       hw = calloc(1, sizeof(snd_seq_hw_t));
+       if (hw == NULL) {
+               close(fd);
+               return -ENOMEM;
+       }
+
+       seq = calloc(1, sizeof(snd_seq_t));
+       if (seq == NULL) {
+               free(hw);
+               close(fd);
+               return -ENOMEM;
+       }
+       hw->fd = fd;
+       if (streams & SND_SEQ_OPEN_OUTPUT) {
+               seq->obuf = (char *) malloc(seq->obufsize = SND_SEQ_OBUF_SIZE);
+               if (!seq->obuf) {
+                       free(hw);
+                       free(seq);
+                       close(fd);
+                       return -ENOMEM;
+               }
+       }
+       if (streams & SND_SEQ_OPEN_INPUT) {
+               seq->ibuf = (snd_seq_event_t *) calloc(sizeof(snd_seq_event_t), seq->ibufsize = SND_SEQ_IBUF_SIZE);
+               if (!seq->ibuf) {
+                       free(seq->ibuf);
+                       free(hw);
+                       free(seq);
+                       close(fd);
+                       return -ENOMEM;
+               }
+       }
+       if (name)
+               seq->name = strdup(name);
+       seq->type = SND_SEQ_TYPE_HW;
+       seq->streams = streams;
+       seq->mode = mode;
+       seq->tmpbuf = NULL;
+       seq->tmpbufsize = 0;
+       seq->poll_fd = fd;
+       seq->ops = &snd_seq_hw_ops;
+       seq->private = hw;
+       client = snd_seq_hw_client_id(seq);
+       if (client < 0) {
+               snd_seq_close(seq);
+               return client;
+       } else
+               seq->client = client;
+       *handle = seq;
+       return 0;
+}
+
+int _snd_seq_hw_open(snd_seq_t **handlep, char *name, snd_config_t *conf,
+                    int streams, int mode)
+{
+       snd_config_iterator_t i;
+       snd_config_foreach(i, conf) {
+               snd_config_t *n = snd_config_entry(i);
+               if (strcmp(n->id, "comment") == 0)
+                       continue;
+               if (strcmp(n->id, "type") == 0)
+                       continue;
+               if (strcmp(n->id, "streams") == 0)
+                       continue;
+               return -EINVAL;
+       }
+       return snd_seq_hw_open(handlep, name, streams, mode);
+}
+                               
diff --git a/src/seq/seq_local.h b/src/seq/seq_local.h
new file mode 100644 (file)
index 0000000..24b815c
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ *  Sequencer Interface - definition of sequencer event handler
+ *  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
+ *   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.
+ *
+ */
+
+#ifndef __SEQ_LOCAL_H
+#define __SEQ_LOCAL_H
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include "asoundlib.h"
+
+#define SND_SEQ_OBUF_SIZE      (16*1024)       /* default size */
+#define SND_SEQ_IBUF_SIZE      500             /* in event_size aligned */
+#define DEFAULT_TMPBUF_SIZE    20
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
+#define ERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, __VA_ARGS__)
+#define SYSERR(...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, __VA_ARGS__)
+#else
+#define ERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, 0, ##args)
+#define SYSERR(args...) snd_lib_error(__FILE__, __LINE__, __FUNCTION__, errno, ##args)
+#endif
+
+typedef struct {
+       int (*close)(snd_seq_t *seq);
+       int (*nonblock)(snd_seq_t *seq, int nonblock);
+       int (*system_info)(snd_seq_t *seq, snd_seq_system_info_t * info);
+       int (*get_client_info)(snd_seq_t *seq, snd_seq_client_info_t * info);
+       int (*set_client_info)(snd_seq_t *seq, snd_seq_client_info_t * info);
+       int (*create_port)(snd_seq_t *seq, snd_seq_port_info_t * port);
+       int (*delete_port)(snd_seq_t *seq, snd_seq_port_info_t * port);
+       int (*get_port_info)(snd_seq_t *seq, snd_seq_port_info_t * info);
+       int (*set_port_info)(snd_seq_t *seq, snd_seq_port_info_t * info);
+       int (*get_port_subscription)(snd_seq_t *seq, snd_seq_port_subscribe_t * sub);
+       int (*subscribe_port)(snd_seq_t *seq, snd_seq_port_subscribe_t * sub);
+       int (*unsubscribe_port)(snd_seq_t *seq, snd_seq_port_subscribe_t * sub);
+       int (*query_port_subscribers)(snd_seq_t *seq, snd_seq_query_subs_t * subs);
+       int (*get_queue_status)(snd_seq_t *seq, snd_seq_queue_status_t * status);
+       int (*get_queue_tempo)(snd_seq_t *seq, snd_seq_queue_tempo_t * tempo);
+       int (*set_queue_tempo)(snd_seq_t *seq, snd_seq_queue_tempo_t * tempo);
+       int (*get_queue_owner)(snd_seq_t *seq, snd_seq_queue_owner_t * owner);
+       int (*set_queue_owner)(snd_seq_t *seq, snd_seq_queue_owner_t * owner);
+       int (*get_queue_timer)(snd_seq_t *seq, snd_seq_queue_timer_t * timer);
+       int (*set_queue_timer)(snd_seq_t *seq, snd_seq_queue_timer_t * timer);
+       int (*get_queue_client)(snd_seq_t *seq, snd_seq_queue_client_t * client);
+       int (*set_queue_client)(snd_seq_t *seq, snd_seq_queue_client_t * client);
+       int (*create_queue)(snd_seq_t *seq, snd_seq_queue_info_t *info);
+       int (*delete_queue)(snd_seq_t *seq, snd_seq_queue_info_t *info);
+       int (*get_queue_info)(snd_seq_t *seq, snd_seq_queue_info_t *info);
+       int (*set_queue_info)(snd_seq_t *seq, snd_seq_queue_info_t *info);
+       int (*get_named_queue)(snd_seq_t *seq, snd_seq_queue_info_t *info);
+       ssize_t (*write)(snd_seq_t *seq, void *buf, size_t len);
+       ssize_t (*read)(snd_seq_t *seq, void *buf, size_t len);
+       int (*remove_events)(snd_seq_t *seq, snd_seq_remove_events_t *rmp);
+       int (*get_client_pool)(snd_seq_t *seq, snd_seq_client_pool_t *info);
+       int (*set_client_pool)(snd_seq_t *seq, snd_seq_client_pool_t *info);
+       int (*query_next_client)(snd_seq_t *seq, snd_seq_client_info_t *info);
+       int (*query_next_port)(snd_seq_t *seq, snd_seq_port_info_t *info);
+} snd_seq_ops_t;
+
+struct _snd_seq {
+       char *name;
+       int type;
+       int streams;
+       int mode;
+       int poll_fd;
+       snd_seq_ops_t *ops;
+       void *private;
+       int client;             /* client number */
+       /* buffers */
+       char *obuf;             /* output buffer */
+       size_t obufsize;                /* output buffer size */
+       size_t obufused;                /* output buffer used size */
+       snd_seq_event_t *ibuf;  /* input buffer */
+       size_t ibufptr;         /* current pointer of input buffer */
+       size_t ibuflen;         /* queued length */
+       size_t ibufsize;                /* input buffer size */
+       snd_seq_event_t *tmpbuf;        /* temporary event for extracted event */
+       size_t tmpbufsize;              /* size of errbuf */
+};
+
+int snd_seq_hw_open(snd_seq_t **handle, char *name, int streams, int mode);
+
+#endif
diff --git a/src/seq/seq_priv.h b/src/seq/seq_priv.h
deleted file mode 100644 (file)
index 7dbb1b3..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- *  Sequencer Interface - definition of sequencer event handler
- *  Copyright (c) 1998 by Jaroslav Kysela <perex@suse.cz>
- *
- *
- *   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.
- *
- */
-
-#ifndef __SEQ_PRIV_H
-#define __SEQ_PRIV_H
-
-struct snd_seq {
-       int client;             /* client number */
-       int fd;
-       /* buffers */
-       char *obuf;             /* output buffer */
-       size_t obufsize;                /* output buffer size */
-       size_t obufused;                /* output buffer used size */
-       snd_seq_event_t *ibuf;  /* input buffer */
-       size_t ibufptr;         /* current pointer of input buffer */
-       size_t ibuflen;         /* queued length */
-       size_t ibufsize;                /* input buffer size */
-       snd_seq_event_t *tmpbuf;        /* temporary event for extracted event */
-       size_t tmpbufsize;              /* size of errbuf */
-};
-
-#endif
index dcef22238a3b1909de28b77ab995981e7961c13f..9b9ff89bc6c81f2a73c660d68fcb29b63cb9a5a9 100644 (file)
@@ -28,7 +28,7 @@
 #include <fcntl.h>
 #include <sys/ioctl.h>
 #include "asoundlib.h"
-#include "seq_priv.h"
+#include "seq_local.h"
 
 /* direct passing (without queued) */
 void snd_seq_ev_set_direct(snd_seq_event_t *ev)
index 7201b0cfd2f2837c71a2c9b3f00376ddd04bd439..535e79d5adbe4d414a719272a04b70649a1758f9 100644 (file)
@@ -31,7 +31,7 @@
 #define SND_FILE_TIMER         "/dev/snd/timer"
 #define SND_TIMER_VERSION_MAX  SND_PROTOCOL_VERSION(2, 0, 0)
 
-struct snd_timer {
+struct _snd_timer {
        int fd;
 };
 
@@ -136,18 +136,6 @@ int snd_timer_params(snd_timer_t *handle, snd_timer_params_t * params)
        return 0;
 }
 
-int snd_timer_setup(snd_timer_t *handle, snd_timer_setup_t * setup)
-{
-       snd_timer_t *tmr;
-
-       tmr = handle;
-       if (!tmr || !setup)
-               return -EINVAL;
-       if (ioctl(tmr->fd, SND_TIMER_IOCTL_SETUP, setup) < 0)
-               return -errno;
-       return 0;
-}
-
 int snd_timer_status(snd_timer_t *handle, snd_timer_status_t * status)
 {
        snd_timer_t *tmr;
index 7d9071c635889d11ad6e4a20dd12d829d94675e6..ed6382d08d6df426bdd64d10f9193a9a84f29187 100644 (file)
@@ -47,7 +47,7 @@ int setparams(snd_pcm_t *phandle, snd_pcm_t *chandle, int *bufsize)
        params.mode = SND_PCM_MODE_FRAME;
 #endif
        params.format.interleave = 1;
-       params.format.sfmt = SND_PCM_SFMT_S16_LE;
+       params.format.sfmt = SND_PCM_FORMAT_S16_LE;
        params.format.channels = 2;
        params.format.rate = USED_RATE;
        params.start_mode = SND_PCM_START_EXPLICIT;
@@ -216,7 +216,7 @@ int main(void)
                frames_in = frames_out = 0;
                if (setparams(phandle, chandle, &latency) < 0)
                        break;
-               if (snd_pcm_format_set_silence(SND_PCM_SFMT_S16_LE, buffer, latency*2) < 0) {
+               if (snd_pcm_format_set_silence(SND_PCM_FORMAT_S16_LE, buffer, latency*2) < 0) {
                        fprintf(stderr, "silence error\n");
                        break;
                }
index 0da03421c408a3d2d36f4e5cbb036657b2abb561..4d7e26dfd4864f628921cebd9f8a06726adea806 100644 (file)
@@ -39,7 +39,7 @@ int main(void)
                fprintf(stderr, "open failed: %s\n", snd_strerror(err));
                return 0;
        }
-       format.sfmt = SND_PCM_SFMT_MU_LAW;
+       format.sfmt = SND_PCM_FORMAT_MU_LAW;
        format.rate = 8000;
        format.channels = 1;
        if ((err = snd_pcm_playback_format(handle, &format)) < 0) {
index 9b750ee73fb4eed7a919a30b75e5c734275005d1..23262253085ad743b4db6968be616371f8cc26c7 100644 (file)
@@ -18,7 +18,7 @@ void setformat(void *phandle, void *rhandle)
        snd_pcm_format_t format;
 
        bzero(&format, sizeof(format));
-       format.sfmt = SND_PCM_SFMT_S16_LE;
+       format.sfmt = SND_PCM_FORMAT_S16_LE;
        format.channels = 2;
        format.rate = 22050;
        if ((err = snd_pcm_playback_format(phandle, &format)) < 0) {
index 6f50a85c68e045f92277e2be14be8534ac111702..c32d5af76aaa71731095d6715abba226bbd69ff1 100644 (file)
@@ -52,53 +52,53 @@ void info_channel(snd_pcm_t *handle, int channel, char *id)
                printf(" overrange");
        printf("\n");
        printf("  formats        :");
-       if (stream_info.formats & SND_PCM_FMT_MU_LAW)
+       if (stream_info.formats & SND_PCM_FMTBIT_MU_LAW)
                printf(" mu-Law");
-       if (stream_info.formats & SND_PCM_FMT_A_LAW)
+       if (stream_info.formats & SND_PCM_FMTBIT_A_LAW)
                printf(" a-Law");
-       if (stream_info.formats & SND_PCM_FMT_IMA_ADPCM)
+       if (stream_info.formats & SND_PCM_FMTBIT_IMA_ADPCM)
                printf(" IMA-ADPCM");
-       if (stream_info.formats & SND_PCM_FMT_U8)
+       if (stream_info.formats & SND_PCM_FMTBIT_U8)
                printf(" U8");
-       if (stream_info.formats & SND_PCM_FMT_S16_LE)
+       if (stream_info.formats & SND_PCM_FMTBIT_S16_LE)
                printf(" S16-LE");
-       if (stream_info.formats & SND_PCM_FMT_S16_BE)
+       if (stream_info.formats & SND_PCM_FMTBIT_S16_BE)
                printf(" S16-BE");
-       if (stream_info.formats & SND_PCM_FMT_S8)
+       if (stream_info.formats & SND_PCM_FMTBIT_S8)
                printf(" S8");
-       if (stream_info.formats & SND_PCM_FMT_U16_LE)
+       if (stream_info.formats & SND_PCM_FMTBIT_U16_LE)
                printf(" U16-LE");
-       if (stream_info.formats & SND_PCM_FMT_U16_BE)
+       if (stream_info.formats & SND_PCM_FMTBIT_U16_BE)
                printf(" U16-BE");
-       if (stream_info.formats & SND_PCM_FMT_MPEG)
+       if (stream_info.formats & SND_PCM_FMTBIT_MPEG)
                printf(" MPEG");
-       if (stream_info.formats & SND_PCM_FMT_GSM)
+       if (stream_info.formats & SND_PCM_FMTBIT_GSM)
                printf(" GSM");
-       if (stream_info.formats & SND_PCM_FMT_S24_LE)
+       if (stream_info.formats & SND_PCM_FMTBIT_S24_LE)
                printf(" S24-LE");
-       if (stream_info.formats & SND_PCM_FMT_S24_BE)
+       if (stream_info.formats & SND_PCM_FMTBIT_S24_BE)
                printf(" S24-BE");
-       if (stream_info.formats & SND_PCM_FMT_U24_LE)
+       if (stream_info.formats & SND_PCM_FMTBIT_U24_LE)
                printf(" U24-LE");
-       if (stream_info.formats & SND_PCM_FMT_U24_BE)
+       if (stream_info.formats & SND_PCM_FMTBIT_U24_BE)
                printf(" U24-BE");
-       if (stream_info.formats & SND_PCM_FMT_S32_LE)
+       if (stream_info.formats & SND_PCM_FMTBIT_S32_LE)
                printf(" S32-LE");
-       if (stream_info.formats & SND_PCM_FMT_S32_BE)
+       if (stream_info.formats & SND_PCM_FMTBIT_S32_BE)
                printf(" S32-BE");
-       if (stream_info.formats & SND_PCM_FMT_U32_LE)
+       if (stream_info.formats & SND_PCM_FMTBIT_U32_LE)
                printf(" U32-LE");
-       if (stream_info.formats & SND_PCM_FMT_U32_BE)
+       if (stream_info.formats & SND_PCM_FMTBIT_U32_BE)
                printf(" U32-BE");
-       if (stream_info.formats & SND_PCM_FMT_FLOAT)
+       if (stream_info.formats & SND_PCM_FMTBIT_FLOAT)
                printf(" Float");
-       if (stream_info.formats & SND_PCM_FMT_FLOAT64)
+       if (stream_info.formats & SND_PCM_FMTBIT_FLOAT64)
                printf(" Float64");
-       if (stream_info.formats & SND_PCM_FMT_IEC958_SUBFRAME_LE)
+       if (stream_info.formats & SND_PCM_FMTBIT_IEC958_SUBFRAME_LE)
                printf(" IEC958-LE");
-       if (stream_info.formats & SND_PCM_FMT_IEC958_SUBFRAME_BE)
+       if (stream_info.formats & SND_PCM_FMTBIT_IEC958_SUBFRAME_BE)
                printf(" IEC958-BE");
-       if (stream_info.formats & SND_PCM_FMT_SPECIAL)
+       if (stream_info.formats & SND_PCM_FMTBIT_SPECIAL)
                printf(" Special");
        printf("\n");
        printf("  rates          :");
index b7c1f6c86cec65455914378c6026b46712893fe2..546f0a91d5e41100f2a0396a7368bc8545a315c7 100644 (file)
@@ -14,7 +14,7 @@ void set_format(snd_pcm_t *phandle)
        snd_pcm_format_t format;
 
        bzero(&format, sizeof(format));
-       format.sfmt = SND_PCM_SFMT_S16_LE;
+       format.sfmt = SND_PCM_FORMAT_S16_LE;
        format.channels = 2;
        format.rate = 44100;
        if ((err = snd_pcm_playback_format(phandle, &format)) < 0) {