diff options
author | Jarod Wilson <jarod@redhat.com> | 2010-07-26 19:30:51 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-08-02 15:43:27 -0400 |
commit | 805a8966659563df68ea7bbd94241dafd645c725 (patch) | |
tree | b5ca7656f9c67f3d0ec6e98729c633b5e9d665fd /drivers | |
parent | c147f9078a6fca5b43b6e9e4b7b6a99b50c6e2bb (diff) |
V4L/DVB: staging/lirc: add lirc_parallel driver
Signed-off-by: Jarod Wilson <jarod@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/staging/lirc/lirc_parallel.c | 705 | ||||
-rw-r--r-- | drivers/staging/lirc/lirc_parallel.h | 26 |
2 files changed, 731 insertions, 0 deletions
diff --git a/drivers/staging/lirc/lirc_parallel.c b/drivers/staging/lirc/lirc_parallel.c new file mode 100644 index 000000000000..df12e7bd3f96 --- /dev/null +++ b/drivers/staging/lirc/lirc_parallel.c | |||
@@ -0,0 +1,705 @@ | |||
1 | /* | ||
2 | * lirc_parallel.c | ||
3 | * | ||
4 | * lirc_parallel - device driver for infra-red signal receiving and | ||
5 | * transmitting unit built by the author | ||
6 | * | ||
7 | * Copyright (C) 1998 Christoph Bartelmus <lirc@bartelmus.de> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | /*** Includes ***/ | ||
26 | |||
27 | #ifdef CONFIG_SMP | ||
28 | #error "--- Sorry, this driver is not SMP safe. ---" | ||
29 | #endif | ||
30 | |||
31 | #include <linux/module.h> | ||
32 | #include <linux/sched.h> | ||
33 | #include <linux/errno.h> | ||
34 | #include <linux/signal.h> | ||
35 | #include <linux/fs.h> | ||
36 | #include <linux/kernel.h> | ||
37 | #include <linux/ioport.h> | ||
38 | #include <linux/time.h> | ||
39 | #include <linux/mm.h> | ||
40 | #include <linux/delay.h> | ||
41 | |||
42 | #include <linux/io.h> | ||
43 | #include <linux/signal.h> | ||
44 | #include <linux/irq.h> | ||
45 | #include <linux/uaccess.h> | ||
46 | #include <asm/div64.h> | ||
47 | |||
48 | #include <linux/poll.h> | ||
49 | #include <linux/parport.h> | ||
50 | |||
51 | #include <media/lirc.h> | ||
52 | #include <media/lirc_dev.h> | ||
53 | |||
54 | #include "lirc_parallel.h" | ||
55 | |||
56 | #define LIRC_DRIVER_NAME "lirc_parallel" | ||
57 | |||
58 | #ifndef LIRC_IRQ | ||
59 | #define LIRC_IRQ 7 | ||
60 | #endif | ||
61 | #ifndef LIRC_PORT | ||
62 | #define LIRC_PORT 0x378 | ||
63 | #endif | ||
64 | #ifndef LIRC_TIMER | ||
65 | #define LIRC_TIMER 65536 | ||
66 | #endif | ||
67 | |||
68 | /*** Global Variables ***/ | ||
69 | |||
70 | static int debug; | ||
71 | static int check_pselecd; | ||
72 | |||
73 | unsigned int irq = LIRC_IRQ; | ||
74 | unsigned int io = LIRC_PORT; | ||
75 | #ifdef LIRC_TIMER | ||
76 | unsigned int timer; | ||
77 | unsigned int default_timer = LIRC_TIMER; | ||
78 | #endif | ||
79 | |||
80 | #define RBUF_SIZE (256) /* this must be a power of 2 larger than 1 */ | ||
81 | |||
82 | static int rbuf[RBUF_SIZE]; | ||
83 | |||
84 | DECLARE_WAIT_QUEUE_HEAD(lirc_wait); | ||
85 | |||
86 | unsigned int rptr; | ||
87 | unsigned int wptr; | ||
88 | unsigned int lost_irqs; | ||
89 | int is_open; | ||
90 | |||
91 | struct parport *pport; | ||
92 | struct pardevice *ppdevice; | ||
93 | int is_claimed; | ||
94 | |||
95 | unsigned int tx_mask = 1; | ||
96 | |||
97 | /*** Internal Functions ***/ | ||
98 | |||
99 | static unsigned int in(int offset) | ||
100 | { | ||
101 | switch (offset) { | ||
102 | case LIRC_LP_BASE: | ||
103 | return parport_read_data(pport); | ||
104 | case LIRC_LP_STATUS: | ||
105 | return parport_read_status(pport); | ||
106 | case LIRC_LP_CONTROL: | ||
107 | return parport_read_control(pport); | ||
108 | } | ||
109 | return 0; /* make compiler happy */ | ||
110 | } | ||
111 | |||
112 | static void out(int offset, int value) | ||
113 | { | ||
114 | switch (offset) { | ||
115 | case LIRC_LP_BASE: | ||
116 | parport_write_data(pport, value); | ||
117 | break; | ||
118 | case LIRC_LP_CONTROL: | ||
119 | parport_write_control(pport, value); | ||
120 | break; | ||
121 | case LIRC_LP_STATUS: | ||
122 | printk(KERN_INFO "%s: attempt to write to status register\n", | ||
123 | LIRC_DRIVER_NAME); | ||
124 | break; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | static unsigned int lirc_get_timer(void) | ||
129 | { | ||
130 | return in(LIRC_PORT_TIMER) & LIRC_PORT_TIMER_BIT; | ||
131 | } | ||
132 | |||
133 | static unsigned int lirc_get_signal(void) | ||
134 | { | ||
135 | return in(LIRC_PORT_SIGNAL) & LIRC_PORT_SIGNAL_BIT; | ||
136 | } | ||
137 | |||
138 | static void lirc_on(void) | ||
139 | { | ||
140 | out(LIRC_PORT_DATA, tx_mask); | ||
141 | } | ||
142 | |||
143 | static void lirc_off(void) | ||
144 | { | ||
145 | out(LIRC_PORT_DATA, 0); | ||
146 | } | ||
147 | |||
148 | static unsigned int init_lirc_timer(void) | ||
149 | { | ||
150 | struct timeval tv, now; | ||
151 | unsigned int level, newlevel, timeelapsed, newtimer; | ||
152 | int count = 0; | ||
153 | |||
154 | do_gettimeofday(&tv); | ||
155 | tv.tv_sec++; /* wait max. 1 sec. */ | ||
156 | level = lirc_get_timer(); | ||
157 | do { | ||
158 | newlevel = lirc_get_timer(); | ||
159 | if (level == 0 && newlevel != 0) | ||
160 | count++; | ||
161 | level = newlevel; | ||
162 | do_gettimeofday(&now); | ||
163 | } while (count < 1000 && (now.tv_sec < tv.tv_sec | ||
164 | || (now.tv_sec == tv.tv_sec | ||
165 | && now.tv_usec < tv.tv_usec))); | ||
166 | |||
167 | timeelapsed = ((now.tv_sec + 1 - tv.tv_sec)*1000000 | ||
168 | + (now.tv_usec - tv.tv_usec)); | ||
169 | if (count >= 1000 && timeelapsed > 0) { | ||
170 | if (default_timer == 0) { | ||
171 | /* autodetect timer */ | ||
172 | newtimer = (1000000*count)/timeelapsed; | ||
173 | printk(KERN_INFO "%s: %u Hz timer detected\n", | ||
174 | LIRC_DRIVER_NAME, newtimer); | ||
175 | return newtimer; | ||
176 | } else { | ||
177 | newtimer = (1000000*count)/timeelapsed; | ||
178 | if (abs(newtimer - default_timer) > default_timer/10) { | ||
179 | /* bad timer */ | ||
180 | printk(KERN_NOTICE "%s: bad timer: %u Hz\n", | ||
181 | LIRC_DRIVER_NAME, newtimer); | ||
182 | printk(KERN_NOTICE "%s: using default timer: " | ||
183 | "%u Hz\n", | ||
184 | LIRC_DRIVER_NAME, default_timer); | ||
185 | return default_timer; | ||
186 | } else { | ||
187 | printk(KERN_INFO "%s: %u Hz timer detected\n", | ||
188 | LIRC_DRIVER_NAME, newtimer); | ||
189 | return newtimer; /* use detected value */ | ||
190 | } | ||
191 | } | ||
192 | } else { | ||
193 | printk(KERN_NOTICE "%s: no timer detected\n", LIRC_DRIVER_NAME); | ||
194 | return 0; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | static int lirc_claim(void) | ||
199 | { | ||
200 | if (parport_claim(ppdevice) != 0) { | ||
201 | printk(KERN_WARNING "%s: could not claim port\n", | ||
202 | LIRC_DRIVER_NAME); | ||
203 | printk(KERN_WARNING "%s: waiting for port becoming available" | ||
204 | "\n", LIRC_DRIVER_NAME); | ||
205 | if (parport_claim_or_block(ppdevice) < 0) { | ||
206 | printk(KERN_NOTICE "%s: could not claim port, giving" | ||
207 | " up\n", LIRC_DRIVER_NAME); | ||
208 | return 0; | ||
209 | } | ||
210 | } | ||
211 | out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP); | ||
212 | is_claimed = 1; | ||
213 | return 1; | ||
214 | } | ||
215 | |||
216 | /*** interrupt handler ***/ | ||
217 | |||
218 | static void rbuf_write(int signal) | ||
219 | { | ||
220 | unsigned int nwptr; | ||
221 | |||
222 | nwptr = (wptr + 1) & (RBUF_SIZE - 1); | ||
223 | if (nwptr == rptr) { | ||
224 | /* no new signals will be accepted */ | ||
225 | lost_irqs++; | ||
226 | printk(KERN_NOTICE "%s: buffer overrun\n", LIRC_DRIVER_NAME); | ||
227 | return; | ||
228 | } | ||
229 | rbuf[wptr] = signal; | ||
230 | wptr = nwptr; | ||
231 | } | ||
232 | |||
233 | static void irq_handler(void *blah) | ||
234 | { | ||
235 | struct timeval tv; | ||
236 | static struct timeval lasttv; | ||
237 | static int init; | ||
238 | long signal; | ||
239 | int data; | ||
240 | unsigned int level, newlevel; | ||
241 | unsigned int timeout; | ||
242 | |||
243 | if (!module_refcount(THIS_MODULE)) | ||
244 | return; | ||
245 | |||
246 | if (!is_claimed) | ||
247 | return; | ||
248 | |||
249 | #if 0 | ||
250 | /* disable interrupt */ | ||
251 | disable_irq(irq); | ||
252 | out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ) & (~LP_PINTEN)); | ||
253 | #endif | ||
254 | if (check_pselecd && (in(1) & LP_PSELECD)) | ||
255 | return; | ||
256 | |||
257 | #ifdef LIRC_TIMER | ||
258 | if (init) { | ||
259 | do_gettimeofday(&tv); | ||
260 | |||
261 | signal = tv.tv_sec - lasttv.tv_sec; | ||
262 | if (signal > 15) | ||
263 | /* really long time */ | ||
264 | data = PULSE_MASK; | ||
265 | else | ||
266 | data = (int) (signal*1000000 + | ||
267 | tv.tv_usec - lasttv.tv_usec + | ||
268 | LIRC_SFH506_DELAY); | ||
269 | |||
270 | rbuf_write(data); /* space */ | ||
271 | } else { | ||
272 | if (timer == 0) { | ||
273 | /* | ||
274 | * wake up; we'll lose this signal, but it will be | ||
275 | * garbage if the device is turned on anyway | ||
276 | */ | ||
277 | timer = init_lirc_timer(); | ||
278 | /* enable_irq(irq); */ | ||
279 | return; | ||
280 | } | ||
281 | init = 1; | ||
282 | } | ||
283 | |||
284 | timeout = timer/10; /* timeout after 1/10 sec. */ | ||
285 | signal = 1; | ||
286 | level = lirc_get_timer(); | ||
287 | do { | ||
288 | newlevel = lirc_get_timer(); | ||
289 | if (level == 0 && newlevel != 0) | ||
290 | signal++; | ||
291 | level = newlevel; | ||
292 | |||
293 | /* giving up */ | ||
294 | if (signal > timeout | ||
295 | || (check_pselecd && (in(1) & LP_PSELECD))) { | ||
296 | signal = 0; | ||
297 | printk(KERN_NOTICE "%s: timeout\n", LIRC_DRIVER_NAME); | ||
298 | break; | ||
299 | } | ||
300 | } while (lirc_get_signal()); | ||
301 | |||
302 | if (signal != 0) { | ||
303 | /* ajust value to usecs */ | ||
304 | unsigned long long helper; | ||
305 | |||
306 | helper = ((unsigned long long) signal)*1000000; | ||
307 | do_div(helper, timer); | ||
308 | signal = (long) helper; | ||
309 | |||
310 | if (signal > LIRC_SFH506_DELAY) | ||
311 | data = signal - LIRC_SFH506_DELAY; | ||
312 | else | ||
313 | data = 1; | ||
314 | rbuf_write(PULSE_BIT|data); /* pulse */ | ||
315 | } | ||
316 | do_gettimeofday(&lasttv); | ||
317 | #else | ||
318 | /* add your code here */ | ||
319 | #endif | ||
320 | |||
321 | wake_up_interruptible(&lirc_wait); | ||
322 | |||
323 | /* enable interrupt */ | ||
324 | /* | ||
325 | enable_irq(irq); | ||
326 | out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ)|LP_PINTEN); | ||
327 | */ | ||
328 | } | ||
329 | |||
330 | /*** file operations ***/ | ||
331 | |||
332 | static loff_t lirc_lseek(struct file *filep, loff_t offset, int orig) | ||
333 | { | ||
334 | return -ESPIPE; | ||
335 | } | ||
336 | |||
337 | static ssize_t lirc_read(struct file *filep, char *buf, size_t n, loff_t *ppos) | ||
338 | { | ||
339 | int result = 0; | ||
340 | int count = 0; | ||
341 | DECLARE_WAITQUEUE(wait, current); | ||
342 | |||
343 | if (n % sizeof(int)) | ||
344 | return -EINVAL; | ||
345 | |||
346 | add_wait_queue(&lirc_wait, &wait); | ||
347 | set_current_state(TASK_INTERRUPTIBLE); | ||
348 | while (count < n) { | ||
349 | if (rptr != wptr) { | ||
350 | if (copy_to_user(buf+count, (char *) &rbuf[rptr], | ||
351 | sizeof(int))) { | ||
352 | result = -EFAULT; | ||
353 | break; | ||
354 | } | ||
355 | rptr = (rptr + 1) & (RBUF_SIZE - 1); | ||
356 | count += sizeof(int); | ||
357 | } else { | ||
358 | if (filep->f_flags & O_NONBLOCK) { | ||
359 | result = -EAGAIN; | ||
360 | break; | ||
361 | } | ||
362 | if (signal_pending(current)) { | ||
363 | result = -ERESTARTSYS; | ||
364 | break; | ||
365 | } | ||
366 | schedule(); | ||
367 | set_current_state(TASK_INTERRUPTIBLE); | ||
368 | } | ||
369 | } | ||
370 | remove_wait_queue(&lirc_wait, &wait); | ||
371 | set_current_state(TASK_RUNNING); | ||
372 | return count ? count : result; | ||
373 | } | ||
374 | |||
375 | static ssize_t lirc_write(struct file *filep, const char *buf, size_t n, | ||
376 | loff_t *ppos) | ||
377 | { | ||
378 | int count; | ||
379 | unsigned int i; | ||
380 | unsigned int level, newlevel; | ||
381 | unsigned long flags; | ||
382 | int counttimer; | ||
383 | int *wbuf; | ||
384 | |||
385 | if (!is_claimed) | ||
386 | return -EBUSY; | ||
387 | |||
388 | count = n / sizeof(int); | ||
389 | |||
390 | if (n % sizeof(int) || count % 2 == 0) | ||
391 | return -EINVAL; | ||
392 | |||
393 | wbuf = memdup_user(buf, n); | ||
394 | if (IS_ERR(wbuf)) | ||
395 | return PTR_ERR(wbuf); | ||
396 | |||
397 | #ifdef LIRC_TIMER | ||
398 | if (timer == 0) { | ||
399 | /* try again if device is ready */ | ||
400 | timer = init_lirc_timer(); | ||
401 | if (timer == 0) | ||
402 | return -EIO; | ||
403 | } | ||
404 | |||
405 | /* adjust values from usecs */ | ||
406 | for (i = 0; i < count; i++) { | ||
407 | unsigned long long helper; | ||
408 | |||
409 | helper = ((unsigned long long) wbuf[i])*timer; | ||
410 | do_div(helper, 1000000); | ||
411 | wbuf[i] = (int) helper; | ||
412 | } | ||
413 | |||
414 | local_irq_save(flags); | ||
415 | i = 0; | ||
416 | while (i < count) { | ||
417 | level = lirc_get_timer(); | ||
418 | counttimer = 0; | ||
419 | lirc_on(); | ||
420 | do { | ||
421 | newlevel = lirc_get_timer(); | ||
422 | if (level == 0 && newlevel != 0) | ||
423 | counttimer++; | ||
424 | level = newlevel; | ||
425 | if (check_pselecd && (in(1) & LP_PSELECD)) { | ||
426 | lirc_off(); | ||
427 | local_irq_restore(flags); | ||
428 | return -EIO; | ||
429 | } | ||
430 | } while (counttimer < wbuf[i]); | ||
431 | i++; | ||
432 | |||
433 | lirc_off(); | ||
434 | if (i == count) | ||
435 | break; | ||
436 | counttimer = 0; | ||
437 | do { | ||
438 | newlevel = lirc_get_timer(); | ||
439 | if (level == 0 && newlevel != 0) | ||
440 | counttimer++; | ||
441 | level = newlevel; | ||
442 | if (check_pselecd && (in(1) & LP_PSELECD)) { | ||
443 | local_irq_restore(flags); | ||
444 | return -EIO; | ||
445 | } | ||
446 | } while (counttimer < wbuf[i]); | ||
447 | i++; | ||
448 | } | ||
449 | local_irq_restore(flags); | ||
450 | #else | ||
451 | /* place code that handles write without external timer here */ | ||
452 | #endif | ||
453 | return n; | ||
454 | } | ||
455 | |||
456 | static unsigned int lirc_poll(struct file *file, poll_table *wait) | ||
457 | { | ||
458 | poll_wait(file, &lirc_wait, wait); | ||
459 | if (rptr != wptr) | ||
460 | return POLLIN | POLLRDNORM; | ||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) | ||
465 | { | ||
466 | int result; | ||
467 | unsigned long features = LIRC_CAN_SET_TRANSMITTER_MASK | | ||
468 | LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2; | ||
469 | unsigned long mode; | ||
470 | unsigned int ivalue; | ||
471 | |||
472 | switch (cmd) { | ||
473 | case LIRC_GET_FEATURES: | ||
474 | result = put_user(features, (unsigned long *) arg); | ||
475 | if (result) | ||
476 | return result; | ||
477 | break; | ||
478 | case LIRC_GET_SEND_MODE: | ||
479 | result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg); | ||
480 | if (result) | ||
481 | return result; | ||
482 | break; | ||
483 | case LIRC_GET_REC_MODE: | ||
484 | result = put_user(LIRC_MODE_MODE2, (unsigned long *) arg); | ||
485 | if (result) | ||
486 | return result; | ||
487 | break; | ||
488 | case LIRC_SET_SEND_MODE: | ||
489 | result = get_user(mode, (unsigned long *) arg); | ||
490 | if (result) | ||
491 | return result; | ||
492 | if (mode != LIRC_MODE_PULSE) | ||
493 | return -EINVAL; | ||
494 | break; | ||
495 | case LIRC_SET_REC_MODE: | ||
496 | result = get_user(mode, (unsigned long *) arg); | ||
497 | if (result) | ||
498 | return result; | ||
499 | if (mode != LIRC_MODE_MODE2) | ||
500 | return -ENOSYS; | ||
501 | break; | ||
502 | case LIRC_SET_TRANSMITTER_MASK: | ||
503 | result = get_user(ivalue, (unsigned int *) arg); | ||
504 | if (result) | ||
505 | return result; | ||
506 | if ((ivalue & LIRC_PARALLEL_TRANSMITTER_MASK) != ivalue) | ||
507 | return LIRC_PARALLEL_MAX_TRANSMITTERS; | ||
508 | tx_mask = ivalue; | ||
509 | break; | ||
510 | default: | ||
511 | return -ENOIOCTLCMD; | ||
512 | } | ||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | static int lirc_open(struct inode *node, struct file *filep) | ||
517 | { | ||
518 | if (module_refcount(THIS_MODULE) || !lirc_claim()) | ||
519 | return -EBUSY; | ||
520 | |||
521 | parport_enable_irq(pport); | ||
522 | |||
523 | /* init read ptr */ | ||
524 | rptr = 0; | ||
525 | wptr = 0; | ||
526 | lost_irqs = 0; | ||
527 | |||
528 | is_open = 1; | ||
529 | return 0; | ||
530 | } | ||
531 | |||
532 | static int lirc_close(struct inode *node, struct file *filep) | ||
533 | { | ||
534 | if (is_claimed) { | ||
535 | is_claimed = 0; | ||
536 | parport_release(ppdevice); | ||
537 | } | ||
538 | is_open = 0; | ||
539 | return 0; | ||
540 | } | ||
541 | |||
542 | static struct file_operations lirc_fops = { | ||
543 | .owner = THIS_MODULE, | ||
544 | .llseek = lirc_lseek, | ||
545 | .read = lirc_read, | ||
546 | .write = lirc_write, | ||
547 | .poll = lirc_poll, | ||
548 | .unlocked_ioctl = lirc_ioctl, | ||
549 | .open = lirc_open, | ||
550 | .release = lirc_close | ||
551 | }; | ||
552 | |||
553 | static int set_use_inc(void *data) | ||
554 | { | ||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | static void set_use_dec(void *data) | ||
559 | { | ||
560 | } | ||
561 | |||
562 | static struct lirc_driver driver = { | ||
563 | .name = LIRC_DRIVER_NAME, | ||
564 | .minor = -1, | ||
565 | .code_length = 1, | ||
566 | .sample_rate = 0, | ||
567 | .data = NULL, | ||
568 | .add_to_buf = NULL, | ||
569 | .set_use_inc = set_use_inc, | ||
570 | .set_use_dec = set_use_dec, | ||
571 | .fops = &lirc_fops, | ||
572 | .dev = NULL, | ||
573 | .owner = THIS_MODULE, | ||
574 | }; | ||
575 | |||
576 | static int pf(void *handle); | ||
577 | static void kf(void *handle); | ||
578 | |||
579 | static struct timer_list poll_timer; | ||
580 | static void poll_state(unsigned long ignored); | ||
581 | |||
582 | static void poll_state(unsigned long ignored) | ||
583 | { | ||
584 | printk(KERN_NOTICE "%s: time\n", | ||
585 | LIRC_DRIVER_NAME); | ||
586 | del_timer(&poll_timer); | ||
587 | if (is_claimed) | ||
588 | return; | ||
589 | kf(NULL); | ||
590 | if (!is_claimed) { | ||
591 | printk(KERN_NOTICE "%s: could not claim port, giving up\n", | ||
592 | LIRC_DRIVER_NAME); | ||
593 | init_timer(&poll_timer); | ||
594 | poll_timer.expires = jiffies + HZ; | ||
595 | poll_timer.data = (unsigned long)current; | ||
596 | poll_timer.function = poll_state; | ||
597 | add_timer(&poll_timer); | ||
598 | } | ||
599 | } | ||
600 | |||
601 | static int pf(void *handle) | ||
602 | { | ||
603 | parport_disable_irq(pport); | ||
604 | is_claimed = 0; | ||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | static void kf(void *handle) | ||
609 | { | ||
610 | if (!is_open) | ||
611 | return; | ||
612 | if (!lirc_claim()) | ||
613 | return; | ||
614 | parport_enable_irq(pport); | ||
615 | lirc_off(); | ||
616 | /* this is a bit annoying when you actually print...*/ | ||
617 | /* | ||
618 | printk(KERN_INFO "%s: reclaimed port\n", LIRC_DRIVER_NAME); | ||
619 | */ | ||
620 | } | ||
621 | |||
622 | /*** module initialization and cleanup ***/ | ||
623 | |||
624 | static int __init lirc_parallel_init(void) | ||
625 | { | ||
626 | pport = parport_find_base(io); | ||
627 | if (pport == NULL) { | ||
628 | printk(KERN_NOTICE "%s: no port at %x found\n", | ||
629 | LIRC_DRIVER_NAME, io); | ||
630 | return -ENXIO; | ||
631 | } | ||
632 | ppdevice = parport_register_device(pport, LIRC_DRIVER_NAME, | ||
633 | pf, kf, irq_handler, 0, NULL); | ||
634 | parport_put_port(pport); | ||
635 | if (ppdevice == NULL) { | ||
636 | printk(KERN_NOTICE "%s: parport_register_device() failed\n", | ||
637 | LIRC_DRIVER_NAME); | ||
638 | return -ENXIO; | ||
639 | } | ||
640 | if (parport_claim(ppdevice) != 0) | ||
641 | goto skip_init; | ||
642 | is_claimed = 1; | ||
643 | out(LIRC_LP_CONTROL, LP_PSELECP|LP_PINITP); | ||
644 | |||
645 | #ifdef LIRC_TIMER | ||
646 | if (debug) | ||
647 | out(LIRC_PORT_DATA, tx_mask); | ||
648 | |||
649 | timer = init_lirc_timer(); | ||
650 | |||
651 | #if 0 /* continue even if device is offline */ | ||
652 | if (timer == 0) { | ||
653 | is_claimed = 0; | ||
654 | parport_release(pport); | ||
655 | parport_unregister_device(ppdevice); | ||
656 | return -EIO; | ||
657 | } | ||
658 | |||
659 | #endif | ||
660 | if (debug) | ||
661 | out(LIRC_PORT_DATA, 0); | ||
662 | #endif | ||
663 | |||
664 | is_claimed = 0; | ||
665 | parport_release(ppdevice); | ||
666 | skip_init: | ||
667 | driver.minor = lirc_register_driver(&driver); | ||
668 | if (driver.minor < 0) { | ||
669 | printk(KERN_NOTICE "%s: register_chrdev() failed\n", | ||
670 | LIRC_DRIVER_NAME); | ||
671 | parport_unregister_device(ppdevice); | ||
672 | return -EIO; | ||
673 | } | ||
674 | printk(KERN_INFO "%s: installed using port 0x%04x irq %d\n", | ||
675 | LIRC_DRIVER_NAME, io, irq); | ||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | static void __exit lirc_parallel_exit(void) | ||
680 | { | ||
681 | parport_unregister_device(ppdevice); | ||
682 | lirc_unregister_driver(driver.minor); | ||
683 | } | ||
684 | |||
685 | module_init(lirc_parallel_init); | ||
686 | module_exit(lirc_parallel_exit); | ||
687 | |||
688 | MODULE_DESCRIPTION("Infrared receiver driver for parallel ports."); | ||
689 | MODULE_AUTHOR("Christoph Bartelmus"); | ||
690 | MODULE_LICENSE("GPL"); | ||
691 | |||
692 | module_param(io, int, S_IRUGO); | ||
693 | MODULE_PARM_DESC(io, "I/O address base (0x3bc, 0x378 or 0x278)"); | ||
694 | |||
695 | module_param(irq, int, S_IRUGO); | ||
696 | MODULE_PARM_DESC(irq, "Interrupt (7 or 5)"); | ||
697 | |||
698 | module_param(tx_mask, int, S_IRUGO); | ||
699 | MODULE_PARM_DESC(tx_maxk, "Transmitter mask (default: 0x01)"); | ||
700 | |||
701 | module_param(debug, bool, S_IRUGO | S_IWUSR); | ||
702 | MODULE_PARM_DESC(debug, "Enable debugging messages"); | ||
703 | |||
704 | module_param(check_pselecd, bool, S_IRUGO | S_IWUSR); | ||
705 | MODULE_PARM_DESC(debug, "Check for printer (default: 0)"); | ||
diff --git a/drivers/staging/lirc/lirc_parallel.h b/drivers/staging/lirc/lirc_parallel.h new file mode 100644 index 000000000000..4bed6afe0632 --- /dev/null +++ b/drivers/staging/lirc/lirc_parallel.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* lirc_parallel.h */ | ||
2 | |||
3 | #ifndef _LIRC_PARALLEL_H | ||
4 | #define _LIRC_PARALLEL_H | ||
5 | |||
6 | #include <linux/lp.h> | ||
7 | |||
8 | #define LIRC_PORT_LEN 3 | ||
9 | |||
10 | #define LIRC_LP_BASE 0 | ||
11 | #define LIRC_LP_STATUS 1 | ||
12 | #define LIRC_LP_CONTROL 2 | ||
13 | |||
14 | #define LIRC_PORT_DATA LIRC_LP_BASE /* base */ | ||
15 | #define LIRC_PORT_TIMER LIRC_LP_STATUS /* status port */ | ||
16 | #define LIRC_PORT_TIMER_BIT LP_PBUSY /* busy signal */ | ||
17 | #define LIRC_PORT_SIGNAL LIRC_LP_STATUS /* status port */ | ||
18 | #define LIRC_PORT_SIGNAL_BIT LP_PACK /* ack signal */ | ||
19 | #define LIRC_PORT_IRQ LIRC_LP_CONTROL /* control port */ | ||
20 | |||
21 | #define LIRC_SFH506_DELAY 0 /* delay t_phl in usecs */ | ||
22 | |||
23 | #define LIRC_PARALLEL_MAX_TRANSMITTERS 8 | ||
24 | #define LIRC_PARALLEL_TRANSMITTER_MASK ((1<<LIRC_PARALLEL_MAX_TRANSMITTERS) - 1) | ||
25 | |||
26 | #endif | ||