linuxqudong.txt

来自「这是2410板子上的按键的驱动程序」· 文本 代码 · 共 221 行

TXT
221
字号
  key_test.c
 ****************************/
/*#ifndef __KERNEL__
 #define __KERNEL__
#endif
#ifndef MODULE
 #define MODULE
#endif
*/
/* 以上语句是用来判断驱动是直接编译到内核里面,还是以模块形式来调用的。驱动程序要在Kconfig
   文件里面定义了,才能出现在make menuconfig的菜单中,到时可选择是作为模块还是直接编译进内核。*/
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/arch/S3C2410.h>
#include "def.h" //定义了按键的地址值和数据类型等。
//以上是头文件,开始看代码,找到最后面的----(1),从那看起。
 
static loff_t key_test_llseek(struct file *filp,loff_t off, int whence);
static ssize_t key_test_read(struct file *filp,char *buf, size_t count,loff_t *f_pos);
static ssize_t key_test_write(struct file *filp,const char *buf,size_t count,loff_t *f_pos);
static int key_test_open(struct inode *inode, struct file *filp);
static int key_test_release(struct inode *inode, struct file *filp);
static int key_test_ioctl(struct inode *inode,struct file *filp, unsigned int cmd, unsigned long param);
int key_test_init(void);
void key_test_cleanup(void);
#define MAJOR_NR 121           //这个定义的主设备号,在linux下用ls -l看得到(在日期项前)
#define DEVICE_NAME "key_test_"  //设备名称,出理在/dev/char目录下
//#define DEVICE_NR(device) MINOR(device)
//#define DEVICE_NO_RANDOM
//#define DEVICE_OFF(d)

//这里是-----(7),这里的内容属于接口与技术这门课的内容了
U8 Key_Scan( void )
{
 Delay( 50 ) ;
 rGPGDAT = rGPGDAT & (~((1<<6)|(1<<2))) | (1<<6) | (0<<2) ;  //GPG6,2 output 0
 rGPEDAT = rGPEDAT & (~((1<<13)|(1<<11))) | (1<<13) | (1<<11) ;  //GPE13,11 output 0
 if(      (rGPFDAT&(1<< 0)) == 0 )  return 16 ;
 else if( (rGPFDAT&(1<< 2)) == 0 )  return 15 ;
 else if( (rGPGDAT&(1<< 3)) == 0 )  return 14 ;
 else if( (rGPGDAT&(1<<11)) == 0 )  return 13 ;
 rGPGDAT = rGPGDAT & (~((1<<6)|(1<<2))) | (0<<6) | (1<<2) ;  //GPG6,2 output 0
 rGPEDAT = rGPEDAT & (~((1<<13)|(1<<11))) | (1<<13) | (1<<11) ;  //GPE13,11 output 0
 if(      (rGPFDAT&(1<< 0)) == 0 )  return 11 ;
 else if( (rGPFDAT&(1<< 2)) == 0 )  return 8 ;
 else if( (rGPGDAT&(1<< 3)) == 0 )  return 5 ;
 else if( (rGPGDAT&(1<<11)) == 0 )  return 2 ;
 rGPGDAT = rGPGDAT & (~((1<<6)|(1<<2))) | (1<<6) | (1<<2) ;  //GPG6,2 output 0
 rGPEDAT = rGPEDAT & (~((1<<13)|(1<<11))) | (1<<13) | (0<<11) ;  //GPE13,11 output 0
 if(      (rGPFDAT&(1<< 0)) == 0 )  return 10 ;
 else if( (rGPFDAT&(1<< 2)) == 0 )  return 7 ;
 else if( (rGPGDAT&(1<< 3)) == 0 )  return 4 ;
 else if( (rGPGDAT&(1<<11)) == 0 )  return 1 ;
 rGPGDAT = rGPGDAT & (~((1<<6)|(1<<2))) | (1<<6) | (1<<2) ;  //GPG6,2 output 0
 rGPEDAT = rGPEDAT & (~((1<<13)|(1<<11))) | (0<<13) | (1<<11) ;  //GPE13,11 output 0
 if(      (rGPFDAT&(1<< 0)) == 0 )  return 12 ;
 else if( (rGPFDAT&(1<< 2)) == 0 )  return 9 ;
 else if( (rGPGDAT&(1<< 3)) == 0 )  return 6 ;
 else if( (rGPGDAT&(1<<11)) == 0 )  return 3 ;
 else return 0xff ;
}

static void __irq KeyISR(void)
{
 U8 key ;
 rGPGCON = rGPGCON & (~((3<<22)|(3<<6))) | ((0<<22)|(0<<6)) ;  //GPG11,3 set input
 rGPFCON = rGPFCON & (~((3<<4)|(3<<0))) | ((0<<4)|(0<<0)) ;  //GPF2,0 set input
 
 if(rINTPND==BIT_EINT8_23) 
 {
  ClearPending(BIT_EINT8_23);
  if(rEINTPEND&(1<<11)) 
  {
   //puts("Interrupt eint11 occur...");
   rEINTPEND |= 1<< 11;
  }
  
  if(rEINTPEND&(1<<19)) 
  {
   //puts("Interrupt eint19 occur...");  
   rEINTPEND |= 1<< 19;
  }
 }
 
 else if(rINTPND==BIT_EINT0)
 {
  //puts("Interrupt eint0 occur...");
  ClearPending(BIT_EINT0);
 }
 
 else if(rINTPND==BIT_EINT2) 
 {
  //puts("Interrupt eint2 occur...");
  ClearPending(BIT_EINT2);
 }
 //这里是-----(6),这里(5)里面实现函数时调用的函数的内容
 //查询按键键值
 key = Key_Scan() ;
 if( key != 0xff )
  printf( "Interrupt occur... K%d is pressed!\n", key ) ;
 //Beep( 2000, 3000 ) ;
 //重新初始化IO口
 rGPGCON = rGPGCON & (~((3<<12)|(3<<4))) | ((1<<12)|(1<<4)) ;  //GPG6,2 set output
 rGPGDAT = rGPGDAT & (~((1<<6)|(1<<2)));  //GPG6,2 output 0
 
 rGPECON = rGPECON & (~((3<<26)|(3<<22))) | ((1<<26)|(1<<22));  //GPE13,11 set output
 rGPEDAT = rGPEDAT & (~((1<<13)|(1<<11)));  //GPE13,11 output 0
 
 rGPGCON = rGPGCON & (~((3<<22)|(3<<6))) | ((2<<22)|(2<<6)) ;  //GPG11,3 set EINT
 rGPFCON = rGPFCON & (~((3<<4)|(3<<0))) | ((2<<4)|(2<<0)) ;  //GPF2,0 set EINT
}
//这里是-----(5),这里(4)里面实现KeyScanInit函数时调用的函数的内容
void KeyScanInit(void)
{
 rGPGCON = rGPGCON & (~((3<<12)|(3<<4))) | ((1<<12)|(1<<4)) ;  //GPG6,2 set output
 rGPGDAT = rGPGDAT & (~((1<<6)|(1<<2)));  //GPG6,2 output 0
 
 rGPECON = rGPECON & (~((3<<26)|(3<<22))) | ((1<<26)|(1<<22));  //GPE13,11 set output
 rGPEDAT = rGPEDAT & (~((1<<13)|(1<<11)));  //GPE13,11 output 0
 
 rGPGCON = rGPGCON & (~((3<<22)|(3<<6))) | ((2<<22)|(2<<6)) ;  //GPG11,3 set EINT
 rGPFCON = rGPFCON & (~((3<<4)|(3<<0))) | ((2<<4)|(2<<0)) ;  //GPF2,0 set EINT
 
 rEXTINT0 &= ~(7|(7<<8)); 
 rEXTINT0 |= (2|(2<<8)); //set eint0,2 falling edge int
 rEXTINT1 &= ~(7<<12);
 rEXTINT1 |= (2<<12); //set eint11 falling edge int
 rEXTINT2 &= ~(0xf<<12);
 rEXTINT2 |= (2<<12); //set eint19 falling edge int
 rEINTPEND |= (1<<11)|(1<<19);  //clear eint 11,19
 rEINTMASK &= ~((1<<11)|(1<<19)); //enable eint11,19
 ClearPending(BIT_EINT0|BIT_EINT2|BIT_EINT8_23);
 pISR_EINT0 = pISR_EINT2 = pISR_EINT8_23 = (U32)KeyISR;
 EnableIrq(BIT_EINT0|BIT_EINT2|BIT_EINT8_23); 
}
//这里是-----(4),这里(3)里面实现open函数时调用的函数的内容
void Key_Scan_Test( void )
{
 
 Uart_Printf( "\n8X2 KEY array TEST ( Interrupt MODE )\n" );
 Uart_Printf( "Press 'ESC' key to Exit this program !\n\n" );
 KeyScanInit() ;//键值
    while( Uart_GetKey() != ESC_KEY ) ;
 rGPGCON = rGPGCON & (~((3<<22)|(3<<6))) | ((0<<22)|(0<<6)) ;  //GPG11,3 set input
 rGPFCON = rGPFCON & (~((3<<4)|(3<<0))) | ((0<<4)|(0<<0)) ;  //GPF2,0 set input
}
 
//这里是-----(3),这里file_operations结构的内容
static struct file_operations key_test_fops=
{
 llseek: key_test_llseek,   //llseek函数;
 read:key_test_read,        //read函数; 
 write:key_test_write,      //write函数
 open: key_test_open,       //open函数
 release:key_test_release,  //....
 ioctl: key_test_ioctl,     // ....这个在CD-ROM里面就是什么弹出,关仓等等的控制了
 };
//上面的每一个字段就指向下面的每一个相应的函数,这些函数就是linux编程时调用的函数(接口)。
 
static loff_t key_test_llseek(struct file *filp,loff_t off, int whence)
{
 printk(KERN_DEBUG"Function llseek...\n");
 return 0;
}
static int key_test_read(struct file *filp,char *buf, size_t count,loff_t *f_pos)
{
 printk(KERN_DEBUG"Device is reading...\n");
 return 0;
}
//上面五句就是实现read函数的具体语句了,下面的都类似,不过真正写时不会这么简单吧。
static int key_test_write(struct file *filp,char *buf, size_t count,loff_t *f_pos)
{
 printk(KERN_DEBUG"Device is writting...\n");
 return 0;
}
static int key_test_open(struct inode *inode, struct file *filp)
{
 printk(KERN_DEBUG"Device is opening...\n");
 Key_Scan_Test();  //这是检测你按的是哪个键的函数
 return 0;
//这个函数的参数的*filp就是我们平时调用open()得到的描述符的结构了,inode则表示文件描述符指向
的是哪个文件,因为一个文件可能会有许多个描述符打开。
}
static int key_test_release(struct inode *inode, struct file *filp)
{
 printk(KERN_DEBUG"Releasing this device...\n");
 return 0;
}
static int key_test_ioctl(struct inode *inode,struct file *filp,
unsigned int cmd,unsigned long arg)
{
 return 0;
}
//这里是-----(2),这里写的是初始化和移除模块里面的内容
int key_test_init(void)
{
 int result;
 result=register_chrdev(MAJOR_NR,DEVICE_NAME,&key_test_fops);
 /*上面这句是注册设备号和设备名称到内核,它们会出现在/proc和sysfs文件夹中。和一个
  file_operations结构,里面的每个字段就是指向一个实现驱动的一个函数。*/
 if(result<0)
 {
 printk(KERN_ERR DEVICE_NAME":get major %d wrong\n",MAJOR_NR);
 return(result);
 }    //当返回结果不为0时,表示初始化失败
 printk("Device KEY initialized OK\n");
 return 0;
}
 
void key_test_cleanup(void)
{
 unregister_blkdev(MAJOR_NR,DEVICE_NAME);//释放设备号和设备名
}
//从这里开始看起,这是-----(1)
module_init(key_test_init); //这是模块初始化,也就是被内核装载时调用,记住参数名是什么?
module_exit(key_test_cleanup); //驱动模块被移除时调用
MODULE_AUTHOR("aaaaa");  //作者名字 
MODULE_DESCRIPTION("SIMPLE Character"); //描述一下这是什么驱动 
MODULE_LICENSE("dual BSD/GPL"); //遵循BSD/GPL协议,没有这句的话可能内核会产生抱怨.

⌨️ 快捷键说明

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