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

📄 ahbus.c

📁 这是高速总线驱动
💻 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 + -