1 /* $NetBSD: btn_obio.c,v 1.8 2023/12/20 15:00:08 thorpej Exp $ */
2
3 /*-
4 * Copyright (C) 2005 NONAKA Kimihiro <nonaka@netbsd.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "pwrsw_obio.h"
29
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: btn_obio.c,v 1.8 2023/12/20 15:00:08 thorpej Exp $");
32
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/device.h>
37 #include <sys/kernel.h>
38 #include <sys/conf.h>
39 #include <sys/ioctl.h>
40 #include <sys/callout.h>
41
42 #include <dev/sysmon/sysmonvar.h>
43 #include <dev/sysmon/sysmon_taskq.h>
44
45 #include <sh3/devreg.h>
46
47 #include <machine/button.h>
48
49 #include <landisk/landisk/landiskreg.h>
50 #include <landisk/dev/obiovar.h>
51 #include <landisk/dev/buttonvar.h>
52
53 #define BTN_SELECT 0
54 #define BTN_COPY 1
55 #define BTN_REMOVE 2
56 #define NBUTTON 3
57
58 struct btn_obio_softc {
59 device_t sc_dev;
60 void *sc_ih;
61
62 struct callout sc_guard_ch;
63 struct sysmon_pswitch sc_smpsw; /* reset */
64 struct btn_event sc_bev[NBUTTON];
65
66 int sc_mask;
67 };
68
69 #ifndef BTN_TIMEOUT
70 #define BTN_TIMEOUT (hz / 10) /* 100ms */
71 #endif
72
73 static int btn_obio_probe(device_t, cfdata_t, void *);
74 static void btn_obio_attach(device_t, device_t, void *);
75
76 static int btn_intr(void *aux);
77 static void btn_sysmon_pressed_event(void *arg);
78 static void btn_pressed_event(void *arg);
79 static void btn_guard_timeout(void *arg);
80
81 static struct btn_obio_softc *btn_softc;
82
83 static const struct {
84 int idx;
85 int mask;
86 const char *name;
87 } btnlist[NBUTTON] = {
88 { BTN_SELECT, BTN_SELECT_BIT, "select" },
89 { BTN_COPY, BTN_COPY_BIT, "copy" },
90 { BTN_REMOVE, BTN_REMOVE_BIT, "remove" },
91 };
92
93 CFATTACH_DECL_NEW(btn_obio, sizeof(struct btn_obio_softc),
94 btn_obio_probe, btn_obio_attach, NULL, NULL);
95
96 static int
btn_obio_probe(device_t parent,cfdata_t cfp,void * aux)97 btn_obio_probe(device_t parent, cfdata_t cfp, void *aux)
98 {
99 struct obio_attach_args *oa = aux;
100
101 if (btn_softc)
102 return (0);
103
104 oa->oa_nio = 0;
105 oa->oa_niomem = 0;
106 oa->oa_nirq = 1;
107 oa->oa_irq[0].or_irq = LANDISK_INTR_BTN;
108
109 return (1);
110 }
111
112 static void
btn_obio_attach(device_t parent,device_t self,void * aux)113 btn_obio_attach(device_t parent, device_t self, void *aux)
114 {
115 struct btn_obio_softc *sc;
116 int i;
117
118 aprint_naive("\n");
119 aprint_normal(": USL-5P buttons\n");
120
121 sc = device_private(self);
122 sc->sc_dev = self;
123
124 btn_softc = sc;
125
126 callout_init(&sc->sc_guard_ch, 0);
127 callout_setfunc(&sc->sc_guard_ch, btn_guard_timeout, sc);
128
129 sc->sc_ih = extintr_establish(LANDISK_INTR_BTN, IPL_TTY, btn_intr, sc);
130 if (sc->sc_ih == NULL) {
131 aprint_error_dev(self, "unable to establish interrupt");
132 panic("extintr_establish");
133 }
134
135 sc->sc_smpsw.smpsw_name = device_xname(self);
136 sc->sc_smpsw.smpsw_type = PSWITCH_TYPE_RESET;
137 if (sysmon_pswitch_register(&sc->sc_smpsw) != 0) {
138 aprint_error_dev(self, "unable to register with sysmon\n");
139 return;
140 }
141 sc->sc_mask |= BTN_RESET_BIT;
142
143 btn_init();
144 for (i = 0; i < NBUTTON; i++) {
145 int idx = btnlist[i].idx;
146 sc->sc_bev[idx].bev_name = btnlist[i].name;
147 if (btn_event_register(&sc->sc_bev[idx]) != 0) {
148 aprint_error_dev(self,
149 "unable to register '%s' button\n",
150 btnlist[i].name);
151 } else {
152 sc->sc_mask |= btnlist[i].mask;
153 }
154 }
155 }
156
157 static int
btn_intr(void * arg)158 btn_intr(void *arg)
159 {
160 struct btn_obio_softc *sc = (void *)arg;
161 device_t self = sc->sc_dev;
162 int status;
163 int i;
164
165 status = (int8_t)_reg_read_1(LANDISK_BTNSTAT);
166 if (status == -1) {
167 return (0);
168 }
169
170 status = ~status;
171 if (status & BTN_ALL_BIT) {
172 if (status & BTN_RESET_BIT) {
173 if (sc->sc_mask & BTN_RESET_BIT) {
174 extintr_disable(sc->sc_ih);
175 #if NPWRSW_OBIO > 0
176 extintr_disable_by_num(LANDISK_INTR_PWRSW);
177 #endif
178 sysmon_task_queue_sched(0,
179 btn_sysmon_pressed_event, sc);
180 return (1);
181 } else {
182 aprint_normal_dev(self,
183 "reset button pressed\n");
184 }
185 }
186
187 for (i = 0; i < NBUTTON; i++) {
188 uint8_t mask = btnlist[i].mask;
189 int rv = 0;
190 if (status & mask) {
191 if (sc->sc_mask & mask) {
192 sysmon_task_queue_sched(1,
193 btn_pressed_event,
194 &sc->sc_bev[btnlist[i].idx]);
195 } else {
196 aprint_normal_dev(self,
197 "%s button pressed\n",
198 btnlist[i].name);
199 }
200 rv = 1;
201 }
202 if (rv != 0) {
203 extintr_disable(sc->sc_ih);
204 callout_schedule(&sc->sc_guard_ch, BTN_TIMEOUT);
205 }
206 }
207 return (1);
208 }
209 return (0);
210 }
211
212 static void
btn_sysmon_pressed_event(void * arg)213 btn_sysmon_pressed_event(void *arg)
214 {
215 struct btn_obio_softc *sc = (void *)arg;
216
217 sysmon_pswitch_event(&sc->sc_smpsw, PSWITCH_EVENT_PRESSED);
218 }
219
220 static void
btn_pressed_event(void * arg)221 btn_pressed_event(void *arg)
222 {
223 struct btn_event *bev = (void *)arg;
224
225 btn_event_send(bev, BUTTON_EVENT_PRESSED);
226 }
227
228 static void
btn_guard_timeout(void * arg)229 btn_guard_timeout(void *arg)
230 {
231 struct btn_obio_softc *sc = arg;
232
233 callout_stop(&sc->sc_guard_ch);
234 extintr_enable(sc->sc_ih);
235 }
236