xref: /netbsd-src/sys/arch/landisk/dev/button.c (revision ceca564c532dcfe51fa03602ee6e8e570fe45ac9)
1 /*	$NetBSD: button.c,v 1.15 2021/09/29 15:17:01 thorpej Exp $	*/
2 
3 /*
4  * Copyright (c) 2003 Wasabi Systems, Inc.
5  * All rights reserved.
6  *
7  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *	This product includes software developed for the NetBSD Project by
20  *	Wasabi Systems, Inc.
21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22  *    or promote products derived from this software without specific prior
23  *    written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: button.c,v 1.15 2021/09/29 15:17:01 thorpej Exp $");
40 
41 #include <sys/param.h>
42 #include <sys/conf.h>
43 #include <sys/systm.h>
44 #include <sys/queue.h>
45 #include <sys/mutex.h>
46 #include <sys/errno.h>
47 #include <sys/fcntl.h>
48 #include <sys/callout.h>
49 #include <sys/kernel.h>
50 #include <sys/once.h>
51 #include <sys/poll.h>
52 #include <sys/select.h>
53 #include <sys/vnode.h>
54 
55 #include <machine/button.h>
56 
57 #include <landisk/dev/buttonvar.h>
58 
59 /*
60  * event handler
61  */
62 static LIST_HEAD(, btn_event) btn_event_list;
63 static kmutex_t btn_event_list_lock;
64 
65 static struct lwp *btn_daemon;
66 
67 #define	BTN_MAX_EVENTS		32
68 
69 static kmutex_t btn_event_queue_lock;
70 static kcondvar_t btn_event_queue_cv;
71 
72 static button_event_t btn_event_queue[BTN_MAX_EVENTS];
73 static int btn_event_queue_head;
74 static int btn_event_queue_tail;
75 static int btn_event_queue_count;
76 static int btn_event_queue_flags;
77 static struct selinfo btn_event_queue_selinfo;
78 
79 static char btn_type[32];
80 
81 #define	BEVQ_F_WAITING		0x01	/* daemon waiting for event */
82 
83 #define	BTN_NEXT_EVENT(x)	(((x) + 1) / BTN_MAX_EVENTS)
84 
85 dev_type_open(btnopen);
86 dev_type_close(btnclose);
87 dev_type_ioctl(btnioctl);
88 dev_type_read(btnread);
89 dev_type_poll(btnpoll);
90 dev_type_kqfilter(btnkqfilter);
91 
92 const struct cdevsw button_cdevsw = {
93 	.d_open = btnopen,
94 	.d_close = btnclose,
95 	.d_read = btnread,
96 	.d_write = nowrite,
97 	.d_ioctl = btnioctl,
98 	.d_stop = nostop,
99 	.d_tty = notty,
100 	.d_poll = btnpoll,
101 	.d_mmap = nommap,
102 	.d_kqfilter = btnkqfilter,
103 	.d_discard = nodiscard,
104 	.d_flag = 0
105 };
106 
107 int
btn_init(void)108 btn_init(void)
109 {
110 
111 	LIST_INIT(&btn_event_list);
112 	mutex_init(&btn_event_list_lock, MUTEX_DEFAULT, IPL_NONE);
113 	mutex_init(&btn_event_queue_lock, MUTEX_DEFAULT, IPL_NONE);
114 	cv_init(&btn_event_queue_cv, "btncv");
115 	selinit(&btn_event_queue_selinfo);
116 
117 	return 0;
118 }
119 
120 static int
btn_queue_event(button_event_t * bev)121 btn_queue_event(button_event_t *bev)
122 {
123 
124 	if (btn_event_queue_count == BTN_MAX_EVENTS)
125 		return (0);
126 
127 	btn_event_queue[btn_event_queue_head] = *bev;
128 	btn_event_queue_head = BTN_NEXT_EVENT(btn_event_queue_head);
129 	btn_event_queue_count++;
130 
131 	return (1);
132 }
133 
134 static int
btn_get_event(button_event_t * bev)135 btn_get_event(button_event_t *bev)
136 {
137 
138 	if (btn_event_queue_count == 0)
139 		return (0);
140 
141 	*bev = btn_event_queue[btn_event_queue_tail];
142 	btn_event_queue_tail = BTN_NEXT_EVENT(btn_event_queue_tail);
143 	btn_event_queue_count--;
144 
145 	return (1);
146 }
147 
148 static void
btn_event_queue_flush(void)149 btn_event_queue_flush(void)
150 {
151 
152 	btn_event_queue_head = 0;
153 	btn_event_queue_tail = 0;
154 	btn_event_queue_count = 0;
155 	btn_event_queue_flags = 0;
156 }
157 
158 int
btnopen(dev_t dev,int flag,int mode,struct lwp * l)159 btnopen(dev_t dev, int flag, int mode, struct lwp *l)
160 {
161 	int error;
162 
163 	if (minor(dev) != 0) {
164 		return (ENODEV);
165 	}
166 
167 	mutex_enter(&btn_event_queue_lock);
168 	if (btn_daemon != NULL) {
169 		error = EBUSY;
170 	} else {
171 		error = 0;
172 		btn_daemon = l;
173 		btn_event_queue_flush();
174 	}
175 	mutex_exit(&btn_event_queue_lock);
176 
177 	return (error);
178 }
179 
180 int
btnclose(dev_t dev,int flag,int mode,struct lwp * l)181 btnclose(dev_t dev, int flag, int mode, struct lwp *l)
182 {
183 	int count;
184 
185 	if (minor(dev) != 0) {
186 		return (ENODEV);
187 	}
188 
189 	mutex_enter(&btn_event_queue_lock);
190 	count = btn_event_queue_count;
191 	btn_daemon = NULL;
192 	btn_event_queue_flush();
193 	mutex_exit(&btn_event_queue_lock);
194 
195 	if (count) {
196 		printf("WARNING: %d events lost by exiting daemon\n", count);
197 	}
198 
199 	return (0);
200 }
201 
202 int
btnioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)203 btnioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
204 {
205 	int error = 0;
206 
207 	if (minor(dev) != 0) {
208 		return (ENODEV);
209 	}
210 
211 	switch (cmd) {
212 	case BUTTON_IOC_GET_TYPE:
213 	    {
214 		struct button_type *button_type = (void *)data;
215 		strcpy(button_type->button_type, btn_type);
216 		break;
217 	    }
218 
219 	default:
220 		error = ENOTTY;
221 		break;
222 	}
223 
224 	return (error);
225 }
226 
227 int
btnread(dev_t dev,struct uio * uio,int flags)228 btnread(dev_t dev, struct uio *uio, int flags)
229 {
230 	button_event_t bev;
231 	int error;
232 
233 	if (minor(dev) != 0) {
234 		return (ENODEV);
235 	}
236 
237 	if (uio->uio_resid != BUTTON_EVENT_MSG_SIZE) {
238 		return (EINVAL);
239 	}
240 
241 	mutex_enter(&btn_event_queue_lock);
242 	for (;;) {
243 		if (btn_get_event(&bev)) {
244 			mutex_exit(&btn_event_queue_lock);
245 			return (uiomove(&bev, BUTTON_EVENT_MSG_SIZE, uio));
246 		}
247 
248 		if (flags & IO_NDELAY) {
249 			mutex_exit(&btn_event_queue_lock);
250 			return (EWOULDBLOCK);
251 		}
252 
253 		btn_event_queue_flags |= BEVQ_F_WAITING;
254 		error = cv_wait_sig(&btn_event_queue_cv, &btn_event_queue_lock);
255 		if (error) {
256 			mutex_exit(&btn_event_queue_lock);
257 			return (error);
258 		}
259 	}
260 }
261 
262 int
btnpoll(dev_t dev,int events,struct lwp * l)263 btnpoll(dev_t dev, int events, struct lwp *l)
264 {
265 	int revents;
266 
267 	if (minor(dev) != 0) {
268 		return (ENODEV);
269 	}
270 
271 	revents = events & (POLLOUT | POLLWRNORM);
272 
273 	/* Attempt to save some work. */
274 	if ((events & (POLLIN | POLLRDNORM)) == 0)
275 		return (revents);
276 
277 	mutex_enter(&btn_event_queue_lock);
278 	if (btn_event_queue_count) {
279 		revents |= events & (POLLIN | POLLRDNORM);
280 	} else {
281 		selrecord(l, &btn_event_queue_selinfo);
282 	}
283 	mutex_exit(&btn_event_queue_lock);
284 
285 	return (revents);
286 }
287 
288 static void
filt_btn_rdetach(struct knote * kn)289 filt_btn_rdetach(struct knote *kn)
290 {
291 
292 	mutex_enter(&btn_event_queue_lock);
293 	selremove_knote(&btn_event_queue_selinfo, kn);
294 	mutex_exit(&btn_event_queue_lock);
295 }
296 
297 static int
filt_btn_read(struct knote * kn,long hint)298 filt_btn_read(struct knote *kn, long hint)
299 {
300 	int rv;
301 
302 	if (hint & NOTE_SUBMIT) {
303 		KASSERT(mutex_owned(&btn_event_queue_lock));
304 	} else {
305 		mutex_enter(&btn_event_queue_lock);
306 	}
307 
308 	kn->kn_data = btn_event_queue_count;
309 	rv = kn->kn_data > 0;
310 
311 	if ((hint & NOTE_SUBMIT) == 0) {
312 		mutex_exit(&btn_event_queue_lock);
313 	}
314 
315 	return rv;
316 }
317 
318 static const struct filterops btn_read_filtops = {
319     .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE,
320     .f_attach = NULL,
321     .f_detach = filt_btn_rdetach,
322     .f_event = filt_btn_read,
323 };
324 
325 int
btnkqfilter(dev_t dev,struct knote * kn)326 btnkqfilter(dev_t dev, struct knote *kn)
327 {
328 
329 	if (minor(dev) != 0) {
330 		return (ENODEV);
331 	}
332 
333 	switch (kn->kn_filter) {
334 	case EVFILT_READ:
335 		kn->kn_fop = &btn_read_filtops;
336 		mutex_enter(&btn_event_queue_lock);
337 		selrecord_knote(&btn_event_queue_selinfo, kn);
338 		mutex_exit(&btn_event_queue_lock);
339 		break;
340 
341 	case EVFILT_WRITE:
342 		kn->kn_fop = &seltrue_filtops;
343 		break;
344 
345 	default:
346 		return (EINVAL);
347 	}
348 
349 	return (0);
350 }
351 
352 void
btn_settype(const char * type)353 btn_settype(const char *type)
354 {
355 
356 	/*
357 	 * Don't bother locking this; it's going to be set
358 	 * during autoconfiguration, and then only read from
359 	 * then on.
360 	 */
361 	strlcpy(btn_type, type, sizeof(btn_type));
362 }
363 
364 int
btn_event_register(struct btn_event * bev)365 btn_event_register(struct btn_event *bev)
366 {
367 
368 	mutex_enter(&btn_event_list_lock);
369 	LIST_INSERT_HEAD(&btn_event_list, bev, bev_list);
370 	mutex_exit(&btn_event_list_lock);
371 
372 	return (0);
373 }
374 
375 void
btn_event_unregister(struct btn_event * bev)376 btn_event_unregister(struct btn_event *bev)
377 {
378 
379 	mutex_enter(&btn_event_list_lock);
380 	LIST_REMOVE(bev, bev_list);
381 	mutex_exit(&btn_event_list_lock);
382 }
383 
384 void
btn_event_send(struct btn_event * bev,int event)385 btn_event_send(struct btn_event *bev, int event)
386 {
387 	button_event_t btnev;
388 	int rv;
389 
390 	mutex_enter(&btn_event_queue_lock);
391 	if (btn_daemon == NULL) {
392 		mutex_exit(&btn_event_queue_lock);
393 		printf("%s: btn_event_send can't handle me.\n", bev->bev_name);
394 		return;
395 	}
396 
397 	btnev.bev_type = BUTTON_EVENT_STATE_CHANGE;
398 	btnev.bev_event.bs_state = event;
399 	strcpy(btnev.bev_event.bs_name, bev->bev_name);
400 
401 	rv = btn_queue_event(&btnev);
402 	if (rv == 0) {
403 		mutex_exit(&btn_event_queue_lock);
404 		printf("%s: WARNING: state change event %d lost; "
405 		    "queue full\n", bev->bev_name, btnev.bev_type);
406 		return;
407 	}
408 	if (btn_event_queue_flags & BEVQ_F_WAITING) {
409 		btn_event_queue_flags &= ~BEVQ_F_WAITING;
410 		cv_broadcast(&btn_event_queue_cv);
411 	}
412 	selnotify(&btn_event_queue_selinfo, POLLIN | POLLRDNORM, NOTE_SUBMIT);
413 	mutex_exit(&btn_event_queue_lock);
414 }
415