2 ; Serial driver for the Atari Lynx ComLynx port.
4 ; Karri Kaksonen, 17.09.2009
8 .include "zeropage.inc"
9 .include "ser-kernel.inc"
10 .include "ser-error.inc"
12 ; ------------------------------------------------------------------------
13 ; Header. Includes jump table
18 .byte $73, $65, $72 ; "ser"
19 .byte SER_API_VERSION ; Serial API version number
32 ;----------------------------------------------------------------------------
35 ; The ring buffers will be at the fixed place
36 ; Tx buffer $200 - $2ff. Rx buffer $300 - $3ff.
37 ; This memory area can usually not be used for anything as the encryption
38 ; stuff needs it. But for this purpose it fits perfectly.
54 ;----------------------------------------------------------------------------
55 ; INSTALL: Is called after the driver is loaded into memory.
57 ; Must return an SER_ERR_xx code in a/x.
62 ;----------------------------------------------------------------------------
63 ; UNINSTALL: Is called before the driver is removed from memory.
64 ; No return code required (the driver is removed from memory on return).
69 ;----------------------------------------------------------------------------
70 ; CLOSE: Close the port and disable interrupts. Called without parameters.
71 ; Must return an SER_ERR_xx code in a/x.
75 ; Done, return an error code
80 ;----------------------------------------------------------------------------
81 ; OPEN: A pointer to a ser_params structure is passed in ptr1.
83 ; The Lynx has only two correct serial data formats:
84 ; 8 bits, parity mark, 1 stop bit
85 ; 8 bits, parity space, 1 stop bit
87 ; It also has two wrong formats;
88 ; 8 bits, even parity, 1 stop bit
89 ; 8 bits, odd parity, 1 stop bit
91 ; Unfortunately the parity bit includes itself in the calculation making
92 ; parity not compatible with the rest of the world.
94 ; We can only specify a few baud rates.
95 ; Lynx has two non-standard speeds 31250 and 62500 which are
96 ; frequently used in games.
98 ; The receiver will always read the parity and report parity errors.
100 ; Must return an SER_ERR_xx code in a/x.
111 ldy #SER_PARAMS::BAUDRATE
191 lda #<SER_ERR_BAUD_UNAVAIL
192 ldx #>SER_ERR_BAUD_UNAVAIL
200 ldx #TxOpenColl|ParEven
202 ldy #SER_PARAMS::DATABITS ; Databits
206 ldy #SER_PARAMS::STOPBITS ; Stopbits
210 ldy #SER_PARAMS::PARITY ; Parity
222 ldx #TxParEnable|TxOpenColl|ParEven
226 ldx #TxParEnable|TxOpenColl
231 ldy #SER_PARAMS::HANDSHAKE ; Handshake
237 ora #RxIntEnable|ResetErr
243 lda #<SER_ERR_INIT_FAILED
244 ldx #>SER_ERR_INIT_FAILED
247 ;----------------------------------------------------------------------------
248 ; GET: Will fetch a character from the receive buffer and store it into the
249 ; variable pointed to by ptr1. If no data is available, SER_ERR_NO_DATA is
256 lda #<SER_ERR_NO_DATA
257 ldx #>SER_ERR_NO_DATA
265 txa ; Return code = 0
268 ;----------------------------------------------------------------------------
269 ; PUT: Output character in A.
270 ; Must return an SER_ERR_xx code in a/x.
278 lda #<SER_ERR_OVERFLOW
279 ldx #>SER_ERR_OVERFLOW
292 ora #TxIntEnable|ResetErr
293 sta SERCTL ; Allow TX-IRQ to hang RX-IRQ
301 ;----------------------------------------------------------------------------
302 ; STATUS: Return the status in the variable pointed to by ptr1.
303 ; Must return an SER_ERR_xx code in a/x.
309 txa ; Return code = 0
312 ;----------------------------------------------------------------------------
313 ; IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl
314 ; specific data in ptr1, and the ioctl code in A.
315 ; Must return an SER_ERR_xx code in a/x.
318 lda #<SER_ERR_INV_IOCTL
319 ldx #>SER_ERR_INV_IOCTL
322 ;----------------------------------------------------------------------------
323 ; IRQ: Called from the builtin runtime IRQ handler as a subroutine. All
324 ; registers are already saved, no parameters are passed, but the carry flag
325 ; is clear on entry. The routine must return with carry set if the interrupt
326 ; was handled, otherwise with carry clear.
328 ; Both the Tx and Rx interrupts are level sensitive instead of edge sensitive.
329 ; Due to this bug you have to disable the interrupt before clearing it.
332 lda INTSET ; Poll all pending interrupts
333 and #SERIAL_INTERRUPT
339 bmi @tx_irq ; Transmit in progress
342 and #RxParityErr|RxOverrun|RxFrameErr|RxBreak
344 tsb SerialStat ; Save error condition
347 stz TxPtrIn ; Break received - drop buffers
353 ora #RxIntEnable|ResetErr
360 ora #RxIntEnable|ResetErr
372 lda #SERIAL_INTERRUPT
381 ldx TxPtrOut ; Has all bytes been sent?
385 lda TxBuffer,x ; Send next byte
391 ora #TxIntEnable|ResetErr
393 lda #SERIAL_INTERRUPT
398 lda SERCTL ; All bytes sent
404 ora #RxIntEnable|ResetErr
407 lda #SERIAL_INTERRUPT