kernels/linux-2.4.0/drivers/net/3c527.c
/**
 *	mc32_command: 
 *	@dev: The 3c527 card to issue the command to
 *	@cmd: The command word to write to the mailbox
 *	@data: A data block if the command expects one
 *	@len: Length of the data block
 *
 *	Sends exec commands in a user context. This permits us to wait around
 *	for the replies and also to wait for the command buffer to complete
 *	from a previous command before we execute our command. After our 
 *	command completes we will complete any pending multicast reload
 *	we blocked off by hogging the exec buffer.
 *
 *	You feed the card a command, you wait, it interrupts you get a 
 *	reply. All well and good. The complication arises because you use
 *	commands for filter list changes which come in at bh level from things
 *	like IPV6 group stuff.
 *
 *	We have a simple state machine
 *
 *	0	- nothing issued
 *
 *	1	- command issued, wait reply
 *
 *	2	- reply waiting - reader then goes to state 0
 *
 *	3	- command issued, trash reply. In which case the irq
 *		  takes it back to state 0
 *
 *	Send command and block for results. On completion spot and reissue
 *	multicasts
 */
@dev: The 3c527 card to issue the command to
@cmd: The command word to write to the mailbox
@data: A data block if the command expects one
@len: Length of the data block

Sends exec commands in a user context. This permits us to wait around
for the replies and also to wait for the command buffer to complete
from a previous command before we execute our command. After our
command completes we will complete any pending multicast reload
we blocked off by hogging the exec buffer.

You feed the card a command, you wait, it interrupts you get a
reply. All well and good. The complication arises because you use
commands for filter list changes which come in at bh level from things
like IPV6 group stuff.

We have a simple state machine

0       - nothing issued

1       - command issued, wait reply

2       - reply waiting - reader then goes to state 0

3       - command issued, trash reply. In which case the irq
takes it back to state 0

Send command and block for results. On completion spot and reissue
multicasts
@dev : The 3c527 card to issue the command to @cmd : The command word to write to the mailbox @data : A data block if the command expects one @len : Length of the data block Sends exec commands in a user context . This permits us to wait around for the replies and also to wait for the command buffer to complete from a previous command before we execute our command . After our command completes we will complete any pending multicast reload we blocked off by hogging the exec buffer . You feed the card a command you wait it interrupts you get a reply . All well and good . The complication arises because you use commands for filter list changes which come in at bh level from things like IPV6 group stuff . We have a simple state machine 0 - nothing issued 1 - command issued wait reply 2 - reply waiting - reader then goes to state 0 3 - command issued trash reply . In which case the irq takes it back to state 0 Send command and block for results . On completion spot and reissue multicasts
static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len)
{
	struct mc32_local *lp = (struct mc32_local *)dev->priv;
	int ioaddr = dev->base_addr;
	unsigned long flags;
	int ret = 0;
	save_flags(flags);
	cli();
	while(lp->exec_pending)
		sleep_on(&lp->event);
	lp->exec_pending=1;
	restore_flags(flags);
	lp->exec_box->mbox=0;
	lp->exec_box->mbox=cmd;
	memcpy((void *)lp->exec_box->data, data, len);
	barrier();	
	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
	outb(1<<6, ioaddr+HOST_CMD);	
	save_flags(flags);
	cli();
	while(lp->exec_pending!=2)
		sleep_on(&lp->event);
	lp->exec_pending=0;
	restore_flags(flags);
	if(lp->exec_box->data[0]&(1<<13))
		ret = -1;
	if(lp->mc_reload_wait)
		mc32_reset_multicast_list(dev);
	return ret;
}
static int mc32_command ( struct net_device * dev , u16 cmd , void * data , int len ) { struct mc32_local * lp = ( struct mc32_local * ) dev -> priv ; int ioaddr = dev -> base_addr ; unsigned long flags ; int ret = 0 ; save_flags ( flags ) ; cli ( ) ; while ( lp -> exec_pending ) sleep_on ( & lp -> event ) ; lp -> exec_pending = 1 ; restore_flags ( flags ) ; lp -> exec_box -> mbox = 0 ; lp -> exec_box -> mbox = cmd ; memcpy ( ( void * ) lp -> exec_box -> data , data , len ) ; barrier ( ) ; while ( ! ( inb ( ioaddr + HOST_STATUS ) & HOST_STATUS_CRR ) ) ; outb ( 1 << 6 , ioaddr + HOST_CMD ) ; save_flags ( flags ) ; cli ( ) ; while ( lp -> exec_pending != 2 ) sleep_on ( & lp -> event ) ; lp -> exec_pending = 0 ; restore_flags ( flags ) ; if ( lp -> exec_box -> data [ 0 ] & ( 1 << 13 ) ) ret = -1 ; if ( lp -> mc_reload_wait ) mc32_reset_multicast_list ( dev ) ; return ret ; }
mc32_command:
      @dev: The 3c527 card to issue the command to
      @cmd: The command word to write to the mailbox
      @data: A data block if the command expects one
      @len: Length of the data block
mc32_command : @dev : The 3c527 card to issue the command to @cmd : The command word to write to the mailbox @data : A data block if the command expects one @len : Length of the data block
/*
	 *	Wait for a command
	 */ /*
	 *	Issue mine
	 */ /* the memcpy forgot the volatile so be sure */ /* Send the command */ /*
	 *	A multicast set got blocked - do it now
	 */