2021-03-20 01:21:02 -03:00
/*
2022-11-13 16:37:58 -05:00
* 86 Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus .
2021-03-20 01:21:02 -03:00
*
2022-11-13 16:37:58 -05:00
* This file is part of the 86 Box distribution .
2021-03-20 01:21:02 -03:00
*
2022-11-13 16:37:58 -05:00
* Implementation of ISA Plug and Play .
2021-03-20 01:21:02 -03:00
*
*
*
2022-11-13 16:37:58 -05:00
* Authors : Miran Grca , < mgrca8 @ gmail . com >
* RichardG , < richardg867 @ gmail . com >
2021-03-20 01:21:02 -03:00
*
2022-11-13 16:37:58 -05:00
* Copyright 2016 - 2018 Miran Grca .
* Copyright 2021 RichardG .
2021-03-20 01:21:02 -03:00
*/
# include <stdarg.h>
# include <stdio.h>
# include <stdint.h>
# include <stdlib.h>
# include <string.h>
# define HAVE_STDARG_H
# include <86box/86box.h>
# include <86box/device.h>
# include <86box/io.h>
# include <86box/isapnp.h>
2022-09-18 17:13:28 -04:00
# define CHECK_CURRENT_LD() \
if ( ! dev - > current_ld ) { \
isapnp_log ( " ISAPnP: No logical device selected \n " ) ; \
break ; \
}
2021-03-20 01:21:02 -03:00
2022-09-18 17:13:28 -04:00
# define CHECK_CURRENT_CARD() \
if ( 1 ) { \
card = dev - > first_card ; \
while ( card ) { \
if ( card - > enable & & ( card - > state = = PNP_STATE_CONFIG ) ) \
break ; \
card = card - > next ; \
} \
if ( ! card ) { \
isapnp_log ( " ISAPnP: No card in CONFIG state \n " ) ; \
break ; \
} \
}
2021-03-20 01:21:02 -03:00
2022-09-18 17:13:28 -04:00
static const uint8_t pnp_init_key [ 32 ] = { 0x6A , 0xB5 , 0xDA , 0xED , 0xF6 , 0xFB , 0x7D , 0xBE ,
0xDF , 0x6F , 0x37 , 0x1B , 0x0D , 0x86 , 0xC3 , 0x61 ,
0xB0 , 0x58 , 0x2C , 0x16 , 0x8B , 0x45 , 0xA2 , 0xD1 ,
0xE8 , 0x74 , 0x3A , 0x9D , 0xCE , 0xE7 , 0x73 , 0x39 } ;
static const device_t isapnp_device ;
2022-03-06 09:39:52 -03:00
2021-03-20 01:21:02 -03:00
# ifdef ENABLE_ISAPNP_LOG
int isapnp_do_log = ENABLE_ISAPNP_LOG ;
static void
isapnp_log ( const char * fmt , . . . )
{
va_list ap ;
if ( isapnp_do_log ) {
2022-09-18 17:13:28 -04:00
va_start ( ap , fmt ) ;
pclog_ex ( fmt , ap ) ;
va_end ( ap ) ;
2021-03-20 01:21:02 -03:00
}
}
# else
2022-09-18 17:13:28 -04:00
# define isapnp_log(fmt, ...)
2021-03-20 01:21:02 -03:00
# endif
enum {
PNP_STATE_WAIT_FOR_KEY = 0 ,
PNP_STATE_CONFIG ,
PNP_STATE_ISOLATION ,
PNP_STATE_SLEEP
} ;
typedef struct _isapnp_device_ {
2022-09-18 17:13:28 -04:00
uint8_t number ;
uint8_t regs [ 256 ] ;
uint8_t mem_upperlimit , irq_types , io_16bit , io_len [ 8 ] ;
2021-04-02 23:46:38 -03:00
const isapnp_device_config_t * defaults ;
2021-03-20 01:21:02 -03:00
struct _isapnp_device_ * next ;
} isapnp_device_t ;
typedef struct _isapnp_card_ {
2022-09-18 17:13:28 -04:00
uint8_t enable , state , csn , id_checksum , serial_read , serial_read_pair , serial_read_pos , * rom ;
uint16_t rom_pos , rom_size ;
void * priv ;
2021-03-20 01:21:02 -03:00
/* ISAPnP memory and I/O addresses are awkwardly big endian, so we populate this
structure whenever something on some device changes , and pass it on instead . */
isapnp_device_config_t config ;
2022-09-18 17:13:28 -04:00
void ( * config_changed ) ( uint8_t ld , isapnp_device_config_t * config , void * priv ) ;
void ( * csn_changed ) ( uint8_t csn , void * priv ) ;
uint8_t ( * read_vendor_reg ) ( uint8_t ld , uint8_t reg , void * priv ) ;
void ( * write_vendor_reg ) ( uint8_t ld , uint8_t reg , uint8_t val , void * priv ) ;
2021-03-20 01:21:02 -03:00
2022-09-18 17:13:28 -04:00
isapnp_device_t * first_ld ;
2021-03-20 01:21:02 -03:00
struct _isapnp_card_ * next ;
} isapnp_card_t ;
typedef struct {
2022-09-18 17:13:28 -04:00
uint8_t reg , key_pos : 5 ;
uint16_t read_data_addr ;
2021-03-20 01:21:02 -03:00
2022-09-18 17:13:28 -04:00
isapnp_card_t * first_card , * isolated_card , * current_ld_card ;
2021-03-20 01:21:02 -03:00
isapnp_device_t * current_ld ;
} isapnp_t ;
static void
2021-03-20 20:58:24 -03:00
isapnp_device_config_changed ( isapnp_card_t * card , isapnp_device_t * ld )
2021-03-20 01:21:02 -03:00
{
2021-03-23 16:49:57 -03:00
/* Ignore card if it hasn't signed up for configuration changes. */
2021-03-20 20:58:24 -03:00
if ( ! card - > config_changed )
2022-09-18 17:13:28 -04:00
return ;
2021-03-20 01:21:02 -03:00
/* Populate config structure, performing endianness conversion as needed. */
card - > config . activate = ld - > regs [ 0x30 ] & 0x01 ;
2023-05-11 03:02:36 -04:00
uint8_t i ;
uint8_t reg_base ;
2021-03-20 01:21:02 -03:00
for ( i = 0 ; i < 4 ; i + + ) {
2022-09-18 17:13:28 -04:00
reg_base = 0x40 + ( 8 * i ) ;
card - > config . mem [ i ] . base = ( ld - > regs [ reg_base ] < < 16 ) | ( ld - > regs [ reg_base + 1 ] < < 8 ) ;
card - > config . mem [ i ] . size = ( ld - > regs [ reg_base + 3 ] < < 16 ) | ( ld - > regs [ reg_base + 4 ] < < 8 ) ;
if ( ld - > regs [ reg_base + 2 ] & 0x01 ) /* upper limit */
card - > config . mem [ i ] . size - = card - > config . mem [ i ] . base ;
2021-03-20 01:21:02 -03:00
}
for ( i = 0 ; i < 4 ; i + + ) {
2022-09-18 17:13:28 -04:00
reg_base = ( i = = 0 ) ? 0x76 : ( 0x80 + ( 16 * i ) ) ;
card - > config . mem32 [ i ] . base = ( ld - > regs [ reg_base ] < < 24 ) | ( ld - > regs [ reg_base + 1 ] < < 16 ) | ( ld - > regs [ reg_base + 2 ] < < 8 ) | ld - > regs [ reg_base + 3 ] ;
card - > config . mem32 [ i ] . size = ( ld - > regs [ reg_base + 5 ] < < 24 ) | ( ld - > regs [ reg_base + 6 ] < < 16 ) | ( ld - > regs [ reg_base + 7 ] < < 8 ) | ld - > regs [ reg_base + 8 ] ;
if ( ld - > regs [ reg_base + 4 ] & 0x01 ) /* upper limit */
card - > config . mem32 [ i ] . size - = card - > config . mem32 [ i ] . base ;
2021-03-20 01:21:02 -03:00
}
for ( i = 0 ; i < 8 ; i + + ) {
2022-09-18 17:13:28 -04:00
reg_base = 0x60 + ( 2 * i ) ;
if ( ld - > regs [ 0x31 ] & 0x02 )
card - > config . io [ i ] . base = 0 ; /* let us handle I/O range check reads */
else
card - > config . io [ i ] . base = ( ld - > regs [ reg_base ] < < 8 ) | ld - > regs [ reg_base + 1 ] ;
2021-03-20 01:21:02 -03:00
}
for ( i = 0 ; i < 2 ; i + + ) {
2022-09-18 17:13:28 -04:00
reg_base = 0x70 + ( 2 * i ) ;
card - > config . irq [ i ] . irq = ld - > regs [ reg_base ] ;
card - > config . irq [ i ] . level = ld - > regs [ reg_base + 1 ] & 0x02 ;
card - > config . irq [ i ] . type = ld - > regs [ reg_base + 1 ] & 0x01 ;
2021-03-20 01:21:02 -03:00
}
for ( i = 0 ; i < 2 ; i + + ) {
2022-09-18 17:13:28 -04:00
reg_base = 0x74 + i ;
card - > config . dma [ i ] . dma = ld - > regs [ reg_base ] ;
2021-03-20 01:21:02 -03:00
}
/* Signal the configuration change. */
card - > config_changed ( ld - > number , & card - > config , card - > priv ) ;
}
2021-04-02 23:46:38 -03:00
static void
isapnp_reset_ld_config ( isapnp_device_t * ld )
{
/* Do nothing if there's no default configuration for this device. */
const isapnp_device_config_t * config = ld - > defaults ;
if ( ! config )
2022-09-18 17:13:28 -04:00
return ;
2021-04-02 23:46:38 -03:00
/* Populate configuration registers. */
ld - > regs [ 0x30 ] = ! ! config - > activate ;
2023-05-11 03:02:36 -04:00
uint8_t i ;
uint8_t reg_base ;
2021-04-02 23:46:38 -03:00
uint32_t size ;
for ( i = 0 ; i < 4 ; i + + ) {
2022-09-18 17:13:28 -04:00
reg_base = 0x40 + ( 8 * i ) ;
ld - > regs [ reg_base ] = config - > mem [ i ] . base > > 16 ;
ld - > regs [ reg_base + 1 ] = config - > mem [ i ] . base > > 8 ;
size = config - > mem [ i ] . size ;
if ( ld - > regs [ reg_base + 2 ] & 0x01 ) /* upper limit */
size + = config - > mem [ i ] . base ;
ld - > regs [ reg_base + 3 ] = size > > 16 ;
ld - > regs [ reg_base + 4 ] = size > > 8 ;
2021-04-02 23:46:38 -03:00
}
for ( i = 0 ; i < 4 ; i + + ) {
2022-09-18 17:13:28 -04:00
reg_base = ( i = = 0 ) ? 0x76 : ( 0x80 + ( 16 * i ) ) ;
ld - > regs [ reg_base ] = config - > mem32 [ i ] . base > > 24 ;
ld - > regs [ reg_base + 1 ] = config - > mem32 [ i ] . base > > 16 ;
ld - > regs [ reg_base + 2 ] = config - > mem32 [ i ] . base > > 8 ;
ld - > regs [ reg_base + 3 ] = config - > mem32 [ i ] . base ;
size = config - > mem32 [ i ] . size ;
if ( ld - > regs [ reg_base + 4 ] & 0x01 ) /* upper limit */
size + = config - > mem32 [ i ] . base ;
ld - > regs [ reg_base + 5 ] = size > > 24 ;
ld - > regs [ reg_base + 6 ] = size > > 16 ;
ld - > regs [ reg_base + 7 ] = size > > 8 ;
ld - > regs [ reg_base + 8 ] = size ;
2021-04-02 23:46:38 -03:00
}
for ( i = 0 ; i < 8 ; i + + ) {
2022-09-18 17:13:28 -04:00
reg_base = 0x60 + ( 2 * i ) ;
ld - > regs [ reg_base ] = config - > io [ i ] . base > > 8 ;
ld - > regs [ reg_base + 1 ] = config - > io [ i ] . base ;
2021-04-02 23:46:38 -03:00
}
for ( i = 0 ; i < 2 ; i + + ) {
2022-09-18 17:13:28 -04:00
reg_base = 0x70 + ( 2 * i ) ;
ld - > regs [ reg_base ] = config - > irq [ i ] . irq ;
ld - > regs [ reg_base + 1 ] = ( ! ! config - > irq [ i ] . level < < 1 ) | ! ! config - > irq [ i ] . type ;
2021-04-02 23:46:38 -03:00
}
for ( i = 0 ; i < 2 ; i + + ) {
2022-09-18 17:13:28 -04:00
reg_base = 0x74 + i ;
ld - > regs [ reg_base ] = config - > dma [ i ] . dma ;
2021-04-02 23:46:38 -03:00
}
}
2021-03-20 14:54:34 -03:00
static void
isapnp_reset_ld_regs ( isapnp_device_t * ld )
{
memset ( ld - > regs , 0 , sizeof ( ld - > regs ) ) ;
/* DMA disable uses a non-zero value. */
ld - > regs [ 0x74 ] = ld - > regs [ 0x75 ] = ISAPNP_DMA_DISABLED ;
2021-03-20 20:58:24 -03:00
/* Set the upper limit bit on memory ranges which require it. */
uint8_t i ;
for ( i = 0 ; i < 4 ; i + + )
2022-09-18 17:13:28 -04:00
ld - > regs [ 0x42 + ( 8 * i ) ] | = ! ! ( ld - > mem_upperlimit & ( 1 < < i ) ) ;
2021-03-22 21:06:42 -03:00
ld - > regs [ 0x7a ] | = ! ! ( ld - > mem_upperlimit & ( 1 < < 4 ) ) ;
2021-03-20 20:58:24 -03:00
for ( i = 1 ; i < 4 ; i + + )
2022-09-18 17:13:28 -04:00
ld - > regs [ 0x84 + ( 16 * i ) ] | = ! ! ( ld - > mem_upperlimit & ( 1 < < ( 4 + i ) ) ) ;
2021-03-22 21:06:42 -03:00
/* Set the default IRQ type bits. */
for ( i = 0 ; i < 2 ; i + + ) {
2022-09-18 17:13:28 -04:00
if ( ld - > irq_types & ( 0x1 < < ( 4 * i ) ) )
ld - > regs [ 0x70 + ( 2 * i ) ] = 0x02 ;
else if ( ld - > irq_types & ( 0x2 < < ( 4 * i ) ) )
ld - > regs [ 0x70 + ( 2 * i ) ] = 0x00 ;
else if ( ld - > irq_types & ( 0x4 < < ( 4 * i ) ) )
ld - > regs [ 0x70 + ( 2 * i ) ] = 0x03 ;
else if ( ld - > irq_types & ( 0x8 < < ( 4 * i ) ) )
ld - > regs [ 0x70 + ( 2 * i ) ] = 0x01 ;
2021-03-22 21:06:42 -03:00
}
2021-04-02 23:46:38 -03:00
/* Reset configuration registers to match the default configuration. */
isapnp_reset_ld_config ( ld ) ;
2021-03-20 14:54:34 -03:00
}
2021-03-20 01:21:02 -03:00
static uint8_t
isapnp_read_rangecheck ( uint16_t addr , void * priv )
{
isapnp_device_t * dev = ( isapnp_device_t * ) priv ;
return ( dev - > regs [ 0x31 ] & 0x01 ) ? 0x55 : 0xaa ;
}
static uint8_t
isapnp_read_data ( uint16_t addr , void * priv )
{
2022-09-18 17:13:28 -04:00
isapnp_t * dev = ( isapnp_t * ) priv ;
2023-05-11 03:02:36 -04:00
uint8_t ret = 0xff ;
uint8_t bit ;
uint8_t next_shift ;
2021-03-20 01:21:02 -03:00
isapnp_card_t * card ;
switch ( dev - > reg ) {
2022-09-18 17:13:28 -04:00
case 0x01 : /* Serial Isolation */
card = dev - > first_card ;
while ( card ) {
if ( card - > enable & & card - > rom & & ( card - > state = = PNP_STATE_ISOLATION ) )
break ;
card = card - > next ;
}
dev - > isolated_card = card ;
if ( card ) {
if ( card - > serial_read_pair ) { /* second byte (aa/00) */
card - > serial_read < < = 1 ;
if ( ! card - > serial_read_pos )
card - > rom_pos = 0x09 ;
} else { /* first byte (55/00) */
if ( card - > serial_read_pos < 64 ) { /* reading 64-bit vendor/serial */
bit = ( card - > rom [ card - > serial_read_pos > > 3 ] > > ( card - > serial_read_pos & 0x7 ) ) & 0x01 ;
next_shift = ( ! ! ( card - > id_checksum & 0x02 ) ^ ! ! ( card - > id_checksum & 0x01 ) ^ bit ) & 0x01 ;
card - > id_checksum > > = 1 ;
card - > id_checksum | = ( next_shift < < 7 ) ;
} else { /* reading 8-bit checksum */
if ( card - > serial_read_pos = = 64 ) /* populate ID checksum in ROM */
card - > rom [ 0x08 ] = card - > id_checksum ;
bit = ( card - > id_checksum > > ( card - > serial_read_pos & 0x7 ) ) & 0x01 ;
}
isapnp_log ( " ISAPnP: Read bit %d of byte %02X (%02X) = %d \n " , card - > serial_read_pos & 0x7 , card - > serial_read_pos > > 3 , card - > rom [ card - > serial_read_pos > > 3 ] , bit ) ;
card - > serial_read = bit ? 0x55 : 0x00 ;
card - > serial_read_pos = ( card - > serial_read_pos + 1 ) % 72 ;
}
card - > serial_read_pair ^ = 1 ;
ret = card - > serial_read ;
}
break ;
case 0x04 : /* Resource Data */
CHECK_CURRENT_CARD ( ) ;
isapnp_log ( " ISAPnP: Read resource data index %02X (%02X) from CSN %02X \n " , card - > rom_pos , card - > rom [ card - > rom_pos ] , card - > csn ) ;
if ( card - > rom_pos > = card - > rom_size )
ret = 0xff ;
else
ret = card - > rom [ card - > rom_pos + + ] ;
break ;
case 0x05 : /* Status */
ret = 0x00 ;
CHECK_CURRENT_CARD ( ) ;
isapnp_log ( " ISAPnP: Query status for CSN %02X \n " , card - > csn ) ;
ret = 0x01 ;
break ;
case 0x06 : /* Card Select Number */
ret = 0x00 ;
CHECK_CURRENT_CARD ( ) ;
isapnp_log ( " ISAPnP: Query CSN %02X \n " , card - > csn ) ;
ret = card - > csn ;
break ;
case 0x07 : /* Logical Device Number */
ret = 0x00 ;
CHECK_CURRENT_LD ( ) ;
isapnp_log ( " ISAPnP: Query LDN for CSN %02X device %02X \n " , dev - > current_ld_card - > csn , dev - > current_ld - > number ) ;
ret = dev - > current_ld - > number ;
break ;
case 0x20 :
case 0x21 :
case 0x22 :
case 0x23 :
case 0x24 :
case 0x25 :
case 0x26 :
case 0x27 :
case 0x28 :
case 0x29 :
case 0x2a :
case 0x2b :
case 0x2c :
case 0x2d :
case 0x2e :
case 0x2f :
CHECK_CURRENT_CARD ( ) ;
isapnp_log ( " ISAPnP: Read vendor-defined register %02X from CSN %02X \n " , dev - > reg , card - > csn ) ;
if ( card - > read_vendor_reg )
ret = card - > read_vendor_reg ( 0 , dev - > reg , card - > priv ) ;
break ;
case 0x38 :
case 0x39 :
case 0x3a :
case 0x3b :
case 0x3c :
case 0x3d :
case 0x3e :
case 0x3f :
case 0xf0 :
case 0xf1 :
case 0xf2 :
case 0xf3 :
case 0xf4 :
case 0xf5 :
case 0xf6 :
case 0xf7 :
case 0xf8 :
case 0xf9 :
case 0xfa :
case 0xfb :
case 0xfc :
case 0xfd :
case 0xfe :
CHECK_CURRENT_LD ( ) ;
isapnp_log ( " ISAPnP: Read vendor-defined register %02X from CSN %02X device %02X \n " , dev - > reg , dev - > current_ld_card - > csn , dev - > current_ld - > number ) ;
if ( dev - > current_ld_card - > read_vendor_reg )
ret = dev - > current_ld_card - > read_vendor_reg ( dev - > current_ld - > number , dev - > reg , dev - > current_ld_card - > priv ) ;
break ;
default :
if ( dev - > reg > = 0x30 ) {
CHECK_CURRENT_LD ( ) ;
isapnp_log ( " ISAPnP: Read register %02X from CSN %02X device %02X \n " , dev - > reg , dev - > current_ld_card - > csn , dev - > current_ld - > number ) ;
ret = dev - > current_ld - > regs [ dev - > reg ] ;
}
break ;
2021-03-20 01:21:02 -03:00
}
isapnp_log ( " ISAPnP: read_data(%02X) = %02X \n " , dev - > reg , ret ) ;
return ret ;
}
static void
isapnp_set_read_data ( uint16_t addr , isapnp_t * dev )
{
/* Remove existing READ_DATA port if set. */
if ( dev - > read_data_addr ) {
2022-09-18 17:13:28 -04:00
io_removehandler ( dev - > read_data_addr , 1 , isapnp_read_data , NULL , NULL , NULL , NULL , NULL , dev ) ;
dev - > read_data_addr = 0 ;
2021-03-20 01:21:02 -03:00
}
/* Set new READ_DATA port if within range. */
if ( ( addr > = 0x203 ) & & ( addr < = 0x3ff ) ) {
2022-09-18 17:13:28 -04:00
dev - > read_data_addr = addr ;
io_sethandler ( dev - > read_data_addr , 1 , isapnp_read_data , NULL , NULL , NULL , NULL , NULL , dev ) ;
2021-03-20 01:21:02 -03:00
}
}
static void
isapnp_write_addr ( uint16_t addr , uint8_t val , void * priv )
{
2022-09-18 17:13:28 -04:00
isapnp_t * dev = ( isapnp_t * ) priv ;
2021-03-20 01:21:02 -03:00
isapnp_card_t * card = dev - > first_card ;
isapnp_log ( " ISAPnP: write_addr(%02X) \n " , val ) ;
if ( ! card ) /* don't do anything if we have no PnP cards */
2022-09-18 17:13:28 -04:00
return ;
2021-03-20 01:21:02 -03:00
2021-04-02 23:46:38 -03:00
dev - > reg = val ;
2021-03-20 01:21:02 -03:00
if ( card - > state = = PNP_STATE_WAIT_FOR_KEY ) { /* checking only the first card should be fine */
2022-09-18 17:13:28 -04:00
/* Check written value against LFSR key. */
if ( val = = pnp_init_key [ dev - > key_pos ] ) {
dev - > key_pos + + ;
if ( ! dev - > key_pos ) {
isapnp_log ( " ISAPnP: Key unlocked, putting cards to SLEEP \n " ) ;
while ( card ) {
if ( card - > enable & & ( card - > enable ! = ISAPNP_CARD_NO_KEY ) & & ( card - > state = = PNP_STATE_WAIT_FOR_KEY ) )
card - > state = PNP_STATE_SLEEP ;
card = card - > next ;
}
}
} else {
dev - > key_pos = 0 ;
}
2021-03-20 01:21:02 -03:00
}
}
static void
isapnp_write_data ( uint16_t addr , uint8_t val , void * priv )
{
2022-09-18 17:13:28 -04:00
isapnp_t * dev = ( isapnp_t * ) priv ;
isapnp_card_t * card ;
2021-03-20 01:21:02 -03:00
isapnp_device_t * ld ;
2023-05-11 03:02:36 -04:00
uint16_t io_addr ;
uint16_t reset_cards = 0 ;
2021-03-20 01:21:02 -03:00
isapnp_log ( " ISAPnP: write_data(%02X) \n " , val ) ;
switch ( dev - > reg ) {
2022-09-18 17:13:28 -04:00
case 0x00 : /* Set RD_DATA Port */
isapnp_set_read_data ( ( val < < 2 ) | 3 , dev ) ;
isapnp_log ( " ISAPnP: Read data port set to %04X \n " , dev - > read_data_addr ) ;
break ;
case 0x02 : /* Config Control */
if ( val & 0x01 ) {
isapnp_log ( " ISAPnP: Reset \n " ) ;
card = dev - > first_card ;
while ( card ) {
ld = card - > first_ld ;
while ( ld ) {
if ( card - > state ! = PNP_STATE_WAIT_FOR_KEY ) {
isapnp_reset_ld_regs ( ld ) ;
isapnp_device_config_changed ( card , ld ) ;
reset_cards + + ;
}
ld = ld - > next ;
}
card = card - > next ;
}
if ( reset_cards ! = 0 ) {
dev - > current_ld = NULL ;
dev - > current_ld_card = NULL ;
dev - > isolated_card = NULL ;
}
}
if ( val & 0x02 ) {
isapnp_log ( " ISAPnP: Return to WAIT_FOR_KEY \n " ) ;
card = dev - > first_card ;
while ( card ) {
card - > state = PNP_STATE_WAIT_FOR_KEY ;
card = card - > next ;
}
}
if ( val & 0x04 ) {
isapnp_log ( " ISAPnP: Reset CSN \n " ) ;
card = dev - > first_card ;
while ( card ) {
isapnp_set_csn ( card , 0 ) ;
card = card - > next ;
}
}
break ;
case 0x03 : /* Wake[CSN] */
isapnp_log ( " ISAPnP: Wake[%02X] \n " , val ) ;
card = dev - > first_card ;
while ( card ) {
if ( card - > csn = = val ) {
card - > rom_pos = 0 ;
card - > id_checksum = pnp_init_key [ 0 ] ;
if ( card - > state = = PNP_STATE_SLEEP )
card - > state = ( val = = 0 ) ? PNP_STATE_ISOLATION : PNP_STATE_CONFIG ;
} else {
card - > state = PNP_STATE_SLEEP ;
}
card = card - > next ;
}
break ;
case 0x06 : /* Card Select Number */
if ( dev - > isolated_card ) {
isapnp_log ( " ISAPnP: Set CSN %02X \n " , val ) ;
isapnp_set_csn ( dev - > isolated_card , val ) ;
dev - > isolated_card - > state = PNP_STATE_CONFIG ;
dev - > isolated_card = NULL ;
} else {
isapnp_log ( " ISAPnP: Set CSN %02X but no card is isolated \n " , val ) ;
}
break ;
case 0x07 : /* Logical Device Number */
CHECK_CURRENT_CARD ( ) ;
ld = card - > first_ld ;
while ( ld ) {
if ( ld - > number = = val ) {
isapnp_log ( " ISAPnP: Select CSN %02X device %02X \n " , card - > csn , val ) ;
dev - > current_ld_card = card ;
dev - > current_ld = ld ;
break ;
}
ld = ld - > next ;
}
if ( ! ld )
isapnp_log ( " ISAPnP: CSN %02X has no device %02X \n " , card - > csn , val ) ;
break ;
case 0x30 : /* Activate */
CHECK_CURRENT_LD ( ) ;
isapnp_log ( " ISAPnP: %sctivate CSN %02X device %02X \n " , ( val & 0x01 ) ? " A " : " Dea " , dev - > current_ld_card - > csn , dev - > current_ld - > number ) ;
dev - > current_ld - > regs [ dev - > reg ] = val & 0x01 ;
isapnp_device_config_changed ( dev - > current_ld_card , dev - > current_ld ) ;
break ;
case 0x31 : /* I/O Range Check */
CHECK_CURRENT_LD ( ) ;
for ( uint8_t i = 0 ; i < 8 ; i + + ) {
if ( ! dev - > current_ld - > io_len [ i ] )
continue ;
io_addr = ( dev - > current_ld - > regs [ 0x60 + ( 2 * i ) ] < < 8 ) | dev - > current_ld - > regs [ 0x61 + ( 2 * i ) ] ;
if ( dev - > current_ld - > regs [ dev - > reg ] & 0x02 )
io_removehandler ( io_addr , dev - > current_ld - > io_len [ i ] , isapnp_read_rangecheck , NULL , NULL , NULL , NULL , NULL , dev - > current_ld ) ;
if ( val & 0x02 )
io_sethandler ( io_addr , dev - > current_ld - > io_len [ i ] , isapnp_read_rangecheck , NULL , NULL , NULL , NULL , NULL , dev - > current_ld ) ;
}
dev - > current_ld - > regs [ dev - > reg ] = val & 0x03 ;
isapnp_device_config_changed ( dev - > current_ld_card , dev - > current_ld ) ;
break ;
case 0x20 :
case 0x21 :
case 0x22 :
case 0x23 :
case 0x24 :
case 0x25 :
case 0x26 :
case 0x27 :
case 0x28 :
case 0x29 :
case 0x2a :
case 0x2b :
case 0x2c :
case 0x2d :
case 0x2e :
case 0x2f :
CHECK_CURRENT_CARD ( ) ;
isapnp_log ( " ISAPnP: Write %02X to vendor-defined register %02X on CSN %02X \n " , val , dev - > reg , card - > csn ) ;
if ( card - > write_vendor_reg )
card - > write_vendor_reg ( 0 , dev - > reg , val , card - > priv ) ;
break ;
case 0x38 :
case 0x39 :
case 0x3a :
case 0x3b :
case 0x3c :
case 0x3d :
case 0x3e :
case 0x3f :
case 0xf0 :
case 0xf1 :
case 0xf2 :
case 0xf3 :
case 0xf4 :
case 0xf5 :
case 0xf6 :
case 0xf7 :
case 0xf8 :
case 0xf9 :
case 0xfa :
case 0xfb :
case 0xfc :
case 0xfd :
case 0xfe :
CHECK_CURRENT_LD ( ) ;
isapnp_log ( " ISAPnP: Write %02X to vendor-defined register %02X on CSN %02X device %02X \n " , val , dev - > reg , dev - > current_ld_card - > csn , dev - > current_ld - > number ) ;
if ( dev - > current_ld_card - > write_vendor_reg )
dev - > current_ld_card - > write_vendor_reg ( dev - > current_ld - > number , dev - > reg , val , dev - > current_ld_card - > priv ) ;
break ;
default :
if ( dev - > reg > = 0x40 ) {
CHECK_CURRENT_LD ( ) ;
isapnp_log ( " ISAPnP: Write %02X to register %02X on CSN %02X device %02X \n " , val , dev - > reg , dev - > current_ld_card - > csn , dev - > current_ld - > number ) ;
switch ( dev - > reg ) {
case 0x42 :
case 0x4a :
case 0x52 :
case 0x5a :
case 0x7a :
case 0x84 :
case 0x94 :
case 0xa4 :
/* Read-only memory range length / upper limit bit. */
val = ( val & 0xfe ) | ( dev - > current_ld - > regs [ dev - > reg ] & 0x01 ) ;
break ;
case 0x60 :
case 0x62 :
case 0x64 :
case 0x66 :
case 0x68 :
case 0x6a :
case 0x6c :
case 0x6e :
/* Discard upper address bits if this I/O range can only decode 10-bit. */
if ( ! ( dev - > current_ld - > io_16bit & ( 1 < < ( ( dev - > reg > > 1 ) & 0x07 ) ) ) )
val & = 0x03 ;
break ;
case 0x71 :
case 0x73 :
/* Limit IRQ types to supported ones. */
if ( ( val & 0x01 ) & & ! ( dev - > current_ld - > irq_types & ( ( dev - > reg = = 0x71 ) ? 0x0c : 0xc0 ) ) ) /* level, not supported = force edge */
val & = ~ 0x01 ;
else if ( ! ( val & 0x01 ) & & ! ( dev - > current_ld - > irq_types & ( ( dev - > reg = = 0x71 ) ? 0x03 : 0x30 ) ) ) /* edge, not supported = force level */
val | = 0x01 ;
if ( ( val & 0x02 ) & & ! ( dev - > current_ld - > irq_types & ( ( dev - > reg = = 0x71 ) ? 0x05 : 0x50 ) ) ) /* high, not supported = force low */
val & = ~ 0x02 ;
else if ( ! ( val & 0x02 ) & & ! ( dev - > current_ld - > irq_types & ( ( dev - > reg = = 0x71 ) ? 0x0a : 0xa0 ) ) ) /* low, not supported = force high */
val | = 0x02 ;
break ;
}
dev - > current_ld - > regs [ dev - > reg ] = val ;
isapnp_device_config_changed ( dev - > current_ld_card , dev - > current_ld ) ;
}
break ;
2021-03-20 01:21:02 -03:00
}
}
static void *
isapnp_init ( const device_t * info )
{
isapnp_t * dev = ( isapnp_t * ) malloc ( sizeof ( isapnp_t ) ) ;
memset ( dev , 0 , sizeof ( isapnp_t ) ) ;
io_sethandler ( 0x279 , 1 , NULL , NULL , NULL , isapnp_write_addr , NULL , NULL , dev ) ;
io_sethandler ( 0xa79 , 1 , NULL , NULL , NULL , isapnp_write_data , NULL , NULL , dev ) ;
return dev ;
}
static void
isapnp_close ( void * priv )
{
2022-09-18 17:13:28 -04:00
isapnp_t * dev = ( isapnp_t * ) priv ;
2023-05-11 03:02:36 -04:00
isapnp_card_t * card = dev - > first_card ;
isapnp_card_t * next_card ;
isapnp_device_t * ld ;
isapnp_device_t * next_ld ;
2021-03-20 01:21:02 -03:00
while ( card ) {
2022-09-18 17:13:28 -04:00
ld = card - > first_ld ;
while ( ld ) {
next_ld = ld - > next ;
free ( ld ) ;
ld = next_ld ;
}
next_card = card - > next ;
free ( card ) ;
card = next_card ;
2021-03-20 01:21:02 -03:00
}
io_removehandler ( 0x279 , 1 , NULL , NULL , NULL , isapnp_write_addr , NULL , NULL , dev ) ;
io_removehandler ( 0xa79 , 1 , NULL , NULL , NULL , isapnp_write_data , NULL , NULL , dev ) ;
free ( dev ) ;
}
void *
isapnp_add_card ( uint8_t * rom , uint16_t rom_size ,
2022-09-18 17:13:28 -04:00
void ( * config_changed ) ( uint8_t ld , isapnp_device_config_t * config , void * priv ) ,
void ( * csn_changed ) ( uint8_t csn , void * priv ) ,
uint8_t ( * read_vendor_reg ) ( uint8_t ld , uint8_t reg , void * priv ) ,
void ( * write_vendor_reg ) ( uint8_t ld , uint8_t reg , uint8_t val , void * priv ) ,
void * priv )
2021-03-20 01:21:02 -03:00
{
isapnp_t * dev = ( isapnp_t * ) device_get_priv ( & isapnp_device ) ;
if ( ! dev )
2022-09-18 17:13:28 -04:00
dev = ( isapnp_t * ) device_add ( & isapnp_device ) ;
2021-03-20 01:21:02 -03:00
isapnp_card_t * card = ( isapnp_card_t * ) malloc ( sizeof ( isapnp_card_t ) ) ;
memset ( card , 0 , sizeof ( isapnp_card_t ) ) ;
2022-09-18 17:13:28 -04:00
card - > enable = 1 ;
card - > priv = priv ;
card - > config_changed = config_changed ;
card - > csn_changed = csn_changed ;
card - > read_vendor_reg = read_vendor_reg ;
2021-03-20 01:21:02 -03:00
card - > write_vendor_reg = write_vendor_reg ;
if ( ! dev - > first_card ) {
2022-09-18 17:13:28 -04:00
dev - > first_card = card ;
2021-03-20 01:21:02 -03:00
} else {
2022-09-18 17:13:28 -04:00
isapnp_card_t * prev_card = dev - > first_card ;
while ( prev_card - > next )
prev_card = prev_card - > next ;
prev_card - > next = card ;
2021-03-20 20:58:24 -03:00
}
2021-05-22 22:27:21 -03:00
if ( rom & & rom_size )
2022-09-18 17:13:28 -04:00
isapnp_update_card_rom ( card , rom , rom_size ) ;
2021-05-22 22:27:21 -03:00
2021-05-20 00:30:12 -03:00
return card ;
}
void
isapnp_update_card_rom ( void * priv , uint8_t * rom , uint16_t rom_size )
{
isapnp_card_t * card = ( isapnp_card_t * ) priv ;
2022-09-18 17:13:28 -04:00
card - > rom = rom ;
card - > rom_size = rom_size ;
2021-05-20 00:30:12 -03:00
2021-03-22 21:06:42 -03:00
/* Parse resources in ROM to allocate logical devices,
and determine the state of read - only register bits . */
2021-03-20 20:58:24 -03:00
# ifdef ENABLE_ISAPNP_LOG
uint16_t vendor = ( card - > rom [ 0 ] < < 8 ) | card - > rom [ 1 ] ;
isapnp_log ( " ISAPnP: Parsing ROM resources for card %c%c%c%02X%02X (serial %08X) \n " , ' @ ' + ( ( vendor > > 10 ) & 0x1f ) , ' @ ' + ( ( vendor > > 5 ) & 0x1f ) , ' @ ' + ( vendor & 0x1f ) , card - > rom [ 2 ] , card - > rom [ 3 ] , ( card - > rom [ 7 ] < < 24 ) | ( card - > rom [ 6 ] < < 16 ) | ( card - > rom [ 5 ] < < 8 ) | card - > rom [ 4 ] ) ;
# endif
2023-05-11 03:02:36 -04:00
uint16_t i = 9 ;
uint8_t existing = 0 ;
uint8_t ldn = 0 ;
uint8_t res ;
uint8_t in_df = 0 ;
uint8_t irq = 0 ;
uint8_t io = 0 ;
uint8_t mem_range = 0 ;
uint8_t mem_range_32 = 0 ;
uint8_t irq_df = 0 ;
uint8_t io_df = 0 ;
uint8_t mem_range_df = 0 ;
uint8_t mem_range_32_df = 0 ;
2022-09-18 17:13:28 -04:00
uint32_t len ;
2023-05-11 03:02:36 -04:00
isapnp_device_t * ld = NULL ;
isapnp_device_t * prev_ld = NULL ;
2021-05-20 00:30:12 -03:00
2021-06-03 14:18:21 -03:00
/* Check if this is an existing card which already has logical devices.
Any new logical devices will be added to the list after existing ones .
Removed LDs are not flushed as we may end up with an invalid ROM . */
existing = ! ! card - > first_ld ;
2021-03-20 20:58:24 -03:00
2021-05-20 00:30:12 -03:00
/* Iterate through ROM resources. */
2021-03-20 20:58:24 -03:00
while ( i < card - > rom_size ) {
2022-09-18 17:13:28 -04:00
if ( card - > rom [ i ] & 0x80 ) { /* large resource */
res = card - > rom [ i ] & 0x7f ;
len = ( card - > rom [ i + 2 ] < < 8 ) | card - > rom [ i + 1 ] ;
switch ( res ) {
case 0x01 : /* memory range */
case 0x05 : /* 32-bit memory range */
if ( res = = 0x01 ) {
if ( ! ld ) {
isapnp_log ( " ISAPnP: >>%s Memory descriptor with no logical device \n " , in_df ? " > " : " " ) ;
break ;
}
if ( mem_range > 3 ) {
isapnp_log ( " ISAPnP: >>%s Memory descriptor overflow (%d) \n " , in_df ? " > " : " " , mem_range + + ) ;
break ;
}
isapnp_log ( " ISAPnP: >>%s Memory range %d uses upper limit = " , in_df ? " > " : " " , mem_range ) ;
res = 1 < < mem_range ;
mem_range + + ;
} else {
if ( ! ld ) {
isapnp_log ( " ISAPnP: >>%s 32-bit memory descriptor with no logical device \n " , in_df ? " > " : " " ) ;
break ;
}
if ( mem_range_32 > 3 ) {
isapnp_log ( " ISAPnP: >>%s 32-bit memory descriptor overflow (%d) \n " , in_df ? " > " : " " , mem_range_32 + + ) ;
break ;
}
isapnp_log ( " ISAPnP: >>%s 32-bit memory range %d uses upper limit = " , in_df ? " > " : " " , mem_range_32 ) ;
res = 1 < < ( 4 + mem_range_32 ) ;
mem_range_32 + + ;
}
if ( card - > rom [ i + 3 ] & 0x4 ) {
isapnp_log ( " yes \n " ) ;
ld - > mem_upperlimit | = res ;
} else {
isapnp_log ( " no \n " ) ;
ld - > mem_upperlimit & = ~ res ;
}
break ;
2021-03-20 20:58:24 -03:00
# ifdef ENABLE_ISAPNP_LOG
2022-09-18 17:13:28 -04:00
case 0x02 : /* ANSI identifier */
res = card - > rom [ i + 3 + len ] ;
card - > rom [ i + 3 + len ] = ' \0 ' ;
isapnp_log ( " ISAPnP: >%s ANSI identifier: \" %s \" \n " , ldn ? " > " : " " , & card - > rom [ i + 3 ] ) ;
card - > rom [ i + 3 + len ] = res ;
break ;
default :
isapnp_log ( " ISAPnP: >%s%s Large resource %02X (length %d) \n " , ldn ? " > " : " " , in_df ? " > " : " " , res , ( card - > rom [ i + 2 ] < < 8 ) | card - > rom [ i + 1 ] ) ;
break ;
2021-03-20 20:58:24 -03:00
# endif
2022-09-18 17:13:28 -04:00
}
2021-03-20 20:58:24 -03:00
2022-09-18 17:13:28 -04:00
i + = 3 ; /* header */
} else { /* small resource */
res = ( card - > rom [ i ] > > 3 ) & 0x0f ;
len = card - > rom [ i ] & 0x07 ;
2021-03-20 20:58:24 -03:00
2022-09-18 17:13:28 -04:00
switch ( res ) {
case 0x02 :
2021-03-20 20:58:24 -03:00
# ifdef ENABLE_ISAPNP_LOG
2022-09-18 17:13:28 -04:00
vendor = ( card - > rom [ i + 1 ] < < 8 ) | card - > rom [ i + 2 ] ;
isapnp_log ( " ISAPnP: > Logical device %02X: %c%c%c%02X%02X \n " , ldn , ' @ ' + ( ( vendor > > 10 ) & 0x1f ) , ' @ ' + ( ( vendor > > 5 ) & 0x1f ) , ' @ ' + ( vendor & 0x1f ) , card - > rom [ i + 3 ] , card - > rom [ i + 4 ] ) ;
2021-03-20 20:58:24 -03:00
# endif
2022-09-18 17:13:28 -04:00
/* We're done with the previous logical device. */
if ( ld & & ! existing )
isapnp_reset_ld_regs ( ld ) ;
/* Look for an existing logical device with this number,
and create one if none exist . */
if ( existing ) {
ld = card - > first_ld ;
while ( ld & & ( ld - > number ! = ldn ) )
ld = ld - > next ;
}
if ( ld & & ( ld - > number = = ldn ) ) {
/* Reset some logical device state. */
ld - > mem_upperlimit = ld - > io_16bit = ld - > irq_types = 0 ;
memset ( ld - > io_len , 0 , sizeof ( ld - > io_len ) ) ;
} else {
/* Create logical device. */
ld = ( isapnp_device_t * ) malloc ( sizeof ( isapnp_device_t ) ) ;
memset ( ld , 0 , sizeof ( isapnp_device_t ) ) ;
/* Add to end of list. */
prev_ld = card - > first_ld ;
if ( prev_ld ) {
while ( prev_ld - > next )
prev_ld = prev_ld - > next ;
prev_ld - > next = ld ;
} else {
card - > first_ld = ld ;
}
}
/* Set and increment logical device number. */
ld - > number = ldn + + ;
/* Start the position counts over. */
irq = io = mem_range = mem_range_32 = irq_df = io_df = mem_range_df = mem_range_32_df = 0 ;
break ;
2021-03-20 20:58:24 -03:00
# ifdef ENABLE_ISAPNP_LOG
2022-09-18 17:13:28 -04:00
case 0x03 : /* compatible device ID */
if ( ! ld ) {
isapnp_log ( " ISAPnP: >> Compatible device ID with no logical device \n " ) ;
break ;
}
vendor = ( card - > rom [ i + 1 ] < < 8 ) | card - > rom [ i + 2 ] ;
isapnp_log ( " ISAPnP: >> Compatible device ID: %c%c%c%02X%02X \n " , ' @ ' + ( ( vendor > > 10 ) & 0x1f ) , ' @ ' + ( ( vendor > > 5 ) & 0x1f ) , ' @ ' + ( vendor & 0x1f ) , card - > rom [ i + 3 ] , card - > rom [ i + 4 ] ) ;
break ;
2021-03-20 20:58:24 -03:00
# endif
2022-09-18 17:13:28 -04:00
case 0x04 : /* IRQ */
if ( ! ld ) {
isapnp_log ( " ISAPnP: >>%s IRQ descriptor with no logical device \n " , in_df ? " > " : " " ) ;
break ;
}
2021-05-22 22:27:21 -03:00
2022-09-18 17:13:28 -04:00
if ( irq > 1 ) {
isapnp_log ( " ISAPnP: >>%s IRQ descriptor overflow (%d) \n " , in_df ? " > " : " " , irq + + ) ;
break ;
}
2021-03-22 21:06:42 -03:00
2022-09-18 17:13:28 -04:00
if ( len = = 2 ) /* default */
res = 0x01 ; /* high true edge sensitive */
else /* specific */
res = card - > rom [ i + 3 ] & 0x0f ;
2021-03-22 21:06:42 -03:00
2022-09-18 17:13:28 -04:00
isapnp_log ( " ISAPnP: >>%s IRQ index %d interrupt types = %01X \n " , in_df ? " > " : " " , irq , res ) ;
2021-03-22 21:06:42 -03:00
2022-09-18 17:13:28 -04:00
ld - > irq_types & = ~ ( 0x0f < < ( 4 * irq ) ) ;
ld - > irq_types | = res < < ( 4 * irq ) ;
2021-03-22 21:06:42 -03:00
2022-09-18 17:13:28 -04:00
irq + + ;
2021-03-22 21:06:42 -03:00
2022-09-18 17:13:28 -04:00
break ;
2021-03-22 21:06:42 -03:00
2022-09-18 17:13:28 -04:00
case 0x06 : /* start dependent function */
if ( ! ld ) {
isapnp_log ( " ISAPnP: >> Start dependent function with no logical device \n " ) ;
break ;
}
2021-05-22 22:27:21 -03:00
2022-09-18 17:13:28 -04:00
isapnp_log ( " ISAPnP: >> Start dependent function: %s \n " , ( ( ( len = = 0 ) | | ( card - > rom [ i + 1 ] = = 1 ) ) ? " acceptable " : ( ( card - > rom [ i + 1 ] = = 0 ) ? " good " : ( ( card - > rom [ i + 1 ] = = 2 ) ? " sub-optimal " : " unknown priority " ) ) ) ) ;
2021-03-20 20:58:24 -03:00
2022-09-18 17:13:28 -04:00
if ( in_df ) {
/* We're in a dependent function and this is the next one starting.
Walk positions back to the saved values . */
irq = irq_df ;
io = io_df ;
mem_range = mem_range_df ;
mem_range_32 = mem_range_32_df ;
} else {
/* Save current positions to restore at the next DF. */
irq_df = irq ;
io_df = io ;
mem_range_df = mem_range ;
mem_range_32_df = mem_range_32 ;
in_df = 1 ;
}
2021-03-20 20:58:24 -03:00
2022-09-18 17:13:28 -04:00
break ;
2021-03-20 20:58:24 -03:00
2022-09-18 17:13:28 -04:00
case 0x07 : /* end dependent function */
isapnp_log ( " ISAPnP: >> End dependent function \n " ) ;
in_df = 0 ;
break ;
2021-03-20 20:58:24 -03:00
2022-09-18 17:13:28 -04:00
case 0x08 : /* I/O port */
if ( ! ld ) {
isapnp_log ( " ISAPnP: >>%s I/O descriptor with no logical device \n " , in_df ? " > " : " " ) ;
break ;
}
2021-05-22 22:27:21 -03:00
2022-09-18 17:13:28 -04:00
if ( io > 7 ) {
isapnp_log ( " ISAPnP: >>%s I/O descriptor overflow (%d) \n " , in_df ? " > " : " " , io + + ) ;
break ;
}
2021-03-22 21:06:42 -03:00
2022-09-18 17:13:28 -04:00
isapnp_log ( " ISAPnP: >>%s I/O range %d %d-bit decode, %d ports \n " , in_df ? " > " : " " , io , ( card - > rom [ i + 1 ] & 0x01 ) ? 16 : 10 , card - > rom [ i + 7 ] ) ;
2021-03-22 21:06:42 -03:00
2022-09-18 17:13:28 -04:00
if ( card - > rom [ i + 1 ] & 0x01 )
ld - > io_16bit | = 1 < < io ;
else
ld - > io_16bit & = ~ ( 1 < < io ) ;
2021-03-22 21:06:42 -03:00
2022-09-18 17:13:28 -04:00
if ( card - > rom [ i + 7 ] > ld - > io_len [ io ] )
ld - > io_len [ io ] = card - > rom [ i + 7 ] ;
2021-03-31 20:53:04 -03:00
2022-09-18 17:13:28 -04:00
io + + ;
2021-03-22 21:06:42 -03:00
2022-09-18 17:13:28 -04:00
break ;
2021-03-22 21:06:42 -03:00
2022-09-18 17:13:28 -04:00
case 0x0f : /* end tag */
/* Calculate checksum. */
res = 0x00 ;
2023-05-11 03:02:36 -04:00
for ( uint16_t j = 9 ; j < = i ; j + + )
2022-09-18 17:13:28 -04:00
res + = card - > rom [ j ] ;
card - > rom [ i + 1 ] = - res ;
2021-03-21 16:59:15 -03:00
2022-09-18 17:13:28 -04:00
isapnp_log ( " ISAPnP: End card resources (checksum %02X) \n " , card - > rom [ i + 1 ] ) ;
2021-05-22 22:27:21 -03:00
2022-09-18 17:13:28 -04:00
/* Stop parsing here. */
card - > rom_size = i + 2 ;
break ;
2021-03-20 20:58:24 -03:00
2021-03-21 16:59:15 -03:00
# ifdef ENABLE_ISAPNP_LOG
2022-09-18 17:13:28 -04:00
default :
isapnp_log ( " ISAPnP: >%s%s Small resource %02X (length %d) \n " , ldn ? " > " : " " , in_df ? " > " : " " , res , card - > rom [ i ] & 0x07 ) ;
break ;
2021-03-20 20:58:24 -03:00
# endif
2022-09-18 17:13:28 -04:00
}
2021-03-20 20:58:24 -03:00
2022-09-18 17:13:28 -04:00
i + + ; /* header */
}
i + = len ; /* specified length */
2021-03-20 01:21:02 -03:00
}
2021-03-20 20:58:24 -03:00
/* We're done with the last logical device. */
2021-06-03 17:30:50 -03:00
if ( ld & & ! existing )
2022-09-18 17:13:28 -04:00
isapnp_reset_ld_regs ( ld ) ;
2021-03-20 01:21:02 -03:00
}
2021-04-02 23:46:38 -03:00
void
isapnp_enable_card ( void * priv , uint8_t enable )
{
isapnp_t * dev = ( isapnp_t * ) device_get_priv ( & isapnp_device ) ;
if ( ! dev )
2022-09-18 17:13:28 -04:00
return ;
2021-04-02 23:46:38 -03:00
/* Look for a matching card. */
isapnp_card_t * card = dev - > first_card ;
while ( card ) {
2022-09-18 17:13:28 -04:00
if ( card = = priv ) {
/* Enable or disable the card. */
if ( ! ! enable ^ ! ! card - > enable )
card - > state = ( enable = = ISAPNP_CARD_FORCE_CONFIG ) ? PNP_STATE_CONFIG : PNP_STATE_WAIT_FOR_KEY ;
card - > enable = enable ;
/* Invalidate other references if we're disabling this card. */
if ( ! card - > enable ) {
if ( dev - > isolated_card = = card )
dev - > isolated_card = NULL ;
if ( dev - > current_ld_card = = card ) {
dev - > current_ld = NULL ;
dev - > current_ld_card = NULL ;
}
}
break ;
}
card = card - > next ;
2021-04-02 23:46:38 -03:00
}
}
2021-03-20 01:21:02 -03:00
void
isapnp_set_csn ( void * priv , uint8_t csn )
{
isapnp_card_t * card = ( isapnp_card_t * ) priv ;
card - > csn = csn ;
if ( card - > csn_changed )
2022-09-18 17:13:28 -04:00
card - > csn_changed ( card - > csn , card - > priv ) ;
2021-03-20 01:21:02 -03:00
}
2021-04-02 23:46:38 -03:00
void
isapnp_set_device_defaults ( void * priv , uint8_t ldn , const isapnp_device_config_t * config )
{
2022-09-18 17:13:28 -04:00
isapnp_card_t * card = ( isapnp_card_t * ) priv ;
isapnp_device_t * ld = card - > first_ld ;
2021-04-02 23:46:38 -03:00
/* Look for a logical device with this number. */
while ( ld & & ( ld - > number ! = ldn ) )
2022-09-18 17:13:28 -04:00
ld = ld - > next ;
2021-04-02 23:46:38 -03:00
if ( ! ld ) /* none found */
2022-09-18 17:13:28 -04:00
return ;
2021-04-02 23:46:38 -03:00
ld - > defaults = config ;
}
void
isapnp_reset_card ( void * priv )
{
2022-09-18 17:13:28 -04:00
isapnp_card_t * card = ( isapnp_card_t * ) priv ;
isapnp_device_t * ld = card - > first_ld ;
2021-04-02 23:46:38 -03:00
/* Reset all logical devices. */
while ( ld ) {
2022-09-18 17:13:28 -04:00
/* Reset the logical device's configuration. */
isapnp_reset_ld_config ( ld ) ;
isapnp_device_config_changed ( card , ld ) ;
2021-04-02 23:46:38 -03:00
2022-09-18 17:13:28 -04:00
ld = ld - > next ;
2021-04-02 23:46:38 -03:00
}
}
void
isapnp_reset_device ( void * priv , uint8_t ldn )
{
2022-09-18 17:13:28 -04:00
isapnp_card_t * card = ( isapnp_card_t * ) priv ;
isapnp_device_t * ld = card - > first_ld ;
2021-04-02 23:46:38 -03:00
/* Look for a logical device with this number. */
while ( ld & & ( ld - > number ! = ldn ) )
2022-09-18 17:13:28 -04:00
ld = ld - > next ;
2021-04-02 23:46:38 -03:00
if ( ! ld ) /* none found */
2022-09-18 17:13:28 -04:00
return ;
2021-04-02 23:46:38 -03:00
/* Reset the logical device's configuration. */
isapnp_reset_ld_config ( ld ) ;
isapnp_device_config_changed ( card , ld ) ;
}
2021-03-20 01:21:02 -03:00
static const device_t isapnp_device = {
2022-09-18 17:13:28 -04:00
. name = " ISA Plug and Play " ,
2022-09-18 16:04:23 -04:00
. internal_name = " isapnp " ,
. flags = 0 ,
. local = 0 ,
. init = isapnp_init ,
. close = isapnp_close ,
. reset = NULL ,
{ . available = NULL } ,
. speed_changed = NULL ,
. force_redraw = NULL ,
. config = NULL
2021-03-20 01:21:02 -03:00
} ;