summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/sys/audiovar.h
blob: 83aff404542aeb6ac077299b6cb8b93fce85ad27 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 1991-1992, 1997-2000 by Sun Microsystems, Inc.
 * All rights reserved.
 */

#ifndef	_SYS_AUDIOVAR_H
#define	_SYS_AUDIOVAR_H

#pragma ident	"%Z%%M%	%I%	%E% SMI"

/*
 * The audio driver is divided into generic (device-independent) and
 * device-specific modules.  The generic routines handle most STREAMS
 * protocol issues, communicating with the device-specific code via
 * function callouts and a chained control block structure.
 *
 * Separate control block lists are maintained for reading (record) and
 * writing (play).  These control blocks simulate a chained-DMA
 * structure, in that each block controls the transfer of data between
 * the device and a single contiguous memory segment.
 *
 * The command block contains buffer start and stop addresses, a link
 * address to the next block in the chain, a 'done' flag, a 'skip' flag
 * (indicating that this command block contains no data), and a pointer
 * to the STREAMS data block structure which is private to the generic
 * driver.
 *
 * The device-specific audio driver code is expected to honor the 'skip'
 * flag and set the 'done' flag when it has completed processing the
 * command block (i.e., the data transfer, if any, is complete).  For
 * record command blocks, it is also expected to add to the 'data'
 * pointer the number of bytes successfully read from the device.
 *
 * The device-specific driver module must initialize the static STREAMS
 * control structures and must provide an identify routine (sbus-only),
 * an attach routine, and an open routine.  The open routine verifies the
 * device unit number and calls the generic open routine with the address
 * of the audio_state structure for that unit.
 *
 * The generic audio driver makes calls to the device-specific code
 * through an ops-vector table.  The following routines must be provided:
 *
 * The 'close' routine is called after either the play or record stream
 * is closed.  It may perform device-specific cleanup and initialization.
 *
 * void dev_close(as)
 * 	aud_stream_t		*as;	// Pointer to audio device state
 *
 *
 * The 'ioctl' routine is called from the STREAMS write put procedure
 * when a non-generic ioctl is encountered (AUDIO_SETINFO, AUDIO_GETINFO,
 * and AUDIO_DRAIN are the generic ioctls).  Any required data mblk_t is
 * allocated; its address is given by mp->b_cont (if this is a read/write
 * ioctl, the user-supplied buffer at mp->b_cont is reused).  If data is
 * successfully returned, the iocp->ioc_count field should be set with
 * the number of bytes returned.  If an error occurs, the 'ioctl' routine
 * should set iocp->ioc_error to the appropriate error code.  Otherwise,
 * the returned value should be AUDRETURN_CHANGE if a device state change
 * occurred (in which case a signal is sent to the control device, if
 * any) and AUDRETURN_NOCHANGE if no signal should be sent. If the ioctl
 * can not complete right away, it should return AUDRETURN_DELAYED
 * indicating that it will ack the ioctl at a later time.
 *
 * aud_return_t dev_ioctl(as, mp, iocp)
 * 	aud_stream_t	*as;		// Pointer to audio device state
 * 	mblk_t		*mp;		// ioctl STREAMS message block
 * 	struct iocblk	*iocp;		// M_IOCTL message data
 *
 *
 * The 'start' routine is called to start i/o.  Ordinarily, it is called
 * from the device-specific 'queuecmd' routine, but it is also called
 * when paused output is resumed.
 *
 * void dev_start(as)
 * 	aud_stream_t	*as;		// Pointer to audio device state
 *
 *
 * The 'stop' routine is called to stop i/o.  It is called when i/o is
 * paused, flushed, or the device is closed.  Note that currently queued
 * command blocks should not be flushed by this routine, since i/o may be
 * resumed from the current point.
 *
 * void dev_stop(as)
 * 	aud_stream_t	*as;		// Pointer to audio device state
 *
 *
 * The 'setflag' routine is called to get a single device-specific flag.
 * The flag argument is either AUD_ACTIVE (return the active flag) or
 * AUD_ERRORRESET (zero the error flag, returning its previous value).
 * (The val argument is currently ignored.)
 *
 * void dev_setflag(as, flag, val)
 * 	aud_stream_t	*as;		// Pointer to audio device state
 * 	enum aud_opflag	flag;		// AUD_ACTIVE || AUD_ERRORESET
 *
 *
 * The 'setinfo' routine is called to get or set device-specific fields
 * in the audio state structure.  If mp is NULL, the sample counters and
 * active flags should be set in v.  If mp is not NULL, then
 * mp->b_cont->data points to the audio_info_t structure supplied in an
 * AUDIO_SETINFO ioctl (ip).  All device-specific fields (gains, ports,
 * sample counts) in both v and the device itself should be updated, as
 * long as the corresponding field in ip is not set to AUD_INIT_VALUE.
 * When the sample counters are set, the value returned in v should be
 * the previous value. If the setinfo can not complete right away, it
 * should return AUDRETURN_DELAYED indicating that it will ack the ioctl
 * at a later time. If an error occurs on setinfo, the iocp->ioc_error
 * should be set as in dev_ioctl
 *
 * aud_return_t dev_setinfo(as, mp, iocp)
 * 	aud_stream_t	*as;		// Pointer to audio device state
 * 	mblk_t		*mp;		// user info structure or NULL
 * 	struct iocblk	*iocp;		// M_IOCTL message data
 *
 *
 * The 'queuecmd' routine is called whenever a new command block is
 * linked into the chained command list.  The device-specific code must
 * ensure that the command is enqueued to the device and that i/o, if not
 * currently active, is started.
 *
 * void dev_queuecmd(as, cmdp)
 * 	aud_stream_t	*as;		// Pointer to audio device state
 * 	struct aud_cmd	*cmdp;		// new command block to queue
 *
 *
 * The 'flushcmd' routine is called whenever the chained command list is
 * flushed.  It is only called after i/o has been stopped (via the 'stop'
 * routine) and after the command list in the audio state structure has
 * been cleared.  The device-specific code should flush the device's
 * queued command list.
 *
 * void dev_flushcmd(as)
 * 	aud_stream_t	*as;		// Pointer to audio device state
 */

