📄 jsm_tty.c
字号:
int s = 0; int i = 0; jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n"); if (!ch) return; tp = ch->uart_port.info->tty; bd = ch->ch_bd; if(!bd) return; spin_lock_irqsave(&ch->ch_lock, lock_flags); /* *Figure the number of characters in the buffer. *Exit immediately if none. */ rmask = RQUEUEMASK; head = ch->ch_r_head & rmask; tail = ch->ch_r_tail & rmask; data_len = (head - tail) & rmask; if (data_len == 0) { spin_unlock_irqrestore(&ch->ch_lock, lock_flags); return; } jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start\n"); /* *If the device is not open, or CREAD is off, flush *input data and return immediately. */ if (!tp || !(tp->termios->c_cflag & CREAD) ) { jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "input. dropping %d bytes on port %d...\n", data_len, ch->ch_portnum); ch->ch_r_head = tail; /* Force queue flow control to be released, if needed */ jsm_check_queue_flow_control(ch); spin_unlock_irqrestore(&ch->ch_lock, lock_flags); return; } /* * If we are throttled, simply don't read any data. */ if (ch->ch_flags & CH_STOPI) { spin_unlock_irqrestore(&ch->ch_lock, lock_flags); jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Port %d throttled, not reading any data. head: %x tail: %x\n", ch->ch_portnum, head, tail); return; } jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "start 2\n"); /* * If the rxbuf is empty and we are not throttled, put as much * as we can directly into the linux TTY flip buffer. * The jsm_rawreadok case takes advantage of carnal knowledge that * the char_buf and the flag_buf are next to each other and * are each of (2 * TTY_FLIPBUF_SIZE) size. * * NOTE: if(!tty->real_raw), the call to ldisc.receive_buf *actually still uses the flag buffer, so you can't *use it for input data */ if (jsm_rawreadok) { if (tp->real_raw) flip_len = MYFLIPLEN; else flip_len = 2 * TTY_FLIPBUF_SIZE; } else flip_len = TTY_FLIPBUF_SIZE - tp->flip.count; len = min(data_len, flip_len); len = min(len, (N_TTY_BUF_SIZE - 1) - tp->read_cnt); if (len <= 0) { spin_unlock_irqrestore(&ch->ch_lock, lock_flags); jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input 1\n"); return; } /* * If we're bypassing flip buffers on rx, we can blast it * right into the beginning of the buffer. */ if (jsm_rawreadok) { if (tp->real_raw) { if (ch->ch_flags & CH_FLIPBUF_IN_USE) { jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "JSM - FLIPBUF in use. delaying input\n"); spin_unlock_irqrestore(&ch->ch_lock, lock_flags); return; } ch->ch_flags |= CH_FLIPBUF_IN_USE; buf = ch->ch_bd->flipbuf; buf2 = NULL; } else { buf = tp->flip.char_buf; buf2 = tp->flip.flag_buf; } } else { buf = tp->flip.char_buf_ptr; buf2 = tp->flip.flag_buf_ptr; } n = len; /* * n now contains the most amount of data we can copy, * bounded either by the flip buffer size or the amount * of data the card actually has pending... */ while (n) { s = ((head >= tail) ? head : RQUEUESIZE) - tail; s = min(s, n); if (s <= 0) break; memcpy(buf, ch->ch_rqueue + tail, s); /* buf2 is only set when port isn't raw */ if (buf2) memcpy(buf2, ch->ch_equeue + tail, s); tail += s; buf += s; if (buf2) buf2 += s; n -= s; /* Flip queue if needed */ tail &= rmask; } /* * In high performance mode, we don't have to update * flag_buf or any of the counts or pointers into flip buf. */ if (!jsm_rawreadok) { if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) { for (i = 0; i < len; i++) { /* * Give the Linux ld the flags in the * format it likes. */ if (tp->flip.flag_buf_ptr[i] & UART_LSR_BI) tp->flip.flag_buf_ptr[i] = TTY_BREAK; else if (tp->flip.flag_buf_ptr[i] & UART_LSR_PE) tp->flip.flag_buf_ptr[i] = TTY_PARITY; else if (tp->flip.flag_buf_ptr[i] & UART_LSR_FE) tp->flip.flag_buf_ptr[i] = TTY_FRAME; else tp->flip.flag_buf_ptr[i] = TTY_NORMAL; } } else { memset(tp->flip.flag_buf_ptr, 0, len); } tp->flip.char_buf_ptr += len; tp->flip.flag_buf_ptr += len; tp->flip.count += len; } else if (!tp->real_raw) { if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) { for (i = 0; i < len; i++) { /* * Give the Linux ld the flags in the * format it likes. */ if (tp->flip.flag_buf_ptr[i] & UART_LSR_BI) tp->flip.flag_buf_ptr[i] = TTY_BREAK; else if (tp->flip.flag_buf_ptr[i] & UART_LSR_PE) tp->flip.flag_buf_ptr[i] = TTY_PARITY; else if (tp->flip.flag_buf_ptr[i] & UART_LSR_FE) tp->flip.flag_buf_ptr[i] = TTY_FRAME; else tp->flip.flag_buf_ptr[i] = TTY_NORMAL; } } else memset(tp->flip.flag_buf, 0, len); } /* * If we're doing raw reads, jam it right into the * line disc bypassing the flip buffers. */ if (jsm_rawreadok) { if (tp->real_raw) { ch->ch_r_tail = tail & rmask; ch->ch_e_tail = tail & rmask; jsm_check_queue_flow_control(ch); /* !!! WE *MUST* LET GO OF ALL LOCKS BEFORE CALLING RECEIVE BUF !!! */ spin_unlock_irqrestore(&ch->ch_lock, lock_flags); jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input. %d real_raw len:%d calling receive_buf for board %d\n", __LINE__, len, ch->ch_bd->boardnum); tp->ldisc.receive_buf(tp, ch->ch_bd->flipbuf, NULL, len); /* Allow use of channel flip buffer again */ spin_lock_irqsave(&ch->ch_lock, lock_flags); ch->ch_flags &= ~CH_FLIPBUF_IN_USE; spin_unlock_irqrestore(&ch->ch_lock, lock_flags); } else { ch->ch_r_tail = tail & rmask; ch->ch_e_tail = tail & rmask; jsm_check_queue_flow_control(ch); /* !!! WE *MUST* LET GO OF ALL LOCKS BEFORE CALLING RECEIVE BUF !!! */ spin_unlock_irqrestore(&ch->ch_lock, lock_flags); jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input. %d not real_raw len:%d calling receive_buf for board %d\n", __LINE__, len, ch->ch_bd->boardnum); tp->ldisc.receive_buf(tp, tp->flip.char_buf, tp->flip.flag_buf, len); } } else { ch->ch_r_tail = tail & rmask; ch->ch_e_tail = tail & rmask; jsm_check_queue_flow_control(ch); spin_unlock_irqrestore(&ch->ch_lock, lock_flags); jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input. %d not jsm_read raw okay scheduling flip\n", __LINE__); tty_schedule_flip(tp); } jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n");}static void jsm_carrier(struct jsm_channel *ch){ struct jsm_board *bd; int virt_carrier = 0; int phys_carrier = 0; jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, "start\n"); if (!ch) return; bd = ch->ch_bd; if (!bd) return; if (ch->ch_mistat & UART_MSR_DCD) { jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, "mistat: %x D_CD: %x\n", ch->ch_mistat, ch->ch_mistat & UART_MSR_DCD); phys_carrier = 1; } if (ch->ch_c_cflag & CLOCAL) virt_carrier = 1; jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, "DCD: physical: %d virt: %d\n", phys_carrier, virt_carrier); /* * Test for a VIRTUAL carrier transition to HIGH. */ if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) { /* * When carrier rises, wake any threads waiting * for carrier in the open routine. */ jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, "carrier: virt DCD rose\n"); if (waitqueue_active(&(ch->ch_flags_wait))) wake_up_interruptible(&ch->ch_flags_wait); } /* * Test for a PHYSICAL carrier transition to HIGH. */ if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) { /* * When carrier rises, wake any threads waiting * for carrier in the open routine. */ jsm_printk(CARR, INFO, &ch->ch_bd->pci_dev, "carrier: physical DCD rose\n"); if (waitqueue_active(&(ch->ch_flags_wait))) wake_up_interruptible(&ch->ch_flags_wait); } /* * Test for a PHYSICAL transition to low, so long as we aren't * currently ignoring physical transitions (which is what "virtual * carrier" indicates). * * The transition of the virtual carrier to low really doesn't * matter... it really only means "ignore carrier state", not * "make pretend that carrier is there". */ if ((virt_carrier == 0) && ((ch->ch_flags & CH_CD) != 0) && (phys_carrier == 0)) { /* * When carrier drops: * * Drop carrier on all open units. * * Flush queues, waking up any task waiting in the * line discipline. * * Send a hangup to the control terminal. * * Enable all select calls. */ if (waitqueue_active(&(ch->ch_flags_wait))) wake_up_interruptible(&ch->ch_flags_wait); } /* * Make sure that our cached values reflect the current reality. */ if (virt_carrier == 1) ch->ch_flags |= CH_FCAR; else ch->ch_flags &= ~CH_FCAR; if (phys_carrier == 1) ch->ch_flags |= CH_CD; else ch->ch_flags &= ~CH_CD;}void jsm_check_queue_flow_control(struct jsm_channel *ch){ int qleft = 0; /* Store how much space we have left in the queue */ if ((qleft = ch->ch_r_tail - ch->ch_r_head - 1) < 0) qleft += RQUEUEMASK + 1; /* * Check to see if we should enforce flow control on our queue because * the ld (or user) isn't reading data out of our queue fast enuf. * * NOTE: This is done based on what the current flow control of the * port is set for. * * 1) HWFLOW (RTS) - Turn off the UART's Receive interrupt. * This will cause the UART's FIFO to back up, and force * the RTS signal to be dropped. * 2) SWFLOW (IXOFF) - Keep trying to send a stop character to * the other side, in hopes it will stop sending data to us. * 3) NONE - Nothing we can do. We will simply drop any extra data * that gets sent into us when the queue fills up. */ if (qleft < 256) { /* HWFLOW */ if (ch->ch_c_cflag & CRTSCTS) { if(!(ch->ch_flags & CH_RECEIVER_OFF)) { ch->ch_bd->bd_ops->disable_receiver(ch); ch->ch_flags |= (CH_RECEIVER_OFF); jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Internal queue hit hilevel mark (%d)! Turning off interrupts.\n", qleft); } } /* SWFLOW */ else if (ch->ch_c_iflag & IXOFF) { if (ch->ch_stops_sent <= MAX_STOPS_SENT) { ch->ch_bd->bd_ops->send_stop_character(ch); ch->ch_stops_sent++; jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Sending stop char! Times sent: %x\n", ch->ch_stops_sent); } } } /* * Check to see if we should unenforce flow control because * ld (or user) finally read enuf data out of our queue. * * NOTE: This is done based on what the current flow control of the * port is set for. * * 1) HWFLOW (RTS) - Turn back on the UART's Receive interrupt. * This will cause the UART's FIFO to raise RTS back up, * which will allow the other side to start sending data again. * 2) SWFLOW (IXOFF) - Send a start character to * the other side, so it will start sending data to us again. * 3) NONE - Do nothing. Since we didn't do anything to turn off the * other side, we don't need to do anything now. */ if (qleft > (RQUEUESIZE / 2)) { /* HWFLOW */ if (ch->ch_c_cflag & CRTSCTS) { if (ch->ch_flags & CH_RECEIVER_OFF) { ch->ch_bd->bd_ops->enable_receiver(ch); ch->ch_flags &= ~(CH_RECEIVER_OFF); jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Internal queue hit lowlevel mark (%d)! Turning on interrupts.\n", qleft); } } /* SWFLOW */ else if (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) { ch->ch_stops_sent = 0; ch->ch_bd->bd_ops->send_start_character(ch); jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Sending start char!\n"); } }}/* * jsm_tty_write() * * Take data from the user or kernel and send it out to the FEP. * In here exists all the Transparent Print magic as well. */int jsm_tty_write(struct uart_port *port){ int bufcount = 0, n = 0; int data_count = 0,data_count1 =0; u16 head; u16 tail; u16 tmask; u32 remain; int temp_tail = port->info->xmit.tail; struct jsm_channel *channel = (struct jsm_channel *)port; tmask = WQUEUEMASK; head = (channel->ch_w_head) & tmask; tail = (channel->ch_w_tail) & tmask; if ((bufcount = tail - head - 1) < 0) bufcount += WQUEUESIZE; n = bufcount; n = min(n, 56); remain = WQUEUESIZE - head; data_count = 0; if (n >= remain) { n -= remain; while ((port->info->xmit.head != temp_tail) && (data_count < remain)) { channel->ch_wqueue[head++] = port->info->xmit.buf[temp_tail]; temp_tail++; temp_tail &= (UART_XMIT_SIZE - 1); data_count++; } if (data_count == remain) head = 0; } data_count1 = 0; if (n > 0) { remain = n; while ((port->info->xmit.head != temp_tail) && (data_count1 < remain)) { channel->ch_wqueue[head++] = port->info->xmit.buf[temp_tail]; temp_tail++; temp_tail &= (UART_XMIT_SIZE - 1); data_count1++; } } port->info->xmit.tail = temp_tail; data_count += data_count1; if (data_count) { head &= tmask; channel->ch_w_head = head; } if (data_count) { channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel); } return data_count;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -