• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* pcm_hw.c
2 **
3 ** Copyright (c) 2019, The Linux Foundation. All rights reserved.
4 **
5 ** Redistribution and use in source and binary forms, with or without
6 ** modification, are permitted provided that the following conditions are
7 ** met:
8 **   * Redistributions of source code must retain the above copyright
9 **     notice, this list of conditions and the following disclaimer.
10 **   * Redistributions in binary form must reproduce the above
11 **     copyright notice, this list of conditions and the following
12 **     disclaimer in the documentation and/or other materials provided
13 **     with the distribution.
14 **   * Neither the name of The Linux Foundation nor the names of its
15 **     contributors may be used to endorse or promote products derived
16 **     from this software without specific prior written permission.
17 **
18 ** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
19 ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
21 ** ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
22 ** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25 ** BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27 ** OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
28 ** IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 **/
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <fcntl.h>
34 #include <stdarg.h>
35 #include <string.h>
36 #include <errno.h>
37 #include <unistd.h>
38 #include <poll.h>
39 
40 #include <sys/ioctl.h>
41 #include <sys/mman.h>
42 #include <linux/ioctl.h>
43 #include <sound/asound.h>
44 #include <tinyalsa/asoundlib.h>
45 
46 #include "pcm_io.h"
47 
48 struct pcm_hw_data {
49     unsigned int card;
50     unsigned int device;
51     unsigned int fd;
52     void *snd_node;
53 };
54 
pcm_hw_close(void * data)55 static void pcm_hw_close(void *data)
56 {
57     struct pcm_hw_data *hw_data = data;
58 
59     if (hw_data->fd >= 0)
60         close(hw_data->fd);
61 
62     free(hw_data);
63 }
64 
pcm_hw_ioctl(void * data,unsigned int cmd,...)65 static int pcm_hw_ioctl(void *data, unsigned int cmd, ...)
66 {
67     struct pcm_hw_data *hw_data = data;
68     va_list ap;
69     void *arg;
70 
71     va_start(ap, cmd);
72     arg = va_arg(ap, void *);
73     va_end(ap);
74 
75     return ioctl(hw_data->fd, cmd, arg);
76 }
77 
pcm_hw_poll(void * data,struct pollfd * pfd,nfds_t nfds,int timeout)78 static int pcm_hw_poll(void *data __attribute__((unused)),
79         struct pollfd *pfd, nfds_t nfds, int timeout)
80 {
81     return poll(pfd, nfds, timeout);
82 }
83 
pcm_hw_mmap(void * data,void * addr,size_t length,int prot,int flags,off_t offset)84 static void* pcm_hw_mmap(void *data, void *addr, size_t length, int prot,
85                        int flags, off_t offset)
86 {
87     struct pcm_hw_data *hw_data = data;
88 
89    return mmap(addr, length, prot, flags, hw_data->fd, offset);
90 }
91 
pcm_hw_munmap(void * data,void * addr,size_t length)92 static int pcm_hw_munmap(void *data __attribute__((unused)), void *addr, size_t length)
93 {
94     return munmap(addr, length);
95 }
96 
pcm_hw_open(unsigned int card,unsigned int device,unsigned int flags,void ** data,void * node)97 static int pcm_hw_open(unsigned int card, unsigned int device,
98                 unsigned int flags, void **data,
99                 __attribute__((unused)) void *node)
100 {
101     struct pcm_hw_data *hw_data;
102     char fn[256];
103     int fd;
104 
105     hw_data = calloc(1, sizeof(*hw_data));
106     if (!hw_data) {
107         return -ENOMEM;
108     }
109 
110     snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device,
111              flags & PCM_IN ? 'c' : 'p');
112     fd = open(fn, O_RDWR|O_NONBLOCK);
113     if (fd < 0) {
114         printf("%s: cannot open device '%s'", __func__, fn);
115         return fd;
116     }
117 
118     if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK) < 0) {
119         printf("%s: failed to reset blocking mode '%s'",
120                 __func__, fn);
121         goto err_close;
122     }
123 
124     hw_data->snd_node = node;
125     hw_data->card = card;
126     hw_data->device = device;
127     hw_data->fd = fd;
128 
129     *data = hw_data;
130 
131     return fd;
132 
133 err_close:
134     close(fd);
135     free(hw_data);
136     return -ENODEV;
137 }
138 
139 struct pcm_ops hw_ops = {
140     .open = pcm_hw_open,
141     .close = pcm_hw_close,
142     .ioctl = pcm_hw_ioctl,
143     .mmap = pcm_hw_mmap,
144     .munmap = pcm_hw_munmap,
145     .poll = pcm_hw_poll,
146 };
147