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 #include <linux/platform_device.h> 13 14 #include <asm/io.h> 15 #include <asm/ebus.h> 16 #ifdef CONFIG_SPARC64 17 #include <asm/isa.h> 18 #endif 19 20 MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); 21 MODULE_DESCRIPTION("Sparc Speaker beeper driver"); 22 MODULE_LICENSE("GPL"); 23 24 const char *beep_name; 25 static unsigned long beep_iobase; 26 static int (*beep_event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); 27 static DEFINE_SPINLOCK(beep_lock); 28 29 static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) 30 { 31 unsigned int count = 0; 32 unsigned long flags; 33 34 if (type != EV_SND) 35 return -1; 36 37 switch (code) { 38 case SND_BELL: if (value) value = 1000; 39 case SND_TONE: break; 40 default: return -1; 41 } 42 43 if (value > 20 && value < 32767) 44 count = 1193182 / value; 45 46 spin_lock_irqsave(&beep_lock, flags); 47 48 /* EBUS speaker only has on/off state, the frequency does not 49 * appear to be programmable. 50 */ 51 if (beep_iobase & 0x2UL) 52 outb(!!count, beep_iobase); 53 else 54 outl(!!count, beep_iobase); 55 56 spin_unlock_irqrestore(&beep_lock, flags); 57 58 return 0; 59 } 60 61 #ifdef CONFIG_SPARC64 62 static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) 63 { 64 unsigned int count = 0; 65 unsigned long flags; 66 67 if (type != EV_SND) 68 return -1; 69 70 switch (code) { 71 case SND_BELL: if (value) value = 1000; 72 case SND_TONE: break; 73 default: return -1; 74 } 75 76 if (value > 20 && value < 32767) 77 count = 1193182 / value; 78 79 spin_lock_irqsave(&beep_lock, flags); 80 81 if (count) { 82 /* enable counter 2 */ 83 outb(inb(beep_iobase + 0x61) | 3, beep_iobase + 0x61); 84 /* set command for counter 2, 2 byte write */ 85 outb(0xB6, beep_iobase + 0x43); 86 /* select desired HZ */ 87 outb(count & 0xff, beep_iobase + 0x42); 88 outb((count >> 8) & 0xff, beep_iobase + 0x42); 89 } else { 90 /* disable counter 2 */ 91 outb(inb_p(beep_iobase + 0x61) & 0xFC, beep_iobase + 0x61); 92 } 93 94 spin_unlock_irqrestore(&beep_lock, flags); 95 96 return 0; 97 } 98 #endif 99 100 static int __devinit sparcspkr_probe(struct platform_device *dev) 101 { 102 struct input_dev *input_dev; 103 int error; 104 105 input_dev = input_allocate_device(); 106 if (!input_dev) 107 return -ENOMEM; 108 109 input_dev->name = beep_name; 110 input_dev->phys = "sparc/input0"; 111 input_dev->id.bustype = BUS_ISA; 112 input_dev->id.vendor = 0x001f; 113 input_dev->id.product = 0x0001; 114 input_dev->id.version = 0x0100; 115 input_dev->cdev.dev = &dev->dev; 116 117 input_dev->evbit[0] = BIT(EV_SND); 118 input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE); 119 120 input_dev->event = beep_event; 121 122 error = input_register_device(input_dev); 123 if (error) { 124 input_free_device(input_dev); 125 return error; 126 } 127 128 platform_set_drvdata(dev, input_dev); 129 130 return 0; 131 } 132 133 static int __devexit sparcspkr_remove(struct platform_device *dev) 134 { 135 struct input_dev *input_dev = platform_get_drvdata(dev); 136 137 input_unregister_device(input_dev); 138 platform_set_drvdata(dev, NULL); 139 /* turn off the speaker */ 140 beep_event(NULL, EV_SND, SND_BELL, 0); 141 142 return 0; 143 } 144 145 static void sparcspkr_shutdown(struct platform_device *dev) 146 { 147 /* turn off the speaker */ 148 beep_event(NULL, EV_SND, SND_BELL, 0); 149 } 150 151 static struct platform_driver sparcspkr_platform_driver = { 152 .driver = { 153 .name = "sparcspkr", 154 .owner = THIS_MODULE, 155 }, 156 .probe = sparcspkr_probe, 157 .remove = __devexit_p(sparcspkr_remove), 158 .shutdown = sparcspkr_shutdown, 159 }; 160 161 static struct platform_device *sparcspkr_platform_device; 162 163 static int __init sparcspkr_drv_init(void) 164 { 165 int error; 166 167 error = platform_driver_register(&sparcspkr_platform_driver); 168 if (error) 169 return error; 170 171 sparcspkr_platform_device = platform_device_alloc("sparcspkr", -1); 172 if (!sparcspkr_platform_device) { 173 error = -ENOMEM; 174 goto err_unregister_driver; 175 } 176 177 error = platform_device_add(sparcspkr_platform_device); 178 if (error) 179 goto err_free_device; 180 181 return 0; 182 183 err_free_device: 184 platform_device_put(sparcspkr_platform_device); 185 err_unregister_driver: 186 platform_driver_unregister(&sparcspkr_platform_driver); 187 188 return error; 189 } 190 191 static int __init sparcspkr_init(void) 192 { 193 struct linux_ebus *ebus; 194 struct linux_ebus_device *edev; 195 #ifdef CONFIG_SPARC64 196 struct sparc_isa_bridge *isa_br; 197 struct sparc_isa_device *isa_dev; 198 #endif 199 200 for_each_ebus(ebus) { 201 for_each_ebusdev(edev, ebus) { 202 if (!strcmp(edev->prom_name, "beep")) { 203 beep_name = "Sparc EBUS Speaker"; 204 beep_event = ebus_spkr_event; 205 beep_iobase = edev->resource[0].start; 206 return sparcspkr_drv_init(); 207 } 208 } 209 } 210 #ifdef CONFIG_SPARC64 211 for_each_isa(isa_br) { 212 for_each_isadev(isa_dev, isa_br) { 213 /* A hack, the beep device's base lives in 214 * the DMA isa node. 215 */ 216 if (!strcmp(isa_dev->prom_name, "dma")) { 217 beep_name = "Sparc ISA Speaker"; 218 beep_event = isa_spkr_event, 219 beep_iobase = isa_dev->resource.start; 220 return sparcspkr_drv_init(); 221 } 222 } 223 } 224 #endif 225 226 return -ENODEV; 227 } 228 229 static void __exit sparcspkr_exit(void) 230 { 231 platform_device_unregister(sparcspkr_platform_device); 232 platform_driver_unregister(&sparcspkr_platform_driver); 233 } 234 235 module_init(sparcspkr_init); 236 module_exit(sparcspkr_exit); 237