blob: 09631bd2e825a7ad5d04cfbd47488f0a5d7f9096 [file] [log] [blame]
Kevin O'Connor4b60c002008-02-25 22:29:55 -05001// 16bit code to handle mouse events.
2//
3// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
4// Copyright (C) 2002 MandrakeSoft S.A.
5//
6// This file may be distributed under the terms of the GNU GPLv3 license.
7
Kevin O'Connor9521e262008-07-04 13:04:29 -04008#include "biosvar.h" // GET_EBDA
Kevin O'Connor15c1f222008-06-12 22:59:43 -04009#include "util.h" // debug_isr
Kevin O'Connord21c0892008-11-26 17:02:43 -050010#include "pic.h" // eoi_pic2
Kevin O'Connor9521e262008-07-04 13:04:29 -040011#include "bregs.h" // struct bregs
Kevin O'Connor3b897192008-07-20 10:08:59 -040012#include "ps2port.h" // aux_command
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -050013
Kevin O'Connorf54c1502008-06-14 15:56:16 -040014void
15mouse_setup()
16{
17 if (! CONFIG_PS2_MOUSE)
18 return;
19 dprintf(3, "init mouse\n");
20 // pointing device installed
21 SETBITS_BDA(equipment_list_flags, 0x04);
Kevin O'Connord21c0892008-11-26 17:02:43 -050022 enable_hwirq(12, entry_74);
Kevin O'Connorf54c1502008-06-14 15:56:16 -040023}
24
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -050025#define RET_SUCCESS 0x00
26#define RET_EINVFUNCTION 0x01
27#define RET_EINVINPUT 0x02
28#define RET_EINTERFACE 0x03
29#define RET_ENEEDRESEND 0x04
30#define RET_ENOHANDLER 0x05
31
Kevin O'Connor3b897192008-07-20 10:08:59 -040032static int
33disable_mouse()
34{
35 u8 ps2ctr = GET_EBDA(ps2ctr);
36 ps2ctr |= I8042_CTR_AUXDIS;
37 ps2ctr &= ~I8042_CTR_AUXINT;
38 SET_EBDA(ps2ctr, ps2ctr);
39
40 return aux_command(PSMOUSE_CMD_DISABLE, NULL);
41}
42
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -050043// Disable Mouse
44static void
45mouse_15c20000(struct bregs *regs)
46{
Kevin O'Connor3b897192008-07-20 10:08:59 -040047 int ret = disable_mouse();
48 if (ret)
49 set_code_fail(regs, RET_ENEEDRESEND);
50 else
51 set_code_success(regs);
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -050052}
53
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -050054// Enable Mouse
55static void
56mouse_15c20001(struct bregs *regs)
57{
58 u8 mouse_flags_2 = GET_EBDA(mouse_flag2);
59 if ((mouse_flags_2 & 0x80) == 0) {
Kevin O'Connor6c781222008-03-09 12:19:23 -040060 set_code_fail(regs, RET_ENOHANDLER);
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -050061 return;
62 }
Kevin O'Connor3b897192008-07-20 10:08:59 -040063
64 u8 ps2ctr = GET_EBDA(ps2ctr);
65 ps2ctr &= ~I8042_CTR_AUXDIS;
66 ps2ctr |= I8042_CTR_AUXINT;
67 SET_EBDA(ps2ctr, ps2ctr);
68
69 int ret = aux_command(PSMOUSE_CMD_ENABLE, NULL);
70 if (ret)
71 set_code_fail(regs, RET_ENEEDRESEND);
72 else
Kevin O'Connor6c781222008-03-09 12:19:23 -040073 set_code_success(regs);
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -050074}
75
76static void
77mouse_15c200XX(struct bregs *regs)
78{
Kevin O'Connor6c781222008-03-09 12:19:23 -040079 set_code_fail(regs, RET_EINVFUNCTION);
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -050080}
81
82// Disable/Enable Mouse
83static void
84mouse_15c200(struct bregs *regs)
85{
86 switch (regs->bh) {
87 case 0x00: mouse_15c20000(regs); break;
88 case 0x01: mouse_15c20001(regs); break;
89 default: mouse_15c200XX(regs); break;
90 }
91}
92
93// Reset Mouse
94static void
95mouse_15c201(struct bregs *regs)
96{
Kevin O'Connor3b897192008-07-20 10:08:59 -040097 u8 param[2];
98 int ret = aux_command(PSMOUSE_CMD_RESET_BAT, param);
Kevin O'Connorf13b0082008-08-17 11:26:42 -040099 if (ret != 0 && ret != 2) {
Kevin O'Connor6c781222008-03-09 12:19:23 -0400100 set_code_fail(regs, RET_ENEEDRESEND);
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500101 return;
102 }
Kevin O'Connor3b897192008-07-20 10:08:59 -0400103 regs->bl = param[0];
104 regs->bh = param[1];
Kevin O'Connor6c781222008-03-09 12:19:23 -0400105 set_code_success(regs);
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500106}
107
108// Set Sample Rate
109static void
110mouse_15c202(struct bregs *regs)
111{
Kevin O'Connor3b897192008-07-20 10:08:59 -0400112 static u8 sample_rates[7] = {10, 20, 40, 60, 80, 100, 200};
113 if (regs->bh >= ARRAY_SIZE(sample_rates)) {
114 set_code_fail(regs, RET_EINVINPUT);
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500115 return;
116 }
Kevin O'Connor3b897192008-07-20 10:08:59 -0400117 u8 mouse_data1 = GET_VAR(CS, sample_rates[regs->bh]);
118 int ret = aux_command(PSMOUSE_CMD_SETRATE, &mouse_data1);
119 if (ret)
120 set_code_fail(regs, RET_ENEEDRESEND);
121 else
122 set_code_success(regs);
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500123}
124
125// Set Resolution
126static void
127mouse_15c203(struct bregs *regs)
128{
129 // BH:
130 // 0 = 25 dpi, 1 count per millimeter
131 // 1 = 50 dpi, 2 counts per millimeter
132 // 2 = 100 dpi, 4 counts per millimeter
133 // 3 = 200 dpi, 8 counts per millimeter
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500134 if (regs->bh >= 4) {
Kevin O'Connor3b897192008-07-20 10:08:59 -0400135 set_code_fail(regs, RET_EINVINPUT);
136 return;
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500137 }
Kevin O'Connor3b897192008-07-20 10:08:59 -0400138 u8 param = regs->bh;
139 int ret = aux_command(PSMOUSE_CMD_SETRES, &param);
140 if (ret)
141 set_code_fail(regs, RET_ENEEDRESEND);
142 else
143 set_code_success(regs);
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500144}
145
146// Get Device ID
147static void
148mouse_15c204(struct bregs *regs)
149{
Kevin O'Connor3b897192008-07-20 10:08:59 -0400150 u8 param[2];
151 int ret = aux_command(PSMOUSE_CMD_GETID, param);
152 if (ret) {
153 set_code_fail(regs, RET_ENEEDRESEND);
154 return;
155 }
156 regs->bh = param[0];
Kevin O'Connor6c781222008-03-09 12:19:23 -0400157 set_code_success(regs);
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500158}
159
160// Initialize Mouse
161static void
162mouse_15c205(struct bregs *regs)
163{
164 if (regs->bh != 3) {
Kevin O'Connor6c781222008-03-09 12:19:23 -0400165 set_code_fail(regs, RET_EINTERFACE);
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500166 return;
167 }
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500168 SET_EBDA(mouse_flag1, 0x00);
169 SET_EBDA(mouse_flag2, regs->bh);
170
171 // Reset Mouse
172 mouse_15c201(regs);
173}
174
175// Return Status
176static void
177mouse_15c20600(struct bregs *regs)
178{
Kevin O'Connor3b897192008-07-20 10:08:59 -0400179 u8 param[3];
180 int ret = aux_command(PSMOUSE_CMD_GETINFO, param);
181 if (ret) {
182 set_code_fail(regs, RET_ENEEDRESEND);
183 return;
184 }
185 regs->bl = param[0];
186 regs->cl = param[1];
187 regs->dl = param[2];
Kevin O'Connor6c781222008-03-09 12:19:23 -0400188 set_code_success(regs);
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500189}
190
191// Set Scaling Factor to 1:1
192static void
193mouse_15c20601(struct bregs *regs)
194{
Kevin O'Connor3b897192008-07-20 10:08:59 -0400195 int ret = aux_command(PSMOUSE_CMD_SETSCALE11, NULL);
196 if (ret)
197 set_code_fail(regs, RET_ENEEDRESEND);
198 else
199 set_code_success(regs);
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500200}
201
202// Set Scaling Factor to 2:1
203static void
204mouse_15c20602(struct bregs *regs)
205{
Kevin O'Connor3b897192008-07-20 10:08:59 -0400206 int ret = aux_command(PSMOUSE_CMD_SETSCALE21, NULL);
207 if (ret)
208 set_code_fail(regs, RET_ENEEDRESEND);
209 else
210 set_code_success(regs);
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500211}
212
213static void
214mouse_15c206XX(struct bregs *regs)
215{
Kevin O'Connor3b897192008-07-20 10:08:59 -0400216 set_code_fail(regs, RET_EINVFUNCTION);
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500217}
218
219// Return Status & Set Scaling Factor...
220static void
221mouse_15c206(struct bregs *regs)
222{
223 switch (regs->bh) {
224 case 0x00: mouse_15c20600(regs); break;
225 case 0x01: mouse_15c20601(regs); break;
226 case 0x02: mouse_15c20602(regs); break;
227 default: mouse_15c206XX(regs); break;
228 }
229}
230
231// Set Mouse Handler Address
232static void
233mouse_15c207(struct bregs *regs)
234{
235 u32 farptr = (regs->es << 16) | regs->bx;
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500236 u8 mouse_flags_2 = GET_EBDA(mouse_flag2);
237 if (! farptr) {
238 /* remove handler */
239 if ((mouse_flags_2 & 0x80) != 0) {
240 mouse_flags_2 &= ~0x80;
Kevin O'Connor3b897192008-07-20 10:08:59 -0400241 disable_mouse();
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500242 }
243 } else {
244 /* install handler */
245 mouse_flags_2 |= 0x80;
246 }
247 SET_EBDA(mouse_flag2, mouse_flags_2);
Kevin O'Connor3b897192008-07-20 10:08:59 -0400248 SET_EBDA(far_call_pointer, farptr);
Kevin O'Connor6c781222008-03-09 12:19:23 -0400249 set_code_success(regs);
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500250}
251
252static void
253mouse_15c2XX(struct bregs *regs)
254{
Kevin O'Connor6c781222008-03-09 12:19:23 -0400255 set_code_fail(regs, RET_EINVFUNCTION);
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500256}
257
258void
259handle_15c2(struct bregs *regs)
260{
Kevin O'Connorc65a3802008-03-02 13:58:23 -0500261 //debug_stub(regs);
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500262
263 if (! CONFIG_PS2_MOUSE) {
Kevin O'Connor6c781222008-03-09 12:19:23 -0400264 set_code_fail(regs, RET_EUNSUPPORTED);
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500265 return;
266 }
267
Kevin O'Connor3b897192008-07-20 10:08:59 -0400268 irq_enable();
269
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500270 switch (regs->al) {
271 case 0x00: mouse_15c200(regs); break;
272 case 0x01: mouse_15c201(regs); break;
273 case 0x02: mouse_15c202(regs); break;
274 case 0x03: mouse_15c203(regs); break;
275 case 0x04: mouse_15c204(regs); break;
276 case 0x05: mouse_15c205(regs); break;
277 case 0x06: mouse_15c206(regs); break;
278 case 0x07: mouse_15c207(regs); break;
279 default: mouse_15c2XX(regs); break;
280 }
281}
282
283static void
Kevin O'Connor4b60c002008-02-25 22:29:55 -0500284int74_function()
285{
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500286 u8 v = inb(PORT_PS2_STATUS);
Kevin O'Connor3b897192008-07-20 10:08:59 -0400287 if ((v & 0x21) != 0x21) {
288 dprintf(1, "int74 but no mouse data.\n");
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500289 return;
Kevin O'Connor3b897192008-07-20 10:08:59 -0400290 }
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500291 v = inb(PORT_PS2_DATA);
292
293 u8 mouse_flags_1 = GET_EBDA(mouse_flag1);
294 u8 mouse_flags_2 = GET_EBDA(mouse_flag2);
295
Kevin O'Connor65e63422008-07-19 14:12:32 -0400296 if (! (mouse_flags_2 & 0x80))
297 // far call handler not installed
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500298 return;
299
300 u8 package_count = mouse_flags_2 & 0x07;
301 u8 index = mouse_flags_1 & 0x07;
302 SET_EBDA(mouse_data[index], v);
303
304 if ((index+1) < package_count) {
305 mouse_flags_1++;
306 SET_EBDA(mouse_flag1, mouse_flags_1);
307 return;
308 }
309
310 //BX_DEBUG_INT74("int74_function: make_farcall=1\n");
311 u16 status = GET_EBDA(mouse_data[0]);
312 u16 X = GET_EBDA(mouse_data[1]);
313 u16 Y = GET_EBDA(mouse_data[2]);
314 SET_EBDA(mouse_flag1, 0);
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500315
316 u32 func = GET_EBDA(far_call_pointer);
317 asm volatile(
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500318 "pushl %0\n"
319 "pushw %w1\n" // status
320 "pushw %w2\n" // X
321 "pushw %w3\n" // Y
322 "pushw $0\n" // Z
323 "lcallw *8(%%esp)\n"
324 "addl $12, %%esp\n"
Kevin O'Connor7a558e42008-03-11 20:38:33 -0400325 "cld\n"
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500326 : "+a" (func), "+b" (status), "+c" (X), "+d" (Y)
327 :
Kevin O'Connor7a558e42008-03-11 20:38:33 -0400328 : "esi", "edi", "ebp", "cc"
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500329 );
Kevin O'Connor4b60c002008-02-25 22:29:55 -0500330}
331
332// INT74h : PS/2 mouse hardware interrupt
Kevin O'Connor19786762008-03-05 21:09:59 -0500333void VISIBLE16
Kevin O'Connored128492008-03-11 11:14:59 -0400334handle_74()
Kevin O'Connor4b60c002008-02-25 22:29:55 -0500335{
Kevin O'Connor15c1f222008-06-12 22:59:43 -0400336 debug_isr(DEBUG_ISR_74);
Kevin O'Connor40967022008-07-21 22:23:05 -0400337 if (! CONFIG_PS2_MOUSE)
338 goto done;
Kevin O'Connor4b60c002008-02-25 22:29:55 -0500339
340 irq_enable();
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500341 int74_function();
Kevin O'Connor4b60c002008-02-25 22:29:55 -0500342 irq_disable();
Kevin O'Connor4d6dbc62008-03-02 08:43:44 -0500343
Kevin O'Connor40967022008-07-21 22:23:05 -0400344done:
Kevin O'Connorf54c1502008-06-14 15:56:16 -0400345 eoi_pic2();
Kevin O'Connor4b60c002008-02-25 22:29:55 -0500346}