1 /*
2 * Mach Operating System
3 * Copyright (c) 1993,1991 Carnegie Mellon University
4 * Copyright (c) 1991 IBM Corporation
5 * All Rights Reserved.
6 *
7 * Permission to use, copy, modify and distribute this software and its
8 * documentation is hereby granted, provided that both the copyright
9 * notice and this permission notice appear in all copies of the
10 * software, derivative works or modified versions, and any portions
11 * thereof, and that both notices appear in supporting documentation,
12 * and that the name IBM not be used in advertising or publicity
13 * pertaining to distribution of the software without specific, written
14 * prior permission.
15 *
16 * CARNEGIE MELLON AND IBM ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
17 * CONDITION. CARNEGIE MELLON AND IBM DISCLAIM ANY LIABILITY OF ANY KIND FOR
18 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
19 *
20 * Carnegie Mellon requests users of this software to return to
21 *
22 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
23 * School of Computer Science
24 * Carnegie Mellon University
25 * Pittsburgh PA 15213-3890
26 *
27 * any improvements or extensions that they make and grant Carnegie Mellon
28 * the rights to redistribute these changes.
29 */
30
31
32 /*
33 * HISTORY
34 * $Log: kd_mouse.c,v $
35 * Revision 2.4 93/11/17 16:54:13 dbg
36 * Use sys_clock instead of 'time'.
37 * [93/09/08 dbg]
38 *
39 * Revision 2.3 93/08/02 21:44:09 mrt
40 * Rewrite mouse driver to work correctly.
41 * [93/07/12 zon]
42 *
43 * Revision 2.2 93/02/04 08:00:56 danner
44 * Integrate PS2 code from IBM.
45 * [93/01/18 prithvi]
46 *
47 */
48
49 /* PS/2 Mouse Driver */
50
51 #include <mach/boolean.h>
52 #include <sys/types.h>
53 #include <device/errno.h>
54 #include <device/io_req.h>
55
56 #include <kern/clock.h>
57 #include <kern/queue.h>
58 #include <kern/time_out.h>
59
60 #include <i386/ipl.h>
61
62 #include <i386at/kd.h>
63 #include <i386at/kd_queue.h>
64
65 #include <i386ps2/abios.h>
66 #include <i386ps2/kd_mouse_abios.h>
67 #include <i386ps2/kd_mouse_io.h>
68
69 boolean_t mouse_in_use = FALSE;
70
71 kd_event_queue mouse_queue;
72
73 queue_head_t mouse_read_queue = { &mouse_read_queue, &mouse_read_queue };
74
75 int kd_mouse = 0; /* used by kd.c */
76
77 struct Mouse_request mouserb;
78 struct Mouse_request mousecontrb;
79
80 struct Logical_id_params mouseparams = { 0 };
81 struct Logical_id_params mousecontparams = { 0 };
82
83 int last_buttons = 0;
84 #define MOUSE_UP 1
85 #define MOUSE_DOWN 0
86 #define MOUSE_ALL_UP 0x7
87
88 #define SPLMS SPLKD
89
90 static void
91 mouseabioswait(struct Mouse_request *request,
92 int abios_function,
93 int mouse_flag);
94
95 static int mouseintr(void);
96
97
98 static int mouse_setup(void)
99 {
100 static int already_done = 0;
101 int lid_num;
102
103 if (already_done)
104 return 0;
105
106 kdq_reset(&mouse_queue);
107
108 last_buttons = MOUSE_ALL_UP;
109
110 /* Init mouse hardware: get logical parameters */
111 mouserb.r_current_req_blck_len = sizeof(struct Mouse_request);
112 mouserb.request_header.Request_Block_Flags = 0;
113 mouserb.request_header.ELA_Offset = 0;
114 lid_num = MS_ID;
115 lid_num = abios_next_LID(MS_ID, lid_num);
116 MOUSE_SET_RESERVED_ABIOS_LOGICAL_PARAMETER(mouserb);
117 mouserb.r_logical_id = lid_num;
118 mouserb.r_unit = 0;
119 mouserb.r_flags = MS_NOERR;
120 mouseabioswait(&mouserb,
121 ABIOS_LOGICAL_PARAMETER,
122 mouseparams.Logical_id_flags);
123
124 if (mouserb.r_return_code != ABIOS_MOUSE_RC_DONE)
125 if (mouserb.r_return_code == ABIOS_MOUSE_RC_INVALID_LOGICAL_ID)
126 return -1;
127
128 if (mouserb.r_request_block_length > mouserb.r_current_req_blck_len)
129 panic("mouse: rb len");
130
131 mouserb.r_current_req_blck_len = mouserb.r_request_block_length;
132 mouseparams = mouserb.un.logical_id_params;
133
134 take_irq(mouserb.r_hardware_intr, 0, mouseintr, SPLTTY, "ms");
135
136 /*
137 * Continuous Read has its own Request Block, because it will
138 * always run in the background.
139 */
140 mousecontrb.r_current_req_blck_len = mouserb.r_current_req_blck_len;
141 mousecontrb.request_header.Request_Block_Flags =
142 mouserb.request_header.Request_Block_Flags;
143 mousecontrb.request_header.ELA_Offset =
144 mouserb.request_header.ELA_Offset;
145 mousecontrb.r_logical_id = mouserb.r_logical_id;
146 mousecontrb.r_unit = mouserb.r_unit;
147 mousecontparams = mouseparams;
148 MOUSE_SET_RESERVED_ABIOS_POINTING_DEVICE_CONTINUOUS_READ(mousecontrb);
149 mousecontrb.r_8_data_package_size = 3;
150 mousecontrb.r_flags = MS_DEFLT;
151 mouseabioswait(&mousecontrb,
152 ABIOS_MOUSE_POINTING_DEVICE_CONTINUOUS_READ,
153 mousecontparams.Logical_id_flags);
154
155 already_done = 1;
156 return 0;
157
158 }
159
160 int mouseopen(dev_t dev, int flags)
161 {
162
163 if (mouse_in_use)
164 return EBUSY;
165 mouse_in_use = TRUE;
166
167 if (mouse_setup())
168 return D_NO_SUCH_DEVICE;
169
170 /* Reset/Initialize Pointing Device */
171 MOUSE_SET_RESERVED_ABIOS_RESET_POINTING_DEVICE(mouserb);
172 mouserb.r_flags = MS_DEFLT;
173 mouseabioswait(&mouserb,
174 ABIOS_MOUSE_RESET_POINTING_DEVICE,
175 mouseparams.Logical_id_flags);
176
177 /* Enable Pointing Device */
178 MOUSE_SET_RESERVED_ABIOS_ENABLE_POINTING_DEVICE(mouserb);
179 mouserb.r_flags = MS_DEFLT;
180 mouseabioswait(&mouserb,
181 ABIOS_MOUSE_ENABLE_POINTING_DEVICE,
182 mouseparams.Logical_id_flags);
183
184 return D_SUCCESS;
185 }
186
187 int mouseclose(dev_t dev, int flags)
188 {
189 int s;
190
191 s = SPLMS();
192
193 MOUSE_SET_RESERVED_ABIOS_DISABLE_POINTING_DEVICE(mouserb);
194 mouserb.r_flags = MS_DEFLT;
195 mouseabioswait(&mouserb,
196 ABIOS_MOUSE_DISABLE_POINTING_DEVICE,
197 mouseparams.Logical_id_flags);
198
199 splx(s);
200
201 kdq_reset(&mouse_queue);
202
203 mouse_in_use = FALSE;
204
205 return 0;
206 }
207
208 #ifdef PRINT_EVENT
209 static void print_event(register kd_event *ev)
210 {
211
212 switch (ev->type) {
213
214 case MOUSE_LEFT:
215 printf("LEFT %s\n", ev->value.up ? "UP" : "DOWN");
216 break;
217
218 case MOUSE_MIDDLE:
219 printf("MIDDLE %s\n", ev->value.up ? "UP" : "DOWN");
220 break;
221
222 case MOUSE_RIGHT:
223 printf("RIGHT %s\n", ev->value.up ? "UP" : "DOWN");
224 break;
225
226 case MOUSE_MOTION:
227 printf("MOVE DX=%d DY=%d\n",
228 ev->value.mmotion.mm_deltaX,
229 ev->value.mmotion.mm_deltaY);
230 break;
231
232 default:
233 printf("ev->type==%d\n", ev->type);
234
235 }
236
237 }
238 #endif
239
240 static boolean_t mouse_read_done(io_req_t ior);
241
242 int mouseread(dev_t dev, register io_req_t ior)
243 {
244 int err;
245 int s;
246 int count;
247
248 err = device_read_alloc(ior, (vm_size_t)ior->io_count);
249 if (err != KERN_SUCCESS)
250 return err;
251
252 s = SPLMS();
253
254 if (kdq_empty(&mouse_queue)) {
255 if (ior->io_mode & D_NOWAIT) {
256 splx(s);
257 return D_WOULD_BLOCK;
258 }
259 ior->io_done = mouse_read_done;
260 enqueue_tail(&mouse_read_queue, (queue_entry_t) ior);
261 splx(s);
262 return D_IO_QUEUED;
263 }
264
265 count = 0;
266 while (!kdq_empty(&mouse_queue) && count < ior->io_count) {
267 register kd_event *ev = kdq_get(&mouse_queue);
268 #ifdef PRINT_EVENT
269 print_event(ev);
270 #endif
271 *(kd_event *)(&ior->io_data[count]) = *ev;
272 count += sizeof(kd_event);
273 }
274
275 splx(s);
276
277 ior->io_residual = ior->io_count - count;
278
279 return D_SUCCESS;
280
281 }
282
283 static boolean_t mouse_read_done(io_req_t ior)
284 {
285 int s;
286 int count;
287
288 s = SPLMS();
289
290 if (kdq_empty(&mouse_queue)) {
291 ior->io_done = mouse_read_done;
292 enqueue_tail(&mouse_read_queue, (queue_entry_t)ior);
293 splx(s);
294 return FALSE;
295 }
296
297 count = 0;
298 while (!kdq_empty(&mouse_queue) && count < ior->io_count) {
299 kd_event *ev = kdq_get(&mouse_queue);
300 #ifdef PRINT_EVENT
301 print_event(ev);
302 #endif
303 *(kd_event *)(&ior->io_data[count]) = *ev;
304 count += sizeof(kd_event);
305 }
306 splx(s);
307
308 ior->io_residual = ior->io_count - count;
309 ds_read_done(ior);
310
311 return TRUE;
312 }
313
314 /*
315 * 3 byte ps2 format used
316 *
317 * 7 6 5 4 3 2 1 0
318 * YO XO YS XS 1 0 R L
319 * X7 X6 X5 X4 X3 X3 X1 X0
320 * Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
321 *
322 */
323 #define BUTTON_MASK 0x3
324 #define LBUTTON_MASK 0x1
325 #define RBUTTON_MASK 0x2
326 #define MBUTTON_MASK 0x3
327 #define XNEG 0x00000010
328 #define YNEG 0x00000020
329 #define XOVER 0x00000040
330 #define YOVER 0x00000080
331 #define DELTA_MASK 0x000000ff
332 #define SIGNXTND 0xffffff00
333
334 static void mouse_enqueue(register kd_event *ev)
335 {
336 register io_req_t ior;
337
338 if (kdq_full(&mouse_queue))
339 printf("mouse: queue full\n");
340 else
341 kdq_put(&mouse_queue, ev);
342
343 while ((ior = (io_req_t)dequeue_head(&mouse_read_queue)) != 0)
344 iodone(ior);
345
346 }
347
348 static void mouse_moved(struct mouse_motion where)
349 {
350 kd_event ev;
351 time_spec_t cur_time;
352
353 clock_read(cur_time, sys_clock);
354
355 ev.type = MOUSE_MOTION;
356 ev.time.seconds = cur_time.seconds;
357 ev.time.microseconds = cur_time.nanoseconds / 1000;
358 ev.value.mmotion = where;
359 mouse_enqueue(&ev);
360
361 }
362
363 static void mouse_button(kev_type which, int up)
364 {
365 kd_event ev;
366 time_spec_t cur_time;
367
368 clock_read(cur_time, sys_clock);
369
370 ev.type = which;
371 ev.time.seconds = cur_time.seconds;
372 ev.time.microseconds = cur_time.nanoseconds / 1000;
373 ev.value.up = up;
374 mouse_enqueue(&ev);
375
376 }
377
378 static void mouse_packet(register int buttons, int x, int y)
379 {
380 unsigned char buttonchanges;
381 struct mouse_motion moved;
382
383 moved.mm_deltaX = ((buttons & XNEG) ? SIGNXTND : 0 ) | x;
384 moved.mm_deltaY = ((buttons & YNEG) ? SIGNXTND : 0 ) | y;
385 if (moved.mm_deltaX || moved.mm_deltaY)
386 mouse_moved(moved);
387
388 buttons &= BUTTON_MASK;
389 if (buttonchanges = buttons ^ last_buttons) {
390 last_buttons = buttons;
391 switch (buttonchanges) {
392 case LBUTTON_MASK:
393 mouse_button(MOUSE_LEFT, !(buttons & LBUTTON_MASK));
394 break;
395 case RBUTTON_MASK:
396 mouse_button(MOUSE_RIGHT, !(buttons & RBUTTON_MASK));
397 break;
398 /* disable the middle button until it can be simulated properly */
399 /*
400 case MBUTTON_MASK:
401 mouse_button(MOUSE_MIDDLE, buttons != MBUTTON_MASK);
402 break;
403 */
404 }
405 }
406
407 }
408
409 static int mouseintr(void)
410 {
411
412 abios_common_interrupt(&mousecontrb,
413 mousecontparams.Logical_id_flags);
414
415 switch (mousecontrb.r_return_code) {
416
417 case ABIOS_MOUSE_RC_DONE:
418 panic("mouseintr: continuous read stopped!");
419 break;
420
421 case ABIOS_MOUSE_RC_STAGE_ON_INT:
422 break;
423
424 case ABIOS_MOUSE_RC_STAGE_ON_TIME:
425 timeout(mouseintr,
426 0,
427 (MOUSE_TIME_TO_WAIT(mousecontrb)/1000000) * hz);
428 break;
429
430 case ABIOS_MOUSE_RC_NOT_MY_INT:
431 case ABIOS_UNDEFINED:
432 /*
433 * Must belong to a different mouse function.
434 * Check the other request block.
435 */
436 abios_common_interrupt(&mouserb,
437 mouseparams.Logical_id_flags);
438 switch (mouserb.r_return_code) {
439 case ABIOS_MOUSE_RC_DONE:
440 wakeup((char *)&mouserb.r_return_code);
441 break;
442 case ABIOS_MOUSE_RC_STAGE_ON_INT:
443 break;
444 case ABIOS_MOUSE_RC_STAGE_ON_TIME:
445 timeout(mouseintr,
446 0,
447 (MOUSE_TIME_TO_WAIT(mouserb)/1000000)*hz);
448 break;
449 case ABIOS_MOUSE_RC_NOT_MY_INT:
450 case ABIOS_UNDEFINED:
451 break; /* ??? */
452 case ABIOS_MOUSE_RC_ATTENTION:
453 default:
454 panic("mouseintr: non CR attention");
455 break;
456 }
457 break;
458
459 case ABIOS_MOUSE_RC_ATTENTION:
460 mouse_packet(mousecontrb.r_pointing_device_data_status,
461 mousecontrb.r_pointing_device_data_deltax,
462 mousecontrb.r_pointing_device_data_deltay);
463 break;
464
465 default:
466 break;
467
468 }
469
470 return 0;
471
472 }
473
474 static void
475 mouseabioswait(register struct Mouse_request *request,
476 int abios_function,
477 int mouse_flag)
478 {
479 int done;
480
481 request->r_function = abios_function;
482 request->r_return_code = ABIOS_UNDEFINED;
483
484 abios_common_start(request, mouse_flag);
485
486 done = 0;
487 while ((request->r_return_code != ABIOS_MOUSE_RC_DONE) && !done)
488 switch (request->r_return_code) {
489
490 case ABIOS_UNDEFINED:
491 break;
492
493 case ABIOS_MOUSE_RC_STAGE_ON_INT:
494 if (request->r_function ==
495 ABIOS_MOUSE_POINTING_DEVICE_CONTINUOUS_READ)
496 done = 1;
497 else
498 sleep((char *) &request->r_return_code, 0);
499 break;
500
501 case ABIOS_MOUSE_RC_STAGE_ON_TIME:
502 timeout(mouseintr,
503 0,
504 (MOUSE_TIME_TO_WAIT(*request)/1000000)*hz);
505 if (request->r_function ==
506 ABIOS_MOUSE_POINTING_DEVICE_CONTINUOUS_READ)
507 done = 1;
508 else
509 sleep((char *) &request->r_return_code, 0);
510 break;
511
512 case ABIOS_MOUSE_RC_NOT_MY_INT:
513 /* Wait until we get an informative reply */
514 if (request->r_function ==
515 ABIOS_MOUSE_POINTING_DEVICE_CONTINUOUS_READ)
516 printf("mouseabioswait: NMI waiting...\n");
517 else
518 sleep((char *) &request->r_return_code, 0);
519 break;
520
521 case ABIOS_MOUSE_RC_ATTENTION:
522 /* We shouldn't get this so soon */
523 panic("mouseabioswait: early attention");
524 break;
525
526 default:
527 if (!(request->r_flags & MS_NOERR))
528 panic("mouseabioswait %x", request->r_return_code);
529 else
530 done = 1;
531 break;
532
533 }
534
535 }
536
537 int mousegetstat(dev_t dev, int flavor, int *data, unsigned int *count)
538 {
539 int s;
540 struct mouse_status *status;
541
542 s = SPLMS();
543 switch (flavor) {
544
545 case MSIC_STATUS:
546 if (*count < sizeof(struct mouse_status)/sizeof(int)) {
547 splx(s);
548 return KERN_INVALID_ARGUMENT;
549 }
550 /* 0x03 Read Device Parameters */
551 status = (struct mouse_status *)data;
552 MOUSE_SET_RESERVED_ABIOS_READ_PARAMETER(mouserb);
553 mouserb.r_flags = MS_DEFLT;
554 mouseabioswait(&mouserb,
555 ABIOS_READ_PARAMETER,
556 mouseparams.Logical_id_flags);
557 /* Fill out data with mouse status */
558 status->interface_status = mouserb.r_interface_status;
559 status->data_package_size = mouserb.r_3_data_package_size;
560 status->flag_word = mouserb.r_flag_word;
561 status->current_resolution = mouserb.r_current_resolution;
562 status->current_sample_rate = mouserb.r_current_sample_rate;
563 break;
564
565 case MSIC_PDIC:
566 /* 0x0E Read Pointing Device Identication Code */
567 MOUSE_SET_RESERVED_ABIOS_READ_POINTING_DEVICE_IDENTIFICATION_CODE(mouserb);
568 mouserb.r_flags = MS_DEFLT;
569 mouseabioswait(&mouserb,
570 ABIOS_MOUSE_READ_POINTING_DEVICE_IDENTIFICATION_CODE,
571 mouseparams.Logical_id_flags);
572 *(long *)data =
573 (long)mouserb.r_auxiliary_device_identification_code;
574 /* IBM's value is 0x0 */
575 break;
576
577 default:
578 splx(s);
579 return EINVAL;
580
581 }
582
583 splx(s);
584 return D_SUCCESS;
585
586 }
587
588 int mousesetstat(dev_t dev, int flavor, int *data, unsigned int count)
589 {
590 int s;
591
592 s = SPLMS();
593 switch (flavor) {
594
595 case MSIC_DISABLE:
596 /* 0x07 Disable Pointing Device */
597 MOUSE_SET_RESERVED_ABIOS_DISABLE_POINTING_DEVICE(mouserb);
598 mouserb.r_flags = MS_DEFLT;
599 mouseabioswait(&mouserb,
600 ABIOS_MOUSE_DISABLE_POINTING_DEVICE,
601 mouseparams.Logical_id_flags);
602 break;
603
604 case MSIC_ENABLE:
605 /* 0x06 Enable Pointing Device */
606 MOUSE_SET_RESERVED_ABIOS_ENABLE_POINTING_DEVICE(mouserb);
607 mouserb.r_flags = MS_DEFLT;
608 mouseabioswait(&mouserb,
609 ABIOS_MOUSE_ENABLE_POINTING_DEVICE,
610 mouseparams.Logical_id_flags);
611 break;
612
613 case MSIC_SCALE:
614 /* 0x0D Set Scaling Factor */
615 MOUSE_SET_RESERVED_ABIOS_SET_SCALING_FACTOR(mouserb);
616 mouserb.r_scaling_factor = (u_char) *data;
617 mouserb.r_flags = MS_DEFLT;
618 mouseabioswait(&mouserb,
619 ABIOS_MOUSE_SET_SCALING_FACTOR,
620 mouseparams.Logical_id_flags);
621 break;
622
623 case MSIC_SAMPLE:
624 /* 0x0B Set Sample Rate */
625 /* MOUSE_SET_RESERVED_ABIOS_SET_SAMPLE_RATE(mouserb); */
626 mouserb.r_sample_rate = (u_short) *data;
627 mouserb.r_flags = MS_DEFLT;
628 mouseabioswait(&mouserb,
629 ABIOS_MOUSE_SET_SAMPLE_RATE,
630 mouseparams.Logical_id_flags);
631 break;
632
633 case MSIC_RESL:
634 /* 0x0C Set Resolution */
635 MOUSE_SET_RESERVED_ABIOS_SET_RESOLUTION(mouserb);
636 mouserb.r_resolution = (u_short) *data;
637 mouserb.r_flags = MS_DEFLT;
638 mouseabioswait(&mouserb,
639 ABIOS_MOUSE_SET_RESOLUTION,
640 mouseparams.Logical_id_flags);
641 break;
642
643 default:
644 splx(s);
645 return EINVAL;
646
647 }
648
649 splx(s);
650 return D_SUCCESS;
651
652 }
653
Cache object: 5215ed0f084565088f1cfb7a6e6900fb
|