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 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 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 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 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 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 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 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 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 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 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