1 /* 2 * Driver for PC-speaker like devices found on various Sparc systems. 3 * 4 * Copyright (c) 2002 Vojtech Pavlik 5 * Copyright (c) 2002 David S. Miller (davem@redhat.com) 6 */ 7 #include <linux/config.h> 8 #include <linux/kernel.h> 9 #include <linux/module.h> 10 #include <linux/init.h> 11 #include <linux/input.h> 12 13 #include <asm/io.h> 14 #include <asm/ebus.h> 15 #ifdef CONFIG_SPARC64 16 #include <asm/isa.h> 17 #endif 18 19 MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); 20 MODULE_DESCRIPTION("Sparc Speaker beeper driver"); 21 MODULE_LICENSE("GPL"); 22 23 static unsigned long beep_iobase; 24 static struct input_dev *sparcspkr_dev; 25 26 DEFINE_SPINLOCK(beep_lock); 27 28 static void __init init_sparcspkr_struct(void) 29 { 30 sparcspkr_dev->evbit[0] = BIT(EV_SND); 31 sparcspkr_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); 32 33 sparcspkr_dev->phys = "sparc/input0"; 34 sparcspkr_dev->id.bustype = BUS_ISA; 35 sparcspkr_dev->id.vendor = 0x001f; 36 sparcspkr_dev->id.product = 0x0001; 37 sparcspkr_dev->id.version = 0x0100; 38 } 39 40 static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) 41 { 42 unsigned int count = 0; 43 unsigned long flags; 44 45 if (type != EV_SND) 46 return -1; 47 48 switch (code) { 49 case SND_BELL: if (value) value = 1000; 50 case SND_TONE: break; 51 default: return -1; 52 } 53 54 if (value > 20 && value < 32767) 55 count = 1193182 / value; 56 57 spin_lock_irqsave(&beep_lock, flags); 58 59 /* EBUS speaker only has on/off state, the frequency does not 60 * appear to be programmable. 61 */ 62 if (count) { 63 if (beep_iobase & 0x2UL) 64 outb(1, beep_iobase); 65 else 66 outl(1, beep_iobase); 67 } else { 68 if (beep_iobase & 0x2UL) 69 outb(0, beep_iobase); 70 else 71 outl(0, beep_iobase); 72 } 73 74 spin_unlock_irqrestore(&beep_lock, flags); 75 76 return 0; 77 } 78 79 static int __init init_ebus_beep(struct linux_ebus_device *edev) 80 { 81 beep_iobase = edev->resource[0].start; 82 83 sparcspkr_dev = input_allocate_device(); 84 if (!sparcspkr_dev) 85 return -ENOMEM; 86 87 sparcspkr_dev->name = "Sparc EBUS Speaker"; 88 sparcspkr_dev->event = ebus_spkr_event; 89 90 input_register_device(sparcspkr_dev); 91 92 return 0; 93 } 94 95 #ifdef CONFIG_SPARC64 96 static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) 97 { 98 unsigned int count = 0; 99 unsigned long flags; 100 101 if (type != EV_SND) 102 return -1; 103 104 switch (code) { 105 case SND_BELL: if (value) value = 1000; 106 case SND_TONE: break; 107 default: return -1; 108 } 109 110 if (value > 20 && value < 32767) 111 count = 1193182 / value; 112 113 spin_lock_irqsave(&beep_lock, flags); 114 115 if (count) { 116 /* enable counter 2 */ 117 outb(inb(beep_iobase + 0x61) | 3, beep_iobase + 0x61); 118 /* set command for counter 2, 2 byte write */ 119 outb(0xB6, beep_iobase + 0x43); 120 /* select desired HZ */ 121 outb(count & 0xff, beep_iobase + 0x42); 122 outb((count >> 8) & 0xff, beep_iobase + 0x42); 123 } else { 124 /* disable counter 2 */ 125 outb(inb_p(beep_iobase + 0x61) & 0xFC, beep_iobase + 0x61); 126 } 127 128 spin_unlock_irqrestore(&beep_lock, flags); 129 130 return 0; 131 } 132 133 static int __init init_isa_beep(struct sparc_isa_device *isa_dev) 134 { 135 beep_iobase = isa_dev->resource.start; 136 137 sparcspkr_dev = input_allocate_device(); 138 if (!sparcspkr_dev) 139 return -ENOMEM; 140 141 init_sparcspkr_struct(); 142 143 sparcspkr_dev->name = "Sparc ISA Speaker"; 144 sparcspkr_dev->event = isa_spkr_event; 145 146 input_register_device(sparcspkr_dev); 147 148 return 0; 149 } 150 #endif 151 152 static int __init sparcspkr_init(void) 153 { 154 struct linux_ebus *ebus; 155 struct linux_ebus_device *edev = NULL; 156 #ifdef CONFIG_SPARC64 157 struct sparc_isa_bridge *isa_br; 158 struct sparc_isa_device *isa_dev; 159 #endif 160 161 for_each_ebus(ebus) { 162 for_each_ebusdev(edev, ebus) { 163 if (!strcmp(edev->prom_name, "beep")) 164 return init_ebus_beep(edev); 165 } 166 } 167 #ifdef CONFIG_SPARC64 168 for_each_isa(isa_br) { 169 for_each_isadev(isa_dev, isa_br) { 170 /* A hack, the beep device's base lives in 171 * the DMA isa node. 172 */ 173 if (!strcmp(isa_dev->prom_name, "dma")) 174 return init_isa_beep(isa_dev); 175 } 176 } 177 #endif 178 179 return -ENODEV; 180 } 181 182 static void __exit sparcspkr_exit(void) 183 { 184 input_unregister_device(sparcspkr_dev); 185 } 186 187 module_init(sparcspkr_init); 188 module_exit(sparcspkr_exit); 189