xref: /dragonfly/sys/dev/misc/syscons/sysmouse.c (revision f9993810)
1 /*-
2  * (MPSAFE)
3  *
4  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
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 as
12  *    the first lines of this file unmodified.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD: src/sys/dev/syscons/sysmouse.c,v 1.2.2.2 2001/07/16 05:21:24 yokota Exp $
29  */
30 
31 /* MPSAFE NOTE: Take care with locking in sysmouse_event which is called
32  *              from syscons.
33  */
34 #include "opt_syscons.h"
35 #include "opt_evdev.h"
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/conf.h>
40 #include <sys/device.h>
41 #include <sys/event.h>
42 #include <sys/uio.h>
43 #include <sys/caps.h>
44 #include <sys/vnode.h>
45 #include <sys/kernel.h>
46 #include <sys/signalvar.h>
47 #include <sys/filio.h>
48 
49 #include <machine/console.h>
50 #include <sys/mouse.h>
51 
52 #ifdef EVDEV_SUPPORT
53 #include <dev/misc/evdev/input.h>
54 #include <dev/misc/evdev/evdev.h>
55 #endif
56 
57 #include "syscons.h"
58 
59 #ifndef SC_NO_SYSMOUSE
60 
61 #define FIFO_SIZE	256
62 
63 struct event_fifo {
64 	mouse_info_t buf[FIFO_SIZE];
65 	int start;
66 	int fill;
67 	unsigned int dropped;
68 };
69 
70 struct sysmouse_state {
71 	struct event_fifo *fifo;
72 	int level;	/* sysmouse protocol level */
73 	mousestatus_t syncstatus;
74 	mousestatus_t readstatus;	/* Only needed for button status */
75 	int opened;
76 	int asyncio;
77 	struct lock sm_lock;
78 	struct sigio *sm_sigio;
79 	struct kqinfo rkq;
80 };
81 
82 static d_open_t		smopen;
83 static d_close_t	smclose;
84 static d_read_t		smread;
85 static d_ioctl_t	smioctl;
86 static d_kqfilter_t	smkqfilter;
87 
88 static struct dev_ops sm_ops = {
89 	{ "sysmouse", 0, D_MPSAFE },
90 	.d_open =	smopen,
91 	.d_close =	smclose,
92 	.d_read =	smread,
93 	.d_ioctl =	smioctl,
94 	.d_kqfilter =	smkqfilter,
95 };
96 
97 /* local variables */
98 static struct sysmouse_state mouse_state;
99 
100 static int	sysmouse_evtopkt(struct sysmouse_state *sc, mouse_info_t *info,
101 		    u_char *buf);
102 static void	smqueue(struct sysmouse_state *sc, mouse_info_t *info);
103 static int	pktlen(struct sysmouse_state *sc);
104 static void	smfilter_detach(struct knote *);
105 static int	smfilter(struct knote *, long);
106 static void	smget(struct sysmouse_state *sc, mouse_info_t *info);
107 static void	smpop(struct sysmouse_state *sc);
108 
109 #ifdef EVDEV_SUPPORT
110 static struct evdev_dev	*sysmouse_evdev;
111 
112 static void
113 smdev_evdev_init(void)
114 {
115 	int i;
116 
117 	sysmouse_evdev = evdev_alloc();
118 	evdev_set_name(sysmouse_evdev, "System mouse");
119 	evdev_set_phys(sysmouse_evdev, "sysmouse");
120 	evdev_set_id(sysmouse_evdev, BUS_VIRTUAL, 0, 0, 0);
121 	evdev_support_prop(sysmouse_evdev, INPUT_PROP_POINTER);
122 	evdev_support_event(sysmouse_evdev, EV_SYN);
123 	evdev_support_event(sysmouse_evdev, EV_REL);
124 	evdev_support_event(sysmouse_evdev, EV_KEY);
125 	evdev_support_rel(sysmouse_evdev, REL_X);
126 	evdev_support_rel(sysmouse_evdev, REL_Y);
127 	evdev_support_rel(sysmouse_evdev, REL_WHEEL);
128 	evdev_support_rel(sysmouse_evdev, REL_HWHEEL);
129 	for (i = 0; i < 8; i++)
130 		evdev_support_key(sysmouse_evdev, BTN_MOUSE + i);
131 	if (evdev_register(sysmouse_evdev)) {
132 		evdev_free(sysmouse_evdev);
133 		sysmouse_evdev = NULL;
134 	}
135 }
136 
137 static void
138 smdev_evdev_write(int x, int y, int z, int buttons)
139 {
140 
141 	if (sysmouse_evdev == NULL || !(evdev_rcpt_mask & EVDEV_RCPT_SYSMOUSE))
142 		return;
143 
144 	evdev_push_event(sysmouse_evdev, EV_REL, REL_X, x);
145 	evdev_push_event(sysmouse_evdev, EV_REL, REL_Y, y);
146 	switch (evdev_sysmouse_t_axis) {
147 	case EVDEV_SYSMOUSE_T_AXIS_PSM:
148 		switch (z) {
149 		case 1:
150 		case -1:
151 			evdev_push_rel(sysmouse_evdev, REL_WHEEL, -z);
152 			break;
153 		case 2:
154 		case -2:
155 			evdev_push_rel(sysmouse_evdev, REL_HWHEEL, z / 2);
156 			break;
157 		}
158 		break;
159 	case EVDEV_SYSMOUSE_T_AXIS_UMS:
160 		if (buttons & (1 << 6))
161 			evdev_push_rel(sysmouse_evdev, REL_HWHEEL, 1);
162 		else if (buttons & (1 << 5))
163 			evdev_push_rel(sysmouse_evdev, REL_HWHEEL, -1);
164 		buttons &= ~((1 << 5)|(1 << 6));
165 		/* PASSTHROUGH */
166 	case EVDEV_SYSMOUSE_T_AXIS_NONE:
167 	default:
168 		evdev_push_rel(sysmouse_evdev, REL_WHEEL, -z);
169 	}
170 	evdev_push_mouse_btn(sysmouse_evdev, buttons);
171 	evdev_sync(sysmouse_evdev);
172 }
173 #endif
174 
175 static int
176 pktlen(struct sysmouse_state *sc)
177 {
178 	if (sc->level == 0)
179 		return 5;
180 	else
181 		return 8;
182 }
183 
184 static int
185 smopen(struct dev_open_args *ap)
186 {
187 	cdev_t dev = ap->a_head.a_dev;
188 	struct sysmouse_state *sc = &mouse_state;
189 	int ret;
190 
191 	DPRINTF(5, ("smopen: dev:%d,%d\n",
192 		major(dev), minor(dev)));
193 
194 	lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
195 	if (!sc->opened) {
196 		sc->fifo = kmalloc(sizeof(struct event_fifo),
197 		    M_SYSCONS, M_WAITOK | M_ZERO);
198 		sc->opened = 1;
199 		sc->asyncio = 0;
200 		sc->sm_sigio = NULL;
201 		bzero(&sc->readstatus, sizeof(sc->readstatus));
202 		bzero(&sc->syncstatus, sizeof(sc->syncstatus));
203 		ret = 0;
204 	} else {
205 		ret = EBUSY;
206 	}
207 	lockmgr(&sc->sm_lock, LK_RELEASE);
208 
209 	return ret;
210 }
211 
212 static int
213 smclose(struct dev_close_args *ap)
214 {
215 	struct sysmouse_state *sc = &mouse_state;
216 
217 	lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
218 	funsetown(&sc->sm_sigio);
219 	sc->opened = 0;
220 	sc->asyncio = 0;
221 	sc->level = 0;
222 	kfree(sc->fifo, M_SYSCONS);
223 	sc->fifo = NULL;
224 	lockmgr(&sc->sm_lock, LK_RELEASE);
225 
226 	return 0;
227 }
228 
229 static int
230 smread(struct dev_read_args *ap)
231 {
232 	struct sysmouse_state *sc = &mouse_state;
233 	mousestatus_t backupstatus;
234 	mouse_info_t info;
235 	u_char buf[8];
236 	struct uio *uio = ap->a_uio;
237 	int error = 0, val, cnt = 0;
238 
239 	lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
240 	while (sc->fifo->fill <= 0) {
241 		/* Buffer too small to fit a complete mouse packet */
242 		if (uio->uio_resid < pktlen(sc)) {
243 			error = EIO;
244 			goto done;
245 		}
246 		if (ap->a_ioflag & IO_NDELAY) {
247 			error = EAGAIN;
248 			goto done;
249 		}
250 		error = lksleep(sc, &sc->sm_lock, PCATCH, "smread", 0);
251 		if (error == EINTR || error == ERESTART) {
252 			goto done;
253 		}
254 	}
255 
256 	do {
257 		/* Buffer too small to fit a complete mouse packet */
258 		if (uio->uio_resid < pktlen(sc)) {
259 			error = EIO;
260 			goto done;
261 		}
262 		smget(sc, &info);
263 		backupstatus = sc->readstatus;
264 		val = sysmouse_evtopkt(sc, &info, buf);
265 		if (val > 0) {
266 			error = uiomove(buf, val, uio);
267 			if (error != 0) {
268 				sc->readstatus = backupstatus;
269 				goto done;
270 			}
271 			cnt++;
272 		}
273 		smpop(sc);
274 	} while (sc->fifo->fill > 0);
275 
276 done:
277 	lockmgr(&sc->sm_lock, LK_RELEASE);
278 	if (cnt > 0 && error != EFAULT)
279 		return 0;
280 	return error;
281 }
282 
283 static int
284 smioctl(struct dev_ioctl_args *ap)
285 {
286 	struct sysmouse_state *sc = &mouse_state;
287 	mousehw_t *hw;
288 	mousemode_t *mode;
289 
290 	switch (ap->a_cmd) {
291 	case FIOSETOWN:
292 		lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
293 		fsetown(*(int *)ap->a_data, &sc->sm_sigio);
294 		lockmgr(&sc->sm_lock, LK_RELEASE);
295 		return 0;
296 	case FIOGETOWN:
297 		lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
298 		*(int *)ap->a_data = fgetown(&sc->sm_sigio);
299 		lockmgr(&sc->sm_lock, LK_RELEASE);
300 		return 0;
301 	case FIOASYNC:
302 		lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
303 		if (*(int *)ap->a_data) {
304 			sc->asyncio = 1;
305 		} else {
306 			sc->asyncio = 0;
307 		}
308 		lockmgr(&sc->sm_lock, LK_RELEASE);
309 		return 0;
310 	case MOUSE_GETHWINFO:	/* get device information */
311 		hw = (mousehw_t *)ap->a_data;
312 		hw->buttons = 10;		/* XXX unknown */
313 		hw->iftype = MOUSE_IF_SYSMOUSE;
314 		hw->type = MOUSE_MOUSE;
315 		hw->model = MOUSE_MODEL_GENERIC;
316 		hw->hwid = 0;
317 		return 0;
318 
319 	case MOUSE_GETMODE:	/* get protocol/mode */
320 		mode = (mousemode_t *)ap->a_data;
321 		lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
322 		mode->level = sc->level;
323 		lockmgr(&sc->sm_lock, LK_RELEASE);
324 		switch (mode->level) {
325 		case 0: /* emulate MouseSystems protocol */
326 			mode->protocol = MOUSE_PROTO_MSC;
327 			mode->rate = -1;		/* unknown */
328 			mode->resolution = -1;	/* unknown */
329 			mode->accelfactor = 0;	/* disabled */
330 			mode->packetsize = MOUSE_MSC_PACKETSIZE;
331 			mode->syncmask[0] = MOUSE_MSC_SYNCMASK;
332 			mode->syncmask[1] = MOUSE_MSC_SYNC;
333 			break;
334 
335 		case 1: /* sysmouse protocol */
336 			mode->protocol = MOUSE_PROTO_SYSMOUSE;
337 			mode->rate = -1;
338 			mode->resolution = -1;
339 			mode->accelfactor = 0;
340 			mode->packetsize = MOUSE_SYS_PACKETSIZE;
341 			mode->syncmask[0] = MOUSE_SYS_SYNCMASK;
342 			mode->syncmask[1] = MOUSE_SYS_SYNC;
343 			break;
344 		}
345 		return 0;
346 
347 	case MOUSE_SETMODE:	/* set protocol/mode */
348 		mode = (mousemode_t *)ap->a_data;
349 		if (mode->level == -1)
350 			; 	/* don't change the current setting */
351 		else if ((mode->level < 0) || (mode->level > 1)) {
352 			return EINVAL;
353 		} else {
354 			lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
355 			sc->level = mode->level;
356 			lockmgr(&sc->sm_lock, LK_RELEASE);
357 		}
358 		return 0;
359 
360 	case MOUSE_GETLEVEL:	/* get operation level */
361 		lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
362 		*(int *)ap->a_data = sc->level;
363 		lockmgr(&sc->sm_lock, LK_RELEASE);
364 		return 0;
365 
366 	case MOUSE_SETLEVEL:	/* set operation level */
367 		if ((*(int *)ap->a_data  < 0) || (*(int *)ap->a_data > 1)) {
368 			return EINVAL;
369 		}
370 		lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
371 		sc->level = *(int *)ap->a_data;
372 		lockmgr(&sc->sm_lock, LK_RELEASE);
373 		return 0;
374 
375 	case MOUSE_GETSTATUS:	/* get accumulated mouse events */
376 		lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
377 		*(mousestatus_t *)ap->a_data = sc->syncstatus;
378 		sc->syncstatus.flags = 0;
379 		sc->syncstatus.obutton = sc->syncstatus.button;
380 		sc->syncstatus.dx = 0;
381 		sc->syncstatus.dy = 0;
382 		sc->syncstatus.dz = 0;
383 		lockmgr(&sc->sm_lock, LK_RELEASE);
384 		return 0;
385 
386 #if 0 /* notyet */
387 	case MOUSE_GETVARS:	/* get internal mouse variables */
388 	case MOUSE_SETVARS:	/* set internal mouse variables */
389 		return ENODEV;
390 #endif
391 
392 	case MOUSE_READSTATE:	/* read status from the device */
393 	case MOUSE_READDATA:	/* read data from the device */
394 		return ENODEV;
395 	}
396 
397 	return ENOTTY;
398 }
399 
400 static struct filterops smfiltops =
401         { FILTEROP_MPSAFE | FILTEROP_ISFD, NULL, smfilter_detach, smfilter };
402 
403 static int
404 smkqfilter(struct dev_kqfilter_args *ap)
405 {
406 	struct sysmouse_state *sc = &mouse_state;
407 	struct knote *kn = ap->a_kn;
408 	struct klist *klist;
409 
410 	ap->a_result = 0;
411 
412 	switch (kn->kn_filter) {
413 	case EVFILT_READ:
414 		kn->kn_fop = &smfiltops;
415 		kn->kn_hook = (caddr_t)sc;
416 		break;
417 	default:
418 		ap->a_result = EOPNOTSUPP;
419 		return (0);
420 	}
421 
422 	klist = &sc->rkq.ki_note;
423 	knote_insert(klist, kn);
424 
425 	return (0);
426 }
427 
428 static void
429 smfilter_detach(struct knote *kn)
430 {
431 	struct sysmouse_state *sc = &mouse_state;
432 	struct klist *klist;
433 
434 	klist = &sc->rkq.ki_note;
435 	knote_remove(klist, kn);
436 }
437 
438 static int
439 smfilter(struct knote *kn, long hint)
440 {
441 	struct sysmouse_state *sc = &mouse_state;
442 	int ready = 0;
443 
444 	lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
445 	if (sc->fifo->fill > 0) {
446 		ready = 1;
447 		kn->kn_data = 0;
448 	}
449 	lockmgr(&sc->sm_lock, LK_RELEASE);
450 
451 	return ready;
452 }
453 
454 static void
455 smqueue(struct sysmouse_state *sc, mouse_info_t *info)
456 {
457 	struct event_fifo *f = sc->fifo;
458 
459 	if (f->fill >= FIFO_SIZE) {
460 		f->fill = FIFO_SIZE;
461 		f->buf[f->start] = *info;
462 		f->start = (f->start + 1) % FIFO_SIZE;
463 		f->dropped++;
464 	} else {
465 		f->buf[(f->start + f->fill) % FIFO_SIZE] = *info;
466 		f->fill++;
467 	}
468 
469 }
470 
471 static void
472 smget(struct sysmouse_state *sc, mouse_info_t *info)
473 {
474 	struct event_fifo *f = sc->fifo;
475 
476 	if (f->fill > 0)
477 		*info = f->buf[f->start];
478 }
479 
480 static void
481 smpop(struct sysmouse_state *sc)
482 {
483 	struct event_fifo *f = sc->fifo;
484 
485 	if (f->fill > 0) {
486 		f->fill--;
487 		f->start = (f->start + 1) % FIFO_SIZE;
488 	}
489 }
490 
491 static void
492 sm_attach_mouse(void *unused)
493 {
494 	struct sysmouse_state *sc = &mouse_state;
495 	cdev_t dev;
496 
497 	lockinit(&mouse_state.sm_lock, "sysmouse", 0, LK_CANRECURSE);
498 	sc->fifo = NULL;
499 
500 	dev = make_dev(&sm_ops, 0, UID_ROOT, GID_WHEEL, 0600, "sysmouse");
501 #ifdef EVDEV_SUPPORT
502 	smdev_evdev_init();
503 #endif
504 }
505 
506 SYSINIT(sysmouse, SI_SUB_DRIVERS, SI_ORDER_ANY, sm_attach_mouse, NULL);
507 
508 static int
509 sysmouse_updatestatus(mousestatus_t *status, mouse_info_t *info)
510 {
511 	int x, y, z;
512 
513 	status->obutton = status->button;
514 
515 	switch (info->operation) {
516 	case MOUSE_ACTION:
517 		status->button = info->u.data.buttons;
518 		/* FALL THROUGH */
519 	case MOUSE_MOTION_EVENT:
520 		x = info->u.data.x;
521 		y = info->u.data.y;
522 		z = info->u.data.z;
523 		break;
524 	case MOUSE_BUTTON_EVENT:
525 		x = y = z = 0;
526 		if (info->u.event.value > 0)
527 			status->button |= info->u.event.id;
528 		else
529 			status->button &= ~info->u.event.id;
530 		break;
531 	default:
532 		return 0;
533 	}
534 
535 	status->dx += x;
536 	status->dy += y;
537 	status->dz += z;
538 	status->flags |= ((x || y || z) ? MOUSE_POSCHANGED : 0)
539 			 | (status->obutton ^ status->button);
540 
541 #ifdef EVDEV_SUPPORT
542 	smdev_evdev_write(x, y, z, status->button);
543 #endif
544 
545 	return 1;
546 }
547 
548 /* Requires buf to hold at least 8 bytes, returns number of bytes written */
549 static int
550 sysmouse_evtopkt(struct sysmouse_state *sc, mouse_info_t *info, u_char *buf)
551 {
552 	/* MOUSE_BUTTON?DOWN -> MOUSE_MSC_BUTTON?UP */
553 	static int butmap[8] = {
554 	    MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
555 	    MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
556 	    MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
557 	    MOUSE_MSC_BUTTON3UP,
558 	    MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
559 	    MOUSE_MSC_BUTTON2UP,
560 	    MOUSE_MSC_BUTTON1UP,
561 	    0,
562 	};
563 	int x, y, z;
564 
565 	sc->readstatus.dx = 0;
566 	sc->readstatus.dy = 0;
567 	sc->readstatus.dz = 0;
568 	sc->readstatus.flags = 0;
569 	if (sysmouse_updatestatus(&sc->readstatus, info) == 0)
570 		return 0;
571 
572 	/* We aren't using the sc->readstatus.dx/dy/dz values */
573 
574 	if (sc->readstatus.flags == 0)
575 		return 0;
576 
577 	x = (info->operation == MOUSE_BUTTON_EVENT ? 0 : info->u.data.x);
578 	y = (info->operation == MOUSE_BUTTON_EVENT ? 0 : info->u.data.y);
579 	z = (info->operation == MOUSE_BUTTON_EVENT ? 0 : info->u.data.z);
580 
581 	/* the first five bytes are compatible with MouseSystems' */
582 	buf[0] = MOUSE_MSC_SYNC
583 		 | butmap[sc->readstatus.button & MOUSE_STDBUTTONS];
584 	x = imax(imin(x, 255), -256);
585 	buf[1] = x >> 1;
586 	buf[3] = x - buf[1];
587 	y = -imax(imin(y, 255), -256);
588 	buf[2] = y >> 1;
589 	buf[4] = y - buf[2];
590 	if (sc->level >= 1) {
591 		/* extended part */
592 		z = imax(imin(z, 127), -128);
593         	buf[5] = (z >> 1) & 0x7f;
594         	buf[6] = (z - (z >> 1)) & 0x7f;
595 		/* buttons 4-10 */
596 		buf[7] = (~sc->readstatus.button >> 3) & 0x7f;
597 	}
598 
599 	if (sc->level >= 1)
600 		return 8;
601 
602 	return 5;
603 }
604 
605 int
606 sysmouse_event(mouse_info_t *info)
607 {
608 	struct sysmouse_state *sc = &mouse_state;
609 	int ret;
610 
611 	lockmgr(&sc->sm_lock, LK_EXCLUSIVE);
612 	ret = sysmouse_updatestatus(&sc->syncstatus, info);
613 	if (ret != 0)
614 		ret = sc->syncstatus.flags;
615 	if (!sc->opened) {
616 		lockmgr(&sc->sm_lock, LK_RELEASE);
617 		return ret;
618 	}
619 
620 	switch (info->operation) {
621 	case MOUSE_ACTION:
622 	case MOUSE_MOTION_EVENT:
623 	case MOUSE_BUTTON_EVENT:
624 		smqueue(sc, info);
625 		if (sc->asyncio)
626 	                pgsigio(sc->sm_sigio, SIGIO, 0);
627 		lockmgr(&sc->sm_lock, LK_RELEASE);
628 		wakeup(sc);
629 		KNOTE(&sc->rkq.ki_note, 0);
630 		break;
631 	default:
632 		lockmgr(&sc->sm_lock, LK_RELEASE);
633 		break;
634 	}
635 
636 	return ret;
637 }
638 
639 #endif /* !SC_NO_SYSMOUSE */
640