/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (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) 4Front Technologies 1996-2008.
 *
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef	_SYS_AUDIO_AUDIO_DRIVER_H
#define	_SYS_AUDIO_AUDIO_DRIVER_H

#include <sys/types.h>
#include <sys/list.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/audio/audio_common.h>


#ifdef	__cplusplus
extern "C" {
#endif

#ifdef	_KERNEL

struct audio_engine_ops {
	int		ae_version;
#define	AUDIO_ENGINE_VERSION	1

	/*
	 * Initialize engine, including buffer allocation.  Arguments
	 * that are pointers are hints.  On return, they are updated with
	 * the actual values configured by the driver.
	 */
	int		(*ae_open)(void *, int flags, int fmt,
			    int *nchan,  int *rate,
			    unsigned *fragfr, unsigned *nfrags, caddr_t *buf);
	void		(*ae_close)(void *);

	/*
	 * Start and stop are used to actually get the hardware runnign
	 * or stop the hardware.  Until this is kicked offed, the engine
	 * will not actually transfer data.  These are not destructive to
	 * ring positions, etc.  (Think of it like pause/play).
	 */
	int		(*ae_start)(void *);
	void		(*ae_stop)(void *);

	/*
	 * Obtain the engine offset.  Offsets start at zero at engine_open,
	 * and keep counting upwards.  Count is returned in frames.
	 */
	uint64_t	(*ae_count)(void *);

	/*
	 * rates returns an integer listing the number of discrete
	 * rates returned in the int **, or 0 to indicate that the
	 * device has a freely changeable clock, in which case the
	 * array contains only two elements; the min and max rate
	 * supported.
	 */
	int		(*ae_rates)(void *, int **);

	/*
	 * DMA cache synzhronization.  The framework does this on
	 * behalf of the driver for both input and output.  The driver
	 * is responsible for tracking the direction (based on the
	 * flags passed to ae_open()), and dealing with any partial
	 * synchronization if any is needed.
	 */
	void		(*ae_sync)(void *);

	/*
	 * The framework may like to know how deep the device queues data.
	 * This can be used to provide a more accurate latency calculation.
	 */
	size_t		(*ae_qlen)(void *);
};

void audio_init_ops(struct dev_ops *, const char *);
void audio_fini_ops(struct dev_ops *);

audio_dev_t *audio_dev_alloc(dev_info_t *, int);
void audio_dev_free(audio_dev_t *);

void audio_dev_set_description(audio_dev_t *, const char *);
void audio_dev_set_version(audio_dev_t *, const char *);
void audio_dev_set_private(audio_dev_t *, void *);
void *audio_dev_get_private(audio_dev_t *);

audio_engine_t *audio_engine_alloc(audio_engine_ops_t *, unsigned, unsigned);
void audio_engine_set_private(audio_engine_t *, void *);
void *audio_engine_get_private(audio_engine_t *);
void audio_engine_free(audio_engine_t *);

void audio_dev_add_engine(audio_dev_t *, audio_engine_t *);
void audio_dev_remove_engine(audio_dev_t *, audio_engine_t *);
int audio_dev_register(audio_dev_t *);
int audio_dev_unregister(audio_dev_t *);
void audio_dev_warn(audio_dev_t *, const char *, ...);
/* DEBUG ONLY */
void audio_dump_bytes(uint8_t *w, int dcount);
void audio_dump_words(uint16_t *w, int dcount);
void audio_dump_dwords(uint32_t *w, int dcount);

/*
 * Drivers call these.
 */
void audio_engine_consume(audio_engine_t *);
void audio_engine_produce(audio_engine_t *);
void audio_engine_reset(audio_engine_t *);

/* Engine flags */
#define	ENGINE_MULTIFRAG	(1U << 1)
#define	ENGINE_OUTPUT_CAP	(1U << 2)
#define	ENGINE_INPUT_CAP	(1U << 3)
#define	ENGINE_SNDSTAT		(1U << 4)
#define	ENGINE_CAPS		(ENGINE_OUTPUT_CAP | ENGINE_INPUT_CAP)
#define	ENGINE_DRIVER_FLAGS	(0xffff)	/* flags usable by driver */

#define	ENGINE_OUTPUT		(1U << 16)	/* fields not for driver use */
#define	ENGINE_INPUT		(1U << 17)
#define	ENGINE_OPEN		(1U << 18)
#define	ENGINE_RUNNING		(1U << 19)
#define	ENGINE_EXCLUSIVE	(1U << 20)	/* exclusive use, e.g. AC3 */
#define	ENGINE_NDELAY		(1U << 21)	/* non-blocking open */
#define	ENGINE_WAKE		(1U << 22)	/* wakeup tq running */

/*
 * entry points used by legacy SADA drivers
 */
int audio_legacy_open(queue_t *, dev_t *, int, int, cred_t *);
int audio_legacy_close(queue_t *, int, cred_t *);
int audio_legacy_wput(queue_t *, mblk_t *);
int audio_legacy_wsrv(queue_t *);
int audio_legacy_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);



/*
 * Audio device controls
 */

/*
 * control read or write driver function type
 *
 * arg              - driver private context
 * value            - for write function, value to set control to, for read
 *		      function a pointer where the value will be stored
 *
 * Returns zero on success, errno on failure.
 */
typedef int (*audio_ctrl_wr_t)(void *arg, uint64_t value);
typedef int (*audio_ctrl_rd_t)(void *arg, uint64_t *value);


/*
 * This will allocate and register a control for my audio device.
 *
 * adev             - The device the control will be attached to.
 * my_control       - Attributes about this control.
 * read_func        - Callback function in driver to read control.
 * write_func       - Callback function in driver to write control.
 * arg              - Driver private context arg.
 *
 * On success this will return a control structure else NULL.
 *
 */
audio_ctrl_t *audio_dev_add_control(audio_dev_t *adev,
    audio_ctrl_desc_t *control, audio_ctrl_rd_t read_func,
    audio_ctrl_wr_t write_func, void *arg);

/*
 * This will remove a control from my audio device.
 *
 * ctrl             - The control will be removed.
 */
void audio_dev_del_control(audio_ctrl_t *ctrl);

/*
 * This will tell the framework that controls have changed
 * and it should update its values.
 *
 * adev             - The device that needs updates.
 */
void audio_dev_update_controls(audio_dev_t *adev);

/*
 * This is used to read the current value of a control.
 * Note, this will cause a callback into the driver to get the value.
 *
 * control     - should be the valid handle for the control being read.
 * value       - is a pointer to the place that will contain the value read.
 *
 * On return zero is returned on success else errno is returned.
 *
 */
int audio_control_read(audio_ctrl_t *control, uint64_t *value);

/*
 * This is used to write a value to a control.
 * Note, this will cause a callback into the driver to write the value.
 *
 * control     - should be the valid handle for the control being written.
 * value       - is value to set the control to.
 *
 * On return zero is returned on success else errno is returned.
 *
 */
int audio_control_write(audio_ctrl_t *control, uint64_t value);

#endif	/* _KERNEL */

#ifdef	__cplusplus
}
#endif

#endif	/* _SYS_AUDIO_AUDIO_DRIVER_H */
