//------------------------------------------------------------------- // syncfix.c Addition of driver 'flush()' method // // Here is the addition of a 'flush()' function for our RealTek // character-mode device-driver versions previously posted, and // an accompanying modification to the interrupt-handler in the // case of a transmit-error. An 'fsync()' function also may be // added with no extra effort, because it's based on 'flush()'. // // programmer: ALLAN CRUSE // written on: 02 MAY 2005 // revised on: 04 MAY 2005 -- removes 'bug' found by Jean Bovet //------------------------------------------------------------------- #include // for init_module() #include // for init_waitqueue_head() #include // for inb(), outb() #include // for request_irq(), free_irq() #include // for kill_fasync() int iobase, irq; // assigned adapter resources wait_queue_head_t tx_wq; // queue for sleeping writers int my_flush( struct file *file ) { // Normally this function should only return when the device // has been completely flushed -- i.e., when all the packets // that had been queued for transmission have been sent out. // (For this, the RealTek's TSAD register can be consulted.) int port = iobase + 0x60; // TSAD register port-address int tsad = inw( port ); // Temporary printk( "Executing flush (tsad=%04X) \n", tsad ); // Temporary // interrupt-handler (below) will now retransmit if TxErr==1 //wait_event_interruptible( tx_wq, inw( port ) == 0xF00F ); <--- bug! wait_event_interruptible( tx_wq, (inw( port )&0xF) == 0xF ); tsad = inw( port ); // Temporary printk( "Verifying flush (tsad=%04X) \n", tsad ); // Temporary return 0; } int my_fsync( struct file *file, struct dentry *dentry, int datasync ) { my_flush( file ); return 0; } struct file_operations my_fops = { owner: THIS_MODULE, flush: my_flush, // <-- ADDED fsync: my_fsync, // <-- ADDED }; irqreturn_t my_isr( int irq, void *dev_id, struct pt_regs *regs ) { int intstatus = inw( iobase + 0x3E ); if ( intstatus == 0 ) return IRQ_NONE; // it wasn't for us // ..... include below changes in interrupt-handler ..... if ( intstatus & 0x04 ) // packet was transmitted OK wake_up_interruptible( &tx_wq ); // wake up any writers if ( intstatus & 0x08 ) // packet had transmission error { printk( "Transmit error! \n" ); // Temporary message // ok, retransmit the packet (see RealTek manual) outl( inl( iobase + 0x40 )|1, iobase + 0x40 ); } // ...................................................... outw( intstatus, iobase + 0x3E ); // clear the interrupts return IRQ_HANDLED; // resume current task }