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