1 1.12 tsutsui /* $NetBSD: comio_direct.c,v 1.12 2022/09/05 14:14:42 tsutsui Exp $ */ 2 1.3 perry 3 1.1 drochner /*- 4 1.1 drochner * Copyright (c) 1993, 1994, 1995, 1996, 1997 5 1.1 drochner * Charles M. Hannum. All rights reserved. 6 1.1 drochner * 7 1.1 drochner * Taken from sys/dev/isa/com.c and integrated into standalone boot 8 1.1 drochner * programs by Martin Husemann. 9 1.1 drochner * 10 1.1 drochner * Redistribution and use in source and binary forms, with or without 11 1.1 drochner * modification, are permitted provided that the following conditions 12 1.1 drochner * are met: 13 1.1 drochner * 1. Redistributions of source code must retain the above copyright 14 1.1 drochner * notice, this list of conditions and the following disclaimer. 15 1.1 drochner * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 drochner * notice, this list of conditions and the following disclaimer in the 17 1.1 drochner * documentation and/or other materials provided with the distribution. 18 1.1 drochner * 3. All advertising materials mentioning features or use of this software 19 1.1 drochner * must display the following acknowledgement: 20 1.1 drochner * This product includes software developed by Charles M. Hannum. 21 1.1 drochner * 4. The name of the author may not be used to endorse or promote products 22 1.1 drochner * derived from this software without specific prior written permission. 23 1.1 drochner * 24 1.1 drochner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 25 1.1 drochner * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 1.1 drochner * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 1.1 drochner * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 28 1.1 drochner * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 29 1.1 drochner * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 1.1 drochner * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 1.1 drochner * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 1.1 drochner * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33 1.1 drochner * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 1.1 drochner */ 35 1.1 drochner 36 1.1 drochner /* 37 1.1 drochner * Copyright (c) 1991 The Regents of the University of California. 38 1.1 drochner * All rights reserved. 39 1.1 drochner * 40 1.1 drochner * Redistribution and use in source and binary forms, with or without 41 1.1 drochner * modification, are permitted provided that the following conditions 42 1.1 drochner * are met: 43 1.1 drochner * 1. Redistributions of source code must retain the above copyright 44 1.1 drochner * notice, this list of conditions and the following disclaimer. 45 1.1 drochner * 2. Redistributions in binary form must reproduce the above copyright 46 1.1 drochner * notice, this list of conditions and the following disclaimer in the 47 1.1 drochner * documentation and/or other materials provided with the distribution. 48 1.7 agc * 3. Neither the name of the University nor the names of its contributors 49 1.1 drochner * may be used to endorse or promote products derived from this software 50 1.1 drochner * without specific prior written permission. 51 1.1 drochner * 52 1.1 drochner * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53 1.1 drochner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 1.1 drochner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 1.1 drochner * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56 1.1 drochner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 1.1 drochner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 1.1 drochner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 1.1 drochner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 1.1 drochner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 1.1 drochner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 1.1 drochner * SUCH DAMAGE. 63 1.1 drochner * 64 1.1 drochner * @(#)com.c 7.5 (Berkeley) 5/16/91 65 1.1 drochner */ 66 1.1 drochner 67 1.1 drochner #include <sys/types.h> 68 1.1 drochner #include <lib/libsa/stand.h> 69 1.1 drochner #include <machine/pio.h> 70 1.2 mycroft #include <dev/ic/comreg.h> 71 1.1 drochner #include "comio_direct.h" 72 1.5 dsl #include "libi386.h" 73 1.1 drochner 74 1.1 drochner /* preread buffer for xon/xoff handling */ 75 1.1 drochner #define XON 0x11 76 1.1 drochner #define XOFF 0x13 77 1.1 drochner #define SERBUFSIZE 16 78 1.1 drochner static u_char serbuf[SERBUFSIZE]; 79 1.1 drochner static int serbuf_read = 0; 80 1.1 drochner static int serbuf_write = 0; 81 1.1 drochner static int stopped = 0; 82 1.1 drochner 83 1.8 dsl #define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */ 84 1.8 dsl #define RATE_9600 divrnd((COM_FREQ / 16), 9600) 85 1.8 dsl 86 1.1 drochner /* 87 1.1 drochner * calculate divisor for a given speed 88 1.1 drochner */ 89 1.1 drochner static int 90 1.8 dsl comspeed(long speed) 91 1.1 drochner { 92 1.1 drochner int x, err; 93 1.1 drochner 94 1.1 drochner if (speed <= 0) 95 1.5 dsl speed = 9600; 96 1.1 drochner x = divrnd((COM_FREQ / 16), speed); 97 1.1 drochner if (x <= 0) 98 1.8 dsl return RATE_9600; 99 1.1 drochner err = divrnd((COM_FREQ / 16) * 1000, speed * x) - 1000; 100 1.1 drochner if (err < 0) 101 1.1 drochner err = -err; 102 1.1 drochner if (err > COM_TOLERANCE) 103 1.8 dsl return RATE_9600; 104 1.9 christos return x; 105 1.1 drochner } 106 1.1 drochner 107 1.1 drochner /* 108 1.1 drochner * get a character 109 1.1 drochner */ 110 1.1 drochner int 111 1.8 dsl comgetc_d(int combase) 112 1.1 drochner { 113 1.1 drochner u_char stat, c; 114 1.1 drochner 115 1.1 drochner if (serbuf_read != serbuf_write) { 116 1.1 drochner c = serbuf[serbuf_read++]; 117 1.1 drochner if (serbuf_read >= SERBUFSIZE) 118 1.1 drochner serbuf_read = 0; 119 1.1 drochner return c; 120 1.1 drochner } 121 1.1 drochner 122 1.1 drochner for (;;) { 123 1.1 drochner while (!ISSET(stat = inb(combase + com_lsr), LSR_RXRDY)) 124 1.10 christos continue; 125 1.1 drochner c = inb(combase + com_data); 126 1.1 drochner inb(combase + com_iir); 127 1.1 drochner if (c != XOFF) { 128 1.1 drochner stopped = 0; 129 1.1 drochner break; /* got a real char, deliver it... */ 130 1.1 drochner } 131 1.1 drochner stopped = 1; 132 1.1 drochner } 133 1.9 christos return c; 134 1.1 drochner } 135 1.1 drochner 136 1.1 drochner /* 137 1.1 drochner * output a character, return nonzero on success 138 1.1 drochner */ 139 1.1 drochner int 140 1.8 dsl computc_d(int c, int combase) 141 1.1 drochner { 142 1.1 drochner u_char stat; 143 1.8 dsl int timo; 144 1.1 drochner 145 1.1 drochner /* check for old XOFF */ 146 1.1 drochner while (stopped) 147 1.1 drochner comgetc_d(combase); /* wait for XON */ 148 1.1 drochner 149 1.1 drochner /* check for new XOFF */ 150 1.1 drochner if (comstatus_d(combase)) { 151 1.11 jakllsch int x = comgetc_d(combase); /* XOFF handled in comgetc_d */ 152 1.1 drochner /* stuff char into preread buffer */ 153 1.11 jakllsch serbuf[serbuf_write++] = x; 154 1.1 drochner if (serbuf_write >= SERBUFSIZE) 155 1.1 drochner serbuf_write = 0; 156 1.1 drochner } 157 1.1 drochner 158 1.1 drochner /* wait for any pending transmission to finish */ 159 1.1 drochner timo = 50000; 160 1.1 drochner while (!ISSET(stat = inb(combase + com_lsr), LSR_TXRDY) 161 1.1 drochner && --timo) 162 1.10 christos continue; 163 1.1 drochner if (timo == 0) return 0; 164 1.1 drochner outb(combase + com_data, c); 165 1.1 drochner /* wait for this transmission to complete */ 166 1.1 drochner timo = 1500000; 167 1.1 drochner while (!ISSET(stat = inb(combase + com_lsr), LSR_TXRDY) 168 1.1 drochner && --timo) 169 1.10 christos continue; 170 1.1 drochner if (timo == 0) return 0; 171 1.1 drochner /* clear any interrupts generated by this transmission */ 172 1.1 drochner inb(combase + com_iir); 173 1.1 drochner 174 1.1 drochner return 1; 175 1.1 drochner } 176 1.1 drochner 177 1.1 drochner /* 178 1.1 drochner * Initialize UART to known state. 179 1.1 drochner */ 180 1.8 dsl int 181 1.8 dsl cominit_d(int combase, int speed) 182 1.1 drochner { 183 1.8 dsl int rate, err; 184 1.1 drochner 185 1.1 drochner serbuf_read = 0; 186 1.1 drochner serbuf_write = 0; 187 1.1 drochner 188 1.1 drochner outb(combase + com_cfcr, LCR_DLAB); 189 1.8 dsl if (speed == 0) { 190 1.8 dsl /* Try to determine the current baud rate */ 191 1.8 dsl rate = inb(combase + com_dlbl) | inb(combase + com_dlbh) << 8; 192 1.8 dsl if (rate == 0) 193 1.8 dsl rate = RATE_9600; 194 1.8 dsl speed = divrnd((COM_FREQ / 16), rate); 195 1.8 dsl err = speed - (speed + 150)/300 * 300; 196 1.8 dsl speed -= err; 197 1.8 dsl if (err < 0) 198 1.8 dsl err = -err; 199 1.8 dsl if (err > 50) 200 1.8 dsl speed = 9600; 201 1.8 dsl } 202 1.5 dsl rate = comspeed(speed); 203 1.1 drochner outb(combase + com_dlbl, rate); 204 1.1 drochner outb(combase + com_dlbh, rate >> 8); 205 1.1 drochner outb(combase + com_cfcr, LCR_8BITS); 206 1.4 drochner outb(combase + com_mcr, MCR_DTR | MCR_RTS); 207 1.1 drochner outb(combase + com_fifo, 208 1.1 drochner FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_1); 209 1.1 drochner outb(combase + com_ier, 0); 210 1.8 dsl 211 1.8 dsl return speed; 212 1.1 drochner } 213 1.1 drochner 214 1.1 drochner /* 215 1.1 drochner * return nonzero if input char available, do XON/XOFF handling 216 1.1 drochner */ 217 1.1 drochner int 218 1.8 dsl comstatus_d(int combase) 219 1.1 drochner { 220 1.1 drochner /* check if any preread input is already there */ 221 1.1 drochner if (serbuf_read != serbuf_write) return 1; 222 1.1 drochner 223 1.1 drochner /* check for new stuff on the port */ 224 1.1 drochner if (ISSET(inb(combase + com_lsr), LSR_RXRDY)) { 225 1.1 drochner /* this could be XOFF, which we would swallow, so we can't 226 1.1 drochner claim there is input available... */ 227 1.1 drochner int c = inb(combase + com_data); 228 1.1 drochner inb(combase + com_iir); 229 1.1 drochner if (c == XOFF) { 230 1.1 drochner stopped = 1; 231 1.1 drochner } else { 232 1.1 drochner /* stuff char into preread buffer */ 233 1.1 drochner serbuf[serbuf_write++] = c; 234 1.1 drochner if (serbuf_write >= SERBUFSIZE) 235 1.1 drochner serbuf_write = 0; 236 1.1 drochner return 1; 237 1.1 drochner } 238 1.1 drochner } 239 1.1 drochner 240 1.1 drochner return 0; /* nothing out there... */ 241 1.1 drochner } 242