📄 lirc_sir.c
字号:
value = LIRC_MODE_MODE2;#endif switch (cmd) { case LIRC_GET_FEATURES: case LIRC_GET_SEND_MODE: case LIRC_GET_REC_MODE:#ifdef KERNEL_2_0 retval = verify_area(VERIFY_WRITE, (unsigned long *) arg, sizeof(unsigned long)); if (retval) break;#else retval =#endif put_user(value, (unsigned long *) arg); break; case LIRC_SET_SEND_MODE: case LIRC_SET_REC_MODE:#ifdef KERNEL_2_0 retval = verify_area(VERIFY_READ, (unsigned long *) arg, sizeof(unsigned long)); if (retval) break; value = get_user((unsigned long *) arg);#else retval = get_user(value, (unsigned long *) arg);#endif break;#ifdef LIRC_ON_SA1100 case LIRC_SET_SEND_DUTY_CYCLE:# ifdef KERNEL_2_1 retval=get_user(ivalue,(unsigned int *) arg); if(retval) return(retval);# else retval=verify_area(VERIFY_READ,(unsigned int *) arg, sizeof(unsigned int)); if(result) return(result); ivalue=get_user((unsigned int *) arg);# endif if(ivalue<=0 || ivalue>100) return(-EINVAL); /* (ivalue/100)*(1000000/freq) */ duty_cycle=ivalue; pulse_width=(unsigned long) duty_cycle*10000/freq; space_width=(unsigned long) 1000000L/freq-pulse_width; if(pulse_width>=LIRC_ON_SA1100_TRANSMITTER_LATENCY) pulse_width-=LIRC_ON_SA1100_TRANSMITTER_LATENCY; if(space_width>=LIRC_ON_SA1100_TRANSMITTER_LATENCY) space_width-=LIRC_ON_SA1100_TRANSMITTER_LATENCY; break; case LIRC_SET_SEND_CARRIER:# ifdef KERNEL_2_1 retval=get_user(ivalue,(unsigned int *) arg); if(retval) return(retval);# else retval=verify_area(VERIFY_READ,(unsigned int *) arg, sizeof(unsigned int)); if(retval) return(retval); ivalue=get_user((unsigned int *) arg);# endif if(ivalue>500000 || ivalue<20000) return(-EINVAL); freq=ivalue; pulse_width=(unsigned long) duty_cycle*10000/freq; space_width=(unsigned long) 1000000L/freq-pulse_width; if(pulse_width>=LIRC_ON_SA1100_TRANSMITTER_LATENCY) pulse_width-=LIRC_ON_SA1100_TRANSMITTER_LATENCY; if(space_width>=LIRC_ON_SA1100_TRANSMITTER_LATENCY) space_width-=LIRC_ON_SA1100_TRANSMITTER_LATENCY; break;#endif default: retval = -ENOIOCTLCMD; } if (retval) return retval; #ifdef LIRC_SIR_TEKRAM if (cmd == LIRC_SET_REC_MODE) { if (value != LIRC_MODE_MODE2) retval = -ENOSYS; } else if (cmd == LIRC_SET_SEND_MODE) { retval = -ENOSYS; }#else if (cmd == LIRC_SET_REC_MODE) { if (value != LIRC_MODE_MODE2) retval = -ENOSYS; } else if (cmd == LIRC_SET_SEND_MODE) { if (value != LIRC_MODE_PULSE) retval = -ENOSYS; }#endif return retval;}static void add_read_queue(int flag, unsigned long val){ unsigned int new_rx_tail; lirc_t newval;#ifdef DEBUG_SIGNAL printk(KERN_DEBUG LIRC_DRIVER_NAME ": add flag %d with val %lu\n", flag,val);#endif newval = val & PULSE_MASK; /* statistically pulses are ~TIME_CONST/2 too long: we could maybe make this more exactly but this is good enough */ if(flag) /* pulse */ { if(newval>TIME_CONST/2) { newval-=TIME_CONST/2; } else /* should not ever happen */ { newval=1; } newval|=PULSE_BIT; } else { newval+=TIME_CONST/2; } new_rx_tail = (rx_tail + 1) & (RBUF_LEN - 1); if (new_rx_tail == rx_head) {# ifdef DEBUG printk(KERN_WARNING LIRC_DRIVER_NAME ": Buffer overrun.\n");# endif return; } rx_buf[rx_tail] = newval; rx_tail = new_rx_tail; wake_up_interruptible(&lirc_read_queue);}static struct file_operations lirc_fops ={ read: lirc_read, write: lirc_write,#ifdef KERNEL_2_1 poll: lirc_poll,#else select: lirc_select,#endif ioctl: lirc_ioctl, open: lirc_open, release: lirc_close,};#ifdef MODULEint init_chrdev(void){ int retval; retval = register_chrdev(major, LIRC_DRIVER_NAME, &lirc_fops); if (retval < 0) { printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n"); return retval; } return 0;}static void drop_chrdev(void){ unregister_chrdev(major, LIRC_DRIVER_NAME);}#endif/* SECTION: Hardware */static long delta(struct timeval * tv1, struct timeval * tv2){ unsigned long deltv; deltv = tv2->tv_sec - tv1->tv_sec; if (deltv > 15) deltv = 0xFFFFFF; else deltv = deltv*1000000 + tv2->tv_usec - tv1->tv_usec; return deltv;}static void sir_timeout(unsigned long data) { /* if last received signal was a pulse, but receiving stopped within the 9 bit frame, we need to finish this pulse and simulate a signal change to from pulse to space. Otherwise upper layers will receive two sequences next time. */ unsigned long flags; unsigned long pulse_end; /* avoid interference with interrupt */ spin_lock_irqsave(&timer_lock, flags); if (last_value) {#ifndef LIRC_ON_SA1100 /* clear unread bits in UART and restart */ outb(UART_FCR_CLEAR_RCVR, io + UART_FCR);#endif /* determine 'virtual' pulse end: */ pulse_end = delta(&last_tv, &last_intr_tv);#ifdef DEBUG_SIGNAL printk(KERN_DEBUG LIRC_DRIVER_NAME ": timeout add %d for %lu usec\n",last_value,pulse_end);#endif add_read_queue(last_value,pulse_end); last_value = 0; last_tv=last_intr_tv; } spin_unlock_irqrestore(&timer_lock, flags); }static void sir_interrupt(int irq, void * dev_id, struct pt_regs * regs){ unsigned char data; struct timeval curr_tv; static unsigned long deltv;#ifdef LIRC_ON_SA1100 int status; static int n=0; //printk("interrupt\n"); status = Ser2UTSR0; /* * Deal with any receive errors first. The bytes in error may be * the only bytes in the receive FIFO, so we do this first. */ while (status & UTSR0_EIF) { int bstat; #ifdef DEBUG printk("EIF\n"); bstat = Ser2UTSR1; if (bstat & UTSR1_FRE) printk("frame error\n"); if (bstat & UTSR1_ROR) printk("receive fifo overrun\n"); if(bstat&UTSR1_PRE) printk("parity error\n");#endif bstat = Ser2UTDR; n++; status = Ser2UTSR0; } if (status & (UTSR0_RFS | UTSR0_RID)) { do_gettimeofday(&curr_tv); deltv = delta(&last_tv, &curr_tv); do {#ifdef DEBUG_SIGNAL printk(KERN_DEBUG LIRC_DRIVER_NAME": t %lu , d %d\n", deltintrtv,(int)data);#endif data=Ser2UTDR; //printk("data: %d\n",data); n++; } while(status&UTSR0_RID && /* do not empty fifo in order to get UTSR0_RID in any case */ Ser2UTSR1 & UTSR1_RNE); /* data ready */ if(status&UTSR0_RID) { //printk("add\n"); add_read_queue(0,deltv-n*TIME_CONST); /*space*/ add_read_queue(1,n*TIME_CONST); /*pulse*/ n=0; last_tv=curr_tv; } } if (status & UTSR0_TFS) { printk("transmit fifo not full, shouldn't ever happen\n"); } /* * We must clear certain bits. */ status &= (UTSR0_RID | UTSR0_RBB | UTSR0_REB); if (status) Ser2UTSR0 = status;#else unsigned long deltintrtv; unsigned long flags; int iir, lsr; while ((iir = inb(io + UART_IIR) & UART_IIR_ID)) { switch (iir&UART_IIR_ID) { /* FIXME toto treba preriedit */ case UART_IIR_MSI: (void) inb(io + UART_MSR); break; case UART_IIR_RLSI: (void) inb(io + UART_LSR); break; case UART_IIR_THRI:#if 0 if (lsr & UART_LSR_THRE) /* FIFO is empty */ outb(data, io + UART_TX)#endif break; case UART_IIR_RDI: /* avoid interference with timer */ spin_lock_irqsave(&timer_lock, flags); do { del_timer(&timerlist); data = inb(io + UART_RX); do_gettimeofday(&curr_tv); deltv = delta(&last_tv, &curr_tv); deltintrtv = delta(&last_intr_tv, &curr_tv);#ifdef DEBUG_SIGNAL printk(KERN_DEBUG LIRC_DRIVER_NAME": t %lu , d %d\n",deltintrtv,(int)data);#endif /* if nothing came in last 2 cycles, it was gap */ if (deltintrtv > TIME_CONST * 2) { if (last_value) {#ifdef DEBUG_SIGNAL printk(KERN_DEBUG LIRC_DRIVER_NAME ": GAP\n");#endif /* simulate signal change */ add_read_queue(last_value, deltv- deltintrtv); last_value = 0; last_tv.tv_sec = last_intr_tv.tv_sec; last_tv.tv_usec = last_intr_tv.tv_usec; deltv = deltintrtv; } } data = 1; if (data ^ last_value) { /* deltintrtv > 2*TIME_CONST, remember ? */ /* the other case is timeout */ add_read_queue(last_value, deltv-TIME_CONST); last_value = data; last_tv = curr_tv; if(last_tv.tv_usec>=TIME_CONST) { last_tv.tv_usec-=TIME_CONST; } else { last_tv.tv_sec--; last_tv.tv_usec+=1000000- TIME_CONST; } } last_intr_tv = curr_tv; if (data) { /* start timer for end of sequence detection */ timerlist.expires = jiffies + SIR_TIMEOUT; add_timer(&timerlist); } } while ((lsr = inb(io + UART_LSR)) & UART_LSR_DR); /* data ready */ spin_unlock_irqrestore(&timer_lock, flags); break; default: break; } }#endif}#ifdef LIRC_ON_SA1100void send_pulse(unsigned long length){ unsigned long k,delay; int flag; if(length==0) return; /* this won't give us the carrier frequency we really want due to integer arithmetic, but we can accept this inaccuracy */ for(k=flag=0;k<length;k+=delay,flag=!flag) { if(flag) { off(); delay=space_width; } else { on(); delay=pulse_width; } safe_udelay(delay); } off();}void send_space(unsigned long length){ if(length==0) return; off(); safe_udelay(length);}#elif defined(LIRC_SIR_TEKRAM)#elsestatic void send_space(unsigned long len){ safe_udelay(len);}static void send_pulse(unsigned long len){ long bytes_out = len / TIME_CONST; long time_left; if (!bytes_out) bytes_out++; time_left = (long)len - (long)bytes_out * (long)TIME_CONST; while (--bytes_out) { outb(PULSE, io + UART_TX); /* FIXME treba seriozne cakanie z drivers/char/serial.c */ while (!(inb(io + UART_LSR) & UART_LSR_THRE)); }#if 0 if (time_left > 0) safe_udelay(time_left);#endif}#endif#ifdef CONFIG_SA1100_COLLIEstatic inline int sa1100_irda_set_power_collie(int state){ if (state) { /* * 0 - off * 1 - short range, lowest power * 2 - medium range, medium power * 3 - maximum range, high power */ ucb1200_set_io_direction(TC35143_GPIO_IR_ON, TC35143_IODIR_OUTPUT); ucb1200_set_io(TC35143_GPIO_IR_ON, TC35143_IODAT_LOW); udelay(100); } else { /* OFF */ ucb1200_set_io_direction(TC35143_GPIO_IR_ON,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -