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