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