📄 lirc_it87.c
字号:
"iir: 0x%x fifo: 0x%x\n", iir, lsr);#endif /* avoid interference with timer */ spin_lock_irqsave(&timer_lock, flags); spin_lock_irqsave(&hardware_lock, hw_flags); do { del_timer(&timerlist); data = inb(io + IT87_CIR_DR);#ifdef DEBUG_SIGNAL printk(KERN_DEBUG LIRC_DRIVER_NAME ": data=%.2x\n", data);#endif 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 + IT87_TIMEOUT; add_timer(&timerlist); } outb((inb(io + IT87_CIR_RCR) & ~IT87_CIR_RCR_RXEN) | IT87_CIR_RCR_RXACT, io + IT87_CIR_RCR); if (it87_RXEN_mask) { outb(inb(io + IT87_CIR_RCR) | IT87_CIR_RCR_RXEN, io + IT87_CIR_RCR); } fifo--; } while (fifo != 0); spin_unlock_irqrestore(&hardware_lock, hw_flags); spin_unlock_irqrestore(&timer_lock, flags); break; default: /* not our irq */#ifdef DEBUG_SIGNAL printk(KERN_DEBUG LIRC_DRIVER_NAME "unknown IRQ (shouldn't happen) !!\n");#endif break; }}static void send_it87(unsigned long len, unsigned long stime, unsigned char send_byte, unsigned int count_bits){ long count = len / stime; long time_left = 0; static unsigned char byte_out = 0;#ifdef DEBUG_SIGNAL printk(KERN_DEBUG LIRC_DRIVER_NAME "send_it87: len=%ld, sb=%d\n", len, send_byte);#endif time_left = (long)len - (long)count * (long)stime; count += ((2 * time_left) / stime); while (count) { long i=0; for (i=0; i<count_bits; i++) { byte_out = (byte_out << 1) | (send_byte & 1); it87_bits_in_byte_out++; } if (it87_bits_in_byte_out == 8) {#ifdef DEBUG_SIGNAL printk(KERN_DEBUG LIRC_DRIVER_NAME "out=0x%x, tsr_txfbc: 0x%x\n", byte_out, inb(io + IT87_CIR_TSR) & IT87_CIR_TSR_TXFBC);#endif while ((inb(io + IT87_CIR_TSR) & IT87_CIR_TSR_TXFBC) >= IT87_CIR_FIFO_SIZE); { unsigned long hw_flags; spin_lock_irqsave(&hardware_lock, hw_flags); outb(byte_out, io + IT87_CIR_DR); spin_unlock_irqrestore(&hardware_lock, hw_flags); } it87_bits_in_byte_out = 0; it87_send_counter++; byte_out = 0; } count--; }}/*maybe: exchange space and pulse becauseit8705 only modulates 0-bits*/static void send_space(unsigned long len){ send_it87(len, TIME_CONST, IT87_CIR_SPACE, IT87_CIR_BAUDRATE_DIVISOR);}static void send_pulse(unsigned long len){ send_it87(len, TIME_CONST, IT87_CIR_PULSE, IT87_CIR_BAUDRATE_DIVISOR);}static void init_send(){ unsigned long flags; spin_lock_irqsave(&hardware_lock, flags); /* RXEN=0: receiver disable */ it87_RXEN_mask = 0; outb(inb(io + IT87_CIR_RCR) & ~IT87_CIR_RCR_RXEN, io + IT87_CIR_RCR); spin_unlock_irqrestore(&hardware_lock, flags); it87_bits_in_byte_out = 0; it87_send_counter = 0;}static void terminate_send(unsigned long len){ unsigned long flags; unsigned long last = 0; last = it87_send_counter; /* make sure all necessary data has been sent */ while (last == it87_send_counter) send_space(len); /* wait until all data sent */ while ((inb(io + IT87_CIR_TSR) & IT87_CIR_TSR_TXFBC) != 0); /* then reenable receiver */ spin_lock_irqsave(&hardware_lock, flags); it87_RXEN_mask = IT87_CIR_RCR_RXEN; outb(inb(io + IT87_CIR_RCR) | IT87_CIR_RCR_RXEN, io + IT87_CIR_RCR); spin_unlock_irqrestore(&hardware_lock, flags);}static int init_hardware(void){ unsigned long flags; unsigned char it87_rcr = 0; spin_lock_irqsave(&hardware_lock, flags); /* init cir-port */ /* enable r/w-access to Baudrate-Register */ outb(IT87_CIR_IER_BR, io + IT87_CIR_IER); outb(IT87_CIR_BAUDRATE_DIVISOR % 0x100, io+IT87_CIR_BDLR); outb(IT87_CIR_BAUDRATE_DIVISOR / 0x100, io+IT87_CIR_BDHR); /* Baudrate Register off, define IRQs: Input only */ outb(IT87_CIR_IER_IEC | IT87_CIR_IER_RDAIE, io + IT87_CIR_IER); /* RX: HCFS=0, RXDCR = 001b (35,6..40,3 kHz), RXEN=1 */ it87_rcr = (IT87_CIR_RCR_RXEN & it87_RXEN_mask) | 0x1; if (it87_enable_demodulator) it87_rcr |= IT87_CIR_RCR_RXEND; outb(it87_rcr, io + IT87_CIR_RCR); /* TX: 38kHz, 13,3us (pulse-width */ outb(((it87_freq - IT87_CIR_FREQ_MIN) << 3) | 0x06, io + IT87_CIR_TCR2); spin_unlock_irqrestore(&hardware_lock, flags); return 0;}static void drop_hardware(void){ unsigned long flags; spin_lock_irqsave(&hardware_lock, flags); disable_irq(irq); /* receiver disable */ it87_RXEN_mask = 0; outb(0x1, io + IT87_CIR_RCR); /* turn off irqs */ outb(0, io + IT87_CIR_IER); /* fifo clear */ outb(IT87_CIR_TCR1_FIFOCLR, io+IT87_CIR_TCR1); /* reset */ outb(IT87_CIR_IER_RESET, io+IT87_CIR_IER); enable_irq(irq); spin_unlock_irqrestore(&hardware_lock, flags);}static unsigned char it87_read(unsigned char port){ outb(port, IT87_ADRPORT); return inb(IT87_DATAPORT);}static void it87_write(unsigned char port, unsigned char data){ outb(port, IT87_ADRPORT); outb(data, IT87_DATAPORT);}/* SECTION: Initialisation */static int init_port(void){ int retval = 0; unsigned char init_bytes[4] = {IT87_INIT}; unsigned char it87_chipid = 0; unsigned char ldn = 0; unsigned int it87_io = 0; unsigned int it87_irq = 0; /* Enter MB PnP Mode */ outb(init_bytes[0], IT87_ADRPORT); outb(init_bytes[1], IT87_ADRPORT); outb(init_bytes[2], IT87_ADRPORT); outb(init_bytes[3], IT87_ADRPORT); /* 8712 or 8705 ? */ it87_chipid = it87_read(IT87_CHIP_ID1); if (it87_chipid != 0x87) { retval = -ENXIO; return retval; } it87_chipid = it87_read(IT87_CHIP_ID2); if ((it87_chipid != 0x12) && (it87_chipid != 0x05)) { printk(KERN_INFO LIRC_DRIVER_NAME ": no IT8705/12 found, exiting..\n"); retval = -ENXIO; return retval; } printk(KERN_INFO LIRC_DRIVER_NAME ": found IT87%.2x.\n", it87_chipid); /* get I/O-Port and IRQ */ if (it87_chipid == 0x12) ldn = IT8712_CIR_LDN; else ldn = IT8705_CIR_LDN; it87_write(IT87_LDN, ldn); it87_io = it87_read(IT87_CIR_BASE_MSB) * 256 + it87_read(IT87_CIR_BASE_LSB); if (it87_io == 0) { if (io == 0) io = IT87_CIR_DEFAULT_IOBASE; printk(KERN_INFO LIRC_DRIVER_NAME ": set default io 0x%x\n", io); it87_write(IT87_CIR_BASE_MSB, io / 0x100); it87_write(IT87_CIR_BASE_LSB, io % 0x100); } else io = it87_io; it87_irq = it87_read(IT87_CIR_IRQ); if (it87_irq == 0) { if (irq == 0) irq = IT87_CIR_DEFAULT_IRQ; printk(KERN_INFO LIRC_DRIVER_NAME ": set default irq 0x%x\n", irq); it87_write(IT87_CIR_IRQ, irq); } else irq = it87_irq; { unsigned long hw_flags; spin_lock_irqsave(&hardware_lock, hw_flags); /* reset */ outb(IT87_CIR_IER_RESET, io+IT87_CIR_IER); /* fifo clear */ outb(IT87_CIR_TCR1_FIFOCLR | /* IT87_CIR_TCR1_ILE | */ IT87_CIR_TCR1_TXRLE | IT87_CIR_TCR1_TXENDF, io+IT87_CIR_TCR1); spin_unlock_irqrestore(&hardware_lock, hw_flags); } /* get I/O port access and IRQ line */ retval = check_region(io, 8); if (retval < 0) { printk(KERN_ERR LIRC_DRIVER_NAME ": i/o port 0x%.4x already in use.\n", io); /* Leaving MB PnP Mode */ it87_write(IT87_CFGCTRL, 0x2); return retval; } /* activate CIR-Device */ it87_write(IT87_CIR_ACT, 0x1); /* Leaving MB PnP Mode */ it87_write(IT87_CFGCTRL, 0x2); retval = request_irq(irq, it87_interrupt, 0 /*SA_INTERRUPT*/, LIRC_DRIVER_NAME, NULL); if (retval < 0) { printk(KERN_ERR LIRC_DRIVER_NAME ": IRQ %d already in use.\n", irq); return retval; } request_region(io, 8, LIRC_DRIVER_NAME); printk(KERN_INFO LIRC_DRIVER_NAME ": I/O port 0x%.4x, IRQ %d.\n", io, irq); init_timer(&timerlist); timerlist.function = it87_timeout; timerlist.data = 0xabadcafe; return 0;}static void drop_port(void){/* unsigned char init_bytes[4] = {IT87_INIT}; / * Enter MB PnP Mode * / outb(init_bytes[0], IT87_ADRPORT); outb(init_bytes[1], IT87_ADRPORT); outb(init_bytes[2], IT87_ADRPORT); outb(init_bytes[3], IT87_ADRPORT); / * deactivate CIR-Device * / it87_write(IT87_CIR_ACT, 0x0); / * Leaving MB PnP Mode * / it87_write(IT87_CFGCTRL, 0x2);*/ del_timer_sync(&timerlist); free_irq(irq, NULL); release_region(io, 8);}int init_lirc_it87(void){ int retval; init_waitqueue_head(&lirc_read_queue); retval = init_port(); if (retval < 0) return retval; init_hardware(); printk(KERN_INFO LIRC_DRIVER_NAME ": Installed.\n"); return 0;}#ifdef MODULEMODULE_AUTHOR("Hans-G黱ter L黷ke Uphues");MODULE_DESCRIPTION("LIRC driver for ITE IT8712/IT8705 CIR port");MODULE_PARM(io, "i");MODULE_PARM_DESC(io, "I/O base address (default: 0x310)");MODULE_PARM(irq, "i");MODULE_PARM_DESC(irq, "Interrupt (1,3-12) (default: 7)");MODULE_PARM(it87_enable_demodulator, "i");MODULE_PARM_DESC(it87_enable_demodulator, "Receiver demodulator enable/disable (1/0), default: 0");#ifdef MODULE_LICENSEMODULE_LICENSE("GPL");#endifEXPORT_NO_SYMBOLS;int init_module(void){ int retval; retval=init_chrdev(); if(retval < 0) return retval; retval = init_lirc_it87(); if (retval) { drop_chrdev(); return retval; } return 0;}void cleanup_module(void){ drop_hardware(); drop_chrdev(); drop_port(); printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n");}#endif/* * Overrides for Emacs so that we follow Linus's tabbing style. * --------------------------------------------------------------------------- * Local variables: * c-basic-offset: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -