4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * This is the Beep module for supporting keyboard beep for keyboards
30 * that do not have the beeping feature within themselves
34 #include <sys/types.h>
38 #include <sys/sunddi.h>
39 #include <sys/modctl.h>
40 #include <sys/ddi_impldefs.h>
44 #include <sys/inttypes.h>
48 * BEEP_DEBUG used for errors
49 * BEEP_DEBUG1 prints when beep_debug > 1 and used for normal messages
53 #define BEEP_DEBUG(args) if (beep_debug) cmn_err args
54 #define BEEP_DEBUG1(args) if (beep_debug > 1) cmn_err args
56 #define BEEP_DEBUG(args)
57 #define BEEP_DEBUG1(args)
60 int beep_queue_size
= BEEP_QUEUE_SIZE
;
63 * Note that mutex_init is not called on the mutex in beep_state,
64 * But assumes that zeroed memory does not need to call mutex_init,
65 * as documented in mutex.c
68 beep_state_t beep_state
;
70 beep_params_t beep_params
[] = {
71 {BEEP_CONSOLE
, 900, 200},
72 {BEEP_TYPE4
, 2000, 0},
73 {BEEP_DEFAULT
, 1000, 200}, /* Must be last */
79 * Allocate the beep_queue structure
80 * Initialize beep_state structure
81 * Called from beep driver attach routine
86 beep_on_func_t beep_on_func
,
87 beep_off_func_t beep_off_func
,
88 beep_freq_func_t beep_freq_func
)
93 "beep_init(0x%lx, 0x%lx, 0x%lx, 0x%lx) : start.",
95 (unsigned long) beep_on_func
,
96 (unsigned long) beep_off_func
,
97 (unsigned long) beep_freq_func
));
99 mutex_enter(&beep_state
.mutex
);
101 if (beep_state
.mode
!= BEEP_UNINIT
) {
102 mutex_exit(&beep_state
.mutex
);
104 "beep_init : beep_state already initialized."));
105 return (DDI_SUCCESS
);
108 queue
= kmem_zalloc(sizeof (beep_entry_t
) * beep_queue_size
,
111 BEEP_DEBUG1((CE_CONT
,
112 "beep_init : beep_queue kmem_zalloc(%d) = 0x%lx.",
113 (int)sizeof (beep_entry_t
) * beep_queue_size
,
114 (unsigned long)queue
));
118 "beep_init : kmem_zalloc of beep_queue failed."));
119 return (DDI_FAILURE
);
122 beep_state
.arg
= arg
;
123 beep_state
.mode
= BEEP_OFF
;
124 beep_state
.beep_freq
= beep_freq_func
;
125 beep_state
.beep_on
= beep_on_func
;
126 beep_state
.beep_off
= beep_off_func
;
127 beep_state
.timeout_id
= 0;
129 beep_state
.queue_head
= 0;
130 beep_state
.queue_tail
= 0;
131 beep_state
.queue_size
= beep_queue_size
;
132 beep_state
.queue
= queue
;
134 mutex_exit(&beep_state
.mutex
);
136 BEEP_DEBUG1((CE_CONT
, "beep_init : done."));
137 return (DDI_SUCCESS
);
144 BEEP_DEBUG1((CE_CONT
, "beep_fini() : start."));
148 mutex_enter(&beep_state
.mutex
);
150 if (beep_state
.mode
== BEEP_UNINIT
) {
151 mutex_exit(&beep_state
.mutex
);
153 "beep_fini : beep_state already uninitialized."));
157 if (beep_state
.queue
!= NULL
)
158 kmem_free(beep_state
.queue
,
159 sizeof (beep_entry_t
) * beep_state
.queue_size
);
161 beep_state
.arg
= (void *)NULL
;
162 beep_state
.mode
= BEEP_UNINIT
;
163 beep_state
.beep_freq
= (beep_freq_func_t
)NULL
;
164 beep_state
.beep_on
= (beep_on_func_t
)NULL
;
165 beep_state
.beep_off
= (beep_off_func_t
)NULL
;
166 beep_state
.timeout_id
= 0;
168 beep_state
.queue_head
= 0;
169 beep_state
.queue_tail
= 0;
170 beep_state
.queue_size
= 0;
171 beep_state
.queue
= (beep_entry_t
*)NULL
;
173 mutex_exit(&beep_state
.mutex
);
175 BEEP_DEBUG1((CE_CONT
, "beep_fini() : done."));
184 BEEP_DEBUG1((CE_CONT
, "beeper_off : start."));
186 mutex_enter(&beep_state
.mutex
);
188 if (beep_state
.mode
== BEEP_UNINIT
) {
189 mutex_exit(&beep_state
.mutex
);
193 if (beep_state
.mode
== BEEP_TIMED
) {
194 (void) untimeout(beep_state
.timeout_id
);
195 beep_state
.timeout_id
= 0;
198 if (beep_state
.mode
!= BEEP_OFF
) {
199 beep_state
.mode
= BEEP_OFF
;
201 if (beep_state
.beep_off
!= NULL
)
202 (*beep_state
.beep_off
)(beep_state
.arg
);
205 beep_state
.queue_head
= 0;
206 beep_state
.queue_tail
= 0;
208 mutex_exit(&beep_state
.mutex
);
210 BEEP_DEBUG1((CE_CONT
, "beeper_off : done."));
216 beeper_freq(enum beep_type type
, int freq
)
220 BEEP_DEBUG1((CE_CONT
, "beeper_freq(%d, %d) : start", type
, freq
));
223 * The frequency value is limited to the range of [0 - 32767]
225 if (freq
< 0 || freq
> INT16_MAX
)
228 for (bp
= beep_params
; bp
->type
!= BEEP_DEFAULT
; bp
++) {
229 if (bp
->type
== type
)
233 if (bp
->type
!= type
) {
234 BEEP_DEBUG((CE_WARN
, "beeper_freq : invalid type."));
239 bp
->frequency
= freq
;
241 BEEP_DEBUG1((CE_CONT
, "beeper_freq : done."));
247 * Start beeping for period specified by the type value,
248 * from the value in the beep_param structure in milliseconds.
251 beep(enum beep_type type
)
256 BEEP_DEBUG1((CE_CONT
, "beep(%d) : start.", type
));
258 for (bp
= beep_params
; bp
->type
!= BEEP_DEFAULT
; bp
++) {
259 if (bp
->type
== type
)
263 if (bp
->type
!= type
) {
265 BEEP_DEBUG((CE_WARN
, "beep : invalid type."));
267 /* If type doesn't match, return silently without beeping */
271 return (beep_mktone(bp
->frequency
, bp
->duration
));
277 beep_polled(enum beep_type type
)
280 * No-op at this time.
282 * Don't think we can make this work in general, as tem_safe
283 * has a requirement of no mutexes, but kbd sends messages
287 BEEP_DEBUG1((CE_CONT
, "beep_polled(%d)", type
));
297 beeper_on(enum beep_type type
)
302 BEEP_DEBUG1((CE_CONT
, "beeper_on(%d) : start.", type
));
304 for (bp
= beep_params
; bp
->type
!= BEEP_DEFAULT
; bp
++) {
305 if (bp
->type
== type
)
309 if (bp
->type
!= type
) {
311 BEEP_DEBUG((CE_WARN
, "beeper_on : invalid type."));
313 /* If type doesn't match, return silently without beeping */
317 mutex_enter(&beep_state
.mutex
);
319 if (beep_state
.mode
== BEEP_UNINIT
) {
322 /* Start another beep only if the previous one is over */
323 } else if (beep_state
.mode
== BEEP_OFF
) {
324 if (bp
->frequency
!= 0) {
325 beep_state
.mode
= BEEP_ON
;
327 if (beep_state
.beep_freq
!= NULL
)
328 (*beep_state
.beep_freq
)(beep_state
.arg
,
331 if (beep_state
.beep_on
!= NULL
)
332 (*beep_state
.beep_on
)(beep_state
.arg
);
338 mutex_exit(&beep_state
.mutex
);
340 BEEP_DEBUG1((CE_CONT
, "beeper_on : done, status %d.", status
));
347 beep_mktone(int frequency
, int duration
)
352 BEEP_DEBUG1((CE_CONT
, "beep_mktone(%d, %d) : start.", frequency
,
356 * The frequency value is limited to the range of [0 - 32767]
358 if (frequency
< 0 || frequency
> INT16_MAX
)
361 mutex_enter(&beep_state
.mutex
);
363 if (beep_state
.mode
== BEEP_UNINIT
) {
366 } else if (beep_state
.mode
== BEEP_TIMED
) {
368 /* If already processing a beep, queue this one */
370 if (frequency
!= 0) {
371 next
= beep_state
.queue_tail
+ 1;
372 if (next
== beep_state
.queue_size
)
375 if (next
!= beep_state
.queue_head
) {
377 * If there is room in the queue,
381 beep_state
.queue
[beep_state
.queue_tail
].
382 frequency
= (unsigned short)frequency
;
384 beep_state
.queue
[beep_state
.queue_tail
].
385 duration
= (unsigned short)duration
;
387 beep_state
.queue_tail
= next
;
393 } else if (beep_state
.mode
== BEEP_OFF
) {
395 /* Start another beep only if the previous one is over */
397 if (frequency
!= 0) {
398 beep_state
.mode
= BEEP_TIMED
;
400 if (beep_state
.beep_freq
!= NULL
)
401 (*beep_state
.beep_freq
)(beep_state
.arg
,
404 if (beep_state
.beep_on
!= NULL
)
405 (*beep_state
.beep_on
)(beep_state
.arg
);
408 * Set timeout for ending the beep after the
412 beep_state
.timeout_id
= timeout(beep_timeout
, NULL
,
413 drv_usectohz(duration
* 1000));
419 mutex_exit(&beep_state
.mutex
);
421 BEEP_DEBUG1((CE_CONT
, "beep_mktone : done, status %d.", status
));
428 * Turn the beeper off which had been turned on from beep()
429 * for a specified period of time
433 beep_timeout(void *arg
)
439 BEEP_DEBUG1((CE_CONT
, "beeper_timeout : start."));
441 mutex_enter(&beep_state
.mutex
);
443 beep_state
.timeout_id
= 0;
445 if (beep_state
.mode
== BEEP_UNINIT
) {
446 mutex_exit(&beep_state
.mutex
);
447 BEEP_DEBUG1((CE_CONT
, "beep_timeout : uninitialized."));
451 if ((beep_state
.mode
== BEEP_ON
) ||
452 (beep_state
.mode
== BEEP_TIMED
)) {
454 beep_state
.mode
= BEEP_OFF
;
456 if (beep_state
.beep_off
!= NULL
)
457 (*beep_state
.beep_off
)(beep_state
.arg
);
460 if (beep_state
.queue_head
!= beep_state
.queue_tail
) {
462 next
= beep_state
.queue_head
;
464 frequency
= beep_state
.queue
[next
].frequency
;
466 duration
= beep_state
.queue
[next
].duration
;
469 if (next
== beep_state
.queue_size
)
472 beep_state
.queue_head
= next
;
474 beep_state
.mode
= BEEP_TIMED
;
476 if (frequency
!= 0) {
477 if (beep_state
.beep_freq
!= NULL
)
478 (*beep_state
.beep_freq
)(beep_state
.arg
,
481 if (beep_state
.beep_on
!= NULL
)
482 (*beep_state
.beep_on
)(beep_state
.arg
);
485 /* Set timeout for ending the beep after the specified time */
487 beep_state
.timeout_id
= timeout(beep_timeout
, NULL
,
488 drv_usectohz(duration
* 1000));
491 mutex_exit(&beep_state
.mutex
);
493 BEEP_DEBUG1((CE_CONT
, "beep_timeout : done."));
498 * Return true (1) if we are sounding a tone.
505 BEEP_DEBUG1((CE_CONT
, "beep_busy : start."));
507 mutex_enter(&beep_state
.mutex
);
509 status
= beep_state
.mode
!= BEEP_UNINIT
&&
510 beep_state
.mode
!= BEEP_OFF
;
512 mutex_exit(&beep_state
.mutex
);
514 BEEP_DEBUG1((CE_CONT
, "beep_busy : status %d.", status
));