xref: /linux/arch/alpha/kernel/smc37c669.c (revision bf52ca5912c07664276c7b94db820fa2d638b681)
1 /*
2  * SMC 37C669 initialization code
3  */
4 #include <linux/kernel.h>
5 
6 #include <linux/mm.h>
7 #include <linux/init.h>
8 #include <linux/delay.h>
9 #include <linux/spinlock.h>
10 
11 #include <asm/hwrpb.h>
12 #include <asm/io.h>
13 
14 #include "proto.h"
15 
16 #if 0
17 # define DBG_DEVS(args)         printk args
18 #else
19 # define DBG_DEVS(args)
20 #endif
21 
22 #define KB              1024
23 #define MB              (1024*KB)
24 #define GB              (1024*MB)
25 
26 #define SMC_DEBUG   0
27 
28 /* File:	smcc669_def.h
29  *
30  * Copyright (C) 1997 by
31  * Digital Equipment Corporation, Maynard, Massachusetts.
32  * All rights reserved.
33  *
34  * This software is furnished under a license and may be used and copied
35  * only  in  accordance  of  the  terms  of  such  license  and with the
36  * inclusion of the above copyright notice. This software or  any  other
37  * copies thereof may not be provided or otherwise made available to any
38  * other person.  No title to and  ownership of the  software is  hereby
39  * transferred.
40  *
41  * The information in this software is  subject to change without notice
42  * and  should  not  be  construed  as a commitment by Digital Equipment
43  * Corporation.
44  *
45  * Digital assumes no responsibility for the use  or  reliability of its
46  * software on equipment which is not supplied by Digital.
47  *
48  *
49  * Abstract:
50  *
51  *	This file contains header definitions for the SMC37c669
52  *	Super I/O controller.
53  *
54  * Author:
55  *
56  *	Eric Rasmussen
57  *
58  * Modification History:
59  *
60  *	er	28-Jan-1997	Initial Entry
61  */
62 
63 #ifndef __SMC37c669_H
64 #define __SMC37c669_H
65 
66 /*
67 ** Macros for handling device IRQs
68 **
69 ** The mask acts as a flag used in mapping actual ISA IRQs (0 - 15)
70 ** to device IRQs (A - H).
71 */
72 #define SMC37c669_DEVICE_IRQ_MASK	0x80000000
73 #define SMC37c669_DEVICE_IRQ( __i )	\
74 	((SMC37c669_DEVICE_IRQ_MASK) | (__i))
75 #define SMC37c669_IS_DEVICE_IRQ(__i)	\
76 	(((__i) & (SMC37c669_DEVICE_IRQ_MASK)) == (SMC37c669_DEVICE_IRQ_MASK))
77 #define SMC37c669_RAW_DEVICE_IRQ(__i)	\
78 	((__i) & ~(SMC37c669_DEVICE_IRQ_MASK))
79 
80 /*
81 ** Macros for handling device DRQs
82 **
83 ** The mask acts as a flag used in mapping actual ISA DMA
84 ** channels to device DMA channels (A - C).
85 */
86 #define SMC37c669_DEVICE_DRQ_MASK	0x80000000
87 #define SMC37c669_DEVICE_DRQ(__d)	\
88 	((SMC37c669_DEVICE_DRQ_MASK) | (__d))
89 #define SMC37c669_IS_DEVICE_DRQ(__d)	\
90 	(((__d) & (SMC37c669_DEVICE_DRQ_MASK)) == (SMC37c669_DEVICE_DRQ_MASK))
91 #define SMC37c669_RAW_DEVICE_DRQ(__d)	\
92 	((__d) & ~(SMC37c669_DEVICE_DRQ_MASK))
93 
94 #define SMC37c669_DEVICE_ID	0x3
95 
96 /*
97 ** SMC37c669 Device Function Definitions
98 */
99 #define SERIAL_0	0
100 #define SERIAL_1	1
101 #define PARALLEL_0	2
102 #define FLOPPY_0	3
103 #define IDE_0		4
104 #define NUM_FUNCS	5
105 
106 /*
107 ** Default Device Function Mappings
108 */
109 #define COM1_BASE	0x3F8
110 #define COM1_IRQ	4
111 #define COM2_BASE	0x2F8
112 #define COM2_IRQ	3
113 #define PARP_BASE	0x3BC
114 #define PARP_IRQ	7
115 #define PARP_DRQ	3
116 #define FDC_BASE	0x3F0
117 #define FDC_IRQ		6
118 #define FDC_DRQ		2
119 
120 /*
121 ** Configuration On/Off Key Definitions
122 */
123 #define SMC37c669_CONFIG_ON_KEY		0x55
124 #define SMC37c669_CONFIG_OFF_KEY	0xAA
125 
126 /*
127 ** SMC 37c669 Device IRQs
128 */
129 #define SMC37c669_DEVICE_IRQ_A	    ( SMC37c669_DEVICE_IRQ( 0x01 ) )
130 #define SMC37c669_DEVICE_IRQ_B	    ( SMC37c669_DEVICE_IRQ( 0x02 ) )
131 #define SMC37c669_DEVICE_IRQ_C	    ( SMC37c669_DEVICE_IRQ( 0x03 ) )
132 #define SMC37c669_DEVICE_IRQ_D	    ( SMC37c669_DEVICE_IRQ( 0x04 ) )
133 #define SMC37c669_DEVICE_IRQ_E	    ( SMC37c669_DEVICE_IRQ( 0x05 ) )
134 #define SMC37c669_DEVICE_IRQ_F	    ( SMC37c669_DEVICE_IRQ( 0x06 ) )
135 /*      SMC37c669_DEVICE_IRQ_G	    *** RESERVED ***/
136 #define SMC37c669_DEVICE_IRQ_H	    ( SMC37c669_DEVICE_IRQ( 0x08 ) )
137 
138 /*
139 ** SMC 37c669 Device DMA Channel Definitions
140 */
141 #define SMC37c669_DEVICE_DRQ_A		    ( SMC37c669_DEVICE_DRQ( 0x01 ) )
142 #define SMC37c669_DEVICE_DRQ_B		    ( SMC37c669_DEVICE_DRQ( 0x02 ) )
143 #define SMC37c669_DEVICE_DRQ_C		    ( SMC37c669_DEVICE_DRQ( 0x03 ) )
144 
145 /*
146 ** Configuration Register Index Definitions
147 */
148 #define SMC37c669_CR00_INDEX	    0x00
149 #define SMC37c669_CR01_INDEX	    0x01
150 #define SMC37c669_CR02_INDEX	    0x02
151 #define SMC37c669_CR03_INDEX	    0x03
152 #define SMC37c669_CR04_INDEX	    0x04
153 #define SMC37c669_CR05_INDEX	    0x05
154 #define SMC37c669_CR06_INDEX	    0x06
155 #define SMC37c669_CR07_INDEX	    0x07
156 #define SMC37c669_CR08_INDEX	    0x08
157 #define SMC37c669_CR09_INDEX	    0x09
158 #define SMC37c669_CR0A_INDEX	    0x0A
159 #define SMC37c669_CR0B_INDEX	    0x0B
160 #define SMC37c669_CR0C_INDEX	    0x0C
161 #define SMC37c669_CR0D_INDEX	    0x0D
162 #define SMC37c669_CR0E_INDEX	    0x0E
163 #define SMC37c669_CR0F_INDEX	    0x0F
164 #define SMC37c669_CR10_INDEX	    0x10
165 #define SMC37c669_CR11_INDEX	    0x11
166 #define SMC37c669_CR12_INDEX	    0x12
167 #define SMC37c669_CR13_INDEX	    0x13
168 #define SMC37c669_CR14_INDEX	    0x14
169 #define SMC37c669_CR15_INDEX	    0x15
170 #define SMC37c669_CR16_INDEX	    0x16
171 #define SMC37c669_CR17_INDEX	    0x17
172 #define SMC37c669_CR18_INDEX	    0x18
173 #define SMC37c669_CR19_INDEX	    0x19
174 #define SMC37c669_CR1A_INDEX	    0x1A
175 #define SMC37c669_CR1B_INDEX	    0x1B
176 #define SMC37c669_CR1C_INDEX	    0x1C
177 #define SMC37c669_CR1D_INDEX	    0x1D
178 #define SMC37c669_CR1E_INDEX	    0x1E
179 #define SMC37c669_CR1F_INDEX	    0x1F
180 #define SMC37c669_CR20_INDEX	    0x20
181 #define SMC37c669_CR21_INDEX	    0x21
182 #define SMC37c669_CR22_INDEX	    0x22
183 #define SMC37c669_CR23_INDEX	    0x23
184 #define SMC37c669_CR24_INDEX	    0x24
185 #define SMC37c669_CR25_INDEX	    0x25
186 #define SMC37c669_CR26_INDEX	    0x26
187 #define SMC37c669_CR27_INDEX	    0x27
188 #define SMC37c669_CR28_INDEX	    0x28
189 #define SMC37c669_CR29_INDEX	    0x29
190 
191 /*
192 ** Configuration Register Alias Definitions
193 */
194 #define SMC37c669_DEVICE_ID_INDEX		    SMC37c669_CR0D_INDEX
195 #define SMC37c669_DEVICE_REVISION_INDEX		    SMC37c669_CR0E_INDEX
196 #define SMC37c669_FDC_BASE_ADDRESS_INDEX	    SMC37c669_CR20_INDEX
197 #define SMC37c669_IDE_BASE_ADDRESS_INDEX	    SMC37c669_CR21_INDEX
198 #define SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX	    SMC37c669_CR22_INDEX
199 #define SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX	    SMC37c669_CR23_INDEX
200 #define SMC37c669_SERIAL0_BASE_ADDRESS_INDEX	    SMC37c669_CR24_INDEX
201 #define SMC37c669_SERIAL1_BASE_ADDRESS_INDEX	    SMC37c669_CR25_INDEX
202 #define SMC37c669_PARALLEL_FDC_DRQ_INDEX	    SMC37c669_CR26_INDEX
203 #define SMC37c669_PARALLEL_FDC_IRQ_INDEX	    SMC37c669_CR27_INDEX
204 #define SMC37c669_SERIAL_IRQ_INDEX		    SMC37c669_CR28_INDEX
205 
206 /*
207 ** Configuration Register Definitions
208 **
209 ** The INDEX (write only) and DATA (read/write) ports are effective
210 ** only when the chip is in the Configuration State.
211 */
212 typedef struct _SMC37c669_CONFIG_REGS {
213     unsigned char index_port;
214     unsigned char data_port;
215 } SMC37c669_CONFIG_REGS;
216 
217 /*
218 ** CR00 - default value 0x28
219 **
220 **  IDE_EN (CR00<1:0>):
221 **	0x - 30ua pull-ups on nIDEEN, nHDCS0, NHDCS1
222 **	11 - IRQ_H available as IRQ output,
223 **	     IRRX2, IRTX2 available as alternate IR pins
224 **	10 - nIDEEN, nHDCS0, nHDCS1 used to control IDE
225 **
226 **  VALID (CR00<7>):
227 **	A high level on this software controlled bit can
228 **	be used to indicate that a valid configuration
229 **	cycle has occurred.  The control software must
230 **	take care to set this bit at the appropriate times.
231 **	Set to zero after power up.  This bit has no
232 **	effect on any other hardware in the chip.
233 **
234 */
235 typedef union _SMC37c669_CR00 {
236     unsigned char as_uchar;
237     struct {
238     	unsigned ide_en : 2;	    /* See note above		*/
239 	unsigned reserved1 : 1;	    /* RAZ			*/
240 	unsigned fdc_pwr : 1;	    /* 1 = supply power to FDC  */
241 	unsigned reserved2 : 3;	    /* Read as 010b		*/
242 	unsigned valid : 1;	    /* See note above		*/
243     }	by_field;
244 } SMC37c669_CR00;
245 
246 /*
247 ** CR01 - default value 0x9C
248 */
249 typedef union _SMC37c669_CR01 {
250     unsigned char as_uchar;
251     struct {
252     	unsigned reserved1 : 2;	    /* RAZ			    */
253 	unsigned ppt_pwr : 1;	    /* 1 = supply power to PPT	    */
254 	unsigned ppt_mode : 1;	    /* 1 = Printer mode, 0 = EPP    */
255 	unsigned reserved2 : 1;	    /* Read as 1		    */
256 	unsigned reserved3 : 2;	    /* RAZ			    */
257 	unsigned lock_crx: 1;	    /* Lock CR00 - CR18		    */
258     }	by_field;
259 } SMC37c669_CR01;
260 
261 /*
262 ** CR02 - default value 0x88
263 */
264 typedef union _SMC37c669_CR02 {
265     unsigned char as_uchar;
266     struct {
267     	unsigned reserved1 : 3;	    /* RAZ			    */
268 	unsigned uart1_pwr : 1;	    /* 1 = supply power to UART1    */
269 	unsigned reserved2 : 3;	    /* RAZ			    */
270 	unsigned uart2_pwr : 1;	    /* 1 = supply power to UART2    */
271     }	by_field;
272 } SMC37c669_CR02;
273 
274 /*
275 ** CR03 - default value 0x78
276 **
277 **  CR03<7>	CR03<2>	    Pin 94
278 **  -------	-------	    ------
279 **     0	   X	    DRV2 (input)
280 **     1	   0	    ADRX
281 **     1	   1	    IRQ_B
282 **
283 **  CR03<6>	CR03<5>	    Op Mode
284 **  -------	-------	    -------
285 **     0	   0	    Model 30
286 **     0	   1	    PS/2
287 **     1	   0	    Reserved
288 **     1	   1	    AT Mode
289 */
290 typedef union _SMC37c669_CR03 {
291     unsigned char as_uchar;
292     struct {
293     	unsigned pwrgd_gamecs : 1;  /* 1 = PWRGD, 0 = GAMECS	    */
294 	unsigned fdc_mode2 : 1;	    /* 1 = Enhanced Mode 2	    */
295 	unsigned pin94_0 : 1;	    /* See note above		    */
296 	unsigned reserved1 : 1;	    /* RAZ			    */
297 	unsigned drvden : 1;	    /* 1 = high, 0 - output	    */
298 	unsigned op_mode : 2;	    /* See note above		    */
299 	unsigned pin94_1 : 1;	    /* See note above		    */
300     }	by_field;
301 } SMC37c669_CR03;
302 
303 /*
304 ** CR04 - default value 0x00
305 **
306 **  PP_EXT_MODE:
307 **	If CR01<PP_MODE> = 0 and PP_EXT_MODE =
308 **	    00 - Standard and Bidirectional
309 **	    01 - EPP mode and SPP
310 **	    10 - ECP mode
311 **		 In this mode, 2 drives can be supported
312 **		 directly, 3 or 4 drives must use external
313 **		 4 drive support.  SPP can be selected
314 **		 through the ECR register of ECP as mode 000.
315 **	    11 - ECP mode and EPP mode
316 **		 In this mode, 2 drives can be supported
317 **		 directly, 3 or 4 drives must use external
318 **		 4 drive support.  SPP can be selected
319 **		 through the ECR register of ECP as mode 000.
320 **		 In this mode, EPP can be selected through
321 **		 the ECR register of ECP as mode 100.
322 **
323 **  PP_FDC:
324 **	00 - Normal
325 **	01 - PPFD1
326 **	10 - PPFD2
327 **	11 - Reserved
328 **
329 **  MIDI1:
330 **	Serial Clock Select:
331 **	    A low level on this bit disables MIDI support,
332 **	    clock = divide by 13.  A high level on this
333 **	    bit enables MIDI support, clock = divide by 12.
334 **
335 **	MIDI operates at 31.25 Kbps which can be derived
336 **	from 125 KHz (24 MHz / 12 = 2 MHz, 2 MHz / 16 = 125 KHz)
337 **
338 **  ALT_IO:
339 **	0 - Use pins IRRX, IRTX
340 **	1 - Use pins IRRX2, IRTX2
341 **
342 **	If this bit is set, the IR receive and transmit
343 **	functions will not be available on pins 25 and 26
344 **	unless CR00<IDE_EN> = 11.
345 */
346 typedef union _SMC37c669_CR04 {
347     unsigned char as_uchar;
348     struct {
349     	unsigned ppt_ext_mode : 2;  /* See note above		    */
350 	unsigned ppt_fdc : 2;	    /* See note above		    */
351 	unsigned midi1 : 1;	    /* See note above		    */
352 	unsigned midi2 : 1;	    /* See note above		    */
353 	unsigned epp_type : 1;	    /* 0 = EPP 1.9, 1 = EPP 1.7	    */
354 	unsigned alt_io : 1;	    /* See note above		    */
355     }	by_field;
356 } SMC37c669_CR04;
357 
358 /*
359 ** CR05 - default value 0x00
360 **
361 **  DEN_SEL:
362 **	00 - Densel output normal
363 **	01 - Reserved
364 **	10 - Densel output 1
365 **	11 - Densel output 0
366 **
367 */
368 typedef union _SMC37c669_CR05 {
369     unsigned char as_uchar;
370     struct {
371     	unsigned reserved1 : 2;	    /* RAZ					*/
372 	unsigned fdc_dma_mode : 1;  /* 0 = burst, 1 = non-burst			*/
373 	unsigned den_sel : 2;	    /* See note above				*/
374 	unsigned swap_drv : 1;	    /* Swap the FDC motor selects		*/
375 	unsigned extx4 : 1;	    /* 0 = 2 drive, 1 = external 4 drive decode	*/
376 	unsigned reserved2 : 1;	    /* RAZ					*/
377     }	by_field;
378 } SMC37c669_CR05;
379 
380 /*
381 ** CR06 - default value 0xFF
382 */
383 typedef union _SMC37c669_CR06 {
384     unsigned char as_uchar;
385     struct {
386     	unsigned floppy_a : 2;	    /* Type of floppy drive A	    */
387 	unsigned floppy_b : 2;	    /* Type of floppy drive B	    */
388 	unsigned floppy_c : 2;	    /* Type of floppy drive C	    */
389 	unsigned floppy_d : 2;	    /* Type of floppy drive D	    */
390     }	by_field;
391 } SMC37c669_CR06;
392 
393 /*
394 ** CR07 - default value 0x00
395 **
396 **  Auto Power Management CR07<7:4>:
397 **	0 - Auto Powerdown disabled (default)
398 **	1 - Auto Powerdown enabled
399 **
400 **	This bit is reset to the default state by POR or
401 **	a hardware reset.
402 **
403 */
404 typedef union _SMC37c669_CR07 {
405     unsigned char as_uchar;
406     struct {
407     	unsigned floppy_boot : 2;   /* 0 = A:, 1 = B:		    */
408 	unsigned reserved1 : 2;	    /* RAZ			    */
409 	unsigned ppt_en : 1;	    /* See note above		    */
410 	unsigned uart1_en : 1;	    /* See note above		    */
411 	unsigned uart2_en : 1;	    /* See note above		    */
412 	unsigned fdc_en : 1;	    /* See note above		    */
413     }	by_field;
414 } SMC37c669_CR07;
415 
416 /*
417 ** CR08 - default value 0x00
418 */
419 typedef union _SMC37c669_CR08 {
420     unsigned char as_uchar;
421     struct {
422     	unsigned zero : 4;	    /* 0			    */
423 	unsigned addrx7_4 : 4;	    /* ADR<7:3> for ADRx decode	    */
424     }	by_field;
425 } SMC37c669_CR08;
426 
427 /*
428 ** CR09 - default value 0x00
429 **
430 **  ADRx_CONFIG:
431 **	00 - ADRx disabled
432 **	01 - 1 byte decode A<3:0> = 0000b
433 **	10 - 8 byte block decode A<3:0> = 0XXXb
434 **	11 - 16 byte block decode A<3:0> = XXXXb
435 **
436 */
437 typedef union _SMC37c669_CR09 {
438     unsigned char as_uchar;
439     struct {
440     	unsigned adra8 : 3;	    /* ADR<10:8> for ADRx decode    */
441 	unsigned reserved1 : 3;
442 	unsigned adrx_config : 2;   /* See note above		    */
443     }	by_field;
444 } SMC37c669_CR09;
445 
446 /*
447 ** CR0A - default value 0x00
448 */
449 typedef union _SMC37c669_CR0A {
450     unsigned char as_uchar;
451     struct {
452     	unsigned ecp_fifo_threshold : 4;
453 	unsigned reserved1 : 4;
454     }	by_field;
455 } SMC37c669_CR0A;
456 
457 /*
458 ** CR0B - default value 0x00
459 */
460 typedef union _SMC37c669_CR0B {
461     unsigned char as_uchar;
462     struct {
463     	unsigned fdd0_drtx : 2;	    /* FDD0 Data Rate Table	    */
464 	unsigned fdd1_drtx : 2;	    /* FDD1 Data Rate Table	    */
465 	unsigned fdd2_drtx : 2;	    /* FDD2 Data Rate Table	    */
466 	unsigned fdd3_drtx : 2;	    /* FDD3 Data Rate Table	    */
467     }	by_field;
468 } SMC37c669_CR0B;
469 
470 /*
471 ** CR0C - default value 0x00
472 **
473 **  UART2_MODE:
474 **	000 - Standard (default)
475 **	001 - IrDA (HPSIR)
476 **	010 - Amplitude Shift Keyed IR @500 KHz
477 **	011 - Reserved
478 **	1xx - Reserved
479 **
480 */
481 typedef union _SMC37c669_CR0C {
482     unsigned char as_uchar;
483     struct {
484     	unsigned uart2_rcv_polarity : 1;    /* 1 = invert RX		*/
485 	unsigned uart2_xmit_polarity : 1;   /* 1 = invert TX		*/
486 	unsigned uart2_duplex : 1;	    /* 1 = full, 0 = half	*/
487 	unsigned uart2_mode : 3;	    /* See note above		*/
488 	unsigned uart1_speed : 1;	    /* 1 = high speed enabled	*/
489 	unsigned uart2_speed : 1;	    /* 1 = high speed enabled	*/
490     }	by_field;
491 } SMC37c669_CR0C;
492 
493 /*
494 ** CR0D - default value 0x03
495 **
496 **  Device ID Register - read only
497 */
498 typedef union _SMC37c669_CR0D {
499     unsigned char as_uchar;
500     struct {
501     	unsigned device_id : 8;	    /* Returns 0x3 in this field    */
502     }	by_field;
503 } SMC37c669_CR0D;
504 
505 /*
506 ** CR0E - default value 0x02
507 **
508 **  Device Revision Register - read only
509 */
510 typedef union _SMC37c669_CR0E {
511     unsigned char as_uchar;
512     struct {
513     	unsigned device_rev : 8;    /* Returns 0x2 in this field    */
514     }	by_field;
515 } SMC37c669_CR0E;
516 
517 /*
518 ** CR0F - default value 0x00
519 */
520 typedef union _SMC37c669_CR0F {
521     unsigned char as_uchar;
522     struct {
523     	unsigned test0 : 1;	    /* Reserved - set to 0	    */
524 	unsigned test1 : 1;	    /* Reserved - set to 0	    */
525 	unsigned test2 : 1;	    /* Reserved - set to 0	    */
526 	unsigned test3 : 1;	    /* Reserved - set t0 0	    */
527 	unsigned test4 : 1;	    /* Reserved - set to 0	    */
528 	unsigned test5 : 1;	    /* Reserved - set t0 0	    */
529 	unsigned test6 : 1;	    /* Reserved - set t0 0	    */
530 	unsigned test7 : 1;	    /* Reserved - set to 0	    */
531     }	by_field;
532 } SMC37c669_CR0F;
533 
534 /*
535 ** CR10 - default value 0x00
536 */
537 typedef union _SMC37c669_CR10 {
538     unsigned char as_uchar;
539     struct {
540     	unsigned reserved1 : 3;	     /* RAZ			    */
541 	unsigned pll_gain : 1;	     /* 1 = 3V, 2 = 5V operation    */
542 	unsigned pll_stop : 1;	     /* 1 = stop PLLs		    */
543 	unsigned ace_stop : 1;	     /* 1 = stop UART clocks	    */
544 	unsigned pll_clock_ctrl : 1; /* 0 = 14.318 MHz, 1 = 24 MHz  */
545 	unsigned ir_test : 1;	     /* Enable IR test mode	    */
546     }	by_field;
547 } SMC37c669_CR10;
548 
549 /*
550 ** CR11 - default value 0x00
551 */
552 typedef union _SMC37c669_CR11 {
553     unsigned char as_uchar;
554     struct {
555     	unsigned ir_loopback : 1;   /* Internal IR loop back		    */
556 	unsigned test_10ms : 1;	    /* Test 10ms autopowerdown FDC timeout  */
557 	unsigned reserved1 : 6;	    /* RAZ				    */
558     }	by_field;
559 } SMC37c669_CR11;
560 
561 /*
562 ** CR12 - CR1D are reserved registers
563 */
564 
565 /*
566 ** CR1E - default value 0x80
567 **
568 **  GAMECS:
569 **	00 - GAMECS disabled
570 **	01 - 1 byte decode ADR<3:0> = 0001b
571 **	10 - 8 byte block decode ADR<3:0> = 0XXXb
572 **	11 - 16 byte block decode ADR<3:0> = XXXXb
573 **
574 */
575 typedef union _SMC37c66_CR1E {
576     unsigned char as_uchar;
577     struct {
578     	unsigned gamecs_config: 2;   /* See note above		    */
579 	unsigned gamecs_addr9_4 : 6; /* GAMECS Addr<9:4>	    */
580     }	by_field;
581 } SMC37c669_CR1E;
582 
583 /*
584 ** CR1F - default value 0x00
585 **
586 **  DT0 DT1 DRVDEN0 DRVDEN1 Drive Type
587 **  --- --- ------- ------- ----------
588 **   0   0  DENSEL  DRATE0  4/2/1 MB 3.5"
589 **                          2/1 MB 5.25"
590 **                          2/1.6/1 MB 3.5" (3-mode)
591 **   0   1  DRATE1  DRATE0
592 **   1   0  nDENSEL DRATE0  PS/2
593 **   1   1  DRATE0  DRATE1
594 **
595 **  Note: DENSEL, DRATE1, and DRATE0 map onto two output
596 **	  pins - DRVDEN0 and DRVDEN1.
597 **
598 */
599 typedef union _SMC37c669_CR1F {
600     unsigned char as_uchar;
601     struct {
602     	unsigned fdd0_drive_type : 2;	/* FDD0 drive type	    */
603 	unsigned fdd1_drive_type : 2;	/* FDD1 drive type	    */
604 	unsigned fdd2_drive_type : 2;	/* FDD2 drive type	    */
605 	unsigned fdd3_drive_type : 2;	/* FDD3 drive type	    */
606     }	by_field;
607 } SMC37c669_CR1F;
608 
609 /*
610 ** CR20 - default value 0x3C
611 **
612 **  FDC Base Address Register
613 **	- To disable this decode set Addr<9:8> = 0
614 **	- A<10> = 0, A<3:0> = 0XXXb to access.
615 **
616 */
617 typedef union _SMC37c669_CR20 {
618     unsigned char as_uchar;
619     struct {
620     	unsigned zero : 2;	    /* 0			    */
621 	unsigned addr9_4 : 6;	    /* FDC Addr<9:4>		    */
622     }	by_field;
623 } SMC37c669_CR20;
624 
625 /*
626 ** CR21 - default value 0x3C
627 **
628 **  IDE Base Address Register
629 **	- To disable this decode set Addr<9:8> = 0
630 **	- A<10> = 0, A<3:0> = 0XXXb to access.
631 **
632 */
633 typedef union _SMC37c669_CR21 {
634     unsigned char as_uchar;
635     struct {
636     	unsigned zero : 2;	    /* 0			    */
637 	unsigned addr9_4 : 6;	    /* IDE Addr<9:4>		    */
638     }	by_field;
639 } SMC37c669_CR21;
640 
641 /*
642 ** CR22 - default value 0x3D
643 **
644 **  IDE Alternate Status Base Address Register
645 **	- To disable this decode set Addr<9:8> = 0
646 **	- A<10> = 0, A<3:0> = 0110b to access.
647 **
648 */
649 typedef union _SMC37c669_CR22 {
650     unsigned char as_uchar;
651     struct {
652     	unsigned zero : 2;	    /* 0			    */
653 	unsigned addr9_4 : 6;	    /* IDE Alt Status Addr<9:4>	    */
654     }	by_field;
655 } SMC37c669_CR22;
656 
657 /*
658 ** CR23 - default value 0x00
659 **
660 **  Parallel Port Base Address Register
661 **	- To disable this decode set Addr<9:8> = 0
662 **	- A<10> = 0 to access.
663 **	- If EPP is enabled, A<2:0> = XXXb to access.
664 **	  If EPP is NOT enabled, A<1:0> = XXb to access
665 **
666 */
667 typedef union _SMC37c669_CR23 {
668     unsigned char as_uchar;
669     struct {
670 	unsigned addr9_2 : 8;	    /* Parallel Port Addr<9:2>	    */
671     }	by_field;
672 } SMC37c669_CR23;
673 
674 /*
675 ** CR24 - default value 0x00
676 **
677 **  UART1 Base Address Register
678 **	- To disable this decode set Addr<9:8> = 0
679 **	- A<10> = 0, A<2:0> = XXXb to access.
680 **
681 */
682 typedef union _SMC37c669_CR24 {
683     unsigned char as_uchar;
684     struct {
685     	unsigned zero : 1;	    /* 0			    */
686 	unsigned addr9_3 : 7;	    /* UART1 Addr<9:3>		    */
687     }	by_field;
688 } SMC37c669_CR24;
689 
690 /*
691 ** CR25 - default value 0x00
692 **
693 **  UART2 Base Address Register
694 **	- To disable this decode set Addr<9:8> = 0
695 **	- A<10> = 0, A<2:0> = XXXb to access.
696 **
697 */
698 typedef union _SMC37c669_CR25 {
699     unsigned char as_uchar;
700     struct {
701     	unsigned zero : 1;	    /* 0			    */
702 	unsigned addr9_3 : 7;	    /* UART2 Addr<9:3>		    */
703     }	by_field;
704 } SMC37c669_CR25;
705 
706 /*
707 ** CR26 - default value 0x00
708 **
709 **  Parallel Port / FDC DMA Select Register
710 **
711 **  D3 - D0	  DMA
712 **  D7 - D4	Selected
713 **  -------	--------
714 **   0000	 None
715 **   0001	 DMA_A
716 **   0010	 DMA_B
717 **   0011	 DMA_C
718 **
719 */
720 typedef union _SMC37c669_CR26 {
721     unsigned char as_uchar;
722     struct {
723     	unsigned ppt_drq : 4;	    /* See note above		    */
724 	unsigned fdc_drq : 4;	    /* See note above		    */
725     }	by_field;
726 } SMC37c669_CR26;
727 
728 /*
729 ** CR27 - default value 0x00
730 **
731 **  Parallel Port / FDC IRQ Select Register
732 **
733 **  D3 - D0	  IRQ
734 **  D7 - D4	Selected
735 **  -------	--------
736 **   0000	 None
737 **   0001	 IRQ_A
738 **   0010	 IRQ_B
739 **   0011	 IRQ_C
740 **   0100	 IRQ_D
741 **   0101	 IRQ_E
742 **   0110	 IRQ_F
743 **   0111	 Reserved
744 **   1000	 IRQ_H
745 **
746 **  Any unselected IRQ REQ is in tristate
747 **
748 */
749 typedef union _SMC37c669_CR27 {
750     unsigned char as_uchar;
751     struct {
752     	unsigned ppt_irq : 4;	    /* See note above		    */
753 	unsigned fdc_irq : 4;	    /* See note above		    */
754     }	by_field;
755 } SMC37c669_CR27;
756 
757 /*
758 ** CR28 - default value 0x00
759 **
760 **  UART IRQ Select Register
761 **
762 **  D3 - D0	  IRQ
763 **  D7 - D4	Selected
764 **  -------	--------
765 **   0000	 None
766 **   0001	 IRQ_A
767 **   0010	 IRQ_B
768 **   0011	 IRQ_C
769 **   0100	 IRQ_D
770 **   0101	 IRQ_E
771 **   0110	 IRQ_F
772 **   0111	 Reserved
773 **   1000	 IRQ_H
774 **   1111	 share with UART1 (only for UART2)
775 **
776 **  Any unselected IRQ REQ is in tristate
777 **
778 **  To share an IRQ between UART1 and UART2, set
779 **  UART1 to use the desired IRQ and set UART2 to
780 **  0xF to enable sharing mechanism.
781 **
782 */
783 typedef union _SMC37c669_CR28 {
784     unsigned char as_uchar;
785     struct {
786     	unsigned uart2_irq : 4;	    /* See note above		    */
787 	unsigned uart1_irq : 4;	    /* See note above		    */
788     }	by_field;
789 } SMC37c669_CR28;
790 
791 /*
792 ** CR29 - default value 0x00
793 **
794 **  IRQIN IRQ Select Register
795 **
796 **  D3 - D0	  IRQ
797 **  D7 - D4	Selected
798 **  -------	--------
799 **   0000	 None
800 **   0001	 IRQ_A
801 **   0010	 IRQ_B
802 **   0011	 IRQ_C
803 **   0100	 IRQ_D
804 **   0101	 IRQ_E
805 **   0110	 IRQ_F
806 **   0111	 Reserved
807 **   1000	 IRQ_H
808 **
809 **  Any unselected IRQ REQ is in tristate
810 **
811 */
812 typedef union _SMC37c669_CR29 {
813     unsigned char as_uchar;
814     struct {
815     	unsigned irqin_irq : 4;	    /* See note above		    */
816 	unsigned reserved1 : 4;	    /* RAZ			    */
817     }	by_field;
818 } SMC37c669_CR29;
819 
820 /*
821 ** Aliases of Configuration Register formats (should match
822 ** the set of index aliases).
823 **
824 ** Note that CR24 and CR25 have the same format and are the
825 ** base address registers for UART1 and UART2.  Because of
826 ** this we only define 1 alias here - for CR24 - as the serial
827 ** base address register.
828 **
829 ** Note that CR21 and CR22 have the same format and are the
830 ** base address and alternate status address registers for
831 ** the IDE controller.  Because of this we only define 1 alias
832 ** here - for CR21 - as the IDE address register.
833 **
834 */
835 typedef SMC37c669_CR0D SMC37c669_DEVICE_ID_REGISTER;
836 typedef SMC37c669_CR0E SMC37c669_DEVICE_REVISION_REGISTER;
837 typedef SMC37c669_CR20 SMC37c669_FDC_BASE_ADDRESS_REGISTER;
838 typedef SMC37c669_CR21 SMC37c669_IDE_ADDRESS_REGISTER;
839 typedef SMC37c669_CR23 SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER;
840 typedef SMC37c669_CR24 SMC37c669_SERIAL_BASE_ADDRESS_REGISTER;
841 typedef SMC37c669_CR26 SMC37c669_PARALLEL_FDC_DRQ_REGISTER;
842 typedef SMC37c669_CR27 SMC37c669_PARALLEL_FDC_IRQ_REGISTER;
843 typedef SMC37c669_CR28 SMC37c669_SERIAL_IRQ_REGISTER;
844 
845 /*
846 ** ISA/Device IRQ Translation Table Entry Definition
847 */
848 typedef struct _SMC37c669_IRQ_TRANSLATION_ENTRY {
849     int device_irq;
850     int isa_irq;
851 } SMC37c669_IRQ_TRANSLATION_ENTRY;
852 
853 /*
854 ** ISA/Device DMA Translation Table Entry Definition
855 */
856 typedef struct _SMC37c669_DRQ_TRANSLATION_ENTRY {
857     int device_drq;
858     int isa_drq;
859 } SMC37c669_DRQ_TRANSLATION_ENTRY;
860 
861 /*
862 ** External Interface Function Prototype Declarations
863 */
864 
865 SMC37c669_CONFIG_REGS *SMC37c669_detect(
866     int
867 );
868 
869 unsigned int SMC37c669_enable_device(
870     unsigned int func
871 );
872 
873 unsigned int SMC37c669_disable_device(
874     unsigned int func
875 );
876 
877 unsigned int SMC37c669_configure_device(
878     unsigned int func,
879     int port,
880     int irq,
881     int drq
882 );
883 
884 void SMC37c669_display_device_info(
885     void
886 );
887 
888 #endif	/* __SMC37c669_H */
889 
890 /* file:	smcc669.c
891  *
892  * Copyright (C) 1997 by
893  * Digital Equipment Corporation, Maynard, Massachusetts.
894  * All rights reserved.
895  *
896  * This software is furnished under a license and may be used and copied
897  * only  in  accordance  of  the  terms  of  such  license  and with the
898  * inclusion of the above copyright notice. This software or  any  other
899  * copies thereof may not be provided or otherwise made available to any
900  * other person.  No title to and  ownership of the  software is  hereby
901  * transferred.
902  *
903  * The information in this software is  subject to change without notice
904  * and  should  not  be  construed  as a commitment by digital equipment
905  * corporation.
906  *
907  * Digital assumes no responsibility for the use  or  reliability of its
908  * software on equipment which is not supplied by digital.
909  */
910 
911 /*
912  *++
913  *  FACILITY:
914  *
915  *      Alpha SRM Console Firmware
916  *
917  *  MODULE DESCRIPTION:
918  *
919  *	SMC37c669 Super I/O controller configuration routines.
920  *
921  *  AUTHORS:
922  *
923  *	Eric Rasmussen
924  *
925  *  CREATION DATE:
926  *
927  *	28-Jan-1997
928  *
929  *  MODIFICATION HISTORY:
930  *
931  *	er	01-May-1997	Fixed pointer conversion errors in
932  *				SMC37c669_get_device_config().
933  *      er	28-Jan-1997	Initial version.
934  *
935  *--
936  */
937 
938 #ifndef TRUE
939 #define TRUE 1
940 #endif
941 #ifndef FALSE
942 #define FALSE 0
943 #endif
944 
945 #define wb( _x_, _y_ )	outb( _y_, (unsigned int)((unsigned long)_x_) )
946 #define rb( _x_ )	inb( (unsigned int)((unsigned long)_x_) )
947 
948 /*
949 ** Local storage for device configuration information.
950 **
951 ** Since the SMC37c669 does not provide an explicit
952 ** mechanism for enabling/disabling individual device
953 ** functions, other than unmapping the device, local
954 ** storage for device configuration information is
955 ** allocated here for use in implementing our own
956 ** function enable/disable scheme.
957 */
958 static struct DEVICE_CONFIG {
959     unsigned int port1;
960     unsigned int port2;
961     int irq;
962     int drq;
963 } local_config [NUM_FUNCS];
964 
965 /*
966 ** List of all possible addresses for the Super I/O chip
967 */
968 static unsigned long SMC37c669_Addresses[] __initdata =
969     {
970 	0x3F0UL,	    /* Primary address	    */
971 	0x370UL,	    /* Secondary address    */
972 	0UL		    /* End of list	    */
973     };
974 
975 /*
976 ** Global Pointer to the Super I/O device
977 */
978 static SMC37c669_CONFIG_REGS *SMC37c669 __initdata = NULL;
979 
980 /*
981 ** IRQ Translation Table
982 **
983 ** The IRQ translation table is a list of SMC37c669 device
984 ** and standard ISA IRQs.
985 **
986 */
987 static SMC37c669_IRQ_TRANSLATION_ENTRY *SMC37c669_irq_table __initdata;
988 
989 /*
990 ** The following definition is for the default IRQ
991 ** translation table.
992 */
993 static SMC37c669_IRQ_TRANSLATION_ENTRY SMC37c669_default_irq_table[]
994 __initdata =
995     {
996 	{ SMC37c669_DEVICE_IRQ_A, -1 },
997 	{ SMC37c669_DEVICE_IRQ_B, -1 },
998 	{ SMC37c669_DEVICE_IRQ_C, 7 },
999 	{ SMC37c669_DEVICE_IRQ_D, 6 },
1000 	{ SMC37c669_DEVICE_IRQ_E, 4 },
1001 	{ SMC37c669_DEVICE_IRQ_F, 3 },
1002 	{ SMC37c669_DEVICE_IRQ_H, -1 },
1003 	{ -1, -1 } /* End of table */
1004     };
1005 
1006 /*
1007 ** The following definition is for the MONET (XP1000) IRQ
1008 ** translation table.
1009 */
1010 static SMC37c669_IRQ_TRANSLATION_ENTRY SMC37c669_monet_irq_table[]
1011 __initdata =
1012     {
1013 	{ SMC37c669_DEVICE_IRQ_A, -1 },
1014 	{ SMC37c669_DEVICE_IRQ_B, -1 },
1015 	{ SMC37c669_DEVICE_IRQ_C, 6 },
1016 	{ SMC37c669_DEVICE_IRQ_D, 7 },
1017 	{ SMC37c669_DEVICE_IRQ_E, 4 },
1018 	{ SMC37c669_DEVICE_IRQ_F, 3 },
1019 	{ SMC37c669_DEVICE_IRQ_H, -1 },
1020 	{ -1, -1 } /* End of table */
1021     };
1022 
1023 static SMC37c669_IRQ_TRANSLATION_ENTRY *SMC37c669_irq_tables[] __initdata =
1024     {
1025 	SMC37c669_default_irq_table,
1026 	SMC37c669_monet_irq_table
1027     };
1028 
1029 /*
1030 ** DRQ Translation Table
1031 **
1032 ** The DRQ translation table is a list of SMC37c669 device and
1033 ** ISA DMA channels.
1034 **
1035 */
1036 static SMC37c669_DRQ_TRANSLATION_ENTRY *SMC37c669_drq_table __initdata;
1037 
1038 /*
1039 ** The following definition is the default DRQ
1040 ** translation table.
1041 */
1042 static SMC37c669_DRQ_TRANSLATION_ENTRY SMC37c669_default_drq_table[]
1043 __initdata =
1044     {
1045 	{ SMC37c669_DEVICE_DRQ_A, 2 },
1046 	{ SMC37c669_DEVICE_DRQ_B, 3 },
1047 	{ SMC37c669_DEVICE_DRQ_C, -1 },
1048 	{ -1, -1 } /* End of table */
1049     };
1050 
1051 /*
1052 ** Local Function Prototype Declarations
1053 */
1054 
1055 static unsigned int SMC37c669_is_device_enabled(
1056     unsigned int func
1057 );
1058 
1059 #if 0
1060 static unsigned int SMC37c669_get_device_config(
1061     unsigned int func,
1062     int *port,
1063     int *irq,
1064     int *drq
1065 );
1066 #endif
1067 
1068 static void SMC37c669_config_mode(
1069     unsigned int enable
1070 );
1071 
1072 static unsigned char SMC37c669_read_config(
1073     unsigned char index
1074 );
1075 
1076 static void SMC37c669_write_config(
1077     unsigned char index,
1078     unsigned char data
1079 );
1080 
1081 static void SMC37c669_init_local_config( void );
1082 
1083 static struct DEVICE_CONFIG *SMC37c669_get_config(
1084     unsigned int func
1085 );
1086 
1087 static int SMC37c669_xlate_irq(
1088     int irq
1089 );
1090 
1091 static int SMC37c669_xlate_drq(
1092     int drq
1093 );
1094 
1095 static  __cacheline_aligned DEFINE_SPINLOCK(smc_lock);
1096 
1097 /*
1098 **++
1099 **  FUNCTIONAL DESCRIPTION:
1100 **
1101 **      This function detects the presence of an SMC37c669 Super I/O
1102 **	controller.
1103 **
1104 **  FORMAL PARAMETERS:
1105 **
1106 **	None
1107 **
1108 **  RETURN VALUE:
1109 **
1110 **      Returns a pointer to the device if found, otherwise,
1111 **	the NULL pointer is returned.
1112 **
1113 **  SIDE EFFECTS:
1114 **
1115 **      None
1116 **
1117 **--
1118 */
1119 SMC37c669_CONFIG_REGS * __init SMC37c669_detect( int index )
1120 {
1121     int i;
1122     SMC37c669_DEVICE_ID_REGISTER id;
1123 
1124     for ( i = 0;  SMC37c669_Addresses[i] != 0;  i++ ) {
1125 /*
1126 ** Initialize the device pointer even though we don't yet know if
1127 ** the controller is at this address.  The support functions access
1128 ** the controller through this device pointer so we need to set it
1129 ** even when we are looking ...
1130 */
1131     	SMC37c669 = ( SMC37c669_CONFIG_REGS * )SMC37c669_Addresses[i];
1132 /*
1133 ** Enter configuration mode
1134 */
1135 	SMC37c669_config_mode( TRUE );
1136 /*
1137 ** Read the device id
1138 */
1139 	id.as_uchar = SMC37c669_read_config( SMC37c669_DEVICE_ID_INDEX );
1140 /*
1141 ** Exit configuration mode
1142 */
1143 	SMC37c669_config_mode( FALSE );
1144 /*
1145 ** Does the device id match?  If so, assume we have found an
1146 ** SMC37c669 controller at this address.
1147 */
1148 	if ( id.by_field.device_id == SMC37c669_DEVICE_ID ) {
1149 /*
1150 ** Initialize the IRQ and DRQ translation tables.
1151 */
1152     	    SMC37c669_irq_table = SMC37c669_irq_tables[ index ];
1153 	    SMC37c669_drq_table = SMC37c669_default_drq_table;
1154 /*
1155 ** erfix
1156 **
1157 ** If the platform can't use the IRQ and DRQ defaults set up in this
1158 ** file, it should call a platform-specific external routine at this
1159 ** point to reset the IRQ and DRQ translation table pointers to point
1160 ** at the appropriate tables for the platform.  If the defaults are
1161 ** acceptable, then the external routine should do nothing.
1162 */
1163 
1164 /*
1165 ** Put the chip back into configuration mode
1166 */
1167 	    SMC37c669_config_mode( TRUE );
1168 /*
1169 ** Initialize local storage for configuration information
1170 */
1171 	    SMC37c669_init_local_config( );
1172 /*
1173 ** Exit configuration mode
1174 */
1175 	    SMC37c669_config_mode( FALSE );
1176 /*
1177 ** SMC37c669 controller found, break out of search loop
1178 */
1179 	    break;
1180 	}
1181 	else {
1182 /*
1183 ** Otherwise, we did not find an SMC37c669 controller at this
1184 ** address so set the device pointer to NULL.
1185 */
1186 	    SMC37c669 = NULL;
1187 	}
1188     }
1189     return SMC37c669;
1190 }
1191 
1192 
1193 /*
1194 **++
1195 **  FUNCTIONAL DESCRIPTION:
1196 **
1197 **      This function enables an SMC37c669 device function.
1198 **
1199 **  FORMAL PARAMETERS:
1200 **
1201 **      func:
1202 **          Which device function to enable
1203 **
1204 **  RETURN VALUE:
1205 **
1206 **      Returns TRUE is the device function was enabled, otherwise, FALSE
1207 **
1208 **  SIDE EFFECTS:
1209 **
1210 **      {@description or none@}
1211 **
1212 **  DESIGN:
1213 **
1214 **      Enabling a device function in the SMC37c669 controller involves
1215 **	setting all of its mappings (port, irq, drq ...).  A local
1216 **	"shadow" copy of the device configuration is kept so we can
1217 **	just set each mapping to what the local copy says.
1218 **
1219 **	This function ALWAYS updates the local shadow configuration of
1220 **	the device function being enabled, even if the device is always
1221 **	enabled.  To avoid replication of code, functions such as
1222 **	configure_device set up the local copy and then call this
1223 **	function to the update the real device.
1224 **
1225 **--
1226 */
1227 unsigned int __init SMC37c669_enable_device ( unsigned int func )
1228 {
1229     unsigned int ret_val = FALSE;
1230 /*
1231 ** Put the device into configuration mode
1232 */
1233     SMC37c669_config_mode( TRUE );
1234     switch ( func ) {
1235     	case SERIAL_0:
1236 	    {
1237 	    	SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
1238 		SMC37c669_SERIAL_IRQ_REGISTER irq;
1239 /*
1240 ** Enable the serial 1 IRQ mapping
1241 */
1242 	    	irq.as_uchar =
1243 		    SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
1244 
1245 		irq.by_field.uart1_irq =
1246 		    SMC37c669_RAW_DEVICE_IRQ(
1247 			SMC37c669_xlate_irq( local_config[ func ].irq )
1248 		    );
1249 
1250 		SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
1251 /*
1252 ** Enable the serial 1 port base address mapping
1253 */
1254 		base_addr.as_uchar = 0;
1255 		base_addr.by_field.addr9_3 = local_config[ func ].port1 >> 3;
1256 
1257 		SMC37c669_write_config(
1258 		    SMC37c669_SERIAL0_BASE_ADDRESS_INDEX,
1259 		    base_addr.as_uchar
1260 		);
1261 		ret_val = TRUE;
1262 		break;
1263 	    }
1264 	case SERIAL_1:
1265 	    {
1266 	    	SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
1267 		SMC37c669_SERIAL_IRQ_REGISTER irq;
1268 /*
1269 ** Enable the serial 2 IRQ mapping
1270 */
1271 	    	irq.as_uchar =
1272 		    SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
1273 
1274 		irq.by_field.uart2_irq =
1275 		    SMC37c669_RAW_DEVICE_IRQ(
1276 			SMC37c669_xlate_irq( local_config[ func ].irq )
1277 		    );
1278 
1279 		SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
1280 /*
1281 ** Enable the serial 2 port base address mapping
1282 */
1283 		base_addr.as_uchar = 0;
1284 		base_addr.by_field.addr9_3 = local_config[ func ].port1 >> 3;
1285 
1286 		SMC37c669_write_config(
1287 		    SMC37c669_SERIAL1_BASE_ADDRESS_INDEX,
1288 		    base_addr.as_uchar
1289 		);
1290 		ret_val = TRUE;
1291 		break;
1292 	    }
1293 	case PARALLEL_0:
1294 	    {
1295 	    	SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER base_addr;
1296 		SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
1297 		SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
1298 /*
1299 ** Enable the parallel port DMA channel mapping
1300 */
1301 	    	drq.as_uchar =
1302 		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
1303 
1304 		drq.by_field.ppt_drq =
1305 		    SMC37c669_RAW_DEVICE_DRQ(
1306 			SMC37c669_xlate_drq( local_config[ func ].drq )
1307 		    );
1308 
1309 		SMC37c669_write_config(
1310 		    SMC37c669_PARALLEL_FDC_DRQ_INDEX,
1311 		    drq.as_uchar
1312 		);
1313 /*
1314 ** Enable the parallel port IRQ mapping
1315 */
1316 		irq.as_uchar =
1317 		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
1318 
1319 		irq.by_field.ppt_irq =
1320 		    SMC37c669_RAW_DEVICE_IRQ(
1321 			SMC37c669_xlate_irq( local_config[ func ].irq )
1322 		    );
1323 
1324 		SMC37c669_write_config(
1325 		    SMC37c669_PARALLEL_FDC_IRQ_INDEX,
1326 		    irq.as_uchar
1327 		);
1328 /*
1329 ** Enable the parallel port base address mapping
1330 */
1331 		base_addr.as_uchar = 0;
1332 		base_addr.by_field.addr9_2 = local_config[ func ].port1 >> 2;
1333 
1334 		SMC37c669_write_config(
1335 		    SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX,
1336 		    base_addr.as_uchar
1337 		);
1338 		ret_val = TRUE;
1339 		break;
1340 	    }
1341 	case FLOPPY_0:
1342 	    {
1343 	    	SMC37c669_FDC_BASE_ADDRESS_REGISTER base_addr;
1344 		SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
1345 		SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
1346 /*
1347 ** Enable the floppy controller DMA channel mapping
1348 */
1349 	    	drq.as_uchar =
1350 		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
1351 
1352 		drq.by_field.fdc_drq =
1353 		    SMC37c669_RAW_DEVICE_DRQ(
1354 			SMC37c669_xlate_drq( local_config[ func ].drq )
1355 		    );
1356 
1357 		SMC37c669_write_config(
1358 		    SMC37c669_PARALLEL_FDC_DRQ_INDEX,
1359 		    drq.as_uchar
1360 		);
1361 /*
1362 ** Enable the floppy controller IRQ mapping
1363 */
1364 		irq.as_uchar =
1365 		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
1366 
1367 		irq.by_field.fdc_irq =
1368 		    SMC37c669_RAW_DEVICE_IRQ(
1369 			SMC37c669_xlate_irq( local_config[ func ].irq )
1370 		    );
1371 
1372 		SMC37c669_write_config(
1373 		    SMC37c669_PARALLEL_FDC_IRQ_INDEX,
1374 		    irq.as_uchar
1375 		);
1376 /*
1377 ** Enable the floppy controller base address mapping
1378 */
1379 		base_addr.as_uchar = 0;
1380 		base_addr.by_field.addr9_4 = local_config[ func ].port1 >> 4;
1381 
1382 		SMC37c669_write_config(
1383 		    SMC37c669_FDC_BASE_ADDRESS_INDEX,
1384 		    base_addr.as_uchar
1385 		);
1386 		ret_val = TRUE;
1387 		break;
1388 	    }
1389 	case IDE_0:
1390 	    {
1391 	    	SMC37c669_IDE_ADDRESS_REGISTER ide_addr;
1392 /*
1393 ** Enable the IDE alternate status base address mapping
1394 */
1395 	    	ide_addr.as_uchar = 0;
1396 		ide_addr.by_field.addr9_4 = local_config[ func ].port2 >> 4;
1397 
1398 		SMC37c669_write_config(
1399 		    SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX,
1400 		    ide_addr.as_uchar
1401 		);
1402 /*
1403 ** Enable the IDE controller base address mapping
1404 */
1405 		ide_addr.as_uchar = 0;
1406 		ide_addr.by_field.addr9_4 = local_config[ func ].port1 >> 4;
1407 
1408 		SMC37c669_write_config(
1409 		    SMC37c669_IDE_BASE_ADDRESS_INDEX,
1410 		    ide_addr.as_uchar
1411 		);
1412 		ret_val = TRUE;
1413 		break;
1414 	    }
1415     }
1416 /*
1417 ** Exit configuration mode and return
1418 */
1419     SMC37c669_config_mode( FALSE );
1420 
1421     return ret_val;
1422 }
1423 
1424 
1425 /*
1426 **++
1427 **  FUNCTIONAL DESCRIPTION:
1428 **
1429 **      This function disables a device function within the
1430 **	SMC37c669 Super I/O controller.
1431 **
1432 **  FORMAL PARAMETERS:
1433 **
1434 **      func:
1435 **          Which function to disable
1436 **
1437 **  RETURN VALUE:
1438 **
1439 **      Return TRUE if the device function was disabled, otherwise, FALSE
1440 **
1441 **  SIDE EFFECTS:
1442 **
1443 **      {@description or none@}
1444 **
1445 **  DESIGN:
1446 **
1447 **      Disabling a function in the SMC37c669 device involves
1448 **	disabling all the function's mappings (port, irq, drq ...).
1449 **	A shadow copy of the device configuration is maintained
1450 **	in local storage so we won't worry aboving saving the
1451 **	current configuration information.
1452 **
1453 **--
1454 */
1455 unsigned int __init SMC37c669_disable_device ( unsigned int func )
1456 {
1457     unsigned int ret_val = FALSE;
1458 
1459 /*
1460 ** Put the device into configuration mode
1461 */
1462     SMC37c669_config_mode( TRUE );
1463     switch ( func ) {
1464     	case SERIAL_0:
1465 	    {
1466 	    	SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
1467 		SMC37c669_SERIAL_IRQ_REGISTER irq;
1468 /*
1469 ** Disable the serial 1 IRQ mapping
1470 */
1471 	    	irq.as_uchar =
1472 		    SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
1473 
1474 		irq.by_field.uart1_irq = 0;
1475 
1476 		SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
1477 /*
1478 ** Disable the serial 1 port base address mapping
1479 */
1480 		base_addr.as_uchar = 0;
1481 		SMC37c669_write_config(
1482 		    SMC37c669_SERIAL0_BASE_ADDRESS_INDEX,
1483 		    base_addr.as_uchar
1484 		);
1485 		ret_val = TRUE;
1486 		break;
1487 	    }
1488 	case SERIAL_1:
1489 	    {
1490 	    	SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
1491 		SMC37c669_SERIAL_IRQ_REGISTER irq;
1492 /*
1493 ** Disable the serial 2 IRQ mapping
1494 */
1495 	    	irq.as_uchar =
1496 		    SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
1497 
1498 		irq.by_field.uart2_irq = 0;
1499 
1500 		SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
1501 /*
1502 ** Disable the serial 2 port base address mapping
1503 */
1504 		base_addr.as_uchar = 0;
1505 
1506 		SMC37c669_write_config(
1507 		    SMC37c669_SERIAL1_BASE_ADDRESS_INDEX,
1508 		    base_addr.as_uchar
1509 		);
1510 		ret_val = TRUE;
1511 		break;
1512 	    }
1513 	case PARALLEL_0:
1514 	    {
1515 	    	SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER base_addr;
1516 		SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
1517 		SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
1518 /*
1519 ** Disable the parallel port DMA channel mapping
1520 */
1521 	    	drq.as_uchar =
1522 		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
1523 
1524 		drq.by_field.ppt_drq = 0;
1525 
1526 		SMC37c669_write_config(
1527 		    SMC37c669_PARALLEL_FDC_DRQ_INDEX,
1528 		    drq.as_uchar
1529 		);
1530 /*
1531 ** Disable the parallel port IRQ mapping
1532 */
1533 		irq.as_uchar =
1534 		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
1535 
1536 		irq.by_field.ppt_irq = 0;
1537 
1538 		SMC37c669_write_config(
1539 		    SMC37c669_PARALLEL_FDC_IRQ_INDEX,
1540 		    irq.as_uchar
1541 		);
1542 /*
1543 ** Disable the parallel port base address mapping
1544 */
1545 		base_addr.as_uchar = 0;
1546 
1547 		SMC37c669_write_config(
1548 		    SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX,
1549 		    base_addr.as_uchar
1550 		);
1551 		ret_val = TRUE;
1552 		break;
1553 	    }
1554 	case FLOPPY_0:
1555 	    {
1556 	    	SMC37c669_FDC_BASE_ADDRESS_REGISTER base_addr;
1557 		SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
1558 		SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
1559 /*
1560 ** Disable the floppy controller DMA channel mapping
1561 */
1562 	    	drq.as_uchar =
1563 		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
1564 
1565 		drq.by_field.fdc_drq = 0;
1566 
1567 		SMC37c669_write_config(
1568 		    SMC37c669_PARALLEL_FDC_DRQ_INDEX,
1569 		    drq.as_uchar
1570 		);
1571 /*
1572 ** Disable the floppy controller IRQ mapping
1573 */
1574 		irq.as_uchar =
1575 		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
1576 
1577 		irq.by_field.fdc_irq = 0;
1578 
1579 		SMC37c669_write_config(
1580 		    SMC37c669_PARALLEL_FDC_IRQ_INDEX,
1581 		    irq.as_uchar
1582 		);
1583 /*
1584 ** Disable the floppy controller base address mapping
1585 */
1586 		base_addr.as_uchar = 0;
1587 
1588 		SMC37c669_write_config(
1589 		    SMC37c669_FDC_BASE_ADDRESS_INDEX,
1590 		    base_addr.as_uchar
1591 		);
1592 		ret_val = TRUE;
1593 		break;
1594 	    }
1595 	case IDE_0:
1596 	    {
1597 	    	SMC37c669_IDE_ADDRESS_REGISTER ide_addr;
1598 /*
1599 ** Disable the IDE alternate status base address mapping
1600 */
1601 	    	ide_addr.as_uchar = 0;
1602 
1603 		SMC37c669_write_config(
1604 		    SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX,
1605 		    ide_addr.as_uchar
1606 		);
1607 /*
1608 ** Disable the IDE controller base address mapping
1609 */
1610 		ide_addr.as_uchar = 0;
1611 
1612 		SMC37c669_write_config(
1613 		    SMC37c669_IDE_BASE_ADDRESS_INDEX,
1614 		    ide_addr.as_uchar
1615 		);
1616 		ret_val = TRUE;
1617 		break;
1618 	    }
1619     }
1620 /*
1621 ** Exit configuration mode and return
1622 */
1623     SMC37c669_config_mode( FALSE );
1624 
1625     return ret_val;
1626 }
1627 
1628 
1629 /*
1630 **++
1631 **  FUNCTIONAL DESCRIPTION:
1632 **
1633 **      This function configures a device function within the
1634 **	SMC37c669 Super I/O controller.
1635 **
1636 **  FORMAL PARAMETERS:
1637 **
1638 **      func:
1639 **          Which device function
1640 **
1641 **      port:
1642 **          I/O port for the function to use
1643 **
1644 **      irq:
1645 **          IRQ for the device function to use
1646 **
1647 **      drq:
1648 **          DMA channel for the device function to use
1649 **
1650 **  RETURN VALUE:
1651 **
1652 **      Returns TRUE if the device function was configured,
1653 **	otherwise, FALSE.
1654 **
1655 **  SIDE EFFECTS:
1656 **
1657 **      {@description or none@}
1658 **
1659 **  DESIGN:
1660 **
1661 **	If this function returns TRUE, the local shadow copy of
1662 **	the configuration is also updated.  If the device function
1663 **	is currently disabled, only the local shadow copy is
1664 **	updated and the actual device function will be updated
1665 **	if/when it is enabled.
1666 **
1667 **--
1668 */
1669 unsigned int __init SMC37c669_configure_device (
1670     unsigned int func,
1671     int port,
1672     int irq,
1673     int drq )
1674 {
1675     struct DEVICE_CONFIG *cp;
1676 
1677 /*
1678 ** Check for a valid configuration
1679 */
1680     if ( ( cp = SMC37c669_get_config ( func ) ) != NULL ) {
1681 /*
1682 ** Configuration is valid, update the local shadow copy
1683 */
1684     	if ( ( drq & ~0xFF ) == 0 ) {
1685 	    cp->drq = drq;
1686 	}
1687 	if ( ( irq & ~0xFF ) == 0 ) {
1688 	    cp->irq = irq;
1689 	}
1690 	if ( ( port & ~0xFFFF ) == 0 ) {
1691 	    cp->port1 = port;
1692 	}
1693 /*
1694 ** If the device function is enabled, update the actual
1695 ** device configuration.
1696 */
1697 	if ( SMC37c669_is_device_enabled( func ) ) {
1698 	    SMC37c669_enable_device( func );
1699 	}
1700 	return TRUE;
1701     }
1702     return FALSE;
1703 }
1704 
1705 
1706 /*
1707 **++
1708 **  FUNCTIONAL DESCRIPTION:
1709 **
1710 **      This function determines whether a device function
1711 **	within the SMC37c669 controller is enabled.
1712 **
1713 **  FORMAL PARAMETERS:
1714 **
1715 **      func:
1716 **          Which device function
1717 **
1718 **  RETURN VALUE:
1719 **
1720 **      Returns TRUE if the device function is enabled, otherwise, FALSE
1721 **
1722 **  SIDE EFFECTS:
1723 **
1724 **      {@description or none@}
1725 **
1726 **  DESIGN:
1727 **
1728 **      To check whether a device is enabled we will only look at
1729 **	the port base address mapping.  According to the SMC37c669
1730 **	specification, all of the port base address mappings are
1731 **	disabled if the addr<9:8> (bits <7:6> of the register) are
1732 **	zero.
1733 **
1734 **--
1735 */
1736 static unsigned int __init SMC37c669_is_device_enabled ( unsigned int func )
1737 {
1738     unsigned char base_addr = 0;
1739     unsigned int dev_ok = FALSE;
1740     unsigned int ret_val = FALSE;
1741 /*
1742 ** Enter configuration mode
1743 */
1744     SMC37c669_config_mode( TRUE );
1745 
1746     switch ( func ) {
1747     	case SERIAL_0:
1748 	    base_addr =
1749 		SMC37c669_read_config( SMC37c669_SERIAL0_BASE_ADDRESS_INDEX );
1750 	    dev_ok = TRUE;
1751 	    break;
1752 	case SERIAL_1:
1753 	    base_addr =
1754 		SMC37c669_read_config( SMC37c669_SERIAL1_BASE_ADDRESS_INDEX );
1755 	    dev_ok = TRUE;
1756 	    break;
1757 	case PARALLEL_0:
1758 	    base_addr =
1759 		SMC37c669_read_config( SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX );
1760 	    dev_ok = TRUE;
1761 	    break;
1762 	case FLOPPY_0:
1763 	    base_addr =
1764 		SMC37c669_read_config( SMC37c669_FDC_BASE_ADDRESS_INDEX );
1765 	    dev_ok = TRUE;
1766 	    break;
1767 	case IDE_0:
1768 	    base_addr =
1769 		SMC37c669_read_config( SMC37c669_IDE_BASE_ADDRESS_INDEX );
1770 	    dev_ok = TRUE;
1771 	    break;
1772     }
1773 /*
1774 ** If we have a valid device, check base_addr<7:6> to see if the
1775 ** device is enabled (mapped).
1776 */
1777     if ( ( dev_ok ) && ( ( base_addr & 0xC0 ) != 0 ) ) {
1778 /*
1779 ** The mapping is not disabled, so assume that the function is
1780 ** enabled.
1781 */
1782     	ret_val = TRUE;
1783     }
1784 /*
1785 ** Exit configuration mode
1786 */
1787     SMC37c669_config_mode( FALSE );
1788 
1789     return ret_val;
1790 }
1791 
1792 
1793 #if 0
1794 /*
1795 **++
1796 **  FUNCTIONAL DESCRIPTION:
1797 **
1798 **      This function retrieves the configuration information of a
1799 **	device function within the SMC37c699 Super I/O controller.
1800 **
1801 **  FORMAL PARAMETERS:
1802 **
1803 **      func:
1804 **          Which device function
1805 **
1806 **      port:
1807 **          I/O port returned
1808 **
1809 **      irq:
1810 **          IRQ returned
1811 **
1812 **      drq:
1813 **          DMA channel returned
1814 **
1815 **  RETURN VALUE:
1816 **
1817 **      Returns TRUE if the device configuration was successfully
1818 **	retrieved, otherwise, FALSE.
1819 **
1820 **  SIDE EFFECTS:
1821 **
1822 **      The data pointed to by the port, irq, and drq parameters
1823 **	my be modified even if the configuration is not successfully
1824 **	retrieved.
1825 **
1826 **  DESIGN:
1827 **
1828 **      The device configuration is fetched from the local shadow
1829 **	copy.  Any unused parameters will be set to -1.  Any
1830 **	parameter which is not desired can specify the NULL
1831 **	pointer.
1832 **
1833 **--
1834 */
1835 static unsigned int __init SMC37c669_get_device_config (
1836     unsigned int func,
1837     int *port,
1838     int *irq,
1839     int *drq )
1840 {
1841     struct DEVICE_CONFIG *cp;
1842     unsigned int ret_val = FALSE;
1843 /*
1844 ** Check for a valid device configuration
1845 */
1846     if ( ( cp = SMC37c669_get_config( func ) ) != NULL ) {
1847     	if ( drq != NULL ) {
1848 	    *drq = cp->drq;
1849 	    ret_val = TRUE;
1850 	}
1851 	if ( irq != NULL ) {
1852 	    *irq = cp->irq;
1853 	    ret_val = TRUE;
1854 	}
1855 	if ( port != NULL ) {
1856 	    *port = cp->port1;
1857 	    ret_val = TRUE;
1858 	}
1859     }
1860     return ret_val;
1861 }
1862 #endif
1863 
1864 
1865 /*
1866 **++
1867 **  FUNCTIONAL DESCRIPTION:
1868 **
1869 **      This function displays the current state of the SMC37c699
1870 **	Super I/O controller's device functions.
1871 **
1872 **  FORMAL PARAMETERS:
1873 **
1874 **      None
1875 **
1876 **  RETURN VALUE:
1877 **
1878 **      None
1879 **
1880 **  SIDE EFFECTS:
1881 **
1882 **      None
1883 **
1884 **--
1885 */
1886 void __init SMC37c669_display_device_info ( void )
1887 {
1888     if ( SMC37c669_is_device_enabled( SERIAL_0 ) ) {
1889     	printk( "  Serial 0:    Enabled [ Port 0x%x, IRQ %d ]\n",
1890 		 local_config[ SERIAL_0 ].port1,
1891 		 local_config[ SERIAL_0 ].irq
1892 	);
1893     }
1894     else {
1895     	printk( "  Serial 0:    Disabled\n" );
1896     }
1897 
1898     if ( SMC37c669_is_device_enabled( SERIAL_1 ) ) {
1899     	printk( "  Serial 1:    Enabled [ Port 0x%x, IRQ %d ]\n",
1900 		 local_config[ SERIAL_1 ].port1,
1901 		 local_config[ SERIAL_1 ].irq
1902 	);
1903     }
1904     else {
1905     	printk( "  Serial 1:    Disabled\n" );
1906     }
1907 
1908     if ( SMC37c669_is_device_enabled( PARALLEL_0 ) ) {
1909     	printk( "  Parallel:    Enabled [ Port 0x%x, IRQ %d/%d ]\n",
1910 		 local_config[ PARALLEL_0 ].port1,
1911 		 local_config[ PARALLEL_0 ].irq,
1912 		 local_config[ PARALLEL_0 ].drq
1913 	);
1914     }
1915     else {
1916     	printk( "  Parallel:    Disabled\n" );
1917     }
1918 
1919     if ( SMC37c669_is_device_enabled( FLOPPY_0 ) ) {
1920     	printk( "  Floppy Ctrl: Enabled [ Port 0x%x, IRQ %d/%d ]\n",
1921 		 local_config[ FLOPPY_0 ].port1,
1922 		 local_config[ FLOPPY_0 ].irq,
1923 		 local_config[ FLOPPY_0 ].drq
1924 	);
1925     }
1926     else {
1927     	printk( "  Floppy Ctrl: Disabled\n" );
1928     }
1929 
1930     if ( SMC37c669_is_device_enabled( IDE_0 ) ) {
1931     	printk( "  IDE 0:       Enabled [ Port 0x%x, IRQ %d ]\n",
1932 		 local_config[ IDE_0 ].port1,
1933 		 local_config[ IDE_0 ].irq
1934 	);
1935     }
1936     else {
1937     	printk( "  IDE 0:       Disabled\n" );
1938     }
1939 }
1940 
1941 
1942 /*
1943 **++
1944 **  FUNCTIONAL DESCRIPTION:
1945 **
1946 **      This function puts the SMC37c669 Super I/O controller into,
1947 **	and takes it out of, configuration mode.
1948 **
1949 **  FORMAL PARAMETERS:
1950 **
1951 **      enable:
1952 **          TRUE to enter configuration mode, FALSE to exit.
1953 **
1954 **  RETURN VALUE:
1955 **
1956 **      None
1957 **
1958 **  SIDE EFFECTS:
1959 **
1960 **      The SMC37c669 controller may be left in configuration mode.
1961 **
1962 **--
1963 */
1964 static void __init SMC37c669_config_mode(
1965     unsigned int enable )
1966 {
1967     if ( enable ) {
1968 /*
1969 ** To enter configuration mode, two writes in succession to the index
1970 ** port are required.  If a write to another address or port occurs
1971 ** between these two writes, the chip does not enter configuration
1972 ** mode.  Therefore, a spinlock is placed around the two writes to
1973 ** guarantee that they complete uninterrupted.
1974 */
1975 	spin_lock(&smc_lock);
1976     	wb( &SMC37c669->index_port, SMC37c669_CONFIG_ON_KEY );
1977     	wb( &SMC37c669->index_port, SMC37c669_CONFIG_ON_KEY );
1978 	spin_unlock(&smc_lock);
1979     }
1980     else {
1981     	wb( &SMC37c669->index_port, SMC37c669_CONFIG_OFF_KEY );
1982     }
1983 }
1984 
1985 /*
1986 **++
1987 **  FUNCTIONAL DESCRIPTION:
1988 **
1989 **      This function reads an SMC37c669 Super I/O controller
1990 **	configuration register.  This function assumes that the
1991 **	device is already in configuration mode.
1992 **
1993 **  FORMAL PARAMETERS:
1994 **
1995 **      index:
1996 **          Index value of configuration register to read
1997 **
1998 **  RETURN VALUE:
1999 **
2000 **      Data read from configuration register
2001 **
2002 **  SIDE EFFECTS:
2003 **
2004 **      None
2005 **
2006 **--
2007 */
2008 static unsigned char __init SMC37c669_read_config(
2009     unsigned char index )
2010 {
2011 	wb(&SMC37c669->index_port, index);
2012 	return rb(&SMC37c669->data_port);
2013 }
2014 
2015 /*
2016 **++
2017 **  FUNCTIONAL DESCRIPTION:
2018 **
2019 **      This function writes an SMC37c669 Super I/O controller
2020 **	configuration register.  This function assumes that the
2021 **	device is already in configuration mode.
2022 **
2023 **  FORMAL PARAMETERS:
2024 **
2025 **      index:
2026 **          Index of configuration register to write
2027 **
2028 **      data:
2029 **          Data to be written
2030 **
2031 **  RETURN VALUE:
2032 **
2033 **      None
2034 **
2035 **  SIDE EFFECTS:
2036 **
2037 **      None
2038 **
2039 **--
2040 */
2041 static void __init SMC37c669_write_config(
2042     unsigned char index,
2043     unsigned char data )
2044 {
2045     wb( &SMC37c669->index_port, index );
2046     wb( &SMC37c669->data_port, data );
2047 }
2048 
2049 
2050 /*
2051 **++
2052 **  FUNCTIONAL DESCRIPTION:
2053 **
2054 **      This function initializes the local device
2055 **	configuration storage.  This function assumes
2056 **	that the device is already in configuration
2057 **	mode.
2058 **
2059 **  FORMAL PARAMETERS:
2060 **
2061 **      None
2062 **
2063 **  RETURN VALUE:
2064 **
2065 **      None
2066 **
2067 **  SIDE EFFECTS:
2068 **
2069 **      Local storage for device configuration information
2070 **	is initialized.
2071 **
2072 **--
2073 */
2074 static void __init SMC37c669_init_local_config ( void )
2075 {
2076     SMC37c669_SERIAL_BASE_ADDRESS_REGISTER uart_base;
2077     SMC37c669_SERIAL_IRQ_REGISTER uart_irqs;
2078     SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER ppt_base;
2079     SMC37c669_PARALLEL_FDC_IRQ_REGISTER ppt_fdc_irqs;
2080     SMC37c669_PARALLEL_FDC_DRQ_REGISTER ppt_fdc_drqs;
2081     SMC37c669_FDC_BASE_ADDRESS_REGISTER fdc_base;
2082     SMC37c669_IDE_ADDRESS_REGISTER ide_base;
2083     SMC37c669_IDE_ADDRESS_REGISTER ide_alt;
2084 
2085 /*
2086 ** Get serial port 1 base address
2087 */
2088     uart_base.as_uchar =
2089 	SMC37c669_read_config( SMC37c669_SERIAL0_BASE_ADDRESS_INDEX );
2090 /*
2091 ** Get IRQs for serial ports 1 & 2
2092 */
2093     uart_irqs.as_uchar =
2094 	SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
2095 /*
2096 ** Store local configuration information for serial port 1
2097 */
2098     local_config[SERIAL_0].port1 = uart_base.by_field.addr9_3 << 3;
2099     local_config[SERIAL_0].irq =
2100 	SMC37c669_xlate_irq(
2101 	    SMC37c669_DEVICE_IRQ( uart_irqs.by_field.uart1_irq )
2102 	);
2103 /*
2104 ** Get serial port 2 base address
2105 */
2106     uart_base.as_uchar =
2107 	SMC37c669_read_config( SMC37c669_SERIAL1_BASE_ADDRESS_INDEX );
2108 /*
2109 ** Store local configuration information for serial port 2
2110 */
2111     local_config[SERIAL_1].port1 = uart_base.by_field.addr9_3 << 3;
2112     local_config[SERIAL_1].irq =
2113 	SMC37c669_xlate_irq(
2114 	    SMC37c669_DEVICE_IRQ( uart_irqs.by_field.uart2_irq )
2115 	);
2116 /*
2117 ** Get parallel port base address
2118 */
2119     ppt_base.as_uchar =
2120 	SMC37c669_read_config( SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX );
2121 /*
2122 ** Get IRQs for parallel port and floppy controller
2123 */
2124     ppt_fdc_irqs.as_uchar =
2125 	SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
2126 /*
2127 ** Get DRQs for parallel port and floppy controller
2128 */
2129     ppt_fdc_drqs.as_uchar =
2130 	SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
2131 /*
2132 ** Store local configuration information for parallel port
2133 */
2134     local_config[PARALLEL_0].port1 = ppt_base.by_field.addr9_2 << 2;
2135     local_config[PARALLEL_0].irq =
2136 	SMC37c669_xlate_irq(
2137 	    SMC37c669_DEVICE_IRQ( ppt_fdc_irqs.by_field.ppt_irq )
2138 	);
2139     local_config[PARALLEL_0].drq =
2140 	SMC37c669_xlate_drq(
2141 	    SMC37c669_DEVICE_DRQ( ppt_fdc_drqs.by_field.ppt_drq )
2142 	);
2143 /*
2144 ** Get floppy controller base address
2145 */
2146     fdc_base.as_uchar =
2147 	SMC37c669_read_config( SMC37c669_FDC_BASE_ADDRESS_INDEX );
2148 /*
2149 ** Store local configuration information for floppy controller
2150 */
2151     local_config[FLOPPY_0].port1 = fdc_base.by_field.addr9_4 << 4;
2152     local_config[FLOPPY_0].irq =
2153 	SMC37c669_xlate_irq(
2154 	    SMC37c669_DEVICE_IRQ( ppt_fdc_irqs.by_field.fdc_irq )
2155 	);
2156     local_config[FLOPPY_0].drq =
2157 	SMC37c669_xlate_drq(
2158 	    SMC37c669_DEVICE_DRQ( ppt_fdc_drqs.by_field.fdc_drq )
2159 	);
2160 /*
2161 ** Get IDE controller base address
2162 */
2163     ide_base.as_uchar =
2164 	SMC37c669_read_config( SMC37c669_IDE_BASE_ADDRESS_INDEX );
2165 /*
2166 ** Get IDE alternate status base address
2167 */
2168     ide_alt.as_uchar =
2169 	SMC37c669_read_config( SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX );
2170 /*
2171 ** Store local configuration information for IDE controller
2172 */
2173     local_config[IDE_0].port1 = ide_base.by_field.addr9_4 << 4;
2174     local_config[IDE_0].port2 = ide_alt.by_field.addr9_4 << 4;
2175     local_config[IDE_0].irq = 14;
2176 }
2177 
2178 
2179 /*
2180 **++
2181 **  FUNCTIONAL DESCRIPTION:
2182 **
2183 **      This function returns a pointer to the local shadow
2184 **	configuration of the requested device function.
2185 **
2186 **  FORMAL PARAMETERS:
2187 **
2188 **      func:
2189 **          Which device function
2190 **
2191 **  RETURN VALUE:
2192 **
2193 **      Returns a pointer to the DEVICE_CONFIG structure for the
2194 **	requested function, otherwise, NULL.
2195 **
2196 **  SIDE EFFECTS:
2197 **
2198 **      {@description or none@}
2199 **
2200 **--
2201 */
2202 static struct DEVICE_CONFIG * __init SMC37c669_get_config( unsigned int func )
2203 {
2204     struct DEVICE_CONFIG *cp = NULL;
2205 
2206     switch ( func ) {
2207     	case SERIAL_0:
2208 	    cp = &local_config[ SERIAL_0 ];
2209 	    break;
2210 	case SERIAL_1:
2211 	    cp = &local_config[ SERIAL_1 ];
2212 	    break;
2213 	case PARALLEL_0:
2214 	    cp = &local_config[ PARALLEL_0 ];
2215 	    break;
2216 	case FLOPPY_0:
2217 	    cp = &local_config[ FLOPPY_0 ];
2218 	    break;
2219 	case IDE_0:
2220 	    cp = &local_config[ IDE_0 ];
2221 	    break;
2222     }
2223     return cp;
2224 }
2225 
2226 /*
2227 **++
2228 **  FUNCTIONAL DESCRIPTION:
2229 **
2230 **      This function translates IRQs back and forth between ISA
2231 **	IRQs and SMC37c669 device IRQs.
2232 **
2233 **  FORMAL PARAMETERS:
2234 **
2235 **      irq:
2236 **          The IRQ to translate
2237 **
2238 **  RETURN VALUE:
2239 **
2240 **      Returns the translated IRQ, otherwise, returns -1.
2241 **
2242 **  SIDE EFFECTS:
2243 **
2244 **      {@description or none@}
2245 **
2246 **--
2247 */
2248 static int __init SMC37c669_xlate_irq ( int irq )
2249 {
2250     int i, translated_irq = -1;
2251 
2252     if ( SMC37c669_IS_DEVICE_IRQ( irq ) ) {
2253 /*
2254 ** We are translating a device IRQ to an ISA IRQ
2255 */
2256     	for ( i = 0; ( SMC37c669_irq_table[i].device_irq != -1 ) || ( SMC37c669_irq_table[i].isa_irq != -1 ); i++ ) {
2257 	    if ( irq == SMC37c669_irq_table[i].device_irq ) {
2258 	    	translated_irq = SMC37c669_irq_table[i].isa_irq;
2259 		break;
2260 	    }
2261 	}
2262     }
2263     else {
2264 /*
2265 ** We are translating an ISA IRQ to a device IRQ
2266 */
2267     	for ( i = 0; ( SMC37c669_irq_table[i].isa_irq != -1 ) || ( SMC37c669_irq_table[i].device_irq != -1 ); i++ ) {
2268 	    if ( irq == SMC37c669_irq_table[i].isa_irq ) {
2269 	    	translated_irq = SMC37c669_irq_table[i].device_irq;
2270 		break;
2271 	    }
2272 	}
2273     }
2274     return translated_irq;
2275 }
2276 
2277 
2278 /*
2279 **++
2280 **  FUNCTIONAL DESCRIPTION:
2281 **
2282 **      This function translates DMA channels back and forth between
2283 **	ISA DMA channels and SMC37c669 device DMA channels.
2284 **
2285 **  FORMAL PARAMETERS:
2286 **
2287 **      drq:
2288 **          The DMA channel to translate
2289 **
2290 **  RETURN VALUE:
2291 **
2292 **      Returns the translated DMA channel, otherwise, returns -1
2293 **
2294 **  SIDE EFFECTS:
2295 **
2296 **      {@description or none@}
2297 **
2298 **--
2299 */
2300 static int __init SMC37c669_xlate_drq ( int drq )
2301 {
2302     int i, translated_drq = -1;
2303 
2304     if ( SMC37c669_IS_DEVICE_DRQ( drq ) ) {
2305 /*
2306 ** We are translating a device DMA channel to an ISA DMA channel
2307 */
2308     	for ( i = 0; ( SMC37c669_drq_table[i].device_drq != -1 ) || ( SMC37c669_drq_table[i].isa_drq != -1 ); i++ ) {
2309 	    if ( drq == SMC37c669_drq_table[i].device_drq ) {
2310 	    	translated_drq = SMC37c669_drq_table[i].isa_drq;
2311 		break;
2312 	    }
2313 	}
2314     }
2315     else {
2316 /*
2317 ** We are translating an ISA DMA channel to a device DMA channel
2318 */
2319     	for ( i = 0; ( SMC37c669_drq_table[i].isa_drq != -1 ) || ( SMC37c669_drq_table[i].device_drq != -1 ); i++ ) {
2320 	    if ( drq == SMC37c669_drq_table[i].isa_drq ) {
2321 	    	translated_drq = SMC37c669_drq_table[i].device_drq;
2322 		break;
2323 	    }
2324 	}
2325     }
2326     return translated_drq;
2327 }
2328 
2329 #if 0
2330 int __init smcc669_init ( void )
2331 {
2332     struct INODE *ip;
2333 
2334     allocinode( smc_ddb.name, 1, &ip );
2335     ip->dva = &smc_ddb;
2336     ip->attr = ATTR$M_WRITE | ATTR$M_READ;
2337     ip->len[0] = 0x30;
2338     ip->misc = 0;
2339     INODE_UNLOCK( ip );
2340 
2341     return msg_success;
2342 }
2343 
2344 int __init smcc669_open( struct FILE *fp, char *info, char *next, char *mode )
2345 {
2346     struct INODE *ip;
2347 /*
2348 ** Allow multiple readers but only one writer.  ip->misc keeps track
2349 ** of the number of writers
2350 */
2351     ip = fp->ip;
2352     INODE_LOCK( ip );
2353     if ( fp->mode & ATTR$M_WRITE ) {
2354 	if ( ip->misc ) {
2355 	    INODE_UNLOCK( ip );
2356 	    return msg_failure;	    /* too many writers */
2357 	}
2358 	ip->misc++;
2359     }
2360 /*
2361 ** Treat the information field as a byte offset
2362 */
2363     *fp->offset = xtoi( info );
2364     INODE_UNLOCK( ip );
2365 
2366     return msg_success;
2367 }
2368 
2369 int __init smcc669_close( struct FILE *fp )
2370 {
2371     struct INODE *ip;
2372 
2373     ip = fp->ip;
2374     if ( fp->mode & ATTR$M_WRITE ) {
2375 	INODE_LOCK( ip );
2376 	ip->misc--;
2377 	INODE_UNLOCK( ip );
2378     }
2379     return msg_success;
2380 }
2381 
2382 int __init smcc669_read( struct FILE *fp, int size, int number, unsigned char *buf )
2383 {
2384     int i;
2385     int length;
2386     int nbytes;
2387     struct INODE *ip;
2388 
2389 /*
2390 ** Always access a byte at a time
2391 */
2392     ip = fp->ip;
2393     length = size * number;
2394     nbytes = 0;
2395 
2396     SMC37c669_config_mode( TRUE );
2397     for ( i = 0; i < length; i++ ) {
2398 	if ( !inrange( *fp->offset, 0, ip->len[0] ) )
2399 	    break;
2400 	*buf++ = SMC37c669_read_config( *fp->offset );
2401 	*fp->offset += 1;
2402 	nbytes++;
2403     }
2404     SMC37c669_config_mode( FALSE );
2405     return nbytes;
2406 }
2407 
2408 int __init smcc669_write( struct FILE *fp, int size, int number, unsigned char *buf )
2409 {
2410     int i;
2411     int length;
2412     int nbytes;
2413     struct INODE *ip;
2414 /*
2415 ** Always access a byte at a time
2416 */
2417     ip = fp->ip;
2418     length = size * number;
2419     nbytes = 0;
2420 
2421     SMC37c669_config_mode( TRUE );
2422     for ( i = 0; i < length; i++ ) {
2423 	if ( !inrange( *fp->offset, 0, ip->len[0] ) )
2424 	    break;
2425 	SMC37c669_write_config( *fp->offset, *buf );
2426 	*fp->offset += 1;
2427 	buf++;
2428 	nbytes++;
2429     }
2430     SMC37c669_config_mode( FALSE );
2431     return nbytes;
2432 }
2433 #endif
2434 
2435 #if SMC_DEBUG
2436 static void __init
2437 SMC37c669_dump_registers(void)
2438 {
2439   int i;
2440   for (i = 0; i <= 0x29; i++)
2441     printk("-- CR%02x : %02x\n", i, SMC37c669_read_config(i));
2442 }
2443 #endif
2444 /*+
2445  * ============================================================================
2446  * = SMC_init - SMC37c669 Super I/O controller initialization                 =
2447  * ============================================================================
2448  *
2449  * OVERVIEW:
2450  *
2451  *      This routine configures and enables device functions on the
2452  *      SMC37c669 Super I/O controller.
2453  *
2454  * FORM OF CALL:
2455  *
2456  *      SMC_init( );
2457  *
2458  * RETURNS:
2459  *
2460  *      Nothing
2461  *
2462  * ARGUMENTS:
2463  *
2464  *      None
2465  *
2466  * SIDE EFFECTS:
2467  *
2468  *      None
2469  *
2470  */
2471 void __init SMC669_Init ( int index )
2472 {
2473     SMC37c669_CONFIG_REGS *SMC_base;
2474     unsigned long flags;
2475 
2476     local_irq_save(flags);
2477     if ( ( SMC_base = SMC37c669_detect( index ) ) != NULL ) {
2478 #if SMC_DEBUG
2479 	SMC37c669_config_mode( TRUE );
2480 	SMC37c669_dump_registers( );
2481 	SMC37c669_config_mode( FALSE );
2482         SMC37c669_display_device_info( );
2483 #endif
2484         SMC37c669_disable_device( SERIAL_0 );
2485         SMC37c669_configure_device(
2486             SERIAL_0,
2487             COM1_BASE,
2488             COM1_IRQ,
2489             -1
2490         );
2491         SMC37c669_enable_device( SERIAL_0 );
2492 
2493         SMC37c669_disable_device( SERIAL_1 );
2494         SMC37c669_configure_device(
2495             SERIAL_1,
2496             COM2_BASE,
2497             COM2_IRQ,
2498             -1
2499         );
2500         SMC37c669_enable_device( SERIAL_1 );
2501 
2502         SMC37c669_disable_device( PARALLEL_0 );
2503         SMC37c669_configure_device(
2504             PARALLEL_0,
2505             PARP_BASE,
2506             PARP_IRQ,
2507             PARP_DRQ
2508         );
2509         SMC37c669_enable_device( PARALLEL_0 );
2510 
2511         SMC37c669_disable_device( FLOPPY_0 );
2512         SMC37c669_configure_device(
2513             FLOPPY_0,
2514             FDC_BASE,
2515             FDC_IRQ,
2516             FDC_DRQ
2517         );
2518         SMC37c669_enable_device( FLOPPY_0 );
2519 
2520 	/* Wake up sometimes forgotten floppy, especially on DP264. */
2521 	outb(0xc, 0x3f2);
2522 
2523         SMC37c669_disable_device( IDE_0 );
2524 
2525 #if SMC_DEBUG
2526 	SMC37c669_config_mode( TRUE );
2527 	SMC37c669_dump_registers( );
2528 	SMC37c669_config_mode( FALSE );
2529         SMC37c669_display_device_info( );
2530 #endif
2531 	local_irq_restore(flags);
2532         printk( "SMC37c669 Super I/O Controller found @ 0x%p\n",
2533 		SMC_base );
2534     }
2535     else {
2536 	local_irq_restore(flags);
2537 #if SMC_DEBUG
2538         printk( "No SMC37c669 Super I/O Controller found\n" );
2539 #endif
2540     }
2541 }
2542