~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/seabios/src/mouse.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// 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 LGPLv3 license.
 
7
 
 
8
#include "biosvar.h" // GET_EBDA
 
9
#include "bregs.h" // struct bregs
 
10
#include "hw/ps2port.h" // ps2_mouse_command
 
11
#include "hw/usb-hid.h" // usb_mouse_command
 
12
#include "output.h" // dprintf
 
13
#include "stacks.h" // stack_hop_back
 
14
#include "util.h" // mouse_init
 
15
 
 
16
void
 
17
mouse_init(void)
 
18
{
 
19
    if (! CONFIG_MOUSE)
 
20
        return;
 
21
    dprintf(3, "init mouse\n");
 
22
    // pointing device installed
 
23
    set_equipment_flags(0x04, 0x04);
 
24
}
 
25
 
 
26
static int
 
27
mouse_command(int command, u8 *param)
 
28
{
 
29
    if (usb_mouse_active())
 
30
        return usb_mouse_command(command, param);
 
31
    return ps2_mouse_command(command, param);
 
32
}
 
33
 
 
34
#define RET_SUCCESS      0x00
 
35
#define RET_EINVFUNCTION 0x01
 
36
#define RET_EINVINPUT    0x02
 
37
#define RET_EINTERFACE   0x03
 
38
#define RET_ENEEDRESEND  0x04
 
39
#define RET_ENOHANDLER   0x05
 
40
 
 
41
// Disable Mouse
 
42
static void
 
43
mouse_15c20000(struct bregs *regs)
 
44
{
 
45
    int ret = mouse_command(PSMOUSE_CMD_DISABLE, NULL);
 
46
    if (ret)
 
47
        set_code_invalid(regs, RET_ENEEDRESEND);
 
48
    else
 
49
        set_code_success(regs);
 
50
}
 
51
 
 
52
// Enable Mouse
 
53
static void
 
54
mouse_15c20001(struct bregs *regs)
 
55
{
 
56
    u16 ebda_seg = get_ebda_seg();
 
57
    u8 mouse_flags_2 = GET_EBDA(ebda_seg, mouse_flag2);
 
58
    if ((mouse_flags_2 & 0x80) == 0) {
 
59
        set_code_invalid(regs, RET_ENOHANDLER);
 
60
        return;
 
61
    }
 
62
 
 
63
    int ret = mouse_command(PSMOUSE_CMD_ENABLE, NULL);
 
64
    if (ret)
 
65
        set_code_invalid(regs, RET_ENEEDRESEND);
 
66
    else
 
67
        set_code_success(regs);
 
68
}
 
69
 
 
70
static void
 
71
mouse_15c200XX(struct bregs *regs)
 
72
{
 
73
    set_code_unimplemented(regs, RET_EINVFUNCTION);
 
74
}
 
75
 
 
76
// Disable/Enable Mouse
 
77
static void
 
78
mouse_15c200(struct bregs *regs)
 
79
{
 
80
    switch (regs->bh) {
 
81
    case 0x00: mouse_15c20000(regs); break;
 
82
    case 0x01: mouse_15c20001(regs); break;
 
83
    default:   mouse_15c200XX(regs); break;
 
84
    }
 
85
}
 
86
 
 
87
// Reset Mouse
 
88
static void
 
89
mouse_15c201(struct bregs *regs)
 
90
{
 
91
    u8 param[2];
 
92
    int ret = mouse_command(PSMOUSE_CMD_RESET_BAT, param);
 
93
    if (ret) {
 
94
        set_code_invalid(regs, RET_ENEEDRESEND);
 
95
        return;
 
96
    }
 
97
    regs->bl = param[0];
 
98
    regs->bh = param[1];
 
99
    set_code_success(regs);
 
100
}
 
101
 
 
102
// Set Sample Rate
 
103
static void
 
104
mouse_15c202(struct bregs *regs)
 
105
{
 
106
    static u8 VAR16 sample_rates[7] = {10, 20, 40, 60, 80, 100, 200};
 
107
    if (regs->bh >= ARRAY_SIZE(sample_rates)) {
 
108
        set_code_invalid(regs, RET_EINVINPUT);
 
109
        return;
 
110
    }
 
111
    u8 mouse_data1 = GET_GLOBAL(sample_rates[regs->bh]);
 
112
    int ret = mouse_command(PSMOUSE_CMD_SETRATE, &mouse_data1);
 
113
    if (ret)
 
114
        set_code_invalid(regs, RET_ENEEDRESEND);
 
115
    else
 
116
        set_code_success(regs);
 
117
}
 
118
 
 
119
// Set Resolution
 
120
static void
 
