root/stand/boot/pc32/boot2/sio.S
/*
 * Copyright (c) 1998 Robert Nordier
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are freely
 * permitted provided that the above copyright notice and this
 * paragraph and the following disclaimer are duplicated in all
 * such forms.
 *
 * This software is provided "AS IS" and without any express or
 * implied warranties, including, without limitation, the implied
 * warranties of merchantability and fitness for a particular
 * purpose.
 *
 * $FreeBSD: src/sys/boot/i386/boot2/sio.s,v 1.4 1999/08/28 00:40:02 peter Exp $
 * $DragonFly: src/sys/boot/pc32/boot2/sio.S,v 1.8 2006/08/12 05:42:26 swildner Exp $
 */
                .set SIO_PRT,SIOPRT             # Base port
                .set SIO_FMT,SIOFMT             # 8N1
                .set SIO_DIV,(115200/SIOSPD)    # 115200 / SPD

                .globl sio_init
                .globl sio_flush
                .globl sio_putc
                .globl sio_getc
                .globl sio_ischar

                /*
                 * int sio_init(void)
                 * 
                 * returns non-zero if we couldn't init, which can happen if
                 * the serial port is unmapped and the inb's all return
                 * 0xFF (we fail to flush the input).
                 */
sio_init:       movw $SIO_PRT+0x3,%dx           # Data format reg
                movb $SIO_FMT|0x80,%al          # Set format and DLAB
                outb %al,(%dx)                  # BASE+3
                subb $0x3,%dl
                movw $SIO_DIV,%ax               # divisor
                outw %ax,(%dx)                  # BASE+0 (divisor w/ DLAB set)
                movw $SIO_PRT+0x2,%dx
                movb $0x01,%al                  # Enable FIFO

                /* 
                 * DISABLED - apparently many new laptops only implement 
                 * 8250s, this might crash them? XXX
                 */
                 /* outb %al,(%dx) */                   # BASE+2
                incl %edx
                movb $SIO_FMT,%al               # Clear DLAB
                outb %al,(%dx)                  # BASE+3
                incl %edx
                movb $0x3,%al                   # RTS+DTR
                outb %al,(%dx)                  # BASE+4
                incl %edx                       # BASE+5 Line status reg

                /* 
                 * fall through to io_flush
                 *
                 * sio_flush: flush pending data in the serial port,
                 * return non-zero if we were unable to flush (aka
                 * ischar always returned true)
                 */
sio_flush:      movb $1,%ch                     # let %cl be garbage
1:              call sio_getc.1
                call sio_ischar
                loopnz 1b
                ret

                /*
                 * void sio_putc(int c)
                 */
sio_putc:       movw $SIO_PRT+0x5,%dx           # Line status reg
                movb $0x40,%ch                  # Timeout counter.  Allow %cl
                                                # to contain garbage.
sio_putc.1:     inb (%dx),%al                   # Transmitter buffer empty?
                testb $0x20,%al
                loopz sio_putc.1                # No
                jz sio_putc.2                   # If timeout
                movb 0x4(%esp,1),%al            # Get character
                subb $0x5,%dl                   # Transmitter hold reg
                outb %al,(%dx)                  # Write character
sio_putc.2:     ret

                /*
                 * int sio_getc(void)
                 */
sio_getc:       call sio_ischar                 # Character available?
                jz sio_getc                     # No
sio_getc.1:     subb $0x5,%dl                   # Receiver buffer reg
                inb (%dx),%al                   # Read character
                ret

                /*
                 * int sio_ischar(void)
                 */
sio_ischar:     movw $SIO_PRT+0x5,%dx           # Line status register
                xorl %eax,%eax                  # Zero
                inb (%dx),%al                   # Received data ready?
                andb $0x1,%al
                ret

                .globl inbser
inbser:         movw $SIO_PRT+5,%dx
                inb (%dx),%al
                ret