/** HwDep information container */
typedef struct _snd_hwdep_info snd_hwdep_info_t;
+/** HwDep interface */
typedef enum _snd_hwdep_iface {
- SND_HWDEP_IFACE_OPL2 = SNDRV_HWDEP_IFACE_OPL2,
- SND_HWDEP_IFACE_OPL3 = SNDRV_HWDEP_IFACE_OPL3,
- SND_HWDEP_IFACE_OPL4 = SNDRV_HWDEP_IFACE_OPL4,
- SND_HWDEP_IFACE_SB16CSP = SNDRV_HWDEP_IFACE_SB16CSP,
- SND_HWDEP_IFACE_EMU10K1 = SNDRV_HWDEP_IFACE_EMU10K1,
- SND_HWDEP_IFACE_YSS225 = SNDRV_HWDEP_IFACE_YSS225,
- SND_HWDEP_IFACE_ICS2115 = SNDRV_HWDEP_IFACE_ICS2115,
- SND_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_LAST,
+ SND_HWDEP_IFACE_OPL2 = SNDRV_HWDEP_IFACE_OPL2, /**< OPL2 raw driver */
+ SND_HWDEP_IFACE_OPL3 = SNDRV_HWDEP_IFACE_OPL3, /**< OPL3 raw driver */
+ SND_HWDEP_IFACE_OPL4 = SNDRV_HWDEP_IFACE_OPL4, /**< OPL4 raw driver */
+ SND_HWDEP_IFACE_SB16CSP = SNDRV_HWDEP_IFACE_SB16CSP, /**< SB16CSP driver */
+ SND_HWDEP_IFACE_EMU10K1 = SNDRV_HWDEP_IFACE_EMU10K1, /**< EMU10K1 driver */
+ SND_HWDEP_IFACE_YSS225 = SNDRV_HWDEP_IFACE_YSS225, /**< YSS225 driver */
+ SND_HWDEP_IFACE_ICS2115 = SNDRV_HWDEP_IFACE_ICS2115, /**< ICS2115 driver */
+ SND_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_LAST, /**< last know hwdep interface */
} snd_hwdep_iface_t;
+/** open for reading */
#define SND_HWDEP_OPEN_READ (O_RDONLY)
+/** open for writing */
#define SND_HWDEP_OPEN_WRITE (O_WRONLY)
+/** open for reading and writing */
#define SND_HWDEP_OPEN_DUPLEX (O_RDWR)
+/** flag: open in nonblock mode */
#define SND_HWDEP_OPEN_NONBLOCK (O_NONBLOCK)
+/** HwDep handle type */
+typedef enum _snd_hwdep_type {
+ /** Kernel level HwDep */
+ SND_HWDEP_TYPE_HW,
+ /** Shared memory client HwDep (not yet implemented) */
+ SND_HWDEP_TYPE_SHM,
+ /** INET client HwDep (not yet implemented) */
+ SND_HWDEP_TYPE_INET,
+} snd_hwdep_type_t;
+
/** HwDep handle */
typedef struct _snd_hwdep snd_hwdep_t;
extern "C" {
#endif
-int snd_hwdep_open(snd_hwdep_t **hwdep, int card, int device, int mode);
+int snd_hwdep_open(snd_hwdep_t **hwdep, const char *name, int mode);
int snd_hwdep_close(snd_hwdep_t *hwdep);
int snd_hwdep_poll_descriptors(snd_hwdep_t *hwdep, struct pollfd *pfds, unsigned int space);
-int snd_hwdep_block_mode(snd_hwdep_t *hwdep, int enable);
+int snd_hwdep_nonblock(snd_hwdep_t *hwdep, int nonblock);
int snd_hwdep_info(snd_hwdep_t *hwdep, snd_hwdep_info_t * info);
int snd_hwdep_ioctl(snd_hwdep_t *hwdep, unsigned int request, void * arg);
ssize_t snd_hwdep_write(snd_hwdep_t *hwdep, const void *buffer, size_t size);
ssize_t snd_hwdep_read(snd_hwdep_t *hwdep, void *buffer, size_t size);
size_t snd_hwdep_info_sizeof(void);
+/** allocate #snd_hwdep_info_t container on stack */
#define snd_hwdep_info_alloca(ptr) do { assert(ptr); *ptr = (snd_hwdep_info_t *) alloca(snd_hwdep_info_sizeof()); memset(*ptr, 0, snd_hwdep_info_sizeof()); } while (0)
int snd_hwdep_info_malloc(snd_hwdep_info_t **ptr);
void snd_hwdep_info_free(snd_hwdep_info_t *obj);
+/*
+ * \file hwdep/hwdep.c
+ * \author Jaroslav Kysela <perex@suse.cz>
+ * \date 2000-2001
+ *
+ * HwDep (hardware dependent) Interface is designed for individual hardware
+ * access. This interface does not cover any API specification.
+ */
/*
* Hardware dependent Interface - main file
* Copyright (c) 2000 by Jaroslav Kysela <perex@suse.cz>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
+#include <dlfcn.h>
#include <sys/ioctl.h>
-#include "local.h"
+#include "hwdep_local.h"
-#define SNDRV_FILE_HWDEP "/dev/snd/hwC%iD%i"
-#define SNDRV_HWDEP_VERSION_MAX SNDRV_PROTOCOL_VERSION(1, 0, 0)
-
-struct _snd_hwdep {
- int card;
- int device;
- int fd;
- int mode;
-};
-
-int snd_hwdep_open(snd_hwdep_t **handle, int card, int device, int mode)
+static int snd_hwdep_open_conf(snd_hwdep_t **hwdep,
+ const char *name, snd_config_t *hwdep_root,
+ snd_config_t *hwdep_conf, int mode)
{
- int fd, ver;
- char filename[32];
- snd_hwdep_t *hwdep;
- assert(handle);
-
- *handle = NULL;
-
- if (card < 0 || card >= 32)
+ const char *str;
+ char buf[256];
+ int err;
+ snd_config_t *conf, *type_conf;
+ snd_config_iterator_t i, next;
+ const char *lib = NULL, *open_name = NULL;
+ int (*open_func)(snd_hwdep_t **, const char *, snd_config_t *, snd_config_t *, int) = NULL;
+ void *h;
+ if (snd_config_get_type(hwdep_conf) != SND_CONFIG_TYPE_COMPOUND) {
+ if (name)
+ SNDERR("Invalid type for HWDEP %s definition", name);
+ else
+ SNDERR("Invalid type for HWDEP definition");
return -EINVAL;
- sprintf(filename, SNDRV_FILE_HWDEP, card, device);
- if ((fd = open(filename, mode)) < 0) {
- snd_card_load(card);
- if ((fd = open(filename, mode)) < 0)
- return -errno;
}
- if (ioctl(fd, SNDRV_HWDEP_IOCTL_PVERSION, &ver) < 0) {
- close(fd);
- return -errno;
+ err = snd_config_search(hwdep_conf, "type", &conf);
+ if (err < 0) {
+ SNDERR("type is not defined");
+ return err;
}
- if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_HWDEP_VERSION_MAX)) {
- close(fd);
- return -SND_ERROR_INCOMPATIBLE_VERSION;
+ err = snd_config_get_string(conf, &str);
+ if (err < 0) {
+ SNDERR("Invalid type for %s", snd_config_get_id(conf));
+ return err;
}
- hwdep = (snd_hwdep_t *) calloc(1, sizeof(snd_hwdep_t));
- if (hwdep == NULL) {
- close(fd);
- return -ENOMEM;
+ err = snd_config_search_definition(hwdep_root, "hwdep_type", str, &type_conf);
+ if (err >= 0) {
+ if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) {
+ SNDERR("Invalid type for HWDEP type %s definition", str);
+ goto _err;
+ }
+ snd_config_for_each(i, next, type_conf) {
+ snd_config_t *n = snd_config_iterator_entry(i);
+ const char *id = snd_config_get_id(n);
+ if (strcmp(id, "comment") == 0)
+ continue;
+ if (strcmp(id, "lib") == 0) {
+ err = snd_config_get_string(n, &lib);
+ if (err < 0) {
+ SNDERR("Invalid type for %s", id);
+ goto _err;
+ }
+ continue;
+ }
+ if (strcmp(id, "open") == 0) {
+ err = snd_config_get_string(n, &open_name);
+ if (err < 0) {
+ SNDERR("Invalid type for %s", id);
+ goto _err;
+ }
+ continue;
+ }
+ SNDERR("Unknown field %s", id);
+ err = -EINVAL;
+ goto _err;
+ }
+ }
+ if (!open_name) {
+ open_name = buf;
+ snprintf(buf, sizeof(buf), "_snd_hwdep_%s_open", str);
+ }
+ if (!lib)
+ lib = ALSA_LIB;
+ h = dlopen(lib, RTLD_NOW);
+ open_func = h ? dlsym(h, open_name) : NULL;
+ if (!h) {
+ SNDERR("Cannot open shared library %s", lib);
+ err = -ENOENT;
+ } else if (!open_func) {
+ SNDERR("symbol %s is not defined inside %s", open_name, lib);
+ dlclose(h);
+ err = -ENXIO;
}
- hwdep->card = card;
- hwdep->device = device;
- hwdep->fd = fd;
- hwdep->mode = mode;
- *handle = hwdep;
+ _err:
+ if (type_conf)
+ snd_config_delete(type_conf);
+ if (err >= 0)
+ err = open_func(hwdep, name, hwdep_root, hwdep_conf, mode);
+ if (err < 0)
+ return err;
return 0;
}
+static int snd_hwdep_open_noupdate(snd_hwdep_t **hwdep, snd_config_t *root, const char *name, int mode)
+{
+ int err;
+ snd_config_t *hwdep_conf;
+ err = snd_config_search_definition(root, "hwdep", name, &hwdep_conf);
+ if (err < 0) {
+ SNDERR("Unknown HwDep %s", name);
+ return err;
+ }
+ err = snd_hwdep_open_conf(hwdep, name, root, hwdep_conf, mode);
+ snd_config_delete(hwdep_conf);
+ return err;
+}
+
+/**
+ * \brief Opens a new connection to the HwDep interface.
+ * \param hwdep Returned handle (NULL if not wanted)
+ * \param name ASCII identifier of the RawMidi handle
+ * \param mode Open mode
+ * \return 0 on success otherwise a negative error code
+ *
+ * Opens a new connection to the RawMidi interface specified with
+ * an ASCII identifier and mode.
+ */
+int snd_hwdep_open(snd_hwdep_t **hwdep, const char *name, int mode)
+{
+ int err;
+ assert(hwdep && name);
+ err = snd_config_update();
+ if (err < 0)
+ return err;
+ return snd_hwdep_open_noupdate(hwdep, snd_config, name, mode);
+}
+
+/**
+ * \brief close RawMidi handle
+ * \param hwdep RawMidi handle
+ * \return 0 on success otherwise a negative error code
+ *
+ * Closes the specified RawMidi handle and frees all associated
+ * resources.
+ */
int snd_hwdep_close(snd_hwdep_t *hwdep)
{
- int res;
- assert(hwdep);
- res = close(hwdep->fd) < 0 ? -errno : 0;
+ int err;
+ assert(hwdep);
+ if ((err = hwdep->ops->close(hwdep)) < 0)
+ return err;
+ if (hwdep->name)
+ free(hwdep->name);
free(hwdep);
- return res;
+ return 0;
+}
+
+/**
+ * \brief get identifier of HwDep handle
+ * \param hwdep a Hwdep handle
+ * \return ascii identifier of RawMidi handle
+ *
+ * Returns the ASCII identifier of given HwDep handle. It's the same
+ * identifier specified in snd_hwdep_open().
+ */
+const char *snd_hwdep_name(snd_hwdep_t *hwdep)
+{
+ assert(hwdep);
+ return hwdep->name;
+}
+
+/**
+ * \brief get type of HwDep handle
+ * \param hwdep a HwDep handle
+ * \return type of HwDep handle
+ *
+ * Returns the type #snd_hwdep_type_t of given HwDep handle.
+ */
+snd_hwdep_type_t snd_hwdep_type(snd_hwdep_t *hwdep)
+{
+ assert(hwdep);
+ return hwdep->type;
+}
+
+/**
+ * \brief get count of poll descriptors for HwDep handle
+ * \param hwdep HwDep handle
+ * \return count of poll descriptors
+ */
+int snd_hwdep_poll_descriptors_count(snd_hwdep_t *hwdep)
+{
+ assert(hwdep);
+ return 1;
}
+/**
+ * \brief get poll descriptors
+ * \param hwdep HwDep handle
+ * \param pfds array of poll descriptors
+ * \param space space in the poll descriptor array
+ * \return count of filled descriptors
+ */
int snd_hwdep_poll_descriptors(snd_hwdep_t *hwdep, struct pollfd *pfds, unsigned int space)
{
assert(hwdep);
if (space >= 1) {
- pfds->fd = hwdep->fd;
- pfds->events = POLLOUT | POLLIN;
+ pfds->fd = hwdep->poll_fd;
+ switch (hwdep->mode & O_ACCMODE) {
+ case O_WRONLY:
+ pfds->events = POLLOUT;
+ break;
+ case O_RDONLY:
+ pfds->events = POLLIN;
+ break;
+ case O_RDWR:
+ pfds->events = POLLOUT|POLLIN;
+ break;
+ default:
+ return -EIO;
+ }
+ return 1;
}
- return 1;
+ return 0;
}
-int snd_hwdep_block_mode(snd_hwdep_t *hwdep, int enable)
+/**
+ * \brief set nonblock mode
+ * \param hwdep HwDep handle
+ * \param nonblock 0 = block, 1 = nonblock mode
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_hwdep_nonblock(snd_hwdep_t *hwdep, int nonblock)
{
- long flags;
+ int err;
assert(hwdep);
- if ((flags = fcntl(hwdep->fd, F_GETFL)) < 0)
- return -errno;
- if (enable)
- flags |= O_NONBLOCK;
+ if ((err = hwdep->ops->nonblock(hwdep, nonblock)) < 0)
+ return err;
+ if (nonblock)
+ hwdep->mode |= SND_HWDEP_OPEN_NONBLOCK;
else
- flags &= ~O_NONBLOCK;
- if (fcntl(hwdep->fd, F_SETFL, flags) < 0)
- return -errno;
+ hwdep->mode &= ~SND_HWDEP_OPEN_NONBLOCK;
return 0;
}
-int snd_hwdep_info(snd_hwdep_t *hwdep, snd_hwdep_info_t *info)
+/**
+ * \brief get size of the snd_hwdep_info_t structure in bytes
+ * \return size of the snd_hwdep_info_t structure in bytes
+ */
+size_t snd_hwdep_info_sizeof()
{
- assert(hwdep && info);
- if (ioctl(hwdep->fd, SNDRV_HWDEP_IOCTL_INFO, info) < 0)
- return -errno;
+ return sizeof(snd_hwdep_info_t);
+}
+
+/**
+ * \brief allocate a new snd_hwdep_info_t structure
+ * \param ptr returned pointer
+ * \return 0 on success otherwise a negative error code if fails
+ *
+ * Allocates a new snd_hwdep_info_t structure using the standard
+ * malloc C library function.
+ */
+int snd_hwdep_info_malloc(snd_hwdep_info_t **info)
+{
+ assert(info);
+ *info = calloc(1, sizeof(snd_hwdep_info_t));
+ if (!*info)
+ return -ENOMEM;
return 0;
}
+/**
+ * \brief frees the snd_hwdep_info_t structure
+ * \param info pointer to the snd_hwdep_info_t structure to free
+ *
+ * Frees the given snd_hwdep_info_t structure using the standard
+ * free C library function.
+ */
+void snd_hwdep_info_free(snd_hwdep_info_t *info)
+{
+ assert(info);
+ free(info);
+}
+
+/**
+ * \brief copy one snd_hwdep_info_t structure to another
+ * \param dst destination snd_hwdep_info_t structure
+ * \param src source snd_hwdep_info_t structure
+ */
+void snd_hwdep_info_copy(snd_hwdep_info_t *dst, const snd_hwdep_info_t *src)
+{
+ assert(dst && src);
+ *dst = *src;
+}
+
+/**
+ * \brief get hwdep card number
+ * \param info pointer to a snd_hwdep_info_t structure
+ * \return hwdep card number
+ */
+int snd_hwdep_info_get_card(const snd_hwdep_info_t *obj)
+{
+ assert(obj);
+ return obj->card;
+}
+
+/**
+ * \brief get hwdep device number
+ * \param info pointer to a snd_hwdep_info_t structure
+ * \return hwdep device number
+ */
+unsigned int snd_hwdep_info_get_device(const snd_hwdep_info_t *info)
+{
+ assert(info);
+ return info->device;
+}
+
+/**
+ * \brief get hwdep driver identifier
+ * \param info pointer to a snd_hwdep_info_t structure
+ * \return hwdep driver identifier
+ */
+const char *snd_hwdep_info_get_id(const snd_hwdep_info_t *obj)
+{
+ assert(obj);
+ return obj->id;
+}
+
+/**
+ * \brief get hwdep driver name
+ * \param info pointer to a snd_hwdep_info_t structure
+ * \return hwdep driver name
+ */
+const char *snd_hwdep_info_get_name(const snd_hwdep_info_t *obj)
+{
+ assert(obj);
+ return obj->name;
+}
+
+/**
+ * \brief get hwdep protocol interface
+ * \param info pointer to a snd_hwdep_info_t structure
+ * \return hwdep protocol interface
+ */
+snd_hwdep_iface_t snd_hwdep_info_get_iface(const snd_hwdep_info_t *obj)
+{
+ assert(obj);
+ return obj->iface;
+}
+
+/**
+ * \brief set hwdep device number
+ * \param info pointer to a snd_hwdep_info_t structure
+ * \param val hwdep device
+ */
+void snd_hwdep_info_set_device(snd_hwdep_info_t *obj, unsigned int val)
+{
+ assert(obj);
+ obj->device = val;
+}
+
+/**
+ * \brief get information about HwDep handle
+ * \param hwdep HwDep handle
+ * \param info pointer to a snd_hwdep_info_t structure to be filled
+ * \return 0 on success otherwise a negative error code
+ */
+int snd_hwdep_info(snd_hwdep_t *hwdep, snd_hwdep_info_t * info)
+{
+ assert(hwdep);
+ assert(info);
+ return hwdep->ops->info(hwdep, info);
+}
+
+/**
+ * \brief do hardware dependent ioctl
+ * \param hwdep HwDep handle
+ * \param request ioctl command
+ * \param arg ioctl argument
+ * \return 0 on success otherwise a negative error code
+ */
int snd_hwdep_ioctl(snd_hwdep_t *hwdep, unsigned int request, void * arg)
{
assert(hwdep);
- if (ioctl(hwdep->fd, request, arg) < 0)
- return -errno;
- return 0;
+ return hwdep->ops->ioctl(hwdep, request, arg);
}
+/**
+ * \brief write bytes using HwDep handle
+ * \param hwdep HwDep handle
+ * \param buffer buffer containing bytes to write
+ * \param size output buffer size in bytes
+ */
ssize_t snd_hwdep_write(snd_hwdep_t *hwdep, const void *buffer, size_t size)
{
- ssize_t result;
- assert(hwdep && (buffer || size == 0));
- result = write(hwdep->fd, buffer, size);
- if (result < 0)
- return -errno;
- return result;
+ assert(hwdep);
+ assert(((hwdep->mode & O_ACCMODE) == O_WRONLY) || ((hwdep->mode & O_ACCMODE) == O_RDWR));
+ assert(buffer || size == 0);
+ return hwdep->ops->write(hwdep, buffer, size);
}
+/**
+ * \brief read bytes using HwDep handle
+ * \param hwdep HwDep handle
+ * \param buffer buffer to store the input bytes
+ * \param size input buffer size in bytes
+ */
ssize_t snd_hwdep_read(snd_hwdep_t *hwdep, void *buffer, size_t size)
{
- ssize_t result;
- assert(hwdep && (buffer || size == 0));
- result = read(hwdep->fd, buffer, size);
- if (result < 0)
- return -errno;
- return result;
+ assert(hwdep);
+ assert(((hwdep->mode & O_ACCMODE) == O_RDONLY) || ((hwdep->mode & O_ACCMODE) == O_RDWR));
+ assert(buffer || size == 0);
+ return hwdep->ops->read(hwdep, buffer, size);
}
--- /dev/null
+/*
+ * Hardware dependent Interface - main file for hardware access
+ * Copyright (c) 2001 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.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "hwdep_local.h"
+
+#define SNDRV_FILE_HWDEP "/dev/snd/hwC%iD%i"
+#define SNDRV_HWDEP_VERSION_MAX SNDRV_PROTOCOL_VERSION(1, 0, 0)
+
+static int snd_hwdep_hw_close(snd_hwdep_t *hwdep)
+{
+ int res;
+ assert(hwdep);
+ res = close(hwdep->poll_fd) < 0 ? -errno : 0;
+ free(hwdep);
+ return res;
+}
+
+static int snd_hwdep_hw_nonblock(snd_hwdep_t *hwdep, int nonblock)
+{
+ long flags;
+ assert(hwdep);
+ if ((flags = fcntl(hwdep->poll_fd, F_GETFL)) < 0)
+ return -errno;
+ if (nonblock)
+ flags |= O_NONBLOCK;
+ else
+ flags &= ~O_NONBLOCK;
+ if (fcntl(hwdep->poll_fd, F_SETFL, flags) < 0)
+ return -errno;
+ return 0;
+}
+
+static int snd_hwdep_hw_info(snd_hwdep_t *hwdep, snd_hwdep_info_t *info)
+{
+ assert(hwdep && info);
+ if (ioctl(hwdep->poll_fd, SNDRV_HWDEP_IOCTL_INFO, info) < 0)
+ return -errno;
+ return 0;
+}
+
+static int snd_hwdep_hw_ioctl(snd_hwdep_t *hwdep, unsigned int request, void * arg)
+{
+ assert(hwdep);
+ if (ioctl(hwdep->poll_fd, request, arg) < 0)
+ return -errno;
+ return 0;
+}
+
+static ssize_t snd_hwdep_hw_write(snd_hwdep_t *hwdep, const void *buffer, size_t size)
+{
+ ssize_t result;
+ assert(hwdep && (buffer || size == 0));
+ result = write(hwdep->poll_fd, buffer, size);
+ if (result < 0)
+ return -errno;
+ return result;
+}
+
+static ssize_t snd_hwdep_hw_read(snd_hwdep_t *hwdep, void *buffer, size_t size)
+{
+ ssize_t result;
+ assert(hwdep && (buffer || size == 0));
+ result = read(hwdep->poll_fd, buffer, size);
+ if (result < 0)
+ return -errno;
+ return result;
+}
+
+static snd_hwdep_ops_t snd_hwdep_hw_ops = {
+ close: snd_hwdep_hw_close,
+ nonblock: snd_hwdep_hw_nonblock,
+ info: snd_hwdep_hw_info,
+ ioctl: snd_hwdep_hw_ioctl,
+ write: snd_hwdep_hw_write,
+ read: snd_hwdep_hw_read,
+};
+
+int snd_hwdep_hw_open(snd_hwdep_t **handle, const char *name, int card, int device, int mode)
+{
+ int fd, ver;
+ char filename[32];
+ snd_hwdep_t *hwdep;
+ assert(handle);
+
+ *handle = NULL;
+
+ if (card < 0 || card >= 32)
+ return -EINVAL;
+ sprintf(filename, SNDRV_FILE_HWDEP, card, device);
+ if ((fd = open(filename, mode)) < 0) {
+ snd_card_load(card);
+ if ((fd = open(filename, mode)) < 0)
+ return -errno;
+ }
+ if (ioctl(fd, SNDRV_HWDEP_IOCTL_PVERSION, &ver) < 0) {
+ close(fd);
+ return -errno;
+ }
+ if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_HWDEP_VERSION_MAX)) {
+ close(fd);
+ return -SND_ERROR_INCOMPATIBLE_VERSION;
+ }
+ hwdep = (snd_hwdep_t *) calloc(1, sizeof(snd_hwdep_t));
+ if (hwdep == NULL) {
+ close(fd);
+ return -ENOMEM;
+ }
+ hwdep->name = strdup(name);
+ hwdep->poll_fd = fd;
+ hwdep->mode = mode;
+ hwdep->type = SND_HWDEP_TYPE_HW;
+ hwdep->ops = &snd_hwdep_hw_ops;
+ *handle = hwdep;
+ return 0;
+}
+
+int _snd_hwdep_hw_open(snd_hwdep_t **hwdep, char *name,
+ snd_config_t *root ATTRIBUTE_UNUSED,
+ snd_config_t *conf, int mode)
+{
+ snd_config_iterator_t i, next;
+ long card = -1, device = 0;
+ const char *str;
+ int err;
+ snd_config_for_each(i, next, conf) {
+ snd_config_t *n = snd_config_iterator_entry(i);
+ const char *id = snd_config_get_id(n);
+ if (strcmp(id, "comment") == 0)
+ continue;
+ if (strcmp(id, "type") == 0)
+ continue;
+ if (strcmp(id, "card") == 0) {
+ err = snd_config_get_integer(n, &card);
+ if (err < 0) {
+ err = snd_config_get_string(n, &str);
+ if (err < 0)
+ return -EINVAL;
+ card = snd_card_get_index(str);
+ if (card < 0)
+ return card;
+ }
+ continue;
+ }
+ if (strcmp(id, "device") == 0) {
+ err = snd_config_get_integer(n, &device);
+ if (err < 0)
+ return err;
+ continue;
+ }
+ SNDERR("Unexpected field %s", id);
+ return -EINVAL;
+ }
+ if (card < 0)
+ return -EINVAL;
+ return snd_hwdep_hw_open(hwdep, name, card, device, mode);
+}