1 /* $OpenBSD: wdc_isa.c,v 1.7 2001/03/25 13:11:58 csapuntz Exp $ */ 2 /* $NetBSD: wdc_isa.c,v 1.15 1999/05/19 14:41:25 bouyer Exp $ */ 3 4 /*- 5 * Copyright (c) 1998 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Charles M. Hannum and by Onno van der Linden. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 #include <sys/types.h> 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/device.h> 44 #include <sys/malloc.h> 45 46 #include <machine/bus.h> 47 #include <machine/intr.h> 48 49 #include <dev/isa/isavar.h> 50 #include <dev/isa/isadmavar.h> 51 52 #include <dev/ata/atavar.h> 53 #include <dev/ic/wdcvar.h> 54 55 #ifdef __OpenBSD__ 56 #include "isadma.h" 57 #else 58 #define NISADMA 1 59 #endif 60 61 #define WDC_ISA_REG_NPORTS 8 62 #define WDC_ISA_AUXREG_OFFSET 0x206 63 #define WDC_ISA_AUXREG_NPORTS 1 /* XXX "fdc" owns ports 0x3f7/0x377 */ 64 65 /* options passed via the 'flags' config keyword */ 66 #define WDC_OPTIONS_32 0x01 /* try to use 32bit data I/O */ 67 68 struct wdc_isa_softc { 69 struct wdc_softc sc_wdcdev; 70 struct channel_softc *wdc_chanptr; 71 struct channel_softc wdc_channel; 72 #ifdef __OpenBSD__ 73 struct device *sc_isa; 74 #endif 75 isa_chipset_tag_t sc_ic; 76 void *sc_ih; 77 int sc_drq; 78 }; 79 80 #ifndef __OpenBSD__ 81 int wdc_isa_probe __P((struct device *, struct cfdata *, void *)); 82 #else 83 int wdc_isa_probe __P((struct device *, void *, void *)); 84 #endif 85 void wdc_isa_attach __P((struct device *, struct device *, void *)); 86 87 struct cfattach wdc_isa_ca = { 88 sizeof(struct wdc_isa_softc), wdc_isa_probe, wdc_isa_attach 89 }; 90 91 #if NISADMA > 0 92 static void wdc_isa_dma_setup __P((struct wdc_isa_softc *)); 93 static int wdc_isa_dma_init __P((void*, int, int, void *, size_t, int)); 94 static void wdc_isa_dma_start __P((void*, int, int)); 95 static int wdc_isa_dma_finish __P((void*, int, int)); 96 #endif /* NISADMA > 0 */ 97 98 int 99 wdc_isa_probe(parent, match, aux) 100 struct device *parent; 101 #ifndef __OpenBSD__ 102 struct cfdata *match; 103 #else 104 void *match; 105 #endif 106 void *aux; 107 { 108 struct channel_softc ch; 109 struct isa_attach_args *ia = aux; 110 struct cfdata *cf = match; 111 int result = 0; 112 113 bzero(&ch, sizeof ch); 114 ch.cmd_iot = ia->ia_iot; 115 if (bus_space_map(ch.cmd_iot, ia->ia_iobase, WDC_ISA_REG_NPORTS, 0, 116 &ch.cmd_ioh)) 117 goto out; 118 119 ch.ctl_iot = ia->ia_iot; 120 if (bus_space_map(ch.ctl_iot, ia->ia_iobase + WDC_ISA_AUXREG_OFFSET, 121 WDC_ISA_AUXREG_NPORTS, 0, &ch.ctl_ioh)) 122 goto outunmap; 123 124 if (cf->cf_flags & WDC_OPTION_PROBE_VERBOSE) 125 ch.ch_flags |= WDCF_VERBOSE_PROBE; 126 127 result = wdcprobe(&ch); 128 if (result) { 129 ia->ia_iosize = WDC_ISA_REG_NPORTS; 130 ia->ia_msize = 0; 131 } 132 133 bus_space_unmap(ch.ctl_iot, ch.ctl_ioh, WDC_ISA_AUXREG_NPORTS); 134 outunmap: 135 bus_space_unmap(ch.cmd_iot, ch.cmd_ioh, WDC_ISA_REG_NPORTS); 136 out: 137 return (result); 138 } 139 140 void 141 wdc_isa_attach(parent, self, aux) 142 struct device *parent, *self; 143 void *aux; 144 { 145 struct wdc_isa_softc *sc = (void *)self; 146 struct isa_attach_args *ia = aux; 147 148 printf("\n"); 149 150 sc->wdc_channel.cmd_iot = ia->ia_iot; 151 sc->wdc_channel.ctl_iot = ia->ia_iot; 152 sc->sc_ic = ia->ia_ic; 153 sc->sc_isa = parent; 154 if (bus_space_map(sc->wdc_channel.cmd_iot, ia->ia_iobase, 155 WDC_ISA_REG_NPORTS, 0, &sc->wdc_channel.cmd_ioh) || 156 bus_space_map(sc->wdc_channel.ctl_iot, 157 ia->ia_iobase + WDC_ISA_AUXREG_OFFSET, WDC_ISA_AUXREG_NPORTS, 158 0, &sc->wdc_channel.ctl_ioh)) { 159 printf("%s: couldn't map registers\n", 160 sc->sc_wdcdev.sc_dev.dv_xname); 161 } 162 sc->wdc_channel.data32iot = sc->wdc_channel.cmd_iot; 163 sc->wdc_channel.data32ioh = sc->wdc_channel.cmd_ioh; 164 165 #ifdef __OpenBSD__ 166 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, 167 IPL_BIO, wdcintr, &sc->wdc_channel, sc->sc_wdcdev.sc_dev.dv_xname); 168 #else 169 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE, 170 IPL_BIO, wdcintr, &sc->wdc_channel); 171 #endif 172 if (ia->ia_drq != DRQUNK) { 173 #if NISADMA > 0 174 sc->sc_drq = ia->ia_drq; 175 176 sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA; 177 sc->sc_wdcdev.dma_arg = sc; 178 sc->sc_wdcdev.dma_init = wdc_isa_dma_init; 179 sc->sc_wdcdev.dma_start = wdc_isa_dma_start; 180 sc->sc_wdcdev.dma_finish = wdc_isa_dma_finish; 181 wdc_isa_dma_setup(sc); 182 #else /* NISADMA > 0 */ 183 printf("%s: ignoring drq, isa dma not supported", 184 sc->sc_wdcdev.sc_dev.dv_xname); 185 #endif /* NISADMA > 0 */ 186 } 187 sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_PREATA; 188 if (sc->sc_wdcdev.sc_dev.dv_cfdata->cf_flags & WDC_OPTIONS_32) 189 sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA32; 190 sc->sc_wdcdev.PIO_cap = 0; 191 sc->wdc_chanptr = &sc->wdc_channel; 192 sc->sc_wdcdev.channels = &sc->wdc_chanptr; 193 sc->sc_wdcdev.nchannels = 1; 194 sc->wdc_channel.channel = 0; 195 sc->wdc_channel.wdc = &sc->sc_wdcdev; 196 sc->wdc_channel.ch_queue = malloc(sizeof(struct channel_queue), 197 M_DEVBUF, M_NOWAIT); 198 if (sc->wdc_channel.ch_queue == NULL) { 199 printf("%s: can't allocate memory for command queue", 200 sc->sc_wdcdev.sc_dev.dv_xname); 201 return; 202 } 203 wdcattach(&sc->wdc_channel); 204 wdc_print_current_modes(&sc->wdc_channel); 205 } 206 207 #if NISADMA > 0 208 static void 209 wdc_isa_dma_setup(sc) 210 struct wdc_isa_softc *sc; 211 { 212 #ifndef __OpenBSD__ 213 if (isa_dmamap_create(sc->sc_ic, sc->sc_drq, 214 MAXPHYS, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) { 215 #else 216 if (isa_dmamap_create(sc->sc_isa, sc->sc_drq, 217 MAXPHYS, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) { 218 #endif 219 printf("%s: can't create map for drq %d\n", 220 sc->sc_wdcdev.sc_dev.dv_xname, sc->sc_drq); 221 sc->sc_wdcdev.cap &= ~WDC_CAPABILITY_DMA; 222 } 223 } 224 225 static int 226 wdc_isa_dma_init(v, channel, drive, databuf, datalen, read) 227 void *v; 228 void *databuf; 229 size_t datalen; 230 int read; 231 { 232 struct wdc_isa_softc *sc = v; 233 234 #ifndef __OpenBSD__ 235 isa_dmastart(sc->sc_ic, sc->sc_drq, databuf, datalen, NULL, 236 (read ? DMAMODE_READ : DMAMODE_WRITE) | DMAMODE_DEMAND, 237 BUS_DMA_NOWAIT); 238 #else 239 isa_dmastart(sc->sc_isa, sc->sc_drq, databuf, datalen, NULL, 240 (read ? DMAMODE_READ : DMAMODE_WRITE), 241 BUS_DMA_NOWAIT); 242 #endif 243 return 0; 244 } 245 246 static void 247 wdc_isa_dma_start(v, channel, drive) 248 void *v; 249 int channel, drive; 250 { 251 /* nothing to do */ 252 } 253 254 static int 255 wdc_isa_dma_finish(v, channel, drive) 256 void *v; 257 int channel, drive; 258 { 259 struct wdc_isa_softc *sc = v; 260 261 #ifndef __OpenBSD__ 262 isa_dmadone(sc->sc_ic, sc->sc_drq); 263 #else 264 isa_dmadone(sc->sc_isa, sc->sc_drq); 265 #endif 266 return 0; 267 } 268 #endif /* NISADMA > 0 */ 269