Merge from vendor branch LIBARCHIVE:
[dragonfly.git] / sys / dev / misc / syscons / sysmouse.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/sysmouse.c,v 1.2.2.2 2001/07/16 05:21:24 yokota Exp $
27  * $DragonFly: src/sys/dev/misc/syscons/sysmouse.c,v 1.12 2006/09/10 01:26:35 dillon Exp $
28  */
29
30 #include "opt_syscons.h"
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/conf.h>
35 #include <sys/proc.h>
36 #include <sys/tty.h>
37 #include <sys/kernel.h>
38 #include <sys/thread2.h>
39
40 #include <machine/console.h>
41 #include <machine/mouse.h>
42
43 #include "syscons.h"
44
45 #ifndef SC_NO_SYSMOUSE
46
47 #define CDEV_MAJOR      12              /* major number, shared with syscons */
48 #define SC_MOUSE        128             /* minor number */
49
50 static d_open_t         smopen;
51 static d_close_t        smclose;
52 static d_ioctl_t        smioctl;
53
54 static struct dev_ops sm_ops = {
55         { "sysmouse", CDEV_MAJOR, D_TTY },
56         .d_open =       smopen,
57         .d_close =      smclose,
58         .d_read =       ttyread,
59         .d_ioctl =      smioctl,
60         .d_poll =       ttypoll,
61 };
62
63 /* local variables */
64 static struct tty       *sysmouse_tty;
65 static int              mouse_level;    /* sysmouse protocol level */
66 static mousestatus_t    mouse_status;
67
68 static void             smstart(struct tty *tp);
69 static int              smparam(struct tty *tp, struct termios *t);
70
71 static int
72 smopen(struct dev_open_args *ap)
73 {
74         cdev_t dev = ap->a_head.a_dev;
75         struct tty *tp;
76
77         DPRINTF(5, ("smopen: dev:%d,%d, vty:%d\n",
78                 major(dev), minor(dev), SC_VTY(dev)));
79
80 #if 0
81         if (SC_VTY(dev) != SC_MOUSE)
82                 return ENXIO;
83 #endif
84
85         tp = dev->si_tty = ttymalloc(dev->si_tty);
86         if (!(tp->t_state & TS_ISOPEN)) {
87                 sysmouse_tty = tp;
88                 tp->t_oproc = smstart;
89                 tp->t_param = smparam;
90                 tp->t_stop = nottystop;
91                 tp->t_dev = dev;
92                 ttychars(tp);
93                 tp->t_iflag = 0;
94                 tp->t_oflag = 0;
95                 tp->t_lflag = 0;
96                 tp->t_cflag = TTYDEF_CFLAG;
97                 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
98                 smparam(tp, &tp->t_termios);
99                 (*linesw[tp->t_line].l_modem)(tp, 1);
100         } else if (tp->t_state & TS_XCLUDE && suser_cred(ap->a_cred, 0)) {
101                 return EBUSY;
102         }
103
104         return (*linesw[tp->t_line].l_open)(dev, tp);
105 }
106
107 static int
108 smclose(struct dev_close_args *ap)
109 {
110         cdev_t dev = ap->a_head.a_dev;
111         struct tty *tp;
112
113         tp = dev->si_tty;
114         crit_enter();
115         mouse_level = 0;
116         (*linesw[tp->t_line].l_close)(tp, ap->a_fflag);
117         ttyclose(tp);
118         crit_exit();
119
120         return 0;
121 }
122
123 static void
124 smstart(struct tty *tp)
125 {
126         struct clist *rbp;
127         u_char buf[PCBURST];
128
129         crit_enter();
130         if (!(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))) {
131                 tp->t_state |= TS_BUSY;
132                 rbp = &tp->t_outq;
133                 while (rbp->c_cc)
134                         q_to_b(rbp, buf, PCBURST);
135                 tp->t_state &= ~TS_BUSY;
136                 ttwwakeup(tp);
137         }
138         crit_exit();
139 }
140
141 static int
142 smparam(struct tty *tp, struct termios *t)
143 {
144         tp->t_ispeed = t->c_ispeed;
145         tp->t_ospeed = t->c_ospeed;
146         tp->t_cflag = t->c_cflag;
147         return 0;
148 }
149
150 static int
151 smioctl(struct dev_ioctl_args *ap)
152 {
153         cdev_t dev = ap->a_head.a_dev;
154         struct tty *tp;
155         mousehw_t *hw;
156         mousemode_t *mode;
157         int error;
158
159         tp = dev->si_tty;
160
161         switch (ap->a_cmd) {
162         case MOUSE_GETHWINFO:   /* get device information */
163                 hw = (mousehw_t *)ap->a_data;
164                 hw->buttons = 10;               /* XXX unknown */
165                 hw->iftype = MOUSE_IF_SYSMOUSE;
166                 hw->type = MOUSE_MOUSE;
167                 hw->model = MOUSE_MODEL_GENERIC;
168                 hw->hwid = 0;
169                 return 0;
170
171         case MOUSE_GETMODE:     /* get protocol/mode */
172                 mode = (mousemode_t *)ap->a_data;
173                 mode->level = mouse_level;
174                 switch (mode->level) {
175                 case 0: /* emulate MouseSystems protocol */
176                         mode->protocol = MOUSE_PROTO_MSC;
177                         mode->rate = -1;                /* unknown */
178                         mode->resolution = -1;  /* unknown */
179                         mode->accelfactor = 0;  /* disabled */
180                         mode->packetsize = MOUSE_MSC_PACKETSIZE;
181                         mode->syncmask[0] = MOUSE_MSC_SYNCMASK;
182                         mode->syncmask[1] = MOUSE_MSC_SYNC;
183                         break;
184
185                 case 1: /* sysmouse protocol */
186                         mode->protocol = MOUSE_PROTO_SYSMOUSE;
187                         mode->rate = -1;
188                         mode->resolution = -1;
189                         mode->accelfactor = 0;
190                         mode->packetsize = MOUSE_SYS_PACKETSIZE;
191                         mode->syncmask[0] = MOUSE_SYS_SYNCMASK;
192                         mode->syncmask[1] = MOUSE_SYS_SYNC;
193                         break;
194                 }
195                 return 0;
196
197         case MOUSE_SETMODE:     /* set protocol/mode */
198                 mode = (mousemode_t *)ap->a_data;
199                 if (mode->level == -1)
200                         ;       /* don't change the current setting */
201                 else if ((mode->level < 0) || (mode->level > 1))
202                         return EINVAL;
203                 else
204                         mouse_level = mode->level;
205                 return 0;
206
207         case MOUSE_GETLEVEL:    /* get operation level */
208                 *(int *)ap->a_data = mouse_level;
209                 return 0;
210
211         case MOUSE_SETLEVEL:    /* set operation level */
212                 if ((*(int *)ap->a_data  < 0) || (*(int *)ap->a_data > 1))
213                         return EINVAL;
214                 mouse_level = *(int *)ap->a_data;
215                 return 0;
216
217         case MOUSE_GETSTATUS:   /* get accumulated mouse events */
218                 crit_enter();
219                 *(mousestatus_t *)ap->a_data = mouse_status;
220                 mouse_status.flags = 0;
221                 mouse_status.obutton = mouse_status.button;
222                 mouse_status.dx = 0;
223                 mouse_status.dy = 0;
224                 mouse_status.dz = 0;
225                 crit_exit();
226                 return 0;
227
228 #if notyet
229         case MOUSE_GETVARS:     /* get internal mouse variables */
230         case MOUSE_SETVARS:     /* set internal mouse variables */
231                 return ENODEV;
232 #endif
233
234         case MOUSE_READSTATE:   /* read status from the device */
235         case MOUSE_READDATA:    /* read data from the device */
236                 return ENODEV;
237         }
238
239         error = (*linesw[tp->t_line].l_ioctl)(tp, ap->a_cmd, ap->a_data, ap->a_fflag, ap->a_cred);
240         if (error != ENOIOCTL)
241                 return error;
242         error = ttioctl(tp, ap->a_cmd, ap->a_data, ap->a_fflag);
243         if (error != ENOIOCTL)
244                 return error;
245         return ENOTTY;
246 }
247
248 static void
249 sm_attach_mouse(void *unused)
250 {
251         cdev_t dev;
252
253         dev_ops_add(&sm_ops, -1, SC_MOUSE);
254         dev = make_dev(&sm_ops, SC_MOUSE, UID_ROOT, GID_WHEEL, 0600,
255                        "sysmouse");
256         /* sysmouse doesn't have scr_stat */
257 }
258
259 SYSINIT(sysmouse, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR,
260         sm_attach_mouse, NULL)
261
262 int
263 sysmouse_event(mouse_info_t *info)
264 {
265         /* MOUSE_BUTTON?DOWN -> MOUSE_MSC_BUTTON?UP */
266         static int butmap[8] = {
267             MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
268             MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP,
269             MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP,
270             MOUSE_MSC_BUTTON3UP,
271             MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP,
272             MOUSE_MSC_BUTTON2UP,
273             MOUSE_MSC_BUTTON1UP,
274             0,
275         };
276         u_char buf[8];
277         int x, y, z;
278         int i;
279
280         switch (info->operation) {
281         case MOUSE_ACTION:
282                 mouse_status.button = info->u.data.buttons;
283                 /* FALL THROUGH */
284         case MOUSE_MOTION_EVENT:
285                 x = info->u.data.x;
286                 y = info->u.data.y;
287                 z = info->u.data.z;
288                 break;
289         case MOUSE_BUTTON_EVENT:
290                 x = y = z = 0;
291                 if (info->u.event.value > 0)
292                         mouse_status.button |= info->u.event.id;
293                 else
294                         mouse_status.button &= ~info->u.event.id;
295                 break;
296         default:
297                 return 0;
298         }
299
300         mouse_status.dx += x;
301         mouse_status.dy += y;
302         mouse_status.dz += z;
303         mouse_status.flags |= ((x || y || z) ? MOUSE_POSCHANGED : 0)
304                               | (mouse_status.obutton ^ mouse_status.button);
305         if (mouse_status.flags == 0)
306                 return 0;
307
308         if ((sysmouse_tty == NULL) || !(sysmouse_tty->t_state & TS_ISOPEN))
309                 return mouse_status.flags;
310
311         /* the first five bytes are compatible with MouseSystems' */
312         buf[0] = MOUSE_MSC_SYNC
313                  | butmap[mouse_status.button & MOUSE_STDBUTTONS];
314         x = imax(imin(x, 255), -256);
315         buf[1] = x >> 1;
316         buf[3] = x - buf[1];
317         y = -imax(imin(y, 255), -256);
318         buf[2] = y >> 1;
319         buf[4] = y - buf[2];
320         for (i = 0; i < MOUSE_MSC_PACKETSIZE; ++i)
321                 (*linesw[sysmouse_tty->t_line].l_rint)(buf[i], sysmouse_tty);
322         if (mouse_level >= 1) {
323                 /* extended part */
324                 z = imax(imin(z, 127), -128);
325                 buf[5] = (z >> 1) & 0x7f;
326                 buf[6] = (z - (z >> 1)) & 0x7f;
327                 /* buttons 4-10 */
328                 buf[7] = (~mouse_status.button >> 3) & 0x7f;
329                 for (i = MOUSE_MSC_PACKETSIZE; i < MOUSE_SYS_PACKETSIZE; ++i)
330                         (*linesw[sysmouse_tty->t_line].l_rint)(buf[i],
331                                                                sysmouse_tty);
332         }
333
334         return mouse_status.flags;
335 }
336
337 #endif /* !SC_NO_SYSMOUSE */