📄 synclink.c
字号:
/* perform existance check and diagnostics */ if ( !retval ) retval = mgsl_adapter_test(info); if ( retval ) {#if LINUX_VERSION_CODE >= VERSION(2,1,0) if (capable(CAP_SYS_ADMIN) && info->tty)#else if (suser() && info->tty)#endif set_bit(TTY_IO_ERROR, &info->tty->flags); mgsl_release_resources(info); return retval; } /* program hardware for current parameters */ mgsl_change_params(info); if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); info->flags |= ASYNC_INITIALIZED; return 0; } /* end of startup() *//* shutdown() * * Called by mgsl_close() and mgsl_hangup() to shutdown hardware * * Arguments: info pointer to device instance data * Return Value: None */static void shutdown(struct mgsl_struct * info){ unsigned long flags; if (!(info->flags & ASYNC_INITIALIZED)) return; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_shutdown(%s)\n", __FILE__,__LINE__, info->device_name ); /* clear status wait queue because status changes */ /* can't happen after shutting down the hardware */ wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); if (info->xmit_buf) { free_page((unsigned long) info->xmit_buf); info->xmit_buf = 0; } spin_lock_irqsave(&info->irq_spinlock,flags); usc_DisableMasterIrqBit(info); usc_stop_receiver(info); usc_stop_transmitter(info); usc_DisableInterrupts(info,RECEIVE_DATA + RECEIVE_STATUS + TRANSMIT_DATA + TRANSMIT_STATUS + IO_PIN + MISC ); usc_DisableDmaInterrupts(info,DICR_MASTER + DICR_TRANSMIT + DICR_RECEIVE); /* Disable DMAEN (Port 7, Bit 14) */ /* This disconnects the DMA request signal from the ISA bus */ /* on the ISA adapter. This has no effect for the PCI adapter */ usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT15) | BIT14)); /* Disable INTEN (Port 6, Bit12) */ /* This disconnects the IRQ request signal to the ISA bus */ /* on the ISA adapter. This has no effect for the PCI adapter */ usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) | BIT12)); if (!info->tty || info->tty->termios->c_cflag & HUPCL) { info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS); usc_set_serial_signals(info); } spin_unlock_irqrestore(&info->irq_spinlock,flags); mgsl_release_resources(info); if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); info->flags &= ~ASYNC_INITIALIZED; } /* end of shutdown() *//* mgsl_change_params() * * Reconfigure adapter based on new parameters * * Arguments: info pointer to device instance data * Return Value: None */static void mgsl_change_params(struct mgsl_struct *info){ unsigned cflag; unsigned long flags; int bits_per_char; if (!info->tty || !info->tty->termios) return; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_change_params(%s)\n", __FILE__,__LINE__, info->device_name ); cflag = info->tty->termios->c_cflag; /* if B0 rate (hangup) specified then negate DTR and RTS */ /* otherwise assert DTR and RTS */ if (cflag & CBAUD) info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; else info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR); /* byte size and parity */ switch (cflag & CSIZE) { case CS5: info->params.data_bits = 5; break; case CS6: info->params.data_bits = 6; break; case CS7: info->params.data_bits = 7; break; case CS8: info->params.data_bits = 8; break; /* Never happens, but GCC is too dumb to figure it out */ default: info->params.data_bits = 7; break; } if (cflag & CSTOPB) info->params.stop_bits = 2; else info->params.stop_bits = 1; info->params.parity = ASYNC_PARITY_NONE; if (cflag & PARENB) { if (cflag & PARODD) info->params.parity = ASYNC_PARITY_ODD; else info->params.parity = ASYNC_PARITY_EVEN;#ifdef CMSPAR if (cflag & CMSPAR) info->params.parity = ASYNC_PARITY_SPACE;#endif } /* calculate number of jiffies to transmit a full * FIFO (32 bytes) at specified data rate */ bits_per_char = info->params.data_bits + info->params.stop_bits + 1; /* if port data rate is set to 460800 or less then * allow tty settings to override, otherwise keep the * current data rate. */ if (info->params.data_rate <= 460800) {#if LINUX_VERSION_CODE >= VERSION(2,1,0) info->params.data_rate = tty_get_baud_rate(info->tty);#else int i = cflag & CBAUD; if (i & CBAUDEX) { i &= ~CBAUDEX; if (i < 1 || i > 4) info->tty->termios->c_cflag &= ~CBAUDEX; else i += 15; } info->params.data_rate = baud_table[i];#endif } if ( info->params.data_rate ) { info->timeout = (32*HZ*bits_per_char) / info->params.data_rate; } info->timeout += HZ/50; /* Add .02 seconds of slop */ if (cflag & CRTSCTS) info->flags |= ASYNC_CTS_FLOW; else info->flags &= ~ASYNC_CTS_FLOW; if (cflag & CLOCAL) info->flags &= ~ASYNC_CHECK_CD; else info->flags |= ASYNC_CHECK_CD; /* process tty input control flags */ info->read_status_mask = RXSTATUS_OVERRUN; if (I_INPCK(info->tty)) info->read_status_mask |= RXSTATUS_PARITY_ERROR | RXSTATUS_FRAMING_ERROR; if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) info->read_status_mask |= RXSTATUS_BREAK_RECEIVED; if (I_IGNPAR(info->tty)) info->ignore_status_mask |= RXSTATUS_PARITY_ERROR | RXSTATUS_FRAMING_ERROR; if (I_IGNBRK(info->tty)) { info->ignore_status_mask |= RXSTATUS_BREAK_RECEIVED; /* If ignoring parity and break indicators, ignore * overruns too. (For real raw support). */ if (I_IGNPAR(info->tty)) info->ignore_status_mask |= RXSTATUS_OVERRUN; } /* reprogram the hardware */ spin_lock_irqsave(&info->irq_spinlock,flags); usc_stop_receiver(info); usc_stop_transmitter(info); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; if ( info->params.mode == MGSL_MODE_HDLC ) usc_set_sync_mode(info); else usc_set_async_mode(info); usc_set_serial_signals(info); /* enable modem signal IRQs and read initial signal states */ usc_EnableStatusIrqs(info,SICR_CTS+SICR_DSR+SICR_DCD+SICR_RI); usc_EnableInterrupts(info, IO_PIN); usc_get_serial_signals(info); if ( cflag & CREAD ) usc_start_receiver(info); spin_unlock_irqrestore(&info->irq_spinlock,flags);} /* end of mgsl_change_params() *//* mgsl_put_char() * * Add a character to the transmit buffer. * * Arguments: tty pointer to tty information structure * ch character to add to transmit buffer * * Return Value: None */static void mgsl_put_char(struct tty_struct *tty, unsigned char ch){ struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; unsigned long flags; if ( debug_level >= DEBUG_LEVEL_INFO ) { printk( "%s(%d):mgsl_put_char(%d) on %s\n", __FILE__,__LINE__,ch,info->device_name); } if (mgsl_paranoia_check(info, tty->device, "mgsl_put_char")) return; if (!tty || !info->xmit_buf) return; spin_lock_irqsave(&info->irq_spinlock,flags); if ( (info->params.mode != MGSL_MODE_HDLC) || !info->tx_active ) { if (info->xmit_cnt < SERIAL_XMIT_SIZE - 1) { info->xmit_buf[info->xmit_head++] = ch; info->xmit_head &= SERIAL_XMIT_SIZE-1; info->xmit_cnt++; } } spin_unlock_irqrestore(&info->irq_spinlock,flags); } /* end of mgsl_put_char() *//* mgsl_flush_chars() * * Enable transmitter so remaining characters in the * transmit buffer are sent. * * Arguments: tty pointer to tty information structure * Return Value: None */static void mgsl_flush_chars(struct tty_struct *tty){ struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; unsigned long flags; if ( debug_level >= DEBUG_LEVEL_INFO ) printk( "%s(%d):mgsl_flush_chars() entry on %s xmit_cnt=%d\n", __FILE__,__LINE__,info->device_name,info->xmit_cnt); if (mgsl_paranoia_check(info, tty->device, "mgsl_flush_chars")) return; if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || !info->xmit_buf) return; if ( debug_level >= DEBUG_LEVEL_INFO ) printk( "%s(%d):mgsl_flush_chars() entry on %s starting transmitter\n", __FILE__,__LINE__,info->device_name ); spin_lock_irqsave(&info->irq_spinlock,flags); if (!info->tx_active) { if ( (info->params.mode == MGSL_MODE_HDLC) && info->xmit_cnt ) { /* operating in synchronous (frame oriented) mode */ /* copy data from circular xmit_buf to */ /* transmit DMA buffer. */ mgsl_load_tx_dma_buffer(info, info->xmit_buf,info->xmit_cnt); } usc_start_transmitter(info); } spin_unlock_irqrestore(&info->irq_spinlock,flags); } /* end of mgsl_flush_chars() *//* mgsl_write() * * Send a block of data * * Arguments: * * tty pointer to tty information structure * from_user flag: 1 = from user process * buf pointer to buffer containing send data * count size of send data in bytes * * Return Value: number of characters written */static int mgsl_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count){ int c, ret = 0, err; struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; unsigned long flags; if ( debug_level >= DEBUG_LEVEL_INFO ) printk( "%s(%d):mgsl_write(%s) count=%d\n", __FILE__,__LINE__,info->device_name,count); if (mgsl_paranoia_check(info, tty->device, "mgsl_write")) goto cleanup; if (!tty || !info->xmit_buf || !tmp_buf) goto cleanup; if ( info->params.mode == MGSL_MODE_HDLC ) { /* operating in synchronous (frame oriented) mode */ if (info->tx_active) { ret = 0; goto cleanup; } if ( info->xmit_cnt ) { /* Send accumulated from send_char() calls */ /* as frame and wait before accepting more data. */ ret = 0; /* copy data from circular xmit_buf to */ /* transmit DMA buffer. */ mgsl_load_tx_dma_buffer(info, info->xmit_buf,info->xmit_cnt); if ( debug_level >= DEBUG_LEVEL_INFO ) printk( "%s(%d):mgsl_write(%s) sync xmit_cnt flushing\n", __FILE__,__LINE__,info->device_name); } else { if ( debug_level >= DEBUG_LEVEL_INFO ) printk( "%s(%d):mgsl_write(%s) sync transmit accepted\n", __FILE__,__LINE__,info->device_name); ret = count; info->xmit_cnt = count; if (from_user) { down(&tmp_buf_sem); COPY_FROM_USER(err,tmp_buf, buf, count); if (err) { if ( debug_level >= DEBUG_LEVEL_INFO ) printk( "%s(%d):mgsl_write(%s) sync user buf copy failed\n", __FILE__,__LINE__,info->device_name); ret = -EFAULT; } else mgsl_load_tx_dma_buffer(info,tmp_buf,count); up(&tmp_buf_sem); } else mgsl_load_tx_dma_buffer(info,buf,count); } } else { if (from_user) { down(&tmp_buf_sem); while (1) { c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) break; COPY_FROM_USER(err,tmp_buf, buf, c); c -= err; if (!c) { if (!ret) ret = -EFAULT; break; } spin_lock_irqsave(&info->irq_spinlock,flags); c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); info->xmit_head = ((info->xmit_head + c) & (SERIAL_XMIT_SIZE-1)); info->xmit_cnt += c; spin_unlock_irqrestore(&info->irq_spinlock,flags); buf += c; count -= c; ret += c; } up(&tmp_buf_sem); } else { while (1) { spin_lock_irqsave(&info->irq_spinlock,flags); c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) { spin_unlock_irqrestore(&info->irq_spinlock,flags); break; } memcpy(info->xmit_buf + info->xmit_head, buf, c); info->xmit_head = ((info->xmit_head + c) & (SERIAL_XMIT_SIZE-1)); info->xmit_cnt += c; spin_unlock_irqrestore(&info->irq_spinlock,flags); buf += c; count -= c;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -