/* pnpmod.c: PnP config manager module */
/*
 * $Header: /root/pnp/module/RCS/pnpmod.c,v 1.5 1996/06/12 18:56:34 root Exp $
 *
 * $Log: pnpmod.c,v $
 * Revision 1.5  1996/06/12  18:56:34  root
 * standard internal i/f & BIOS read/query
 *
 * Revision 1.4  1996/06/09  10:40:34  root
 * card configuration now done
 *
 * Revision 1.3  1996/06/02  14:07:23  root
 * current config read implemented on ISA cards
 *
 * Revision 1.2  1996/05/28  20:37:55  root
 * Read-only index version works
 *
 * Revision 1.1  1996/05/26  15:38:03  root
 * Initial revision
 *
 */

/*
 * (c) Copyright 1996  D.W.Howells <dwh@nexor.co.uk>,
 */

#include <linux/config.h>
#include <linux/module.h>
#ifdef MODULE
#include <linux/version.h>
#endif

#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/ldt.h>
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/bitops.h>
#include "pnp_if.h"

extern int pnp_bios_init(void);
extern int pnp_isa_discover(void);
extern int pnp_isa_read_cards(void);
extern int pnp_dump_all_sysdev(void);

extern struct proc_dir_entry proc_dir_pnp_list, proc_dir_pnpconf;

extern void pnp_inc_mod_usage(void);
extern void pnp_dec_mod_usage(void);
extern int init_pnp_subsystem(void);

/*****************************************************************************/
/* This is required so that we can load attach PnP drivers later */
struct symbol_table pnp_syms = {
/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */
#include <linux/symtab_begin.h>
	X(pnp_register),
	X(pnp_unregister),
#include <linux/symtab_end.h>
};

void pnp_inc_mod_usage() { MOD_INC_USE_COUNT; }
void pnp_dec_mod_usage() { MOD_DEC_USE_COUNT; }

/*****************************************************************************/
int pnp_init(void)
{
    int rt;

    printk("Plug'n'Play configuration manager loading\n");

    if (check_region(PNP_ADDRESS_PORT,1)<0 ||
	check_region(PNP_WRITE_DATA_PORT,1)<0 ||
	check_region(0x267,1)<0)
	return -EBUSY;

    request_region(PNP_ADDRESS_PORT,1,"PnP address");
    request_region(PNP_WRITE_DATA_PORT,1,"PnP write");

    /* try talking to BIOS (success provides us with a read port) */
    if (pnp_bios_init()<0) {
	/* find a read port and see if any cards attached */
	rt = pnp_isa_discover();
	if (rt<0) {
	    /* no PnP BIOS, no cards */
	    release_region(PNP_WRITE_DATA_PORT,1);
	    release_region(PNP_ADDRESS_PORT,1);
	    return rt;
	}
    }

    rt = register_symtab(&pnp_syms);
    if (rt<0)
	return rt;

    printk("ISA cards: readport=%04x\n",pnp_isa_rdport);

    /* reserve the read port */
    request_region(pnp_isa_rdport,1,"PnP read");

    pnp_isa_read_cards();

#ifdef CONFIG_PROC_FS
    proc_register_dynamic(&proc_root,&proc_dir_pnp_list);
    proc_register_dynamic(&proc_root,&proc_dir_pnpconf);
#endif

    printk("Plug'n'Play configuration manager loaded\n");
    return 0;
} /* end init_pnp_subsystem() */

/*****************************************************************************/
#ifdef MODULE
int init_module(void)
{
    return init_pnp_subsystem();
}

void cleanup_module(void)
{
    pnp_card *card;
    pnp_device *device;

    register_symtab(NULL);

#ifdef CONFIG_PROC_FS
    proc_unregister(&proc_root,proc_dir_pnpconf.low_ino);
    proc_unregister(&proc_root,proc_dir_pnp_list.low_ino);
#endif

    while (pnp_card_list) {
	card = pnp_card_list;
	pnp_card_list = card->pc_next;
	if (card->pc_resources)
	    kfree(card->pc_resources);
	kfree(card);
    }

    while (pnp_device_list) {
	device = pnp_device_list;
	pnp_device_list = device->pd_next;
	kfree(device);
    }

    release_region(pnp_isa_rdport,1);
    release_region(PNP_WRITE_DATA_PORT,1);
    release_region(PNP_ADDRESS_PORT,1);
    printk("Plug'n'Play configuration manager unloaded\n");
}
#endif

