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

📄 s3c2410_scankey.c

📁 2410bios 实现简单功能 裸板传输 跑马灯 定时器
💻 C
字号:
/*
 * s3c2410_scankey.c
 *
 * genric routine for S3C2410-base machine's button
 *
 * Author: Ligang Wang <wangzitan@163.com>
 * Date  : 2006/05/3 
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License. See the file COPYING in the main directory of this archive
 * for more details.
 *
 * 2006-05-03  Initial code by nandy
 */
 
#ifndef __KERNEL__
	#define __KERNEL__
#endif

#ifndef MODULE
	#define MODULE
#endif

#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/hardware.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h>


/*
 * define some macro for debug
 */
 
#define TEST_DEBUG

#ifdef TEST_DEBUG
	#define DEBUG(str,args...) printk ("device_test:"str,##args)
#else
	#define DEBUG(str,args...)
#endif

/*
 * scankey device data struct
 */
struct s3c2410_key_device 
{
	struct fasync_struct *async_queue;       /* Asynchronous notification    */
	wait_queue_head_t     waitq;             /* Wait queue for reading       */
	struct semaphore      lock;              /* Mutex for reading            */
	unsigned int          usage_count;       /* Increment on each open       */
	unsigned              scankey;
	spinlock_t 						irq_lock;
	int 									keypressed;
};

//static int key_pressed = 0;
static char skey_major = 0;
struct s3c2410_key_device s3c2410_key;

/* 
 * declear opration funcation for VFS
 */
static int scankey_open (struct inode *inode, struct file *filp);
static int scankey_release (struct inode *inode, struct file *filp);
static ssize_t scankey_read (struct file *filp, char *buf, size_t count,loff_t *f_pos);
static ssize_t scankey_write (struct file *filp, const char *buf, size_t count,loff_t *f_pos);

/* 
 * declear some funcation for this module
 */
static int setup_scankey(void);
static void clear_line(void);
static void set_line(int line);


/*
 * Create a file operations struct
 */
static struct file_operations s3c2410_scankey_fops = 
{
	owner:		THIS_MODULE,
	open:			scankey_open,
	read:			scankey_read,
	write:		scankey_write,
	release:	scankey_release,
};

/*
 * routine open function for VFS
 */
static int scankey_open (struct inode *inode, struct file *filp)
{
	struct s3c2410_key_device *dev ;

	filp->private_data = &s3c2410_key;
	dev = &s3c2410_key;

	dev->usage_count++; /* We're the first open - clear the buffer */
	dev->keypressed = 0;

	MOD_INC_USE_COUNT;
	return 0;
}

/*
 * routine close/release function for VFS
 */
static int scankey_release (struct inode *inode, struct file *filp)
{
	struct s3c2410_key_device *dev = (struct s3c2410_key_device *)filp->private_data;

	dev->usage_count--;

	filp->f_op->fasync( -1, filp, 0 ); /* Remove ourselves from the async list */
	MOD_DEC_USE_COUNT;

	return 0;
} 

/*
 * routine write function for VFS
 */
static ssize_t scankey_write (struct file *filp, const char *buf, size_t count,loff_t *f_pos)
{

	return 0;
}

static ssize_t scankey_read (struct file *filp, char *buf, size_t count,loff_t *f_pos)
{
	struct s3c2410_key_device *dev = (struct s3c2410_key_device *)filp->private_data;
	
	if (count < sizeof(unsigned char))
		return -EINVAL;

	if(dev->keypressed == 0)
		return 0;
		
	if (copy_to_user(buf, &(dev->scankey), sizeof(unsigned char))) 
   	return -EFAULT;
   		
	dev->keypressed = 0;
	return sizeof(unsigned char);
}

/*
 * routine setup scankey
 */
static int setup_scankey(void)
{
	/* setup GPE13,GPE11,GPG6,GPG2 for line scan 
	 * Output Disable pullup reg
	 */
	set_gpio_ctrl(GPIO_MODE_OUT | GPIO_PULLUP_DIS | GPIO_E13);
	set_gpio_ctrl(GPIO_MODE_OUT | GPIO_PULLUP_DIS | GPIO_E11);
	set_gpio_ctrl(GPIO_MODE_OUT | GPIO_PULLUP_DIS | GPIO_G6);
	set_gpio_ctrl(GPIO_MODE_OUT | GPIO_PULLUP_DIS | GPIO_G2);

	/* setup GPF0,GPF2,GPG3,GPG1 for row scan 
	 * interrupt, enable pullup reg
	 */	
	set_gpio_ctrl(GPIO_MODE_ALT0 | GPIO_PULLUP_EN | GPIO_F0);
	set_gpio_ctrl(GPIO_MODE_ALT0 | GPIO_PULLUP_EN | GPIO_F2);
	set_gpio_ctrl(GPIO_MODE_ALT0 | GPIO_PULLUP_EN | GPIO_G3);
	set_gpio_ctrl(GPIO_MODE_ALT0 | GPIO_PULLUP_EN | GPIO_G11);
	
	/*
	 * setup ext interrupt EXT_FALLING_EDGE
	 */
	set_external_irq(IRQ_EINT0, EXT_LOWLEVEL, GPIO_PULLUP_EN);
	set_external_irq(IRQ_EINT2, EXT_LOWLEVEL, GPIO_PULLUP_EN);
	set_external_irq(IRQ_EINT11, EXT_LOWLEVEL, GPIO_PULLUP_EN);
	set_external_irq(IRQ_EINT19, EXT_LOWLEVEL, GPIO_PULLUP_EN);
	
	/*
	 * Now we has finished setup scankey,so we should enable interrupt
	 */
	 enable_irq(IRQ_EINT0);
	 enable_irq(IRQ_EINT2);
	 enable_irq(IRQ_EINT11);	  
	 enable_irq(IRQ_EINT19);
	 
	/*
	 * claer all line for line scan
	 */
	 clear_line();
	 
	/* everything has been down*/
	 
	return 0;
}

/*
 * routine clear line for line scan
 */
static void clear_line(void)
{
	write_gpio_bit(GPIO_E13,0);
	write_gpio_bit(GPIO_E11,0);
	write_gpio_bit(GPIO_G6,0);
	write_gpio_bit(GPIO_G2,0);
}
	
/*
 * routine set line for line scan
 */	
static void set_line(int line)
{
	clear_line();
	switch (line)
	{
		case 0:
			write_gpio_bit(GPIO_E11,1);
			break;
		case 1:
			write_gpio_bit(GPIO_G6,1);
			break;
		case 2:
			write_gpio_bit(GPIO_E13,1);
			break;
		case 3:
			write_gpio_bit(GPIO_G2,1);
			break;
		}
}	


static void test_scankey_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
	int i;
	struct s3c2410_key_device *dev ;
	int row = -1;
	int line = -1;
	dev = &s3c2410_key;
	spin_lock_irq(&(dev->irq_lock));
	
	mdelay(80);
	switch(irq)
	{
		case IRQ_EINT0:
			if(read_gpio_bit(GPIO_F0) == 0)
				row = 0;
			break;
		case IRQ_EINT2:
			if(read_gpio_bit(GPIO_F2) == 0)
				row = 1;
			break;
  	case IRQ_EINT11:
			if(read_gpio_bit(GPIO_G3) == 0)
  			row = 2;
  		break;	  
	  case IRQ_EINT19:
			if(read_gpio_bit(GPIO_G11) == 0)
	  		row = 3;
	  	break; 
	}

	if(row == -1)
		goto done;
	
	for(i=0; i<4; i++)
	{
		set_line(i);
		if( read_gpio_bit(GPIO_F0) && read_gpio_bit(GPIO_F2) 
			&& read_gpio_bit(GPIO_G3) && read_gpio_bit(GPIO_G11))
		{
			line = i;
			break;
		}
	}
	if(line != -1) 
	{
		dev->scankey = row * 4 + line + 1;
		dev->keypressed = 1;
		mdelay(30);
	}
	
done:
	clear_line();
	spin_unlock_irq(&(dev->irq_lock));
	return;
}
	
/* 
 * routine module init
 */
int __init scankey_init(void)
{
  int result,i;
  int ext_irq_id[4] = {IRQ_EINT11,IRQ_EINT19,IRQ_EINT2,IRQ_EINT0};
  struct s3c2410_key_device *dev;
  dev = &s3c2410_key;

	DEBUG("[INFO: start init scankey ]\n");
    
  result = register_chrdev(0,"s3c2410_scankey", &s3c2410_scankey_fops);

  if(result < 0)
  {
  	printk("[FAILED: Cannot register s3c2410_scankey!] \n");
    return result;
  }
  else
  {
  	skey_major = result;
  	printk("[INFO:s3c2410_scankey major is %d\n",skey_major);
  }
	setup_scankey();
	for(i=0; i<4; i++)
	{
	  if((result = request_irq(ext_irq_id[i], test_scankey_interrupt, 
	  	SA_INTERRUPT, "s3c2410_scankey",  NULL)) != 0)
	  {
	  	printk("[FAILED: result of irq is :%d\n]",result);
	  	printk(KERN_INFO "[FAILED:Cannot register scankey scankey_interrupt!],%d\n",ext_irq_id[i]);
	    return -EBUSY;
	  }
	}
	init_waitqueue_head(&dev->waitq);   //当有几个程序同时使用键盘,避免冲突
	init_MUTEX(&dev->lock);
	dev->async_queue = NULL;
  DEBUG("[INFO:s3c44b0 scankey driver installed. ]\n");
  return 0;
}

/*
 * routine module clean
 */
void __exit scankey_cleanup(void)
{
	int i;
  int ext_irq_id[4] = {IRQ_EINT11,IRQ_EINT19,IRQ_EINT2,IRQ_EINT0};
	DEBUG("[INFO: clean scankey. ]\n");
	for(i=0; i<4; i++)
	{
	  free_irq(ext_irq_id[i], NULL);
	}
	
	unregister_chrdev(skey_major,"s3c2410_scankey");
	return ;	
}

module_init(scankey_init);
module_exit(scankey_cleanup);


MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ligang Wang wangzitan@163.com");
MODULE_DESCRIPTION("scankey for S3C2410");

⌨️ 快捷键说明

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