121
mouse_15c203(struct bregs *regs)
 
122
{
 
123
    // BH:
 
124
    //      0 =  25 dpi, 1 count  per millimeter
 
125
    //      1 =  50 dpi, 2 counts per millimeter
 
126
    //      2 = 100 dpi, 4 counts per millimeter
 
127
    //      3 = 200 dpi, 8 counts per millimeter
 
128
    if (regs->bh >= 4) {
 
129
        set_code_invalid(regs, RET_EINVINPUT);
 
130
        return;
 
131
    }
 
132
    u8 param = regs->bh;
 
133
    int ret = mouse_command(PSMOUSE_CMD_SETRES, &param);
 
134
    if (ret)
 
135
        set_code_invalid(regs, RET_ENEEDRESEND);
 
136
    else
 
137
        set_code_success(regs);
 
138
}
 
139
 
 
140
// Get Device ID
 
141
static void
 
142
mouse_15c204(struct bregs *regs)
 
143
{
 
144
    u8 param[2];
 
145
    int ret = mouse_command(PSMOUSE_CMD_GETID, param);
 
146
    if (ret) {
 
147
        set_code_invalid(regs, RET_ENEEDRESEND);
 
148
        return;
 
149
    }
 
150
    regs->bh = param[0];
 
151
    set_code_success(regs);
 
152
}
 
153
 
 
154
// Initialize Mouse
 
155
static void
 
156
mouse_15c205(struct bregs *regs)
 
157
{
 
158
    if (regs->bh != 3) {
 
159
        set_code_invalid(regs, RET_EINTERFACE);
 
160
        return;
 
161
    }
 
162
    u16 ebda_seg = get_ebda_seg();
 
163
    SET_EBDA(ebda_seg, mouse_flag1, 0x00);
 
164
    SET_EBDA(ebda_seg, mouse_flag2, regs->bh);
 
165
 
 
166
    // Reset Mouse
 
167
    mouse_15c201(regs);
 
168
}
 
169
 
 
170
// Return Status
 
171
static void
 
172
mouse_15c20600(struct bregs *regs)
 
173
{
 
174
    u8 param[3];
 
175
    int ret = mouse_command(PSMOUSE_CMD_GETINFO, param);
 
176
    if (ret) {
 
177
        set_code_invalid(regs, RET_ENEEDRESEND);
 
178
        return;
 
179
    }
 
180
    regs->bl = param[0];
 
181
    regs->cl = param[1];
 
182
    regs->dl = param[2];
 
183
    set_code_success(regs);
 
184
}
 
185
 
 
186
// Set Scaling Factor to 1:1
 
187
static void
 
188
mouse_15c20601(struct bregs *regs)
 
189
{
 
190
    int ret = mouse_command(PSMOUSE_CMD_SETSCALE11, NULL);
 
191
    if (ret)
 
192
        set_code_invalid(regs, RET_ENEEDRESEND);
 
193
    else
 
194
        set_code_success(regs);
 
195
}
 
196
 
 
197
// Set Scaling Factor to 2:1
 
198
static void
 
199
mouse_15c20602(struct bregs *regs)
 
200
{
 
201
    int ret = mouse_command(PSMOUSE_CMD_SETSCALE21, NULL);
 
202
    if (ret)
 
203
        set_code_invalid(regs, RET_ENEEDRESEND);
 
204
    else
 
205
        set_code_success(regs);
 
206
}
 
207
 
 
208
static void
 
209
mouse_15c206XX(struct bregs *regs)
 
210
{
 
211
    set_code_unimplemented(regs, RET_EINVFUNCTION);
 
212
}
 
213
 
 
214
// Return Status & Set Scaling Factor...
 
215
static void
 
216
mouse_15c206(struct bregs *regs)
 
217
{
 
218
    switch (regs->bh) {
 
219
    case 0x00: mouse_15c20600(regs); break;
 
220
    case 0x01: mouse_15c20601(regs); break;
 
221
    case 0x02: mouse_15c20602(regs); break;
 
222
    default:   mouse_15c206XX(regs); break;
 
223
    }
 
224
}
 
225
 
 
226
// Set Mouse Handler Address
 
227
static void
 
228
mouse_15c207(struct bregs *regs)
 
229
{
 
230
    struct segoff_s farptr = SEGOFF(regs->es, regs->bx);
 
231
    u16 ebda_seg = get_ebda_seg();
 
232
    u8 mouse_flags_2 = GET_EBDA(ebda_seg, mouse_flag2);
 
233
    if (! farptr.segoff) {
 
234
        /* remove handler */
 
235
        if ((mouse_flags_2 & 0x80) != 0) {
 
236
            mouse_flags_2 &= ~0x80;
 
237
            mouse_command(PSMOUSE_CMD_DISABLE, NULL);
 
238
        }
 
239
    } else {
 
240
        /* install handler */
 
241
        mouse_flags_2 |= 0x80;
 
242
    }
 
243
    SET_EBDA(ebda_seg, mouse_flag2, mouse_flags_2);
 
244
    SET_EBDA(ebda_seg, far_call_pointer, farptr);
 
245
    set_code_success(regs);
 
246
}
 
247
 
 
248
static void
 
249
mouse_15c2XX(struct bregs *regs)
 
250
{
 
251
    set_code_unimplemented(regs, RET_EINVFUNCTION);
 
252
}
 
253
 
 
254
void
 
255
handle_15c2(struct bregs *regs)
 
256
{
 
257
    //debug_stub(regs);
 
258
 
 
259
    if (! CONFIG_MOUSE) {
 
260
        set_code_invalid(regs, RET_EUNSUPPORTED);
 
261
        return;
 
262
    }
 
263
 
 
264
    switch (regs->al) {
 
265
    case 0x00: mouse_15c200(regs); break;
 
266
    case 0x01: mouse_15c201(regs); break;
 
267
    case 0x02: mouse_15c202(regs); break;
 
268
    case 0x03: mouse_15c203(regs); break;
 
269
    case 0x04: mouse_15c204(regs); break;
 
270
    case 0x05: mouse_15c205(regs); break;
 
271
    case 0x06: mouse_15c206(regs); break;
 
272
    case 0x07: mouse_15c207(regs); break;
 
273
    default:   mouse_15c2XX(regs); break;
 
274
    }
 
275
}
 
276
 
 
277
void VISIBLE16
 
278
invoke_mouse_handler(void)
 
279
{
 
280
    if (!CONFIG_MOUSE)
 
281
        return;
 
282
    if (need_hop_back()) {
 
283
        stack_hop_back(invoke_mouse_handler, 0, 0);
 
284
        return;
 
285
    }
 
286
    ASSERT16();
 
287
    u16 ebda_seg = get_ebda_seg();
 
288
    u16 status = GET_EBDA(ebda_seg, mouse_data[0]);
 
289
    u16 X      = GET_EBDA(ebda_seg, mouse_data[1]);
 
290
    u16 Y      = GET_EBDA(ebda_seg, mouse_data[2]);
 
291
 
 
292
    struct segoff_s func = GET_EBDA(ebda_seg, far_call_pointer);
 
293
    dprintf(16, "mouse farcall s=%04x x=%04x y=%04x func=%04x:%04x\n"
 
294
            , status, X, Y, func.seg, func.offset);
 
295
 
 
296
    asm volatile(
 
297
        "pushl %%ebp\n"
 
298
        "sti\n"
 
299
 
 
300
        "pushl %0\n"
 
301
        "pushw %w1\n"  // status
 
302
        "pushw %w2\n"  // X
 
303
        "pushw %w3\n"  // Y
 
304
        "pushw $0\n"   // Z
 
305
        "lcallw *8(%%esp)\n"
 
306
        "addl $12, %%esp\n"
 
307
 
 
308
        "cli\n"
 
309
        "cld\n"
 
310
        "popl %%ebp"
 
311
        : "+a"(func.segoff), "+c"(status), "+d"(X), "+b"(Y)
 
312
        :
 
313
        : "edi", "esi", "cc", "memory");
 
314
}
 
315
 
 
316
void
 
317
process_mouse(u8 data)
 
318
{
 
319
    if (!CONFIG_MOUSE)
 
320
        return;
 
321
 
 
322
    u16 ebda_seg = get_ebda_seg();
 
323
    u8 mouse_flags_1 = GET_EBDA(ebda_seg, mouse_flag1);
 
324
    u8 mouse_flags_2 = GET_EBDA(ebda_seg, mouse_flag2);
 
325
 
 
326
    if (! (mouse_flags_2 & 0x80))
 
327
        // far call handler not installed
 
328
        return;
 
329
 
 
330
    u8 package_count = mouse_flags_2 & 0x07;
 
331
    u8 index = mouse_flags_1 & 0x07;
 
332
    SET_EBDA(ebda_seg, mouse_data[index], data);
 
333
 
 
334
    if ((index+1) < package_count) {
 
335
        mouse_flags_1++;
 
336
        SET_EBDA(ebda_seg, mouse_flag1, mouse_flags_1);
 
337
        return;
 
338
    }
 
339
 
 
340
    SET_EBDA(ebda_seg, mouse_flag1, 0);
 
341
    invoke_mouse_handler();
 
342
}