1 /* $NetBSD: cac_eisa.c,v 1.20 2009/05/12 12:12:52 cegger Exp $ */
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
33 * Copyright (c) 2000 Jonathan Lemon
34 * Copyright (c) 1999 by Matthew N. Dodd <winter@jurai.net>
35 * All Rights Reserved.
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions, and the following disclaimer,
42 * without modification, immediately at the beginning of the file.
43 * 2. The name of the author may not be used to endorse or promote products
44 * derived from this software without specific prior written permission.
46 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
50 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * EISA front-end for cac(4) driver.
63 #include <sys/cdefs.h>
64 __KERNEL_RCSID(0, "$NetBSD: cac_eisa.c,v 1.20 2009/05/12 12:12:52 cegger Exp $");
66 #include <sys/param.h>
67 #include <sys/systm.h>
68 #include <sys/device.h>
73 #include <dev/eisa/eisavar.h>
74 #include <dev/eisa/eisadevs.h>
76 #include <dev/ic/cacreg.h>
77 #include <dev/ic/cacvar.h>
79 #define CAC_EISA_SLOT_OFFSET 0x0c88
80 #define CAC_EISA_IOSIZE 0x0017
81 #define CAC_EISA_IOCONF 0x38
83 static void cac_eisa_attach(device_t
, device_t
, void *);
84 static int cac_eisa_match(device_t
, cfdata_t
, void *);
86 static struct cac_ccb
*cac_eisa_l0_completed(struct cac_softc
*);
87 static int cac_eisa_l0_fifo_full(struct cac_softc
*);
88 static void cac_eisa_l0_intr_enable(struct cac_softc
*, int);
89 static int cac_eisa_l0_intr_pending(struct cac_softc
*);
90 static void cac_eisa_l0_submit(struct cac_softc
*, struct cac_ccb
*);
92 CFATTACH_DECL(cac_eisa
, sizeof(struct cac_softc
),
93 cac_eisa_match
, cac_eisa_attach
, NULL
, NULL
);
95 static const struct cac_linkage cac_eisa_l0
= {
96 cac_eisa_l0_completed
,
97 cac_eisa_l0_fifo_full
,
98 cac_eisa_l0_intr_enable
,
99 cac_eisa_l0_intr_pending
,
103 static struct cac_eisa_type
{
104 const char *ct_prodstr
;
105 const char *ct_typestr
;
106 const struct cac_linkage
*ct_linkage
;
107 } cac_eisa_type
[] = {
108 { "CPQ4001", "IDA", &cac_eisa_l0
},
109 { "CPQ4002", "IDA-2", &cac_eisa_l0
},
110 { "CPQ4010", "IEAS", &cac_eisa_l0
},
111 { "CPQ4020", "SMART", &cac_eisa_l0
},
112 { "CPQ4030", "SMART-2/E", &cac_l0
},
116 cac_eisa_match(device_t parent
, cfdata_t match
,
119 struct eisa_attach_args
*ea
;
124 for (i
= 0; i
< sizeof(cac_eisa_type
) / sizeof(cac_eisa_type
[0]); i
++)
125 if (strcmp(ea
->ea_idstring
, cac_eisa_type
[i
].ct_prodstr
) == 0)
132 cac_eisa_attach(device_t parent
, device_t self
, void *aux
)
134 struct eisa_attach_args
*ea
;
135 bus_space_handle_t ioh
;
136 eisa_chipset_tag_t ec
;
137 eisa_intr_handle_t ih
;
138 struct cac_softc
*sc
;
144 sc
= device_private(self
);
148 if (bus_space_map(iot
, EISA_SLOT_ADDR(ea
->ea_slot
) +
149 CAC_EISA_SLOT_OFFSET
, CAC_EISA_IOSIZE
, 0, &ioh
)) {
150 printf("can't map i/o space\n");
156 sc
->sc_dmat
= ea
->ea_dmat
;
159 * Map and establish the interrupt.
161 switch (bus_space_read_1(iot
, ioh
, CAC_EISA_IOCONF
) & 0xf0) {
175 printf("controller on invalid IRQ\n");
179 if (eisa_intr_map(ec
, irq
, &ih
)) {
180 printf("can't map interrupt (%d)\n", irq
);
184 intrstr
= eisa_intr_string(ec
, ih
);
185 if ((sc
->sc_ih
= eisa_intr_establish(ec
, ih
, IST_LEVEL
, IPL_BIO
,
186 cac_intr
, sc
)) == NULL
) {
187 printf("can't establish interrupt");
189 printf(" at %s", intrstr
);
195 * Print board type and attach to the bus-independent code.
197 for (i
= 0; i
< sizeof(cac_eisa_type
) / sizeof(cac_eisa_type
[0]); i
++)
198 if (strcmp(ea
->ea_idstring
, cac_eisa_type
[i
].ct_prodstr
) == 0)
201 printf(": Compaq %s\n", cac_eisa_type
[i
].ct_typestr
);
202 memcpy(&sc
->sc_cl
, cac_eisa_type
[i
].ct_linkage
, sizeof(sc
->sc_cl
));
203 cac_init(sc
, intrstr
, 0);
207 * Linkage specific to EISA boards.
211 cac_eisa_l0_fifo_full(struct cac_softc
*sc
)
214 return ((cac_inb(sc
, CAC_EISAREG_SYSTEM_DOORBELL
) &
215 CAC_EISA_CHANNEL_CLEAR
) == 0);
219 cac_eisa_l0_submit(struct cac_softc
*sc
, struct cac_ccb
*ccb
)
224 * On these boards, `ccb_hdr.size' is actually for control flags.
225 * Set it to zero and pass the value by means of an I/O port.
227 size
= le16toh(ccb
->ccb_hdr
.size
) << 2;
228 ccb
->ccb_hdr
.size
= 0;
230 bus_dmamap_sync(sc
->sc_dmat
, sc
->sc_dmamap
,
231 (char *)ccb
- (char *)sc
->sc_ccbs
,
232 sizeof(struct cac_ccb
), BUS_DMASYNC_PREWRITE
| BUS_DMASYNC_PREREAD
);
234 cac_outb(sc
, CAC_EISAREG_SYSTEM_DOORBELL
, CAC_EISA_CHANNEL_CLEAR
);
235 cac_outl(sc
, CAC_EISAREG_LIST_ADDR
, ccb
->ccb_paddr
);
236 cac_outw(sc
, CAC_EISAREG_LIST_LEN
, size
);
237 cac_outb(sc
, CAC_EISAREG_LOCAL_DOORBELL
, CAC_EISA_CHANNEL_BUSY
);
240 static struct cac_ccb
*
241 cac_eisa_l0_completed(struct cac_softc
*sc
)
247 if ((cac_inb(sc
, CAC_EISAREG_SYSTEM_DOORBELL
) &
248 CAC_EISA_CHANNEL_BUSY
) == 0)
251 cac_outb(sc
, CAC_EISAREG_SYSTEM_DOORBELL
, CAC_EISA_CHANNEL_BUSY
);
252 off
= cac_inl(sc
, CAC_EISAREG_COMPLETE_ADDR
);
253 status
= cac_inb(sc
, CAC_EISAREG_LIST_STATUS
);
254 cac_outb(sc
, CAC_EISAREG_LOCAL_DOORBELL
, CAC_EISA_CHANNEL_CLEAR
);
259 off
= (off
& ~3) - sc
->sc_ccbs_paddr
;
260 ccb
= (struct cac_ccb
*)((char *)sc
->sc_ccbs
+ off
);
262 bus_dmamap_sync(sc
->sc_dmat
, sc
->sc_dmamap
, off
, sizeof(struct cac_ccb
),
263 BUS_DMASYNC_POSTWRITE
| BUS_DMASYNC_POSTREAD
);
265 ccb
->ccb_req
.error
= status
;
267 if ((off
& 3) != 0 && ccb
->ccb_req
.error
== 0)
268 ccb
->ccb_req
.error
= CAC_RET_CMD_REJECTED
;
274 cac_eisa_l0_intr_pending(struct cac_softc
*sc
)
277 return (cac_inb(sc
, CAC_EISAREG_SYSTEM_DOORBELL
) &
278 CAC_EISA_CHANNEL_BUSY
);
282 cac_eisa_l0_intr_enable(struct cac_softc
*sc
, int state
)
286 cac_outb(sc
, CAC_EISAREG_SYSTEM_DOORBELL
,
287 ~CAC_EISA_CHANNEL_CLEAR
);
288 cac_outb(sc
, CAC_EISAREG_LOCAL_DOORBELL
,
289 CAC_EISA_CHANNEL_BUSY
);
290 cac_outb(sc
, CAC_EISAREG_INTR_MASK
, CAC_INTR_ENABLE
);
291 cac_outb(sc
, CAC_EISAREG_SYSTEM_MASK
, CAC_INTR_ENABLE
);
293 cac_outb(sc
, CAC_EISAREG_SYSTEM_MASK
, CAC_INTR_DISABLE
);