]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/adb/adb_mouse.c
MFV r362143:
[FreeBSD/FreeBSD.git] / sys / dev / adb / adb_mouse.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (C) 2008 Nathan Whitehorn
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.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  * $FreeBSD$
28  */
29
30 #include <sys/cdefs.h>
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/lock.h>
34 #include <sys/module.h>
35 #include <sys/mutex.h>
36 #include <sys/bus.h>
37 #include <sys/conf.h>
38 #include <sys/mouse.h>
39 #include <sys/poll.h>
40 #include <sys/condvar.h>
41 #include <sys/selinfo.h>
42 #include <sys/sysctl.h>
43 #include <sys/uio.h>
44 #include <sys/fcntl.h>
45 #include <sys/kernel.h>
46
47 #include <machine/bus.h>
48
49 #include <vm/vm.h>
50 #include <vm/pmap.h>
51
52 #include "adb.h"
53
54 #define CDEV_GET_SOFTC(x) (x)->si_drv1
55
56 static int adb_mouse_probe(device_t dev);
57 static int adb_mouse_attach(device_t dev);
58 static int adb_mouse_detach(device_t dev);
59 static void adb_init_trackpad(device_t dev);
60 static int adb_tapping_sysctl(SYSCTL_HANDLER_ARGS);
61
62 static d_open_t  ams_open;
63 static d_close_t ams_close;
64 static d_read_t  ams_read;
65 static d_ioctl_t ams_ioctl;
66 static d_poll_t  ams_poll;
67
68 static u_int adb_mouse_receive_packet(device_t dev, u_char status, 
69     u_char command, u_char reg, int len, u_char *data);
70
71 struct adb_mouse_softc {
72         device_t sc_dev;
73
74         struct mtx sc_mtx;
75         struct cv  sc_cv;
76
77         int flags;
78 #define AMS_EXTENDED    0x1
79 #define AMS_TOUCHPAD    0x2
80         uint16_t dpi;
81
82         mousehw_t hw;
83         mousemode_t mode;
84         u_char id[4];
85
86         int buttons;
87         u_int sc_tapping;
88         int button_buf;
89         int last_buttons;
90         int xdelta, ydelta;
91
92         int8_t packet[8];
93         size_t packet_read_len;
94
95         struct cdev *cdev;
96         struct selinfo rsel;
97 };
98
99 static device_method_t adb_mouse_methods[] = {
100         /* Device interface */
101         DEVMETHOD(device_probe,         adb_mouse_probe),
102         DEVMETHOD(device_attach,        adb_mouse_attach),
103         DEVMETHOD(device_detach,        adb_mouse_detach),
104         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
105         DEVMETHOD(device_suspend,       bus_generic_suspend),
106         DEVMETHOD(device_resume,        bus_generic_resume),
107
108         /* ADB interface */
109         DEVMETHOD(adb_receive_packet,   adb_mouse_receive_packet),
110
111         { 0, 0 }
112 };
113
114 static driver_t adb_mouse_driver = {
115         "ams",
116         adb_mouse_methods,
117         sizeof(struct adb_mouse_softc),
118 };
119
120 static devclass_t adb_mouse_devclass;
121
122 DRIVER_MODULE(ams, adb, adb_mouse_driver, adb_mouse_devclass, 0, 0);
123
124 static struct cdevsw ams_cdevsw = {
125         .d_version =    D_VERSION,
126         .d_flags   =    0,
127         .d_open    =    ams_open,
128         .d_close   =    ams_close,
129         .d_read    =    ams_read,
130         .d_ioctl   =    ams_ioctl,
131         .d_poll    =    ams_poll,
132         .d_name    =    "ams",
133 };
134
135 static int 
136 adb_mouse_probe(device_t dev)
137 {
138         uint8_t type;
139
140         type = adb_get_device_type(dev);
141
142         if (type != ADB_DEVICE_MOUSE)
143                 return (ENXIO);
144
145         device_set_desc(dev,"ADB Mouse");
146         return (0);
147 }
148         
149 static int 
150 adb_mouse_attach(device_t dev) 
151 {
152         struct adb_mouse_softc *sc;
153         char *description = "Unknown Pointing Device";
154
155         size_t r1_len;
156         u_char r1[8];
157
158         sc = device_get_softc(dev);
159         sc->sc_dev = dev;
160
161         mtx_init(&sc->sc_mtx, "ams", NULL, MTX_DEF);
162         cv_init(&sc->sc_cv,"ams");
163
164         sc->flags = 0;
165
166         sc->hw.buttons = 2;
167         sc->hw.iftype = MOUSE_IF_UNKNOWN;
168         sc->hw.type = MOUSE_UNKNOWN;
169         sc->hw.model = sc->hw.hwid = 0;
170
171         sc->mode.protocol = MOUSE_PROTO_SYSMOUSE;
172         sc->mode.rate = -1;
173         sc->mode.resolution = 100;
174         sc->mode.accelfactor = 0;
175         sc->mode.level = 0;
176         sc->mode.packetsize = 5;
177
178         sc->buttons = 0;
179         sc->sc_tapping = 0;
180         sc->button_buf = 0;
181         sc->last_buttons = 0;
182         sc->packet_read_len = 0;
183
184         /* Try to switch to extended protocol */
185         adb_set_device_handler(dev,4);
186
187         switch(adb_get_device_handler(dev)) {
188         case 1:
189                 sc->mode.resolution = 100;
190                 break;
191         case 2:
192                 sc->mode.resolution = 200;
193                 break;
194         case 4:
195                 r1_len = adb_read_register(dev,1,r1);
196                 if (r1_len < 8)
197                         break;
198
199                 sc->flags |= AMS_EXTENDED;
200                 memcpy(&sc->hw.hwid,r1,4);
201                 sc->mode.resolution = (r1[4] << 8) | r1[5];
202
203                 switch (r1[6]) {
204                 case 0:
205                         sc->hw.type = MOUSE_PAD;
206                         description = "Tablet";
207                         break;
208                 case 1:
209                         sc->hw.type = MOUSE_MOUSE;
210                         description = "Mouse";
211                         break;
212                 case 2:
213                         sc->hw.type = MOUSE_TRACKBALL;
214                         description = "Trackball";
215                         break;
216                 case 3:
217                         sc->flags |= AMS_TOUCHPAD;
218                         sc->hw.type = MOUSE_PAD;
219                         adb_init_trackpad(dev);
220                         description = "Touchpad";
221                         break;
222                 }
223
224                 sc->hw.buttons = r1[7];
225
226                 device_printf(dev,"%d-button %d-dpi %s\n",
227                     sc->hw.buttons, sc->mode.resolution,description);
228
229                 /*
230                  * Check for one of MacAlly's non-compliant 2-button mice.
231                  * These claim to speak the extended mouse protocol, but
232                  * instead speak the standard protocol and only when their
233                  * handler is set to 0x42.
234                  */
235
236                 if (sc->hw.hwid == 0x4b4f4954) {
237                         adb_set_device_handler(dev,0x42);
238
239                         if (adb_get_device_handler(dev) == 0x42) {
240                                 device_printf(dev, "MacAlly 2-Button Mouse\n");
241                                 sc->flags &= ~AMS_EXTENDED;
242                         }
243                 }
244                         
245                 break;
246         }
247
248         sc->cdev = make_dev(&ams_cdevsw, device_get_unit(dev),
249                        UID_ROOT, GID_OPERATOR, 0644, "ams%d", 
250                        device_get_unit(dev));
251         sc->cdev->si_drv1 = sc;
252
253         adb_set_autopoll(dev,1);
254
255         return (0);
256 }
257
258 static int 
259 adb_mouse_detach(device_t dev) 
260 {
261         struct adb_mouse_softc *sc;
262
263         adb_set_autopoll(dev,0);
264
265         sc = device_get_softc(dev);
266         destroy_dev(sc->cdev);
267
268         mtx_destroy(&sc->sc_mtx);
269         cv_destroy(&sc->sc_cv);
270
271         return (0);
272 }
273
274 static void
275 adb_init_trackpad(device_t dev)
276 {
277         struct adb_mouse_softc *sc;
278         struct sysctl_ctx_list *ctx;
279         struct sysctl_oid *tree;
280
281         size_t r1_len;
282         u_char r1[8];
283         u_char r2[8];
284
285         sc = device_get_softc(dev);
286
287         r1_len = adb_read_register(dev, 1, r1);
288
289         /* An Extended Mouse register1 must return 8 bytes. */
290         if (r1_len != 8)
291                 return;
292
293         if((r1[6] != 0x0d))
294         {
295                 r1[6] = 0x0d;
296                 
297                 adb_write_register(dev, 1, 8, r1); 
298       
299                 r1_len = adb_read_register(dev, 1, r1);
300       
301                 if (r1[6] != 0x0d)
302                 {
303                         device_printf(dev, "ADB Mouse = 0x%x "
304                                       "(non-Extended Mode)\n", r1[6]);
305                         return;
306                 } else {
307                         device_printf(dev, "ADB Mouse = 0x%x "
308                                       "(Extended Mode)\n", r1[6]);
309                         
310                         /* Set ADB Extended Features to default values,
311                            enabled. */
312                         r2[0] = 0x19; /* Clicking: 0x19 disabled 0x99 enabled */
313                         r2[1] = 0x94; /* Dragging: 0x14 disabled 0x94 enabled */
314                         r2[2] = 0x19;
315                         r2[3] = 0xff; /* DragLock: 0xff disabled 0xb2 enabled */
316                         r2[4] = 0xb2;
317                         r2[5] = 0x8a;
318                         r2[6] = 0x1b;
319                        
320                         r2[7] = 0x57;  /* 0x57 bits 3:0 for W mode */
321                         
322                         adb_write_register(dev, 2, 8, r2);
323                         
324                 }
325         }
326
327         /*
328          * Set up sysctl
329          */
330         ctx = device_get_sysctl_ctx(dev);
331         tree = device_get_sysctl_tree(dev);
332         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tapping",
333             CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0,
334             adb_tapping_sysctl, "I", "Tapping the pad causes button events");
335         return;
336 }
337
338 static u_int 
339 adb_mouse_receive_packet(device_t dev, u_char status, u_char command, 
340     u_char reg, int len, u_char *data) 
341 {
342         struct adb_mouse_softc *sc;
343         int i = 0;
344         int xdelta, ydelta;
345         int buttons, tmp_buttons;
346
347         sc = device_get_softc(dev);
348
349         if (command != ADB_COMMAND_TALK || reg != 0 || len < 2)
350                 return (0);
351
352         ydelta = data[0] & 0x7f;
353         xdelta = data[1] & 0x7f;
354
355         buttons = 0;
356         buttons |= !(data[0] & 0x80);
357         buttons |= !(data[1] & 0x80) << 1;
358
359         if (sc->flags & AMS_EXTENDED) {
360                 for (i = 2; i < len && i < 5; i++) {
361                         xdelta |= (data[i] & 0x07) << (3*i + 1);
362                         ydelta |= (data[i] & 0x70) << (3*i - 3);
363
364                         buttons |= !(data[i] & 0x08) << (2*i - 2);
365                         buttons |= !(data[i] & 0x80) << (2*i - 1);
366                 }
367         } else {
368                 len = 2; /* Ignore extra data */
369         }
370
371         /* Do sign extension as necessary */
372         if (xdelta & (0x40 << 3*(len-2)))
373                 xdelta |= 0xffffffc0 << 3*(len - 2);
374         if (ydelta & (0x40 << 3*(len-2)))
375                 ydelta |= 0xffffffc0 << 3*(len - 2);
376
377         if ((sc->flags & AMS_TOUCHPAD) && (sc->sc_tapping == 1)) {
378                 tmp_buttons = buttons;
379                 if (buttons == 0x12) {
380                         /* Map a double tap on button 3.
381                            Keep the button state for the next sequence.
382                            A double tap sequence is followed by a single tap
383                            sequence.
384                         */
385                         tmp_buttons = 0x3;
386                         sc->button_buf = tmp_buttons;
387                 } else if (buttons == 0x2) {
388                         /* Map a single tap on button 2. But only if it is
389                            not a successor from a double tap.
390                         */
391                         if (sc->button_buf != 0x3) 
392                                 tmp_buttons = 0x2;
393                         else
394                                 tmp_buttons = 0;
395
396                         sc->button_buf = 0;
397                 }
398                 buttons = tmp_buttons;
399         }
400
401         /*
402          * Some mice report high-numbered buttons on the wrong button number,
403          * so set the highest-numbered real button as pressed if there are
404          * mysterious high-numbered ones set.
405          *
406          * Don't do this for touchpads, because touchpads also trigger
407          * high button events when they are touched.
408          */
409
410         if (rounddown2(buttons, 1 << sc->hw.buttons)
411             && !(sc->flags & AMS_TOUCHPAD)) {
412                 buttons |= 1 << (sc->hw.buttons - 1);
413         }
414         buttons &= (1 << sc->hw.buttons) - 1;
415
416         mtx_lock(&sc->sc_mtx);
417
418         /* Add in our new deltas, and take into account
419            Apple's opposite meaning for Y axis motion */
420
421         sc->xdelta += xdelta;
422         sc->ydelta -= ydelta;
423
424         sc->buttons = buttons;
425
426         mtx_unlock(&sc->sc_mtx);
427
428         cv_broadcast(&sc->sc_cv);
429         selwakeuppri(&sc->rsel, PZERO);
430
431         return (0);
432 }
433
434 static int
435 ams_open(struct cdev *dev, int flag, int fmt, struct thread *p)
436 {
437         struct adb_mouse_softc *sc;
438
439         sc = CDEV_GET_SOFTC(dev);
440         if (sc == NULL)
441                 return (ENXIO);
442
443         mtx_lock(&sc->sc_mtx);
444         sc->packet_read_len = 0;
445         sc->xdelta = 0;
446         sc->ydelta = 0;
447         sc->buttons = 0;
448         mtx_unlock(&sc->sc_mtx);
449
450         return (0);
451 }
452
453 static int
454 ams_close(struct cdev *dev, int flag, int fmt, struct thread *p)
455 {
456         struct adb_mouse_softc *sc;
457
458         sc = CDEV_GET_SOFTC(dev);
459
460         cv_broadcast(&sc->sc_cv);
461         selwakeuppri(&sc->rsel, PZERO);
462         return (0);
463 }
464
465 static int
466 ams_poll(struct cdev *dev, int events, struct thread *p)
467 {
468         struct adb_mouse_softc *sc;
469
470         sc = CDEV_GET_SOFTC(dev);
471         if (sc == NULL)
472                 return (EIO);
473
474         if (events & (POLLIN | POLLRDNORM)) {
475                 mtx_lock(&sc->sc_mtx);
476                 
477                 if (sc->xdelta == 0 && sc->ydelta == 0 && 
478                    sc->buttons == sc->last_buttons &&
479                    sc->packet_read_len == 0) {
480                         selrecord(p, &sc->rsel);
481                         events = 0;
482                 } else {
483                         events &= (POLLIN | POLLRDNORM);
484                 }
485
486                 mtx_unlock(&sc->sc_mtx);
487         }
488
489         return events;
490 }
491
492 static int
493 ams_read(struct cdev *dev, struct uio *uio, int flag)
494 {
495         struct adb_mouse_softc *sc;
496         size_t len;
497         int8_t outpacket[8];
498         int error;
499
500         sc = CDEV_GET_SOFTC(dev);
501         if (sc == NULL)
502                 return (EIO);
503
504         if (uio->uio_resid <= 0)
505                 return (0);
506
507         mtx_lock(&sc->sc_mtx);
508
509         if (!sc->packet_read_len) {
510                 if (sc->xdelta == 0 && sc->ydelta == 0 && 
511                    sc->buttons == sc->last_buttons) {
512
513                         if (flag & O_NONBLOCK) {
514                                 mtx_unlock(&sc->sc_mtx);
515                                 return EWOULDBLOCK;
516                         }
517
518         
519                         /* Otherwise, block on new data */
520                         error = cv_wait_sig(&sc->sc_cv, &sc->sc_mtx);
521                         if (error) {
522                                 mtx_unlock(&sc->sc_mtx);
523                                 return (error);
524                         }
525                 }
526
527                 sc->packet[0] = 1U << 7;
528                 sc->packet[0] |= (!(sc->buttons & 1)) << 2;
529                 sc->packet[0] |= (!(sc->buttons & 4)) << 1;
530                 sc->packet[0] |= (!(sc->buttons & 2));
531
532                 if (sc->xdelta > 127) {
533                         sc->packet[1] = 127;
534                         sc->packet[3] = sc->xdelta - 127;
535                 } else if (sc->xdelta < -127) {
536                         sc->packet[1] = -127;
537                         sc->packet[3] = sc->xdelta + 127;
538                 } else {
539                         sc->packet[1] = sc->xdelta;
540                         sc->packet[3] = 0;
541                 }
542
543                 if (sc->ydelta > 127) {
544                         sc->packet[2] = 127;
545                         sc->packet[4] = sc->ydelta - 127;
546                 } else if (sc->ydelta < -127) {
547                         sc->packet[2] = -127;
548                         sc->packet[4] = sc->ydelta + 127;
549                 } else {
550                         sc->packet[2] = sc->ydelta;
551                         sc->packet[4] = 0;
552                 }
553
554                 /* No Z movement */
555                 sc->packet[5] = 0;
556                 sc->packet[6] = 0; 
557
558                 sc->packet[7] = ~((uint8_t)(sc->buttons >> 3)) & 0x7f;
559
560
561                 sc->last_buttons = sc->buttons;
562                 sc->xdelta = 0;
563                 sc->ydelta = 0;
564
565                 sc->packet_read_len = sc->mode.packetsize;
566         }
567
568         len = (sc->packet_read_len > uio->uio_resid) ? 
569                 uio->uio_resid : sc->packet_read_len;
570
571         memcpy(outpacket,sc->packet + 
572                 (sc->mode.packetsize - sc->packet_read_len),len);
573         sc->packet_read_len -= len;
574
575         mtx_unlock(&sc->sc_mtx);
576
577         error = uiomove(outpacket,len,uio);
578
579         return (error);
580 }
581
582
583 static int
584 ams_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, 
585     struct thread *p)
586 {
587         struct adb_mouse_softc *sc;
588         mousemode_t mode;
589
590         sc = CDEV_GET_SOFTC(dev);
591         if (sc == NULL)
592                 return (EIO);
593
594         switch (cmd) {
595         case MOUSE_GETHWINFO:
596                 *(mousehw_t *)addr = sc->hw;
597                 break;
598         case MOUSE_GETMODE:
599                 *(mousemode_t *)addr = sc->mode;
600                 break;
601         case MOUSE_SETMODE:
602                 mode = *(mousemode_t *)addr;
603                 addr = (caddr_t)&mode.level;
604
605                 /* Fallthrough */
606
607         case MOUSE_SETLEVEL:
608                 if (*(int *)addr == -1)
609                         break;
610                 else if (*(int *)addr == 1) {
611                         sc->mode.level = 1;
612                         sc->mode.packetsize = 8;
613                         break;
614                 } else if (*(int *)addr == 0) {
615                         sc->mode.level = 0;
616                         sc->mode.packetsize = 5;
617                         break;
618                 }
619         
620                 return EINVAL;
621         case MOUSE_GETLEVEL:
622                 *(int *)addr = sc->mode.level;
623                 break;
624         
625         case MOUSE_GETSTATUS: {
626                 mousestatus_t *status = (mousestatus_t *) addr;
627
628                 mtx_lock(&sc->sc_mtx);
629
630                 status->button = sc->buttons;
631                 status->obutton = sc->last_buttons;
632                 
633                 status->flags = status->button ^ status->obutton;
634
635                 if (sc->xdelta != 0 || sc->ydelta)
636                         status->flags |= MOUSE_POSCHANGED;
637                 if (status->button != status->obutton)
638                         status->flags |= MOUSE_BUTTONSCHANGED;
639
640                 status->dx = sc->xdelta;
641                 status->dy = sc->ydelta;
642                 status->dz = 0;
643
644                 sc->xdelta = 0;
645                 sc->ydelta = 0;
646                 sc->last_buttons = sc->buttons;
647
648                 mtx_unlock(&sc->sc_mtx);
649
650                 break; }
651         default:
652                 return ENOTTY;
653         }
654
655         return (0);
656 }
657
658 static int
659 adb_tapping_sysctl(SYSCTL_HANDLER_ARGS)
660 {
661         struct adb_mouse_softc *sc = arg1;
662         device_t dev;
663         int error;
664         u_char r2[8];
665         u_int tapping;
666
667         dev = sc->sc_dev;
668         tapping = sc->sc_tapping;
669
670         error = sysctl_handle_int(oidp, &tapping, 0, req);
671
672         if (error || !req->newptr)
673                 return (error);
674
675         if (tapping == 1) {
676                 adb_read_register(dev, 2, r2);
677                 r2[0] = 0x99; /* enable tapping. */
678                 adb_write_register(dev, 2, 8, r2);
679                 sc->sc_tapping = 1;
680         } else if (tapping == 0) {
681                 adb_read_register(dev, 2, r2);
682                 r2[0] = 0x19; /* disable tapping. */
683                 adb_write_register(dev, 2, 8, r2);
684                 sc->sc_tapping = 0;
685         }
686         else
687                 return (EINVAL);
688
689         return (0);
690 }