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

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

diff -u --recursive --new-file v2.2.9/linux/net/irda/ircomm/irvtd_driver.c linux/net/irda/ircomm/irvtd_driver.c
@@ -8,7 +8,7 @@
  * Source:        serial.c by Linus Torvalds
  *                isdn_tty.c by Fritz Elfert
  *
- *     Copyright (c) 1998, Takahide Higuchi, <thiguchi@pluto.dti.ne.jp>,
+ *     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
@@ -51,7 +51,7 @@
 static int irvtd_refcount;
 struct irvtd_cb **irvtd = NULL;
 
-static char *revision_date = "Sun Apr 18 17:31:53 1999";
+static char *revision_date = "Wed May 26 00:49:11 1999";
 
 
 /*
@@ -83,8 +83,10 @@
 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_timer( struct irvtd_cb *driver);
-static void irvtd_timer_expired(unsigned long data);
+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,
@@ -118,7 +120,7 @@
 	if(driver->rx_disable)
 		return;
 
-	skb = skb_dequeue(&driver->rxbuff);
+ 	skb = skb_dequeue(&driver->rxbuff);
 	if(skb == NULL)
 		return; /* there's nothing */
 
@@ -211,8 +213,13 @@
 	
 	if(skb_queue_len(&driver->rxbuff)< IRVTD_RX_QUEUE_LOW &&
 	   driver->ttp_stoprx){
-		irttp_flow_request(driver->comm->tsap, FLOW_START);
+		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){
@@ -236,10 +243,14 @@
 	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;
 }
 
@@ -255,22 +266,36 @@
  */
 
 
-static void irvtd_start_timer( struct irvtd_cb *driver)
+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->timer);
+	del_timer( &driver->rx_timer);
 	
-	driver->timer.data     = (unsigned long) driver;
-	driver->timer.function = &irvtd_timer_expired;
-	driver->timer.expires  = jiffies + (HZ / 5);  /* 200msec */
+	driver->rx_timer.data     = (unsigned long) driver;
+	driver->rx_timer.function = &irvtd_rx_timer_expired;
+	driver->rx_timer.expires  = jiffies + timeout;
 	
-	add_timer( &driver->timer);
+	add_timer( &driver->rx_timer);
 }
 
 
-static void irvtd_timer_expired(unsigned long data)
+static void irvtd_tx_timer_expired(unsigned long data)
 {
 	struct irvtd_cb *driver = (struct irvtd_cb *)data;
 
@@ -279,11 +304,26 @@
 	DEBUG(4, __FUNCTION__"()\n");
 
 	irvtd_send_data_request(driver);
+}
 
-	irvtd_write_to_tty(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");
 
-	/* start our timer again and again */
-	irvtd_start_timer(driver);
+	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);
 }
 
 
@@ -310,21 +350,23 @@
 	}
 #endif
 
-	DEBUG(1, __FUNCTION__"():sending %d octets\n",(int)skb->len );
+	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(0,"%d chars are lost\n",(int)skb->len);
+		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->comm->max_txbuff_size);
+	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, COMM_HEADER_SIZE);
+		skb_reserve(skb, driver->max_header_size);
 	}
 
 	wake_up_interruptible(&driver->tty->write_wait);
@@ -341,20 +383,23 @@
  ***********************************************************************
  */
 
-
 /*
  * Function irvtd_connect_confirm (instance, sap, qos, max_sdu_size, skb)
  *
- *    ircomm_connect_request which we have send have succeed!
+ *    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, struct sk_buff *skb)
+			   __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
 	 */
@@ -364,7 +409,7 @@
 	/*
 	 * sending initial control parameters here
 	 */
-	if(driver->comm->servicetype ==	THREE_WIRE_RAW)
+	if (driver->comm->servicetype ==	THREE_WIRE_RAW)
 		return;                /* do nothing */
 
 	driver->comm->dte |= (MCR_DTR | MCR_RTS | DELTA_DTR | DELTA_RTS);
@@ -376,7 +421,7 @@
 	ircomm_control_request(driver->comm, XON_XOFF_CHAR);
 	/* ircomm_control_request(driver->comm, ENQ_ACK_CHAR); */
 
-	switch(driver->comm->servicetype){
+	switch (driver->comm->servicetype) {
 	case CENTRONICS:
 		break;
 
@@ -397,17 +442,20 @@
  *
  */
 void irvtd_connect_indication(void *instance, void *sap, struct qos_info *qos,
-			      __u32 max_sdu_size, struct sk_buff *skb)
+			      __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;);
 
-	DEBUG(4,"irvtd_connect_indication:sending connect_response...\n");
+	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 );
 
@@ -416,7 +464,7 @@
 	/*
 	 * send initial control parameters
 	 */
-	if(driver->comm->servicetype ==	THREE_WIRE_RAW)
+	if (driver->comm->servicetype == THREE_WIRE_RAW)
 		return;                /* do nothing */
 
 	driver->comm->dte |= (MCR_DTR | MCR_RTS | DELTA_DTR | DELTA_RTS);
@@ -426,6 +474,7 @@
 		ircomm_control_request(driver->comm, DTELINE_STATE);
 		break;
 	default:
+		DEBUG(0, __FUNCTION__ "(), not implemented!\n");
 	}
 
 
