hsq.c revision 1.2
1/* $OpenBSD: hsq.c,v 1.2 2002/03/14 01:26:56 millert Exp $ */ 2 3/*- 4 * Copyright (c) 1999 Denis A. Doroshenko. All rights reserved. 5 * 6 * This code is derived from BSD-licensed software written by 7 * Christopher G. Demetriou and Charles Hannum, which was 8 * derived from public-domain software written by Roland McGrath. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer in the documentation and/or other materials provided 18 * with the distribution. 19 * 3. All advertising materials mentioning features or use of this 20 * software must display the following acknowledgement: 21 * 22 * This product includes software developed by Denis A. Doroshenko 23 * 24 * 4. Neither the name of the author nor the names of its contributors 25 * may be used to endorse or promote products derived from this 26 * software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 29 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 30 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 32 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 34 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 36 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 * 40 * Note: this copyright notice is a version of Berkeley-style license 41 * derived from the original by Regents of the University of California. 42 */ 43 44/* 45 * This is OpenBSD driver for Hostess 4-channel serial mux -- hsq 46 * ("hsq" stands for "HoStess Quad channel mux"; funny enough). 47 * 48 * Hostess may be the registered trademark of Comtrol Corp. 49 * WARNING! The information that is below about Hostess family 50 * serial cards is not based on any information from Comtrol, 51 * and I DON'T guarantee this information is authentic or right. 52 * For authentic information on Hostess serial cards visit 53 * http://www.comtrol.com 54 * 55 * Hostess mux is a very simple thing -- it's 4/8/16(?) UARTs one 56 * after another, that share one IRQ. Under linux they may be used 57 * with setserial, BSD systems are not so flexible with serial ports, 58 * so i took ast driver and changed it, in the way i think Hostess 59 * muxes should work. It works ifine with my mux (it has ti16c750 60 * UARTs on it, and current pccom driver detects them as 550A, so i 61 * changed it a bit, to use the power of 750). 62 * 63 * Hostess cards use scratch register of lead UART to control the mux. 64 * When a byte is written to the register it is meant as mask, which 65 * enables/disables interrupts from 1-8 UARTs by setting 0-7 bits to 66 * 1/0. Let us call this register UER -- UARTs Enable Register. 67 * When a byte is read it is mask of bits for UARTs, that have some 68 * event(s), which are analyzed using that UART's IIR. Let us call 69 * this register UIR -- UARTs Interrrupt Register. 70 * 71 * Note: four higher bits of the UIR are alway 1 for 4-channel mux, 72 * I have no idea what could that mean, it would be better to have 73 * them zeroed. 74 * 75 * Shitty feature: UER's value upon power up is absolutely random, 76 * so that UARTs can work and can not and you don't uderstand what's up... 77 * Thus, we have to set it's value to 0x0f to get all four UARTs 78 * interrupting, just after we've attached the mux... 79 * 80 * Use it and share my fun! 81 * -- 82 * Denis A. Doroshenko <cyxob@isl.vtu.lt> 83 */ 84 85#include <sys/param.h> 86#include <sys/systm.h> 87#include <sys/device.h> 88#include <sys/termios.h> 89 90#include <machine/bus.h> 91#include <machine/intr.h> 92 93#include <dev/isa/isavar.h> 94#include <dev/ic/comreg.h> 95#include <dev/ic/comvar.h> 96 97/* 98 * For 8-channel Hostess serial card change: NSLAVES -> 8, UART_MASK -> 0xff 99 */ 100#define NSLAVES (4) 101#define UART_MASK (0x0f) 102 103#define com_uer (com_scratch) 104#define com_uir (com_scratch) 105 106struct hsq_softc { 107 struct device sc_dev; 108 void *sc_ih; 109 110 bus_space_tag_t sc_iot; 111 int sc_iobase; 112 113 void *sc_slaves[NSLAVES]; /* com device unit numbers */ 114 bus_space_handle_t sc_slaveioh[NSLAVES]; 115}; 116 117int hsqprobe(struct device *, void *, void *); 118void hsqattach(struct device *, struct device *, void *); 119int hsqintr(void *); 120int hsqprint(void *, const char *); 121 122struct cfattach hsq_ca = { 123 sizeof(struct hsq_softc), hsqprobe, hsqattach 124}; 125 126struct cfdriver hsq_cd = { 127 NULL, "hsq", DV_TTY 128}; 129 130int 131hsqprobe(parent, self, aux) 132 struct device *parent; 133 void *self; 134 void *aux; 135{ 136 struct isa_attach_args *ia = aux; 137 int iobase = ia->ia_iobase; 138 bus_space_tag_t iot = ia->ia_iot; 139 bus_space_handle_t ioh; 140 int i, rv = 1; 141 142 /* 143 * Do the normal com probe for the first UART and assume 144 * its presence, and the ability to map the other UARTs, 145 * means there is a multiport board there. 146 * XXX Needs more robustness. 147 */ 148 149 /* if the first port is in use as console, then it. */ 150 if (iobase == comconsaddr && !comconsattached) 151 goto checkmappings; 152 153 /* map UART ports (COM_NPORTS == 8) */ 154 if (bus_space_map(iot, iobase, COM_NPORTS, 0, &ioh)) { 155 rv = 0; 156 goto out; 157 } 158 159 rv = comprobe1(iot, ioh); 160 bus_space_unmap(iot, ioh, COM_NPORTS); 161 if (rv == 0) 162 goto out; 163 164checkmappings: 165 for (i = 1; i < NSLAVES; i++) { 166 iobase += COM_NPORTS; 167 168 if (iobase == comconsaddr && !comconsattached) 169 continue; 170 171 if (bus_space_map(iot, iobase, COM_NPORTS, 0, &ioh)) { 172 rv = 0; 173 goto out; 174 } 175 bus_space_unmap(iot, ioh, COM_NPORTS); 176 } 177 178out: 179 if (rv) 180 ia->ia_iosize = NSLAVES * COM_NPORTS; 181 return (rv); 182} 183 184int 185hsqprint(aux, pnp) 186 void *aux; 187 const char *pnp; 188{ 189 struct commulti_attach_args *ca = aux; 190 191 if (pnp) 192 printf("com at %s", pnp); 193 printf(" slave %d", ca->ca_slave); 194 return (UNCONF); 195} 196 197void 198hsqattach(parent, self, aux) 199 struct device *parent, *self; 200 void *aux; 201{ 202 struct hsq_softc *sc = (void *)self; 203 struct isa_attach_args *ia = aux; 204 struct commulti_attach_args ca; 205 int i; 206 207 sc->sc_iot = ia->ia_iot; 208 sc->sc_iobase = ia->ia_iobase; 209 210 for (i = 0; i < NSLAVES; i++) 211 if (bus_space_map(sc->sc_iot, sc->sc_iobase + i * COM_NPORTS, 212 COM_NPORTS, 0, &sc->sc_slaveioh[i])) 213 panic("hsqattach: couldn't map slave %d", i); 214 215 216 printf("\n"); 217 218 for (i = 0; i < NSLAVES; i++) { 219 ca.ca_slave = i; 220 ca.ca_iot = sc->sc_iot; 221 ca.ca_ioh = sc->sc_slaveioh[i]; 222 ca.ca_iobase = sc->sc_iobase + i * COM_NPORTS; 223 ca.ca_noien = 1; 224 225 sc->sc_slaves[i] = config_found(self, &ca, hsqprint); 226 } 227 228 /* allow interrupts from all four UARTs */ 229 bus_space_write_1(sc->sc_iot, sc->sc_slaveioh[0], com_uer, UART_MASK); 230 231 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, 232 IPL_TTY, hsqintr, sc, sc->sc_dev.dv_xname); 233} 234 235int 236hsqintr(arg) 237 void *arg; 238{ 239 struct hsq_softc *sc = arg; 240 bus_space_tag_t iot = sc->sc_iot; 241 int bits; 242 243 bits = bus_space_read_1(iot, sc->sc_slaveioh[0], com_uir) & UART_MASK; 244 if ( !bits ) 245 return (0); /* no interrupts pending */ 246 247 for (;;) { 248#define TRY(n) \ 249 if ( sc->sc_slaves[n] && bits & (1 << (n)) ) \ 250 comintr(sc->sc_slaves[n]); 251 252 TRY(0); 253 TRY(1); 254 TRY(2); 255 TRY(3); 256#undef TRY 257 258 bits = bus_space_read_1(iot, sc->sc_slaveioh[0], 259 com_uir) & UART_MASK; 260 if ( !bits ) 261 return (1); /* no interrupts pending */ 262 } 263} 264