Remember to enable/disable the interrupt at the PIC.
Handle failures in undi_open() properly.
This commit is contained in:
parent
9ab5c0dde7
commit
23cb837951
|
@ -32,6 +32,8 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static void undi_close ( struct net_device *netdev );
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
*
|
*
|
||||||
* UNDI interrupt service routine
|
* UNDI interrupt service routine
|
||||||
|
@ -47,28 +49,33 @@
|
||||||
*/
|
*/
|
||||||
extern void undi_isr ( void );
|
extern void undi_isr ( void );
|
||||||
|
|
||||||
/** Vector for chaining to other interrupts handlers */
|
/** Dummy chain vector */
|
||||||
static struct segoff __text16 ( undi_isr_chain );
|
static struct segoff undi_isr_dummy_chain;
|
||||||
#define undi_isr_chain __use_text16 ( undi_isr_chain )
|
|
||||||
|
|
||||||
/** IRQ trigger count */
|
/** IRQ trigger count */
|
||||||
static volatile uint16_t __text16 ( trigger_count );
|
static volatile uint16_t __text16 ( trigger_count ) = 0;
|
||||||
#define trigger_count __use_text16 ( trigger_count )
|
#define trigger_count __use_text16 ( trigger_count )
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook UNDI interrupt service routine
|
* Hook UNDI interrupt service routine
|
||||||
*
|
*
|
||||||
* @v irq IRQ number
|
* @v irq IRQ number
|
||||||
|
*
|
||||||
|
* The UNDI ISR specifically does @b not chain to the previous
|
||||||
|
* interrupt handler. BIOSes seem to install somewhat perverse
|
||||||
|
* default interrupt handlers; some do nothing other than an iret (and
|
||||||
|
* so will cause a screaming interrupt if there really is another
|
||||||
|
* interrupting device) and some disable the interrupt at the PIC (and
|
||||||
|
* so will bring our own interrupts to a shuddering halt).
|
||||||
*/
|
*/
|
||||||
static void undi_hook_isr ( unsigned int irq ) {
|
static void undi_hook_isr ( unsigned int irq ) {
|
||||||
__asm__ __volatile__ ( TEXT16_CODE ( "\nundi_isr:\n\t"
|
__asm__ __volatile__ ( TEXT16_CODE ( "\nundi_isr:\n\t"
|
||||||
"incl %%cs:%c0\n\t"
|
"incl %%cs:%c0\n\t"
|
||||||
"ljmp *%%cs:%c1\n\t" )
|
"iret\n\t" )
|
||||||
: : "p" ( & __from_text16 ( trigger_count ) ),
|
: : "p" ( & __from_text16 ( trigger_count ) ) );
|
||||||
"p" ( & __from_text16 ( undi_isr_chain ) ));
|
|
||||||
|
|
||||||
hook_bios_interrupt ( IRQ_INT ( irq ), ( ( unsigned int ) undi_isr ),
|
hook_bios_interrupt ( IRQ_INT ( irq ), ( ( unsigned int ) undi_isr ),
|
||||||
&undi_isr_chain );
|
&undi_isr_dummy_chain );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +86,7 @@ static void undi_hook_isr ( unsigned int irq ) {
|
||||||
*/
|
*/
|
||||||
static void undi_unhook_isr ( unsigned int irq ) {
|
static void undi_unhook_isr ( unsigned int irq ) {
|
||||||
unhook_bios_interrupt ( IRQ_INT ( irq ), ( ( unsigned int ) undi_isr ),
|
unhook_bios_interrupt ( IRQ_INT ( irq ), ( ( unsigned int ) undi_isr ),
|
||||||
&undi_isr_chain );
|
&undi_isr_dummy_chain );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,7 +95,7 @@ static void undi_unhook_isr ( unsigned int irq ) {
|
||||||
* @ret triggered ISR has been triggered since last check
|
* @ret triggered ISR has been triggered since last check
|
||||||
*/
|
*/
|
||||||
static int undi_isr_triggered ( void ) {
|
static int undi_isr_triggered ( void ) {
|
||||||
static unsigned int last_trigger_count;
|
static unsigned int last_trigger_count = 0;
|
||||||
unsigned int this_trigger_count;
|
unsigned int this_trigger_count;
|
||||||
|
|
||||||
/* Read trigger_count. Do this only once; it is volatile */
|
/* Read trigger_count. Do this only once; it is volatile */
|
||||||
|
@ -285,8 +292,9 @@ static int undi_open ( struct net_device *netdev ) {
|
||||||
struct s_PXENV_UNDI_OPEN open;
|
struct s_PXENV_UNDI_OPEN open;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Hook interrupt service routine */
|
/* Hook interrupt service routine and enable interrupt */
|
||||||
undi_hook_isr ( pxe->irq );
|
undi_hook_isr ( pxe->irq );
|
||||||
|
enable_irq ( pxe->irq );
|
||||||
|
|
||||||
/* Set station address. Required for some PXE stacks; will
|
/* Set station address. Required for some PXE stacks; will
|
||||||
* spuriously fail on others. Ignore failures. We only ever
|
* spuriously fail on others. Ignore failures. We only ever
|
||||||
|
@ -307,10 +315,14 @@ static int undi_open ( struct net_device *netdev ) {
|
||||||
if ( ( rc = pxe_call ( pxe, PXENV_UNDI_OPEN, &open,
|
if ( ( rc = pxe_call ( pxe, PXENV_UNDI_OPEN, &open,
|
||||||
sizeof ( open ) ) ) != 0 ) {
|
sizeof ( open ) ) ) != 0 ) {
|
||||||
DBG ( "UNDI_OPEN failed: %s\n", strerror ( rc ) );
|
DBG ( "UNDI_OPEN failed: %s\n", strerror ( rc ) );
|
||||||
return rc;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
undi_close ( netdev );
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -329,7 +341,8 @@ static void undi_close ( struct net_device *netdev ) {
|
||||||
DBG ( "UNDI_CLOSE failed: %s\n", strerror ( rc ) );
|
DBG ( "UNDI_CLOSE failed: %s\n", strerror ( rc ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unhook ISR */
|
/* Disable interrupt and unhook ISR */
|
||||||
|
disable_irq ( pxe->irq );
|
||||||
undi_unhook_isr ( pxe->irq );
|
undi_unhook_isr ( pxe->irq );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,6 +382,7 @@ int undi_probe ( struct pxe_device *pxe ) {
|
||||||
|
|
||||||
err:
|
err:
|
||||||
free_netdev ( netdev );
|
free_netdev ( netdev );
|
||||||
|
pxe_set_drvdata ( pxe, NULL );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in New Issue