1d5ac70f0Sopenharmony_ci/*
2d5ac70f0Sopenharmony_ci *  Hardware dependent Interface - main file for hardware access
3d5ac70f0Sopenharmony_ci *  Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
4d5ac70f0Sopenharmony_ci *
5d5ac70f0Sopenharmony_ci *
6d5ac70f0Sopenharmony_ci *   This library is free software; you can redistribute it and/or modify
7d5ac70f0Sopenharmony_ci *   it under the terms of the GNU Lesser General Public License as
8d5ac70f0Sopenharmony_ci *   published by the Free Software Foundation; either version 2.1 of
9d5ac70f0Sopenharmony_ci *   the License, or (at your option) any later version.
10d5ac70f0Sopenharmony_ci *
11d5ac70f0Sopenharmony_ci *   This program is distributed in the hope that it will be useful,
12d5ac70f0Sopenharmony_ci *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13d5ac70f0Sopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14d5ac70f0Sopenharmony_ci *   GNU Lesser General Public License for more details.
15d5ac70f0Sopenharmony_ci *
16d5ac70f0Sopenharmony_ci *   You should have received a copy of the GNU Lesser General Public
17d5ac70f0Sopenharmony_ci *   License along with this library; if not, write to the Free Software
18d5ac70f0Sopenharmony_ci *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19d5ac70f0Sopenharmony_ci *
20d5ac70f0Sopenharmony_ci */
21d5ac70f0Sopenharmony_ci
22d5ac70f0Sopenharmony_ci#include "hwdep_local.h"
23d5ac70f0Sopenharmony_ci#include <stdio.h>
24d5ac70f0Sopenharmony_ci#include <stdlib.h>
25d5ac70f0Sopenharmony_ci#include <unistd.h>
26d5ac70f0Sopenharmony_ci#include <string.h>
27d5ac70f0Sopenharmony_ci#include <fcntl.h>
28d5ac70f0Sopenharmony_ci#include <sys/ioctl.h>
29d5ac70f0Sopenharmony_ci
30d5ac70f0Sopenharmony_ci#ifndef PIC
31d5ac70f0Sopenharmony_ci/* entry for static linking */
32d5ac70f0Sopenharmony_ciconst char *_snd_module_hwdep_hw = "";
33d5ac70f0Sopenharmony_ci#endif
34d5ac70f0Sopenharmony_ci
35d5ac70f0Sopenharmony_ci#define SNDRV_FILE_HWDEP	ALSA_DEVICE_DIRECTORY "hwC%iD%i"
36d5ac70f0Sopenharmony_ci#define SNDRV_HWDEP_VERSION_MAX	SNDRV_PROTOCOL_VERSION(1, 0, 1)
37d5ac70f0Sopenharmony_ci
38d5ac70f0Sopenharmony_cistatic int snd_hwdep_hw_close(snd_hwdep_t *hwdep)
39d5ac70f0Sopenharmony_ci{
40d5ac70f0Sopenharmony_ci	int res;
41d5ac70f0Sopenharmony_ci	assert(hwdep);
42d5ac70f0Sopenharmony_ci	res = close(hwdep->poll_fd) < 0 ? -errno : 0;
43d5ac70f0Sopenharmony_ci	return res;
44d5ac70f0Sopenharmony_ci}
45d5ac70f0Sopenharmony_ci
46d5ac70f0Sopenharmony_cistatic int snd_hwdep_hw_nonblock(snd_hwdep_t *hwdep, int nonblock)
47d5ac70f0Sopenharmony_ci{
48d5ac70f0Sopenharmony_ci	long flags;
49d5ac70f0Sopenharmony_ci	assert(hwdep);
50d5ac70f0Sopenharmony_ci	if ((flags = fcntl(hwdep->poll_fd, F_GETFL)) < 0)
51d5ac70f0Sopenharmony_ci		return -errno;
52d5ac70f0Sopenharmony_ci	if (nonblock)
53d5ac70f0Sopenharmony_ci		flags |= O_NONBLOCK;
54d5ac70f0Sopenharmony_ci	else
55d5ac70f0Sopenharmony_ci		flags &= ~O_NONBLOCK;
56d5ac70f0Sopenharmony_ci	if (fcntl(hwdep->poll_fd, F_SETFL, flags) < 0)
57d5ac70f0Sopenharmony_ci		return -errno;
58d5ac70f0Sopenharmony_ci	return 0;
59d5ac70f0Sopenharmony_ci}
60d5ac70f0Sopenharmony_ci
61d5ac70f0Sopenharmony_cistatic int snd_hwdep_hw_info(snd_hwdep_t *hwdep, snd_hwdep_info_t *info)
62d5ac70f0Sopenharmony_ci{
63d5ac70f0Sopenharmony_ci	assert(hwdep && info);
64d5ac70f0Sopenharmony_ci	if (ioctl(hwdep->poll_fd, SNDRV_HWDEP_IOCTL_INFO, info) < 0)
65d5ac70f0Sopenharmony_ci		return -errno;
66d5ac70f0Sopenharmony_ci	return 0;
67d5ac70f0Sopenharmony_ci}
68d5ac70f0Sopenharmony_ci
69d5ac70f0Sopenharmony_cistatic int snd_hwdep_hw_ioctl(snd_hwdep_t *hwdep, unsigned int request, void * arg)
70d5ac70f0Sopenharmony_ci{
71d5ac70f0Sopenharmony_ci	assert(hwdep);
72d5ac70f0Sopenharmony_ci	if (ioctl(hwdep->poll_fd, request, arg) < 0)
73d5ac70f0Sopenharmony_ci		return -errno;
74d5ac70f0Sopenharmony_ci	return 0;
75d5ac70f0Sopenharmony_ci}
76d5ac70f0Sopenharmony_ci
77d5ac70f0Sopenharmony_cistatic ssize_t snd_hwdep_hw_write(snd_hwdep_t *hwdep, const void *buffer, size_t size)
78d5ac70f0Sopenharmony_ci{
79d5ac70f0Sopenharmony_ci	ssize_t result;
80d5ac70f0Sopenharmony_ci	assert(hwdep && (buffer || size == 0));
81d5ac70f0Sopenharmony_ci	result = write(hwdep->poll_fd, buffer, size);
82d5ac70f0Sopenharmony_ci	if (result < 0)
83d5ac70f0Sopenharmony_ci		return -errno;
84d5ac70f0Sopenharmony_ci	return result;
85d5ac70f0Sopenharmony_ci}
86d5ac70f0Sopenharmony_ci
87d5ac70f0Sopenharmony_cistatic ssize_t snd_hwdep_hw_read(snd_hwdep_t *hwdep, void *buffer, size_t size)
88d5ac70f0Sopenharmony_ci{
89d5ac70f0Sopenharmony_ci	ssize_t result;
90d5ac70f0Sopenharmony_ci	assert(hwdep && (buffer || size == 0));
91d5ac70f0Sopenharmony_ci	result = read(hwdep->poll_fd, buffer, size);
92d5ac70f0Sopenharmony_ci	if (result < 0)
93d5ac70f0Sopenharmony_ci		return -errno;
94d5ac70f0Sopenharmony_ci	return result;
95d5ac70f0Sopenharmony_ci}
96d5ac70f0Sopenharmony_ci
97d5ac70f0Sopenharmony_cistatic const snd_hwdep_ops_t snd_hwdep_hw_ops = {
98d5ac70f0Sopenharmony_ci	.close = snd_hwdep_hw_close,
99d5ac70f0Sopenharmony_ci	.nonblock = snd_hwdep_hw_nonblock,
100d5ac70f0Sopenharmony_ci	.info = snd_hwdep_hw_info,
101d5ac70f0Sopenharmony_ci	.ioctl = snd_hwdep_hw_ioctl,
102d5ac70f0Sopenharmony_ci	.write = snd_hwdep_hw_write,
103d5ac70f0Sopenharmony_ci	.read = snd_hwdep_hw_read,
104d5ac70f0Sopenharmony_ci};
105d5ac70f0Sopenharmony_ci
106d5ac70f0Sopenharmony_ciint snd_hwdep_hw_open(snd_hwdep_t **handle, const char *name, int card, int device, int mode)
107d5ac70f0Sopenharmony_ci{
108d5ac70f0Sopenharmony_ci	int fd, ver, ret;
109d5ac70f0Sopenharmony_ci	char filename[sizeof(SNDRV_FILE_HWDEP) + 20];
110d5ac70f0Sopenharmony_ci	snd_hwdep_t *hwdep;
111d5ac70f0Sopenharmony_ci	assert(handle);
112d5ac70f0Sopenharmony_ci
113d5ac70f0Sopenharmony_ci	*handle = NULL;
114d5ac70f0Sopenharmony_ci
115d5ac70f0Sopenharmony_ci	if (card < 0 || card >= SND_MAX_CARDS)
116d5ac70f0Sopenharmony_ci		return -EINVAL;
117d5ac70f0Sopenharmony_ci	sprintf(filename, SNDRV_FILE_HWDEP, card, device);
118d5ac70f0Sopenharmony_ci	fd = snd_open_device(filename, mode);
119d5ac70f0Sopenharmony_ci	if (fd < 0) {
120d5ac70f0Sopenharmony_ci		snd_card_load(card);
121d5ac70f0Sopenharmony_ci		fd = snd_open_device(filename, mode);
122d5ac70f0Sopenharmony_ci		if (fd < 0)
123d5ac70f0Sopenharmony_ci			return -errno;
124d5ac70f0Sopenharmony_ci	}
125d5ac70f0Sopenharmony_ci	if (ioctl(fd, SNDRV_HWDEP_IOCTL_PVERSION, &ver) < 0) {
126d5ac70f0Sopenharmony_ci		ret = -errno;
127d5ac70f0Sopenharmony_ci		close(fd);
128d5ac70f0Sopenharmony_ci		return ret;
129d5ac70f0Sopenharmony_ci	}
130d5ac70f0Sopenharmony_ci	if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_HWDEP_VERSION_MAX)) {
131d5ac70f0Sopenharmony_ci		close(fd);
132d5ac70f0Sopenharmony_ci		return -SND_ERROR_INCOMPATIBLE_VERSION;
133d5ac70f0Sopenharmony_ci	}
134d5ac70f0Sopenharmony_ci	hwdep = (snd_hwdep_t *) calloc(1, sizeof(snd_hwdep_t));
135d5ac70f0Sopenharmony_ci	if (hwdep == NULL) {
136d5ac70f0Sopenharmony_ci		close(fd);
137d5ac70f0Sopenharmony_ci		return -ENOMEM;
138d5ac70f0Sopenharmony_ci	}
139d5ac70f0Sopenharmony_ci	hwdep->name = strdup(name);
140d5ac70f0Sopenharmony_ci	hwdep->poll_fd = fd;
141d5ac70f0Sopenharmony_ci	hwdep->mode = mode;
142d5ac70f0Sopenharmony_ci	hwdep->type = SND_HWDEP_TYPE_HW;
143d5ac70f0Sopenharmony_ci	hwdep->ops = &snd_hwdep_hw_ops;
144d5ac70f0Sopenharmony_ci	*handle = hwdep;
145d5ac70f0Sopenharmony_ci	return 0;
146d5ac70f0Sopenharmony_ci}
147d5ac70f0Sopenharmony_ci
148d5ac70f0Sopenharmony_ciint _snd_hwdep_hw_open(snd_hwdep_t **hwdep, char *name,
149d5ac70f0Sopenharmony_ci		       snd_config_t *root ATTRIBUTE_UNUSED,
150d5ac70f0Sopenharmony_ci		       snd_config_t *conf, int mode)
151d5ac70f0Sopenharmony_ci{
152d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
153d5ac70f0Sopenharmony_ci	long card = -1, device = 0;
154d5ac70f0Sopenharmony_ci	int err;
155d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, conf) {
156d5ac70f0Sopenharmony_ci		snd_config_t *n = snd_config_iterator_entry(i);
157d5ac70f0Sopenharmony_ci		const char *id;
158d5ac70f0Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
159d5ac70f0Sopenharmony_ci			continue;
160d5ac70f0Sopenharmony_ci		if (_snd_conf_generic_id(id))
161d5ac70f0Sopenharmony_ci			continue;
162d5ac70f0Sopenharmony_ci		if (strcmp(id, "card") == 0) {
163d5ac70f0Sopenharmony_ci			err = snd_config_get_card(n);
164d5ac70f0Sopenharmony_ci			if (err < 0)
165d5ac70f0Sopenharmony_ci				return err;
166d5ac70f0Sopenharmony_ci			card = err;
167d5ac70f0Sopenharmony_ci			continue;
168d5ac70f0Sopenharmony_ci		}
169d5ac70f0Sopenharmony_ci		if (strcmp(id, "device") == 0) {
170d5ac70f0Sopenharmony_ci			err = snd_config_get_integer(n, &device);
171d5ac70f0Sopenharmony_ci			if (err < 0)
172d5ac70f0Sopenharmony_ci				return err;
173d5ac70f0Sopenharmony_ci			continue;
174d5ac70f0Sopenharmony_ci		}
175d5ac70f0Sopenharmony_ci		SNDERR("Unexpected field %s", id);
176d5ac70f0Sopenharmony_ci		return -EINVAL;
177d5ac70f0Sopenharmony_ci	}
178d5ac70f0Sopenharmony_ci	if (card < 0)
179d5ac70f0Sopenharmony_ci		return -EINVAL;
180d5ac70f0Sopenharmony_ci	return snd_hwdep_hw_open(hwdep, name, card, device, mode);
181d5ac70f0Sopenharmony_ci}
182d5ac70f0Sopenharmony_ciSND_DLSYM_BUILD_VERSION(_snd_hwdep_hw_open, SND_HWDEP_DLSYM_VERSION);
183