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