Deleted Added
full compact
1/*-
2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
3 * 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
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/dev/sound/pcm/channel.h 170521 2007-06-11 00:49:46Z ariff $
26 * $FreeBSD: head/sys/dev/sound/pcm/channel.h 170815 2007-06-16 03:37:28Z ariff $
27 */
28
29struct pcmchan_caps {
30 u_int32_t minspeed, maxspeed;
31 u_int32_t *fmtlist;
32 u_int32_t caps;
33};
34
35/* Forward declarations */
36struct pcm_channel;
37struct pcmchan_syncgroup;
38struct pcmchan_syncmember;
39
40extern struct mtx snd_pcm_syncgroups_mtx;
41extern SLIST_HEAD(pcm_synclist, pcmchan_syncgroup) snd_pcm_syncgroups;
42
43#define PCM_SG_LOCK() mtx_lock(&snd_pcm_syncgroups_mtx)
44#define PCM_SG_TRYLOCK() mtx_trylock(&snd_pcm_syncgroups_mtx)
45#define PCM_SG_UNLOCK() mtx_unlock(&snd_pcm_syncgroups_mtx)
46#define PCM_SG_LOCKASSERT(arg) mtx_assert(&snd_pcm_syncgroups_mtx, arg)
47
48/**
49 * @brief Specifies an audio device sync group
50 */
51struct pcmchan_syncgroup {
52 SLIST_ENTRY(pcmchan_syncgroup) link;
53 SLIST_HEAD(, pcmchan_syncmember) members;
54 int id; /**< Group identifier; set to address of group. */
55};
56
57/**
58 * @brief Specifies a container for members of a sync group
59 */
60struct pcmchan_syncmember {
61 SLIST_ENTRY(pcmchan_syncmember) link;
62 struct pcmchan_syncgroup *parent; /**< group head */
63 struct pcm_channel *ch;
64};
65
66#define CHN_NAMELEN 32
67struct pcm_channel {
68 kobj_t methods;
69
70 pid_t pid;
71 int refcount;
72 struct pcm_feeder *feeder;
73 u_int32_t align;
74
75 int volume;
76 int latency;
77 u_int32_t speed;
78 u_int32_t format;
79 u_int32_t flags;
80 u_int32_t feederflags;
81 u_int32_t blocks;
82
83 int direction;
84 unsigned int interrupts, xruns, feedcount;
85 unsigned int timeout;
86 struct snd_dbuf *bufhard, *bufsoft;
87 struct snddev_info *parentsnddev;
88 struct pcm_channel *parentchannel;
89 void *devinfo;
90 device_t dev;
91 int unit;
92 char name[CHN_NAMELEN];
93 struct mtx *lock;
94 int trigger;
95 /**
96 * For interrupt manipulations.
97 */
98 struct cv intr_cv;
99 /**
100 * Increment,decrement this around operations that temporarily yield
101 * lock.
102 */
103 unsigned int inprog;
104 /**
105 * Special channel operations should examine @c inprog after acquiring
106 * lock. If zero, operations may continue. Else, thread should
107 * wait on this cv for previous operation to finish.
108 */
109 struct cv cv;
110 /**
111 * Low water mark for select()/poll().
112 *
113 * This is initialized to the channel's fragment size, and will be
114 * overwritten if a new fragment size is set. Users may alter this
115 * value directly with the @c SNDCTL_DSP_LOW_WATER ioctl.
116 */
117 unsigned int lw;
118 /**
119 * If part of a sync group, this will point to the syncmember
120 * container.
121 */
122 struct pcmchan_syncmember *sm;
123#ifdef OSSV4_EXPERIMENT
124 u_int16_t lpeak, rpeak; /**< Peak value from 0-32767. */
125#endif
126
127 struct {
128 SLIST_HEAD(, pcm_channel) head;
129 SLIST_ENTRY(pcm_channel) link;
130 struct {
131 SLIST_HEAD(, pcm_channel) head;
132 SLIST_ENTRY(pcm_channel) link;
133 } busy;
134 } children;
135
136 struct {
137 struct {
138 SLIST_ENTRY(pcm_channel) link;
139 struct {
140 SLIST_ENTRY(pcm_channel) link;
141 } busy;
142 } pcm;
143 } channels;
144
145 void *data1, *data2;
146};
147
148#define CHN_HEAD(x, y) &(x)->y.head
149#define CHN_INIT(x, y) SLIST_INIT(CHN_HEAD(x, y))
150#define CHN_LINK(y) y.link
151#define CHN_EMPTY(x, y) SLIST_EMPTY(CHN_HEAD(x, y))
152#define CHN_FIRST(x, y) SLIST_FIRST(CHN_HEAD(x, y))
153
154#define CHN_FOREACH(x, y, z) \
155 SLIST_FOREACH(x, CHN_HEAD(y, z), CHN_LINK(z))
156
157#define CHN_FOREACH_SAFE(w, x, y, z) \
158 SLIST_FOREACH_SAFE(w, CHN_HEAD(x, z), CHN_LINK(z), y)
159
160#define CHN_INSERT_HEAD(x, y, z) \
161 SLIST_INSERT_HEAD(CHN_HEAD(x, z), y, CHN_LINK(z))
162
163#define CHN_INSERT_AFTER(x, y, z) \
164 SLIST_INSERT_AFTER(x, y, CHN_LINK(z))
165
166#define CHN_REMOVE(x, y, z) \
167 SLIST_REMOVE(CHN_HEAD(x, z), y, pcm_channel, CHN_LINK(z))
168
169#define CHN_INSERT_HEAD_SAFE(x, y, z) do { \
170 struct pcm_channel *t = NULL; \
171 CHN_FOREACH(t, x, z) { \
172 if (t == y) \
173 break; \
174 } \
175 if (t != y) { \
176 CHN_INSERT_HEAD(x, y, z); \
177 } \
178} while(0)
179
180#define CHN_INSERT_AFTER_SAFE(w, x, y, z) do { \
181 struct pcm_channel *t = NULL; \
182 CHN_FOREACH(t, w, z) { \
183 if (t == y) \
184 break; \
185 } \
186 if (t != y) { \
187 CHN_INSERT_AFTER(x, y, z); \
188 } \
189} while(0)
190
191#define CHN_REMOVE_SAFE(x, y, z) do { \
192 struct pcm_channel *t = NULL; \
193 CHN_FOREACH(t, x, z) { \
194 if (t == y) \
195 break; \
196 } \
197 if (t == y) { \
198 CHN_REMOVE(x, y, z); \
199 } \
200} while(0)
201
202#define CHN_UNIT(x) (snd_unit2u((x)->unit))
203#define CHN_DEV(x) (snd_unit2d((x)->unit))
204#define CHN_CHAN(x) (snd_unit2c((x)->unit))
205
206#define CHN_BUF_PARENT(x, y) \
207 (((x) != NULL && (x)->parentchannel != NULL && \
208 (x)->parentchannel->bufhard != NULL) ? \
209 (x)->parentchannel->bufhard : (y))
210
211#define CHN_BROADCAST(x) do { \
212 if ((x)->cv_waiters != 0) \
213 cv_broadcastpri(x, PRIBIO); \
214} while(0)
215
216#include "channel_if.h"
217
218int chn_reinit(struct pcm_channel *c);
219int chn_write(struct pcm_channel *c, struct uio *buf);
220int chn_read(struct pcm_channel *c, struct uio *buf);
221u_int32_t chn_start(struct pcm_channel *c, int force);
222int chn_sync(struct pcm_channel *c, int threshold);
223int chn_flush(struct pcm_channel *c);
224int chn_poll(struct pcm_channel *c, int ev, struct thread *td);
225
226int chn_init(struct pcm_channel *c, void *devinfo, int dir, int direction);
227int chn_kill(struct pcm_channel *c);
228int chn_setdir(struct pcm_channel *c, int dir);
229int chn_reset(struct pcm_channel *c, u_int32_t fmt);
230int chn_setvolume(struct pcm_channel *c, int left, int right);
231int chn_setspeed(struct pcm_channel *c, int speed);
232int chn_setformat(struct pcm_channel *c, u_int32_t fmt);
233int chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz);
234int chn_setlatency(struct pcm_channel *c, int latency);
235int chn_trigger(struct pcm_channel *c, int go);
236int chn_getptr(struct pcm_channel *c);
237struct pcmchan_caps *chn_getcaps(struct pcm_channel *c);
238u_int32_t chn_getformats(struct pcm_channel *c);
239
240void chn_resetbuf(struct pcm_channel *c);
241void chn_intr(struct pcm_channel *c);
242int chn_wrfeed(struct pcm_channel *c);
243int chn_rdfeed(struct pcm_channel *c);
244int chn_abort(struct pcm_channel *c);
245
246void chn_wrupdate(struct pcm_channel *c);
247void chn_rdupdate(struct pcm_channel *c);
248
249int chn_notify(struct pcm_channel *c, u_int32_t flags);
250void chn_lock(struct pcm_channel *c);
251void chn_unlock(struct pcm_channel *c);
252
253int chn_getrates(struct pcm_channel *c, int **rates);
254int chn_syncdestroy(struct pcm_channel *c);
255
256#ifdef OSSV4_EXPERIMENT
257int chn_getpeaks(struct pcm_channel *c, int *lpeak, int *rpeak);
258#endif
259
260#ifdef USING_MUTEX
261#define CHN_LOCK(c) mtx_lock((struct mtx *)((c)->lock))
262#define CHN_UNLOCK(c) mtx_unlock((struct mtx *)((c)->lock))
263#define CHN_TRYLOCK(c) mtx_trylock((struct mtx *)((c)->lock))
264#define CHN_LOCKASSERT(c) mtx_assert((struct mtx *)((c)->lock), MA_OWNED)
265#else
266#define CHN_LOCK(c)
267#define CHN_UNLOCK(c)
268#define CHN_TRYLOCK(c)
269#define CHN_LOCKASSERT(c)
270#endif
271
272int fmtvalid(u_int32_t fmt, u_int32_t *fmtlist);
273
274#define AFMTSTR_NONE 0 /* "s16le" */
275#define AFMTSTR_SIMPLE 1 /* "s16le:s" */
276#define AFMTSTR_NUM 2 /* "s16le:2" */
277#define AFMTSTR_FULL 3 /* "s16le:stereo" */
278
279#define AFMTSTR_MAXSZ 13 /* include null terminator */
280
281#define AFMTSTR_MONO_RETURN 0
282#define AFMTSTR_STEREO_RETURN 1
283
284struct afmtstr_table {
285 char *fmtstr;
286 u_int32_t format;
287};
288
289int afmtstr_swap_sign(char *);
290int afmtstr_swap_endian(char *);
291u_int32_t afmtstr2afmt(struct afmtstr_table *, const char *, int);
292u_int32_t afmt2afmtstr(struct afmtstr_table *, u_int32_t, char *, size_t, int, int);
293
294extern int chn_latency;
295extern int chn_latency_profile;
296extern int report_soft_formats;
297
298#define PCMDIR_FAKE 0
299#define PCMDIR_PLAY 1
300#define PCMDIR_PLAY_VIRTUAL 2
301#define PCMDIR_REC -1
302#define PCMDIR_REC_VIRTUAL -2
303
304#define PCMTRIG_START 1
305#define PCMTRIG_EMLDMAWR 2
306#define PCMTRIG_EMLDMARD 3
307#define PCMTRIG_STOP 0
308#define PCMTRIG_ABORT -1
309
310#define PCMTRIG_COMMON(x) ((x) == PCMTRIG_START || \
311 (x) == PCMTRIG_STOP || \
312 (x) == PCMTRIG_ABORT)
313
314#define CHN_F_CLOSING 0x00000004 /* a pending close */
315#define CHN_F_ABORTING 0x00000008 /* a pending abort */
316#define CHN_F_RUNNING 0x00000010 /* dma is running */
317#define CHN_F_TRIGGERED 0x00000020
318#define CHN_F_NOTRIGGER 0x00000040
319#define CHN_F_SLEEPING 0x00000080
320
321#define CHN_F_BUSY 0x00001000 /* has been opened */
322#define CHN_F_HAS_SIZE 0x00002000 /* user set block size */
323#define CHN_F_NBIO 0x00004000 /* do non-blocking i/o */
324#define CHN_F_MAPPED 0x00010000 /* has been mmap()ed */
325#define CHN_F_DEAD 0x00020000
326#define CHN_F_BADSETTING 0x00040000
327#define CHN_F_SETBLOCKSIZE 0x00080000
328#define CHN_F_HAS_VCHAN 0x00100000
329
330#define CHN_F_VIRTUAL 0x10000000 /* not backed by hardware */
331
318#define CHN_F_RESET (CHN_F_BUSY | CHN_F_DEAD | \
319 CHN_F_HAS_VCHAN | CHN_F_VIRTUAL)
332#define CHN_F_RESET (CHN_F_BUSY | CHN_F_DEAD | \
333 CHN_F_HAS_VCHAN | CHN_F_VIRTUAL)
334
335#define CHN_F_MMAP_INVALID (CHN_F_DEAD | CHN_F_RUNNING)
336
337
338
339#define CHN_N_RATE 0x00000001
340#define CHN_N_FORMAT 0x00000002
341#define CHN_N_VOLUME 0x00000004
342#define CHN_N_BLOCKSIZE 0x00000008
343#define CHN_N_TRIGGER 0x00000010
344
345#define CHN_LATENCY_MIN 0
346#define CHN_LATENCY_MAX 10
347#define CHN_LATENCY_DEFAULT 5
348#define CHN_POLICY_MIN CHN_LATENCY_MIN
349#define CHN_POLICY_MAX CHN_LATENCY_MAX
350#define CHN_POLICY_DEFAULT CHN_LATENCY_DEFAULT
351
352#define CHN_LATENCY_PROFILE_MIN 0
353#define CHN_LATENCY_PROFILE_MAX 1
354#define CHN_LATENCY_PROFILE_DEFAULT CHN_LATENCY_PROFILE_MAX
355
356#define CHN_STARTED(c) ((c)->flags & CHN_F_TRIGGERED)
357#define CHN_STOPPED(c) (!CHN_STARTED(c))
358#define CHN_DIRSTR(c) (((c)->direction == PCMDIR_PLAY) ? \
359 "PCMDIR_PLAY" : "PCMDIR_REC")
360
361#define CHN_TIMEOUT 5
362#define CHN_TIMEOUT_MIN 1
363#define CHN_TIMEOUT_MAX 10
364
365/*
366 * This should be large enough to hold all pcm data between
367 * tsleeps in chn_{read,write} at the highest sample rate.
368 * (which is usually 48kHz * 16bit * stereo = 192000 bytes/sec)
369 */
370#define CHN_2NDBUFBLKSIZE (2 * 1024)
371/* The total number of blocks per secondary bufhard. */
372#define CHN_2NDBUFBLKNUM (32)
373/* The size of a whole secondary bufhard. */
374#define CHN_2NDBUFMAXSIZE (131072)
375
376#define CHANNEL_DECLARE(name) static DEFINE_CLASS(name, name ## _methods, sizeof(struct kobj))