#ifdef __cplusplus
extern "C" {
#endif


/*
 * Various generic audio driver constants
 */
#define	AUD_INITVALUE	(~0)
#define	Modify(X)	((uint_t)(X) != AUD_INITVALUE)
#define	Modifys(X)	((X) != (ushort_t)AUD_INITVALUE)
#define	Modifyc(X)	((X) != (uchar_t)AUD_INITVALUE)


/*
 * Define the virtual chained-DMA control structure
 */
typedef struct aud_cmd aud_cmd_t;
struct aud_cmd {
	/*
	 * Data pointers
	 */
	uchar_t *data;		/* address of next transfer */
	uchar_t *enddata;	/* address+1 of last transfer */

	/*
	 * Linked list management
	 */
	aud_cmd_t *next;	/* pointer to next or NULL */
	aud_cmd_t *lastfragment; /* last fragment in packet */

	/*
	 * Flags
	 */
	uint_t :0;		/* Force word alignment */
	uchar_t skip;		/* TRUE => no xfers on buffer */
	uchar_t done;		/* TRUE => buffer processed */

	uchar_t iotype;		/* copy of mblk's db_type */
	boolean_t processed;	/* TRUE if processed cmd at head of list */

	audtrace_hdr_t tracehdr; /* trace info */

	/*
	 * Device-independent private, opaque storage
	 */
	void *dihandle;
};


/*
 * Define the list-head for queued control structures
 */
typedef struct aud_cmdlist aud_cmdlist_t;
struct aud_cmdlist {
	aud_cmd_t *head;	/* First queued command block */
	aud_cmd_t *tail;	/* Last queued command block */
	aud_cmd_t *free;	/* Head of free list */
};


/*
 * Define possible return values from the setinfo and ioctl calls
 */
typedef enum {
	AUDRETURN_CHANGE,
	AUDRETURN_NOCHANGE,
	AUDRETURN_DELAYED
} aud_return_t;


/*
 * Define legal values for the 'flag' argument to the 'setflag' callout
 */
enum aud_opflag {
	AUD_ACTIVE,		/* active flag */
	AUD_ERRORRESET		/* error flag (reset after read) */
};


/*
 * The audio stream type determines the legal operations for a stream in the
 * generic portion of an audio driver.
 */
typedef enum {
	AUDTYPE_NONE = 00,	/* Not a legal device */
	AUDTYPE_DATA = 01,	/* Data, IOCTL, etc., but not signals */
	AUDTYPE_CONTROL = 02,	/* IOCTL, etc., but not M_DATA */
	AUDTYPE_BOTH = 03	/* Anything is ok, signals delivered */
} aud_streamtype_t;

#define	ISPLAYSTREAM(as)	(ISDATASTREAM(as) && (as->openflag & FWRITE))
#define	ISRECORDSTREAM(as)	(ISDATASTREAM(as) && (as->openflag & FREAD))
#define	ISDATASTREAM(as)	(((as->type) & (AUDTYPE_DATA)) != 0)
#define	ISCONTROLSTREAM(as)	(((as->type) & (AUDTYPE_CONTROL)) != 0)


typedef enum {
	AUDMODE_NONE = 00,	/* Not a legal mode */
	AUDMODE_AUDIO = 01,	/* Transparent audio mode */
	AUDMODE_HDLC = 02	/* HDLC datacomm mode */
} aud_modetype_t;


/*
 * This structure describes the state of the audio device and queues
 */
typedef struct aud_state aud_state_t;
struct aud_state {
	/*
	 * Back-pointer to the device-dependent audio state
	 */
	void *ddstate;

	/*
	 * Device-independent audio state
	 */
	uint_t monitor_gain;	/* input to output mix: 0 - 255 */
	boolean_t output_muted;	/* true if output is muted */
	uint_t hw_features;	/* hardware features this driver supports */
	uint_t sw_features;	/* software features this driver supports */
	uint_t sw_features_enabled;	/* supported SW features enabled */

	/*
	 * Audio ops vector
	 */
	struct aud_ops *ops;
};

/*
 * STREAMS routines pass the address of a 'struct audstream' when calling
 * put and service procedures.  This structure points to the STREAMS
 * queues and back to the containing 'struct aud_state'.
 */
typedef struct aud_stream aud_stream_t;
struct aud_stream {
	aud_state_t *distate;	/* pointer to driver data */
	aud_streamtype_t type;	/* defines legal operations */
	aud_modetype_t mode;	/* Audio or HDLC data */
	boolean_t signals_okay;	/* Can send sigs up this aud_stream */

	/*
	 * Sideways pointers to related aud_stream_t structures
	 */
	aud_stream_t *control_as; /* control stream */
	aud_stream_t *output_as; /* play stream */
	aud_stream_t *input_as;	/* record stream */

	/*
	 * Software state
	 */
	aud_cmdlist_t cmdlist;	/* command chains */
	audio_prinfo_t info;	/* info for this stream side */
	int openflag;		/* open flag & (FREAD|FWRITE) */
	boolean_t draining;	/* TRUE if output draining */
	int maxfrag_size;	/* max aud_cmd_t fragment size */
	struct {
		int action;		/* IOCTL action */
		mblk_t *mp;		/* Pending ioctl */
		ulong_t priv;		/* private state */
		uint_t ioctl_id;	/* from ioc_id */
		cred_t *credp;		/* from ioc_cr */
		int reason;		/* HW implementation dep. reason */
		boolean_t (*handler)(aud_stream_t *, mblk_t *, int,
		    boolean_t);
	} dioctl;		/* Delayed ioctls */
	uint_t sequence;	/* packet sequence number */

	/*
	 * STREAMS information
	 */
	queue_t *readq;		/* STREAMS read queue */
	queue_t *writeq;	/* STREAMS write queue */
	queue_t *traceq;	/* STREAMS trace queue */

	/*
	 * OS-Dependent information
	 *
	 * NB - For now we lock on a per-unit basis, so this points to
	 * the mutex of the unit it belongs to.  Other arrangements can
	 * be made later
	 *
	 * The condition variable in a output stream is used to wait for
	 * output to drain.
	 *
	 * The condition variable in a control stream is used to wait on
	 * open if the device is in use.
	 */
	kmutex_t *lock;		/* low-level lock */
	kcondvar_t cv;		/* generic condition variable */
};

#define	LOCK_AS(as)	mutex_enter((as)->lock)
#define	UNLOCK_AS(as)	mutex_exit((as)->lock)
#define	ASSERT_ASLOCKED(as) ASSERT(MUTEX_HELD((as)->lock))

#define	AUDIOCACTION_INIT	(0) /* no ioctl in progress */
#define	AUDIOCACTION_WAIT	(1) /* copyout response not received */
#define	AUDIOCACTION_WAITING	(2) /* read to ack/nak */


/*
 * Argument for audio_sensig
 */
typedef enum {
	AUDIO_SENDSIG_NONE = 0,	/* Default */
	AUDIO_SENDSIG_EXPLICIT,	/* Send signal up this aud_stream only */
	AUDIO_SENDSIG_ALL	/* Send signal up all related aud_streams */
} audio_sendsig_t;


/*
 * Define the ops-vector table for device-specific callouts
 *
 * close	close routine
 * ioctl	ioctl routine
 * start	routine to start I/O on a stream
 * stop		routine to stop I/O on a stream
 * setflag	routine to get or set a flag value
 * setinfo	routine to get or set the audio state structure
 * queuecmd	routine to queue a command on the HW command list
 * flushcmd	routine to flush the HW's command list
 */
typedef struct aud_ops	aud_ops_t;
struct aud_ops {
#ifdef __STDC__
	void (*close)(aud_stream_t *);
	aud_return_t (*ioctl)(aud_stream_t *, queue_t *, mblk_t *);
	aud_return_t (*mproto)(aud_stream_t *, mblk_t *);
	void (*start)(aud_stream_t *);
	void (*stop)(aud_stream_t *);
	uint_t (*setflag)(aud_stream_t *, enum aud_opflag, uint_t);
	aud_return_t (*setinfo)(aud_stream_t *, mblk_t *, int *);
	void (*queuecmd)(aud_stream_t *, aud_cmd_t *);
	void (*flushcmd)(aud_stream_t *);
#else /* __STDC__ */
	void (*close)();
	aud_return_t (*ioctl)();
	aud_return_t (*mproto)();
	void (*start)();
	void (*stop)();
	uint_t (*setflag)();
	aud_return_t (*setinfo)();
	void (*queuecmd)();
	void (*flushcmd)();
#endif /* __STDC__ */
};


/*
 * Define pseudo-routine names for the device-specific callouts
 */
#define	AUD_CLOSE(A)		(*(A)->distate->ops->close)(A)
#define	AUD_IOCTL(A, Q, M)	(*(A)->distate->ops->ioctl)(A, Q, M)
#define	AUD_MPROTO(A, M)	(*(A)->distate->ops->mproto)(A, M)
#define	AUD_START(A)		(*(A)->distate->ops->start)(A)
#define	AUD_STOP(A)		(*(A)->distate->ops->stop)(A)
#define	AUD_SETFLAG(A, F, X)	(*(A)->distate->ops->setflag)(A, F, X)
#define	AUD_GETFLAG(A, F)	(*(A)->distate->ops->setflag)(A, F, \
    AUD_INITVALUE)
#define	AUD_SETINFO(A, M, E)	(*(A)->distate->ops->setinfo)(A, M, E)
#define	AUD_GETINFO(A)		(*(A)->distate->ops->setinfo)(A, NULL, NULL)
#define	AUD_QUEUECMD(A, C)	(*(A)->distate->ops->queuecmd)(A, C)
#define	AUD_FLUSHCMD(A)		(*(A)->distate->ops->flushcmd)(A)


/*
 * Device Independent Audio driver function prototypes
 */
#ifdef __STDC__
extern int	audio_open(aud_stream_t *, queue_t *, dev_t *, int, int);
extern int	audio_close(queue_t *, int, cred_t *);
extern int	audio_wput(queue_t *, mblk_t *);
extern int	audio_wsrv(queue_t *);
extern int	audio_rput(queue_t *, mblk_t *);
extern int	audio_rsrv(queue_t *);
extern void	audio_gc_output(aud_stream_t *);
extern void	audio_process_output(aud_stream_t *);
extern void	audio_process_input(aud_stream_t *);
extern void	audio_sendsig(aud_stream_t *, audio_sendsig_t);
extern void	audio_flush_cmdlist(aud_stream_t *);
extern void	audio_ack(queue_t *, mblk_t *, int);
extern void	audio_copyout(queue_t *, mblk_t *, caddr_t, uint_t);
extern void	audio_pause_play(aud_stream_t *);
extern void	audio_pause_record(aud_stream_t *);
extern void	audio_resume_play(aud_stream_t *);
extern void	audio_resume_record(aud_stream_t *);
extern void	audio_trace(aud_stream_t *, aud_cmd_t *);
extern void	audio_trace_hdr(aud_stream_t *, audtrace_hdr_t *);
#else /* __STDC__ */
extern int	audio_open();
extern int	audio_close();
extern int	audio_wput();
extern int	audio_wsrv();
extern int	audio_rput();
extern int	audio_rsrv();
extern void	audio_gc_output();
extern void	audio_process_output();
extern void	audio_process_input();
extern void	audio_sendsig();
extern void	audio_flush_cmdlist();
extern void	audio_ack();
extern void	audio_copyout();
extern void	audio_pause_play();
extern void	audio_pause_record();
extern void	audio_resume_play();
extern void	audio_resume_record();
extern void	audio_trace()
extern void	audio_trace_hdr();
#endif /* __STDC__ */

#ifdef __cplusplus
}
#endif

#endif /* _SYS_AUDIOVAR_H */