📄 ahbus.c
字号:
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/module.h>
#include <asm/irq.h> //disable && enable irq
#include <asm/uaccess.h>//copy_from_user | to_user
#include <linux/ioctl.h>
#include <linux/fs.h> /* everything... */
#include <asm/io.h>
#include <linux/ioport.h>//ioremap
#include <linux/sched.h>//wait_queue
#include <linux/wait.h>
#include <linux/mm.h>
#include <linux/slab.h> //kmalloc
#include <linux/interrupt.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/time.h>
#define DRIVER_VERSION "v1.0"
MODULE_LICENSE("Dual BSD/GPL");
#define AHBUS_BASE 0x52FE0000
#define AHBUS_LEN 16*1024 //Modified by MLT at 2008.01.15:高速总线RAM的地址应该为16K
#define AHBUS_REG 0x52FFF003
#define GPIO_INT_TYPE_REG1 0xc8004010
#define MODULE_STATUS 0x52FFF000
#define AHBUS_INT_NUM 20
volatile unsigned int *gpio_int_type_reg = NULL;
volatile unsigned char *ahbus_addr = NULL;
volatile unsigned char *ahbus_reg = NULL;
volatile unsigned char *ahbus_reg_1 = NULL;
volatile unsigned char *module_status = NULL;
volatile unsigned int AddrOffset[4] = {0,0,0,0};
volatile unsigned char ucMark[4] = {0xf7,0xfb,0xfd,0xfe};//分别对应2,3,4,5号槽
int ahbus_major = -1;
static int intcounter = 0;
struct ahbus
{
wait_queue_head_t queue;
int flag;
};
struct ahbus ahb[4][16];
int check_channel_int(int ChannelNum, int abaddr0, int abaddr1)
{
//printk("ahbus->check channel abaddr0:[0x%02x]\n",abaddr0);//8-13通道
//printk("ahbus->check channel abaddr1:[0x%02x]\n",abaddr1);//0-7通道
if( ChannelNum >= 0 && ChannelNum < 8)
{
if((abaddr1&(0x01<<ChannelNum)) == (0x01<<ChannelNum))
{
printk("ahbus->%dth channel int!\n",ChannelNum);
return 1;
}
}
else
if( ChannelNum >= 8 && ChannelNum <=15)
{
//printk("ahbus->%d move result!\n",(0x01<<(ChannelNum-8)));
if((abaddr0&(0x01<<(ChannelNum-8))) == (0x01<<(ChannelNum-8)))
{
printk("ahbus->%dth channel int!\n",ChannelNum);
return 1;
}
}
else
{
printk("ahbus->channel int error!\n");
}
//printk("ahbus->channel int error!\n");
return 0;
}
int check_slot_int(int SlotNum, int ChannelNum, int abreg, int abaddr0, int abaddr1)
{
int temp = abreg;
if(SlotNum>=2 && SlotNum<=5)
{
if((temp|ucMark[SlotNum-2]) == ucMark[SlotNum-2])
{
printk("ahbus->there comes %dth slot int!\n",SlotNum);
return(check_channel_int(ChannelNum,abaddr0,abaddr1));
}
}
printk("ahbus->there comes no slot int!\n");
printk("ahbus->abreg:[0x%02x]\n",temp);
return 0;
}
int ahbus_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long argv)
{
volatile unsigned int SlotNum;
volatile unsigned int ChannelNum;
volatile unsigned int Timeout;
volatile unsigned char abreg;
volatile unsigned char abaddr0;
volatile unsigned char abaddr1;
struct args
{
volatile unsigned int slotnum;
volatile unsigned int channelnum;
volatile unsigned int timeout;
volatile unsigned int addroffset[4];
}arg;
copy_from_user(&arg,(void *)argv,sizeof(struct args));
if (cmd == 0) //传递偏移地址
{
AddrOffset[0] = arg.addroffset[0];
AddrOffset[1] = arg.addroffset[1];
AddrOffset[2] = arg.addroffset[2];
AddrOffset[3] = arg.addroffset[3];
printk("ahbus->ADDR:%x,%x,%x,%x\n",arg.addroffset[0],arg.addroffset[1],arg.addroffset[2],arg.addroffset[3]);
}
if (cmd == 1) //非阻塞
{
printk("ahbus->NONBLOCK:arg.slotnum:%d,arg.channelnum:%d,arg.timeout:%d\n",arg.slotnum,arg.channelnum,arg.timeout);
SlotNum = arg.slotnum;
ChannelNum = arg.channelnum;
Timeout = arg.timeout;
abreg = *(volatile unsigned char *) ahbus_reg;
abaddr0 = ahbus_addr[AddrOffset[SlotNum-2]];
udelay(100);
abaddr0 = ahbus_addr[AddrOffset[SlotNum-2]];
abaddr1 = ahbus_addr[AddrOffset[SlotNum-2] + 1];
udelay(100);
abaddr1 = ahbus_addr[AddrOffset[SlotNum-2] + 1];
return(check_slot_int(SlotNum,ChannelNum,abreg,abaddr0,abaddr1));
}
if (cmd == 2) //阻塞
{
printk("ahbus->BLOCK:arg.slotnum:%d,arg.channelnum:%d,arg.timeout:%d\n",arg.slotnum,arg.channelnum,arg.timeout);
SlotNum = arg.slotnum;
ChannelNum = arg.channelnum;
Timeout = arg.timeout;
printk("ahbus->SlotNum:%d,ChannelNum:%d going to sleep!\n",SlotNum,ChannelNum);
if ( Timeout != 0 )
{
if (wait_event_interruptible_timeout(ahb[SlotNum-2][ChannelNum].queue, ahb[SlotNum-2][ChannelNum].flag != 0, Timeout) == 0)
{
printk("ahbus->Time out and wake up!\n");
ahb[SlotNum-2][ChannelNum].flag = 0;
return 0;
}
else
{
printk("ahbus->Int comes and wake up!\n");
ahb[SlotNum-2][ChannelNum].flag = 0;
return 1;
}
}
else
{
wait_event_interruptible(ahb[SlotNum-2][ChannelNum].queue, ahb[SlotNum-2][ChannelNum].flag !=0);
printk("ahbus->KERN:wake up!!!\n");
ahb[SlotNum-2][ChannelNum].flag = 0;
return 1;
}
}
if (cmd == 3)
{
return jiffies;
}
else
return 0;
}
irqreturn_t ahbus_isr(int irq, void *dev_id, struct pt_regs * pr)
{
volatile unsigned char abreg,abreg_1;
volatile unsigned char abaddr0;
volatile unsigned char abaddr1;
int temp0,temp1,temp2;
int iSlot = 0;
int ChannelNum = 0;
abreg = *(volatile unsigned char *) ahbus_reg; //读取,清中断
abreg_1 = *(volatile unsigned char *) ahbus_reg_1; //读取,清中断
temp0 = abreg;
printk("ahbus->INT:%d",intcounter++);
printk("ahbus->INT:abreg:0x%02x,abreg_1:0x%02x\n",abreg,abreg_1);
for(iSlot = 0;iSlot < 4;iSlot++)
{
if( (temp0|ucMark[iSlot]) == ucMark[iSlot] )//本槽有中断发生
{//可能会有多个通道同时产生中断
printk("ahbus->Slot %d comes int!\n",iSlot+2);
abaddr0 = ahbus_addr[AddrOffset[iSlot]];
udelay(100);
abaddr0 = ahbus_addr[AddrOffset[iSlot]];
abaddr1 = ahbus_addr[AddrOffset[iSlot]+1];
udelay(100);
abaddr1 = ahbus_addr[AddrOffset[iSlot]+1];
temp1 = abaddr0;
temp2 = abaddr1;
printk("ahbus->abaddr0:0x%02x,abaddr1:0x%02x\n",temp1,temp2);
for(ChannelNum=0;ChannelNum<=15;ChannelNum++)
{
if(check_channel_int(ChannelNum,temp1,temp2))
{
printk("ahbus->channel %d is valid!\n",ChannelNum);
ahb[iSlot][ChannelNum].flag = 1;
wake_up_interruptible(&(ahb[iSlot][ChannelNum].queue));
}
}
return IRQ_HANDLED;
}
}
printk("ahbus->slot error!abreg:0x%02x\n",temp0);
return IRQ_HANDLED;
}
struct file_operations ahbus_fops = {
.owner = THIS_MODULE,
.ioctl = ahbus_ioctl,
};
void register_irq(void)
{
if (request_irq(AHBUS_INT_NUM,ahbus_isr,SA_SHIRQ,"ahbus",ahbus_isr)!=0)
printk("ahbus->ERROR:register failed\n");
else
printk("ahbus->register irq successful\n");
}
static int __init ahbus_init(void)
{
int i,j;
ahbus_addr=(volatile unsigned char *)ioremap_nocache(AHBUS_BASE,AHBUS_LEN);
ahbus_reg =(volatile unsigned char *)ioremap_nocache(AHBUS_REG,1);
ahbus_reg_1 =(volatile unsigned char *)ioremap_nocache(0x52fff004,1);
gpio_int_type_reg=(volatile unsigned int *)ioremap_nocache(GPIO_INT_TYPE_REG1,1);
module_status=(volatile unsigned char *)ioremap_nocache(MODULE_STATUS,1);
//printk("ahbus->*gpio_int_type_reg1:[0x%08x]\n",*(volatile unsigned int *)gpio_int_type_reg);
*(volatile unsigned int *)gpio_int_type_reg &= 0xfffff7ff; //GPIO3 falling edge
*(volatile unsigned int *)gpio_int_type_reg |= 0x00000600;
//printk("ahbus->*gpio_int_type_reg1:[0x%08x]\n",*(volatile unsigned int *)gpio_int_type_reg);
//printk("ahbus->*ahbus_reg:[0x%02x]\n",*(volatile unsigned char *)ahbus_reg);
ahbus_major = register_chrdev(234, "ahbus", &ahbus_fops);
//printk("ahbus->ahbus_major:%d\n",ahbus_major);
register_irq();
for ( i = 0; i <= 3; i++ )
{
for ( j = 0; j <= 15; j++ )
{
init_waitqueue_head(&(ahb[i][j].queue));
}
}
printk("ahbus->Hello AHBUS!\n");
return 0;
}
static void __exit ahbus_exit(void)
{
unregister_chrdev(ahbus_major, "ahbus");
iounmap((void *)gpio_int_type_reg);
iounmap((void *)ahbus_addr);
iounmap((void *)ahbus_reg);
iounmap((void *)module_status);
free_irq(AHBUS_INT_NUM, ahbus_isr);
printk("ahbus->Bye AHBUS.\n");
}
module_init(ahbus_init);
module_exit(ahbus_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -