Annotation of sys/dev/pcmcia/esp_pcmcia.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: esp_pcmcia.c,v 1.6 2006/04/20 20:30:28 miod Exp $ */
2: /* $NetBSD: esp_pcmcia.c,v 1.8 2000/06/05 15:36:45 tsutsui Exp $ */
3:
4: /*-
5: * Copyright (c) 2000 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.
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/param.h>
41: #include <sys/systm.h>
42: #include <sys/device.h>
43: #include <sys/buf.h>
44:
45: #include <machine/bus.h>
46: #include <machine/intr.h>
47:
48: #include <scsi/scsi_all.h>
49: #include <scsi/scsiconf.h>
50:
51: #include <dev/pcmcia/pcmciareg.h>
52: #include <dev/pcmcia/pcmciavar.h>
53: #include <dev/pcmcia/pcmciadevs.h>
54:
55: #include <dev/ic/ncr53c9xreg.h>
56: #include <dev/ic/ncr53c9xvar.h>
57:
58: struct esp_pcmcia_softc {
59: struct ncr53c9x_softc sc_ncr53c9x; /* glue to MI code */
60:
61: int sc_active; /* Pseudo-DMA state vars */
62: int sc_tc;
63: int sc_datain;
64: size_t sc_dmasize;
65: size_t sc_dmatrans;
66: char **sc_dmaaddr;
67: size_t *sc_pdmalen;
68:
69: /* PCMCIA-specific goo. */
70: struct pcmcia_io_handle sc_pcioh; /* PCMCIA i/o space info */
71: int sc_io_window; /* our i/o window */
72: struct pcmcia_function *sc_pf; /* our PCMCIA function */
73: void *sc_ih; /* interrupt handler */
74: #ifdef ESP_PCMCIA_POLL
75: struct callout sc_poll_ch;
76: #endif
77: int sc_flags;
78: #define ESP_PCMCIA_ATTACHED 1 /* attach completed */
79: #define ESP_PCMCIA_ATTACHING 2 /* attach in progress */
80: };
81:
82: int esp_pcmcia_match(struct device *, void *, void *);
83: void esp_pcmcia_attach(struct device *, struct device *, void *);
84: void esp_pcmcia_init(struct esp_pcmcia_softc *);
85: int esp_pcmcia_detach(struct device *, int);
86: int esp_pcmcia_enable(void *, int);
87:
88: struct scsi_adapter esp_pcmcia_adapter = {
89: ncr53c9x_scsi_cmd, /* cmd */
90: minphys, /* minphys */
91: 0, /* open */
92: 0, /* close */
93: };
94:
95: struct cfattach esp_pcmcia_ca = {
96: sizeof(struct esp_pcmcia_softc), esp_pcmcia_match, esp_pcmcia_attach
97: };
98:
99: /*
100: * Functions and the switch for the MI code.
101: */
102: #ifdef ESP_PCMCIA_POLL
103: void esp_pcmcia_poll(void *);
104: #endif
105: u_char esp_pcmcia_read_reg(struct ncr53c9x_softc *, int);
106: void esp_pcmcia_write_reg(struct ncr53c9x_softc *, int, u_char);
107: int esp_pcmcia_dma_isintr(struct ncr53c9x_softc *);
108: void esp_pcmcia_dma_reset(struct ncr53c9x_softc *);
109: int esp_pcmcia_dma_intr(struct ncr53c9x_softc *);
110: int esp_pcmcia_dma_setup(struct ncr53c9x_softc *, caddr_t *,
111: size_t *, int, size_t *);
112: void esp_pcmcia_dma_go(struct ncr53c9x_softc *);
113: void esp_pcmcia_dma_stop(struct ncr53c9x_softc *);
114: int esp_pcmcia_dma_isactive(struct ncr53c9x_softc *);
115:
116: struct ncr53c9x_glue esp_pcmcia_glue = {
117: esp_pcmcia_read_reg,
118: esp_pcmcia_write_reg,
119: esp_pcmcia_dma_isintr,
120: esp_pcmcia_dma_reset,
121: esp_pcmcia_dma_intr,
122: esp_pcmcia_dma_setup,
123: esp_pcmcia_dma_go,
124: esp_pcmcia_dma_stop,
125: esp_pcmcia_dma_isactive,
126: NULL, /* gl_clear_latched_intr */
127: };
128:
129: struct esp_pcmcia_product {
130: u_int16_t app_vendor; /* PCMCIA vendor ID */
131: u_int16_t app_product; /* PCMCIA product ID */
132: int app_expfunc; /* expected function number */
133: } esp_pcmcia_prod[] = {
134: { PCMCIA_VENDOR_PANASONIC, PCMCIA_PRODUCT_PANASONIC_KXLC002, 0 },
135: { PCMCIA_VENDOR_PANASONIC, PCMCIA_PRODUCT_PANASONIC_KME, 0 },
136: { PCMCIA_VENDOR_NEWMEDIA2, PCMCIA_PRODUCT_NEWMEDIA2_BUSTOASTER, 0 }
137: };
138:
139: int
140: esp_pcmcia_match(parent, match, aux)
141: struct device *parent;
142: void *match, *aux;
143: {
144: struct pcmcia_attach_args *pa = aux;
145: int i;
146:
147: for (i = 0; i < sizeof(esp_pcmcia_prod)/sizeof(esp_pcmcia_prod[0]); i++)
148: if (pa->manufacturer == esp_pcmcia_prod[i].app_vendor &&
149: pa->product == esp_pcmcia_prod[i].app_product &&
150: pa->pf->number == esp_pcmcia_prod[i].app_expfunc)
151: return (1);
152: return (0);
153: }
154:
155: void
156: esp_pcmcia_attach(parent, self, aux)
157: struct device *parent, *self;
158: void *aux;
159: {
160: struct esp_pcmcia_softc *esc = (void *)self;
161: struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
162: struct pcmcia_attach_args *pa = aux;
163: struct pcmcia_config_entry *cfe;
164: struct pcmcia_function *pf = pa->pf;
165: const char *intrstr;
166:
167: esc->sc_pf = pf;
168:
169: for (cfe = SIMPLEQ_FIRST(&pf->cfe_head); cfe != NULL;
170: cfe = SIMPLEQ_NEXT(cfe, cfe_list)) {
171: if (cfe->num_memspace != 0 ||
172: cfe->num_iospace != 1)
173: continue;
174:
175: if (pcmcia_io_alloc(pa->pf, cfe->iospace[0].start,
176: cfe->iospace[0].length, 0, &esc->sc_pcioh) == 0)
177: break;
178: }
179:
180: if (cfe == 0) {
181: printf(": can't alloc i/o space\n");
182: goto no_config_entry;
183: }
184:
185: /* Enable the card. */
186: pcmcia_function_init(pf, cfe);
187: if (pcmcia_function_enable(pf)) {
188: printf(": function enable failed\n");
189: goto enable_failed;
190: }
191:
192: /* Map in the I/O space */
193: if (pcmcia_io_map(pa->pf, PCMCIA_WIDTH_AUTO, 0, esc->sc_pcioh.size,
194: &esc->sc_pcioh, &esc->sc_io_window)) {
195: printf(": can't map i/o space\n");
196: goto iomap_failed;
197: }
198:
199: printf(" port 0x%lx/%lu", esc->sc_pcioh.addr,
200: (u_long)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, sc->sc_dev.dv_xname);
206: intrstr = pcmcia_intr_string(esc->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
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
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
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
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
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
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
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
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
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
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
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
509: esp_pcmcia_dma_stop(sc)
510: struct ncr53c9x_softc *sc;
511: {
512: }
513:
514: int
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: }
CVSweb