linux-old/arch/i386/kernel/mca.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/i386/kernel/mca.c
   3 *  Written by Martin Kolinek, February 1996
   4 *
   5 * Changes:
   6 *
   7 *      Chris Beauregard July 28th, 1996
   8 *      - Fixed up integrated SCSI detection
   9 *
  10 *      Chris Beauregard August 3rd, 1996
  11 *      - Made mca_info local
  12 *      - Made integrated registers accessible through standard function calls
  13 *      - Added name field
  14 *      - More sanity checking
  15 *
  16 *      Chris Beauregard August 9th, 1996
  17 *      - Rewrote /proc/mca
  18 *
  19 *      Chris Beauregard January 7th, 1997
  20 *      - Added basic NMI-processing
  21 *      - Added more information to mca_info structure
  22 *
  23 *      David Weinehall October 12th, 1998
  24 *      - Made a lot of cleaning up in the source
  25 *      - Added use of save_flags / restore_flags
  26 *      - Added the 'driver_loaded' flag in MCA_adapter
  27 *      - Added an alternative implemention of ZP Gu's mca_find_unused_adapter
  28 *
  29 *      David Weinehall March 24th, 1999
  30 *      - Fixed the output of 'Driver Installed' in /proc/mca/pos
  31 *      - Made the Integrated Video & SCSI show up even if they have id 0000
  32 *
  33 *      Alexander Viro November 9th, 1999
  34 *      - Switched to regular procfs methods
  35 *
  36 *      Alfred Arnold & David Weinehall August 23rd, 2000
  37 *      - Added support for Planar POS-registers
  38 */
  39
  40#include <linux/module.h>
  41#include <linux/types.h>
  42#include <linux/errno.h>
  43#include <linux/kernel.h>
  44#include <linux/mca.h>
  45#include <asm/system.h>
  46#include <asm/io.h>
  47#include <linux/proc_fs.h>
  48#include <linux/mman.h>
  49#include <linux/config.h>
  50#include <linux/mm.h>
  51#include <linux/pagemap.h>
  52#include <linux/ioport.h>
  53#include <asm/uaccess.h>
  54#include <linux/init.h>
  55
  56/* This structure holds MCA information. Each (plug-in) adapter has
  57 * eight POS registers. Then the machine may have integrated video and
  58 * SCSI subsystems, which also have eight POS registers.
  59 * Finally, the motherboard (planar) has got POS-registers.
  60 * Other miscellaneous information follows.
  61 */
  62
  63typedef enum {
  64        MCA_ADAPTER_NORMAL = 0,
  65        MCA_ADAPTER_NONE = 1,
  66        MCA_ADAPTER_DISABLED = 2,
  67        MCA_ADAPTER_ERROR = 3
  68} MCA_AdapterStatus;
  69
  70struct MCA_adapter {
  71        MCA_AdapterStatus status;       /* is there a valid adapter? */
  72        int id;                         /* adapter id value */
  73        unsigned char pos[8];           /* POS registers */
  74        int driver_loaded;              /* is there a driver installed? */
  75                                        /* 0 - No, 1 - Yes */
  76        char name[48];                  /* adapter-name provided by driver */
  77        char procname[8];               /* name of /proc/mca file */
  78        MCA_ProcFn procfn;              /* /proc info callback */
  79        void* dev;                      /* device/context info for callback */
  80};
  81
  82struct MCA_info {
  83        /* one for each of the 8 possible slots, plus one for integrated SCSI
  84         * and one for integrated video.
  85         */
  86
  87        struct MCA_adapter slot[MCA_NUMADAPTERS];
  88
  89        /* two potential addresses for integrated SCSI adapter - this will
  90         * track which one we think it is.
  91         */
  92
  93        unsigned char which_scsi;
  94};
  95
  96/* The mca_info structure pointer. If MCA bus is present, the function
  97 * mca_probe() is invoked. The function puts motherboard, then all
  98 * adapters into setup mode, allocates and fills an MCA_info structure,
  99 * and points this pointer to the structure. Otherwise the pointer
 100 * is set to zero.
 101 */
 102
 103static struct MCA_info* mca_info = NULL;
 104
 105/* MCA registers */
 106
 107#define MCA_MOTHERBOARD_SETUP_REG       0x94
 108#define MCA_ADAPTER_SETUP_REG           0x96
 109#define MCA_POS_REG(n)                  (0x100+(n))
 110
 111#define MCA_ENABLED     0x01    /* POS 2, set if adapter enabled */
 112
 113/*--------------------------------------------------------------------*/
 114
 115#ifdef CONFIG_PROC_FS
 116static void mca_do_proc_init(void);
 117#endif
 118
 119/*--------------------------------------------------------------------*/
 120
 121/* Build the status info for the adapter */
 122
 123static void mca_configure_adapter_status(int slot) {
 124        mca_info->slot[slot].status = MCA_ADAPTER_NONE;
 125
 126        mca_info->slot[slot].id = mca_info->slot[slot].pos[0]
 127                + (mca_info->slot[slot].pos[1] << 8);
 128
 129        if(!mca_info->slot[slot].id && slot < MCA_MAX_SLOT_NR) {
 130
 131                /* id = 0x0000 usually indicates hardware failure,
 132                 * however, ZP Gu (zpg@castle.net> reports that his 9556
 133                 * has 0x0000 as id and everything still works. There
 134                 * also seem to be an adapter with id = 0x0000; the
 135                 * NCR Parallel Bus Memory Card. Until this is confirmed,
 136                 * however, this code will stay.
 137                 */
 138
 139                mca_info->slot[slot].status = MCA_ADAPTER_ERROR;
 140
 141                return;
 142        } else if(mca_info->slot[slot].id != 0xffff) {
 143
 144                /* 0xffff usually indicates that there's no adapter,
 145                 * however, some integrated adapters may have 0xffff as
 146                 * their id and still be valid. Examples are on-board
 147                 * VGA of the 55sx, the integrated SCSI of the 56 & 57,
 148                 * and possibly also the 95 ULTIMEDIA.
 149                 */
 150
 151                mca_info->slot[slot].status = MCA_ADAPTER_NORMAL;
 152        }
 153
 154        if((mca_info->slot[slot].id == 0xffff ||
 155           mca_info->slot[slot].id == 0x0000) && slot >= MCA_MAX_SLOT_NR) {
 156                int j;
 157
 158                for(j = 2; j < 8; j++) {
 159                        if(mca_info->slot[slot].pos[j] != 0xff) {
 160                                mca_info->slot[slot].status = MCA_ADAPTER_NORMAL;
 161                                break;
 162                        }
 163                }
 164        }
 165
 166        if(!(mca_info->slot[slot].pos[2] & MCA_ENABLED)) {
 167
 168                /* enabled bit is in POS 2 */
 169
 170                mca_info->slot[slot].status = MCA_ADAPTER_DISABLED;
 171        }
 172} /* mca_configure_adapter_status */
 173
 174/*--------------------------------------------------------------------*/
 175
 176struct resource mca_standard_resources[] = {
 177        { "system control port B (MCA)", 0x60, 0x60 },
 178        { "arbitration (MCA)", 0x90, 0x90 },
 179        { "card Select Feedback (MCA)", 0x91, 0x91 },
 180        { "system Control port A (MCA)", 0x92, 0x92 },
 181        { "system board setup (MCA)", 0x94, 0x94 },
 182        { "POS (MCA)", 0x96, 0x97 },
 183        { "POS (MCA)", 0x100, 0x107 }
 184};
 185
 186#define MCA_STANDARD_RESOURCES  (sizeof(mca_standard_resources)/sizeof(struct resource))
 187
 188void __init mca_init(void)
 189{
 190        unsigned int i, j;
 191        unsigned long flags;
 192
 193        /* WARNING: Be careful when making changes here. Putting an adapter
 194         * and the motherboard simultaneously into setup mode may result in
 195         * damage to chips (according to The Indispensible PC Hardware Book
 196         * by Hans-Peter Messmer). Also, we disable system interrupts (so
 197         * that we are not disturbed in the middle of this).
 198         */
 199
 200        /* Make sure the MCA bus is present */
 201
 202        if(!MCA_bus)
 203                return;
 204        printk("Micro Channel bus detected.\n");
 205
 206        /* Allocate MCA_info structure (at address divisible by 8) */
 207
 208        mca_info = (struct MCA_info *)kmalloc(sizeof(struct MCA_info), GFP_KERNEL);
 209
 210        if(mca_info == NULL) {
 211                printk("Failed to allocate memory for mca_info!");
 212                return;
 213        }
 214        memset(mca_info, 0, sizeof(struct MCA_info));
 215
 216        save_flags(flags);
 217        cli();
 218
 219        /* Make sure adapter setup is off */
 220
 221        outb_p(0, MCA_ADAPTER_SETUP_REG);
 222
 223        /* Read motherboard POS registers */
 224
 225        outb_p(0x7f, MCA_MOTHERBOARD_SETUP_REG);
 226        mca_info->slot[MCA_MOTHERBOARD].name[0] = 0;
 227        for(j=0; j<8; j++) {
 228                mca_info->slot[MCA_MOTHERBOARD].pos[j] = inb_p(MCA_POS_REG(j));
 229        }
 230        mca_configure_adapter_status(MCA_MOTHERBOARD);
 231
 232        /* Put motherboard into video setup mode, read integrated video
 233         * POS registers, and turn motherboard setup off.
 234         */
 235
 236        outb_p(0xdf, MCA_MOTHERBOARD_SETUP_REG);
 237        mca_info->slot[MCA_INTEGVIDEO].name[0] = 0;
 238        for(j=0; j<8; j++) {
 239                mca_info->slot[MCA_INTEGVIDEO].pos[j] = inb_p(MCA_POS_REG(j));
 240        }
 241        mca_configure_adapter_status(MCA_INTEGVIDEO);
 242
 243        /* Put motherboard into scsi setup mode, read integrated scsi
 244         * POS registers, and turn motherboard setup off.
 245         *
 246         * It seems there are two possible SCSI registers. Martin says that
 247         * for the 56,57, 0xf7 is the one, but fails on the 76.
 248         * Alfredo (apena@vnet.ibm.com) says
 249         * 0xfd works on his machine. We'll try both of them. I figure it's
 250         * a good bet that only one could be valid at a time. This could
 251         * screw up though if one is used for something else on the other
 252         * machine.
 253         */
 254
 255        outb_p(0xf7, MCA_MOTHERBOARD_SETUP_REG);
 256        mca_info->slot[MCA_INTEGSCSI].name[0] = 0;
 257        for(j=0; j<8; j++) {
 258                if((mca_info->slot[MCA_INTEGSCSI].pos[j] = inb_p(MCA_POS_REG(j))) != 0xff)
 259                {
 260                        /* 0xff all across means no device. 0x00 means
 261                         * something's broken, but a device is probably there.
 262                         * However, if you get 0x00 from a motherboard
 263                         * register it won't matter what we find.  For the
 264                         * record, on the 57SLC, the integrated SCSI
 265                         * adapter has 0xffff for the adapter ID, but
 266                         * nonzero for other registers.
 267                         */
 268
 269                        mca_info->which_scsi = 0xf7;
 270                }
 271        }
 272        if(!mca_info->which_scsi) {
 273
 274                /* Didn't find it at 0xf7, try somewhere else... */
 275                mca_info->which_scsi = 0xfd;
 276
 277                outb_p(0xfd, MCA_MOTHERBOARD_SETUP_REG);
 278                for(j=0; j<8; j++)
 279                        mca_info->slot[MCA_INTEGSCSI].pos[j] = inb_p(MCA_POS_REG(j));
 280        }
 281        mca_configure_adapter_status(MCA_INTEGSCSI);
 282
 283        /* Turn off motherboard setup */
 284
 285        outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
 286
 287        /* Now loop over MCA slots: put each adapter into setup mode, and
 288         * read its POS registers. Then put adapter setup off.
 289         */
 290
 291        for(i=0; i<MCA_MAX_SLOT_NR; i++) {
 292                outb_p(0x8|(i&0xf), MCA_ADAPTER_SETUP_REG);
 293                for(j=0; j<8; j++) {
 294                        mca_info->slot[i].pos[j]=inb_p(MCA_POS_REG(j));
 295                }
 296                mca_info->slot[i].name[0] = 0;
 297                mca_info->slot[i].driver_loaded = 0;
 298                mca_configure_adapter_status(i);
 299        }
 300        outb_p(0, MCA_ADAPTER_SETUP_REG);
 301
 302        /* Enable interrupts and return memory start */
 303
 304        restore_flags(flags);
 305
 306        for (i = 0; i < MCA_STANDARD_RESOURCES; i++)
 307                request_resource(&ioport_resource, mca_standard_resources + i);
 308
 309#ifdef CONFIG_PROC_FS
 310        mca_do_proc_init();
 311#endif
 312}
 313
 314/*--------------------------------------------------------------------*/
 315
 316static void mca_handle_nmi_slot(int slot, int check_flag)
 317{
 318        if(slot < MCA_MAX_SLOT_NR) {
 319                printk("NMI: caused by MCA adapter in slot %d (%s)\n", slot+1,
 320                        mca_info->slot[slot].name);
 321        } else if(slot == MCA_INTEGSCSI) {
 322                printk("NMI: caused by MCA integrated SCSI adapter (%s)\n",
 323                        mca_info->slot[slot].name);
 324        } else if(slot == MCA_INTEGVIDEO) {
 325                printk("NMI: caused by MCA integrated video adapter (%s)\n",
 326                        mca_info->slot[slot].name);
 327        } else if(slot == MCA_MOTHERBOARD) {
 328                printk("NMI: caused by motherboard (%s)\n",
 329                        mca_info->slot[slot].name);
 330        }
 331
 332        /* More info available in POS 6 and 7? */
 333
 334        if(check_flag) {
 335                unsigned char pos6, pos7;
 336
 337                pos6 = mca_read_pos(slot, 6);
 338                pos7 = mca_read_pos(slot, 7);
 339
 340                printk("NMI: POS 6 = 0x%x, POS 7 = 0x%x\n", pos6, pos7);
 341        }
 342
 343} /* mca_handle_nmi_slot */
 344
 345/*--------------------------------------------------------------------*/
 346
 347void mca_handle_nmi(void)
 348{
 349
 350        int i;
 351        unsigned char pos5;
 352
 353        /* First try - scan the various adapters and see if a specific
 354         * adapter was responsible for the error.
 355         */
 356
 357        for(i = 0; i < MCA_NUMADAPTERS; i++) {
 358
 359        /* Bit 7 of POS 5 is reset when this adapter has a hardware
 360         * error. Bit 7 it reset if there's error information
 361         * available in POS 6 and 7.
 362         */
 363
 364        pos5 = mca_read_pos(i, 5);
 365
 366        if(!(pos5 & 0x80)) {
 367                        mca_handle_nmi_slot(i, !(pos5 & 0x40));
 368                        return;
 369                }
 370        }
 371
 372        /* If I recall correctly, there's a whole bunch of other things that
 373         * we can do to check for NMI problems, but that's all I know about
 374         * at the moment.
 375         */
 376
 377        printk("NMI generated from unknown source!\n");
 378} /* mca_handle_nmi */
 379
 380/*--------------------------------------------------------------------*/
 381
 382/**
 383 *      mca_find_adapter - scan for adapters
 384 *      @id:    MCA identification to search for
 385 *      @start: starting slot
 386 *
 387 *      Search the MCA configuration for adapters matching the 16bit
 388 *      ID given. The first time it should be called with start as zero
 389 *      and then further calls made passing the return value of the
 390 *      previous call until %MCA_NOTFOUND is returned.
 391 *
 392 *      Disabled adapters are not reported.
 393 */
 394
 395int mca_find_adapter(int id, int start)
 396{
 397        if(mca_info == NULL || id == 0xffff) {
 398                return MCA_NOTFOUND;
 399        }
 400
 401        for(; start >= 0 && start < MCA_NUMADAPTERS; start++) {
 402
 403                /* Not sure about this. There's no point in returning
 404                 * adapters that aren't enabled, since they can't actually
 405                 * be used. However, they might be needed for statistical
 406                 * purposes or something... But if that is the case, the
 407                 * user is free to write a routine that manually iterates
 408                 * through the adapters.
 409                 */
 410
 411                if(mca_info->slot[start].status == MCA_ADAPTER_DISABLED) {
 412                        continue;
 413                }
 414
 415                if(id == mca_info->slot[start].id) {
 416                        return start;
 417                }
 418        }
 419
 420        return MCA_NOTFOUND;
 421} /* mca_find_adapter() */
 422
 423EXPORT_SYMBOL(mca_find_adapter);
 424
 425/*--------------------------------------------------------------------*/
 426
 427/**
 428 *      mca_find_unused_adapter - scan for unused adapters
 429 *      @id:    MCA identification to search for
 430 *      @start: starting slot
 431 *
 432 *      Search the MCA configuration for adapters matching the 16bit
 433 *      ID given. The first time it should be called with start as zero
 434 *      and then further calls made passing the return value of the
 435 *      previous call until %MCA_NOTFOUND is returned.
 436 *
 437 *      Adapters that have been claimed by drivers and those that
 438 *      are disabled are not reported. This function thus allows a driver
 439 *      to scan for further cards when some may already be driven.
 440 */
 441
 442int mca_find_unused_adapter(int id, int start)
 443{
 444        if(mca_info == NULL || id == 0xffff) {
 445                return MCA_NOTFOUND;
 446        }
 447
 448        for(; start >= 0 && start < MCA_NUMADAPTERS; start++) {
 449
 450                /* not sure about this. There's no point in returning
 451                 * adapters that aren't enabled, since they can't actually
 452                 * be used. However, they might be needed for statistical
 453                 * purposes or something... But if that is the case, the
 454                 * user is free to write a routine that manually iterates
 455                 * through the adapters.
 456                 */
 457
 458                if(mca_info->slot[start].status == MCA_ADAPTER_DISABLED ||
 459                   mca_info->slot[start].driver_loaded) {
 460                        continue;
 461                }
 462
 463                if(id == mca_info->slot[start].id) {
 464                        return start;
 465                }
 466        }
 467
 468        return MCA_NOTFOUND;
 469} /* mca_find_unused_adapter() */
 470
 471EXPORT_SYMBOL(mca_find_unused_adapter);
 472
 473/*--------------------------------------------------------------------*/
 474
 475/**
 476 *      mca_read_stored_pos - read POS register from boot data
 477 *      @slot: slot number to read from
 478 *      @reg:  register to read from
 479 *
 480 *      Fetch a POS value that was stored at boot time by the kernel
 481 *      when it scanned the MCA space. The register value is returned.
 482 *      Missing or invalid registers report 0.
 483 */
 484
 485unsigned char mca_read_stored_pos(int slot, int reg)
 486{
 487        if(slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == NULL) return 0;
 488        if(reg < 0 || reg >= 8) return 0;
 489        return mca_info->slot[slot].pos[reg];
 490} /* mca_read_stored_pos() */
 491
 492EXPORT_SYMBOL(mca_read_stored_pos);
 493
 494/*--------------------------------------------------------------------*/
 495
 496/**
 497 *      mca_read_pos - read POS register from card
 498 *      @slot: slot number to read from
 499 *      @reg:  register to read from
 500 *
 501 *      Fetch a POS value directly from the hardware to obtain the
 502 *      current value. This is much slower than mca_read_stored_pos and
 503 *      may not be invoked from interrupt context. It handles the
 504 *      deep magic required for onboard devices transparently.
 505 */
 506
 507unsigned char mca_read_pos(int slot, int reg)
 508{
 509        unsigned int byte = 0;
 510        unsigned long flags;
 511
 512        if(slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == NULL) return 0;
 513        if(reg < 0 || reg >= 8) return 0;
 514
 515        save_flags(flags);
 516        cli();
 517
 518        /* Make sure motherboard setup is off */
 519
 520        outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
 521
 522        /* Read in the appropriate register */
 523
 524        if(slot == MCA_INTEGSCSI && mca_info->which_scsi) {
 525
 526                /* Disable adapter setup, enable motherboard setup */
 527
 528                outb_p(0, MCA_ADAPTER_SETUP_REG);
 529                outb_p(mca_info->which_scsi, MCA_MOTHERBOARD_SETUP_REG);
 530
 531                byte = inb_p(MCA_POS_REG(reg));
 532                outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
 533        } else if(slot == MCA_INTEGVIDEO) {
 534
 535                /* Disable adapter setup, enable motherboard setup */
 536
 537                outb_p(0, MCA_ADAPTER_SETUP_REG);
 538                outb_p(0xdf, MCA_MOTHERBOARD_SETUP_REG);
 539
 540                byte = inb_p(MCA_POS_REG(reg));
 541                outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
 542        } else if(slot == MCA_MOTHERBOARD) {
 543
 544                /* Disable adapter setup, enable motherboard setup */
 545                outb_p(0, MCA_ADAPTER_SETUP_REG);
 546                outb_p(0x7f, MCA_MOTHERBOARD_SETUP_REG);
 547
 548                byte = inb_p(MCA_POS_REG(reg));
 549                outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
 550        } else if(slot < MCA_MAX_SLOT_NR) {
 551
 552                /* Make sure motherboard setup is off */
 553
 554                outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
 555
 556                /* Read the appropriate register */
 557
 558                outb_p(0x8|(slot&0xf), MCA_ADAPTER_SETUP_REG);
 559                byte = inb_p(MCA_POS_REG(reg));
 560                outb_p(0, MCA_ADAPTER_SETUP_REG);
 561        }
 562
 563        /* Make sure the stored values are consistent, while we're here */
 564
 565        mca_info->slot[slot].pos[reg] = byte;
 566
 567        restore_flags(flags);
 568
 569        return byte;
 570} /* mca_read_pos() */
 571
 572EXPORT_SYMBOL(mca_read_pos);
 573
 574/*--------------------------------------------------------------------*/
 575
 576/**
 577 *      mca_write_pos - read POS register from card
 578 *      @slot: slot number to read from
 579 *      @reg:  register to read from
 580 *      @byte: byte to write to the POS registers
 581 *
 582 *      Store a POS value directly from the hardware. You should not
 583 *      normally need to use this function and should have a very good
 584 *      knowledge of MCA bus before you do so. Doing this wrongly can
 585 *      damage the hardware.
 586 *
 587 *      This function may not be used from interrupt context.
 588 *
 589 *      Note that this a technically a Bad Thing, as IBM tech stuff says
 590 *      you should only set POS values through their utilities.
 591 *      However, some devices such as the 3c523 recommend that you write
 592 *      back some data to make sure the configuration is consistent.
 593 *      I'd say that IBM is right, but I like my drivers to work.
 594 *
 595 *      This function can't do checks to see if multiple devices end up
 596 *      with the same resources, so you might see magic smoke if someone
 597 *      screws up.
 598 */
 599
 600void mca_write_pos(int slot, int reg, unsigned char byte)
 601{
 602        unsigned long flags;
 603
 604        if(slot < 0 || slot >= MCA_MAX_SLOT_NR)
 605                return;
 606        if(reg < 0 || reg >= 8)
 607                return;
 608        if(mca_info == NULL)
 609                return;
 610
 611        save_flags(flags);
 612        cli();
 613
 614        /* Make sure motherboard setup is off */
 615
 616        outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
 617
 618        /* Read in the appropriate register */
 619
 620        outb_p(0x8|(slot&0xf), MCA_ADAPTER_SETUP_REG);
 621        outb_p(byte, MCA_POS_REG(reg));
 622        outb_p(0, MCA_ADAPTER_SETUP_REG);
 623
 624        restore_flags(flags);
 625
 626        /* Update the global register list, while we have the byte */
 627
 628        mca_info->slot[slot].pos[reg] = byte;
 629} /* mca_write_pos() */
 630
 631EXPORT_SYMBOL(mca_write_pos);
 632
 633/*--------------------------------------------------------------------*/
 634
 635/**
 636 *      mca_set_adapter_name - Set the description of the card
 637 *      @slot: slot to name
 638 *      @name: text string for the namen
 639 *
 640 *      This function sets the name reported via /proc for this
 641 *      adapter slot. This is for user information only. Setting a
 642 *      name deletes any previous name.
 643 */
 644
 645void mca_set_adapter_name(int slot, char* name)
 646{
 647        if(mca_info == NULL) return;
 648
 649        if(slot >= 0 && slot < MCA_NUMADAPTERS) {
 650                if(name != NULL) {
 651                        strncpy(mca_info->slot[slot].name, name,
 652                                sizeof(mca_info->slot[slot].name)-1);
 653                        mca_info->slot[slot].name[
 654                                sizeof(mca_info->slot[slot].name)-1] = 0;
 655                } else {
 656                        mca_info->slot[slot].name[0] = 0;
 657                }
 658        }
 659}
 660
 661EXPORT_SYMBOL(mca_set_adapter_name);
 662
 663/**
 664 *      mca_set_adapter_procfn - Set the /proc callback
 665 *      @slot: slot to configure
 666 *      @procfn: callback function to call for /proc
 667 *      @dev: device information passed to the callback
 668 *
 669 *      This sets up an information callback for /proc/mca/slot?.  The
 670 *      function is called with the buffer, slot, and device pointer (or
 671 *      some equally informative context information, or nothing, if you
 672 *      prefer), and is expected to put useful information into the
 673 *      buffer.  The adapter name, ID, and POS registers get printed
 674 *      before this is called though, so don't do it again.
 675 *
 676 *      This should be called with a %NULL @procfn when a module
 677 *      unregisters, thus preventing kernel crashes and other such
 678 *      nastiness.
 679 */
 680
 681void mca_set_adapter_procfn(int slot, MCA_ProcFn procfn, void* dev)
 682{
 683        if(mca_info == NULL) return;
 684
 685        if(slot >= 0 && slot < MCA_NUMADAPTERS) {
 686                mca_info->slot[slot].procfn = procfn;
 687                mca_info->slot[slot].dev = dev;
 688        }
 689}
 690
 691EXPORT_SYMBOL(mca_set_adapter_procfn);
 692
 693/**
 694 *      mca_is_adapter_used - check if claimed by driver
 695 *      @slot:  slot to check
 696 *
 697 *      Returns 1 if the slot has been claimed by a driver
 698 */
 699
 700int mca_is_adapter_used(int slot)
 701{
 702        return mca_info->slot[slot].driver_loaded;
 703}
 704
 705EXPORT_SYMBOL(mca_is_adapter_used);
 706
 707/**
 708 *      mca_mark_as_used - claim an MCA device
 709 *      @slot:  slot to claim
 710 *      FIXME:  should we make this threadsafe
 711 *
 712 *      Claim an MCA slot for a device driver. If the
 713 *      slot is already taken the function returns 1,
 714 *      if it is not taken it is claimed and 0 is
 715 *      returned.
 716 */
 717
 718int mca_mark_as_used(int slot)
 719{
 720        if(mca_info->slot[slot].driver_loaded) return 1;
 721        mca_info->slot[slot].driver_loaded = 1;
 722        return 0;
 723}
 724
 725EXPORT_SYMBOL(mca_mark_as_used);
 726
 727/**
 728 *      mca_mark_as_unused - release an MCA device
 729 *      @slot:  slot to claim
 730 *
 731 *      Release the slot for other drives to use.
 732 */
 733
 734void mca_mark_as_unused(int slot)
 735{
 736        mca_info->slot[slot].driver_loaded = 0;
 737}
 738
 739EXPORT_SYMBOL(mca_mark_as_unused);
 740
 741/**
 742 *      mca_get_adapter_name - get the adapter description
 743 *      @slot:  slot to query
 744 *
 745 *      Return the adapter description if set. If it has not been
 746 *      set or the slot is out range then return NULL.
 747 */
 748
 749char *mca_get_adapter_name(int slot)
 750{
 751        if(mca_info == NULL) return 0;
 752
 753        if(slot >= 0 && slot < MCA_NUMADAPTERS) {
 754                return mca_info->slot[slot].name;
 755        }
 756
 757        return 0;
 758}
 759
 760EXPORT_SYMBOL(mca_get_adapter_name);
 761
 762/**
 763 *      mca_isadapter - check if the slot holds an adapter
 764 *      @slot:  slot to query
 765 *
 766 *      Returns zero if the slot does not hold an adapter, non zero if
 767 *      it does.
 768 */
 769
 770int mca_isadapter(int slot)
 771{
 772        if(mca_info == NULL) return 0;
 773
 774        if(slot >= 0 && slot < MCA_NUMADAPTERS) {
 775                return ((mca_info->slot[slot].status == MCA_ADAPTER_NORMAL)
 776                        || (mca_info->slot[slot].status == MCA_ADAPTER_DISABLED));
 777        }
 778
 779        return 0;
 780}
 781
 782EXPORT_SYMBOL(mca_isadapter);
 783
 784
 785/**
 786 *      mca_isadapter - check if the slot holds an adapter
 787 *      @slot:  slot to query
 788 *
 789 *      Returns a non zero value if the slot holds an enabled adapter
 790 *      and zero for any other case.
 791 */
 792
 793int mca_isenabled(int slot)
 794{
 795        if(mca_info == NULL) return 0;
 796
 797        if(slot >= 0 && slot < MCA_NUMADAPTERS) {
 798                return (mca_info->slot[slot].status == MCA_ADAPTER_NORMAL);
 799        }
 800
 801        return 0;
 802}
 803
 804EXPORT_SYMBOL(mca_isenabled);
 805
 806/*--------------------------------------------------------------------*/
 807
 808#ifdef CONFIG_PROC_FS
 809
 810int get_mca_info(char *page, char **start, off_t off,
 811                                 int count, int *eof, void *data)
 812{
 813        int i, j, len = 0;
 814
 815        if(MCA_bus && mca_info != NULL) {
 816                /* Format POS registers of eight MCA slots */
 817
 818                for(i=0; i<MCA_MAX_SLOT_NR; i++) {
 819                        len += sprintf(page+len, "Slot %d: ", i+1);
 820                        for(j=0; j<8; j++)
 821                                len += sprintf(page+len, "%02x ", mca_info->slot[i].pos[j]);
 822                        len += sprintf(page+len, " %s\n", mca_info->slot[i].name);
 823                }
 824
 825                /* Format POS registers of integrated video subsystem */
 826
 827                len += sprintf(page+len, "Video : ");
 828                for(j=0; j<8; j++)
 829                        len += sprintf(page+len, "%02x ", mca_info->slot[MCA_INTEGVIDEO].pos[j]);
 830                len += sprintf(page+len, " %s\n", mca_info->slot[MCA_INTEGVIDEO].name);
 831
 832                /* Format POS registers of integrated SCSI subsystem */
 833
 834                len += sprintf(page+len, "SCSI  : ");
 835                for(j=0; j<8; j++)
 836                        len += sprintf(page+len, "%02x ", mca_info->slot[MCA_INTEGSCSI].pos[j]);
 837                len += sprintf(page+len, " %s\n", mca_info->slot[MCA_INTEGSCSI].name);
 838
 839                /* Format POS registers of motherboard */
 840
 841                len += sprintf(page+len, "Planar: ");
 842                for(j=0; j<8; j++)
 843                        len += sprintf(page+len, "%02x ", mca_info->slot[MCA_MOTHERBOARD].pos[j]);
 844                len += sprintf(page+len, " %s\n", mca_info->slot[MCA_MOTHERBOARD].name);
 845        } else {
 846                /* Leave it empty if MCA not detected - this should *never*
 847                 * happen!
 848                 */
 849        }
 850
 851        if (len <= off+count) *eof = 1;
 852        *start = page + off;
 853        len -= off;
 854        if (len>count) len = count;
 855        if (len<0) len = 0;
 856        return len;
 857}
 858
 859/*--------------------------------------------------------------------*/
 860
 861static int mca_default_procfn(char* buf, struct MCA_adapter *p)
 862{
 863        int len = 0, i;
 864        int slot = p - mca_info->slot;
 865
 866        /* Print out the basic information */
 867
 868        if(slot < MCA_MAX_SLOT_NR) {
 869                len += sprintf(buf+len, "Slot: %d\n", slot+1);
 870        } else if(slot == MCA_INTEGSCSI) {
 871                len += sprintf(buf+len, "Integrated SCSI Adapter\n");
 872        } else if(slot == MCA_INTEGVIDEO) {
 873                len += sprintf(buf+len, "Integrated Video Adapter\n");
 874        } else if(slot == MCA_MOTHERBOARD) {
 875                len += sprintf(buf+len, "Motherboard\n");
 876        }
 877        if(p->name[0]) {
 878
 879                /* Drivers might register a name without /proc handler... */
 880
 881                len += sprintf(buf+len, "Adapter Name: %s\n",
 882                        p->name);
 883        } else {
 884                len += sprintf(buf+len, "Adapter Name: Unknown\n");
 885        }
 886        len += sprintf(buf+len, "Id: %02x%02x\n",
 887                p->pos[1], p->pos[0]);
 888        len += sprintf(buf+len, "Enabled: %s\nPOS: ",
 889                mca_isenabled(slot) ? "Yes" : "No");
 890        for(i=0; i<8; i++) {
 891                len += sprintf(buf+len, "%02x ", p->pos[i]);
 892        }
 893        len += sprintf(buf+len, "\nDriver Installed: %s",
 894                mca_is_adapter_used(slot) ? "Yes" : "No");
 895        buf[len++] = '\n';
 896        buf[len] = 0;
 897
 898        return len;
 899} /* mca_default_procfn() */
 900
 901static int get_mca_machine_info(char* page, char **start, off_t off,
 902                                 int count, int *eof, void *data)
 903{
 904        int len = 0;
 905
 906        len += sprintf(page+len, "Model Id: 0x%x\n", machine_id);
 907        len += sprintf(page+len, "Submodel Id: 0x%x\n", machine_submodel_id);
 908        len += sprintf(page+len, "BIOS Revision: 0x%x\n", BIOS_revision);
 909
 910        if (len <= off+count) *eof = 1;
 911        *start = page + off;
 912        len -= off;
 913        if (len>count) len = count;
 914        if (len<0) len = 0;
 915        return len;
 916}
 917
 918static int mca_read_proc(char *page, char **start, off_t off,
 919                                 int count, int *eof, void *data)
 920{
 921        struct MCA_adapter *p = (struct MCA_adapter *)data;
 922        int len = 0;
 923
 924        /* Get the standard info */
 925
 926        len = mca_default_procfn(page, p);
 927
 928        /* Do any device-specific processing, if there is any */
 929
 930        if(p->procfn) {
 931                len += p->procfn(page+len, p-mca_info->slot, p->dev);
 932        }
 933        if (len <= off+count) *eof = 1;
 934        *start = page + off;
 935        len -= off;
 936        if (len>count) len = count;
 937        if (len<0) len = 0;
 938        return len;
 939} /* mca_read_proc() */
 940
 941/*--------------------------------------------------------------------*/
 942
 943void __init mca_do_proc_init(void)
 944{
 945        int i;
 946        struct proc_dir_entry *proc_mca;
 947        struct proc_dir_entry* node = NULL;
 948        struct MCA_adapter *p;
 949
 950        if(mca_info == NULL) return;    /* Should never happen */
 951
 952        proc_mca = proc_mkdir("mca", &proc_root);
 953        create_proc_read_entry("pos",0,proc_mca,get_mca_info,NULL);
 954        create_proc_read_entry("machine",0,proc_mca,get_mca_machine_info,NULL);
 955
 956        /* Initialize /proc/mca entries for existing adapters */
 957
 958        for(i = 0; i < MCA_NUMADAPTERS; i++) {
 959                p = &mca_info->slot[i];
 960                p->procfn = 0;
 961
 962                if(i < MCA_MAX_SLOT_NR) sprintf(p->procname,"slot%d", i+1);
 963                else if(i == MCA_INTEGVIDEO) sprintf(p->procname,"video");
 964                else if(i == MCA_INTEGSCSI) sprintf(p->procname,"scsi");
 965                else if(i == MCA_MOTHERBOARD) sprintf(p->procname,"planar");
 966
 967                if(!mca_isadapter(i)) continue;
 968
 969                node = create_proc_read_entry(p->procname, 0, proc_mca,
 970                                                mca_read_proc, (void *)p);
 971
 972                if(node == NULL) {
 973                        printk("Failed to allocate memory for MCA proc-entries!");
 974                        return;
 975                }
 976        }
 977
 978} /* mca_do_proc_init() */
 979
 980#endif
 981
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.