Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / sound / drivers / pcsp / pcsp_input.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  *  PC Speaker beeper driver for Linux
4  *
5  *  Copyright (c) 2002 Vojtech Pavlik
6  *  Copyright (c) 1992 Orest Zborowski
7  */
8
9
10 #include <linux/init.h>
11 #include <linux/input.h>
12 #include <linux/io.h>
13 #include "pcsp.h"
14 #include "pcsp_input.h"
15
16 static void pcspkr_do_sound(unsigned int count)
17 {
18         unsigned long flags;
19
20         raw_spin_lock_irqsave(&i8253_lock, flags);
21
22         if (count) {
23                 /* set command for counter 2, 2 byte write */
24                 outb_p(0xB6, 0x43);
25                 /* select desired HZ */
26                 outb_p(count & 0xff, 0x42);
27                 outb((count >> 8) & 0xff, 0x42);
28                 /* enable counter 2 */
29                 outb_p(inb_p(0x61) | 3, 0x61);
30         } else {
31                 /* disable counter 2 */
32                 outb(inb_p(0x61) & 0xFC, 0x61);
33         }
34
35         raw_spin_unlock_irqrestore(&i8253_lock, flags);
36 }
37
38 void pcspkr_stop_sound(void)
39 {
40         pcspkr_do_sound(0);
41 }
42
43 static int pcspkr_input_event(struct input_dev *dev, unsigned int type,
44                               unsigned int code, int value)
45 {
46         unsigned int count = 0;
47
48         if (atomic_read(&pcsp_chip.timer_active) || !pcsp_chip.pcspkr)
49                 return 0;
50
51         switch (type) {
52         case EV_SND:
53                 switch (code) {
54                 case SND_BELL:
55                         if (value)
56                                 value = 1000;
57                 case SND_TONE:
58                         break;
59                 default:
60                         return -1;
61                 }
62                 break;
63
64         default:
65                 return -1;
66         }
67
68         if (value > 20 && value < 32767)
69                 count = PIT_TICK_RATE / value;
70
71         pcspkr_do_sound(count);
72
73         return 0;
74 }
75
76 int pcspkr_input_init(struct input_dev **rdev, struct device *dev)
77 {
78         int err;
79
80         struct input_dev *input_dev = input_allocate_device();
81         if (!input_dev)
82                 return -ENOMEM;
83
84         input_dev->name = "PC Speaker";
85         input_dev->phys = "isa0061/input0";
86         input_dev->id.bustype = BUS_ISA;
87         input_dev->id.vendor = 0x001f;
88         input_dev->id.product = 0x0001;
89         input_dev->id.version = 0x0100;
90         input_dev->dev.parent = dev;
91
92         input_dev->evbit[0] = BIT(EV_SND);
93         input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
94         input_dev->event = pcspkr_input_event;
95
96         err = input_register_device(input_dev);
97         if (err) {
98                 input_free_device(input_dev);
99                 return err;
100         }
101
102         *rdev = input_dev;
103         return 0;
104 }
105
106 int pcspkr_input_remove(struct input_dev *dev)
107 {
108         pcspkr_stop_sound();
109         input_unregister_device(dev);   /* this also does kfree() */
110
111         return 0;
112 }