esp_pcmcia.c revision 1.37
1/* $NetBSD: esp_pcmcia.c,v 1.37 2009/03/14 15:36:20 dsl Exp $ */ 2 3/*- 4 * Copyright (c) 2000, 2004 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Charles M. Hannum. 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33__KERNEL_RCSID(0, "$NetBSD: esp_pcmcia.c,v 1.37 2009/03/14 15:36:20 dsl Exp $"); 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/device.h> 38#include <sys/buf.h> 39 40#include <sys/bus.h> 41#include <sys/intr.h> 42 43#include <dev/scsipi/scsi_all.h> 44#include <dev/scsipi/scsipi_all.h> 45#include <dev/scsipi/scsiconf.h> 46 47#include <dev/pcmcia/pcmciareg.h> 48#include <dev/pcmcia/pcmciavar.h> 49#include <dev/pcmcia/pcmciadevs.h> 50 51#include <dev/ic/ncr53c9xreg.h> 52#include <dev/ic/ncr53c9xvar.h> 53 54struct esp_pcmcia_softc { 55 struct ncr53c9x_softc sc_ncr53c9x; /* glue to MI code */ 56 57 int sc_active; /* Pseudo-DMA state vars */ 58 int sc_tc; 59 int sc_datain; 60 size_t sc_dmasize; 61 size_t sc_dmatrans; 62 uint8_t **sc_dmaaddr; 63 size_t *sc_pdmalen; 64 65 /* PCMCIA-specific goo. */ 66 struct pcmcia_function *sc_pf; /* our PCMCIA function */ 67 void *sc_ih; /* interrupt handler */ 68#ifdef ESP_PCMCIA_POLL 69 struct callout sc_poll_ch; 70#endif 71 bus_space_tag_t sc_iot; 72 bus_space_handle_t sc_ioh; 73 74 int sc_state; 75#define ESP_PCMCIA_ATTACHED 3 76}; 77 78int esp_pcmcia_match(device_t, cfdata_t, void *); 79int esp_pcmcia_validate_config(struct pcmcia_config_entry *); 80void esp_pcmcia_attach(device_t, device_t, void *); 81void esp_pcmcia_init(struct esp_pcmcia_softc *); 82int esp_pcmcia_detach(device_t, int); 83int esp_pcmcia_enable(device_t, int); 84 85CFATTACH_DECL_NEW(esp_pcmcia, sizeof(struct esp_pcmcia_softc), 86 esp_pcmcia_match, esp_pcmcia_attach, esp_pcmcia_detach, NULL); 87 88/* 89 * Functions and the switch for the MI code. 90 */ 91#ifdef ESP_PCMCIA_POLL 92void esp_pcmcia_poll(void *); 93#endif 94uint8_t esp_pcmcia_read_reg(struct ncr53c9x_softc *, int); 95void esp_pcmcia_write_reg(struct ncr53c9x_softc *, int, uint8_t); 96int esp_pcmcia_dma_isintr(struct ncr53c9x_softc *); 97void esp_pcmcia_dma_reset(struct ncr53c9x_softc *); 98int esp_pcmcia_dma_intr(struct ncr53c9x_softc *); 99int esp_pcmcia_dma_setup(struct ncr53c9x_softc *, uint8_t **, 100 size_t *, int, size_t *); 101void esp_pcmcia_dma_go(struct ncr53c9x_softc *); 102void esp_pcmcia_dma_stop(struct ncr53c9x_softc *); 103int esp_pcmcia_dma_isactive(struct ncr53c9x_softc *); 104 105const struct ncr53c9x_glue esp_pcmcia_glue = { 106 esp_pcmcia_read_reg, 107 esp_pcmcia_write_reg, 108 esp_pcmcia_dma_isintr, 109 esp_pcmcia_dma_reset, 110 esp_pcmcia_dma_intr, 111 esp_pcmcia_dma_setup, 112 esp_pcmcia_dma_go, 113 esp_pcmcia_dma_stop, 114 esp_pcmcia_dma_isactive, 115 NULL, /* gl_clear_latched_intr */ 116}; 117 118const struct pcmcia_product esp_pcmcia_products[] = { 119 { PCMCIA_VENDOR_PANASONIC, PCMCIA_PRODUCT_PANASONIC_KXLC002, 120 PCMCIA_CIS_PANASONIC_KXLC002 }, 121 122 { PCMCIA_VENDOR_RATOC, PCMCIA_PRODUCT_RATOC_REX_9530, 123 PCMCIA_CIS_RATOC_REX_9530 }, 124}; 125const size_t esp_pcmcia_nproducts = __arraycount(esp_pcmcia_products); 126 127int 128esp_pcmcia_match(device_t parent, cfdata_t cf, void *aux) 129{ 130 struct pcmcia_attach_args *pa = aux; 131 132 if (pcmcia_product_lookup(pa, esp_pcmcia_products, esp_pcmcia_nproducts, 133 sizeof(esp_pcmcia_products[0]), NULL)) 134 return 1; 135 return 0; 136} 137 138int 139esp_pcmcia_validate_config(struct pcmcia_config_entry *cfe) 140{ 141 142 if (cfe->iftype != PCMCIA_IFTYPE_IO || 143 cfe->num_memspace != 0 || 144 cfe->num_iospace != 1) 145 return EINVAL; 146 return 0; 147} 148 149void 150esp_pcmcia_attach(device_t parent, device_t self, void *aux) 151{ 152 struct esp_pcmcia_softc *esc = device_private(self); 153 struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x; 154 struct pcmcia_attach_args *pa = aux; 155 struct pcmcia_config_entry *cfe; 156 struct pcmcia_function *pf = pa->pf; 157 int error; 158 159 sc->sc_dev = self; 160 161 esc->sc_pf = pf; 162 163 error = pcmcia_function_configure(pf, esp_pcmcia_validate_config); 164 if (error) { 165 aprint_error_dev(self, "configure failed, error=%d\n", 166 error); 167 return; 168 } 169 170 cfe = pf->cfe; 171 esc->sc_iot = cfe->iospace[0].handle.iot; 172 esc->sc_ioh = cfe->iospace[0].handle.ioh; 173 esp_pcmcia_init(esc); 174 175 aprint_normal("%s", device_xname(self)); 176 177 sc->sc_adapter.adapt_minphys = minphys; 178 sc->sc_adapter.adapt_request = ncr53c9x_scsipi_request; 179 sc->sc_adapter.adapt_enable = esp_pcmcia_enable; 180 181 ncr53c9x_attach(sc); 182 esc->sc_state = ESP_PCMCIA_ATTACHED; 183} 184 185void 186esp_pcmcia_init(struct esp_pcmcia_softc *esc) 187{ 188 struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x; 189 190 /* id 7, clock 40M, parity ON, sync OFF, fast ON, slow ON */ 191 192 sc->sc_glue = &esp_pcmcia_glue; 193 194#ifdef ESP_PCMCIA_POLL 195 callout_init(&esc->sc_poll_ch, 0); 196#endif 197 198 sc->sc_rev = NCR_VARIANT_ESP406; 199 sc->sc_id = 7; 200 sc->sc_freq = 40; 201 /* try -PARENB -SLOW */ 202 sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB | NCRCFG1_SLOW; 203 /* try +FE */ 204 sc->sc_cfg2 = NCRCFG2_SCSI2; 205 /* try -IDM -FSCSI -FCLK */ 206 sc->sc_cfg3 = NCRESPCFG3_CDB | NCRESPCFG3_FCLK | NCRESPCFG3_IDM | 207 NCRESPCFG3_FSCSI; 208 sc->sc_cfg4 = NCRCFG4_ACTNEG; 209 /* try +INTP */ 210 sc->sc_cfg5 = NCRCFG5_CRS1 | NCRCFG5_AADDR | NCRCFG5_PTRINC; 211 sc->sc_minsync = 0; 212 sc->sc_maxxfer = 64 * 1024; 213} 214 215int 216esp_pcmcia_detach(struct device *self, int flags) 217{ 218 struct esp_pcmcia_softc *sc = device_private(self); 219 int error; 220 221 if (sc->sc_state != ESP_PCMCIA_ATTACHED) 222 return 0; 223 224 error = ncr53c9x_detach(&sc->sc_ncr53c9x, flags); 225 if (error) 226 return error; 227 228 pcmcia_function_unconfigure(sc->sc_pf); 229 230 return 0; 231} 232 233int 234esp_pcmcia_enable(struct device *self, int onoff) 235{ 236 struct esp_pcmcia_softc *sc = device_private(self); 237 int error; 238 239 if (onoff) { 240#ifdef ESP_PCMCIA_POLL 241 callout_reset(&sc->sc_poll_ch, 1, esp_pcmcia_poll, sc); 242#else 243 /* Establish the interrupt handler. */ 244 sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_BIO, 245 ncr53c9x_intr, &sc->sc_ncr53c9x); 246 if (!sc->sc_ih) 247 return EIO; 248#endif 249 250 error = pcmcia_function_enable(sc->sc_pf); 251 if (error) { 252 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); 253 sc->sc_ih = 0; 254 return error; 255 } 256 257 /* Initialize only chip. */ 258 ncr53c9x_init(&sc->sc_ncr53c9x, 0); 259 } else { 260 pcmcia_function_disable(sc->sc_pf); 261#ifdef ESP_PCMCIA_POLL 262 callout_stop(&sc->sc_poll_ch); 263#else 264 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih); 265 sc->sc_ih = 0; 266#endif 267 } 268 269 return 0; 270} 271 272#ifdef ESP_PCMCIA_POLL 273void 274esp_pcmcia_poll(void *arg) 275{ 276 struct esp_pcmcia_softc *esc = arg; 277 278 (void)ncr53c9x_intr(&esc->sc_ncr53c9x); 279 callout_reset(&esc->sc_poll_ch, 1, esp_pcmcia_poll, esc); 280} 281#endif 282 283/* 284 * Glue functions. 285 */ 286uint8_t 287esp_pcmcia_read_reg(struct ncr53c9x_softc *sc, int reg) 288{ 289 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc; 290 291 return bus_space_read_1(esc->sc_iot, esc->sc_ioh, reg); 292} 293 294void 295esp_pcmcia_write_reg(struct ncr53c9x_softc *sc, int reg, uint8_t val) 296{ 297 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc; 298 uint8_t v = val; 299 300 if (reg == NCR_CMD && v == (NCRCMD_TRANS|NCRCMD_DMA)) 301 v = NCRCMD_TRANS; 302 bus_space_write_1(esc->sc_iot, esc->sc_ioh, reg, v); 303} 304 305int 306esp_pcmcia_dma_isintr(struct ncr53c9x_softc *sc) 307{ 308 309 return NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT; 310} 311 312void 313esp_pcmcia_dma_reset(struct ncr53c9x_softc *sc) 314{ 315 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc; 316 317 esc->sc_active = 0; 318 esc->sc_tc = 0; 319} 320 321int 322esp_pcmcia_dma_intr(struct ncr53c9x_softc *sc) 323{ 324 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc; 325 uint8_t *p; 326 u_int espphase, espstat, espintr; 327 int cnt; 328 329 if (esc->sc_active == 0) { 330 printf("%s: dma_intr--inactive DMA\n", 331 device_xname(sc->sc_dev)); 332 return -1; 333 } 334 335 if ((sc->sc_espintr & NCRINTR_BS) == 0) { 336 esc->sc_active = 0; 337 return 0; 338 } 339 340 cnt = *esc->sc_pdmalen; 341 if (*esc->sc_pdmalen == 0) { 342 printf("%s: data interrupt, but no count left\n", 343 device_xname(sc->sc_dev)); 344 } 345 346 p = *esc->sc_dmaaddr; 347 espphase = sc->sc_phase; 348 espstat = (u_int)sc->sc_espstat; 349 espintr = (u_int)sc->sc_espintr; 350 do { 351 if (esc->sc_datain) { 352 *p++ = NCR_READ_REG(sc, NCR_FIFO); 353 cnt--; 354 if (espphase == DATA_IN_PHASE) 355 NCR_WRITE_REG(sc, NCR_CMD, NCRCMD_TRANS); 356 else 357 esc->sc_active = 0; 358 } else { 359 if (espphase == DATA_OUT_PHASE || 360 espphase == MESSAGE_OUT_PHASE) { 361 NCR_WRITE_REG(sc, NCR_FIFO, *p++); 362 cnt--; 363 NCR_WRITE_REG(sc, NCR_CMD, NCRCMD_TRANS); 364 } else 365 esc->sc_active = 0; 366 } 367 368 if (esc->sc_active) { 369 while ((NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT) == 0) 370 ; 371 espstat = NCR_READ_REG(sc, NCR_STAT); 372 espintr = NCR_READ_REG(sc, NCR_INTR); 373 espphase = (espintr & NCRINTR_DIS) 374 ? /* Disconnected */ BUSFREE_PHASE 375 : espstat & PHASE_MASK; 376 } 377 } while (esc->sc_active && espintr); 378 sc->sc_phase = espphase; 379 sc->sc_espstat = (uint8_t)espstat; 380 sc->sc_espintr = (uint8_t)espintr; 381 *esc->sc_dmaaddr = p; 382 *esc->sc_pdmalen = cnt; 383 384 if (*esc->sc_pdmalen == 0) 385 esc->sc_tc = NCRSTAT_TC; 386 sc->sc_espstat |= esc->sc_tc; 387 return 0; 388} 389 390int 391esp_pcmcia_dma_setup(struct ncr53c9x_softc *sc, uint8_t **addr, size_t *len, 392 int datain, size_t *dmasize) 393{ 394 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc; 395 396 esc->sc_dmaaddr = addr; 397 esc->sc_pdmalen = len; 398 esc->sc_datain = datain; 399 esc->sc_dmasize = *dmasize; 400 esc->sc_tc = 0; 401 402 return 0; 403} 404 405void 406esp_pcmcia_dma_go(struct ncr53c9x_softc *sc) 407{ 408 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc; 409 410 esc->sc_active = 1; 411} 412 413void 414esp_pcmcia_dma_stop(struct ncr53c9x_softc *sc) 415{ 416} 417 418int 419esp_pcmcia_dma_isactive(struct ncr53c9x_softc *sc) 420{ 421 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc; 422 423 return esc->sc_active; 424} 425