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