1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#ifndef _8253_H
20#define _8253_H
21
22#include "../comedi.h"
23
24#define i8253_cascade_ns_to_timer i8253_cascade_ns_to_timer_2div
25
26static inline void i8253_cascade_ns_to_timer_2div_old(int i8253_osc_base,
27 unsigned int *d1,
28 unsigned int *d2,
29 unsigned int *nanosec,
30 int round_mode)
31{
32 int divider;
33 int div1, div2;
34 int div1_glb, div2_glb, ns_glb;
35 int div1_lub, div2_lub, ns_lub;
36 int ns;
37
38 divider = (*nanosec + i8253_osc_base / 2) / i8253_osc_base;
39
40
41
42
43 div1_lub = div2_lub = 0;
44 div1_glb = div2_glb = 0;
45
46 ns_glb = 0;
47 ns_lub = 0xffffffff;
48
49 div2 = 0x10000;
50 for (div1 = divider / 65536 + 1; div1 < div2; div1++) {
51 div2 = divider / div1;
52
53 ns = i8253_osc_base * div1 * div2;
54 if (ns <= *nanosec && ns > ns_glb) {
55 ns_glb = ns;
56 div1_glb = div1;
57 div2_glb = div2;
58 }
59
60 div2++;
61 if (div2 <= 65536) {
62 ns = i8253_osc_base * div1 * div2;
63 if (ns > *nanosec && ns < ns_lub) {
64 ns_lub = ns;
65 div1_lub = div1;
66 div2_lub = div2;
67 }
68 }
69 }
70
71 *nanosec = div1_lub * div2_lub * i8253_osc_base;
72 *d1 = div1_lub & 0xffff;
73 *d2 = div2_lub & 0xffff;
74 return;
75}
76
77static inline void i8253_cascade_ns_to_timer_power(int i8253_osc_base,
78 unsigned int *d1,
79 unsigned int *d2,
80 unsigned int *nanosec,
81 int round_mode)
82{
83 int div1, div2;
84 int base;
85
86 for (div1 = 2; div1 <= (1 << 16); div1 <<= 1) {
87 base = i8253_osc_base * div1;
88 round_mode &= TRIG_ROUND_MASK;
89 switch (round_mode) {
90 case TRIG_ROUND_NEAREST:
91 default:
92 div2 = (*nanosec + base / 2) / base;
93 break;
94 case TRIG_ROUND_DOWN:
95 div2 = (*nanosec) / base;
96 break;
97 case TRIG_ROUND_UP:
98 div2 = (*nanosec + base - 1) / base;
99 break;
100 }
101 if (div2 < 2)
102 div2 = 2;
103 if (div2 <= 65536) {
104 *nanosec = div2 * base;
105 *d1 = div1 & 0xffff;
106 *d2 = div2 & 0xffff;
107 return;
108 }
109 }
110
111
112 div1 = 0x10000;
113 div2 = 0x10000;
114 *nanosec = div1 * div2 * i8253_osc_base;
115 *d1 = div1 & 0xffff;
116 *d2 = div2 & 0xffff;
117}
118
119static inline void i8253_cascade_ns_to_timer_2div(int i8253_osc_base,
120 unsigned int *d1,
121 unsigned int *d2,
122 unsigned int *nanosec,
123 int round_mode)
124{
125 unsigned int divider;
126 unsigned int div1, div2;
127 unsigned int div1_glb, div2_glb, ns_glb;
128 unsigned int div1_lub, div2_lub, ns_lub;
129 unsigned int ns;
130 unsigned int start;
131 unsigned int ns_low, ns_high;
132 static const unsigned int max_count = 0x10000;
133
134
135
136 div1 = *d1 ? *d1 : max_count;
137 div2 = *d2 ? *d2 : max_count;
138 divider = div1 * div2;
139 if (div1 * div2 * i8253_osc_base == *nanosec &&
140 div1 > 1 && div1 <= max_count && div2 > 1 && div2 <= max_count &&
141
142 divider > div1 && divider > div2 &&
143 divider * i8253_osc_base > divider &&
144 divider * i8253_osc_base > i8253_osc_base) {
145 return;
146 }
147
148 divider = *nanosec / i8253_osc_base;
149
150 div1_lub = div2_lub = 0;
151 div1_glb = div2_glb = 0;
152
153 ns_glb = 0;
154 ns_lub = 0xffffffff;
155
156 div2 = max_count;
157 start = divider / div2;
158 if (start < 2)
159 start = 2;
160 for (div1 = start; div1 <= divider / div1 + 1 && div1 <= max_count;
161 div1++) {
162 for (div2 = divider / div1;
163 div1 * div2 <= divider + div1 + 1 && div2 <= max_count;
164 div2++) {
165 ns = i8253_osc_base * div1 * div2;
166 if (ns <= *nanosec && ns > ns_glb) {
167 ns_glb = ns;
168 div1_glb = div1;
169 div2_glb = div2;
170 }
171 if (ns >= *nanosec && ns < ns_lub) {
172 ns_lub = ns;
173 div1_lub = div1;
174 div2_lub = div2;
175 }
176 }
177 }
178
179 round_mode &= TRIG_ROUND_MASK;
180 switch (round_mode) {
181 case TRIG_ROUND_NEAREST:
182 default:
183 ns_high = div1_lub * div2_lub * i8253_osc_base;
184 ns_low = div1_glb * div2_glb * i8253_osc_base;
185 if (ns_high - *nanosec < *nanosec - ns_low) {
186 div1 = div1_lub;
187 div2 = div2_lub;
188 } else {
189 div1 = div1_glb;
190 div2 = div2_glb;
191 }
192 break;
193 case TRIG_ROUND_UP:
194 div1 = div1_lub;
195 div2 = div2_lub;
196 break;
197 case TRIG_ROUND_DOWN:
198 div1 = div1_glb;
199 div2 = div2_glb;
200 break;
201 }
202
203 *nanosec = div1 * div2 * i8253_osc_base;
204
205 *d1 = div1 & 0xffff;
206 *d2 = div2 & 0xffff;
207 return;
208}
209
210#ifndef CMDTEST
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231#define i8254_control_reg 3
232
233static inline int i8254_load(unsigned long base_address, unsigned int regshift,
234 unsigned int counter_number, unsigned int count,
235 unsigned int mode)
236{
237 unsigned int byte;
238
239 if (counter_number > 2)
240 return -1;
241 if (count > 0xffff)
242 return -1;
243 if (mode > 5)
244 return -1;
245 if ((mode == 2 || mode == 3) && count == 1)
246 return -1;
247
248 byte = counter_number << 6;
249 byte |= 0x30;
250 byte |= (mode << 1);
251 outb(byte, base_address + (i8254_control_reg << regshift));
252 byte = count & 0xff;
253 outb(byte, base_address + (counter_number << regshift));
254 byte = (count >> 8) & 0xff;
255 outb(byte, base_address + (counter_number << regshift));
256
257 return 0;
258}
259
260static inline int i8254_mm_load(void __iomem *base_address,
261 unsigned int regshift,
262 unsigned int counter_number,
263 unsigned int count,
264 unsigned int mode)
265{
266 unsigned int byte;
267
268 if (counter_number > 2)
269 return -1;
270 if (count > 0xffff)
271 return -1;
272 if (mode > 5)
273 return -1;
274 if ((mode == 2 || mode == 3) && count == 1)
275 return -1;
276
277 byte = counter_number << 6;
278 byte |= 0x30;
279 byte |= (mode << 1);
280 writeb(byte, base_address + (i8254_control_reg << regshift));
281 byte = count & 0xff;
282 writeb(byte, base_address + (counter_number << regshift));
283 byte = (count >> 8) & 0xff;
284 writeb(byte, base_address + (counter_number << regshift));
285
286 return 0;
287}
288
289
290static inline int i8254_read(unsigned long base_address, unsigned int regshift,
291 unsigned int counter_number)
292{
293 unsigned int byte;
294 int ret;
295
296 if (counter_number > 2)
297 return -1;
298
299
300 byte = counter_number << 6;
301 outb(byte, base_address + (i8254_control_reg << regshift));
302
303
304 ret = inb(base_address + (counter_number << regshift));
305
306 ret += inb(base_address + (counter_number << regshift)) << 8;
307
308 return ret;
309}
310
311static inline int i8254_mm_read(void __iomem *base_address,
312 unsigned int regshift,
313 unsigned int counter_number)
314{
315 unsigned int byte;
316 int ret;
317
318 if (counter_number > 2)
319 return -1;
320
321
322 byte = counter_number << 6;
323 writeb(byte, base_address + (i8254_control_reg << regshift));
324
325
326 ret = readb(base_address + (counter_number << regshift));
327
328 ret += readb(base_address + (counter_number << regshift)) << 8;
329
330 return ret;
331}
332
333
334static inline void i8254_write(unsigned long base_address,
335 unsigned int regshift,
336 unsigned int counter_number, unsigned int count)
337{
338 unsigned int byte;
339
340 if (counter_number > 2)
341 return;
342
343 byte = count & 0xff;
344 outb(byte, base_address + (counter_number << regshift));
345 byte = (count >> 8) & 0xff;
346 outb(byte, base_address + (counter_number << regshift));
347}
348
349static inline void i8254_mm_write(void __iomem *base_address,
350 unsigned int regshift,
351 unsigned int counter_number,
352 unsigned int count)
353{
354 unsigned int byte;
355
356 if (counter_number > 2)
357 return;
358
359 byte = count & 0xff;
360 writeb(byte, base_address + (counter_number << regshift));
361 byte = (count >> 8) & 0xff;
362 writeb(byte, base_address + (counter_number << regshift));
363}
364
365
366
367
368
369
370
371
372static inline int i8254_set_mode(unsigned long base_address,
373 unsigned int regshift,
374 unsigned int counter_number, unsigned int mode)
375{
376 unsigned int byte;
377
378 if (counter_number > 2)
379 return -1;
380 if (mode > (I8254_MODE5 | I8254_BINARY))
381 return -1;
382
383 byte = counter_number << 6;
384 byte |= 0x30;
385 byte |= mode;
386 outb(byte, base_address + (i8254_control_reg << regshift));
387
388 return 0;
389}
390
391static inline int i8254_mm_set_mode(void __iomem *base_address,
392 unsigned int regshift,
393 unsigned int counter_number,
394 unsigned int mode)
395{
396 unsigned int byte;
397
398 if (counter_number > 2)
399 return -1;
400 if (mode > (I8254_MODE5 | I8254_BINARY))
401 return -1;
402
403 byte = counter_number << 6;
404 byte |= 0x30;
405 byte |= mode;
406 writeb(byte, base_address + (i8254_control_reg << regshift));
407
408 return 0;
409}
410
411static inline int i8254_status(unsigned long base_address,
412 unsigned int regshift,
413 unsigned int counter_number)
414{
415 outb(0xE0 | (2 << counter_number),
416 base_address + (i8254_control_reg << regshift));
417 return inb(base_address + (counter_number << regshift));
418}
419
420static inline int i8254_mm_status(void __iomem *base_address,
421 unsigned int regshift,
422 unsigned int counter_number)
423{
424 writeb(0xE0 | (2 << counter_number),
425 base_address + (i8254_control_reg << regshift));
426 return readb(base_address + (counter_number << regshift));
427}
428
429#endif
430
431#endif
432