1 /* $NetBSD: atppc_puc.c,v 1.4 2005/12/11 12:22:48 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2004 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jaromir Dolecek. 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 copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include "opt_atppc.h" 40 41 #include <sys/cdefs.h> 42 __KERNEL_RCSID(0, "$NetBSD: atppc_puc.c,v 1.4 2005/12/11 12:22:48 christos Exp $"); 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/errno.h> 47 #include <sys/ioctl.h> 48 #include <sys/syslog.h> 49 #include <sys/device.h> 50 #include <sys/proc.h> 51 #include <sys/termios.h> 52 53 #include <machine/bus.h> 54 #include <uvm/uvm_extern.h> 55 56 #include <dev/pci/pcivar.h> 57 #include <dev/pci/pucvar.h> 58 59 #include <dev/ic/atppcvar.h> 60 61 static int atppc_puc_match(struct device *, struct cfdata *, void *); 62 static void atppc_puc_attach(struct device *, struct device *, void *); 63 64 struct atppc_puc_softc { 65 /* Machine independent device data */ 66 struct atppc_softc sc_atppc; 67 68 bus_dmamap_t sc_dmamap; 69 }; 70 71 CFATTACH_DECL(atppc_puc, sizeof(struct atppc_puc_softc), atppc_puc_match, 72 atppc_puc_attach, NULL, NULL); 73 74 static int atppc_puc_dma_setup(struct atppc_puc_softc *); 75 static int atppc_puc_dma_start(struct atppc_softc *, void *, u_int, 76 u_int8_t); 77 static int atppc_puc_dma_finish(struct atppc_softc *); 78 static int atppc_puc_dma_abort(struct atppc_softc *); 79 static int atppc_puc_dma_malloc(struct device *, caddr_t *, bus_addr_t *, 80 bus_size_t); 81 static void atppc_puc_dma_free(struct device *, caddr_t *, bus_addr_t *, 82 bus_size_t); 83 84 /* 85 * atppc_acpi_match: autoconf(9) match routine 86 */ 87 static int 88 atppc_puc_match(struct device *parent, struct cfdata *match, void *aux) 89 { 90 struct puc_attach_args *aa = aux; 91 92 /* 93 * Locators already matched, just check the type. 94 */ 95 if (aa->type != PUC_PORT_TYPE_LPT) 96 return (0); 97 98 return (1); 99 } 100 101 static void 102 atppc_puc_attach(struct device *parent, struct device *self, void *aux) 103 { 104 struct atppc_softc *sc = (struct atppc_softc *) self; 105 struct atppc_puc_softc *psc = (struct atppc_puc_softc *) self; 106 struct puc_attach_args *aa = aux; 107 const char *intrstr; 108 109 sc->sc_dev_ok = ATPPC_NOATTACH; 110 111 printf(": AT Parallel Port\n"); 112 113 /* Attach */ 114 sc->sc_iot = aa->t; 115 sc->sc_ioh = aa->h; 116 sc->sc_dmat = aa->dmat; 117 sc->sc_has = 0; 118 119 intrstr = pci_intr_string(aa->pc, aa->intrhandle); 120 sc->sc_ieh = pci_intr_establish(aa->pc, aa->intrhandle, IPL_TTY, 121 atppcintr, sc); 122 if (sc->sc_ieh == NULL) { 123 printf("%s: couldn't establish interrupt", 124 sc->sc_dev.dv_xname); 125 if (intrstr != NULL) 126 printf(" at %s", intrstr); 127 printf("\n"); 128 return; 129 } 130 printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); 131 sc->sc_has |= ATPPC_HAS_INTR; 132 133 /* setup DMA hooks */ 134 if (atppc_puc_dma_setup(psc) == 0) { 135 sc->sc_has |= ATPPC_HAS_DMA; 136 sc->sc_dma_start = atppc_puc_dma_start; 137 sc->sc_dma_finish = atppc_puc_dma_finish; 138 sc->sc_dma_abort = atppc_puc_dma_abort; 139 sc->sc_dma_malloc = atppc_puc_dma_malloc; 140 sc->sc_dma_free = atppc_puc_dma_free; 141 } 142 143 /* Finished attach */ 144 sc->sc_dev_ok = ATPPC_ATTACHED; 145 146 /* Run soft configuration attach */ 147 atppc_sc_attach(sc); 148 } 149 150 /* Setup DMA structures */ 151 static int 152 atppc_puc_dma_setup(struct atppc_puc_softc *psc) 153 { 154 return EOPNOTSUPP; /* XXX DMA not tested yet */ 155 #if 0 156 struct atppc_softc *sc = (struct atppc_softc *)psc; 157 int error; 158 159 #define BUFSIZE PAGE_SIZE /* XXX see lptvar.h */ 160 if ((error = bus_dmamap_create(sc->sc_dmat, BUFSIZE, 1, BUFSIZE, 0, 161 BUS_DMA_NOWAIT, &psc->sc_dmamap))) 162 return error; 163 164 return (0); 165 #endif 166 } 167 168 /* Start DMA operation over PCI bus */ 169 static int 170 atppc_puc_dma_start(struct atppc_softc *dev, void *buf, u_int nbytes, 171 u_int8_t mode) 172 { 173 struct atppc_puc_softc *psc = (struct atppc_puc_softc *) dev; 174 struct atppc_softc *sc = &psc->sc_atppc; 175 176 bus_dmamap_sync(sc->sc_dmat, psc->sc_dmamap, 0, nbytes, 177 (mode == ATPPC_DMA_MODE_WRITE) ? BUS_DMASYNC_PREWRITE 178 : BUS_DMASYNC_PREREAD); 179 180 return (0); 181 } 182 183 /* Stop DMA operation over PCI bus */ 184 static int 185 atppc_puc_dma_finish(struct atppc_softc *dev) 186 { 187 188 struct atppc_puc_softc *psc = (struct atppc_puc_softc *) dev; 189 struct atppc_softc *sc = &psc->sc_atppc; 190 191 /* 192 * We don't know direction of DMA, so sync both. We can safely 193 * assume the dma map is loaded. 194 */ 195 bus_dmamap_sync(sc->sc_dmat, psc->sc_dmamap, 0, 196 psc->sc_dmamap->dm_segs[0].ds_len, 197 BUS_DMASYNC_POSTWRITE|BUS_DMASYNC_POSTREAD); 198 199 return (0); 200 } 201 202 /* Abort DMA operation over PCI bus */ 203 int 204 atppc_puc_dma_abort(struct atppc_softc * lsc) 205 { 206 207 /* Nothing to do - we do not need to sync, op is aborted */ 208 return (0); 209 } 210 211 /* Allocate memory for DMA over PCI bus */ 212 int 213 atppc_puc_dma_malloc(struct device *dev, caddr_t *buf, bus_addr_t *bus_addr, 214 bus_size_t size) 215 { 216 struct atppc_puc_softc *psc = (struct atppc_puc_softc *) dev; 217 struct atppc_softc *sc = &psc->sc_atppc; 218 int error; 219 220 error = bus_dmamap_load(sc->sc_dmat, psc->sc_dmamap, *buf, size, 221 NULL /* kernel address */, BUS_DMA_WAITOK|BUS_DMA_STREAMING); 222 if (error) 223 return (error); 224 225 *bus_addr = psc->sc_dmamap->dm_segs[0].ds_addr; 226 return (0); 227 } 228 229 /* Free memory allocated by atppc_isa_dma_malloc() */ 230 void 231 atppc_puc_dma_free(struct device *dev, caddr_t *buf, bus_addr_t *bus_addr, 232 bus_size_t size) 233 { 234 struct atppc_puc_softc *psc = (struct atppc_puc_softc *) dev; 235 struct atppc_softc *sc = &psc->sc_atppc; 236 237 return (bus_dmamap_unload(sc->sc_dmat, psc->sc_dmamap)); 238 } 239