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