1 | /* Poll.c Demonstration program for WinSystems PCM-MIO Driver */ |
---|
2 | |
---|
3 | /* |
---|
4 | * |
---|
5 | * $Header$ |
---|
6 | * |
---|
7 | * $Id$ |
---|
8 | * |
---|
9 | * $Log$ |
---|
10 | * |
---|
11 | */ |
---|
12 | |
---|
13 | /* This program demonstrates one manner in which an unprivledged |
---|
14 | application running in user space can sychronize to hardware events |
---|
15 | handled by a device driver running in Kernel space. |
---|
16 | */ |
---|
17 | |
---|
18 | |
---|
19 | #include "mio_io.h" |
---|
20 | |
---|
21 | #include <stdio.h> |
---|
22 | #include <fcntl.h> /* open */ |
---|
23 | #include <unistd.h> /* exit */ |
---|
24 | #include <sys/ioctl.h> /* ioctl */ |
---|
25 | #include <stdlib.h> |
---|
26 | #include <pthread.h> |
---|
27 | |
---|
28 | |
---|
29 | /* This function will be a sub-processe using the Posix threads |
---|
30 | capability of Linux. This thread will simulate a type of |
---|
31 | Interrupt service routine in that it will start up and then suspend |
---|
32 | until an interrupt occurs and the driver awakens it. |
---|
33 | */ |
---|
34 | |
---|
35 | void *thread_function(void *arg); |
---|
36 | |
---|
37 | /* Event count, counts the number of events we've handled */ |
---|
38 | |
---|
39 | volatile int event_count; |
---|
40 | volatile int exit_flag = 0; |
---|
41 | |
---|
42 | char line[80]; |
---|
43 | |
---|
44 | main(int argc, char *argv[]) |
---|
45 | { |
---|
46 | int res, res1; |
---|
47 | pthread_t a_thread; |
---|
48 | int c; |
---|
49 | int x; |
---|
50 | |
---|
51 | /* Do a read_bit to test for port/driver availability */ |
---|
52 | |
---|
53 | c = dio_read_bit(1); |
---|
54 | if(mio_error_code) |
---|
55 | { |
---|
56 | printf("%s\n",mio_error_string); |
---|
57 | exit(1); |
---|
58 | } |
---|
59 | |
---|
60 | |
---|
61 | /* Here, we'll enable all 24 bits for falling edge interrupts on both |
---|
62 | chips. We'll also make sure that they're ready and armed by |
---|
63 | explicitly calling the clr_int() function. |
---|
64 | */ |
---|
65 | |
---|
66 | for(x=1; x < 25; x++) |
---|
67 | { |
---|
68 | dio_enab_bit_int(x,FALLING); |
---|
69 | dio_clr_int(x); |
---|
70 | } |
---|
71 | |
---|
72 | |
---|
73 | /* We'll also clear out any events that are queued up within the |
---|
74 | driver and clear any pending interrupts |
---|
75 | */ |
---|
76 | |
---|
77 | enable_dio_interrupt(); |
---|
78 | |
---|
79 | if(mio_error_code) |
---|
80 | { |
---|
81 | printf("%s\n",mio_error_string); |
---|
82 | exit(1); |
---|
83 | } |
---|
84 | |
---|
85 | while((x= dio_get_int())) |
---|
86 | { |
---|
87 | printf("Clearing interrupt on Chip 1 bit %d\n",x); |
---|
88 | dio_clr_int(x); |
---|
89 | } |
---|
90 | |
---|
91 | |
---|
92 | /* Now the sub-thread will be started */ |
---|
93 | |
---|
94 | printf("Splitting off polling process\n"); |
---|
95 | |
---|
96 | res = pthread_create(&a_thread,NULL,thread_function,NULL); |
---|
97 | |
---|
98 | if(res != 0) |
---|
99 | { |
---|
100 | perror("Thread creation failed"); |
---|
101 | exit(EXIT_FAILURE); |
---|
102 | } |
---|
103 | |
---|
104 | |
---|
105 | /* The thread is now running in the background. It will execute up |
---|
106 | to the point were there are no interrupts and suspend. We as its |
---|
107 | parent continue on. The nice thing about POSIX threads is that we're |
---|
108 | all in the same data space the parent and the children so we can |
---|
109 | share data directly. In this program we share the event_count |
---|
110 | variable. |
---|
111 | */ |
---|
112 | |
---|
113 | |
---|
114 | /* We'll continue on in this loop until we're terminated */ |
---|
115 | |
---|
116 | while(1) |
---|
117 | { |
---|
118 | /* Print Something so we know the foreground is alive */ |
---|
119 | |
---|
120 | printf("**"); |
---|
121 | |
---|
122 | |
---|
123 | /* The foreground will now wait for an input from the console |
---|
124 | We could actually go on and do anything we wanted to at this |
---|
125 | point. |
---|
126 | */ |
---|
127 | |
---|
128 | fgets(line,75,stdin); |
---|
129 | |
---|
130 | if(line[0] == 'q' || line[0] == 'Q') |
---|
131 | break; |
---|
132 | |
---|
133 | /* Here's the actual exit. If we hit 'Q' and Enter. The program |
---|
134 | terminates. |
---|
135 | */ |
---|
136 | |
---|
137 | } |
---|
138 | |
---|
139 | |
---|
140 | /* This flag is a shared variable that the children can look at to |
---|
141 | know we're finished and they can exit too. |
---|
142 | */ |
---|
143 | |
---|
144 | exit_flag = 1; |
---|
145 | |
---|
146 | disable_dio_interrupt(); |
---|
147 | |
---|
148 | /* Display our event count total */ |
---|
149 | |
---|
150 | printf("Event count = %05d\r",event_count); |
---|
151 | |
---|
152 | printf("\n\nAttempting to cancel subthread\n"); |
---|
153 | |
---|
154 | /* If out children are not in a position to see the exit_flag, we |
---|
155 | will use a more forceful technique to make sure they terminate with |
---|
156 | us. If we leave them hanging and we try to re-run the program or |
---|
157 | if another program wants to talk to the device they may be locked |
---|
158 | out. This way everything cleans up much nicer. |
---|
159 | */ |
---|
160 | |
---|
161 | pthread_cancel(a_thread); |
---|
162 | printf("\nExiting Now\n"); |
---|
163 | |
---|
164 | fflush(NULL); |
---|
165 | |
---|
166 | } |
---|
167 | |
---|
168 | /* This is the the sub-procesc. For the purpose of this |
---|
169 | example, it does nothing but wait for an interrupt to be active on |
---|
170 | chip 1 and then reports that fact via the console. It also |
---|
171 | increments the shared data variable event_count. |
---|
172 | */ |
---|
173 | |
---|
174 | void *thread_function(void *arg) |
---|
175 | { |
---|
176 | int c; |
---|
177 | |
---|
178 | while(1) |
---|
179 | { |
---|
180 | /* Test for a thread cancellation signal */ |
---|
181 | |
---|
182 | pthread_testcancel(); |
---|
183 | |
---|
184 | /* Test the exit_flag also for exit */ |
---|
185 | |
---|
186 | if(exit_flag) |
---|
187 | break; |
---|
188 | |
---|
189 | /* This call will put THIS process to sleep until either an |
---|
190 | interrupt occurs or a terminating signal is sent by the |
---|
191 | parent or the system. |
---|
192 | */ |
---|
193 | c = wait_dio_int(); |
---|
194 | |
---|
195 | /* We check to see if it was a real interrupt instead of a |
---|
196 | termination request. |
---|
197 | */ |
---|
198 | |
---|
199 | if(c > 0) |
---|
200 | { |
---|
201 | printf("Event sense occured on bit %d\n",c); |
---|
202 | ++event_count; |
---|
203 | } |
---|
204 | else |
---|
205 | break; |
---|
206 | } |
---|
207 | } |
---|
208 | |
---|