1. 创建设备节点,设备号,这些不多说了。我们要对操作集中修改。
static const struct
file_operations ralink_gpio_fops =
{
.owner = THIS_MODULE,
.unlocked_ioctl = ralink_gpio_ioctl,
.open = ralink_gpio_open,
.release = ralink_gpio_release,
};
int __init ralink_gpio_init(void){
int r = register_chrdev(ralink_gpio_major, RALINK_GPIO_DEVNAME, &ralink_gpio_fops);
if(r < 0) {
printk(KERN_ERR "%s: unable to register character device\n", RALINK_GPIO_NAME);
return r;
}
//......
ralink_gpio_init_irq();
}
2.open函数中对引脚进行寄存器初始化设置
#define GPIO_PIN_NUM 67
volatile unsigned long *GPIO_CTRL_0; //--- GPIO direction control register 0-input 1-output
volatile unsigned long *GINT_REDGE_0; //--GPIO rising edge interrupt enable register
volatile unsigned long *GINT_FEDGE_0; //--GPIO falling edge interrupt enable register
volatile unsigned long *GINT_STAT_0; //---GPIO interrupt status register 1-
static int
ralink_gpio_open(struct inode *inode, struct file *file)
{
try_module_get(THIS_MODULE);
/* 67 pin set input interrupt */
GPIO_CTRL_0=(volatile unsigned long *)ioremap(0x10000674,4); //--- GPIO40 to GPIO71 direction control register 0-input 1-output
GINT_REDGE_0=(volatile unsigned long *)ioremap(0x10000668,4); //--GPIO40 to GPIO71 rising edge interrupt enable register
GINT_FEDGE_0=(volatile unsigned long *)ioremap(0x1000066C,4); //--GPIO0-31, falling edge interrupt enable register
GINT_STAT_0=(volatile unsigned long *)ioremap(0x10000660,4); //---GPIO0 to GPIO31 interrupt status register 1-int 0 -no int
//GINT_EDGE_0; //---GPIO0 to GPIO31 interrupt edge status register 1-rising 0-falling
//--------- set GPIO purpose -----------
*GPIO_CTRL_0 &=~(0x1<<(GPIO_PIN_NUM-40)); //---bit set 0, input mode
*GINT_REDGE_0 |=(0x1<<(GPIO_PIN_NUM-40)); //--bit set 1,enable Rising Edge interrupt
*GINT_FEDGE_0 &=~(0x1<<(GPIO_PIN_NUM-40)); //--bit set 0,disable Falling Edge interrupt
return 0;
}
3.open函数中对引脚释放寄存器
static int
ralink_gpio_release(struct inode *inode, struct file *file)
{
module_put(THIS_MODULE);
iounmap(GPIO_CTRL_0);
iounmap(GINT_REDGE_0);
iounmap(GINT_FEDGE_0);
iounmap(GINT_STAT_0);
return 0;
}
4.中断初始化
回过来,我们再来看最开始的__init函数,初始化中断那里。申请了一个中断号为14的中断事件。
static void
ralink_gpio_irq_clear(void)
{
*(volatile u32 *)(RALINK_REG_PIOINT) = cpu_to_le32(0x00FFFFFF);
*(volatile u32 *)(RALINK_REG_PIO3924INT) = cpu_to_le32(0x0000FFFF);
*(volatile u32 *)(RALINK_REG_PIO7140INT) = cpu_to_le32(0xFFFFFFFF);
*(volatile u32 *)(RALINK_REG_PIO72INT) = cpu_to_le32(0x00000001);
}//清除中断
static void
ralink_gpio_init_irq(void)
{
int err;
memset(ralink_gpio_irq_data, 0, sizeof(ralink_gpio_irq_data));
ralink_gpio_irq_clear();
err = request_irq(SURFBOARDINT_GPIO, ralink_gpio_irq_handler, IRQF_DISABLED|IRQF_TRIGGER_FALLING, "ralink_gpio", NULL); //注册中断,中断号为14,代码中设置的,中断名称为"ralink_gpio"
}
5.中断函数
这个函数不需要了解细节,只需要知道,最后执行一个ralink_gpio_notify_user函数。这个才是重点。
irqreturn_t ralink_gpio_irq_handler(int irq, void *dev_id)
{
u32 i, rise_edge;
u32 ralink_gpio_intp = le32_to_cpu(*(volatile u32 *)(RALINK_REG_PIOINT));
u32 ralink_gpio_edge = le32_to_cpu(*(volatile u32 *)(RALINK_REG_PIOEDGE));
u32 ralink_gpio3924_intp = le32_to_cpu(*(volatile u32 *)(RALINK_REG_PIO3924INT));
u32 ralink_gpio3924_edge = le32_to_cpu(*(volatile u32 *)(RALINK_REG_PIO3924EDGE));
u32 ralink_gpio7140_intp = le32_to_cpu(*(volatile u32 *)(RALINK_REG_PIO7140INT));
u32 ralink_gpio7140_edge = le32_to_cpu(*(volatile u32 *)(RALINK_REG_PIO7140EDGE));
u32 ralink_gpio72_intp = le32_to_cpu(*(volatile u32 *)(RALINK_REG_PIO72INT));
u32 ralink_gpio72_edge = le32_to_cpu(*(volatile u32 *)(RALINK_REG_PIO72EDGE));
ralink_gpio_irq_clear();
for (i = 0; i < 24; i++) {
if ( !(ralink_gpio_intp & RALINK_GPIO(i)) )
continue;
rise_edge = (ralink_gpio_edge & RALINK_GPIO(i)) ? 1 : 0;
if (ralink_gpio_notify_user(i, rise_edge))
break;
}
for (i = 24; i < 40; i++) {
if ( !(ralink_gpio3924_intp & RALINK_GPIO((i-24))) )
continue;
rise_edge = (ralink_gpio3924_edge & RALINK_GPIO((i-24))) ? 1 : 0;
if (ralink_gpio_notify_user(i, rise_edge))
break;
}
for (i = 40; i < 72; i++) {
if ( !(ralink_gpio7140_intp & RALINK_GPIO((i-40))) )
continue;
rise_edge = (ralink_gpio7140_edge & RALINK_GPIO((i-40))) ? 1 : 0;
if (ralink_gpio_notify_user(i, rise_edge))
break;
}
for (i = 72; i < RALINK_GPIO_NUMBER; i++) {
if ( !(ralink_gpio72_intp & RALINK_GPIO((i-72))) )
continue;
rise_edge = (ralink_gpio72_edge & RALINK_GPIO((i-72))) ? 1 : 0;
if (ralink_gpio_notify_user(i, rise_edge))
break;
}
return IRQ_HANDLED;
}
6.向用户空间发送信号
在这个函数里面我们可以做我们想做的事情。最终,在文件系统下使用cat /proc/interrupts命令可以读取到中断的上升沿次数的变化
/*
* send a signal(SIGUSR2) to the registered user process whenever
* any gpio interrupt comes (called by interrupt handler)
*/
static int
ralink_gpio_notify_user(u32 irq_gpio, u32 rise_edge)
{
struct task_struct *p = NULL;
/************************USER DO SOMETHING****************************/
//printk("irq_gpio = %d , rise_edge = %d\n" , irq_gpio , rise_edge);
if(irq_gpio == GPIO_PIN_NUM ){
}
/****************************************************/
if (irq_gpio >= RALINK_GPIO_NUMBER)
return 0;
// don't send any signal if pid < 1
if (ralink_gpio_irq_data[irq_gpio].pid < 1)
return 0;
if (!(ralink_gpio_irq_data[irq_gpio].rise && rise_edge) &&
!(ralink_gpio_irq_data[irq_gpio].fall && !rise_edge))
return 0;
p = find_task_by_vpid(ralink_gpio_irq_data[irq_gpio].pid);
if (!p)
return 0;
send_sig(SIGUSR2, p, 0);
return 1;
}