📄 extint.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 + -