vserver 1.9.5.x5
[linux-2.6.git] / net / irda / ircomm / ircomm_tty_attach.c
index fa066ee..e01be88 100644 (file)
@@ -52,8 +52,9 @@ static void ircomm_tty_discovery_indication(discinfo_t *discovery,
                                            void *priv);
 static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id, 
                                        struct ias_value *value, void *priv);
-void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self, int timeout);
-void ircomm_tty_watchdog_timer_expired(void *data);
+static void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self,
+                                           int timeout);
+static void ircomm_tty_watchdog_timer_expired(void *data);
 
 static int ircomm_tty_state_idle(struct ircomm_tty_cb *self, 
                                 IRCOMM_TTY_EVENT event, 
@@ -90,7 +91,8 @@ char *ircomm_tty_state[] = {
        "*** ERROR *** ",
 };
 
-char *ircomm_tty_event[] = {
+#ifdef CONFIG_IRDA_DEBUG
+static char *ircomm_tty_event[] = {
        "IRCOMM_TTY_ATTACH_CABLE",
        "IRCOMM_TTY_DETACH_CABLE",
        "IRCOMM_TTY_DATA_REQUEST",
@@ -106,6 +108,7 @@ char *ircomm_tty_event[] = {
        "IRCOMM_TTY_GOT_LSAPSEL",
        "*** ERROR ****",
 };
+#endif /* CONFIG_IRDA_DEBUG */
 
 static int (*state[])(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
                      struct sk_buff *skb, struct ircomm_tty_info *info) = 
@@ -143,12 +146,6 @@ int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
 
        ircomm_tty_ias_register(self);
 
-       /* Check if somebody has already connected to us */
-       if (ircomm_is_connected(self->ircomm)) {
-               IRDA_DEBUG(0, "%s(), already connected!\n", __FUNCTION__ );
-               return 0;
-       }
-
        ircomm_tty_do_event(self, IRCOMM_TTY_ATTACH_CABLE, NULL, NULL);
 
        return 0;
@@ -169,9 +166,16 @@ void ircomm_tty_detach_cable(struct ircomm_tty_cb *self)
 
        del_timer(&self->watchdog_timer);
 
+       /* Remove discovery handler */
+       if (self->ckey) {
+               irlmp_unregister_client(self->ckey);
+               self->ckey = NULL;
+       }
        /* Remove IrCOMM hint bits */
-       irlmp_unregister_client(self->ckey);
-       irlmp_unregister_service(self->skey);
+       if (self->skey) {
+               irlmp_unregister_service(self->skey);
+               self->skey = NULL;
+       }
 
        if (self->iriap) { 
                iriap_close(self->iriap);
@@ -209,18 +213,30 @@ static void ircomm_tty_ias_register(struct ircomm_tty_cb *self)
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
        
+       /* Compute hint bits based on service */
+       hints = irlmp_service_to_hint(S_COMM);
+       if (self->service_type & IRCOMM_3_WIRE_RAW)
+               hints |= irlmp_service_to_hint(S_PRINTER);
+
+       /* Advertise IrCOMM hint bit in discovery */
+       if (!self->skey)
+               self->skey = irlmp_register_service(hints);
+       /* Set up a discovery handler */
+       if (!self->ckey)
+               self->ckey = irlmp_register_client(hints,
+                                                  ircomm_tty_discovery_indication,
+                                                  NULL, (void *) self);
+
+       /* If already done, no need to do it again */
+       if (self->obj)
+               return;
+
        if (self->service_type & IRCOMM_3_WIRE_RAW) {
-               hints = irlmp_service_to_hint(S_PRINTER);
-               hints |= irlmp_service_to_hint(S_COMM);
-               
                /* Register IrLPT with LM-IAS */
                self->obj = irias_new_object("IrLPT", IAS_IRLPT_ID);
                irias_add_integer_attrib(self->obj, "IrDA:IrLMP:LsapSel", 
                                         self->slsap_sel, IAS_KERNEL_ATTR);
-               irias_insert_object(self->obj);
        } else {
-               hints = irlmp_service_to_hint(S_COMM);
-
                /* Register IrCOMM with LM-IAS */
                self->obj = irias_new_object("IrDA:IrCOMM", IAS_IRCOMM_ID);
                irias_add_integer_attrib(self->obj, "IrDA:TinyTP:LsapSel", 
@@ -234,12 +250,45 @@ static void ircomm_tty_ias_register(struct ircomm_tty_cb *self)
                /* Register parameters with LM-IAS */
                irias_add_octseq_attrib(self->obj, "Parameters", oct_seq, 6,
                                        IAS_KERNEL_ATTR);
-               irias_insert_object(self->obj);
        }
-       self->skey = irlmp_register_service(hints);
-       self->ckey = irlmp_register_client(hints,
-                                          ircomm_tty_discovery_indication,
-                                          NULL, (void *) self);
+       irias_insert_object(self->obj);
+}
+
+/*
+ * Function ircomm_tty_ias_unregister (self)
+ *
+ *    Remove our IAS object and client hook while connected.
+ *
+ */
+static void ircomm_tty_ias_unregister(struct ircomm_tty_cb *self)
+{
+       /* Remove LM-IAS object now so it is not reused.
+        * IrCOMM deals very poorly with multiple incoming connections.
+        * It should looks a lot more like IrNET, and "dup" a server TSAP
+        * to the application TSAP (based on various rules).
+        * This is a cheap workaround allowing multiple clients to
+        * connect to us. It will not always work.
+        * Each IrCOMM socket has an IAS entry. Incoming connection will
+        * pick the first one found. So, when we are fully connected,
+        * we remove our IAS entries so that the next IAS entry is used.
+        * We do that for *both* client and server, because a server
+        * can also create client instances.
+        * Jean II */
+       if (self->obj) {
+               irias_delete_object(self->obj);
+               self->obj = NULL;
+       }
+
+#if 0
+       /* Remove discovery handler.
+        * While we are connected, we no longer need to receive
+        * discovery events. This would be the case if there is
+        * multiple IrLAP interfaces. Jean II */
+       if (self->ckey) {
+               irlmp_unregister_client(self->ckey);
+               self->ckey = NULL;
+       }
+#endif
 }
 
 /*
@@ -333,7 +382,8 @@ static void ircomm_tty_discovery_indication(discinfo_t *discovery,
        info.daddr = discovery->daddr;
        info.saddr = discovery->saddr;
 
-       /* FIXME. We probably need to use hashbin_find_next(), but we first
+       /* FIXME. We have a locking problem on the hashbin here.
+        * We probably need to use hashbin_find_next(), but we first
         * need to ensure that "line" is unique. - Jean II */
        self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty);
        while (self != NULL) {
@@ -519,23 +569,6 @@ void ircomm_tty_link_established(struct ircomm_tty_cb *self)
        
        del_timer(&self->watchdog_timer);
 
-       /* Remove LM-IAS object now so it is not reused.
-        * IrCOMM deals very poorly with multiple incoming connections.
-        * It should looks a lot more like IrNET, and "dup" a server TSAP
-        * to the application TSAP (based on various rules).
-        * This is a cheap workaround allowing multiple clients to
-        * connect to us. It will not always work.
-        * Each IrCOMM socket has an IAS entry. Incoming connection will
-        * pick the first one found. So, when we are fully connected,
-        * we remove our IAS entries so that the next IAS entry is used.
-        * We do that for *both* client and server, because a server
-        * can also create client instances.
-        * Jean II */
-       if (self->obj) {
-               irias_delete_object(self->obj);
-               self->obj = NULL;
-       }
-
        /* 
         * IrCOMM link is now up, and if we are not using hardware
         * flow-control, then declare the hardware as running. Otherwise we
@@ -558,13 +591,14 @@ void ircomm_tty_link_established(struct ircomm_tty_cb *self)
 }
 
 /*
- * Function irlan_start_watchdog_timer (self, timeout)
+ * Function ircomm_tty_start_watchdog_timer (self, timeout)
  *
  *    Start the watchdog timer. This timer is used to make sure that any 
  *    connection attempt is successful, and if not, we will retry after 
  *    the timeout
  */
-void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self, int timeout)
+static void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self,
+                                           int timeout)
 {
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -579,7 +613,7 @@ void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self, int timeout)
  *    Called when the connect procedure have taken to much time.
  *
  */
-void ircomm_tty_watchdog_timer_expired(void *data)
+static void ircomm_tty_watchdog_timer_expired(void *data)
 {
        struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) data;
        
@@ -591,6 +625,43 @@ void ircomm_tty_watchdog_timer_expired(void *data)
        ircomm_tty_do_event(self, IRCOMM_TTY_WD_TIMER_EXPIRED, NULL, NULL);
 }
 
+
+/*
+ * Function ircomm_tty_do_event (self, event, skb)
+ *
+ *    Process event
+ *
+ */
+int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
+                       struct sk_buff *skb, struct ircomm_tty_info *info) 
+{
+       ASSERT(self != NULL, return -1;);
+       ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
+
+       IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
+                  ircomm_tty_state[self->state], ircomm_tty_event[event]);
+       
+       return (*state[self->state])(self, event, skb, info);
+}
+
+/*
+ * Function ircomm_tty_next_state (self, state)
+ *
+ *    Switch state
+ *
+ */
+static inline void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_STATE state)
+{
+       /*
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
+
+       IRDA_DEBUG(2, "%s: next state=%s, service type=%d\n", __FUNCTION__ , 
+                  ircomm_tty_state[self->state], self->service_type);
+       */
+       self->state = state;
+}
+
 /*
  * Function ircomm_tty_state_idle (self, event, skb, info)
  *
@@ -700,6 +771,7 @@ static int ircomm_tty_state_search(struct ircomm_tty_cb *self,
                break;
        case IRCOMM_TTY_CONNECT_INDICATION:
                del_timer(&self->watchdog_timer);
+               ircomm_tty_ias_unregister(self);
 
                /* Accept connection */
                ircomm_connect_response(self->ircomm, NULL);
