diff options
Diffstat (limited to 'drivers/input/misc/pcspkr.c')
-rw-r--r-- | drivers/input/misc/pcspkr.c | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c new file mode 100644 index 000000000000..3013194f462b --- /dev/null +++ b/drivers/input/misc/pcspkr.c | |||
@@ -0,0 +1,97 @@ | |||
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 char pcspkr_name[] = "PC Speaker"; | ||
27 | static char pcspkr_phys[] = "isa0061/input0"; | ||
28 | static struct input_dev pcspkr_dev; | ||
29 | |||
30 | static DEFINE_SPINLOCK(i8253_beep_lock); | ||
31 | |||
32 | static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | ||
33 | { | ||
34 | unsigned int count = 0; | ||
35 | unsigned long flags; | ||
36 | |||
37 | if (type != EV_SND) | ||
38 | return -1; | ||
39 | |||
40 | switch (code) { | ||
41 | case SND_BELL: if (value) value = 1000; | ||
42 | case SND_TONE: break; | ||
43 | default: return -1; | ||
44 | } | ||
45 | |||
46 | if (value > 20 && value < 32767) | ||
47 | count = PIT_TICK_RATE / value; | ||
48 | |||
49 | spin_lock_irqsave(&i8253_beep_lock, flags); | ||
50 | |||
51 | if (count) { | ||
52 | /* enable counter 2 */ | ||
53 | outb_p(inb_p(0x61) | 3, 0x61); | ||
54 | /* set command for counter 2, 2 byte write */ | ||
55 | outb_p(0xB6, 0x43); | ||
56 | /* select desired HZ */ | ||
57 | outb_p(count & 0xff, 0x42); | ||
58 | outb((count >> 8) & 0xff, 0x42); | ||
59 | } else { | ||
60 | /* disable counter 2 */ | ||
61 | outb(inb_p(0x61) & 0xFC, 0x61); | ||
62 | } | ||
63 | |||
64 | spin_unlock_irqrestore(&i8253_beep_lock, flags); | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static int __init pcspkr_init(void) | ||
70 | { | ||
71 | pcspkr_dev.evbit[0] = BIT(EV_SND); | ||
72 | pcspkr_dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); | ||
73 | pcspkr_dev.event = pcspkr_event; | ||
74 | |||
75 | pcspkr_dev.name = pcspkr_name; | ||
76 | pcspkr_dev.phys = pcspkr_phys; | ||
77 | pcspkr_dev.id.bustype = BUS_ISA; | ||
78 | pcspkr_dev.id.vendor = 0x001f; | ||
79 | pcspkr_dev.id.product = 0x0001; | ||
80 | pcspkr_dev.id.version = 0x0100; | ||
81 | |||
82 | input_register_device(&pcspkr_dev); | ||
83 | |||
84 | printk(KERN_INFO "input: %s\n", pcspkr_name); | ||
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); | ||