Fork Me on GitHub

源码开放学ARM

LASO - Learn ARM with Source Open

首页         目录索引         资料下载         代码下载         联系作者        
下载PDF打印版本

GPIO/UART 中断代码实现

相关文件

中断框架代码

//#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/fs.h>
//#include <asm/uaccess.h>

int flag = 0;
#define MA	134

wait_queue_head_t myqueue;

ssize_t myread(struct file *fl, char * buf, size_t size, loff_t * loff)
{
	printk("myread() begin!\n");
	printk("myread() &flag = %p\n", &flag);

	printk("myread() wait begin!\n");
	wait_event_interruptible(myqueue, flag != 0);
	flag = 0;
	printk("myread() wait end!\n");

	//return sizeof(int);
	return 0;
}

int mywrite(struct file *fl, const char * buf, size_t size, loff_t * loff)
{
	printk("mywrite() begin!\n");
	printk("mywrite() &flag = %p\n", &flag);

	printk("mywrite() wake up begin!\n");
	wake_up_interruptible(&myqueue);
	flag = 1;
	printk("mywrite() wake up end!\n");

	return 1;
}

struct file_operations fops =
{
	.read = myread,
	.write = mywrite,
};


int int_init(void)
{
	int rc;

	printk("int init\n");

	rc = register_chrdev(MA, "mychar", &fops);

	if (rc < 0)
	{
		printk("register failed\n");
		return -1;
	}

	init_waitqueue_head(&myqueue);

	return 0;
}

void int_exit(void)
{
	printk("int exit\n");

	unregister_chrdev(MA, "mychar");

	return;
}

module_init(int_init);
module_exit(int_exit);

GPIO 中断代码

#include <linux/module.h>	// module_init
#include <asm/io.h>		// ioremap
#include <linux/fs.h>		// file_operations
#include <asm/uaccess.h>	// copy_from_user
#include <linux/sched.h>	// wait_queue 

#include <mach/gpio.h>		// S5PV210_GPH2
#include <mach/regs-gpio.h>
#include <linux/interrupt.h>	// requst_irq
#include <linux/irq.h>		// IRQ_TYPE_EDGE_BOTH


MODULE_LICENSE("GPL");

#define MA	240

volatile int * pbtn;
static int ev_press = 0;

wait_queue_head_t  btn_waitq;

static int irq;

struct btn_desc 
{
	int gpio;
	int number;
	char * name;
};

static struct btn_desc btns[] = 
{
	{ S5PV210_GPH2(0), 0, "KEY0" },
	{ S5PV210_GPH2(1), 1, "KEY0" },
	{ S5PV210_GPH2(2), 2, "KEY0" },
};


static irqreturn_t btn_irq_handler(int irq, void * dev_id)
{
	printk("btn irq handler !!!\n");

	ev_press = 1;
	wake_up_interruptible(&btn_waitq);

	return IRQ_HANDLED;
}

int btn_drv_open(struct inode *inode, struct file *filp)
{
	int major, minor;
	int err;

	major = MAJOR(inode->i_rdev);
	minor = MINOR(inode->i_rdev);

	printk("btn drv open: major %d, minor %d\n", major, minor);

	irq = gpio_to_irq(btns[0].gpio);
	printk("irq = %d\n", irq);

	// see include/linux/irq.h for more types
	//err = request_irq(irq, btn_irq_handler, IRQ_TYPE_EDGE_BOTH,
	err = request_irq(irq, btn_irq_handler, IRQ_TYPE_EDGE_FALLING,
			"btn0", NULL);
	if (err)
	{
		printk("request irq failed!\n");
	}

	printk("request irq ok! err = %d\n", err);

	init_waitqueue_head(&btn_waitq);

	return 0;
}

ssize_t btn_drv_read(struct file *filp, char __user * buf, size_t count, loff_t *f_pos)
{
	printk("btn read!\n");	

	wait_event_interruptible(btn_waitq, ev_press);
	ev_press = 0;

	return 0;
}

ssize_t btn_drv_write(struct file *filp, const char __user * buf, size_t count, loff_t *f_pos)
{
	//char kbuf[128];

	//buf[count] = '\0';
	printk("btn drv write %d\n", count);

//	printk("buf = %s\n", buf);
//	printk("buf at %p\n", buf);
	printk("count = %d\n", count);

//	copy_from_user(kbuf, buf, count);
	*pbtn = buf[0];

//	printk("kbuf = %s\n", kbuf);
//	printk("kbuf at %p\n", kbuf);

	return count;
}

int btn_drv_release(struct inode *inode, struct file *filp)
{
	printk("btn drv release ok!\n");

	free_irq(irq, NULL);

	return 0;
}

struct file_operations btn_fops = 
{
	.owner = THIS_MODULE,
	.open = btn_drv_open,
	.read = btn_drv_read,
	.write = btn_drv_write,
	.release = btn_drv_release,
};

