1 /** $MirOS: src/sys/dev/pcmcia/esp_pcmcia.c,v 1.3 2005/07/04 01:15:48 tg Exp $ */
2 /* $OpenBSD: esp_pcmcia.c,v 1.5 2005/01/27 17:04:55 millert Exp $ */
3 /* $NetBSD: esp_pcmcia.c,v 1.8 2000/06/05 15:36:45 tsutsui Exp $ */
4
5 /*-
6 * Copyright (c) 2000 The NetBSD Foundation, Inc.
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by Charles M. Hannum.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the NetBSD
23 * Foundation, Inc. and its contributors.
24 * 4. Neither the name of The NetBSD Foundation nor the names of its
25 * contributors may be used to endorse or promote products derived
26 * from this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 */
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/device.h>
44 #include <sys/buf.h>
45
46 #include <machine/bus.h>
47 #include <machine/intr.h>
48
49 #include <scsi/scsi_all.h>
50 #include <scsi/scsiconf.h>
51
52 #include <dev/pcmcia/pcmciareg.h>
53 #include <dev/pcmcia/pcmciavar.h>
54 #include <dev/pcmcia/pcmciadevs.h>
55
56 #include <dev/ic/ncr53c9xreg.h>
57 #include <dev/ic/ncr53c9xvar.h>
58
59 struct esp_pcmcia_softc {
60 struct ncr53c9x_softc sc_ncr53c9x; /* glue to MI code */
61
62 int sc_active; /* Pseudo-DMA state vars */
63 int sc_tc;
64 int sc_datain;
65 size_t sc_dmasize;
66 size_t sc_dmatrans;
67 char **sc_dmaaddr;
68 size_t *sc_pdmalen;
69
70 /* PCMCIA-specific goo. */
71 struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */
72 int sc_io_window; /* our i/o window */
73 struct pcmcia_function *sc_pf; /* our PCMCIA function */
74 void *sc_ih; /* interrupt handler */
75 #ifdef ESP_PCMCIA_POLL
76 struct callout sc_poll_ch;
77 #endif
78 int sc_flags;
79 #define ESP_PCMCIA_ATTACHED 1 /* attach completed */
80 #define ESP_PCMCIA_ATTACHING 2 /* attach in progress */
81 };
82
83 int esp_pcmcia_match(struct device *, void *, void *);
84 void esp_pcmcia_attach(struct device *, struct device *, void *);
85 void esp_pcmcia_init(struct esp_pcmcia_softc *);
86 int esp_pcmcia_detach(struct device *, int);
87 int esp_pcmcia_enable(void *, int);
88
89 struct scsi_adapter esp_pcmcia_adapter = {
90 ncr53c9x_scsi_cmd, /* cmd */
91 minphys, /* minphys */
92 0, /* open */
93 0, /* close */
94 };
95
96 struct cfattach esp_pcmcia_ca = {
97 sizeof(struct esp_pcmcia_softc), esp_pcmcia_match, esp_pcmcia_attach
98 };
99
100 /*
101 * Functions and the switch for the MI code.
102 */
103 #ifdef ESP_PCMCIA_POLL
104 void esp_pcmcia_poll(void *);
105 #endif
106 u_char esp_pcmcia_read_reg(struct ncr53c9x_softc *, int);
107 void esp_pcmcia_write_reg(struct ncr53c9x_softc *, int, u_char);
108 int esp_pcmcia_dma_isintr(struct ncr53c9x_softc *);
109 void esp_pcmcia_dma_reset(struct ncr53c9x_softc *);
110 int esp_pcmcia_dma_intr(struct ncr53c9x_softc *);
111 int esp_pcmcia_dma_setup(struct ncr53c9x_softc *, caddr_t *,
112 size_t *, int, size_t *);
113 void esp_pcmcia_dma_go(struct ncr53c9x_softc *);
114 void esp_pcmcia_dma_stop(struct ncr53c9x_softc *);
115 int esp_pcmcia_dma_isactive(struct ncr53c9x_softc *);
116
117 struct ncr53c9x_glue esp_pcmcia_glue = {
118 esp_pcmcia_read_reg,
119 esp_pcmcia_write_reg,
120 esp_pcmcia_dma_isintr,
121 esp_pcmcia_dma_reset,
122 esp_pcmcia_dma_intr,
123 esp_pcmcia_dma_setup,
124 esp_pcmcia_dma_go,
125 esp_pcmcia_dma_stop,
126 esp_pcmcia_dma_isactive,
127 NULL, /* gl_clear_latched_intr */
128 };
129
130 struct esp_pcmcia_product {
131 u_int16_t app_vendor; /* PCMCIA vendor ID */
132 u_int16_t app_product; /* PCMCIA product ID */
133 int app_expfunc; /* expected function number */
134 } esp_pcmcia_prod[] = {
135 { PCMCIA_VENDOR_PANASONIC, PCMCIA_PRODUCT_PANASONIC_KXLC002, 0 },
136 { PCMCIA_VENDOR_PANASONIC, PCMCIA_PRODUCT_PANASONIC_KME, 0 },
137 { PCMCIA_VENDOR_NEWMEDIA2, PCMCIA_PRODUCT_NEWMEDIA2_BUSTOASTER, 0 }
138 };
139
140 int
esp_pcmcia_match(parent,match,aux)141 esp_pcmcia_match(parent, match, aux)
142 struct device *parent;
143 void *match, *aux;
144 {
145 struct pcmcia_attach_args *pa = aux;
146 int i;
147
148 for (i = 0; i < sizeof(esp_pcmcia_prod)/sizeof(esp_pcmcia_prod[0]); i++)
149 if (pa->manufacturer == esp_pcmcia_prod[i].app_vendor &&
150 pa->product == esp_pcmcia_prod[i].app_product &&
151 pa->pf->number == esp_pcmcia_prod[i].app_expfunc)
152 return (1);
153 return (0);
154 }
155
156 void
esp_pcmcia_attach(parent,self,aux)157 esp_pcmcia_attach(parent, self, aux)
158 struct device *parent, *self;
159 void *aux;
160 {
161 struct esp_pcmcia_softc *esc = (void *)self;
162 struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
163 struct pcmcia_attach_args *pa = aux;
164 struct pcmcia_config_entry *cfe;
165 struct pcmcia_function *pf = pa->pf;
166 const char *intrstr;
167
168 esc->sc_pf = pf;
169
170 for (cfe = SIMPLEQ_FIRST(&pf->cfe_head); cfe != NULL;
171 cfe = SIMPLEQ_NEXT(cfe, cfe_list)) {
172 if (cfe->num_memspace != 0 ||
173 cfe->num_iospace != 1)
174 continue;
175
176 if (pcmcia_io_alloc(pa->pf, cfe->iospace[0].start,
177 cfe->iospace[0].length, 0, &esc->sc_pcioh) == 0)
178 break;
179 }
180
181 if (cfe == 0) {
182 printf(": can't alloc i/o space\n");
183 goto no_config_entry;
184 }
185
186 /* Enable the card. */
187 pcmcia_function_init(pf, cfe);
188 if (pcmcia_function_enable(pf)) {
189 printf(": function enable failed\n");
190 goto enable_failed;
191 }
192
193 /* Map in the I/O space */
194 if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_AUTO, 0, esc->sc_pcioh.size,
195 &esc->sc_pcioh, &esc->sc_io_window)) {
196 printf(": can't map i/o space\n");
197 goto iomap_failed;
198 }
199
200 printf(" port 0x%lx/%d", esc->sc_pcioh.addr, (int)(esc->sc_pcioh.size));
201
202 esp_pcmcia_init(esc);
203
204 esc->sc_ih = pcmcia_intr_establish(esc->sc_pf, IPL_BIO,
205 ncr53c9x_intr, &esc->sc_ncr53c9x, esc->sc_dev.dv_xname);
206 intrstr = pcmcia_intr_string(psc->sc_pf, esc->sc_ih);
207 if (esc->sc_ih == NULL) {
208 printf(", %s\n", intrstr);
209 goto iomap_failed;
210 }
211 if (*intrstr)
212 printf(", %s", intrstr);
213
214 /*
215 * Initialize nca board itself.
216 */
217 esc->sc_flags |= ESP_PCMCIA_ATTACHING;
218 ncr53c9x_attach(sc, &esp_pcmcia_adapter, NULL);
219 esc->sc_flags &= ~ESP_PCMCIA_ATTACHING;
220 esc->sc_flags |= ESP_PCMCIA_ATTACHED;
221 return;
222
223 iomap_failed:
224 /* Disable the device. */
225 pcmcia_function_disable(esc->sc_pf);
226
227 enable_failed:
228 /* Unmap our I/O space. */
229 pcmcia_io_free(esc->sc_pf, &esc->sc_pcioh);
230
231 no_config_entry:
232 return;
233 }
234
235 void
esp_pcmcia_init(esc)236 esp_pcmcia_init(esc)
237 struct esp_pcmcia_softc *esc;
238 {
239 struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
240 bus_space_tag_t iot = esc->sc_pcioh.iot;
241 bus_space_handle_t ioh = esc->sc_pcioh.ioh;
242
243 /* id 7, clock 40M, parity ON, sync OFF, fast ON, slow ON */
244
245 sc->sc_glue = &esp_pcmcia_glue;
246
247 #ifdef ESP_PCMCIA_POLL
248 callout_init(&esc->sc_poll_ch);
249 #endif
250
251 sc->sc_rev = NCR_VARIANT_ESP406;
252 sc->sc_id = 7;
253 sc->sc_freq = 40;
254 /* try -PARENB -SLOW */
255 sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB | NCRCFG1_SLOW;
256 /* try +FE */
257 sc->sc_cfg2 = NCRCFG2_SCSI2;
258 /* try -IDM -FSCSI -FCLK */
259 sc->sc_cfg3 = NCRESPCFG3_CDB | NCRESPCFG3_FCLK | NCRESPCFG3_IDM |
260 NCRESPCFG3_FSCSI;
261 sc->sc_cfg4 = NCRCFG4_ACTNEG;
262 /* try +INTP */
263 sc->sc_cfg5 = NCRCFG5_CRS1 | NCRCFG5_AADDR | NCRCFG5_PTRINC;
264 sc->sc_minsync = 0;
265 sc->sc_maxxfer = 64 * 1024;
266
267 bus_space_write_1(iot, ioh, NCR_CFG5, sc->sc_cfg5);
268
269 bus_space_write_1(iot, ioh, NCR_PIOI, 0);
270 bus_space_write_1(iot, ioh, NCR_PSTAT, 0);
271 bus_space_write_1(iot, ioh, 0x09, 0x24);
272
273 bus_space_write_1(iot, ioh, NCR_CFG4, sc->sc_cfg4);
274 }
275
276 #ifdef notyet
277 int
esp_pcmcia_detach(self,flags)278 esp_pcmcia_detach(self, flags)
279 struct device *self;
280 int flags;
281 {
282 struct esp_pcmcia_softc *esc = (void *)self;
283 int error;
284
285 if ((esc->sc_flags & ESP_PCMCIA_ATTACHED) == 0) {
286 /* Nothing to detach. */
287 return (0);
288 }
289
290 error = ncr53c9x_detach(&esc->sc_ncr53c9x, flags);
291 if (error)
292 return (error);
293
294 /* Unmap our i/o window and i/o space. */
295 pcmcia_io_unmap(esc->sc_pf, esc->sc_io_window);
296 pcmcia_io_free(esc->sc_pf, &esc->sc_pcioh);
297
298 return (0);
299 }
300 #endif
301
302 int
esp_pcmcia_enable(arg,onoff)303 esp_pcmcia_enable(arg, onoff)
304 void *arg;
305 int onoff;
306 {
307 struct esp_pcmcia_softc *esc = arg;
308
309 if (onoff) {
310 #ifdef ESP_PCMCIA_POLL
311 callout_reset(&esc->sc_poll_ch, 1, esp_pcmcia_poll, esc);
312 #else
313 /* Establish the interrupt handler. */
314 esc->sc_ih = pcmcia_intr_establish(esc->sc_pf, IPL_BIO,
315 ncr53c9x_intr, &esc->sc_ncr53c9x,
316 esc->sc_ncr53c9x.sc_dev.dv_xname);
317 if (esc->sc_ih == NULL) {
318 printf("%s: couldn't establish interrupt handler\n",
319 esc->sc_ncr53c9x.sc_dev.dv_xname);
320 return (EIO);
321 }
322 #endif
323
324 /*
325 * If attach is in progress, we know that card power is
326 * enabled and chip will be initialized later.
327 * Otherwise, enable and reset now.
328 */
329 if ((esc->sc_flags & ESP_PCMCIA_ATTACHING) == 0) {
330 if (pcmcia_function_enable(esc->sc_pf)) {
331 printf("%s: couldn't enable PCMCIA function\n",
332 esc->sc_ncr53c9x.sc_dev.dv_xname);
333 pcmcia_intr_disestablish(esc->sc_pf,
334 esc->sc_ih);
335 return (EIO);
336 }
337
338 /* Initialize only chip. */
339 ncr53c9x_init(&esc->sc_ncr53c9x, 0);
340 }
341 } else {
342 pcmcia_function_disable(esc->sc_pf);
343 #ifdef ESP_PCMCIA_POLL
344 callout_stop(&esc->sc_poll_ch);
345 #else
346 pcmcia_intr_disestablish(esc->sc_pf, esc->sc_ih);
347 #endif
348 }
349
350 return (0);
351 }
352
353 #ifdef ESP_PCMCIA_POLL
354 void
esp_pcmcia_poll(arg)355 esp_pcmcia_poll(arg)
356 void *arg;
357 {
358 struct esp_pcmcia_softc *esc = arg;
359
360 (void) ncr53c9x_intr(&esc->sc_ncr53c9x);
361 callout_reset(&esc->sc_poll_ch, 1, esp_pcmcia_poll, esc);
362 }
363 #endif
364
365 /*
366 * Glue functions.
367 */
368 u_char
esp_pcmcia_read_reg(sc,reg)369 esp_pcmcia_read_reg(sc, reg)
370 struct ncr53c9x_softc *sc;
371 int reg;
372 {
373 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
374 u_char v;
375
376 v = bus_space_read_1(esc->sc_pcioh.iot, esc->sc_pcioh.ioh, reg);
377 return v;
378 }
379
380 void
esp_pcmcia_write_reg(sc,reg,val)381 esp_pcmcia_write_reg(sc, reg, val)
382 struct ncr53c9x_softc *sc;
383 int reg;
384 u_char val;
385 {
386 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
387 u_char v = val;
388
389 if (reg == NCR_CMD && v == (NCRCMD_TRANS|NCRCMD_DMA))
390 v = NCRCMD_TRANS;
391 bus_space_write_1(esc->sc_pcioh.iot, esc->sc_pcioh.ioh, reg, v);
392 }
393
394 int
esp_pcmcia_dma_isintr(sc)395 esp_pcmcia_dma_isintr(sc)
396 struct ncr53c9x_softc *sc;
397 {
398
399 return NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT;
400 }
401
402 void
esp_pcmcia_dma_reset(sc)403 esp_pcmcia_dma_reset(sc)
404 struct ncr53c9x_softc *sc;
405 {
406 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
407
408 esc->sc_active = 0;
409 esc->sc_tc = 0;
410 }
411
412 int
esp_pcmcia_dma_intr(sc)413 esp_pcmcia_dma_intr(sc)
414 struct ncr53c9x_softc *sc;
415 {
416 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
417 u_char *p;
418 u_int espphase, espstat, espintr;
419 int cnt;
420
421 if (esc->sc_active == 0) {
422 printf("%s: dma_intr--inactive DMA\n", sc->sc_dev.dv_xname);
423 return -1;
424 }
425
426 if ((sc->sc_espintr & NCRINTR_BS) == 0) {
427 esc->sc_active = 0;
428 return 0;
429 }
430
431 cnt = *esc->sc_pdmalen;
432 if (*esc->sc_pdmalen == 0) {
433 printf("%s: data interrupt, but no count left\n",
434 sc->sc_dev.dv_xname);
435 }
436
437 p = *esc->sc_dmaaddr;
438 espphase = sc->sc_phase;
439 espstat = (u_int) sc->sc_espstat;
440 espintr = (u_int) sc->sc_espintr;
441 do {
442 if (esc->sc_datain) {
443 *p++ = NCR_READ_REG(sc, NCR_FIFO);
444 cnt--;
445 if (espphase == DATA_IN_PHASE)
446 NCR_WRITE_REG(sc, NCR_CMD, NCRCMD_TRANS);
447 else
448 esc->sc_active = 0;
449 } else {
450 if (espphase == DATA_OUT_PHASE ||
451 espphase == MESSAGE_OUT_PHASE) {
452 NCR_WRITE_REG(sc, NCR_FIFO, *p++);
453 cnt--;
454 NCR_WRITE_REG(sc, NCR_CMD, NCRCMD_TRANS);
455 } else
456 esc->sc_active = 0;
457 }
458
459 if (esc->sc_active) {
460 while (!(NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT));
461 espstat = NCR_READ_REG(sc, NCR_STAT);
462 espintr = NCR_READ_REG(sc, NCR_INTR);
463 espphase = (espintr & NCRINTR_DIS)
464 ? /* Disconnected */ BUSFREE_PHASE
465 : espstat & PHASE_MASK;
466 }
467 } while (esc->sc_active && espintr);
468 sc->sc_phase = espphase;
469 sc->sc_espstat = (u_char) espstat;
470 sc->sc_espintr = (u_char) espintr;
471 *esc->sc_dmaaddr = p;
472 *esc->sc_pdmalen = cnt;
473
474 if (*esc->sc_pdmalen == 0)
475 esc->sc_tc = NCRSTAT_TC;
476 sc->sc_espstat |= esc->sc_tc;
477 return 0;
478 }
479
480 int
esp_pcmcia_dma_setup(sc,addr,len,datain,dmasize)481 esp_pcmcia_dma_setup(sc, addr, len, datain, dmasize)
482 struct ncr53c9x_softc *sc;
483 caddr_t *addr;
484 size_t *len;
485 int datain;
486 size_t *dmasize;
487 {
488 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
489
490 esc->sc_dmaaddr = addr;
491 esc->sc_pdmalen = len;
492 esc->sc_datain = datain;
493 esc->sc_dmasize = *dmasize;
494 esc->sc_tc = 0;
495
496 return 0;
497 }
498
499 void
esp_pcmcia_dma_go(sc)500 esp_pcmcia_dma_go(sc)
501 struct ncr53c9x_softc *sc;
502 {
503 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
504
505 esc->sc_active = 1;
506 }
507
508 void
esp_pcmcia_dma_stop(sc)509 esp_pcmcia_dma_stop(sc)
510 struct ncr53c9x_softc *sc;
511 {
512 }
513
514 int
esp_pcmcia_dma_isactive(sc)515 esp_pcmcia_dma_isactive(sc)
516 struct ncr53c9x_softc *sc;
517 {
518 struct esp_pcmcia_softc *esc = (struct esp_pcmcia_softc *)sc;
519
520 return (esc->sc_active);
521 }
522