2005-04-17 02:20:36 +04:00
/*
* PC Speaker beeper driver for Linux
*
* Copyright ( c ) 2002 Vojtech Pavlik
* Copyright ( c ) 1992 Orest Zborowski
*
*/
/*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation
*/
# include <linux/kernel.h>
# include <linux/module.h>
2011-06-01 22:05:02 +04:00
# include <linux/i8253.h>
2005-04-17 02:20:36 +04:00
# include <linux/init.h>
# include <linux/input.h>
2005-12-21 08:52:22 +03:00
# include <linux/platform_device.h>
2009-06-17 02:31:12 +04:00
# include <linux/timex.h>
2005-04-17 02:20:36 +04:00
# include <asm/io.h>
MODULE_AUTHOR ( " Vojtech Pavlik <vojtech@ucw.cz> " ) ;
MODULE_DESCRIPTION ( " PC Speaker beeper driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
2007-08-18 06:40:39 +04:00
MODULE_ALIAS ( " platform:pcspkr " ) ;
2005-04-17 02:20:36 +04:00
static int pcspkr_event ( struct input_dev * dev , unsigned int type , unsigned int code , int value )
{
unsigned int count = 0 ;
unsigned long flags ;
if ( type ! = EV_SND )
return - 1 ;
switch ( code ) {
case SND_BELL : if ( value ) value = 1000 ;
case SND_TONE : break ;
default : return - 1 ;
}
if ( value > 20 & & value < 32767 )
count = PIT_TICK_RATE / value ;
2010-02-17 19:47:10 +03:00
raw_spin_lock_irqsave ( & i8253_lock , flags ) ;
2005-04-17 02:20:36 +04:00
if ( count ) {
/* set command for counter 2, 2 byte write */
outb_p ( 0xB6 , 0x43 ) ;
/* select desired HZ */
outb_p ( count & 0xff , 0x42 ) ;
outb ( ( count > > 8 ) & 0xff , 0x42 ) ;
2008-11-13 07:05:40 +03:00
/* enable counter 2 */
outb_p ( inb_p ( 0x61 ) | 3 , 0x61 ) ;
2005-04-17 02:20:36 +04:00
} else {
/* disable counter 2 */
outb ( inb_p ( 0x61 ) & 0xFC , 0x61 ) ;
}
2010-02-17 19:47:10 +03:00
raw_spin_unlock_irqrestore ( & i8253_lock , flags ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2012-11-24 09:38:25 +04:00
static int pcspkr_probe ( struct platform_device * dev )
2005-04-17 02:20:36 +04:00
{
2005-12-21 08:52:22 +03:00
struct input_dev * pcspkr_dev ;
int err ;
2005-09-15 11:01:51 +04:00
pcspkr_dev = input_allocate_device ( ) ;
if ( ! pcspkr_dev )
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
2005-09-15 11:01:51 +04:00
pcspkr_dev - > name = " PC Speaker " ;
2005-10-31 09:30:05 +03:00
pcspkr_dev - > phys = " isa0061/input0 " ;
2005-09-15 11:01:51 +04:00
pcspkr_dev - > id . bustype = BUS_ISA ;
pcspkr_dev - > id . vendor = 0x001f ;
pcspkr_dev - > id . product = 0x0001 ;
pcspkr_dev - > id . version = 0x0100 ;
2007-04-12 09:35:32 +04:00
pcspkr_dev - > dev . parent = & dev - > dev ;
2005-04-17 02:20:36 +04:00
2007-10-19 10:40:32 +04:00
pcspkr_dev - > evbit [ 0 ] = BIT_MASK ( EV_SND ) ;
pcspkr_dev - > sndbit [ 0 ] = BIT_MASK ( SND_BELL ) | BIT_MASK ( SND_TONE ) ;
2005-09-15 11:01:51 +04:00
pcspkr_dev - > event = pcspkr_event ;
2005-04-17 02:20:36 +04:00
2005-12-21 08:52:22 +03:00
err = input_register_device ( pcspkr_dev ) ;
if ( err ) {
input_free_device ( pcspkr_dev ) ;
return err ;
}
platform_set_drvdata ( dev , pcspkr_dev ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2012-11-24 09:50:47 +04:00
static int pcspkr_remove ( struct platform_device * dev )
2005-12-21 08:52:22 +03:00
{
struct input_dev * pcspkr_dev = platform_get_drvdata ( dev ) ;
input_unregister_device ( pcspkr_dev ) ;
/* turn off the speaker */
pcspkr_event ( NULL , EV_SND , SND_BELL , 0 ) ;
return 0 ;
}
2009-07-13 07:51:32 +04:00
static int pcspkr_suspend ( struct device * dev )
2005-12-21 08:52:22 +03:00
{
pcspkr_event ( NULL , EV_SND , SND_BELL , 0 ) ;
return 0 ;
}
static void pcspkr_shutdown ( struct platform_device * dev )
2005-04-17 02:20:36 +04:00
{
/* turn off the speaker */
pcspkr_event ( NULL , EV_SND , SND_BELL , 0 ) ;
}
2009-12-15 05:00:08 +03:00
static const struct dev_pm_ops pcspkr_pm_ops = {
2009-07-13 07:51:32 +04:00
. suspend = pcspkr_suspend ,
} ;
2005-12-21 08:52:22 +03:00
static struct platform_driver pcspkr_platform_driver = {
. driver = {
. name = " pcspkr " ,
. owner = THIS_MODULE ,
2009-07-13 07:51:32 +04:00
. pm = & pcspkr_pm_ops ,
2005-12-21 08:52:22 +03:00
} ,
. probe = pcspkr_probe ,
2012-11-24 09:27:39 +04:00
. remove = pcspkr_remove ,
2005-12-21 08:52:22 +03:00
. shutdown = pcspkr_shutdown ,
} ;
2011-11-29 23:08:40 +04:00
module_platform_driver ( pcspkr_platform_driver ) ;
2005-12-21 08:52:22 +03:00