pnp.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 651 行 · 第 1/2 页

C
651
字号
/* * Copyright (c) 1996, Sujal M. Patel * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *      $Id: pnp.c,v 1.9 1999/01/14 06:22:07 jdp Exp $ */#include <sys/param.h>#include <sys/systm.h>#include <sys/linker_set.h>#include <sys/malloc.h>#include <sys/interrupt.h>#include <machine/clock.h>#include <machine/md_var.h>#include <i386/isa/icu.h>#include <i386/isa/isa_device.h>#include <i386/isa/pnp.h>typedef struct _pnp_id {	u_long vendor_id;	u_long serial;	u_char checksum;	u_long comp_id;} pnp_id;static int num_pnp_cards = 0;pnp_id pnp_devices[MAX_PNP_CARDS];struct pnp_dlist_node *pnp_device_list;static struct pnp_dlist_node **pnp_device_list_last_ptr;/* * these entries are initialized using the autoconfig menu * The struct is invalid (and must be initialized) if the first * CSN is zero. The init code fills invalid entries with CSN 255 * which is not a supported value. */struct pnp_cinfo pnp_ldn_overrides[MAX_PNP_LDN] = { { 0 } };/* * the following is a flag which tells if the data is valid. */static int doing_pnp_probe = 0 ;static int current_csn ;static int current_pnp_id ;static int current_pnp_serial ;/* * the following block is an example on what is needed for * a PnP device driver. */static  char*   nullpnp_probe(u_long csn, u_long vendor_id);static  void    nullpnp_attach(u_long csn, u_long vendor_id, char *name,    struct isa_device *dev);static  u_long	nullpnp_count = 0 ;static struct pnp_device nullpnp_device = {    "goodpnp",    nullpnp_probe,    nullpnp_attach,    &nullpnp_count,    NULL /* imask */};DATA_SET (pnpdevice_set, nullpnp_device);static char*nullpnp_probe(u_long tag, u_long type){    if (bootverbose)	    printf("Called nullpnp_probe with tag 0x%08lx, type 0x%08lx\n",		    tag, type);    return NULL;}static voidnullpnp_attach(u_long csn, u_long vend_id, char *name,	struct isa_device *dev){    printf("nullpnp_attach: csn %ld, vend_id 0x%08lx name %s unit %d\n",	    csn, vend_id, name, dev->id_unit);    return;}/* The READ_DATA port that we are using currently */static int pnp_rd_port;static void   pnp_send_Initiation_LFSR (void);static int    pnp_get_serial (pnp_id *p);static void   config_pnp_device (pnp_id *p, int csn);static int    pnp_isolation_protocol (void);voidpnp_write(int d, u_char r){    outb (_PNP_ADDRESS, d);    outb (_PNP_WRITE_DATA, r);}u_charpnp_read(int d){    outb (_PNP_ADDRESS, d);    return (inb(3 | (pnp_rd_port <<2)));}/* * Send Initiation LFSR as described in "Plug and Play ISA Specification", * Intel May 94. */static voidpnp_send_Initiation_LFSR(){    int cur, i;    /* Reset the LSFR */    outb(_PNP_ADDRESS, 0);    outb(_PNP_ADDRESS, 0); /* yes, we do need it twice! */    cur = 0x6a;    outb(_PNP_ADDRESS, cur);    for (i = 1; i < 32; i++) {	cur = (cur >> 1) | (((cur ^ (cur >> 1)) << 7) & 0xff);	outb(_PNP_ADDRESS, cur);    }}/* * Get the device's serial number.  Returns 1 if the serial is valid. */static intpnp_get_serial(pnp_id *p){    int i, bit, valid = 0, sum = 0x6a;    u_char *data = (u_char *)p;    bzero(data, sizeof(char) * 9);    outb(_PNP_ADDRESS, SERIAL_ISOLATION);    for (i = 0; i < 72; i++) {	bit = inb((pnp_rd_port << 2) | 0x3) == 0x55;	DELAY(250);	/* Delay 250 usec */	/* Can't Short Circuit the next evaluation, so 'and' is last */	bit = (inb((pnp_rd_port << 2) | 0x3) == 0xaa) && bit;	DELAY(250);	/* Delay 250 usec */	valid = valid || bit;	if (i < 64)	    sum = (sum >> 1) |		(((sum ^ (sum >> 1) ^ bit) << 7) & 0xff);	data[i / 8] = (data[i / 8] >> 1) | (bit ? 0x80 : 0);    }    valid = valid && (data[8] == sum);    return valid;}/* * Fill's the buffer with resource info from the device. * Returns 0 if the device fails to report */static intpnp_get_resource_info(u_char *buffer, int len){    int i, j;    u_char temp;    for (i = 0; i < len; i++) {	outb(_PNP_ADDRESS, STATUS);	for (j = 0; j < 100; j++) {	    if ((inb((pnp_rd_port << 2) | 0x3)) & 0x1)		break;	    DELAY(1);	}	if (j == 100) {	    printf("PnP device failed to report resource data\n");	    return 0;	}	outb(_PNP_ADDRESS, RESOURCE_DATA);	temp = inb((pnp_rd_port << 2) | 0x3);	if (buffer != NULL)	    buffer[i] = temp;    }    return 1;}/* * read_pnp_parms loads pnp parameters from the currently selected * device into the struct pnp_cinfo parameter passed. * The second argument specifies the Logical Device to use. */intread_pnp_parms(struct pnp_cinfo *d, int ldn){    int i ;    if (doing_pnp_probe == 0 || d == NULL)	return 0 ;	/* fail */    bzero(d, sizeof(struct pnp_cinfo));    d->vendor_id = current_pnp_id ;    d->serial = current_pnp_serial ;    d->csn = current_csn ;    d->ldn = ldn ;	/* XXX this should be different ... */    pnp_write (SET_LDN, ldn );    i = pnp_read(SET_LDN) ;    if (i != ldn) {	printf("Warning: LDN %d does not exist\n", ldn);    }    for (i = 0; i < 8; i++) {	d->port[i] = pnp_read(IO_CONFIG_BASE + i * 2) << 8 ;	d->port[i] |= pnp_read(IO_CONFIG_BASE + i * 2 + 1);	if (i < 4) {	    d->mem[i].base = pnp_read (MEM_CONFIG + i*8) << 16 ;	    d->mem[i].base |= pnp_read (MEM_CONFIG + i*8 + 1) << 8 ;	    d->mem[i].control = pnp_read (MEM_CONFIG + i*8 + 2) ;	    d->mem[i].range = pnp_read (MEM_CONFIG + i*8 + 3) << 16 ;	    d->mem[i].range |= pnp_read (MEM_CONFIG + i*8 + 4) << 8 ;	}	if (i < 2) {	    d->irq[i] = pnp_read(IRQ_CONFIG + i * 2);	    d->irq_type[i] = pnp_read(IRQ_CONFIG + 1 + i * 2);	    d->drq[i] = pnp_read(DRQ_CONFIG + i);	}    }    d->enable = pnp_read(ACTIVATE);    for (i = 0 ; i < MAX_PNP_LDN; i++) {	if (pnp_ldn_overrides[i].csn == d->csn &&		pnp_ldn_overrides[i].ldn == ldn) {	    d->flags = pnp_ldn_overrides[i].flags ;	    d->override = pnp_ldn_overrides[i].override ;	    break ;	}    }    if (bootverbose)	printf("port 0x%04x 0x%04x 0x%04x 0x%04x irq %d:%d drq %d:%d en %d\n",	    d->port[0], d->port[1], d->port[2], d->port[3],	    d->irq[0], d->irq[1],	    d->drq[0], d->drq[1],	    d->enable);    return 1 ; /* success */}/* * write_pnp_parms initializes a logical device with the parms * in d, and then activates the board if the last parameter is 1. */intwrite_pnp_parms(struct pnp_cinfo *d, int ldn){    int i, empty = -1 ;    /*     * some safety checks first.     */    if (doing_pnp_probe == 0 || d==NULL || d->vendor_id != current_pnp_id)	return 0 ;	/* fail */    pnp_write (SET_LDN, ldn );    i = pnp_read(SET_LDN) ;    if (i != ldn) {	printf("Warning: LDN %d does not exist\n", ldn);    }    for (i = 0; i < 8; i++) {	pnp_write(IO_CONFIG_BASE + i * 2, d->port[i] >> 8 );	pnp_write(IO_CONFIG_BASE + i * 2 + 1, d->port[i] & 0xff );    }    for (i = 0; i < 4; i++) {	pnp_write(MEM_CONFIG + i*8, (d->mem[i].base >> 16) & 0xff );	pnp_write(MEM_CONFIG + i*8+1, (d->mem[i].base >> 8) & 0xff );	pnp_write(MEM_CONFIG + i*8+2, d->mem[i].control & 0xff );	pnp_write(MEM_CONFIG + i*8+3, (d->mem[i].range >> 16) & 0xff );	pnp_write(MEM_CONFIG + i*8+4, (d->mem[i].range >> 8) & 0xff );    }    for (i = 0; i < 2; i++) {	pnp_write(IRQ_CONFIG + i*2    , d->irq[i] );	pnp_write(IRQ_CONFIG + i*2 + 1, d->irq_type[i] );	pnp_write(DRQ_CONFIG + i, d->drq[i] );    }    /*     * store parameters read into the current kernel     * so manual editing next time is easier     */    for (i = 0 ; i < MAX_PNP_LDN; i++) {	if (pnp_ldn_overrides[i].csn == d->csn &&		pnp_ldn_overrides[i].ldn == ldn) {	    d->flags = pnp_ldn_overrides[i].flags ;	    pnp_ldn_overrides[i] = *d ;	    break ;	} else if (pnp_ldn_overrides[i].csn < 1 ||		pnp_ldn_overrides[i].csn == 255)	    empty = i ;    }    if (i== MAX_PNP_LDN && empty != -1)	pnp_ldn_overrides[empty] = *d;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?