歡迎您光臨本站 註冊首頁

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include


#define DEVICE_NAME "buttondev"
#define BUTTONDEV_NR_DEVS 1
#define BUTTON_MAJOR 0

const char *button_dev;
struct cdev cdev;
static button_major = BUTTON_MAJOR;
static volatile int ev_press = 0; /* 中斷事件標誌, 中斷服務程序將它置1,buttons_read將它清0 */
static struct class *button_class;

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);//初始化等待隊列



/* 定義含中斷,管腳,管腳設置等信息的結構體 */
struct button_irq_desc
{
int irq;
int pin;
int pin_setting;
int number;
char *name;
};

static int key_values=0;


/* 用來指定按鍵所用的外部中斷引腳及中斷觸發方式, 名字 */
static struct button_irq_desc button_irqs [] =
{
{IRQ_EINT1, S3C2410_GPF1, S3C2410_GPF1_EINT1, 0, "KEY1"}, /* K1 */
{IRQ_EINT4, S3C2410_GPF4, S3C2410_GPF4_EINT4, 1, "KEY2"}, /* K2 */
{IRQ_EINT2, S3C2410_GPF2, S3C2410_GPF2_EINT2, 2, "KEY3"}, /* K3 */
{IRQ_EINT0, S3C2410_GPF0, S3C2410_GPF0_EINT0, 3, "KEY4"}, /* K4 */
};



/* 中斷處理函數*/
static irqreturn_t button_interrupt(int irq, void *dev_id)
{

struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;
int down;
// udelay(0);

/*上升沿觸發,GPIO DAT 應該為非0 的數*/
down = !s3c2410_gpio_getpin(button_irqs->pin);
if (!down) {
//printk("rising\n");
key_values = button_irqs->number;
ev_press = 1;
wake_up_interruptible(&button_waitq);
}
else {
//printk("falling\n");
ev_press = 0;
return 0;
}
return IRQ_RETVAL(IRQ_HANDLED);
}


/*文件打開函數*/
static int button_open(struct inode *inode, struct file *filp)
{
int i;
int err=0;
for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++)//計算一個結構體變數大小
{
/*註冊中斷處理函數*/
//s3c2410_gpio_cfgpin(button_irqs.pin,button_irqs.pin_setting);
err = request_irq(button_irqs.irq, button_interrupt,IRQ_TYPE_EDGE_RISING, button_irqs.name, (void *)&button_irqs);
if (err)
// printf("request irq error");
break;
}

if (err) {
i--;
for (; i >= 0; i--) {
if (button_irqs.irq < 0)
continue;

disable_irq(button_irqs.irq);
free_irq(button_irqs.irq, (void *)&button_irqs);
}
return -EBUSY;
}
ev_press = 0;
return 0;

}

/*讀文件在驅動中的實現*/
static int button_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
unsigned long err;

if (!ev_press)
{
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
else
/* 如果ev_press等於0,休眠 */
wait_event_interruptible(button_waitq, ev_press);
}

ev_press = 0;

/* 把按鍵值的信息從內核空間複製到用戶空間*/
err = copy_to_user(buff, (const void *)key_values, min(sizeof(key_values), count));
memset((void *)key_values, 0, sizeof(key_values));//清零鍵值,以便下一次中斷

return err ? -EFAULT : min(sizeof(key_values), count);
}


/* 被上層應用程序調用的select函數在驅動程序里的實現*/
static unsigned int button_poll( struct file *file, struct poll_table_struct *wait)
{
unsigned int mask = 0;
poll_wait(file, &button_waitq, wait);
if (ev_press)
mask |= POLLIN | POLLRDNORM;
return mask;
}


/* 被上層應用程序調用的ioctl函數在驅動程序里的實現*/
/*static int button_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
if (arg > 4)
{
return -EINVAL;
}
switch(cmd) {
case IOCTL_LED_ON: //如果是點亮
s3c2410_gpio_setpin(led_table[arg], 0);//點亮相應的管腳
return 0;
case IOCTL_LED_OFF://如果是熄滅
s3c2410_gpio_setpin(led_table[arg], 1);//熄滅相應的管腳
return 0;
default:
return -EINVAL;
}
}*/


int button_release(struct inode *inode, struct file *filp)
{
int i;
for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {
if (button_irqs.irq < 0) {
continue;
}
free_irq(button_irqs.irq, (void *)&button_irqs);
}
return 0;
}

/*文件操作結構體*/
static const struct file_operations button_fops =
{
.owner = THIS_MODULE,
.read = button_read,
.open = button_open,
.poll = button_poll,
// .ioctl = button_ioctl,
.release = button_release,
};

static int button_init(void)
{
int result;

dev_t devno = MKDEV(button_major, 0);

/* 靜態申請設備號*/
if (button_major)
result = register_chrdev_region(devno, 1, DEVICE_NAME);
else /* 動態分配設備號 */
{
result = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME);
button_major = MAJOR(devno);
}

if (result < 0)
return result;

/*初始化cdev結構*/
cdev_init(&cdev, &button_fops);
cdev.owner = THIS_MODULE;
cdev.ops = &button_fops;

/* 註冊字元設備 */
cdev_add(&cdev, MKDEV(button_major, 0), BUTTONDEV_NR_DEVS);

button_class = class_create(THIS_MODULE, DEVICE_NAME);
if(IS_ERR(button_class))
{
printk("Err: failed in button class. \n");
return -1;
}
//創建一個設備節點,節點名為DEVICE_NAME
device_create(button_class, NULL, MKDEV(button_major, 0), NULL, DEVICE_NAME);
return 0;

}

static void button_exit(void)
{
cdev_del(&cdev); /*註銷設備*/
unregister_chrdev_region(MKDEV(button_major, 0), 1); /*釋放設備號*/
device_destroy(button_class,MKDEV(button_major,0));
}


MODULE_AUTHOR("OuYang");
MODULE_LICENSE("GPL");

module_init(button_init);
module_exit(button_exit);



測試程序如下

/*調用系統的頭文件*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

int main(void)
{
int i;
int buttons_fd;
int key_values;


/*打開按鍵設備文件*/
buttons_fd = open("/dev/buttondev", 0);
if (buttons_fd < 0) {
perror("open device buttondev");
exit(1);
}
printf("buttondev open success/n");
for (;;) //一直循環來監聽是否有按鍵按下
{
fd_set rds;
int ret;

FD_ZERO(&rds);
FD_SET(buttons_fd, &rds);

/*使用系統調用select檢查是否能夠從/dev/buttondev設備讀取數據*/
ret = select(buttons_fd + 1, &rds, NULL, NULL, NULL);

/*讀取出錯則退出程序*/
if (ret < 0) {
perror("select");
exit(1);
}

if (ret == 0) {
printf("Timeout.\n");
}
/*能夠讀取到數據*/
else if (FD_ISSET(buttons_fd, &rds)) {
/*開始讀取鍵盤驅動發出的數據,注意key_value和鍵盤驅動中定義為一致的類型*/
printf("keydown/n");
int ret = read(buttons_fd, &key_values, sizeof key_values);
if (ret != sizeof key_values) {
if (errno != EAGAIN)
perror("read buttons\n");
continue;
} else {
printf("buttons_value: %d\n", key_values+1);
}

}
}
/*關閉設備文件句柄*/
close(buttons_fd);
return 0;
}

[火星人 ] 我編的字元按鍵驅動不知道哪裡出錯了,測試沒有反應,大家幫幫忙啊已經有518次圍觀

http://coctec.com/docs/linux/show-post-183164.html