V0 support for the pandaboard.
aboutsummaryrefslogblamecommitdiffstats
path: root/drivers/char/isicom.c
blob: 8f7cc190b62d420116b5c0d30e70899c3332c94d (plain) (tree)





















                                                                                
                                                                       









                                                                           
                                                                         


                                                                       
                                                                 


                                                                    

  
                                                                      

  





                                                                       
                                                                        
                                                     
  








                                                                            
                                                                            
                                                         
  







                                                                            
  




                                                                          






                                                                               






                                                                              
                                                                 

                                                     
  









                                                                               




                                   
                           

                         
                           




                          




                            

                          





                         


                                                    
                                               
            

                                                                             


                                        


                                                                        
                                                








                                          



                                         






                                                    


                                                                          
                                           
                                                 
 

                                         


                                                   
                                                                            


                   
                                     
                                    

                                           
                                                                         
                                            
                                       
                                      

                                                                               
                                      



                                      
                                     

                                        
                                      
                                          












                                                                         
 
                                                        












                                                                     

                                            
                                        
                                
 
                                                    
                                                                 



                                                  
                 

                                                                      
         


                                                                    
                                                         

 







                                                              
 
                               
                                            
 
                                            

                                        
 
                                     

                       
                                                                   


                                

 
                               


                                                  

                                        
 
                                     

                       
                                                                   
                           
                               
                                 

 
                               
                                                   
 
                                            

                                        
 
                                     

                       
                                                                   
                           
                               
                                
 

                               
                                                  
 
                                            

                                        
 
                                     

                       
                                                                   
                           
                               
                                 

 
                                 
                                                       
 
                                            

                                        



                             
                                                                   





                                            
                               
                                               
 
                                            

                                        
 
                                     

                       
                                                                   
                           
                               
                                             

 



                                           
 

                                                                      
 
                    

                                                                            


                                          

                                                                            
                         
         
 

                 
 
  
                    






                                                                         
                                  
                             
                                            
                                                     


                               

                                          
                             
                                                         
                              
                                           


                                                    
 
                         
 


                                          









                                                            
                                            
                                                                          
                                                              
                                                           
                                 
 
                                     
 
                                
                                 
 
                                                                
                                                                    
                                 

                                                               
                                 
 



                                                                             
                             
                        
                           

                                                                   


                                              
                                                                                    


                                                                               


                                                         
                                                        
                                        


                                                        
                         

                                      
                                              
                                                                                     

                                                                              



                                                            
                                                                           

                                                                       








                                                   
                                        
         
 

                                                                 

                                                                  
                                                       

 
  
                                      
   
 
                                                          
 
                                        

                               

                                               
                         
                          
 

                                                       
 
                          




                                        
                                    
 





                                                                 
 





                                                            

                                                                        
                                                                
                                              
                                   

                                     
                                                      
                                                                
                                              
                                   

         
                             

                                             
                                        




                                        
                                                                


                                              
 

                                                           
                                        
                                                   
                                                                


                                                                    

                                                                               
                                                                         
                                                                
                                         



                                                                          
                                                                                     
                                 
                                





                                                                 

                                                                 
                                                               
                                                                               
                                                                  

                                                                         
                                                                
                                         
                                                                 
                                                                       

                                                                              
                                 
                                

                                                                
                                    














                                                                 
                                                
                                                                
                                                         




                                                   
                                                                


                              
                                                                         

                              
                                                                   

                                                                           
                                                                            
                                        
                                           

                                                

                                                                    
                                        
                 
                                     

                                                                                

                                                



                                                
                                          
         
                                                        
                                      
 
                           
 
 
                                                     
 

                                            
                           


                                                   
                                
 
                             

                        
                       
                                               


                                 
 


                                                                               

                   

                                                                 
                                                                     

                                   
         
                         

                                                                      

                                                                    

                   
                                                                        
                                                
                                                                         
                                                   
                                                                         
                                                
                                                                          
                                                


                                         

                               
              
                                
 
                                            
                                                                     

                                                             
                                       











                                                    
                 
 




                                                      
                                                              
                 
                                          
                                       
         
                          
                                                    
            
                                                   
 

                                      
                                            
                             
                                                   
                                           

                        

                                                    

                                                     
                                            
                                                                     


                                                                      
         
 





                                                                  
 


                                                           

                    
                              
                            
 






                                                              
                                                                      
                                   
                                                      
 

                                                   
 
                                            
                            
 
                                                 
                         

                                                     

                                                   


                                                                
                              
 
                                                               
 
                                                  





                                                                                
 
                                 
                                              
                                                        



                 

                                                                     
 
                                            





                                                             
                                                                      
                                                                

                                                               



                                            
 
                                             
 

                                                             
                                                             
                                                        


                         

                              

                                                          

                                                                      
                                                     


                                                   

                                   
                                                        
 



                                                      

                                                                                     



                                                      
                 
                                                          
                                                                          
                              
                 



                                              
                           

                                        
                                                        

                                                   

                                   


                                                        
                                                

                 

                                                                 
 

                               

                           





                                            
 

                                              
 



                                                                          
                                

                                                                  


                                 
                           
                                
                             



                                                         
 
 

                  
                                                              
 
                                      
                                            

 
                               
                                                       
 

                                            
 
                             
 
                                                    
                       
 

                                               
                                                 
                              
 


                                                                 
                                                                  
                                                        

                         

                                           

                                     

                                                   
 
                                
                                                                            
                                                 
                                
         
 
                                                          
                           




                                                    















                                                                          
                                                                   
 
                                                 
                               
                            
 

                       
                          

                                                                   
 
                                    
 




                                                                
 
                                                       

                                                                            

                                                      
         
                                     

                                                                              

                                          
         
 
                               

                                                                
         
                                          

                                                        
 

                                                                  
                                                                 

                                                   
                                                   

                                                           
         

                                                        
 
                                 




                                                   
                                      
                                                                
                                             
                                                               
                                             
                                                                          

                                                           
                                                             
         

                                                                   



                                                        

                                                                         
 
                                                 
                                            




                                                                   
 
                                                   
 
                   

                                                                             
                             
                              
 
                                                                        

                                                                             



                                      
         


                                                                
                     


                     
                                                                    
 
                                                 
                                            
                            
 
                                                                      
                         
 
                                                   



                                                                
 
                                                    


                                                        
                 


                        
                                                      
 
                                                 
 

                                                                         
 
                                                                     
                                             
                       
 

                                                                    
                                 


                       
                                                    
 
                                                 



                                                                        
 






                                                     
                                                         
 
                                                 





                                                                             
                                                                
 
                                                 
                                            
                                        
 


                                   
                             
                               
 





                                                                            
                 



                                                                     
                                                 
                                       
                                  


                                                                   
 








                                                                     
                                             
 
                                                 
                            
 

                                                                   
 
                                                         








                                
                                                              

                 
 
 

                                                        



                                     
                                                            
                               
 

                      
                                                               

                                                  
                                      

                                                                                    
                                                                     
                                                                        
                                        
                                      
                 
                                                                          
                                                                  
                

                                                               
                                                                       


                                                               

                                                                 
                                         
                                                                      
         
                        

                 
 

                                                        

                                      
 
                      




                                               
                                          
                                 

                                                        
                        
                                                            

                               
 
 

                                                                  
 
                                                 
                                               



                                                                   
                      







                                                          




                        
                                                      
                                     
 
                                                 
                            
 

                                                                         
 
                                                            
                                                                      
                       
 
                                                         
                                 
                                                              
 
                                               
                                                             
                                    

                                  


                     
                                                   
 
                                                 

                                            

                                                                      
 





                                                                              
                                                     
 
                                                 

                                            

                                                                        
 





                                                                       
                                               
 
                                                 


                                                                  
 





                                                                   
                                                
 
                                                 
 

                                                                   
 




                                                               
                                                 
 
                                                 
                            
 

                                                                    
 
                                                         
                                   

                                                              



                                                     

 
 


                                   
 
                                                 





                                                     
                                                         









                                                      
                                                    

  

                                                         
 

                                                        
                                        
                       
 

                                                                            
 
                        
 
                   


                                        
                     
 











                                                                              
 
                                    
                                                                            
                                                                     
                                                                          
                                  

                              

         
                      


                  
                                                             


                                        
                  


                                        
         
                                        
                         
 

                      

 




































                                                               
         




                                                         

                      

                                                                        

                                                                      















                                                                   

                                         
                                                                             


                                                             











                                                                              

                                         



                                                                          
         
 

                                                                             



                                                                        















                                                                    

                                         
                                                                               


                                                              




                                                                              




                                                                          

















                                                                              

                                         





                                                                             










                                                      








                                         


                                                          
                               



                                                       
                                      
                            

                                       
                                      

                         





                                                          








                                                                            
                             

                                                  
                     


                                     

                                                          



                                                                             
                            
         
 




                                                                             
                             
         




                                                     



                                                       



                                                                             




                                    
                                    
       
                        
                     
                                 
    





                                                         



                                                                            

                                    
                                    

                        
                                 
 
 
                                   
 

                                 
 
                                                 



                                                                    
                                                   


                                                    

                                                                
                                         
                                     
                 

                                       
         
 



                                                     
                           










                                                                               
                                                                       
                                                                   






                                                                
 
                                                     
                         
                                                                            
                                
         
 
                                    
 
                 



                                             

                      



                                    
                            
 
                                              

                                             

 
                         
                         



                                                                      
/*
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License
 *	as published by the Free Software Foundation; either version
 *	2 of the License, or (at your option) any later version.
 *
 *	Original driver code supplied by Multi-Tech
 *
 *	Changes
 *	1/9/98	alan@redhat.com		Merge to 2.0.x kernel tree
 *					Obtain and use official major/minors
 *					Loader switched to a misc device
 *					(fixed range check bug as a side effect)
 *					Printk clean up
 *	9/12/98	alan@redhat.com		Rough port to 2.1.x
 *
 *	10/6/99 sameer			Merged the ISA and PCI drivers to
 *					a new unified driver.
 *
 *	3/9/99	sameer			Added support for ISI4616 cards.
 *
 *	16/9/99	sameer			We do not force RTS low anymore.
 *					This is to prevent the firmware
 *					from getting confused.
 *
 *	26/10/99 sameer			Cosmetic changes:The driver now
 *					dumps the Port Count information
 *					along with I/O address and IRQ.
 *
 *	13/12/99 sameer			Fixed the problem with IRQ sharing.
 *
 *	10/5/00  sameer			Fixed isicom_shutdown_board()
 *					to not lower DTR on all the ports
 *					when the last port on the card is
 *					closed.
 *
 *	10/5/00  sameer			Signal mask setup command added
 *					to  isicom_setup_port and
 *					isicom_shutdown_port.
 *
 *	24/5/00  sameer			The driver is now SMP aware.
 *
 *
 *	27/11/00 Vinayak P Risbud	Fixed the Driver Crash Problem
 *
 *
 *	03/01/01  anil .s		Added support for resetting the
 *					internal modems on ISI cards.
 *
 *	08/02/01  anil .s		Upgraded the driver for kernel
 *					2.4.x
 *
 *	11/04/01  Kevin			Fixed firmware load problem with
 *					ISIHP-4X card
 *
 *	30/04/01  anil .s		Fixed the remote login through
 *					ISI port problem. Now the link
 *					does not go down before password
 *					prompt.
 *
 *	03/05/01  anil .s		Fixed the problem with IRQ sharing
 *					among ISI-PCI cards.
 *
 *	03/05/01  anil .s		Added support to display the version
 *					info during insmod as well as module
 *					listing by lsmod.
 *
 *	10/05/01  anil .s		Done the modifications to the source
 *					file and Install script so that the
 *					same installation can be used for
 *					2.2.x and 2.4.x kernel.
 *
 *	06/06/01  anil .s		Now we drop both dtr and rts during
 *					shutdown_port as well as raise them
 *					during isicom_config_port.
 *
 *	09/06/01 acme@conectiva.com.br	use capable, not suser, do
 *					restore_flags on failure in
 *					isicom_send_break, verify put_user
 *					result
 *
 *	11/02/03  ranjeeth		Added support for 230 Kbps and 460 Kbps
 *					Baud index extended to 21
 *
 *	20/03/03  ranjeeth		Made to work for Linux Advanced server.
 *					Taken care of license warning.
 *
 *	10/12/03  Ravindra		Made to work for Fedora Core 1 of
 *					Red Hat Distribution
 *
 *	06/01/05  Alan Cox 		Merged the ISI and base kernel strands
 *					into a single 2.6 driver
 *
 *	***********************************************************
 *
 *	To use this driver you also need the support package. You
 *	can find this in RPM format on
 *		ftp://ftp.linux.org.uk/pub/linux/alan
 *
 *	You can find the original tools for this direct from Multitech
 *		ftp://ftp.multitech.com/ISI-Cards/
 *
 *	Having installed the cards the module options (/etc/modprobe.conf)
 *
 *	options isicom   io=card1,card2,card3,card4 irq=card1,card2,card3,card4
 *
 *	Omit those entries for boards you don't have installed.
 *
 *	TODO
 *		Merge testing
 *		64-bit verification
 */

#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/kernel.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/termios.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/serial.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/ioport.h>

#include <linux/uaccess.h>
#include <linux/io.h>
#include <asm/system.h>

#include <linux/pci.h>

#include <linux/isicom.h>

#define InterruptTheCard(base) outw(0, (base) + 0xc)
#define ClearInterrupt(base) inw((base) + 0x0a)

#define pr_dbg(str...) pr_debug("ISICOM: " str)
#ifdef DEBUG
#define isicom_paranoia_check(a, b, c) __isicom_paranoia_check((a), (b), (c))
#else
#define isicom_paranoia_check(a, b, c) 0
#endif

static int isicom_probe(struct pci_dev *, const struct pci_device_id *);
static void __devexit isicom_remove(struct pci_dev *);

static struct pci_device_id isicom_pci_tbl[] = {
	{ PCI_DEVICE(VENDOR_ID, 0x2028) },
	{ PCI_DEVICE(VENDOR_ID, 0x2051) },
	{ PCI_DEVICE(VENDOR_ID, 0x2052) },
	{ PCI_DEVICE(VENDOR_ID, 0x2053) },
	{ PCI_DEVICE(VENDOR_ID, 0x2054) },
	{ PCI_DEVICE(VENDOR_ID, 0x2055) },
	{ PCI_DEVICE(VENDOR_ID, 0x2056) },
	{ PCI_DEVICE(VENDOR_ID, 0x2057) },
	{ PCI_DEVICE(VENDOR_ID, 0x2058) },
	{ 0 }
};
MODULE_DEVICE_TABLE(pci, isicom_pci_tbl);

static struct pci_driver isicom_driver = {
	.name		= "isicom",
	.id_table	= isicom_pci_tbl,
	.probe		= isicom_probe,
	.remove		= __devexit_p(isicom_remove)
};

static int prev_card = 3;	/*	start servicing isi_card[0]	*/
static struct tty_driver *isicom_normal;

static void isicom_tx(unsigned long _data);
static void isicom_start(struct tty_struct *tty);

static DEFINE_TIMER(tx, isicom_tx, 0, 0);

/*   baud index mappings from linux defns to isi */

static signed char linuxb_to_isib[] = {
	-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17, 18, 19, 20, 21
};

struct	isi_board {
	unsigned long		base;
	int			irq;
	unsigned char		port_count;
	unsigned short		status;
	unsigned short		port_status; /* each bit for each port */
	unsigned short		shift_count;
	struct isi_port		*ports;
	signed char		count;
	spinlock_t		card_lock; /* Card wide lock 11/5/00 -sameer */
	unsigned long		flags;
	unsigned int		index;
};

struct	isi_port {
	unsigned short		magic;
	struct tty_port		port;
	u16			channel;
	u16			status;
	struct isi_board	*card;
	unsigned char		*xmit_buf;
	int			xmit_head;
	int			xmit_tail;
	int			xmit_cnt;
};

static struct isi_board isi_card[BOARD_COUNT];
static struct isi_port  isi_ports[PORT_COUNT];

/*
 *	Locking functions for card level locking. We need to own both
 *	the kernel lock for the card and have the card in a position that
 *	it wants to talk.
 */

static inline int WaitTillCardIsFree(unsigned long base)
{
	unsigned int count = 0;
	unsigned int a = in_atomic(); /* do we run under spinlock? */

	while (!(inw(base + 0xe) & 0x1) && count++ < 100)
		if (a)
			mdelay(1);
		else
			msleep(1);

	return !(inw(base + 0xe) & 0x1);
}

static int lock_card(struct isi_board *card)
{
	unsigned long base = card->base;
	unsigned int retries, a;

	for (retries = 0; retries < 10; retries++) {
		spin_lock_irqsave(&card->card_lock, card->flags);
		for (a = 0; a < 10; a++) {
			if (inw(base + 0xe) & 0x1)
				return 1;
			udelay(10);
		}
		spin_unlock_irqrestore(&card->card_lock, card->flags);
		msleep(10);
	}
	printk(KERN_WARNING "ISICOM: Failed to lock Card (0x%lx)\n",
		card->base);

	return 0;	/* Failed to acquire the card! */
}

static void unlock_card(struct isi_board *card)
{
	spin_unlock_irqrestore(&card->card_lock, card->flags);
}

/*
 *  ISI Card specific ops ...
 */

/* card->lock HAS to be held */
static void raise_dtr(struct isi_port *port)
{
	struct isi_board *card = port->card;
	unsigned long base = card->base;
	u16 channel = port->channel;

	if (WaitTillCardIsFree(base))
		return;

	outw(0x8000 | (channel << card->shift_count) | 0x02, base);
	outw(0x0504, base);
	InterruptTheCard(base);
	port->status |= ISI_DTR;
}

/* card->lock HAS to be held */
static inline void drop_dtr(struct isi_port *port)
{
	struct isi_board *card = port->card;
	unsigned long base = card->base;
	u16 channel = port->channel;

	if (WaitTillCardIsFree(base))
		return;

	outw(0x8000 | (channel << card->shift_count) | 0x02, base);
	outw(0x0404, base);
	InterruptTheCard(base);
	port->status &= ~ISI_DTR;
}

/* card->lock HAS to be held */
static inline void raise_rts(struct isi_port *port)
{
	struct isi_board *card = port->card;
	unsigned long base = card->base;
	u16 channel = port->channel;

	if (WaitTillCardIsFree(base))
		return;

	outw(0x8000 | (channel << card->shift_count) | 0x02, base);
	outw(0x0a04, base);
	InterruptTheCard(base);
	port->status |= ISI_RTS;
}

/* card->lock HAS to be held */
static inline void drop_rts(struct isi_port *port)
{
	struct isi_board *card = port->card;
	unsigned long base = card->base;
	u16 channel = port->channel;

	if (WaitTillCardIsFree(base))
		return;

	outw(0x8000 | (channel << card->shift_count) | 0x02, base);
	outw(0x0804, base);
	InterruptTheCard(base);
	port->status &= ~ISI_RTS;
}

/* card->lock MUST NOT be held */
static inline void raise_dtr_rts(struct isi_port *port)
{
	struct isi_board *card = port->card;
	unsigned long base = card->base;
	u16 channel = port->channel;

	if (!lock_card(card))
		return;

	outw(0x8000 | (channel << card->shift_count) | 0x02, base);
	outw(0x0f04, base);
	InterruptTheCard(base);
	port->status |= (ISI_DTR | ISI_RTS);
	unlock_card(card);
}

/* card->lock HAS to be held */
static void drop_dtr_rts(struct isi_port *port)
{
	struct isi_board *card = port->card;
	unsigned long base = card->base;
	u16 channel = port->channel;

	if (WaitTillCardIsFree(base))
		return;

	outw(0x8000 | (channel << card->shift_count) | 0x02, base);
	outw(0x0c04, base);
	InterruptTheCard(base);
	port->status &= ~(ISI_RTS | ISI_DTR);
}

/*
 *	ISICOM Driver specific routines ...
 *
 */

static inline int __isicom_paranoia_check(struct isi_port const *port,
	char *name, const char *routine)
{
	if (!port) {
		printk(KERN_WARNING "ISICOM: Warning: bad isicom magic for "
			"dev %s in %s.\n", name, routine);
		return 1;
	}
	if (port->magic != ISICOM_MAGIC) {
		printk(KERN_WARNING "ISICOM: Warning: NULL isicom port for "
			"dev %s in %s.\n", name, routine);
		return 1;
	}

	return 0;
}

/*
 *	Transmitter.
 *
 *	We shovel data into the card buffers on a regular basis. The card
 *	will do the rest of the work for us.
 */

static void isicom_tx(unsigned long _data)
{
	unsigned long flags, base;
	unsigned int retries;
	short count = (BOARD_COUNT-1), card;
	short txcount, wrd, residue, word_count, cnt;
	struct isi_port *port;
	struct tty_struct *tty;

	/*	find next active board	*/
	card = (prev_card + 1) & 0x0003;
	while (count-- > 0) {
		if (isi_card[card].status & BOARD_ACTIVE)
			break;
		card = (card + 1) & 0x0003;
	}
	if (!(isi_card[card].status & BOARD_ACTIVE))
		goto sched_again;

	prev_card = card;

	count = isi_card[card].port_count;
	port = isi_card[card].ports;
	base = isi_card[card].base;

	spin_lock_irqsave(&isi_card[card].card_lock, flags);
	for (retries = 0; retries < 100; retries++) {
		if (inw(base + 0xe) & 0x1)
			break;
		udelay(2);
	}
	if (retries >= 100)
		goto unlock;

	for (; count > 0; count--, port++) {
		/* port not active or tx disabled to force flow control */
		if (!(port->port.flags & ASYNC_INITIALIZED) ||
				!(port->status & ISI_TXOK))
			continue;

		tty = port->port.tty;

		if (tty == NULL)
			continue;

		txcount = min_t(short, TX_SIZE, port->xmit_cnt);
		if (txcount <= 0 || tty->stopped || tty->hw_stopped)
			continue;

		if (!(inw(base + 0x02) & (1 << port->channel)))
			continue;

		pr_dbg("txing %d bytes, port%d.\n", txcount,
			port->channel + 1);
		outw((port->channel << isi_card[card].shift_count) | txcount,
			base);
		residue = NO;
		wrd = 0;
		while (1) {
			cnt = min_t(int, txcount, (SERIAL_XMIT_SIZE
					- port->xmit_tail));
			if (residue == YES) {
				residue = NO;
				if (cnt > 0) {
					wrd |= (port->port.xmit_buf[port->xmit_tail]
									<< 8);
					port->xmit_tail = (port->xmit_tail + 1)
						& (SERIAL_XMIT_SIZE - 1);
					port->xmit_cnt--;
					txcount--;
					cnt--;
					outw(wrd, base);
				} else {
					outw(wrd, base);
					break;
				}
			}
			if (cnt <= 0)
				break;
			word_count = cnt >> 1;
			outsw(base, port->port.xmit_buf+port->xmit_tail, word_count);
			port->xmit_tail = (port->xmit_tail
				+ (word_count << 1)) & (SERIAL_XMIT_SIZE - 1);
			txcount -= (word_count << 1);
			port->xmit_cnt -= (word_count << 1);
			if (cnt & 0x0001) {
				residue = YES;
				wrd = port->port.xmit_buf[port->xmit_tail];
				port->xmit_tail = (port->xmit_tail + 1)
					& (SERIAL_XMIT_SIZE - 1);
				port->xmit_cnt--;
				txcount--;
			}
		}

		InterruptTheCard(base);
		if (port->xmit_cnt <= 0)
			port->status &= ~ISI_TXOK;
		if (port->xmit_cnt <= WAKEUP_CHARS)
			tty_wakeup(tty);
	}

unlock:
	spin_unlock_irqrestore(&isi_card[card].card_lock, flags);
	/*	schedule another tx for hopefully in about 10ms	*/
sched_again:
	mod_timer(&tx, jiffies + msecs_to_jiffies(10));
}

/*
 *	Main interrupt handler routine
 */

static irqreturn_t isicom_interrupt(int irq, void *dev_id)
{
	struct isi_board *card = dev_id;
	struct isi_port *port;
	struct tty_struct *tty;
	unsigned long base;
	u16 header, word_count, count, channel;
	short byte_count;
	unsigned char *rp;

	if (!card || !(card->status & FIRMWARE_LOADED))
		return IRQ_NONE;

	base = card->base;

	/* did the card interrupt us? */
	if (!(inw(base + 0x0e) & 0x02))
		return IRQ_NONE;

	spin_lock(&card->card_lock);

	/*
	 * disable any interrupts from the PCI card and lower the
	 * interrupt line
	 */
	outw(0x8000, base+0x04);
	ClearInterrupt(base);

	inw(base);		/* get the dummy word out */
	header = inw(base);
	channel = (header & 0x7800) >> card->shift_count;
	byte_count = header & 0xff;

	if (channel + 1 > card->port_count) {
		printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%lx): "
			"%d(channel) > port_count.\n", base, channel+1);
		outw(0x0000, base+0x04); /* enable interrupts */
		spin_unlock(&card->card_lock);
		return IRQ_HANDLED;
	}
	port = card->ports + channel;
	if (!(port->port.flags & ASYNC_INITIALIZED)) {
		outw(0x0000, base+0x04); /* enable interrupts */
		spin_unlock(&card->card_lock);
		return IRQ_HANDLED;
	}

	tty = port->port.tty;
	if (tty == NULL) {
		word_count = byte_count >> 1;
		while (byte_count > 1) {
			inw(base);
			byte_count -= 2;
		}
		if (byte_count & 0x01)
			inw(base);
		outw(0x0000, base+0x04); /* enable interrupts */
		spin_unlock(&card->card_lock);
		return IRQ_HANDLED;
	}

	if (header & 0x8000) {		/* Status Packet */
		header = inw(base);
		switch (header & 0xff) {
		case 0:	/* Change in EIA signals */
			if (port->port.flags & ASYNC_CHECK_CD) {
				if (port->status & ISI_DCD) {
					if (!(header & ISI_DCD)) {
					/* Carrier has been lost  */
						pr_dbg("interrupt: DCD->low.\n"
							);
						port->status &= ~ISI_DCD;
						tty_hangup(tty);
					}
				} else if (header & ISI_DCD) {
				/* Carrier has been detected */
					pr_dbg("interrupt: DCD->high.\n");
					port->status |= ISI_DCD;
					wake_up_interruptible(&port->port.open_wait);
				}
			} else {
				if (header & ISI_DCD)
					port->status |= ISI_DCD;
				else
					port->status &= ~ISI_DCD;
			}

			if (port->port.flags & ASYNC_CTS_FLOW) {
				if (port->port.tty->hw_stopped) {
					if (header & ISI_CTS) {
						port->port.tty->hw_stopped = 0;
						/* start tx ing */
						port->status |= (ISI_TXOK
							| ISI_CTS);
						tty_wakeup(tty);
					}
				} else if (!(header & ISI_CTS)) {
					port->port.tty->hw_stopped = 1;
					/* stop tx ing */
					port->status &= ~(ISI_TXOK | ISI_CTS);
				}
			} else {
				if (header & ISI_CTS)
					port->status |= ISI_CTS;
				else
					port->status &= ~ISI_CTS;
			}

			if (header & ISI_DSR)
				port->status |= ISI_DSR;
			else
				port->status &= ~ISI_DSR;

			if (header & ISI_RI)
				port->status |= ISI_RI;
			else
				port->status &= ~ISI_RI;

			break;

		case 1:	/* Received Break !!! */
			tty_insert_flip_char(tty, 0, TTY_BREAK);
			if (port->port.flags & ASYNC_SAK)
				do_SAK(tty);
			tty_flip_buffer_push(tty);
			break;

		case 2:	/* Statistics		 */
			pr_dbg("isicom_interrupt: stats!!!.\n");
			break;

		default:
			pr_dbg("Intr: Unknown code in status packet.\n");
			break;
		}
	} else {				/* Data   Packet */

		count = tty_prepare_flip_string(tty, &rp, byte_count & ~1);
		pr_dbg("Intr: Can rx %d of %d bytes.\n", count, byte_count);
		word_count = count >> 1;
		insw(base, rp, word_count);
		byte_count -= (word_count << 1);
		if (count & 0x0001) {
			tty_insert_flip_char(tty,  inw(base) & 0xff,
				TTY_NORMAL);
			byte_count -= 2;
		}
		if (byte_count > 0) {
			pr_dbg("Intr(0x%lx:%d): Flip buffer overflow! dropping "
				"bytes...\n", base, channel + 1);
		/* drain out unread xtra data */
		while (byte_count > 0) {
				inw(base);
				byte_count -= 2;
			}
		}
		tty_flip_buffer_push(tty);
	}
	outw(0x0000, base+0x04); /* enable interrupts */
	spin_unlock(&card->card_lock);

	return IRQ_HANDLED;
}

