File: atrrdev.s

package info (click to toggle)
cc65 2.19-2
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 20,268 kB
  • sloc: ansic: 117,151; asm: 66,339; pascal: 4,248; makefile: 1,009; perl: 607
file content (585 lines) | stat: -rw-r--r-- 14,499 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
;
; Christian Groessler, Dec-2001
; converted to driver interface Dec-2013
;
; RS232 routines using the R: device (currently tested with an 850 only)
;

        .include        "zeropage.inc"
        .include        "ser-kernel.inc"
        .include        "ser-error.inc"
        .include        "atari.inc"

        .macpack        module


; ------------------------------------------------------------------------
; Header. Includes jump table

.ifdef __ATARIXL__
        module_header   _atrxrdev_ser
.else
        module_header   _atrrdev_ser
.endif

; Driver signature

        .byte   $73, $65, $72           ; "ser"
        .byte   SER_API_VERSION         ; Serial API version number

; Library reference

libref: .addr   $0000

; Jump table

        .word   SER_INSTALL
        .word   SER_UNINSTALL
        .word   SER_OPEN
        .word   SER_CLOSE
        .word   SER_GET
        .word   SER_PUT
        .word   SER_STATUS
        .word   SER_IOCTL
        .word   SER_IRQ


        .rodata

rdev:   .byte   "R:", ATEOL, 0
bauds:  .byte   1               ; SER_BAUD_45_5
        .byte   2               ; SER_BAUD_50
        .byte   4               ; SER_BAUD_75
        .byte   5               ; SER_BAUD_110
        .byte   6               ; SER_BAUD_134_5
        .byte   7               ; SER_BAUD_150
        .byte   8               ; SER_BAUD_300
        .byte   9               ; SER_BAUD_600
        .byte   10              ; SER_BAUD_1200
        .byte   11              ; SER_BAUD_1800
        .byte   12              ; SER_BAUD_2400
        .byte   0               ; SER_BAUD_3600
        .byte   13              ; SER_BAUD_4800
        .byte   0               ; SER_BAUD_7200
        .byte   14              ; SER_BAUD_9600
        .byte   0               ; SER_BAUD_19200
        .byte   0               ; SER_BAUD_38400
        .byte   0               ; SER_BAUD_57600
        .byte   0               ; SER_BAUD_115200
        .byte   0               ; SER_BAUD_230400
        .byte   0               ; SER_BAUD_31250
        .byte   0               ; SER_BAUD_62500
        .byte   3               ; SER_BAUD_56_875
num_bauds       =       * - bauds
databits:
        .byte   48              ; SER_BITS_5
        .byte   32              ; SER_BITS_6
        .byte   16              ; SER_BITS_7
        .byte   0               ; SER_BITS_8
num_databits    =       * - databits
parities:
        .byte   0               ; SER_PAR_NONE
        .byte   4+1             ; SER_PAR_ODD
        .byte   2+8             ; SER_PAR_EVEN
        ;.byte  0               ; SER_PAR_MARK
        ;.byte  0               ; SER_PAR_SPACE
num_parities    =       * - parities

        .bss

; receive buffer
RECVBUF_SZ = 256
recv_buf: .res  RECVBUF_SZ

cm_run: .res    1       ; concurrent mode running?

        .data

rshand: .word   $ffff

; jump table into main program, initialized from libref
my_newfd:
        .byte   $4C
        .word   0
my__close:
        .byte   $4C
        .word   0
my_pushax:
        .byte   $4C
        .word   0
my_popax:
        .byte   $4C
        .word   0
my_findfreeiocb:
        .byte   $4C
        .word   0
my___do_oserror:
        .byte   $4C
        .word   0
my_fddecusage:
        .byte   $4C
        .word   0
my_fdtoiocb:
        .byte   $4C
        .word   0
my___inviocb:
        .byte   $4C
        .word   0
my_clriocb:
        .byte   $4C
        .word   0
my_CIOV:
        .byte   $4C
        .word   0

        .code

invbaud:
        lda     #<SER_ERR_BAUD_UNAVAIL
        ldx     #>SER_ERR_BAUD_UNAVAIL
openerr:
        rts


;----------------------------------------------------------------------------
; SER_OPEN: A pointer to a ser_params structure is passed in ptr1.
; Must return an SER_ERR_xx code in a/x.

SER_OPEN:
        jsr     do_open
        bne     openerr

; set line parameters
        lda     rshand
        ldx     #0
        jsr     my_fdtoiocb     ; get iocb index into X
        bmi     openerr         ; shouldn't happen
        tax

        ; set baud rate, word size, stop bits and ready monitoring

        ; build ICAX1 value
        ldy     #SER_PARAMS::BAUDRATE
        lda     (ptr1),y
        cmp     #num_bauds
        bcs     invbaud

        tay
        lda     bauds,y
        beq     invbaud
        sta     ICAX1,x

        ldy     #SER_PARAMS::DATABITS
        lda     (ptr1),y
        cmp     #num_databits
        bcs     init_err

        tay
        lda     databits,y
        ora     ICAX1,x
        sta     ICAX1,x

        ldy     #SER_PARAMS::STOPBITS
        lda     (ptr1),y
        clc
        ror     a
        ror     a
        ora     ICAX1,x
        sta     ICAX1,x

        lda     #36             ; xio 36, baud rate
        sta     ICCOM,x
        lda     #0
        ;ICAX2 = 0, monitor nothing
        sta     ICAX2,x
        sta     ICBLL,x
        sta     ICBLH,x
        sta     ICBAL,x
        sta     ICBAH,x
        jsr     my_CIOV
        bmi     cioerr

        ; check if the handshake setting is valid
        ldy     #SER_PARAMS::HANDSHAKE
        lda     (ptr1),y
        cmp     #SER_HS_HW      ; this is all we support
        bne     init_err

        ; set handshake lines
        lda     #34             ; xio 34, set cts, dtr etc
        sta     ICCOM,x
        lda     #192+48+3       ; DTR on, RTS on, XMT on
        sta     ICAX1,x
        jsr     my_CIOV
        bmi     cioerr

        ; set translation and parity
        ldy     #SER_PARAMS::PARITY
        lda     (ptr1),y
        cmp     #num_parities
        bcs     init_err

        tay
        lda     parities,y
        ora     #32             ; no translation
        sta     ICAX1,x

        lda     #38             ; xio 38, translation and parity
        sta     ICCOM,x
        jsr     my_CIOV
        bmi     cioerr

        lda     #<SER_ERR_OK
        tax                             ; A is zero
        rts

inverr: jmp     my___inviocb

cioerr:
        ; @@@ need to close IOCB here
        jsr     my_fddecusage   ; decrement usage counter of fd as open failed

init_err:
        ldx     #0
        lda     #SER_ERR_INIT_FAILED
        rts

;---- open the device

do_open:
        jsr     my_findfreeiocb
        bne     init_err
        txa
        tay                     ; move iocb # into Y
        lda     #3
        sta     tmp3            ; name length + 1
        lda     #<rdev
        ldx     #>rdev
        jsr     my_newfd
        tya
        bcs     @doopen         ; C set: open needed / device not already open

        pha
        jsr     SER_CLOSE       ;** shut down if started  @@@TODO check this out!!
        pla

@doopen:tax
        pha
        jsr     my_clriocb
        pla
        tax
        lda     #<rdev
        sta     ICBAL,x
        lda     #>rdev
        sta     ICBAH,x
        lda     #OPEN
        sta     ICCOM,x

        lda     #$0D            ; mode in+out+concurrent
        sta     ICAX1,x
        lda     #0
        sta     ICAX2,x
        sta     ICBLL,x         ; zap buf len
        sta     ICBLH,x
        jsr     my_CIOV
        bmi     cioerr

        lda     tmp2            ; get fd (from newfd)
        sta     rshand
        ldx     #0
        stx     rshand+1
        txa
        rts

;----------------------------------------------------------------------------
; CLOSE: Close the port, disable interrupts and flush the buffer. Called
; without parameters. Must return an error code in a/x.
;
;----------------------------------------------------------------------------
; SER_UNINSTALL routine. Is called before the driver is removed from memory.
; Must return an SER_ERR_xx code in a/x.
;

SER_UNINSTALL:
SER_CLOSE:
        lda     rshand
        cmp     #$ff
        beq     @done

        ldx     rshand+1
        jsr     my__close
        ldx     #$ff
        stx     rshand
        stx     rshand+1
        inx
        stx     cm_run
@done:  lda     #<SER_ERR_OK
        ldx     #>SER_ERR_OK
        rts

;----------------------------------------------------------------------------
; SER_GET: Will fetch a character from the receive buffer and store it into the
; variable pointer to by ptr1. If no data is available, SER_ERR_NO_DATA is
; return.
;

SER_GET:
        ldy     rshand
        cpy     #$ff
        beq     ni_err           ; work only if initialized

        lda     rshand
        ldx     #0
        jsr     my_fdtoiocb
        tax
        lda     cm_run          ; concurrent mode already running?
        bne     @go
        jsr     ena_cm          ; turn on concurrent mode

@go:    ; check whether there is any input available

        lda     #STATIS         ; status request, returns bytes pending
        sta     ICCOM,x
        jsr     my_CIOV
        bmi     ser_error

        lda     DVSTAT+1        ; get byte count pending
        ora     DVSTAT+2
        beq     @nix_da         ; no input waiting...

        ; input is available: get it!

        lda     #GETCHR         ; get raw bytes
        sta     ICCOM,x         ; in command code
        lda     #0
        sta     ICBLL,x
        sta     ICBLH,x
        sta     ICBAL,x
        sta     ICBAH,x
        jsr     my_CIOV         ; go get it
        bmi     ser_error

        ldx     #0
        sta     (ptr1,x)        ; return received byte
        txa
        rts

@nix_da:lda     #SER_ERR_NO_DATA
        ldx     #0
        rts

ser_error:
        lda     #SER_ERR_OVERFLOW       ; there is no large selection of serial error codes... :-/
        ldx     #0
        rts

ni_err: lda     #SER_ERR_NOT_OPEN
        ldx     #0
        rts

;----------------------------------------------------------------------------
; SER_PUT: Output character in A.
; Must return an error code in a/x.
;

SER_PUT:
        ldy     rshand
        cpy     #$ff
        beq     ni_err          ; work only if initialized

        pha                     ; remember char to write
        lda     rshand
        ldx     #0
        jsr     my_fdtoiocb
        tax

        lda     cm_run          ; concurrent mode already running?
        bne     @go
        jsr     ena_cm          ; turn on concurrent mode

        ; @@@TODO:       check output buffer overflow
@go:    lda     #PUTCHR         ; put raw bytes
        sta     ICCOM,x         ; in command code
        lda     #0
        sta     ICBLL,x
        sta     ICBLH,x
        sta     ICBAL,x
        sta     ICBAH,x
        pla                     ; get the char back
        jsr     my_CIOV         ; go do it
        bmi     ser_error
        lda     #0
        tax
        rts

;----------------------------------------------------------------------------
; SER_STATUS: Return the status in the variable pointed to by ptr1.
; Must return an error code in a/x.
;

SER_STATUS:
        ; fall through to SER_IOCTL

;----------------------------------------------------------------------------
; SER_IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
; specific data in ptr1, and the ioctl code in A.
; Must return an error code in a/x.
;

SER_IOCTL:
        lda     #<SER_ERR_INV_IOCTL     ; We don't support ioclts for now
        ldx     #>SER_ERR_INV_IOCTL
        rts

;----------------------------------------------------------------------------
; SER_IRQ: Not used on the Atari
;

SER_IRQ     = $0000

;----------------------------------------------------------------------------
; SER_INSTALL routine. Is called after the driver is loaded into memory. If
; possible, check if the hardware is present.
; Must return an SER_ERR_xx code in a/x.

SER_INSTALL:
        ; check if R: device is installed
        ldy     #0
search: lda     HATABS,y                ; get device name
        cmp     #'R'
        beq     found
        iny
        iny
        iny
        cpy     #MAXDEV
        bcc     search

; R: device not found, return error

        lda     #<SER_ERR_NO_DEVICE
        ldx     #0
        rts

; R: device found, initialize jump table into main program

found:  lda     ptr3
        pha
        lda     ptr3+1
        pha
        lda     libref
        sta     ptr3
        lda     libref+1
        sta     ptr3+1

        ldy     #0
        lda     (ptr3),y
        sta     my_newfd+1
        iny
        lda     (ptr3),y
        sta     my_newfd+2
        iny

        lda     (ptr3),y
        sta     my__close+1
        iny
        lda     (ptr3),y
        sta     my__close+2
        iny

        lda     (ptr3),y
        sta     my_pushax+1
        iny
        lda     (ptr3),y
        sta     my_pushax+2
        iny

        lda     (ptr3),y
        sta     my_popax+1
        iny
        lda     (ptr3),y
        sta     my_popax+2
        iny

        lda     (ptr3),y
        sta     my_findfreeiocb+1
        iny
        lda     (ptr3),y
        sta     my_findfreeiocb+2
        iny

        lda     (ptr3),y
        sta     my___do_oserror+1
        iny
        lda     (ptr3),y
        sta     my___do_oserror+2
        iny

        lda     (ptr3),y
        sta     my_fddecusage+1
        iny
        lda     (ptr3),y
        sta     my_fddecusage+2
        iny

        lda     (ptr3),y
        sta     my_fdtoiocb+1
        iny
        lda     (ptr3),y
        sta     my_fdtoiocb+2
        iny

        lda     (ptr3),y
        sta     my___inviocb+1
        iny
        lda     (ptr3),y
        sta     my___inviocb+2
        iny

        lda     (ptr3),y
        sta     my_clriocb+1
        iny
        lda     (ptr3),y
        sta     my_clriocb+2
        iny

        lda     (ptr3),y
        sta     my_CIOV+1
        iny
        lda     (ptr3),y
        sta     my_CIOV+2
        ;iny

        pla
        sta     ptr3+1
        pla
        sta     ptr3

        lda     #<SER_ERR_OK
        tax                     ; A is zero
        rts


; enable concurrent rs232 mode
; gets iocb index in X
; all registers destroyed

.proc   ena_cm

        lda     #40             ; XIO 40, start concurrent IO
        sta     ICCOM,x
        sta     cm_run          ; indicate concurrent mode is running
        lda     #$0D            ; value from 850 manual, p62.  must be $0D?,
        sta     ICAX1,x         ;  or any non-zero?
        lda     #0
        sta     ICAX2,x
        lda     #<recv_buf
        sta     ICBAL,x
        lda     #>recv_buf
        sta     ICBAH,x
        lda     #<RECVBUF_SZ
        sta     ICBLL,x
        lda     #>RECVBUF_SZ
        sta     ICBLH,x
        jmp     my_CIOV

.endproc        ;ena_cm