1 /* $NetBSD: button.c,v 1.4 2008/01/07 00:27:35 ad Exp $ */
4 * Copyright (c) 2003 Wasabi Systems, Inc.
7 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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
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.
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: button.c,v 1.4 2008/01/07 00:27:35 ad Exp $");
41 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/malloc.h>
45 #include <sys/simplelock.h>
46 #include <sys/queue.h>
48 #include <sys/kthread.h>
49 #include <sys/errno.h>
50 #include <sys/fcntl.h>
51 #include <sys/callout.h>
52 #include <sys/kernel.h>
54 #include <sys/select.h>
55 #include <sys/vnode.h>
57 #include <machine/button.h>
59 #include <landisk/dev/buttonvar.h>
64 static LIST_HEAD(, btn_event
) btn_event_list
=
65 LIST_HEAD_INITIALIZER(btn_event_list
);
66 static struct simplelock btn_event_list_slock
=
67 SIMPLELOCK_INITIALIZER
;
69 static struct lwp
*btn_daemon
;
71 #define BTN_MAX_EVENTS 32
73 static struct simplelock btn_event_queue_slock
=
74 SIMPLELOCK_INITIALIZER
;
75 static button_event_t btn_event_queue
[BTN_MAX_EVENTS
];
76 static int btn_event_queue_head
;
77 static int btn_event_queue_tail
;
78 static int btn_event_queue_count
;
79 static int btn_event_queue_flags
;
80 static struct selinfo btn_event_queue_selinfo
;
82 static char btn_type
[32];
84 #define BEVQ_F_WAITING 0x01 /* daemon waiting for event */
86 #define BTN_NEXT_EVENT(x) (((x) + 1) / BTN_MAX_EVENTS)
88 dev_type_open(btnopen
);
89 dev_type_close(btnclose
);
90 dev_type_ioctl(btnioctl
);
91 dev_type_read(btnread
);
92 dev_type_poll(btnpoll
);
93 dev_type_kqfilter(btnkqfilter
);
95 const struct cdevsw button_cdevsw
= {
96 btnopen
, btnclose
, btnread
, nowrite
, btnioctl
,
97 nostop
, notty
, btnpoll
, nommap
, btnkqfilter
,
101 btn_queue_event(button_event_t
*bev
)
104 if (btn_event_queue_count
== BTN_MAX_EVENTS
)
107 btn_event_queue
[btn_event_queue_head
] = *bev
;
108 btn_event_queue_head
= BTN_NEXT_EVENT(btn_event_queue_head
);
109 btn_event_queue_count
++;
115 btn_get_event(button_event_t
*bev
)
118 if (btn_event_queue_count
== 0)
121 *bev
= btn_event_queue
[btn_event_queue_tail
];
122 btn_event_queue_tail
= BTN_NEXT_EVENT(btn_event_queue_tail
);
123 btn_event_queue_count
--;
129 btn_event_queue_flush(void)
132 btn_event_queue_head
= 0;
133 btn_event_queue_tail
= 0;
134 btn_event_queue_count
= 0;
135 btn_event_queue_flags
= 0;
139 btnopen(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
141 static bool btn_event_queue_selinfo_init
; /* XXX */
144 if (!btn_event_queue_selinfo_init
) {
145 selinit(&btn_event_queue_selinfo
);
146 btn_event_queue_selinfo_init
= true;
149 if (minor(dev
) != 0) {
153 simple_lock(&btn_event_queue_slock
);
154 if (btn_daemon
!= NULL
) {
159 btn_event_queue_flush();
161 simple_unlock(&btn_event_queue_slock
);
167 btnclose(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
171 if (minor(dev
) != 0) {
175 simple_lock(&btn_event_queue_slock
);
176 count
= btn_event_queue_count
;
178 btn_event_queue_flush();
179 simple_unlock(&btn_event_queue_slock
);
182 printf("WARNING: %d events lost by exiting daemon\n", count
);
189 btnioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
193 if (minor(dev
) != 0) {
198 case BUTTON_IOC_GET_TYPE
:
200 struct button_type
*button_type
= (void *)data
;
201 strcpy(button_type
->button_type
, btn_type
);
214 btnread(dev_t dev
, struct uio
*uio
, int flags
)
219 if (minor(dev
) != 0) {
223 if (uio
->uio_resid
!= BUTTON_EVENT_MSG_SIZE
) {
227 simple_lock(&btn_event_queue_slock
);
229 if (btn_get_event(&bev
)) {
230 simple_unlock(&btn_event_queue_slock
);
231 return (uiomove(&bev
, BUTTON_EVENT_MSG_SIZE
, uio
));
234 if (flags
& IO_NDELAY
) {
235 simple_unlock(&btn_event_queue_slock
);
236 return (EWOULDBLOCK
);
239 btn_event_queue_flags
|= BEVQ_F_WAITING
;
240 error
= ltsleep(&btn_event_queue_count
,
241 (PRIBIO
|PCATCH
), "btnread", 0, &btn_event_queue_slock
);
243 simple_unlock(&btn_event_queue_slock
);
250 btnpoll(dev_t dev
, int events
, struct lwp
*l
)
254 if (minor(dev
) != 0) {
258 revents
= events
& (POLLOUT
| POLLWRNORM
);
260 /* Attempt to save some work. */
261 if ((events
& (POLLIN
| POLLRDNORM
)) == 0)
264 simple_lock(&btn_event_queue_slock
);
265 if (btn_event_queue_count
) {
266 revents
|= events
& (POLLIN
| POLLRDNORM
);
268 selrecord(l
, &btn_event_queue_selinfo
);
270 simple_unlock(&btn_event_queue_slock
);
276 filt_btn_rdetach(struct knote
*kn
)
279 simple_lock(&btn_event_queue_slock
);
280 SLIST_REMOVE(&btn_event_queue_selinfo
.sel_klist
,
281 kn
, knote
, kn_selnext
);
282 simple_unlock(&btn_event_queue_slock
);
286 filt_btn_read(struct knote
*kn
, long hint
)
289 simple_lock(&btn_event_queue_slock
);
290 kn
->kn_data
= btn_event_queue_count
;
291 simple_unlock(&btn_event_queue_slock
);
293 return (kn
->kn_data
> 0);
296 static const struct filterops btn_read_filtops
=
297 { 1, NULL
, filt_btn_rdetach
, filt_btn_read
};
299 static const struct filterops btn_write_filtops
=
300 { 1, NULL
, filt_btn_rdetach
, filt_seltrue
};
303 btnkqfilter(dev_t dev
, struct knote
*kn
)
307 if (minor(dev
) != 0) {
311 switch (kn
->kn_filter
) {
313 klist
= &btn_event_queue_selinfo
.sel_klist
;
314 kn
->kn_fop
= &btn_read_filtops
;
318 klist
= &btn_event_queue_selinfo
.sel_klist
;
319 kn
->kn_fop
= &btn_write_filtops
;
326 simple_lock(&btn_event_queue_slock
);
327 SLIST_INSERT_HEAD(klist
, kn
, kn_selnext
);
328 simple_unlock(&btn_event_queue_slock
);
334 btn_settype(const char *type
)
338 * Don't bother locking this; it's going to be set
339 * during autoconfiguration, and then only read from
342 strlcpy(btn_type
, type
, sizeof(btn_type
));
346 btn_event_register(struct btn_event
*bev
)
349 simple_lock(&btn_event_list_slock
);
350 LIST_INSERT_HEAD(&btn_event_list
, bev
, bev_list
);
351 simple_unlock(&btn_event_list_slock
);
357 btn_event_unregister(struct btn_event
*bev
)
360 simple_lock(&btn_event_list_slock
);
361 LIST_REMOVE(bev
, bev_list
);
362 simple_unlock(&btn_event_list_slock
);
366 btn_event_send(struct btn_event
*bev
, int event
)
368 button_event_t btnev
;
371 simple_lock(&btn_event_queue_slock
);
372 if (btn_daemon
!= NULL
) {
373 btnev
.bev_type
= BUTTON_EVENT_STATE_CHANGE
;
374 btnev
.bev_event
.bs_state
= event
;
375 strcpy(btnev
.bev_event
.bs_name
, bev
->bev_name
);
377 rv
= btn_queue_event(&btnev
);
379 simple_unlock(&btn_event_queue_slock
);
380 printf("%s: WARNING: state change event %d lost; "
381 "queue full\n", bev
->bev_name
, btnev
.bev_type
);
383 if (btn_event_queue_flags
& BEVQ_F_WAITING
) {
384 btn_event_queue_flags
&= ~BEVQ_F_WAITING
;
385 simple_unlock(&btn_event_queue_slock
);
386 wakeup(&btn_event_queue_count
);
388 simple_unlock(&btn_event_queue_slock
);
390 selnotify(&btn_event_queue_selinfo
, 0, 0);
394 simple_unlock(&btn_event_queue_slock
);
396 printf("%s: btn_event_send can't handle me.\n", bev
->bev_name
);