File: /usr/src/linux/arch/alpha/kernel/smc37c669.c

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