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