@@ -479,11 +528,12 @@
 	if(cmd == TX_READY){
 		driver->ttp_stoptx = 0;
 		driver->tty->hw_stopped = driver->cts_stoptx;
-		irvtd_start_timer( driver);
 
 		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.
@@ -498,7 +548,7 @@
 
 	if(cmd == TX_BUSY){
 		driver->ttp_stoptx = driver->tty->hw_stopped = 1;
-		del_timer( &driver->timer);
+		del_timer( &driver->tx_timer);
 		return;
 	}
 
@@ -576,6 +626,7 @@
 	case DATA_RATE:
 	case XON_XOFF_CHAR:
 	case DTELINE_STATE:
+	case ENQ_ACK_CHAR:	/* got this from win95 */
 		/* (maybe) nothing to do  */
 		break;
 	default:
@@ -678,7 +729,7 @@
 
 	driver->blocked_open--;
 
-	DEBUG(0, __FUNCTION__"():after blocking\n");
+	DEBUG(1, __FUNCTION__"():after blocking\n");
 
 	if (retval)
 		return retval;
@@ -765,7 +816,7 @@
 	struct notify_t irvtd_notify;
 
 	/* FIXME: it should not be hard coded */
-	__u8 oct_seq[6] = { 0,1,4,1,1,1 }; 
+	__u8 oct_seq[6] = { 0,1,6,1,1,1 }; 
 
 	DEBUG(4,__FUNCTION__"()\n" );
 	if(driver->flags & ASYNC_INITIALIZED)
@@ -776,12 +827,12 @@
 	 */
 
 	skb_queue_head_init(&driver->rxbuff);
-	driver->txbuff = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE); 
+	driver->txbuff = dev_alloc_skb(COMM_DEFAULT_SDU_SIZE + COMM_MAX_HEADER_SIZE); 
 	if (!driver->txbuff){
-		DEBUG(0,__FUNCTION__"():alloc_skb failed!\n");
+		DEBUG(0,__FUNCTION__"(), alloc_skb failed!\n");
 		return -ENOMEM;
 	}
-	skb_reserve(driver->txbuff, COMM_HEADER_SIZE);
+	skb_reserve(driver->txbuff, COMM_MAX_HEADER_SIZE);
 
 	irda_notify_init(&irvtd_notify);
 	irvtd_notify.data_indication = irvtd_receive_data;
@@ -793,9 +844,8 @@
 	irvtd_notify.instance = driver;
 
 	driver->comm = ircomm_open_instance(irvtd_notify);
-	if(!driver->comm){
+	if (!driver->comm)
 		return -ENODEV;
-	}
 
 
 	/* 
@@ -811,22 +861,20 @@
 
 	driver->flags |= ASYNC_INITIALIZED;
 
-	/*
-	 * discover a peer device
-	 *	   TODO: other servicetype(i.e. 3wire,3wireraw) support
-	 */
-	ircomm_connect_request(driver->comm, NINE_WIRE);
-	
-	/*
-	 * TODO:we have to initialize control-channel here!
-	 *   i.e.set something into RTS,CTS and so on....
-	 */
-
 	if (driver->tty)
 		clear_bit(TTY_IO_ERROR, &driver->tty->flags);
 
 	change_speed(driver);
-	irvtd_start_timer( 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;
@@ -989,7 +1037,8 @@
 	if (driver->tty)
 		set_bit(TTY_IO_ERROR, &driver->tty->flags);
 	
-	del_timer( &driver->timer);
+	del_timer( &driver->tx_timer);
+	del_timer( &driver->rx_timer);
 
 	irias_delete_object("IrDA:IrCOMM");
 
@@ -1144,13 +1193,21 @@
 	DEBUG(4, __FUNCTION__"()\n");
 
 	save_flags(flags);
-	while(1){
+	while(count > 0){
 		cli();
 		skb = driver->txbuff;
 		ASSERT(skb != NULL, break;);
 		c = MIN(count, (skb_tailroom(skb)));
 		if (c <= 0)
-			break;
+		{
+			if(!driver->ttp_stoptx)
+			{
+				irvtd_send_data_request(driver);
+				continue;
+			}
+			else
+				break;
+		}
 
 		/* write to the frame */
 
@@ -1164,9 +1221,9 @@
 		wrote += c;
 		count -= c;
 		buf += c;
-		irvtd_send_data_request(driver);
 	}
 	restore_flags(flags);
+	irvtd_send_data_request(driver);
 	return (wrote);
 }
 
@@ -1199,19 +1256,27 @@
 	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) MAX(%d):\n",
+	DEBUG(4, "irvtd_put_char(0x%02x) skb_len(%d) room(%d):\n",
 	      (int)ch ,(int)skb->len,
-	      driver->comm->max_txbuff_size - COMM_HEADER_SIZE);
+	      skb_tailroom(skb));
 
 	/* append a character  */
 	frame = skb_put(skb,1);
 	frame[0] = ch;
 
 	restore_flags(flags);
+	irvtd_start_tx_timer(driver,20);
 	return;
 }
 
@@ -1635,6 +1700,7 @@
 	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);
 }
 
@@ -1649,6 +1715,7 @@
 	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);
 }
 
@@ -1858,6 +1925,12 @@
                 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");

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