summaryrefslogtreecommitdiffstats
path: root/net/irda/ircomm
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-06-13 16:29:25 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-06-13 16:29:25 +0000
commitdb7d4daea91e105e3859cf461d7e53b9b77454b2 (patch)
tree9bb65b95440af09e8aca63abe56970dd3360cc57 /net/irda/ircomm
parent9c1c01ead627bdda9211c9abd5b758d6c687d8ac (diff)
Merge with Linux 2.2.8.
Diffstat (limited to 'net/irda/ircomm')
-rw-r--r--net/irda/ircomm/Makefile8
-rw-r--r--net/irda/ircomm/attach.c364
-rw-r--r--net/irda/ircomm/ircomm_common.c1489
-rw-r--r--net/irda/ircomm/irvtd.c153
-rw-r--r--net/irda/ircomm/irvtd_driver.c1883
5 files changed, 2064 insertions, 1833 deletions
diff --git a/net/irda/ircomm/Makefile b/net/irda/ircomm/Makefile
index 1ff2e45be..7df055ea1 100644
--- a/net/irda/ircomm/Makefile
+++ b/net/irda/ircomm/Makefile
@@ -8,9 +8,9 @@
# Note 2! The CFLAGS definition is now in the main makefile...
O_TARGET := ircomm_n_vtd.o
-O_OBJS := ircomm_common.o attach.o irvtd.o irvtd_driver.o
+O_OBJS := ircomm_common.o irvtd_driver.o
M_OBJS := ircomm.o ircomm_tty.o
-MI_OBJS := ircomm_common.o attach.o irvtd.o irvtd_driver.o
+MI_OBJS := ircomm_common.o irvtd_driver.o
OX_OBJS +=
@@ -18,10 +18,10 @@ OX_OBJS +=
ifeq ($(CONFIG_IRCOMM),m)
ircomm.o: $(MI_OBJS)
- $(LD) $(LD_RFLAG) -r -o $@ ircomm_common.o attach.o
+ $(LD) $(LD_RFLAG) -r -o $@ ircomm_common.o
ircomm_tty.o: $(MI_OBJS)
- $(LD) $(LD_RFLAG) -r -o $@ irvtd.o irvtd_driver.o
+ $(LD) $(LD_RFLAG) -r -o $@ irvtd_driver.o
endif
include $(TOPDIR)/Rules.make
diff --git a/net/irda/ircomm/attach.c b/net/irda/ircomm/attach.c
deleted file mode 100644
index 1e5e373ee..000000000
--- a/net/irda/ircomm/attach.c
+++ /dev/null
@@ -1,364 +0,0 @@
-/*********************************************************************
- *
- * Filename: attach.c
- * Version:
- * Description: An implementation of IrCOMM service interface.
- * Status: Experimental.
- * Author: Takahide Higuchi <thiguchi@pluto.dti.ne.jp>
- *
- * Copyright (c) 1998, 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.
- *
- ********************************************************************/
-
-
-/*
- * ----------------------------------------------------------------------
- * IrIAS related things for IrCOMM
- * If you are to use ircomm layer, use ircomm_attach_cable to
- * setup it and register your program.
- * ----------------------------------------------------------------------
- */
-
-
-#include <linux/sched.h>
-#include <linux/tqueue.h>
-
-#include <net/irda/irlap.h>
-#include <net/irda/irttp.h>
-#include <net/irda/iriap.h>
-#include <net/irda/irias_object.h>
-
-#include <net/irda/ircomm_common.h>
-
-extern struct ircomm_cb **ircomm;
-struct ircomm_cb *discovering_instance;
-
-static void got_lsapsel(struct ircomm_cb * info);
-static void query_lsapsel(struct ircomm_cb * self);
-void ircomm_getvalue_confirm( __u16 obj_id, struct ias_value *value, void *priv );
-
-#if 0
-static char *rcsid = "$Id: attach.c,v 1.11 1998/10/22 12:02:20 dagb Exp $";
-#endif
-
-
-/*
- * handler for iriap_getvaluebyclass_request()
- *
- */
-
-void ircomm_getvalue_confirm( __u16 obj_id, struct ias_value *value, void *priv ){
-
- struct ircomm_cb *self = (struct ircomm_cb *) priv;
-
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == IRCOMM_MAGIC, return;);
-
- DEBUG(0, __FUNCTION__"type(%d)\n", value->type);
-
- switch(value->type){
-
- case IAS_OCT_SEQ:
- /*
- * FIXME:we should use data which came here
- * it is used for nothing at this time
- */
-
-#if 1
- DEBUG(0, "octet sequence is:\n");
- {
- int i;
- for ( i=0;i<value->len;i++)
- printk("%02x",
- (int)(*value->t.oct_seq + i) );
- printk("\n");
- }
-#endif
- query_lsapsel(self);
- break;
-
- case IAS_INTEGER:
- /* LsapSel seems to be sent to me */
-
- if ( value->t.integer == -1){
- DEBUG( 0, "ircomm_getvalue_confirm: invalid value!\n");
- return;
- }
- if(self->state == COMM_IDLE){
- self->dlsap = value->t.integer;
- got_lsapsel(self);
- }
- break;
-
- case IAS_STRING:
- DEBUG( 0, __FUNCTION__":STRING is not implemented\n");
- DEBUG( 0, __FUNCTION__":received string:%s\n",
- value->t.string);
- query_lsapsel(self); /* experiment */
- break;
-
- case IAS_MISSING:
- DEBUG( 0, __FUNCTION__":MISSING is not implemented\n");
- break;
-
- default:
- DEBUG( 0, __FUNCTION__":unknown type!\n");
- break;
- }
-}
-
-
-static void got_lsapsel(struct ircomm_cb * self){
-
- struct notify_t notify;
-
- DEBUG(0, "ircomm:got_lsapsel: got peersap!(%d)\n", self->dlsap );
-
- /* remove tsap for server */
- irttp_close_tsap(self->tsap);
-
- /* create TSAP for initiater ... */
- irda_notify_init(&notify);
- notify.data_indication = ircomm_accept_data_indication;
- notify.connect_confirm = ircomm_accept_connect_confirm;
- notify.connect_indication = ircomm_accept_connect_indication;
- notify.flow_indication = ircomm_accept_flow_indication;
- notify.disconnect_indication = ircomm_accept_disconnect_indication;
- strncpy( notify.name, "IrCOMM cli", NOTIFY_MAX_NAME);
- notify.instance = self;
-
- self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT,
- &notify );
- ASSERT(self->tsap != NULL, return;);
-
-
- /*
- * invoke state machine
- * and notify that I'm ready to accept connect_request
- */
-
- ircomm_next_state(self, COMM_IDLE);
- if(self->d_handler)
- self->d_handler(self);
-}
-
-
-
-
-
-static void query_lsapsel(struct ircomm_cb * self){
-
- DEBUG(0, "ircomm:query_lsapsel..\n");
-
- /*
- * since we've got Parameters field of IAS, we are to get peersap.
- */
-
- if(!(self->servicetype & THREE_WIRE_RAW)){
- iriap_getvaluebyclass_request
- (self->daddr, "IrDA:IrCOMM", "IrDA:TinyTP:LsapSel",
- ircomm_getvalue_confirm, self );
- } else {
- DEBUG(0,"ircomm:query_lsap:"
- "THREE_WIRE_RAW is not implemented!\n");
- }
-}
-
-
-
-/*
- * ircomm_discovery_indication()
- * Remote device is discovered, try query the remote IAS to see which
- * device it is, and which services it has.
- */
-
-void ircomm_discovery_indication( DISCOVERY *discovery)
-{
-
- struct ircomm_cb *self;
-
- DEBUG( 0, "ircomm_discovery_indication\n");
-
- self = discovering_instance;
- ASSERT(self != NULL, return;);
- ASSERT(self->magic == IRCOMM_MAGIC, return;);
-
- self->daddr = discovery->daddr;
-
- DEBUG( 0, "ircomm_discovery_indication:daddr=%08x\n", self->daddr);
-
- /* query "Parameters" attribute of LM-IAS */
-
- DEBUG(0, "ircomm:querying parameters..\n");
-#if 0
- iriap_getvaluebyclass_request(self->daddr, "IrDA:IrCOMM",
-
- "Parameters",
- ircomm_getvalue_confirm,
- self);
-#else
- query_lsapsel(self);
-#endif
- return;
-}
-
-
-struct ircomm_cb * ircomm_attach_cable( __u8 servicetype,
- struct notify_t notify,
- void *handler ){
-
- int i;
- struct ircomm_cb *self = NULL;
- struct notify_t server_notify;
- struct ias_object* obj;
-
- /* FIXME: it should not be hard coded */
- __u8 oct_seq[6] = { 0,1,4,1,1,1 };
-
- ASSERT(ircomm != NULL,return NULL;);
- DEBUG(0,"ircomm_attach_cable:\n");
-
-
- /* find free handle */
-
- for(i = 0; i < IRCOMM_MAX_CONNECTION; i++){
- ASSERT(ircomm[i] != NULL,return(NULL););
- if(!ircomm[i]->in_use){
- self = ircomm[i];
- break;
- }
- }
-
- if (!self){
- DEBUG(0,"ircomm_attach_cable:no free handle!\n");
- return (NULL);
- }
-
- self->in_use = 1;
- self->servicetype = servicetype;
-
- DEBUG(0,"attach_cable:servicetype:%d\n",servicetype);
- self->d_handler = handler;
- self->notify = notify;
-
- /* register server.. */
-
- /*
- * TODO: since server TSAP is currentry hard coded,
- * we can use *only one* IrCOMM connection.
- * We have to create one more TSAP and register IAS entry dynamically
- * each time when we are to allocate new server here.
- */
- irda_notify_init(&server_notify);
- server_notify.data_indication = ircomm_accept_data_indication;
- server_notify.connect_confirm = ircomm_accept_connect_confirm;
- server_notify.connect_indication = ircomm_accept_connect_indication;
- server_notify.flow_indication = ircomm_accept_flow_indication;
- server_notify.disconnect_indication = ircomm_accept_disconnect_indication;
- server_notify.instance = self;
- strncpy( server_notify.name, "IrCOMM srv", NOTIFY_MAX_NAME);
-
- self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT,
- &server_notify);
- if(!self->tsap){
- DEBUG(0,"ircomm:Sorry, failed to allocate server_tsap\n");
- return NULL;
- }
-
- /*
- * Register with LM-IAS
- */
- obj = irias_new_object( "IrDA:IrCOMM", IAS_IRCOMM_ID);
- irias_add_integer_attrib( obj, "IrDA:TinyTP:LsapSel",
- self->tsap->stsap_sel );
-
- /* FIXME: it should not be hard coded */
-
- irias_add_octseq_attrib( obj, "Parameters",
- &oct_seq[0], 6);
- irias_insert_object( obj);
-
-/* obj = irias_new_object( "IrDA:IrCOMM", IAS_IRCOMM_ID); */
-/* irias_add_octseq_attrib( obj, "Parameters", len, &octseq); */
-/* irias_insert_object( obj); */
-
-
-
- /* and start discovering .. */
- discovering_instance = self;
-
- switch(servicetype){
- case NINE_WIRE:
- DEBUG(0,"ircomm_attach_cable:discovering..\n");
- irlmp_register_layer(S_COMM , CLIENT|SERVER, TRUE,
- ircomm_discovery_indication);
- break;
-
-/* case CENTRONICS: */
-/* case THREE_WIRE: */
-/* case THREE_WIRE_RAW: */
-
- default:
- DEBUG(0,"ircomm_attach_cable:requested servicetype is not "
- "implemented!\n");
- return NULL;
- }
-
- ircomm_next_state(self, COMM_IDLE);
- return (self);
-}
-
-
-
-
-int ircomm_detach_cable(struct ircomm_cb *self){
-
- ASSERT( self != NULL, return -EIO;);
- ASSERT( self->magic == IRCOMM_MAGIC, return -EIO;);
-
-
- DEBUG(0,"ircomm_detach_cable:\n");
-
- /* shutdown ircomm layer */
- if(self->state != COMM_IDLE ){
- DEBUG(0,"ircomm:detach_cable:not IDLE\n");
- if(self->state != COMM_WAITI)
- ircomm_disconnect_request(self, NULL);
- }
-
-
- switch(self->servicetype){
-/* case CENTRONICS: */
- case NINE_WIRE:
-/* case THREE_WIRE: */
- irlmp_unregister_layer( S_COMM, CLIENT|SERVER );
- break;
-
-/* case THREE_WIRE_RAW: */
-/* irlmp_unregister( S_COMM ) */
-/* irlmp_unregister( S_PRINTER) */
-/* break; */
-
- default:
- DEBUG(0,"ircomm_detach_cable:requested servicetype is not "
- "implemented!\n");
- return -ENODEV;
- }
-
- /* remove tsaps */
- if(self->tsap)
- irttp_close_tsap(self->tsap);
-
- self->tsap = NULL;
- self->in_use = 0;
- return 0;
-}
diff --git a/net/irda/ircomm/ircomm_common.c b/net/irda/ircomm/ircomm_common.c
index cfda567ce..bc8758e1e 100644
--- a/net/irda/ircomm/ircomm_common.c
+++ b/net/irda/ircomm/ircomm_common.c
@@ -33,25 +33,29 @@
#include <linux/proc_fs.h>
#include <linux/init.h>
-#include <net/irda/irmod.h>
+#include <net/irda/irda.h>
#include <net/irda/irlmp.h>
#include <net/irda/iriap.h>
#include <net/irda/irttp.h>
+#include <net/irda/irias_object.h>
#include <net/irda/ircomm_common.h>
-#if 0
-static char *rcsid = "$Id: ircomm_common.c,v 1.13 1998/10/13 12:59:05 takahide Exp $";
-#endif
-static char *version = "IrCOMM_common, $Revision: 1.13 $ $Date: 1998/10/13 12:59:05 $ (Takahide Higuchi)";
-
+static char *revision_date = "Sun Apr 18 00:40:19 1999";
-
-static void ircomm_state_discovery( struct ircomm_cb *self,
- IRCOMM_EVENT event, struct sk_buff *skb );
static void ircomm_state_idle( struct ircomm_cb *self, IRCOMM_EVENT event,
struct sk_buff *skb );
+
+static void ircomm_state_discoverywait( struct ircomm_cb *self, IRCOMM_EVENT event,
+ struct sk_buff *skb );
+
+static void ircomm_state_queryparamwait( struct ircomm_cb *self, IRCOMM_EVENT event,
+ struct sk_buff *skb );
+
+static void ircomm_state_querylsapwait( struct ircomm_cb *self, IRCOMM_EVENT event,
+ struct sk_buff *skb );
+
static void ircomm_state_waiti( struct ircomm_cb *self, IRCOMM_EVENT event,
struct sk_buff *skb );
static void ircomm_state_waitr( struct ircomm_cb *self, IRCOMM_EVENT event,
@@ -60,15 +64,43 @@ static void ircomm_state_conn( struct ircomm_cb *self, IRCOMM_EVENT event,
struct sk_buff *skb );
static void ircomm_do_event( struct ircomm_cb *self, IRCOMM_EVENT event,
struct sk_buff *skb);
-void ircomm_next_state( struct ircomm_cb *self, IRCOMM_STATE state);
+static void ircomm_next_state( struct ircomm_cb *self, IRCOMM_STATE state);
+
+static void ircomm_discovery_indication(discovery_t *discovery);
+static void ircomm_tx_controlchannel(struct ircomm_cb *self );
+static int ircomm_proc_read(char *buf, char **start, off_t offset,
+ int len, int unused);
+
+static void start_discovering(struct ircomm_cb *self);
+static void query_lsapsel(struct ircomm_cb * self);
+static void query_parameters(struct ircomm_cb *self);
+static void queryias_done(struct ircomm_cb *self);
+static void ircomm_getvalue_confirm(int result, __u16 obj_id,
+ struct ias_value *value, void *priv);
+
+
+struct ircomm_cb *discovering_instance;
+
+/*
+ * debug parameter ircomm_cs:
+ * 0 = client/server, 1 = client only 2 = server only
+ * usage for example:
+ * insmod ircomm ircomm_cs=1
+ * LILO boot : Linux ircomm_cs=2 etc.
+ */
+
+static int ircomm_cs = 0;
+MODULE_PARM(ircomm_cs, "i");
+
-int ircomm_check_handle(int handle);
-static void ircomm_parse_control(struct ircomm_cb *self, struct sk_buff *skb,
- int type);
static char *ircommstate[] = {
- "DISCOVERY",
"IDLE",
+
+ "DISCOVERY_WAIT",
+ "QUERYPARAM_WAIT",
+ "QUERYLSAP_WAIT",
+
"WAITI",
"WAITR",
"CONN",
@@ -107,38 +139,38 @@ static char *ircommevent[] = {
"IRCOMM_DATA_REQUEST",
"LMP_DATA_INDICATION",
"IRCOMM_CONTROL_REQUEST",
-};
-int ircomm_proc_read(char *buf, char **start, off_t offset,
- int len, int unused);
+ "DISCOVERY_INDICATION",
+ "GOT_PARAMETERS",
+ "GOT_LSAPSEL",
+ "QUERYIAS_ERROR",
+};
#ifdef CONFIG_PROC_FS
-extern struct proc_dir_entry proc_irda;
-struct proc_dir_entry proc_ircomm = {
- 0, 6, "ircomm",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, NULL,
- &ircomm_proc_read,
-};
+extern struct proc_dir_entry *proc_irda;
#endif
static void (*state[])( struct ircomm_cb *self, IRCOMM_EVENT event,
struct sk_buff *skb) =
{
- ircomm_state_discovery,
ircomm_state_idle,
+
+ ircomm_state_discoverywait,
+ ircomm_state_queryparamwait,
+ ircomm_state_querylsapwait,
+
ircomm_state_waiti,
ircomm_state_waitr,
ircomm_state_conn,
};
-
__initfunc(int ircomm_init(void))
{
int i;
- printk( KERN_INFO "%s\n", version);
- DEBUG( 4, "ircomm_common:init_module\n");
+ printk( "Linux-IrDA: IrCOMM protocol ( revision:%s ) \n",
+ revision_date);
+ DEBUG( 4, __FUNCTION__"()\n");
/* allocate master array */
@@ -146,7 +178,7 @@ __initfunc(int ircomm_init(void))
IRCOMM_MAX_CONNECTION,
GFP_KERNEL);
if ( ircomm == NULL) {
- printk( KERN_WARNING "IrCOMM: Can't allocate ircomm array!\n");
+ printk( KERN_ERR __FUNCTION__"(): kmalloc failed!\n");
return -ENOMEM;
}
@@ -158,7 +190,7 @@ __initfunc(int ircomm_init(void))
ircomm[i] = kmalloc( sizeof(struct ircomm_cb), GFP_KERNEL );
if(!ircomm[i]){
- printk(KERN_ERR "ircomm:kmalloc failed!\n");
+ printk( KERN_ERR __FUNCTION__"(): kmalloc failed!\n");
return -ENOMEM;
}
@@ -191,17 +223,20 @@ __initfunc(int ircomm_init(void))
*/
#ifdef CONFIG_PROC_FS
- proc_register( &proc_irda, &proc_ircomm);
+ create_proc_entry("ircomm", 0, proc_irda)->get_info = ircomm_proc_read;
#endif /* CONFIG_PROC_FS */
+
+ discovering_instance = NULL;
return 0;
}
+#ifdef MODULE
void ircomm_cleanup(void)
{
int i;
- DEBUG( 4, "ircomm_common:cleanup_module\n");
+ DEBUG( 4, "ircomm:cleanup_module\n");
/*
* free some resources
*/
@@ -226,9 +261,10 @@ void ircomm_cleanup(void)
}
#ifdef CONFIG_PROC_FS
- proc_unregister( &proc_irda, proc_ircomm.low_ino);
-#endif
+ remove_proc_entry("ircomm", proc_irda);
+#endif /* CONFIG_PROC_FS */
}
+#endif /* MODULE */
/*
* ----------------------------------------------------------------------
@@ -236,21 +272,27 @@ void ircomm_cleanup(void)
* ----------------------------------------------------------------------
*/
-void ircomm_accept_data_indication(void *instance, void *sap, struct sk_buff *skb){
+static int ircomm_accept_data_indication(void *instance, void *sap,
+ struct sk_buff *skb)
+{
struct ircomm_cb *self = (struct ircomm_cb *)instance;
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == IRCOMM_MAGIC, return;);
- ASSERT( skb != NULL, return;);
+ ASSERT( self != NULL, return -1;);
+ ASSERT( self->magic == IRCOMM_MAGIC, return -1;);
+ ASSERT( skb != NULL, return -1;);
- DEBUG(4,"ircomm_accept_data_indication:\n");
+ DEBUG(4,__FUNCTION__"():\n");
ircomm_do_event( self, TTP_DATA_INDICATION, skb);
+ self->rx_packets++;
+
+ return 0;
}
-void ircomm_accept_connect_confirm(void *instance, void *sap,
+static void ircomm_accept_connect_confirm(void *instance, void *sap,
struct qos_info *qos,
- int maxsdusize, struct sk_buff *skb){
+ __u32 maxsdusize, struct sk_buff *skb)
+{
struct ircomm_cb *self = (struct ircomm_cb *)instance;
@@ -259,7 +301,7 @@ void ircomm_accept_connect_confirm(void *instance, void *sap,
ASSERT( skb != NULL, return;);
ASSERT( qos != NULL, return;);
- DEBUG(0,"ircomm_accept_connect_confirm:\n");
+ DEBUG(0,__FUNCTION__"(): got connected!\n");
if(maxsdusize == SAR_DISABLE)
self->max_txbuff_size = qos->data_size.value;
@@ -274,11 +316,11 @@ void ircomm_accept_connect_confirm(void *instance, void *sap,
ircomm_do_event( self, TTP_CONNECT_CONFIRM, skb);
}
-void ircomm_accept_connect_indication(void *instance, void *sap,
+static void ircomm_accept_connect_indication(void *instance, void *sap,
struct qos_info *qos,
- int maxsdusize,
- struct sk_buff *skb ){
-
+ __u32 maxsdusize,
+ struct sk_buff *skb )
+{
struct ircomm_cb *self = (struct ircomm_cb *)instance;
ASSERT( self != NULL, return;);
@@ -286,7 +328,7 @@ void ircomm_accept_connect_indication(void *instance, void *sap,
ASSERT( skb != NULL, return;);
ASSERT( qos != NULL, return;);
- DEBUG(0,"ircomm_accept_connect_indication:\n");
+ DEBUG(0,__FUNCTION__"()\n");
if(maxsdusize == SAR_DISABLE)
self->max_txbuff_size = qos->data_size.value;
@@ -295,22 +337,31 @@ void ircomm_accept_connect_indication(void *instance, void *sap,
self->qos = qos;
ircomm_do_event( self, TTP_CONNECT_INDICATION, skb);
+
+ /* stop connecting */
+ wake_up_interruptible( &self->discovery_wait);
+ wake_up_interruptible( &self->ias_wait);
+
}
-void ircomm_accept_disconnect_indication(void *instance, void *sap, LM_REASON reason,
- struct sk_buff *skb){
+static void ircomm_accept_disconnect_indication(void *instance, void *sap,
+ LM_REASON reason,
+ struct sk_buff *skb)
+{
struct ircomm_cb *self = (struct ircomm_cb *)instance;
ASSERT( self != NULL, return;);
ASSERT( self->magic == IRCOMM_MAGIC, return;);
- ASSERT( skb != NULL, return;);
- DEBUG(0,"ircomm_accept_disconnect_indication:\n");
+ DEBUG(0,__FUNCTION__"():\n");
ircomm_do_event( self, TTP_DISCONNECT_INDICATION, skb);
+
}
-void ircomm_accept_flow_indication( void *instance, void *sap, LOCAL_FLOW cmd){
-
+static void ircomm_accept_flow_indication( void *instance, void *sap,
+ LOCAL_FLOW cmd)
+{
+ IRCOMM_CMD command;
struct ircomm_cb *self = (struct ircomm_cb *)instance;
ASSERT( self != NULL, return;);
@@ -318,73 +369,204 @@ void ircomm_accept_flow_indication( void *instance, void *sap, LOCAL_FLOW cmd){
switch(cmd){
case FLOW_START:
- DEBUG(0,"ircomm_accept_flow_indication:START\n");
-
- self->pi = TX_READY;
+ DEBUG(4,__FUNCTION__"():START\n");
+ command = TX_READY;
self->ttp_stop = 0;
if(self->notify.flow_indication)
self->notify.flow_indication( self->notify.instance,
- self, cmd);
- ircomm_control_request(self);
+ self, command);
break;
case FLOW_STOP:
- DEBUG(0,"ircomm_accept_flow_indication:STOP\n");
- self->pi = TX_BUSY;
+ DEBUG(4,__FUNCTION__":STOP\n");
+ command = TX_BUSY;
self->ttp_stop = 1;
if(self->notify.flow_indication)
self->notify.flow_indication( self->notify.instance,
- self, cmd);
+ self, command);
break;
default:
- DEBUG(0,"ircomm_accept_flow_indication:unknown status!\n");
+ DEBUG(0,__FUNCTION__"();unknown status!\n");
}
}
+
+/*
+ * ircomm_discovery_indication()
+ * Remote device is discovered, try query the remote IAS to see which
+ * device it is, and which services it has.
+ */
+
+static void ircomm_discovery_indication(discovery_t *discovery)
+{
+ struct ircomm_cb *self;
+
+ self = discovering_instance;
+ if(self == NULL)
+ return;
+ ASSERT(self->magic == IRCOMM_MAGIC, return;);
+
+ self->daddr = discovery->daddr;
+ self->saddr = discovery->saddr;
+
+ DEBUG( 0, __FUNCTION__"():daddr=%08x\n", self->daddr);
+
+ ircomm_do_event(self, DISCOVERY_INDICATION, NULL);
+ return;
+}
+
+/*
+ * ircomm_getvalue_confirm()
+ * handler for iriap_getvaluebyclass_request()
+ */
+static void ircomm_getvalue_confirm(int result, __u16 obj_id,
+ struct ias_value *value, void *priv)
+{
+ struct ircomm_cb *self = (struct ircomm_cb *) priv;
+ struct sk_buff *skb= NULL;
+ __u8 *frame;
+ __u8 servicetype = 0 ;
+ ASSERT( self != NULL, return;);
+ ASSERT( self->magic == IRCOMM_MAGIC, return;);
+
+ /* Check if request succeeded */
+ if (result != IAS_SUCCESS) {
+ DEBUG( 0, __FUNCTION__ "(), got NULL value!\n");
+ ircomm_do_event(self, QUERYIAS_ERROR, NULL);
+ return;
+ }
+
+ DEBUG(4, __FUNCTION__"():type(%d)\n", value->type);
+
+ self->ias_type = value->type;
+ switch(value->type){
+ case IAS_OCT_SEQ:
+
+ DEBUG(4, __FUNCTION__"():got octet sequence:\n");
+#if 0
+ {
+ int i;
+ for ( i=0;i<value->len;i++)
+ printk("%02x",
+ (__u8)(*(value->t.oct_seq + i)));
+ printk("\n");
+ }
+#endif
+ skb = dev_alloc_skb((value->len) + 2);
+ ASSERT(skb != NULL, ircomm_do_event(self, QUERYIAS_ERROR, NULL);return;);
+ frame = skb_put(skb,2);
+ /* MSB first */
+ frame[0] = ( value->len >> 8 ) & 0xff;
+ frame[1] = value->len & 0xff;
+
+ frame = skb_put(skb,value->len);
+ memcpy(frame, value->t.oct_seq, value->len);
+ ircomm_parse_tuples(self, skb, IAS_PARAM);
+ kfree_skb(skb);
+
+ /*
+ * check if servicetype we want is available
+ */
+
+ DEBUG(0,__FUNCTION__"():peer capability is:\n");
+ DEBUG(0,"3wire raw: %s\n",
+ ((self->peer_servicetype & THREE_WIRE_RAW) ? "yes":"no"));
+ DEBUG(0,"3wire : %s\n",
+ ((self->peer_servicetype & THREE_WIRE) ? "yes":"no"));
+ DEBUG(0,"9wire : %s\n",
+ ((self->peer_servicetype & NINE_WIRE) ? "yes":"no"));
+ DEBUG(0,"IEEE1284 : %s\n",
+ ((self->peer_servicetype & CENTRONICS) ? "yes":"no"));
+
+ self->servicetype &= self->peer_servicetype;
+ if(!(self->servicetype)){
+ DEBUG(0,__FUNCTION__"(): servicetype mismatch!\n");
+ ircomm_do_event(self, QUERYIAS_ERROR, NULL);
+ break;
+ }
+
+ /*
+ * then choose better one
+ */
+ if(self->servicetype & THREE_WIRE_RAW)
+ servicetype = THREE_WIRE_RAW;
+ if(self->servicetype & THREE_WIRE)
+ servicetype = THREE_WIRE;
+ if(self->servicetype & NINE_WIRE)
+ servicetype = NINE_WIRE;
+ if(self->servicetype & CENTRONICS)
+ servicetype = CENTRONICS;
+
+ self->servicetype = servicetype;
+
+ /* enter next state */
+ ircomm_do_event(self, GOT_PARAMETERS, NULL);
+ break;
+
+ case IAS_INTEGER:
+ /* LsapSel seems to be sent to me */
+ DEBUG(0, __FUNCTION__"():got lsapsel = %d\n", value->t.integer);
+
+ if ( value->t.integer == -1){
+ DEBUG( 0, __FUNCTION__"():invalid value!\n");
+ ircomm_do_event(self, QUERYIAS_ERROR, NULL);
+ return;
+ }
+ self->dlsap = value->t.integer;
+ ircomm_do_event(self, GOT_LSAPSEL, NULL);
+ break;
+
+ case IAS_MISSING:
+ DEBUG( 0, __FUNCTION__":got IAS_MISSING\n");
+ ircomm_do_event(self, QUERYIAS_ERROR, NULL);
+ break;
+
+ default:
+ DEBUG( 0, __FUNCTION__":got unknown (strange?)type!\n");
+ ircomm_do_event(self, QUERYIAS_ERROR, NULL);
+ break;
+ }
+}
+
+
+
/*
* ----------------------------------------------------------------------
- * Implementation of actions,descrived in section 7.4 of the reference.
+ * Impl. of actions (descrived in section 7.4 of the reference)
* ----------------------------------------------------------------------
*/
-
static void issue_connect_request(struct ircomm_cb *self,
- struct sk_buff *userdata ){
-
+ struct sk_buff *userdata )
+{
/* TODO: we have to send/build userdata field which contains
InitialControlParameters */
- /* but userdata field is not implemeted in irttp.c.. */
switch(self->servicetype){
case THREE_WIRE_RAW:
- /* not implemented yet! Do nothing */
- DEBUG(0, "ircomm:issue_connect_request:"
- "not implemented servicetype!");
+ DEBUG(0, __FUNCTION__"():THREE_WIRE_RAW is not implemented\n");
break;
case DEFAULT:
- irttp_connect_request(self->tsap, self->dlsap, self->daddr,
- NULL, self->maxsdusize, NULL);
- break;
-
case THREE_WIRE:
case NINE_WIRE:
case CENTRONICS:
- irttp_connect_request(self->tsap, self->dlsap, self->daddr,
- NULL, self->maxsdusize, NULL);
+ irttp_connect_request(self->tsap, self->dlsap,
+ self->saddr, self->daddr,
+ NULL, self->maxsdusize, userdata);
break;
default:
- DEBUG(0,"ircomm:issue_connect_request:Illegal servicetype %d\n"
- ,self->servicetype);
+ printk(KERN_ERR __FUNCTION__"():Illegal servicetype %d\n"
+ ,self->servicetype);
}
}
-
-static void disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb){
+static void disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb)
+{
/*
* Not implemented parameter"Reason".That is optional.
@@ -394,12 +576,13 @@ static void disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb){
if(self->notify.disconnect_indication)
self->notify.disconnect_indication( self->notify.instance,
self,
- self->reason,skb);
+ self->reason, skb);
}
static void connect_indication(struct ircomm_cb *self, struct qos_info *qos,
- struct sk_buff *skb){
+ struct sk_buff *skb)
+{
/* If controlparameters don't exist, we use the servicetype"DEFAULT".*/
/* if( !ircomm_parse_controlchannel( self, data)) */
@@ -412,13 +595,16 @@ static void connect_indication(struct ircomm_cb *self, struct qos_info *qos,
#if 0
/* it's for THREE_WIRE_RAW.*/
-static void connect_indication_three_wire_raw(void){
+static void connect_indication_three_wire_raw(void)
+{
DEBUG(0,"ircomm:connect_indication_threewire():not implemented!");
}
#endif
-static void connect_confirmation(struct ircomm_cb *self, struct sk_buff *skb){
+static void connect_confirmation(struct ircomm_cb *self, struct sk_buff *skb)
+{
+ DEBUG(4 ,__FUNCTION__"()\n");
/* give a connect_confirm to the client */
if( self->notify.connect_confirm )
@@ -427,13 +613,13 @@ static void connect_confirmation(struct ircomm_cb *self, struct sk_buff *skb){
}
static void issue_connect_response(struct ircomm_cb *self,
- struct sk_buff *skb ){
+ struct sk_buff *skb)
+{
- DEBUG(0,"ircomm:issue_connect_response:\n");
+ DEBUG(0,__FUNCTION__"()\n");
if( self->servicetype == THREE_WIRE_RAW){
- DEBUG(0,"ircomm:issue_connect_response():3WIRE-RAW is not "
- "implemented yet !\n");
+ DEBUG(0,__FUNCTION__"():THREE_WIRE_RAW is not implemented yet\n");
/* irlmp_connect_rsp(); */
} else {
irttp_connect_response(self->tsap, self->maxsdusize, skb);
@@ -441,64 +627,91 @@ static void issue_connect_response(struct ircomm_cb *self,
}
static void issue_disconnect_request(struct ircomm_cb *self,
- struct sk_buff *userdata ){
+ struct sk_buff *userdata)
+{
if(self->servicetype == THREE_WIRE_RAW){
- DEBUG(0,"ircomm:issue_disconnect_request():3wireraw is not implemented!");
+ DEBUG(0,__FUNCTION__"():3wireraw is not implemented\n");
}
else
- irttp_disconnect_request(self->tsap, NULL, P_NORMAL);
+ irttp_disconnect_request(self->tsap, userdata,
+ self->disconnect_priority);
}
static void issue_data_request(struct ircomm_cb *self,
- struct sk_buff *userdata ){
+ struct sk_buff *userdata )
+{
int err;
if(self->servicetype == THREE_WIRE_RAW){
/* irlmp_data_request(self->lmhandle,userdata); */
- DEBUG(0,"ircomm:issue_data_request():not implemented!");
+ DEBUG(0,__FUNCTION__"():not implemented!");
return;
}
- DEBUG(4,"ircomm:issue_data_request():sending frame\n");
+ DEBUG(4,__FUNCTION__"():sending frame\n");
err = irttp_data_request(self->tsap , userdata );
- if(err)
- DEBUG(0,"ircomm:ttp_data_request failed\n");
- if(userdata && err)
- dev_kfree_skb( userdata);
-
+ if(err){
+ printk(KERN_ERR __FUNCTION__":ttp_data_request failed\n");
+ if(userdata)
+ dev_kfree_skb( userdata);
+ }
+ self->tx_packets++;
}
static void issue_control_request(struct ircomm_cb *self,
- struct sk_buff *userdata ){
- if(self->servicetype == THREE_WIRE_RAW){
- DEBUG(0,"THREE_WIRE_RAW is not implemented\n");
+ struct sk_buff *userdata )
+{
+ int err;
+
+ DEBUG(4,__FUNCTION__"()\n");
+ if(self->servicetype == THREE_WIRE_RAW)
+ {
+ DEBUG(0,__FUNCTION__"():THREE_WIRE_RAW is not implemented\n");
- }else {
- irttp_data_request(self->tsap,userdata);
}
-}
+ else
+ {
+ err = irttp_data_request(self->tsap,userdata);
+ if(err)
+ {
+ printk( __FUNCTION__"():ttp_data_request failed\n");
+ if(userdata)
+ dev_kfree_skb( userdata);
+ }
+ else
+ self->tx_controls++;
+ self->pending_control_tuples = 0;
+ }
+}
-static void process_data(struct ircomm_cb *self, struct sk_buff *skb ){
+static void process_data(struct ircomm_cb *self, struct sk_buff *skb )
+{
- DEBUG(4,"ircomm:process_data:skb_len is(%d),clen_is(%d)\n",
+ DEBUG(4,__FUNCTION__":skb->len=%d, ircomm header = 1, clen=%d\n",
(int)skb->len ,(int)skb->data[0]);
- /*
- * we always have to parse control channel
- * (see page17 of IrCOMM standard)
+ /* we have to parse control channel when receiving. (see
+ * page17 of IrCOMM standard) but it is not parsed here since
+ * upper layer may have some receive buffer.
+ *
+ * hence upper layer have to parse it when it consumes a packet.
+ * -- TH
*/
- ircomm_parse_control(self, skb, CONTROL_CHANNEL);
+ /* ircomm_parse_control(self, skb, CONTROL_CHANNEL); */
if(self->notify.data_indication && skb->len)
self->notify.data_indication(self->notify.instance, self,
skb);
}
-void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb){
+int ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb)
+{
/* Not implemented yet:THREE_WIRE_RAW service uses this function. */
DEBUG(0,"ircomm_data_indication:not implemented yet!\n");
+
+ return 0;
}
@@ -510,45 +723,38 @@ void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb){
*/
static void ircomm_do_event( struct ircomm_cb *self, IRCOMM_EVENT event,
- struct sk_buff *skb) {
+ struct sk_buff *skb)
+{
- DEBUG( 4, "ircomm_do_event: STATE = %s, EVENT = %s\n",
+ DEBUG( 4, __FUNCTION__": STATE = %s, EVENT = %s\n",
ircommstate[self->state], ircommevent[event]);
(*state[ self->state ]) ( self, event, skb);
}
-void ircomm_next_state( struct ircomm_cb *self, IRCOMM_STATE state) {
+static void ircomm_next_state( struct ircomm_cb *self, IRCOMM_STATE state)
+{
self->state = state;
- DEBUG( 0, "ircomm_next_state: NEXT STATE = %d(%s), sv(%d)\n",
+ DEBUG( 0, __FUNCTION__": NEXT STATE=%d(%s), servicetype=(%d)\n",
(int)state, ircommstate[self->state],self->servicetype);
}
-/*
- * we currently need dummy (discovering) state for debugging,
- * which state is not defined in the reference.
- */
-
-static void ircomm_state_discovery( struct ircomm_cb *self,
- IRCOMM_EVENT event, struct sk_buff *skb ){
- DEBUG(0,"ircomm_state_discovery: "
- "why call me? \n");
- if(skb)
- dev_kfree_skb( skb);
-}
-
/*
* ircomm_state_idle
*/
static void ircomm_state_idle( struct ircomm_cb *self, IRCOMM_EVENT event,
- struct sk_buff *skb ){
+ struct sk_buff *skb )
+{
switch(event){
case IRCOMM_CONNECT_REQUEST:
- ircomm_next_state(self, COMM_WAITI);
- issue_connect_request( self, skb );
+ /* ircomm_next_state(self, COMM_WAITI); */
+ /* issue_connect_request( self, skb ); */
+
+ ircomm_next_state(self, COMM_DISCOVERY_WAIT);
+ start_discovering(self);
break;
case TTP_CONNECT_INDICATION:
@@ -559,15 +765,128 @@ static void ircomm_state_idle( struct ircomm_cb *self, IRCOMM_EVENT event,
case LMP_CONNECT_INDICATION:
- /* I think this is already done in irlpt_event.c */
-
- DEBUG(0,"ircomm_state_idle():LMP_CONNECT_IND is notimplemented!");
+ DEBUG(0,__FUNCTION__"():LMP_CONNECT_IND is notimplemented!");
/* connect_indication_three_wire_raw(); */
/* ircomm_next_state(self, COMM_WAITR); */
break;
default:
- DEBUG(0,"ircomm_state_idle():unknown event =%d(%s)\n",
+ DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n",
+ event, ircommevent[event]);
+ }
+}
+
+/*
+ * ircomm_state_discoverywait
+ */
+static void ircomm_state_discoverywait(struct ircomm_cb *self, IRCOMM_EVENT event,
+ struct sk_buff *skb )
+{
+ switch(event){
+
+ case TTP_CONNECT_INDICATION:
+
+ ircomm_next_state(self, COMM_WAITR);
+ queryias_done(self);
+ connect_indication( self, self->qos, skb);
+ break;
+
+ case DISCOVERY_INDICATION:
+ ircomm_next_state(self, COMM_QUERYPARAM_WAIT);
+ query_parameters(self);
+ break;
+
+ case IRCOMM_DISCONNECT_REQUEST:
+ ircomm_next_state(self, COMM_IDLE);
+ queryias_done(self);
+ break;
+
+ case QUERYIAS_ERROR:
+ ircomm_next_state(self, COMM_IDLE);
+ disconnect_indication(self, NULL);
+ queryias_done(self);
+ break;
+
+ default:
+ DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n",
+ event, ircommevent[event]);
+ }
+}
+
+/*
+ * ircomm_state_queryparamwait
+ */
+
+static void ircomm_state_queryparamwait(struct ircomm_cb *self, IRCOMM_EVENT event,
+ struct sk_buff *skb )
+{
+ switch(event){
+
+ case TTP_CONNECT_INDICATION:
+
+ ircomm_next_state(self, COMM_WAITR);
+ connect_indication( self, self->qos, skb);
+ break;
+
+ case GOT_PARAMETERS:
+
+ ircomm_next_state(self, COMM_QUERYLSAP_WAIT);
+ query_lsapsel( self );
+ break;
+
+ case IRCOMM_DISCONNECT_REQUEST:
+ ircomm_next_state(self, COMM_IDLE);
+ queryias_done(self);
+ break;
+
+ case QUERYIAS_ERROR:
+ ircomm_next_state(self, COMM_IDLE);
+ disconnect_indication(self, NULL);
+ queryias_done(self);
+ break;
+
+ default:
+ DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n",
+ event, ircommevent[event]);
+ }
+}
+
+/*
+ * ircomm_state_querylsapwait
+ */
+
+static void ircomm_state_querylsapwait(struct ircomm_cb *self, IRCOMM_EVENT event,
+ struct sk_buff *skb )
+{
+ switch(event){
+
+ case TTP_CONNECT_INDICATION:
+
+ ircomm_next_state(self, COMM_WAITR);
+ connect_indication( self, self->qos, skb);
+ break;
+
+ case GOT_LSAPSEL:
+
+ ircomm_next_state(self, COMM_WAITI);
+ queryias_done(self);
+ issue_connect_request( self, skb );
+ break;
+
+ case IRCOMM_DISCONNECT_REQUEST:
+ ircomm_next_state(self, COMM_IDLE);
+ queryias_done(self);
+ break;
+
+ case QUERYIAS_ERROR:
+ ircomm_next_state(self, COMM_IDLE);
+ disconnect_indication(self, NULL);
+ queryias_done(self);
+ break;
+
+
+ default:
+ DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n",
event, ircommevent[event]);
}
}
@@ -577,7 +896,8 @@ static void ircomm_state_idle( struct ircomm_cb *self, IRCOMM_EVENT event,
*/
static void ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event,
- struct sk_buff *skb ){
+ struct sk_buff *skb )
+{
switch(event){
case TTP_CONNECT_CONFIRM:
ircomm_next_state(self, COMM_CONN);
@@ -596,7 +916,7 @@ static void ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event,
/* ircomm_next_state(self, COMM_IDLE); */
/* break; */
default:
- DEBUG(0,"ircomm_state_waiti:unknown event =%d(%s)\n",
+ DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n",
event, ircommevent[event]);
}
}
@@ -607,7 +927,8 @@ static void ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event,
* ircomm_state_waitr
*/
static void ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
- struct sk_buff *skb ) {
+ struct sk_buff *skb )
+{
switch(event){
case IRCOMM_CONNECT_RESPONSE:
@@ -615,8 +936,7 @@ static void ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
/* issue_connect_response */
if(self->servicetype==THREE_WIRE_RAW){
- DEBUG(0,"ircomm:issue_connect_response:"
- "THREE_WIRE_RAW is not implemented!\n");
+ DEBUG(0,__FUNCTION__"():3WIRE_RAW is not implemented\n");
/* irlmp_connect_response(Vpeersap,
* ACCEPT,null);
*/
@@ -629,6 +949,7 @@ static void ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
case IRCOMM_DISCONNECT_REQUEST:
ircomm_next_state(self, COMM_IDLE);
issue_disconnect_request(self, skb);
+ queryias_done(self);
break;
case TTP_DISCONNECT_INDICATION:
@@ -636,6 +957,19 @@ static void ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
disconnect_indication(self, skb);
break;
+ case DISCOVERY_INDICATION:
+ DEBUG(0, __FUNCTION__"():DISCOVERY_INDICATION\n");
+ queryias_done(self);
+ break;
+ case GOT_PARAMETERS:
+ DEBUG(0, __FUNCTION__"():GOT_PARAMETERS\n");
+ queryias_done(self);
+ break;
+ case GOT_LSAPSEL:
+ DEBUG(0, __FUNCTION__"():GOT_LSAPSEL\n");
+ queryias_done(self);
+ break;
+
/* case LMP_DISCONNECT_INDICATION: */
/* disconnect_indication(); */
/* ircomm_next_state(self, COMM_IDLE); */
@@ -651,23 +985,20 @@ static void ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
*/
static void ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
- struct sk_buff *skb ){
+ struct sk_buff *skb )
+{
switch(event){
case TTP_DATA_INDICATION:
process_data(self, skb);
- /* stay CONN state*/
break;
case IRCOMM_DATA_REQUEST:
issue_data_request(self, skb);
- /* stay CONN state*/
break;
/* case LMP_DATA_INDICATION: */
/* ircomm_data_indicated(); */
-/* stay CONN state */
/* break; */
case IRCOMM_CONTROL_REQUEST:
issue_control_request(self, skb);
- /* stay CONN state*/
break;
case TTP_DISCONNECT_INDICATION:
ircomm_next_state(self, COMM_IDLE);
@@ -676,11 +1007,26 @@ static void ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
case IRCOMM_DISCONNECT_REQUEST:
ircomm_next_state(self, COMM_IDLE);
issue_disconnect_request(self, skb);
+ queryias_done(self);
break;
/* case LM_DISCONNECT_INDICATION: */
/* disconnect_indication(); */
/* ircomm_next_state(self, COMM_IDLE); */
/* break; */
+
+ case DISCOVERY_INDICATION:
+ DEBUG(0, __FUNCTION__"():DISCOVERY_INDICATION\n");
+ queryias_done(self);
+ break;
+ case GOT_PARAMETERS:
+ DEBUG(0, __FUNCTION__"():GOT_PARAMETERS\n");
+ queryias_done(self);
+ break;
+ case GOT_LSAPSEL:
+ DEBUG(0, __FUNCTION__"():GOT_LSAPSEL\n");
+ queryias_done(self);
+ break;
+
default:
DEBUG(0,"ircomm_state_conn:unknown event =%d(%s)\n",
event, ircommevent[event]);
@@ -688,16 +1034,116 @@ static void ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
}
+
/*
* ----------------------------------------------------------------------
- * ircomm requests
+ * IrCOMM service interfaces and supporting functions
*
* ----------------------------------------------------------------------
*/
+/*
+ * start_discovering()
+ *
+ * start discovering and enter DISCOVERY_WAIT state
+ */
+
+static void start_discovering(struct ircomm_cb *self)
+{
+ __u16 hints;
+ ASSERT( self != NULL, return;);
+ ASSERT( self->magic == IRCOMM_MAGIC, return;);
+ DEBUG(4,__FUNCTION__"():servicetype = %d\n",self->servicetype);
+
+
+ hints = irlmp_service_to_hint(S_COMM);
+
+ DEBUG(0,__FUNCTION__"():start discovering..\n");
+ switch (ircomm_cs) {
+ case 0:
+ MOD_INC_USE_COUNT;
+ self->queryias_lock = 1;
+ discovering_instance = self;
+ self->skey = irlmp_register_service(hints);
+ self->ckey = irlmp_register_client(hints, ircomm_discovery_indication,
+ NULL);
+ break;
+
+ case 1: /* client only */
+ MOD_INC_USE_COUNT;
+ self->queryias_lock = 1;
+ discovering_instance = self;
+ DEBUG( 0, __FUNCTION__"():client only mode\n");
+ self->ckey = irlmp_register_client(hints, ircomm_discovery_indication,
+ NULL);
+ break;
+
+ case 2: /* server only */
+ default:
+ DEBUG( 0, __FUNCTION__"():server only mode\n");
+ self->skey = irlmp_register_service(hints);
+ discovering_instance = NULL;
+ break;
+ }
+
+ return;
+}
+
+/*
+ * queryias_done(self)
+ *
+ * called when discovery process got wrong results, completed, or terminated.
+ */
+
+static void queryias_done(struct ircomm_cb *self)
+{
+ DEBUG(0, __FUNCTION__"():\n");
+ if(self->queryias_lock){
+ self->queryias_lock = 0;
+ discovering_instance = NULL;
+ MOD_DEC_USE_COUNT;
+ irlmp_unregister_client(self->ckey);
+ }
+ if(ircomm_cs != 1)
+ irlmp_unregister_service(self->skey);
+ return;
+}
+
+
+
+static void query_parameters(struct ircomm_cb *self)
+{
+
+ DEBUG(0, __FUNCTION__"():querying IAS: Parameters..\n");
+ iriap_getvaluebyclass_request( "IrDA:IrCOMM", "Parameters",
+ self->saddr, self->daddr,
+ ircomm_getvalue_confirm, self );
+}
+
+
+static void query_lsapsel(struct ircomm_cb * self)
+{
+ DEBUG(0, __FUNCTION__"():querying IAS: Lsapsel...\n");
-void ircomm_connect_request(struct ircomm_cb *self, int maxsdusize){
+ if (!(self->servicetype & THREE_WIRE_RAW)) {
+ iriap_getvaluebyclass_request(
+ "IrDA:IrCOMM", "IrDA:TinyTP:LsapSel",
+ self->saddr, self->daddr,
+ ircomm_getvalue_confirm, self );
+ } else {
+ DEBUG(0, __FUNCTION__ "THREE_WIRE_RAW is not implemented!\n");
+ }
+}
+/*
+ * ircomm_connect_request()
+ * Impl. of this function is differ from one of the reference.
+ * This functin does discovery as well as sending connect request
+ */
+
+
+void ircomm_connect_request(struct ircomm_cb *self, __u8 servicetype)
+{
/*
* TODO:build a packet which contains "initial control parameters"
* and send it with connect_request
@@ -706,14 +1152,19 @@ void ircomm_connect_request(struct ircomm_cb *self, int maxsdusize){
ASSERT( self != NULL, return;);
ASSERT( self->magic == IRCOMM_MAGIC, return;);
- DEBUG(0,"ircomm_connect_request:\n");
- self->maxsdusize = maxsdusize;
+ DEBUG(0, __FUNCTION__"():sending connect_request...\n");
+
+ self->servicetype= servicetype;
+ /* ircomm_control_request(self, SERVICETYPE); */ /*servictype*/
+
+ self->maxsdusize = SAR_DISABLE;
ircomm_do_event( self, IRCOMM_CONNECT_REQUEST, NULL);
}
void ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata,
- int maxsdusize){
+ __u32 maxsdusize)
+{
ASSERT( self != NULL, return;);
ASSERT( self->magic == IRCOMM_MAGIC, return;);
@@ -729,11 +1180,8 @@ void ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata,
if(!userdata){
/* FIXME: check for errors and initialize? DB */
userdata = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE);
- if(!userdata){
- DEBUG(0, __FUNCTION__"alloc_skb failed\n");
- return;
- }
- IS_SKB(userdata, return;);
+ ASSERT(userdata != NULL, return;);
+
skb_reserve(userdata,COMM_HEADER_SIZE);
}
@@ -746,31 +1194,73 @@ void ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata,
ircomm_do_event(self, IRCOMM_CONNECT_RESPONSE, userdata);
}
-void ircomm_disconnect_request(struct ircomm_cb *self, struct sk_buff *userdata){
+void ircomm_disconnect_request(struct ircomm_cb *self,
+ struct sk_buff *userdata,
+ int priority)
+{
ASSERT( self != NULL, return;);
ASSERT( self->magic == IRCOMM_MAGIC, return;);
+ DEBUG(0,__FUNCTION__"()\n");
+
+#if 0
+ /* unregister layer */
+ switch (ircomm_cs) {
+ case 1: /* client only */
+ irlmp_unregister_client(ckey);
+ break;
+
+ case 2: /* server only */
+ irlmp_unregister_service(skey);
+ break;
+ case 0:
+ default:
+ irlmp_unregister_client(ckey);
+ irlmp_unregister_service(skey);
+ break;
+ }
+#endif
+
+ self->disconnect_priority = priority;
+ if(priority != P_HIGH)
+ self->disconnect_priority = P_NORMAL;
- DEBUG(0,"ircomm_disconnect_request\n");
- ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, NULL);
+ ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, userdata);
}
-void ircomm_data_request(struct ircomm_cb *self, struct sk_buff *userdata){
+int ircomm_data_request(struct ircomm_cb *self, struct sk_buff *userdata)
+{
+ __u8 * frame;
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == IRCOMM_MAGIC, return;);
- ASSERT( userdata != NULL, return;);
+ DEBUG(4,__FUNCTION__"()\n");
+ ASSERT( self != NULL, return -EFAULT;);
+ ASSERT( self->magic == IRCOMM_MAGIC, return -EFAULT;);
+ ASSERT( userdata != NULL, return -EFAULT;);
+
if(self->state != COMM_CONN){
- DEBUG(4,"ignore IRCOMM_DATA_REQUEST:not connected\n");
- if(userdata)
- dev_kfree_skb(userdata);
- return;
+ DEBUG(4,__FUNCTION__"():not connected, data is ignored\n");
+ return -EINVAL;
}
- DEBUG(4,"ircomm_data_request\n");
+ if(self->ttp_stop)
+ return -EBUSY;
+
+ if(self->control_ch_pending){
+ /* send control_channel */
+ ircomm_tx_controlchannel(self);
+ }
+
+ if(self->ttp_stop)
+ return -EBUSY;
+
+ /* add "clen" field */
+ frame = skb_push(userdata,1);
+ frame[0]=0; /* without control channel */
+
ircomm_do_event(self, IRCOMM_DATA_REQUEST, userdata);
+ return 0;
}
/*
@@ -780,19 +1270,25 @@ void ircomm_data_request(struct ircomm_cb *self, struct sk_buff *userdata){
* ----------------------------------------------------------------------
*/
-static void ircomm_tx_ctrlbuffer(struct ircomm_cb *self ){
+
+static void ircomm_tx_controlchannel(struct ircomm_cb *self )
+{
__u8 clen;
struct sk_buff *skb = self->ctrl_skb;
- DEBUG(4,"ircomm_tx_ctrlbuffer:\n");
+ DEBUG(4,__FUNCTION__"()\n");
+ /* 'self' should have been checked */
+ ASSERT(!self->ttp_stop, return ;);
+ ASSERT(self->state == COMM_CONN, return ;);
/* add "clen" field */
clen=skb->len;
- if(clen){
- skb_push(skb,1);
- skb->data[0]=clen;
+ ASSERT(clen != 0,return;);
+
+ skb_push(skb,1);
+ skb->data[0]=clen;
#if 0
printk("tx_ctrl:");
@@ -803,145 +1299,106 @@ static void ircomm_tx_ctrlbuffer(struct ircomm_cb *self ){
printk("\n");
}
#endif
-
- ircomm_do_event(self, IRCOMM_CONTROL_REQUEST, skb);
-
- skb = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE);
- if (skb==NULL){
- DEBUG(0,"ircomm_tx_ctrlbuffer:alloc_skb failed!\n");
- return;
- }
- skb_reserve(skb,COMM_HEADER_SIZE);
- self->ctrl_skb = skb;
- }
-}
-
-
-void ircomm_control_request(struct ircomm_cb *self){
- struct sk_buff *skb;
+ ircomm_do_event(self, IRCOMM_CONTROL_REQUEST, skb);
+ self->control_ch_pending = 0;
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == IRCOMM_MAGIC, return;);
+ skb = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE);
+ ASSERT(skb != NULL, return ;);
- DEBUG(0, "ircomm_control_request:\n");
-
- if(self->ttp_stop || self->state != COMM_CONN){
- DEBUG(0,"ircomm_control_request:can't send it.. ignore it\n");
- return;
- }
-
- skb = self->ctrl_skb;
- IS_SKB(skb,return;);
-
- if(skb->len)
- ircomm_tx_ctrlbuffer(self);
+ skb_reserve(skb,COMM_HEADER_SIZE);
+ self->ctrl_skb = skb;
}
-static void append_tuple(struct ircomm_cb *self,
- __u8 instruction, __u8 pl , __u8 *value){
-
+static void append_tuple(struct ircomm_cb *self, __u8 instruction, __u8 pl ,
+ __u8 *value)
+{
__u8 *frame;
struct sk_buff *skb;
- int i,c;
+ int i,c = 0;
+ unsigned long flags;
+
+ save_flags(flags);cli();
skb = self->ctrl_skb;
ASSERT(skb != NULL, return;);
- IS_SKB(skb,return;);
- /*if there is little room in the packet... */
-
- if(skb->len > COMM_DEFAULT_DATA_SIZE - COMM_HEADER_SIZE - (pl+2)){
- if(!self->ttp_stop && self->state == COMM_CONN){
-
- /* send a packet if we can */
- ircomm_tx_ctrlbuffer(self);
- skb = self->ctrl_skb;
- } else {
- DEBUG(0, "ircomm_append_ctrl:there's no room.. ignore it\n");
-
- /* TODO: we have to detect whether we have to resend some
- information after ttp_stop is cleared */
-
- /* self->resend_ctrl = 1; */
- return;
- }
+ if(skb_tailroom(skb) < (pl+2)){
+ DEBUG(0, __FUNCTION__"there's no room.. ignore it\n");
+ self->ignored_control_tuples++;
+ restore_flags(flags);
+ return;
}
frame = skb_put(skb,pl+2);
- c = 0;
frame[c++] = instruction; /* PI */
frame[c++] = pl; /* PL */
for(i=0; i < pl ; i++)
frame[c++] = *value++; /* PV */
-
+ restore_flags(flags);
+ self->pending_control_tuples++;
+ self->control_ch_pending = 1;
}
/*
- * ircomm_append_ctrl();
+ * ircomm_control_request();
* this function is exported as a request to send some control-channel tuples
* to peer device
*/
-void ircomm_append_ctrl(struct ircomm_cb *self, __u8 instruction){
+void ircomm_control_request(struct ircomm_cb *self, __u8 instruction)
+{
- __u8 pv[70];
+ __u8 pv[32]; /* 32 max, for PORT_NAME */
__u8 *value = &pv[0];
__u32 temp;
+ int notsupp=0;
ASSERT( self != NULL, return;);
ASSERT( self->magic == IRCOMM_MAGIC, return;);
- if(self->state != COMM_CONN)
- return;
-
if(self->servicetype == THREE_WIRE_RAW){
- DEBUG(0,"THREE_WIRE_RAW shuold not use me!\n");
+ DEBUG(0,__FUNCTION__"():THREE_WIRE_RAW shuold not use me!\n");
return;
}
- DEBUG(4,"ircomm_append_ctrl:\n");
+ DEBUG(4,__FUNCTION__"()\n");
/* find parameter and its length */
- switch(instruction){
+ if(self->servicetype == THREE_WIRE) goto threewire;
+ if(self->servicetype == NINE_WIRE) goto ninewire;
- case POLL_FOR_LINE_SETTINGS:
- case STATUS_QUERY:
+
+ /* FIXME: centronics service is not fully implemented yet*/
+ switch(instruction){
case IEEE1284_MODE_SUPPORT:
case IEEE1284_DEVICEID:
append_tuple(self,instruction,0,NULL);
break;
-
- case SERVICETYPE:
- value[0] = self->servicetype;
- append_tuple(self,instruction,1,value);
+ case STATUS_QUERY:
+ append_tuple(self,instruction,0,NULL);
break;
- case DATA_FORMAT:
- value[0] = self->data_format;
+ case SET_BUSY_TIMEOUT:
+ value[0] = self->busy_timeout;
append_tuple(self,instruction,1,value);
break;
- case FLOW_CONTROL:
- if(self->null_modem_mode){
+ case IEEE1284_ECP_EPP_DATA_TRANSFER:
+ value[0] = self->ecp_epp_mode;
+ value[1] = self->channel_or_addr;
+ append_tuple(self,instruction,2,value);
+ break;
+ default:
+ notsupp=1;
+ }
- /* inside out */
- value[0] = (self->flow_ctrl & 0x55) << 1;
- value[0] |= (self->flow_ctrl & 0xAA) >> 1;
- }else{
- value[0] = self->flow_ctrl;
- }
- append_tuple(self,instruction,1,value);
- break;
- case LINESTATUS:
- value[0] = self->line_status;
- append_tuple(self,instruction,1,value);
- break;
- case BREAK_SIGNAL:
- value[0] = self->break_signal;
- append_tuple(self,instruction,1,value);
+ ninewire:
+ switch(instruction){
+ case POLL_FOR_LINE_SETTINGS:
+ append_tuple(self,instruction,0,NULL);
break;
case DTELINE_STATE:
if(self->null_modem_mode){
@@ -972,8 +1429,42 @@ void ircomm_append_ctrl(struct ircomm_cb *self, __u8 instruction){
value[0] = self->dce;
append_tuple(self,instruction,1,value);
break;
- case SET_BUSY_TIMEOUT:
- value[0] = self->busy_timeout;
+
+ default:
+ notsupp=1;
+ }
+
+ threewire:
+ switch(instruction){
+
+ case SERVICETYPE:
+ value[0] = self->servicetype;
+ append_tuple(self,instruction,1,value);
+ break;
+
+ case DATA_FORMAT:
+ value[0] = self->data_format;
+ append_tuple(self,instruction,1,value);
+ break;
+
+ case FLOW_CONTROL:
+ if(self->null_modem_mode){
+ /* inside out */
+ value[0] = (self->flow_ctrl & 0x55) << 1;
+ value[0] |= (self->flow_ctrl & 0xAA) >> 1;
+ }else{
+ value[0] = self->flow_ctrl;
+ }
+ append_tuple(self,instruction,1,value);
+ break;
+
+ case LINESTATUS:
+ value[0] = self->line_status;
+ append_tuple(self,instruction,1,value);
+ break;
+
+ case BREAK_SIGNAL:
+ value[0] = self->break_signal;
append_tuple(self,instruction,1,value);
break;
@@ -989,12 +1480,6 @@ void ircomm_append_ctrl(struct ircomm_cb *self, __u8 instruction){
append_tuple(self,instruction,2,value);
break;
- case IEEE1284_ECP_EPP_DATA_TRANSFER:
- value[0] = self->ecp_epp_mode;
- value[1] = self->channel_or_addr;
- append_tuple(self,instruction,2,value);
- break;
-
case DATA_RATE:
temp = self->data_rate;
value[3] = (__u8)((temp >> 24) & 0x000000ff);
@@ -1003,202 +1488,300 @@ void ircomm_append_ctrl(struct ircomm_cb *self, __u8 instruction){
value[0] = (__u8)(temp & 0x000000ff);
append_tuple(self,instruction,4,value);
break;
-
#if 0
case PORT_NAME:
case FIXED_PORT_NAME:
temp = strlen(&self->port_name);
- if(temp < 70){
+ if(temp < 32){
value = (__u8) (self->port_name);
append_tuple(self,instruction,temp,value);
- }
- break;
+ }else
+ DEBUG(0,__FUNCTION__"() PORT_NAME:too long\n");
#endif
-
-/* TODO: control tuples for centronics emulation is not implemented */
-/* case IEEE1284_MODE: */
+ break;
default:
- DEBUG(0,"ircomm_append_ctrl:instruction(0x%02x)is not"
- "implemented\n",instruction);
+ if(notsupp)
+ DEBUG(0,__FUNCTION__"():instruction(0x%02x)is not"
+ "implemented\n",instruction);
}
}
-static void ircomm_parse_control(struct ircomm_cb *self,
- struct sk_buff *skb,
- int type){
+void ircomm_parse_tuples(struct ircomm_cb *self, struct sk_buff *skb, int type)
+{
__u8 *data;
- __u8 pi,pl,pv[64];
+ __u8 pi,plen;
int clen = 0;
- int i,indicate,count = 0;
+ int indicate=0;
-
- data = skb->data;
- if(type == IAS_PARAM)
- clen = ((data[count++] << 8) & data[count++]); /* MSB first */
- else /* CONTROL_CHANNEL */
- clen = data[count++];
+ ASSERT(skb != NULL, return;);
+ ASSERT(self != NULL, return ;);
+ ASSERT(self->magic == IRCOMM_MAGIC, return ;);
- if(clen == 0){
- skb_pull( skb, 1); /* remove clen field */
- return;
+#ifdef IRCOMM_DEBUG_TUPLE
+ DEBUG(0, __FUNCTION__"():tuple sequence is:\n");
+ {
+ int i;
+ for ( i=0;i< skb->len;i++)
+ printk("%02x", (__u8)(skb->data[i]));
+ printk("\n");
}
+#endif
+ data = skb->data;
+ if(type == IAS_PARAM)
+ {
+ clen = (data[0] << 8) & 0xff00;
+ clen |= data[1] & 0x00ff;
+ ASSERT( clen <= (skb->len - 2) && clen <= 1024, goto corrupted;);
+ DEBUG(4, __FUNCTION__"():IAS_PARAM len = %d\n",clen );
+ skb_pull( skb, 2);
+ }
+ else
+ {
+ /* CONTROL_CHANNEL */
+ clen = data[0];
+ ASSERT( clen < skb->len, goto corrupted;);
+ DEBUG(4, __FUNCTION__"():CONTROL_CHANNEL:len = %d\n",clen );
+ skb_pull( skb, 1);
+ }
+ while( clen >= 2 ){
+ data = skb->data;
+ indicate = 0;
-
- while( count < clen ){
/*
* parse controlparameters and set value into structure
*/
- pi = data[count++];
- pl = data[count++];
-
- DEBUG(0, "parse_control:instruction(0x%02x)\n",pi) ;
+ pi = data[0];
+ plen = data[1];
+ ASSERT( clen >= 2+plen, goto corrupted; );
+ DEBUG(4, __FUNCTION__"():instruction=0x%02x,len=%d\n",
+ pi, plen) ;
- /* copy a tuple into pv[] */
-#ifdef IRCOMM_DEBUG_TUPLE
- printk("data:");
- for(i=0; i < pl; i++){
- pv[i] = data[count++];
- printk("%02x",pv[i]);
- }
- printk("\n");
-#else
- for(i=0; i < pl; i++)
- pv[i] = data[count++];
-#endif
+ switch(pi)
+ {
+ case POLL_FOR_LINE_SETTINGS:
+ ircomm_control_request(self, DTELINE_STATE);
+ break;
-
- /* parse pv */
- indicate = 0;
-
- switch(pi){
-
- /*
- * for 3-wire/9-wire/centronics
- */
-
case SERVICETYPE:
- self->peer_servicetype = pv[0];
+ self->peer_servicetype = data[2];
break;
+
case PORT_TYPE:
- self->peer_port_type = pv[0];
- break;
-#if 0
- case PORT_NAME:
- self->peer_port_name = *pv;
- break;
- case FIXED_PORT_NAME:
- self->peer_port_name = *pv;
- /*
- * We should not connect if user of IrCOMM can't
- * recognize the port name
- */
- self->port_name_critical = TRUE;
- break;
-#endif
- case DATA_RATE:
- self->peer_data_rate = (pv[3]<<24) & (pv[2]<<16)
- & (pv[1]<<8) & pv[0];
- indicate = 1;
+ self->peer_port_type = data[2];
break;
+
case DATA_FORMAT:
- self->peer_data_format = pv[0];
+ self->peer_data_format = data[2];
break;
+
case FLOW_CONTROL:
- self->peer_flow_ctrl = pv[0];
- indicate = 1;
- break;
- case XON_XOFF_CHAR:
- self->peer_xon_char = pv[0];
- self->peer_xoff_char = pv[1];
- indicate = 1;
- break;
- case ENQ_ACK_CHAR:
- self->peer_enq_char = pv[0];
- self->peer_ack_char = pv[1];
+ self->peer_flow_ctrl = data[2];
indicate = 1;
break;
+
case LINESTATUS:
- self->peer_line_status = pv[0];
+ self->peer_line_status = data[2];
indicate = 1;
break;
+
case BREAK_SIGNAL:
- self->peer_break_signal = pv[0];
+ self->peer_break_signal = data[2];
/* indicate = 1; */
break;
-
- /*
- * for 9-wire
- */
+
+ case DCELINE_STATE:
+ self->peer_dce = data[2];
+ indicate = 1;
+ break;
case DTELINE_STATE:
if(self->null_modem_mode){
/* input DTR as {DSR & CD & RI} */
self->peer_dce = 0;
- if(pv[0] & DELTA_DTR)
- self->peer_dce |= DELTA_DSR|DELTA_RI|DELTA_DCD;
- if(pv[0] & MCR_DTR)
- self->peer_dce |= MSR_DSR|MSR_RI|MSR_DCD;
-
+ if(data[2] & DELTA_DTR)
+ self->peer_dce |= (DELTA_DSR|
+ DELTA_RI|
+ DELTA_DCD);
+ if(data[2] & MCR_DTR)
+ self->peer_dce |= (MSR_DSR|
+ MSR_RI|
+ MSR_DCD);
/* rts as cts */
- if(pv[0] & DELTA_RTS)
+ if(data[2] & DELTA_RTS)
self->peer_dce |= DELTA_CTS;
- if(pv[0] & MCR_RTS)
+ if(data[2] & MCR_RTS)
self->peer_dce |= MSR_CTS;
}else{
- self->peer_dte = pv[0];
+ self->peer_dte = data[2];
}
indicate = 1;
break;
+
+ case XON_XOFF_CHAR:
+ self->peer_xon_char = data[2];
+ self->peer_xoff_char = data[3];
+ indicate = 1;
+ break;
- case DCELINE_STATE:
- self->peer_dce = pv[0];
+ case ENQ_ACK_CHAR:
+ self->peer_enq_char = data[2];
+ self->peer_ack_char = data[3];
indicate = 1;
break;
- case POLL_FOR_LINE_SETTINGS:
- ircomm_append_ctrl(self, DTELINE_STATE);
- ircomm_control_request(self);
+ case DATA_RATE:
+ self->peer_data_rate = ( data[5]<<24
+ & data[4]<<16
+ & data[3]<<8
+ & data[2]);
+ indicate = 1;
break;
- /*
- * for centronics .... not implemented yet
+ case PORT_NAME:
+ ASSERT(plen <= 32 , goto corrupted;);
+ memcpy(self->port_name, data + 2, plen);
+ *(__u8 *)(self->port_name+plen) = 0;
+ break;
+
+ case FIXED_PORT_NAME:
+ ASSERT(plen <= 32 , goto corrupted;);
+ memcpy(self->port_name, data + 2, plen);
+ *(__u8 *)(self->port_name+plen) = 0;
+ /*
+ * We should not connect if user of IrCOMM can't
+ * recognize the port name
*/
-/* case STATUS_QUERY: */
-/* case SET_BUSY_TIMEOUT: */
-/* case IEEE1284_MODE_SUPPORT: */
-/* case IEEE1284_DEVICEID: */
-/* case IEEE1284_MODE: */
-/* case IEEE1284_ECP_EPP_DATA_TRANSFER: */
-
- default:
- DEBUG(0, "ircomm_parse_control:not implemented "
- "instruction(%d)\n", pi);
+ self->port_name_critical = TRUE;
break;
+
+ default:
+ DEBUG(0, __FUNCTION__
+ "():not implemented (PI=%d)\n", pi);
}
- if(indicate && self->notify.flow_indication
- && type == CONTROL_CHANNEL){
-
- DEBUG(0,"ircomm:parse_control:indicating..:\n");
+
+ if(indicate &&
+ self->notify.flow_indication && type == CONTROL_CHANNEL)
+ {
+ DEBUG(4,__FUNCTION__":indicating..:\n");
self->pi = pi;
if(self->notify.flow_indication)
- self->notify.flow_indication(self->notify.instance, self, 0);
- indicate = 0;
+ self->notify.flow_indication(self->notify.instance,
+ self,
+ CONTROL_CHANNEL);
}
+ skb_pull(skb, 2+plen);
+ clen -= (2+plen);
}
- skb_pull( skb, 1+clen);
+
return;
+
+ corrupted:
+ skb_pull(skb, skb->len); /* remove suspicious data */
+ return;
+}
+
+/*
+ * ----------------------------------------------------------------------
+ * Function ircomm_open_instance() ,ircomm_close_instance() and friends
+ *
+ * ircomm_open_instance discoveres the peer device and then issues a
+ * connect request
+ * ----------------------------------------------------------------------
+ */
+
+
+
+struct ircomm_cb * ircomm_open_instance( struct notify_t client_notify)
+{
+ int i;
+ struct ircomm_cb *self = NULL;
+ struct notify_t notify;
+ unsigned long flags;
+
+ ASSERT(ircomm != NULL,return NULL;);
+ DEBUG(0,__FUNCTION__"():\n");
+
+ /* find free handle */
+
+ save_flags(flags);
+ cli();
+ for(i = 0; i < IRCOMM_MAX_CONNECTION; i++){
+ ASSERT(ircomm[i] != NULL,return(NULL););
+ if(!ircomm[i]->in_use){
+ self = ircomm[i];
+ break;
+ }
+ }
+
+ if (!self){
+ DEBUG(0,__FUNCTION__"():no free handle!\n");
+ return (NULL);
+ }
+
+ self->in_use = 1;
+ restore_flags(flags);
+
+ self->notify = client_notify;
+ self->ttp_stop = 0;
+ self->control_ch_pending = 0;
+
+ /* register callbacks */
+
+ irda_notify_init(&notify);
+ notify.data_indication = ircomm_accept_data_indication;
+ notify.connect_confirm = ircomm_accept_connect_confirm;
+ notify.connect_indication = ircomm_accept_connect_indication;
+ notify.flow_indication = ircomm_accept_flow_indication;
+ notify.disconnect_indication = ircomm_accept_disconnect_indication;
+ notify.instance = self;
+ strncpy( notify.name, "IrCOMM", NOTIFY_MAX_NAME);
+
+ self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT,
+ &notify);
+ if(!self->tsap){
+ DEBUG(0,__FUNCTION__"failed to allocate tsap\n");
+ return NULL;
+ }
+
+ ircomm_next_state(self, COMM_IDLE);
+ return (self);
}
+int ircomm_close_instance(struct ircomm_cb *self)
+{
+ ASSERT( self != NULL, return -EIO;);
+ ASSERT( self->magic == IRCOMM_MAGIC, return -EIO;);
+ ASSERT( self->ctrl_skb != NULL, return -EIO;);
+
+ DEBUG(0,__FUNCTION__"()\n");
+
+ /* shutdown ircomm layer */
+ if(self->state != COMM_IDLE && self->state != COMM_WAITI)
+ {
+ DEBUG(0,__FUNCTION__"():force disconnecting..\n");
+ ircomm_disconnect_request(self, NULL, P_HIGH);
+ }
+
+ skb_trim(self->ctrl_skb,0);
+ /* remove a tsap */
+ if(self->tsap)
+ irttp_close_tsap(self->tsap);
+ self->tsap = NULL;
+ self->in_use = 0;
+ return 0;
+}
+
+
/*
* ----------------------------------------------------------------------
* Function init_module(void) ,cleanup_module()
@@ -1209,20 +1792,21 @@ static void ircomm_parse_control(struct ircomm_cb *self,
*/
#ifdef MODULE
+int init_module(void)
+{
+ int err;
-int init_module(void) {
- ircomm_init();
+ err = ircomm_init();
- DEBUG( 4, "ircomm:init_module:done\n");
- return 0;
+ DEBUG( 4, __FUNCTION__"():done.\n");
+ return err;
}
void cleanup_module(void)
{
ircomm_cleanup();
- DEBUG( 0, "ircomm_common:cleanup_module:done.\n");
+ DEBUG( 4, __FUNCTION__"():done.\n");
}
-
#endif /* MODULE */
/************************************************************
@@ -1238,53 +1822,92 @@ void cleanup_module(void)
*
*/
int ircomm_proc_read(char *buf, char **start, off_t offset,
- int len, int unused){
+ int len, int unused)
+{
int i, index;
len = 0;
for (i=0; i<IRCOMM_MAX_CONNECTION; i++) {
+ len += sprintf(buf+len, "instance %d:\n",i);
+ if(ircomm[i]->in_use == 0){
+ len += sprintf(buf+len, "\tunused\n");
+ continue;
+ }
+
if (ircomm[i] == NULL || ircomm[i]->magic != IRCOMM_MAGIC) {
- len += sprintf(buf+len, "???\t");
- }else {
- switch (ircomm[i]->servicetype) {
- case UNKNOWN:
- index = 0;
- break;
- case THREE_WIRE_RAW:
- index = 1;
- break;
- case THREE_WIRE:
- index = 2;
- break;
- case NINE_WIRE:
- index = 3;
- break;
- case CENTRONICS:
- index = 4;
- break;
- default:
- index = 0;
- break;
- }
- len += sprintf(buf+len, "service: %s\t",
- ircommservicetype[index]);
- if(index){
- len += sprintf(buf+len, "porttype: %s ",
- ircommporttype[ircomm[i]->port_type]);
- len += sprintf(buf+len, "state: %s ",
- ircommstate[ircomm[i]->state]);
- len += sprintf(buf+len, "user: %s ",
- ircomm[i]->notify.name);
- len += sprintf(buf+len, "nullmodem emulation: %s",
- (ircomm[i]->null_modem_mode ? "yes":"no"));
- }
+ len += sprintf(buf+len, "\tbroken???\n");
+ continue;
+ }
+
+ switch (ircomm[i]->servicetype) {
+ case UNKNOWN:
+ index = 0;
+ break;
+ case THREE_WIRE_RAW:
+ index = 1;
+ break;
+ case THREE_WIRE:
+ index = 2;
+ break;
+ case NINE_WIRE:
+ index = 3;
+ break;
+ case CENTRONICS:
+ index = 4;
+ break;
+ default:
+ index = 0;
+ break;
}
- len += sprintf(buf+len, "\n");
+ len += sprintf(buf+len, " service: %s ",
+ ircommservicetype[index]);
+ if(!index)
+ continue;
+
+ len += sprintf(buf+len, "porttype: %s ",
+ ircommporttype[ircomm[i]->port_type]);
+ len += sprintf(buf+len, "state: %s ",
+ ircommstate[ircomm[i]->state]);
+ len += sprintf(buf+len, "user: %s\n",
+ ircomm[i]->notify.name);
+
+ len += sprintf(buf+len, " tx packets: %d ",
+ ircomm[i]->tx_packets);
+ len += sprintf(buf+len, "rx packets: %d ",
+ ircomm[i]->rx_packets);
+ len += sprintf(buf+len, "tx controls: %d\n",
+ ircomm[i]->tx_controls);
+
+ len += sprintf(buf+len, " pending tuples: %d ",
+ ircomm[i]->pending_control_tuples);
+ len += sprintf(buf+len, " ignored tuples: %d\n",
+ ircomm[i]->ignored_control_tuples);
+
+ len += sprintf(buf+len, " nullmodem emulation: %s ",
+ (ircomm[i]->null_modem_mode ? "yes":"no"));
+ len += sprintf(buf+len, "IrTTP: %s\n",
+ (ircomm[i]->ttp_stop ? "BUSY":"READY"));
+
+ len += sprintf(buf+len, " Peer capability: ");
+ if(ircomm[i]->peer_cap & THREE_WIRE_RAW)
+ len += sprintf(buf+len, "3wire-raw ");
+ if(ircomm[i]->peer_cap & THREE_WIRE)
+ len += sprintf(buf+len, "3wire ");
+ if(ircomm[i]->peer_cap & NINE_WIRE)
+ len += sprintf(buf+len, "9wire ");
+ if(ircomm[i]->peer_cap & CENTRONICS)
+ len += sprintf(buf+len, "centronics");
+
+ len += sprintf(buf+len, "\n Port name: %s\n",
+ (ircomm[i]->port_name));
}
+
return len;
}
-
#endif /* CONFIG_PROC_FS */
+
+
+
diff --git a/net/irda/ircomm/irvtd.c b/net/irda/ircomm/irvtd.c
deleted file mode 100644
index e01781556..000000000
--- a/net/irda/ircomm/irvtd.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/*********************************************************************
- *
- * Filename: irvtd.c
- * Version:
- * Description: A virtual tty driver implementaion,
- * which also may be called as "Port Emulation Entity"
- * in IrCOMM specification.
- * Status: Experimental.
- * Author: Takahide Higuchi <thiguchi@pluto.dti.ne.jp>
- * Source: irlpt.c
- *
- * Copyright (c) 1998, 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 <net/irda/irda.h>
-#include <net/irda/irlmp.h>
-
-#include <net/irda/irvtd.h>
-#include <net/irda/irvtd_driver.h>
-
-struct irvtd_cb **irvtd = NULL;
-extern struct ircomm_cb **ircomm;
-
-#if 0
-static char *rcsid = "$Id: irvtd.c,v 1.2 1998/09/27 08:37:04 takahide Exp $";
-#endif
-static char *version = "IrVTD, $Revision: 1.2 $ $Date: 1998/09/27 08:37:04 $ (Takahide Higuchi)";
-
-
-/************************************************************
- * init & cleanup this module
- ************************************************************/
-
-/*
- * Function init_module(void)
- *
- * Initializes the ircomm control structure
- * This Function is called when you do insmod.
- */
-
-__initfunc(int irvtd_init(void))
-{
- int i;
-
- DEBUG( 4, "irvtd:init_module:\n");
- printk( KERN_INFO "%s\n", version);
-
- /* we allocate master array */
-
- irvtd = (struct irvtd_cb **) kmalloc( sizeof(void *) *
- COMM_MAX_TTY,GFP_KERNEL);
- if ( irvtd == NULL) {
- printk( KERN_WARNING "irvtd: Can't allocate array!\n");
- return -ENOMEM;
- }
-
- memset( irvtd, 0, sizeof(void *) * COMM_MAX_TTY);
-
-
- /* we initialize structure */
-
- for (i=0; i < COMM_MAX_TTY; i++){
- irvtd[i] = kmalloc( sizeof(struct irvtd_cb), GFP_KERNEL);
- if(irvtd[i] == NULL){
- printk(KERN_ERR "ircomm_open(): kmalloc failed!\n");
- return -ENOMEM;
- }
-
- memset( irvtd[i], 0, sizeof(struct irvtd_cb));
- irvtd[i]->magic = IRVTD_MAGIC;
- }
-
- /*
- * initialize a "port emulation entity"
- */
-
- if(irvtd_register_ttydriver()){
- printk( KERN_WARNING "IrCOMM: Error in ircomm_register_device\n");
- return -ENODEV;
- }
-
-
- DEBUG( 4, "irvtd:init_module:done\n");
- return 0;
-}
-
-void irvtd_cleanup(void)
-{
- int i;
- DEBUG( 4, "--> ircomm:cleanup_module\n");
-
- /*
- * free some resources
- */
- if (irvtd) {
- for (i=0; i<COMM_MAX_TTY; i++) {
- if (irvtd[i]) {
- DEBUG( 4, "freeing structures\n");
- /* irvtd_close(); :{| */
- kfree(irvtd[i]);
- irvtd[i] = NULL;
- }
- }
- DEBUG( 4, "freeing master array\n");
- kfree(irvtd);
- irvtd = NULL;
- }
-
-
-
- DEBUG( 0, "unregister_ttydriver..\n");
- irvtd_unregister_ttydriver();
-
- DEBUG( 4, "ircomm:cleanup_module -->\n");
-}
-
-#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 */
-
-
-
diff --git a/net/irda/ircomm/irvtd_driver.c b/net/irda/ircomm/irvtd_driver.c
index 7738e3e78..2df2fdd60 100644
--- a/net/irda/ircomm/irvtd_driver.c
+++ b/net/irda/ircomm/irvtd_driver.c
@@ -2,7 +2,7 @@
*
* Filename: irvtd_driver.c
* Version:
- * Description: An implementation of "port emulation entity" of IrCOMM
+ * 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
@@ -22,17 +22,20 @@
********************************************************************/
#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>
-#include <net/irda/irvtd_driver.h>
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
@@ -41,14 +44,15 @@
#define DO_RESTART
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-static char *irvtd_ttyname = "irnine";
-struct tty_driver irvtd_drv, irvtd_callout_driver;
+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 ircomm_vsd_refcount;
-extern struct ircomm_cb **ircomm;
-extern struct irvtd_cb **irvtd;
+static int irvtd_refcount;
+struct irvtd_cb **irvtd = NULL;
+
+static char *revision_date = "Sun Apr 18 17:31:53 1999";
+
/*
* prototypes
@@ -70,158 +74,32 @@ 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 flush_txbuff(struct irvtd_cb *info);
static void change_speed(struct irvtd_cb *driver);
-static void irvtd_write_to_tty( void *instance );
-
+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);
-#if 0
-static char *rcsid = "$Id: irvtd_driver.c,v 1.13 1998/12/06 10:09:07 takahide Exp $";
-#endif
-
-
-
-
-/*
- * Function ircomm_register_device(void)
- * we register "port emulation entity"(see IrCOMM specification) here
- * as a tty device.
- * it will be called when you insmod.
- * ( This function derives from linux/drivers/char/serial.c )
- */
-
-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.name = irvtd_ttyname;
- 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 */
- irvtd_drv.subtype = IRVTD_TYPE_NORMAL; /* private type */
-
- /*
- * 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 = &ircomm_vsd_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 = NULL;
- irvtd_drv.wait_until_sent = NULL;
-
- /*
- * The callout device is just like normal device except for
- * minor number and the subtype.
- */
-
- /* What is difference between callout device and normal device? */
- /* My system dosen't have /dev/cua??, so we don't need it? :{| */
- irvtd_callout_driver = irvtd_drv;
- irvtd_callout_driver.name = "irninecua";
- irvtd_callout_driver.minor_start = IRVTD_CALLOUT_MINOR;
- irvtd_callout_driver.subtype = IRVTD_TYPE_CALLOUT;
-
-
- if (tty_register_driver(&irvtd_drv)){
- DEBUG(0,"IrCOMM:Couldn't register tty driver\n");
- return(1);
- }
- if (tty_register_driver(&irvtd_callout_driver))
- DEBUG(0,"IrCOMM:Couldn't register callout tty driver\n");
-
- 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);
- err = tty_unregister_driver(&irvtd_callout_driver);
- if (err)
- printk("IrCOMM: failed to unregister vtd_callout driver(%d)\n", err);
-
- DEBUG( 4, "irvtd_unregister_device -->\n");
- return;
-}
+static void irvtd_start_timer( struct irvtd_cb *driver);
+static void irvtd_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);
/*
- * ----------------------------------------------------------------------
- * Routines for Virtual tty driver
+ **********************************************************************
*
- * most of infomation is descrived in linux/tty_driver.h, but
- * a function ircomm_receive() derives from receive_chars() which is
- * in 2.0.30 kernel (driver/char/serial.c).
- * if you want to understand them, please see related kernel source
- * (and my comments :).
- * ----------------------------------------------------------------------
- */
-
-/*
- * ----------------------------------------------------------------------
- * ircomm_receive_data()
+ * ircomm_receive_data() and friends
*
* like interrupt handler in the serial.c,we receive data when
* ircomm_data_indication comes
- * ----------------------------------------------------------------------
+ *
+ **********************************************************************
*/
@@ -231,25 +109,24 @@ void irvtd_unregister_ttydriver(void){
* send incoming/queued data to tty
*/
-static void irvtd_write_to_tty( void *instance ){
-
+static void irvtd_write_to_tty( struct irvtd_cb *driver)
+{
int status, c, flag;
-
struct sk_buff *skb;
- struct irvtd_cb *driver = (struct irvtd_cb *)instance;
struct tty_struct *tty = driver->tty;
- /* does instance still exist ? should be checked */
- ASSERT(driver->magic == IRVTD_MAGIC, return;);
-
- if(driver->rx_disable ){
- DEBUG(0,__FUNCTION__"rx_disable is true:do_nothing..\n");
+ if(driver->rx_disable)
return;
- }
-
+
skb = skb_dequeue(&driver->rxbuff);
- ASSERT(skb != NULL, return;); /* there's nothing */
- IS_SKB(skb, return;);
+ 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:");
@@ -264,12 +141,6 @@ static void irvtd_write_to_tty( void *instance ){
status = driver->comm->peer_line_status & driver->read_status_mask;
/*
- * FIXME: we must do ircomm_parse_ctrl() here, instead of
- * ircomm_common.c!!
- */
-
-
- /*
* if there are too many errors which make a character ignored,
* drop characters
*/
@@ -289,7 +160,7 @@ static void irvtd_write_to_tty( void *instance ){
DEBUG(0,"handling break....\n");
flag = TTY_BREAK;
- if (driver->flags & IRVTD_ASYNC_SAK)
+ if (driver->flags & ASYNC_SAK)
/*
* do_SAK() seems to be an implementation of the
* idea called "Secure Attention Key",
@@ -311,7 +182,8 @@ static void irvtd_write_to_tty( void *instance ){
flag = TTY_NORMAL;
if(c){
- DEBUG(0,"writing %d chars to tty\n",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;
@@ -325,205 +197,207 @@ static void irvtd_write_to_tty( void *instance ){
else
{
/* queue rest of data again */
- DEBUG(0,__FUNCTION__":retrying frame!\n");
+ 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 );
}
- /*
- * in order to optimize this routine, these two tasks should be
- * queued in following order
- * ( see run_task_queue() and queue_task() in tqueue.h
- */
- if(skb_queue_len(&driver->rxbuff))
- /* let me try again! */
- queue_task(&driver->rx_tqueue, &tq_timer);
if(c)
- /* read your buffer! */
- queue_task(&tty->flip.tqueue, &tq_timer);
+ /* let the process read its buffer! */
+ tty_flip_buffer_push(tty);
-
- if(skb_queue_len(&driver->rxbuff)< IRVTD_RX_QUEUE_LOW
- && driver->ttp_stoprx){
+ if(skb_queue_len(&driver->rxbuff)< IRVTD_RX_QUEUE_LOW &&
+ driver->ttp_stoprx){
irttp_flow_request(driver->comm->tsap, FLOW_START);
driver->ttp_stoprx = 0;
}
+
+ if(skb_queue_empty(&driver->rxbuff) && driver->disconnect_pend){
+ /* disconnect */
+ driver->disconnect_pend = 0;
+ driver->rx_disable = 1;
+ tty_hangup(driver->tty);
+ }
}
-void irvtd_receive_data(void *instance, void *sap, struct sk_buff *skb){
-
+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;);
- ASSERT(driver->magic == IRVTD_MAGIC, return;);
+ 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) == 1)
- irvtd_write_to_tty(driver);
+
if(skb_queue_len(&driver->rxbuff) > IRVTD_RX_QUEUE_HIGH){
irttp_flow_request(driver->comm->tsap, FLOW_STOP);
driver->ttp_stoprx = 1;
}
- return;
+ irvtd_write_to_tty(driver);
+ return 0;
}
-#if 0
-void irvtd_receive_data(void *instance, void *sap, struct sk_buff *skb){
+/*
+ ***********************************************************************
+ *
+ * irvtd_send_data() and friends
+ *
+ * like interrupt handler in the serial.c,we send data when
+ * a timer is expired
+ *
+ ***********************************************************************
+ */
+
+
+static void irvtd_start_timer( struct irvtd_cb *driver)
+{
+ ASSERT( driver != NULL, return;);
+ ASSERT( driver->magic == IRVTD_MAGIC, return;);
+
+ del_timer( &driver->timer);
- int flag,status;
- __u8 c;
- struct tty_struct *tty;
- struct irvtd_cb *driver = (struct irvtd_cb *)instance;
+ driver->timer.data = (unsigned long) driver;
+ driver->timer.function = &irvtd_timer_expired;
+ driver->timer.expires = jiffies + (HZ / 5); /* 200msec */
+
+ add_timer( &driver->timer);
+}
- ASSERT(driver != NULL, return;);
- ASSERT(driver->magic == IRVTD_MAGIC, return;);
- if(driver->rx_disable ){
- DEBUG(0,__FUNCTION__"rx_disable is true:do nothing\n");
- return;
- }
+static void irvtd_timer_expired(unsigned long data)
+{
+ struct irvtd_cb *driver = (struct irvtd_cb *)data;
- tty = driver->tty;
- status = driver->comm->peer_line_status & driver->read_status_mask;
+ ASSERT(driver != NULL,return;);
+ ASSERT(driver->magic == IRVTD_MAGIC,return;);
+ DEBUG(4, __FUNCTION__"()\n");
- c = MIN(skb->len, (TTY_FLIPBUF_SIZE - tty->flip.count));
- DEBUG(0, __FUNCTION__"skb_len=%d, tty->flip.count=%d \n"
- ,(int)skb->len, tty->flip.count);
+ irvtd_send_data_request(driver);
-#ifdef IRVTD_DEBUG_RX
- printk("received data:");
+ irvtd_write_to_tty(driver);
+
+ /* start our timer again and again */
+ irvtd_start_timer(driver);
+}
+
+
+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("%02x", skb->data[i]);
printk("\n");
}
#endif
- /*
- * if there are too many errors which make a character ignored,
- * drop characters
- */
-
- if(status & driver->ignore_status_mask){
- DEBUG(0,__FUNCTION__"I/O error:ignore characters.\n");
- dev_kfree_skb(skb, FREE_READ);
- return;
- }
-
- if (driver->comm->peer_break_signal ) {
- driver->comm->peer_break_signal = 0;
- DEBUG(0,"handling break....\n");
-
- flag = TTY_BREAK;
- if (driver->flags & IRVTD_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 is "Orange book"!?
- */
- 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;
+ DEBUG(1, __FUNCTION__"():sending %d octets\n",(int)skb->len );
+ 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);
+ skb_trim(skb, 0);
+ }
- if(c){
- DEBUG(0,"writing %d chars to tty\n",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);
- queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+ /* allocate a new frame */
+ skb = driver->txbuff = dev_alloc_skb(driver->comm->max_txbuff_size);
+ if (skb == NULL){
+ printk(__FUNCTION__"():alloc_skb failed!\n");
+ } else {
+ skb_reserve(skb, COMM_HEADER_SIZE);
}
- if(skb->len >0)
- DEBUG(0,__FUNCTION__":dropping frame!\n");
- dev_kfree_skb(skb, FREE_READ);
- DEBUG(4,__FUNCTION__":done\n");
+
+ wake_up_interruptible(&driver->tty->write_wait);
}
-#endif
+
/*
- * ----------------------------------------------------------------------
+ ***********************************************************************
+ *
* indication/confirmation handlers:
- * they will be registerd in irvtd_startup() to know that we
- * discovered (or we are discovered by) remote device.
- * ----------------------------------------------------------------------
+ *
+ * these routines are handlers for IrCOMM protocol stack
+ *
+ ***********************************************************************
*/
-/* this function is called whed ircomm_attach_cable succeed */
-
-void irvtd_attached(struct ircomm_cb *comm){
-
- ASSERT(comm != NULL, return;);
- ASSERT(comm->magic == IRCOMM_MAGIC, return;);
-
- DEBUG(0,"irvtd_attached:sending connect_request"
- " for servicetype(%d)..\n",comm->servicetype);
- ircomm_connect_request(comm, SAR_DISABLE );
-}
-
/*
- * irvtd_connect_confirm()
- * ircomm_connect_request which we have send have succeed!
+ * Function irvtd_connect_confirm (instance, sap, qos, max_sdu_size, skb)
+ *
+ * ircomm_connect_request which we have send have succeed!
+ *
*/
-
void irvtd_connect_confirm(void *instance, void *sap, struct qos_info *qos,
- int max_sdu_size, struct sk_buff *skb){
-
+ __u32 max_sdu_size, struct sk_buff *skb)
+{
struct irvtd_cb *driver = (struct irvtd_cb *)instance;
ASSERT(driver != NULL, return;);
ASSERT(driver->magic == IRVTD_MAGIC, return;);
/*
+ * set default value
+ */
+
+ driver->msr |= (MSR_DCD|MSR_RI|MSR_DSR|MSR_CTS);
+
+ /*
* sending initial control parameters here
- *
- * TODO: it must be done in ircomm_connect_request()
*/
-#if 1
if(driver->comm->servicetype == THREE_WIRE_RAW)
return; /* do nothing */
- ircomm_append_ctrl(driver->comm, SERVICETYPE);
- /* ircomm_append_ctrl(self, DATA_RATE); */
- ircomm_append_ctrl(driver->comm, DATA_FORMAT);
- ircomm_append_ctrl(driver->comm, FLOW_CONTROL);
- ircomm_append_ctrl(driver->comm, XON_XOFF_CHAR);
- /* ircomm_append_ctrl(driver->comm, ENQ_ACK_CHAR); */
+ 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_append_ctrl(driver->comm, DTELINE_STATE);
+ ircomm_control_request(driver->comm, DTELINE_STATE);
break;
default:
}
- ircomm_control_request(driver->comm);
-#endif
-
+ driver->tx_disable = 0;
wake_up_interruptible(&driver->open_wait);
}
/*
- * irvtd_connect_indication()
- * we are discovered and being requested to connect by remote device !
+ * 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,
- int max_sdu_size, struct sk_buff *skb)
+ __u32 max_sdu_size, struct sk_buff *skb)
{
struct irvtd_cb *driver = (struct irvtd_cb *)instance;
@@ -535,46 +409,103 @@ void irvtd_connect_indication(void *instance, void *sap, struct qos_info *qos,
DEBUG(4,"irvtd_connect_indication:sending connect_response...\n");
- /*TODO: connect_response should send initialcontrolparameters! TH*/
-
ircomm_connect_response(comm, NULL, SAR_DISABLE );
- wake_up_interruptible(&driver->open_wait);
-}
+ 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:
+ }
-void irvtd_disconnect_indication(void *instance, void *sap , LM_REASON reason,
- struct sk_buff *skb){
+ 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");
- tty_hangup(driver->tty);
+
+ driver->tx_disable = 1;
+ if(skb_queue_empty(&driver->rxbuff)){
+ /* disconnect */
+ driver->rx_disable = 1;
+ tty_hangup(driver->tty);
+ } else {
+ driver->disconnect_pend = 1;
+ }
}
/*
- * irvtd_control_indication
+ * Function irvtd_control_indication (instance, sap, cmd)
+ *
+ *
*
*/
-
-
-void irvtd_control_indication(void *instance, void *sap, LOCAL_FLOW flow){
-
+void irvtd_control_indication(void *instance, void *sap, IRCOMM_CMD cmd)
+{
struct irvtd_cb *driver = (struct irvtd_cb *)instance;
- __u8 pi; /* instruction of control channel */
ASSERT(driver != NULL, return;);
ASSERT(driver->magic == IRVTD_MAGIC, return;);
- DEBUG(0,"irvtd_control_indication:\n");
+ DEBUG(4,__FUNCTION__"()\n");
+
+ if(cmd == TX_READY){
+ driver->ttp_stoptx = 0;
+ driver->tty->hw_stopped = driver->cts_stoptx;
+ irvtd_start_timer( driver);
+
+ if(driver->cts_stoptx)
+ return;
+
+ /*
+ * 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->timer);
+ return;
+ }
+
- pi = driver->comm->pi;
+ ASSERT(cmd == CONTROL_CHANNEL,return;);
- switch(pi){
+ switch(driver->comm->pi){
case DCELINE_STATE:
driver->msr = driver->comm->peer_dce;
@@ -591,19 +522,23 @@ void irvtd_control_indication(void *instance, void *sap, LOCAL_FLOW flow){
wake_up_interruptible(&driver->delta_msr_wait);
}
- if ((driver->flags & IRVTD_ASYNC_CHECK_CD) && (driver->msr & DELTA_DCD)) {
+ 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 & DELTA_DCD)
+ if (driver->msr & MSR_DCD)
+ {
+ /* DCD raised! */
wake_up_interruptible(&driver->open_wait);
- else if (!((driver->flags & IRVTD_ASYNC_CALLOUT_ACTIVE) &&
- (driver->flags & IRVTD_ASYNC_CALLOUT_NOHUP))) {
-
- DEBUG(0,"irvtd_control_indication:hangup..\n");
+ }
+ else
+ {
+ /* DCD falled */
+ DEBUG(0,__FUNCTION__"():hangup..\n");
tty_hangup(driver->tty);
}
+
}
if (driver->comm->flow_ctrl & USE_CTS) {
@@ -632,50 +567,38 @@ void irvtd_control_indication(void *instance, void *sap, LOCAL_FLOW flow){
driver->cts_stoptx = 1;
driver->tty->hw_stopped = 1;
-/* driver->IER &= ~UART_IER_THRI; */
-/* serial_out(info, UART_IER, info->IER); */
}
}
}
-
-
break;
- case TX_READY:
- driver->ttp_stoptx = 0;
- driver->tty->hw_stopped = driver->cts_stoptx;
-
- /*
- * driver->tty->write_wait will keep asleep if
- * our txbuff is not empty.
- * so if we can really send a packet now,
- * send it and then wake it up.
- */
-
- if(driver->cts_stoptx)
- break;
-
- flush_txbuff(driver);
- if ((driver->tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- driver->tty->ldisc.write_wakeup)
- (driver->tty->ldisc.write_wakeup)(driver->tty);
- break;
-
- case TX_BUSY:
- driver->ttp_stoptx = driver->tty->hw_stopped = 1;
+ case FLOW_CONTROL:
+ case DATA_RATE:
+ case XON_XOFF_CHAR:
+ case DTELINE_STATE:
+ /* (maybe) nothing to do */
break;
default:
- DEBUG(0,"irvtd:unknown control..\n");
-
+ 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
*
- *
* ----------------------------------------------------------------------
*/
@@ -685,114 +608,45 @@ static int irvtd_block_til_ready(struct tty_struct *tty, struct file * filp,
{
struct wait_queue wait = { current, NULL };
- int retval;
+ int retval = 0;
int do_clocal = 0;
/*
- * If the device is in the middle of being closed, then block
- * (sleep) until it's done, and (when being woke up)then try again.
- */
-
- if (tty_hung_up_p(filp) ||
- (driver->flags & IRVTD_ASYNC_CLOSING)) {
- if (driver->flags & IRVTD_ASYNC_CLOSING)
- interruptible_sleep_on(&driver->close_wait);
-#ifdef DO_RESTART
- if (driver->flags & IRVTD_ASYNC_HUP_NOTIFY)
- return -EAGAIN;
- else
- return -ERESTARTSYS;
-#else
- return -EAGAIN;
-#endif
- }
-
- /*
- * If this is a callout device, then just make sure the normal
- * device isn't being used.
- */
-
- if (tty->driver.subtype == IRVTD_TYPE_CALLOUT) {
- if (driver->flags & IRVTD_ASYNC_NORMAL_ACTIVE)
- return -EBUSY;
- if ((driver->flags & IRVTD_ASYNC_CALLOUT_ACTIVE) &&
- (driver->flags & IRVTD_ASYNC_SESSION_LOCKOUT) &&
- (driver->session != current->session))
- return -EBUSY;
- if ((driver->flags & IRVTD_ASYNC_CALLOUT_ACTIVE) &&
- (driver->flags & IRVTD_ASYNC_PGRP_LOCKOUT) &&
- (driver->pgrp != current->pgrp))
- return -EBUSY;
-
- driver->flags |= IRVTD_ASYNC_CALLOUT_ACTIVE;
- return 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))) {
- if (driver->flags & IRVTD_ASYNC_CALLOUT_ACTIVE)
- return -EBUSY;
- driver->flags |= IRVTD_ASYNC_NORMAL_ACTIVE;
return 0;
}
- if (driver->flags & IRVTD_ASYNC_CALLOUT_ACTIVE) {
- if (driver->normal_termios.c_cflag & CLOCAL)
- do_clocal = 1;
- } else {
- if (tty->termios->c_cflag & CLOCAL)
- do_clocal = 1;
- }
-
+ if (tty->termios->c_cflag & CLOCAL)
+ do_clocal = 1;
+
+
/*
* We wait until ircomm_connect_request() succeed or
* ircomm_connect_indication comes
- *
- * This is what is written in serial.c:
- * "Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, driver->count is dropped by one, so that
- * rs_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal."
*/
- retval = 0;
+
add_wait_queue(&driver->open_wait, &wait);
- DEBUG(0,"block_til_ready before block: line%d, count = %d\n",
- driver->line, driver->count);
+ DEBUG(0,__FUNCTION__"():before block( line = %d, count = %d )\n",
+ driver->line, driver->count);
- cli();
- if (!tty_hung_up_p(filp))
- driver->count--;
- sti();
driver->blocked_open++;
-
+ /* wait for a connection established */
while (1) {
current->state = TASK_INTERRUPTIBLE;
-
- if (!(driver->flags & IRVTD_ASYNC_CALLOUT_ACTIVE) &&
- (driver->comm->state == COMM_CONN)){
- /*
- * signal DTR and RTS
- */
- driver->comm->dte = driver->mcr |= (MCR_DTR | MCR_RTS |DELTA_DTR|DELTA_RTS);
-
- ircomm_append_ctrl(driver->comm, DTELINE_STATE);
- ircomm_control_request(driver->comm);
- }
-
+
if (tty_hung_up_p(filp) ||
- !(driver->flags & IRVTD_ASYNC_INITIALIZED)) {
+ !(driver->flags & ASYNC_INITIALIZED)) {
#ifdef DO_RESTART
- if (driver->flags & IRVTD_ASYNC_HUP_NOTIFY)
+ if (driver->flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
retval = -ERESTARTSYS;
@@ -802,15 +656,9 @@ static int irvtd_block_til_ready(struct tty_struct *tty, struct file * filp,
break;
}
- /*
- * if clocal == 0 or received DCD or state become CONN,then break
- */
-
- if (!(driver->flags & IRVTD_ASYNC_CALLOUT_ACTIVE) &&
- !(driver->flags & IRVTD_ASYNC_CLOSING) &&
+ if (!(driver->flags & ASYNC_CLOSING) &&
(driver->comm->state == COMM_CONN) &&
- ( do_clocal || (driver->msr & MSR_DCD) )
- )
+ ( do_clocal || (driver->msr & MSR_DCD)))
break;
if(signal_pending(current)){
@@ -818,63 +666,51 @@ static int irvtd_block_til_ready(struct tty_struct *tty, struct file * filp,
break;
}
-#ifdef IRVTD_DEBUG_OPEN
- printk(KERN_INFO"block_til_ready blocking:"
- " ttys%d, count = %d\n", driver->line, driver->count);
-#endif
+
+ 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);
- if (!tty_hung_up_p(filp))
- driver->count++;
driver->blocked_open--;
-#ifdef IRVTD_DEBUG_OPEN
- printk("block_til_ready after blocking: ttys%d, count = %d\n",
- driver->line, driver->count);
-#endif
+
+ DEBUG(0, __FUNCTION__"():after blocking\n");
+
if (retval)
return retval;
- driver->flags |= IRVTD_ASYNC_NORMAL_ACTIVE;
return 0;
}
-static void change_speed(struct irvtd_cb *driver){
-
+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;
-
-
- /*
- * change baud rate here. but not implemented now
- */
-
-
-
-
/*
* byte size and parity
*/
- switch (cflag & CSIZE) {
- case CS5: cval = 0x00; break;
- case CS6: cval = 0x01; break;
- case CS7: cval = 0x02; break;
- case CS8: cval = 0x03; break;
- default: cval = 0x00; break; /* too keep GCC shut... */
+ 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 |= 0x04;
+ cval |= IRCOMM_STOP2;
}
if (cflag & PARENB)
- cval |= 0x08;
+ cval |= IRCOMM_PARENB; /* enable parity check */
if (!(cflag & PARODD))
- cval |= 0x10;
+ cval |= IRCOMM_PAREVEN; /* even parity */
/* CTS flow control flag and modem status interrupts */
@@ -884,74 +720,68 @@ static void change_speed(struct irvtd_cb *driver){
driver->comm->flow_ctrl |= ~USE_CTS;
if (cflag & CLOCAL)
- driver->flags &= ~IRVTD_ASYNC_CHECK_CD;
+ driver->flags &= ~ASYNC_CHECK_CD;
else
- driver->flags |= IRVTD_ASYNC_CHECK_CD;
+ driver->flags |= ASYNC_CHECK_CD;
/*
* Set up parity check flag
*/
- driver->read_status_mask = LSR_OE ;
+ 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;
- driver->read_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 | \
- LSR_PE | LSR_FE;
- driver->read_status_mask |= LSR_OE | \
- LSR_PE | LSR_FE;
- }
+ if (I_IGNPAR(driver->tty))
+ driver->ignore_status_mask |= LSR_OE;
}
- driver->comm->data_format = cval;
- ircomm_append_ctrl(driver->comm, DATA_FORMAT);
- ircomm_append_ctrl(driver->comm, FLOW_CONTROL);
- ircomm_control_request(driver->comm);
- /* output to IrCOMM here*/
+ 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){
-
+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,4,1,1,1 };
- DEBUG(4,"irvtd_startup:\n" );
+ DEBUG(4,__FUNCTION__"()\n" );
+ if(driver->flags & ASYNC_INITIALIZED)
+ return 0;
/*
* initialize our tx/rx buffer
*/
- if(driver->flags & IRVTD_ASYNC_INITIALIZED)
- return(0);
-
skb_queue_head_init(&driver->rxbuff);
- driver->rx_tqueue.data = driver;
- driver->rx_tqueue.routine = irvtd_write_to_tty;
-
- if(!driver->txbuff){
- driver->txbuff = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE);
- if (!driver->txbuff){
- DEBUG(0,"irvtd_open():alloc_skb failed!\n");
- return -ENOMEM;
- }
-
- skb_reserve(driver->txbuff, COMM_HEADER_SIZE);
+ driver->txbuff = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE);
+ if (!driver->txbuff){
+ DEBUG(0,__FUNCTION__"():alloc_skb failed!\n");
+ return -ENOMEM;
}
+ skb_reserve(driver->txbuff, COMM_HEADER_SIZE);
irda_notify_init(&irvtd_notify);
irvtd_notify.data_indication = irvtd_receive_data;
@@ -959,18 +789,33 @@ static int irvtd_startup(struct irvtd_cb *driver){
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;
- strncpy( irvtd_notify.name, "irvtd", NOTIFY_MAX_NAME);
+
+ 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;
/*
- * register ourself as a service user of IrCOMM
- * TODO: other servicetype(i.e. 3wire,3wireraw)
+ * discover a peer device
+ * TODO: other servicetype(i.e. 3wire,3wireraw) support
*/
-
- driver->comm = ircomm_attach_cable(NINE_WIRE, irvtd_notify,
- irvtd_attached);
- if(driver->comm == NULL)
- return -ENODEV;
+ ircomm_connect_request(driver->comm, NINE_WIRE);
/*
* TODO:we have to initialize control-channel here!
@@ -981,63 +826,83 @@ static int irvtd_startup(struct irvtd_cb *driver){
clear_bit(TTY_IO_ERROR, &driver->tty->flags);
change_speed(driver);
+ irvtd_start_timer( driver);
- driver->flags |= IRVTD_ASYNC_INITIALIZED;
+ driver->rx_disable = 0;
+ driver->tx_disable = 1;
+ driver->disconnect_pend = 0;
return 0;
}
-int irvtd_open(struct tty_struct * tty, struct file * filp){
-
+int irvtd_open(struct tty_struct * tty, struct file * filp)
+{
struct irvtd_cb *driver;
int retval;
int line;
- DEBUG(4, "irvtd_open():\n");
+ DEBUG(4, __FUNCTION__"():\n");
+ MOD_INC_USE_COUNT;
line = MINOR(tty->device) - tty->driver.minor_start;
- if ((line <0) || (line >= COMM_MAX_TTY))
+ if ((line <0) || (line >= COMM_MAX_TTY)){
+ MOD_DEC_USE_COUNT;
return -ENODEV;
+ }
+
driver = irvtd[line];
- driver->line = 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, "irvtd_open : %s%d count %d\n", tty->driver.name, line,
+ 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)
+ if (retval){
+ DEBUG(0, __FUNCTION__"():irvtd_startup returns %d\n",retval);
return retval;
- MOD_INC_USE_COUNT;
+ }
retval = irvtd_block_til_ready(tty, filp, driver);
if (retval){
- DEBUG(0,"irvtd_open returning after block_til_ready with %d\n",
- retval);
+ DEBUG(0,__FUNCTION__
+ "():returning after block_til_ready (errno = %d)\n", retval);
return retval;
}
- if ((driver->count == 1) && driver->flags & IRVTD_ASYNC_SPLIT_TERMIOS){
- if(tty->driver.subtype == IRVTD_TYPE_NORMAL)
- *tty->termios = driver->normal_termios;
- else
- *tty->termios = driver->callout_termios;
-
- change_speed(driver);
- }
-
driver->session = current->session;
driver->pgrp = current->pgrp;
- driver->rx_disable = 0;
- return (0);
+ return 0;
}
@@ -1052,15 +917,55 @@ int irvtd_open(struct tty_struct * tty, struct file * filp){
* ----------------------------------------------------------------------
*/
+/*
+ * 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 & IRVTD_ASYNC_INITIALIZED))
+ if (!(driver->flags & ASYNC_INITIALIZED))
return;
- DEBUG(4,"irvtd_shutdown:\n");
+ DEBUG(1,__FUNCTION__"()\n");
/*
* This comment is written in serial.c:
@@ -1075,8 +980,8 @@ static void irvtd_shutdown(struct irvtd_cb * driver)
driver->mcr &= ~(MCR_DTR|MCR_RTS);
driver->comm->dte = driver->mcr;
- ircomm_append_ctrl(driver->comm, DTELINE_STATE );
- ircomm_control_request(driver->comm);
+ ircomm_control_request(driver->comm, DTELINE_STATE );
+
save_flags(flags); cli(); /* Disable interrupts */
@@ -1084,42 +989,49 @@ static void irvtd_shutdown(struct irvtd_cb * driver)
if (driver->tty)
set_bit(TTY_IO_ERROR, &driver->tty->flags);
- ircomm_detach_cable(driver->comm);
+ del_timer( &driver->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); /* is it OK?*/
+ dev_kfree_skb(driver->txbuff);
driver->txbuff = NULL;
}
-
- driver->flags &= ~IRVTD_ASYNC_INITIALIZED;
+ 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){
-
+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(0, "irvtd_close:refc(%d)\n",ircomm_vsd_refcount);
+ DEBUG(1, __FUNCTION__"():refcount= %d\n",irvtd_refcount);
ASSERT(driver != NULL, return;);
ASSERT(driver->magic == IRVTD_MAGIC, return;);
save_flags(flags);cli();
- /*
- * tty_hung_up_p() is defined as
- * " return(filp->f_op == &hung_up_tty_fops); "
- * see driver/char/tty_io.c
- */
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;
@@ -1127,7 +1039,7 @@ void irvtd_close(struct tty_struct * tty, struct file * filp){
line = MINOR(tty->device) - tty->driver.minor_start;
- DEBUG(0, "irvtd_close : %s%d count %d\n", tty->driver.name, line,
+ DEBUG(0, __FUNCTION__"():%s%d count %d\n", tty->driver.name, line,
driver->count);
if ((tty->count == 1) && (driver->count != 1)) {
@@ -1143,313 +1055,218 @@ void irvtd_close(struct tty_struct * tty, struct file * filp){
driver->count = 1;
}
if (--driver->count < 0) {
- printk("irvtd_close: bad count for line%d: %d\n",
+ 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 |= IRVTD_ASYNC_CLOSING;
-
- /*
- * Save the termios structure, since this port may have
- * separate termios for callout and dialin.
- */
-
- if (driver->flags & IRVTD_ASYNC_NORMAL_ACTIVE)
- driver->normal_termios = *tty->termios;
- if (driver->flags & IRVTD_ASYNC_CALLOUT_ACTIVE)
- driver->callout_termios = *tty->termios;
+ 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 != IRVTD_ASYNC_CLOSING_WAIT_NONE)
+ 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;
-
- /*
- * Now we flush our buffer.., and shutdown ircomm service layer
- */
-
- /* drop our tx/rx buffer */
- if (tty->driver.flush_buffer)
- tty->driver.flush_buffer(tty);
-
- while(skb_queue_len(&driver->rxbuff)){
- struct sk_buff *skb;
- skb = skb_dequeue( &driver->rxbuff);
- dev_kfree_skb(skb);
- }
-
- /* drop users buffer? */
+ /* 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;
- /*
- * ad-hoc coding:
- * we wait 2 sec before ircomm_detach_cable so that
- * irttp will send all contents of its queue
- */
-
-#if 0
- if (driver->blocked_open) {
+ if (driver->blocked_open)
+ {
if (driver->close_delay) {
-#endif
-
/* kill time */
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(driver->close_delay + 2*HZ);
-#if 0
+ schedule_timeout(driver->close_delay);
}
wake_up_interruptible(&driver->open_wait);
}
-#endif
-
- driver->flags &= ~(IRVTD_ASYNC_NORMAL_ACTIVE|
- IRVTD_ASYNC_CALLOUT_ACTIVE|
- IRVTD_ASYNC_CLOSING);
+ irvtd_shutdown(driver);
+ driver->flags &= ~ASYNC_CLOSING;
wake_up_interruptible(&driver->close_wait);
- irvtd_shutdown(driver);
MOD_DEC_USE_COUNT;
restore_flags(flags);
- DEBUG(4,"irvtd_close:done:refc(%d)\n",ircomm_vsd_refcount);
+ DEBUG(4, __FUNCTION__"():done\n");
}
-
-
/*
* ----------------------------------------------------------------------
* irvtd_write() and friends
* This routine will be called when something data are passed from
* kernel or user.
- *
- * NOTE:I have stolen copy_from_user() from 2.0.30 kernel(linux/isdnif.h)
- * to access user space of memory carefully. Thanks a lot!:)
* ----------------------------------------------------------------------
*/
int irvtd_write(struct tty_struct * tty, int from_user,
- const unsigned char *buf, int count){
-
- struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
+ const unsigned char *buf, int count)
+{
+ struct irvtd_cb *driver;
int c = 0;
int wrote = 0;
- struct sk_buff *skb = NULL;
+ unsigned long flags;
+ struct sk_buff *skb;
__u8 *frame;
- DEBUG(4, "irvtd_write():\n");
+ ASSERT(tty != NULL, return -EFAULT;);
+ driver = (struct irvtd_cb *)tty->driver_data;
+ ASSERT(driver != NULL, return -EFAULT;);
+ ASSERT(driver->magic == IRVTD_MAGIC, return -EFAULT;);
- if (!tty || !driver->txbuff)
- return 0;
+ DEBUG(4, __FUNCTION__"()\n");
-
-
+ save_flags(flags);
while(1){
+ cli();
skb = driver->txbuff;
-
- c = MIN(count, (skb_tailroom(skb) - COMM_HEADER_SIZE));
- if (c <= 0)
+ ASSERT(skb != NULL, break;);
+ c = MIN(count, (skb_tailroom(skb)));
+ if (c <= 0)
break;
/* write to the frame */
-
frame = skb_put(skb,c);
if(from_user){
copy_from_user(frame,buf,c);
} else
memcpy(frame, buf, c);
- /* flush the frame */
- irvtd_flush_chars(tty);
+ restore_flags(flags);
wrote += c;
count -= c;
+ buf += c;
+ irvtd_send_data_request(driver);
}
+ restore_flags(flags);
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);
+}
+
+
/*
- * ----------------------------------------------------------------------
- * irvtd_put_char()
- * This routine is called by the kernel to pass a single character.
- * If we exausted our buffer,we can ignore the character!
- * ----------------------------------------------------------------------
+ * 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){
-
+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 = driver->txbuff;
+ struct sk_buff *skb;
+ unsigned long flags;
- ASSERT(tty->driver_data != NULL, return;);
+ ASSERT(driver != NULL, return;);
+ DEBUG(4, __FUNCTION__"()\n");
- DEBUG(4, "irvtd_put_char:\n");
- if(!driver->txbuff)
- return;
+ save_flags(flags);cli();
+ skb = driver->txbuff;
+ ASSERT(skb != NULL,return;);
+ ASSERT(skb_tailroom(skb) > 0, return;);
DEBUG(4, "irvtd_put_char(0x%02x) skb_len(%d) MAX(%d):\n",
(int)ch ,(int)skb->len,
- driver->comm->maxsdusize - COMM_HEADER_SIZE);
+ driver->comm->max_txbuff_size - COMM_HEADER_SIZE);
/* append a character */
-
frame = skb_put(skb,1);
frame[0] = ch;
- return;
-}
-
-/*
- * ----------------------------------------------------------------------
- * irvtd_flush_chars() and friend
- * This routine will be called after a series of characters was written using
- * irvtd_put_char().We have to send them down to IrCOMM.
- * ----------------------------------------------------------------------
- */
-
-static void flush_txbuff(struct irvtd_cb *driver){
-
- struct sk_buff *skb = driver->txbuff;
- struct tty_struct *tty = driver->tty;
- ASSERT(tty != NULL, return;);
-
-#ifdef IRVTD_DEBUG_TX
- printk("flush_txbuff:");
- {
- int i;
- for ( i=0;i<skb->len;i++)
- printk("%02x", skb->data[i]);
- printk("\n");
- }
-#else
- DEBUG(4, "flush_txbuff:count(%d)\n",(int)skb->len);
-#endif
-
- /* add "clen" field */
- skb_push(skb,1);
- skb->data[0]=0; /* without control channel */
-
- ircomm_data_request(driver->comm, driver->txbuff);
-
- /* allocate new frame */
- skb = driver->txbuff = dev_alloc_skb(driver->comm->max_txbuff_size);
- if (skb == NULL){
- printk(KERN_ERR"flush_txbuff():alloc_skb failed!\n");
- } else {
- skb_reserve(skb, COMM_HEADER_SIZE);
- }
- wake_up_interruptible(&driver->tty->write_wait);
-}
-
-void irvtd_flush_chars(struct tty_struct *tty){
-
- struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
- if(!driver || driver->magic != IRVTD_MAGIC || !driver->txbuff){
- DEBUG(0,"irvtd_flush_chars:null structure:ignore\n");
- return;
- }
- DEBUG(4, "irvtd_flush_chars():\n");
-
- while(tty->hw_stopped){
- DEBUG(4,"irvtd_flush_chars:hw_stopped:sleep..\n");
- tty_wait_until_sent(tty,0);
- DEBUG(4,"irvtd_flush_chars:waken up!\n");
- if(!driver->txbuff->len)
- return;
- }
- flush_txbuff(driver);
+ restore_flags(flags);
+ return;
}
-
-
-
/*
- * ----------------------------------------------------------------------
- * irvtd_write_room()
- * This routine returns the room that our buffer has now.
+ * Function irvtd_write_room (tty)
+ *
+ * This routine returns the room that our buffer has now.
*
- * NOTE:
- * driver/char/n_tty.c drops a character(s) when this routine returns 0,
- * and then linux will be frozen after a few minutes :( why? bug?
- * ( I found this on linux-2.0.33 )
- * So this routine flushes a buffer if there is few room, TH
- * ----------------------------------------------------------------------
*/
-
int irvtd_write_room(struct tty_struct *tty){
int ret;
- struct sk_buff *skb = (struct sk_buff *)((struct irvtd_cb *) tty->driver_data)->txbuff;
-
- if(!skb){
- DEBUG(0,"irvtd_write_room:NULL skb\n");
- return(0);
- }
+ struct sk_buff *skb = ((struct irvtd_cb *) tty->driver_data)->txbuff;
- ret = skb_tailroom(skb) - COMM_HEADER_SIZE;
-
- if(ret < 0){
- DEBUG(0,"irvtd_write_room:error:room is %d!",ret);
- ret = 0;
- }
- DEBUG(4, "irvtd_write_room:\n");
- DEBUG(4, "retval(%d)\n",ret);
+ ASSERT(skb !=NULL, return 0;);
+ ret = skb_tailroom(skb);
- /* flush buffer automatically to avoid kernel freeze :< */
- if(ret < 8) /* why 8? there's no reason :) */
- irvtd_flush_chars(tty);
+ DEBUG(4, __FUNCTION__"(): room is %d bytes\n",ret);
return(ret);
}
/*
- * ----------------------------------------------------------------------
- * irvtd_chars_in_buffer()
- * This function returns how many characters which have not been sent yet
- * are still in buffer.
- * ----------------------------------------------------------------------
+ * 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 =
- (struct sk_buff *) ((struct irvtd_cb *)tty->driver_data) ->txbuff;
- DEBUG(4, "irvtd_chars_in_buffer()\n");
+ struct sk_buff *skb;
+ unsigned long flags;
- if(!skb){
- printk(KERN_ERR"irvtd_chars_in_buffer:NULL skb\n");
- return(0);
- }
+ 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 */
}
/*
- * ----------------------------------------------------------------------
- * irvtd_break()
- * routine which turns the break handling on or off
- * ----------------------------------------------------------------------
+ * 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;
@@ -1463,14 +1280,14 @@ static void irvtd_break(struct tty_struct *tty, int break_state){
if (break_state == -1)
{
driver->comm->break_signal = 0x01;
- ircomm_append_ctrl(driver->comm, BREAK_SIGNAL);
- ircomm_control_request(driver->comm);
+ ircomm_control_request(driver->comm, BREAK_SIGNAL);
+
}
else
{
driver->comm->break_signal = 0x00;
- ircomm_append_ctrl(driver->comm, BREAK_SIGNAL);
- ircomm_control_request(driver->comm);
+ ircomm_control_request(driver->comm, BREAK_SIGNAL);
+
}
restore_flags(flags);
@@ -1497,8 +1314,7 @@ static int get_modem_info(struct irvtd_cb * driver, unsigned int *value)
| ((driver->msr & DELTA_RI) ? TIOCM_RNG : 0)
| ((driver->msr & DELTA_DSR) ? TIOCM_DSR : 0)
| ((driver->msr & DELTA_CTS) ? TIOCM_CTS : 0);
- put_user(result,value);
- return 0;
+ return put_user(result,value);
}
static int set_modem_info(struct irvtd_cb * driver, unsigned int cmd,
@@ -1537,19 +1353,111 @@ static int set_modem_info(struct irvtd_cb * driver, unsigned int cmd,
}
driver->comm->dte = driver->mcr;
- ircomm_append_ctrl(driver->comm, DTELINE_STATE );
- ircomm_control_request(driver->comm);
+ ircomm_control_request(driver->comm, DTELINE_STATE );
+
return 0;
}
-int irvtd_ioctl(struct tty_struct *tty, struct file * file,
- unsigned int cmd, unsigned long arg){
+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 icounter_struct cnow;
- struct icounter_struct *p_cuser; /* user space */
+ struct serial_icounter_struct cnow,cprev;
+ struct serial_icounter_struct *p_cuser; /* user space */
DEBUG(4,"irvtd_ioctl:requested ioctl(0x%08x)\n",cmd);
@@ -1557,7 +1465,6 @@ int irvtd_ioctl(struct tty_struct *tty, struct file * file,
#ifdef IRVTD_DEBUG_IOCTL
{
/* kill time so that debug messages will come slowly */
- unsigned long flags;
save_flags(flags);cli();
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + HZ/4; /*0.25sec*/
@@ -1572,7 +1479,6 @@ int irvtd_ioctl(struct tty_struct *tty, struct file * file,
(cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
(cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
if (tty->flags & (1 << TTY_IO_ERROR)){
- DEBUG(0,"irvtd_ioctl:I/O error...\n");
return -EIO;
}
}
@@ -1580,143 +1486,89 @@ int irvtd_ioctl(struct tty_struct *tty, struct file * file,
switch (cmd) {
case TIOCMGET:
- error = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(unsigned int));
- if (error)
- return error;
return get_modem_info(driver, (unsigned int *) arg);
case TIOCMBIS:
case TIOCMBIC:
case TIOCMSET:
return set_modem_info(driver, cmd, (unsigned int *) arg);
-#if 0
- /*
- * we wouldn't implement them since we don't use serial_struct
- */
case TIOCGSERIAL:
- error = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(struct serial_struct));
- if (error)
- return error;
- return irvtd_get_serial_info(driver,
- (struct serial_struct *) arg);
+ return get_serial_info(driver, (struct serial_struct *) arg);
case TIOCSSERIAL:
- error = verify_area(VERIFY_READ, (void *) arg,
- sizeof(struct serial_struct));
- if (error)
- return error;
- return irvtd_set_serial_info(driver,
- (struct serial_struct *) arg);
-
-
- case TIOCSERGETLSR: /* Get line status register */
- error = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(unsigned int));
- if (error)
- return error;
- else
- return get_lsr_info(driver, (unsigned int *) arg);
-#endif
+ return set_serial_info(driver, (struct serial_struct *) arg);
-/*
- * I think we don't need them
- */
-/* case TIOCSERCONFIG: */
-
-
-/*
- * They cannot be implemented because we don't use async_struct
- * which is defined in serial.h
- */
-
-/* case TIOCSERGSTRUCT: */
-/* error = verify_area(VERIFY_WRITE, (void *) arg, */
-/* sizeof(struct async_struct)); */
-/* if (error) */
-/* return error; */
-/* memcpy_tofs((struct async_struct *) arg, */
-/* driver, sizeof(struct async_struct)); */
-/* return 0; */
-
-/* case TIOCSERGETMULTI: */
-/* error = verify_area(VERIFY_WRITE, (void *) arg, */
-/* sizeof(struct serial_multiport_struct)); */
-/* if (error) */
-/* return error; */
-/* return get_multiport_struct(driver, */
-/* (struct serial_multiport_struct *) arg); */
-/* case TIOCSERSETMULTI: */
-/* error = verify_area(VERIFY_READ, (void *) arg, */
-/* sizeof(struct serial_multiport_struct)); */
-/* if (error) */
-/* return error; */
-/* return set_multiport_struct(driver, */
-/* (struct serial_multiport_struct *) arg); */
- /*
- * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)
- * to change
- * - mask passed in arg for lines of interest
- * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
- * Caller should use TIOCGICOUNT to see which one it was
- */
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 (current->signal & ~current->blocked) */
-/* return -ERESTARTSYS; */
-
- if ( ((arg & TIOCM_RNG) && (driver->msr & DELTA_RI)) ||
- ((arg & TIOCM_DSR) && (driver->msr & DELTA_DSR)) ||
- ((arg & TIOCM_CD) && (driver->msr & DELTA_DCD)) ||
- ((arg & TIOCM_CTS) && (driver->msr & DELTA_CTS))) {
+ /* 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:
- /*
- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
- * Return: write counters to the user passed counter struct
- * NB: both 1->0 and 0->1 transitions are counted except for
- * RI where only 0->1 is counted.
- */
- error = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(struct icounter_struct));
- if (error)
- return error;
- cli();
+ save_flags(flags); cli();
cnow = driver->icount;
- sti();
- p_cuser = (struct icounter_struct *) arg;
- put_user(cnow.cts, &p_cuser->cts);
- put_user(cnow.dsr, &p_cuser->dsr);
- put_user(cnow.rng, &p_cuser->rng);
- put_user(cnow.dcd, &p_cuser->dcd);
+ 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 TIOCGSERIAL:
- case TIOCSSERIAL:
+ 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:
- case TIOCSERGWILD:
- case TIOCSERSWILD:
- case TIOCSERGSTRUCT:
- case TIOCSERGETMULTI:
- case TIOCSERSETMULTI:
- DEBUG(0,"irvtd_ioctl:sorry, ioctl(0x%08x)is not implemented\n",cmd);
- return -ENOIOCTLCMD; /* ioctls which are imcompatible with serial.c */
-
- case TCSETS:
- case TCGETS:
- case TCFLSH:
+ DEBUG(0,__FUNCTION__"():sorry, TIOCSERCONFIG is not supported\n");
+ return -ENOIOCTLCMD;
+
+
default:
- return -ENOIOCTLCMD; /* ioctls which we must not touch */
+ return -ENOIOCTLCMD; /* ioctls which we must ignore */
}
return 0;
}
@@ -1766,14 +1618,14 @@ void irvtd_set_termios(struct tty_struct *tty, struct termios * old_termios){
static void irvtd_send_xchar(struct tty_struct *tty, char ch){
- DEBUG(0, __FUNCTION__"():\n");
+ 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(0, "irvtd_throttle:\n");
+ DEBUG(1, "irvtd_throttle:\n");
if (I_IXOFF(tty))
irvtd_put_char(tty, STOP_CHAR(tty));
@@ -1781,22 +1633,22 @@ void irvtd_throttle(struct tty_struct *tty){
driver->mcr &= ~MCR_RTS;
driver->mcr |= DELTA_RTS;
driver->comm->dte = driver->mcr;
- ircomm_append_ctrl(driver->comm, DTELINE_STATE );
- ircomm_control_request(driver->comm);
+ ircomm_control_request(driver->comm, DTELINE_STATE );
+
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(0, "irvtd_unthrottle:\n");
+ 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_append_ctrl(driver->comm, DTELINE_STATE );
- ircomm_control_request(driver->comm);
+ ircomm_control_request(driver->comm, DTELINE_STATE );
+
irttp_flow_request(driver->comm->tsap, FLOW_START);
}
@@ -1829,19 +1681,17 @@ irvtd_start(struct tty_struct *tty){
* ------------------------------------------------------------
* irvtd_hangup()
* This routine notifies that tty layer have got HUP signal
- * Is this routine right ? :{|
* ------------------------------------------------------------
*/
void irvtd_hangup(struct tty_struct *tty){
struct irvtd_cb *info = (struct irvtd_cb *)tty->driver_data;
- DEBUG(0, "irvtd_hangup()\n");
+ DEBUG(0, __FUNCTION__"()\n");
irvtd_flush_buffer(tty);
irvtd_shutdown(info);
info->count = 0;
- info->flags &= ~(IRVTD_ASYNC_NORMAL_ACTIVE|IRVTD_ASYNC_CALLOUT_ACTIVE);
info->tty = NULL;
wake_up_interruptible(&info->open_wait);
}
@@ -1851,15 +1701,18 @@ void irvtd_flush_buffer(struct tty_struct *tty){
struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
struct sk_buff *skb;
- skb = (struct sk_buff *)driver->txbuff;
+ skb = driver->txbuff;
+ ASSERT(skb != NULL, return;);
- DEBUG(4, "irvtd_flush_buffer:%d chars are gone..\n",(int)skb->len);
- skb_trim(skb,0);
+ 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);
+ wake_up_interruptible(&tty->write_wait);
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
@@ -1867,3 +1720,275 @@ void irvtd_flush_buffer(struct tty_struct *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");
+
+ 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 ;
+ }
+
+ /*
+ * 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 */