1 /*	$OpenBSD: opti.c,v 1.7 2003/06/02 19:24:22 mickey Exp $	*/
2 
3 /*
4  * Copyright (c) 1996 Michael Shalayeff
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  */
29 
30 /*
31  * Code to setup 82C929 chipset
32  */
33 
34 /* #define	OPTI_DEBUG	9 */
35 
36 #include <sys/param.h>
37 #include <sys/types.h>
38 #include <sys/kernel.h>
39 #include <sys/conf.h>
40 #include <sys/device.h>
41 
42 #include <machine/pio.h>
43 
44 #include <i386/isa/icu.h>
45 #include <dev/isa/isavar.h>
46 
47 #include <dev/isa/opti.h>
48 
49 #ifdef OPTI_DEBUG
50    int opti_debuglevel = OPTI_DEBUG;
51 #  define XDEBUG(level, data)	((opti_debuglevel >= level)? printf data:0)
52 #else
53 #  define XDEBUG(level, data)	/* ((opti_debuglevel >= level)? printf data:0) */
54 #endif
55 
56 int	opti_type = OPTI_C929;	/* XXX only one card can be installed */
57 
58 #define	OPTI_cd_valid_ift(i)	((i)==OPTI_SONY||(i)==OPTI_PANASONIC||\
59 					(i)==OPTI_MITSUMI||(i)==OPTI_IDE)
60 
61 static __inline int OPTI_cd_addr(int);
62 static __inline int OPTI_cd_irq(int);
63 static __inline int OPTI_cd_drq(int);
64 static __inline int OPTI_snd_addr(int);
65 static __inline int OPTI_snd_irq(int);
66 static __inline int OPTI_snd_drq(int);
67 static __inline void opti_outb(u_short, u_char);
68 static __inline u_char opti_inb(u_short);
69 static int opti_present(void);
70 
71 static __inline int
OPTI_cd_addr(a)72 OPTI_cd_addr(a)
73 	int	a;
74 {
75 	switch(a) {
76 	case 0x320:
77 		return 0xc0;
78 	case 0x330:
79 		return 0x40;
80 	case 0x340:
81 		return 0x00;
82 	case 0x360:
83 		return 0x80;
84 	default:
85 		return -1;
86 	}
87 }
88 
89 static __inline int
OPTI_cd_irq(i)90 OPTI_cd_irq(i)
91 	int	i;
92 {
93 	switch(i) {
94 	case 5:
95 		return 0x04;
96 	case 7:
97 		return 0x08;
98 	case 3:
99 		return 0x0c;
100 	case 9:
101 		return 0x10;
102 	case 10:
103 		return 0x14;
104 	case 11:
105 		return 0x18;
106 	case -1:
107 		return 0x00;
108 	default:
109 		return -1;
110 	}
111 }
112 
113 static __inline int
OPTI_cd_drq(d)114 OPTI_cd_drq(d)
115 	int	d;
116 {
117 	switch(d) {
118 	case 3:
119 	case 5:
120 		return 0;
121 	case 6:
122 		return 1;
123 	case 7:
124 		return 2;
125 	default:
126 		return 3;
127 	}
128 }
129 
130 #define	OPTI_snd_valid_ift(i)	((i)==OPTI_WSS||(i)==OPTI_SB)
131 
132 static __inline int
OPTI_snd_addr(a)133 OPTI_snd_addr(a)
134 	int	a;
135 {
136 	switch(a) {
137 	case 0x220:
138 		return 0x0;
139 	case 0x240:
140 		return 0x3;
141 	case 0x530:
142 		return 0x8;
143 	case 0xE80:
144 		return 0x9;
145 	case 0xF40:
146 		return 0xa;
147 	case 0x604:
148 		return 0xb;
149 	default:
150 		return -1;
151 	}
152 }
153 
154 static __inline int
OPTI_snd_irq(i)155 OPTI_snd_irq(i)
156 	int	i;
157 {
158 	switch(i) {
159 	case 5:
160 		return 0x04;
161 	case 7:
162 		return 0x08;
163 	case 3:
164 		return 0x0c;
165 	case 9:
166 		return 0x10;
167 	case 10:
168 		return 0x14;
169 	case 11:
170 		return 0x18;
171 	case -1:
172 		return 0x00;
173 	default:
174 		return -1;
175 	}
176 }
177 
178 static __inline int
OPTI_snd_drq(d)179 OPTI_snd_drq(d)
180 	int	d;
181 {
182 	switch(d) {
183 	case 3:
184 	case 5:
185 		return 0;
186 	case 6:
187 		return 1;
188 	case 7:
189 		return 2;
190 	default:
191 		return 3;
192 	}
193 }
194 
195 static __inline void
opti_outb(port,byte)196 opti_outb(port, byte)
197 	u_short port;
198 	u_char byte;
199 {
200 	outb( OPTI_PASSWD, opti_type );
201 	outb( port, byte );
202 }
203 
204 static __inline u_char
opti_inb(port)205 opti_inb(port)
206 	u_short port;
207 {
208 	outb( OPTI_PASSWD, opti_type );
209 	return inb( port );
210 }
211 
212 static int
opti_present()213 opti_present()
214 {
215 	register u_char	a, b;
216 	int s = splhigh();
217 
218 	a = opti_inb( OPTI_PASSWD );
219 	opti_outb( OPTI_PASSWD, 0x00 );
220 	b = opti_inb( OPTI_PASSWD );
221 	opti_outb( OPTI_PASSWD, a );
222 
223 	if (b != 2) {
224 		opti_type = OPTI_C928;
225 
226 		a = opti_inb( OPTI_PASSWD );
227 		opti_outb( OPTI_PASSWD, 0x00 );
228 		b = opti_inb( OPTI_PASSWD );
229 		opti_outb( OPTI_PASSWD, a );
230 	}
231 
232 	splx(s);
233 
234 	return b == 2;
235 }
236 
237 int
opti_cd_setup(ift,addr,irq,drq)238 opti_cd_setup(ift, addr, irq, drq)
239 	int	ift, addr, irq, drq;
240 {
241 	int	ret = 0;
242 
243 	XDEBUG( 2, ("opti: do CD setup type=%u, addr=0x%x, irq=%d, drq=%d\n",
244 		    ift, addr, irq, drq));
245 
246 	if( !opti_present() )
247 		XDEBUG( 2, ("opti: not present.\n"));
248 	else if( !OPTI_cd_valid_ift(ift) )
249 		XDEBUG( 2, ("opti: invalid CD-ROM interface type.\n"));
250 	else if( OPTI_cd_addr(addr) == -1)
251 		XDEBUG( 2, ("opti: illegal CD-ROM interface address.\n"));
252 	else if( OPTI_cd_irq(irq) == -1)
253 		XDEBUG( 2, ("opti: wrong CD-ROM irq number.\n"));
254 	else if( OPTI_cd_drq(drq) == -1)
255 		XDEBUG( 2, ("opti: bad CD_ROM drq number.\n"));
256 	else {
257 			/* so the setup */
258 		int s = splhigh();
259 		register u_char	a, b;
260 
261 			/* set interface type */
262 		a = opti_inb( OPTI_IFTP );
263 		b = (opti_inb( OPTI_DATA ) & 0x20) | 3 ;
264 		opti_outb( OPTI_DATA,  b );
265 		opti_outb( OPTI_IFTP, (a & OPTI_SND_MASK) | 2 * ift );
266 		opti_outb( OPTI_ENBL, 0x80 );
267 
268 			/* we don't need any additional setup for IDE CD-ROM */
269 		if( ift != OPTI_IDE )
270 		{
271 				/* set address */
272 			a = opti_inb( OPTI_DATA );
273 			opti_outb( OPTI_DATA, (a & 0x3f) |
274 			     (0x40 * OPTI_cd_addr(addr)) );
275 
276 				/* set irq */
277 			if( irq != IRQUNK )
278 			{
279 				a = opti_inb( OPTI_DATA );
280 				opti_outb( OPTI_DATA,
281 					  (inb( OPTI_DATA ) & 0xe3) |
282 					  OPTI_cd_irq(irq) );
283 			}
284 
285 				/* set drq */
286 			if( drq != DRQUNK )
287 			{
288 				a = opti_inb( OPTI_DATA );
289 				opti_outb( OPTI_DATA,
290 					  (inb( OPTI_DATA ) & 0xfc) |
291 					  OPTI_cd_drq(drq) );
292 			}
293 		}
294 		splx(s);
295 		DELAY(1000);
296 		ret = 1;
297 	}
298 
299 	return ret;
300 }
301 
302 int
opti_snd_setup(ift,addr,irq,drq)303 opti_snd_setup(ift, addr, irq, drq)
304 	int	ift, addr, irq, drq;
305 {
306 	XDEBUG( 2, ("opti: do SND setup type=%u,addr=%x,irq=%d,drq=%d\n",
307 		    ift, addr, irq, drq));
308 
309 	if( !opti_present() )
310 		XDEBUG( 2, ("opti: not present.\n"));
311 	else if( !OPTI_snd_valid_ift(ift) )
312 		XDEBUG( 2, ("opti: invalid SND interface type.\n"));
313 	else if( OPTI_snd_addr(addr) == -1)
314 		XDEBUG( 2, ("opti: illegal SND interface address.\n"));
315 	else if( OPTI_snd_irq(irq) == -1)
316 		XDEBUG( 2, ("opti: wrong SND irq number.\n"));
317 	else if( OPTI_snd_drq(drq) == -1)
318 		XDEBUG( 2, ("opti: bad SND drq number.\n"));
319 	else {
320 			/* so the setup */
321 		int s = splhigh();
322 		register u_char	a;
323 
324 		if (ift == OPTI_WSS) {
325 			a = opti_inb(OPTI_IFTP);
326 			opti_outb(OPTI_IFTP, ((a & ~OPTI_SND_MASK)
327 				  | (OPTI_snd_addr(addr)*16)) + 1);
328 			opti_outb(OPTI_ENBL, 0x1a);
329 		}
330 
331 		splx(s);
332 		DELAY(1000);
333 		return 1;
334 	}
335 
336 	return 0;
337 }
338