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

📄 readio_end_lk.c

📁 用于读写多个I/O设备的端口
💻 C
字号:
/******************************************************************************************
    Function:  Linux Driver module for accessing  IO port in Intel IPX425
               include led port,red port,watchdog/count port, addr port,
               key port.
    author:liuxs -- Hollysys .
    Date:2005-10-25
    Kernel Dep: linux 2.6.20
	bugfix: 1. when read addr base,if only read once,the return value is wrong ,the second read
	         will get the right value. 2006/07/27
		
		2.when read/write 16 bit port,readw/writew cannot work well,should directly use
		 addr :2006-12-12		
******************************************************************************************/
#ifndef __KERNEL__
#define __KERNEL__
#endif

#ifndef MODULE
#define MODULE
#endif

#define READIO					1
#define WRITEIO					2

#define	WATCHDOG_REG			1
#define LED_REG					2
#define	RED_REG					3
#define	ADDR_REG				4
#define AHB_IOSTATE_REG			5
#define KEY_REG					6
#define DOUBLE_REG				7
#define FREE_COUNT_REG			8
#define AHB_CST_REG				9
#define BAT_STATUS_REG			10
#define COM_REG					11					//wangyue added
#define SOE_COUNT_REG			12					//Added by ZhuPenghui

#define INVALID_REG				-1



//watchdog/FREE COUNT base
#define WATCHDOG_BASE			0x54FFFFE0			//clr 
#define WATCHDOG_SET			0x54FFFFE2			//WATCHDOG time setting
#define WATCHDOG_CLR			0x54FFFFE1			//
#define WATCHDOG_LEN			4

#define BAT_STATUS_ADDR			0x56FFFFE0 			
#define BAT_STATUS_LEN			4


#define LED_BASE      			0x54FFFFF0   
#define LED_LEN					8

#define KEY_BASE				0x54FFFFC0   //key base
#define ADDR_BASE				0x54FFFFC1	  //addr base
#define KEY_LEN					2

#define DOUBLE_BASE				0x54FFFFBF
#define DOUBLE_LEN				1

//AHB iostate
#define AHB_IOSTATE_BASE		0x52FFF000 //2-9 io module
//#define AHB_IOSTATE_BASE		0x52FFF001 //10-15 io module
#define AHB_IOSTATE_ACTIVE		0x52FFF002 //work or listening
#define AHB_IOSTATE_LEN			4

//free count
#define FREE_COUNT_BASE			0x55FFBFF0
#define FREE_COUNT_LEN			16

//SOE counter
#define	SOE_COUNT_BASE			0x55FFBFE0		//Added by ZhuPenghui
#define SOE_COUNT_LEN			16

//Ahb cst time
#define AHB_CSTTIME_ADDR		0x52fff010
#define AHB_CSTTIME_LEN			16

//com
#define COM_BASE_ADDR			0x54ffffdf		//wangyue added
#define COM_BASE_LEN			1

volatile unsigned char  * watchdogbase;			
volatile unsigned char  * ledbase;
volatile unsigned char  * ahbiostatebase;
volatile unsigned char *  keybase;
volatile unsigned char *  doublebase;
volatile unsigned short * freecountbase;
volatile unsigned short * soecountbase;			//Added by ZhuPenghui
volatile unsigned char *  ahbcstimebase;
volatile unsigned char *  batstatusbase;
volatile unsigned char *  combase;				//wangyue added


#include <linux/config.h>
#include <linux/module.h>

#include <linux/kernel.h>   /* printk() */
#include <linux/fs.h>       /* everything... */
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/ioport.h>



int ioport_major=0;

MODULE_LICENSE("DUAL BSD/GPL");

unsigned char safe_readb(unsigned long addr);
void delaytime(int data);
int ioport_open (struct inode *inode, struct file *filp);
int ioport_release(struct inode *ino, struct file *f);
int ioport_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long *arg);
struct file_operations ioport_fops = {
    open:    ioport_open,
	ioctl:			ioport_ioctl,	
	release:    ioport_release,
};

//chech valid of parameter
int check_arg_valid(unsigned long addr)
{	
		// printk(KERN_INFO"para  in readio addr=%08X\n",addr);
	    if((addr>=WATCHDOG_BASE) && (addr <=WATCHDOG_BASE+WATCHDOG_LEN))	
			return WATCHDOG_REG;
		if((addr>=LED_BASE) && (addr<=LED_BASE+LED_LEN))
			return	LED_REG;
		if((addr>=AHB_IOSTATE_BASE) && (addr<=AHB_IOSTATE_BASE+AHB_IOSTATE_LEN))
			return AHB_IOSTATE_REG;
		if((addr>=KEY_BASE) && (addr<=KEY_BASE+KEY_LEN))
			return KEY_REG;

		if((addr>=DOUBLE_BASE) && (addr<=DOUBLE_BASE+DOUBLE_LEN))
			return DOUBLE_REG;
		
		if((addr>=FREE_COUNT_BASE) && (addr<=FREE_COUNT_BASE+FREE_COUNT_LEN))
			return FREE_COUNT_REG;
		
		if((addr>=SOE_COUNT_BASE) && (addr<=SOE_COUNT_BASE+SOE_COUNT_LEN))
			return SOE_COUNT_REG;

		 if((addr>=AHB_CSTTIME_ADDR) && (addr<=AHB_CSTTIME_ADDR+AHB_CSTTIME_LEN))
			return AHB_CST_REG;		
		if((addr>=BAT_STATUS_ADDR) && (addr<=BAT_STATUS_ADDR+BAT_STATUS_LEN))
			return BAT_STATUS_REG;		
		if( addr==COM_BASE_ADDR )		//wangyue added
			return COM_REG;

		printk(KERN_INFO"para is invalid in readio addr=%08X\n",addr);
			return INVALID_REG;
}

int ioport_ioctl(struct inode *inode, struct file *filp,
                 unsigned int cmd, unsigned long *arg)
{
	int res=0;
	unsigned long port;
	unsigned long write_value;
	unsigned char *ucioaddr;		//byte
	unsigned short *usioaddr;		//16 bit
	int check_res=-1;

	if(arg==NULL)
		return -1;
//	printk(KERN_INFO"in ioctl\n");
	port=arg[0];
	write_value=arg[1];
	
	check_res=check_arg_valid(port);
	switch(check_res){
	case WATCHDOG_REG:
		ucioaddr=watchdogbase+port-WATCHDOG_BASE;
		break;
	case LED_REG:
		ucioaddr=ledbase+port-LED_BASE;
		break;

	case AHB_IOSTATE_REG:
		 ucioaddr=ahbiostatebase+port-AHB_IOSTATE_BASE;	
		 break;	
	
	case KEY_REG:
		 ucioaddr=keybase+port-KEY_BASE;
		 break;
	
	case DOUBLE_REG:
		 ucioaddr=doublebase+port-DOUBLE_BASE;
		 break;
	case FREE_COUNT_REG:
		if((port%2)!=0)
			return -1;
		else
		  usioaddr=(unsigned short *)freecountbase+(port-FREE_COUNT_BASE)/2;
		  break;
	case SOE_COUNT_REG:					//Added by ZhuPenghui
		if((port%2)!=0)
			return -1;
		else
		  usioaddr=(unsigned short *)soecountbase+(port-SOE_COUNT_BASE)/2;
		  break;
	case AHB_CST_REG:
		ucioaddr=ahbcstimebase+port-AHB_CSTTIME_ADDR;
		break;
       case  BAT_STATUS_REG:
		ucioaddr=batstatusbase+port-BAT_STATUS_ADDR; 
		break;
	case COM_REG:
		ucioaddr=combase+port-COM_BASE_ADDR;			//wangyue added
		break;
		
	case INVALID_REG:
		 return -1;
	default:
		 return -1;
	
	}

	switch(cmd) {
	case READIO:
		if(check_res==FREE_COUNT_REG)
		{
			//res=readw(usioaddr);
			res=*(volatile unsigned short *)usioaddr;
			break;
		}
		else
		{
			if(check_res==SOE_COUNT_REG)
			{
				res=*(volatile unsigned short *)usioaddr;
				break;
			}
			else
			{
				res=readb(ucioaddr);
			}
		}
		break;
	case WRITEIO:
		if(check_res==FREE_COUNT_REG)
		{
		//	writew(write_value,usioaddr);
			*(volatile unsigned short *)usioaddr=write_value;	
		}
		else
		{
			if(check_res==SOE_COUNT_REG)
			{
				*(volatile unsigned short *)usioaddr=write_value;
				break;
			}
			else
			{
				writeb(write_value,ucioaddr);
			}
		}
		break;
	
	default:
		res=-1;
		break;
	}
   
	return res;

}

int ioport_open(struct inode *inode, struct file *filp)
{
	printk("<0>,in open \n");
//	 MOD_INC_USE_COUNT;
	return 0;

}



int ioport_release(struct inode *inode, struct file *filp)
{
 //   MOD_DEC_USE_COUNT;
    return 0;
}


int init_module(void)
{
	int result=0;

	printk(KERN_INFO"hello release vern 12-06\n");
	
	watchdogbase=(volatile unsigned char *)ioremap_nocache(WATCHDOG_BASE,WATCHDOG_LEN);
    ledbase=(volatile unsigned char *)ioremap_nocache(LED_BASE,LED_LEN);
	ahbiostatebase=(volatile unsigned char *)ioremap_nocache(AHB_IOSTATE_BASE,AHB_IOSTATE_LEN);

	keybase=(volatile unsigned char *)ioremap_nocache(KEY_BASE,KEY_LEN);
	doublebase=(volatile unsigned char *)ioremap_nocache(DOUBLE_BASE,DOUBLE_LEN);
	freecountbase=(volatile unsigned short *)ioremap_nocache(FREE_COUNT_BASE,FREE_COUNT_LEN);
	soecountbase=(volatile unsigned short *)ioremap_nocache(SOE_COUNT_BASE,SOE_COUNT_LEN);	//Added by ZhuPenghui
	ahbcstimebase=(volatile unsigned char *)ioremap_nocache(AHB_CSTTIME_ADDR,AHB_CSTTIME_LEN);	
	batstatusbase=(volatile unsigned char *)ioremap_nocache(BAT_STATUS_ADDR,BAT_STATUS_LEN);	
	
	combase=(volatile unsigned char *)ioremap_nocache(COM_BASE_ADDR,COM_BASE_LEN);		//wangyue added
	
    result = register_chrdev(232, "readio", &ioport_fops);
	ioport_major=result;

//	writeb(0x01,redbase); //first set state as slave;
	printk(KERN_INFO"major133333 =%d \n",result);
	return 0;

}

void cleanup_module(void)
{
	int result=0;
	if(watchdogbase!=NULL)
		iounmap(watchdogbase);
	if(ledbase!=NULL)
		iounmap(ledbase);
	if(keybase!=NULL)
		iounmap(keybase);
	if(doublebase!=NULL)
		iounmap(doublebase);
	if(freecountbase!=NULL)
		iounmap(freecountbase);
	if(soecountbase!=NULL)			//Added by ZhuPenghui
		iounmap(soecountbase);
	if(ahbiostatebase)
		iounmap(ahbiostatebase);
	
	if(combase!=NULL)
		iounmap(combase);			//wangyue added

	result=  unregister_chrdev(ioport_major, "readio");
	printk(KERN_INFO"goodbye\n");
}


void delaytime(int data)
{
    int i;
	int j=data;
	int k;

	for(i=0;i<10;i++)
		for(j=0;j<data;j++)
		{
			k=i+j;
		}


}

unsigned char safe_readb(unsigned long addr)
{
	unsigned char i=0;
	unsigned char j=0;
	unsigned char tmp=0;
	unsigned char tmp2=0;

	tmp2=readb(addr);
	while(i<5)
	{
		tmp=readb(addr);
		delaytime(2);
		if(tmp!=tmp2)
		{
			i=0;
		}
		tmp2=tmp;
		i++;
		j++;
		if(j>=15)
			break;
	}
	return tmp2;

}


//module_init(ioport_init_module);
//module_exit(ioport_cleanup_module);



⌨️ 快捷键说明

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