14 } __attribute__((packed
));
20 #define KBD_REG_STATUS 0x64
21 #define KBD_STATUS_OUT_DATA (1 << 0)
22 #define KBD_STATUS_IN_DATA (1 << 1)
23 #define KBD_STATUS_SYSFLAG (1 << 2)
24 #define KBD_STATUS_INDATA_CMD (1 << 3)
25 #define KBD_STATUS_ENABLE (1 << 4)
26 #define KBD_STATUS_XMIT_TIMEOUT (1 << 5)
27 #define KBD_STATUS_AUX_DATA (1 << 5)
28 #define KBD_STATUS_RECV_TIMEOUT (1 << 6)
29 #define KBD_STATUS_PARITY_EVEN (1 << 7)
31 #define KBD_CMD_KBDIRQ 0x01
32 #define KBD_CMD_AUXIRQ 0x02
33 #define KBD_CMD_KBDDIS 0x10
34 #define KBD_CMD_AUXDIS 0x20
35 #define KBD_CMD_XLATE 0x40
38 #define KBD_REG_COMMAND 0x64
39 #define KBD_REG_DATA 0x60
41 #define MOUSE_ACK 0xfa
44 #define RTC_PORT_ADDR 0x70
45 #define RTC_PORT_DATA 0x71
52 #define RTC_AHOUR 0x05
58 #define RTC_REG_A 0x0a
59 #define RTC_REG_A_RATE 0x0f
60 #define RTC_REG_A_DIV 0x70
61 #define RTC_REG_A_UIP 0x80
63 #define RTC_REG_B 0x0b
64 #define RTC_REG_B_DST (1 << 0)
65 #define RTC_REG_B_24H (1 << 1)
66 #define RTC_REG_B_BIN (1 << 2)
67 #define RTC_REG_B_SQE (1 << 3)
68 #define RTC_REG_B_UIE (1 << 4)
69 #define RTC_REG_B_AIE (1 << 5)
70 #define RTC_REG_B_PIE (1 << 6)
71 #define RTC_REG_B_DCU (1 << 7)
73 #define RTC_REG_C 0x0c
74 #define RTC_REG_C_UIE (1 << 4)
75 #define RTC_REG_C_AIE (1 << 5)
76 #define RTC_REG_C_PIE (1 << 6)
77 #define RTC_REG_C_IRQF (1 << 7)
80 #define RTC_REG_D_RAMP (1 << 7)
82 #define BCD_TO_BIN(b) (((((b) >> 4) & 0xf) * 10) + ((b) & 0xf))
109 mask
&= ~(1 << (irq
- 8));
124 outb(0x60 | (irq
- 8), 0xa0);
128 outb(0x60 | irq
, 0x20);
137 static uint64 curID
= 0;
140 * XXX: One day this should be a little more robust than a one-up.
146 static struct MouseCB
*mouseCB
;
149 InstallMouseCB(MouseCBFun cb
)
153 new = alloc(sizeof(struct MouseCB
));
164 RemoveMouseCB(CbID id
)
166 struct MouseCB
*s
, *del
= NULL
;
168 ASSERT(mouseCB
!= NULL
);
170 /* Shouldn't need a lock here */
171 if (mouseCB
->id
== id
) {
176 for (s
= mouseCB
; s
->next
!= NULL
; s
= s
->next
) {
177 if (s
->next
->id
== id
) {
179 s
->next
= s
->next
->next
;
186 bzero(del
, sizeof(struct MouseCB
));
192 InstallIDTEntry(uint64 vec
, void (*stub
)(void))
194 uint64
*idt
= (uint64
*)IDT
;
195 VA stubAddr
= (VA
)stub
;
197 *(idt
+ 2 * vec
) = (((stubAddr
& 0xffff0000) << 32) |
199 ((CS64
& 0xffff) << 16) |
200 (stubAddr
& 0xffff));
201 *(idt
+ 2 * vec
+ 1) = (stubAddr
>> 32) & 0xffffffff;
209 char time
[] = { ' ', ' ', ':', ' ', ' ', ':', ' ', ' ', 0 };
211 time
[0] = tod
.hour
/ 10 + '0';
212 time
[1] = tod
.hour
% 10 + '0';
213 time
[3] = tod
.minute
/ 10 + '0';
214 time
[4] = tod
.minute
% 10 + '0';
215 time
[6] = tod
.second
/ 10 + '0';
216 time
[7] = tod
.second
% 10 + '0';
218 p1
.x
= xResolution
- 4;
219 p1
.y
= yResolution
- 4;
224 ColorRectangle(COLOR_PLEASING_GREEN
, p0
, p1
);
225 PrintMessage(COLOR_BLACK
, p0
, time
);
231 /* ACK the interrupt */
232 outb(RTC_REG_C
, RTC_PORT_ADDR
);
235 /* update the time of day */
236 if (++tod
.second
>= 60) {
238 if (++tod
.minute
>= 60) {
240 if (++tod
.hour
>= 24) {
251 while (inb(KBD_REG_STATUS
) & KBD_STATUS_IN_DATA
); // 0x2
257 while (~inb(KBD_REG_STATUS
) & KBD_STATUS_OUT_DATA
); // 0x1
264 return inb(KBD_REG_DATA
);
269 ClearKeyDisplay(void)
274 p0
.y
= yResolution
- 4 - 16;
276 p1
.x
= 4 + 8 * 16; // max of 16 16 pix wide chars
277 p1
.y
= yResolution
- 4;
279 ColorRectangle(COLOR_PLEASING_GREEN
, p0
, p1
);
285 #define lbHex(b) ((((b) & 0xf) < 0xa) ? \
286 ((b) & 0xf) + '0' : \
287 (((b) & 0xf) - 0xa) + 'a')
288 #define hbHex(b) (lbHex((b) >> 4))
299 for (k
= 0; k
< keyp
; k
++) {
300 c
[2 * k
] = hbHex(keys
[k
]);
301 c
[2 * k
+ 1] = lbHex(keys
[k
]);
305 p
.y
= yResolution
- 4 - 16;
307 PrintMessage(COLOR_BLACK
, p
, c
);
312 * HaveCompleteScancode --
314 * Check that a fully formed mode 2 raw scancode has been received.
318 HaveCompleteScancode(void)
329 if (keys
[0] == 0xe0) {
330 if (keyp
== 1 || (keyp
== 2 && keys
[1] == 0xf0)) {
333 } else if (keys
[0] == 0xe1) {
334 if (keyp
< 3 || (keyp
== 3 && keys
[1] == 0xf0) || keyp
== 4) {
337 } else if (keys
[0] == 0xf0 && keyp
== 1) {
347 * Handle the keyboard interrupt.
355 if (HaveCompleteScancode()) {
359 bzero(keys
, sizeof(keys
));
367 uint64 mousePacketLength
;
371 MousePacketDisplay(uint8
*packet
, uint64 N
)
380 p0
.y
= yResolution
- 8 - 32;
383 ColorRectangle(COLOR_PLEASING_GREEN
, p0
, p1
);
385 for (k
= 0; k
< N
; k
++) {
386 s
[2 * k
] = hbHex(packet
[k
]);
387 s
[2 * k
+ 1] = lbHex(packet
[k
]);
390 PrintMessage(COLOR_BLACK
, p0
, s
);
397 mouse
[mousep
++] = data
;
399 if (mousep
== mousePacketLength
) {
402 for (s
= mouseCB
; s
!= NULL
; s
= s
->next
) {
403 s
->cb(mouse
, mousep
);
406 bzero(mouse
, sizeof(mouse
));
417 status
= inb(KBD_REG_STATUS
);
418 if (!(status
& KBD_STATUS_OUT_DATA
)) {
422 data
= inb(KBD_REG_DATA
);
424 if (status
& KBD_STATUS_AUX_DATA
) {
435 * Display an indicator of received interrupts.
439 _IRQPrint(uint64 irq
)
441 /* Not reentrant, but that isn't important here. */
442 static int counts
[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
443 char s
[] = { 'I', 'R', 'Q', ' ', '(', ' ', ')', 0 };
444 char c
[] = { '-', '\\', '|', '/' };
449 count
= counts
[irq
]++;
451 count
= counts
[16]++;
454 s
[3] = (irq
< 0xa) ? irq
+ 0x30 : irq
- 0xa + 'a';
455 s
[5] = c
[count
% sizeof(c
)];
460 p0
.y
= 30 + irq
* 18;
468 ColorRectangle(COLOR_PLEASING_GREEN
, p0
, p1
);
469 PrintMessage(COLOR_BLACK
, p0
, s
);
476 _IRQPrint(irq
- 0x20);
483 TaskSchedule(irq
); // does not return
495 UnmaskPIC(irq
- 0x20);
505 * Actually 1193181.666... but this isn't used for keeping time to the
506 * round off error isn't significant (and it's doubtful the clock is
507 * that accurate anyways).
509 #define PIT_CLK_FREQ 1193182
510 #define PIT_COUNTDOWN (PIT_CLK_FREQ / TICK_Hz)
512 #define PIT_CW_BIN 0x00
513 #define PIT_CW_BCD 0x01
514 #define PIT_CW_MODE0 0x00
515 #define PIT_CW_MODE1 0x02
516 #define PIT_CW_MODE2 0x04
517 #define PIT_CW_MODE3 0x06
518 #define PIT_CW_MODE4 0x08
519 #define PIT_CW_MODE5 0x0a
520 #define PIT_CW_RW_LATCH 0x00
521 #define PIT_CW_RW_LSB 0x10
522 #define PIT_CW_RW_MSB 0x20
523 #define PIT_CW_RW_LSBMSB 0x30
524 #define PIT_CW_CTR0 0x00
525 #define PIT_CW_CTR1 0x40
526 #define PIT_CW_CTR2 0x80
527 #define PIT_CW_READBACK 0xc0
536 * Set the PIT to TICK_Hz.
539 tick
= PIT_COUNTDOWN
;
540 outb(PIT_CW_BIN
| PIT_CW_MODE2
| PIT_CW_RW_LSBMSB
| PIT_CW_CTR0
, PIT_CW
);
541 outb(tick
& 0xff, PIT_C0
);
542 outb(tick
>> 8, PIT_C0
);
544 InstallIDTEntry(PIT_IRQ
, _IRQStub_PIT
);
545 UnmaskPIC(PIT_IRQ
- 0x20);
553 * Disable daylight savings, enable 24 hour clock, and enable
554 * update ended interrupt.
557 outb(RTC_REG_B
, RTC_PORT_ADDR
);
558 outb(RTC_REG_B_24H
| RTC_REG_B_UIE
, RTC_PORT_DATA
);
561 * Initialize the clock.
565 outb(RTC_REG_A
, RTC_PORT_ADDR
);
566 if ((inb(RTC_PORT_DATA
) & RTC_REG_A_UIP
) == 0) {
571 outb(RTC_SEC
, RTC_PORT_ADDR
);
572 tod
.second
= BCD_TO_BIN(inb(RTC_PORT_DATA
));
573 outb(RTC_MIN
, RTC_PORT_ADDR
);
574 tod
.minute
= BCD_TO_BIN(inb(RTC_PORT_DATA
));
575 outb(RTC_HOUR
, RTC_PORT_ADDR
);
576 tod
.hour
= BCD_TO_BIN(inb(RTC_PORT_DATA
));
581 InstallIDTEntry(RTC_IRQ
, _IRQStub_RTC
);
582 UnmaskPIC(RTC_IRQ
- 0x20);
587 i8042_WriteCmd(uint8 cmd
)
590 outb(cmd
, KBD_REG_COMMAND
);
597 return inb(KBD_REG_DATA
);
601 i8042_WriteData(uint8 data
)
604 outb(data
, KBD_REG_DATA
);
612 /* Get keyboard command register. */
613 i8042_WriteCmd(0x20);
614 cmd
= i8042_ReadData();
616 /* Enable keyboard. */
617 cmd
&= ~KBD_CMD_KBDDIS
;
618 cmd
|= KBD_CMD_KBDIRQ
;
620 i8042_WriteCmd(0x60);
621 i8042_WriteData(cmd
);
623 /* Set keyboard mode 2. */
624 i8042_WriteData(0xf0);
625 i8042_WriteData(0x02);
627 /* Clear keyboard buffer. */
629 bzero(keys
, sizeof(keys
));
632 /* Install handler. */
633 InstallIDTEntry(KBD_IRQ
, _IRQStub_KBD
);
634 UnmaskPIC(KBD_IRQ
- 0x20);
639 i8042_WriteAuxCmd(uint8 cmd
)
642 outb(0xd4, KBD_REG_COMMAND
);
644 outb(cmd
, KBD_REG_DATA
);
646 return inb(KBD_REG_DATA
);
654 /* Get keyboard command register. */
655 i8042_WriteCmd(0x20);
656 cmd
= i8042_ReadData();
658 /* Enable PS/2 mouse. */
659 cmd
&= ~KBD_CMD_KBDDIS
;
660 cmd
|= KBD_CMD_KBDIRQ
;
662 i8042_WriteCmd(0x60);
663 i8042_WriteData(cmd
);
665 i8042_WriteData(0xa8);
667 /* Check for intellimouse extension */
668 i8042_WriteAuxCmd(0xf3);
669 i8042_WriteAuxCmd(200);
670 i8042_WriteAuxCmd(0xf3);
671 i8042_WriteAuxCmd(100);
672 i8042_WriteAuxCmd(0xf3);
673 i8042_WriteAuxCmd(80);
675 i8042_WriteAuxCmd(0xf2);
676 data
= inb(KBD_REG_DATA
);
679 mousePacketLength
= 4;
681 mousePacketLength
= 3;
684 /* Set sample rate */
685 i8042_WriteAuxCmd(0xf3);
686 i8042_WriteAuxCmd(MOUSE_SAMPLE_RATE
);
688 /* Set stream mode */
689 i8042_WriteAuxCmd(0xea); // set stream mode
692 i8042_WriteAuxCmd(0xe8);
693 i8042_WriteAuxCmd(3);
696 i8042_WriteAuxCmd(0xe7);
698 /* Enable data reporting */
699 i8042_WriteAuxCmd(0xf4); // enable data reporting
701 bzero(mouse
, sizeof(mouse
));
706 InstallMouseCB(MousePacketDisplay
);
708 /* Install mouse interrupt handler. */
709 InstallIDTEntry(MOUSE_IRQ
, _IRQStub_MOUSE
);
710 UnmaskPIC(MOUSE_IRQ
- 0x20);