Rev 523 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
494 | giacomo | 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 <linuxcomp.h> |
||
16 | |||
17 | #include <linux/kernel.h> |
||
18 | #include <linux/module.h> |
||
19 | #include <linux/init.h> |
||
20 | #include <linux/input.h> |
||
21 | #include <asm/io.h> |
||
22 | |||
23 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); |
||
24 | MODULE_DESCRIPTION("PC Speaker beeper driver"); |
||
25 | MODULE_LICENSE("GPL"); |
||
26 | |||
27 | static char pcspkr_name[] = "PC Speaker"; |
||
28 | static char pcspkr_phys[] = "isa0061/input0"; |
||
29 | static struct input_dev pcspkr_dev; |
||
30 | |||
31 | spinlock_t i8253_beep_lock = SPIN_LOCK_UNLOCKED; |
||
32 | |||
33 | static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) |
||
34 | { |
||
35 | unsigned int count = 0; |
||
36 | unsigned long flags; |
||
37 | |||
38 | if (type != EV_SND) |
||
39 | return -1; |
||
40 | |||
41 | switch (code) { |
||
42 | case SND_BELL: if (value) value = 1000; |
||
43 | case SND_TONE: break; |
||
44 | default: return -1; |
||
45 | } |
||
46 | |||
47 | if (value > 20 && value < 32767) |
||
48 | count = CLOCK_TICK_RATE / value; |
||
49 | |||
50 | spin_lock_irqsave(&i8253_beep_lock, flags); |
||
51 | |||
52 | if (count) { |
||
53 | /* enable counter 2 */ |
||
54 | outb_p(inb_p(0x61) | 3, 0x61); |
||
55 | /* set command for counter 2, 2 byte write */ |
||
56 | outb_p(0xB6, 0x43); |
||
57 | /* select desired HZ */ |
||
58 | outb_p(count & 0xff, 0x42); |
||
59 | outb((count >> 8) & 0xff, 0x42); |
||
60 | } else { |
||
61 | /* disable counter 2 */ |
||
62 | outb(inb_p(0x61) & 0xFC, 0x61); |
||
63 | } |
||
64 | |||
65 | spin_unlock_irqrestore(&i8253_beep_lock, flags); |
||
66 | |||
67 | return 0; |
||
68 | } |
||
69 | |||
70 | /*static*/ int __init pcspkr_init(void) |
||
71 | { |
||
72 | pcspkr_dev.evbit[0] = BIT(EV_SND); |
||
73 | pcspkr_dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); |
||
74 | pcspkr_dev.event = pcspkr_event; |
||
75 | |||
76 | pcspkr_dev.name = pcspkr_name; |
||
77 | pcspkr_dev.phys = pcspkr_phys; |
||
78 | pcspkr_dev.id.bustype = BUS_ISA; |
||
79 | pcspkr_dev.id.vendor = 0x001f; |
||
80 | pcspkr_dev.id.product = 0x0001; |
||
81 | pcspkr_dev.id.version = 0x0100; |
||
82 | |||
83 | input_register_device(&pcspkr_dev); |
||
84 | |||
523 | mauro | 85 | printk(KERN_INFO "input: %s\n", pcspkr_name); |
494 | giacomo | 86 | |
87 | return 0; |
||
88 | } |
||
89 | |||
90 | /*static*/ void __exit pcspkr_exit(void) |
||
91 | { |
||
92 | input_unregister_device(&pcspkr_dev); |
||
93 | } |
||
94 | |||
95 | module_init(pcspkr_init); |
||
96 | module_exit(pcspkr_exit); |