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