A drv_open function analysis
Configure a pin as an external trigger interrupt source:
(1) Pin label-void *dev_id
(2) Sensitive edge-unsigned long irqflags
(3) Interrupt label-unsigned int irq;
(4) Interrupt type-irq_handler_t handler
(5) ) Device name -const char *devname The
above parameters are request_irq
set by function in the linux kernel .
[1] request_irq
Function call
request_irq(IRQ_EINT0, buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
[2] request_irq
Function internal processing: call the setup_irq
function to initialize the interrupt.
Among them,
irq= (3) interrupt label-unsigned int irq = IRQ_EINT0
action->handler = (4) function called after the interrupt occurs-irq_handler_t handler = buttons_irq
action->flags = (2) sensitive edge-unsigned long irqflags = IRQT_BOTHEDGE
action->name = (5) Device name-const char *devname = “S2” You can take any value as you
like action->next = NULL;
action->dev_id = (1) Pin label-void *dev_id = &pins_desc[0 ] Any value can be selected, the purpose is to determine which driver to uninstall
int request_irq(unsigned int irq, irq_handler_t handler,unsigned long irqflags, const char *devname, void *dev_id)
{
...
retval = setup_irq(irq, action);
...
}
[3] setup_irq
Function internal processing: use set_type
function processing
int setup_irq(unsigned int irq, struct irqaction *new)
{
...
if (desc->chip && desc->chip->set_type)
desc->chip->set_type(irq,new->flags & IRQF_TRIGGER_MASK);
...
}
Among them, desc->chip
where is it defined?
arch\arm\plat-s3c24xx\irq.c\void __init s3c24xx_init_irq(void)
, As defined in [1] IRQ_EINT0
, desc->chip corresponds to s3c_irq_eint0t4.
void __init s3c24xx_init_irq(void)
{
...
/* external interrupts */
for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
irqdbf("registering irq %d (ext int)\n", irqno);
set_irq_chip(irqno, &s3c_irq_eint0t4);
set_irq_handler(irqno, handle_edge_irq);
set_irq_flags(irqno, IRQF_VALID);
}
for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {
irqdbf("registering irq %d (extended s3c irq)\n", irqno);
set_irq_chip(irqno, &s3c_irqext_chip);
set_irq_handler(irqno, handle_edge_irq);
set_irq_flags(irqno, IRQF_VALID);
}
...
}
View s3c_irq_eint0t4
definition:
static struct irq_chip s3c_irq_eint0t4 = {
.name = "s3c-ext0",
.ack = s3c_irq_ack,
.mask = s3c_irq_mask,
.unmask = s3c_irq_unmask,
.set_wake = s3c_irq_wake,
.set_type = s3c_irqext_type,
};
[4] set_type
Function = s3c_irqext_type
Function The
previous calling code is:
new->flags=action->flags = (2)敏感沿-unsigned long irqflags=IRQT_BOTHEDGE
desc->chip->set_type(irq,new->flags & IRQF_TRIGGER_MASK);
The definition of the function is:
s3c_irqext_type(unsigned int irq, unsigned int type)
{
...
if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3))
{
gpcon_reg = S3C2410_GPFCON;
extint_reg = S3C24XX_EXTINT0;
gpcon_offset = (irq - IRQ_EINT0) * 2;
extint_offset = (irq - IRQ_EINT0) * 4;
}
...
/* 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;
//与前面request_irq函数调用一致
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;
}
}
Two drv_close function analysis
Function purpose: release interrupt source
- free_irq function call
irq=(3)中断标号-unsigned int irq = IRQ_EINT0
dev_id = (1)引脚标号-void *dev_id = &pins_desc[0]
free_irq(IRQ_EINT0, &pins_desc[0]);
The free_irq function definition:
void free_irq(unsigned int irq, void *dev_id)
Three buttons_irq interrupt service function analysis-wake-up function
- Function declaration format:
static irqreturn_t buttons_irq(int irq, void *dev_id)
Note: You can see thedev_id
function here : Determine the interrupt source - return value:
return IRQ_RETVAL(IRQ_HANDLED);
- Wake-up function:
wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */
Four drv_read function analysis-sleep function:
- Sleep function call
/* 如果没有按键动作, 休眠 */
wait_event_interruptible(button_waitq, ev_press);
- Sleep function prototype
#define wait_event_interruptible(wq, condition) \
({ \
int __ret = 0; \
if (!(condition)) \ //condition数值为0的时候休眠
__wait_event_interruptible(wq, condition, __ret); \
__ret; \
})
- Parameter declaration
[1]ev_press parameters:
/* 中断事件标志, 中断服务程序将它置1:表示唤醒
third_drv_read将它清0:表示休眠 */
static volatile int ev_press = 0;
[2] button_waitq parameter:
represents the process hanging in the queue
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
Five drive test 1
When the app program executes the read function: if the interrupt function does not occur, the sleep process is executed;
if an interrupt occurs, the process is awakened
-
How to call
drv_open
functions after the development board loads the driver ?
exec 5</dev/buttons
Meaning: Turn on the device/dev/buttons
and locate to 5Note: The shell process number shown in the figure below is 770
/proc/770/fd: fd — This is a directory that contains the file descriptors of each file opened by the current process. These file descriptors point to the actual files A symbolic link; the
execution effect of the driver /dev/buttons opened by the shell process :
-
Call the close function?
carried out:exec 5<&-
Six drive test 2
- Executing the test program (execution in the background): ./app &
As can be seen from the figure: the driver and the test program are executed in the background. Among them, the test program is in a sleep state (S) to
view the CPU resources occupied by each process:top
command (ctrl+c to exit)