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