]> git.sur5r.net Git - cc65/blob - libsrc/atari/mou/atrtt.s
Detect pen button. If we read 228 for X or Y position, don't change cursor
[cc65] / libsrc / atari / mou / atrtt.s
1 ;
2 ; Mouse driver for Atari Trakball
3 ;
4 ; Christian Groessler, 2014-01-05
5 ;
6
7         .include        "zeropage.inc"
8         .include        "mouse-kernel.inc"
9         .include        "atari.inc"
10
11         .macpack        generic
12
13 ; ------------------------------------------------------------------------
14 ; Header. Includes jump table
15
16 .segment        "JUMPTABLE"
17
18 HEADER:
19
20 ; Driver signature
21
22         .byte   $6d, $6f, $75           ; "mou"
23         .byte   MOUSE_API_VERSION       ; Mouse driver API version number
24
25 ; Library reference
26
27         .addr   $0000
28
29 ; Jump table
30
31         .addr   INSTALL
32         .addr   UNINSTALL
33         .addr   HIDE
34         .addr   SHOW
35         .addr   SETBOX
36         .addr   GETBOX
37         .addr   MOVE
38         .addr   BUTTONS
39         .addr   POS
40         .addr   INFO
41         .addr   IOCTL
42         .addr   IRQ
43
44 ; Mouse driver flags
45
46         .byte   MOUSE_FLAG_LATE_IRQ
47
48 ; Callback table, set by the kernel before INSTALL is called
49
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 ; Constants
58
59 SCREEN_HEIGHT   = 191
60 SCREEN_WIDTH    = 319
61
62 .enum   JOY
63         UP      = $01
64         DOWN    = $02
65         LEFT    = $04
66         RIGHT   = $08
67 .endenum
68
69 ;----------------------------------------------------------------------------
70 ; Global variables. The bounding box values are sorted so that they can be
71 ; written with the least effort in the SETBOX and GETBOX routines, so don't
72 ; reorder them.
73
74 .bss
75
76 Vars:
77 YPos:           .res    2               ; Current mouse position, Y
78 XPos:           .res    2               ; Current mouse position, X
79 XMin:           .res    2               ; X1 value of bounding box
80 YMin:           .res    2               ; Y1 value of bounding box
81 XMax:           .res    2               ; X2 value of bounding box
82 YMax:           .res    2               ; Y2 value of bounding box
83 Buttons:        .res    1               ; Button mask
84
85
86 visible:        .res    1
87
88 ; Default values for above variables
89
90 .rodata
91
92 .proc   DefVars
93         .word   SCREEN_HEIGHT/2         ; YPos
94         .word   SCREEN_WIDTH/2          ; XPos
95         .word   0                       ; XMin
96         .word   0                       ; YMin
97         .word   SCREEN_WIDTH            ; XMax
98         .word   SCREEN_HEIGHT           ; YMax
99         .byte   0                       ; Buttons
100 .endproc
101
102 .code
103
104 ;----------------------------------------------------------------------------
105 ; INSTALL routine. Is called after the driver is loaded into memory. If
106 ; possible, check if the hardware is present.
107 ; Must return an MOUSE_ERR_xx code in a/x.
108
109 INSTALL:
110
111 ; Initialize variables. Just copy the default stuff over
112
113         ldx     #.sizeof(DefVars)-1
114 @L1:    lda     DefVars,x
115         sta     Vars,x
116         dex
117         bpl     @L1
118
119 ; Be sure the mouse cursor is invisible and at the default location. We
120 ; need to do that here, because our mouse interrupt handler doesn't set the
121 ; mouse position if it hasn't changed.
122
123         php
124         sei
125         jsr     CHIDE
126         lda     XPos
127         ldx     XPos+1
128         jsr     CMOVEX
129         lda     YPos
130         ldx     YPos+1
131         jsr     CMOVEY
132         plp
133
134 ; Done, return zero (= MOUSE_ERR_OK)
135
136         ldx     #$00
137         txa
138         rts
139
140 ;----------------------------------------------------------------------------
141 ; UNINSTALL routine. Is called before the driver is removed from memory.
142 ; No return code required (the driver is removed from memory on return).
143
144 UNINSTALL       = HIDE                  ; Hide cursor on exit
145
146 ;----------------------------------------------------------------------------
147 ; HIDE routine. Is called to hide the mouse pointer. The mouse kernel manages
148 ; a counter for calls to show/hide, and the driver entry point is only called
149 ; if the mouse is currently visible and should get hidden. For most drivers,
150 ; no special action is required besides hiding the mouse cursor.
151 ; No return code required.
152
153 HIDE:   dec     visible
154         php
155         sei
156         jsr     CHIDE
157         plp
158         rts
159
160 ;----------------------------------------------------------------------------
161 ; SHOW routine. Is called to show the mouse pointer. The mouse kernel manages
162 ; a counter for calls to show/hide, and the driver entry point is only called
163 ; if the mouse is currently hidden and should become visible. For most drivers,
164 ; no special action is required besides enabling the mouse cursor.
165 ; No return code required.
166
167 SHOW:   inc     visible
168         php
169         sei
170         jsr     CSHOW
171         plp
172         rts
173
174 ;----------------------------------------------------------------------------
175 ; SETBOX: Set the mouse bounding box. The parameters are passed as they come
176 ; from the C program, that is, a pointer to a mouse_box struct in a/x.
177 ; No checks are done if the mouse is currently inside the box, this is the job
178 ; of the caller. It is not necessary to validate the parameters, trust the
179 ; caller and save some code here. No return code required.
180
181 SETBOX: sta     ptr1
182         stx     ptr1+1                  ; Save data pointer
183
184         ldy     #.sizeof (MOUSE_BOX)-1
185         php
186         sei
187
188 @L1:    lda     (ptr1),y
189         sta     XMin,y
190         dey
191         bpl     @L1
192
193         plp
194         rts
195
196 ;----------------------------------------------------------------------------
197 ; GETBOX: Return the mouse bounding box. The parameters are passed as they
198 ; come from the C program, that is, a pointer to a mouse_box struct in a/x.
199
200 GETBOX: sta     ptr1
201         stx     ptr1+1                  ; Save data pointer
202
203         ldy     #.sizeof (MOUSE_BOX)-1
204         php
205         sei
206
207 @L1:    lda     XMin,y
208         sta     (ptr1),y
209         dey
210         bpl     @L1
211
212         plp
213         rts
214
215 ;----------------------------------------------------------------------------
216 ; MOVE: Move the mouse to a new position. The position is passed as it comes
217 ; from the C program, that is: X on the stack and Y in a/x. The C wrapper will
218 ; remove the parameter from the stack on return.
219 ; No checks are done if the new position is valid (within the bounding box or
220 ; the screen). No return code required.
221 ;
222
223 MOVE:   php
224         sei                             ; No interrupts
225
226         pha
227         lda     visible
228         beq     @nohide
229         txa
230         pha
231         jsr     CHIDE
232         pla
233         tax
234 @nohide:pla
235
236         sta     YPos
237         stx     YPos+1                  ; New Y position
238         jsr     CMOVEY                  ; Set it
239
240         ldy     #$01
241         lda     (sp),y
242         sta     XPos+1
243         tax
244         dey
245         lda     (sp),y
246         sta     XPos                    ; New X position
247
248         jsr     CMOVEX                  ; Move the cursor
249
250         lda     visible
251         beq     @Ret
252         
253         jsr     CSHOW
254
255 @Ret:   plp                             ; Restore interrupt flag
256         rts
257
258 ;----------------------------------------------------------------------------
259 ; BUTTONS: Return the button mask in a/x.
260
261 BUTTONS:
262         lda     Buttons
263         ldx     #$00
264         rts
265
266 ;----------------------------------------------------------------------------
267 ; POS: Return the mouse position in the MOUSE_POS struct pointed to by ptr1.
268 ; No return code required.
269
270 POS:    ldy     #MOUSE_POS::XCOORD      ; Structure offset
271
272         php
273         sei                             ; Disable interrupts
274         lda     XPos                    ; Transfer the position
275         sta     (ptr1),y
276         lda     XPos+1
277         iny
278         sta     (ptr1),y
279         lda     YPos
280         iny
281         sta     (ptr1),y
282         lda     YPos+1
283         plp                             ; Restore interrupt flag
284
285         iny
286         sta     (ptr1),y                ; Store last byte
287
288         rts                             ; Done
289
290 ;----------------------------------------------------------------------------
291 ; INFO: Returns mouse position and current button mask in the MOUSE_INFO
292 ; struct pointed to by ptr1. No return code required.
293 ;
294 ; We're cheating here to keep the code smaller: The first fields of the
295 ; mouse_info struct are identical to the mouse_pos struct, so we will just
296 ; call _mouse_pos to initialize the struct pointer and fill the position
297 ; fields.
298
299 INFO:   jsr     POS
300
301 ; Fill in the button state
302
303         lda     Buttons
304         ldy     #MOUSE_INFO::BUTTONS
305         sta     (ptr1),y
306
307         rts
308
309 ;----------------------------------------------------------------------------
310 ; IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
311 ; specific data in ptr1, and the ioctl code in A.
312 ; Must return an error code in a/x.
313 ;
314
315 IOCTL:  lda     #<MOUSE_ERR_INV_IOCTL     ; We don't support ioclts for now
316         ldx     #>MOUSE_ERR_INV_IOCTL
317         rts
318
319 ;----------------------------------------------------------------------------
320 ; IRQ: Irq handler entry point. Called as a subroutine but in IRQ context
321 ; (so be careful). The routine MUST return carry set if the interrupt has been
322 ; 'handled' - which means that the interrupt source is gone. Otherwise it
323 ; MUST return carry clear.
324 ;
325
326 IRQ:
327
328 ; Check for a pressed button and place the result into Buttons
329
330         ldx     #0
331         stx     XPos+1
332         stx     YPos+1
333         stx     Buttons
334
335         lda     PORTA                   ; get other buttons
336         eor     #255
337         tax
338         and     #5                      ; pen button and left button are mapped to left mouse button
339         beq     @L01
340         lda     #MOUSE_BTN_LEFT
341         ora     Buttons
342         sta     Buttons
343 @L01:   txa
344         and     #8
345         beq     @L02
346         lda     #MOUSE_BTN_RIGHT
347         ora     Buttons
348         sta     Buttons
349
350 ; If we read 228 for X or Y positions, we assume the user has lifted the pen
351 ; and don't change the cursor position.
352
353 @L02:   lda     PADDL0
354         cmp     #228
355         beq     @Dont
356         lda     PADDL1
357         cmp     #228
358         bne     @Do
359 @Dont:  jmp     @Done
360
361 @Do:    lda     visible
362         beq     @L03
363         jsr     CHIDE
364
365 ; Get cursor position
366 ; -------------------
367 ; The touchpad is read thru the paddle potentiometers. The possible
368 ; values are 1..228. Since the maximum value is less than the X
369 ; dimension we have to "stretch" this value. In order to use only
370 ; divisions by powers of two, we use the following appoximation:
371 ; 320/227 = 1.4096
372 ; 1+1/2-1/8+1/32 = 1.4062
373 ; For Y we subtract 1/8 of it to get in the YMax ballpark.
374 ; 228-228/8=199.5
375 ; A small area in the Y dimension of the touchpad isn't used with
376 ; this approximation. The Y value is inverted, (0,0) is the bottom
377 ; left corner of the touchpad.
378
379 ; X
380
381 @L03:   ldx     PADDL0                  ; get X postion
382         dex                             ; decrement, since it's 1-based
383         stx     XPos
384         txa
385         lsr     a
386         tax
387         clc
388         adc     XPos
389         sta     XPos
390         bcc     @L04
391         inc     XPos+1
392 @L04:   txa
393         lsr     a                       ; port value / 4
394         lsr     a                       ; port value / 8
395         tax
396         sec
397         lda     XPos
398         stx     XPos
399         sbc     XPos
400         sta     XPos
401         bcs     @L05
402         dec     XPos+1
403 @L05:   txa
404         lsr     a                       ; port value / 16
405         lsr     a                       ; port value / 32
406         clc
407         adc     XPos
408         sta     XPos
409         bcc     @L06
410         inc     XPos+1
411
412 @L06:   tay
413         lda     XPos+1
414         tax
415
416 ; Limit the X coordinate to the bounding box
417
418         cpy     XMin
419         sbc     XMin+1
420         bpl     @L07
421         ldy     XMin
422         ldx     XMin+1
423         jmp     @L08
424 @L07:   txa
425
426         cpy     XMax
427         sbc     XMax+1
428         bmi     @L08
429         ldy     XMax
430         ldx     XMax+1
431 @L08:   sty     XPos
432         stx     XPos+1
433
434 ; Move the mouse pointer to the new X pos
435
436         tya
437         jsr     CMOVEX
438
439 ; Y
440
441         ldx     PADDL1                  ; get Y postion
442         dex                             ; decrement, since it's 1-based
443         stx     YPos
444         lda     #228
445         sec
446         sbc     YPos                    ; invert value
447         tax
448         lsr     a
449         lsr     a
450         lsr     a
451         sta     YPos
452         txa
453         sec
454         sbc     YPos
455         sta     YPos
456         tay
457         lda     YPos+1
458         tax
459
460 ; Limit the Y coordinate to the bounding box
461
462         cpy     YMin
463         sbc     YMin+1
464         bpl     @L09
465         ldy     YMin
466         ldx     YMin+1
467         jmp     @L10
468 @L09:   txa
469
470         cpy     YMax
471         sbc     YMax+1
472         bmi     @L10
473         ldy     YMax
474         ldx     YMax+1
475 @L10:   sty     YPos
476         stx     YPos+1
477
478 ; Move the mouse pointer to the new X pos
479
480         tya
481         jsr     CMOVEY
482
483         lda     visible
484         beq     @Done
485         jsr     CSHOW
486
487 @Done:  clc                             ; Interrupt not "handled"
488         rts
489