📄 lirc_serial.c
字号:
soutp(UART_TX,output); while(!(sinp(UART_LSR) & UART_LSR_THRE)); output=0x7f; i=0; } } if(i!=0) { soutp(UART_TX,output); while(!(sinp(UART_LSR) & UART_LSR_TEMT)); } if(i==0) { return((-rawbits)*10000/1152); } else { return((3-i)*3*10000/1152+(-rawbits)*10000/1152); }}long send_pulse_homebrew(unsigned long length){# ifdef USE_RDTSC unsigned long target, start, now;# else unsigned long actual, target, d;# endif int flag; if(length<=0) return 0; if(softcarrier) {# ifdef USE_RDTSC /* Version that uses Pentium rdtsc instruction to measure clocks */ /* Get going quick as we can */ rdtscl(start);on(); /* Convert length from microseconds to clocks */ length*=conv_us_to_clocks; /* And loop till time is up - flipping at right intervals */ now=start; target=pulse_width; flag=1; while((now-start)<length) { /* Delay till flip time */ do { rdtscl(now); } while ((now-start)<target); /* flip */ if(flag) { rdtscl(now);off(); target+=space_width; } else { rdtscl(now);on(); target+=pulse_width; } flag=!flag; } rdtscl(now); return(((now-start)-length)/conv_us_to_clocks); # else /* ! USE_RDTSC */ /* here we use fixed point arithmetic, with 8 fractional bits. that gets us within 0.1% or so of the right average frequency, albeit with some jitter in pulse length - Steve */ /* To match 8 fractional bits used for pulse/space length */ length<<=8; actual=target=0; flag=0; while(actual<length) { if(flag) { off(); target+=space_width; } else { on(); target+=pulse_width; } d=(target-actual-LIRC_SERIAL_TRANSMITTER_LATENCY+128)>>8; /* Note - we've checked in ioctl that the pulse/space widths are big enough so that d is > 0 */ udelay(d); actual+=(d<<8)+LIRC_SERIAL_TRANSMITTER_LATENCY; flag=!flag; } return((actual-length)>>8);# endif /* USE_RDTSC */ } else { on(); safe_udelay(length); return(0); }}void send_space_irdeo(long length){ if(length<=0) return; safe_udelay(length);}void send_space_homebrew(long length){ off(); if(length<=0) return; safe_udelay(length);}static void inline rbwrite(lirc_t l){ unsigned int nrbt; nrbt=(rbt+1) & (RBUF_LEN-1); if(nrbt==rbh) /* no new signals will be accepted */ {# ifdef DEBUG printk(KERN_WARNING LIRC_DRIVER_NAME ": Buffer overrun\n");# endif return; } rbuf[rbt]=l; rbt=nrbt;}static void inline frbwrite(lirc_t l){ /* simple noise filter */ static lirc_t pulse=0L,space=0L; static unsigned int ptr=0; if(ptr>0 && (l&PULSE_BIT)) { pulse+=l&PULSE_MASK; if(pulse>250) { rbwrite(space); rbwrite(pulse|PULSE_BIT); ptr=0; pulse=0; } return; } if(!(l&PULSE_BIT)) { if(ptr==0) { if(l>20000) { space=l; ptr++; return; } } else { if(l>20000) { space+=pulse; if(space>PULSE_MASK) space=PULSE_MASK; space+=l; if(space>PULSE_MASK) space=PULSE_MASK; pulse=0; return; } rbwrite(space); rbwrite(pulse|PULSE_BIT); ptr=0; pulse=0; } } rbwrite(l);}void irq_handler(int i, void *blah, struct pt_regs *regs){ struct timeval tv; int status,counter,dcd; long deltv; lirc_t data; counter=0; do{ counter++; status=sinp(UART_MSR); if(counter>RS_ISR_PASS_LIMIT) { printk(KERN_WARNING LIRC_DRIVER_NAME ": AIEEEE: " "We're caught!\n"); break; } if((status&hardware[type].signal_pin_change) && sense!=-1) { /* get current time */ do_gettimeofday(&tv); /* New mode, written by Trent Piepho <xyzzy@u.washington.edu>. */ /* The old format was not very portable. We now use the type lirc_t to pass pulses and spaces to user space. If PULSE_BIT is set a pulse has been received, otherwise a space has been received. The driver needs to know if your receiver is active high or active low, or the space/pulse sense could be inverted. The bits denoted by PULSE_MASK are the length in microseconds. Lengths greater than or equal to 16 seconds are clamped to PULSE_MASK. All other bits are unused. This is a much simpler interface for user programs, as well as eliminating "out of phase" errors with space/pulse autodetection. */ /* calculate time since last interrupt in microseconds */ dcd=(status & hardware[type].signal_pin) ? 1:0; deltv=tv.tv_sec-lasttv.tv_sec; if(deltv>15) {#ifdef DEBUG printk(KERN_WARNING LIRC_DRIVER_NAME ": AIEEEE: %d %d %lx %lx %lx %lx\n", dcd,sense, tv.tv_sec,lasttv.tv_sec, tv.tv_usec,lasttv.tv_usec);#endif data=PULSE_MASK; /* really long time */ if(!(dcd^sense)) /* sanity check */ { /* detecting pulse while this MUST be a space! */ sense=sense ? 0:1; } } else { data=(lirc_t) (deltv*1000000+ tv.tv_usec- lasttv.tv_usec); }; if(tv.tv_sec<lasttv.tv_sec || (tv.tv_sec==lasttv.tv_sec && tv.tv_usec<lasttv.tv_usec)) { printk(KERN_WARNING LIRC_DRIVER_NAME ": AIEEEE: your clock just jumped " "backwards\n"); printk(KERN_WARNING LIRC_DRIVER_NAME ": %d %d %lx %lx %lx %lx\n", dcd,sense, tv.tv_sec,lasttv.tv_sec, tv.tv_usec,lasttv.tv_usec); data=PULSE_MASK; } frbwrite(dcd^sense ? data : (data|PULSE_BIT)); lasttv=tv; wake_up_interruptible(&lirc_wait_in); } } while(!(sinp(UART_IIR) & UART_IIR_NO_INT)); /* still pending ? */}#ifdef KERNEL_2_3static DECLARE_WAIT_QUEUE_HEAD(power_supply_queue);#elsestatic struct wait_queue *power_supply_queue = NULL;#endif#ifndef KERNEL_2_1static struct timer_list power_supply_timer;static void power_supply_up(unsigned long ignored){ wake_up(&power_supply_queue);}#endifstatic int init_port(void){ unsigned long flags; /* Check io region*/ if((check_region(io,8))==-EBUSY) {#if 0 /* this is the correct behaviour but many people have the serial driver compiled into the kernel... */ printk(KERN_ERR LIRC_DRIVER_NAME ": port %04x already in use\n", io); return(-EBUSY);#else printk(KERN_ERR LIRC_DRIVER_NAME ": port %04x already in use, proceeding anyway\n", io); printk(KERN_WARNING LIRC_DRIVER_NAME ": compile the serial port driver as module and\n"); printk(KERN_WARNING LIRC_DRIVER_NAME ": make sure this module is loaded first\n"); release_region(io,8);#endif } /* Reserve io region. */ request_region(io, 8, LIRC_DRIVER_NAME); save_flags(flags);cli(); /* Set DLAB 0. */ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); /* First of all, disable all interrupts */ soutp(UART_IER, sinp(UART_IER)& (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); /* Clear registers. */ sinp(UART_LSR); sinp(UART_RX); sinp(UART_IIR); sinp(UART_MSR); /* Set line for power source */ soutp(UART_MCR, hardware[type].off); /* Clear registers again to be sure. */ sinp(UART_LSR); sinp(UART_RX); sinp(UART_IIR); sinp(UART_MSR); switch(hardware[type].type) { case LIRC_IRDEO: case LIRC_IRDEO_REMOTE: /* setup port to 7N1 @ 115200 Baud */ /* 7N1+start = 9 bits at 115200 ~ 3 bits at 38kHz */ /* Set DLAB 1. */ soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); /* Set divisor to 1 => 115200 Baud */ soutp(UART_DLM,0); soutp(UART_DLL,1); /* Set DLAB 0 + 7N1 */ soutp(UART_LCR,UART_LCR_WLEN7); /* THR interrupt already disabled at this point */ break; default: break; } restore_flags(flags); # ifdef USE_RDTSC /* Initialize pulse/space widths */ calc_pulse_lengths_in_clocks();# endif /* If pin is high, then this must be an active low receiver. */ if(sense==-1) { /* wait 1 sec for the power supply */ # ifdef KERNEL_2_1 sleep_on_timeout(&power_supply_queue,HZ);# else init_timer(&power_supply_timer); power_supply_timer.expires=jiffies+HZ; power_supply_timer.data=(unsigned long) current; power_supply_timer.function=power_supply_up; add_timer(&power_supply_timer); sleep_on(&power_supply_queue); del_timer(&power_supply_timer);# endif sense=(sinp(UART_MSR) & hardware[type].signal_pin) ? 1:0; printk(KERN_INFO LIRC_DRIVER_NAME ": auto-detected active " "%s receiver\n",sense ? "low":"high"); } else { printk(KERN_INFO LIRC_DRIVER_NAME ": Manually using active " "%s receiver\n",sense ? "low":"high"); }; return 0;}static int lirc_open(struct inode *ino, struct file *filep){ int result; unsigned long flags; # ifdef KERNEL_2_1 spin_lock(&lirc_lock);# endif if(MOD_IN_USE) {# ifdef KERNEL_2_1 spin_unlock(&lirc_lock);# endif return -EBUSY; } /* initialize timestamp */ do_gettimeofday(&lasttv); result=request_irq(irq,irq_handler,SA_INTERRUPT,LIRC_DRIVER_NAME,NULL); switch(result) { case -EBUSY: printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d busy\n", irq);# ifdef KERNEL_2_1 spin_unlock(&lirc_lock);# endif return -EBUSY; case -EINVAL: printk(KERN_ERR LIRC_DRIVER_NAME ": Bad irq number or handler\n");# ifdef KERNEL_2_1 spin_unlock(&lirc_lock);# endif return -EINVAL; default:# ifdef DEBUG
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -