📄 lirc_serial.c
字号:
printk(KERN_INFO LIRC_DRIVER_NAME ": Interrupt %d, port %04x obtained\n", irq, io);# endif break; }; /* finally enable interrupts. */ save_flags(flags);cli(); /* Set DLAB 0. */ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI); restore_flags(flags); /* Init read buffer pointers. */ rbh = rbt = 0; MOD_INC_USE_COUNT;# ifdef KERNEL_2_1 spin_unlock(&lirc_lock);# endif return 0;}#ifdef KERNEL_2_1static int lirc_close(struct inode *node, struct file *file)#elsestatic void lirc_close(struct inode *node, struct file *file)#endif{ unsigned long flags; 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))); restore_flags(flags); free_irq(irq, NULL);# ifdef DEBUG printk(KERN_INFO LIRC_DRIVER_NAME ": freed IRQ %d\n", irq);# endif MOD_DEC_USE_COUNT; # ifdef KERNEL_2_1 return 0;# endif}#ifdef KERNEL_2_1static unsigned int lirc_poll(struct file *file, poll_table * wait){ poll_wait(file, &lirc_wait_in, wait); if (rbh != rbt) return POLLIN | POLLRDNORM; return 0;}#elsestatic int lirc_select(struct inode *node, struct file *file, int sel_type, select_table * wait){ if (sel_type != SEL_IN) return 0; if (rbh != rbt) return 1; select_wait(&lirc_wait_in, wait); return 0;}#endif#ifdef KERNEL_2_1static ssize_t lirc_read(struct file *file, char *buf, size_t count, loff_t * ppos)#elsestatic int lirc_read(struct inode *node, struct file *file, char *buf, int count)#endif{ int n=0,retval=0;#ifdef KERNEL_2_3 DECLARE_WAITQUEUE(wait,current);#else struct wait_queue wait={current,NULL};#endif if(n%sizeof(lirc_t)) return(-EINVAL); add_wait_queue(&lirc_wait_in,&wait); current->state=TASK_INTERRUPTIBLE; while (n < count) { if (rbt != rbh) {# ifdef KERNEL_2_1 copy_to_user((void *) buf+n, (void *) &rbuf[rbh],sizeof(lirc_t));# else memcpy_tofs((void *) buf+n, (void *) &rbuf[rbh],sizeof(lirc_t));# endif rbh = (rbh + 1) & (RBUF_LEN - 1); n+=sizeof(lirc_t); } else { if (file->f_flags & O_NONBLOCK) { retval = -EAGAIN; break; }# ifdef KERNEL_2_1 if (signal_pending(current)) { retval = -ERESTARTSYS; break; }# else if (current->signal & ~current->blocked) { retval = -EINTR; break; }# endif schedule(); current->state=TASK_INTERRUPTIBLE; } } remove_wait_queue(&lirc_wait_in,&wait); current->state=TASK_RUNNING; return (n ? n : retval);}#ifdef KERNEL_2_1static ssize_t lirc_write(struct file *file, const char *buf, size_t n, loff_t * ppos)#elsestatic int lirc_write(struct inode *node, struct file *file, const char *buf, int n)#endif{ int retval,i,count; unsigned long flags; long delta=0; if(!(hardware[type].features&LIRC_CAN_SEND_PULSE)) { return(-EBADF); } if(n%sizeof(lirc_t)) return(-EINVAL); retval=verify_area(VERIFY_READ,buf,n); if(retval) return(retval); count=n/sizeof(lirc_t); if(count>WBUF_LEN || count%2==0) return(-EINVAL);# ifdef KERNEL_2_1 copy_from_user(wbuf,buf,n);# else memcpy_fromfs(wbuf,buf,n);# endif save_flags(flags);cli(); if(hardware[type].type==LIRC_IRDEO) { /* DTR, RTS down */ on(); } for(i=0;i<count;i++) { if(i%2) hardware[type].send_space(wbuf[i]-delta); else delta=hardware[type].send_pulse(wbuf[i]); } off(); restore_flags(flags); return(n);}static int lirc_ioctl(struct inode *node,struct file *filep,unsigned int cmd, unsigned long arg){ int result; unsigned long value; unsigned int ivalue; switch(cmd) { case LIRC_GET_FEATURES:# ifdef KERNEL_2_1 result=put_user(hardware[type].features, (unsigned long *) arg); if(result) return(result); # else result=verify_area(VERIFY_WRITE,(unsigned long*) arg, sizeof(unsigned long)); if(result) return(result); put_user(hardware[type].features,(unsigned long *) arg);# endif break; case LIRC_GET_SEND_MODE: if(!(hardware[type].features&LIRC_CAN_SEND_MASK)) { return(-ENOIOCTLCMD); } # ifdef KERNEL_2_1 result=put_user(LIRC_SEND2MODE (hardware[type].features&LIRC_CAN_SEND_MASK), (unsigned long *) arg); if(result) return(result); # else result=verify_area(VERIFY_WRITE,(unsigned long *) arg, sizeof(unsigned long)); if(result) return(result); put_user(LIRC_SEND2MODE (hardware[type].features&LIRC_CAN_SEND_MASK), (unsigned long *) arg);# endif break; case LIRC_GET_REC_MODE: if(!(hardware[type].features&LIRC_CAN_REC_MASK)) { return(-ENOIOCTLCMD); } # ifdef KERNEL_2_1 result=put_user(LIRC_REC2MODE (hardware[type].features&LIRC_CAN_REC_MASK), (unsigned long *) arg); if(result) return(result); # else result=verify_area(VERIFY_WRITE,(unsigned long *) arg, sizeof(unsigned long)); if(result) return(result); put_user(LIRC_REC2MODE (hardware[type].features&LIRC_CAN_REC_MASK), (unsigned long *) arg);# endif break; case LIRC_SET_SEND_MODE: if(!(hardware[type].features&LIRC_CAN_SEND_MASK)) { return(-ENOIOCTLCMD); } # ifdef KERNEL_2_1 result=get_user(value,(unsigned long *) arg); if(result) return(result);# else result=verify_area(VERIFY_READ,(unsigned long *) arg, sizeof(unsigned long)); if(result) return(result); value=get_user((unsigned long *) arg);# endif /* only LIRC_MODE_PULSE supported */ if(value!=LIRC_MODE_PULSE) return(-ENOSYS); break; case LIRC_SET_REC_MODE: if(!(hardware[type].features&LIRC_CAN_REC_MASK)) { return(-ENOIOCTLCMD); } # ifdef KERNEL_2_1 result=get_user(value,(unsigned long *) arg); if(result) return(result);# else result=verify_area(VERIFY_READ,(unsigned long *) arg, sizeof(unsigned long)); if(result) return(result); value=get_user((unsigned long *) arg);# endif /* only LIRC_MODE_MODE2 supported */ if(value!=LIRC_MODE_MODE2) return(-ENOSYS); break; case LIRC_SET_SEND_DUTY_CYCLE: if(!(hardware[type].features&LIRC_CAN_SET_SEND_DUTY_CYCLE)) { return(-ENOIOCTLCMD); } # ifdef KERNEL_2_1 result=get_user(ivalue,(unsigned int *) arg); if(result) return(result);# else result=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);# ifdef USE_RDTSC duty_cycle=ivalue; calc_pulse_lengths_in_clocks();# else /* ! USE_RDTSC */ if(256*1000000L/freq*ivalue/100<= LIRC_SERIAL_TRANSMITTER_LATENCY) return(-EINVAL); if(256*1000000L/freq*(100-ivalue)/100<= LIRC_SERIAL_TRANSMITTER_LATENCY) return(-EINVAL); duty_cycle=ivalue; period=256*1000000L/freq; pulse_width=period*duty_cycle/100; space_width=period-pulse_width;# endif /* USE_RDTSC */# ifdef DEBUG printk(KERN_WARNING LIRC_DRIVER_NAME ": after SET_SEND_DUTY_CYCLE, freq=%d pulse=%ld, " "space=%ld, conv_us_to_clocks=%ld\n", freq, pulse_width, space_width, conv_us_to_clocks);# endif break; case LIRC_SET_SEND_CARRIER: if(!(hardware[type].features&LIRC_CAN_SET_SEND_CARRIER)) { return(-ENOIOCTLCMD); } # ifdef KERNEL_2_1 result=get_user(ivalue,(unsigned int *) arg); if(result) return(result);# else result=verify_area(VERIFY_READ,(unsigned int *) arg, sizeof(unsigned int)); if(result) return(result); ivalue=get_user((unsigned int *) arg);# endif if(ivalue>500000 || ivalue<20000) return(-EINVAL);# ifdef USE_RDTSC freq=ivalue; calc_pulse_lengths_in_clocks();# else /* !USE_RDTSC */ if(256*1000000L/freq*ivalue/100<= LIRC_SERIAL_TRANSMITTER_LATENCY) return(-EINVAL); if(256*1000000L/freq*(100-ivalue)/100<= LIRC_SERIAL_TRANSMITTER_LATENCY) return(-EINVAL); freq=ivalue; period=256*1000000L/freq; pulse_width=period*duty_cycle/100; space_width=period-pulse_width;# endif /* USE_RDTSC */# ifdef DEBUG printk(KERN_WARNING LIRC_DRIVER_NAME ": after SET_SEND_CARRIER, freq=%d pulse=%ld, " "space=%ld, conv_us_to_clocks=%ld\n", freq, pulse_width, space_width, conv_us_to_clocks);# endif break; default: return(-ENOIOCTLCMD); } return(0);}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 MODULE#if LINUX_VERSION_CODE >= 0x020100MODULE_AUTHOR("Ralph Metzler, Trent Piepho, Ben Pfaff, Christoph Bartelmus");MODULE_DESCRIPTION("Infra-red receiver driver for serial ports.");#ifdef MODULE_LICENSEMODULE_LICENSE("GPL");#endifMODULE_PARM(type, "i");MODULE_PARM_DESC(type, "Hardware type (0 = home-brew, 1 = IRdeo," " 2 = IRdeo Remote, 3 = AnimaX");MODULE_PARM(io, "i");MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)");MODULE_PARM(irq, "i");MODULE_PARM_DESC(irq, "Interrupt (4 or 3)");MODULE_PARM(sense, "i");MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit" " (0 = active high, 1 = active low )");MODULE_PARM(softcarrier, "i");MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on)");EXPORT_NO_SYMBOLS;#endifint init_module(void){ int result; switch(type) { case LIRC_HOMEBREW: case LIRC_IRDEO: case LIRC_IRDEO_REMOTE: case LIRC_ANIMAX: break; default: return(-EINVAL); } if(!softcarrier && hardware[type].type==LIRC_HOMEBREW) { hardware[type].features&=~(LIRC_CAN_SET_SEND_DUTY_CYCLE| LIRC_CAN_SET_SEND_CARRIER); } if ((result = init_port()) < 0) return result; if (register_chrdev(major, LIRC_DRIVER_NAME, &lirc_fops) < 0) { printk(KERN_ERR LIRC_DRIVER_NAME ": register_chrdev failed!\n"); release_region(io, 8); return -EIO; } return 0;}void cleanup_module(void){ release_region(io, 8); unregister_chrdev(major, LIRC_DRIVER_NAME);# ifdef DEBUG printk(KERN_INFO LIRC_DRIVER_NAME ": cleaned up module\n");# endif}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -