📄 eibdrv.c
字号:
(ftstation.state==FT_STATE_WAIT_FOR_RESET_ACK) || (ftstation.state==FT_STATE_WAIT_FOR_RESP_STATUS)) wake_up_interruptible(&wq_wait_for_ack); } set_fs(fs); } while(1);}int open_ftstation(void){ #if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0) struct dentry *ser_dentry=NULL;#endif struct inode *ser_inode=NULL; struct async_struct ser_async; struct termios help_termios; fs=get_fs(); set_fs(KERNEL_DS);#ifdef __SMP__ lock_kernel();#endif#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0) ftstation.port.filp=filp_open(port,O_RDWR|O_NOCTTY|O_EXCL,0600); if (IS_ERR(ftstation.port.filp)) { printk(KERN_ERR "eibdrv (%i): cannot open serial port %s\n",c++,port); goto fail_open_serport; } ser_dentry=ftstation.port.filp->f_dentry; ftstation.port.inodp=ser_inode=ser_dentry->d_inode;#else ftstation.port.filp=open_fp(port,O_RDWR|O_NOCTTY|O_EXCL,0600); if (ftstation.port.filp==NULL) { printk(KERN_ERR "eibdrv (%i): cannot open serial port %s\n",c++,port); goto fail_open_serport; } ftstation.port.inodp=ser_inode=ftstation.port.filp->f_inode; #endif if (ftstation.port.filp->f_op->ioctl(ser_inode,ftstation.port.filp, TIOCSERGSTRUCT,(unsigned long)&ser_async)<0) { printk(KERN_ERR "eibdrv (%i): cannot get async_struct\n",c++); goto fail_get_async; } ftstation.port.tty=ser_async.tty; ftstation.port.old_termios=*(ftstation.port.tty->termios); ftstation.port.tty->termios->c_iflag=IGNPAR | // ignore bytes with parity or framing errors INPCK; // enable input parity checking ftstation.port.tty->termios->c_oflag=0x00; ftstation.port.tty->termios->c_cflag=symb_baudrate | // baudrate CRTSCTS | // hardware flow control CS8 | // character size 8 bit PARENB | // parity bit CLOCAL | // ignore modem control lines CREAD; // enable receiver ftstation.port.tty->termios->c_lflag=0x00; ftstation.port.tty->termios->c_cc[VTIME]=0; ftstation.port.tty->termios->c_cc[VMIN]=0; ftstation.port.tty->driver.set_termios(ftstation.port.tty,&help_termios); ftstation.port.tty->ldisc.set_termios(ftstation.port.tty,&help_termios);#ifdef __SMP__ unlock_kernel();#endif if (mode==FT_SERVERMODE) { if ((ftstation.wpbuf=eib_get_wpbuf(wpbuf_size))==NULL) { printk(KERN_ERR "eibdrv (%i): cannot allocate memory for list of write processes\n",c++); goto fail_wpbuf; } if ((ftstation.rpbuf=eib_get_rpbuf(rpbuf_size,rpbuf_msgbuf_size))==NULL) { printk(KERN_ERR "eibdrv (%i): cannot allocate memory for list of read processes\n",c++); goto fail_rpbuf; } if ((ftstation.outbuf=eib_get_buf(outbuf_size))==NULL) { printk(KERN_ERR "eibdrv (%i): cannot allocate memory for message buffer\n",c++); goto fail_outbuf; } } set_fs(fs); return 0; fail_outbuf: eib_return_rpbuf(ftstation.rpbuf); fail_rpbuf: eib_return_wpbuf(ftstation.wpbuf); fail_wpbuf: *(ftstation.port.tty->termios)=ftstation.port.old_termios; ftstation.port.tty->driver.set_termios(ftstation.port.tty,&help_termios); ftstation.port.tty->ldisc.set_termios(ftstation.port.tty,&help_termios); fail_get_async: #if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0) filp_close(ftstation.port.filp,NULL);#else close_fp(ftstation.port.filp);#endif fail_open_serport: #ifdef __SMP__ unlock_kernel();#endif set_fs(fs); return -ESHUTDOWN;}int close_ftstation(void){ struct termios help_termios; if (mode==FT_SERVERMODE) { eib_return_buf(ftstation.outbuf); eib_return_rpbuf(ftstation.rpbuf); eib_return_wpbuf(ftstation.wpbuf); } fs=get_fs(); set_fs(KERNEL_DS);#ifdef __SMP__ lock_kernel();#endif *(ftstation.port.tty->termios)=ftstation.port.old_termios; ftstation.port.tty->driver.set_termios(ftstation.port.tty,&help_termios); ftstation.port.tty->ldisc.set_termios(ftstation.port.tty,&help_termios);#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0) filp_close(ftstation.port.filp,NULL); if (IS_ERR(ftstation.port.filp)) { printk(KERN_ERR "eibdrv (%i): cannot close serial port %s\n",c++,port); goto fail_close_serport; }#else if (close_fp(ftstation.port.filp)!=0) { printk(KERN_ERR "eibdrv (%i): cannot close serial port %s\n",c++,port); goto fail_close_serport; }#endif #ifdef __SMP__ unlock_kernel();#endif set_fs(fs); return 0; fail_close_serport: #ifdef __SMP__ unlock_kernel();#endif set_fs(fs); return -ESHUTDOWN;}int eibdrv_open(struct inode *eib_inode,struct file *eib_filp){ int blockmode; int result; switch(mode) { case FT_SERVERMODE: switch(ftstation.state) { case FT_STATE_INIT: if (ftstation.servproc==2) return -EBUSY; ftstation.servproc++; return 0; case FT_STATE_SHUTDOWN: return -EBUSY; default: if (!MOD_IN_USE) // first open { if ((eib_filp->f_flags & O_EXCL)!=0) ftstation.f_exclusive=FT_EXCLUSIVE_RW; else ftstation.f_exclusive=FT_SHARED_RW; } else { if (((eib_filp->f_flags & O_EXCL)!=0) || (ftstation.f_exclusive==FT_EXCLUSIVE_RW)) return -EBUSY; } if (!(eib_filp->f_flags&O_NONBLOCK)) blockmode=FT_PROC_BLOCKED; else blockmode=FT_PROC_NONBLOCKED; result=eib_ins_rpbuf(ftstation.rpbuf,eib_filp,blockmode); if (!result) MOD_INC_USE_COUNT; return result; } case FT_STANDARDMODE: if (!MOD_IN_USE) // first open { if ((eib_filp->f_flags & O_EXCL)!=0) ftstation.f_exclusive=FT_EXCLUSIVE_RW; else ftstation.f_exclusive=FT_SHARED_RW; } else { if (((eib_filp->f_flags & O_EXCL)!=0) || (ftstation.f_exclusive==FT_EXCLUSIVE_RW)) return -EBUSY; } MOD_INC_USE_COUNT; return 0; } return 0;}#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)int eibdrv_release(struct inode *eib_inodp,struct file *eib_filp)#elsevoid eibdrv_release(struct inode *eib_inodp,struct file *eib_filp)#endif{ switch(mode) { case FT_SERVERMODE: switch(ftstation.state) { case FT_STATE_SHUTDOWN: ftstation.servproc--; wake_up_interruptible(&wq_shutdown); break; default: MOD_DEC_USE_COUNT; eib_rm_rpbuf(ftstation.rpbuf,eib_filp); break; } break; case FT_STANDARDMODE: MOD_DEC_USE_COUNT; break; }#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0) return 0;#endif} #if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)ssize_t eibdrv_write(struct file *eib_filp,const char *buf,size_t len,loff_t *pos)#elseread_write_t eibdrv_write(struct inode *eib_inodp, struct file *eib_filp,const char *buf,int len)#endif{ unsigned char element[EIB_BUF_ELEMENT_SIZE]; int blockmode; int result; int copylen; int wmode,rmmode; if (len>23) copylen=23; else copylen=len;#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0) if (copy_from_user(&element[0],buf,copylen)!=0) return -EFAULT;#else memcpy_fromfs(&element[0],buf,copylen);#endif if (!(eib_filp->f_flags & O_NONBLOCK)) blockmode=FT_PROC_BLOCKED; else blockmode=FT_PROC_NONBLOCKED; wmode=eib_get_rpbuf_wmode(ftstation.rpbuf,eib_filp); rmmode=wmode+1; while((ftstation.wpbuf->count==wpbuf_size)||(ftstation.outbuf->count==outbuf_size)) { if (blockmode==FT_PROC_NONBLOCKED) return -EAGAIN; else interruptible_sleep_on(&wq_fullwproc); } eib_write_buf(ftstation.outbuf,&element[0],copylen); eib_write_wpbuf(ftstation.wpbuf,current->pid,rmmode); wake_up_interruptible(&wq_ser_write); if (wmode==FT_WRITE_STANDARD) return copylen; do { interruptible_sleep_on(&wq_wproc); result=eib_condrm_wpbuf(ftstation.wpbuf,current->pid); } while (result==-ENORESULT); return result;}#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)ssize_t eibdrv_read(struct file *eib_filp,char *buf,size_t len,loff_t *pos)#elseread_write_t eibdrv_read(struct inode *eib_inodp,struct file *eib_filp,char *buf,int len)#endif{ unsigned char element[EIB_BUF_ELEMENT_SIZE]; int blockmode; int copylen; if (!(eib_filp->f_flags & O_NONBLOCK)) blockmode=FT_PROC_BLOCKED; else blockmode=FT_PROC_NONBLOCKED; do { copylen=eib_rmsg_rpbuf(ftstation.rpbuf,eib_filp,&element[0]); if (copylen>0) { if (copylen>len) copylen=len;#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0) if (copy_to_user(buf,&element[0],copylen)!=0) return -EFAULT;#else memcpy_tofs(buf,&element[0],copylen);#endif return copylen; } if (blockmode==FT_PROC_NONBLOCKED) return -EAGAIN; interruptible_sleep_on(&wq_rproc); } while(1);}#if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)int eibdrv_fasync(int eib_fd,struct file *eib_filp,int flag){ return fasync_helper(eib_fd,eib_filp,flag,&(ftstation.pasync));}#elseint eibdrv_fasync(struct inode *eib_inodp,struct file *eib_filp,int flag){ return fasync_helper(eib_inodp,eib_filp,flag,&(ftstation.pasync));}#endifint eibdrv_ioctl(struct inode *eib_inode,struct file *eib_filp, unsigned int cmd,unsigned long arg){ int result; Eib_statistics stat;/* if (current->euid!=0) // cmd only available to root user { switch(cmd) { case FT_SET_OUTBUF_SIZE: case FT_SET_WPBUF_SIZE: case FT_SET_RPBUF_SIZE: case FT_SET_RPBUF_MSGSIZE: case FT_GET_BAUDRATE: case FT_GET_PORT_LENGTH: case FT_GET_PORT: case FT_ISSERVPROC: case FT_RESET: case FT_RESET_STAT: case FT_GET_STAT: case FT_GETRESET_STAT: return -EACCES; } } */ switch(cmd) { case FT_GET_MODE : return mode; case FT_GET_BAUDRATE : return symb_baudrate; case FT_GET_PORT_LENGTH : return strlen(port); case FT_GET_PORT: #if LINUX_VERSION_CODE >= VERSION_CODE(2,1,0) if (copy_to_user((char *)arg,port,strlen(port)+1)!=0) return -EFAULT;#else memcpy_tofs((void *)arg,port,strlen(port)+1); #endif return strlen(port); case FT_RESET : return ser_reset(); case FT_RESP_STATUS : return ser_status(); case FT_RESET_STAT : reset_statistics(&ftstation.stat); return 0; case FT_GET_STAT : case FT_GETRESET_STAT : if (ftstation.stat.overflow>0) return -EOVERFLOW; stat=ftstation.stat; // copy_to_user may block! if (mode==FT_SERVERMODE) { stat.outbuf_count=eib_get_buf_count(ftstation.outbuf); stat.wpbuf_count=eib_get_wpbuf_count(ftstation.wpbuf); stat.rpbuf_count=eib_get_rpbuf_cou
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -