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/init.h> 16 #include <linux/input.h> 17 #include <asm/io.h> 18 #include "pcsp.h" 19 20 static void pcspkr_do_sound(unsigned int count) 21 { 22 unsigned long flags; 23 24 raw_spin_lock_irqsave(&i8253_lock, flags); 25 26 if (count) { 27 /* set command for counter 2, 2 byte write */ 28 outb_p(0xB6, 0x43); 29 /* select desired HZ */ 30 outb_p(count & 0xff, 0x42); 31 outb((count >> 8) & 0xff, 0x42); 32 /* enable counter 2 */ 33 outb_p(inb_p(0x61) | 3, 0x61); 34 } else { 35 /* disable counter 2 */ 36 outb(inb_p(0x61) & 0xFC, 0x61); 37 } 38 39 raw_spin_unlock_irqrestore(&i8253_lock, flags); 40 } 41 42 void pcspkr_stop_sound(void) 43 { 44 pcspkr_do_sound(0); 45 } 46 47 static int pcspkr_input_event(struct input_dev *dev, unsigned int type, 48 unsigned int code, int value) 49 { 50 unsigned int count = 0; 51 52 if (atomic_read(&pcsp_chip.timer_active) || !pcsp_chip.pcspkr) 53 return 0; 54 55 switch (type) { 56 case EV_SND: 57 switch (code) { 58 case SND_BELL: 59 if (value) 60 value = 1000; 61 case SND_TONE: 62 break; 63 default: 64 return -1; 65 } 66 break; 67 68 default: 69 return -1; 70 } 71 72 if (value > 20 && value < 32767) 73 count = PIT_TICK_RATE / value; 74 75 pcspkr_do_sound(count); 76 77 return 0; 78 } 79 80 int __devinit pcspkr_input_init(struct input_dev **rdev, struct device *dev) 81 { 82 int err; 83 84 struct input_dev *input_dev = input_allocate_device(); 85 if (!input_dev) 86 return -ENOMEM; 87 88 input_dev->name = "PC Speaker"; 89 input_dev->phys = "isa0061/input0"; 90 input_dev->id.bustype = BUS_ISA; 91 input_dev->id.vendor = 0x001f; 92 input_dev->id.product = 0x0001; 93 input_dev->id.version = 0x0100; 94 input_dev->dev.parent = dev; 95 96 input_dev->evbit[0] = BIT(EV_SND); 97 input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); 98 input_dev->event = pcspkr_input_event; 99 100 err = input_register_device(input_dev); 101 if (err) { 102 input_free_device(input_dev); 103 return err; 104 } 105 106 *rdev = input_dev; 107 return 0; 108 } 109 110 int pcspkr_input_remove(struct input_dev *dev) 111 { 112 pcspkr_stop_sound(); 113 input_unregister_device(dev); /* this also does kfree() */ 114 115 return 0; 116 } 117