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#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*/
211typedef 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*/
234typedef 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*/
248typedef 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*/
263typedef 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*/
289typedef 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*/
345typedef 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*/
367typedef 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*/
382typedef 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*/
403typedef 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*/
418typedef 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*/
436typedef 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*/
448typedef 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*/
459typedef 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*/
480typedef 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*/
497typedef 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*/
509typedef 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*/
519typedef 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*/
536typedef 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*/
551typedef 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*/
574typedef 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*/
598typedef 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*/
616typedef 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*/
632typedef 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*/
648typedef 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*/
666typedef 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*/
681typedef 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*/
697typedef 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*/
719typedef 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*/
748typedef 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*/
782typedef 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*/
811typedef 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*/
834typedef SMC37c669_CR0D SMC37c669_DEVICE_ID_REGISTER;
835typedef SMC37c669_CR0E SMC37c669_DEVICE_REVISION_REGISTER;
836typedef SMC37c669_CR20 SMC37c669_FDC_BASE_ADDRESS_REGISTER;
837typedef SMC37c669_CR21 SMC37c669_IDE_ADDRESS_REGISTER;
838typedef SMC37c669_CR23 SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER;
839typedef SMC37c669_CR24 SMC37c669_SERIAL_BASE_ADDRESS_REGISTER;
840typedef SMC37c669_CR26 SMC37c669_PARALLEL_FDC_DRQ_REGISTER;
841typedef SMC37c669_CR27 SMC37c669_PARALLEL_FDC_IRQ_REGISTER;
842typedef SMC37c669_CR28 SMC37c669_SERIAL_IRQ_REGISTER;
843
844/*
845** ISA/Device IRQ Translation Table Entry Definition
846*/
847typedef 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*/
855typedef 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
864SMC37c669_CONFIG_REGS *SMC37c669_detect(
865    int
866);
867
868unsigned int SMC37c669_enable_device(
869    unsigned int func
870);
871
872unsigned int SMC37c669_disable_device(
873    unsigned int func
874);
875
876unsigned int SMC37c669_configure_device(
877    unsigned int func,
878    int port,
879    int irq,
880    int drq
881);
882
883void 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
937#ifndef TRUE
938#define TRUE 1
939#endif
940#ifndef FALSE
941#define FALSE 0
942#endif
943
944#define wb( _x_, _y_ )	outb( _y_, (unsigned int)((unsigned long)_x_) )
945#define rb( _x_ )	inb( (unsigned int)((unsigned long)_x_) )
946
947/*
948** Local storage for device configuration information.
949**
950** Since the SMC37c669 does not provide an explicit
951** mechanism for enabling/disabling individual device
952** functions, other than unmapping the device, local
953** storage for device configuration information is
954** allocated here for use in implementing our own
955** function enable/disable scheme.
956*/
957static struct DEVICE_CONFIG {
958    unsigned int port1;
959    unsigned int port2;
960    int irq;
961    int drq;
962} local_config [NUM_FUNCS];
963
964/*
965** List of all possible addresses for the Super I/O chip
966*/
967static unsigned long SMC37c669_Addresses[] __initdata =
968    {
969	0x3F0UL,	    /* Primary address	    */
970	0x370UL,	    /* Secondary address    */
971	0UL		    /* End of list	    */
972    };
973
974/*
975** Global Pointer to the Super I/O device
976*/
977static SMC37c669_CONFIG_REGS *SMC37c669 __initdata = NULL;
978
979/*
980** IRQ Translation Table
981**
982** The IRQ translation table is a list of SMC37c669 device
983** and standard ISA IRQs.
984**
985*/
986static SMC37c669_IRQ_TRANSLATION_ENTRY *SMC37c669_irq_table __initdata;
987
988/*
989** The following definition is for the default IRQ
990** translation table.
991*/
992static SMC37c669_IRQ_TRANSLATION_ENTRY SMC37c669_default_irq_table[]
993__initdata =
994    {
995	{ SMC37c669_DEVICE_IRQ_A, -1 },
996	{ SMC37c669_DEVICE_IRQ_B, -1 },
997	{ SMC37c669_DEVICE_IRQ_C, 7 },
998	{ SMC37c669_DEVICE_IRQ_D, 6 },
999	{ SMC37c669_DEVICE_IRQ_E, 4 },
1000	{ SMC37c669_DEVICE_IRQ_F, 3 },
1001	{ SMC37c669_DEVICE_IRQ_H, -1 },
1002	{ -1, -1 } /* End of table */
1003    };
1004
1005/*
1006** The following definition is for the MONET (XP1000) IRQ
1007** translation table.
1008*/
1009static SMC37c669_IRQ_TRANSLATION_ENTRY SMC37c669_monet_irq_table[]
1010__initdata =
1011    {
1012	{ SMC37c669_DEVICE_IRQ_A, -1 },
1013	{ SMC37c669_DEVICE_IRQ_B, -1 },
1014	{ SMC37c669_DEVICE_IRQ_C, 6 },
1015	{ SMC37c669_DEVICE_IRQ_D, 7 },
1016	{ SMC37c669_DEVICE_IRQ_E, 4 },
1017	{ SMC37c669_DEVICE_IRQ_F, 3 },
1018	{ SMC37c669_DEVICE_IRQ_H, -1 },
1019	{ -1, -1 } /* End of table */
1020    };
1021
1022static SMC37c669_IRQ_TRANSLATION_ENTRY *SMC37c669_irq_tables[] __initdata =
1023    {
1024	SMC37c669_default_irq_table,
1025	SMC37c669_monet_irq_table
1026    };
1027
1028/*
1029** DRQ Translation Table
1030**
1031** The DRQ translation table is a list of SMC37c669 device and
1032** ISA DMA channels.
1033**
1034*/
1035static SMC37c669_DRQ_TRANSLATION_ENTRY *SMC37c669_drq_table __initdata;
1036
1037/*
1038** The following definition is the default DRQ
1039** translation table.
1040*/
1041static SMC37c669_DRQ_TRANSLATION_ENTRY SMC37c669_default_drq_table[]
1042__initdata =
1043    {
1044	{ SMC37c669_DEVICE_DRQ_A, 2 },
1045	{ SMC37c669_DEVICE_DRQ_B, 3 },
1046	{ SMC37c669_DEVICE_DRQ_C, -1 },
1047	{ -1, -1 } /* End of table */
1048    };
1049
1050/*
1051** Local Function Prototype Declarations
1052*/
1053
1054static unsigned int SMC37c669_is_device_enabled(
1055    unsigned int func
1056);
1057
1058#if 0
1059static unsigned int SMC37c669_get_device_config(
1060    unsigned int func,
1061    int *port,
1062    int *irq,
1063    int *drq
1064);
1065#endif
1066
1067static void SMC37c669_config_mode(
1068    unsigned int enable
1069);
1070
1071static unsigned char SMC37c669_read_config(
1072    unsigned char index
1073);
1074
1075static void SMC37c669_write_config(
1076    unsigned char index,
1077    unsigned char data
1078);
1079
1080static void SMC37c669_init_local_config( void );
1081
1082static struct DEVICE_CONFIG *SMC37c669_get_config(
1083    unsigned int func
1084);
1085
1086static int SMC37c669_xlate_irq(
1087    int irq
1088);
1089
1090static int SMC37c669_xlate_drq(
1091    int drq
1092);
1093
1094static  __cacheline_aligned DEFINE_SPINLOCK(smc_lock);
1095
1096/*
1097**++
1098**  FUNCTIONAL DESCRIPTION:
1099**
1100**      This function detects the presence of an SMC37c669 Super I/O
1101**	controller.
1102**
1103**  FORMAL PARAMETERS:
1104**
1105**	None
1106**
1107**  RETURN VALUE:
1108**
1109**      Returns a pointer to the device if found, otherwise,
1110**	the NULL pointer is returned.
1111**
1112**  SIDE EFFECTS:
1113**
1114**      None
1115**
1116**--
1117*/
1118SMC37c669_CONFIG_REGS * __init SMC37c669_detect( int index )
1119{
1120    int i;
1121    SMC37c669_DEVICE_ID_REGISTER id;
1122
1123    for ( i = 0;  SMC37c669_Addresses[i] != 0;  i++ ) {
1124/*
1125** Initialize the device pointer even though we don't yet know if
1126** the controller is at this address.  The support functions access
1127** the controller through this device pointer so we need to set it
1128** even when we are looking ...
1129*/
1130    	SMC37c669 = ( SMC37c669_CONFIG_REGS * )SMC37c669_Addresses[i];
1131/*
1132** Enter configuration mode
1133*/
1134	SMC37c669_config_mode( TRUE );
1135/*
1136** Read the device id
1137*/
1138	id.as_uchar = SMC37c669_read_config( SMC37c669_DEVICE_ID_INDEX );
1139/*
1140** Exit configuration mode
1141*/
1142	SMC37c669_config_mode( FALSE );
1143/*
1144** Does the device id match?  If so, assume we have found an
1145** SMC37c669 controller at this address.
1146*/
1147	if ( id.by_field.device_id == SMC37c669_DEVICE_ID ) {
1148/*
1149** Initialize the IRQ and DRQ translation tables.
1150*/
1151    	    SMC37c669_irq_table = SMC37c669_irq_tables[ index ];
1152	    SMC37c669_drq_table = SMC37c669_default_drq_table;
1153/*
1154** erfix
1155**
1156** If the platform can't use the IRQ and DRQ defaults set up in this
1157** file, it should call a platform-specific external routine at this
1158** point to reset the IRQ and DRQ translation table pointers to point
1159** at the appropriate tables for the platform.  If the defaults are
1160** acceptable, then the external routine should do nothing.
1161*/
1162
1163/*
1164** Put the chip back into configuration mode
1165*/
1166	    SMC37c669_config_mode( TRUE );
1167/*
1168** Initialize local storage for configuration information
1169*/
1170	    SMC37c669_init_local_config( );
1171/*
1172** Exit configuration mode
1173*/
1174	    SMC37c669_config_mode( FALSE );
1175/*
1176** SMC37c669 controller found, break out of search loop
1177*/
1178	    break;
1179	}
1180	else {
1181/*
1182** Otherwise, we did not find an SMC37c669 controller at this
1183** address so set the device pointer to NULL.
1184*/
1185	    SMC37c669 = NULL;
1186	}
1187    }
1188    return SMC37c669;
1189}
1190
1191
1192/*
1193**++
1194**  FUNCTIONAL DESCRIPTION:
1195**
1196**      This function enables an SMC37c669 device function.
1197**
1198**  FORMAL PARAMETERS:
1199**
1200**      func:
1201**          Which device function to enable
1202**
1203**  RETURN VALUE:
1204**
1205**      Returns TRUE is the device function was enabled, otherwise, FALSE
1206**
1207**  SIDE EFFECTS:
1208**
1209**      {@description or none@}
1210**
1211**  DESIGN:
1212**
1213**      Enabling a device function in the SMC37c669 controller involves
1214**	setting all of its mappings (port, irq, drq ...).  A local
1215**	"shadow" copy of the device configuration is kept so we can
1216**	just set each mapping to what the local copy says.
1217**
1218**	This function ALWAYS updates the local shadow configuration of
1219**	the device function being enabled, even if the device is always
1220**	enabled.  To avoid replication of code, functions such as
1221**	configure_device set up the local copy and then call this
1222**	function to the update the real device.
1223**
1224**--
1225*/
1226unsigned int __init SMC37c669_enable_device ( unsigned int func )
1227{
1228    unsigned int ret_val = FALSE;
1229/*
1230** Put the device into configuration mode
1231*/
1232    SMC37c669_config_mode( TRUE );
1233    switch ( func ) {
1234    	case SERIAL_0:
1235	    {
1236	    	SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
1237		SMC37c669_SERIAL_IRQ_REGISTER irq;
1238/*
1239** Enable the serial 1 IRQ mapping
1240*/
1241	    	irq.as_uchar =
1242		    SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
1243
1244		irq.by_field.uart1_irq =
1245		    SMC37c669_RAW_DEVICE_IRQ(
1246			SMC37c669_xlate_irq( local_config[ func ].irq )
1247		    );
1248
1249		SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
1250/*
1251** Enable the serial 1 port base address mapping
1252*/
1253		base_addr.as_uchar = 0;
1254		base_addr.by_field.addr9_3 = local_config[ func ].port1 >> 3;
1255
1256		SMC37c669_write_config(
1257		    SMC37c669_SERIAL0_BASE_ADDRESS_INDEX,
1258		    base_addr.as_uchar
1259		);
1260		ret_val = TRUE;
1261		break;
1262	    }
1263	case SERIAL_1:
1264	    {
1265	    	SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
1266		SMC37c669_SERIAL_IRQ_REGISTER irq;
1267/*
1268** Enable the serial 2 IRQ mapping
1269*/
1270	    	irq.as_uchar =
1271		    SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
1272
1273		irq.by_field.uart2_irq =
1274		    SMC37c669_RAW_DEVICE_IRQ(
1275			SMC37c669_xlate_irq( local_config[ func ].irq )
1276		    );
1277
1278		SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
1279/*
1280** Enable the serial 2 port base address mapping
1281*/
1282		base_addr.as_uchar = 0;
1283		base_addr.by_field.addr9_3 = local_config[ func ].port1 >> 3;
1284
1285		SMC37c669_write_config(
1286		    SMC37c669_SERIAL1_BASE_ADDRESS_INDEX,
1287		    base_addr.as_uchar
1288		);
1289		ret_val = TRUE;
1290		break;
1291	    }
1292	case PARALLEL_0:
1293	    {
1294	    	SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER base_addr;
1295		SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
1296		SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
1297/*
1298** Enable the parallel port DMA channel mapping
1299*/
1300	    	drq.as_uchar =
1301		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
1302
1303		drq.by_field.ppt_drq =
1304		    SMC37c669_RAW_DEVICE_DRQ(
1305			SMC37c669_xlate_drq( local_config[ func ].drq )
1306		    );
1307
1308		SMC37c669_write_config(
1309		    SMC37c669_PARALLEL_FDC_DRQ_INDEX,
1310		    drq.as_uchar
1311		);
1312/*
1313** Enable the parallel port IRQ mapping
1314*/
1315		irq.as_uchar =
1316		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
1317
1318		irq.by_field.ppt_irq =
1319		    SMC37c669_RAW_DEVICE_IRQ(
1320			SMC37c669_xlate_irq( local_config[ func ].irq )
1321		    );
1322
1323		SMC37c669_write_config(
1324		    SMC37c669_PARALLEL_FDC_IRQ_INDEX,
1325		    irq.as_uchar
1326		);
1327/*
1328** Enable the parallel port base address mapping
1329*/
1330		base_addr.as_uchar = 0;
1331		base_addr.by_field.addr9_2 = local_config[ func ].port1 >> 2;
1332
1333		SMC37c669_write_config(
1334		    SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX,
1335		    base_addr.as_uchar
1336		);
1337		ret_val = TRUE;
1338		break;
1339	    }
1340	case FLOPPY_0:
1341	    {
1342	    	SMC37c669_FDC_BASE_ADDRESS_REGISTER base_addr;
1343		SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
1344		SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
1345/*
1346** Enable the floppy controller DMA channel mapping
1347*/
1348	    	drq.as_uchar =
1349		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
1350
1351		drq.by_field.fdc_drq =
1352		    SMC37c669_RAW_DEVICE_DRQ(
1353			SMC37c669_xlate_drq( local_config[ func ].drq )
1354		    );
1355
1356		SMC37c669_write_config(
1357		    SMC37c669_PARALLEL_FDC_DRQ_INDEX,
1358		    drq.as_uchar
1359		);
1360/*
1361** Enable the floppy controller IRQ mapping
1362*/
1363		irq.as_uchar =
1364		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
1365
1366		irq.by_field.fdc_irq =
1367		    SMC37c669_RAW_DEVICE_IRQ(
1368			SMC37c669_xlate_irq( local_config[ func ].irq )
1369		    );
1370
1371		SMC37c669_write_config(
1372		    SMC37c669_PARALLEL_FDC_IRQ_INDEX,
1373		    irq.as_uchar
1374		);
1375/*
1376** Enable the floppy controller base address mapping
1377*/
1378		base_addr.as_uchar = 0;
1379		base_addr.by_field.addr9_4 = local_config[ func ].port1 >> 4;
1380
1381		SMC37c669_write_config(
1382		    SMC37c669_FDC_BASE_ADDRESS_INDEX,
1383		    base_addr.as_uchar
1384		);
1385		ret_val = TRUE;
1386		break;
1387	    }
1388	case IDE_0:
1389	    {
1390	    	SMC37c669_IDE_ADDRESS_REGISTER ide_addr;
1391/*
1392** Enable the IDE alternate status base address mapping
1393*/
1394	    	ide_addr.as_uchar = 0;
1395		ide_addr.by_field.addr9_4 = local_config[ func ].port2 >> 4;
1396
1397		SMC37c669_write_config(
1398		    SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX,
1399		    ide_addr.as_uchar
1400		);
1401/*
1402** Enable the IDE controller base address mapping
1403*/
1404		ide_addr.as_uchar = 0;
1405		ide_addr.by_field.addr9_4 = local_config[ func ].port1 >> 4;
1406
1407		SMC37c669_write_config(
1408		    SMC37c669_IDE_BASE_ADDRESS_INDEX,
1409		    ide_addr.as_uchar
1410		);
1411		ret_val = TRUE;
1412		break;
1413	    }
1414    }
1415/*
1416** Exit configuration mode and return
1417*/
1418    SMC37c669_config_mode( FALSE );
1419
1420    return ret_val;
1421}
1422
1423
1424/*
1425**++
1426**  FUNCTIONAL DESCRIPTION:
1427**
1428**      This function disables a device function within the
1429**	SMC37c669 Super I/O controller.
1430**
1431**  FORMAL PARAMETERS:
1432**
1433**      func:
1434**          Which function to disable
1435**
1436**  RETURN VALUE:
1437**
1438**      Return TRUE if the device function was disabled, otherwise, FALSE
1439**
1440**  SIDE EFFECTS:
1441**
1442**      {@description or none@}
1443**
1444**  DESIGN:
1445**
1446**      Disabling a function in the SMC37c669 device involves
1447**	disabling all the function's mappings (port, irq, drq ...).
1448**	A shadow copy of the device configuration is maintained
1449**	in local storage so we won't worry aboving saving the
1450**	current configuration information.
1451**
1452**--
1453*/
1454unsigned int __init SMC37c669_disable_device ( unsigned int func )
1455{
1456    unsigned int ret_val = FALSE;
1457
1458/*
1459** Put the device into configuration mode
1460*/
1461    SMC37c669_config_mode( TRUE );
1462    switch ( func ) {
1463    	case SERIAL_0:
1464	    {
1465	    	SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
1466		SMC37c669_SERIAL_IRQ_REGISTER irq;
1467/*
1468** Disable the serial 1 IRQ mapping
1469*/
1470	    	irq.as_uchar =
1471		    SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
1472
1473		irq.by_field.uart1_irq = 0;
1474
1475		SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
1476/*
1477** Disable the serial 1 port base address mapping
1478*/
1479		base_addr.as_uchar = 0;
1480		SMC37c669_write_config(
1481		    SMC37c669_SERIAL0_BASE_ADDRESS_INDEX,
1482		    base_addr.as_uchar
1483		);
1484		ret_val = TRUE;
1485		break;
1486	    }
1487	case SERIAL_1:
1488	    {
1489	    	SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
1490		SMC37c669_SERIAL_IRQ_REGISTER irq;
1491/*
1492** Disable the serial 2 IRQ mapping
1493*/
1494	    	irq.as_uchar =
1495		    SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
1496
1497		irq.by_field.uart2_irq = 0;
1498
1499		SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
1500/*
1501** Disable the serial 2 port base address mapping
1502*/
1503		base_addr.as_uchar = 0;
1504
1505		SMC37c669_write_config(
1506		    SMC37c669_SERIAL1_BASE_ADDRESS_INDEX,
1507		    base_addr.as_uchar
1508		);
1509		ret_val = TRUE;
1510		break;
1511	    }
1512	case PARALLEL_0:
1513	    {
1514	    	SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER base_addr;
1515		SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
1516		SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
1517/*
1518** Disable the parallel port DMA channel mapping
1519*/
1520	    	drq.as_uchar =
1521		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
1522
1523		drq.by_field.ppt_drq = 0;
1524
1525		SMC37c669_write_config(
1526		    SMC37c669_PARALLEL_FDC_DRQ_INDEX,
1527		    drq.as_uchar
1528		);
1529/*
1530** Disable the parallel port IRQ mapping
1531*/
1532		irq.as_uchar =
1533		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
1534
1535		irq.by_field.ppt_irq = 0;
1536
1537		SMC37c669_write_config(
1538		    SMC37c669_PARALLEL_FDC_IRQ_INDEX,
1539		    irq.as_uchar
1540		);
1541/*
1542** Disable the parallel port base address mapping
1543*/
1544		base_addr.as_uchar = 0;
1545
1546		SMC37c669_write_config(
1547		    SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX,
1548		    base_addr.as_uchar
1549		);
1550		ret_val = TRUE;
1551		break;
1552	    }
1553	case FLOPPY_0:
1554	    {
1555	    	SMC37c669_FDC_BASE_ADDRESS_REGISTER base_addr;
1556		SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
1557		SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
1558/*
1559** Disable the floppy controller DMA channel mapping
1560*/
1561	    	drq.as_uchar =
1562		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
1563
1564		drq.by_field.fdc_drq = 0;
1565
1566		SMC37c669_write_config(
1567		    SMC37c669_PARALLEL_FDC_DRQ_INDEX,
1568		    drq.as_uchar
1569		);
1570/*
1571** Disable the floppy controller IRQ mapping
1572*/
1573		irq.as_uchar =
1574		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
1575
1576		irq.by_field.fdc_irq = 0;
1577
1578		SMC37c669_write_config(
1579		    SMC37c669_PARALLEL_FDC_IRQ_INDEX,
1580		    irq.as_uchar
1581		);
1582/*
1583** Disable the floppy controller base address mapping
1584*/
1585		base_addr.as_uchar = 0;
1586
1587		SMC37c669_write_config(
1588		    SMC37c669_FDC_BASE_ADDRESS_INDEX,
1589		    base_addr.as_uchar
1590		);
1591		ret_val = TRUE;
1592		break;
1593	    }
1594	case IDE_0:
1595	    {
1596	    	SMC37c669_IDE_ADDRESS_REGISTER ide_addr;
1597/*
1598** Disable the IDE alternate status base address mapping
1599*/
1600	    	ide_addr.as_uchar = 0;
1601
1602		SMC37c669_write_config(
1603		    SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX,
1604		    ide_addr.as_uchar
1605		);
1606/*
1607** Disable the IDE controller base address mapping
1608*/
1609		ide_addr.as_uchar = 0;
1610
1611		SMC37c669_write_config(
1612		    SMC37c669_IDE_BASE_ADDRESS_INDEX,
1613		    ide_addr.as_uchar
1614		);
1615		ret_val = TRUE;
1616		break;
1617	    }
1618    }
1619/*
1620** Exit configuration mode and return
1621*/
1622    SMC37c669_config_mode( FALSE );
1623
1624    return ret_val;
1625}
1626
1627
1628/*
1629**++
1630**  FUNCTIONAL DESCRIPTION:
1631**
1632**      This function configures a device function within the
1633**	SMC37c669 Super I/O controller.
1634**
1635**  FORMAL PARAMETERS:
1636**
1637**      func:
1638**          Which device function
1639**
1640**      port:
1641**          I/O port for the function to use
1642**
1643**      irq:
1644**          IRQ for the device function to use
1645**
1646**      drq:
1647**          DMA channel for the device function to use
1648**
1649**  RETURN VALUE:
1650**
1651**      Returns TRUE if the device function was configured,
1652**	otherwise, FALSE.
1653**
1654**  SIDE EFFECTS:
1655**
1656**      {@description or none@}
1657**
1658**  DESIGN:
1659**
1660**	If this function returns TRUE, the local shadow copy of
1661**	the configuration is also updated.  If the device function
1662**	is currently disabled, only the local shadow copy is
1663**	updated and the actual device function will be updated
1664**	if/when it is enabled.
1665**
1666**--
1667*/
1668unsigned int __init SMC37c669_configure_device (
1669    unsigned int func,
1670    int port,
1671    int irq,
1672    int drq )
1673{
1674    struct DEVICE_CONFIG *cp;
1675
1676/*
1677** Check for a valid configuration
1678*/
1679    if ( ( cp = SMC37c669_get_config ( func ) ) != NULL ) {
1680/*
1681** Configuration is valid, update the local shadow copy
1682*/
1683    	if ( ( drq & ~0xFF ) == 0 ) {
1684	    cp->drq = drq;
1685	}
1686	if ( ( irq & ~0xFF ) == 0 ) {
1687	    cp->irq = irq;
1688	}
1689	if ( ( port & ~0xFFFF ) == 0 ) {
1690	    cp->port1 = port;
1691	}
1692/*
1693** If the device function is enabled, update the actual
1694** device configuration.
1695*/
1696	if ( SMC37c669_is_device_enabled( func ) ) {
1697	    SMC37c669_enable_device( func );
1698	}
1699	return TRUE;
1700    }
1701    return FALSE;
1702}
1703
1704
1705/*
1706**++
1707**  FUNCTIONAL DESCRIPTION:
1708**
1709**      This function determines whether a device function
1710**	within the SMC37c669 controller is enabled.
1711**
1712**  FORMAL PARAMETERS:
1713**
1714**      func:
1715**          Which device function
1716**
1717**  RETURN VALUE:
1718**
1719**      Returns TRUE if the device function is enabled, otherwise, FALSE
1720**
1721**  SIDE EFFECTS:
1722**
1723**      {@description or none@}
1724**
1725**  DESIGN:
1726**
1727**      To check whether a device is enabled we will only look at
1728**	the port base address mapping.  According to the SMC37c669
1729**	specification, all of the port base address mappings are
1730**	disabled if the addr<9:8> (bits <7:6> of the register) are
1731**	zero.
1732**
1733**--
1734*/
1735static unsigned int __init SMC37c669_is_device_enabled ( unsigned int func )
1736{
1737    unsigned char base_addr = 0;
1738    unsigned int dev_ok = FALSE;
1739    unsigned int ret_val = FALSE;
1740/*
1741** Enter configuration mode
1742*/
1743    SMC37c669_config_mode( TRUE );
1744
1745    switch ( func ) {
1746    	case SERIAL_0:
1747	    base_addr =
1748		SMC37c669_read_config( SMC37c669_SERIAL0_BASE_ADDRESS_INDEX );
1749	    dev_ok = TRUE;
1750	    break;
1751	case SERIAL_1:
1752	    base_addr =
1753		SMC37c669_read_config( SMC37c669_SERIAL1_BASE_ADDRESS_INDEX );
1754	    dev_ok = TRUE;
1755	    break;
1756	case PARALLEL_0:
1757	    base_addr =
1758		SMC37c669_read_config( SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX );
1759	    dev_ok = TRUE;
1760	    break;
1761	case FLOPPY_0:
1762	    base_addr =
1763		SMC37c669_read_config( SMC37c669_FDC_BASE_ADDRESS_INDEX );
1764	    dev_ok = TRUE;
1765	    break;
1766	case IDE_0:
1767	    base_addr =
1768		SMC37c669_read_config( SMC37c669_IDE_BASE_ADDRESS_INDEX );
1769	    dev_ok = TRUE;
1770	    break;
1771    }
1772/*
1773** If we have a valid device, check base_addr<7:6> to see if the
1774** device is enabled (mapped).
1775*/
1776    if ( ( dev_ok ) && ( ( base_addr & 0xC0 ) != 0 ) ) {
1777/*
1778** The mapping is not disabled, so assume that the function is
1779** enabled.
1780*/
1781    	ret_val = TRUE;
1782    }
1783/*
1784** Exit configuration mode
1785*/
1786    SMC37c669_config_mode( FALSE );
1787
1788    return ret_val;
1789}
1790
1791
1792#if 0
1793/*
1794**++
1795**  FUNCTIONAL DESCRIPTION:
1796**
1797**      This function retrieves the configuration information of a
1798**	device function within the SMC37c699 Super I/O controller.
1799**
1800**  FORMAL PARAMETERS:
1801**
1802**      func:
1803**          Which device function
1804**
1805**      port:
1806**          I/O port returned
1807**
1808**      irq:
1809**          IRQ returned
1810**
1811**      drq:
1812**          DMA channel returned
1813**
1814**  RETURN VALUE:
1815**
1816**      Returns TRUE if the device configuration was successfully
1817**	retrieved, otherwise, FALSE.
1818**
1819**  SIDE EFFECTS:
1820**
1821**      The data pointed to by the port, irq, and drq parameters
1822**	my be modified even if the configuration is not successfully
1823**	retrieved.
1824**
1825**  DESIGN:
1826**
1827**      The device configuration is fetched from the local shadow
1828**	copy.  Any unused parameters will be set to -1.  Any
1829**	parameter which is not desired can specify the NULL
1830**	pointer.
1831**
1832**--
1833*/
1834static unsigned int __init SMC37c669_get_device_config (
1835    unsigned int func,
1836    int *port,
1837    int *irq,
1838    int *drq )
1839{
1840    struct DEVICE_CONFIG *cp;
1841    unsigned int ret_val = FALSE;
1842/*
1843** Check for a valid device configuration
1844*/
1845    if ( ( cp = SMC37c669_get_config( func ) ) != NULL ) {
1846    	if ( drq != NULL ) {
1847	    *drq = cp->drq;
1848	    ret_val = TRUE;
1849	}
1850	if ( irq != NULL ) {
1851	    *irq = cp->irq;
1852	    ret_val = TRUE;
1853	}
1854	if ( port != NULL ) {
1855	    *port = cp->port1;
1856	    ret_val = TRUE;
1857	}
1858    }
1859    return ret_val;
1860}
1861#endif
1862
1863
1864/*
1865**++
1866**  FUNCTIONAL DESCRIPTION:
1867**
1868**      This function displays the current state of the SMC37c699
1869**	Super I/O controller's device functions.
1870**
1871**  FORMAL PARAMETERS:
1872**
1873**      None
1874**
1875**  RETURN VALUE:
1876**
1877**      None
1878**
1879**  SIDE EFFECTS:
1880**
1881**      None
1882**
1883**--
1884*/
1885void __init SMC37c669_display_device_info ( void )
1886{
1887    if ( SMC37c669_is_device_enabled( SERIAL_0 ) ) {
1888    	printk( "  Serial 0:    Enabled [ Port 0x%x, IRQ %d ]\n",
1889		 local_config[ SERIAL_0 ].port1,
1890		 local_config[ SERIAL_0 ].irq
1891	);
1892    }
1893    else {
1894    	printk( "  Serial 0:    Disabled\n" );
1895    }
1896
1897    if ( SMC37c669_is_device_enabled( SERIAL_1 ) ) {
1898    	printk( "  Serial 1:    Enabled [ Port 0x%x, IRQ %d ]\n",
1899		 local_config[ SERIAL_1 ].port1,
1900		 local_config[ SERIAL_1 ].irq
1901	);
1902    }
1903    else {
1904    	printk( "  Serial 1:    Disabled\n" );
1905    }
1906
1907    if ( SMC37c669_is_device_enabled( PARALLEL_0 ) ) {
1908    	printk( "  Parallel:    Enabled [ Port 0x%x, IRQ %d/%d ]\n",
1909		 local_config[ PARALLEL_0 ].port1,
1910		 local_config[ PARALLEL_0 ].irq,
1911		 local_config[ PARALLEL_0 ].drq
1912	);
1913    }
1914    else {
1915    	printk( "  Parallel:    Disabled\n" );
1916    }
1917
1918    if ( SMC37c669_is_device_enabled( FLOPPY_0 ) ) {
1919    	printk( "  Floppy Ctrl: Enabled [ Port 0x%x, IRQ %d/%d ]\n",
1920		 local_config[ FLOPPY_0 ].port1,
1921		 local_config[ FLOPPY_0 ].irq,
1922		 local_config[ FLOPPY_0 ].drq
1923	);
1924    }
1925    else {
1926    	printk( "  Floppy Ctrl: Disabled\n" );
1927    }
1928
1929    if ( SMC37c669_is_device_enabled( IDE_0 ) ) {
1930    	printk( "  IDE 0:       Enabled [ Port 0x%x, IRQ %d ]\n",
1931		 local_config[ IDE_0 ].port1,
1932		 local_config[ IDE_0 ].irq
1933	);
1934    }
1935    else {
1936    	printk( "  IDE 0:       Disabled\n" );
1937    }
1938}
1939
1940
1941/*
1942**++
1943**  FUNCTIONAL DESCRIPTION:
1944**
1945**      This function puts the SMC37c669 Super I/O controller into,
1946**	and takes it out of, configuration mode.
1947**
1948**  FORMAL PARAMETERS:
1949**
1950**      enable:
1951**          TRUE to enter configuration mode, FALSE to exit.
1952**
1953**  RETURN VALUE:
1954**
1955**      None
1956**
1957**  SIDE EFFECTS:
1958**
1959**      The SMC37c669 controller may be left in configuration mode.
1960**
1961**--
1962*/
1963static void __init SMC37c669_config_mode(
1964    unsigned int enable )
1965{
1966    if ( enable ) {
1967/*
1968** To enter configuration mode, two writes in succession to the index
1969** port are required.  If a write to another address or port occurs
1970** between these two writes, the chip does not enter configuration
1971** mode.  Therefore, a spinlock is placed around the two writes to
1972** guarantee that they complete uninterrupted.
1973*/
1974	spin_lock(&smc_lock);
1975    	wb( &SMC37c669->index_port, SMC37c669_CONFIG_ON_KEY );
1976    	wb( &SMC37c669->index_port, SMC37c669_CONFIG_ON_KEY );
1977	spin_unlock(&smc_lock);
1978    }
1979    else {
1980    	wb( &SMC37c669->index_port, SMC37c669_CONFIG_OFF_KEY );
1981    }
1982}
1983
1984/*
1985**++
1986**  FUNCTIONAL DESCRIPTION:
1987**
1988**      This function reads an SMC37c669 Super I/O controller
1989**	configuration register.  This function assumes that the
1990**	device is already in configuration mode.
1991**
1992**  FORMAL PARAMETERS:
1993**
1994**      index:
1995**          Index value of configuration register to read
1996**
1997**  RETURN VALUE:
1998**
1999**      Data read from configuration register
2000**
2001**  SIDE EFFECTS:
2002**
2003**      None
2004**
2005**--
2006*/
2007static unsigned char __init SMC37c669_read_config(
2008    unsigned char index )
2009{
2010    unsigned char data;
2011
2012    wb( &SMC37c669->index_port, index );
2013    data = rb( &SMC37c669->data_port );
2014    return data;
2015}
2016
2017/*
2018**++
2019**  FUNCTIONAL DESCRIPTION:
2020**
2021**      This function writes an SMC37c669 Super I/O controller
2022**	configuration register.  This function assumes that the
2023**	device is already in configuration mode.
2024**
2025**  FORMAL PARAMETERS:
2026**
2027**      index:
2028**          Index of configuration register to write
2029**
2030**      data:
2031**          Data to be written
2032**
2033**  RETURN VALUE:
2034**
2035**      None
2036**
2037**  SIDE EFFECTS:
2038**
2039**      None
2040**
2041**--
2042*/
2043static void __init SMC37c669_write_config(
2044    unsigned char index,
2045    unsigned char data )
2046{
2047    wb( &SMC37c669->index_port, index );
2048    wb( &SMC37c669->data_port, data );
2049}
2050
2051
2052/*
2053**++
2054**  FUNCTIONAL DESCRIPTION:
2055**
2056**      This function initializes the local device
2057**	configuration storage.  This function assumes
2058**	that the device is already in configuration
2059**	mode.
2060**
2061**  FORMAL PARAMETERS:
2062**
2063**      None
2064**
2065**  RETURN VALUE:
2066**
2067**      None
2068**
2069**  SIDE EFFECTS:
2070**
2071**      Local storage for device configuration information
2072**	is initialized.
2073**
2074**--
2075*/
2076static void __init SMC37c669_init_local_config ( void )
2077{
2078    SMC37c669_SERIAL_BASE_ADDRESS_REGISTER uart_base;
2079    SMC37c669_SERIAL_IRQ_REGISTER uart_irqs;
2080    SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER ppt_base;
2081    SMC37c669_PARALLEL_FDC_IRQ_REGISTER ppt_fdc_irqs;
2082    SMC37c669_PARALLEL_FDC_DRQ_REGISTER ppt_fdc_drqs;
2083    SMC37c669_FDC_BASE_ADDRESS_REGISTER fdc_base;
2084    SMC37c669_IDE_ADDRESS_REGISTER ide_base;
2085    SMC37c669_IDE_ADDRESS_REGISTER ide_alt;
2086
2087/*
2088** Get serial port 1 base address
2089*/
2090    uart_base.as_uchar =
2091	SMC37c669_read_config( SMC37c669_SERIAL0_BASE_ADDRESS_INDEX );
2092/*
2093** Get IRQs for serial ports 1 & 2
2094*/
2095    uart_irqs.as_uchar =
2096	SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
2097/*
2098** Store local configuration information for serial port 1
2099*/
2100    local_config[SERIAL_0].port1 = uart_base.by_field.addr9_3 << 3;
2101    local_config[SERIAL_0].irq =
2102	SMC37c669_xlate_irq(
2103	    SMC37c669_DEVICE_IRQ( uart_irqs.by_field.uart1_irq )
2104	);
2105/*
2106** Get serial port 2 base address
2107*/
2108    uart_base.as_uchar =
2109	SMC37c669_read_config( SMC37c669_SERIAL1_BASE_ADDRESS_INDEX );
2110/*
2111** Store local configuration information for serial port 2
2112*/
2113    local_config[SERIAL_1].port1 = uart_base.by_field.addr9_3 << 3;
2114    local_config[SERIAL_1].irq =
2115	SMC37c669_xlate_irq(
2116	    SMC37c669_DEVICE_IRQ( uart_irqs.by_field.uart2_irq )
2117	);
2118/*
2119** Get parallel port base address
2120*/
2121    ppt_base.as_uchar =
2122	SMC37c669_read_config( SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX );
2123/*
2124** Get IRQs for parallel port and floppy controller
2125*/
2126    ppt_fdc_irqs.as_uchar =
2127	SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
2128/*
2129** Get DRQs for parallel port and floppy controller
2130*/
2131    ppt_fdc_drqs.as_uchar =
2132	SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
2133/*
2134** Store local configuration information for parallel port
2135*/
2136    local_config[PARALLEL_0].port1 = ppt_base.by_field.addr9_2 << 2;
2137    local_config[PARALLEL_0].irq =
2138	SMC37c669_xlate_irq(
2139	    SMC37c669_DEVICE_IRQ( ppt_fdc_irqs.by_field.ppt_irq )
2140	);
2141    local_config[PARALLEL_0].drq =
2142	SMC37c669_xlate_drq(
2143	    SMC37c669_DEVICE_DRQ( ppt_fdc_drqs.by_field.ppt_drq )
2144	);
2145/*
2146** Get floppy controller base address
2147*/
2148    fdc_base.as_uchar =
2149	SMC37c669_read_config( SMC37c669_FDC_BASE_ADDRESS_INDEX );
2150/*
2151** Store local configuration information for floppy controller
2152*/
2153    local_config[FLOPPY_0].port1 = fdc_base.by_field.addr9_4 << 4;
2154    local_config[FLOPPY_0].irq =
2155	SMC37c669_xlate_irq(
2156	    SMC37c669_DEVICE_IRQ( ppt_fdc_irqs.by_field.fdc_irq )
2157	);
2158    local_config[FLOPPY_0].drq =
2159	SMC37c669_xlate_drq(
2160	    SMC37c669_DEVICE_DRQ( ppt_fdc_drqs.by_field.fdc_drq )
2161	);
2162/*
2163** Get IDE controller base address
2164*/
2165    ide_base.as_uchar =
2166	SMC37c669_read_config( SMC37c669_IDE_BASE_ADDRESS_INDEX );
2167/*
2168** Get IDE alternate status base address
2169*/
2170    ide_alt.as_uchar =
2171	SMC37c669_read_config( SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX );
2172/*
2173** Store local configuration information for IDE controller
2174*/
2175    local_config[IDE_0].port1 = ide_base.by_field.addr9_4 << 4;
2176    local_config[IDE_0].port2 = ide_alt.by_field.addr9_4 << 4;
2177    local_config[IDE_0].irq = 14;
2178}
2179
2180
2181/*
2182**++
2183**  FUNCTIONAL DESCRIPTION:
2184**
2185**      This function returns a pointer to the local shadow
2186**	configuration of the requested device function.
2187**
2188**  FORMAL PARAMETERS:
2189**
2190**      func:
2191**          Which device function
2192**
2193**  RETURN VALUE:
2194**
2195**      Returns a pointer to the DEVICE_CONFIG structure for the
2196**	requested function, otherwise, NULL.
2197**
2198**  SIDE EFFECTS:
2199**
2200**      {@description or none@}
2201**
2202**--
2203*/
2204static struct DEVICE_CONFIG * __init SMC37c669_get_config( unsigned int func )
2205{
2206    struct DEVICE_CONFIG *cp = NULL;
2207
2208    switch ( func ) {
2209    	case SERIAL_0:
2210	    cp = &local_config[ SERIAL_0 ];
2211	    break;
2212	case SERIAL_1:
2213	    cp = &local_config[ SERIAL_1 ];
2214	    break;
2215	case PARALLEL_0:
2216	    cp = &local_config[ PARALLEL_0 ];
2217	    break;
2218	case FLOPPY_0:
2219	    cp = &local_config[ FLOPPY_0 ];
2220	    break;
2221	case IDE_0:
2222	    cp = &local_config[ IDE_0 ];
2223	    break;
2224    }
2225    return cp;
2226}
2227
2228/*
2229**++
2230**  FUNCTIONAL DESCRIPTION:
2231**
2232**      This function translates IRQs back and forth between ISA
2233**	IRQs and SMC37c669 device IRQs.
2234**
2235**  FORMAL PARAMETERS:
2236**
2237**      irq:
2238**          The IRQ to translate
2239**
2240**  RETURN VALUE:
2241**
2242**      Returns the translated IRQ, otherwise, returns -1.
2243**
2244**  SIDE EFFECTS:
2245**
2246**      {@description or none@}
2247**
2248**--
2249*/
2250static int __init SMC37c669_xlate_irq ( int irq )
2251{
2252    int i, translated_irq = -1;
2253
2254    if ( SMC37c669_IS_DEVICE_IRQ( irq ) ) {
2255/*
2256** We are translating a device IRQ to an ISA IRQ
2257*/
2258    	for ( i = 0; ( SMC37c669_irq_table[i].device_irq != -1 ) || ( SMC37c669_irq_table[i].isa_irq != -1 ); i++ ) {
2259	    if ( irq == SMC37c669_irq_table[i].device_irq ) {
2260	    	translated_irq = SMC37c669_irq_table[i].isa_irq;
2261		break;
2262	    }
2263	}
2264    }
2265    else {
2266/*
2267** We are translating an ISA IRQ to a device IRQ
2268*/
2269    	for ( i = 0; ( SMC37c669_irq_table[i].isa_irq != -1 ) || ( SMC37c669_irq_table[i].device_irq != -1 ); i++ ) {
2270	    if ( irq == SMC37c669_irq_table[i].isa_irq ) {
2271	    	translated_irq = SMC37c669_irq_table[i].device_irq;
2272		break;
2273	    }
2274	}
2275    }
2276    return translated_irq;
2277}
2278
2279
2280/*
2281**++
2282**  FUNCTIONAL DESCRIPTION:
2283**
2284**      This function translates DMA channels back and forth between
2285**	ISA DMA channels and SMC37c669 device DMA channels.
2286**
2287**  FORMAL PARAMETERS:
2288**
2289**      drq:
2290**          The DMA channel to translate
2291**
2292**  RETURN VALUE:
2293**
2294**      Returns the translated DMA channel, otherwise, returns -1
2295**
2296**  SIDE EFFECTS:
2297**
2298**      {@description or none@}
2299**
2300**--
2301*/
2302static int __init SMC37c669_xlate_drq ( int drq )
2303{
2304    int i, translated_drq = -1;
2305
2306    if ( SMC37c669_IS_DEVICE_DRQ( drq ) ) {
2307/*
2308** We are translating a device DMA channel to an ISA DMA channel
2309*/
2310    	for ( i = 0; ( SMC37c669_drq_table[i].device_drq != -1 ) || ( SMC37c669_drq_table[i].isa_drq != -1 ); i++ ) {
2311	    if ( drq == SMC37c669_drq_table[i].device_drq ) {
2312	    	translated_drq = SMC37c669_drq_table[i].isa_drq;
2313		break;
2314	    }
2315	}
2316    }
2317    else {
2318/*
2319** We are translating an ISA DMA channel to a device DMA channel
2320*/
2321    	for ( i = 0; ( SMC37c669_drq_table[i].isa_drq != -1 ) || ( SMC37c669_drq_table[i].device_drq != -1 ); i++ ) {
2322	    if ( drq == SMC37c669_drq_table[i].isa_drq ) {
2323	    	translated_drq = SMC37c669_drq_table[i].device_drq;
2324		break;
2325	    }
2326	}
2327    }
2328    return translated_drq;
2329}
2330
2331#if 0
2332int __init smcc669_init ( void )
2333{
2334    struct INODE *ip;
2335
2336    allocinode( smc_ddb.name, 1, &ip );
2337    ip->dva = &smc_ddb;
2338    ip->attr = ATTR$M_WRITE | ATTR$M_READ;
2339    ip->len[0] = 0x30;
2340    ip->misc = 0;
2341    INODE_UNLOCK( ip );
2342
2343    return msg_success;
2344}
2345
2346int __init smcc669_open( struct FILE *fp, char *info, char *next, char *mode )
2347{
2348    struct INODE *ip;
2349/*
2350** Allow multiple readers but only one writer.  ip->misc keeps track
2351** of the number of writers
2352*/
2353    ip = fp->ip;
2354    INODE_LOCK( ip );
2355    if ( fp->mode & ATTR$M_WRITE ) {
2356	if ( ip->misc ) {
2357	    INODE_UNLOCK( ip );
2358	    return msg_failure;	    /* too many writers */
2359	}
2360	ip->misc++;
2361    }
2362/*
2363** Treat the information field as a byte offset
2364*/
2365    *fp->offset = xtoi( info );
2366    INODE_UNLOCK( ip );
2367
2368    return msg_success;
2369}
2370
2371int __init smcc669_close( struct FILE *fp )
2372{
2373    struct INODE *ip;
2374
2375    ip = fp->ip;
2376    if ( fp->mode & ATTR$M_WRITE ) {
2377	INODE_LOCK( ip );
2378	ip->misc--;
2379	INODE_UNLOCK( ip );
2380    }
2381    return msg_success;
2382}
2383
2384int __init smcc669_read( struct FILE *fp, int size, int number, unsigned char *buf )
2385{
2386    int i;
2387    int length;
2388    int nbytes;
2389    struct INODE *ip;
2390
2391/*
2392** Always access a byte at a time
2393*/
2394    ip = fp->ip;
2395    length = size * number;
2396    nbytes = 0;
2397
2398    SMC37c669_config_mode( TRUE );
2399    for ( i = 0; i < length; i++ ) {
2400	if ( !inrange( *fp->offset, 0, ip->len[0] ) )
2401	    break;
2402	*buf++ = SMC37c669_read_config( *fp->offset );
2403	*fp->offset += 1;
2404	nbytes++;
2405    }
2406    SMC37c669_config_mode( FALSE );
2407    return nbytes;
2408}
2409
2410int __init smcc669_write( struct FILE *fp, int size, int number, unsigned char *buf )
2411{
2412    int i;
2413    int length;
2414    int nbytes;
2415    struct INODE *ip;
2416/*
2417** Always access a byte at a time
2418*/
2419    ip = fp->ip;
2420    length = size * number;
2421    nbytes = 0;
2422
2423    SMC37c669_config_mode( TRUE );
2424    for ( i = 0; i < length; i++ ) {
2425	if ( !inrange( *fp->offset, 0, ip->len[0] ) )
2426	    break;
2427	SMC37c669_write_config( *fp->offset, *buf );
2428	*fp->offset += 1;
2429	buf++;
2430	nbytes++;
2431    }
2432    SMC37c669_config_mode( FALSE );
2433    return nbytes;
2434}
2435#endif
2436
2437void __init
2438SMC37c669_dump_registers(void)
2439{
2440  int i;
2441  for (i = 0; i <= 0x29; i++)
2442    printk("-- CR%02x : %02x\n", i, SMC37c669_read_config(i));
2443}
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 */
2471void __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