1 1.23 thorpej /* $NetBSD: com_mca.c,v 1.23 2018/12/08 17:46:14 thorpej Exp $ */ 2 1.1 jdolecek 3 1.1 jdolecek /*- 4 1.2 jdolecek * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 1.1 jdolecek * All rights reserved. 6 1.1 jdolecek * 7 1.1 jdolecek * This code is derived from software contributed to The NetBSD Foundation 8 1.1 jdolecek * by Charles M. Hannum. 9 1.1 jdolecek * 10 1.1 jdolecek * Redistribution and use in source and binary forms, with or without 11 1.1 jdolecek * modification, are permitted provided that the following conditions 12 1.1 jdolecek * are met: 13 1.1 jdolecek * 1. Redistributions of source code must retain the above copyright 14 1.1 jdolecek * notice, this list of conditions and the following disclaimer. 15 1.1 jdolecek * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 jdolecek * notice, this list of conditions and the following disclaimer in the 17 1.1 jdolecek * documentation and/or other materials provided with the distribution. 18 1.1 jdolecek * 19 1.1 jdolecek * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 jdolecek * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 jdolecek * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 jdolecek * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 jdolecek * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 jdolecek * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 jdolecek * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 jdolecek * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 jdolecek * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 jdolecek * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 jdolecek * POSSIBILITY OF SUCH DAMAGE. 30 1.1 jdolecek */ 31 1.1 jdolecek 32 1.1 jdolecek /*- 33 1.1 jdolecek * Copyright (c) 1991 The Regents of the University of California. 34 1.1 jdolecek * All rights reserved. 35 1.1 jdolecek * 36 1.1 jdolecek * Redistribution and use in source and binary forms, with or without 37 1.1 jdolecek * modification, are permitted provided that the following conditions 38 1.1 jdolecek * are met: 39 1.1 jdolecek * 1. Redistributions of source code must retain the above copyright 40 1.1 jdolecek * notice, this list of conditions and the following disclaimer. 41 1.1 jdolecek * 2. Redistributions in binary form must reproduce the above copyright 42 1.1 jdolecek * notice, this list of conditions and the following disclaimer in the 43 1.1 jdolecek * documentation and/or other materials provided with the distribution. 44 1.10 agc * 3. Neither the name of the University nor the names of its contributors 45 1.1 jdolecek * may be used to endorse or promote products derived from this software 46 1.1 jdolecek * without specific prior written permission. 47 1.1 jdolecek * 48 1.1 jdolecek * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 1.1 jdolecek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 1.1 jdolecek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 1.1 jdolecek * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 1.1 jdolecek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 1.1 jdolecek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 1.1 jdolecek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 1.1 jdolecek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 1.1 jdolecek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 1.1 jdolecek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 1.1 jdolecek * SUCH DAMAGE. 59 1.1 jdolecek * 60 1.1 jdolecek * @(#)com.c 7.5 (Berkeley) 5/16/91 61 1.1 jdolecek */ 62 1.1 jdolecek 63 1.1 jdolecek /* 64 1.1 jdolecek * This driver attaches serial port boards and internal modems. 65 1.1 jdolecek */ 66 1.5 lukem 67 1.5 lukem #include <sys/cdefs.h> 68 1.23 thorpej __KERNEL_RCSID(0, "$NetBSD: com_mca.c,v 1.23 2018/12/08 17:46:14 thorpej Exp $"); 69 1.1 jdolecek 70 1.1 jdolecek #include <sys/param.h> 71 1.1 jdolecek #include <sys/systm.h> 72 1.1 jdolecek #include <sys/ioctl.h> 73 1.1 jdolecek #include <sys/select.h> 74 1.1 jdolecek #include <sys/tty.h> 75 1.1 jdolecek #include <sys/proc.h> 76 1.1 jdolecek #include <sys/file.h> 77 1.1 jdolecek #include <sys/uio.h> 78 1.1 jdolecek #include <sys/kernel.h> 79 1.1 jdolecek #include <sys/syslog.h> 80 1.1 jdolecek #include <sys/device.h> 81 1.1 jdolecek 82 1.18 ad #include <sys/intr.h> 83 1.18 ad #include <sys/bus.h> 84 1.1 jdolecek 85 1.1 jdolecek #include <dev/ic/comreg.h> 86 1.1 jdolecek #include <dev/ic/comvar.h> 87 1.1 jdolecek 88 1.1 jdolecek #include <dev/mca/mcavar.h> 89 1.1 jdolecek #include <dev/mca/mcadevs.h> 90 1.1 jdolecek 91 1.1 jdolecek struct com_mca_softc { 92 1.1 jdolecek struct com_softc sc_com; /* real "com" softc */ 93 1.1 jdolecek 94 1.1 jdolecek /* MCA-specific goo. */ 95 1.1 jdolecek void *sc_ih; /* interrupt handler */ 96 1.1 jdolecek }; 97 1.1 jdolecek 98 1.20 cube int com_mca_probe(device_t, cfdata_t , void *); 99 1.20 cube void com_mca_attach(device_t, device_t, void *); 100 1.11 perry 101 1.11 perry static int ibm_modem_getcfg(struct mca_attach_args *, int *, int *); 102 1.11 perry static int neocom1_getcfg(struct mca_attach_args *, int *, int *); 103 1.11 perry static int ibm_mpcom_getcfg(struct mca_attach_args *, int *, int *); 104 1.1 jdolecek 105 1.20 cube CFATTACH_DECL_NEW(com_mca, sizeof(struct com_mca_softc), 106 1.9 thorpej com_mca_probe, com_mca_attach, NULL, NULL); 107 1.1 jdolecek 108 1.1 jdolecek static const struct com_mca_product { 109 1.1 jdolecek u_int32_t cp_prodid; /* MCA product ID */ 110 1.1 jdolecek const char *cp_name; /* device name */ 111 1.11 perry int (*cp_getcfg)(struct mca_attach_args *, int *iobase, int *irq); 112 1.1 jdolecek /* get device i/o base and irq */ 113 1.1 jdolecek } com_mca_products[] = { 114 1.1 jdolecek { MCA_PRODUCT_IBM_MOD, "IBM Internal Modem", ibm_modem_getcfg }, 115 1.3 jdolecek { MCA_PRODUCT_NEOCOM1, "NeoTecH Single RS-232 Async. Adapter, SM110", 116 1.3 jdolecek neocom1_getcfg }, 117 1.4 jdolecek { MCA_PRODUCT_IBM_MPCOM,"IBM Multi-Protocol Communications Adapter", 118 1.4 jdolecek ibm_mpcom_getcfg }, 119 1.1 jdolecek { 0, NULL, NULL }, 120 1.1 jdolecek }; 121 1.1 jdolecek 122 1.11 perry static const struct com_mca_product *com_mca_lookup(int); 123 1.1 jdolecek 124 1.1 jdolecek static const struct com_mca_product * 125 1.20 cube com_mca_lookup(int ma_id) 126 1.1 jdolecek { 127 1.1 jdolecek const struct com_mca_product *cpp; 128 1.1 jdolecek 129 1.1 jdolecek for (cpp = com_mca_products; cpp->cp_name != NULL; cpp++) 130 1.1 jdolecek if (cpp->cp_prodid == ma_id) 131 1.1 jdolecek return (cpp); 132 1.1 jdolecek 133 1.1 jdolecek return (NULL); 134 1.1 jdolecek } 135 1.1 jdolecek 136 1.1 jdolecek int 137 1.20 cube com_mca_probe(device_t parent, cfdata_t match, void *aux) 138 1.1 jdolecek { 139 1.1 jdolecek struct mca_attach_args *ma = aux; 140 1.1 jdolecek 141 1.1 jdolecek if (com_mca_lookup(ma->ma_id)) 142 1.1 jdolecek return (1); 143 1.1 jdolecek 144 1.1 jdolecek return (0); 145 1.1 jdolecek } 146 1.1 jdolecek 147 1.1 jdolecek void 148 1.20 cube com_mca_attach(device_t parent, device_t self, void *aux) 149 1.1 jdolecek { 150 1.14 thorpej struct com_mca_softc *isc = device_private(self); 151 1.1 jdolecek struct com_softc *sc = &isc->sc_com; 152 1.1 jdolecek int iobase, irq; 153 1.1 jdolecek struct mca_attach_args *ma = aux; 154 1.1 jdolecek const struct com_mca_product *cpp; 155 1.15 gdamore bus_space_handle_t ioh; 156 1.1 jdolecek 157 1.20 cube sc->sc_dev = self; 158 1.1 jdolecek cpp = com_mca_lookup(ma->ma_id); 159 1.1 jdolecek 160 1.1 jdolecek /* get iobase and irq */ 161 1.4 jdolecek if ((*cpp->cp_getcfg)(ma, &iobase, &irq)) 162 1.1 jdolecek return; 163 1.1 jdolecek 164 1.15 gdamore if (bus_space_map(ma->ma_iot, iobase, COM_NPORTS, 0, &ioh)) { 165 1.20 cube aprint_error(": can't map i/o space\n"); 166 1.1 jdolecek return; 167 1.1 jdolecek } 168 1.1 jdolecek 169 1.23 thorpej com_init_regs(&sc->sc_regs, ma->ma_iot, ioh, iobase); 170 1.1 jdolecek sc->sc_frequency = COM_FREQ; 171 1.1 jdolecek 172 1.20 cube aprint_normal(" slot %d i/o %#x-%#x irq %d", ma->ma_slot + 1, 173 1.3 jdolecek iobase, iobase + COM_NPORTS - 1, irq); 174 1.3 jdolecek 175 1.1 jdolecek com_attach_subr(sc); 176 1.1 jdolecek 177 1.20 cube aprint_normal_dev(self, "%s\n", cpp->cp_name); 178 1.3 jdolecek 179 1.1 jdolecek isc->sc_ih = mca_intr_establish(ma->ma_mc, irq, IPL_SERIAL, 180 1.1 jdolecek comintr, sc); 181 1.1 jdolecek if (isc->sc_ih == NULL) { 182 1.20 cube aprint_error_dev(self, 183 1.20 cube "couldn't establish interrupt handler\n"); 184 1.1 jdolecek return; 185 1.1 jdolecek } 186 1.1 jdolecek 187 1.1 jdolecek /* 188 1.19 dyoung * com_cleanup: shutdown hook for buggy BIOSs that don't 189 1.19 dyoung * recognize the UART without a disabled FIFO. 190 1.1 jdolecek * XXX is this necessary on MCA ? --- jdolecek 191 1.1 jdolecek */ 192 1.19 dyoung if (!pmf_device_register1(self, com_suspend, com_resume, com_cleanup)) 193 1.19 dyoung aprint_error_dev(self, "could not establish shutdown hook\n"); 194 1.1 jdolecek } 195 1.1 jdolecek 196 1.1 jdolecek /* map serial_X to iobase and irq */ 197 1.1 jdolecek static const struct { 198 1.1 jdolecek int iobase; 199 1.1 jdolecek int irq; 200 1.1 jdolecek } MCA_SERIAL[] = { 201 1.1 jdolecek { 0x03f8, 4 }, /* SERIAL_1 */ 202 1.1 jdolecek { 0x02f8, 3 }, /* SERIAL_2 */ 203 1.1 jdolecek { 0x3220, 3 }, /* SERIAL_3 */ 204 1.1 jdolecek { 0x3228, 3 }, /* SERIAL_4 */ 205 1.1 jdolecek { 0x4220, 3 }, /* SERIAL_5 */ 206 1.1 jdolecek { 0x4228, 3 }, /* SERIAL_6 */ 207 1.1 jdolecek { 0x5220, 3 }, /* SERIAL_7 */ 208 1.1 jdolecek { 0x5228, 3 }, /* SERIAL_8 */ 209 1.1 jdolecek }; 210 1.1 jdolecek 211 1.1 jdolecek /* 212 1.1 jdolecek * Get config for IBM Internal Modem (ID 0xEDFF). This beast doesn't 213 1.1 jdolecek * seem to support even AT commands, it's good as example for adding 214 1.1 jdolecek * other stuff though. 215 1.1 jdolecek */ 216 1.1 jdolecek static int 217 1.20 cube ibm_modem_getcfg(struct mca_attach_args *ma, int *iobasep, int *irqp) 218 1.1 jdolecek { 219 1.1 jdolecek int pos2; 220 1.1 jdolecek int snum; 221 1.1 jdolecek 222 1.1 jdolecek pos2 = mca_conf_read(ma->ma_mc, ma->ma_slot, 2); 223 1.1 jdolecek 224 1.1 jdolecek /* 225 1.1 jdolecek * POS register 2: (adf pos0) 226 1.1 jdolecek * 7 6 5 4 3 2 1 0 227 1.1 jdolecek * \__/ \__ enable: 0=adapter disabled, 1=adapter enabled 228 1.12 perry * \_____ Serial Configuration: XX=SERIAL_XX 229 1.12 perry */ 230 1.12 perry 231 1.1 jdolecek snum = (pos2 & 0x0e) >> 1; 232 1.1 jdolecek 233 1.1 jdolecek *iobasep = MCA_SERIAL[snum].iobase; 234 1.1 jdolecek *irqp = MCA_SERIAL[snum].irq; 235 1.3 jdolecek 236 1.3 jdolecek return (0); 237 1.3 jdolecek } 238 1.3 jdolecek 239 1.3 jdolecek /* 240 1.3 jdolecek * Get configuration for NeoTecH Single RS-232 Async. Adapter, SM110. 241 1.3 jdolecek */ 242 1.3 jdolecek static int 243 1.20 cube neocom1_getcfg(struct mca_attach_args *ma, int *iobasep, int *irqp) 244 1.3 jdolecek { 245 1.3 jdolecek int pos2, pos3, pos4; 246 1.3 jdolecek static const int neotech_irq[] = { 12, 9, 4, 3 }; 247 1.3 jdolecek 248 1.3 jdolecek pos2 = mca_conf_read(ma->ma_mc, ma->ma_slot, 2); 249 1.3 jdolecek pos3 = mca_conf_read(ma->ma_mc, ma->ma_slot, 3); 250 1.3 jdolecek pos4 = mca_conf_read(ma->ma_mc, ma->ma_slot, 4); 251 1.3 jdolecek 252 1.3 jdolecek /* 253 1.3 jdolecek * POS register 2: (adf pos0) 254 1.3 jdolecek * 7 6 5 4 3 2 1 0 255 1.3 jdolecek * 1 \_/ \__ enable: 0=adapter disabled, 1=adapter enabled 256 1.3 jdolecek * \____ IRQ: 11=3 10=4 01=9 00=12 257 1.3 jdolecek * 258 1.3 jdolecek * POS register 3: (adf pos1) 259 1.3 jdolecek * 7 6 5 4 3 2 1 0 260 1.3 jdolecek * \______/ 261 1.3 jdolecek * \_________ I/O Address: bits 7-3 262 1.3 jdolecek * 263 1.3 jdolecek * POS register 4: (adf pos2) 264 1.3 jdolecek * 7 6 5 4 3 2 1 0 265 1.3 jdolecek * \_____________/ 266 1.3 jdolecek * \__ I/O Address: bits 15-8 267 1.12 perry */ 268 1.12 perry 269 1.3 jdolecek *iobasep = (pos4 << 8) | (pos3 & 0xf8); 270 1.3 jdolecek *irqp = neotech_irq[(pos2 & 0x06) >> 1]; 271 1.4 jdolecek 272 1.4 jdolecek return (0); 273 1.4 jdolecek } 274 1.4 jdolecek 275 1.4 jdolecek /* 276 1.4 jdolecek * Get configuration for IBM Multi-Protocol Communications Adapter. 277 1.4 jdolecek * We only support SERIAL mode, bail out if set to SDLC or BISYNC. 278 1.4 jdolecek */ 279 1.4 jdolecek static int 280 1.20 cube ibm_mpcom_getcfg(struct mca_attach_args *ma, int *iobasep, int *irqp) 281 1.4 jdolecek { 282 1.4 jdolecek int snum, pos2; 283 1.4 jdolecek 284 1.4 jdolecek pos2 = mca_conf_read(ma->ma_mc, ma->ma_slot, 2); 285 1.4 jdolecek 286 1.4 jdolecek /* 287 1.4 jdolecek * For SERIAL mode, bit 4 has to be 0. 288 1.4 jdolecek * 289 1.4 jdolecek * POS register 2: (adf pos0) 290 1.4 jdolecek * 7 6 5 4 3 2 1 0 291 1.4 jdolecek * 0 \__/ \__ enable: 0=adapter disabled, 1=adapter enabled 292 1.12 perry * \_____ Serial Configuration: XX=SERIAL_XX 293 1.12 perry */ 294 1.12 perry 295 1.4 jdolecek if (pos2 & 0x10) { 296 1.20 cube aprint_error(": not set to SERIAL mode, ignored\n"); 297 1.4 jdolecek return (1); 298 1.4 jdolecek } 299 1.4 jdolecek 300 1.4 jdolecek snum = (pos2 & 0x0e) >> 1; 301 1.4 jdolecek 302 1.4 jdolecek *iobasep = MCA_SERIAL[snum].iobase; 303 1.4 jdolecek *irqp = MCA_SERIAL[snum].irq; 304 1.1 jdolecek 305 1.1 jdolecek return (0); 306 1.1 jdolecek } 307