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

📄 s3c2440_gpio.c

📁 s3c2440 gpio 的控制
💻 C
字号:
 #include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/miscdevice.h>#include <linux/sched.h>#include <linux/delay.h>#include <linux/poll.h>#include <linux/spinlock.h>#include <linux/irq.h>#include <linux/delay.h> #include <asm/hardware.h>#include <stelcom/stel_proc.h>	//定义/proc下模块版本信息相关变量#define DEBUG#ifdef DEBUG#define DBG(arg... )	printk( "<gpio "__FUNCTION__ "()>\t" ##arg )#else#define DBG(args...)#endif#define DRIVER_VERSION 		"0.02"#define DRIVER_AUTHOR 		"Siki <shi@162.com>"#define STELCOM_DEV_DIR 		"ee100"#define DRIVER_DESC			" GPIO control Driver"#define DEVICE_NAME			"gpio"#define DEVICE_MAJOR 		0#ifdef CONFIG_PROC_MODVERSIONstatic int stel_proc_read(char *buf, char **start, off_t off,			    int count, int *eof, void *data);static struct stelproc_entry stel = {	"stel_gpio",	stel_proc_read , DRIVER_VERSION};static char 	proc_name[50];#endif	/* CONFIG_PROC_MODVERSION *//* ioctl number, NR *//* ioctl contain 4 bytes.The content from lower to higer bit is: *   Nr(8 bits), Type(8 bits), Size(14 bits), Direction(2 bits) for arm architeture * In this source, Nr decides the GPIO to be controled in ioctl,Type=GPIO_IOC_MAGIC,  *   Size=1, Direction shows whether to read data from userspace or to write data *   to userspace. * Nr must only be one of below: *   GPA0~GPA24:0-24 *   GPB0~GPB15:25-40 *   GPC0~GPC15:41-56 *   GPD0~GPD15:57-72 *   GPE0~GPE15:73-88 *   GPF0~GPF15:89-104 *   GPG0~GPG15:105-120 *   GPH0~GPH15:121-136 *   GPJ0~GPJ15:137-152 * * Attention: change the GPIO output may result in crash of the system.Be careful!!!! */#define GPIO_IOC_MAGIC		0xB4#define GPIO_IOC_MAXNR 		152static int 	gpio_major, gpio_opened = 0;static 	devfs_handle_t 	devfs_handle, devfs_dir_handle;static int gpio_open(struct inode *inode, struct file *file){		DBG("Open the gpio driver...\n");	MOD_INC_USE_COUNT;	gpio_opened = 1;		return 0;}static int gpio_close(struct inode *inode, struct file *filp){	DBG("Close the gpio driver...\n");	if( gpio_opened == 0 ) {		printk("The gpio driver hasn't opened!\n");		return 0;	}		MOD_DEC_USE_COUNT;	gpio_opened = 0;		return 0;}static int gpio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){	int 	err = 0, dir, tmp, port, nr;//port and nr to specify the GPIO.for example, GPA2:port=0,nr=2	u32		tmp2, value = 0;	char	from, to;	int 	retval = 0;    	/*	 * extract the type and number bitfields, and don't decode	 * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()	 */	if (_IOC_TYPE(cmd) != GPIO_IOC_MAGIC) return -ENOTTY;	if (_IOC_NR(cmd) > GPIO_IOC_MAXNR) return -ENOTTY;	/*	 * the direction is a bitmask, and VERIFY_WRITE catches R/W	 * transfers. `Type' is user-oriented, while	 * access_ok is kernel-oriented, so the concept of "read" and	 * "write" is reversed	 */	if (_IOC_DIR(cmd) & _IOC_READ)		err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));	else if (_IOC_DIR(cmd) & _IOC_WRITE)		err =  !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));	if (err) return -EFAULT;    	dir = _IOC_DIR(cmd);	tmp = _IOC_NR(cmd);	if(tmp < 25) {		port = 0;		nr = tmp;	}	else {		port = (tmp-25)/16 + 1;		nr = (tmp-25) % 16;	}		DBG("cmd is 0x%x.\n",cmd);	DBG("dir is %d.\n",dir);	DBG("port is %d.\n",port);	DBG("nr is %d.\n",nr);	switch(dir) {	  case _IOC_READ:	  	DBG("Enter the IOC_READ.\n");	  	if(port == 0) {	//GPA			DBG("sikinzen1.\n");						GPACON &= (0xffffffff^(0x00000001<<nr));			DBG("sikinzen2.\n");			value = GPADAT & (0x00000001<<nr); 			DBG("sikinzen3.\n");			value >>= nr;				DBG("GPA:value is 0x%x.\n", value);	  	}		else if(port == 8) {	//GPJ		    	tmp2 = GPJCON;			tmp2 |= (0x00000003<<(2*nr));			tmp2 &= (0xffffffff^(0x00000002<<(2*nr)));			GPJCON = tmp2;			value = GPJDAT & (0x00000001<<nr); 			value >>= nr;				DBG("GPJ:value is 0x%x.\n", value);		}		else { //GPB ~ GPH			tmp = port*0x10;			tmp2 = bGPIO(tmp);			tmp2 |= (0x00000003<<(2*nr));			tmp2 &= (0xffffffff^(0x00000002<<(2*nr)));			bGPIO(tmp) = tmp2;			value = bGPIO(tmp+4) & (0x00000001<<nr); 			value >>= nr;			DBG("GPB ~ GPH:value is 0x%x.\n", value);		}		from = value;				DBG("Data read is %d.\n", from);		put_user(from, (char *)arg);		break;							  case _IOC_WRITE:	  	DBG("Enter the IOC_WRITE.\n");	  	get_user(to, (char *)arg);		value = to;		DBG("Data to be write is 0x%x.\n", value);		if((value != 0) &&(value != 1)) {			printk("The data write to I/O is wrong!\n");			return -1;    		}		value <<= nr;		DBG("Value is:0x%x.\n", value);		if(port == 0) {	//GPA			DBG("sikinzen1.\n");						GPACON &= (0xffffffff^(0x00000001<<nr));			tmp2 = GPACON;			DBG("GPACON:0x%x.\n", tmp2);			tmp2 = GPADAT;			tmp2 &= (0xffffffff^(0x00000001<<nr));			tmp2 |= value;			GPADAT = tmp2;						DBG("GPADAT:0x%x.\n", tmp2);	  	}		else if(port == 8) {	//GPJ			DBG("sikinzen1.\n");			tmp2 = GPJCON;			tmp2 |= (0x00000003<<(2*nr));			tmp2 &= (0xffffffff^(0x00000002<<(2*nr)));			GPJCON = tmp2;			DBG("GPJCON:0x%x.\n", tmp2);			tmp2 = GPJDAT;			tmp2 &= (0xffffffff^(0x00000001<<nr));			tmp2 |= value;			GPJDAT = tmp2;			DBG("GPJDAT:0x%x.\n", tmp2);		}		else { //GPB ~ GPH			tmp = port*0x10;			tmp2 = bGPIO(tmp);			tmp2 |= (0x00000003<<(2*nr));			tmp2 &= (0xffffffff^(0x00000002<<(2*nr)));			bGPIO(tmp)= tmp2;						DBG("GPBCON~GPHCON:0x%x.\n", tmp2);			tmp2 = bGPIO(tmp+4);			tmp2 &= (0xffffffff^(0x00000001<<nr));			tmp2 |= value;			bGPIO(tmp+4) = tmp2;						DBG("GPBDAT~GPHDAT:0x%x.\n", tmp2);			tmp2 = bGPIO(tmp+8);			tmp2 &= (0xffffffff^(0x00000001<<nr));			//tmp2 |= value;			bGPIO(tmp+8) = tmp2;						DBG("GPBUP~GPHUP:0x%x.\n", tmp2);		}		break;			  default:  	  	DBG("Users haven't specified the direction.\n");		return -ENOTTY;	}	return retval;	}static struct file_operations gpio_fops = {	owner:		THIS_MODULE,	open:		gpio_open,	release:		gpio_close,	ioctl:		gpio_ioctl,};#ifdef CONFIG_PROC_MODVERSIONstatic int stel_proc_read(char *buf, char **start, off_t off,			    int count, int *eof, void *data){	int		len = 0;	len = sprintf(buf, "%s\n", stel.version);	return len;}#endif  /* CONFIG_PROC_MODVERSION */static int __init gpio_init(void){	int ret;			// 注册为字符设备:主设备号为0时,由系统自动分配未使用的设备号	ret = register_chrdev(DEVICE_MAJOR, DEVICE_NAME, &gpio_fops);	if(ret < 0)  {		printk(DEVICE_NAME " can't register major number\n");		return ret;	}		// 向设备文件系统注册该设备#ifdef CONFIG_DEVFS_FS	gpio_major = ret;	devfs_dir_handle = devfs_mk_dir(NULL,STELCOM_DEV_DIR, NULL);	devfs_handle = devfs_register(devfs_dir_handle,DEVICE_NAME, DEVFS_FL_DEFAULT,				gpio_major, 0, S_IFCHR | S_IRUSR | S_IWUSR, &gpio_fops, NULL);#endif#ifdef CONFIG_PROC_MODVERSION	sprintf(proc_name, "%s/%s", PROC_MODVER_DIR,stel.name);	create_proc_read_entry ( proc_name, 0, NULL, stel.fn, NULL);#endif	printk(KERN_INFO DRIVER_DESC "v" DRIVER_VERSION " has been initialized.\n");	return 0;}static void __exit gpio_exit(void){#if CONFIG_PROC_MODVERSION	remove_proc_entry ( proc_name, NULL);#endif	devfs_unregister(devfs_handle);					// 从设备文件系统注销该设备	unregister_chrdev(gpio_major, DEVICE_NAME);	// 从字符设备注销该设备	printk(KERN_INFO"The GPIO driver has been unregistered!\n");}module_init(gpio_init);module_exit(gpio_exit);MODULE_AUTHOR( DRIVER_AUTHOR );MODULE_DESCRIPTION( DRIVER_DESC );MODULE_LICENSE("GPL");EXPORT_NO_SYMBOLS;

⌨️ 快捷键说明

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