1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun pseudo.h (c) 1997-8 Grant R. Guenther <grant@torque.net>
3*4882a593Smuzhiyun Under the terms of the GNU General Public License.
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun This is the "pseudo-interrupt" logic for parallel port drivers.
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun This module is #included into each driver. It makes one
8*4882a593Smuzhiyun function available:
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun ps_set_intr( void (*continuation)(void),
11*4882a593Smuzhiyun int (*ready)(void),
12*4882a593Smuzhiyun int timeout,
13*4882a593Smuzhiyun int nice )
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun Which will arrange for ready() to be evaluated frequently and
16*4882a593Smuzhiyun when either it returns true, or timeout jiffies have passed,
17*4882a593Smuzhiyun continuation() will be invoked.
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun If nice is 1, the test will done approximately once a
20*4882a593Smuzhiyun jiffy. If nice is 0, the test will also be done whenever
21*4882a593Smuzhiyun the scheduler runs (by adding it to a task queue). If
22*4882a593Smuzhiyun nice is greater than 1, the test will be done once every
23*4882a593Smuzhiyun (nice-1) jiffies.
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun */
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun /* Changes:
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun 1.01 1998.05.03 Switched from cli()/sti() to spinlocks
30*4882a593Smuzhiyun 1.02 1998.12.14 Added support for nice > 1
31*4882a593Smuzhiyun */
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #define PS_VERSION "1.02"
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #include <linux/sched.h>
36*4882a593Smuzhiyun #include <linux/workqueue.h>
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun static void ps_tq_int(struct work_struct *work);
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun static void (* ps_continuation)(void);
41*4882a593Smuzhiyun static int (* ps_ready)(void);
42*4882a593Smuzhiyun static unsigned long ps_timeout;
43*4882a593Smuzhiyun static int ps_tq_active = 0;
44*4882a593Smuzhiyun static int ps_nice = 0;
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun static DEFINE_SPINLOCK(ps_spinlock __attribute__((unused)));
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun static DECLARE_DELAYED_WORK(ps_tq, ps_tq_int);
49*4882a593Smuzhiyun
ps_set_intr(void (* continuation)(void),int (* ready)(void),int timeout,int nice)50*4882a593Smuzhiyun static void ps_set_intr(void (*continuation)(void),
51*4882a593Smuzhiyun int (*ready)(void),
52*4882a593Smuzhiyun int timeout, int nice)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun unsigned long flags;
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun spin_lock_irqsave(&ps_spinlock,flags);
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun ps_continuation = continuation;
59*4882a593Smuzhiyun ps_ready = ready;
60*4882a593Smuzhiyun ps_timeout = jiffies + timeout;
61*4882a593Smuzhiyun ps_nice = nice;
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun if (!ps_tq_active) {
64*4882a593Smuzhiyun ps_tq_active = 1;
65*4882a593Smuzhiyun if (!ps_nice)
66*4882a593Smuzhiyun schedule_delayed_work(&ps_tq, 0);
67*4882a593Smuzhiyun else
68*4882a593Smuzhiyun schedule_delayed_work(&ps_tq, ps_nice-1);
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun spin_unlock_irqrestore(&ps_spinlock,flags);
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun
ps_tq_int(struct work_struct * work)73*4882a593Smuzhiyun static void ps_tq_int(struct work_struct *work)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun void (*con)(void);
76*4882a593Smuzhiyun unsigned long flags;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun spin_lock_irqsave(&ps_spinlock,flags);
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun con = ps_continuation;
81*4882a593Smuzhiyun ps_tq_active = 0;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun if (!con) {
84*4882a593Smuzhiyun spin_unlock_irqrestore(&ps_spinlock,flags);
85*4882a593Smuzhiyun return;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun if (!ps_ready || ps_ready() || time_after_eq(jiffies, ps_timeout)) {
88*4882a593Smuzhiyun ps_continuation = NULL;
89*4882a593Smuzhiyun spin_unlock_irqrestore(&ps_spinlock,flags);
90*4882a593Smuzhiyun con();
91*4882a593Smuzhiyun return;
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun ps_tq_active = 1;
94*4882a593Smuzhiyun if (!ps_nice)
95*4882a593Smuzhiyun schedule_delayed_work(&ps_tq, 0);
96*4882a593Smuzhiyun else
97*4882a593Smuzhiyun schedule_delayed_work(&ps_tq, ps_nice-1);
98*4882a593Smuzhiyun spin_unlock_irqrestore(&ps_spinlock,flags);
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun /* end of pseudo.h */
102*4882a593Smuzhiyun
103