static void isicom_config_port(struct isi_port *port)
{
	struct isi_board *card = port->card;
	struct tty_struct *tty;
	unsigned long baud;
	unsigned long base = card->base;
	u16 channel_setup, channel = port->channel,
		shift_count = card->shift_count;
	unsigned char flow_ctrl;

	tty = port->port.tty;

	if (tty == NULL)
		return;
	/* FIXME: Switch to new tty baud API */
	baud = C_BAUD(tty);
	if (baud & CBAUDEX) {
		baud &= ~CBAUDEX;

		/*  if CBAUDEX bit is on and the baud is set to either 50 or 75
		 *  then the card is programmed for 57.6Kbps or 115Kbps
		 *  respectively.
		 */

		/* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */
		if (baud < 1 || baud > 4)
			port->port.tty->termios->c_cflag &= ~CBAUDEX;
		else
			baud += 15;
	}
	if (baud == 15) {

		/*  the ASYNC_SPD_HI and ASYNC_SPD_VHI options are set
		 *  by the set_serial_info ioctl ... this is done by
		 *  the 'setserial' utility.
		 */

		if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
			baud++; /*  57.6 Kbps */
		if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
			baud += 2; /*  115  Kbps */
		if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
			baud += 3; /* 230 kbps*/
		if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
			baud += 4; /* 460 kbps*/
	}
	if (linuxb_to_isib[baud] == -1) {
		/* hang up */
		drop_dtr(port);
		return;
	} else
		raise_dtr(port);

	if (WaitTillCardIsFree(base) == 0) {
		outw(0x8000 | (channel << shift_count) | 0x03, base);
		outw(linuxb_to_isib[baud] << 8 | 0x03, base);
		channel_setup = 0;
		switch (C_CSIZE(tty)) {
		case CS5:
			channel_setup |= ISICOM_CS5;
			break;
		case CS6:
			channel_setup |= ISICOM_CS6;
			break;
		case CS7:
			channel_setup |= ISICOM_CS7;
			break;
		case CS8:
			channel_setup |= ISICOM_CS8;
			break;
		}

		if (C_CSTOPB(tty))
			channel_setup |= ISICOM_2SB;
		if (C_PARENB(tty)) {
			channel_setup |= ISICOM_EVPAR;
			if (C_PARODD(tty))
				channel_setup |= ISICOM_ODPAR;
		}
		outw(channel_setup, base);
		InterruptTheCard(base);
	}
	if (C_CLOCAL(tty))
		port->port.flags &= ~ASYNC_CHECK_CD;
	else
		port->port.flags |= ASYNC_CHECK_CD;

	/* flow control settings ...*/
	flow_ctrl = 0;
	port->port.flags &= ~ASYNC_CTS_FLOW;
	if (C_CRTSCTS(tty)) {
		port->port.flags |= ASYNC_CTS_FLOW;
		flow_ctrl |= ISICOM_CTSRTS;
	}
	if (I_IXON(tty))
		flow_ctrl |= ISICOM_RESPOND_XONXOFF;
	if (I_IXOFF(tty))
		flow_ctrl |= ISICOM_INITIATE_XONXOFF;

	if (WaitTillCardIsFree(base) == 0) {
		outw(0x8000 | (channel << shift_count) | 0x04, base);
		outw(flow_ctrl << 8 | 0x05, base);
		outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base);
		InterruptTheCard(base);
	}

	/*	rx enabled -> enable port for rx on the card	*/
	if (C_CREAD(tty)) {
		card->port_status |= (1 << channel);
		outw(card->port_status, base + 0x02);
	}
}

/* open et all */

static inline void isicom_setup_board(struct isi_board *bp)
{
	int channel;
	struct isi_port *port;
	unsigned long flags;

	spin_lock_irqsave(&bp->card_lock, flags);
	if (bp->status & BOARD_ACTIVE) {
		spin_unlock_irqrestore(&bp->card_lock, flags);
		return;
	}
	port = bp->ports;
	bp->status |= BOARD_ACTIVE;
	for (channel = 0; channel < bp->port_count; channel++, port++)
		drop_dtr_rts(port);
	spin_unlock_irqrestore(&bp->card_lock, flags);
}

static int isicom_setup_port(struct isi_port *port)
{
	struct isi_board *card = port->card;
	unsigned long flags;

	if (port->port.flags & ASYNC_INITIALIZED)
		return 0;
	if (tty_port_alloc_xmit_buf(&port->port) < 0)
		return -ENOMEM;

	spin_lock_irqsave(&card->card_lock, flags);
	if (port->port.tty)
		clear_bit(TTY_IO_ERROR, &port->port.tty->flags);
	if (port->port.count == 1)
		card->count++;

	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;

	/*	discard any residual data	*/
	if (WaitTillCardIsFree(card->base) == 0) {
		outw(0x8000 | (port->channel << card->shift_count) | 0x02,
				card->base);
		outw(((ISICOM_KILLTX | ISICOM_KILLRX) << 8) | 0x06, card->base);
		InterruptTheCard(card->base);
	}

	isicom_config_port(port);
	port->port.flags |= ASYNC_INITIALIZED;
	spin_unlock_irqrestore(&card->card_lock, flags);

	return 0;
}

static int block_til_ready(struct tty_struct *tty, struct file *filp,
	struct isi_port *port)
{
	struct isi_board *card = port->card;
	int do_clocal = 0, retval;
	unsigned long flags;
	DECLARE_WAITQUEUE(wait, current);

	/* block if port is in the process of being closed */

	if (tty_hung_up_p(filp) || port->port.flags & ASYNC_CLOSING) {
		pr_dbg("block_til_ready: close in progress.\n");
		interruptible_sleep_on(&port->port.close_wait);
		if (port->port.flags & ASYNC_HUP_NOTIFY)
			return -EAGAIN;
		else
			return -ERESTARTSYS;
	}

	/* if non-blocking mode is set ... */

	if ((filp->f_flags & O_NONBLOCK) ||
			(tty->flags & (1 << TTY_IO_ERROR))) {
		pr_dbg("block_til_ready: non-block mode.\n");
		port->port.flags |= ASYNC_NORMAL_ACTIVE;
		return 0;
	}

	if (C_CLOCAL(tty))
		do_clocal = 1;

	/* block waiting for DCD to be asserted, and while
						callout dev is busy */
	retval = 0;
	add_wait_queue(&port->port.open_wait, &wait);

	spin_lock_irqsave(&card->card_lock, flags);
	if (!tty_hung_up_p(filp))
		port->port.count--;
	port->port.blocked_open++;
	spin_unlock_irqrestore(&card->card_lock, flags);

	while (1) {
		raise_dtr_rts(port);

		set_current_state(TASK_INTERRUPTIBLE);
		if (tty_hung_up_p(filp) || !(port->port.flags & ASYNC_INITIALIZED)) {