]> git.dujemihanovic.xyz Git - nameless-os.git/blob - kernel/drivers/input/ps2.c
e765b24bcbcd316fa9448df3cfbacd14afaaa964
[nameless-os.git] / kernel / drivers / input / ps2.c
1 #include <tty.h>
2 #include <io.h>
3 #include <input/ps2.h>
4 #include <bitflags.h>
5
6 int ps2_initialize()
7 {
8 uint8_t ccb, is_2channel, port_1_test, port_2_test;
9
10 kprint("ps2: Begin initializing PS/2 controller\n", 0);
11 outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_2_DISABLE);
12 ps2_input_wait();
13 outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_1_DISABLE);
14 ps2_input_wait();
15 inb(PS2_DATA_PORT);
16
17 outb(PS2_CMD_STS_PORT, PS2_CMD_READ_CCB);
18 ps2_output_wait();
19 ccb = inb(PS2_DATA_PORT);
20
21 CLEAR(ccb, 0);
22 CLEAR(ccb, 1);
23 CLEAR(ccb, 6);
24
25 ps2_input_wait();
26 outb(PS2_CMD_STS_PORT, PS2_CMD_WRITE_CCB);
27 ps2_input_wait();
28 outb(PS2_DATA_PORT, ccb);
29
30 ps2_input_wait();
31 outb(PS2_CMD_STS_PORT, PS2_CMD_CONTROLLER_TEST);
32 ps2_output_wait();
33 if (inb(PS2_DATA_PORT) != PS2_CONTROLLER_GOOD) {
34 kprint("ps2: Controller self test failed, exiting!\n", 0);
35 return -1;
36 };
37
38 ps2_input_wait();
39 outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_2_ENABLE);
40 ps2_input_wait();
41 outb(PS2_CMD_STS_PORT, PS2_CMD_READ_CCB);
42 ps2_output_wait();
43 ccb = inb(PS2_DATA_PORT);
44
45 if (ccb & PORT_2_CLK != PORT_2_CLK) {
46 is_2channel = 0;
47 kprint("ps2: Controller is single-channel\n", 0);
48 } else {
49 is_2channel = 1;
50 kprint("ps2: Controller is dual-channel\n", 0);
51 ps2_input_wait();
52 outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_2_DISABLE);
53 }
54
55 ps2_input_wait();
56 outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_1_TEST);
57 ps2_output_wait();
58
59 if (inb(PS2_DATA_PORT) != 0) {
60 port_1_test = 0;
61 kprint("ps2: Port 1 test failed!\n", 0);
62 if (!is_2channel) {
63 kprint("ps2: No functional port, exiting!\n", 0);
64 return -1;
65 }
66 } else port_1_test = 1;
67
68 ps2_input_wait();
69 if (is_2channel) {
70 outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_2_TEST);
71 ps2_output_wait();
72
73 if (inb(PS2_DATA_PORT) != 0) {
74 port_2_test = 0;
75 kprint("ps2: Port 2 test failed!", 0);
76 if (!port_1_test) {
77 kprint("ps2: No functional port, exiting!\n", 0);
78 return -1;
79 }
80 } else port_2_test = 1;
81 }
82
83 if (port_1_test) { ps2_input_wait(); outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_1_ENABLE); }
84 if (port_2_test) { ps2_input_wait(); outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_2_ENABLE); }
85
86 int dev_1_test, dev_2_test;
87
88 if (port_1_test) {
89 uint8_t resp;
90
91 do {
92 ps2_input_wait();
93 outb(PS2_DATA_PORT, PS2_DEV_RESET);
94 ps2_output_wait();
95 resp = inb(PS2_DATA_PORT);
96 } while (resp == RESEND);
97
98 if (resp == SELF_TEST_BAD || resp == SELF_TEST_BAD_2) {
99 dev_1_test = 0;
100 kprint("ps2: Port 1 device self test failed!\n", 0);
101 if (!port_2_test) {
102 kprint("ps2: No functioning devices, exiting!\n", 0);
103 return -1;
104 }
105 } else { dev_1_test = 1; kprint("ps2: Port 1 device test successful\n", 0); }
106 }
107
108 inb(PS2_DATA_PORT);
109 ps2_input_wait();
110
111 if (port_2_test) {
112 uint8_t resp;
113
114 do {
115 ps2_input_wait();
116 outb(PS2_CMD_STS_PORT, PS2_CMD_PORT_2_WRITE);
117 ps2_input_wait();
118 outb(PS2_DATA_PORT, PS2_DEV_RESET);
119 ps2_output_wait();
120 resp = inb(PS2_DATA_PORT);
121 } while (resp == RESEND);
122
123 if (resp == SELF_TEST_BAD || resp == SELF_TEST_BAD_2) {
124 dev_2_test = 0;
125 kprint("ps2: Port 2 device self test failed!\n", 0);
126 if (!dev_1_test) {
127 kprint("ps2: No functioning devices, exiting!\n", 0);
128 return -1;
129 }
130 } else { dev_2_test = 1; kprint("ps2: Port 2 device test successful\n", 0); }
131 }
132
133 inb(PS2_DATA_PORT);
134 inb(PS2_DATA_PORT);
135 ps2_input_wait();
136 outb(PS2_CMD_STS_PORT, PS2_CMD_READ_CCB);
137 ps2_output_wait();
138 ccb = inb(PS2_DATA_PORT);
139
140 SET(ccb, PORT_1_IRQ);
141
142 ps2_input_wait();
143 outb(PS2_CMD_STS_PORT, PS2_CMD_WRITE_CCB);
144 ps2_input_wait();
145 outb(PS2_DATA_PORT, ccb);
146
147 if (dev_2_test && dev_1_test) return 1;
148 else return 0;
149 }
150
151 void ps2_output_wait()
152 {
153 uint8_t status;
154 status = inb(PS2_CMD_STS_PORT);
155
156 while (!IS_SET(status, OUT_STATUS)) status = inb(PS2_CMD_STS_PORT);
157 return;
158 }
159
160 void ps2_input_wait()
161 {
162 uint8_t status;
163 status = inb(PS2_CMD_STS_PORT);
164
165 while (IS_SET(status, IN_STATUS)) status = inb(PS2_CMD_STS_PORT);
166 return;
167 }