patch-2.2.6 linux/net/irda/ircomm/ircomm_common.c
Next file: linux/net/irda/ircomm/irvtd.c
Previous file: linux/net/irda/ircomm/attach.c
Back to the patch index
Back to the overall index
- Lines: 1837
- Date:
Thu Apr 15 05:42:42 1999
- Orig file:
v2.2.5/linux/net/irda/ircomm/ircomm_common.c
- Orig date:
Wed Mar 10 15:29:52 1999
diff -u --recursive --new-file v2.2.5/linux/net/irda/ircomm/ircomm_common.c linux/net/irda/ircomm/ircomm_common.c
@@ -33,23 +33,19 @@
#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 = "Tue Mar 2 02:03:58 1999";
-static void ircomm_state_discovery( struct ircomm_cb *self,
- IRCOMM_EVENT event, struct sk_buff *skb );
+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_waiti( struct ircomm_cb *self, IRCOMM_EVENT event,
@@ -60,12 +56,35 @@
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 query_lsapsel(struct ircomm_cb * self);
+static void ircomm_getvalue_confirm( __u16 obj_id, struct ias_value *value,
+ void *priv);
+
+
+static __u32 ckey;
+static __u32 skey;
+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",
@@ -109,9 +128,6 @@
"IRCOMM_CONTROL_REQUEST",
};
-int ircomm_proc_read(char *buf, char **start, off_t offset,
- int len, int unused);
-
#ifdef CONFIG_PROC_FS
extern struct proc_dir_entry proc_irda;
struct proc_dir_entry proc_ircomm = {
@@ -132,13 +148,13 @@
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 +162,7 @@
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 +174,7 @@
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;
}
@@ -194,14 +210,17 @@
proc_register( &proc_irda, &proc_ircomm);
#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
*/
@@ -227,8 +246,9 @@
#ifdef CONFIG_PROC_FS
proc_unregister( &proc_irda, proc_ircomm.low_ino);
-#endif
+#endif /* CONFIG_PROC_FS */
}
+#endif /* MODULE */
/*
* ----------------------------------------------------------------------
@@ -236,23 +256,26 @@
* ----------------------------------------------------------------------
*/
-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;
@@ -262,7 +285,7 @@
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;
@@ -277,9 +300,9 @@
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,
+ __u32 maxsdusize,
struct sk_buff *skb )
{
struct ircomm_cb *self = (struct ircomm_cb *)instance;
@@ -289,7 +312,7 @@
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;
@@ -298,9 +321,14 @@
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,
+static void ircomm_accept_disconnect_indication(void *instance, void *sap,
LM_REASON reason,
struct sk_buff *skb)
{
@@ -308,15 +336,16 @@
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;);
@@ -324,34 +353,32 @@
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");
}
}
/*
* ----------------------------------------------------------------------
- * Implementation of actions,descrived in section 7.4 of the reference.
+ * Impl. of actions (descrived in section 7.4 of the reference)
* ----------------------------------------------------------------------
*/
@@ -360,33 +387,25 @@
{
/* 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->saddr, self->daddr,
- NULL, self->maxsdusize, NULL);
- break;
-
case THREE_WIRE:
case NINE_WIRE:
case CENTRONICS:
irttp_connect_request(self->tsap, self->dlsap,
self->saddr, self->daddr,
- NULL, self->maxsdusize, NULL);
+ 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);
}
}
@@ -401,7 +420,7 @@
if(self->notify.disconnect_indication)
self->notify.disconnect_indication( self->notify.instance,
self,
- self->reason,skb);
+ self->reason, skb);
}
@@ -429,6 +448,7 @@
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 )
@@ -440,11 +460,10 @@
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);
@@ -455,10 +474,11 @@
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,
@@ -468,52 +488,74 @@
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");
+ 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 )
{
- 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;
}
@@ -528,15 +570,15 @@
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);
}
@@ -549,8 +591,7 @@
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");
+ printk(KERN_ERR __FUNCTION__"():why call me? something is wrong..\n");
if(skb)
dev_kfree_skb( skb);
}
@@ -578,15 +619,13 @@
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]);
}
}
@@ -616,7 +655,7 @@
/* 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]);
}
}
@@ -636,8 +675,7 @@
/* 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);
*/
@@ -677,19 +715,15 @@
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);
@@ -712,16 +746,189 @@
/*
* ----------------------------------------------------------------------
- * ircomm requests
+ * IrCOMM service interfaces and supporting functions
*
* ----------------------------------------------------------------------
*/
-
-void ircomm_connect_request(struct ircomm_cb *self, int maxsdusize)
+int ircomm_query_ias_and_connect(struct ircomm_cb *self, __u8 servicetype)
{
+ int retval=0;
+ __u16 hints;
+
+ ASSERT( self != NULL, return -EFAULT;);
+ ASSERT( self->magic == IRCOMM_MAGIC, return -EFAULT;);
+ DEBUG(4,__FUNCTION__"():servicetype = %d\n",servicetype);
/*
+ * wait if another instance is discovering now
+ */
+ if(discovering_instance){
+ interruptible_sleep_on( &self->discovery_wait);
+ if(signal_pending(current)){
+ return -EINTR; /* cought a signal */
+ }
+ if(self->state == COMM_CONN)
+ return 0; /* got connected */
+ }
+ ASSERT(discovering_instance == NULL, return -EFAULT;);
+ discovering_instance = self;
+
+ /*
+ * start discovering
+ */
+ hints = irlmp_service_to_hint(S_COMM);
+
+ DEBUG(0,__FUNCTION__"():start discovering..\n");
+ switch (ircomm_cs) {
+ case 0:
+ skey = irlmp_register_service(hints);
+ ckey = irlmp_register_client(hints, ircomm_discovery_indication,
+ NULL);
+ break;
+
+ case 1: /* client only */
+ DEBUG( 0, __FUNCTION__"():client only mode\n");
+ ckey = irlmp_register_client(hints, ircomm_discovery_indication,
+ NULL);
+ break;
+
+ case 2: /* server only */
+ default:
+ DEBUG( 0, __FUNCTION__"():server only mode\n");
+ skey = irlmp_register_service(hints);
+ discovering_instance = NULL;
+ return 0;
+ }
+
+
+ /*
+ * waiting for discovery
+ */
+ interruptible_sleep_on( &self->discovery_wait);
+ if(signal_pending(current)){
+ retval = -EINTR; goto bailout; /* cought a signal */
+ }
+ if(self->state == COMM_CONN)
+ goto bailout; /* got connected */
+
+ /*
+ * query Parameters field of IAS and waiting for answer
+ */
+
+ self->servicetype = 0;
+ DEBUG(0, __FUNCTION__"():querying IAS: Parameters..\n");
+ iriap_getvaluebyclass_request( "IrDA:IrCOMM", "Parameters",
+ self->saddr, self->daddr,
+ ircomm_getvalue_confirm, self );
+
+ interruptible_sleep_on( &self->ias_wait);
+ if(signal_pending(current)){
+ retval = -EINTR; goto bailout; /* cought a signal */
+ }
+ if(self->state == COMM_CONN)
+ goto bailout; /* got connected */
+
+
+ /* really got Parameters field? */
+ if(self->ias_type != IAS_OCT_SEQ){
+ retval = -EFAULT;
+ goto bailout;
+ }
+
+ /*
+ * check if servicetype we want is available
+ */
+ self->peer_cap = self->servicetype;
+
+ DEBUG(0,__FUNCTION__"():peer capability is:\n");
+ DEBUG(0,"3wire raw: %s\n",((self->servicetype & THREE_WIRE_RAW) ? "yes":"no"));
+ DEBUG(0,"3wire : %s\n",((self->servicetype & THREE_WIRE) ? "yes":"no"));
+ DEBUG(0,"9wire : %s\n",((self->servicetype & NINE_WIRE) ? "yes":"no"));
+ DEBUG(0,"IEEE1284 : %s\n",((self->servicetype & CENTRONICS) ? "yes":"no"));
+
+ self->servicetype &= servicetype;
+ if(!(self->servicetype)){
+ retval = -ENODEV;
+ goto bailout;
+ }
+
+ /*
+ * 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;
+#if 1
+ /*
+ * waiting for discovery again
+ */
+ interruptible_sleep_on( &self->discovery_wait);
+ if(signal_pending(current)){
+ retval = -EINTR; goto bailout; /* cought a signal */
+ }
+ if(self->state == COMM_CONN)
+ goto bailout; /* got connected */
+#endif
+ /*
+ * query lsapsel field and waiting for answer
+ */
+ query_lsapsel(self);
+ interruptible_sleep_on( &self->ias_wait);
+ if(signal_pending(current)){
+ retval = -EINTR; goto bailout; /* cought a signal */
+ }
+ if(self->state == COMM_CONN)
+ goto bailout; /* got connected */
+
+ /* really got Lsapsel field? */
+ if(self->ias_type != IAS_INTEGER){
+ retval = -EFAULT;
+ goto bailout;
+ }
+#if 1
+ /*
+ * waiting for discovery again...
+ */
+ interruptible_sleep_on( &self->discovery_wait);
+ if(signal_pending(current)){
+ retval = -EINTR; goto bailout; /* cought a signal */
+ }
+ if(self->state == COMM_CONN)
+ goto bailout; /* got connected */
+#endif
+
+ /* succeed! ready to connect */
+ discovering_instance = NULL;
+ ircomm_connect_request(self);
+ return 0;
+
+ bailout:
+ /* failed. not ready to connect */
+ discovering_instance = NULL;
+ irlmp_unregister_service(skey);
+ irlmp_unregister_client(ckey);
+ return retval;
+}
+
+/*
+ * 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)
+{
+ /*
* TODO:build a packet which contains "initial control parameters"
* and send it with connect_request
*/
@@ -729,14 +936,17 @@
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");
+
+ 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;);
@@ -753,11 +963,8 @@
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);
}
@@ -771,33 +978,70 @@
}
void ircomm_disconnect_request(struct ircomm_cb *self,
- struct sk_buff *userdata)
+ struct sk_buff *userdata,
+ int priority)
{
ASSERT( self != NULL, return;);
ASSERT( self->magic == IRCOMM_MAGIC, return;);
+ DEBUG(0,__FUNCTION__"()\n");
+
+ /* 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;
+ }
- DEBUG(0,"ircomm_disconnect_request\n");
- ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, NULL);
+ self->disconnect_priority = priority;
+ if(priority != P_HIGH)
+ self->disconnect_priority = P_NORMAL;
+
+ 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;
}
/*
@@ -807,20 +1051,25 @@
* ----------------------------------------------------------------------
*/
-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:");
@@ -831,148 +1080,106 @@
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)
{
-
__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){
@@ -1003,8 +1210,42 @@
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;
@@ -1020,12 +1261,6 @@
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);
@@ -1034,203 +1269,422 @@
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->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;
+
+ case PORT_NAME:
+ ASSERT(plen <= 32 , goto corrupted;);
+ memcpy(self->port_name, data + 2, plen);
+ *(__u8 *)(self->port_name+plen) = 0;
break;
- /*
- * for centronics .... not implemented yet
+ 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);
+ }
+
+ 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
+ * ----------------------------------------------------------------------
+ */
+
+
+
+/*
+ * ircomm_getvalue_confirm()
+ * handler for iriap_getvaluebyclass_request()
+ */
+
+static void ircomm_getvalue_confirm( __u16 obj_id, struct ias_value *value,
+ void *priv)
+{
+ struct ircomm_cb *self = (struct ircomm_cb *) priv;
+ struct sk_buff *skb= NULL;
+ __u8 *frame;
+ ASSERT( self != NULL, return;);
+ ASSERT( self->magic == IRCOMM_MAGIC, return;);
+
+ /* Check if request succeeded */
+ if ( !value) {
+ DEBUG( 0, __FUNCTION__ "(), got NULL value!\n");
+ 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, 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);
+
+ wake_up_interruptible( &self->ias_wait);
+ 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");
+ return;
+ }
+
+ if(self->state == COMM_IDLE){
+ self->dlsap = value->t.integer;
+
+ wake_up_interruptible( &self->ias_wait);
+ }
+ break;
+
+ case IAS_MISSING:
+ DEBUG( 0, __FUNCTION__":got IAS_MISSING\n");
+ break;
+
+ default:
+ DEBUG( 0, __FUNCTION__":got unknown (strange?)type!\n");
+ break;
+ }
+}
+
+
+/*
+ * query_lsapsel()
+ * quering the remote IAS to ask which
+ * dlsap we should use
+ */
+
+static void query_lsapsel(struct ircomm_cb * self)
+{
+ DEBUG(0, __FUNCTION__"():querying IAS: Lsapsel...\n");
+
+ 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");
}
- skb_pull( skb, 1+clen);
+}
+
+/*
+ * 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;
+ ASSERT(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);
+
+ wake_up_interruptible( &self->discovery_wait);
return;
}
+
+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(¬ify);
+ 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,
+ ¬ify);
+ 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()
@@ -1241,21 +1695,21 @@
*/
#ifdef MODULE
-
int init_module(void)
{
- ircomm_init();
+ int err;
- DEBUG( 4, "ircomm:init_module:done\n");
- return 0;
+ err = ircomm_init();
+
+ 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 */
/************************************************************
@@ -1278,46 +1732,85 @@
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 */
+
+
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)