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

📄 8255a.c

📁 基于AT91RM9200的IO口扩展
💻 C
字号:
/*  * 8255a GPIO interface for Linux on Atmel AT91RM9200 * Copyright (c) 2006 Ligang Wang * wangzitan@163.com *//* include some file */ #include <linux/module.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/ioport.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/string.h>#include <linux/poll.h>#include <linux/init.h>#include <asm/io.h>#include <asm/system.h>#include <asm/arch/hardware.h>#include <asm/segment.h>#include "8255a.h"/* define some macro for this module*/#define MAX_DEV_NUM 5			//Max number of 8255 device#define DEV_MEM_SIZE 1024		//define memory size for device#define DEV_MAJOR		252   //major of 8255a//NCS2:8255A0  NCS4:8255A1  NCS5:8255A2//NCS6:8255A3  NCS7:8055A4static unsigned long REG_ADDR_BASE[MAX_DEV_NUM] = {0x30000000,0x50000000,0x60000000,0x70000000,0x80000000};#define PA_REG_V(i) 	(dev_list[(i)].dev_base_addr_v + 0)#define PB_REG_V(i) 	(dev_list[(i)].dev_base_addr_v + 1)#define PC_REG_V(i) 	(dev_list[(i)].dev_base_addr_v + 2)#define CTL_REG_V(i) 	(dev_list[(i)].dev_base_addr_v + 3)#define	CURRENT_PORT_REG	(dev_list[current_dev].dev_base_addr_v + dev_list[current_dev].current_port)#define	CURRENT_CTL_REG	(dev_list[current_dev].dev_base_addr_v + 3)typedef struct device_8255a{	char dev_num;										//device id	int current_port;								//current port	char port_state[3];							//state of portA/B/C	unsigned long dev_base_addr_v;	//base virtual address of device}dev_8255a;static dev_8255a dev_list[MAX_DEV_NUM];static int current_dev;static int set_port(int dev, int port, int io_mode);static int select_port(int dev, int port);AT91PS_SYS AT91_SYS1 = (AT91PS_SYS) AT91C_VA_BASE_SYS;/* * Read funcation for vfs */ssize_t at91_8255A_read(struct file * file, char *buf, size_t count, loff_t * ppos){	int retval;	char data;	//printk("8255: Read fun\n");		// check current port of current device is input mode	if(dev_list[current_dev].port_state[dev_list[current_dev].current_port] != PARM_INPUT)		return -EINVAL;	// check count arg 	if (count < sizeof(unsigned char))		return -EINVAL;	// read data from 8255a	writeb(0x9b,CURRENT_CTL_REG);	data = readb(CURRENT_PORT_REG);		// copy data to user space	retval = copy_to_user(buf,&(data),sizeof(unsigned char));	if (!retval)		retval = sizeof(unsigned char);	return retval;}/* * Write funcation for vfs */ssize_t at91_8255A_write(struct file * file, const char * buf, size_t count, loff_t * ppos){	int retval;	char data;	//check current port of current device is input mode	if(dev_list[current_dev].port_state[dev_list[current_dev].current_port] != PARM_OUTPUT)		return -EINVAL;	//copy data from user to kernel	retval = copy_from_user(&(data),buf,sizeof(unsigned char));	if (!retval)	{		//write data to 8255a		//printk("8255a:write %d to %x\n",data,CURRENT_PORT_REG);		outb(data,CURRENT_PORT_REG);		retval = sizeof(unsigned char);	}	return retval;}		/* open a device */static int at91_8255A_open(struct inode* inode,struct file* file){	MOD_INC_USE_COUNT;
	return 0;	}/* * Handle commands from user-space. */static int at91_825A_ioctl(struct inode *inode, struct file *file,		unsigned int cmd, unsigned long arg){		int arg_data = 0;		switch(cmd) 		{			//handle select dev and port command			case CMD_SELECT_DEV_PORT:				copy_from_user(&arg_data,(int *)arg,sizeof(int));				select_port(get_dev(arg_data),get_port(arg_data));				break;			//get current dev and port			case CMD_GET_CURRENT_DEV_PORT:				arg_data |= ((current_dev<<16) | (dev_list[current_dev].current_port << 8));				copy_to_user(&arg_data,(int *)arg,sizeof(int));				break;						//set port state			case CMD_SET_PORT_STATE:				copy_from_user(&arg_data,(int *)arg,sizeof(int));				set_port(get_dev(arg_data), get_port(arg_data), get_io_mod(arg_data));				break;							//get poart state			case CMD_GET_PORT_STATE:				copy_from_user(&arg_data,(int *)arg,sizeof(int));				return (dev_list[get_dev(arg_data)].port_state[get_port(arg_data)]);							default:				return -EINVAL;		}		return 0;		}/* * set port i/o mode * dev:	the dev we will setting * port:the port we will setting  * io_mode: i/o mode */ static int set_port(int dev, int port, int io_mode){	char ctl_word;	if(dev < 0 || dev > MAX_DEV_NUM || port < 0 || port > 2			|| io_mode<0 || io_mode>1)			return -1;				dev_list[dev].port_state[port] = io_mode;	ctl_word = (1<<7) | (dev_list[dev].port_state[PORT_A] << 4)						| (dev_list[dev].port_state[PORT_C] << 3)						| (dev_list[dev].port_state[PORT_B] << 1)						| (dev_list[dev].port_state[PORT_C] << 0);	//outb(ctl_word,CTL_REG_V(dev));	//printk("8255a: write control word to %x\n",CTL_REG_V(dev));	//printk("8255a: dev:%d,port:%d,io:%d,control word:%x\n",dev,port,io_mode,ctl_word);	return 0;}/*  * select a port as current port * char dev: current dev * char port:current port */static int select_port(int dev, int port){	if(dev<0 || dev>MAX_DEV_NUM || port<0 || port>2)		return -1;	current_dev = dev;	dev_list[dev].current_port = port;	//printk("8255a:current dev is %d,port is :%d\n",dev,port);	return 0;}/* * setup 8255A hardware */	static void at91_8255A_setup(void){	int i;	//Setup bus access time width.	AT91_SYS1->EBI_SMC2_CSR[2] = (AT91C_SMC2_NWS & 0x8) | AT91C_SMC2_WSEN
									| (AT91C_SMC2_TDF & 0x300) | AT91C_SMC2_BAT | AT91C_SMC2_DBW_8;	AT91_SYS1->EBI_SMC2_CSR[4] = (AT91C_SMC2_NWS & 0x8) | AT91C_SMC2_WSEN
									| (AT91C_SMC2_TDF & 0x300) | AT91C_SMC2_BAT | AT91C_SMC2_DBW_8;	AT91_SYS1->EBI_SMC2_CSR[5] = (AT91C_SMC2_NWS & 0x8) | AT91C_SMC2_WSEN
									| (AT91C_SMC2_TDF & 0x300) | AT91C_SMC2_BAT | AT91C_SMC2_DBW_8;	AT91_SYS1->EBI_SMC2_CSR[6] = (AT91C_SMC2_NWS & 0x8) | AT91C_SMC2_WSEN
									| (AT91C_SMC2_TDF & 0x300) | AT91C_SMC2_BAT | AT91C_SMC2_DBW_8;	AT91_SYS1->EBI_SMC2_CSR[7] = (AT91C_SMC2_NWS & 0x8) | AT91C_SMC2_WSEN
									| (AT91C_SMC2_TDF & 0x300) | AT91C_SMC2_BAT | AT91C_SMC2_DBW_8;	//Initialize private data foe 8255a devices	//all port of 8255a is input mode	//and current 8255a device is 8255a 0,current port is port A;	for(i = 0; i<MAX_DEV_NUM; i++)	{		dev_list[i].dev_num = i;		dev_list[i].current_port = PORT_A;		set_port(i,PORT_A,PARM_INPUT);		set_port(i,PORT_B,PARM_INPUT);		set_port(i,PORT_C,PARM_INPUT);	}		//Set 8255a0 as output mode	set_port(DEV8255A0,PORT_A,PARM_OUTPUT);	set_port(DEV8255A0,PORT_B,PARM_OUTPUT);	set_port(DEV8255A0,PORT_C,PARM_OUTPUT);	/**/		outb(0x9b,CTL_REG_V(1));		outb(0x9b,CTL_REG_V(2));		outb(0x9b,CTL_REG_V(3));		outb(0x9b,CTL_REG_V(4));			outb(0x80,CTL_REG_V(0));	current_dev = DEV8255A0;										return;}static int at91_8255A_release(struct inode* inode,struct file* file){	MOD_DEC_USE_COUNT;	return 0;}struct file_operations at91_8255A_fops = {	owner:       THIS_MODULE,
	write:		at91_8255A_write,
	read:			at91_8255A_read,	open:     at91_8255A_open,	ioctl:		at91_825A_ioctl,	release:  at91_8255A_release,};/* * Initialize and install 8255A driver */static int __init at91_8255A_init(void){	int i;	printk("8255A: at91_8255A_init has been called\n");		//remap memory for 8255A*5	for(i = 0; i<MAX_DEV_NUM; i++)	{		dev_list[i].dev_base_addr_v = (unsigned long)(ioremap(REG_ADDR_BASE[i], DEV_MEM_SIZE));		if (check_region(dev_list[i].dev_base_addr_v, DEV_MEM_SIZE)<0) 
	  {	  	printk("8255A: Cannot map memory:%08x, memory already in use\n", (int)REG_ADDR_BASE[i]);	  	return -1; 	  }	  else	  {	  	printk("8255A: Memory remap:%x => %x\n",REG_ADDR_BASE[i],dev_list[i].dev_base_addr_v);	  }	  request_region(dev_list[i].dev_base_addr_v, DEV_MEM_SIZE,"8255a");	}		//setup 8255a,initialize hardware	at91_8255A_setup();		//register device 	if(register_chrdev(DEV_MAJOR,"8255A",&at91_8255A_fops))
	{		printk("8255A: Can not register 8255A driver \n");
		return -1;
	}
	else	{		printk("8255A: Registerd the 8255A driver  success\n");	}	printk("8255A: the 8255A is working now\n");	return 0;}/* * Disable and remove the 8255A driver */static void __exit at91_8255A_exit(void){	printk("8255A: at91_8255A_exit has been called\n");	unregister_chrdev(DEV_MAJOR,"8255A");	return;}module_init(at91_8255A_init);module_exit(at91_8255A_exit);MODULE_AUTHOR("Ligang Wang");MODULE_DESCRIPTION("AT91 rm9200 8255a driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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