📄 tid_intr.c
字号:
/*********************************************************************** * * (C) Copyright 2000 * Jean-Jacques Germond, Fr閐閞ic Soulier, Christian Batt; Alcatel * C/O jjg@sxb.bsf.alcatel.fr * * All rights reserved. * * This code is free software; you can redistribute it and/or * modify it under the terms of the GNU *Library* General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This code is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * *Library* General Public License for more details. * * You should have received a copy of the GNU *Library* General Public * License along with this program (see file COPYING.LIB); if not, * write to the Free Software Foundation, Inc., 675 Mass Ave, * Cambridge, MA 02139, USA. * ***********************************************************************//* This file implements the portable foreground code for the * Trivial interrupt driver */ /* See AR pg:21 */# define __NO_VERSION__#include "tid_def.h"#include <linux/interrupt.h>void tid_bh_entry(void); /* Forward declaration */#define TID_SIMU_IRQNBR -1234 /* An interrupt # never used by linux *//************************************************ * Static variable shared between the top * and bottom halves of the interrupt handlers ************************************************//* The queue of waiting unix processes for the tid device */struct wait_queue* tid_queue;/* The # of intr. not yet procerssed by by bottom half */static volatile int tid_pending_count;static volatile int tid_bh_busy; /* Tells that the bh is busy or scheduled *//* The structure to describe the bh routine */static struct tq_struct tid_bh_descr = { NULL, /* link to next active bh */ 0, /* Sync */ (void(*)(void*)) tid_bh_entry, /* Entry point */ NULL, /* Argument to bh routine */};/************************************************** * The wait routines for unix processes. * (tricky: see AR pg 209) **************************************************/ static inttid_proc_must_still_wait(Tid_Dev* dev, int initFilePos, int initialUnique) /* Test the wakeup condition at the process level */{ int nbNewChars; /* Test if we got a signal */ if (tid_caughtSignal()) { return -ERESTARTSYS; } if (initialUnique != dev->uniqueId) { /* The file was erased by an other process, while we were waiting */ return -EIO; } nbNewChars = dev->nbChars - initFilePos; if (nbNewChars < 0) { /* Should never be here. Better safe than sorry */ return -EFAULT; } return nbNewChars;} inttid_wait(loff_t initFilePos) /* Wait for some (more) chars available in the device * This runs at the process level, NOT at the interrupt level */{ struct wait_queue wait = {current, NULL}; /* Must be in the stack */ int wakeupCode; Tid_Dev* dev = &tid_dev_struct; /* The device descriptor structure */ long initialUnique = dev->uniqueId; /* Adding to the tid_queue is not atomic, but we are not preemptible * since we are in the kernel space. * Similarly, the tid_queue is NOT emtied under interrupts. * Therefore we wont be preempted by any other UNIX process willing * to wait on the tid device as well and do not need to protect this * call to add_wait_queue. */ add_wait_queue(&tid_queue, &wait); do { current->state = TASK_INTERRUPTIBLE; schedule(); wakeupCode = tid_proc_must_still_wait(dev, initFilePos, initialUnique); dev->nbWakeUp++; /* Used to idendify the wakeup */ dev->lastWakeup = wakeupCode; /* Log the last wakeup code */ } while (wakeupCode == 0); /* Remove this process from the wait queue (see above about non atomicity) */ remove_wait_queue(&tid_queue, &wait); return wakeupCode;}/************************************** * The bottom half interrupt handler **************************************/ voidtid_bh_entry(void){ unsigned long flags; int cur_count; Tid_Dev* dev = &tid_dev_struct; /* The device descriptor structure */ int nextNbChars; dev->nbBhActiv++; /* The # of times the bh was activated */ /* Loop to process all pending interrupts at the bh level * This simulates the porcessing of a fifo queue of pending events * between the bh and th levels. */ while (1) { save_flags(flags); cli(); cur_count = tid_pending_count; /* The local count */ tid_pending_count = 0; /* The inter halves count */ if (cur_count == 0) { /* All pending interrupts are now processed at our bh level */ tid_bh_busy = 0; /* Enable bh wake-up from the top-half */ restore_flags(flags); wake_up_interruptible(&tid_queue); return; } /* Process the pending events. * This simulates a longish processing at the bh level. */ restore_flags(flags); nextNbChars = dev->nbChars + cur_count; if (nextNbChars > dev->maxChars) { nextNbChars = dev->maxChars; } dev->nbChars = nextNbChars; }}/************************************************ * The Top half interrupt handler ************************************************/ voidtid_it_handler(void* dev_id){ Tid_Dev *dev = (Tid_Dev *)dev_id; dev->nbIntrEver++; /* # of interrupts since init */ /* Ignore the interrupt if we have too many virtual chars into */ if (dev->nbChars < dev->maxChars) { /* Bump the # of chars pending to be processed by the bh */ tid_pending_count++; /* Schedule the bh if not busy or already scheduled */ if (tid_bh_busy == 0) { tid_bh_busy = 1; if (tid_useSimulatedTimer()) { /* Here in simulated interrupt mode */ queue_task(&tid_bh_descr, &tq_timer); mark_bh(TQUEUE_BH); } else { queue_task(&tid_bh_descr, &tq_immediate); mark_bh(IMMEDIATE_BH); } } } /* Clear off the interrupting bit as appropriate */ tid_ackTimerInterrupt(dev_id);}inttid_connect_timer(Tid_Dev* dev, unsigned long period){ /* Followng inits are useless (globals are reset at boot time) but * it is a matter of programming style. */ tid_pending_count = 0; /* # of intr. not yet procerssed by by bottom half */ tid_bh_busy = 0; /* Tells that the bh is busy or scheduled */ tid_queue = NULL; /* The queue of waiting processes */ tid_init_timer (dev, period); return 0;}voidtid_disconnect_timer(Tid_Dev* dev){ tid_cancel_timer (dev); /* reset timer */} voidtid_simu_timer_interrupt(int nbIntr) /* This is called in timer simulated mode */{ unsigned long flags; while (nbIntr > 0) { nbIntr--; save_flags(flags); cli(); tid_it_handler(NULL); restore_flags(flags); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -