www.pudn.com > extint.rar > extint.c, change:2007-07-10,size:6036b


/*  
*extint.c : external interrupt demo device driver of uClinux, making use of GPIO 8  
*as external interrupt source on samsung s3c 4510b.  
*see extint.h for MACRO DEFINITION  
* Copyright(C) 2005.millionwood <millionwood@163.com>  
* This software is released under the GPL licence.  
* version 0.1 5 july, 2005  
*  yangyong re.er 
*/  
 
#include <linux/init.h> 
#include <linux/types.h>  
#include <linux/fs.h>  
#include <linux/ioctl.h>  
#include <linux/wait.h>  
#include <linux/sched.h>  
#include <linux/errno.h>  
#include <linux/interrupt.h> 
 
#include <asm-armnommu/uaccess.h>  
#include <asm-armnommu/arch-espd_4510b/hardware.h>  
#include <asm-armnommu/arch-espd_4510b/irq.h>  
#include <asm-armnommu/arch-espd_4510b/irqs.h>  
#include <asm-armnommu/arch-espd_4510b/s3c4510b.h>  
#include <asm-armnommu/signal.h>  
 
#ifdef MODULE  
	#include <linux/module.h>  
	#include <linux/version.h>  
#else  
	#define MOD_INC_USE_COUNT  
	#define MOD_DEC_USE_COUNT  
#endif  
 
 
#define myoutl(addr,data) 		(*(volatile unsigned int *)addr = data)  
#define myinl(addr) 			(*(volatile unsigned int *)addr)  
 
//#define SET_EXTINT(n)			myinl(REG_IOPCON) |= (0x18 << (5*n)) //set as external interrupt 
#define SET_EXTINT(n)			(*(volatile unsigned *)0x03ff5004 |= (0x1c << (5*n))) 
#define EXTINT_NAME			"extint" 
#define EXTINT_MAJOR			240 
 
#define EXTINT_IRQ0			INT_EXTINT0		//irq0=0,INT_EXTINT0 defined in file uclinux\linux2.4x\include\asm-armnommu\arch-snds100\irqs.h 
#define EXTINT_IRQ2			INT_EXTINT2 
#define EXTINT_IRQ3			INT_EXTINT3 
 
#define	GET_IOSTATUS			myinl(REG_IOPDATA) 
#define CLEAN_IOSTATUS			myinl(REG_IOPDATA) &= 0xfffffff0  
#define IOPORT_0			0x00000001 
#define	IOPORT_1			0x00000002 
#define	IOPORT_2			0x00000004 
#define	IOPORT_3			0x00000008 
 
struct extint_info_t { 
	int	extint1_num; 
	int	extint2_num; 
	int	extint3_num; 
	int	extint4_num; 
	int	extint5_num; 
}; 
 
struct extint_info_t extint_info; 
 
static void delay_us(int n) 
{ 
    volatile unsigned int i = 0; 
    while (n-- >= 0) { 
      i = 5; 
      while (--i > 0); 
    } 
} 
 
static int extint_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)  
{ 
	copy_to_user(buf,(char *)&extint_info,sizeof(struct extint_info_t)); 
	return 0;  
}  
 
static int extint_write(struct file *filp, char *buf, size_t count, loff_t *f_pos)  
{  
	return 0;  
}  
 
 
static int extint_ioctl(struct inode *inode, struct file *flip,unsigned int cmd, unsigned long arg)  
{  
	return 0;  
}  
 
static int extint_release(struct inode *inode, struct file *flip)  
{  
	MOD_DEC_USE_COUNT;  
	free_irq(EXTINT_IRQ0,NULL); 
	free_irq(EXTINT_IRQ2,NULL); 
	return 0;  
}  
 
