static unsigned int init_lirc_timer(void) { struct timeval tv, now; unsigned int level, newlevel, timeelapsed, newtimer; int count = 0; do_gettimeofday(&tv); tv.tv_sec++; /* wait max. 1 sec. */ level = lirc_get_timer(); do { newlevel = lirc_get_timer(); if (level == 0 && newlevel != 0) count++; level = newlevel; do_gettimeofday(&now); } while (count < 1000 && (now.tv_sec < tv.tv_sec || (now.tv_sec == tv.tv_sec && now.tv_usec < tv.tv_usec))); timeelapsed = ((now.tv_sec + 1 - tv.tv_sec)*1000000 + (now.tv_usec - tv.tv_usec)); if (count >= 1000 && timeelapsed > 0) { if (default_timer == 0) { /* autodetect timer */ newtimer = (1000000*count)/timeelapsed; printk(KERN_INFO "%s: %u Hz timer detected\n", LIRC_DRIVER_NAME, newtimer); return newtimer; } else { newtimer = (1000000*count)/timeelapsed; if (abs(newtimer - default_timer) > default_timer/10) { /* bad timer */ printk(KERN_NOTICE "%s: bad timer: %u Hz\n", LIRC_DRIVER_NAME, newtimer); printk(KERN_NOTICE "%s: using default timer: " "%u Hz\n", LIRC_DRIVER_NAME, default_timer); return default_timer; } else { printk(KERN_INFO "%s: %u Hz timer detected\n", LIRC_DRIVER_NAME, newtimer); return newtimer; /* use detected value */ } } } else { printk(KERN_NOTICE "%s: no timer detected\n", LIRC_DRIVER_NAME); return 0; } }
static unsigned int init_lirc_timer(void) { ktime_t kt, now, timeout; unsigned int level, newlevel, timeelapsed, newtimer; int count = 0; kt = ktime_get(); /* wait max. 1 sec. */ timeout = ktime_add_ns(kt, NSEC_PER_SEC); level = lirc_get_timer(); do { newlevel = lirc_get_timer(); if (level == 0 && newlevel != 0) count++; level = newlevel; now = ktime_get(); } while (count < 1000 && (ktime_before(now, timeout))); timeelapsed = ktime_us_delta(now, kt); if (count >= 1000 && timeelapsed > 0) { if (default_timer == 0) { /* autodetect timer */ newtimer = (1000000 * count) / timeelapsed; pr_info("%u Hz timer detected\n", newtimer); return newtimer; } newtimer = (1000000 * count) / timeelapsed; if (abs(newtimer - default_timer) > default_timer / 10) { /* bad timer */ pr_notice("bad timer: %u Hz\n", newtimer); pr_notice("using default timer: %u Hz\n", default_timer); return default_timer; } pr_info("%u Hz timer detected\n", newtimer); return newtimer; /* use detected value */ } pr_notice("no timer detected\n"); return 0; }
static ssize_t lirc_write(struct file *filep, const char __user *buf, size_t n, loff_t *ppos) { int count; unsigned int i; unsigned int level, newlevel; unsigned long flags; int counttimer; int *wbuf; ssize_t ret; if (!is_claimed) return -EBUSY; count = n / sizeof(int); if (n % sizeof(int) || count % 2 == 0) return -EINVAL; wbuf = memdup_user(buf, n); if (IS_ERR(wbuf)) return PTR_ERR(wbuf); #ifdef LIRC_TIMER if (timer == 0) { /* try again if device is ready */ timer = init_lirc_timer(); if (timer == 0) { ret = -EIO; goto out; } } /* adjust values from usecs */ for (i = 0; i < count; i++) { __u64 helper; helper = ((__u64) wbuf[i])*timer; do_div(helper, 1000000); wbuf[i] = (int) helper; } local_irq_save(flags); i = 0; while (i < count) { level = lirc_get_timer(); counttimer = 0; lirc_on(); do { newlevel = lirc_get_timer(); if (level == 0 && newlevel != 0) counttimer++; level = newlevel; if (check_pselecd && (in(1) & LP_PSELECD)) { lirc_off(); local_irq_restore(flags); ret = -EIO; goto out; } } while (counttimer < wbuf[i]); i++; lirc_off(); if (i == count) break; counttimer = 0; do { newlevel = lirc_get_timer(); if (level == 0 && newlevel != 0) counttimer++; level = newlevel; if (check_pselecd && (in(1) & LP_PSELECD)) { local_irq_restore(flags); ret = -EIO; goto out; } } while (counttimer < wbuf[i]); i++; } local_irq_restore(flags); #else /* place code that handles write without external timer here */ #endif ret = n; out: kfree(wbuf); return ret; }
static void lirc_lirc_irq_handler(void *blah) { struct timeval tv; static struct timeval lasttv; static int init; long signal; int data; unsigned int level, newlevel; unsigned int timeout; if (!is_open) return; if (!is_claimed) return; #if 0 /* disable interrupt */ disable_irq(irq); out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ) & (~LP_PINTEN)); #endif if (check_pselecd && (in(1) & LP_PSELECD)) return; #ifdef LIRC_TIMER if (init) { do_gettimeofday(&tv); signal = tv.tv_sec - lasttv.tv_sec; if (signal > 15) /* really long time */ data = PULSE_MASK; else data = (int) (signal*1000000 + tv.tv_usec - lasttv.tv_usec + LIRC_SFH506_DELAY); rbuf_write(data); /* space */ } else { if (timer == 0) { /* * wake up; we'll lose this signal, but it will be * garbage if the device is turned on anyway */ timer = init_lirc_timer(); /* enable_irq(irq); */ return; } init = 1; } timeout = timer/10; /* timeout after 1/10 sec. */ signal = 1; level = lirc_get_timer(); do { newlevel = lirc_get_timer(); if (level == 0 && newlevel != 0) signal++; level = newlevel; /* giving up */ if (signal > timeout || (check_pselecd && (in(1) & LP_PSELECD))) { signal = 0; pr_notice("timeout\n"); break; } } while (lirc_get_signal()); if (signal != 0) { /* adjust value to usecs */ __u64 helper; helper = ((__u64) signal)*1000000; do_div(helper, timer); signal = (long) helper; if (signal > LIRC_SFH506_DELAY) data = signal - LIRC_SFH506_DELAY; else data = 1; rbuf_write(PULSE_BIT|data); /* pulse */ } do_gettimeofday(&lasttv); #else /* add your code here */ #endif wake_up_interruptible(&lirc_wait); /* enable interrupt */ /* enable_irq(irq); out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ)|LP_PINTEN); */ }
static void irq_handler(void *blah) { struct timeval tv; static struct timeval lasttv; static int init; long signal; int data; unsigned int level, newlevel; unsigned int timeout; if (!is_open) return; if (!is_claimed) return; #if 0 disable_irq(irq); out(LIRC_PORT_IRQ, in(LIRC_PORT_IRQ) & (~LP_PINTEN)); #endif if (check_pselecd && (in(1) & LP_PSELECD)) return; #ifdef LIRC_TIMER if (init) { do_gettimeofday(&tv); signal = tv.tv_sec - lasttv.tv_sec; if (signal > 15) data = PULSE_MASK; else data = (int) (signal*1000000 + tv.tv_usec - lasttv.tv_usec + LIRC_SFH506_DELAY); rbuf_write(data); } else { if (timer == 0) { timer = init_lirc_timer(); return; } init = 1; } timeout = timer/10; signal = 1; level = lirc_get_timer(); do { newlevel = lirc_get_timer(); if (level == 0 && newlevel != 0) signal++; level = newlevel; if (signal > timeout || (check_pselecd && (in(1) & LP_PSELECD))) { signal = 0; printk(KERN_NOTICE "%s: timeout\n", LIRC_DRIVER_NAME); break; } } while (lirc_get_signal()); if (signal != 0) { __u64 helper; helper = ((__u64) signal)*1000000; do_div(helper, timer); signal = (long) helper; if (signal > LIRC_SFH506_DELAY) data = signal - LIRC_SFH506_DELAY; else data = 1; rbuf_write(PULSE_BIT|data); } do_gettimeofday(&lasttv); #else #endif wake_up_interruptible(&lirc_wait); }
static ssize_t lirc_write(struct file *filep, const char *buf, size_t n, loff_t *ppos) { int count; unsigned int i; unsigned int level, newlevel; unsigned long flags; lirc_t counttimer; if (!is_claimed) return -EBUSY; if (n % sizeof(lirc_t)) return -EINVAL; count = n / sizeof(lirc_t); if (count > WBUF_SIZE || count % 2 == 0) return -EINVAL; if (copy_from_user(wbuf, buf, n)) return -EFAULT; #ifdef LIRC_TIMER if (timer == 0) { /* try again if device is ready */ timer = init_lirc_timer(); if (timer == 0) return -EIO; } /* adjust values from usecs */ for (i = 0; i < count; i++) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) unsigned long long helper; helper = ((unsigned long long) wbuf[i])*timer; do_div(helper, 1000000); wbuf[i] = (lirc_t) helper; #else wbuf[i] = (lirc_t) (((double) wbuf[i])*timer/1000000); #endif } local_irq_save(flags); i = 0; while (i < count) { level = lirc_get_timer(); counttimer = 0; lirc_on(); do { newlevel = lirc_get_timer(); if (level == 0 && newlevel != 0) counttimer++; level = newlevel; if (check_pselecd && (in(1) & LP_PSELECD)) { lirc_off(); local_irq_restore(flags); return -EIO; } } while (counttimer < wbuf[i]); i++; lirc_off(); if (i == count) break; counttimer = 0; do { newlevel = lirc_get_timer(); if (level == 0 && newlevel != 0) counttimer++; level = newlevel; if (check_pselecd && (in(1) & LP_PSELECD)) { local_irq_restore(flags); return -EIO; } } while (counttimer < wbuf[i]); i++; } local_irq_restore(flags); #else /* place code that handles write without external timer here */ #endif return n; }