#include <sys/types.h>
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/modctl.h>
#include <sys/ddi_impldefs.h>
#include <sys/kmem.h>
#include <sys/beep.h>
#include <sys/inttypes.h>
#ifdef DEBUG
int beep_debug = 0;
#define BEEP_DEBUG(args) if (beep_debug) cmn_err args
#define BEEP_DEBUG1(args) if (beep_debug > 1) cmn_err args
#else
#define BEEP_DEBUG(args)
#define BEEP_DEBUG1(args)
#endif
int beep_queue_size = BEEP_QUEUE_SIZE;
beep_state_t beep_state;
beep_params_t beep_params[] = {
{BEEP_CONSOLE, 900, 200},
{BEEP_TYPE4, 2000, 0},
{BEEP_DEFAULT, 1000, 200},
};
int
beep_init(void *arg,
beep_on_func_t beep_on_func,
beep_off_func_t beep_off_func,
beep_freq_func_t beep_freq_func)
{
beep_entry_t *queue;
BEEP_DEBUG1((CE_CONT,
"beep_init(0x%lx, 0x%lx, 0x%lx, 0x%lx) : start.",
(unsigned long) arg,
(unsigned long) beep_on_func,
(unsigned long) beep_off_func,
(unsigned long) beep_freq_func));
mutex_enter(&beep_state.mutex);
if (beep_state.mode != BEEP_UNINIT) {
mutex_exit(&beep_state.mutex);
BEEP_DEBUG((CE_WARN,
"beep_init : beep_state already initialized."));
return (DDI_SUCCESS);
}
queue = kmem_zalloc(sizeof (beep_entry_t) * beep_queue_size,
KM_SLEEP);
BEEP_DEBUG1((CE_CONT,
"beep_init : beep_queue kmem_zalloc(%d) = 0x%lx.",
(int)sizeof (beep_entry_t) * beep_queue_size,
(unsigned long)queue));
if (queue == NULL) {
BEEP_DEBUG((CE_WARN,
"beep_init : kmem_zalloc of beep_queue failed."));
return (DDI_FAILURE);
}
beep_state.arg = arg;
beep_state.mode = BEEP_OFF;
beep_state.beep_freq = beep_freq_func;
beep_state.beep_on = beep_on_func;
beep_state.beep_off = beep_off_func;
beep_state.timeout_id = 0;
beep_state.queue_head = 0;
beep_state.queue_tail = 0;
beep_state.queue_size = beep_queue_size;
beep_state.queue = queue;
mutex_exit(&beep_state.mutex);
BEEP_DEBUG1((CE_CONT, "beep_init : done."));
return (DDI_SUCCESS);
}
int
beep_fini(void)
{
BEEP_DEBUG1((CE_CONT, "beep_fini() : start."));
(void) beeper_off();
mutex_enter(&beep_state.mutex);
if (beep_state.mode == BEEP_UNINIT) {
mutex_exit(&beep_state.mutex);
BEEP_DEBUG((CE_WARN,
"beep_fini : beep_state already uninitialized."));
return (0);
}
if (beep_state.queue != NULL)
kmem_free(beep_state.queue,
sizeof (beep_entry_t) * beep_state.queue_size);
beep_state.arg = (void *)NULL;
beep_state.mode = BEEP_UNINIT;
beep_state.beep_freq = (beep_freq_func_t)NULL;
beep_state.beep_on = (beep_on_func_t)NULL;
beep_state.beep_off = (beep_off_func_t)NULL;
beep_state.timeout_id = 0;
beep_state.queue_head = 0;
beep_state.queue_tail = 0;
beep_state.queue_size = 0;
beep_state.queue = (beep_entry_t *)NULL;
mutex_exit(&beep_state.mutex);
BEEP_DEBUG1((CE_CONT, "beep_fini() : done."));
return (0);
}
int
beeper_off(void)
{
BEEP_DEBUG1((CE_CONT, "beeper_off : start."));
mutex_enter(&beep_state.mutex);
if (beep_state.mode == BEEP_UNINIT) {
mutex_exit(&beep_state.mutex);
return (ENXIO);
}
if (beep_state.mode == BEEP_TIMED) {
(void) untimeout(beep_state.timeout_id);
beep_state.timeout_id = 0;
}
if (beep_state.mode != BEEP_OFF) {
beep_state.mode = BEEP_OFF;
if (beep_state.beep_off != NULL)
(*beep_state.beep_off)(beep_state.arg);
}
beep_state.queue_head = 0;
beep_state.queue_tail = 0;
mutex_exit(&beep_state.mutex);
BEEP_DEBUG1((CE_CONT, "beeper_off : done."));
return (0);
}
int
beeper_freq(enum beep_type type, int freq)
{
beep_params_t *bp;
BEEP_DEBUG1((CE_CONT, "beeper_freq(%d, %d) : start", type, freq));
if (freq < 0 || freq > INT16_MAX)
return (EINVAL);
for (bp = beep_params; bp->type != BEEP_DEFAULT; bp++) {
if (bp->type == type)
break;
}
if (bp->type != type) {
BEEP_DEBUG((CE_WARN, "beeper_freq : invalid type."));
return (EINVAL);
}
bp->frequency = freq;
BEEP_DEBUG1((CE_CONT, "beeper_freq : done."));
return (0);
}
int
beep(enum beep_type type)
{
beep_params_t *bp;
BEEP_DEBUG1((CE_CONT, "beep(%d) : start.", type));
for (bp = beep_params; bp->type != BEEP_DEFAULT; bp++) {
if (bp->type == type)
break;
}
if (bp->type != type) {
BEEP_DEBUG((CE_WARN, "beep : invalid type."));
return (EINVAL);
}
return (beep_mktone(bp->frequency, bp->duration));
}
int
beep_polled(enum beep_type type)
{
BEEP_DEBUG1((CE_CONT, "beep_polled(%d)", type));
return (0);
}
int
beeper_on(enum beep_type type)
{
beep_params_t *bp;
int status = 0;
BEEP_DEBUG1((CE_CONT, "beeper_on(%d) : start.", type));
for (bp = beep_params; bp->type != BEEP_DEFAULT; bp++) {
if (bp->type == type)
break;
}
if (bp->type != type) {
BEEP_DEBUG((CE_WARN, "beeper_on : invalid type."));
return (EINVAL);
}
mutex_enter(&beep_state.mutex);
if (beep_state.mode == BEEP_UNINIT) {
status = ENXIO;
} else if (beep_state.mode == BEEP_OFF) {
if (bp->frequency != 0) {
beep_state.mode = BEEP_ON;
if (beep_state.beep_freq != NULL)
(*beep_state.beep_freq)(beep_state.arg,
bp->frequency);
if (beep_state.beep_on != NULL)
(*beep_state.beep_on)(beep_state.arg);
}
} else {
status = EBUSY;
}
mutex_exit(&beep_state.mutex);
BEEP_DEBUG1((CE_CONT, "beeper_on : done, status %d.", status));
return (status);
}
int
beep_mktone(int frequency, int duration)
{
int next;
int status = 0;
BEEP_DEBUG1((CE_CONT, "beep_mktone(%d, %d) : start.", frequency,
duration));
if (frequency < 0 || frequency > INT16_MAX)
return (EINVAL);
mutex_enter(&beep_state.mutex);
if (beep_state.mode == BEEP_UNINIT) {
status = ENXIO;
} else if (beep_state.mode == BEEP_TIMED) {
if (frequency != 0) {
next = beep_state.queue_tail + 1;
if (next == beep_state.queue_size)
next = 0;
if (next != beep_state.queue_head) {
beep_state.queue[beep_state.queue_tail].
frequency = (unsigned short)frequency;
beep_state.queue[beep_state.queue_tail].
duration = (unsigned short)duration;
beep_state.queue_tail = next;
} else {
status = EAGAIN;
}
}
} else if (beep_state.mode == BEEP_OFF) {
if (frequency != 0) {
beep_state.mode = BEEP_TIMED;
if (beep_state.beep_freq != NULL)
(*beep_state.beep_freq)(beep_state.arg,
frequency);
if (beep_state.beep_on != NULL)
(*beep_state.beep_on)(beep_state.arg);
beep_state.timeout_id = timeout(beep_timeout, NULL,
drv_usectohz(duration * 1000));
}
} else {
status = EBUSY;
}
mutex_exit(&beep_state.mutex);
BEEP_DEBUG1((CE_CONT, "beep_mktone : done, status %d.", status));
return (status);
}
void
beep_timeout(void *arg)
{
int frequency;
int duration;
int next;
BEEP_DEBUG1((CE_CONT, "beeper_timeout : start."));
mutex_enter(&beep_state.mutex);
beep_state.timeout_id = 0;
if (beep_state.mode == BEEP_UNINIT) {
mutex_exit(&beep_state.mutex);
BEEP_DEBUG1((CE_CONT, "beep_timeout : uninitialized."));
return;
}
if ((beep_state.mode == BEEP_ON) ||
(beep_state.mode == BEEP_TIMED)) {
beep_state.mode = BEEP_OFF;
if (beep_state.beep_off != NULL)
(*beep_state.beep_off)(beep_state.arg);
}
if (beep_state.queue_head != beep_state.queue_tail) {
next = beep_state.queue_head;
frequency = beep_state.queue[next].frequency;
duration = beep_state.queue[next].duration;
next++;
if (next == beep_state.queue_size)
next = 0;
beep_state.queue_head = next;
beep_state.mode = BEEP_TIMED;
if (frequency != 0) {
if (beep_state.beep_freq != NULL)
(*beep_state.beep_freq)(beep_state.arg,
frequency);
if (beep_state.beep_on != NULL)
(*beep_state.beep_on)(beep_state.arg);
}
beep_state.timeout_id = timeout(beep_timeout, NULL,
drv_usectohz(duration * 1000));
}
mutex_exit(&beep_state.mutex);
BEEP_DEBUG1((CE_CONT, "beep_timeout : done."));
}
int
beep_busy(void)
{
int status;
BEEP_DEBUG1((CE_CONT, "beep_busy : start."));
mutex_enter(&beep_state.mutex);
status = beep_state.mode != BEEP_UNINIT &&
beep_state.mode != BEEP_OFF;
mutex_exit(&beep_state.mutex);
BEEP_DEBUG1((CE_CONT, "beep_busy : status %d.", status));
return (status);
}