mirror of
https://github.com/xcat2/xNBA.git
synced 2024-12-14 07:11:32 +00:00
Extraced from 3c509.c
This commit is contained in:
parent
a4f1a058a4
commit
200b39a645
136
src/drivers/bus/eisa.c
Normal file
136
src/drivers/bus/eisa.c
Normal file
@ -0,0 +1,136 @@
|
||||
#include "etherboot.h"
|
||||
#include "dev.h"
|
||||
#include "io.h"
|
||||
#include "timer.h"
|
||||
#include "eisa.h"
|
||||
|
||||
#define DEBUG_EISA
|
||||
|
||||
#undef DBG
|
||||
#ifdef DEBUG_EISA
|
||||
#define DBG(...) printf ( __VA_ARGS__ )
|
||||
#else
|
||||
#define DBG(...)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Fill in parameters for an EISA device based on slot number
|
||||
*
|
||||
* Return 1 if device present, 0 otherwise
|
||||
*
|
||||
*/
|
||||
static int fill_eisa_device ( struct eisa_device *eisa ) {
|
||||
uint8_t present;
|
||||
|
||||
/* Set ioaddr */
|
||||
eisa->ioaddr = EISA_SLOT_BASE ( eisa->slot );
|
||||
|
||||
/* Test for board present */
|
||||
outb ( 0xff, eisa->ioaddr + EISA_MFG_ID_HI );
|
||||
present = inb ( eisa->ioaddr + EISA_MFG_ID_HI );
|
||||
if ( present & 0x80 ) {
|
||||
/* No board present */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read mfg and product IDs. Yes, the resulting uint16_ts
|
||||
* will be upside-down. This appears to be by design.
|
||||
*/
|
||||
eisa->mfg_id = ( inb ( eisa->ioaddr + EISA_MFG_ID_LO ) << 8 )
|
||||
+ present;
|
||||
eisa->prod_id = ( inb ( eisa->ioaddr + EISA_PROD_ID_LO ) << 8 )
|
||||
+ inb ( eisa->ioaddr + EISA_PROD_ID_HI );
|
||||
|
||||
DBG ( "EISA slot %d (base %#hx) ID %hx:%hx (\"%s\")\n",
|
||||
eisa->slot, eisa->ioaddr, eisa->mfg_id, eisa->prod_id,
|
||||
isa_id_string ( eisa->mfg_id, eisa->prod_id ) );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Obtain a struct eisa * from a struct dev *
|
||||
*
|
||||
* If dev has not previously been used for an EISA device scan, blank
|
||||
* out dev.eisa
|
||||
*/
|
||||
struct eisa_device * eisa_device ( struct dev *dev ) {
|
||||
struct eisa_device *eisa = &dev->eisa;
|
||||
|
||||
if ( dev->devid.bus_type != EISA_BUS_TYPE ) {
|
||||
memset ( eisa, 0, sizeof ( *eisa ) );
|
||||
dev->devid.bus_type = EISA_BUS_TYPE;
|
||||
eisa->slot = EISA_MIN_SLOT;
|
||||
}
|
||||
eisa->dev = dev;
|
||||
return eisa;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find an EISA device matching the specified driver
|
||||
*
|
||||
*/
|
||||
int find_eisa_device ( struct eisa_device *eisa, struct eisa_driver *driver ) {
|
||||
unsigned int i;
|
||||
|
||||
/* Iterate through all possible EISA slots, starting where we
|
||||
* left off/
|
||||
*/
|
||||
for ( ; eisa->slot <= EISA_MAX_SLOT ; eisa->slot++ ) {
|
||||
/* If we've already used this device, skip it */
|
||||
if ( eisa->already_tried ) {
|
||||
eisa->already_tried = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Fill in device parameters */
|
||||
if ( ! fill_eisa_device ( eisa ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Compare against driver's ID list */
|
||||
for ( i = 0 ; i < driver->id_count ; i++ ) {
|
||||
struct eisa_id *id = &driver->ids[i];
|
||||
|
||||
if ( ( eisa->mfg_id == id->mfg_id ) &&
|
||||
( ISA_PROD_ID ( eisa->prod_id ) ==
|
||||
ISA_PROD_ID ( id->prod_id ) ) ) {
|
||||
DBG ( "Device %s (driver %s) matches ID %s\n",
|
||||
id->name, driver->name,
|
||||
isa_id_string ( eisa->mfg_id,
|
||||
eisa->prod_id ) );
|
||||
if ( eisa->dev ) {
|
||||
eisa->dev->name = driver->name;
|
||||
eisa->dev->devid.vendor_id
|
||||
= eisa->mfg_id;
|
||||
eisa->dev->devid.device_id
|
||||
= eisa->prod_id;
|
||||
}
|
||||
eisa->already_tried = 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* No device found */
|
||||
eisa->slot = EISA_MIN_SLOT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset and enable an EISA device
|
||||
*
|
||||
*/
|
||||
void enable_eisa_device ( struct eisa_device *eisa ) {
|
||||
/* Set reset line high for 1000 µs. Spec says 500 µs, but
|
||||
* this doesn't work for all cards, so we are conservative.
|
||||
*/
|
||||
outb ( EISA_CMD_RESET, eisa->ioaddr + EISA_GLOBAL_CONFIG );
|
||||
udelay ( 1000 ); /* Must wait 800 */
|
||||
|
||||
/* Set reset low and write a 1 to ENABLE. Delay again, in
|
||||
* case the card takes a while to wake up.
|
||||
*/
|
||||
outb ( EISA_CMD_ENABLE, eisa->ioaddr + EISA_GLOBAL_CONFIG );
|
||||
udelay ( 1000 ); /* Must wait 800 */
|
||||
}
|
76
src/include/eisa.h
Normal file
76
src/include/eisa.h
Normal file
@ -0,0 +1,76 @@
|
||||
#ifndef EISA_H
|
||||
#define EISA_H
|
||||
|
||||
#include "isa_ids.h"
|
||||
|
||||
/*
|
||||
* EISA constants
|
||||
*
|
||||
*/
|
||||
|
||||
#define EISA_MIN_SLOT (0x1)
|
||||
#define EISA_MAX_SLOT (0xf)
|
||||
#define EISA_SLOT_BASE( n ) ( 0x1000 * (n) )
|
||||
|
||||
#define EISA_MFG_ID_HI ( 0xc80 )
|
||||
#define EISA_MFG_ID_LO ( 0xc81 )
|
||||
#define EISA_PROD_ID_HI ( 0xc82 )
|
||||
#define EISA_PROD_ID_LO ( 0xc83 )
|
||||
#define EISA_GLOBAL_CONFIG ( 0xc84 )
|
||||
|
||||
#define EISA_CMD_RESET ( 1 << 2 )
|
||||
#define EISA_CMD_ENABLE ( 1 << 0 )
|
||||
|
||||
/*
|
||||
* A physical EISA device
|
||||
*
|
||||
*/
|
||||
struct dev;
|
||||
struct eisa_device {
|
||||
struct dev *dev;
|
||||
unsigned int slot;
|
||||
uint16_t ioaddr;
|
||||
uint16_t mfg_id;
|
||||
uint16_t prod_id;
|
||||
int already_tried;
|
||||
};
|
||||
|
||||
/*
|
||||
* An individual EISA device identified by ID
|
||||
*
|
||||
*/
|
||||
struct eisa_id {
|
||||
const char *name;
|
||||
uint16_t mfg_id, prod_id;
|
||||
};
|
||||
|
||||
/*
|
||||
* An EISA driver, with a device ID (struct eisa_id) table.
|
||||
*
|
||||
*/
|
||||
struct eisa_driver {
|
||||
const char *name;
|
||||
struct eisa_id *ids;
|
||||
unsigned int id_count;
|
||||
};
|
||||
|
||||
/*
|
||||
* Define an EISA driver
|
||||
*
|
||||
*/
|
||||
#define EISA_DRIVER( driver_name, eisa_ids ) { \
|
||||
.name = driver_name, \
|
||||
.ids = eisa_ids, \
|
||||
.id_count = sizeof ( eisa_ids ) / sizeof ( eisa_ids[0] ), \
|
||||
}
|
||||
|
||||
/*
|
||||
* Functions in eisa.c
|
||||
*
|
||||
*/
|
||||
extern struct eisa_device * eisa_device ( struct dev *dev );
|
||||
extern int find_eisa_device ( struct eisa_device *eisa,
|
||||
struct eisa_driver *driver );
|
||||
extern void enable_eisa_device ( struct eisa_device *eisa );
|
||||
|
||||
#endif /* EISA_H */
|
Loading…
Reference in New Issue
Block a user