게시일: 2018. 12. 18 오전 9:53:59
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <asm/fcntl.h>
#include <linux/ioport.h>
#include <asm/ioctl.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/delay.h>
#define DRIVER_DESC "keysw program" // 모듈에 대한 설명
#define KEY_MAJOR_NUMBER 245 // 디바이스 주번호
#define KEY_NAME "KEYSW" // 디바이스 이름
#define KEY_MODULE_VERSION "KEYSW V0.1" // 디바이스 버전
#define ADDR_KEY_PHY 0x88000070 // keysw 의 물리주소
#define KEY_ADDRESS_RANGE 0x1000 // I/O 영역의 크기
#define TIMER_INTERVAL 4
static unsigned int keysw_usage = 0;
static unsigned long keysw_ioremap;
static unsigned short *keycoladdr;
static unsigned short *keyrowaddr;
int keysw_open(struct inode *inode, struct file *filp)
{
// 디바이스가 열려 있는지 확인.
if (keysw_usage != 0) return -EBUSY;
// keysw 의 가상 주소 매핑
keysw_ioremap = (unsigned long)ioremap(ADDR_KEY_PHY, KEY_ADDRESS_RANGE);
// 등록할 수 있는 I/O 영역인지 확인
if (!check_mem_region(keysw_ioremap, KEY_ADDRESS_RANGE)) {// I/O 메모리 영역을 등록
request_mem_region(keysw_ioremap, KEY_ADDRESS_RANGE, KEY_NAME);
}
else printk("driver : unable to register this!\n");
// keysw 의 첫번째줄과 두번째줄에 대한 주소 설정
keycoladdr = (unsigned short*)keysw_ioremap;
keyrowaddr = (unsigned short*)(keysw_ioremap + 0x2);
keysw_usage = 1;
return 0;
}
int keysw_release(struct inode *inode, struct file *filp)
{
// 매핑된 가상주소를 해제
iounmap((unsigned long*)keysw_ioremap);
// 등록된 I/O 메모리 영역을 해제
release_mem_region(keysw_ioremap, KEY_ADDRESS_RANGE);
keysw_usage = 0;
return 0;
}
ssize_t keysw_read(struct file *inode, char *gdata, size_t length, loff_t *off_what)
{
int key_value = 0;
int key_test = 0x01;
int ret;
int i = 0;
int k = 0;
int j=0;
key_test = 0x01;
for (i = 0; i < 4; i++)
{
if(key_value != 0)
break;
*keyrowaddr = key_test;
for (j = 0; j < 2000; j++);
key_value = *keycoladdr;
if (key_value != 0)
{
if (*keyrowaddr == 0x01)
{
switch (key_value)
{
case 0x01: key_value = 0x01; break;
case 0x02: key_value = 0x02; break;
case 0x04: key_value = 0x03; break;
case 0x08: key_value = 0x04; break;
}
}
if (*keyrowaddr == 0x02)
{
switch (key_value)
{
case 0x01: key_value = 0x05; break;
case 0x02: key_value = 0x06; break;
case 0x04: key_value = 0x07; break;
case 0x08: key_value = 0x08; break;
}
}
if (*keyrowaddr == 0x04)
{
switch (key_value)
{
case 0x01: key_value = 0x09; break;
case 0x02: key_value = 0x0a; break;
case 0x04: key_value = 0x0b; break;
case 0x08: key_value = 0x0c; break;
}
}
if (*keyrowaddr == 0x08)
{
switch (key_value)
{
case 0x01: key_value = 0x0d; break;
case 0x02: key_value = 0x0e; break;
case 0x04: key_value = 0x0f; break;
case 0x08: key_value = 0x10; break;
}
}
}
key_test = key_test * 2;
}
ret = copy_to_user(gdata, &key_value, 4);
if (ret < 0) return -1;
return length;
}
struct file_operations keysw_fops =
{
.owner = THIS_MODULE,
.open = keysw_open,
.read = keysw_read,
.release = keysw_release,
};
int keysw_init(void)
{
int result;
// 문자 디바이스 드라이버를 등록한다.
result = register_chrdev(KEY_MAJOR_NUMBER, KEY_NAME, &keysw_fops);
if (result < 0) { // 등록실패
printk(KERN_WARNING"Can't get any major\n");
return result;
}
// major 번호를 출력한다.
printk("Init Module, Dipsw Major Number : %d\n", KEY_MAJOR_NUMBER);
return 0;
}
// 모듈을 커널에서 제거
void keysw_exit(void)
{
// 문자 디바이스 드라이버를 제거한다.
unregister_chrdev(KEY_MAJOR_NUMBER, KEY_NAME);
printk("driver: %s DRIVER EXIT\n", KEY_NAME);
}
module_init(keysw_init); // 모듈 적재 시 호출되는 함수
module_exit(keysw_exit); // 모듈 제거 시 호출되는 함수
MODULE_DESCRIPTION(DRIVER_DESC); // 모듈에 대한 설명
MODULE_LICENSE("Dual BSD/GPL"); // 모듈의 라이선스 등록