summaryrefslogtreecommitdiffstats
path: root/sys/i386/isa/pnp.c
diff options
context:
space:
mode:
authoreivind <eivind@FreeBSD.org>1998-09-13 22:15:44 +0000
committereivind <eivind@FreeBSD.org>1998-09-13 22:15:44 +0000
commit27ef9ec914d81ea0c488146b8253a532ea99c410 (patch)
tree94f52a56aa1d8f7f4c8521e99dfe55bccc26eec3 /sys/i386/isa/pnp.c
parent72ee84b6f2c6d6005ad43fe391bec63340e5aca6 (diff)
downloadFreeBSD-src-27ef9ec914d81ea0c488146b8253a532ea99c410.zip
FreeBSD-src-27ef9ec914d81ea0c488146b8253a532ea99c410.tar.gz
Support PnP compatibility IDs. This allow e.g. the ed driver to pick
up any PnP NE2000 compatible card, instead of forcing us to always update ID lists. Submitted by: Ugo Paternostro <paterno@dsi.unifi.it>
Diffstat (limited to 'sys/i386/isa/pnp.c')
-rw-r--r--sys/i386/isa/pnp.c115
1 files changed, 103 insertions, 12 deletions
diff --git a/sys/i386/isa/pnp.c b/sys/i386/isa/pnp.c
index 3bc63ed..9b4bb55 100644
--- a/sys/i386/isa/pnp.c
+++ b/sys/i386/isa/pnp.c
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: pnp.c,v 1.4 1997/11/18 11:45:26 bde Exp $
+ * $Id: pnp.c,v 1.5 1998/02/09 06:08:38 eivind Exp $
*/
#include <sys/param.h>
@@ -38,6 +38,13 @@
#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;
@@ -51,10 +58,10 @@ static struct pnp_dlist_node **pnp_device_list_last_ptr;
*/
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 ;
@@ -100,12 +107,10 @@ nullpnp_attach(u_long csn, u_long vend_id, char *name,
/* 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);
-void pnp_write(int d, u_char r);
-u_char pnp_read(int d);
+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);
void
pnp_write(int d, u_char r)
@@ -178,6 +183,35 @@ pnp_get_serial(pnp_id *p)
}
/*
+ * Fill's the buffer with resource info from the device.
+ * Returns 0 if the device fails to report
+ */
+static int
+pnp_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.
@@ -335,15 +369,22 @@ config_pnp_device(pnp_id *p, int csn)
static struct pnp_dlist_node *nod = NULL;
int i;
u_char *data = (u_char *)p;
+ u_char *comp = (u_char *)&p->comp_id;
/* these are for autoconfigure a-la pci */
struct pnp_device *dvp, **dvpp;
char *name ;
- printf("CSN %d Vendor ID: %c%c%c%02x%02x [0x%08lx] Serial 0x%08lx\n", csn,
+ printf("CSN %d Vendor ID: %c%c%c%02x%02x [0x%08x] Serial 0x%08x Comp ID: %c%c%c%02x%02x [0x%08x]\n",
+ csn,
((data[0] & 0x7c) >> 2) + '@',
(((data[0] & 0x03) << 3) | ((data[1] & 0xe0) >> 5)) + '@',
- (data[1] & 0x1f) + '@', data[2], data[3], p->vendor_id, p->serial);
+ (data[1] & 0x1f) + '@', data[2], data[3],
+ p->vendor_id, p->serial,
+ ((comp[0] & 0x7c) >> 2) + '@',
+ (((comp[0] & 0x03) << 3) | ((comp[1] & 0xe0) >> 5)) + '@',
+ (comp[1] & 0x1f) + '@', comp[2], comp[3],
+ p->comp_id);
doing_pnp_probe = 1 ;
current_csn = csn ;
@@ -382,11 +423,13 @@ config_pnp_device(pnp_id *p, int csn)
dvpp = (struct pnp_device **)pnpdevice_set.ls_items;
while ((dvp = *dvpp++)) {
if (dvp->pd_probe) {
- if ((name = (*dvp->pd_probe)(csn, p->vendor_id)))
+ if ( ((name = (*dvp->pd_probe)(csn, p->vendor_id)) && *name) ||
+ (p->comp_id &&
+ (name = (*dvp->pd_probe)(csn, p->comp_id))))
break;
}
}
- if (dvp && name && dvp->pd_count) { /* found a matching device */
+ if (dvp && name && *name && dvp->pd_count) { /* found a matching device */
int unit ;
/* pnpcb->pnpcb_seen |= ( 1ul << csn ) ; */
@@ -467,6 +510,52 @@ config_pnp_device(pnp_id *p, int csn)
doing_pnp_probe = 0 ;
}
+/*
+ * Scan Resource Data for Compatible Device ID.
+ *
+ * This function exits as soon as it gets a Compatible Device ID, an error
+ * reading *ANY* Resource Data or ir reaches the end of Resource Data.
+ * In the first case the return value will be TRUE, FALSE otherwise.
+ */
+static int
+pnp_scan_resdata(pnp_id *p, int csn)
+{
+ u_char tag, resinfo[8];
+ int large_len, scanning = 1024, retval = FALSE;
+
+ while (scanning-- > 0 && pnp_get_resource_info(&tag, 1)) {
+ if (PNP_RES_TYPE(tag) == 0) {
+ /* Small resource */
+ switch (PNP_SRES_NUM(tag)) {
+ case COMP_DEVICE_ID:
+ /* Got a compatible device id resource */
+ if (pnp_get_resource_info(resinfo, PNP_SRES_LEN(tag))) {
+ bcopy(resinfo, &p->comp_id, 4);
+ retval = TRUE;
+ if (bootverbose)
+ printf("PnP: CSN %d COMP_DEVICE_ID = 0x%08x\n", csn, p->comp_id);
+ }
+ /*
+ * We found what we were looking for, or got an error from
+ * pnp_get_resource, => stop scanning (FALLTHROUGH)
+ */
+ case END_TAG:
+ scanning = 0;
+ break;
+ default:
+ /* Skip this resource */
+ if (pnp_get_resource_info(NULL, PNP_SRES_LEN(tag)) == 0)
+ scanning = 0;
+ break;
+ }
+ } else
+ /* Large resource, skip it */
+ if (!(pnp_get_resource_info((u_char *)&large_len, 2) && pnp_get_resource_info(NULL, large_len)))
+ scanning = 0;
+ }
+
+ return retval;
+}
/*
* Run the isolation protocol. Use pnp_rd_port as the READ_DATA port
@@ -497,6 +586,8 @@ pnp_isolation_protocol()
if (pnp_get_serial( &(pnp_devices[csn-1]) ) ) {
pnp_write(SET_CSN, csn);
/* pnp_write(CONFIG_CONTROL, 2); */
+ if (!pnp_scan_resdata(&(pnp_devices[csn-1]), csn))
+ pnp_devices[csn-1].comp_id = NULL;
} else
break;
}
OpenPOWER on IntegriCloud