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

📄 ircomm_tty.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
		self->service_type = IRCOMM_3_WIRE_RAW;		self->settings.service_type = IRCOMM_3_WIRE_RAW; /* Default */	}	ret = ircomm_tty_startup(self);	if (ret)		return ret;	ret = ircomm_tty_block_til_ready(self, filp);	if (ret) {		IRDA_DEBUG(2, 		      "%s(), returning after block_til_ready with %d\n", __FUNCTION__ ,		      ret);		return ret;	}	return 0;}/* * Function ircomm_tty_close (tty, filp) * *    This routine is called when a particular tty device is closed. * */static void ircomm_tty_close(struct tty_struct *tty, struct file *filp){	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;	unsigned long flags;	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );	if (!tty)		return;	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);	spin_lock_irqsave(&self->spinlock, flags);	if (tty_hung_up_p(filp)) {		spin_unlock_irqrestore(&self->spinlock, flags);		IRDA_DEBUG(0, "%s(), returning 1\n", __FUNCTION__ );		return;	}	if ((tty->count == 1) && (self->open_count != 1)) {		/*		 * Uh, oh.  tty->count is 1, which means that the tty		 * structure will be freed.  state->count should always		 * be one in these conditions.  If it's greater than		 * one, we've got real problems, since it means the		 * serial port won't be shutdown.		 */		IRDA_DEBUG(0, "%s(), bad serial port count; "			   "tty->count is 1, state->count is %d\n", __FUNCTION__ , 			   self->open_count);		self->open_count = 1;	}	if (--self->open_count < 0) {		IRDA_ERROR("%s(), bad serial port count for ttys%d: %d\n",			   __FUNCTION__, self->line, self->open_count);		self->open_count = 0;	}	if (self->open_count) {		spin_unlock_irqrestore(&self->spinlock, flags);		IRDA_DEBUG(0, "%s(), open count > 0\n", __FUNCTION__ );		return;	}	/* Hum... Should be test_and_set_bit ??? - Jean II */	set_bit(ASYNC_B_CLOSING, &self->flags);	/* We need to unlock here (we were unlocking at the end of this	 * function), because tty_wait_until_sent() may schedule.	 * I don't know if the rest should be protected somehow,	 * so someone should check. - Jean II */	spin_unlock_irqrestore(&self->spinlock, flags);	/*	 * Now we wait for the transmit buffer to clear; and we notify 	 * the line discipline to only process XON/XOFF characters.	 */	tty->closing = 1;	if (self->closing_wait != ASYNC_CLOSING_WAIT_NONE)		tty_wait_until_sent(tty, self->closing_wait);	ircomm_tty_shutdown(self);	if (tty->driver->flush_buffer)		tty->driver->flush_buffer(tty);	if (tty->ldisc.flush_buffer)		tty->ldisc.flush_buffer(tty);	tty->closing = 0;	self->tty = NULL;	if (self->blocked_open) {		if (self->close_delay)			schedule_timeout_interruptible(self->close_delay);		wake_up_interruptible(&self->open_wait);	}	self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);	wake_up_interruptible(&self->close_wait);}/* * Function ircomm_tty_flush_buffer (tty) * *     * */static void ircomm_tty_flush_buffer(struct tty_struct *tty){	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);	/* 	 * Let do_softint() do this to avoid race condition with 	 * do_softint() ;-) 	 */	schedule_work(&self->tqueue);}/* * Function ircomm_tty_do_softint (private_) * *    We use this routine to give the write wakeup to the user at at a *    safe time (as fast as possible after write have completed). This  *    can be compared to the Tx interrupt. */static void ircomm_tty_do_softint(void *private_){	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) private_;	struct tty_struct *tty;	unsigned long flags;	struct sk_buff *skb, *ctrl_skb;	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );	if (!self || self->magic != IRCOMM_TTY_MAGIC)		return;	tty = self->tty;	if (!tty)		return;	/* Unlink control buffer */	spin_lock_irqsave(&self->spinlock, flags);	ctrl_skb = self->ctrl_skb;	self->ctrl_skb = NULL;	spin_unlock_irqrestore(&self->spinlock, flags);	/* Flush control buffer if any */	if(ctrl_skb) {		if(self->flow == FLOW_START)			ircomm_control_request(self->ircomm, ctrl_skb);		/* Drop reference count - see ircomm_ttp_data_request(). */		dev_kfree_skb(ctrl_skb);	}	if (tty->hw_stopped)		return;	/* Unlink transmit buffer */	spin_lock_irqsave(&self->spinlock, flags);		skb = self->tx_skb;	self->tx_skb = NULL;	spin_unlock_irqrestore(&self->spinlock, flags);	/* Flush transmit buffer if any */	if (skb) {		ircomm_tty_do_event(self, IRCOMM_TTY_DATA_REQUEST, skb, NULL);		/* Drop reference count - see ircomm_ttp_data_request(). */		dev_kfree_skb(skb);	}			/* Check if user (still) wants to be waken up */	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 	    tty->ldisc.write_wakeup)	{		(tty->ldisc.write_wakeup)(tty);	}	wake_up_interruptible(&tty->write_wait);}/* * Function ircomm_tty_write (tty, buf, count) * *    This routine is called by the kernel to write a series of characters *    to the tty device. The characters may come from user space or kernel *    space. This routine will return the number of characters actually *    accepted for writing. This routine is mandatory. */static int ircomm_tty_write(struct tty_struct *tty,			    const unsigned char *buf, int count){	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;	unsigned long flags;	struct sk_buff *skb;	int tailroom = 0;	int len = 0;	int size;	IRDA_DEBUG(2, "%s(), count=%d, hw_stopped=%d\n", __FUNCTION__ , count,		   tty->hw_stopped);	IRDA_ASSERT(self != NULL, return -1;);	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);	/* We may receive packets from the TTY even before we have finished	 * our setup. Not cool.	 * The problem is that we don't know the final header and data size	 * to create the proper skb, so any skb we would create would have	 * bogus header and data size, so need care.	 * We use a bogus header size to safely detect this condition.	 * Another problem is that hw_stopped was set to 0 way before it	 * should be, so we would drop this skb. It should now be fixed.	 * One option is to not accept data until we are properly setup.	 * But, I suspect that when it happens, the ppp line discipline	 * just "drops" the data, which might screw up connect scripts.	 * The second option is to create a "safe skb", with large header	 * and small size (see ircomm_tty_open() for values).	 * We just need to make sure that when the real values get filled,	 * we don't mess up the original "safe skb" (see tx_data_size).	 * Jean II */	if (self->max_header_size == IRCOMM_TTY_HDR_UNINITIALISED) {		IRDA_DEBUG(1, "%s() : not initialised\n", __FUNCTION__);#ifdef IRCOMM_NO_TX_BEFORE_INIT		/* We didn't consume anything, TTY will retry */		return 0;#endif	}	if (count < 1)		return 0;	/* Protect our manipulation of self->tx_skb and related */	spin_lock_irqsave(&self->spinlock, flags);	/* Fetch current transmit buffer */	skb = self->tx_skb;	/*  	 * Send out all the data we get, possibly as multiple fragmented	 * frames, but this will only happen if the data is larger than the	 * max data size. The normal case however is just the opposite, and	 * this function may be called multiple times, and will then actually	 * defragment the data and send it out as one packet as soon as 	 * possible, but at a safer point in time	 */	while (count) {		size = count;		/* Adjust data size to the max data size */		if (size > self->max_data_size)			size = self->max_data_size;				/* 		 * Do we already have a buffer ready for transmit, or do		 * we need to allocate a new frame 		 */		if (skb) {						/* 			 * Any room for more data at the end of the current 			 * transmit buffer? Cannot use skb_tailroom, since			 * dev_alloc_skb gives us a larger skb than we 			 * requested			 * Note : use tx_data_size, because max_data_size			 * may have changed and we don't want to overwrite			 * the skb. - Jean II			 */			if ((tailroom = (self->tx_data_size - skb->len)) > 0) {				/* Adjust data to tailroom */				if (size > tailroom)					size = tailroom;			} else {				/* 				 * Current transmit frame is full, so break 				 * out, so we can send it as soon as possible				 */				break;			}		} else {			/* Prepare a full sized frame */			skb = dev_alloc_skb(self->max_data_size+					    self->max_header_size);			if (!skb) {				spin_unlock_irqrestore(&self->spinlock, flags);				return -ENOBUFS;			}			skb_reserve(skb, self->max_header_size);			self->tx_skb = skb;			/* Remember skb size because max_data_size may			 * change later on - Jean II */			self->tx_data_size = self->max_data_size;		}		/* Copy data */		memcpy(skb_put(skb,size), buf + len, size);		count -= size;		len += size;	}	spin_unlock_irqrestore(&self->spinlock, flags);	/*     	 * Schedule a new thread which will transmit the frame as soon	 * as possible, but at a safe point in time. We do this so the	 * "user" can give us data multiple times, as PPP does (because of	 * its 256 byte tx buffer). We will then defragment and send out	 * all this data as one single packet.  	 */	schedule_work(&self->tqueue);		return len;}/* * Function ircomm_tty_write_room (tty) * *    This routine returns the numbers of characters the tty driver will *    accept for queuing to be written. This number is subject to change as *    output buffers get emptied, or if the output flow control is acted. */static int ircomm_tty_write_room(struct tty_struct *tty){	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;	unsigned long flags;	int ret;	IRDA_ASSERT(self != NULL, return -1;);	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);#ifdef IRCOMM_NO_TX_BEFORE_INIT	/* max_header_size tells us if the channel is initialised or not. */	if (self->max_header_size == IRCOMM_TTY_HDR_UNINITIALISED)		/* Don't bother us yet */		return 0;#endif	/* Check if we are allowed to transmit any data.	 * hw_stopped is the regular flow control.	 * Jean II */	if (tty->hw_stopped)		ret = 0;	else {		spin_lock_irqsave(&self->spinlock, flags);		if (self->tx_skb)			ret = self->tx_data_size - self->tx_skb->len;		else			ret = self->max_data_size;		spin_unlock_irqrestore(&self->spinlock, flags);	}	IRDA_DEBUG(2, "%s(), ret=%d\n", __FUNCTION__ , ret);	return ret;}/* * Function ircomm_tty_wait_until_sent (tty, timeout) * *    This routine waits until the device has written out all of the *    characters in its transmitter FIFO. */static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout){	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;	unsigned long orig_jiffies, poll_time;	unsigned long flags;		IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);	orig_jiffies = jiffies;	/* Set poll time to 200 ms */	poll_time = IRDA_MIN(timeout, msecs_to_jiffies(200));	spin_lock_irqsave(&self->spinlock, flags);	while (self->tx_skb && self->tx_skb->len) {		spin_unlock_irqrestore(&self->spinlock, flags);		schedule_timeout_interruptible(poll_time);		spin_lock_irqsave(&self->spinlock, flags);		if (signal_pending(current))			break;		if (timeout && time_after(jiffies, orig_jiffies + timeout))			break;	}	spin_unlock_irqrestore(&self->spinlock, flags);	current->state = TASK_RUNNING;}/* * Function ircomm_tty_throttle (tty) * *    This routine notifies the tty driver that input buffers for the line *    discipline are close to full, and it should somehow signal that no *    more characters should be sent to the tty.   */static void ircomm_tty_throttle(struct tty_struct *tty){	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);	/* Software flow control? */	if (I_IXOFF(tty))		ircomm_tty_send_xchar(tty, STOP_CHAR(tty));		/* Hardware flow control? */	if (tty->termios->c_cflag & CRTSCTS) {		self->settings.dte &= ~IRCOMM_RTS;		self->settings.dte |= IRCOMM_DELTA_RTS;			ircomm_param_request(self, IRCOMM_DTE, TRUE);	}        ircomm_flow_request(self->ircomm, FLOW_STOP);}/* * Function ircomm_tty_unthrottle (tty) * *    This routine notifies the tty drivers that it should signals that *    characters can now be sent to the tty without fear of overrunning the *    input buffers of the line disciplines. */static void ircomm_tty_unthrottle(struct tty_struct *tty){	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );	IRDA_ASSERT(self != NULL, return;);	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);	/* Using software flow control? */	if (I_IXOFF(tty)) {		ircomm_tty_send_xchar(tty, START_CHAR(tty));	}	/* Using hardware flow control? */	if (tty->termios->c_cflag & CRTSCTS) {		self->settings.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS);		ircomm_param_request(self, IRCOMM_DTE, TRUE);		IRDA_DEBUG(1, "%s(), FLOW_START\n", __FUNCTION__ );	}        ircomm_flow_request(self->ircomm, FLOW_START);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -