/* * Loadable module to replace the stock console beep routine * * Requires patches to .../linux/drivers/char/vt_kern.h and * .../linux/drivers/char/vt.c * * dave madden * * changed the patches and some includes for 2.0.21 * changed calculating different legth and note * and changed it up to kernel 2.2.13 * Gernot Zander * * Almost totally changed (while sharing a lot of code) by JFM * to use "fancy beep" device and userspace beep daemon. Incorporates * some code by Bernd Meyer See file COPYING * for license information. * * Version 0.01: initial released version. * Version 0.02: fallback to speaker beep if there is not a beepd * listening. * * v 0.02-2.4.0: cleaned up somewhat and modified to fit 2.4.x kernels * Frank Johnson */ /* Kernel includes */ #include #include #include #include #include #include /* * Definitions */ #define BEEP_MAJOR 10 #define BEEP_MINOR 128 /* * Static data */ static DECLARE_WAIT_QUEUE_HEAD (beep_wait); static int beep_listening=0; static char what_beep=0; extern void (*kd_nosound)( unsigned long ignored ); extern void (*kd_mksound)( unsigned int count, unsigned int ticks ); static void (*old_nosound)( unsigned long ignored ); static void (*old_mksound)( unsigned int count, unsigned int ticks ); static void my_nosound( unsigned long ignored ); static void my_mksound( unsigned int count, unsigned int ticks ); static int activate_beep(char beepkind) { #ifdef DEBUG printk("activate_beep called.\n"); #endif what_beep=beepkind; wake_up(&beep_wait); return 0; } static int close_beep(struct inode * inode, struct file * file) { #ifdef DEBUG printk(KERN_WARNING "close_beep called\n"); #endif if ((file->f_flags & O_ACCMODE) == O_RDONLY) { if (beep_listening) { beep_listening--; MOD_DEC_USE_COUNT; } } return(0); } /* * open access to the beep, currently only one reading open is * allowed. We can do as many writes as we like. This really calls * for some kind of buffering of events, something more accurate than * the simple static what_beep. Later.... */ static int open_beep(struct inode * inode, struct file * file) { #ifdef DEBUG printk(KERN_WARNING "open_beep called.\n"); #endif switch(file->f_flags & O_ACCMODE) { case O_RDONLY: if (beep_listening) return -EBUSY; MOD_INC_USE_COUNT; beep_listening++; what_beep=0; /* Zero means we don't have any beeps waiting to be fetched */ return 0; case O_NONBLOCK: return -EAGAIN; case O_WRONLY: return 0; default: return -EINVAL; } } static ssize_t read_beep(struct file * file, char * buffer, size_t len, loff_t *ppos) { size_t bytes_sent=0; /* Can't seek (pread) on this device */ if (ppos != &file->f_pos) return -ESPIPE; if (!access_ok(VERIFY_WRITE, buffer, sizeof(what_beep))) { what_beep = 0; return -EFAULT; } if (!beep_listening) /* Pretty improbable...*/ { #ifdef DEBUG printk("beep: no one listening.\n"); #endif return -EAGAIN; /* Uh? Is this a good return value? */ } /* OK, now for the fun bit.... I never did anything in kernel space * before, so if this is completely foolish, just tell me, OK? */ while (!what_beep) { interruptible_sleep_on(&beep_wait); /* We need to handle the reader being signaled. */ if (signal_pending(current)) { if (beep_listening) { beep_listening--; MOD_DEC_USE_COUNT; } return -EINTR; } } while ((len>0) && (what_beep>0)) { put_user(what_beep, buffer); what_beep--; len--; bytes_sent++; } #ifdef DEBUG printk("Beep!\n"); #endif return(bytes_sent); } struct file_operations beep_fops = { read: read_beep, open: open_beep, release: close_beep, }; static struct miscdevice beep_device = { BEEP_MINOR, "beep", &beep_fops }; int __init beep_init(void) { /* Try to register device */ int rc; rc = misc_register(&beep_device); if (rc < 0) { printk(KERN_WARNING "beep: can't get misc device %d\n", BEEP_MINOR); return(rc); } printk( "Replacing keyboard beeper\n" ); kd_nosound( 0 ); /* make sure the beeper is turned off now */ old_nosound = kd_nosound; old_mksound = kd_mksound; kd_nosound = my_nosound; kd_mksound = my_mksound; return 0; } static void my_nosound(unsigned long ignored) { /* Turn off beeping somehow. */ } static void my_mksound(unsigned int count, unsigned int ticks) { /* Do a single beep */ if (beep_listening) activate_beep(1); else old_mksound(count, ticks); } int init_module(void) { return beep_init(); } static void __exit beep_cleanup_module(void) { misc_deregister(&beep_device); printk( "Restoring old keyboard beeper\n" ); kd_nosound( 0 ); kd_nosound = old_nosound; kd_mksound = old_mksound; } module_exit(beep_cleanup_module);