key_drv_poll.c
#include <linux/init.h> /* For __init/__exit/... */
#include <linux/kernel.h> /* For printk/panic/... */
#include <linux/module.h> /* For module specific items */
#include <linux/fs.h> /* For file operations */
#include <linux/types.h> /* For standard types (like size_t) */
#include <linux/errno.h> /* For the -ENODEV/... values */
#include <linux/ioport.h> /* For io-port access */
#include <linux/uaccess.h> /* For copy_to_user/put_user/... */
#include <linux/io.h> /* For inb/outb/.../ioremap/... */
#include <linux/device.h> /* For class_create */
#define S3C6410_GPNCON_PA (0x7F008830)
#define S3C6410_GPNDAT_PA (0x7F008834)
#define S3C6410_GPNPUD_PA (0x7F008838)
#define S3C6410_GPLCON0_PA (0x7F008810)
#define S3C6410_GPLCON1_PA (0x7F008814)
#define S3C6410_GPLDAT_PA (0x7F008818)
#define S3C6410_GPLPUD_PA (0x7F00881C)
static int major = 0;
static struct class* key_drv_poll_class;
static volatile unsigned long* gpncon = NULL;
static volatile unsigned long* gpndat = NULL;
static volatile unsigned long* gplcon0 = NULL;
static volatile unsigned long* gplcon1 = NULL;
static volatile unsigned long* gpldat = NULL;
static int key_drv_poll_open(struct inode *inode, struct file *filp)
{
/* set key(1~8) gpio pin = input */
*gpncon &= ~((0x3<<0)|(0x3<<2)|(0x3<<4)|(0x3<<6)|(0x3<<8)|(0x3<<10)); /* set key1~key6 pin = input*/
*gpncon |= ((0x0<<0)|(0x0<<2)|(0x0<<4)|(0x0<<6)|(0x0<<8)|(0x0<<10)); /* GPN0~GPN5 */
*gplcon1 &= ~((0xF<<12)|(0xF<<16)); /* set key7~key8 pin = input*/
*gplcon1 |= ((0x0<<12)|(0x0<<16)); /* GPL11~GPL12 */
return 0;
}
static ssize_t key_drv_poll_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
/* read key gpio pin status */
unsigned char key_val_arr[8];
key_val_arr[0] = (*gpndat&(0x1<<0)?1:0);
key_val_arr[1] = (*gpndat&(0x1<<1)?1:0);
key_val_arr[2] = (*gpndat&(0x1<<2)?1:0);
key_val_arr[3] = (*gpndat&(0x1<<3)?1:0);
key_val_arr[4] = (*gpndat&(0x1<<4)?1:0);
key_val_arr[5] = (*gpndat&(0x1<<5)?1:0);
key_val_arr[6] = (*gpldat&(0x1<<11)?1:0);
key_val_arr[7] = (*gpldat&(0x1<<12)?1:0);
copy_to_user(buf, key_val_arr, sizeof(key_val_arr));
return sizeof(key_val_arr);
}
static int key_drv_poll_close(struct inode *inode, struct file *file)
{
return 0;
}
static struct file_operations key_drv_poll = {
.owner = THIS_MODULE,
.open = key_drv_poll_open,
.read = key_drv_poll_read,
.release = key_drv_poll_close,
};
static int key_drv_poll_init(void)
{
major = register_chrdev(0, "key_drv_poll", &key_drv_poll);
if(major < 0)
{
printk(KERN_ALERT "Register key_driver_poll failed!\n");
return -1;
}
printk(KERN_ALERT "Register key_driver_poll succeed!\n");
/* 动态创建设备号,根据创建的设备号创建设备节点(/dev/key_drv_poll) */
key_drv_poll_class= class_create(THIS_MODULE, "key_drv_poll"); /* sysfs */
device_create(key_drv_poll_class, NULL, MKDEV(major, 0), NULL, "key_drv_poll"); /* /dev/key_drv_poll */
/* map key gpio config_register and data_register virtual address */
gpncon = ioremap(S3C6410_GPNCON_PA, 4); /* key1~key6 */
gpndat = ioremap(S3C6410_GPNDAT_PA, 4);
gplcon0 = ioremap(S3C6410_GPLCON0_PA, 4); /* key7~key8 */
gplcon1 = ioremap(S3C6410_GPLCON1_PA, 4); /* key7~key8 */
gpldat = ioremap(S3C6410_GPLDAT_PA, 4);
return 0;
}
static void key_drv_poll_exit(void)
{
device_destroy(key_drv_poll_class, MKDEV(major, 0));
class_destroy(key_drv_poll_class);
unregister_chrdev(major, "key_drv_poll");
/* unmap key gpio virtual address */
iounmap(gpncon);
iounmap(gpndat);
iounmap(gplcon0);
iounmap(gplcon1);
iounmap(gpldat);
printk(KERN_ALERT "Unregister key_driver_poll succeed!\n");
}
module_init(key_drv_poll_init);
module_exit(key_drv_poll_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("key driver use poll");
MODULE_AUTHOR("dl CS0921 WTU");
key_app_poll.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define DEVICE_NAME "/dev/key_drv_poll"
int main(int argc, char* argv[])
{
int fd;
fd = open(DEVICE_NAME, O_RDWR);
if(fd < 0)
{
printf("Open %s failed!\n", DEVICE_NAME);
exit(-1);
}
unsigned char key_val_arr[8];
for( ; ; )
{
read(fd, key_val_arr, sizeof(key_val_arr));
/* 如果有任意一个按键按下,就打印 */
if(!key_val_arr[0] || !key_val_arr[1]|| !key_val_arr[2] || !key_val_arr[3] || \
!key_val_arr[4] || !key_val_arr[5]|| !key_val_arr[6] || !key_val_arr[7] )
{
printf("key(1~8) value: %d %d %d %d %d %d %d %d\n", \
key_val_arr[0], key_val_arr[1], key_val_arr[2], key_val_arr[3],\
key_val_arr[4], key_val_arr[5], key_val_arr[6], key_val_arr[7]);
}
}
close(fd);
return 0;
}
Makefile
KERNELDIR = /sdb/kernel/linux-2.6.38-tiny6410/linux-2.6.38/
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY: modules clean
obj-m := led_drv.o
结果
