xref: /illumos-gate/usr/src/uts/common/io/beep.c (revision 2d6eb4a5)
1*c35aa225Smarx /*
2*c35aa225Smarx  * CDDL HEADER START
3*c35aa225Smarx  *
4*c35aa225Smarx  * The contents of this file are subject to the terms of the
5*c35aa225Smarx  * Common Development and Distribution License (the "License").
6*c35aa225Smarx  * You may not use this file except in compliance with the License.
7*c35aa225Smarx  *
8*c35aa225Smarx  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*c35aa225Smarx  * or http://www.opensolaris.org/os/licensing.
10*c35aa225Smarx  * See the License for the specific language governing permissions
11*c35aa225Smarx  * and limitations under the License.
12*c35aa225Smarx  *
13*c35aa225Smarx  * When distributing Covered Code, include this CDDL HEADER in each
14*c35aa225Smarx  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*c35aa225Smarx  * If applicable, add the following below this CDDL HEADER, with the
16*c35aa225Smarx  * fields enclosed by brackets "[]" replaced with your own identifying
17*c35aa225Smarx  * information: Portions Copyright [yyyy] [name of copyright owner]
18*c35aa225Smarx  *
19*c35aa225Smarx  * CDDL HEADER END
20*c35aa225Smarx  */
21*c35aa225Smarx /*
22*c35aa225Smarx  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*c35aa225Smarx  * Use is subject to license terms.
24*c35aa225Smarx  */
25*c35aa225Smarx 
26*c35aa225Smarx /*
27*c35aa225Smarx  * This is the Beep module for supporting keyboard beep for keyboards
28*c35aa225Smarx  * that do not have the beeping feature within themselves
29*c35aa225Smarx  *
30*c35aa225Smarx  */
31*c35aa225Smarx 
32*c35aa225Smarx #include <sys/types.h>
33*c35aa225Smarx #include <sys/conf.h>
34*c35aa225Smarx 
35*c35aa225Smarx #include <sys/ddi.h>
36*c35aa225Smarx #include <sys/sunddi.h>
37*c35aa225Smarx #include <sys/modctl.h>
38*c35aa225Smarx #include <sys/ddi_impldefs.h>
39*c35aa225Smarx #include <sys/kmem.h>
40*c35aa225Smarx 
41*c35aa225Smarx #include <sys/beep.h>
42*c35aa225Smarx #include <sys/inttypes.h>
43*c35aa225Smarx 
44*c35aa225Smarx /*
45*c35aa225Smarx  * Debug stuff
46*c35aa225Smarx  * BEEP_DEBUG used for errors
47*c35aa225Smarx  * BEEP_DEBUG1 prints when beep_debug > 1 and used for normal messages
48*c35aa225Smarx  */
49*c35aa225Smarx #ifdef DEBUG
50*c35aa225Smarx int beep_debug = 0;
51*c35aa225Smarx #define	BEEP_DEBUG(args)	if (beep_debug) cmn_err args
52*c35aa225Smarx #define	BEEP_DEBUG1(args)	if (beep_debug > 1) cmn_err args
53*c35aa225Smarx #else
54*c35aa225Smarx #define	BEEP_DEBUG(args)
55*c35aa225Smarx #define	BEEP_DEBUG1(args)
56*c35aa225Smarx #endif
57*c35aa225Smarx 
58*c35aa225Smarx int beep_queue_size = BEEP_QUEUE_SIZE;
59*c35aa225Smarx 
60*c35aa225Smarx /*
61*c35aa225Smarx  * Note that mutex_init is not called on the mutex in beep_state,
62*c35aa225Smarx  * But assumes that zeroed memory does not need to call mutex_init,
63*c35aa225Smarx  * as documented in mutex.c
64*c35aa225Smarx  */
65*c35aa225Smarx 
66*c35aa225Smarx beep_state_t beep_state;
67*c35aa225Smarx 
68*c35aa225Smarx beep_params_t beep_params[] = {
69*c35aa225Smarx 	{BEEP_CONSOLE,	900,	200},
70*c35aa225Smarx 	{BEEP_TYPE4,	2000,	0},
71*c35aa225Smarx 	{BEEP_DEFAULT,	1000,	200},	/* Must be last */
72*c35aa225Smarx };
73*c35aa225Smarx 
74*c35aa225Smarx 
75*c35aa225Smarx /*
76*c35aa225Smarx  * beep_init:
77*c35aa225Smarx  * Allocate the beep_queue structure
78*c35aa225Smarx  * Initialize beep_state structure
79*c35aa225Smarx  * Called from beep driver attach routine
80*c35aa225Smarx  */
81*c35aa225Smarx 
82*c35aa225Smarx 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)83*c35aa225Smarx beep_init(void *arg,
84*c35aa225Smarx     beep_on_func_t beep_on_func,
85*c35aa225Smarx     beep_off_func_t beep_off_func,
86*c35aa225Smarx     beep_freq_func_t beep_freq_func)
87*c35aa225Smarx {
88*c35aa225Smarx 	beep_entry_t *queue;
89*c35aa225Smarx 
90*c35aa225Smarx 	BEEP_DEBUG1((CE_CONT,
91*c35aa225Smarx 	    "beep_init(0x%lx, 0x%lx, 0x%lx, 0x%lx) : start.",
92*c35aa225Smarx 	    (unsigned long) arg,
93*c35aa225Smarx 	    (unsigned long) beep_on_func,
94*c35aa225Smarx 	    (unsigned long) beep_off_func,
95*c35aa225Smarx 	    (unsigned long) beep_freq_func));
96*c35aa225Smarx 
97*c35aa225Smarx 	mutex_enter(&beep_state.mutex);
98*c35aa225Smarx 
99*c35aa225Smarx 	if (beep_state.mode != BEEP_UNINIT) {
100*c35aa225Smarx 		mutex_exit(&beep_state.mutex);
101*c35aa225Smarx 		BEEP_DEBUG((CE_WARN,
102*c35aa225Smarx 		    "beep_init : beep_state already initialized."));
103*c35aa225Smarx 		return (DDI_SUCCESS);
104*c35aa225Smarx 	}
105*c35aa225Smarx 
106*c35aa225Smarx 	queue = kmem_zalloc(sizeof (beep_entry_t) * beep_queue_size,
107*c35aa225Smarx 	    KM_SLEEP);
108*c35aa225Smarx 
109*c35aa225Smarx 	BEEP_DEBUG1((CE_CONT,
110*c35aa225Smarx 	    "beep_init : beep_queue kmem_zalloc(%d) = 0x%lx.",
111*c35aa225Smarx 	    (int)sizeof (beep_entry_t) * beep_queue_size,
112*c35aa225Smarx 	    (unsigned long)queue));
113*c35aa225Smarx 
114*c35aa225Smarx 	if (queue == NULL) {
115*c35aa225Smarx 		BEEP_DEBUG((CE_WARN,
116*c35aa225Smarx 		    "beep_init : kmem_zalloc of beep_queue failed."));
117*c35aa225Smarx 		return (DDI_FAILURE);
118*c35aa225Smarx 	}
119*c35aa225Smarx 
120*c35aa225Smarx 	beep_state.arg = arg;
121*c35aa225Smarx 	beep_state.mode = BEEP_OFF;
122*c35aa225Smarx 	beep_state.beep_freq = beep_freq_func;
123*c35aa225Smarx 	beep_state.beep_on = beep_on_func;
124*c35aa225Smarx 	beep_state.beep_off = beep_off_func;
125*c35aa225Smarx 	beep_state.timeout_id = 0;
126*c35aa225Smarx 
127*c35aa225Smarx 	beep_state.queue_head = 0;
128*c35aa225Smarx 	beep_state.queue_tail = 0;
129*c35aa225Smarx 	beep_state.queue_size = beep_queue_size;
130*c35aa225Smarx 	beep_state.queue = queue;
131*c35aa225Smarx 
132*c35aa225Smarx 	mutex_exit(&beep_state.mutex);
133*c35aa225Smarx 
134*c35aa225Smarx 	BEEP_DEBUG1((CE_CONT, "beep_init : done."));
135*c35aa225Smarx 	return (DDI_SUCCESS);
136*c35aa225Smarx }
137*c35aa225Smarx 
138*c35aa225Smarx 
139*c35aa225Smarx int
beep_fini(void)140*c35aa225Smarx beep_fini(void)
141*c35aa225Smarx {
142*c35aa225Smarx 	BEEP_DEBUG1((CE_CONT, "beep_fini() : start."));
143*c35aa225Smarx 
144*c35aa225Smarx 	(void) beeper_off();
145*c35aa225Smarx 
146*c35aa225Smarx 	mutex_enter(&beep_state.mutex);
147*c35aa225Smarx 
148*c35aa225Smarx 	if (beep_state.mode == BEEP_UNINIT) {
149*c35aa225Smarx 		mutex_exit(&beep_state.mutex);
150*c35aa225Smarx 		BEEP_DEBUG((CE_WARN,
151*c35aa225Smarx 		    "beep_fini : beep_state already uninitialized."));
152*c35aa225Smarx 		return (0);
153*c35aa225Smarx 	}
154*c35aa225Smarx 
155*c35aa225Smarx 	if (beep_state.queue != NULL)
156*c35aa225Smarx 		kmem_free(beep_state.queue,
157*c35aa225Smarx 		    sizeof (beep_entry_t) * beep_state.queue_size);
158*c35aa225Smarx 
159*c35aa225Smarx 	beep_state.arg = (void *)NULL;
160*c35aa225Smarx 	beep_state.mode = BEEP_UNINIT;
161*c35aa225Smarx 	beep_state.beep_freq = (beep_freq_func_t)NULL;
162*c35aa225Smarx 	beep_state.beep_on = (beep_on_func_t)NULL;
163*c35aa225Smarx 	beep_state.beep_off = (beep_off_func_t)NULL;
164*c35aa225Smarx 	beep_state.timeout_id = 0;
165*c35aa225Smarx 
166*c35aa225Smarx 	beep_state.queue_head = 0;
167*c35aa225Smarx 	beep_state.queue_tail = 0;
168*c35aa225Smarx 	beep_state.queue_size = 0;
169*c35aa225Smarx 	beep_state.queue = (beep_entry_t *)NULL;
170*c35aa225Smarx 
171*c35aa225Smarx 	mutex_exit(&beep_state.mutex);
172*c35aa225Smarx 
173*c35aa225Smarx 	BEEP_DEBUG1((CE_CONT, "beep_fini() : done."));
174*c35aa225Smarx 
175*c35aa225Smarx 	return (0);
176*c35aa225Smarx }
177*c35aa225Smarx 
178*c35aa225Smarx 
179*c35aa225Smarx int
beeper_off(void)180*c35aa225Smarx beeper_off(void)
181*c35aa225Smarx {
182*c35aa225Smarx 	BEEP_DEBUG1((CE_CONT, "beeper_off : start."));
183*c35aa225Smarx 
184*c35aa225Smarx 	mutex_enter(&beep_state.mutex);
185*c35aa225Smarx 
186*c35aa225Smarx 	if (beep_state.mode == BEEP_UNINIT) {
187*c35aa225Smarx 		mutex_exit(&beep_state.mutex);
188*c35aa225Smarx 		return (ENXIO);
189*c35aa225Smarx 	}
190*c35aa225Smarx 
191*c35aa225Smarx 	if (beep_state.mode == BEEP_TIMED) {
192*c35aa225Smarx 		(void) untimeout(beep_state.timeout_id);
193*c35aa225Smarx 		beep_state.timeout_id = 0;
194*c35aa225Smarx 	}
195*c35aa225Smarx 
196*c35aa225Smarx 	if (beep_state.mode != BEEP_OFF) {
197*c35aa225Smarx 		beep_state.mode = BEEP_OFF;
198*c35aa225Smarx 
199*c35aa225Smarx 		if (beep_state.beep_off != NULL)
200*c35aa225Smarx 			(*beep_state.beep_off)(beep_state.arg);
201*c35aa225Smarx 	}
202*c35aa225Smarx 
203*c35aa225Smarx 	beep_state.queue_head = 0;
204*c35aa225Smarx 	beep_state.queue_tail = 0;
205*c35aa225Smarx 
206*c35aa225Smarx 	mutex_exit(&beep_state.mutex);
207*c35aa225Smarx 
208*c35aa225Smarx 	BEEP_DEBUG1((CE_CONT, "beeper_off : done."));
209*c35aa225Smarx 
210*c35aa225Smarx 	return (0);
211*c35aa225Smarx }
212*c35aa225Smarx 
213*c35aa225Smarx int
beeper_freq(enum beep_type type,int freq)214*c35aa225Smarx beeper_freq(enum beep_type type, int freq)
215*c35aa225Smarx {
216*c35aa225Smarx 	beep_params_t *bp;
217*c35aa225Smarx 
218*c35aa225Smarx 	BEEP_DEBUG1((CE_CONT, "beeper_freq(%d, %d) : start", type, freq));
219*c35aa225Smarx 
220*c35aa225Smarx 	/*
221*c35aa225Smarx 	 * The frequency value is limited to the range of [0 - 32767]
222*c35aa225Smarx 	 */
223*c35aa225Smarx 	if (freq < 0 || freq > INT16_MAX)
224*c35aa225Smarx 		return (EINVAL);
225*c35aa225Smarx 
226*c35aa225Smarx 	for (bp = beep_params; bp->type != BEEP_DEFAULT; bp++) {
227*c35aa225Smarx 		if (bp->type == type)
228*c35aa225Smarx 			break;
229*c35aa225Smarx 	}
230*c35aa225Smarx 
231*c35aa225Smarx 	if (bp->type != type) {
232*c35aa225Smarx 		BEEP_DEBUG((CE_WARN, "beeper_freq : invalid type."));
233*c35aa225Smarx 
234*c35aa225Smarx 		return (EINVAL);
235*c35aa225Smarx 	}
236*c35aa225Smarx 
237*c35aa225Smarx 	bp->frequency = freq;
238*c35aa225Smarx 
239*c35aa225Smarx 	BEEP_DEBUG1((CE_CONT, "beeper_freq : done."));
240*c35aa225Smarx 	return (0);
241*c35aa225Smarx }
242*c35aa225Smarx 
243*c35aa225Smarx /*
244*c35aa225Smarx  * beep :
245*c35aa225Smarx  *      Start beeping for period specified by the type value,
246*c35aa225Smarx  *      from the value in the beep_param structure in milliseconds.
247*c35aa225Smarx  */
248*c35aa225Smarx int
beep(enum beep_type type)249*c35aa225Smarx beep(enum beep_type type)
250*c35aa225Smarx {
251*c35aa225Smarx 
252*c35aa225Smarx 	beep_params_t *bp;
253*c35aa225Smarx 
254*c35aa225Smarx 	BEEP_DEBUG1((CE_CONT, "beep(%d) : start.", type));
255*c35aa225Smarx 
256*c35aa225Smarx 	for (bp = beep_params; bp->type != BEEP_DEFAULT; bp++) {
257*c35aa225Smarx 		if (bp->type == type)
258*c35aa225Smarx 			break;
259*c35aa225Smarx 	}
260*c35aa225Smarx 
261*c35aa225Smarx 	if (bp->type != type) {
262*c35aa225Smarx 
263*c35aa225Smarx 		BEEP_DEBUG((CE_WARN, "beep : invalid type."));
264*c35aa225Smarx 
265*c35aa225Smarx 		/* If type doesn't match, return silently without beeping */
266*c35aa225Smarx 		return (EINVAL);
267*c35aa225Smarx 	}
268*c35aa225Smarx 
269*c35aa225Smarx 	return (beep_mktone(bp->frequency, bp->duration));
270*c35aa225Smarx }
271*c35aa225Smarx 
272*c35aa225Smarx 
273*c35aa225Smarx /*ARGSUSED*/
274*c35aa225Smarx int
beep_polled(enum beep_type type)275*c35aa225Smarx beep_polled(enum beep_type type)
276*c35aa225Smarx {
277*c35aa225Smarx 	/*
278*c35aa225Smarx 	 * No-op at this time.
279*c35aa225Smarx 	 *
280*c35aa225Smarx 	 * Don't think we can make this work in general, as tem_safe
281*c35aa225Smarx 	 * has a requirement of no mutexes, but kbd sends messages
282*c35aa225Smarx 	 * through streams.
283*c35aa225Smarx 	 */
284*c35aa225Smarx 
285*c35aa225Smarx 	BEEP_DEBUG1((CE_CONT, "beep_polled(%d)", type));
286*c35aa225Smarx 
287*c35aa225Smarx 	return (0);
288*c35aa225Smarx }
289*c35aa225Smarx 
290*c35aa225Smarx /*
291*c35aa225Smarx  * beeper_on :
292*c35aa225Smarx  *      Turn the beeper on
293*c35aa225Smarx  */
294*c35aa225Smarx int
beeper_on(enum beep_type type)295*c35aa225Smarx beeper_on(enum beep_type type)
296*c35aa225Smarx {
297*c35aa225Smarx 	beep_params_t *bp;
298*c35aa225Smarx 	int status = 0;
299*c35aa225Smarx 
300*c35aa225Smarx 	BEEP_DEBUG1((CE_CONT, "beeper_on(%d) : start.", type));
301*c35aa225Smarx 
302*c35aa225Smarx 	for (bp = beep_params; bp->type != BEEP_DEFAULT; bp++) {
303*c35aa225Smarx 		if (bp->type == type)
304*c35aa225Smarx 			break;
305*c35aa225Smarx 	}
306*c35aa225Smarx 
307*c35aa225Smarx 	if (bp->type != type) {
308*c35aa225Smarx 
309*c35aa225Smarx 		BEEP_DEBUG((CE_WARN, "beeper_on : invalid type."));
310*c35aa225Smarx 
311*c35aa225Smarx 		/* If type doesn't match, return silently without beeping */
312*c35aa225Smarx 		return (EINVAL);
313*c35aa225Smarx 	}
314*c35aa225Smarx 
315*c35aa225Smarx 	mutex_enter(&beep_state.mutex);
316*c35aa225Smarx 
317*c35aa225Smarx 	if (beep_state.mode == BEEP_UNINIT) {
318*c35aa225Smarx 		status = ENXIO;
319*c35aa225Smarx 
320*c35aa225Smarx 	/* Start another beep only if the previous one is over */
321*c35aa225Smarx 	} else if (beep_state.mode == BEEP_OFF) {
322*c35aa225Smarx 		if (bp->frequency != 0) {
323*c35aa225Smarx 			beep_state.mode = BEEP_ON;
324*c35aa225Smarx 
325*c35aa225Smarx 			if (beep_state.beep_freq != NULL)
326*c35aa225Smarx 				(*beep_state.beep_freq)(beep_state.arg,
327*c35aa225Smarx 				    bp->frequency);
328*c35aa225Smarx 
329*c35aa225Smarx 			if (beep_state.beep_on != NULL)
330*c35aa225Smarx 				(*beep_state.beep_on)(beep_state.arg);
331*c35aa225Smarx 		}
332*c35aa225Smarx 	} else {
333*c35aa225Smarx 		status = EBUSY;
334*c35aa225Smarx 	}
335*c35aa225Smarx 
336*c35aa225Smarx 	mutex_exit(&beep_state.mutex);
337*c35aa225Smarx 
338*c35aa225Smarx 	BEEP_DEBUG1((CE_CONT, "beeper_on : done, status %d.", status));
339*c35aa225Smarx 
340*c35aa225Smarx 	return (status);
341*c35aa225Smarx }
342*c35aa225Smarx 
343*c35aa225Smarx 
344*c35aa225Smarx int
beep_mktone(int frequency,int duration)345*c35aa225Smarx beep_mktone(int frequency, int duration)
346*c35aa225Smarx {
347*c35aa225Smarx 	int next;
348*c35aa225Smarx 	int status = 0;
349*c35aa225Smarx 
350*c35aa225Smarx 	BEEP_DEBUG1((CE_CONT, "beep_mktone(%d, %d) : start.", frequency,
351*c35aa225Smarx 	    duration));
352*c35aa225Smarx 
353*c35aa225Smarx 	/*
354*c35aa225Smarx 	 * The frequency value is limited to the range of [0 - 32767]
355*c35aa225Smarx 	 */
356*c35aa225Smarx 	if (frequency < 0 || frequency > INT16_MAX)
357*c35aa225Smarx 		return (EINVAL);
358*c35aa225Smarx 
359*c35aa225Smarx 	mutex_enter(&beep_state.mutex);
360*c35aa225Smarx 
361*c35aa225Smarx 	if (beep_state.mode == BEEP_UNINIT) {
362*c35aa225Smarx 		status = ENXIO;
363*c35aa225Smarx 
364*c35aa225Smarx 	} else if (beep_state.mode == BEEP_TIMED) {
365*c35aa225Smarx 
366*c35aa225Smarx 		/* If already processing a beep, queue this one */
367*c35aa225Smarx 
368*c35aa225Smarx 		if (frequency != 0) {
369*c35aa225Smarx 			next = beep_state.queue_tail + 1;
370*c35aa225Smarx 			if (next == beep_state.queue_size)
371*c35aa225Smarx 				next = 0;
372*c35aa225Smarx 
373*c35aa225Smarx 			if (next != beep_state.queue_head) {
374*c35aa225Smarx 				/*
375*c35aa225Smarx 				 * If there is room in the queue,
376*c35aa225Smarx 				 * add this entry
377*c35aa225Smarx 				 */
378*c35aa225Smarx 
379*c35aa225Smarx 				beep_state.queue[beep_state.queue_tail].
380*c35aa225Smarx 				    frequency = (unsigned short)frequency;
381*c35aa225Smarx 
382*c35aa225Smarx 				beep_state.queue[beep_state.queue_tail].
383*c35aa225Smarx 				    duration = (unsigned short)duration;
384*c35aa225Smarx 
385*c35aa225Smarx 				beep_state.queue_tail = next;
386*c35aa225Smarx 			} else {
387*c35aa225Smarx 				status = EAGAIN;
388*c35aa225Smarx 			}
389*c35aa225Smarx 		}
390*c35aa225Smarx 
391*c35aa225Smarx 	} else if (beep_state.mode == BEEP_OFF) {
392*c35aa225Smarx 
393*c35aa225Smarx 		/* Start another beep only if the previous one is over */
394*c35aa225Smarx 
395*c35aa225Smarx 		if (frequency != 0) {
396*c35aa225Smarx 			beep_state.mode = BEEP_TIMED;
397*c35aa225Smarx 
398*c35aa225Smarx 			if (beep_state.beep_freq != NULL)
399*c35aa225Smarx 				(*beep_state.beep_freq)(beep_state.arg,
400*c35aa225Smarx 				    frequency);
401*c35aa225Smarx 
402*c35aa225Smarx 			if (beep_state.beep_on != NULL)
403*c35aa225Smarx 				(*beep_state.beep_on)(beep_state.arg);
404*c35aa225Smarx 
405*c35aa225Smarx 			/*
406*c35aa225Smarx 			 * Set timeout for ending the beep after the
407*c35aa225Smarx 			 * specified time
408*c35aa225Smarx 			 */
409*c35aa225Smarx 
410*c35aa225Smarx 			beep_state.timeout_id = timeout(beep_timeout, NULL,
411*c35aa225Smarx 			    drv_usectohz(duration * 1000));
412*c35aa225Smarx 		}
413*c35aa225Smarx 	} else {
414*c35aa225Smarx 		status = EBUSY;
415*c35aa225Smarx 	}
416*c35aa225Smarx 
417*c35aa225Smarx 	mutex_exit(&beep_state.mutex);
418*c35aa225Smarx 
419*c35aa225Smarx 	BEEP_DEBUG1((CE_CONT, "beep_mktone : done, status %d.", status));
420*c35aa225Smarx 
421*c35aa225Smarx 	return (status);
422*c35aa225Smarx }
423*c35aa225Smarx 
424*c35aa225Smarx 
425*c35aa225Smarx /*
426*c35aa225Smarx  * Turn the beeper off which had been turned on from beep()
427*c35aa225Smarx  * for a specified period of time
428*c35aa225Smarx  */
429*c35aa225Smarx /*ARGSUSED*/
430*c35aa225Smarx void
beep_timeout(void * arg)431*c35aa225Smarx beep_timeout(void *arg)
432*c35aa225Smarx {
433*c35aa225Smarx 	int frequency;
434*c35aa225Smarx 	int duration;
435*c35aa225Smarx 	int next;
436*c35aa225Smarx 
437*c35aa225Smarx 	BEEP_DEBUG1((CE_CONT, "beeper_timeout : start."));
438*c35aa225Smarx 
439*c35aa225Smarx 	mutex_enter(&beep_state.mutex);
440*c35aa225Smarx 
441*c35aa225Smarx 	beep_state.timeout_id = 0;
442*c35aa225Smarx 
443*c35aa225Smarx 	if (beep_state.mode == BEEP_UNINIT) {
444*c35aa225Smarx 		mutex_exit(&beep_state.mutex);
445*c35aa225Smarx 		BEEP_DEBUG1((CE_CONT, "beep_timeout : uninitialized."));
446*c35aa225Smarx 		return;
447*c35aa225Smarx 	}
448*c35aa225Smarx 
449*c35aa225Smarx 	if ((beep_state.mode == BEEP_ON) ||
450*c35aa225Smarx 	    (beep_state.mode == BEEP_TIMED)) {
451*c35aa225Smarx 
452*c35aa225Smarx 		beep_state.mode = BEEP_OFF;
453*c35aa225Smarx 
454*c35aa225Smarx 		if (beep_state.beep_off != NULL)
455*c35aa225Smarx 			(*beep_state.beep_off)(beep_state.arg);
456*c35aa225Smarx 	}
457*c35aa225Smarx 
458*c35aa225Smarx 	if (beep_state.queue_head != beep_state.queue_tail) {
459*c35aa225Smarx 
460*c35aa225Smarx 		next = beep_state.queue_head;
461*c35aa225Smarx 
462*c35aa225Smarx 		frequency = beep_state.queue[next].frequency;
463*c35aa225Smarx 
464*c35aa225Smarx 		duration = beep_state.queue[next].duration;
465*c35aa225Smarx 
466*c35aa225Smarx 		next++;
467*c35aa225Smarx 		if (next == beep_state.queue_size)
468*c35aa225Smarx 			next = 0;
469*c35aa225Smarx 
470*c35aa225Smarx 		beep_state.queue_head = next;
471*c35aa225Smarx 
472*c35aa225Smarx 		beep_state.mode = BEEP_TIMED;
473*c35aa225Smarx 
474*c35aa225Smarx 		if (frequency != 0) {
475*c35aa225Smarx 			if (beep_state.beep_freq != NULL)
476*c35aa225Smarx 				(*beep_state.beep_freq)(beep_state.arg,
477*c35aa225Smarx 				    frequency);
478*c35aa225Smarx 
479*c35aa225Smarx 			if (beep_state.beep_on != NULL)
480*c35aa225Smarx 				(*beep_state.beep_on)(beep_state.arg);
481*c35aa225Smarx 		}
482*c35aa225Smarx 
483*c35aa225Smarx 		/* Set timeout for ending the beep after the specified time */
484*c35aa225Smarx 
485*c35aa225Smarx 		beep_state.timeout_id = timeout(beep_timeout, NULL,
486*c35aa225Smarx 		    drv_usectohz(duration * 1000));
487*c35aa225Smarx 	}
488*c35aa225Smarx 
489*c35aa225Smarx 	mutex_exit(&beep_state.mutex);
490*c35aa225Smarx 
491*c35aa225Smarx 	BEEP_DEBUG1((CE_CONT, "beep_timeout : done."));
492*c35aa225Smarx }
493*c35aa225Smarx 
494*c35aa225Smarx 
495*c35aa225Smarx /*
496*c35aa225Smarx  * Return true (1) if we are sounding a tone.
497*c35aa225Smarx  */
498*c35aa225Smarx int
beep_busy(void)499*c35aa225Smarx beep_busy(void)
500*c35aa225Smarx {
501*c35aa225Smarx 	int status;
502*c35aa225Smarx 
503*c35aa225Smarx 	BEEP_DEBUG1((CE_CONT, "beep_busy : start."));
504*c35aa225Smarx 
505*c35aa225Smarx 	mutex_enter(&beep_state.mutex);
506*c35aa225Smarx 
507*c35aa225Smarx 	status = beep_state.mode != BEEP_UNINIT &&
508*c35aa225Smarx 	    beep_state.mode != BEEP_OFF;
509*c35aa225Smarx 
510*c35aa225Smarx 	mutex_exit(&beep_state.mutex);
511*c35aa225Smarx 
512*c35aa225Smarx 	BEEP_DEBUG1((CE_CONT, "beep_busy : status %d.", status));
513*c35aa225Smarx 
514*c35aa225Smarx 	return (status);
515*c35aa225Smarx }
516