channel.h revision 184610
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 184610 2008-11-04 02:31:03Z alfred $
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_OWNED(c) mtx_owned((struct mtx *)((c)->lock))
262#define CHN_LOCK(c) mtx_lock((struct mtx *)((c)->lock))
263#define CHN_UNLOCK(c) mtx_unlock((struct mtx *)((c)->lock))
264#define CHN_TRYLOCK(c) mtx_trylock((struct mtx *)((c)->lock))
265#define CHN_LOCKASSERT(c) mtx_assert((struct mtx *)((c)->lock), MA_OWNED)
266#else
267#define CHN_LOCK_OWNED(c) 0
268#define CHN_LOCK(c)
269#define CHN_UNLOCK(c)
270#define CHN_TRYLOCK(c)
271#define CHN_LOCKASSERT(c)
272#endif
273
274int fmtvalid(u_int32_t fmt, u_int32_t *fmtlist);
275
276#define AFMTSTR_NONE		0 /* "s16le" */
277#define AFMTSTR_SIMPLE		1 /* "s16le:s" */
278#define AFMTSTR_NUM		2 /* "s16le:2" */
279#define AFMTSTR_FULL		3 /* "s16le:stereo" */
280
281#define AFMTSTR_MAXSZ		13 /* include null terminator */
282
283#define AFMTSTR_MONO_RETURN	0
284#define AFMTSTR_STEREO_RETURN	1
285
286struct afmtstr_table {
287	char *fmtstr;
288	u_int32_t format;
289};
290
291int afmtstr_swap_sign(char *);
292int afmtstr_swap_endian(char *);
293u_int32_t afmtstr2afmt(struct afmtstr_table *, const char *, int);
294u_int32_t afmt2afmtstr(struct afmtstr_table *, u_int32_t, char *, size_t, int, int);
295
296extern int chn_latency;
297extern int chn_latency_profile;
298extern int report_soft_formats;
299
300#define PCMDIR_FAKE		0
301#define PCMDIR_PLAY		1
302#define PCMDIR_PLAY_VIRTUAL	2
303#define PCMDIR_REC		-1
304#define PCMDIR_REC_VIRTUAL	-2
305
306#define PCMTRIG_START 1
307#define PCMTRIG_EMLDMAWR 2
308#define PCMTRIG_EMLDMARD 3
309#define PCMTRIG_STOP 0
310#define PCMTRIG_ABORT -1
311
312#define PCMTRIG_COMMON(x)	((x) == PCMTRIG_START ||		\
313				 (x) == PCMTRIG_STOP ||			\
314				 (x) == PCMTRIG_ABORT)
315
316#define CHN_F_CLOSING           0x00000004  /* a pending close */
317#define CHN_F_ABORTING          0x00000008  /* a pending abort */
318#define CHN_F_RUNNING		0x00000010  /* dma is running */
319#define CHN_F_TRIGGERED		0x00000020
320#define CHN_F_NOTRIGGER		0x00000040
321#define CHN_F_SLEEPING		0x00000080
322
323#define CHN_F_BUSY              0x00001000  /* has been opened 	*/
324#define	CHN_F_HAS_SIZE		0x00002000  /* user set block size */
325#define CHN_F_NBIO              0x00004000  /* do non-blocking i/o */
326#define CHN_F_MAPPED		0x00010000  /* has been mmap()ed */
327#define CHN_F_DEAD		0x00020000
328#define CHN_F_BADSETTING	0x00040000
329#define CHN_F_SETBLOCKSIZE	0x00080000
330#define CHN_F_HAS_VCHAN		0x00100000
331
332#define	CHN_F_VIRTUAL		0x10000000  /* not backed by hardware */
333
334#define CHN_F_RESET		(CHN_F_BUSY | CHN_F_DEAD |		\
335				 CHN_F_HAS_VCHAN | CHN_F_VIRTUAL)
336
337#define CHN_F_MMAP_INVALID	(CHN_F_DEAD | CHN_F_RUNNING)
338
339
340
341#define CHN_N_RATE		0x00000001
342#define CHN_N_FORMAT		0x00000002
343#define CHN_N_VOLUME		0x00000004
344#define CHN_N_BLOCKSIZE		0x00000008
345#define CHN_N_TRIGGER		0x00000010
346
347#define CHN_LATENCY_MIN		0
348#define CHN_LATENCY_MAX		10
349#define CHN_LATENCY_DEFAULT	5
350#define CHN_POLICY_MIN		CHN_LATENCY_MIN
351#define CHN_POLICY_MAX		CHN_LATENCY_MAX
352#define CHN_POLICY_DEFAULT	CHN_LATENCY_DEFAULT
353
354#define CHN_LATENCY_PROFILE_MIN		0
355#define CHN_LATENCY_PROFILE_MAX		1
356#define CHN_LATENCY_PROFILE_DEFAULT	CHN_LATENCY_PROFILE_MAX
357
358#define CHN_STARTED(c)		((c)->flags & CHN_F_TRIGGERED)
359#define CHN_STOPPED(c)		(!CHN_STARTED(c))
360#define CHN_DIRSTR(c)		(((c)->direction == PCMDIR_PLAY) ? \
361				"PCMDIR_PLAY" : "PCMDIR_REC")
362
363#define CHN_TIMEOUT		5
364#define CHN_TIMEOUT_MIN		1
365#define CHN_TIMEOUT_MAX		10
366
367/*
368 * This should be large enough to hold all pcm data between
369 * tsleeps in chn_{read,write} at the highest sample rate.
370 * (which is usually 48kHz * 16bit * stereo = 192000 bytes/sec)
371 */
372#define CHN_2NDBUFBLKSIZE	(2 * 1024)
373/* The total number of blocks per secondary bufhard. */
374#define CHN_2NDBUFBLKNUM	(32)
375/* The size of a whole secondary bufhard. */
376#define CHN_2NDBUFMAXSIZE	(131072)
377
378#define CHANNEL_DECLARE(name) static DEFINE_CLASS(name, name ## _methods, sizeof(struct kobj))
379