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