11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * PC Speaker beeper driver for Linux 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (c) 2002 Vojtech Pavlik 51da177e4SLinus Torvalds * Copyright (c) 1992 Orest Zborowski 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds */ 81da177e4SLinus Torvalds 91da177e4SLinus Torvalds /* 101da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify it 111da177e4SLinus Torvalds * under the terms of the GNU General Public License version 2 as published by 121da177e4SLinus Torvalds * the Free Software Foundation 131da177e4SLinus Torvalds */ 141da177e4SLinus Torvalds 151da177e4SLinus Torvalds #include <linux/kernel.h> 161da177e4SLinus Torvalds #include <linux/module.h> 1716ba9b06SRalf Baechle #include <linux/i8253.h> 181da177e4SLinus Torvalds #include <linux/init.h> 191da177e4SLinus Torvalds #include <linux/input.h> 2059317747SDmitry Torokhov #include <linux/platform_device.h> 2108604bd9SArnd Bergmann #include <linux/timex.h> 221da177e4SLinus Torvalds #include <asm/io.h> 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 251da177e4SLinus Torvalds MODULE_DESCRIPTION("PC Speaker beeper driver"); 261da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 2743cc71eeSKay Sievers MODULE_ALIAS("platform:pcspkr"); 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) 301da177e4SLinus Torvalds { 311da177e4SLinus Torvalds unsigned int count = 0; 321da177e4SLinus Torvalds unsigned long flags; 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds if (type != EV_SND) 351da177e4SLinus Torvalds return -1; 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds switch (code) { 381da177e4SLinus Torvalds case SND_BELL: if (value) value = 1000; 391da177e4SLinus Torvalds case SND_TONE: break; 401da177e4SLinus Torvalds default: return -1; 411da177e4SLinus Torvalds } 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds if (value > 20 && value < 32767) 441da177e4SLinus Torvalds count = PIT_TICK_RATE / value; 451da177e4SLinus Torvalds 46ced918ebSThomas Gleixner raw_spin_lock_irqsave(&i8253_lock, flags); 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds if (count) { 491da177e4SLinus Torvalds /* set command for counter 2, 2 byte write */ 501da177e4SLinus Torvalds outb_p(0xB6, 0x43); 511da177e4SLinus Torvalds /* select desired HZ */ 521da177e4SLinus Torvalds outb_p(count & 0xff, 0x42); 531da177e4SLinus Torvalds outb((count >> 8) & 0xff, 0x42); 5459bdb437SZoltan Devai /* enable counter 2 */ 5559bdb437SZoltan Devai outb_p(inb_p(0x61) | 3, 0x61); 561da177e4SLinus Torvalds } else { 571da177e4SLinus Torvalds /* disable counter 2 */ 581da177e4SLinus Torvalds outb(inb_p(0x61) & 0xFC, 0x61); 591da177e4SLinus Torvalds } 601da177e4SLinus Torvalds 61ced918ebSThomas Gleixner raw_spin_unlock_irqrestore(&i8253_lock, flags); 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds return 0; 641da177e4SLinus Torvalds } 651da177e4SLinus Torvalds 6659317747SDmitry Torokhov static int __devinit pcspkr_probe(struct platform_device *dev) 671da177e4SLinus Torvalds { 6859317747SDmitry Torokhov struct input_dev *pcspkr_dev; 6959317747SDmitry Torokhov int err; 7059317747SDmitry Torokhov 7176b7cddfSDmitry Torokhov pcspkr_dev = input_allocate_device(); 7276b7cddfSDmitry Torokhov if (!pcspkr_dev) 7376b7cddfSDmitry Torokhov return -ENOMEM; 741da177e4SLinus Torvalds 7576b7cddfSDmitry Torokhov pcspkr_dev->name = "PC Speaker"; 761259f2b3SDmitry Torokhov pcspkr_dev->phys = "isa0061/input0"; 7776b7cddfSDmitry Torokhov pcspkr_dev->id.bustype = BUS_ISA; 7876b7cddfSDmitry Torokhov pcspkr_dev->id.vendor = 0x001f; 7976b7cddfSDmitry Torokhov pcspkr_dev->id.product = 0x0001; 8076b7cddfSDmitry Torokhov pcspkr_dev->id.version = 0x0100; 81293e6392SDmitry Torokhov pcspkr_dev->dev.parent = &dev->dev; 821da177e4SLinus Torvalds 837b19ada2SJiri Slaby pcspkr_dev->evbit[0] = BIT_MASK(EV_SND); 847b19ada2SJiri Slaby pcspkr_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); 8576b7cddfSDmitry Torokhov pcspkr_dev->event = pcspkr_event; 861da177e4SLinus Torvalds 8759317747SDmitry Torokhov err = input_register_device(pcspkr_dev); 8859317747SDmitry Torokhov if (err) { 8959317747SDmitry Torokhov input_free_device(pcspkr_dev); 9059317747SDmitry Torokhov return err; 9159317747SDmitry Torokhov } 9259317747SDmitry Torokhov 9359317747SDmitry Torokhov platform_set_drvdata(dev, pcspkr_dev); 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds return 0; 961da177e4SLinus Torvalds } 971da177e4SLinus Torvalds 9859317747SDmitry Torokhov static int __devexit pcspkr_remove(struct platform_device *dev) 991da177e4SLinus Torvalds { 10059317747SDmitry Torokhov struct input_dev *pcspkr_dev = platform_get_drvdata(dev); 10159317747SDmitry Torokhov 10276b7cddfSDmitry Torokhov input_unregister_device(pcspkr_dev); 10359317747SDmitry Torokhov platform_set_drvdata(dev, NULL); 1041da177e4SLinus Torvalds /* turn off the speaker */ 1051da177e4SLinus Torvalds pcspkr_event(NULL, EV_SND, SND_BELL, 0); 10659317747SDmitry Torokhov 10759317747SDmitry Torokhov return 0; 10859317747SDmitry Torokhov } 10959317747SDmitry Torokhov 11035db715bSFrans Pop static int pcspkr_suspend(struct device *dev) 11159317747SDmitry Torokhov { 11259317747SDmitry Torokhov pcspkr_event(NULL, EV_SND, SND_BELL, 0); 11359317747SDmitry Torokhov 11459317747SDmitry Torokhov return 0; 11559317747SDmitry Torokhov } 11659317747SDmitry Torokhov 11759317747SDmitry Torokhov static void pcspkr_shutdown(struct platform_device *dev) 11859317747SDmitry Torokhov { 11959317747SDmitry Torokhov /* turn off the speaker */ 12059317747SDmitry Torokhov pcspkr_event(NULL, EV_SND, SND_BELL, 0); 12159317747SDmitry Torokhov } 12259317747SDmitry Torokhov 12347145210SAlexey Dobriyan static const struct dev_pm_ops pcspkr_pm_ops = { 12435db715bSFrans Pop .suspend = pcspkr_suspend, 12535db715bSFrans Pop }; 12635db715bSFrans Pop 12759317747SDmitry Torokhov static struct platform_driver pcspkr_platform_driver = { 12859317747SDmitry Torokhov .driver = { 12959317747SDmitry Torokhov .name = "pcspkr", 13059317747SDmitry Torokhov .owner = THIS_MODULE, 13135db715bSFrans Pop .pm = &pcspkr_pm_ops, 13259317747SDmitry Torokhov }, 13359317747SDmitry Torokhov .probe = pcspkr_probe, 13459317747SDmitry Torokhov .remove = __devexit_p(pcspkr_remove), 13559317747SDmitry Torokhov .shutdown = pcspkr_shutdown, 13659317747SDmitry Torokhov }; 13759317747SDmitry Torokhov 13859317747SDmitry Torokhov 13959317747SDmitry Torokhov static int __init pcspkr_init(void) 14059317747SDmitry Torokhov { 141e5c6c8e4SMichael Neuling return platform_driver_register(&pcspkr_platform_driver); 14259317747SDmitry Torokhov } 14359317747SDmitry Torokhov 14459317747SDmitry Torokhov static void __exit pcspkr_exit(void) 14559317747SDmitry Torokhov { 14659317747SDmitry Torokhov platform_driver_unregister(&pcspkr_platform_driver); 1471da177e4SLinus Torvalds } 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds module_init(pcspkr_init); 1501da177e4SLinus Torvalds module_exit(pcspkr_exit); 151