static int btn_drv_init(void)
{
	int rc;

	printk("btn init \n");

	pbtn = ioremap(0xE0200284, 4);

	//*pbtn = 0;
	rc = register_chrdev(MA, "akae", &btn_fops);
	if (rc < 0)
	{
		printk("register failed\n");
		return -1;
	}

	printk("register char ok %d!\n", rc);

	return 0;
}

static void btn_drv_exit(void)
{
	printk("btn exit \n");

	//*pbtn = 0xF;
	unregister_chrdev(MA, "akae");

	printk("unregister char ok!\n");

	return;
}

module_init(btn_drv_init);
module_exit(btn_drv_exit);

参考实现

arch/arm/mach-s5pv210/include/mach/gpio.h:175:

#define S5PV210_GPH2(_nr)	(S5PV210_GPIO_H2_START + (_nr))

arch/arm/mach-s5pv210/include/mach/gpio.h

	S5PV210_GPIO_H2_START	= S5PV210_GPIO_NEXT(S5PV210_GPIO_H1),
	
#define S5PV210_GPIO_NEXT(__gpio) \
	((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)

#define S5PV210_GPIO_H2_NR	(8)

如何从 gpio 号获得中断号 irq

查看以下两个文件:

arch/arm/mach-s5pv210/include/mach/irqs.h
arch/arm/plat-samsung/include/plat/irqs.h

也可以通过 gpio_to_irq 得到中断号:

drivers/gpio/gpiolib.c:1575: * __gpio_to_irq() - return the IRQ corresponding to a GPIO
drivers/gpio/gpiolib.c:1583:int __gpio_to_irq(unsigned gpio)

/**
 * __gpio_to_irq() - return the IRQ corresponding to a GPIO
 * @gpio: gpio whose IRQ will be returned (already requested)
 * Context: any
 *
 * This is used directly or indirectly to implement gpio_to_irq().
 * It returns the number of the IRQ signaled by this (input) GPIO,
 * or a negative errno.
 */
int __gpio_to_irq(unsigned gpio)
{
	struct gpio_chip	*chip;

	chip = gpio_to_chip(gpio);
	return chip->to_irq ? chip->to_irq(chip, gpio - chip->base) : -ENXIO;
}
EXPORT_SYMBOL_GPL(__gpio_to_irq);

arch/arm/mach-s5pv210/mach-mini210.c

arch/arm/mach-s5pv210/mach-mini210.c:2128: .init_irq = s5pv210_init_irq,

arch/arm/mach-s5pv210/cpu.c:150:void init s5pv210_init_irq(void)

arch/arm/plat-samsung/include/plat/cpu.h:51:extern void s5p_init_irq(u32 vic, u32 num_vic);

arch/arm/plat-s5p/irq-eint.c:217:int init s5p_init_irq_eint(void)

UART 中断代码

#include <linux/module.h>
#include <linux/fs.h>	// register_chrdev
#include <asm/io.h>
#include <plat/map-base.h>
#include <plat/regs-serial.h>
//#include <asm/uaccess.h>

#define MA	243

MODULE_LICENSE("GPL");

struct uart_sfr
{
	int ulcon;
	int ucon;
	int ufcon;
	int umcon;
	int utrstat;
	int uerstat;
	int ufstat;
	int umstat;
	int utxh;
	int urxh;
	int ubrdiv;
	int udivslot;
};

typedef struct uart_sfr USFR;

static volatile USFR *puart;
static volatile USFR *puart2;

//#define printk 		noprintk	

int noprintk(char * fmt, ...)
{ 
	return 0; 
} 

#define PRINT(x)	printk(#x " = 0x%x\n", x);

#include <linux/irq.h>
#include <linux/interrupt.h>		// request_irq

// see it in arch/arm/plat-s5p/include/plat/irqs.h
#define UART_RX			(28 + 0)
#define UART_ERR		(28 + 1)
#define UART_TX			(28 + 2)

int flag = 0;
wait_queue_head_t  uart_waitq;

int myputchar(char);

char outputc;

static irqreturn_t uart_read_irq_handler(int irq, void * dev_id)
{
	char c;

	printk("in read irq!!!\n");

	flag = 1;
	wake_up_interruptible(&uart_waitq);

	c = puart2->urxh;
	myputchar(c);

	return IRQ_HANDLED;
}

static irqreturn_t uart_write_irq_handler(int irq, void * dev_id)
{
	static int i = 0;

	printk("in write irq!!! %d \n", i++);

	puart2->utxh = outputc;

	disable_irq_nosync(UART_TX);
	//disable_irq(UART_TX);		

	return IRQ_HANDLED;
}

int uart_open(struct inode * inode, struct file * filp)
{
	int major = MAJOR(inode->i_rdev);
	int minor = MINOR(inode->i_rdev);
	int * p;
	int i;
	int ri;

	printk("uart open: major %d, minor %d\n", major, minor);

//	puart = ioremap(0xe2900000, sizeof(USFR));	// uart0
//	puart = ioremap(0xe2900000, 0x10000);	// uart0
	puart = S3C24XX_VA_UART0;

	puart2 = ioremap(0xe2900c00, sizeof(USFR));	// uart3
//	puart2 = S3C24XX_VA_UART1;
	p = (int *)puart;
	PRINT((int)p);	
	for (i = 0; i < sizeof(USFR)/4; i++)
	{ 
		PRINT(*p++);	
	} 
//	puart = (USFR *)(((int)puart) + 0xc000);
//	puart->ufcon = 0;		// fifo is important!
	p = (int *)puart2;
	PRINT((int)p);	
	for (i = 0; i < sizeof(USFR)/4; i++)
	{
		PRINT(*p++);	
	}

	puart2->ucon = 0x7c5;
	puart2->ubrdiv = 0x23;		// 115200
	puart2->udivslot = 0x808;	// 115200

	p = (int *)puart2;
	PRINT((int)p);	
	for (i = 0; i < sizeof(USFR)/4; i++)
	{ PRINT(*p++);	
	}
#if 0
	puart->ulcon = 3;
	puart->ucon = 0x7c5;
//	puart->ufcon = 0x111;		// fifo is important!
	puart->umcon = 0;
	puart->ubrdiv = 0x23;		// 115200
	puart->udivslot = 0x808;	// 115200
#endif

	ri = request_irq(UART_RX, uart_read_irq_handler, 0, "read_irq", NULL);
	if (ri)
		printk("request irq %d failed! ri = %d\n", UART_RX, ri);
	else
		printk("request irq %d ok! ri = %d\n", UART_RX, ri);

	init_waitqueue_head(&uart_waitq);

	ri = request_irq(UART_TX, uart_write_irq_handler, 0, "write_irq", NULL);
	if (ri)
		printk("request irq %d failed! ri = %d\n", UART_TX, ri);
	else
		printk("request irq %d ok! ri = %d\n", UART_TX, ri);

	printk("uart open finished!\n"); 

	return 0;
}

int uart_release(struct inode * inode, struct file * filp)
{
	printk("uart release\n");

	free_irq(UART_RX, NULL);
	free_irq(UART_TX, NULL);
	printk("free irq %d ok! \n", UART_RX);
	printk("free irq %d ok! \n", UART_TX);

	return 0;
}

#if 0
int uart_putchar(char c)
{
	while ((puart->utrstat & (1<<2)) == 0)
		;

	puart->utxh = c;
#if 1
	while ((puart2->utrstat & (1<<2)) == 0)
		;

	puart2->utxh = c;
#endif

	return 0;
}
#else

int uart_putchar(char c)
{
	// uart0 putchar using polling 
#if 0 
	while ((puart->utrstat & (1<<2)) == 0)
		;

	puart->utxh = c;
#endif
	printk("uart putchar %c(%d)\n", c, c);

	// uart3 putchar using irq
	outputc = c;	
	enable_irq(UART_TX);

	return 1; 
}

#endif

int myputchar(char c)
{
	if (c == '\n')
		uart_putchar('\r');

	uart_putchar(c);

	return 0;
}


int uart_read(struct file * filp, char __user * buf, size_t count, loff_t *f_pos)
{
	printk("uart read\n");

	wait_event_interruptible(uart_waitq, flag != 0);
	flag = 0;

	return 0;
}

int uart_write(struct file * filp, const char __user * buf, size_t count, loff_t *f_pos)
{
	int i;

	printk("uart write\n");

	printk("buf = %c\n", buf[0]);
	printk("count = %d\n", count);

	for (i = 0; i < count; i++)
	{
		//myputchar(buf[i]);
		uart_putchar(buf[i]);
	}

//	myputchar(buf[0]);

	return count;
}

int uart_ioctl(struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg)
{
	printk("uart ioctl\n");

	printk("cmd = %d\n", cmd);

	if (cmd == 19200)
		puart->ubrdiv = 0xd5;

	if (cmd == 115200)
		puart->ubrdiv = 0x23;

	return 0;
}

struct file_operations uart_fops = 
{
	.owner = THIS_MODULE,
	.open = uart_open,
	.release = uart_release,
	.write = uart_write,
	.read = uart_read,
	//.ioctl = uart_ioctl,
};


int uart_init(void)
{
	int rc;

	rc = register_chrdev(MA, "myuart", &uart_fops);

	if (rc < 0)
	{
		printk("register chrdev failed! %d\n", rc);
		return -1;
	}

	printk("uart init ok \n");

	return 0;
}

void uart_exit(void)
{
	printk("uart exit ok \n");

	unregister_chrdev(MA, "myuart");


	return;
}


module_init(uart_init);
module_exit(uart_exit);

上一节 | 目录索引 | 下一节

blog comments powered by Disqus