/* * 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 */