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