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