⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 extint.c

📁 本程序是Linux下的一个为S3C4510B开发板写的一个外部中断的驱动程序。可以作为linux驱动的编写典范
💻 C
字号:
/* 
*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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -