很简单有兴趣的可以扩展2位,4位,8位,16位读取和图片压缩放大 屏幕为16位TFT-LCE
键盘驱动:key_dd.c
#include <linux/module.h>//모듈에 관한 정의 ex)MOD_INC_USE_COUNT
#include <linux/init.h>//init_module() 과 cleanup_module()
#include <linux/delay.h>//udelay()
#include <linux/kernel.h>
#include <asm/uaccess.h>//copy_to_user()
#include <asm/io.h>//GPIO controller에 관한 정의
#include <asm/irq.h>// interrupt에 관한 정의
/* Prototypes */
int key_init (void );
int key_open(struct inode *, struct file *);
int key_release(struct inode *, struct file *);
ssize_t key_read (struct file *inode, char *gdata, size_t length, loff_t *off_what);
ssize_t key_write (struct file *inode, char *gdata, size_t length, loff_t *off_what);
void led_blink(unsigned long i);
void key_handler(int irq, void *dev_id, struct pt_regs *regs);
void clean_module(void);
#define DEVICE_NAME "KEY"
#define KEY_MAJOR 233 //0x00000001로 정의됨
#define KEY_GPIO_0 GPIO_0 // IRQ_GPIO(0)는 0로 정의됨
#define KEY_IRQ IRQ_GPIO(0) //key pad data input address
#define KEY_BASE 0x14000000
#define KEY_BYTES 1
#define GPIO_LED_82 0x40000
#define GPIO_LED_83 0x80000
static struct file_operations key_fops =
{
open: key_open,
read: key_read,
write: key_write,
release:key_release,
};
static DECLARE_WAIT_QUEUE_HEAD(wq);
static int Major;
static unsigned long *keyport;
static char key_value;
int key_init(void) {
int return_val;
printk("keypad_init n");
Major = register_chrdev (KEY_MAJOR, DEVICE_NAME, &key_fops);
if (Major < 0) {
printk ("KEY init_module: failed with %d n", Major);
return Major;
}
printk ("KEY driver registred: major = %d n", KEY_MAJOR);
//GPIO 0을 입력으로 설정
GPDR0 &= ~(GPIO_0);
//alternate function을 normal GPIO function으로 설정
GAFR0_L &= ~(0x3);
//GPIO 0을 falling edge일 때 detect 하도록 설정
set_GPIO_IRQ_edge( 0, GPIO_FALLING_EDGE);
//IRQ 요청
return_val = request_irq(KEY_IRQ, key_handler, SA_INTERRUPT, "KEY PAD INT", NULL );
if( return_val < 0 ) {
printk(KERN_ERR "pxa255_pro_key_init() : Can't reqeust irq %#010x n", IRQ_GPIO(0) );
return -1;
}
return 0;
}
/* interrupt service routine */
void key_handler(int irq, void *dev_id, struct pt_regs *regs)
{
// 키의 물리주소 값을 커널의 임의의 메모리 영역의 주소에 매핑
keyport = (unsigned long)ioremap(KEY_BASE, 0x10);
//매핑된 메모리 주소를 이용하여 실제 물리 주소에 있는 값을 가져온다.
key_value = *(keyport+0) & 0xf;
printk("KEY INPUT : [0x%x] n",key_value);
switch(key_value) {
case 0x3 : printk("u pushed 3rd button. OST will be played.. n"); break;
case 0xb : printk("u pushed 12th button. Ad will be played.. n"); break;
default :led_blink(key_value);break;
}
//매핑되었던 물리 주소와 메모리 주소를 해제
iounmap(keyport);
//block시켜놨던 read() process를 release한다.
wake_up_interruptible(&wq);
}
ssize_t key_read (struct file *inode, char *gdata, size_t length, loff_t *off_what)
{
// interrupt가 발생할 때까지 sleep 시킴
interruptible_sleep_on(&wq);
printk("value being sent to application : %x n",key_value);
//application에게 interrupt 번호를 pass한다.
copy_to_user(gdata, &key_value,sizeof(1));
return 0;
}
int key_open (struct inode *inode, struct file *file)
{
printk ("open..ok n");
printk ("push any key! n");
//LED D6, D7의 방향을 출력으로 설정한다.
GPDR2 |= 0xC0000;
MOD_INC_USE_COUNT;
return 0;
}
int key_release (struct inode *inode, struct file *file)
{
printk ("device_release(%p,%p) n", inode, file);
MOD_DEC_USE_COUNT;
return 0;
}
ssize_t key_write (struct file *inode, char *gdata, size_t length, loff_t *off_what)
{
return 0;
}
void led_blink(unsigned long i)
{
int j=(i & 0xf)+1;
printk("LED will toggle %x times n", j);
while(j) {
GPCR2 |= GPIO_LED_83;//83번을 CLEAR, LED D7 GREEN이 켜짐
GPSR2 |= GPIO_LED_82;//82번을 SET, LED D6 RED가 꺼짐
udelay(90000000000);
GPCR2 |= GPIO_LED_82;//82번을 CLEAR, LED D6 RED가 켜짐
GPSR2 |= GPIO_LED_83;//83번을 SET, LED D7 GREEN이 꺼짐
udelay(90000000000);
j--;
}
GPSR2 |= GPIO_LED_82;//82번을 SET, LED D6 RED가 꺼짐
return;
}
module_init(key_init);
module_exit(clean_module);
void clean_module (void)
{
int ret;
ret = unregister_chrdev (KEY_MAJOR, DEVICE_NAME);
if (ret < 0) {
printk ("unregister_chrdev: error %d n", ret);
}
else {
printk ("module clean up ok!! n");
}
}
/****************************************************************************/
键盘测试程序:app-key-test.c
#include <stdio.h>
#include <fcntl.h> //open()의 flag 정의되어 있음
#include <errno.h> //errno에 정의 됨
int fd;
int main(int argc, char **argv)
{
unsigned long status = 0;
char passed_value;
if( (fd = open("/dev/KEY", O_RDWR)) < 3) {
fprintf(stderr, "/dev/int_test device file open error!! .. %s n",strerror(errno));
close(fd);
return 0;
}
while(1) {
//커널로부터 넘어온 interrupt 번호를 받는다.
read(fd, &passed_value,sizeof(1));
printf("value passed from kernel :%x n", passed_value);
//3번 key를 눌렸을 경우
if(passed_value==3) {
system("mixer vol 100");
system("mixer pcm 100");
system("madplay /mnt/mtd/sample/sample.mp3");
}
//12번 key를 눌렸을 경우
else if(passed_value==0xb) {
system("mixer vol 100");
system("mixer pcm 100");
system("mplayer /mnt/mtd/sample/sample.mpg");
}
};
close(fd);
return 0;
}
/****************************************************************************/
Makefile文件:
CC=arm-linux-gcc
INCLUDEDIR = /home/es/Toolchain/linux-2.4.19-pro3_nlcd/include
CFLAGS = -D__KERNEL__ -DMODULE -Wall -O2
CFLAGS2 = -I.. -I$(INCLUDEDIR)
All: key_test_dd test
key_test_dd : key_dd.c
$(CC) $(CFLAGS) $(CFLAGS2) -c -o key_dd.o key_dd.c
test :app-key-test.c
$(CC) -o test app-key-test.c
clean :
rm -rf key_dd.o test
/****************************************************************************/
程序主文件:
#include <math.h>
#include <dirent.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h> //errno에 정의 됨
#include <termios.h>
#include <stdio.h>
#include <stdlib.h> /* for exit */
#include <unistd.h> /* for open/close.. */
#include <fcntl.h> /* for O_RDONLY */
#include <sys/ioctl.h> /* for ioctl */
#include <sys/types.h> /* for lseek() */
#include <sys/stat.h>
#include <sys/signal.h>
#include <linux/fb.h> /*for fb_var_screeninfo, FBIOGET_VSCREENINFO*/
#define FBDEVFILE "/dev/fb"
#define WIDTHBYTES(bits) (((bits)+31)/32*4)
typedef unsigned char ubyte;
unsigned short makepixel(struct fb_var_screeninfo *fbvar, ubyte r, ubyte g, ubyte b)
{
return (unsigned short)(((r>>3)<<11)|((g>>2)<<5)|(b>>3));
}
typedef struct
{
unsigned short bfType;//表明位图文件的类型,必须为BM
unsigned long bfSize;//表明位图文件的大小,以字节为单位
unsigned short bfReserved1;//属于保留字,必须为本0
//unsigned short bfReserved2;//也是保留字,必须为本0
unsigned long bfOffBits;//位图阵列的起始位置,以字节为单位
} BITMAPFILEHEADER;
typedef struct
{
unsigned long biSize; //指出本数据结构所需要的字节数
long biWidth;//以象素为单位,给出BMP图象的宽度
long biHeight;//以象素为单位,给出BMP图象的高度
unsigned short biPlanes;//输出设备的位平面数,必须置为1
unsigned short biBitCount;//给出每个象素的位数
unsigned long biCompress;//给出位图的压缩类型
unsigned long biSizeImage;//给出图象字节数的多少
long biXPelsPerMeter;//图像的水平分辨率
long biYPelsPerMeter;//图象的垂直分辨率
unsigned long biClrUsed;//調色板中图象实际使用的颜色素数
unsigned long biClrImportant;//给出重要颜色的索引值
} BITMAPINFOHEADER;
typedef struct
{
//public:
ubyte rgbBlue; //该颜色的蓝色分量
ubyte rgbGreen; //该颜色的绿色分量
ubyte rgbRed; //该颜色的红色分量
ubyte rgbReserved; //保留值
} RGBQUAD;
int bmpload(char* filename)
{
FILE* fp;
BITMAPFILEHEADER bmpfile;
BITMAPINFOHEADER bmpinfo;
RGBQUAD *dataOfBmp;
int i, j, k;
int index = 0;
long plant;
int num;
int bmpwidth;
int bmpheigh;
int lwidth;
ubyte *pColorData;
long nData;
int fbfd;
int ret;
struct fb_var_screeninfo fbvar;
unsigned short pixel;
int offset;
fbfd = open(FBDEVFILE, O_RDWR);
if(fbfd < 0)
{
perror("fbdev open");
exit(1);
}
// 커널로부터 lcd에 관한 정보를 fbvar에 저장한다.
ret = ioctl(fbfd, FBIOGET_VSCREENINFO, &fbvar);
if(ret < 0)
{
perror("fbdev ioctl");
exit(1);
}
if(fbvar.bits_per_pixel!=16)
{ //bpp가 16bit인지 check
fprintf(stderr, "bpp is not 16n");
exit(1);
}
fp = fopen(filename, "rb");
fread(&bmpfile,14L, 1, fp);
if(bmpfile.bfType != 0x4d42)
return -1;
fseek(fp, 14L, 0);
fread(&bmpinfo,sizeof(BITMAPINFOHEADER), 1, fp);
bmpwidth = bmpinfo.biWidth;//图片宽度
bmpheigh = bmpinfo.biHeight;//图片长度
lwidth = WIDTHBYTES(bmpwidth * bmpinfo.biBitCount);//每行像素大小
pColorData = (ubyte *)malloc(bmpheigh * lwidth);
memset(pColorData,0, bmpheigh * lwidth);
nData = bmpheigh * lwidth;
dataOfBmp = (RGBQUAD *)malloc(bmpwidth * bmpheigh * sizeof(RGBQUAD));//用于保存各像素对应的RGB数据
memset(dataOfBmp, 0, bmpwidth * bmpheigh * sizeof(RGBQUAD));
//把位图数据信息读到数组里
fread(pColorData,1,nData,fp);
index = 0;
for(i=0; i < bmpheigh; i++)
for(j= 0; j < bmpwidth ; j++)
{
k = i * lwidth + j*3;
dataOfBmp[index].rgbRed = pColorData[k+2];
dataOfBmp[index].rgbGreen = pColorData[k+1];
dataOfBmp[index].rgbBlue = pColorData[k];
index++;
}
k = 0;
for (i = 479; i > -1; i--)
for (j = 0; j < 640; j++)
{
offset = i*fbvar.xres*(16/8)+ j*(16/8);
if(lseek(fbfd, offset, SEEK_SET) < 0) //file point를 맨 앞에서 offset만큼 옮김
{
perror("fbdev lseek");
exit(1);
}
pixel = makepixel(&fbvar, dataOfBmp[k].rgbRed, dataOfBmp[k].rgbGreen, dataOfBmp[k].rgbBlue);
write(fbfd, &pixel, 2);
k += 1;
}
fclose(fp);
free(dataOfBmp);
free(pColorData);
return 0;
}
int getkey()
{
int fd, c, res, i;
char key;
fd = open("/dev/KEY", O_RDONLY);
if(fd < 0)
{
perror("/dev/KEY");
exit(-1);
}
else
{
while(key != 0x7)
{
printf("Key test startn");
read(fd, &key, sizeof(1));
switch(key)
{
case 0x0:
//printf("Number 3");
return 3;
break;
case 0x1:
//printf("Number 6");
return 6;
break;
case 0x2:
//printf("Number 9");
return 9;
break;
case 0x3:
//printf("Number *");
return 11;
break;
case 0x4:
//printf("Number 2");
return 2;
break;
case 0x5:
//printf("Number 5");
return 5;
break;
case 0x6:
//printf("Number 8");
return 8;
break;
case 0x7:
//printf("Number 0");
return 0;
break;
case 0x8:
//printf("Number 1");
return 1;
break;
case 0x9:
//printf("Number 4");
return 4;
break;
case 0xa:
//printf("Number 7");
return 7;
break;
case 0xb:
//printf("Number #");
return 10;
break;
}
}
}
close(fd);
return 0;
}
int load_dd()
{
int ret;
ret = system("insmod key_dd.o");
if (ret == 0)
ret = system("mknod /dev/KEY c 233 0");
if (ret != 0)
{
printf ("KeyPad fail!");
}
return 0;
}
int load_bmp(int key)
{
char fname[255];
struct dirent *ptr;
DIR *dir;
dir=opendir("/mnt/usbdisk/");
while((ptr=readdir(dir))!=NULL)
{
//跳过'.'和'..'两个目录
if(ptr->d_name[0] == '.')
continue;
else if(strstr(ptr->d_name,".bmp"))
{
printf("%s is ready...n",ptr->d_name);
sprintf(fname,"/mnt/usbdisk/%s",ptr->d_name);
bmpload(fname);
if (key == 1)
{
sleep(4);
}
else if (key == 2)
{
sleep(4);
}
else
{
key = getkey();
while (1)
{
if (key == 5)
break;
else if (key == 1)
break;
else if (key == 2)
break;
else if(key == 0)
{
closedir(dir);
return -1;
}
key = getkey();
}
}
}
}
closedir(dir);
switch (key)
{
case 1 :
return 1;
break;
case 2:
return 2;
break;
default :
return 0;
break;
}
}
int main()
{
int ret;
int key;
load_dd();
key = load_bmp(100);
while (1)
{
if(key == 1)
key = 100;
else if(key == -1)
break;
key = load_bmp(key);
}
exit(0);
}