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