7b19ada2ed
get rid of input BIT* duplicate defines use newly global defined macros for input layer. Also remove includes of input.h from non-input sources only for BIT macro definiton. Define the macro temporarily in local manner, all those local definitons will be removed further in this patchset (to not break bisecting). BIT macro will be globally defined (1<<x) Signed-off-by: Jiri Slaby <jirislaby@gmail.com> Cc: <dtor@mail.ru> Acked-by: Jiri Kosina <jkosina@suse.cz> Cc: <lenb@kernel.org> Acked-by: Marcel Holtmann <marcel@holtmann.org> Cc: <perex@suse.cz> Acked-by: Mauro Carvalho Chehab <mchehab@infradead.org> Cc: <vernux@us.ibm.com> Cc: <malattia@linux.it> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
263 lines
5.8 KiB
C
263 lines
5.8 KiB
C
/*
|
|
* Driver for PC-speaker like devices found on various Sparc systems.
|
|
*
|
|
* Copyright (c) 2002 Vojtech Pavlik
|
|
* Copyright (c) 2002, 2006 David S. Miller (davem@davemloft.net)
|
|
*/
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/input.h>
|
|
#include <linux/platform_device.h>
|
|
|
|
#include <asm/io.h>
|
|
#include <asm/ebus.h>
|
|
#include <asm/isa.h>
|
|
|
|
MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
|
|
MODULE_DESCRIPTION("Sparc Speaker beeper driver");
|
|
MODULE_LICENSE("GPL");
|
|
|
|
struct sparcspkr_state {
|
|
const char *name;
|
|
unsigned long iobase;
|
|
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
|
|
spinlock_t lock;
|
|
struct input_dev *input_dev;
|
|
};
|
|
|
|
static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
|
{
|
|
struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
|
|
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 = 1193182 / value;
|
|
|
|
spin_lock_irqsave(&state->lock, flags);
|
|
|
|
/* EBUS speaker only has on/off state, the frequency does not
|
|
* appear to be programmable.
|
|
*/
|
|
if (state->iobase & 0x2UL)
|
|
outb(!!count, state->iobase);
|
|
else
|
|
outl(!!count, state->iobase);
|
|
|
|
spin_unlock_irqrestore(&state->lock, flags);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
|
{
|
|
struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
|
|
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 = 1193182 / value;
|
|
|
|
spin_lock_irqsave(&state->lock, flags);
|
|
|
|
if (count) {
|
|
/* enable counter 2 */
|
|
outb(inb(state->iobase + 0x61) | 3, state->iobase + 0x61);
|
|
/* set command for counter 2, 2 byte write */
|
|
outb(0xB6, state->iobase + 0x43);
|
|
/* select desired HZ */
|
|
outb(count & 0xff, state->iobase + 0x42);
|
|
outb((count >> 8) & 0xff, state->iobase + 0x42);
|
|
} else {
|
|
/* disable counter 2 */
|
|
outb(inb_p(state->iobase + 0x61) & 0xFC, state->iobase + 0x61);
|
|
}
|
|
|
|
spin_unlock_irqrestore(&state->lock, flags);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __devinit sparcspkr_probe(struct device *dev)
|
|
{
|
|
struct sparcspkr_state *state = dev_get_drvdata(dev);
|
|
struct input_dev *input_dev;
|
|
int error;
|
|
|
|
input_dev = input_allocate_device();
|
|
if (!input_dev)
|
|
return -ENOMEM;
|
|
|
|
input_dev->name = state->name;
|
|
input_dev->phys = "sparc/input0";
|
|
input_dev->id.bustype = BUS_ISA;
|
|
input_dev->id.vendor = 0x001f;
|
|
input_dev->id.product = 0x0001;
|
|
input_dev->id.version = 0x0100;
|
|
input_dev->dev.parent = dev;
|
|
|
|
input_dev->evbit[0] = BIT_MASK(EV_SND);
|
|
input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
|
|
|
|
input_dev->event = state->event;
|
|
|
|
error = input_register_device(input_dev);
|
|
if (error) {
|
|
input_free_device(input_dev);
|
|
return error;
|
|
}
|
|
|
|
state->input_dev = input_dev;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __devexit sparcspkr_remove(struct of_device *dev)
|
|
{
|
|
struct sparcspkr_state *state = dev_get_drvdata(&dev->dev);
|
|
struct input_dev *input_dev = state->input_dev;
|
|
|
|
/* turn off the speaker */
|
|
state->event(input_dev, EV_SND, SND_BELL, 0);
|
|
|
|
input_unregister_device(input_dev);
|
|
|
|
dev_set_drvdata(&dev->dev, NULL);
|
|
kfree(state);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int sparcspkr_shutdown(struct of_device *dev)
|
|
{
|
|
struct sparcspkr_state *state = dev_get_drvdata(&dev->dev);
|
|
struct input_dev *input_dev = state->input_dev;
|
|
|
|
/* turn off the speaker */
|
|
state->event(input_dev, EV_SND, SND_BELL, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __devinit ebus_beep_probe(struct of_device *dev, const struct of_device_id *match)
|
|
{
|
|
struct linux_ebus_device *edev = to_ebus_device(&dev->dev);
|
|
struct sparcspkr_state *state;
|
|
int err;
|
|
|
|
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
|
if (!state)
|
|
return -ENOMEM;
|
|
|
|
state->name = "Sparc EBUS Speaker";
|
|
state->iobase = edev->resource[0].start;
|
|
state->event = ebus_spkr_event;
|
|
spin_lock_init(&state->lock);
|
|
|
|
dev_set_drvdata(&dev->dev, state);
|
|
|
|
err = sparcspkr_probe(&dev->dev);
|
|
if (err) {
|
|
dev_set_drvdata(&dev->dev, NULL);
|
|
kfree(state);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct of_device_id ebus_beep_match[] = {
|
|
{
|
|
.name = "beep",
|
|
},
|
|
{},
|
|
};
|
|
|
|
static struct of_platform_driver ebus_beep_driver = {
|
|
.name = "beep",
|
|
.match_table = ebus_beep_match,
|
|
.probe = ebus_beep_probe,
|
|
.remove = sparcspkr_remove,
|
|
.shutdown = sparcspkr_shutdown,
|
|
};
|
|
|
|
static int __devinit isa_beep_probe(struct of_device *dev, const struct of_device_id *match)
|
|
{
|
|
struct sparc_isa_device *idev = to_isa_device(&dev->dev);
|
|
struct sparcspkr_state *state;
|
|
int err;
|
|
|
|
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
|
if (!state)
|
|
return -ENOMEM;
|
|
|
|
state->name = "Sparc ISA Speaker";
|
|
state->iobase = idev->resource.start;
|
|
state->event = isa_spkr_event;
|
|
spin_lock_init(&state->lock);
|
|
|
|
dev_set_drvdata(&dev->dev, state);
|
|
|
|
err = sparcspkr_probe(&dev->dev);
|
|
if (err) {
|
|
dev_set_drvdata(&dev->dev, NULL);
|
|
kfree(state);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct of_device_id isa_beep_match[] = {
|
|
{
|
|
.name = "dma",
|
|
},
|
|
{},
|
|
};
|
|
|
|
static struct of_platform_driver isa_beep_driver = {
|
|
.name = "beep",
|
|
.match_table = isa_beep_match,
|
|
.probe = isa_beep_probe,
|
|
.remove = sparcspkr_remove,
|
|
.shutdown = sparcspkr_shutdown,
|
|
};
|
|
|
|
static int __init sparcspkr_init(void)
|
|
{
|
|
int err = of_register_driver(&ebus_beep_driver, &ebus_bus_type);
|
|
|
|
if (!err) {
|
|
err = of_register_driver(&isa_beep_driver, &isa_bus_type);
|
|
if (err)
|
|
of_unregister_driver(&ebus_beep_driver);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static void __exit sparcspkr_exit(void)
|
|
{
|
|
of_unregister_driver(&ebus_beep_driver);
|
|
of_unregister_driver(&isa_beep_driver);
|
|
}
|
|
|
|
module_init(sparcspkr_init);
|
|
module_exit(sparcspkr_exit);
|