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