patch-2.3.16 linux/net/irda/ircomm/irvtd_driver.c

Next file: linux/net/irda/irda_device.c
Previous file: linux/net/irda/ircomm/ircomm_tty_ioctl.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.15/linux/net/irda/ircomm/irvtd_driver.c linux/net/irda/ircomm/irvtd_driver.c
@@ -1,2071 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      irvtd_driver.c
- * Version:       
- * Description:   Virtual tty driver (the "port emulation entity" of IrCOMM)
- * Status:        Experimental.
- * Author:        Takahide Higuchi <thiguchi@pluto.dti.ne.jp>
- * Source:        serial.c by Linus Torvalds
- *                isdn_tty.c by Fritz Elfert
- *
- *     Copyright (c) 1998-1999, Takahide Higuchi, <thiguchi@pluto.dti.ne.jp>,
- *     All Rights Reserved.
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of
- *     the License, or (at your option) any later version.
- *
- *     I, Takahide Higuchi, provide no warranty for any of this software.
- *     This material is provided "AS-IS" and at no charge.
- *
- ********************************************************************/
-
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/termios.h>
-#include <linux/tty.h>
-#include <asm/segment.h>
-#include <asm/uaccess.h>
-
-#include <net/irda/irda.h>
-#include <net/irda/irttp.h>
-#include <net/irda/irias_object.h>
-
-#include <net/irda/irvtd.h>
-
-#ifndef MIN
-#define MIN(a,b)        ((a) < (b) ? (a) : (b))
-#endif
-
-#define DO_RESTART
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
-struct tty_driver irvtd_drv;
-struct tty_struct *irvtd_table[COMM_MAX_TTY];
-struct termios *irvtd_termios[COMM_MAX_TTY];
-struct termios *irvtd_termios_locked[COMM_MAX_TTY];
-static int irvtd_refcount;
-struct irvtd_cb **irvtd = NULL;
-
-static char *revision_date = "Wed May 26 00:49:11 1999";
-
-
-/*
- * prototypes
- */
-
-int irvtd_open(struct tty_struct *tty, struct file *filp);
-void irvtd_close(struct tty_struct * tty, struct file * filp);
-int irvtd_write(struct tty_struct * tty, int from_user,
-			const unsigned char *buf, int count);
-void irvtd_put_char(struct tty_struct *tty, unsigned char ch);
-int irvtd_write_room(struct tty_struct *tty);
-int irvtd_chars_in_buffer(struct tty_struct *tty);
-int irvtd_ioctl(struct tty_struct *tty, struct file * file,
-	     unsigned int cmd, unsigned long arg);
-void irvtd_set_termios(struct tty_struct *tty, struct termios * old);
-void irvtd_throttle(struct tty_struct *tty);
-void irvtd_unthrottle(struct tty_struct *tty);
-void irvtd_stop(struct tty_struct *tty);
-void irvtd_start(struct tty_struct *tty);
-void irvtd_hangup(struct tty_struct *tty);
-void irvtd_flush_buffer(struct tty_struct *tty);
-void irvtd_flush_chars(struct tty_struct *tty);
-
-static void change_speed(struct irvtd_cb *driver);
-static void irvtd_write_to_tty( struct irvtd_cb *);
-static void irvtd_send_data_request( struct irvtd_cb *);
-static void irvtd_break(struct tty_struct *tty, int break_state);
-static void irvtd_send_xchar(struct tty_struct *tty, char ch);
-static void irvtd_wait_until_sent(struct tty_struct *tty, int timeout);
-
-static void irvtd_start_tx_timer( struct irvtd_cb *driver, int timeout);
-static void irvtd_tx_timer_expired(unsigned long data);
-static void irvtd_start_rx_timer( struct irvtd_cb *driver, int timeout);
-static void irvtd_rx_timer_expired(unsigned long data);
-
-static int line_info(char *buf, struct irvtd_cb *driver);
-static int irvtd_read_proc(char *buf, char **start, off_t offset, int len,
-			   int *eof, void *unused);
-
-
-/*
- **********************************************************************
- *
- * ircomm_receive_data() and friends
- *
- * like interrupt handler in the serial.c,we receive data when 
- * ircomm_data_indication comes
- *
- **********************************************************************
- */
-
-
-
-/* 
- * irvtd_write_to_tty
- * send incoming/queued data to tty
- */
-
-static void irvtd_write_to_tty( struct irvtd_cb *driver)
-{	
-	int status, c, flag;
-	struct sk_buff *skb;
-	struct tty_struct *tty = driver->tty;
-	
-	if(driver->rx_disable)
-		return;
-
- 	skb = skb_dequeue(&driver->rxbuff);
-	if(skb == NULL)
-		return; /* there's nothing */
-
-	/* 
-	 * we should parse controlchannel field here. 
-	 * (see process_data() in ircomm.c)
-	 */
-	ircomm_parse_tuples(driver->comm, skb, CONTROL_CHANNEL);
-	
-#ifdef IRVTD_DEBUG_RX
-	printk("received data:");
-	{
-		int i;
-		for ( i=0;i<skb->len;i++)
-			printk("%02x ", skb->data[i]);
-		printk("\n");
-	}
-#endif
-	
-	status = driver->comm->peer_line_status & driver->read_status_mask;
-	
-	/* 
-	 * if there are too many errors which make a character ignored,
-	 * drop characters
-	 */
-
-	if(status & driver->ignore_status_mask){
-		DEBUG(0,__FUNCTION__":some error:ignore characters.\n");
-		dev_kfree_skb(skb);
-		return;
-	}
-	
-	c = MIN(skb->len, (TTY_FLIPBUF_SIZE - tty->flip.count));
-	DEBUG(4, __FUNCTION__"skb_len=%d, tty->flip.count=%d \n"
-	      ,(int)skb->len, tty->flip.count);
-	
-	if (driver->comm->peer_break_signal ) {
-		driver->comm->peer_break_signal = 0;
-		DEBUG(0,"handling break....\n");
-		
-		flag = TTY_BREAK;
-		if (driver->flags & ASYNC_SAK)
-			/*
-			 * do_SAK() seems to be an implementation of the 
-			 * idea called "Secure Attention Key",
-			 * which seems to be discribed in "Orange book".
-			 * (which is published by U.S.military!!?? ,
-			 * see source of do_SAK())
-			 *
-			 * but what kind of security do we need 
-			 * when we use infrared communication??? :p)
-			 */
-			do_SAK(tty);
-	}else if (status & LSR_PE)
-		flag = TTY_PARITY;
-	else if (status & LSR_FE)
-		flag = TTY_FRAME;
-	else if (status & LSR_OE)
-		flag = TTY_OVERRUN;
-	else 
-		flag = TTY_NORMAL;
-	
-	if(c){
-		DEBUG(4,"writing %d chars to tty\n",c);
-		driver->icount.rx += c;
-		memset(tty->flip.flag_buf_ptr, flag, c);
-		memcpy(tty->flip.char_buf_ptr, skb->data, c);
-		tty->flip.flag_buf_ptr += c;
-		tty->flip.char_buf_ptr += c;
-		tty->flip.count += c;
-		skb_pull(skb,c);
-	}
-
-	if(skb->len == 0)
-		dev_kfree_skb(skb);
-	else
-	{
-		/* queue rest of data again */
-		DEBUG(4,__FUNCTION__":retrying frame!\n");
-
-		/* build a dummy control channel */
-		skb_push(skb,1);
-		*skb->data = 0;  /* clen is 0 */
-		skb_queue_head( &driver->rxbuff, skb );
-	}
-	
-	if(c)
-	/* let the process read its buffer! */
-		tty_flip_buffer_push(tty);
-	
-	if(skb_queue_len(&driver->rxbuff)< IRVTD_RX_QUEUE_LOW &&
-	   driver->ttp_stoprx){
-		DEBUG(1, __FUNCTION__"():FLOW_START\n");
-		/* 
-		 * next 2 lines must follow this order since irttp_flow_request()
-		 * will run its rx queue
-		 */
-		driver->ttp_stoprx = 0;
-		irttp_flow_request(driver->comm->tsap, FLOW_START);
-	}
-
-	if(skb_queue_empty(&driver->rxbuff) && driver->disconnect_pend){
-		/* disconnect */
-		driver->disconnect_pend = 0;
-		driver->rx_disable = 1;
-		tty_hangup(driver->tty);
-	}
-}
-
-static int irvtd_receive_data(void *instance, void *sap, struct sk_buff *skb)
-{	
-	struct irvtd_cb *driver = (struct irvtd_cb *)instance;
-
-	ASSERT(driver != NULL, return -1;);
-	ASSERT(driver->magic == IRVTD_MAGIC, return -1;);
-	DEBUG(4, __FUNCTION__"(): queue frame\n");
-
-	/* queue incoming data and make bottom half handler ready */
-
-	skb_queue_tail( &driver->rxbuff, skb );
-
-	if(skb_queue_len(&driver->rxbuff) > IRVTD_RX_QUEUE_HIGH){
-		DEBUG(1, __FUNCTION__"():FLOW_STOP\n");
-		irttp_flow_request(driver->comm->tsap, FLOW_STOP);
-		driver->ttp_stoprx = 1;
-	}
-	irvtd_write_to_tty(driver);
-
-	if(!skb_queue_empty(&driver->rxbuff))
-		irvtd_start_rx_timer(driver,0);
-	return 0;
-}
-
-/*
- ***********************************************************************
- *
- * irvtd_send_data() and friends
- *
- * like interrupt handler in the serial.c,we send data when 
- * a timer is expired
- *
- ***********************************************************************
- */
-
-
-static void irvtd_start_tx_timer( struct irvtd_cb *driver, int timeout)
-{
-	ASSERT( driver != NULL, return;);
-	ASSERT( driver->magic == IRVTD_MAGIC, return;);
-
-	del_timer( &driver->tx_timer);
-	
-	driver->tx_timer.data     = (unsigned long) driver;
-	driver->tx_timer.function = &irvtd_tx_timer_expired;
-	driver->tx_timer.expires  = jiffies + timeout;
-	
-	add_timer( &driver->tx_timer);
-}
-
-static void irvtd_start_rx_timer( struct irvtd_cb *driver, int timeout)
-{
-	ASSERT( driver != NULL, return;);
-	ASSERT( driver->magic == IRVTD_MAGIC, return;);
-
-	del_timer( &driver->rx_timer);
-	
-	driver->rx_timer.data     = (unsigned long) driver;
-	driver->rx_timer.function = &irvtd_rx_timer_expired;
-	driver->rx_timer.expires  = jiffies + timeout;
-	
-	add_timer( &driver->rx_timer);
-}
-
-
-static void irvtd_tx_timer_expired(unsigned long data)
-{
-	struct irvtd_cb *driver = (struct irvtd_cb *)data;
-
-	ASSERT(driver != NULL,return;);
-	ASSERT(driver->magic == IRVTD_MAGIC,return;);
-	DEBUG(4, __FUNCTION__"()\n");
-
-	irvtd_send_data_request(driver);
-}
-
-static void irvtd_rx_timer_expired(unsigned long data)
-{
-	struct irvtd_cb *driver = (struct irvtd_cb *)data;
-
-	ASSERT(driver != NULL,return;);
-	ASSERT(driver->magic == IRVTD_MAGIC,return;);
-	DEBUG(4, __FUNCTION__"()\n");
-
-	while(TTY_FLIPBUF_SIZE - driver->tty->flip.count
-	      && !skb_queue_empty(&driver->rxbuff))
-		irvtd_write_to_tty(driver);
-
-	DEBUG(1, __FUNCTION__"(): room in flip_buffer = %d\n",
-	      TTY_FLIPBUF_SIZE - driver->tty->flip.count);
-	
-	if(!skb_queue_empty(&driver->rxbuff))
-		/* handle it later */
-		irvtd_start_rx_timer(driver, 1);
-}
-
-
-static void irvtd_send_data_request(struct irvtd_cb *driver)
-{
-	int err;
-	struct sk_buff *skb = driver->txbuff;
-
-	ASSERT(skb != NULL,return;);
-	DEBUG(4, __FUNCTION__"()\n");
-
-	if(driver->tty->hw_stopped || driver->tx_disable)
-		return;
-	if(!skb->len)
-		return;   /* no data to send */
-
-#ifdef IRVTD_DEBUG_TX
-	DEBUG(4, "flush_txbuff:count(%d)\n",(int)skb->len);
-	{
-		int i;
-		for ( i=0;i<skb->len;i++)
-			printk("%02x", skb->data[i]);
-		printk("\n");
-	}
-#endif
-
-	DEBUG(1, __FUNCTION__"():len = %d, room = %d\n",(int)skb->len,
-	      skb_tailroom(skb));
-	driver->icount.tx += skb->len;
-	err = ircomm_data_request(driver->comm, driver->txbuff);
-	if (err){
-		ASSERT(err == 0,;);
-		DEBUG(1,"%d chars are lost\n",(int)skb->len);
-		skb_trim(skb, 0);
-	}
-
-	/* allocate a new frame */
-	skb = driver->txbuff 
-		= dev_alloc_skb(driver->tx_max_sdu_size + driver->max_header_size);
-	if (skb == NULL){
-		printk(__FUNCTION__"():alloc_skb failed!\n");
-	} else {
-		skb_reserve(skb, driver->max_header_size);
-	}
-
-	wake_up_interruptible(&driver->tty->write_wait);
-}
-
-
-/*
- ***********************************************************************
- *
- * indication/confirmation handlers:
- *
- * these routines are handlers for IrCOMM protocol stack
- *
- ***********************************************************************
- */
-
-/*
- * Function irvtd_connect_confirm (instance, sap, qos, max_sdu_size, skb)
- *
- *    ircomm_connect_request which we have send, has succeeded!
- *
- */
-void irvtd_connect_confirm(void *instance, void *sap, struct qos_info *qos,
-			   __u32 max_sdu_size, __u8 max_header_size, 
-			   struct sk_buff *skb)
-{
-	struct irvtd_cb *driver = (struct irvtd_cb *)instance;
-	ASSERT(driver != NULL, return;);
-	ASSERT(driver->magic == IRVTD_MAGIC, return;);
-
-
-	driver->tx_max_sdu_size = max_sdu_size;
-	driver->max_header_size = max_header_size;
-	/*
-	 * set default value
-	 */
-	
-	driver->msr |= (MSR_DCD|MSR_RI|MSR_DSR|MSR_CTS);
-
-	/*
-	 * sending initial control parameters here
-	 */
-	if (driver->comm->servicetype ==	THREE_WIRE_RAW)
-		return;                /* do nothing */
-
-	driver->comm->dte |= (MCR_DTR | MCR_RTS | DELTA_DTR | DELTA_RTS);
-
-	ircomm_control_request(driver->comm, SERVICETYPE);
-	ircomm_control_request(driver->comm, DATA_RATE);
-	ircomm_control_request(driver->comm, DATA_FORMAT);
-	ircomm_control_request(driver->comm, FLOW_CONTROL);
-	ircomm_control_request(driver->comm, XON_XOFF_CHAR);
-	/* ircomm_control_request(driver->comm, ENQ_ACK_CHAR); */
-
-	switch (driver->comm->servicetype) {
-	case CENTRONICS:
-		break;
-
-	case NINE_WIRE:
-		ircomm_control_request(driver->comm, DTELINE_STATE);
-		break;
-	default:
-	}
-	
-	driver->tx_disable = 0;
-	wake_up_interruptible(&driver->open_wait);
-}
-
-/*
- * Function irvtd_connect_indication (instance, sap, qos, max_sdu_size, skb)
- *
- *    we are discovered and being requested to connect by remote device !
- *
- */
-void irvtd_connect_indication(void *instance, void *sap, struct qos_info *qos,
-			      __u32 max_sdu_size, __u8 max_header_size, 
-			      struct sk_buff *skb)
-{
-	struct irvtd_cb *driver = (struct irvtd_cb *)instance;
-	struct ircomm_cb *comm = (struct ircomm_cb *)sap;
-
-	ASSERT(driver != NULL, return;);
-	ASSERT(driver->magic == IRVTD_MAGIC, return;);
-	ASSERT(comm != NULL, return;);
-	ASSERT(comm->magic == IRCOMM_MAGIC, return;);
-
-	driver->tx_max_sdu_size = max_sdu_size;
-	driver->max_header_size = max_header_size;
-	DEBUG(4, __FUNCTION__ "():sending connect_response...\n");
-
-	ircomm_connect_response(comm, NULL, SAR_DISABLE );
-
-	driver->tx_disable = 0;
-
-	/*
-	 * send initial control parameters
-	 */
-	if (driver->comm->servicetype == THREE_WIRE_RAW)
-		return;                /* do nothing */
-
-	driver->comm->dte |= (MCR_DTR | MCR_RTS | DELTA_DTR | DELTA_RTS);
-
-	switch(driver->comm->servicetype){
-	case NINE_WIRE:
-		ircomm_control_request(driver->comm, DTELINE_STATE);
-		break;
-	default:
-		DEBUG(0, __FUNCTION__ "(), not implemented!\n");
-	}
-
-
-	driver->msr |= (MSR_DCD|MSR_RI|MSR_DSR|MSR_CTS);
-	wake_up_interruptible(&driver->open_wait);
-}
-
-/*
- * Function irvtd_disconnect_indication (instance, sap, reason, skb)
- *
- *    This is a handler for ircomm_disconnect_indication. since this
- *    function is called in the context of interrupt handler,
- *    interruptible_sleep_on() MUST not be used.
- */
-void irvtd_disconnect_indication(void *instance, void *sap , LM_REASON reason,
-				 struct sk_buff *skb)
-{
-	struct irvtd_cb *driver = (struct irvtd_cb *)instance;
-
-	ASSERT(driver != NULL, return;);
-	ASSERT(driver->tty != NULL, return;);
-	ASSERT(driver->magic == IRVTD_MAGIC, return;);
-
-	DEBUG(4,"irvtd_disconnect_indication:\n");
-
-	driver->tx_disable = 1;
-	if(skb_queue_empty(&driver->rxbuff)){
-		/* disconnect */
-		driver->rx_disable = 1;
-		tty_hangup(driver->tty);
-	} else {
-		driver->disconnect_pend = 1;
-	}
-}
-
-/*
- * Function irvtd_control_indication (instance, sap, cmd)
- *
- *    
- *
- */
-void irvtd_control_indication(void *instance, void *sap, IRCOMM_CMD cmd)
-{
-	struct irvtd_cb *driver = (struct irvtd_cb *)instance;
-
-	ASSERT(driver != NULL, return;);
-	ASSERT(driver->magic == IRVTD_MAGIC, return;);
-
-	DEBUG(4,__FUNCTION__"()\n");
-
-	if(cmd == TX_READY){
-		driver->ttp_stoptx = 0;
-		driver->tty->hw_stopped = driver->cts_stoptx;
-
-		if(driver->cts_stoptx)
-			return;
-
-		/* push tx queue so that client can send at least 1 octet */
-		irvtd_send_data_request(driver);
-		/* 
-		 * driver->tty->write_wait will keep asleep if
-		 * our txbuff is full.
-		 * now that we can send packets to IrTTP layer,
-		 * we kick it here.
-		 */
-		if ((driver->tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && 
-		    driver->tty->ldisc.write_wakeup)
-			(driver->tty->ldisc.write_wakeup)(driver->tty);
-		return;
-	}
-
-	if(cmd == TX_BUSY){
-		driver->ttp_stoptx = driver->tty->hw_stopped = 1;
-		del_timer( &driver->tx_timer);
-		return;
-	}
-
-
-	ASSERT(cmd == CONTROL_CHANNEL,return;);
-
-	switch(driver->comm->pi){
-
-	case DCELINE_STATE:
-	driver->msr = driver->comm->peer_dce;
-
-	if(driver->msr & (DELTA_CTS|DELTA_DSR|DELTA_RI|DELTA_DCD)){
-		if(driver->msr & DELTA_CTS)
-			driver->icount.cts++;
-		if(driver->msr & DELTA_DSR)
-			driver->icount.dsr++;
-		if(driver->msr & DELTA_RI)
-			driver->icount.rng++;
-		if(driver->msr & DELTA_DCD)
-			driver->icount.dcd++;
-		wake_up_interruptible(&driver->delta_msr_wait);
-	}
-
-	if ((driver->flags & ASYNC_CHECK_CD) && (driver->msr & DELTA_DCD)) {
-
-		DEBUG(0,"CD now %s...\n",
-		      (driver->msr & MSR_DCD) ? "on" : "off");
-
-		if (driver->msr & MSR_DCD)
-		{
-			/* DCD raised! */
-			wake_up_interruptible(&driver->open_wait);
-		}
-		else
-		{
-			/* DCD falled */
-                        DEBUG(0,__FUNCTION__"():hangup..\n");
-			tty_hangup(driver->tty);
-		}
-
-	}
-
-	if (driver->comm->flow_ctrl & USE_CTS) {
-		if (driver->tty->hw_stopped) {
-			if (driver->msr & MSR_CTS) {
-				DEBUG(0,"CTS tx start...\n");
-
-				driver->cts_stoptx = 0;
-				driver->tty->hw_stopped = driver->ttp_stoptx;
-				/*  
-				 * replacement of 
-				 * rs_sched_event(info, RS_EVENT_WRITE_WAKEUP)
-				 * in serial.c
-				 */
-
-				if ((driver->tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-				    driver->tty->ldisc.write_wakeup)
-					(driver->tty->ldisc.write_wakeup)(driver->tty);
-
-				wake_up_interruptible(&driver->tty->write_wait);
-				return;
-			}
-		} else {
-			if (!(driver->msr & MSR_CTS)) {
-				DEBUG(0,"CTS tx stop...");
-
-				driver->cts_stoptx = 1;
-				driver->tty->hw_stopped = 1;
-                        }
-                }
-        }
-	break;
-
-	case FLOW_CONTROL:
-	case DATA_RATE:
-	case XON_XOFF_CHAR:
-	case DTELINE_STATE:
-	case ENQ_ACK_CHAR:	/* got this from win95 */
-		/* (maybe) nothing to do  */
-		break;
-	default:
-		DEBUG(0,__FUNCTION__"():PI = 0x%02x is not implemented\n",
-		      (int)driver->comm->pi);
-	}
-}
-
-/*
- ***********************************************************************
- *
- * driver kernel interfaces
- * these functions work as an interface between the kernel and this driver
- *
- ***********************************************************************
- */
-
-
-
-/*
- * ----------------------------------------------------------------------
- * irvtd_open() and friends
- *
- * ----------------------------------------------------------------------
- */
-
-
-static int irvtd_block_til_ready(struct tty_struct *tty, struct file * filp,
-				 struct irvtd_cb *driver)
-{
-
- 	DECLARE_WAITQUEUE(wait,current);
-	int		retval = 0;
-	int		do_clocal = 0;
-
-	/*
-	 * If non-blocking mode is set, or the port is not enabled,
-	 * then make the check up front and then exit.
-	 */
-
-	if ((filp->f_flags & O_NONBLOCK) ||
-	    (tty->flags & (1 << TTY_IO_ERROR))) {
-
-		return 0;
-	}
-
-	if (tty->termios->c_cflag & CLOCAL)
-		do_clocal = 1;
-
-
-	/*
-	 * We wait until ircomm_connect_request() succeed or
-	 *   ircomm_connect_indication comes
-	 */
-
-
-	add_wait_queue(&driver->open_wait, &wait);
-
-	DEBUG(0,__FUNCTION__"():before block( line = %d, count = %d )\n",
-	      driver->line, driver->count);
-
-	driver->blocked_open++;
-
-	/* wait for a connection established */
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		
-		if (tty_hung_up_p(filp) ||
-		    !(driver->flags & ASYNC_INITIALIZED)) {
-#ifdef DO_RESTART
-			if (driver->flags & ASYNC_HUP_NOTIFY)
-				retval = -EAGAIN;
-			else
-				retval = -ERESTARTSYS;	
-#else
-			retval = -EAGAIN;
-#endif
-			break;
-		}
-
-		if (!(driver->flags & ASYNC_CLOSING) &&
-		    (driver->comm->state == COMM_CONN) && 
-		    ( do_clocal || (driver->msr & MSR_DCD)))
-			break;
-
-		if(signal_pending(current)){
-			retval = -ERESTARTSYS;
-			break;
-		}
-
-
-		DEBUG(4,__FUNCTION__"():blocking( %s%d, count = %d )\n",
-		      tty->driver.name, driver->line, driver->count);
-
-		schedule();
-	}
-
-	current->state = TASK_RUNNING;
-	remove_wait_queue(&driver->open_wait, &wait);
-
-	driver->blocked_open--;
-
-	DEBUG(1, __FUNCTION__"():after blocking\n");
-
-	if (retval)
-		return retval;
-	return 0;
-}	
-
-static void change_speed(struct irvtd_cb *driver)
-{
-	unsigned cflag,cval;
-
-	if (!driver->tty || !driver->tty->termios || !driver->comm)
-		return;
-	cflag = driver->tty->termios->c_cflag;
-
-	/* 
-	 * byte size and parity
-	 */
-	switch (cflag & CSIZE) 
-	{
-	case CS5: cval = IRCOMM_WLEN5; break;
-	case CS6: cval = IRCOMM_WLEN6; break;
-	case CS7: cval = IRCOMM_WLEN7; break;
-	case CS8: cval = IRCOMM_WLEN8; break;
-	default:  cval = IRCOMM_WLEN5; break;	/* too keep GCC shut... */
-	}
-	if (cflag & CSTOPB) {      /* use 2 stop bit mode */
-		cval |= IRCOMM_STOP2;
-	}
-	if (cflag & PARENB)
-		cval |= IRCOMM_PARENB;    /* enable parity check */
-	if (!(cflag & PARODD))
-		cval |= IRCOMM_PAREVEN;         /* even parity */
-	
-	/* CTS flow control flag and modem status interrupts */
-
-	if (cflag & CRTSCTS)
-		driver->comm->flow_ctrl |= USE_CTS;
-	else
-		driver->comm->flow_ctrl |= ~USE_CTS;
-	
-	if (cflag & CLOCAL)
-		driver->flags &= ~ASYNC_CHECK_CD;
-	else
-		driver->flags |= ASYNC_CHECK_CD;
-	
-	/*
-	 * Set up parity check flag
-	 */
-
-	driver->read_status_mask = LSR_OE;
-	if (I_INPCK(driver->tty))
-		driver->read_status_mask |= LSR_FE | LSR_PE;
-	if (I_BRKINT(driver->tty) || I_PARMRK(driver->tty))
-		driver->read_status_mask |= LSR_BI;
-	
-	/*
-	 * Characters to ignore
-	 */
-	driver->ignore_status_mask = 0;
-	if (I_IGNPAR(driver->tty))
-		driver->ignore_status_mask |= LSR_PE | LSR_FE;
-
-	if (I_IGNBRK(driver->tty)) {
-		driver->ignore_status_mask |= LSR_BI;
-		/*
-		 * If we're ignore parity and break indicators, ignore 
-		 * overruns too.  (For real raw support).
-		 */
-		if (I_IGNPAR(driver->tty)) 
-			driver->ignore_status_mask |= LSR_OE;
-	}
-
-	driver->comm->data_format = cval;
-	ircomm_control_request(driver->comm, DATA_FORMAT);
- 	ircomm_control_request(driver->comm, FLOW_CONTROL);
-}
-
-
-
-
-static int irvtd_startup(struct irvtd_cb *driver)
-{
-	struct ias_object* obj;
-	struct notify_t irvtd_notify;
-
-	/* FIXME: it should not be hard coded */
-	__u8 oct_seq[6] = { 0,1,6,1,1,1 }; 
-
-	DEBUG(4,__FUNCTION__"()\n" );
-	if(driver->flags & ASYNC_INITIALIZED)
-		return 0;
-
-	/*
-	 * initialize our tx/rx buffer
-	 */
-
-	skb_queue_head_init(&driver->rxbuff);
-	driver->txbuff = dev_alloc_skb(COMM_DEFAULT_SDU_SIZE + COMM_MAX_HEADER_SIZE); 
-	if (!driver->txbuff){
-		DEBUG(0,__FUNCTION__"(), alloc_skb failed!\n");
-		return -ENOMEM;
-	}
-	skb_reserve(driver->txbuff, COMM_MAX_HEADER_SIZE);
-
-	irda_notify_init(&irvtd_notify);
-	irvtd_notify.data_indication = irvtd_receive_data;
-	irvtd_notify.connect_confirm = irvtd_connect_confirm;
-	irvtd_notify.connect_indication = irvtd_connect_indication;
-	irvtd_notify.disconnect_indication = irvtd_disconnect_indication;
-	irvtd_notify.flow_indication = irvtd_control_indication;
-	strncpy( irvtd_notify.name, "ircomm_tty", NOTIFY_MAX_NAME);
-	irvtd_notify.instance = driver;
-
-	driver->comm = ircomm_open_instance(irvtd_notify);
-	if (!driver->comm)
-		return -ENODEV;
-
-
-	/* 
-         *  Register with LM-IAS as a server
-         */
-
-	obj = irias_new_object( "IrDA:IrCOMM", IAS_IRCOMM_ID);
-	irias_add_integer_attrib( obj, "IrDA:TinyTP:LsapSel", 
-				  driver->comm->tsap->stsap_sel );
-
-	irias_add_octseq_attrib( obj, "Parameters", &oct_seq[0], 6);
-	irias_insert_object( obj);
-
-	driver->flags |= ASYNC_INITIALIZED;
-
-	if (driver->tty)
-		clear_bit(TTY_IO_ERROR, &driver->tty->flags);
-
-	change_speed(driver);
-
-	/*
-	 * discover a peer device
-	 */
-	if(driver->tty->termios->c_cflag & CRTSCTS)
-	  ircomm_connect_request(driver->comm, NINE_WIRE);
-	else
-	  ircomm_connect_request(driver->comm, THREE_WIRE);
-
-	/* irvtd_start_timer( driver); */
-
-	driver->rx_disable = 0;
-	driver->tx_disable = 1;
-	driver->disconnect_pend = 0;
-	return 0;
-}
-
-
-int irvtd_open(struct tty_struct * tty, struct file * filp)
-{
-	struct irvtd_cb *driver;
-	int retval;
-	int line;
-
-	DEBUG(4, __FUNCTION__"():\n");
-	MOD_INC_USE_COUNT;
-
-	line = MINOR(tty->device) - tty->driver.minor_start;
-	if ((line <0) || (line >= COMM_MAX_TTY)){
-		MOD_DEC_USE_COUNT;
-		return -ENODEV;
-	}
-
-	driver = irvtd[line];
-	ASSERT(driver != NULL, MOD_DEC_USE_COUNT;return -ENOMEM;);
-	ASSERT(driver->magic == IRVTD_MAGIC, MOD_DEC_USE_COUNT;return -EINVAL;);
-
-	driver->count++;
-
-	DEBUG(0, __FUNCTION__"():%s%d count %d\n", tty->driver.name, line, 
-	      driver->count);
-	
-	tty->driver_data = driver;
-	driver->tty = tty;
-
-	driver->tty->low_latency = (driver->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-
-	/*
-	 * If the device is in the middle of being closed, then block
-	 * (sleep) until it's done, then exit.
-	 */
-
-	if (tty_hung_up_p(filp) ||
-	    (driver->flags & ASYNC_CLOSING)) {
-		if (driver->flags & ASYNC_CLOSING)
-			interruptible_sleep_on(&driver->close_wait);
-#ifdef DO_RESTART
-		if (driver->flags & ASYNC_HUP_NOTIFY)
-			return -EAGAIN;
-		else
-			return -ERESTARTSYS;
-#else
-		return -EAGAIN;
-#endif
-	}
-
-	/* 
-	 * start up discovering process and ircomm_layer 
-	 */
-	
-	retval = irvtd_startup(driver);
-	if (retval){
-		DEBUG(0, __FUNCTION__"():irvtd_startup returns %d\n",retval);
-		return retval;
-	}
-
-	retval = irvtd_block_til_ready(tty, filp, driver);
-	if (retval){
-		DEBUG(0,__FUNCTION__
-		      "():returning after block_til_ready (errno = %d)\n", retval);
-                return retval;
-	}
-
-	driver->session = current->session;
-	driver->pgrp = current->pgrp;
-	return 0;
-}
-
-
-
-
-
-/*
- * ----------------------------------------------------------------------
- * irvtd_close() and friends
- *
- * most of this function is stolen from serial.c
- * ----------------------------------------------------------------------
- */
-
-/*
- * Function irvtd_wait_until_sent (tty, timeout)
- *
- *    wait until Tx queue of IrTTP is empty 
- *
- */
-static void irvtd_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
-	unsigned long orig_jiffies;
-
-	ASSERT(driver != NULL, return;);
-	ASSERT(driver->magic == IRVTD_MAGIC, return;);
-	ASSERT(driver->comm != NULL, return;);
-
-	DEBUG(1, __FUNCTION__"():\n");	
-	if(!tty->closing)
-		return;   /* nothing to do */
-	
-	/* 
-	 * at disconnection, we should wait until Tx queue of IrTTP is
-	 * flushed
-	 */
-
- 	ircomm_disconnect_request(driver->comm, NULL, P_NORMAL);
-	orig_jiffies = jiffies;
-
-	while (driver->comm->tsap->disconnect_pend) {
-		DEBUG(1, __FUNCTION__"():wait..\n");
-		current->state = TASK_INTERRUPTIBLE;
-		current->counter = 0;	/* make us low-priority */
-		schedule_timeout(HZ);    /* 1sec */
-		if (signal_pending(current))
-			break;
-		if (timeout && time_after(jiffies, orig_jiffies + timeout))
-			break;
-	}
-	current->state = TASK_RUNNING;
-}
-
-
-static void irvtd_shutdown(struct irvtd_cb * driver)
-{
-	unsigned long	flags;
-
-	if (!(driver->flags & ASYNC_INITIALIZED))
-		return;
-
-	DEBUG(1,__FUNCTION__"()\n");
-
-	/*
-	 * This comment is written in serial.c:
-	 *
-	 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
-	 * here so the queue might never be waken up
-	 */
- 	wake_up_interruptible(&driver->delta_msr_wait);
-	
-	/* clear DTR and RTS */
-	if (!driver->tty || (driver->tty->termios->c_cflag & HUPCL))
- 		driver->mcr &= ~(MCR_DTR|MCR_RTS);
-
-	driver->comm->dte = driver->mcr;
-	ircomm_control_request(driver->comm, DTELINE_STATE );
-
-
-
-	save_flags(flags); cli(); /* Disable interrupts */
-
-	if (driver->tty)
-		set_bit(TTY_IO_ERROR, &driver->tty->flags);
-	
-	del_timer( &driver->tx_timer);
-	del_timer( &driver->rx_timer);
-
-	irias_delete_object("IrDA:IrCOMM");
-
-	/*
-	 * Free the transmit buffer here 
-	 */
-
-	while(skb_queue_len(&driver->rxbuff)){
-		struct sk_buff *skb;
-		skb = skb_dequeue( &driver->rxbuff);
-		dev_kfree_skb(skb);
-	}
-	if(driver->txbuff){
-		dev_kfree_skb(driver->txbuff);
-		driver->txbuff = NULL;
-	}
-	ircomm_close_instance(driver->comm);
-	driver->comm = NULL;
-	driver->flags &= ~ASYNC_INITIALIZED;
-	restore_flags(flags);
-}
-
-void irvtd_close(struct tty_struct * tty, struct file * filp)
-{
-	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
-	int line;
-	unsigned long flags;
-
-	DEBUG(1, __FUNCTION__"():refcount= %d\n",irvtd_refcount);
-
-	ASSERT(driver != NULL, return;);
-	ASSERT(driver->magic == IRVTD_MAGIC, return;);
-
-	save_flags(flags);cli();
-
-
-	if(tty_hung_up_p(filp)){
-		/*
-		 * upper tty layer caught a HUP signal and called irvtd_hangup()
-		 * before. so we do nothing here.
-		 */
-		DEBUG(1, __FUNCTION__"():tty_hung_up_p.\n");
-		MOD_DEC_USE_COUNT;
-		restore_flags(flags);
-		return;
-	}
-	
-
-	line = MINOR(tty->device) - tty->driver.minor_start;
-	DEBUG(0, __FUNCTION__"():%s%d count %d\n", tty->driver.name, line, 
-	      driver->count);
-
-	if ((tty->count == 1) && (driver->count != 1)) {
-		/*
-		 * Uh, oh.  tty->count is 1, which means that the tty
-		 * structure will be freed.  Driver->count should always
-		 * be one in these conditions.  If it's greater than
-		 * one, we've got real problems, since it means the
-		 * ircomm service layer won't be shutdown.
-		 */
-		printk(KERN_ERR"irvtd_close: bad serial port count;" 
-		       "tty->count is 1, but driver->count is %d\n", driver->count);
-		driver->count = 1;
-	}
-	if (--driver->count < 0) {
-		printk(KERN_ERR"irvtd_close: bad count for line%d: %d\n",
-		       line, driver->count);
-		driver->count = 0;
-	}
-
-	if (driver->count) { 	/* do nothing */
-		DEBUG(0, __FUNCTION__"():driver->count is not 0\n");
-		MOD_DEC_USE_COUNT;
-		restore_flags(flags);
-		return; 
-	}
-
-	driver->flags |= ASYNC_CLOSING;
-	
-	/*
-	 * 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 (driver->closing_wait != ASYNC_CLOSING_WAIT_NONE){
-		DEBUG(4, __FUNCTION__"():calling tty_wait_until_sent()\n");
-		tty_wait_until_sent(tty, driver->closing_wait);
-	}
-	/* 
-	 * we can send disconnect_request with P_HIGH since
-	 * tty_wait_until_sent() and irvtd_wait_until_sent() should
-	 * have disconnected the link
-	 */
-	ircomm_disconnect_request(driver->comm, NULL, P_HIGH);
-	
-	/* 
-	 * Now we stop accepting input.
-	 */
-
-	driver->rx_disable = TRUE;
-	/* drop ldisc's buffer */
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
-
- 	if (tty->driver.flush_buffer) 
- 		tty->driver.flush_buffer(driver->tty);  
-
-	tty->closing = 0;
-	driver->tty = NULL;
-
-	if (driver->blocked_open)
-	{
-		if (driver->close_delay) {
-			/* kill time */
-			current->state = TASK_INTERRUPTIBLE;
-			schedule_timeout(driver->close_delay);
-		}
-		wake_up_interruptible(&driver->open_wait);
-	}
-	irvtd_shutdown(driver);
-	driver->flags &= ~ASYNC_CLOSING;
-        wake_up_interruptible(&driver->close_wait); 
-
-	MOD_DEC_USE_COUNT;
-        restore_flags(flags);
-	DEBUG(4, __FUNCTION__"():done\n");
-}
-
-/*
- * ----------------------------------------------------------------------
- * irvtd_write() and friends
- * This routine will be called when something data are passed from
- * kernel or user.
- * ----------------------------------------------------------------------
- */
-
-int irvtd_write(struct tty_struct * tty, int from_user,
-		const unsigned char *buf, int count)
-{
-	struct irvtd_cb *driver;
-	int c = 0;
-	int wrote = 0;
- 	unsigned long flags;
-	struct sk_buff *skb;
-	__u8 *frame;
-
-	ASSERT(tty != NULL, return -EFAULT;);
-	driver = (struct irvtd_cb *)tty->driver_data;
-	ASSERT(driver != NULL, return -EFAULT;);
-	ASSERT(driver->magic == IRVTD_MAGIC, return -EFAULT;);
-
-	DEBUG(4, __FUNCTION__"()\n");
-
-	save_flags(flags);
-	while(count > 0){
-		cli();
-		skb = driver->txbuff;
-		ASSERT(skb != NULL, break;);
-		c = MIN(count, (skb_tailroom(skb)));
-		if (c <= 0)
-		{
-			if(!driver->ttp_stoptx)
-			{
-				irvtd_send_data_request(driver);
-				continue;
-			}
-			else
-				break;
-		}
-
-		/* write to the frame */
-
-		frame = skb_put(skb,c);
-		if(from_user){
-			copy_from_user(frame,buf,c);
-		} else
-			memcpy(frame, buf, c);
-
-		restore_flags(flags);
-		wrote += c;
-		count -= c;
-		buf += c;
-	}
-	restore_flags(flags);
-	irvtd_send_data_request(driver);
-	return (wrote);
-}
-
-void irvtd_flush_chars(struct tty_struct *tty)
-{
-	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
-	ASSERT( driver != NULL, return;);
-	ASSERT( driver->magic == IRVTD_MAGIC, return;);
-
-	DEBUG(4, __FUNCTION__"()\n");
-	irvtd_send_data_request(driver);
-}
-
-
-/*
- * Function irvtd_put_char (tty, ch)
- *
- *    This routine is called by the kernel to pass a single character.
- *    If we exausted our buffer,we can ignore the character!
- *
- */
-void irvtd_put_char(struct tty_struct *tty, unsigned char ch)
-{
-	__u8 *frame ;
-	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
-	struct sk_buff *skb;
-	unsigned long flags;
-
-	ASSERT(driver != NULL, return;);
-	DEBUG(4, __FUNCTION__"()\n");
-
-
- again:
-	save_flags(flags);cli();
-	skb = driver->txbuff;
-	ASSERT(skb != NULL,return;);
-	if(!skb_tailroom(skb))
-	{
-		restore_flags(flags);
-		irvtd_send_data_request(driver);
-		goto again;
-	}
-	ASSERT(skb_tailroom(skb) > 0, return;);
-	DEBUG(4, "irvtd_put_char(0x%02x) skb_len(%d) room(%d):\n",
-	      (int)ch ,(int)skb->len,
-	      skb_tailroom(skb));
-
-	/* append a character  */
-	frame = skb_put(skb,1);
-	frame[0] = ch;
-
-	restore_flags(flags);
-	irvtd_start_tx_timer(driver,20);
-	return;
-}
-
-/*
- * Function irvtd_write_room (tty)
- *
- *    This routine returns the room that our buffer has now.
- *
- */
-int irvtd_write_room(struct tty_struct *tty){
-
-	int ret;
-	struct sk_buff *skb = ((struct irvtd_cb *) tty->driver_data)->txbuff;
-
-	ASSERT(skb !=NULL, return 0;);
-
-	ret = skb_tailroom(skb);
-
-	DEBUG(4, __FUNCTION__"(): room is %d bytes\n",ret);
-
-	return(ret);
-}
-
-/*
- * Function irvtd_chars_in_buffer (tty)
- *
- *    This function returns how many characters which have not been sent yet 
- *    are still in buffer.
- *
- */
-int irvtd_chars_in_buffer(struct tty_struct *tty){
-
-	struct sk_buff *skb;
-	unsigned long flags;
-
-	DEBUG(4, __FUNCTION__"()\n");
-
-	save_flags(flags);cli();
-	skb = ((struct irvtd_cb *) tty->driver_data)->txbuff;
-	if(skb == NULL) goto err;
-
-	restore_flags(flags);
-	return (skb->len );
-err:	
-	ASSERT(skb != NULL, ;);
-	restore_flags(flags);
-	return 0;   /* why not -EFAULT or such? see driver/char/serial.c */
-}
-
-/*
- * Function irvtd_break (tty, break_state)
- *
- *    Routine which turns the break handling on or off
- *
- */
-static void irvtd_break(struct tty_struct *tty, int break_state){
-	
- 	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
-	unsigned long flags;
-
-	DEBUG(0, __FUNCTION__"()\n");
-	ASSERT(tty->driver_data != NULL, return;);
-	ASSERT(driver->magic == IRVTD_MAGIC, return;);
-	
-	save_flags(flags);cli();
-	if (break_state == -1)
-	{
-		driver->comm->break_signal = 0x01;
-		ircomm_control_request(driver->comm, BREAK_SIGNAL);
-
-	}
-	else
-	{
-		driver->comm->break_signal = 0x00;
-		ircomm_control_request(driver->comm, BREAK_SIGNAL);
-
-	}
-
-	restore_flags(flags);
-}
-
-/*
- * ----------------------------------------------------------------------
- * irvtd_ioctl() and friends
- * This routine allows us to implement device-specific ioctl's.
- * If passed ioctl number (i.e.cmd) is unknown one, we should return 
- * ENOIOCTLCMD.
- *
- * TODO: we can't use setserial on IrCOMM because some ioctls are not implemented.
- * we should add some ioctls and make some tool which is resemble to setserial.
- * ----------------------------------------------------------------------
- */
-
-static int get_modem_info(struct irvtd_cb * driver, unsigned int *value)
-{
-	unsigned int result;
-	result =  ((driver->mcr & MCR_RTS) ? TIOCM_RTS : 0)
-		| ((driver->mcr & MCR_DTR) ? TIOCM_DTR : 0)
-		| ((driver->msr & DELTA_DCD) ? TIOCM_CAR : 0)
-		| ((driver->msr & DELTA_RI) ? TIOCM_RNG : 0)
-		| ((driver->msr & DELTA_DSR) ? TIOCM_DSR : 0)
-		| ((driver->msr & DELTA_CTS) ? TIOCM_CTS : 0);
-	return put_user(result,value);
-}
-
-static int set_modem_info(struct irvtd_cb * driver, unsigned int cmd,
-			  unsigned int *value)
-{ 
-	int error;
-	unsigned int arg;
-
-	error = get_user(arg, value);
-	if(error)
-		return error;
-
-	switch (cmd) {
-	case TIOCMBIS: 
-		if (arg & TIOCM_RTS) 
-			driver->mcr |= MCR_RTS;
-		if (arg & TIOCM_DTR)
-			driver->mcr |= MCR_DTR;
-		break;
-		
-	case TIOCMBIC:
-		if (arg & TIOCM_RTS)
-			driver->mcr &= ~MCR_RTS;
-		if (arg & TIOCM_DTR)
- 			driver->mcr &= ~MCR_DTR;
- 		break;
-		
-	case TIOCMSET:
- 		driver->mcr = ((driver->mcr & ~(MCR_RTS | MCR_DTR))
-			       | ((arg & TIOCM_RTS) ? MCR_RTS : 0)
-			       | ((arg & TIOCM_DTR) ? MCR_DTR : 0));
-		break;
-		
-	default:
-		return -EINVAL;
-	}
-	
-	driver->comm->dte = driver->mcr;
-	ircomm_control_request(driver->comm, DTELINE_STATE );
-
-	return 0;
-}
-
-static int get_serial_info(struct irvtd_cb * driver,
-			   struct serial_struct * retinfo)
-{
-	struct serial_struct tmp;
-   
-	if (!retinfo)
-		return -EFAULT;
-	memset(&tmp, 0, sizeof(tmp));
-	tmp.line = driver->line;
-	tmp.flags = driver->flags;
-	tmp.baud_base = driver->comm->data_rate;
-	tmp.close_delay = driver->close_delay;
-	tmp.closing_wait = driver->closing_wait;
-
-	/* for compatibility  */
-
- 	tmp.type = PORT_16550A;
- 	tmp.port = 0;
- 	tmp.irq = 0;
-	tmp.xmit_fifo_size = 0;
-	tmp.hub6 = 0;   
-	tmp.custom_divisor = driver->custom_divisor;
-
-	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
-		return -EFAULT;
-	return 0;
-}
-
-static int set_serial_info(struct irvtd_cb * driver,
-			   struct serial_struct * new_info)
-{
-	struct serial_struct new_serial;
-	struct irvtd_cb old_driver;
-
-	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
-		return -EFAULT;
-
-	old_driver = *driver;
-  
-	if (!capable(CAP_SYS_ADMIN)) {
-		if ((new_serial.baud_base != driver->comm->data_rate) ||
-		    (new_serial.close_delay != driver->close_delay) ||
-		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
-		     (driver->flags & ~ASYNC_USR_MASK)))
-			return -EPERM;
-		driver->flags = ((driver->flags & ~ASYNC_USR_MASK) |
-				 (new_serial.flags & ASYNC_USR_MASK));
-		driver->custom_divisor = new_serial.custom_divisor;
-		goto check_and_exit;
-	}
-
-	/*
-	 * OK, past this point, all the error checking has been done.
-	 * At this point, we start making changes.....
-	 */
-
-	if(driver->comm->data_rate != new_serial.baud_base){
-		driver->comm->data_rate = new_serial.baud_base;
-		if(driver->comm->state == COMM_CONN)
-			ircomm_control_request(driver->comm,DATA_RATE);
-	}
-	driver->close_delay = new_serial.close_delay * HZ/100;
-	driver->closing_wait = new_serial.closing_wait * HZ/100;
-	driver->custom_divisor = new_serial.custom_divisor;
-
-	driver->flags = ((driver->flags & ~ASYNC_FLAGS) |
-			 (new_serial.flags & ASYNC_FLAGS));
-	driver->tty->low_latency = (driver->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-
- check_and_exit:
-	if (driver->flags & ASYNC_INITIALIZED) {
-		if (((old_driver.flags & ASYNC_SPD_MASK) !=
-		     (driver->flags & ASYNC_SPD_MASK)) ||
-		    (old_driver.custom_divisor != driver->custom_divisor)) {
-			if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
-				driver->tty->alt_speed = 57600;
-			if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
-				driver->tty->alt_speed = 115200;
-			if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
-				driver->tty->alt_speed = 230400;
-			if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
-				driver->tty->alt_speed = 460800;
-			change_speed(driver);
-		}
-	}
-	return 0;
-}
-
-
-
-
-int irvtd_ioctl(struct tty_struct *tty, struct file * file,
-		unsigned int cmd, unsigned long arg)
-{
-	int error;
-	unsigned long flags;
- 	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
-
-	struct serial_icounter_struct cnow,cprev;
-	struct serial_icounter_struct *p_cuser;	/* user space */
-
-
-	DEBUG(4,"irvtd_ioctl:requested ioctl(0x%08x)\n",cmd);
-
-#ifdef IRVTD_DEBUG_IOCTL
-	{
-		/* kill time so that debug messages will come slowly  */
-		save_flags(flags);cli();
-		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + HZ/4; /*0.25sec*/
-		schedule();
-		restore_flags(flags);
-	}
-#endif
-
-
-
-	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
-	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
-	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
-		if (tty->flags & (1 << TTY_IO_ERROR)){
-			return -EIO;
-		}
-	}
-	
-	switch (cmd) {
-
-	case TIOCMGET:
-		return get_modem_info(driver, (unsigned int *) arg);
-
-	case TIOCMBIS:
-	case TIOCMBIC:
-	case TIOCMSET:
-		return set_modem_info(driver, cmd, (unsigned int *) arg);
-	case TIOCGSERIAL:
-		return get_serial_info(driver, (struct serial_struct *) arg);
-	case TIOCSSERIAL:
-		return set_serial_info(driver, (struct serial_struct *) arg);
-
-
-	case TIOCMIWAIT:
-		save_flags(flags); cli();
-		/* note the counters on entry */
-		cprev = driver->icount;
-		restore_flags(flags);
-		while (1) {
-			interruptible_sleep_on(&driver->delta_msr_wait);
-				/* see if a signal did it */
-			if (signal_pending(current))
-				return -ERESTARTSYS;
-			save_flags(flags); cli();
-			cnow = driver->icount; /* atomic copy */
-			restore_flags(flags);
-			if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 
-			    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
-				return -EIO; /* no change => error */
-			if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
-			     ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
-			     ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
-			     ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
-				return 0;
-			}
-			cprev = cnow;
-		}
-		/* NOTREACHED */
-
-	case TIOCGICOUNT:
-		save_flags(flags); cli();
-		cnow = driver->icount;
-		restore_flags(flags);
-		p_cuser = (struct serial_icounter_struct *) arg;
-		error = put_user(cnow.cts, &p_cuser->cts);
-		if (error) return error;
-		error = put_user(cnow.dsr, &p_cuser->dsr);
-		if (error) return error;
-		error = put_user(cnow.rng, &p_cuser->rng);
-		if (error) return error;
-		error = put_user(cnow.dcd, &p_cuser->dcd);
-		if (error) return error;
-		error = put_user(cnow.rx, &p_cuser->rx);
-		if (error) return error;
-		error = put_user(cnow.tx, &p_cuser->tx);
-		if (error) return error;
-		error = put_user(cnow.frame, &p_cuser->frame);
-		if (error) return error;
-		error = put_user(cnow.overrun, &p_cuser->overrun);
-		if (error) return error;
-		error = put_user(cnow.parity, &p_cuser->parity);
-		if (error) return error;
-		error = put_user(cnow.brk, &p_cuser->brk);
-		if (error) return error;
-		error = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
-		if (error) return error;			
-		return 0;
-		
-		
-		/* ioctls which are imcompatible with serial.c */
-
-	case TIOCSERGSTRUCT:
-		DEBUG(0,__FUNCTION__"():sorry, TIOCSERGSTRUCT is not supported\n");
-		return -ENOIOCTLCMD;  
-	case TIOCSERGETLSR:
-		DEBUG(0,__FUNCTION__"():sorry, TIOCSERGETLSR is not supported\n");
-		return -ENOIOCTLCMD;  
- 	case TIOCSERCONFIG:
-		DEBUG(0,__FUNCTION__"():sorry, TIOCSERCONFIG is not supported\n");
-		return -ENOIOCTLCMD;  
-
-
-	default:
-		return -ENOIOCTLCMD;  /* ioctls which we must ignore */
-	}
-	return 0;
-}
-
-
-
-/*
- * ----------------------------------------------------------------------
- * irvtd_set_termios()
- * This is called when termios is changed.
- * If things that changed is significant for us,(i.e. changing baud rate etc.)
- * send something to peer device.
- * ----------------------------------------------------------------------
- */
-
-void irvtd_set_termios(struct tty_struct *tty, struct termios * old_termios){
-
-	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
-
-	ASSERT(driver != NULL,return;);
-	ASSERT(driver->magic == IRVTD_MAGIC ,return;);
-
-	DEBUG(0, "irvtd_set_termios:\n");
-	return;
-
-	if((tty->termios->c_cflag == old_termios->c_cflag) &&
-	   (RELEVANT_IFLAG(tty->termios->c_iflag) 
-	    == RELEVANT_IFLAG(old_termios->c_iflag)))
-		return;
-
-	change_speed(driver);
-
-	if((old_termios->c_cflag & CRTSCTS) &&
-	   !(tty->termios->c_cflag & CRTSCTS)) {
-		tty->hw_stopped = driver->ttp_stoptx;
-		/* irvtd_start(tty); */       /* we don't need this */
-	}
-}
-
-/*
- * ----------------------------------------------------------------------
- * irvtd_throttle,irvtd_unthrottle
- *   These routines will be called when we have to pause sending up data to tty.
- *   We use RTS virtual signal when servicetype is NINE_WIRE
- * ----------------------------------------------------------------------
- */
-
-static void irvtd_send_xchar(struct tty_struct *tty, char ch){
-
-	DEBUG(1, __FUNCTION__"():\n");
-	irvtd_put_char(tty, ch);
-}
-
-void irvtd_throttle(struct tty_struct *tty){
-	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
-
-	DEBUG(1, "irvtd_throttle:\n");
-
-	if (I_IXOFF(tty))
-		irvtd_put_char(tty, STOP_CHAR(tty));
-
-	driver->mcr &= ~MCR_RTS; 
-	driver->mcr |= DELTA_RTS; 
-	driver->comm->dte = driver->mcr;
-	ircomm_control_request(driver->comm, DTELINE_STATE );
-
-	DEBUG(1, __FUNCTION__"():FLOW_STOP\n");
-        irttp_flow_request(driver->comm->tsap, FLOW_STOP);
-}
-
-void irvtd_unthrottle(struct tty_struct *tty){
-	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
-	DEBUG(1, "irvtd_unthrottle:\n");
-
-	if (I_IXOFF(tty))
-		irvtd_put_char(tty, START_CHAR(tty));
-
-	driver->mcr |= (MCR_RTS|DELTA_RTS);
-	driver->comm->dte = driver->mcr;
-	ircomm_control_request(driver->comm, DTELINE_STATE );
-
-	DEBUG(1, __FUNCTION__"():FLOW_START\n");
-        irttp_flow_request(driver->comm->tsap, FLOW_START);
-}
-
-
-/*
- * ------------------------------------------------------------
- * irvtd_stop() and irvtd_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable an interrupt which means "transmitter-is-ready"
- * in serial.c, but  I think these routine are not necessary for us. 
- * ------------------------------------------------------------
- */
-
-#if 0
-irvtd_stop(struct tty_struct *tty){
- 	DEBUG(0, "irvtd_stop()\n");
-
-	struct irvtd_cb *info = (struct irvtd_cb *)tty->driver_data; 
-	DEBUG(0, "irvtd_start():not implemented!\n");
-}
-irvtd_start(struct tty_struct *tty){
-
-	struct irvtd_cb *info = (struct irvtd_cb *)tty->driver_data;
-	DEBUG(0, "irvtd_start():not_implemented!\n");
-}
-#endif
-
-/*
- * ------------------------------------------------------------
- * irvtd_hangup()
- * This routine notifies that tty layer have got HUP signal
- * ------------------------------------------------------------
- */
-
-void irvtd_hangup(struct tty_struct *tty){
-
-	struct irvtd_cb *info = (struct irvtd_cb *)tty->driver_data;
-	DEBUG(0, __FUNCTION__"()\n");
-
-	irvtd_flush_buffer(tty);
-	irvtd_shutdown(info);
-	info->count = 0;
-	info->tty = NULL;
-	wake_up_interruptible(&info->open_wait);
-}
-
-void irvtd_flush_buffer(struct tty_struct *tty){
-
-	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
-	struct sk_buff *skb;
-
-	skb = driver->txbuff;
-	ASSERT(skb != NULL, return;); 
-
-	if(skb->len){
-		DEBUG(0, __FUNCTION__"():%d chars in txbuff are lost..\n",(int)skb->len);
-		skb_trim(skb,0); 
-	}
-	
-	/* write_wait is a wait queue of tty_wait_until_sent().
-	 * see tty_io.c of kernel 
-	 */
-	wake_up_interruptible(&tty->write_wait); 
-
-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-	    tty->ldisc.write_wakeup)
-		(tty->ldisc.write_wakeup)(tty);
-}
-
-
-
-/*
- * Function ircomm_register_device(void), init_module() and friends
- *
- *   we register "port emulation entity"(see IrCOMM specification) here
- *   as a tty device.
- */
-
-int irvtd_register_ttydriver(void){
-
-        DEBUG( 4, "-->irvtd_register_ttydriver\n");
-
-	/* setup virtual serial port device */
-
-        /* Initialize the tty_driver structure ,which is defined in 
-	   tty_driver.h */
-        
-        memset(&irvtd_drv, 0, sizeof(struct tty_driver));
-	irvtd_drv.magic = IRVTD_MAGIC;
-	irvtd_drv.driver_name = "IrCOMM_tty";
-	irvtd_drv.name = "irnine";
-	irvtd_drv.major = IRCOMM_MAJOR;
-	irvtd_drv.minor_start = IRVTD_MINOR;
-	irvtd_drv.num = COMM_MAX_TTY;
-	irvtd_drv.type = TTY_DRIVER_TYPE_SERIAL;  /* see tty_driver.h */
-
-
-	/*
-	 * see drivers/char/tty_io.c and termios(3)
-	 */
-
-        irvtd_drv.init_termios = tty_std_termios;
-        irvtd_drv.init_termios.c_cflag =
-		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-        irvtd_drv.flags = TTY_DRIVER_REAL_RAW;   /* see tty_driver.h */
-        irvtd_drv.refcount = &irvtd_refcount;
-
-	/* pointer to the tty data structures */
-
-        irvtd_drv.table = irvtd_table;  
-        irvtd_drv.termios = irvtd_termios;
-        irvtd_drv.termios_locked = irvtd_termios_locked;
-
-        /*
-         * Interface table from the kernel(tty driver) to the ircomm
-         * layer
-         */
-
-        irvtd_drv.open = irvtd_open;
-        irvtd_drv.close = irvtd_close;
-        irvtd_drv.write = irvtd_write;
-        irvtd_drv.put_char = irvtd_put_char;
-	irvtd_drv.flush_chars = irvtd_flush_chars;
-        irvtd_drv.write_room = irvtd_write_room;
-	irvtd_drv.chars_in_buffer = irvtd_chars_in_buffer; 
-        irvtd_drv.flush_buffer = irvtd_flush_buffer;
- 	irvtd_drv.ioctl = irvtd_ioctl; 
-	irvtd_drv.throttle = irvtd_throttle;
-	irvtd_drv.unthrottle = irvtd_unthrottle;
- 	irvtd_drv.set_termios = irvtd_set_termios;
-	irvtd_drv.stop = NULL;          /*  irvtd_stop; */
-	irvtd_drv.start = NULL;         /* irvtd_start; */
-        irvtd_drv.hangup = irvtd_hangup;
-
-        irvtd_drv.send_xchar = irvtd_send_xchar;
-	irvtd_drv.break_ctl = irvtd_break;
-	irvtd_drv.read_proc = irvtd_read_proc;
- 	irvtd_drv.wait_until_sent = irvtd_wait_until_sent;
-
-
-
-	if (tty_register_driver(&irvtd_drv)){
-		DEBUG(0,"IrCOMM:Couldn't register tty driver\n");
-		return(1);
-	}
-
-	DEBUG( 4, "irvtd_register_ttydriver: done.\n");
-	return(0);
-}
-
-
-/*
- * Function irvtd_unregister_device(void) 
- *   it will be called when you rmmod
- */
-
-void irvtd_unregister_ttydriver(void){
-
-	int err;	
-        DEBUG( 4, "--> irvtd_unregister_device\n");
-
-	/* unregister tty device   */
-
-	err = tty_unregister_driver(&irvtd_drv);
-        if (err)
-                printk("IrCOMM: failed to unregister vtd driver(%d)\n",err);
-        DEBUG( 4, "irvtd_unregister_device -->\n");
-	return;
-}
-
-/*
- **********************************************************************
- *    proc stuff
- *
- **********************************************************************
- */
-
-static int line_info(char *buf, struct irvtd_cb *driver)
-{
-	int	ret=0;
-
-	ASSERT(driver != NULL,goto exit;);
-	ASSERT(driver->magic == IRVTD_MAGIC,goto exit;);
-
-	ret += sprintf(buf, "tx: %d rx: %d"
-		      ,driver->icount.tx, driver->icount.rx);
-
-	if (driver->icount.frame)
-                ret += sprintf(buf+ret, " fe:%d", driver->icount.frame);
-        if (driver->icount.parity)
-                ret += sprintf(buf+ret, " pe:%d", driver->icount.parity);
-        if (driver->icount.brk)
-                ret += sprintf(buf+ret, " brk:%d", driver->icount.brk);  
-        if (driver->icount.overrun)
-                ret += sprintf(buf+ret, " oe:%d", driver->icount.overrun);
-
-	if (driver->mcr & MCR_RTS)
-                ret += sprintf(buf+ret, "|RTS");
-        if (driver->msr & MSR_CTS)
-                ret += sprintf(buf+ret, "|CTS");
-        if (driver->mcr & MCR_DTR)
-                ret += sprintf(buf+ret, "|DTR");
-        if (driver->msr & MSR_DSR)
-                ret += sprintf(buf+ret, "|DSR");
-        if (driver->msr & MSR_DCD)
-                ret += sprintf(buf+ret, "|CD");
-	if (driver->msr & MSR_RI) 
-		ret += sprintf(buf+ret, "|RI");
-
-	ret += sprintf(buf+ret, "\n");
-	ret += sprintf(buf+ret, "rx queue:%d",
-		       skb_queue_len( &driver->rxbuff));
-	ret += sprintf(buf+ret, "ttp_stoprx:%s",
-		       driver->ttp_stoprx?"TRUE":"FALSE");
-
- exit:
-	ret += sprintf(buf+ret, "\n");
-	return ret;
-}
-
-
-
-static int irvtd_read_proc(char *buf, char **start, off_t offset, int len,
-		 int *eof, void *unused)
-{
-	int i, count = 0, l;
-	off_t	begin = 0;
-
-	count += sprintf(buf, "driver revision:%s\n", revision_date);
-	for (i = 0; i < COMM_MAX_TTY && count < 4000; i++) {
-		l = line_info(buf + count, irvtd[i]);
-		count += l;
-		if (count+begin > offset+len)
-			goto done;
-		if (count+begin < offset) {
-			begin += count;
-			count = 0;
-		}
-	}
-	*eof = 1;
-done:
-	if (offset >= count+begin)
-		return 0;
-	*start = buf + (begin-offset);
-	return ((len < begin+count-offset) ? len : begin+count-offset);
-}
-
-
-
-
-/************************************************************
- *    init & cleanup this module 
- ************************************************************/
-
-__initfunc(int irvtd_init(void))
-{
-	int i;
-
-	DEBUG( 4, __FUNCTION__"()\n");
-	printk( KERN_INFO 
-		"ircomm_tty: virtual tty driver for IrCOMM ( revision:%s )\n",
-		revision_date);
-
-
-	/* allocate a master array */
-
-	irvtd = (struct irvtd_cb **) kmalloc( sizeof(void *) *
-						COMM_MAX_TTY,GFP_KERNEL);
-	if ( irvtd == NULL) {
-		printk( KERN_WARNING __FUNCTION__"(): kmalloc failed!\n");
-		return -ENOMEM;
-	}
-
-	memset( irvtd, 0, sizeof(void *) * COMM_MAX_TTY);
-
-	for (i=0; i < COMM_MAX_TTY; i++){
-		irvtd[i] = kmalloc( sizeof(struct irvtd_cb), GFP_KERNEL);	
-		if(irvtd[i] == NULL){
-			printk(KERN_ERR __FUNCTION__"(): kmalloc failed!\n");
-			return -ENOMEM;
-		}
-		memset( irvtd[i], 0, sizeof(struct irvtd_cb));
-		irvtd[i]->magic = IRVTD_MAGIC;
-		irvtd[i]->line = i;
-		irvtd[i]->closing_wait = 10*HZ ;
-		irvtd[i]->close_delay = 5*HZ/10 ; 
-		init_waitqueue_head(&irvtd[i]->open_wait);
-		init_waitqueue_head(&irvtd[i]->close_wait);
-		init_waitqueue_head(&irvtd[i]->tx_wait);
-		init_waitqueue_head(&irvtd[i]->delta_msr_wait);
-	}
-
-	/* 
-	 * initialize a "port emulation entity"
-	 */
-
-	if(irvtd_register_ttydriver()){
-		printk( KERN_WARNING "IrCOMM: Error in ircomm_register_device\n");
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-void irvtd_cleanup(void)
-{
-	int i;
-	DEBUG( 4, __FUNCTION__"()\n");
-
-	/*
-	 * free some resources
-	 */
-	if (irvtd) {
-		for (i=0; i<COMM_MAX_TTY; i++) {
-			if (irvtd[i]) {
-				if(irvtd[i]->comm)
-					ircomm_close_instance(irvtd[i]->comm);
-				if(irvtd[i]->txbuff)
-					dev_kfree_skb(irvtd[i]->txbuff);
-				DEBUG( 4, "freeing structures\n");
-				kfree(irvtd[i]);
-				irvtd[i] = NULL;
-			}
-		}
-		DEBUG( 4, "freeing master array\n");
-		kfree(irvtd);
-		irvtd = NULL;
-	}
-
- 	irvtd_unregister_ttydriver();
-
-}
-
-#ifdef MODULE
-
-int init_module(void) 
-{
-	irvtd_init();
-	return 0;
-}
-
-/*
- * Function ircomm_cleanup (void)
- *   This is called when you rmmod.
- */
-
-void cleanup_module(void)
-{
-	irvtd_cleanup();
-}
-
-#endif /* MODULE */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)