1 /* 2 * PC Speaker beeper driver for Linux 3 * 4 * Copyright (c) 2002 Vojtech Pavlik 5 * Copyright (c) 1992 Orest Zborowski 6 * 7 */ 8 9 /* 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License version 2 as published by 12 * the Free Software Foundation 13 */ 14 15 #include <linux/kernel.h> 16 #include <linux/module.h> 17 #include <linux/init.h> 18 #include <linux/input.h> 19 #include <asm/8253pit.h> 20 #include <asm/io.h> 21 22 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 23 MODULE_DESCRIPTION("PC Speaker beeper driver"); 24 MODULE_LICENSE("GPL"); 25 26 static struct input_dev *pcspkr_dev; 27 28 static DEFINE_SPINLOCK(i8253_beep_lock); 29 30 static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) 31 { 32 unsigned int count = 0; 33 unsigned long flags; 34 35 if (type != EV_SND) 36 return -1; 37 38 switch (code) { 39 case SND_BELL: if (value) value = 1000; 40 case SND_TONE: break; 41 default: return -1; 42 } 43 44 if (value > 20 && value < 32767) 45 count = PIT_TICK_RATE / value; 46 47 spin_lock_irqsave(&i8253_beep_lock, flags); 48 49 if (count) { 50 /* enable counter 2 */ 51 outb_p(inb_p(0x61) | 3, 0x61); 52 /* set command for counter 2, 2 byte write */ 53 outb_p(0xB6, 0x43); 54 /* select desired HZ */ 55 outb_p(count & 0xff, 0x42); 56 outb((count >> 8) & 0xff, 0x42); 57 } else { 58 /* disable counter 2 */ 59 outb(inb_p(0x61) & 0xFC, 0x61); 60 } 61 62 spin_unlock_irqrestore(&i8253_beep_lock, flags); 63 64 return 0; 65 } 66 67 static int __init pcspkr_init(void) 68 { 69 pcspkr_dev = input_allocate_device(); 70 if (!pcspkr_dev) 71 return -ENOMEM; 72 73 pcspkr_dev->name = "PC Speaker"; 74 pcspkr_dev->name = "isa0061/input0"; 75 pcspkr_dev->id.bustype = BUS_ISA; 76 pcspkr_dev->id.vendor = 0x001f; 77 pcspkr_dev->id.product = 0x0001; 78 pcspkr_dev->id.version = 0x0100; 79 80 pcspkr_dev->evbit[0] = BIT(EV_SND); 81 pcspkr_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); 82 pcspkr_dev->event = pcspkr_event; 83 84 input_register_device(pcspkr_dev); 85 86 return 0; 87 } 88 89 static void __exit pcspkr_exit(void) 90 { 91 input_unregister_device(pcspkr_dev); 92 /* turn off the speaker */ 93 pcspkr_event(NULL, EV_SND, SND_BELL, 0); 94 } 95 96 module_init(pcspkr_init); 97 module_exit(pcspkr_exit); 98