⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 s3c2410-button.c

📁 开发一个基于中断机制的字符设备驱动程序
💻 C
字号:
/* * LiuRui */ /*Headers-------------------------------------------------*/#include <linux/kernel.h>#include <linux/init.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/config.h>#include <linux/fs.h>#include <linux/cdev.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <asm/arch/regs-gpio.h>#include <asm/arch/regs-irq.h>#include <asm/io.h>#include <asm/uaccess.h>#ifdef CONFIG_DEVFS_FS#include <linux/devfs_fs_kernel.h>#endif#define DEVICE_NAME "buttons"#define EXTINT_OFF (IRQ_EINT4 - 4)/*Vars----------------------------------------------------*/unsigned int buttons_major_number=0;struct cdev buttons_dev;unsigned int type = IRQT_FALLING;static int ready = 0;static int key_value = 0;struct key_info {	unsigned int irq_no;	unsigned int gpio_port;	int key_no;};static struct key_info key_info_tab[4] = {	{ IRQ_EINT19, S3C2410_GPG11, 1 },	{ IRQ_EINT11, S3C2410_GPG3,  2 },	{ IRQ_EINT2,  S3C2410_GPF2,  3 },	{ IRQ_EINT8,  S3C2410_GPG0,  4 },};static int extint_num[4] = {0};static inline void s3c_irq_ack(unsigned int irqno){	unsigned long bitval = 1UL << (irqno - IRQ_EINT0);	__raw_writel(bitval, S3C2410_SRCPND);	__raw_writel(bitval, S3C2410_INTPND);} static void s3c_irqext_ack(unsigned int irqno){	unsigned long req;	unsigned long bit;	unsigned long mask;	bit = 1UL << (irqno - EXTINT_OFF);	mask = __raw_readl(S3C2410_EINTMASK);	__raw_writel(bit, S3C2410_EINTPEND);  req = __raw_readl(S3C2410_EINTPEND); 	req &= ~mask;	/* not sure if we should be acking the parent irq... */	if (irqno <= IRQ_EINT7 ) {		if ((req & 0xf0) == 0)			s3c_irq_ack(IRQ_EINT4t7);	} else {		if ((req >> 8) == 0)			s3c_irq_ack(IRQ_EINT8t23);	}}static int s3c_irqext_type(unsigned int irq, unsigned int type){	unsigned long gpcon_reg;	unsigned long gpcon_offset;	unsigned long extint_reg;	unsigned long extint_offset;	unsigned long newvalue = 0;	unsigned long value;	if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3))	{		gpcon_reg = S3C2410_GPFCON;		extint_reg = S3C2410_EXTINT0;		gpcon_offset = (irq - IRQ_EINT0) * 2;		extint_offset = (irq - IRQ_EINT0) * 4;	}	else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7))	{		gpcon_reg = S3C2410_GPFCON;		extint_reg = S3C2410_EXTINT0;		gpcon_offset = (irq - (EXTINT_OFF)) * 2;		extint_offset = (irq - (EXTINT_OFF)) * 4;	}	else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15))	{		gpcon_reg = S3C2410_GPGCON;		extint_reg = S3C2410_EXTINT1;		gpcon_offset = (irq - IRQ_EINT8) * 2;		extint_offset = (irq - IRQ_EINT8) * 4;	}	else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23))	{		gpcon_reg = S3C2410_GPGCON;		extint_reg = S3C2410_EXTINT2;		gpcon_offset = (irq - IRQ_EINT8) * 2;		extint_offset = (irq - IRQ_EINT16) * 4;	} else	{		return -1;	}		/* Set the GPIO to external interrupt mode */	value = __raw_readl(gpcon_reg);	value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);	__raw_writel(value, gpcon_reg);	/* Set the external interrupt to pointed trigger type */	switch (type)	{		case IRQT_NOEDGE:			printk(KERN_WARNING "No edge setting!\n");			break;		case IRQT_RISING:			newvalue = S3C2410_EXTINT_RISEEDGE;			break;		case IRQT_FALLING:			newvalue = S3C2410_EXTINT_FALLEDGE;			break;		case IRQT_BOTHEDGE:			newvalue = S3C2410_EXTINT_BOTHEDGE;			break;		case IRQT_LOW:			newvalue = S3C2410_EXTINT_LOWLEV;			break;		case IRQT_HIGH:			newvalue = S3C2410_EXTINT_HILEV;			break;		default:			printk(KERN_ERR "No such irq type %d", type);			return -1;	}	value = __raw_readl(extint_reg);	value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset);	__raw_writel(value, extint_reg);	return 0;}static irqreturn_t buttons_irq(int irq, void *dev_id, struct pt_regs *req){	struct key_info *k;	int i;	int found = 0;	for (i = 0; i < sizeof key_info_tab / sizeof key_info_tab[0]; i++) {		k = key_info_tab + i;		if (k->irq_no == irq) {			found = 1;			extint_num[i]++;			break;		}	}		if (!found) {		printk("bad irq %d in button\n", irq);		return IRQ_NONE;	}	return IRQ_HANDLED;}static int request_irqs(void){	struct key_info *k;	int i;	int request;	unsigned int irq;  for (i = 0; i < sizeof key_info_tab / sizeof key_info_tab[0]; i++) {		k = key_info_tab + i;    irq = k->irq_no;    s3c_irqext_type(irq,  type);        if(irq < IRQ_EINT7)    	s3c_irq_ack(irq);    else    	s3c_irqext_ack(irq);				request = request_irq(k->irq_no, &buttons_irq, SA_INTERRUPT, DEVICE_NAME, NULL);    if (request) {    	printk(KERN_WARNING "buttons:can't get irq no.\n");			return -1;		}	}	return 0;}static void free_irqs(void){	struct key_info *k;	int i;		for (i = 0; i < sizeof key_info_tab / sizeof key_info_tab[1]; i++) {		k = key_info_tab + i;		free_irq(k->irq_no, NULL);	}}static ssize_t buttons_read(struct file *filp,char __user *buffer,size_t count,loff_t *ppos){	if(copy_to_user(buffer, (char *)extint_num, sizeof(extint_num)))	{		printk(KERN_ALERT "Copy to user error.\n");		return -EFAULT;	}	return sizeof(extint_num); }static struct file_operations buttons_fops = {	.owner	=	THIS_MODULE,	.read	=	buttons_read,};static int __init buttons_init(void){	int ret;	int devno;	dev_t dev;	printk(KERN_INFO "Initial RealARM Buttons driver!\n");				  ret = alloc_chrdev_region(&dev,0,1,DEVICE_NAME);  buttons_major_number = MAJOR(dev);  if (ret < 0) {  	printk(KERN_WARNING "button:can't get major number %d\n",buttons_major_number);    return ret;  }          ret = request_irqs();  if (ret < 0) {  	unregister_chrdev_region(dev,1);    printk(KERN_WARNING "button:can't request irqs\n");    return ret;  }    devno = MKDEV(buttons_major_number,0);  cdev_init(&buttons_dev, &buttons_fops);  buttons_dev.owner = THIS_MODULE;  buttons_dev.ops   = &buttons_fops;  ret = cdev_add(&buttons_dev,devno,1);  if (ret) {  	free_irqs();    unregister_chrdev_region(dev,1);    printk(KERN_NOTICE "Error %d adding buttons device\n",ret);    return ret;  }#ifdef CONFIG_DEVFS_FS	devfs_mk_cdev(MKDEV(buttons_major_number,0), S_IFCHR | S_IRUSR | S_IWUSR,DEVICE_NAME);  printk(KERN_INFO"/dev/%s has been added to your system.\n",DEVICE_NAME);#else  printk(DEVICE_NAME "Initialized\n");  printk(KERN_INFO "You must create the dev file manually.\n");  printk(KERN_INFO "Todo: mknod c /dev/%s %d 0\n",DEVICE_NAME,buttons_major_number);#endif  return 0;}static void __exit buttons_cleanup(void){	dev_t dev=MKDEV(buttons_major_number,0);	free_irqs();	cdev_del(&buttons_dev);	unregister_chrdev_region(dev,1);        #ifdef CONFIG_DEVFS_FS  devfs_remove(DEVICE_NAME);#endif  printk(KERN_INFO "unregistered the %s\n",DEVICE_NAME);}module_init(buttons_init);module_exit(buttons_cleanup);                             MODULE_AUTHOR("LiuRui");MODULE_LICENSE("GPL");MODULE_DESCRIPTION("Key driver for RealARM");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -