Problem with driver for serial PCI-Multiport-Card

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi, 
 
within my degree dissertation I'm writing a driver-module for the serial  
pci-multiport-card APCI-7800 (by ADDI-Data) under kernel 2.4.20, but I have 

a huge problem: The card doesn't generate any interrupts. I've put the  
driver through his paces and consulted some persons, but nobody recognized  
any error in my drivercode. Now I'm really despaired, because my project- 
time will finish in a few weeks. I hope anyone can help me in any way. 
 
Here's the problem: The pci-card contains 8 standard UART's 16c654 and 
is simply a dumb multiport card. Communication in pollingmode goes well, 
but no interrupt will be released although all interrupts are activated in 
the IER-register. The card uses a collector-register (base-address+7), 
which shows the source of the interrupt (if it was module 1 bit 1 is set to 
1, if it was module 2 bit 2 is set and so on). When I'm reading the 
ISR-register, which gives me the status of the pending interrupt, it shows 
the pending interrupts with the right status. But the collector-register 
never contains another value than zero. As the manufacturer assures this 
register is enabled all the time, I don't have to initialize the card 
before starting. The only thing I have to do is configuring the UART, of 
course. But it's no error of the card, because with the standard serial 
driver the card works as requested (unfortunately my driver has to support 
special features, which aren't provided by the standard driver). I don't 
know what's going wrong, I made all possible configurations but every time 
the collector register is zero. 
If anyone needs further information I will post it immediately.Beneath the 
text there is a short test-drivercode. At the bottom is the sourcecode of 
the headerfile "addi_7800_sys.h". 
 
If anyone will give me any hints to solve this problem I would be very very 
very thankful! 
 
 
Best regards 
Thorsten Kruse 
 
PS: Sorry for posting this message twice. The formatting of the first 
    one was pretty damaged. 
 
 
 
 
 
/********************************************************************* 
********************* Short driver for testing *********************** 
*********************************************************************/ 
#ifndef __KERNEL__ 
	#define__KERNEL__ 
#endif 
 
#ifndef MODULE 
	#define MODULE 
#endif 
 
#include <linux/config.h> 
#include <linux/module.h> 
#include <linux/kernel.h> 
#include <linux/init.h> 
#include <linux/slab.h> 
#include <linux/fs.h> 
#include <linux/errno.h> 
#include <linux/types.h> 
#include <asm/system.h> 
#include <linux/pci.h> 
#include <linux/string.h> 
 
#include "addi_7800_sys.h" 
 
#if (LINUX_VERSION_CODE >= 132096)	/* 2.4.0 */ 
 
 
static char *driver_name = "APCI-7800"; 
 
static int major = 40;		/*Major-Nr. static for testing*/ 
static int trm_fifo_size = 4096; 
static int rec_fifo_size = 4096; 
 
 
static struct addi_pci_info info; 
 
 
static struct file_operations addi_fops = 
{ 
	owner:		THIS_MODULE, 
	open:		addi_open, 
	release:	addi_release, 
	read:		addi_read, 
	write:		addi_write, 
	ioctl:		addi_ioctl, 
}; 
 
 
static struct pci_device_id addi_pci_tbl[] __initdata = 
{ 
	{ ADDI_VENDOR_ID, ADDI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, }, 
	{ 0, }, 
}; 
MODULE_DEVICE_TABLE(pci, addi_pci_tbl); 
 
 
static struct pci_driver apci_7800 = 
{ 
	name:		"apci_7800", 
	id_table:	addi_pci_tbl, 
	probe:		addi_probe, 
	remove:		addi_remove, 
}; 
 
 
static int __init addi_probe(struct pci_dev *dev, 
			     const struct pci_device_id *id) 
{ 
	int ret = 0; 
 
	pci_enable_device(dev); 
	info.dev = dev; 
	info.irq = info.dev->irq; 
	info.io_base = pci_resource_start(dev, 0); 
	info.io_end = pci_resource_end(dev, 0); 
	info.io_len = pci_resource_len(dev, 0); 
 
	if(!request_region(info.io_base, info.io_len, driver_name)) 
	{ 
		printk(KERN_ERR "%s: Can't get I/O at 0x%lx\n", 
			driver_name, info.io_base); 
		unregister_chrdev(major, driver_name); 
		goto fail; 
	} 
	return ret; 
 
fail: 
	ret = -ENODEV; 
	return ret; 
} 
 
 
static void __exit addi_remove (struct pci_dev *dev) 
{ 
	release_region(info.io_base, info.io_len); 
} 
 
 
void addi_interrupt(int irq, void *dev_id, struct pt_regs *regs) 
{ 
	char sir, isr; 
	addi_module *module_info; 
	module_info = (addi_module*) dev_id; 
 
	sir = inb(module_info->io_base+UART_SIR); 
	isr = inb(module_info->io_base+UART_ISR); 
 
	if(isr == (1 << (module_info->module_nr - 1))) 
	{ 
		/*Interruptcode*/ 
	} 
} 
 
 
 
static ssize_t addi_read(struct file *filp, char *buf, size_t count, 
			 loff_t *f_pos) 
{ 
/************************************** 
* Read 64 Bytes from FIFO for testing * 
**************************************/ 
 
	int i; 
	int ret = 0; 
	addi_module *module_info; 
	char feld[64]; 
 
	module_info = (addi_module*) filp->private_data; 
	if(down_interruptible(&module_info->sem)) 
		return(-ERESTARTSYS); 
 
	for(i=0;i<64;i++) 
		feld[i] = inb(module_info->io_base+UART_RBR); 
 
	up(&module_info->sem); 
 
	return(ret); 
} 
 
 
static ssize_t addi_write(struct file *filp, const char *buf, size_t count, 

			  loff_t *offset) 
{ 
/*************************************** 
** Write 64 Bytes to FIFO for testing ** 
***************************************/ 
 
	int i; 
	int ret = 0; 
	addi_module *module_info; 
 
	module_info = (addi_module*) filp->private_data; 
 
	if(down_interruptible(&module_info->sem)) 
		return(-ERESTARTSYS); 
 
	for(i=0;i<64;i++) 
	{ 
		outb((char) i, module_info->io_base+UART_THR); 
	} 
 
	up(&module_info->sem); 
 
	return(ret); 
} 
 
 
 
static void addi_configure(addi_module *module_info) 
{ 
/******************************************* 
****Hard coded configuration for testing**** 
*******************************************/ 
 
	unsigned long flags; 
 
	save_flags(flags); 
	cli(); 
 
	/*Set MCR*/ 
	outb(0x10, (module_info->io_base+UART_MCR));	/*Loop on*/ 
 
	/*Enable Interrupts*/ 
	outb(0x0F, (module_info->io_base+UART_IER)); 
 
	/*Set FCR*/ 
	outb(0x01, (module_info->io_base+UART_FCR)); 
	outb(0xA9, (module_info->io_base+UART_FCR)); 
 
	outb(0x80, (module_info->io_base+UART_LCR));	/*Set DLAB*/ 
	outb(0x18, (module_info->io_base+UART_DLL)); 
	outb(0x00, (module_info->io_base+UART_DLM)); 
	outb(0, (module_info->io_base+UART_LCR)); 
 
	/*Set LCR*/ 
	outb(0x03, (module_info->io_base+UART_LCR)); 
 
	outb(0x07, (module_info->io_base+UART_FCR));	/*Reset FIFOs*/ 
 
	restore_flags(flags); 
} 
 
 
static int addi_ioctl(struct inode *inode, struct file *filp, 
		      unsigned int cmd, unsigned long arg) 
{ 
/*********************** 
***Configurationcode**** 
***********************/ 
 
	return(0); 
} 
 
 
static int addi_open(struct inode *inode, struct file *filp) 
{ 
	int ret = 0, minor, pci_area; 
	addi_module *module_info; 
 
	minor = MINOR(inode->i_rdev); 
	if(!(module_info = kmalloc(sizeof(addi_module), GFP_KERNEL))) 
	{ 
		printk(KERN_ERR "%s: kmalloc() causes an error\n",driver_name); 
		goto fail; 
	} 
 
	sema_init(&module_info->sem, 1); 
	module_info->pci_info = &info; 
	module_info->irq = module_info->pci_info->irq; 
	module_info->module_nr = minor; 
	module_info->trm_fifo_size = trm_fifo_size; 
	module_info->rec_fifo_size = rec_fifo_size; 
 
	/********************************************************************* 
	*****Find out the right baseaddress of the module on the pci-card***** 
	*********************************************************************/ 
	pci_area = (module_info->module_nr + 1) / 2; 
	module_info->io_base = pci_resource_start(module_info->pci_info->dev,  
						  pci_area); 
	module_info->io_end = pci_resource_end(module_info->pci_info->dev, 
					       pci_area); 
	module_info->io_len = (pci_resource_len(module_info->pci_info->dev, 
						pci_area)) / 2; 
 
	if(!(module_info->module_nr % 2)) 
		module_info->io_base += module_info->io_len; 
	else 
		module_info->io_end -= module_info->io_len; 
	/********************************************************************/ 
 
 
	ret = request_irq(module_info->irq, addi_interrupt, SA_SHIRQ, 
		driver_name, module_info); 
	if(ret) 
	{ 
		printk(KERN_ERR "%s: Can't get IRQ %d\n",driver_name, 
			module_info->irq); 
		kfree(module_info); 
		goto fail; 
	} 
 
 
	if(!(request_region(module_info->io_base, module_info->io_len, 
		driver_name))) 
	{ 
		printk(KERN_ERR "%s: Can't get I/O at 0x%lx\n", driver_name, 
			module_info->io_base); 
		free_irq(module_info->irq, module_info); 
		kfree(module_info); 
		goto fail; 
	} 
 
	/* Which module is inserted ??? */ 
	module_info->io_type = ((inl(module_info->pci_info->io_base + MODULE_RD)) 
				>> ((module_info->module_nr - 1) * 4)) & 0x07; 
 
	if(module_info->io_type < 0 || module_info->io_type > 7 
	   || module_info->io_type == 2) 
	{ 
		ret = -ENODEV; 
		printk(KERN_ERR "%s: No SI-Module found at port %d\n", 
				driver_name,module_info->module_nr); 
		free_irq(module_info->irq, module_info); 
		release_region(module_info->io_base, module_info->io_len); 
		kfree(module_info); 
		goto fail; 
	} 
 
	addi_configure(module_info); 
 
	(addi_module*) filp->private_data = module_info; 
	return(ret); 
 
fail: 
	return(ret); 
} 
 
 
static int addi_release(struct inode *inode, struct file *filp) 
{ 
	addi_module *module_info; 
 
 	module_info = (addi_module*) filp->private_data; 
	free_irq(module_info->irq, module_info); 
	release_region(module_info->io_base, module_info->io_len); 
	kfree(module_info); 
	filp->private_data = NULL; 
 
	return(0); 
} 
 
 
static int __init addi_init(void) 
{ 
	int ret; 
 
	ret = register_chrdev(major, driver_name, &addi_fops); 
	if(ret < 0) 
	{ 
		printk(KERN_ERR "%s: Can't register Major-Nr. %d\n", 
				driver_name, major); 
		goto fail; 
	} 
	if(major == 0) 
		major = ret; 
 
	ret = pci_module_init(&apci_7800); 
	if(ret) 
	{ 
		printk(KERN_ERR "%s: Can't register PCI-Device\n",driver_name); 
		unregister_chrdev(major, driver_name); 
		goto fail; 
	} 
 
	return(0); 
 
fail: 
	return(ret); 
} 
 
 
static void __exit addi_exit(void) 
{ 
	pci_unregister_driver(&apci_7800); 
	unregister_chrdev(major, driver_name); 
} 
 
 
module_init(addi_init); 
module_exit(addi_exit); 
 
EXPORT_NO_SYMBOLS; 
 
MODULE_LICENSE("GPL"); 
 
 
#else 
#	error "Linux Kernel-Version 2.4 or higher required" 
#endif	/*LINUX_VERSION_CODE*/ 
  
 
 
 
 
/************************************************************** 
**************** Header file addi_7800_sys.h ****************** 
**************************************************************/ 
 
#ifndef ADDI_7800_H 
#define ADDI_7800_H 
 
 
#define ADDI_VENDOR_ID	0x10E8 
#define ADDI_DEVICE_ID	0x818E 
 
#define MODULE_WR	0x00	/*Base 0 + 0x00*/ 
#define MODULE_RD	0x10	/*Base 0 + 0x10*/ 
 
 
char* module_type[] = 
{ 
	"PM232", 
	"PM485", 
	"", 
	"PM422", 
	"PM232-G", 
	"PM485-G", 
	"PMTTY-G", 
	"PM422-G" 
}; 
 
 
 
/*****************************************/ 
/*****Register-Adresses of UART 16654*****/ 
/*****************************************/ 
 
#define UART_RBR	0x00	/*DLAB == 0, read-only*/ 
#define UART_THR	0x00	/*DLAB == 0, write-only*/ 
#define UART_DLL	0x00 	/*DLAB == 1*/ 
#define UART_DLM	0x01	/*DLAB == 1*/ 
#define UART_IER	0x01	/*DLAB == 0*/ 
#define UART_FCR	0x02	/*write-only*/ 
#define UART_ISR	0x02	/*read-only*/ 
#define UART_LCR	0x03 
#define UART_MCR	0x04 
#define UART_LSR	0x05 
#define UART_MSR	0x06 
#define UART_SPR	0x07	/*write-only*/ 
#define UART_SIR	0x07	/*read-only*/ 
#define UART_EFR	0x02	/*LCR = 0xBF*/ 
 
 
 
typedef struct addi_pci_info 
{ 
	unsigned short	io_base; 
	unsigned short	io_end; 
	int		io_len; 
	int		irq; 
	struct pci_dev	*dev; 
}addi_pci_info; 
 
 
typedef struct addi_module 
{ 
	int			module_nr; 
	int			io_type; 
	unsigned short		io_base; 
	unsigned short		io_end; 
	int			io_len; 
	int			trm_fifo_size; 
	int			rec_fifo_size; 
	int			irq; 
	struct semaphore	sem; 
	addi_pci_info		*pci_info; 
}addi_module; 
 
 
 
static int __init addi_init(void); 
static void __exit addi_exit(void); 
static int __init addi_probe(struct pci_dev *, const struct pci_device_id  
*);static void __exit addi_remove (struct pci_dev *); 
static int addi_open(struct inode *, struct file *); 
static int addi_release(struct inode *, struct file *); 
static ssize_t addi_read(struct file *, char *, size_t, loff_t *); 
static ssize_t addi_write(struct file *, const char *, size_t, loff_t *); 
static int addi_ioctl(struct inode *, struct file *, unsigned int, unsigned 

long);static void addi_interrupt(int, void *, struct pt_regs *); 
static void addi_configure(addi_module *); 
 
 
#endif 
 
 

-- 
Supergünstige DSL-Tarife + WLAN-Router für 0,- EUR*
Jetzt zu GMX wechseln und sparen http://www.gmx.net/de/go/dsl


--
Kernelnewbies: Help each other learn about the Linux kernel.
Archive:       http://mail.nl.linux.org/kernelnewbies/
FAQ:           http://kernelnewbies.org/faq/


[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux