xref: /netbsd-src/sys/arch/hp300/dev/dio.c (revision d0fed6c87ddc40a8bffa6f99e7433ddfc864dd83)
1 /*	$NetBSD: dio.c,v 1.5 1997/04/04 09:53:43 thorpej Exp $	*/
2 
3 /*-
4  * Copyright (c) 1996 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
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  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
30  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Autoconfiguration and mapping support for the DIO bus.
41  */
42 
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/device.h>
46 #include <sys/kernel.h>
47 #include <sys/device.h>
48 
49 #include <machine/autoconf.h>
50 #include <machine/cpu.h>
51 
52 #include <hp300/dev/dioreg.h>
53 #include <hp300/dev/diovar.h>
54 
55 #include <hp300/dev/diodevs.h>
56 #include <hp300/dev/diodevs_data.h>
57 
58 extern	caddr_t internalhpib;
59 
60 int	dio_scodesize __P((struct dio_attach_args *));
61 char	*dio_devinfo __P((struct dio_attach_args *, char *, size_t));
62 
63 int	diomatch __P((struct device *, struct cfdata *, void *));
64 void	dioattach __P((struct device *, struct device *, void *));
65 int	dioprint __P((void *, const char *));
66 int	diosubmatch __P((struct device *, struct cfdata *, void *));
67 
68 struct cfattach dio_ca = {
69 	sizeof(struct device), diomatch, dioattach
70 };
71 
72 struct cfdriver dio_cd = {
73 	NULL, "dio", DV_DULL
74 };
75 
76 int
77 diomatch(parent, match, aux)
78 	struct device *parent;
79 	struct cfdata *match;
80 	void *aux;
81 {
82 	static int dio_matched = 0;
83 
84 	/* Allow only one instance. */
85 	if (dio_matched)
86 		return (0);
87 
88 	dio_matched = 1;
89 	return (1);
90 }
91 
92 void
93 dioattach(parent, self, aux)
94 	struct device *parent, *self;
95 	void *aux;
96 {
97 	struct dio_attach_args da;
98 	caddr_t pa, va;
99 	int scode, scmax, didmap, scodesize;
100 
101 	scmax = DIO_SCMAX(machineid);
102 	printf("\n");
103 
104 	for (scode = 0; scode < scmax; ) {
105 		if (DIO_INHOLE(scode)) {
106 			scode++;
107 			continue;
108 		}
109 
110 		didmap = 0;
111 
112 		/*
113 		 * Temporarily map the space corresponding to
114 		 * the current select code unless:
115 		 *	- this is the internal hpib select code,
116 		 *	- this is the console select code.
117 		 */
118 		pa = dio_scodetopa(scode);
119 		if (scode == conscode)
120 			va = conaddr;
121 		else if ((scode == 7) && internalhpib)
122 			va = internalhpib = (caddr_t)IIOV(pa);
123 		else {
124 			va = iomap(pa, NBPG);
125 			if (va == NULL) {
126 				printf("%s: can't map scode %d\n",
127 				    self->dv_xname, scode);
128 				scode++;
129 				continue;
130 			}
131 			didmap = 1;
132 		}
133 
134 		/* Check for hardware. */
135 		if (badaddr(va)) {
136 			if (didmap)
137 				iounmap(va, NBPG);
138 			scode++;
139 			continue;
140 		}
141 
142 		/* Fill out attach args. */
143 		bzero(&da, sizeof(da));
144 		da.da_scode = scode;
145 		da.da_id = DIO_ID(va);
146 
147 		if (DIO_ISFRAMEBUFFER(da.da_id))
148 			da.da_secid = DIO_SECID(va);
149 
150 		da.da_size = DIO_SIZE(scode, va);
151 		scodesize = dio_scodesize(&da);
152 		if (DIO_ISDIO(scode))
153 			da.da_size *= scodesize;
154 
155 		/* No longer need the device to be mapped. */
156 		if (didmap)
157 			iounmap(va, NBPG);
158 
159 		/* Attach matching device. */
160 		config_found_sm(self, &da, dioprint, diosubmatch);
161 		scode += scodesize;
162 	}
163 }
164 
165 int
166 diosubmatch(parent, cf, aux)
167 	struct device *parent;
168 	struct cfdata *cf;
169 	void *aux;
170 {
171 	struct dio_attach_args *da = aux;
172 
173 	if (cf->diocf_scode != DIO_UNKNOWN_SCODE &&
174 	    cf->diocf_scode != da->da_scode)
175 		return (0);
176 
177 	return ((*cf->cf_attach->ca_match)(parent, cf, aux));
178 }
179 
180 int
181 dioprint(aux, pnp)
182 	void *aux;
183 	const char *pnp;
184 {
185 	struct dio_attach_args *da = aux;
186 	char buf[128];
187 
188 	if (pnp)
189 		printf("%s at %s", dio_devinfo(da, buf, sizeof(buf)), pnp);
190 	printf(" scode %d", da->da_scode);
191 	return (UNCONF);
192 }
193 
194 /*
195  * Convert a select code to a system physical address.
196  */
197 void *
198 dio_scodetopa(scode)
199 	int scode;
200 {
201 	u_long rval;
202 
203 	if (scode == 7 && internalhpib)
204 		rval = DIO_IHPIBADDR;
205 	else if (DIO_ISDIO(scode))
206 		rval = DIO_BASE + (scode * DIO_DEVSIZE);
207 	else if (DIO_ISDIOII(scode))
208 		rval = DIOII_BASE + ((scode - DIOII_SCBASE) * DIOII_DEVSIZE);
209 	else
210 		rval = 0;
211 
212 	return ((void *)rval);
213 }
214 
215 /*
216  * Return the select code size for this device, defaulting to 1
217  * if we don't know what kind of device we have.
218  */
219 int
220 dio_scodesize(da)
221 	struct dio_attach_args *da;
222 {
223 	int i;
224 
225 	/*
226 	 * Deal with lame internal HP-IB controllers which don't have
227 	 * consistent/reliable device ids.
228 	 */
229 	if (da->da_scode == 7 && internalhpib)
230 		return (1);
231 
232 	/*
233 	 * Find the dio_devdata matchind the primary id.
234 	 * If we're a framebuffer, we also check the secondary id.
235 	 */
236 	for (i = 0; i < DIO_NDEVICES; i++) {
237 		if (da->da_id == dio_devdatas[i].dd_id) {
238 			if (DIO_ISFRAMEBUFFER(da->da_id)) {
239 				if (da->da_secid == dio_devdatas[i].dd_secid) {
240 					goto foundit;
241 				}
242 			} else {
243 			foundit:
244 				return (dio_devdatas[i].dd_nscode);
245 			}
246 		}
247 	}
248 
249 	/*
250 	 * Device is unknown.  Print a warning and assume a default.
251 	 */
252 	printf("WARNING: select code size unknown for id = 0x%x secid = 0x%x\n",
253 	    da->da_id, da->da_secid);
254 	return (1);
255 }
256 
257 /*
258  * Return a reasonable description of a DIO device.
259  */
260 char *
261 dio_devinfo(da, buf, buflen)
262 	struct dio_attach_args *da;
263 	char *buf;
264 	size_t buflen;
265 {
266 #ifdef DIOVERBOSE
267 	int i;
268 #endif
269 
270 	bzero(buf, buflen);
271 
272 	/*
273 	 * Deal with lame internal HP-IB controllers which don't have
274 	 * consistent/reliable device ids.
275 	 */
276 	if (da->da_scode == 7 && internalhpib) {
277 		sprintf(buf, DIO_DEVICE_DESC_IHPIB);
278 		return (buf);
279 	}
280 
281 #ifdef DIOVERBOSE
282 	/*
283 	 * Find the description matching our primary id.
284 	 * If we're a framebuffer, we also check the secondary id.
285 	 */
286 	for (i = 0; i < DIO_NDEVICES; i++) {
287 		if (da->da_id == dio_devdescs[i].dd_id) {
288 			if (DIO_ISFRAMEBUFFER(da->da_id)) {
289 				if (da->da_secid == dio_devdescs[i].dd_secid) {
290 					goto foundit;
291 				}
292 			} else {
293 			foundit:
294 				sprintf(buf, "%s", dio_devdescs[i].dd_desc);
295 				return (buf);
296 			}
297 		}
298 	}
299 #endif /* DIOVERBOSE */
300 
301 	/*
302 	 * Device is unknown.  Construct something reasonable.
303 	 */
304 	sprintf(buf, "device id = 0x%x secid = 0x%x",
305 	    da->da_id, da->da_secid);
306 	return (buf);
307 }
308