@@ -765,6 +837,7 @@ static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self,
                break;
        case IRCOMM_TTY_CONNECT_INDICATION:
                del_timer(&self->watchdog_timer);
+               ircomm_tty_ias_unregister(self);
 
                /* Accept connection */
                ircomm_connect_response(self->ircomm, NULL);
@@ -813,6 +886,7 @@ static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self,
                break;
        case IRCOMM_TTY_CONNECT_INDICATION:
                del_timer(&self->watchdog_timer);
+               ircomm_tty_ias_unregister(self);
 
                /* Accept connection */
                ircomm_connect_response(self->ircomm, NULL);
@@ -848,7 +922,7 @@ static int ircomm_tty_state_setup(struct ircomm_tty_cb *self,
        switch (event) {
        case IRCOMM_TTY_CONNECT_CONFIRM:
                del_timer(&self->watchdog_timer);
-               ircomm_tty_next_state(self, IRCOMM_TTY_READY);
+               ircomm_tty_ias_unregister(self);
                
                /* 
                 * Send initial parameters. This will also send out queued
@@ -856,9 +930,11 @@ static int ircomm_tty_state_setup(struct ircomm_tty_cb *self,
                 */
                ircomm_tty_send_initial_parameters(self);
                ircomm_tty_link_established(self);
+               ircomm_tty_next_state(self, IRCOMM_TTY_READY);
                break;
        case IRCOMM_TTY_CONNECT_INDICATION:
                del_timer(&self->watchdog_timer);
+               ircomm_tty_ias_unregister(self);
                
                /* Accept connection */
                ircomm_connect_response(self->ircomm, NULL);
@@ -903,6 +979,7 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
                ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
                break;
        case IRCOMM_TTY_DISCONNECT_INDICATION:
+               ircomm_tty_ias_register(self);
                ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
                ircomm_tty_start_watchdog_timer(self, 3*HZ);
 
@@ -924,38 +1001,3 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
        return ret;
 }
 
-/*
- * Function ircomm_tty_do_event (self, event, skb)
- *
- *    Process event
- *
- */
-int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
-                       struct sk_buff *skb, struct ircomm_tty_info *info) 
-{
-       ASSERT(self != NULL, return -1;);
-       ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
-
-       IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
-                  ircomm_tty_state[self->state], ircomm_tty_event[event]);
-       
-       return (*state[self->state])(self, event, skb, info);
-}
-
-/*
- * Function ircomm_tty_next_state (self, state)
- *
- *    Switch state
- *
- */
-void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_STATE state)
-{
-       ASSERT(self != NULL, return;);
-       ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
-
-       self->state = state;
-       
-       IRDA_DEBUG(2, "%s: next state=%s, service type=%d\n", __FUNCTION__ , 
-                  ircomm_tty_state[self->state], self->service_type);
-}
-