Lines Matching defs:*
2 * RawMIDI - Hardware
3 * Copyright (c) 2000 by Jaroslav Kysela <perex@perex.cz>
4 * Abramo Bagnara <abramo@alsa-project.org>
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <fcntl.h>
28 #include <sys/ioctl.h>
29 #include "../control/control_local.h"
30 #include "rawmidi_local.h"
32 #ifndef PIC
33 /* entry for static linking */
34 const char *_snd_module_rawmidi_hw = "";
35 #endif
37 #define SNDRV_FILE_RAWMIDI ALSA_DEVICE_DIRECTORY "midiC%iD%i"
38 #define SNDRV_RAWMIDI_VERSION_MAX SNDRV_PROTOCOL_VERSION(2, 0, 0)
40 #ifndef DOC_HIDDEN
41 typedef struct {
42 int open;
43 int fd;
44 int card, device, subdevice;
45 } snd_rawmidi_hw_t;
46 #endif
48 static int snd_rawmidi_hw_close(snd_rawmidi_t *rmidi)
50 snd_rawmidi_hw_t *hw = rmidi->private_data;
51 int err = 0;
53 hw->open--;
54 if (hw->open)
55 return 0;
56 if (close(hw->fd)) {
57 err = -errno;
58 SYSERR("close failed\n");
60 free(hw);
61 return err;
64 static int snd_rawmidi_hw_nonblock(snd_rawmidi_t *rmidi, int nonblock)
66 snd_rawmidi_hw_t *hw = rmidi->private_data;
67 long flags;
69 if ((flags = fcntl(hw->fd, F_GETFL)) < 0) {
70 SYSERR("F_GETFL failed");
71 return -errno;
73 if (nonblock)
74 flags |= O_NONBLOCK;
75 else
76 flags &= ~O_NONBLOCK;
77 if (fcntl(hw->fd, F_SETFL, flags) < 0) {
78 SYSERR("F_SETFL for O_NONBLOCK failed");
79 return -errno;
81 return 0;
84 static int snd_rawmidi_hw_info(snd_rawmidi_t *rmidi, snd_rawmidi_info_t * info)
86 snd_rawmidi_hw_t *hw = rmidi->private_data;
87 info->stream = rmidi->stream;
88 if (ioctl(hw->fd, SNDRV_RAWMIDI_IOCTL_INFO, info) < 0) {
89 SYSERR("SNDRV_RAWMIDI_IOCTL_INFO failed");
90 return -errno;
92 return 0;
95 static int snd_rawmidi_hw_params(snd_rawmidi_t *rmidi, snd_rawmidi_params_t * params)
97 snd_rawmidi_hw_t *hw = rmidi->private_data;
98 params->stream = rmidi->stream;
99 if (ioctl(hw->fd, SNDRV_RAWMIDI_IOCTL_PARAMS, params) < 0) {
100 SYSERR("SNDRV_RAWMIDI_IOCTL_PARAMS failed");
101 return -errno;
103 return 0;
106 static int snd_rawmidi_hw_status(snd_rawmidi_t *rmidi, snd_rawmidi_status_t * status)
108 snd_rawmidi_hw_t *hw = rmidi->private_data;
109 status->stream = rmidi->stream;
110 if (ioctl(hw->fd, SNDRV_RAWMIDI_IOCTL_STATUS, status) < 0) {
111 SYSERR("SNDRV_RAWMIDI_IOCTL_STATUS failed");
112 return -errno;
114 return 0;
117 static int snd_rawmidi_hw_drop(snd_rawmidi_t *rmidi)
119 snd_rawmidi_hw_t *hw = rmidi->private_data;
120 int str = rmidi->stream;
121 if (ioctl(hw->fd, SNDRV_RAWMIDI_IOCTL_DROP, &str) < 0) {
122 SYSERR("SNDRV_RAWMIDI_IOCTL_DROP failed");
123 return -errno;
125 return 0;
128 static int snd_rawmidi_hw_drain(snd_rawmidi_t *rmidi)
130 snd_rawmidi_hw_t *hw = rmidi->private_data;
131 int str = rmidi->stream;
132 if (ioctl(hw->fd, SNDRV_RAWMIDI_IOCTL_DRAIN, &str) < 0) {
133 SYSERR("SNDRV_RAWMIDI_IOCTL_DRAIN failed");
134 return -errno;
136 return 0;
139 static ssize_t snd_rawmidi_hw_write(snd_rawmidi_t *rmidi, const void *buffer, size_t size)
141 snd_rawmidi_hw_t *hw = rmidi->private_data;
142 ssize_t result;
143 result = write(hw->fd, buffer, size);
144 if (result < 0)
145 return -errno;
146 return result;
149 static ssize_t snd_rawmidi_hw_read(snd_rawmidi_t *rmidi, void *buffer, size_t size)
151 snd_rawmidi_hw_t *hw = rmidi->private_data;
152 ssize_t result;
153 result = read(hw->fd, buffer, size);
154 if (result < 0)
155 return -errno;
156 return result;
159 static const snd_rawmidi_ops_t snd_rawmidi_hw_ops = {
160 .close = snd_rawmidi_hw_close,
161 .nonblock = snd_rawmidi_hw_nonblock,
162 .info = snd_rawmidi_hw_info,
163 .params = snd_rawmidi_hw_params,
164 .status = snd_rawmidi_hw_status,
165 .drop = snd_rawmidi_hw_drop,
166 .drain = snd_rawmidi_hw_drain,
167 .write = snd_rawmidi_hw_write,
168 .read = snd_rawmidi_hw_read,
172 int snd_rawmidi_hw_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
173 const char *name, int card, int device, int subdevice,
174 int mode)
176 int fd, ver, ret;
177 int attempt = 0;
178 char filename[sizeof(SNDRV_FILE_RAWMIDI) + 20];
179 snd_ctl_t *ctl;
180 snd_rawmidi_t *rmidi;
181 snd_rawmidi_hw_t *hw = NULL;
182 snd_rawmidi_info_t info;
183 int fmode;
185 if (inputp)
186 *inputp = NULL;
187 if (outputp)
188 *outputp = NULL;
190 if ((ret = snd_ctl_hw_open(&ctl, NULL, card, 0)) < 0)
191 return ret;
192 sprintf(filename, SNDRV_FILE_RAWMIDI, card, device);
194 __again:
195 if (attempt++ > 3) {
196 snd_ctl_close(ctl);
197 return -EBUSY;
199 ret = snd_ctl_rawmidi_prefer_subdevice(ctl, subdevice);
200 if (ret < 0) {
201 snd_ctl_close(ctl);
202 return ret;
205 if (!inputp)
206 fmode = O_WRONLY;
207 else if (!outputp)
208 fmode = O_RDONLY;
209 else
210 fmode = O_RDWR;
212 if (mode & SND_RAWMIDI_APPEND) {
213 assert(outputp);
214 fmode |= O_APPEND;
217 if (mode & SND_RAWMIDI_NONBLOCK) {
218 fmode |= O_NONBLOCK;
221 if (mode & SND_RAWMIDI_SYNC) {
222 fmode |= O_SYNC;
225 assert(!(mode & ~(SND_RAWMIDI_APPEND|SND_RAWMIDI_NONBLOCK|SND_RAWMIDI_SYNC)));
227 fd = snd_open_device(filename, fmode);
228 if (fd < 0) {
229 snd_card_load(card);
230 fd = snd_open_device(filename, fmode);
231 if (fd < 0) {
232 snd_ctl_close(ctl);
233 SYSERR("open %s failed", filename);
234 return -errno;
237 if (ioctl(fd, SNDRV_RAWMIDI_IOCTL_PVERSION, &ver) < 0) {
238 ret = -errno;
239 SYSERR("SNDRV_RAWMIDI_IOCTL_PVERSION failed");
240 close(fd);
241 snd_ctl_close(ctl);
242 return ret;
244 if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_RAWMIDI_VERSION_MAX)) {
245 close(fd);
246 snd_ctl_close(ctl);
247 return -SND_ERROR_INCOMPATIBLE_VERSION;
249 if (subdevice >= 0) {
250 memset(&info, 0, sizeof(info));
251 info.stream = outputp ? SNDRV_RAWMIDI_STREAM_OUTPUT : SNDRV_RAWMIDI_STREAM_INPUT;
252 if (ioctl(fd, SNDRV_RAWMIDI_IOCTL_INFO, &info) < 0) {
253 SYSERR("SNDRV_RAWMIDI_IOCTL_INFO failed");
254 ret = -errno;
255 close(fd);
256 snd_ctl_close(ctl);
257 return ret;
259 if (info.subdevice != (unsigned int) subdevice) {
260 close(fd);
261 goto __again;
264 snd_ctl_close(ctl);
266 hw = calloc(1, sizeof(snd_rawmidi_hw_t));
267 if (hw == NULL)
268 goto _nomem;
269 hw->card = card;
270 hw->device = device;
271 hw->subdevice = subdevice;
272 hw->fd = fd;
274 if (inputp) {
275 rmidi = calloc(1, sizeof(snd_rawmidi_t));
276 if (rmidi == NULL)
277 goto _nomem;
278 if (name)
279 rmidi->name = strdup(name);
280 rmidi->type = SND_RAWMIDI_TYPE_HW;
281 rmidi->stream = SND_RAWMIDI_STREAM_INPUT;
282 rmidi->mode = mode;
283 rmidi->poll_fd = fd;
284 rmidi->ops = &snd_rawmidi_hw_ops;
285 rmidi->private_data = hw;
286 hw->open++;
287 *inputp = rmidi;
289 if (outputp) {
290 rmidi = calloc(1, sizeof(snd_rawmidi_t));
291 if (rmidi == NULL)
292 goto _nomem;
293 if (name)
294 rmidi->name = strdup(name);
295 rmidi->type = SND_RAWMIDI_TYPE_HW;
296 rmidi->stream = SND_RAWMIDI_STREAM_OUTPUT;
297 rmidi->mode = mode;
298 rmidi->poll_fd = fd;
299 rmidi->ops = &snd_rawmidi_hw_ops;
300 rmidi->private_data = hw;
301 hw->open++;
302 *outputp = rmidi;
304 return 0;
306 _nomem:
307 close(fd);
308 free(hw);
309 if (inputp)
310 free(*inputp);
311 if (outputp)
312 free(*outputp);
313 return -ENOMEM;
316 int _snd_rawmidi_hw_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
317 char *name, snd_config_t *root ATTRIBUTE_UNUSED,
318 snd_config_t *conf, int mode)
320 snd_config_iterator_t i, next;
321 long card = -1, device = 0, subdevice = -1;
322 const char *str;
323 int err;
324 snd_config_for_each(i, next, conf) {
325 snd_config_t *n = snd_config_iterator_entry(i);
326 const char *id;
327 if (snd_config_get_id(n, &id) < 0)
328 continue;
329 if (snd_rawmidi_conf_generic_id(id))
330 continue;
331 if (strcmp(id, "card") == 0) {
332 err = snd_config_get_integer(n, &card);
333 if (err < 0) {
334 err = snd_config_get_string(n, &str);
335 if (err < 0)
336 return -EINVAL;
337 card = snd_card_get_index(str);
338 if (card < 0)
339 return card;
341 continue;
343 if (strcmp(id, "device") == 0) {
344 err = snd_config_get_integer(n, &device);
345 if (err < 0)
346 return err;
347 continue;
349 if (strcmp(id, "subdevice") == 0) {
350 err = snd_config_get_integer(n, &subdevice);
351 if (err < 0)
352 return err;
353 continue;
355 return -EINVAL;
357 if (card < 0)
358 return -EINVAL;
359 return snd_rawmidi_hw_open(inputp, outputp, name, card, device, subdevice, mode);
361 SND_DLSYM_BUILD_VERSION(_snd_rawmidi_hw_open, SND_RAWMIDI_DLSYM_VERSION);