Annotation of sys/dev/cardbus/com_cardbus.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: com_cardbus.c,v 1.30 2007/05/08 21:28:11 deraadt Exp $ */
! 2: /* $NetBSD: com_cardbus.c,v 1.4 2000/04/17 09:21:59 joda Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 2000 Johan Danielsson
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: *
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: *
! 15: * 2. Redistributions in binary form must reproduce the above copyright
! 16: * notice, this list of conditions and the following disclaimer in the
! 17: * documentation and/or other materials provided with the distribution.
! 18: *
! 19: * 3. Neither the name of author nor the names of any contributors may
! 20: * be used to endorse or promote products derived from this
! 21: * software without specific prior written permission.
! 22: *
! 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 26: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
! 27: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
! 28: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
! 29: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
! 30: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
! 31: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
! 32: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
! 33: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 34: */
! 35:
! 36: /* This is a driver for CardBus based serial devices. It is less
! 37: generic than it could be, but it keeps the complexity down. So far
! 38: it assumes that anything that reports itself as a `serial' device
! 39: is infact a 16x50 or 8250, which is not necessarily true (in
! 40: practice this shouldn't be a problem). It also does not handle
! 41: devices in the `multiport serial' or `modem' sub-classes, I've
! 42: never seen any of these, so I don't know what they might look like.
! 43:
! 44: If the CardBus device only has one BAR (that is not also the CIS
! 45: BAR) listed in the CIS, it is assumed to be the one to use. For
! 46: devices with more than one BAR, the list of known devies has to be
! 47: updated below. */
! 48:
! 49: #include <sys/param.h>
! 50: #include <sys/systm.h>
! 51: #include <sys/tty.h>
! 52: #include <sys/device.h>
! 53:
! 54: #include <dev/cardbus/cardbusvar.h>
! 55: #include <dev/pci/pcidevs.h>
! 56:
! 57: #include <dev/pcmcia/pcmciareg.h>
! 58:
! 59: #include "com.h"
! 60: #ifdef i386
! 61: #include "pccom.h"
! 62: #endif
! 63:
! 64: #include <dev/ic/comreg.h>
! 65: #if NPCCOM > 0
! 66: #include <i386/isa/pccomvar.h>
! 67: #endif
! 68: #if NCOM > 0
! 69: #include <dev/ic/comvar.h>
! 70: #endif
! 71: #include <dev/ic/ns16550reg.h>
! 72:
! 73: #define com_lcr com_cfcr
! 74:
! 75: struct com_cardbus_softc {
! 76: struct com_softc cc_com;
! 77: void *cc_ih;
! 78: cardbus_devfunc_t cc_ct;
! 79: bus_addr_t cc_addr;
! 80: cardbusreg_t cc_base;
! 81: bus_size_t cc_size;
! 82: cardbusreg_t cc_csr;
! 83: int cc_cben;
! 84: cardbustag_t cc_tag;
! 85: cardbusreg_t cc_reg;
! 86: int cc_type;
! 87: u_char cc_bug;
! 88: };
! 89:
! 90: #define DEVNAME(CSC) ((CSC)->cc_com.sc_dev.dv_xname)
! 91:
! 92: int com_cardbus_match(struct device *, void *, void *);
! 93: void com_cardbus_attach(struct device *, struct device *, void *);
! 94: int com_cardbus_detach(struct device *, int);
! 95:
! 96: void com_cardbus_setup(struct com_cardbus_softc *);
! 97: int com_cardbus_enable(struct com_softc *);
! 98: void com_cardbus_disable(struct com_softc *);
! 99: struct csdev *com_cardbus_find_csdev(struct cardbus_attach_args *);
! 100: int com_cardbus_gofigure(struct cardbus_attach_args *,
! 101: struct com_cardbus_softc *);
! 102:
! 103: #if NCOM_CARDBUS
! 104: struct cfattach com_cardbus_ca = {
! 105: sizeof(struct com_cardbus_softc), com_cardbus_match,
! 106: com_cardbus_attach, com_cardbus_detach, com_activate
! 107: };
! 108: #elif NPCCOM_CARDBUS
! 109: struct cfattach pccom_cardbus_ca = {
! 110: sizeof(struct com_cardbus_softc), com_cardbus_match,
! 111: com_cardbus_attach, com_cardbus_detach, com_activate
! 112: };
! 113: #endif
! 114:
! 115: #define BUG_BROADCOM 0x01
! 116:
! 117: static struct csdev {
! 118: u_short vendor;
! 119: u_short product;
! 120: cardbusreg_t reg;
! 121: u_char type;
! 122: u_char bug;
! 123: } csdevs[] = {
! 124: { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_GLOBALMODEM56,
! 125: CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
! 126: { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_MODEM56,
! 127: CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
! 128: { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4322,
! 129: CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO, BUG_BROADCOM },
! 130: { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_SERIAL,
! 131: CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO, BUG_BROADCOM },
! 132: { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_SERIAL_GC,
! 133: CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
! 134: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_MODEM56,
! 135: CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
! 136: { PCI_VENDOR_OXFORD2, PCI_PRODUCT_OXFORD2_OXCB950,
! 137: CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
! 138: { PCI_VENDOR_XIRCOM, PCI_PRODUCT_XIRCOM_CBEM56G,
! 139: CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
! 140: { PCI_VENDOR_XIRCOM, PCI_PRODUCT_XIRCOM_MODEM56,
! 141: CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO }
! 142: };
! 143:
! 144: static const int ncsdevs = sizeof(csdevs) / sizeof(csdevs[0]);
! 145:
! 146: struct csdev*
! 147: com_cardbus_find_csdev(struct cardbus_attach_args *ca)
! 148: {
! 149: struct csdev *cp;
! 150:
! 151: for (cp = csdevs; cp < csdevs + ncsdevs; cp++)
! 152: if (cp->vendor == CARDBUS_VENDOR(ca->ca_id) &&
! 153: cp->product == CARDBUS_PRODUCT(ca->ca_id))
! 154: return (cp);
! 155: return (NULL);
! 156: }
! 157:
! 158: int
! 159: com_cardbus_match(struct device *parent, void *match, void *aux)
! 160: {
! 161: struct cardbus_attach_args *ca = aux;
! 162:
! 163: /* known devices are ok */
! 164: if (com_cardbus_find_csdev(ca) != NULL)
! 165: return (10);
! 166:
! 167: /* as are serial devices with a known UART */
! 168: if (ca->ca_cis.funcid == PCMCIA_FUNCTION_SERIAL &&
! 169: ca->ca_cis.funce.serial.uart_present != 0 &&
! 170: (ca->ca_cis.funce.serial.uart_type == 0 || /* 8250 */
! 171: ca->ca_cis.funce.serial.uart_type == 1 || /* 16450 */
! 172: ca->ca_cis.funce.serial.uart_type == 2)) /* 16550 */
! 173: return (1);
! 174:
! 175: return (0);
! 176: }
! 177:
! 178: int
! 179: com_cardbus_gofigure(struct cardbus_attach_args *ca,
! 180: struct com_cardbus_softc *csc)
! 181: {
! 182: int i, index = -1;
! 183: cardbusreg_t cis_ptr;
! 184: struct csdev *cp;
! 185:
! 186: /* If this device is listed above, use the known values, */
! 187: cp = com_cardbus_find_csdev(ca);
! 188: if (cp != NULL) {
! 189: csc->cc_reg = cp->reg;
! 190: csc->cc_type = cp->type;
! 191: csc->cc_bug = cp->bug;
! 192: return (0);
! 193: }
! 194:
! 195: cis_ptr = Cardbus_conf_read(csc->cc_ct, csc->cc_tag, CARDBUS_CIS_REG);
! 196:
! 197: /* otherwise try to deduce which BAR and type to use from CIS. If
! 198: there is only one BAR, it must be the one we should use, if
! 199: there are more, we're out of luck. */
! 200: for (i = 0; i < 7; i++) {
! 201: /* ignore zero sized BARs */
! 202: if (ca->ca_cis.bar[i].size == 0)
! 203: continue;
! 204: /* ignore the CIS BAR */
! 205: if (CARDBUS_CIS_ASI_BAR(cis_ptr) ==
! 206: CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
! 207: continue;
! 208: if (index != -1)
! 209: goto multi_bar;
! 210: index = i;
! 211: }
! 212: if (index == -1) {
! 213: printf(": couldn't find any base address tuple\n");
! 214: return (1);
! 215: }
! 216: csc->cc_reg = CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[index].flags);
! 217: if ((ca->ca_cis.bar[index].flags & 0x10) == 0)
! 218: csc->cc_type = CARDBUS_MAPREG_TYPE_MEM;
! 219: else
! 220: csc->cc_type = CARDBUS_MAPREG_TYPE_IO;
! 221: return (0);
! 222:
! 223: multi_bar:
! 224: printf(": there are more than one possible base\n");
! 225:
! 226: printf("%s: address for this device, "
! 227: "please report the following information\n",
! 228: DEVNAME(csc));
! 229: printf("%s: vendor 0x%x product 0x%x\n", DEVNAME(csc),
! 230: CARDBUS_VENDOR(ca->ca_id), CARDBUS_PRODUCT(ca->ca_id));
! 231: for (i = 0; i < 7; i++) {
! 232: /* ignore zero sized BARs */
! 233: if (ca->ca_cis.bar[i].size == 0)
! 234: continue;
! 235: /* ignore the CIS BAR */
! 236: if (CARDBUS_CIS_ASI_BAR(cis_ptr) ==
! 237: CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
! 238: continue;
! 239: printf("%s: base address %x type %s size %x\n",
! 240: DEVNAME(csc), CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags),
! 241: (ca->ca_cis.bar[i].flags & 0x10) ? "i/o" : "mem",
! 242: ca->ca_cis.bar[i].size);
! 243: }
! 244: return (1);
! 245: }
! 246:
! 247: void
! 248: com_cardbus_attach(struct device *parent, struct device *self, void *aux)
! 249: {
! 250: struct com_softc *sc = (struct com_softc*)self;
! 251: struct com_cardbus_softc *csc = (struct com_cardbus_softc*)self;
! 252: struct cardbus_attach_args *ca = aux;
! 253:
! 254: csc->cc_ct = ca->ca_ct;
! 255: csc->cc_tag = Cardbus_make_tag(csc->cc_ct);
! 256:
! 257: if (com_cardbus_gofigure(ca, csc) != 0)
! 258: return;
! 259:
! 260: if (Cardbus_mapreg_map(ca->ca_ct, csc->cc_reg, csc->cc_type, 0,
! 261: &sc->sc_iot, &sc->sc_ioh, &csc->cc_addr, &csc->cc_size) != 0) {
! 262: printf("failed to map memory");
! 263: return;
! 264: }
! 265:
! 266: csc->cc_base = csc->cc_addr;
! 267: csc->cc_csr = CARDBUS_COMMAND_MASTER_ENABLE;
! 268: if (csc->cc_type == CARDBUS_MAPREG_TYPE_IO) {
! 269: csc->cc_base |= CARDBUS_MAPREG_TYPE_IO;
! 270: csc->cc_csr |= CARDBUS_COMMAND_IO_ENABLE;
! 271: csc->cc_cben = CARDBUS_IO_ENABLE;
! 272: } else {
! 273: csc->cc_csr |= CARDBUS_COMMAND_MEM_ENABLE;
! 274: csc->cc_cben = CARDBUS_MEM_ENABLE;
! 275: }
! 276:
! 277: sc->sc_iobase = csc->cc_addr;
! 278: sc->sc_frequency = COM_FREQ;
! 279:
! 280: sc->enable = com_cardbus_enable;
! 281: sc->disable = com_cardbus_disable;
! 282: sc->enabled = 0;
! 283:
! 284: if (ca->ca_cis.cis1_info[0] && ca->ca_cis.cis1_info[1]) {
! 285: printf(": %s %s\n", ca->ca_cis.cis1_info[0],
! 286: ca->ca_cis.cis1_info[1]);
! 287: printf("%s", DEVNAME(csc));
! 288: }
! 289:
! 290: if (com_cardbus_enable(sc))
! 291: printf(": function enable failed\n");
! 292: sc->enabled = 1;
! 293:
! 294: sc->sc_hwflags = 0;
! 295: sc->sc_swflags = 0;
! 296:
! 297: if (csc->cc_bug & BUG_BROADCOM)
! 298: sc->sc_fifolen = 15;
! 299:
! 300: com_attach_subr(sc);
! 301: }
! 302:
! 303: void
! 304: com_cardbus_setup(struct com_cardbus_softc *csc)
! 305: {
! 306: cardbus_devfunc_t ct = csc->cc_ct;
! 307: cardbus_chipset_tag_t cc = ct->ct_cc;
! 308: cardbus_function_tag_t cf = ct->ct_cf;
! 309: cardbusreg_t reg;
! 310:
! 311: cardbus_conf_write(cc, cf, csc->cc_tag, csc->cc_reg, csc->cc_base);
! 312:
! 313: /* enable accesses on cardbus bridge */
! 314: cf->cardbus_ctrl(cc, csc->cc_cben);
! 315: cf->cardbus_ctrl(cc, CARDBUS_BM_ENABLE);
! 316:
! 317: /* and the card itself */
! 318: reg = cardbus_conf_read(cc, cf, csc->cc_tag, CARDBUS_COMMAND_STATUS_REG);
! 319: reg &= ~(CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MEM_ENABLE);
! 320: reg |= csc->cc_csr;
! 321: cardbus_conf_write(cc, cf, csc->cc_tag, CARDBUS_COMMAND_STATUS_REG, reg);
! 322:
! 323: /*
! 324: * Make sure the latency timer is set to some reasonable
! 325: * value.
! 326: */
! 327: reg = cardbus_conf_read(cc, cf, csc->cc_tag, CARDBUS_BHLC_REG);
! 328: if (CARDBUS_LATTIMER(reg) < 0x20) {
! 329: reg &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT);
! 330: reg |= (0x20 << CARDBUS_LATTIMER_SHIFT);
! 331: cardbus_conf_write(cc, cf, csc->cc_tag, CARDBUS_BHLC_REG, reg);
! 332: }
! 333: }
! 334:
! 335: int
! 336: com_cardbus_enable(struct com_softc *sc)
! 337: {
! 338: struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
! 339: struct cardbus_softc *psc =
! 340: (struct cardbus_softc *)sc->sc_dev.dv_parent;
! 341: cardbus_chipset_tag_t cc = psc->sc_cc;
! 342: cardbus_function_tag_t cf = psc->sc_cf;
! 343:
! 344: Cardbus_function_enable(csc->cc_ct);
! 345:
! 346: com_cardbus_setup(csc);
! 347:
! 348: /* establish the interrupt. */
! 349: csc->cc_ih = cardbus_intr_establish(cc, cf, psc->sc_intrline,
! 350: IPL_TTY, comintr, sc, DEVNAME(csc));
! 351: if (csc->cc_ih == NULL) {
! 352: printf("%s: couldn't establish interrupt\n", DEVNAME(csc));
! 353: return (1);
! 354: }
! 355:
! 356: printf(": irq %d", psc->sc_intrline);
! 357:
! 358: return (0);
! 359: }
! 360:
! 361: void
! 362: com_cardbus_disable(struct com_softc *sc)
! 363: {
! 364: struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
! 365: struct cardbus_softc *psc =
! 366: (struct cardbus_softc *)sc->sc_dev.dv_parent;
! 367: cardbus_chipset_tag_t cc = psc->sc_cc;
! 368: cardbus_function_tag_t cf = psc->sc_cf;
! 369:
! 370: cardbus_intr_disestablish(cc, cf, csc->cc_ih);
! 371: Cardbus_function_disable(csc->cc_ct);
! 372: }
! 373:
! 374: int
! 375: com_cardbus_detach(struct device *self, int flags)
! 376: {
! 377: struct com_cardbus_softc *csc = (struct com_cardbus_softc *) self;
! 378: struct com_softc *sc = (struct com_softc *) self;
! 379: struct cardbus_softc *psc = (struct cardbus_softc *)self->dv_parent;
! 380: int error;
! 381:
! 382: if ((error = com_detach(self, flags)) != 0)
! 383: return (error);
! 384:
! 385: cardbus_intr_disestablish(psc->sc_cc, psc->sc_cf, csc->cc_ih);
! 386:
! 387: Cardbus_mapreg_unmap(csc->cc_ct, csc->cc_reg, sc->sc_iot, sc->sc_ioh,
! 388: csc->cc_size);
! 389:
! 390: return (0);
! 391: }
CVSweb