Path: blob/master/net/irda/ircomm/ircomm_tty_attach.c
15111 views
/*********************************************************************1*2* Filename: ircomm_tty_attach.c3* Version:4* Description: Code for attaching the serial driver to IrCOMM5* Status: Experimental.6* Author: Dag Brattli <[email protected]>7* Created at: Sat Jun 5 17:42:00 19998* Modified at: Tue Jan 4 14:20:49 20009* Modified by: Dag Brattli <[email protected]>10*11* Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.12* Copyright (c) 2000-2003 Jean Tourrilhes <[email protected]>13*14* This program is free software; you can redistribute it and/or15* modify it under the terms of the GNU General Public License as16* published by the Free Software Foundation; either version 2 of17* the License, or (at your option) any later version.18*19* This program is distributed in the hope that it will be useful,20* but WITHOUT ANY WARRANTY; without even the implied warranty of21* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the22* GNU General Public License for more details.23*24* You should have received a copy of the GNU General Public License25* along with this program; if not, write to the Free Software26* Foundation, Inc., 59 Temple Place, Suite 330, Boston,27* MA 02111-1307 USA28*29********************************************************************/3031#include <linux/init.h>32#include <linux/sched.h>3334#include <net/irda/irda.h>35#include <net/irda/irlmp.h>36#include <net/irda/iriap.h>37#include <net/irda/irttp.h>38#include <net/irda/irias_object.h>39#include <net/irda/parameters.h>4041#include <net/irda/ircomm_core.h>42#include <net/irda/ircomm_param.h>43#include <net/irda/ircomm_event.h>4445#include <net/irda/ircomm_tty.h>46#include <net/irda/ircomm_tty_attach.h>4748static void ircomm_tty_ias_register(struct ircomm_tty_cb *self);49static void ircomm_tty_discovery_indication(discinfo_t *discovery,50DISCOVERY_MODE mode,51void *priv);52static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id,53struct ias_value *value, void *priv);54static void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self,55int timeout);56static void ircomm_tty_watchdog_timer_expired(void *data);5758static int ircomm_tty_state_idle(struct ircomm_tty_cb *self,59IRCOMM_TTY_EVENT event,60struct sk_buff *skb,61struct ircomm_tty_info *info);62static int ircomm_tty_state_search(struct ircomm_tty_cb *self,63IRCOMM_TTY_EVENT event,64struct sk_buff *skb,65struct ircomm_tty_info *info);66static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self,67IRCOMM_TTY_EVENT event,68struct sk_buff *skb,69struct ircomm_tty_info *info);70static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self,71IRCOMM_TTY_EVENT event,72struct sk_buff *skb,73struct ircomm_tty_info *info);74static int ircomm_tty_state_setup(struct ircomm_tty_cb *self,75IRCOMM_TTY_EVENT event,76struct sk_buff *skb,77struct ircomm_tty_info *info);78static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,79IRCOMM_TTY_EVENT event,80struct sk_buff *skb,81struct ircomm_tty_info *info);8283const char *const ircomm_tty_state[] = {84"IRCOMM_TTY_IDLE",85"IRCOMM_TTY_SEARCH",86"IRCOMM_TTY_QUERY_PARAMETERS",87"IRCOMM_TTY_QUERY_LSAP_SEL",88"IRCOMM_TTY_SETUP",89"IRCOMM_TTY_READY",90"*** ERROR *** ",91};9293#ifdef CONFIG_IRDA_DEBUG94static const char *const ircomm_tty_event[] = {95"IRCOMM_TTY_ATTACH_CABLE",96"IRCOMM_TTY_DETACH_CABLE",97"IRCOMM_TTY_DATA_REQUEST",98"IRCOMM_TTY_DATA_INDICATION",99"IRCOMM_TTY_DISCOVERY_REQUEST",100"IRCOMM_TTY_DISCOVERY_INDICATION",101"IRCOMM_TTY_CONNECT_CONFIRM",102"IRCOMM_TTY_CONNECT_INDICATION",103"IRCOMM_TTY_DISCONNECT_REQUEST",104"IRCOMM_TTY_DISCONNECT_INDICATION",105"IRCOMM_TTY_WD_TIMER_EXPIRED",106"IRCOMM_TTY_GOT_PARAMETERS",107"IRCOMM_TTY_GOT_LSAPSEL",108"*** ERROR ****",109};110#endif /* CONFIG_IRDA_DEBUG */111112static int (*state[])(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,113struct sk_buff *skb, struct ircomm_tty_info *info) =114{115ircomm_tty_state_idle,116ircomm_tty_state_search,117ircomm_tty_state_query_parameters,118ircomm_tty_state_query_lsap_sel,119ircomm_tty_state_setup,120ircomm_tty_state_ready,121};122123/*124* Function ircomm_tty_attach_cable (driver)125*126* Try to attach cable (IrCOMM link). This function will only return127* when the link has been connected, or if an error condition occurs.128* If success, the return value is the resulting service type.129*/130int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)131{132IRDA_DEBUG(0, "%s()\n", __func__ );133134IRDA_ASSERT(self != NULL, return -1;);135IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);136137/* Check if somebody has already connected to us */138if (ircomm_is_connected(self->ircomm)) {139IRDA_DEBUG(0, "%s(), already connected!\n", __func__ );140return 0;141}142143/* Make sure nobody tries to write before the link is up */144self->tty->hw_stopped = 1;145146ircomm_tty_ias_register(self);147148ircomm_tty_do_event(self, IRCOMM_TTY_ATTACH_CABLE, NULL, NULL);149150return 0;151}152153/*154* Function ircomm_detach_cable (driver)155*156* Detach cable, or cable has been detached by peer157*158*/159void ircomm_tty_detach_cable(struct ircomm_tty_cb *self)160{161IRDA_DEBUG(0, "%s()\n", __func__ );162163IRDA_ASSERT(self != NULL, return;);164IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);165166del_timer(&self->watchdog_timer);167168/* Remove discovery handler */169if (self->ckey) {170irlmp_unregister_client(self->ckey);171self->ckey = NULL;172}173/* Remove IrCOMM hint bits */174if (self->skey) {175irlmp_unregister_service(self->skey);176self->skey = NULL;177}178179if (self->iriap) {180iriap_close(self->iriap);181self->iriap = NULL;182}183184/* Remove LM-IAS object */185if (self->obj) {186irias_delete_object(self->obj);187self->obj = NULL;188}189190ircomm_tty_do_event(self, IRCOMM_TTY_DETACH_CABLE, NULL, NULL);191192/* Reset some values */193self->daddr = self->saddr = 0;194self->dlsap_sel = self->slsap_sel = 0;195196memset(&self->settings, 0, sizeof(struct ircomm_params));197}198199/*200* Function ircomm_tty_ias_register (self)201*202* Register with LM-IAS depending on which service type we are203*204*/205static void ircomm_tty_ias_register(struct ircomm_tty_cb *self)206{207__u8 oct_seq[6];208__u16 hints;209210IRDA_DEBUG(0, "%s()\n", __func__ );211212IRDA_ASSERT(self != NULL, return;);213IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);214215/* Compute hint bits based on service */216hints = irlmp_service_to_hint(S_COMM);217if (self->service_type & IRCOMM_3_WIRE_RAW)218hints |= irlmp_service_to_hint(S_PRINTER);219220/* Advertise IrCOMM hint bit in discovery */221if (!self->skey)222self->skey = irlmp_register_service(hints);223/* Set up a discovery handler */224if (!self->ckey)225self->ckey = irlmp_register_client(hints,226ircomm_tty_discovery_indication,227NULL, (void *) self);228229/* If already done, no need to do it again */230if (self->obj)231return;232233if (self->service_type & IRCOMM_3_WIRE_RAW) {234/* Register IrLPT with LM-IAS */235self->obj = irias_new_object("IrLPT", IAS_IRLPT_ID);236irias_add_integer_attrib(self->obj, "IrDA:IrLMP:LsapSel",237self->slsap_sel, IAS_KERNEL_ATTR);238} else {239/* Register IrCOMM with LM-IAS */240self->obj = irias_new_object("IrDA:IrCOMM", IAS_IRCOMM_ID);241irias_add_integer_attrib(self->obj, "IrDA:TinyTP:LsapSel",242self->slsap_sel, IAS_KERNEL_ATTR);243244/* Code the parameters into the buffer */245irda_param_pack(oct_seq, "bbbbbb",246IRCOMM_SERVICE_TYPE, 1, self->service_type,247IRCOMM_PORT_TYPE, 1, IRCOMM_SERIAL);248249/* Register parameters with LM-IAS */250irias_add_octseq_attrib(self->obj, "Parameters", oct_seq, 6,251IAS_KERNEL_ATTR);252}253irias_insert_object(self->obj);254}255256/*257* Function ircomm_tty_ias_unregister (self)258*259* Remove our IAS object and client hook while connected.260*261*/262static void ircomm_tty_ias_unregister(struct ircomm_tty_cb *self)263{264/* Remove LM-IAS object now so it is not reused.265* IrCOMM deals very poorly with multiple incoming connections.266* It should looks a lot more like IrNET, and "dup" a server TSAP267* to the application TSAP (based on various rules).268* This is a cheap workaround allowing multiple clients to269* connect to us. It will not always work.270* Each IrCOMM socket has an IAS entry. Incoming connection will271* pick the first one found. So, when we are fully connected,272* we remove our IAS entries so that the next IAS entry is used.273* We do that for *both* client and server, because a server274* can also create client instances.275* Jean II */276if (self->obj) {277irias_delete_object(self->obj);278self->obj = NULL;279}280281#if 0282/* Remove discovery handler.283* While we are connected, we no longer need to receive284* discovery events. This would be the case if there is285* multiple IrLAP interfaces. Jean II */286if (self->ckey) {287irlmp_unregister_client(self->ckey);288self->ckey = NULL;289}290#endif291}292293/*294* Function ircomm_send_initial_parameters (self)295*296* Send initial parameters to the remote IrCOMM device. These parameters297* must be sent before any data.298*/299int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self)300{301IRDA_ASSERT(self != NULL, return -1;);302IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);303304if (self->service_type & IRCOMM_3_WIRE_RAW)305return 0;306307/*308* Set default values, but only if the application for some reason309* haven't set them already310*/311IRDA_DEBUG(2, "%s(), data-rate = %d\n", __func__ ,312self->settings.data_rate);313if (!self->settings.data_rate)314self->settings.data_rate = 9600;315IRDA_DEBUG(2, "%s(), data-format = %d\n", __func__ ,316self->settings.data_format);317if (!self->settings.data_format)318self->settings.data_format = IRCOMM_WSIZE_8; /* 8N1 */319320IRDA_DEBUG(2, "%s(), flow-control = %d\n", __func__ ,321self->settings.flow_control);322/*self->settings.flow_control = IRCOMM_RTS_CTS_IN|IRCOMM_RTS_CTS_OUT;*/323324/* Do not set delta values for the initial parameters */325self->settings.dte = IRCOMM_DTR | IRCOMM_RTS;326327/* Only send service type parameter when we are the client */328if (self->client)329ircomm_param_request(self, IRCOMM_SERVICE_TYPE, FALSE);330ircomm_param_request(self, IRCOMM_DATA_RATE, FALSE);331ircomm_param_request(self, IRCOMM_DATA_FORMAT, FALSE);332333/* For a 3 wire service, we just flush the last parameter and return */334if (self->settings.service_type == IRCOMM_3_WIRE) {335ircomm_param_request(self, IRCOMM_FLOW_CONTROL, TRUE);336return 0;337}338339/* Only 9-wire service types continue here */340ircomm_param_request(self, IRCOMM_FLOW_CONTROL, FALSE);341#if 0342ircomm_param_request(self, IRCOMM_XON_XOFF, FALSE);343ircomm_param_request(self, IRCOMM_ENQ_ACK, FALSE);344#endif345/* Notify peer that we are ready to receive data */346ircomm_param_request(self, IRCOMM_DTE, TRUE);347348return 0;349}350351/*352* Function ircomm_tty_discovery_indication (discovery)353*354* Remote device is discovered, try query the remote IAS to see which355* device it is, and which services it has.356*357*/358static void ircomm_tty_discovery_indication(discinfo_t *discovery,359DISCOVERY_MODE mode,360void *priv)361{362struct ircomm_tty_cb *self;363struct ircomm_tty_info info;364365IRDA_DEBUG(2, "%s()\n", __func__ );366367/* Important note :368* We need to drop all passive discoveries.369* The LSAP management of IrComm is deficient and doesn't deal370* with the case of two instance connecting to each other371* simultaneously (it will deadlock in LMP).372* The proper fix would be to use the same technique as in IrNET,373* to have one server socket and separate instances for the374* connecting/connected socket.375* The workaround is to drop passive discovery, which drastically376* reduce the probability of this happening.377* Jean II */378if(mode == DISCOVERY_PASSIVE)379return;380381info.daddr = discovery->daddr;382info.saddr = discovery->saddr;383384self = (struct ircomm_tty_cb *) priv;385ircomm_tty_do_event(self, IRCOMM_TTY_DISCOVERY_INDICATION,386NULL, &info);387}388389/*390* Function ircomm_tty_disconnect_indication (instance, sap, reason, skb)391*392* Link disconnected393*394*/395void ircomm_tty_disconnect_indication(void *instance, void *sap,396LM_REASON reason,397struct sk_buff *skb)398{399struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;400401IRDA_DEBUG(2, "%s()\n", __func__ );402403IRDA_ASSERT(self != NULL, return;);404IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);405406if (!self->tty)407return;408409/* This will stop control data transfers */410self->flow = FLOW_STOP;411412/* Stop data transfers */413self->tty->hw_stopped = 1;414415ircomm_tty_do_event(self, IRCOMM_TTY_DISCONNECT_INDICATION, NULL,416NULL);417}418419/*420* Function ircomm_tty_getvalue_confirm (result, obj_id, value, priv)421*422* Got result from the IAS query we make423*424*/425static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id,426struct ias_value *value,427void *priv)428{429struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) priv;430431IRDA_DEBUG(2, "%s()\n", __func__ );432433IRDA_ASSERT(self != NULL, return;);434IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);435436/* We probably don't need to make any more queries */437iriap_close(self->iriap);438self->iriap = NULL;439440/* Check if request succeeded */441if (result != IAS_SUCCESS) {442IRDA_DEBUG(4, "%s(), got NULL value!\n", __func__ );443return;444}445446switch (value->type) {447case IAS_OCT_SEQ:448IRDA_DEBUG(2, "%s(), got octet sequence\n", __func__ );449450irda_param_extract_all(self, value->t.oct_seq, value->len,451&ircomm_param_info);452453ircomm_tty_do_event(self, IRCOMM_TTY_GOT_PARAMETERS, NULL,454NULL);455break;456case IAS_INTEGER:457/* Got LSAP selector */458IRDA_DEBUG(2, "%s(), got lsapsel = %d\n", __func__ ,459value->t.integer);460461if (value->t.integer == -1) {462IRDA_DEBUG(0, "%s(), invalid value!\n", __func__ );463} else464self->dlsap_sel = value->t.integer;465466ircomm_tty_do_event(self, IRCOMM_TTY_GOT_LSAPSEL, NULL, NULL);467break;468case IAS_MISSING:469IRDA_DEBUG(0, "%s(), got IAS_MISSING\n", __func__ );470break;471default:472IRDA_DEBUG(0, "%s(), got unknown type!\n", __func__ );473break;474}475irias_delete_value(value);476}477478/*479* Function ircomm_tty_connect_confirm (instance, sap, qos, max_sdu_size, skb)480*481* Connection confirmed482*483*/484void ircomm_tty_connect_confirm(void *instance, void *sap,485struct qos_info *qos,486__u32 max_data_size,487__u8 max_header_size,488struct sk_buff *skb)489{490struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;491492IRDA_DEBUG(2, "%s()\n", __func__ );493494IRDA_ASSERT(self != NULL, return;);495IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);496497self->client = TRUE;498self->max_data_size = max_data_size;499self->max_header_size = max_header_size;500self->flow = FLOW_START;501502ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_CONFIRM, NULL, NULL);503504/* No need to kfree_skb - see ircomm_ttp_connect_confirm() */505}506507/*508* Function ircomm_tty_connect_indication (instance, sap, qos, max_sdu_size,509* skb)510*511* we are discovered and being requested to connect by remote device !512*513*/514void ircomm_tty_connect_indication(void *instance, void *sap,515struct qos_info *qos,516__u32 max_data_size,517__u8 max_header_size,518struct sk_buff *skb)519{520struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;521int clen;522523IRDA_DEBUG(2, "%s()\n", __func__ );524525IRDA_ASSERT(self != NULL, return;);526IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);527528self->client = FALSE;529self->max_data_size = max_data_size;530self->max_header_size = max_header_size;531self->flow = FLOW_START;532533clen = skb->data[0];534if (clen)535irda_param_extract_all(self, skb->data+1,536IRDA_MIN(skb->len, clen),537&ircomm_param_info);538539ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_INDICATION, NULL, NULL);540541/* No need to kfree_skb - see ircomm_ttp_connect_indication() */542}543544/*545* Function ircomm_tty_link_established (self)546*547* Called when the IrCOMM link is established548*549*/550void ircomm_tty_link_established(struct ircomm_tty_cb *self)551{552IRDA_DEBUG(2, "%s()\n", __func__ );553554IRDA_ASSERT(self != NULL, return;);555IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);556557if (!self->tty)558return;559560del_timer(&self->watchdog_timer);561562/*563* IrCOMM link is now up, and if we are not using hardware564* flow-control, then declare the hardware as running. Otherwise we565* will have to wait for the peer device (DCE) to raise the CTS566* line.567*/568if ((self->flags & ASYNC_CTS_FLOW) && ((self->settings.dce & IRCOMM_CTS) == 0)) {569IRDA_DEBUG(0, "%s(), waiting for CTS ...\n", __func__ );570return;571} else {572IRDA_DEBUG(1, "%s(), starting hardware!\n", __func__ );573574self->tty->hw_stopped = 0;575576/* Wake up processes blocked on open */577wake_up_interruptible(&self->open_wait);578}579580schedule_work(&self->tqueue);581}582583/*584* Function ircomm_tty_start_watchdog_timer (self, timeout)585*586* Start the watchdog timer. This timer is used to make sure that any587* connection attempt is successful, and if not, we will retry after588* the timeout589*/590static void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self,591int timeout)592{593IRDA_ASSERT(self != NULL, return;);594IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);595596irda_start_timer(&self->watchdog_timer, timeout, (void *) self,597ircomm_tty_watchdog_timer_expired);598}599600/*601* Function ircomm_tty_watchdog_timer_expired (data)602*603* Called when the connect procedure have taken to much time.604*605*/606static void ircomm_tty_watchdog_timer_expired(void *data)607{608struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) data;609610IRDA_DEBUG(2, "%s()\n", __func__ );611612IRDA_ASSERT(self != NULL, return;);613IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);614615ircomm_tty_do_event(self, IRCOMM_TTY_WD_TIMER_EXPIRED, NULL, NULL);616}617618619/*620* Function ircomm_tty_do_event (self, event, skb)621*622* Process event623*624*/625int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,626struct sk_buff *skb, struct ircomm_tty_info *info)627{628IRDA_ASSERT(self != NULL, return -1;);629IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);630631IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,632ircomm_tty_state[self->state], ircomm_tty_event[event]);633634return (*state[self->state])(self, event, skb, info);635}636637/*638* Function ircomm_tty_next_state (self, state)639*640* Switch state641*642*/643static inline void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_STATE state)644{645/*646IRDA_ASSERT(self != NULL, return;);647IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);648649IRDA_DEBUG(2, "%s: next state=%s, service type=%d\n", __func__ ,650ircomm_tty_state[self->state], self->service_type);651*/652self->state = state;653}654655/*656* Function ircomm_tty_state_idle (self, event, skb, info)657*658* Just hanging around659*660*/661static int ircomm_tty_state_idle(struct ircomm_tty_cb *self,662IRCOMM_TTY_EVENT event,663struct sk_buff *skb,664struct ircomm_tty_info *info)665{666int ret = 0;667668IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,669ircomm_tty_state[self->state], ircomm_tty_event[event]);670switch (event) {671case IRCOMM_TTY_ATTACH_CABLE:672/* Try to discover any remote devices */673ircomm_tty_start_watchdog_timer(self, 3*HZ);674ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);675676irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);677break;678case IRCOMM_TTY_DISCOVERY_INDICATION:679self->daddr = info->daddr;680self->saddr = info->saddr;681682if (self->iriap) {683IRDA_WARNING("%s(), busy with a previous query\n",684__func__);685return -EBUSY;686}687688self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,689ircomm_tty_getvalue_confirm);690691iriap_getvaluebyclass_request(self->iriap,692self->saddr, self->daddr,693"IrDA:IrCOMM", "Parameters");694695ircomm_tty_start_watchdog_timer(self, 3*HZ);696ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_PARAMETERS);697break;698case IRCOMM_TTY_CONNECT_INDICATION:699del_timer(&self->watchdog_timer);700701/* Accept connection */702ircomm_connect_response(self->ircomm, NULL);703ircomm_tty_next_state(self, IRCOMM_TTY_READY);704break;705case IRCOMM_TTY_WD_TIMER_EXPIRED:706/* Just stay idle */707break;708case IRCOMM_TTY_DETACH_CABLE:709ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);710break;711default:712IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,713ircomm_tty_event[event]);714ret = -EINVAL;715}716return ret;717}718719/*720* Function ircomm_tty_state_search (self, event, skb, info)721*722* Trying to discover an IrCOMM device723*724*/725static int ircomm_tty_state_search(struct ircomm_tty_cb *self,726IRCOMM_TTY_EVENT event,727struct sk_buff *skb,728struct ircomm_tty_info *info)729{730int ret = 0;731732IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,733ircomm_tty_state[self->state], ircomm_tty_event[event]);734735switch (event) {736case IRCOMM_TTY_DISCOVERY_INDICATION:737self->daddr = info->daddr;738self->saddr = info->saddr;739740if (self->iriap) {741IRDA_WARNING("%s(), busy with a previous query\n",742__func__);743return -EBUSY;744}745746self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,747ircomm_tty_getvalue_confirm);748749if (self->service_type == IRCOMM_3_WIRE_RAW) {750iriap_getvaluebyclass_request(self->iriap, self->saddr,751self->daddr, "IrLPT",752"IrDA:IrLMP:LsapSel");753ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_LSAP_SEL);754} else {755iriap_getvaluebyclass_request(self->iriap, self->saddr,756self->daddr,757"IrDA:IrCOMM",758"Parameters");759760ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_PARAMETERS);761}762ircomm_tty_start_watchdog_timer(self, 3*HZ);763break;764case IRCOMM_TTY_CONNECT_INDICATION:765del_timer(&self->watchdog_timer);766ircomm_tty_ias_unregister(self);767768/* Accept connection */769ircomm_connect_response(self->ircomm, NULL);770ircomm_tty_next_state(self, IRCOMM_TTY_READY);771break;772case IRCOMM_TTY_WD_TIMER_EXPIRED:773#if 1774/* Give up */775#else776/* Try to discover any remote devices */777ircomm_tty_start_watchdog_timer(self, 3*HZ);778irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);779#endif780break;781case IRCOMM_TTY_DETACH_CABLE:782ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);783break;784default:785IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,786ircomm_tty_event[event]);787ret = -EINVAL;788}789return ret;790}791792/*793* Function ircomm_tty_state_query (self, event, skb, info)794*795* Querying the remote LM-IAS for IrCOMM parameters796*797*/798static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self,799IRCOMM_TTY_EVENT event,800struct sk_buff *skb,801struct ircomm_tty_info *info)802{803int ret = 0;804805IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,806ircomm_tty_state[self->state], ircomm_tty_event[event]);807808switch (event) {809case IRCOMM_TTY_GOT_PARAMETERS:810if (self->iriap) {811IRDA_WARNING("%s(), busy with a previous query\n",812__func__);813return -EBUSY;814}815816self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,817ircomm_tty_getvalue_confirm);818819iriap_getvaluebyclass_request(self->iriap, self->saddr,820self->daddr, "IrDA:IrCOMM",821"IrDA:TinyTP:LsapSel");822823ircomm_tty_start_watchdog_timer(self, 3*HZ);824ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_LSAP_SEL);825break;826case IRCOMM_TTY_WD_TIMER_EXPIRED:827/* Go back to search mode */828ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);829ircomm_tty_start_watchdog_timer(self, 3*HZ);830break;831case IRCOMM_TTY_CONNECT_INDICATION:832del_timer(&self->watchdog_timer);833ircomm_tty_ias_unregister(self);834835/* Accept connection */836ircomm_connect_response(self->ircomm, NULL);837ircomm_tty_next_state(self, IRCOMM_TTY_READY);838break;839case IRCOMM_TTY_DETACH_CABLE:840ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);841break;842default:843IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,844ircomm_tty_event[event]);845ret = -EINVAL;846}847return ret;848}849850/*851* Function ircomm_tty_state_query_lsap_sel (self, event, skb, info)852*853* Query remote LM-IAS for the LSAP selector which we can connect to854*855*/856static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self,857IRCOMM_TTY_EVENT event,858struct sk_buff *skb,859struct ircomm_tty_info *info)860{861int ret = 0;862863IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,864ircomm_tty_state[self->state], ircomm_tty_event[event]);865866switch (event) {867case IRCOMM_TTY_GOT_LSAPSEL:868/* Connect to remote device */869ret = ircomm_connect_request(self->ircomm, self->dlsap_sel,870self->saddr, self->daddr,871NULL, self->service_type);872ircomm_tty_start_watchdog_timer(self, 3*HZ);873ircomm_tty_next_state(self, IRCOMM_TTY_SETUP);874break;875case IRCOMM_TTY_WD_TIMER_EXPIRED:876/* Go back to search mode */877ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);878ircomm_tty_start_watchdog_timer(self, 3*HZ);879break;880case IRCOMM_TTY_CONNECT_INDICATION:881del_timer(&self->watchdog_timer);882ircomm_tty_ias_unregister(self);883884/* Accept connection */885ircomm_connect_response(self->ircomm, NULL);886ircomm_tty_next_state(self, IRCOMM_TTY_READY);887break;888case IRCOMM_TTY_DETACH_CABLE:889ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);890break;891default:892IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,893ircomm_tty_event[event]);894ret = -EINVAL;895}896return ret;897}898899/*900* Function ircomm_tty_state_setup (self, event, skb, info)901*902* Trying to connect903*904*/905static int ircomm_tty_state_setup(struct ircomm_tty_cb *self,906IRCOMM_TTY_EVENT event,907struct sk_buff *skb,908struct ircomm_tty_info *info)909{910int ret = 0;911912IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,913ircomm_tty_state[self->state], ircomm_tty_event[event]);914915switch (event) {916case IRCOMM_TTY_CONNECT_CONFIRM:917del_timer(&self->watchdog_timer);918ircomm_tty_ias_unregister(self);919920/*921* Send initial parameters. This will also send out queued922* parameters waiting for the connection to come up923*/924ircomm_tty_send_initial_parameters(self);925ircomm_tty_link_established(self);926ircomm_tty_next_state(self, IRCOMM_TTY_READY);927break;928case IRCOMM_TTY_CONNECT_INDICATION:929del_timer(&self->watchdog_timer);930ircomm_tty_ias_unregister(self);931932/* Accept connection */933ircomm_connect_response(self->ircomm, NULL);934ircomm_tty_next_state(self, IRCOMM_TTY_READY);935break;936case IRCOMM_TTY_WD_TIMER_EXPIRED:937/* Go back to search mode */938ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);939ircomm_tty_start_watchdog_timer(self, 3*HZ);940break;941case IRCOMM_TTY_DETACH_CABLE:942/* ircomm_disconnect_request(self->ircomm, NULL); */943ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);944break;945default:946IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,947ircomm_tty_event[event]);948ret = -EINVAL;949}950return ret;951}952953/*954* Function ircomm_tty_state_ready (self, event, skb, info)955*956* IrCOMM is now connected957*958*/959static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,960IRCOMM_TTY_EVENT event,961struct sk_buff *skb,962struct ircomm_tty_info *info)963{964int ret = 0;965966switch (event) {967case IRCOMM_TTY_DATA_REQUEST:968ret = ircomm_data_request(self->ircomm, skb);969break;970case IRCOMM_TTY_DETACH_CABLE:971ircomm_disconnect_request(self->ircomm, NULL);972ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);973break;974case IRCOMM_TTY_DISCONNECT_INDICATION:975ircomm_tty_ias_register(self);976ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);977ircomm_tty_start_watchdog_timer(self, 3*HZ);978979if (self->flags & ASYNC_CHECK_CD) {980/* Drop carrier */981self->settings.dce = IRCOMM_DELTA_CD;982ircomm_tty_check_modem_status(self);983} else {984IRDA_DEBUG(0, "%s(), hanging up!\n", __func__ );985if (self->tty)986tty_hangup(self->tty);987}988break;989default:990IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,991ircomm_tty_event[event]);992ret = -EINVAL;993}994return ret;995}996997998999