static irqreturn_t  extint_handle0(int irq, void *dev_id, struct pt_regs *regs)  
{ 
	unsigned int iopstatus; 
 
	iopstatus = GET_IOSTATUS; 
 
	if(iopstatus & IOPORT_0) { 
		extint_info.extint5_num += 1; 
	} 
	if(iopstatus & IOPORT_1) { 
                extint_info.extint4_num += 1; 
        } 
	if(iopstatus & IOPORT_2) { 
                extint_info.extint3_num += 1; 
        } 
	if(iopstatus & IOPORT_3) { 
                extint_info.extint4_num += 1; 
        } 
 
	CLEAN_IOSTATUS; 
	 
	delay_us(10); 
        CLEAR_PEND_INT(EXTINT_IRQ0); 
  
 
	return IRQ_HANDLED; 
}  
 
 
static irqreturn_t extint_handle2(int irq, void *dev_id, struct pt_regs *regs)  
{ 
	unsigned int iopstatus; 
 
	iopstatus = GET_IOSTATUS; 
	 
	if(iopstatus & IOPORT_2) { 
                extint_info.extint3_num += 1; 
        } 
        if(iopstatus & IOPORT_3) { 
                extint_info.extint2_num += 1; 
        } 
 
 
	CLEAN_IOSTATUS; 
 
	delay_us(10); 
	CLEAR_PEND_INT(EXTINT_IRQ2); 
	return IRQ_HANDLED; 
}  
 
static irqreturn_t extint_handle3(int irq, void *dev_id, struct pt_regs *regs)  
{ 
	extint_info.extint1_num += 1 ; 
	delay_us(10); 
	CLEAR_PEND_INT(EXTINT_IRQ3); 
	return IRQ_HANDLED; 
} 
 
static int extint_open(struct inode *inode, struct file *flip)  
{  
	int ret;  
 
	MOD_INC_USE_COUNT;  
 
	extint_info.extint1_num = 0; 
	extint_info.extint2_num = 0; 
	extint_info.extint3_num = 0; 
	extint_info.extint4_num = 0; 
	extint_info.extint5_num = 0; 
 
 
	CLEAR_PEND_INT(EXTINT_IRQ0);  
	CLEAR_PEND_INT(EXTINT_IRQ2);  
 
	*(volatile unsigned *)0x03ff5000  &= 0x3faf0; 
	*(volatile unsigned *)0x03ff5008  &= 0x3faf0; 
 
	ret = request_irq(EXTINT_IRQ0, extint_handle0, SA_INTERRUPT, "extint_0", NULL) ;  
	if(ret){  
	//	printk("extint: can NOT get assigned irq EXTINT_IRQ0\n"); 
	} else { 
		 
		INT_ENABLE(EXTINT_IRQ0); // clear the corresponding INTMASK register bit to open the interrupt  
		SET_EXTINT(EXTINT_IRQ0); //set the corresponding bit in register IOPCON 
	} 
 
	ret = request_irq(EXTINT_IRQ2, extint_handle2, SA_INTERRUPT, "extint_2", NULL) ;  
	if(ret){  
	//	printk("extint: can NOT get assigned irq EXTINT_IRQ2\n");  
	} else {  
		INT_ENABLE(EXTINT_IRQ2); // clear the corresponding INTMASK register bit to open the interrupt  
		SET_EXTINT(EXTINT_IRQ2); //set the corresponding bit in register IOPCON  
	} 
 
	ret = request_irq(EXTINT_IRQ3, extint_handle3, SA_INTERRUPT, "extint_3", NULL) ;  
	if(ret){  
	//	printk("extint: can NOT get assigned irq EXTINT_IRQ3\n");  
	} else {  
		INT_ENABLE(EXTINT_IRQ3); // clear the corresponding INTMASK register bit to open the interrupt  
		SET_EXTINT(EXTINT_IRQ3); //set the corresponding bit in register IOPCON  
	} 
 
	return 0;  
}  
 
/*  
* BELOW is initialization, setting its irq number and set it as FIQ(fast interrupt request) mode  
*/  
 
 
struct file_operations extint_fops = { 
        .read =  extint_read, 
        .write =  extint_write, 
        .ioctl = extint_ioctl, 
        .open =  extint_open, 
        .release =  extint_release, 
}; 
 
static int __init extint_init()  
{ 
	int ret;  
	 
	ret = register_chrdev(EXTINT_MAJOR, "/dev/extint", &extint_fops);  
	if(ret<0) {  
		printk("failed to register EXTINT_NAME\n");  
	} 
  
	return 0; 
} 
 
void __exit extint_exit(void) 
{ 
        unregister_chrdev(EXTINT_MAJOR, "/dev/extint"); 
} 
 
 
module_init(extint_init);