// SPDX-License-Identifier: GPL-2.0+ /************************************************************************ * Copyright 2003 Digi International (www.digi.com) * * Copyright (C) 2004 IBM Corporation. All rights reserved. * * Contact Information: * Scott H Kilau <Scott_Kilau@digi.com> * Ananda Venkatarman <mansarov@us.ibm.com> * Modifications: * 01/19/06: changed jsm_input routine to use the dynamically allocated * tty_buffer changes. Contributors: Scott Kilau and Ananda V.
***********************************************************************/ #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/serial_reg.h> #include <linux/delay.h> /* For udelay */ #include <linux/pci.h> #include <linux/slab.h>
#include"jsm.h"
static DECLARE_BITMAP(linemap, MAXLINES);
staticvoid jsm_carrier(struct jsm_channel *ch);
staticinlineint jsm_get_mstat(struct jsm_channel *ch)
{ unsignedchar mstat; int result;
jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, "start\n");
mstat = (ch->ch_mostat | ch->ch_mistat);
result = 0;
if (mstat & UART_MCR_DTR)
result |= TIOCM_DTR; if (mstat & UART_MCR_RTS)
result |= TIOCM_RTS; if (mstat & UART_MSR_CTS)
result |= TIOCM_CTS; if (mstat & UART_MSR_DSR)
result |= TIOCM_DSR; if (mstat & UART_MSR_RI)
result |= TIOCM_RI; if (mstat & UART_MSR_DCD)
result |= TIOCM_CD;
/* * 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.
*/ staticvoid jsm_tty_write(struct uart_port *port)
{ struct jsm_channel *channel;
/* * If we have HUPCL set, lower DTR and RTS
*/ if (channel->ch_c_cflag & HUPCL) {
jsm_dbg(CLOSE, &channel->ch_bd->pci_dev, "Close. HUPCL set, dropping DTR/RTS\n");
/* * jsm_tty_init() * * Init the tty subsystem. Called once per board after board has been * downloaded and init'ed.
*/ int jsm_tty_init(struct jsm_board *brd)
{ int i; void __iomem *vaddr; struct jsm_channel *ch;
if (!brd) return -ENXIO;
jsm_dbg(INIT, &brd->pci_dev, "start\n");
/* * Initialize board structure elements.
*/
brd->nasync = brd->maxports;
/* * Allocate channel memory that might not have been allocated * when the driver was first loaded.
*/ for (i = 0; i < brd->nasync; i++) { if (!brd->channels[i]) {
/* * Okay to malloc with GFP_KERNEL, we are not at * interrupt context, and there are no locks held.
*/
brd->channels[i] = kzalloc(sizeof(struct jsm_channel), GFP_KERNEL); if (!brd->channels[i]) {
jsm_dbg(CORE, &brd->pci_dev, "%s:%d Unable to allocate memory for channel struct\n",
__FILE__, __LINE__);
}
}
}
/* * 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_dbg(READ, &ch->ch_bd->pci_dev, "Port %d throttled, not reading any data. head: %x tail: %x\n",
ch->ch_portnum, head, tail); return;
}
jsm_dbg(READ, &ch->ch_bd->pci_dev, "start 2\n");
len = tty_buffer_request_room(port, data_len);
/* * len 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 (len) {
s = ((head >= tail) ? head : RQUEUESIZE) - tail;
s = min(s, len);
if (s <= 0) break;
/* * If conditions are such that ld needs to see all * UART errors, we will have to walk each character * and error byte and send them to the buffer one at * a time.
*/
if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) { for (i = 0; i < s; i++) {
u8 chr = ch->ch_rqueue[tail + i];
u8 error = ch->ch_equeue[tail + i]; char flag = TTY_NORMAL;
/* * Give the Linux ld the flags in the format it * likes.
*/ if (error & UART_LSR_BI)
flag = TTY_BREAK; elseif (error & UART_LSR_PE)
flag = TTY_PARITY; elseif (error & UART_LSR_FE)
flag = TTY_FRAME;
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;
/* Store how much space we have left in the queue */
qleft = ch->ch_r_tail - ch->ch_r_head - 1; if (qleft < 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)) {
bd_ops->disable_receiver(ch);
ch->ch_flags |= (CH_RECEIVER_OFF);
jsm_dbg(READ, &ch->ch_bd->pci_dev, "Internal queue hit hilevel mark (%d)! Turning off interrupts\n",
qleft);
}
} /* SWFLOW */ elseif (ch->ch_c_iflag & IXOFF) { if (ch->ch_stops_sent <= MAX_STOPS_SENT) {
bd_ops->send_stop_character(ch);
ch->ch_stops_sent++;
jsm_dbg(READ, &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) {
bd_ops->enable_receiver(ch);
ch->ch_flags &= ~(CH_RECEIVER_OFF);
jsm_dbg(READ, &ch->ch_bd->pci_dev, "Internal queue hit lowlevel mark (%d)! Turning on interrupts\n",
qleft);
}
} /* SWFLOW */ elseif (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) {
ch->ch_stops_sent = 0;
bd_ops->send_start_character(ch);
jsm_dbg(READ, &ch->ch_bd->pci_dev, "Sending start char!\n");
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.