1 /* $NetBSD: button.c,v 1.6 2011/05/14 02:27:35 rmind 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.6 2011/05/14 02:27:35 rmind 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 ONCE_DECL(btn_once); 63 static LIST_HEAD(, btn_event) btn_event_list; 64 static kmutex_t btn_event_list_lock; 65 66 static struct lwp *btn_daemon; 67 68 #define BTN_MAX_EVENTS 32 69 70 static kmutex_t btn_event_queue_lock; 71 static kcondvar_t btn_event_queue_cv; 72 73 static button_event_t btn_event_queue[BTN_MAX_EVENTS]; 74 static int btn_event_queue_head; 75 static int btn_event_queue_tail; 76 static int btn_event_queue_count; 77 static int btn_event_queue_flags; 78 static struct selinfo btn_event_queue_selinfo; 79 80 static char btn_type[32]; 81 82 #define BEVQ_F_WAITING 0x01 /* daemon waiting for event */ 83 84 #define BTN_NEXT_EVENT(x) (((x) + 1) / BTN_MAX_EVENTS) 85 86 dev_type_open(btnopen); 87 dev_type_close(btnclose); 88 dev_type_ioctl(btnioctl); 89 dev_type_read(btnread); 90 dev_type_poll(btnpoll); 91 dev_type_kqfilter(btnkqfilter); 92 93 const struct cdevsw button_cdevsw = { 94 btnopen, btnclose, btnread, nowrite, btnioctl, 95 nostop, notty, btnpoll, nommap, btnkqfilter, 96 }; 97 98 static int 99 btn_init(void) 100 { 101 102 LIST_INIT(&btn_event_list); 103 mutex_init(&btn_event_list_lock, MUTEX_DEFAULT, IPL_NONE); 104 mutex_init(&btn_event_queue_lock, MUTEX_DEFAULT, IPL_NONE); 105 cv_init(&btn_event_queue_cv, "btncv"); 106 selinit(&btn_event_queue_selinfo); 107 108 return 0; 109 } 110 111 static int 112 btn_queue_event(button_event_t *bev) 113 { 114 115 if (btn_event_queue_count == BTN_MAX_EVENTS) 116 return (0); 117 118 btn_event_queue[btn_event_queue_head] = *bev; 119 btn_event_queue_head = BTN_NEXT_EVENT(btn_event_queue_head); 120 btn_event_queue_count++; 121 122 return (1); 123 } 124 125 static int 126 btn_get_event(button_event_t *bev) 127 { 128 129 if (btn_event_queue_count == 0) 130 return (0); 131 132 *bev = btn_event_queue[btn_event_queue_tail]; 133 btn_event_queue_tail = BTN_NEXT_EVENT(btn_event_queue_tail); 134 btn_event_queue_count--; 135 136 return (1); 137 } 138 139 static void 140 btn_event_queue_flush(void) 141 { 142 143 btn_event_queue_head = 0; 144 btn_event_queue_tail = 0; 145 btn_event_queue_count = 0; 146 btn_event_queue_flags = 0; 147 } 148 149 int 150 btnopen(dev_t dev, int flag, int mode, struct lwp *l) 151 { 152 int error; 153 154 error = RUN_ONCE(&btn_once, btn_init); 155 if (error) { 156 return error; 157 } 158 159 if (minor(dev) != 0) { 160 return (ENODEV); 161 } 162 163 mutex_enter(&btn_event_queue_lock); 164 if (btn_daemon != NULL) { 165 error = EBUSY; 166 } else { 167 error = 0; 168 btn_daemon = l; 169 btn_event_queue_flush(); 170 } 171 mutex_exit(&btn_event_queue_lock); 172 173 return (error); 174 } 175 176 int 177 btnclose(dev_t dev, int flag, int mode, struct lwp *l) 178 { 179 int count; 180 181 if (minor(dev) != 0) { 182 return (ENODEV); 183 } 184 185 mutex_enter(&btn_event_queue_lock); 186 count = btn_event_queue_count; 187 btn_daemon = NULL; 188 btn_event_queue_flush(); 189 mutex_exit(&btn_event_queue_lock); 190 191 if (count) { 192 printf("WARNING: %d events lost by exiting daemon\n", count); 193 } 194 195 return (0); 196 } 197 198 int 199 btnioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 200 { 201 int error = 0; 202 203 if (minor(dev) != 0) { 204 return (ENODEV); 205 } 206 207 switch (cmd) { 208 case BUTTON_IOC_GET_TYPE: 209 { 210 struct button_type *button_type = (void *)data; 211 strcpy(button_type->button_type, btn_type); 212 break; 213 } 214 215 default: 216 error = ENOTTY; 217 break; 218 } 219 220 return (error); 221 } 222 223 int 224 btnread(dev_t dev, struct uio *uio, int flags) 225 { 226 button_event_t bev; 227 int error; 228 229 if (minor(dev) != 0) { 230 return (ENODEV); 231 } 232 233 if (uio->uio_resid != BUTTON_EVENT_MSG_SIZE) { 234 return (EINVAL); 235 } 236 237 mutex_enter(&btn_event_queue_lock); 238 for (;;) { 239 if (btn_get_event(&bev)) { 240 mutex_exit(&btn_event_queue_lock); 241 return (uiomove(&bev, BUTTON_EVENT_MSG_SIZE, uio)); 242 } 243 244 if (flags & IO_NDELAY) { 245 mutex_exit(&btn_event_queue_lock); 246 return (EWOULDBLOCK); 247 } 248 249 btn_event_queue_flags |= BEVQ_F_WAITING; 250 error = cv_wait_sig(&btn_event_queue_cv, &btn_event_queue_lock); 251 if (error) { 252 mutex_exit(&btn_event_queue_lock); 253 return (error); 254 } 255 } 256 } 257 258 int 259 btnpoll(dev_t dev, int events, struct lwp *l) 260 { 261 int revents; 262 263 if (minor(dev) != 0) { 264 return (ENODEV); 265 } 266 267 revents = events & (POLLOUT | POLLWRNORM); 268 269 /* Attempt to save some work. */ 270 if ((events & (POLLIN | POLLRDNORM)) == 0) 271 return (revents); 272 273 mutex_enter(&btn_event_queue_lock); 274 if (btn_event_queue_count) { 275 revents |= events & (POLLIN | POLLRDNORM); 276 } else { 277 selrecord(l, &btn_event_queue_selinfo); 278 } 279 mutex_exit(&btn_event_queue_lock); 280 281 return (revents); 282 } 283 284 static void 285 filt_btn_rdetach(struct knote *kn) 286 { 287 288 mutex_enter(&btn_event_queue_lock); 289 SLIST_REMOVE(&btn_event_queue_selinfo.sel_klist, 290 kn, knote, kn_selnext); 291 mutex_exit(&btn_event_queue_lock); 292 } 293 294 static int 295 filt_btn_read(struct knote *kn, long hint) 296 { 297 298 mutex_enter(&btn_event_queue_lock); 299 kn->kn_data = btn_event_queue_count; 300 mutex_exit(&btn_event_queue_lock); 301 302 return (kn->kn_data > 0); 303 } 304 305 static const struct filterops btn_read_filtops = 306 { 1, NULL, filt_btn_rdetach, filt_btn_read }; 307 308 static const struct filterops btn_write_filtops = 309 { 1, NULL, filt_btn_rdetach, filt_seltrue }; 310 311 int 312 btnkqfilter(dev_t dev, struct knote *kn) 313 { 314 struct klist *klist; 315 316 if (minor(dev) != 0) { 317 return (ENODEV); 318 } 319 320 switch (kn->kn_filter) { 321 case EVFILT_READ: 322 klist = &btn_event_queue_selinfo.sel_klist; 323 kn->kn_fop = &btn_read_filtops; 324 break; 325 326 case EVFILT_WRITE: 327 klist = &btn_event_queue_selinfo.sel_klist; 328 kn->kn_fop = &btn_write_filtops; 329 break; 330 331 default: 332 return (1); 333 } 334 335 mutex_enter(&btn_event_queue_lock); 336 SLIST_INSERT_HEAD(klist, kn, kn_selnext); 337 mutex_exit(&btn_event_queue_lock); 338 339 return (0); 340 } 341 342 void 343 btn_settype(const char *type) 344 { 345 346 /* 347 * Don't bother locking this; it's going to be set 348 * during autoconfiguration, and then only read from 349 * then on. 350 */ 351 strlcpy(btn_type, type, sizeof(btn_type)); 352 } 353 354 int 355 btn_event_register(struct btn_event *bev) 356 { 357 358 mutex_enter(&btn_event_list_lock); 359 LIST_INSERT_HEAD(&btn_event_list, bev, bev_list); 360 mutex_exit(&btn_event_list_lock); 361 362 return (0); 363 } 364 365 void 366 btn_event_unregister(struct btn_event *bev) 367 { 368 369 mutex_enter(&btn_event_list_lock); 370 LIST_REMOVE(bev, bev_list); 371 mutex_exit(&btn_event_list_lock); 372 } 373 374 void 375 btn_event_send(struct btn_event *bev, int event) 376 { 377 button_event_t btnev; 378 int rv; 379 380 mutex_enter(&btn_event_queue_lock); 381 if (btn_daemon == NULL) { 382 mutex_exit(&btn_event_queue_lock); 383 printf("%s: btn_event_send can't handle me.\n", bev->bev_name); 384 return; 385 } 386 387 btnev.bev_type = BUTTON_EVENT_STATE_CHANGE; 388 btnev.bev_event.bs_state = event; 389 strcpy(btnev.bev_event.bs_name, bev->bev_name); 390 391 rv = btn_queue_event(&btnev); 392 if (rv == 0) { 393 mutex_exit(&btn_event_queue_lock); 394 printf("%s: WARNING: state change event %d lost; " 395 "queue full\n", bev->bev_name, btnev.bev_type); 396 return; 397 } 398 if (btn_event_queue_flags & BEVQ_F_WAITING) { 399 btn_event_queue_flags &= ~BEVQ_F_WAITING; 400 cv_broadcast(&btn_event_queue_cv); 401 } 402 selnotify(&btn_event_queue_selinfo, 0, 0); 403 mutex_exit(&btn_event_queue_lock); 404 } 405