netinet{,6}: Assert in{,6}_inithead() are only used for system routing tables.
[dragonfly.git] / sys / dev / misc / syscons / scmouse.c
1 /*-
2  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer as
10  *    the first lines of this file unmodified.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * $FreeBSD: src/sys/dev/syscons/scmouse.c,v 1.12.2.3 2001/07/28 12:51:47 yokota Exp $
27  */
28
29 #include "opt_syscons.h"
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/conf.h>
35 #include <sys/signalvar.h>
36 #include <sys/proc.h>
37 #include <sys/tty.h>
38 #include <sys/thread2.h>
39 #include <sys/mplock2.h>
40
41 #include <machine/console.h>
42 #include <sys/mouse.h>
43
44 #include "syscons.h"
45
46 #ifdef SC_TWOBUTTON_MOUSE
47 #define SC_MOUSE_PASTEBUTTON    MOUSE_BUTTON3DOWN       /* right button */
48 #define SC_MOUSE_EXTENDBUTTON   MOUSE_BUTTON2DOWN       /* not really used */
49 #else
50 #define SC_MOUSE_PASTEBUTTON    MOUSE_BUTTON2DOWN       /* middle button */
51 #define SC_MOUSE_EXTENDBUTTON   MOUSE_BUTTON3DOWN       /* right button */
52 #endif /* SC_TWOBUTTON_MOUSE */
53
54 #define SC_WAKEUP_DELTA         20
55
56 #ifndef SC_NO_SYSMOUSE
57
58 static int              cut_buffer_size;
59 static u_char           *cut_buffer;
60
61 /* local functions */
62 static void sc_mouse_init(void *);
63 static void sc_mouse_uninit(void *);
64
65 static void set_mouse_pos(scr_stat *scp);
66 #ifndef SC_NO_CUTPASTE
67 static int skip_spc_right(scr_stat *scp, int p);
68 static int skip_spc_left(scr_stat *scp, int p);
69 static void mouse_cut(scr_stat *scp);
70 static void mouse_cut_start(scr_stat *scp);
71 static void mouse_cut_end(scr_stat *scp);
72 static void mouse_cut_word(scr_stat *scp);
73 static void mouse_cut_line(scr_stat *scp);
74 static void mouse_cut_extend(scr_stat *scp);
75 static void mouse_paste(scr_stat *scp);
76 #endif /* SC_NO_CUTPASTE */
77
78 #ifndef SC_NO_CUTPASTE
79 /* allocate a cut buffer */
80 void
81 sc_alloc_cut_buffer(scr_stat *scp, int wait)
82 {
83     u_char *p;
84
85     if ((cut_buffer == NULL)
86         || (cut_buffer_size < scp->xsize * scp->ysize + 1)) {
87         p = cut_buffer;
88         cut_buffer = NULL;
89         if (p != NULL)
90             kfree(p, M_SYSCONS);
91         cut_buffer_size = scp->xsize * scp->ysize + 1;
92         p = kmalloc(cut_buffer_size, M_SYSCONS, (wait) ? M_WAITOK : M_NOWAIT);
93         if (p != NULL)
94             p[0] = '\0';
95         cut_buffer = p;
96     }
97 }
98 #endif /* SC_NO_CUTPASTE */
99
100 /* move mouse */
101 void
102 sc_mouse_move(scr_stat *scp, int x, int y)
103 {
104     crit_enter();
105     scp->mouse_xpos = scp->mouse_oldxpos = x;
106     scp->mouse_ypos = scp->mouse_oldypos = y;
107     if (scp->font_height <= 0)
108         scp->mouse_pos = scp->mouse_oldpos = 0;
109     else
110         scp->mouse_pos = scp->mouse_oldpos = 
111             (y / scp->font_height - scp->yoff) * scp->xsize +
112             x / scp->font_width - scp->xoff;
113     scp->status |= MOUSE_MOVED;
114     crit_exit();
115 }
116
117 /* adjust mouse position */
118 static void
119 set_mouse_pos(scr_stat *scp)
120 {
121     if (scp->mouse_xpos < scp->xoff * scp->font_width)
122         scp->mouse_xpos = scp->xoff * scp->font_width;
123     if (scp->mouse_ypos < scp->yoff * scp->font_height)
124         scp->mouse_ypos = scp->yoff * scp->font_height;
125     if (ISGRAPHSC(scp)) {
126         if (scp->mouse_xpos > scp->xpixel - 1)
127             scp->mouse_xpos = scp->xpixel - 1;
128         if (scp->mouse_ypos > scp->ypixel - 1)
129             scp->mouse_ypos = scp->ypixel - 1;
130         return;
131     } else {
132         if (scp->mouse_xpos > (scp->xsize + scp->xoff) * scp->font_width - 1)
133             scp->mouse_xpos = (scp->xsize + scp->xoff) * scp->font_width - 1;
134         if (scp->mouse_ypos > (scp->ysize + scp->yoff) * scp->font_height - 1)
135             scp->mouse_ypos = (scp->ysize + scp->yoff) * scp->font_height - 1;
136     }
137
138     if (scp->mouse_xpos != scp->mouse_oldxpos ||
139         scp->mouse_ypos != scp->mouse_oldypos) {
140         scp->status |= MOUSE_MOVED;
141         scp->mouse_pos =
142             (scp->mouse_ypos / scp->font_height - scp->yoff) * scp->xsize +
143             scp->mouse_xpos / scp->font_width - scp->xoff;
144 #ifndef SC_NO_CUTPASTE
145         if ((scp->status & MOUSE_VISIBLE) && (scp->status & MOUSE_CUTTING))
146             mouse_cut(scp);
147 #endif
148     }
149 }
150
151 #ifndef SC_NO_CUTPASTE
152
153 void
154 sc_draw_mouse_image(scr_stat *scp)
155 {
156     if (ISGRAPHSC(scp))
157         return;
158
159     atomic_add_int(&scp->sc->videoio_in_progress, 1);
160     (*scp->rndr->draw_mouse)(scp, scp->mouse_xpos, scp->mouse_ypos, TRUE);
161     scp->mouse_oldpos = scp->mouse_pos;
162     scp->mouse_oldxpos = scp->mouse_xpos;
163     scp->mouse_oldypos = scp->mouse_ypos;
164     scp->status |= MOUSE_VISIBLE;
165     atomic_add_int(&scp->sc->videoio_in_progress, -1);
166 }
167
168 void
169 sc_remove_mouse_image(scr_stat *scp)
170 {
171     int size;
172     int i;
173
174     if (ISGRAPHSC(scp))
175         return;
176
177     atomic_add_int(&scp->sc->videoio_in_progress, 1);
178     (*scp->rndr->draw_mouse)(scp,
179                              (scp->mouse_oldpos%scp->xsize + scp->xoff) *
180                               scp->font_width,
181                              (scp->mouse_oldpos/scp->xsize + scp->yoff) *
182                               scp->font_height,
183                              FALSE);
184     size = scp->xsize * scp->ysize;
185     i = scp->mouse_oldpos;
186     mark_for_update(scp, i);
187     mark_for_update(scp, i);
188     if (i + scp->xsize + 1 < size) {
189         mark_for_update(scp, i + scp->xsize + 1);
190     } else if (i + scp->xsize < size) {
191         mark_for_update(scp, i + scp->xsize);
192     } else if (i + 1 < size) {
193         mark_for_update(scp, i + 1);
194     }
195     scp->status &= ~MOUSE_VISIBLE;
196     atomic_add_int(&scp->sc->videoio_in_progress, -1);
197 }
198
199 int
200 sc_inside_cutmark(scr_stat *scp, int pos)
201 {
202     int start;
203     int end;
204
205     if (scp->mouse_cut_end < 0)
206         return FALSE;
207     if (scp->mouse_cut_start <= scp->mouse_cut_end) {
208         start = scp->mouse_cut_start;
209         end = scp->mouse_cut_end;
210     } else {
211         start = scp->mouse_cut_end;
212         end = scp->mouse_cut_start - 1;
213     }
214     return ((start <= pos) && (pos <= end));
215 }
216
217 void
218 sc_remove_cutmarking(scr_stat *scp)
219 {
220     crit_enter();
221     if (scp->mouse_cut_end >= 0) {
222         mark_for_update(scp, scp->mouse_cut_start);
223         mark_for_update(scp, scp->mouse_cut_end);
224     }
225     scp->mouse_cut_start = scp->xsize*scp->ysize;
226     scp->mouse_cut_end = -1;
227     crit_exit();
228     scp->status &= ~MOUSE_CUTTING;
229 }
230
231 void
232 sc_remove_all_cutmarkings(sc_softc_t *sc)
233 {
234     scr_stat *scp;
235     int i;
236
237     /* delete cut markings in all vtys */
238     for (i = 0; i < sc->vtys; ++i) {
239         scp = SC_STAT(sc->dev[i]);
240         if (scp == NULL)
241             continue;
242         sc_remove_cutmarking(scp);
243     }
244 }
245
246 void
247 sc_remove_all_mouse(sc_softc_t *sc)
248 {
249     scr_stat *scp;
250     int i;
251
252     for (i = 0; i < sc->vtys; ++i) {
253         scp = SC_STAT(sc->dev[i]);
254         if (scp == NULL)
255             continue;
256         if (scp->status & MOUSE_VISIBLE) {
257             scp->status &= ~MOUSE_VISIBLE;
258             mark_all(scp);
259         }
260     }
261 }
262
263 #define IS_SPACE_CHAR(c)        (((c) & 0xff) == ' ')
264
265 /* skip spaces to right */
266 static int
267 skip_spc_right(scr_stat *scp, int p)
268 {
269     int c;
270     int i;
271
272     for (i = p % scp->xsize; i < scp->xsize; ++i) {
273         c = sc_vtb_getc(&scp->vtb, p);
274         if (!IS_SPACE_CHAR(c))
275             break;
276         ++p;
277     }
278     return i;
279 }
280
281 /* skip spaces to left */
282 static int
283 skip_spc_left(scr_stat *scp, int p)
284 {
285     int c;
286     int i;
287
288     for (i = p-- % scp->xsize - 1; i >= 0; --i) {
289         c = sc_vtb_getc(&scp->vtb, p);
290         if (!IS_SPACE_CHAR(c))
291             break;
292         --p;
293     }
294     return i;
295 }
296
297 /* copy marked region to the cut buffer */
298 static void
299 mouse_cut(scr_stat *scp)
300 {
301     int start;
302     int end;
303     int from;
304     int to;
305     int blank;
306     int c;
307     int p;
308     int i;
309
310     start = scp->mouse_cut_start;
311     if (scp->mouse_pos >= start) {
312         from = start;
313         to = end = scp->mouse_pos;
314     } else {
315         from = end = scp->mouse_pos;
316         to = start - 1;
317     }
318     for (p = from, i = blank = 0; p <= to; ++p) {
319         cut_buffer[i] = sc_vtb_getc(&scp->vtb, p);
320         /* remember the position of the last non-space char */
321         if (!IS_SPACE_CHAR(cut_buffer[i++]))
322             blank = i;          /* the first space after the last non-space */
323         /* trim trailing blank when crossing lines */
324         if ((p % scp->xsize) == (scp->xsize - 1)) {
325             cut_buffer[blank] = '\r';
326             i = blank + 1;
327         }
328     }
329     cut_buffer[i] = '\0';
330
331     /* scan towards the end of the last line */
332     --p;
333     for (i = p % scp->xsize; i < scp->xsize; ++i) {
334         c = sc_vtb_getc(&scp->vtb, p);
335         if (!IS_SPACE_CHAR(c))
336             break;
337         ++p;
338     }
339     /* if there is nothing but blank chars, trim them, but mark towards eol */
340     if (i >= scp->xsize) {
341         if (end >= start)
342             to = end = p - 1;
343         else
344             to = start = p;
345         cut_buffer[blank++] = '\r';
346         cut_buffer[blank] = '\0';
347     }
348
349     /* remove the current marking */
350     crit_enter();
351     if (scp->mouse_cut_start <= scp->mouse_cut_end) {
352         mark_for_update(scp, scp->mouse_cut_start);
353         mark_for_update(scp, scp->mouse_cut_end);
354     } else if (scp->mouse_cut_end >= 0) {
355         mark_for_update(scp, scp->mouse_cut_end);
356         mark_for_update(scp, scp->mouse_cut_start);
357     }
358
359     /* mark the new region */
360     scp->mouse_cut_start = start;
361     scp->mouse_cut_end = end;
362     mark_for_update(scp, from);
363     mark_for_update(scp, to);
364     crit_exit();
365 }
366
367 /* a mouse button is pressed, start cut operation */
368 static void
369 mouse_cut_start(scr_stat *scp) 
370 {
371     int i;
372     int j;
373
374     if (scp->status & MOUSE_VISIBLE) {
375         i = scp->mouse_cut_start;
376         j = scp->mouse_cut_end;
377         sc_remove_all_cutmarkings(scp->sc);
378         if (scp->mouse_pos == i && i == j) {
379             cut_buffer[0] = '\0';
380         } else if (skip_spc_right(scp, scp->mouse_pos) >= scp->xsize) {
381             /* if the pointer is on trailing blank chars, mark towards eol */
382             i = skip_spc_left(scp, scp->mouse_pos) + 1;
383             crit_enter();
384             scp->mouse_cut_start =
385                 (scp->mouse_pos / scp->xsize) * scp->xsize + i;
386             scp->mouse_cut_end =
387                 (scp->mouse_pos / scp->xsize + 1) * scp->xsize - 1;
388             crit_exit();
389             cut_buffer[0] = '\r';
390             cut_buffer[1] = '\0';
391             scp->status |= MOUSE_CUTTING;
392         } else {
393             crit_enter();
394             scp->mouse_cut_start = scp->mouse_pos;
395             scp->mouse_cut_end = scp->mouse_cut_start;
396             crit_exit();
397             cut_buffer[0] = sc_vtb_getc(&scp->vtb, scp->mouse_cut_start);
398             cut_buffer[1] = '\0';
399             scp->status |= MOUSE_CUTTING;
400         }
401         mark_all(scp);  /* this is probably overkill XXX */
402     }
403 }
404
405 /* end of cut operation */
406 static void
407 mouse_cut_end(scr_stat *scp) 
408 {
409     if (scp->status & MOUSE_VISIBLE)
410         scp->status &= ~MOUSE_CUTTING;
411 }
412
413 /* copy a word under the mouse pointer */
414 static void
415 mouse_cut_word(scr_stat *scp)
416 {
417     int start;
418     int end;
419     int sol;
420     int eol;
421     int c;
422     int i;
423     int j;
424
425     /*
426      * Because we don't have locale information in the kernel,
427      * we only distinguish space char and non-space chars.  Punctuation
428      * chars, symbols and other regular chars are all treated alike.
429      */
430     if (scp->status & MOUSE_VISIBLE) {
431         /* remove the current cut mark */
432         crit_enter();
433         if (scp->mouse_cut_start <= scp->mouse_cut_end) {
434             mark_for_update(scp, scp->mouse_cut_start);
435             mark_for_update(scp, scp->mouse_cut_end);
436         } else if (scp->mouse_cut_end >= 0) {
437             mark_for_update(scp, scp->mouse_cut_end);
438             mark_for_update(scp, scp->mouse_cut_start);
439         }
440         scp->mouse_cut_start = scp->xsize*scp->ysize;
441         scp->mouse_cut_end = -1;
442         crit_exit();
443
444         sol = (scp->mouse_pos / scp->xsize) * scp->xsize;
445         eol = sol + scp->xsize;
446         c = sc_vtb_getc(&scp->vtb, scp->mouse_pos);
447         if (IS_SPACE_CHAR(c)) {
448             /* blank space */
449             for (j = scp->mouse_pos; j >= sol; --j) {
450                 c = sc_vtb_getc(&scp->vtb, j);
451                 if (!IS_SPACE_CHAR(c))
452                     break;
453             }
454             start = ++j;
455             for (j = scp->mouse_pos; j < eol; ++j) {
456                 c = sc_vtb_getc(&scp->vtb, j);
457                 if (!IS_SPACE_CHAR(c))
458                     break;
459             }
460             end = j - 1;
461         } else {
462             /* non-space word */
463             for (j = scp->mouse_pos; j >= sol; --j) {
464                 c = sc_vtb_getc(&scp->vtb, j);
465                 if (IS_SPACE_CHAR(c))
466                     break;
467             }
468             start = ++j;
469             for (j = scp->mouse_pos; j < eol; ++j) {
470                 c = sc_vtb_getc(&scp->vtb, j);
471                 if (IS_SPACE_CHAR(c))
472                     break;
473             }
474             end = j - 1;
475         }
476
477         /* copy the found word */
478         for (i = 0, j = start; j <= end; ++j)
479             cut_buffer[i++] = sc_vtb_getc(&scp->vtb, j);
480         cut_buffer[i] = '\0';
481         scp->status |= MOUSE_CUTTING;
482
483         /* mark the region */
484         crit_enter();
485         scp->mouse_cut_start = start;
486         scp->mouse_cut_end = end;
487         mark_for_update(scp, start);
488         mark_for_update(scp, end);
489         crit_exit();
490     }
491 }
492
493 /* copy a line under the mouse pointer */
494 static void
495 mouse_cut_line(scr_stat *scp)
496 {
497     int i;
498     int j;
499
500     if (scp->status & MOUSE_VISIBLE) {
501         /* remove the current cut mark */
502         crit_enter();
503         if (scp->mouse_cut_start <= scp->mouse_cut_end) {
504             mark_for_update(scp, scp->mouse_cut_start);
505             mark_for_update(scp, scp->mouse_cut_end);
506         } else if (scp->mouse_cut_end >= 0) {
507             mark_for_update(scp, scp->mouse_cut_end);
508             mark_for_update(scp, scp->mouse_cut_start);
509         }
510
511         /* mark the entire line */
512         scp->mouse_cut_start =
513             (scp->mouse_pos / scp->xsize) * scp->xsize;
514         scp->mouse_cut_end = scp->mouse_cut_start + scp->xsize - 1;
515         mark_for_update(scp, scp->mouse_cut_start);
516         mark_for_update(scp, scp->mouse_cut_end);
517         crit_exit();
518
519         /* copy the line into the cut buffer */
520         for (i = 0, j = scp->mouse_cut_start; j <= scp->mouse_cut_end; ++j)
521             cut_buffer[i++] = sc_vtb_getc(&scp->vtb, j);
522         cut_buffer[i++] = '\r';
523         cut_buffer[i] = '\0';
524         scp->status |= MOUSE_CUTTING;
525     }
526 }
527
528 /* extend the marked region to the mouse pointer position */
529 static void
530 mouse_cut_extend(scr_stat *scp) 
531 {
532     int start;
533     int end;
534
535     if ((scp->status & MOUSE_VISIBLE) && !(scp->status & MOUSE_CUTTING)
536         && (scp->mouse_cut_end >= 0)) {
537         if (scp->mouse_cut_start <= scp->mouse_cut_end) {
538             start = scp->mouse_cut_start;
539             end = scp->mouse_cut_end;
540         } else {
541             start = scp->mouse_cut_end;
542             end = scp->mouse_cut_start - 1;
543         }
544         crit_enter();
545         if (scp->mouse_pos > end) {
546             scp->mouse_cut_start = start;
547             scp->mouse_cut_end = end;
548         } else if (scp->mouse_pos < start) {
549             scp->mouse_cut_start = end + 1;
550             scp->mouse_cut_end = start;
551         } else {
552             if (scp->mouse_pos - start > end + 1 - scp->mouse_pos) {
553                 scp->mouse_cut_start = start;
554                 scp->mouse_cut_end = end;
555             } else {
556                 scp->mouse_cut_start = end + 1;
557                 scp->mouse_cut_end = start;
558             }
559         }
560         crit_exit();
561         mouse_cut(scp);
562         scp->status |= MOUSE_CUTTING;
563     }
564 }
565
566 /* paste cut buffer contents into the current vty */
567 static void
568 mouse_paste(scr_stat *scp) 
569 {
570     if (scp->status & MOUSE_VISIBLE)
571         sc_paste(scp, cut_buffer, strlen(cut_buffer));
572 }
573
574 #endif /* SC_NO_CUTPASTE */
575
576 static void
577 sc_mouse_exit1_proc(struct proc *p)
578 {
579     scr_stat *scp;
580
581     scp = p->p_drv_priv;
582     KKASSERT(scp != NULL);
583
584     get_mplock();
585     KKASSERT(scp->mouse_proc == p);
586     KKASSERT(scp->mouse_pid == p->p_pid);
587
588     scp->mouse_signal = 0;
589     scp->mouse_proc = NULL;
590     scp->mouse_pid = 0;
591     rel_mplock();
592
593     PRELE(p);
594     p->p_flags &= ~P_SCMOUSE;
595     p->p_drv_priv = NULL;
596 }
597
598 /*
599  * sc_mouse_exit1:
600  *
601  *      Handle exit1 for processes registered as MOUSE_MODE handlers.
602  *      We must remove a process hold, established when MOUSE_MODE
603  *      was enabled.
604  */
605 static void
606 sc_mouse_exit1(struct thread *td)
607 {
608     struct proc *p;
609
610     p = td->td_proc;
611     KKASSERT(p != NULL);
612
613     if ((p->p_flags & P_SCMOUSE) == 0)
614         return;
615
616
617     sc_mouse_exit1_proc(p);
618 }
619
620 int
621 sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, int flag)
622 {
623     mouse_info_t *mouse;
624     scr_stat *cur_scp;
625     scr_stat *scp;
626     int f;
627
628     scp = SC_STAT(tp->t_dev);
629
630     switch (cmd) {
631
632     case CONS_MOUSECTL:         /* control mouse arrow */
633         mouse = (mouse_info_t*) data;
634         cur_scp = scp->sc->cur_scp;
635
636         switch (mouse->operation) {
637         /*
638          * Setup a process to receive signals on mouse events.
639          */
640         case MOUSE_MODE:
641             get_mplock();
642
643             if (!ISSIGVALID(mouse->u.mode.signal)) {
644                 /* Setting MOUSE_MODE w/ an invalid signal is used to disarm */
645                 if (scp->mouse_proc == curproc) {
646                     sc_mouse_exit1_proc(curproc);
647                     rel_mplock();
648                     return 0;
649                 } else {
650                     rel_mplock();
651                     return EINVAL;
652                 }
653             } else {
654                 /* Only one mouse process per syscons */
655                 if (scp->mouse_proc) {
656                     rel_mplock();
657                     return EINVAL;
658                 }
659
660                 /* Only one syscons signal source per process */
661                 if (curproc->p_flags & P_SCMOUSE) {
662                     rel_mplock();
663                     return EINVAL;
664                 }
665
666                 /*
667                  * Process is stabilized by a hold, which is removed from
668                  * sc_mouse_exit1. scp's mouse_{signal,proc,pid} fields
669                  * are synchronized by the MP Lock.
670                  */
671                 scp->mouse_signal = mouse->u.mode.signal;
672                 scp->mouse_proc = curproc;
673                 scp->mouse_pid = curproc->p_pid;
674                 curproc->p_flags |= P_SCMOUSE;
675                 KKASSERT(curproc->p_drv_priv == NULL);
676                 curproc->p_drv_priv = scp;
677                 PHOLD(curproc);
678
679                 rel_mplock();
680                 return 0;
681             }
682             /*NOTREACHED*/
683             break;
684
685         case MOUSE_SHOW:
686             crit_enter();
687             if (!(scp->sc->flags & SC_MOUSE_ENABLED)) {
688                 scp->sc->flags |= SC_MOUSE_ENABLED;
689                 cur_scp->status &= ~MOUSE_HIDDEN;
690                 if (!ISGRAPHSC(cur_scp))
691                     mark_all(cur_scp);
692                 crit_exit();
693                 return 0;
694             } else {
695                 crit_exit();
696                 return EINVAL;
697             }
698             break;
699
700         case MOUSE_HIDE:
701             crit_enter();
702             if (scp->sc->flags & SC_MOUSE_ENABLED) {
703                 scp->sc->flags &= ~SC_MOUSE_ENABLED;
704                 sc_remove_all_mouse(scp->sc);
705                 crit_exit();
706                 return 0;
707             } else {
708                 crit_exit();
709                 return EINVAL;
710             }
711             break;
712
713         case MOUSE_MOVEABS:
714             crit_enter();
715             scp->mouse_xpos = mouse->u.data.x;
716             scp->mouse_ypos = mouse->u.data.y;
717             set_mouse_pos(scp);
718             crit_exit();
719             break;
720
721         case MOUSE_MOVEREL:
722             crit_enter();
723             scp->mouse_xpos += mouse->u.data.x;
724             scp->mouse_ypos += mouse->u.data.y;
725             set_mouse_pos(scp);
726             crit_exit();
727             break;
728
729         case MOUSE_GETINFO:
730             mouse->u.data.x = scp->mouse_xpos;
731             mouse->u.data.y = scp->mouse_ypos;
732             mouse->u.data.z = 0;
733             mouse->u.data.buttons = scp->mouse_buttons;
734             return 0;
735
736         case MOUSE_ACTION:
737         case MOUSE_MOTION_EVENT:
738             /* send out mouse event on /dev/sysmouse */
739 #if 0
740             /* this should maybe only be settable from /dev/consolectl SOS */
741             if (SC_VTY(tp->t_dev) != SC_CONSOLECTL)
742                 return ENOTTY;
743 #endif
744             crit_enter();
745             if (mouse->u.data.x != 0 || mouse->u.data.y != 0) {
746                 cur_scp->mouse_xpos += mouse->u.data.x;
747                 cur_scp->mouse_ypos += mouse->u.data.y;
748                 set_mouse_pos(cur_scp);
749             }
750             f = 0;
751             if (mouse->operation == MOUSE_ACTION) {
752                 f = cur_scp->mouse_buttons ^ mouse->u.data.buttons;
753                 cur_scp->mouse_buttons = mouse->u.data.buttons;
754             }
755             crit_exit();
756
757             if (sysmouse_event(mouse) == 0)
758                 return 0;
759
760             /* 
761              * If any buttons are down or the mouse has moved a lot, 
762              * stop the screen saver.
763              */
764             if (((mouse->operation == MOUSE_ACTION) && mouse->u.data.buttons)
765                 || (mouse->u.data.x*mouse->u.data.x
766                         + mouse->u.data.y*mouse->u.data.y
767                         >= SC_WAKEUP_DELTA*SC_WAKEUP_DELTA)) {
768                 sc_touch_scrn_saver();
769             }
770
771             cur_scp->status &= ~MOUSE_HIDDEN;
772
773             get_mplock();
774             if (cur_scp->mouse_signal) {
775                 KKASSERT(cur_scp->mouse_proc != NULL);
776                 ksignal(cur_scp->mouse_proc, cur_scp->mouse_signal);
777                 rel_mplock();
778                 break;
779             }
780             rel_mplock();
781
782             if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL))
783                 break;
784
785 #ifndef SC_NO_CUTPASTE
786             if ((mouse->operation == MOUSE_ACTION) && f) {
787                 /* process button presses */
788                 if (cur_scp->mouse_buttons & MOUSE_BUTTON1DOWN)
789                     mouse_cut_start(cur_scp);
790                 else
791                     mouse_cut_end(cur_scp);
792                 if (cur_scp->mouse_buttons & MOUSE_BUTTON2DOWN ||
793                     cur_scp->mouse_buttons & MOUSE_BUTTON3DOWN)
794                     mouse_paste(cur_scp);
795             }
796 #endif /* SC_NO_CUTPASTE */
797             break;
798
799         case MOUSE_BUTTON_EVENT:
800             if ((mouse->u.event.id & MOUSE_BUTTONS) == 0)
801                 return EINVAL;
802             if (mouse->u.event.value < 0)
803                 return EINVAL;
804 #if 0
805             /* this should maybe only be settable from /dev/consolectl SOS */
806             if (SC_VTY(tp->t_dev) != SC_CONSOLECTL)
807                 return ENOTTY;
808 #endif
809             if (mouse->u.event.value > 0)
810                 cur_scp->mouse_buttons |= mouse->u.event.id;
811             else
812                 cur_scp->mouse_buttons &= ~mouse->u.event.id;
813
814             if (sysmouse_event(mouse) == 0)
815                 return 0;
816
817             /* if a button is held down, stop the screen saver */
818             if (mouse->u.event.value > 0)
819                 sc_touch_scrn_saver();
820
821             cur_scp->status &= ~MOUSE_HIDDEN;
822
823             get_mplock();
824             if (cur_scp->mouse_signal) {
825                 KKASSERT(cur_scp->mouse_proc != NULL);
826                 ksignal(cur_scp->mouse_proc, cur_scp->mouse_signal);
827                 rel_mplock();
828                 break;
829             }
830             rel_mplock();
831
832             if (ISGRAPHSC(cur_scp) || (cut_buffer == NULL))
833                 break;
834
835 #ifndef SC_NO_CUTPASTE
836             switch (mouse->u.event.id) {
837             case MOUSE_BUTTON1DOWN:
838                 switch (mouse->u.event.value % 4) {
839                 case 0: /* up */
840                     mouse_cut_end(cur_scp);
841                     break;
842                 case 1: /* single click: start cut operation */
843                     mouse_cut_start(cur_scp);
844                     break;
845                 case 2: /* double click: cut a word */
846                     mouse_cut_word(cur_scp);
847                     mouse_cut_end(cur_scp);
848                     break;
849                 case 3: /* triple click: cut a line */
850                     mouse_cut_line(cur_scp);
851                     mouse_cut_end(cur_scp);
852                     break;
853                 }
854                 break;
855             case SC_MOUSE_PASTEBUTTON:
856                 switch (mouse->u.event.value) {
857                 case 0: /* up */
858                     break;
859                 default:
860                     mouse_paste(cur_scp);
861                     break;
862                 }
863                 break;
864             case SC_MOUSE_EXTENDBUTTON:
865                 switch (mouse->u.event.value) {
866                 case 0: /* up */
867                     if (!(cur_scp->mouse_buttons & MOUSE_BUTTON1DOWN))
868                         mouse_cut_end(cur_scp);
869                     break;
870                 default:
871                     mouse_cut_extend(cur_scp);
872                     break;
873                 }
874                 break;
875             }
876 #endif /* SC_NO_CUTPASTE */
877             break;
878
879         case MOUSE_MOUSECHAR:
880             if (mouse->u.mouse_char < 0) {
881                 mouse->u.mouse_char = scp->sc->mouse_char;
882             } else {
883                 if (mouse->u.mouse_char >= (unsigned char)-1 - 4)
884                     return EINVAL;
885                 crit_enter();
886                 sc_remove_all_mouse(scp->sc);
887 #ifndef SC_NO_FONT_LOADING
888                 if (ISTEXTSC(cur_scp) && (cur_scp->font != NULL))
889                     sc_load_font(cur_scp, 0, cur_scp->font_height,
890                                  cur_scp->font,
891                                  cur_scp->sc->mouse_char, 4);
892 #endif
893                 scp->sc->mouse_char = mouse->u.mouse_char;
894                 crit_exit();
895             }
896             break;
897
898         default:
899             return EINVAL;
900         }
901
902         return 0;
903     }
904
905     return ENOIOCTL;
906 }
907
908 void
909 sc_mouse_init(void *unused)
910 {
911     at_exit(sc_mouse_exit1);
912 }
913
914 void
915 sc_mouse_uninit(void *unused)
916 {
917 }
918
919 SYSINIT(sc_mouse_init, SI_SUB_DRIVERS, SI_ORDER_ANY, sc_mouse_init, NULL);
920 SYSUNINIT(sc_mouse_uninit, SI_SUB_DRIVERS, SI_ORDER_ANY, sc_mouse_uninit, NULL);
921
922 #endif /* SC_NO_SYSMOUSE */