1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file control/control_hw.c 3d5ac70f0Sopenharmony_ci * \brief CTL HW Plugin Interface 4d5ac70f0Sopenharmony_ci * \author Jaroslav Kysela <perex@perex.cz> 5d5ac70f0Sopenharmony_ci * \date 2000 6d5ac70f0Sopenharmony_ci */ 7d5ac70f0Sopenharmony_ci/* 8d5ac70f0Sopenharmony_ci * Control Interface - Hardware 9d5ac70f0Sopenharmony_ci * Copyright (c) 1998,1999,2000 by Jaroslav Kysela <perex@perex.cz> 10d5ac70f0Sopenharmony_ci * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org> 11d5ac70f0Sopenharmony_ci * 12d5ac70f0Sopenharmony_ci * 13d5ac70f0Sopenharmony_ci * This library is free software; you can redistribute it and/or modify 14d5ac70f0Sopenharmony_ci * it under the terms of the GNU Lesser General Public License as 15d5ac70f0Sopenharmony_ci * published by the Free Software Foundation; either version 2.1 of 16d5ac70f0Sopenharmony_ci * the License, or (at your option) any later version. 17d5ac70f0Sopenharmony_ci * 18d5ac70f0Sopenharmony_ci * This program is distributed in the hope that it will be useful, 19d5ac70f0Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 20d5ac70f0Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21d5ac70f0Sopenharmony_ci * GNU Lesser General Public License for more details. 22d5ac70f0Sopenharmony_ci * 23d5ac70f0Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public 24d5ac70f0Sopenharmony_ci * License along with this library; if not, write to the Free Software 25d5ac70f0Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 26d5ac70f0Sopenharmony_ci * 27d5ac70f0Sopenharmony_ci */ 28d5ac70f0Sopenharmony_ci 29d5ac70f0Sopenharmony_ci#include "control_local.h" 30d5ac70f0Sopenharmony_ci#include <stdio.h> 31d5ac70f0Sopenharmony_ci#include <stdlib.h> 32d5ac70f0Sopenharmony_ci#include <unistd.h> 33d5ac70f0Sopenharmony_ci#include <signal.h> 34d5ac70f0Sopenharmony_ci#include <string.h> 35d5ac70f0Sopenharmony_ci#include <fcntl.h> 36d5ac70f0Sopenharmony_ci#include <sys/ioctl.h> 37d5ac70f0Sopenharmony_ci 38d5ac70f0Sopenharmony_ci#ifndef PIC 39d5ac70f0Sopenharmony_ci/* entry for static linking */ 40d5ac70f0Sopenharmony_ciconst char *_snd_module_control_hw = ""; 41d5ac70f0Sopenharmony_ci#endif 42d5ac70f0Sopenharmony_ci 43d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 44d5ac70f0Sopenharmony_ci 45d5ac70f0Sopenharmony_ci#ifndef F_SETSIG 46d5ac70f0Sopenharmony_ci#define F_SETSIG 10 47d5ac70f0Sopenharmony_ci#endif 48d5ac70f0Sopenharmony_ci 49d5ac70f0Sopenharmony_ci#define SNDRV_FILE_CONTROL ALSA_DEVICE_DIRECTORY "controlC%i" 50d5ac70f0Sopenharmony_ci#define SNDRV_CTL_VERSION_MAX SNDRV_PROTOCOL_VERSION(2, 0, 4) 51d5ac70f0Sopenharmony_ci 52d5ac70f0Sopenharmony_citypedef struct { 53d5ac70f0Sopenharmony_ci int card; 54d5ac70f0Sopenharmony_ci int fd; 55d5ac70f0Sopenharmony_ci unsigned int protocol; 56d5ac70f0Sopenharmony_ci} snd_ctl_hw_t; 57d5ac70f0Sopenharmony_ci#endif /* DOC_HIDDEN */ 58d5ac70f0Sopenharmony_ci 59d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_close(snd_ctl_t *handle) 60d5ac70f0Sopenharmony_ci{ 61d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 62d5ac70f0Sopenharmony_ci int res; 63d5ac70f0Sopenharmony_ci res = close(hw->fd) < 0 ? -errno : 0; 64d5ac70f0Sopenharmony_ci free(hw); 65d5ac70f0Sopenharmony_ci return res; 66d5ac70f0Sopenharmony_ci} 67d5ac70f0Sopenharmony_ci 68d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_nonblock(snd_ctl_t *handle, int nonblock) 69d5ac70f0Sopenharmony_ci{ 70d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 71d5ac70f0Sopenharmony_ci long flags; 72d5ac70f0Sopenharmony_ci int fd = hw->fd; 73d5ac70f0Sopenharmony_ci if ((flags = fcntl(fd, F_GETFL)) < 0) { 74d5ac70f0Sopenharmony_ci SYSERR("F_GETFL failed"); 75d5ac70f0Sopenharmony_ci return -errno; 76d5ac70f0Sopenharmony_ci } 77d5ac70f0Sopenharmony_ci if (nonblock) 78d5ac70f0Sopenharmony_ci flags |= O_NONBLOCK; 79d5ac70f0Sopenharmony_ci else 80d5ac70f0Sopenharmony_ci flags &= ~O_NONBLOCK; 81d5ac70f0Sopenharmony_ci if (fcntl(fd, F_SETFL, flags) < 0) { 82d5ac70f0Sopenharmony_ci SYSERR("F_SETFL for O_NONBLOCK failed"); 83d5ac70f0Sopenharmony_ci return -errno; 84d5ac70f0Sopenharmony_ci } 85d5ac70f0Sopenharmony_ci return 0; 86d5ac70f0Sopenharmony_ci} 87d5ac70f0Sopenharmony_ci 88d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_async(snd_ctl_t *ctl, int sig, pid_t pid) 89d5ac70f0Sopenharmony_ci{ 90d5ac70f0Sopenharmony_ci long flags; 91d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = ctl->private_data; 92d5ac70f0Sopenharmony_ci int fd = hw->fd; 93d5ac70f0Sopenharmony_ci 94d5ac70f0Sopenharmony_ci if ((flags = fcntl(fd, F_GETFL)) < 0) { 95d5ac70f0Sopenharmony_ci SYSERR("F_GETFL failed"); 96d5ac70f0Sopenharmony_ci return -errno; 97d5ac70f0Sopenharmony_ci } 98d5ac70f0Sopenharmony_ci if (sig >= 0) 99d5ac70f0Sopenharmony_ci flags |= O_ASYNC; 100d5ac70f0Sopenharmony_ci else 101d5ac70f0Sopenharmony_ci flags &= ~O_ASYNC; 102d5ac70f0Sopenharmony_ci if (fcntl(fd, F_SETFL, flags) < 0) { 103d5ac70f0Sopenharmony_ci SYSERR("F_SETFL for O_ASYNC failed"); 104d5ac70f0Sopenharmony_ci return -errno; 105d5ac70f0Sopenharmony_ci } 106d5ac70f0Sopenharmony_ci if (sig < 0) 107d5ac70f0Sopenharmony_ci return 0; 108d5ac70f0Sopenharmony_ci if (fcntl(fd, F_SETSIG, (long)sig) < 0) { 109d5ac70f0Sopenharmony_ci SYSERR("F_SETSIG failed"); 110d5ac70f0Sopenharmony_ci return -errno; 111d5ac70f0Sopenharmony_ci } 112d5ac70f0Sopenharmony_ci if (fcntl(fd, F_SETOWN, (long)pid) < 0) { 113d5ac70f0Sopenharmony_ci SYSERR("F_SETOWN failed"); 114d5ac70f0Sopenharmony_ci return -errno; 115d5ac70f0Sopenharmony_ci } 116d5ac70f0Sopenharmony_ci return 0; 117d5ac70f0Sopenharmony_ci} 118d5ac70f0Sopenharmony_ci 119d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_subscribe_events(snd_ctl_t *handle, int subscribe) 120d5ac70f0Sopenharmony_ci{ 121d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 122d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS, &subscribe) < 0) { 123d5ac70f0Sopenharmony_ci SYSERR("SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS failed"); 124d5ac70f0Sopenharmony_ci return -errno; 125d5ac70f0Sopenharmony_ci } 126d5ac70f0Sopenharmony_ci return 0; 127d5ac70f0Sopenharmony_ci} 128d5ac70f0Sopenharmony_ci 129d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_card_info(snd_ctl_t *handle, snd_ctl_card_info_t *info) 130d5ac70f0Sopenharmony_ci{ 131d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 132d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_CARD_INFO, info) < 0) { 133d5ac70f0Sopenharmony_ci SYSERR("SNDRV_CTL_IOCTL_CARD_INFO failed"); 134d5ac70f0Sopenharmony_ci return -errno; 135d5ac70f0Sopenharmony_ci } 136d5ac70f0Sopenharmony_ci return 0; 137d5ac70f0Sopenharmony_ci} 138d5ac70f0Sopenharmony_ci 139d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_elem_list(snd_ctl_t *handle, snd_ctl_elem_list_t *list) 140d5ac70f0Sopenharmony_ci{ 141d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 142d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_ELEM_LIST, list) < 0) 143d5ac70f0Sopenharmony_ci return -errno; 144d5ac70f0Sopenharmony_ci return 0; 145d5ac70f0Sopenharmony_ci} 146d5ac70f0Sopenharmony_ci 147d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_elem_info(snd_ctl_t *handle, snd_ctl_elem_info_t *info) 148d5ac70f0Sopenharmony_ci{ 149d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 150d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_ELEM_INFO, info) < 0) 151d5ac70f0Sopenharmony_ci return -errno; 152d5ac70f0Sopenharmony_ci return 0; 153d5ac70f0Sopenharmony_ci} 154d5ac70f0Sopenharmony_ci 155d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_elem_add(snd_ctl_t *handle, snd_ctl_elem_info_t *info) 156d5ac70f0Sopenharmony_ci{ 157d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 158d5ac70f0Sopenharmony_ci 159d5ac70f0Sopenharmony_ci if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED && 160d5ac70f0Sopenharmony_ci hw->protocol < SNDRV_PROTOCOL_VERSION(2, 0, 7)) 161d5ac70f0Sopenharmony_ci return -ENXIO; 162d5ac70f0Sopenharmony_ci 163d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_ELEM_ADD, info) < 0) 164d5ac70f0Sopenharmony_ci return -errno; 165d5ac70f0Sopenharmony_ci return 0; 166d5ac70f0Sopenharmony_ci} 167d5ac70f0Sopenharmony_ci 168d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_elem_replace(snd_ctl_t *handle, snd_ctl_elem_info_t *info) 169d5ac70f0Sopenharmony_ci{ 170d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 171d5ac70f0Sopenharmony_ci 172d5ac70f0Sopenharmony_ci if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED && 173d5ac70f0Sopenharmony_ci hw->protocol < SNDRV_PROTOCOL_VERSION(2, 0, 7)) 174d5ac70f0Sopenharmony_ci return -ENXIO; 175d5ac70f0Sopenharmony_ci 176d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_ELEM_REPLACE, info) < 0) 177d5ac70f0Sopenharmony_ci return -errno; 178d5ac70f0Sopenharmony_ci return 0; 179d5ac70f0Sopenharmony_ci} 180d5ac70f0Sopenharmony_ci 181d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_elem_remove(snd_ctl_t *handle, snd_ctl_elem_id_t *id) 182d5ac70f0Sopenharmony_ci{ 183d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 184d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_ELEM_REMOVE, id) < 0) 185d5ac70f0Sopenharmony_ci return -errno; 186d5ac70f0Sopenharmony_ci return 0; 187d5ac70f0Sopenharmony_ci} 188d5ac70f0Sopenharmony_ci 189d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_elem_read(snd_ctl_t *handle, snd_ctl_elem_value_t *control) 190d5ac70f0Sopenharmony_ci{ 191d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 192d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_ELEM_READ, control) < 0) 193d5ac70f0Sopenharmony_ci return -errno; 194d5ac70f0Sopenharmony_ci return 0; 195d5ac70f0Sopenharmony_ci} 196d5ac70f0Sopenharmony_ci 197d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_elem_write(snd_ctl_t *handle, snd_ctl_elem_value_t *control) 198d5ac70f0Sopenharmony_ci{ 199d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 200d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, control) < 0) 201d5ac70f0Sopenharmony_ci return -errno; 202d5ac70f0Sopenharmony_ci return 0; 203d5ac70f0Sopenharmony_ci} 204d5ac70f0Sopenharmony_ci 205d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_elem_lock(snd_ctl_t *handle, snd_ctl_elem_id_t *id) 206d5ac70f0Sopenharmony_ci{ 207d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 208d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_ELEM_LOCK, id) < 0) 209d5ac70f0Sopenharmony_ci return -errno; 210d5ac70f0Sopenharmony_ci return 0; 211d5ac70f0Sopenharmony_ci} 212d5ac70f0Sopenharmony_ci 213d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_elem_unlock(snd_ctl_t *handle, snd_ctl_elem_id_t *id) 214d5ac70f0Sopenharmony_ci{ 215d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 216d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_ELEM_UNLOCK, id) < 0) 217d5ac70f0Sopenharmony_ci return -errno; 218d5ac70f0Sopenharmony_ci return 0; 219d5ac70f0Sopenharmony_ci} 220d5ac70f0Sopenharmony_ci 221d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_elem_tlv(snd_ctl_t *handle, int op_flag, 222d5ac70f0Sopenharmony_ci unsigned int numid, 223d5ac70f0Sopenharmony_ci unsigned int *tlv, unsigned int tlv_size) 224d5ac70f0Sopenharmony_ci{ 225d5ac70f0Sopenharmony_ci unsigned int inum; 226d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 227d5ac70f0Sopenharmony_ci struct snd_ctl_tlv *xtlv; 228d5ac70f0Sopenharmony_ci 229d5ac70f0Sopenharmony_ci /* we don't support TLV on protocol ver 2.0.3 or earlier */ 230d5ac70f0Sopenharmony_ci if (hw->protocol < SNDRV_PROTOCOL_VERSION(2, 0, 4)) 231d5ac70f0Sopenharmony_ci return -ENXIO; 232d5ac70f0Sopenharmony_ci 233d5ac70f0Sopenharmony_ci switch (op_flag) { 234d5ac70f0Sopenharmony_ci case -1: inum = SNDRV_CTL_IOCTL_TLV_COMMAND; break; 235d5ac70f0Sopenharmony_ci case 0: inum = SNDRV_CTL_IOCTL_TLV_READ; break; 236d5ac70f0Sopenharmony_ci case 1: inum = SNDRV_CTL_IOCTL_TLV_WRITE; break; 237d5ac70f0Sopenharmony_ci default: return -EINVAL; 238d5ac70f0Sopenharmony_ci } 239d5ac70f0Sopenharmony_ci xtlv = malloc(sizeof(struct snd_ctl_tlv) + tlv_size); 240d5ac70f0Sopenharmony_ci if (xtlv == NULL) 241d5ac70f0Sopenharmony_ci return -ENOMEM; 242d5ac70f0Sopenharmony_ci xtlv->numid = numid; 243d5ac70f0Sopenharmony_ci xtlv->length = tlv_size; 244d5ac70f0Sopenharmony_ci memcpy(xtlv->tlv, tlv, tlv_size); 245d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, inum, xtlv) < 0) { 246d5ac70f0Sopenharmony_ci free(xtlv); 247d5ac70f0Sopenharmony_ci return -errno; 248d5ac70f0Sopenharmony_ci } 249d5ac70f0Sopenharmony_ci if (op_flag == 0) { 250d5ac70f0Sopenharmony_ci unsigned int size; 251d5ac70f0Sopenharmony_ci size = xtlv->tlv[SNDRV_CTL_TLVO_LEN] + 2 * sizeof(unsigned int); 252d5ac70f0Sopenharmony_ci if (size > tlv_size) { 253d5ac70f0Sopenharmony_ci free(xtlv); 254d5ac70f0Sopenharmony_ci return -EFAULT; 255d5ac70f0Sopenharmony_ci } 256d5ac70f0Sopenharmony_ci memcpy(tlv, xtlv->tlv, size); 257d5ac70f0Sopenharmony_ci } 258d5ac70f0Sopenharmony_ci free(xtlv); 259d5ac70f0Sopenharmony_ci return 0; 260d5ac70f0Sopenharmony_ci} 261d5ac70f0Sopenharmony_ci 262d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_hwdep_next_device(snd_ctl_t *handle, int * device) 263d5ac70f0Sopenharmony_ci{ 264d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 265d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE, device) < 0) 266d5ac70f0Sopenharmony_ci return -errno; 267d5ac70f0Sopenharmony_ci return 0; 268d5ac70f0Sopenharmony_ci} 269d5ac70f0Sopenharmony_ci 270d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_hwdep_info(snd_ctl_t *handle, snd_hwdep_info_t * info) 271d5ac70f0Sopenharmony_ci{ 272d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 273d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_HWDEP_INFO, info) < 0) 274d5ac70f0Sopenharmony_ci return -errno; 275d5ac70f0Sopenharmony_ci return 0; 276d5ac70f0Sopenharmony_ci} 277d5ac70f0Sopenharmony_ci 278d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_pcm_next_device(snd_ctl_t *handle, int * device) 279d5ac70f0Sopenharmony_ci{ 280d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 281d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE, device) < 0) 282d5ac70f0Sopenharmony_ci return -errno; 283d5ac70f0Sopenharmony_ci return 0; 284d5ac70f0Sopenharmony_ci} 285d5ac70f0Sopenharmony_ci 286d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_pcm_info(snd_ctl_t *handle, snd_pcm_info_t * info) 287d5ac70f0Sopenharmony_ci{ 288d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 289d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_PCM_INFO, info) < 0) 290d5ac70f0Sopenharmony_ci return -errno; 291d5ac70f0Sopenharmony_ci /* may be configurable (optional) */ 292d5ac70f0Sopenharmony_ci if (__snd_pcm_info_eld_fixup_check(info)) 293d5ac70f0Sopenharmony_ci return __snd_pcm_info_eld_fixup(info); 294d5ac70f0Sopenharmony_ci return 0; 295d5ac70f0Sopenharmony_ci} 296d5ac70f0Sopenharmony_ci 297d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_pcm_prefer_subdevice(snd_ctl_t *handle, int subdev) 298d5ac70f0Sopenharmony_ci{ 299d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 300d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE, &subdev) < 0) 301d5ac70f0Sopenharmony_ci return -errno; 302d5ac70f0Sopenharmony_ci return 0; 303d5ac70f0Sopenharmony_ci} 304d5ac70f0Sopenharmony_ci 305d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_rawmidi_next_device(snd_ctl_t *handle, int * device) 306d5ac70f0Sopenharmony_ci{ 307d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 308d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE, device) < 0) 309d5ac70f0Sopenharmony_ci return -errno; 310d5ac70f0Sopenharmony_ci return 0; 311d5ac70f0Sopenharmony_ci} 312d5ac70f0Sopenharmony_ci 313d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_rawmidi_info(snd_ctl_t *handle, snd_rawmidi_info_t * info) 314d5ac70f0Sopenharmony_ci{ 315d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 316d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_RAWMIDI_INFO, info) < 0) 317d5ac70f0Sopenharmony_ci return -errno; 318d5ac70f0Sopenharmony_ci return 0; 319d5ac70f0Sopenharmony_ci} 320d5ac70f0Sopenharmony_ci 321d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_rawmidi_prefer_subdevice(snd_ctl_t *handle, int subdev) 322d5ac70f0Sopenharmony_ci{ 323d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 324d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE, &subdev) < 0) 325d5ac70f0Sopenharmony_ci return -errno; 326d5ac70f0Sopenharmony_ci return 0; 327d5ac70f0Sopenharmony_ci} 328d5ac70f0Sopenharmony_ci 329d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_ump_next_device(snd_ctl_t *handle, int *device) 330d5ac70f0Sopenharmony_ci{ 331d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 332d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_UMP_NEXT_DEVICE, device) < 0) 333d5ac70f0Sopenharmony_ci return -errno; 334d5ac70f0Sopenharmony_ci return 0; 335d5ac70f0Sopenharmony_ci} 336d5ac70f0Sopenharmony_ci 337d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_ump_endpoint_info(snd_ctl_t *handle, 338d5ac70f0Sopenharmony_ci snd_ump_endpoint_info_t *info) 339d5ac70f0Sopenharmony_ci{ 340d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 341d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_UMP_ENDPOINT_INFO, info) < 0) 342d5ac70f0Sopenharmony_ci return -errno; 343d5ac70f0Sopenharmony_ci return 0; 344d5ac70f0Sopenharmony_ci} 345d5ac70f0Sopenharmony_ci 346d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_ump_block_info(snd_ctl_t *handle, 347d5ac70f0Sopenharmony_ci snd_ump_block_info_t *info) 348d5ac70f0Sopenharmony_ci{ 349d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 350d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_UMP_BLOCK_INFO, info) < 0) 351d5ac70f0Sopenharmony_ci return -errno; 352d5ac70f0Sopenharmony_ci return 0; 353d5ac70f0Sopenharmony_ci} 354d5ac70f0Sopenharmony_ci 355d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_set_power_state(snd_ctl_t *handle, unsigned int state) 356d5ac70f0Sopenharmony_ci{ 357d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 358d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_POWER, &state) < 0) 359d5ac70f0Sopenharmony_ci return -errno; 360d5ac70f0Sopenharmony_ci return 0; 361d5ac70f0Sopenharmony_ci} 362d5ac70f0Sopenharmony_ci 363d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_get_power_state(snd_ctl_t *handle, unsigned int *state) 364d5ac70f0Sopenharmony_ci{ 365d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 366d5ac70f0Sopenharmony_ci if (ioctl(hw->fd, SNDRV_CTL_IOCTL_POWER_STATE, state) < 0) 367d5ac70f0Sopenharmony_ci return -errno; 368d5ac70f0Sopenharmony_ci return 0; 369d5ac70f0Sopenharmony_ci} 370d5ac70f0Sopenharmony_ci 371d5ac70f0Sopenharmony_cistatic int snd_ctl_hw_read(snd_ctl_t *handle, snd_ctl_event_t *event) 372d5ac70f0Sopenharmony_ci{ 373d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw = handle->private_data; 374d5ac70f0Sopenharmony_ci ssize_t res = read(hw->fd, event, sizeof(*event)); 375d5ac70f0Sopenharmony_ci if (res <= 0) 376d5ac70f0Sopenharmony_ci return -errno; 377d5ac70f0Sopenharmony_ci if (CHECK_SANITY(res != sizeof(*event))) { 378d5ac70f0Sopenharmony_ci SNDMSG("snd_ctl_hw_read: read size error (req:%d, got:%d)", 379d5ac70f0Sopenharmony_ci sizeof(*event), res); 380d5ac70f0Sopenharmony_ci return -EINVAL; 381d5ac70f0Sopenharmony_ci } 382d5ac70f0Sopenharmony_ci return 1; 383d5ac70f0Sopenharmony_ci} 384d5ac70f0Sopenharmony_ci 385d5ac70f0Sopenharmony_cistatic const snd_ctl_ops_t snd_ctl_hw_ops = { 386d5ac70f0Sopenharmony_ci .close = snd_ctl_hw_close, 387d5ac70f0Sopenharmony_ci .nonblock = snd_ctl_hw_nonblock, 388d5ac70f0Sopenharmony_ci .async = snd_ctl_hw_async, 389d5ac70f0Sopenharmony_ci .subscribe_events = snd_ctl_hw_subscribe_events, 390d5ac70f0Sopenharmony_ci .card_info = snd_ctl_hw_card_info, 391d5ac70f0Sopenharmony_ci .element_list = snd_ctl_hw_elem_list, 392d5ac70f0Sopenharmony_ci .element_info = snd_ctl_hw_elem_info, 393d5ac70f0Sopenharmony_ci .element_add = snd_ctl_hw_elem_add, 394d5ac70f0Sopenharmony_ci .element_replace = snd_ctl_hw_elem_replace, 395d5ac70f0Sopenharmony_ci .element_remove = snd_ctl_hw_elem_remove, 396d5ac70f0Sopenharmony_ci .element_read = snd_ctl_hw_elem_read, 397d5ac70f0Sopenharmony_ci .element_write = snd_ctl_hw_elem_write, 398d5ac70f0Sopenharmony_ci .element_lock = snd_ctl_hw_elem_lock, 399d5ac70f0Sopenharmony_ci .element_unlock = snd_ctl_hw_elem_unlock, 400d5ac70f0Sopenharmony_ci .element_tlv = snd_ctl_hw_elem_tlv, 401d5ac70f0Sopenharmony_ci .hwdep_next_device = snd_ctl_hw_hwdep_next_device, 402d5ac70f0Sopenharmony_ci .hwdep_info = snd_ctl_hw_hwdep_info, 403d5ac70f0Sopenharmony_ci .pcm_next_device = snd_ctl_hw_pcm_next_device, 404d5ac70f0Sopenharmony_ci .pcm_info = snd_ctl_hw_pcm_info, 405d5ac70f0Sopenharmony_ci .pcm_prefer_subdevice = snd_ctl_hw_pcm_prefer_subdevice, 406d5ac70f0Sopenharmony_ci .rawmidi_next_device = snd_ctl_hw_rawmidi_next_device, 407d5ac70f0Sopenharmony_ci .rawmidi_info = snd_ctl_hw_rawmidi_info, 408d5ac70f0Sopenharmony_ci .rawmidi_prefer_subdevice = snd_ctl_hw_rawmidi_prefer_subdevice, 409d5ac70f0Sopenharmony_ci .ump_next_device = snd_ctl_hw_ump_next_device, 410d5ac70f0Sopenharmony_ci .ump_endpoint_info = snd_ctl_hw_ump_endpoint_info, 411d5ac70f0Sopenharmony_ci .ump_block_info = snd_ctl_hw_ump_block_info, 412d5ac70f0Sopenharmony_ci .set_power_state = snd_ctl_hw_set_power_state, 413d5ac70f0Sopenharmony_ci .get_power_state = snd_ctl_hw_get_power_state, 414d5ac70f0Sopenharmony_ci .read = snd_ctl_hw_read, 415d5ac70f0Sopenharmony_ci}; 416d5ac70f0Sopenharmony_ci 417d5ac70f0Sopenharmony_ci/** 418d5ac70f0Sopenharmony_ci * \brief Creates a new hw control 419d5ac70f0Sopenharmony_ci * \param handle Returns created control handle 420d5ac70f0Sopenharmony_ci * \param name Name of control device 421d5ac70f0Sopenharmony_ci * \param card Number of card 422d5ac70f0Sopenharmony_ci * \param mode Control mode 423d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code 424d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 425d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 426d5ac70f0Sopenharmony_ci * changed in future. 427d5ac70f0Sopenharmony_ci */ 428d5ac70f0Sopenharmony_ciint snd_ctl_hw_open(snd_ctl_t **handle, const char *name, int card, int mode) 429d5ac70f0Sopenharmony_ci{ 430d5ac70f0Sopenharmony_ci int fd, ver; 431d5ac70f0Sopenharmony_ci char filename[sizeof(SNDRV_FILE_CONTROL) + 10]; 432d5ac70f0Sopenharmony_ci int fmode; 433d5ac70f0Sopenharmony_ci snd_ctl_t *ctl; 434d5ac70f0Sopenharmony_ci snd_ctl_hw_t *hw; 435d5ac70f0Sopenharmony_ci int err; 436d5ac70f0Sopenharmony_ci 437d5ac70f0Sopenharmony_ci *handle = NULL; 438d5ac70f0Sopenharmony_ci 439d5ac70f0Sopenharmony_ci if (CHECK_SANITY(card < 0 || card >= SND_MAX_CARDS)) { 440d5ac70f0Sopenharmony_ci SNDMSG("Invalid card index %d", card); 441d5ac70f0Sopenharmony_ci return -EINVAL; 442d5ac70f0Sopenharmony_ci } 443d5ac70f0Sopenharmony_ci sprintf(filename, SNDRV_FILE_CONTROL, card); 444d5ac70f0Sopenharmony_ci if (mode & SND_CTL_READONLY) 445d5ac70f0Sopenharmony_ci fmode = O_RDONLY; 446d5ac70f0Sopenharmony_ci else 447d5ac70f0Sopenharmony_ci fmode = O_RDWR; 448d5ac70f0Sopenharmony_ci if (mode & SND_CTL_NONBLOCK) 449d5ac70f0Sopenharmony_ci fmode |= O_NONBLOCK; 450d5ac70f0Sopenharmony_ci if (mode & SND_CTL_ASYNC) 451d5ac70f0Sopenharmony_ci fmode |= O_ASYNC; 452d5ac70f0Sopenharmony_ci fd = snd_open_device(filename, fmode); 453d5ac70f0Sopenharmony_ci if (fd < 0) { 454d5ac70f0Sopenharmony_ci snd_card_load(card); 455d5ac70f0Sopenharmony_ci fd = snd_open_device(filename, fmode); 456d5ac70f0Sopenharmony_ci if (fd < 0) 457d5ac70f0Sopenharmony_ci return -errno; 458d5ac70f0Sopenharmony_ci } 459d5ac70f0Sopenharmony_ci if (ioctl(fd, SNDRV_CTL_IOCTL_PVERSION, &ver) < 0) { 460d5ac70f0Sopenharmony_ci err = -errno; 461d5ac70f0Sopenharmony_ci close(fd); 462d5ac70f0Sopenharmony_ci return err; 463d5ac70f0Sopenharmony_ci } 464d5ac70f0Sopenharmony_ci if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_CTL_VERSION_MAX)) { 465d5ac70f0Sopenharmony_ci close(fd); 466d5ac70f0Sopenharmony_ci return -SND_ERROR_INCOMPATIBLE_VERSION; 467d5ac70f0Sopenharmony_ci } 468d5ac70f0Sopenharmony_ci hw = calloc(1, sizeof(snd_ctl_hw_t)); 469d5ac70f0Sopenharmony_ci if (hw == NULL) { 470d5ac70f0Sopenharmony_ci close(fd); 471d5ac70f0Sopenharmony_ci return -ENOMEM; 472d5ac70f0Sopenharmony_ci } 473d5ac70f0Sopenharmony_ci hw->card = card; 474d5ac70f0Sopenharmony_ci hw->fd = fd; 475d5ac70f0Sopenharmony_ci hw->protocol = ver; 476d5ac70f0Sopenharmony_ci 477d5ac70f0Sopenharmony_ci err = snd_ctl_new(&ctl, SND_CTL_TYPE_HW, name, mode); 478d5ac70f0Sopenharmony_ci if (err < 0) { 479d5ac70f0Sopenharmony_ci close(fd); 480d5ac70f0Sopenharmony_ci free(hw); 481d5ac70f0Sopenharmony_ci return err; 482d5ac70f0Sopenharmony_ci } 483d5ac70f0Sopenharmony_ci ctl->ops = &snd_ctl_hw_ops; 484d5ac70f0Sopenharmony_ci ctl->private_data = hw; 485d5ac70f0Sopenharmony_ci ctl->poll_fd = fd; 486d5ac70f0Sopenharmony_ci *handle = ctl; 487d5ac70f0Sopenharmony_ci return 0; 488d5ac70f0Sopenharmony_ci} 489d5ac70f0Sopenharmony_ci 490d5ac70f0Sopenharmony_ci/*! \page control_plugins 491d5ac70f0Sopenharmony_ci 492d5ac70f0Sopenharmony_ci\section control_plugins_hw Plugin: hw 493d5ac70f0Sopenharmony_ci 494d5ac70f0Sopenharmony_ciThis plugin communicates directly with the ALSA kernel driver. It is a raw 495d5ac70f0Sopenharmony_cicommunication without any conversions. 496d5ac70f0Sopenharmony_ci 497d5ac70f0Sopenharmony_ci\code 498d5ac70f0Sopenharmony_cicontrol.name { 499d5ac70f0Sopenharmony_ci type hw # Kernel PCM 500d5ac70f0Sopenharmony_ci card INT/STR # Card name (string) or number (integer) 501d5ac70f0Sopenharmony_ci} 502d5ac70f0Sopenharmony_ci\endcode 503d5ac70f0Sopenharmony_ci 504d5ac70f0Sopenharmony_ci\subsection control_plugins_hw_funcref Function reference 505d5ac70f0Sopenharmony_ci 506d5ac70f0Sopenharmony_ci<UL> 507d5ac70f0Sopenharmony_ci <LI>snd_ctl_hw_open() 508d5ac70f0Sopenharmony_ci <LI>_snd_ctl_hw_open() 509d5ac70f0Sopenharmony_ci</UL> 510d5ac70f0Sopenharmony_ci 511d5ac70f0Sopenharmony_ci*/ 512d5ac70f0Sopenharmony_ci 513d5ac70f0Sopenharmony_ci/** 514d5ac70f0Sopenharmony_ci * \brief Creates a new hw control handle 515d5ac70f0Sopenharmony_ci * \param handlep Returns created control handle 516d5ac70f0Sopenharmony_ci * \param name Name of control device 517d5ac70f0Sopenharmony_ci * \param root Root configuration node 518d5ac70f0Sopenharmony_ci * \param conf Configuration node with hw PCM description 519d5ac70f0Sopenharmony_ci * \param mode Control Mode 520d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 521d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 522d5ac70f0Sopenharmony_ci * changed in future. 523d5ac70f0Sopenharmony_ci */ 524d5ac70f0Sopenharmony_ciint _snd_ctl_hw_open(snd_ctl_t **handlep, char *name, snd_config_t *root ATTRIBUTE_UNUSED, snd_config_t *conf, int mode) 525d5ac70f0Sopenharmony_ci{ 526d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 527d5ac70f0Sopenharmony_ci long card = -1; 528d5ac70f0Sopenharmony_ci int err; 529d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, conf) { 530d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 531d5ac70f0Sopenharmony_ci const char *id; 532d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 533d5ac70f0Sopenharmony_ci continue; 534d5ac70f0Sopenharmony_ci if (_snd_conf_generic_id(id)) 535d5ac70f0Sopenharmony_ci continue; 536d5ac70f0Sopenharmony_ci if (strcmp(id, "card") == 0) { 537d5ac70f0Sopenharmony_ci err = snd_config_get_card(n); 538d5ac70f0Sopenharmony_ci if (err < 0) 539d5ac70f0Sopenharmony_ci return err; 540d5ac70f0Sopenharmony_ci card = err; 541d5ac70f0Sopenharmony_ci continue; 542d5ac70f0Sopenharmony_ci } 543d5ac70f0Sopenharmony_ci return -EINVAL; 544d5ac70f0Sopenharmony_ci } 545d5ac70f0Sopenharmony_ci if (card < 0) 546d5ac70f0Sopenharmony_ci return -EINVAL; 547d5ac70f0Sopenharmony_ci return snd_ctl_hw_open(handlep, name, card, mode); 548d5ac70f0Sopenharmony_ci} 549d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 550d5ac70f0Sopenharmony_ciSND_DLSYM_BUILD_VERSION(_snd_ctl_hw_open, SND_CONTROL_DLSYM_VERSION); 551d5ac70f0Sopenharmony_ci#endif 552