⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jsm_tty.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
	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 + -