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

📄 sw4.c

📁 基于linux和arm s3c2410的键盘驱动程序
💻 C
字号:
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/interrupt.h>        /* for in_interrupt */
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/delay.h>              /* for udelay */
#include <linux/modversions.h>
#include <linux/miscdevice.h>
#include <linux/version.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/hardware.h>

#define IRQ_KBD  IRQ_EINT1  //linux在初始化的时候已经把每个中断向量的地址准备好
								IRQ_EINT1是外部1号中断
#define GPIO_SimpleINT_EINT2           (GPIO_MODE_ALT0 | GPIO_PULLUP_EN | GPIO_F2) //通用输入输出口设置For ringing 

#define ZLGCSDIS()       	(GPBDAT |=(0x01 << 6))//片选置成无效
#define ZLGCSEN()      	(GPBDAT &=~(0x01 << 6))// 片选置成有效
#define ZLGMO()       	(GPBDAT &=~(0x01 << 0))//置成输出方向
#define ZLGMI()      	(GPBDAT |=(0x01 << 0))// 置成输入方向

#define Keypad_MAJOR 97//定义键盘设备号


devfs_handle_t dev_handle;             /* register handle to store device fs */
static unsigned char Keycode = 0;
static unsigned char haveData = 0;

static DECLARE_WAIT_QUEUE_HEAD(keypad);// 经过宏展开后就是定义了一个keypad等待队列头变量,核心运行过程中,经常会因为某些条件不满足而需要挂起当前线程,直至条件满足了才继续执行

static unsigned char spiRead();
static void spi_Init();
static void ZLG_interrupt(int nr, void *devid, struct pt_regs *regs);

ssize_t keypad_read (struct file * file ,char * buf, size_t count, loff_t * f_ops)
{
      interruptible_sleep_on(&keypad);//挂起程序
      copy_to_user(buf, &Keycode, sizeof Keycode);
      haveData = 0;
      return 1;
}


ssize_t SimpleINT_open (struct inode * inode ,struct file * file)
{
      printk("s3c2410:device open operation!\n");
      return 0;
}

struct file_operations Keypad_ops ={
      open:       SimpleINT_open,
      read:       keypad_read,
     // poll:    	  keypad_select,
};

	
//中断处理函数
static void ZLG_interrupt(int nr, void *devid, struct pt_regs *regs)
{
        Keycode = spiRead();
	haveData = 1;
	wake_up_interruptible(&keypad);//唤醒程序

}

static int __init keypad_init(void)//键盘初始化程序
{
	int ret = -ENODEV;
	spi_Init();//spi外围串口初始化程序

        set_external_irq(IRQ_KBD,EXT_FALLING_EDGE, GPIO_PULLUP_EN);
//请求中断
	ret = devfs_register_chrdev(Keypad_MAJOR, "Keypad", &Keypad_ops);
		//字符设备注册,主设备号,设备名,函数关联结构体
	if( ret < 0 ){
             printk (" Keypad: init_module failed with %d\n", ret);
             return ret;
    }
	ret = request_irq(IRQ_KBD, ZLG_interrupt, SA_INTERRUPT,
                      "Keypad", NULL);// 注册中断服务程序,把中断向量和中断服务程序对应起来。
	if (ret) {
			  devfs_unregister_chrdev(Keypad_MAJOR, "Keypad");//取消注册
              printk(KERN_INFO "request Keypad IRQ failed (%d)\n", IRQ_KBD);
        	  return ret;
    }
    
    dev_handle = devfs_register( NULL, "Keypad", DEVFS_FL_DEFAULT,
                                 Keypad_MAJOR, 0, S_IFCHR, &Keypad_ops, NULL);
//登记设备入口点,获得文件句柄
    return ret;
}

int spiWrite(u8 keycode)
{
	ZLGCSEN();
	ZLGMO();
	udelay(60);
	
	while((SPSTA1 & 0x01)== 0);
		SPTDAT1 = keycode;//数据寄存器
	while((SPSTA1 & 0x01)== 0);
	
	ZLGCSDIS();
	
	return 0;
}
	
static unsigned char spiRead(void)
{
	unsigned char code;
	
	ZLGCSEN();
	ZLGMO();
	udelay(60);
	
	while((SPSTA1 & 0x01)== 0);
		SPTDAT1 = 0x15;
	while((SPSTA1 & 0x01)== 0);
	
	udelay(30);
	
	ZLGMI();
	SPTDAT1 = 0xff;//状态寄存器
	while((SPSTA1 & 0x01)== 0);
	
	ZLGCSDIS();
	ZLGMO();
	code = SPSTA1; //状态寄存器
	return code;
}

static void spi_Init()//spi外围串口初始化程序
{
	// Setup IO port for SPI interface & Keyboard
	
	// Setup EINT1 (KBDINT)
    	GPFCON &= ~(0x3 << 2); 		// Clear GPF1 
    	GPFCON |= (0x2 << 2);  		// Set GPF1 to EINT1 for Keyboard interrupt

    	EXTINT0 &= ~(0x7 << 4);    	// Clear EINT1
    	EXTINT0 |= (0x2 << 4);     	// fallig edge triggered for EINT1

	// setup SPI interface
	GPGCON &= ~((0x3 << 10) | (0x3 << 12) | (0x3 << 14));   // Clear GPG5,6,7
    	GPGCON |= ((0x3 << 10) | (0x3 << 12) | (0x3 << 14));    
     
	// setup _SS signal(nSS_KBD)
    	GPBCON &= ~(0x3 << 12);         // Clear GPB6
    	GPBCON |= (0x01 << 12);       // Set Port GPB6 to output for nSS signal
    
   	ZLGCSDIS();			         // Set /SS high 

	// setup Dir signal (KEYBOARD)  CPU->7289
    	GPBCON &= ~(0x3 << 0);         // Clear GPB0 
    	GPBCON |= (0x01 << 0);       // Set Port GPB0 to output for _PWR_OK signal
	
	ZLGMO();
        
	// Setup SPI registers
    	SPCON1 = (0<<5)|(0X01 << 4)|(0X01 << 3)|(0x0<<2)|(0<<1);
        
	// Developer MUST change the value of prescaler properly whenever value of PCLK is changed.
    	SPPRE1 = 255;					// 99.121K = 203M/4/2/(255+1) PCLK=50.75Mhz FCLK=203Mhz 	    		SPICLK=99.121Khz

	spiWrite(0xa4);				//send init command

    	printk("Key Pad Init complete:\n");	

 }
	


/*static int keypad_select(struct file *file, struct poll_table_struct *wait)
{
	if(haveData)
		return 1;
	return 0;
}*/

int __init sw4_init_module() 
{
      int ret = -ENODEV;
      ret = keypad_init();//键盘初始化
      if (ret)
         return ret;
      return 0;
}
void __exit sw4_cleanup_module()
{
			
         free_irq(IRQ_KBD, NULL);// 释放中断
         devfs_unregister_chrdev( Keypad_MAJOR, "Keypad" );//注销设备号
         devfs_unregister( dev_handle );//注销设备文件句柄
			return;
}

module_init(sw4_init_module);//内核特殊的宏,指明次函数为模块
module_exit(sw4_cleanup_module);

MODULE_LICENSE("GPL");//采用GPL软件许可证


			
			

⌨️ 快捷键说明

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