]> git.sur5r.net Git - cc65/blob - libsrc/apple2/apple2-stdmou.s
Apple 2 mouse driver and other stuff from Oliver Schmidt
[cc65] / libsrc / apple2 / apple2-stdmou.s
1 ;
2 ; Driver for the AppleMouse II Card.
3 ;
4 ; Oliver Schmidt, 03.09.2005
5 ;
6
7         .include        "zeropage.inc"
8         .include        "mouse-kernel.inc"
9
10 ; ------------------------------------------------------------------------
11
12 SETMOUSE        = $12   ; Sets mouse mode
13 SERVEMOUSE      = $13   ; Services mouse interrupt
14 READMOUSE       = $14   ; Reads mouse position
15 CLEARMOUSE      = $15   ; Clears mouse position to 0 (for delta mode)
16 POSMOUSE        = $16   ; Sets mouse position to a user-defined pos
17 CLAMPMOUSE      = $17   ; Sets mouse bounds in a window
18 HOMEMOUSE       = $18   ; Sets mouse to upper-left corner of clamp win
19 INITMOUSE       = $19   ; Resets mouse clamps to default values and
20                         ; sets mouse position to 0,0
21
22 pos1_lo         := $0478
23 pos1_hi         := $0578
24 pos2_lo         := $04F8
25 pos2_hi         := $05F8
26 status          := $0778
27
28 ; ------------------------------------------------------------------------
29
30         .segment        "JUMPTABLE"
31
32         ; Driver signature
33         .byte   $6D, $6F, $75           ; "mou"
34         .byte   MOUSE_API_VERSION       ; Mouse driver API version number
35
36         ; Jump table.
37         .addr   INSTALL
38         .addr   UNINSTALL
39         .addr   HIDE
40         .addr   SHOW
41         .addr   BOX
42         .addr   MOVE
43         .addr   BUTTONS
44         .addr   POS
45         .addr   INFO
46         .addr   IOCTL
47         .addr   IRQ
48
49         ; Callback table, set by the kernel before INSTALL is called
50 CHIDE:  jmp     $0000                   ; Hide the cursor
51 CSHOW:  jmp     $0000                   ; Show the cursor
52 CMOVEX: jmp     $0000                   ; Move the cursor to X coord
53 CMOVEY: jmp     $0000                   ; Move the cursor to Y coord
54
55 ; ------------------------------------------------------------------------
56
57         .bss
58         
59 slot:   .res    1
60 visible:.res    1
61                 
62 ; ------------------------------------------------------------------------
63
64         .rodata
65
66 offsets:.byte   $05             ; Pascal 1.0 ID byte
67         .byte   $07             ; Pascal 1.0 ID byte
68         .byte   $0B             ; Pascal 1.1 generic signature byte
69         .byte   $0C             ; Device signature byte
70
71 values: .byte   $38             ; Fixed
72         .byte   $18             ; Fixed
73         .byte   $01             ; Fixed
74         .byte   $20             ; X-Y pointing device type 0
75
76 size    = * - values
77
78 ; ------------------------------------------------------------------------
79
80         .data
81         
82 info:   .word   279 / 2         ; MOUSE_INFO::MOUSE_POS::XCOORD
83         .word   191 / 2         ; MOUSE_INFO::MOUSE_POS::YCOORD
84         .byte   %00000000       ; MOUSE_INFO::BUTTONS
85
86 firmware:
87         ; Lookup and patch firmware address lobyte
88 lookup: ldy     $FF00,x         ; Patched at runtime
89         sty     jump+1          ; Modify code below
90
91         ; Apple II Mouse TechNote #1, Interrupt Environment with the Mouse:
92         ; "Enter all mouse routines (...) with the X register set to $Cn
93         ;  and Y register set to $n0, where n = the slot number."
94 xparam: ldx     #$FF            ; Patched at runtime
95 yparam: ldy     #$FF            ; Patched at runtime
96
97 jump:   jmp     $FFFF           ; Patched at runtime
98         
99 ; ------------------------------------------------------------------------
100
101         .code
102
103 ; INSTALL: Is called after the driver is loaded into memory. If possible,
104 ; check if the hardware is present. Must return an MOUSE_ERR_xx code in A/X.
105 INSTALL:
106         lda     #<$C000
107         sta     ptr1
108         lda     #>$C000
109         sta     ptr1+1
110
111         ; Search for AppleMouse II firmware in slots 1 - 7
112 next:   inc     ptr1+1
113         lda     ptr1+1
114         cmp     #>$C800
115         bcc     :+
116
117         ; Mouse firmware not found
118         lda     #<MOUSE_ERR_NO_DEVICE
119         ldx     #>MOUSE_ERR_NO_DEVICE
120         rts
121
122         ; Check Pascal 1.1 Firmware Protocol ID bytes
123 :       ldx     #size - 1
124 :       ldy     offsets,x
125         lda     values,x
126         cmp     (ptr1),y
127         bne     next
128         dex
129         bpl     :-
130         
131         ; Get and patch firmware address hibyte
132         lda     ptr1+1
133         sta     lookup+2
134         sta     xparam+1
135         sta     jump+2
136         
137         ; Convert to and save slot number
138         and     #$0F
139         sta     slot
140
141         ; Convert to and patch I/O register index
142         asl
143         asl
144         asl
145         asl
146         sta     yparam+1
147
148         ; Apple II Mouse TechNote #1, Interrupt Environment with the Mouse:
149         ; "Disable interrupts when calling any mouse routine."
150         sei
151
152         ; Reset mouse hardware
153         ldx     #INITMOUSE
154         jsr     firmware
155
156         ; Turn mouse on
157         lda     #%00000001
158         ldx     #SETMOUSE
159         jsr     firmware
160
161         ; Set initial mouse clamps      
162         lda     #<279
163         ldx     #>279
164         sta     pos2_lo
165         stx     pos2_hi
166         lda     #$00            ; Set x clamps
167         sta     pos1_lo
168         sta     pos1_hi
169         ldx     #CLAMPMOUSE
170         jsr     firmware
171         lda     #<191
172         ldx     #>191
173         sta     pos2_lo
174         stx     pos2_hi
175         lda     #$01            ; Set y clamps
176         ldx     #CLAMPMOUSE
177         jsr     firmware
178
179         ; Set initial mouse position
180         ldx     slot
181         lda     #<(279 / 2)
182         sta     pos1_lo,x
183         lda     #>(279 / 2)
184         sta     pos1_hi,x
185         lda     #<(191 / 2)
186         sta     pos2_lo,x
187         lda     #>(191 / 2)
188         sta     pos2_hi,x
189         ldx     #POSMOUSE
190         jsr     firmware
191
192         ; Turn VBL interrupt on
193         lda     #%00001001
194         ldx     #SETMOUSE
195 common: jsr     firmware
196
197         ; Enable interrupts and return success
198         cli
199         lda     #<MOUSE_ERR_OK
200         ldx     #>MOUSE_ERR_OK
201         rts
202
203 ; UNINSTALL: Is called before the driver is removed from memory.
204 ; No return code required (the driver is removed from memory on return).
205 UNINSTALL:
206         ; Hide cursor
207         sei
208         jsr     CHIDE
209         
210         ; Turn mouse off
211         lda     #%00000000
212         ldx     #SETMOUSE
213         bne     common          ; Branch always
214
215 ; HIDE: Is called to hide the mouse cursor. The mouse kernel manages a
216 ; counter for calls to show/hide, and the driver entry point is only called
217 ; if the mouse is currently visible and should get hidden. For most drivers,
218 ; no special action is required besides hiding the mouse cursor.
219 ; No return code required.
220 HIDE:
221         dec     visible
222         sei
223         jsr     CHIDE
224         cli
225         rts
226
227 ; SHOW: Is called to show the mouse cursor. The mouse kernel manages a
228 ; counter for calls to show/hide, and the driver entry point is only called
229 ; if the mouse is currently hidden and should become visible. For most drivers,
230 ; no special action is required besides enabling the mouse cursor.
231 ; No return code required.
232 SHOW:
233         inc     visible
234         rts
235
236 ; BOX: Set the mouse bounding box. The parameters are passed as they come from
237 ; the C program, that is, maxy in A/X and the other parameters on the stack.
238 ; The C wrapper will remove the parameters from the stack when the driver
239 ; routine returns.
240 ; No checks are done if the mouse is currently inside the box, this is the job
241 ; of the caller. It is not necessary to validate the parameters, trust the
242 ; caller and save some code here. No return code required.
243 BOX:
244         ; Apple II Mouse TechNote #1, Interrupt Environment with the Mouse:
245         ; "Disable interrupts before placing position information in the screen holes."
246         sei
247
248         ; Set high clamp
249         sta     pos2_lo
250         txa
251
252         ldx     #$01            ; Set y clamps
253         ldy     #$00            ; Start at top of stack
254         jsr     :+
255         
256         ldx     #$00            ; Set x clamps
257         ldy     #$00            ; Start at top of stack
258
259         ; Set high clamp
260         lda     (sp),y
261         iny
262         sei
263         sta     pos2_lo
264         lda     (sp),y
265         iny
266 :       sta     pos2_hi
267
268         ; Skip one parameter
269         iny
270         iny
271
272         ; Set low clamp
273         lda     (sp),y
274         iny
275         sta     pos1_lo
276         lda     (sp),y
277         sta     pos1_hi
278
279         txa
280         ldx     #CLAMPMOUSE
281         bne     common          ; Branch always
282
283 ; MOVE: Move the mouse to a new position. The position is passed as it comes
284 ; from the C program, that is: x on the stack and y in A/X. The C wrapper will
285 ; remove the parameter from the stack on return.
286 ; No checks are done if the new position is valid (within the bounding box or
287 ; the screen). No return code required.
288 MOVE:
289         ldy     slot
290         sei
291
292         ; Set y
293         sta     pos2_lo,y
294         txa
295         sta     pos2_hi,y
296
297         tya
298         tax
299         ldy     #$00            ; Start at top of stack
300
301         ; Set x
302         lda     (sp),y
303         iny
304         sta     pos1_lo,x
305         lda     (sp),y
306         sta     pos1_hi,x
307
308         ; Update cursor
309         jsr     update
310         
311         ldx     #POSMOUSE
312         bne     common          ; Branch always
313
314 ; BUTTONS: Return the button mask in A/X.
315 BUTTONS:
316         lda     info + MOUSE_INFO::BUTTONS
317         ldx     #$00
318         rts
319
320 ; POS: Return the mouse position in the MOUSE_POS struct pointed to by ptr1.
321 ; No return code required.
322 POS:
323         ldx     #.sizeof(MOUSE_POS)-1
324         bne     copy            ; Branch always
325
326 ; INFO: Returns mouse position and current button mask in the MOUSE_INFO
327 ; struct pointed to by ptr1. No return code required.
328 INFO:
329         ldx     #.sizeof(MOUSE_INFO)-1
330 copy:   txa
331         tay
332         sei
333 :       lda     info,x
334         sta     (ptr1),y
335         dex
336         dey
337         bpl     :-
338         cli
339         rts
340
341 ; IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
342 ; specific data in ptr1, and the ioctl code in A.
343 ; Must return an MOUSE_ERR_xx code in A/X.
344 IOCTL:
345         lda     #<MOUSE_ERR_INV_IOCTL
346         ldx     #>MOUSE_ERR_INV_IOCTL
347         rts
348         
349 ; IRQ: Called from the builtin runtime IRQ handler as a subroutine. All
350 ; registers are already saved, no parameters are passed, but the carry flag
351 ; is clear on entry. The routine must return with carry set if the interrupt
352 ; was handled, otherwise with carry clear.
353 IRQ:
354         ; Check for mouse interrupt
355         ldx     #SERVEMOUSE
356         jsr     firmware
357         bcc     :+
358         clc                     ; Interrupt not handled
359         rts
360
361 :       ldx     #READMOUSE
362         jsr     firmware
363
364         ; Get status
365         ldy     slot
366         lda     status,y
367         tax                     ; Save status
368         
369         ; Extract button down values
370         asl                     ;  C = Button 0 is currently down
371         and     #%00100000      ; !Z = Button 1 is currently down
372
373         ; Set button mask
374         beq     :+
375         lda     #MOUSE_BTN_RIGHT
376 :       bcc     :+
377         ora     #MOUSE_BTN_LEFT
378 :       sta     info + MOUSE_INFO::BUTTONS
379         
380         ; Check for mouse movement
381         txa                     ; Restore status
382         and     #%00100000      ; X or Y changed since last READMOUSE
383         beq     :+
384
385         ; Remove the cursor at the old position
386 update: jsr     CHIDE
387         
388         ; Get and set the new X position
389         ldy     slot
390         lda     pos1_lo,y
391         ldx     pos1_hi,y
392         sta     info + MOUSE_POS::XCOORD
393         stx     info + MOUSE_POS::XCOORD+1
394         jsr     CMOVEX
395         
396         ; Get and set the new Y position
397         ldy     slot
398         lda     pos2_lo,y
399         ldx     pos2_hi,y
400         sta     info + MOUSE_POS::YCOORD
401         stx     info + MOUSE_POS::YCOORD+1
402         jsr     CMOVEY
403
404         ; Check for visibility
405 :       lda     visible
406         beq     :+
407
408         ; Draw the cursor at the new position
409         jsr     CSHOW
410 :       sec                     ; Interrupt handled
411         rts