Mobile & Embedded System Lab. Dept. of Computer Engineering Kyung Hee Univ.
Keypad Device Control in Embedded Linux HBE-SM5-S4210 에는 16 개의 Tack Switch 를사용하여 4 행 4 열의 Keypad 가장착되어있다. 2
Keypad Device Driver Device Driver Version 소스파일작성 Keypad 드라이버는커널에포함되어있다. menuconfig 를실행 root@ubuntu:~/working/linux-2.6.35-s4210# make menuconfig Device Drivers -> Input device supprot -> [*] keyboards [*] HBE- XXX-S4210 FPGA keypad support 3
Keypad Device Driver 소스코드확인 소스코드는 ~/working/linux-2.6.35-s4210/drivers/input/keyboard 에있다. root@ubuntu:~/working/linux-2.6.35-s4210# cd drivers/input/keyboard root@ubuntu:~/working/linux-2.6.35-s4210/drviers/input/keyboard# vi hanback_fpga_keypad.c 001: #include <linux/init.h> 002: #include <linux/module.h> 003: #include <mach/hardware.h> 004: #include <asm/uaccess.h> 005: #include <linux/kernel.h> 006: #include <linux/fs.h> 007: #include <linux/types.h> 008: #include <asm/ioctl.h> 009: #include <linux/ioport.h> 010: #include <asm/io.h> 011: #include <linux/delay.h> 012: #include <linux/timer.h> 013: #include <linux/signal.h> 014: #include <linux/sched.h> 015: #include <linux/input.h> 4
Keypad Device Driver 015: #include <linux/input.h> 016: 017: #define DRIVER_AUTHOR "Hanback Electronics" 018: #define DRIVER_DESC "KEYPAD program" 019: 020: #define KEYPAD_NAME "fpga-keypad" 021: #define KEYPAD_PHY_ADDR 0x05000000 022: #define KEYPAD_ADDR_RANGE 0x1000 023: #define TIMER_INTERVAL 35 024: 025: static struct timer_list mytimer; 026: static unsigned short value; 027: static unsigned long keypad_ioremap; 028: static unsigned char *keypad_row_addr,*keypad_col_addr; 029: static unsigned short *keypad_check_addr; 030: 5
Keypad Device Driver 031: #ifdef CONFIG_LINUX 032: char keypad_fpga_keycode[16] = { 033: 1,2,3,4, 034: 5,6,7,8, 035: 9,10,11,12, 036: 13,14,15,16 037: }; 038: #else 039: char keypad_fpga_keycode[16] = { 040: 2,3,4,61, 041: 5,6,7,62, 042: 8,9,10,212, 043: 227,11,228,14 044: }; 045: #endif 046: static struct input_dev *idev; 047: void mypollingfunction(unsigned long data); 048: 6
Keypad Device Driver 049: int keypad_open(struct inode *minode, struct file *mfile) 050: { 051: keypad_col_addr = (unsigned char *)(keypad_ioremap+0x70); 052: keypad_row_addr = (unsigned char *)(keypad_ioremap+0x72); 053: 054: init_timer(&mytimer); 055: 056: mytimer.expires = get_jiffies_64() + TIMER_INTERVAL; 057: mytimer.function = &mypollingfunction; 058: 059: add_timer(&mytimer); 060: 061: return 0; 062: } 063: 064: int keypad_release(struct inode *minode, struct file *mfile) 065: { 066: del_timer(&mytimer); 067: 068: return 0; 069: } 7
Keypad Device Driver 071: void mypollingfunction(unsigned long data) 072: { 073: int j=1,k,i; 074: int funtion_key = 0; 075: 076: unsigned char tmp[4] = {0x01, 0x02, 0x04, 0x08}; 077: 078: value =0; 079: for(i=0;i<4;i++) { 080: *keypad_row_addr = tmp[i]; 081: value = *keypad_col_addr & 0x0f; 082: if(value > 0) { 083: for(k=0;k<4;k++) { 084: if(value == tmp[k]) { 085: value = j+(i*4); 086: funtion_key = keypad_fpga_keycode[value-1]; 087: if(value!= 0x00) goto stop_poll; 088: } 089: j++; 090: } 091: } 092: } 8
Keypad Device Driver 094: stop_poll: 095: if(value > 0) { 096: if(*keypad_check_addr == 0x2a) { 097: input_report_key(idev, funtion_key,1); 098: input_report_key(idev, funtion_key,0); 099: input_sync(idev); 100: // kill_pid(id,sigusr1,1); 101: } 102: } 103: else 104: *keypad_row_addr = 0x00; 105: 106: mytimer.expires = get_jiffies_64() + TIMER_INTERVAL; 107: add_timer(&mytimer); 108: } 109: 9
Keypad Device Driver 127: int keypad_init(void) 128: { 129: int result; 130: int i = 0; 131: 132: keypad_ioremap=(unsigned long)ioremap(keypad_phy_addr,keypad_a DDR_RANGE); 133: 134: if(!check_mem_region(keypad_ioremap, KEYPAD_ADDR_RANGE)) { 135: request_mem_region(keypad_ioremap, KEYPAD_ADDR_RANGE, KEYPAD_NAME); 136: } 137: else { 138: printk("fpga KEYPAD Memory Alloc Faild!\n"); 139: return -1; 140: } 141: 142: keypad_check_addr = (unsigned short *)(keypad_ioremap+0x92); 10
Keypad Device Driver 144: if(*keypad_check_addr!= 0x2a) { 145: printk("hbe-sm5-s4210 M3 Board is not exist...,0x%x\r\n",*ke ypad_check_addr); 146: iounmap((unsigned long*)keypad_ioremap); 147: release_region(keypad_ioremap, KEYPAD_ADDR_RANGE); 148: return -1; 149: } 151: idev = input_allocate_device(); 152: 153: set_bit(ev_key,idev->evbit); 154: set_bit(ev_key,idev->keybit); 155: 156: for(i = 0; i < 30; i++) 157: set_bit(i & KEY_MAX,idev->keybit); 158: 159: idev->name = "fpga-keypad"; 160: idev->id.vendor = 0x1002; 161: idev->id.product = 0x1002; 162: idev->id.bustype = BUS_HOST; 163: idev->phys = "keypad/input1"; 164: idev->open = keypad_open; 165: idev->close = keypad_release; 11
Keypad Device Driver 167: result = input_register_device(idev); 168: 169: if(result < 0) { 170: printk(kern_warning"fpga KEYPAD Register Faild... \n"); 171: return result; 172: } 173: 174: return 0; 175: } 176: 177: void keypad_exit(void) 178: { 179: iounmap((unsigned long*)keypad_ioremap); 180: release_region(keypad_ioremap, KEYPAD_ADDR_RANGE); 181: 182: input_unregister_device(idev); 183: } 12
Keypad Device Driver 184: 185: module_init(keypad_init); 186: module_exit(keypad_exit); 187: 188: MODULE_AUTHOR(DRIVER_AUTHOR); 189: MODULE_DESCRIPTION(DRIVER_DESC); 190: MODULE_LICENSE("Dual BSD/GPL"); 13
Keypad Application Program 테스트프로그램작성 소스코드는 [CD3]/source/application_peri/device_driver/keypad_driver 에있다. ( 밑에작성하는 Makefile 도동일한위치에있다.) root@ubuntu:~/working/device_driver/keypad_driver# vi key_test.c 001: #include <stdio.h> 002: #include <stdlib.h> 003: #include <string.h> 004: #include <sys/ioctl.h> 005: #include <sys/types.h> 006: #include <sys/stat.h> 007: #include <fcntl.h> 008: #include <unistd.h> 009: #include <linux/input.h> 010: 011: #define EVENT_BUF_NUM 64 012: 14
Keypad Application Program 013: int main(void) 014: { 015: int i, quit=1; 016: int fd = -1; 017: size_t read_bytes; 018: struct input_event event_buf[event_buf_num]; 019: 020: if ((fd = open("/dev/input/event2", O_RDONLY)) < 0) 021: { 022: printf("application : keypad driver open fail!\n"); 023: exit(1); 024: } 025: 026: printf("press the key button!\n"); 027: printf("press the key 16 to exit!\n"); 028: 15
Keypad Application Program 029: while(quit) 030: { 031: read_bytes = read(fd, event_buf, (sizeof(struct input_ event)*event_buf_num) ); 032: if( read_bytes < sizeof(struct input_event) ) 033: { 034: printf("application : read error!!"); 035: exit(1); 036: } 037: 038: for( i=0; i<(read_bytes/sizeof(struct input_event)); i ++ ) 039: { 040: if ( (event_buf[i].type == EV_KEY) && (event_b uf[i].value == 0)) 041: { 042: printf("\n Button key : %d\n", event_b uf[i].code); 16
Keypad Application Program 043: 044: if(event_buf[i].code == 16) { 045: printf("\napplication : Exit Pr ogram!! (key = %d)\n", event_buf[i].code); 046: quit = 0; 047: } 048: } 049: } 050: } 051: close(fd); 052: return 0; 053: } 17
Keypad Application Program root@ubuntu:/working/device_driver/keypad_driver# vi Makefile CC = arm-linux-gcc CFLAGS = -DNO_DEBUG EXEC=key_test OBJS=$(EXEC).o ####### Implicit rules.suffixes:.cpp.cxx.cc.c.c.cpp.o: $(CXX) -c $(CXXFLAGS) -o $@ $<.cxx.o: $(CXX) -c $(CXXFLAGS) -o $@ $<.cc.o: $(CXX) -c $(CXXFLAGS) -o $@ $<.C.o: $(CXX) -c $(CXXFLAGS) -o $@ $<.c.o: $(CC) -c $(CFLAGS) -o $@ $< all: $(EXEC) $(EXEC): $(OBJS) $(CC) -o $@ $^ clean: rm -f $(OBJS) $(EXEC) 18
Keypad Application Program 컴파일 root@ubuntu:~/working/device_driver/keypad_driver# ls Makefile key_test.c root@ubuntu:~/working/device_driver/keypad_driver# make clean;make ------------------다음과같은메시지가출력된다 ----------------- rm -f key_test.o key_test arm-linux-gcc -c -DNO_DEBUG -o key_test.o key_test.c arm-linux-gcc -o key_test key_test.o root@ubuntu:~/working/device_driver/keypad_driver# ls Makefile key_test key_test.c key_test.o 타겟보드에다운받기및실행 다음과같이타겟보드에서 tftp 로다운받기위해 keypad_test 파일을 /var/lib/tftpboot 에복사 root@ubuntu:~/working/device_driver/keypad_driver# cp key_tes t /var/lib/tftpboot/ 19
Keypad Application Program /var/lib/tftpboot로복사가완료되면타겟보드에서아래와같이명령어를입력 key_test를다운받고 chmod 명령어를사용하여실행권한부여 [root@sm5s4210 ~]# cd ~/device_driver [root@sm5s4210 device_driver]# tftp -r key_test -g 192.168.0.100 [root@sm5s4210 device_driver]# ll ------------------다음과같은메시지가출력된다 ----------------- -rw-r--r-- 1 root root 6835 Sep 20 19:49 key_test [root@sm5s4210 device_driver]# chmod +x key_test [root@sm5s4210 device_driver]# ll ------------------다음과같은메시지가출력된다 ----------------- -rwxr-xr-x 1 root root 6835 Sep 20 19:49 key_test 20
Keypad Application Program (mmap) mmap Version ~/working/mmap/keypad 디렉터리에서 keypad.c 작성 소스코드는 [CD3]/source/application_peri/mmap/keypad 에있다. ( 밑에작성하는 Makefile 도동일한위치에있다.) root@ubuntu:# mkdir -p ~/working/mmap/keypad root@ubuntu:# cd ~/working/mmap/keypad/ root@ubuntu:~/working/mmap/keypad# vi keypad.c 001: #include <stdio.h> 002: #include <string.h> 003: #include <stdlib.h> 004: #include <unistd.h> 005: #include <sys/mman.h> 006: #include <fcntl.h> 007: 008: #define FPGA_BASEADDRESS 0x05000000 009: #define PIEZO_OFFSET 0x50 010: #define KEY_COL_OFFSET 0x70 011: #define KEY_ROW_OFFSET 0x72 012: 21
Keypad Application Program (mmap) 013: int main(void) 014: { 015: short value; 016: unsigned short *addr_fpga; 017: unsigned short *keypad_row_addr, *keypad_col_addr, *piezo_addr; 018: int fd; 019: int i,quit=1; 020: if ((fd=open("/dev/mem",o_rdwr O_SYNC)) < 0) { 021: perror("mem open fail\n"); 022: exit(1); 023: } 024: 025: addr_fpga= (unsigned short *)mmap(null, 4096, 026: PROT_WRITE PROT_READ, MAP_SHARED, fd, FPGA_BASEADDRESS); 027: keypad_col_addr = addr_fpga + 028: KEY_COL_OFFSET/sizeof(unsigned short); 029: keypad_row_addr = addr_fpga + 030: KEY_ROW_OFFSET/sizeof(unsigned short); 031: piezo_addr = addr_fpga + PIEZO_OFFSET/sizeof(unsigned short); 032: 22
Keypad Application Program (mmap) 033: if(*keypad_row_addr ==(unsigned short)-1 034: *keypad_col_addr ==(unsigned short)-1 ) 035: { 036: close(fd); 037: printf("mmap error\n"); 038: exit(1); 039: } 040: 041: printf("- Keypad\n"); 042: printf("press the key button!\n"); 043: printf("press the key 0x16 to exit!\n"); 044: 045: while(quit) { 046: *keypad_row_addr = 0x01; 047: usleep(1000); 048: value =(*keypad_col_addr & 0x0f); 049: *keypad_row_addr = 0x00; 050: switch(value) { 051: case 0x01 : value = 0x01; break; 052: case 0x02 : value = 0x02; break; 053: case 0x04 : value = 0x03; break; 054: case 0x08 : value = 0x04; break; 055: } 23
Keypad Application Program (mmap) 056: if(value!= 0x00) goto stop_poll; 057: 058: *keypad_row_addr = 0x02; 059: for(i=0;i<2000;i++); 060: value = value (*keypad_col_addr & 0x0f); 061: *keypad_row_addr = 0x00; 062: switch(value) { 063: case 0x01 : value = 0x05; break; 064: case 0x02 : value = 0x06; break; 065: case 0x04 : value = 0x07; break; 066: case 0x08 : value = 0x08; break; 067: } 068: if(value!= 0x00) goto stop_poll; 069: 070: *keypad_row_addr = 0x04; 071: for(i=0;i<2000;i++); 072: value = value (*keypad_col_addr & 0x0f); 073: *keypad_row_addr = 0x00; 074: switch(value) { 075: case 0x01 : value = 0x09; break; 076: case 0x02 : value = 0x0a; break; 077: case 0x04 : value = 0x0b; break; 078: case 0x08 : value = 0x0c; break; 079: } 080: if(value!= 0x00) goto stop_poll; 24
Keypad Application Program (mmap) 081: 082: *keypad_row_addr = 0x08; 083: for(i=0;i<2000;i++); 084: value = value (*keypad_col_addr & 0x0f); 085: *keypad_row_addr = 0x00; 086: switch(value) { 087: case 0x01 : value = 0x0d; break; 088: case 0x02 : value = 0x0e; break; 089: case 0x04 : value = 0x0f; break; 090: case 0x08 : value = 0x10; break; 091: } 092: 093: stop_poll: 094: if(value>0) { 095: printf("\n pressed key = %02d\n",value); 096: *piezo_addr=0x1; 097: usleep(50000); 098: *piezo_addr=0x0; 099: } 25
Keypad Application Program (mmap) 100: else *keypad_row_addr = 0x00; 101: for(i=0;i<4000000;i++); 102: 103: if(value == 16) { 104: printf("\nexit Program!! (key = %02d)\n\n", value); 105: *piezo_addr=0x1; 106: usleep(150000); 107: *piezo_addr=0x0; 108: quit = 0; 109: } 110: } 111: 112: munmap(addr_fpga,4096); 113: close(fd); 114: return 0; 115: } 26
Keypad Application Program (mmap) 소스를컴파일하기위한 Makefile 을작성 root@ubuntu:~/working/mmap/5.keypad# vi Makefile CC = arm-linux-gcc CFLAGS = -DNO_DEBUG EXEC=keypad OBJS=$(EXEC).o ####### Implicit rules.suffixes:.cpp.cxx.cc.c.c.cpp.o: $(CXX) -c $(CXXFLAGS) -o $@ $<.cxx.o: $(CXX) -c $(CXXFLAGS) -o $@ $<.cc.o: $(CXX) -c $(CXXFLAGS) -o $@ $<.C.o: $(CXX) -c $(CXXFLAGS) -o $@ $<.c.o: $(CC) -c $(CFLAGS) -o $@ $< all: $(EXEC) $(EXEC): $(OBJS) $(CC) -o $@ $^ clean: rm -f $(OBJS) $(EXEC) 27
Keypad Application Program (mmap) 소스를컴파일하고, 실행파일 (keypad) 를 /var/lib/tftpboot 에복사 root@ubuntu:~/working/mmap/keypad# make arm-linux-gcc -c -DNO_DEBUG -o keypad.o keypad.c arm-linux-gcc -o keypad keypad.o root@ubuntu:~/working/mmap/keypad# ls Makefile keypad keypad.c keypad.o root@ubuntu:~/working/mmap/keypad# cp keypad /var/lib/tftpboot/ 타겟보드에서실행파일 (keypad) 를다운, 권한변경후실행 [root@sm5s4210 ~]$tftp -r keypad -g 192.168.0.100 [root@sm5s4210 ~]$ls -l -rw-r--r-- 1 root root 7991 Feb 1 20:06 keypad [root@sm5s4210 ~]$chmod 777 keypad [root@sm5s4210 ~]$./keypad - Keypad press the key button! press the key 0x16 to exit! pressed key = 01 pressed key = 16 Exit Program!! (key = 16) 28