ircomm_tty_attach.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:25k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*********************************************************************
  2.  *                
  3.  * Filename:      ircomm_tty_attach.c
  4.  * Version:       
  5.  * Description:   Code for attaching the serial driver to IrCOMM
  6.  * Status:        Experimental.
  7.  * Author:        Dag Brattli <dagb@cs.uit.no>
  8.  * Created at:    Sat Jun  5 17:42:00 1999
  9.  * Modified at:   Tue Jan  4 14:20:49 2000
  10.  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  11.  * 
  12.  *     Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
  13.  *     
  14.  *     This program is free software; you can redistribute it and/or 
  15.  *     modify it under the terms of the GNU General Public License as 
  16.  *     published by the Free Software Foundation; either version 2 of 
  17.  *     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 of
  21.  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22.  *     GNU General Public License for more details.
  23.  * 
  24.  *     You should have received a copy of the GNU General Public License 
  25.  *     along with this program; if not, write to the Free Software 
  26.  *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
  27.  *     MA 02111-1307 USA
  28.  *     
  29.  ********************************************************************/
  30. #include <linux/sched.h>
  31. #include <linux/init.h>
  32. #include <net/irda/irda.h>
  33. #include <net/irda/irlmp.h>
  34. #include <net/irda/iriap.h>
  35. #include <net/irda/irttp.h>
  36. #include <net/irda/irias_object.h>
  37. #include <net/irda/parameters.h>
  38. #include <net/irda/ircomm_core.h>
  39. #include <net/irda/ircomm_param.h>
  40. #include <net/irda/ircomm_event.h>
  41. #include <net/irda/ircomm_tty.h>
  42. #include <net/irda/ircomm_tty_attach.h>
  43. static void ircomm_tty_ias_register(struct ircomm_tty_cb *self);
  44. static void ircomm_tty_discovery_indication(discovery_t *discovery,
  45.     void *priv);
  46. static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id, 
  47. struct ias_value *value, void *priv);
  48. void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self, int timeout);
  49. void ircomm_tty_watchdog_timer_expired(void *data);
  50. static int ircomm_tty_state_idle(struct ircomm_tty_cb *self, 
  51.  IRCOMM_TTY_EVENT event, 
  52.  struct sk_buff *skb, 
  53.  struct ircomm_tty_info *info);
  54. static int ircomm_tty_state_search(struct ircomm_tty_cb *self, 
  55.    IRCOMM_TTY_EVENT event, 
  56.    struct sk_buff *skb, 
  57.    struct ircomm_tty_info *info);
  58. static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self, 
  59.      IRCOMM_TTY_EVENT event, 
  60.      struct sk_buff *skb, 
  61.      struct ircomm_tty_info *info);
  62. static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self, 
  63.    IRCOMM_TTY_EVENT event, 
  64.    struct sk_buff *skb, 
  65.    struct ircomm_tty_info *info);
  66. static int ircomm_tty_state_setup(struct ircomm_tty_cb *self, 
  67.   IRCOMM_TTY_EVENT event, 
  68.   struct sk_buff *skb, 
  69.   struct ircomm_tty_info *info);
  70. static int ircomm_tty_state_ready(struct ircomm_tty_cb *self, 
  71.   IRCOMM_TTY_EVENT event, 
  72.   struct sk_buff *skb, 
  73.   struct ircomm_tty_info *info);
  74. char *ircomm_tty_state[] = {
  75. "IRCOMM_TTY_IDLE",
  76. "IRCOMM_TTY_SEARCH",
  77. "IRCOMM_TTY_QUERY_PARAMETERS",
  78. "IRCOMM_TTY_QUERY_LSAP_SEL",
  79. "IRCOMM_TTY_SETUP",
  80. "IRCOMM_TTY_READY",
  81. "*** ERROR *** ",
  82. };
  83. char *ircomm_tty_event[] = {
  84. "IRCOMM_TTY_ATTACH_CABLE",
  85. "IRCOMM_TTY_DETACH_CABLE",
  86. "IRCOMM_TTY_DATA_REQUEST",
  87. "IRCOMM_TTY_DATA_INDICATION",
  88. "IRCOMM_TTY_DISCOVERY_REQUEST",
  89. "IRCOMM_TTY_DISCOVERY_INDICATION",
  90. "IRCOMM_TTY_CONNECT_CONFIRM",
  91. "IRCOMM_TTY_CONNECT_INDICATION",
  92. "IRCOMM_TTY_DISCONNECT_REQUEST",
  93. "IRCOMM_TTY_DISCONNECT_INDICATION",
  94. "IRCOMM_TTY_WD_TIMER_EXPIRED",
  95. "IRCOMM_TTY_GOT_PARAMETERS",
  96. "IRCOMM_TTY_GOT_LSAPSEL",
  97. "*** ERROR ****",
  98. };
  99. static int (*state[])(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
  100.       struct sk_buff *skb, struct ircomm_tty_info *info) = 
  101. {
  102. ircomm_tty_state_idle,
  103. ircomm_tty_state_search,
  104. ircomm_tty_state_query_parameters,
  105. ircomm_tty_state_query_lsap_sel,
  106. ircomm_tty_state_setup,
  107. ircomm_tty_state_ready,
  108. };
  109. /*
  110.  * Function ircomm_tty_attach_cable (driver)
  111.  *
  112.  *    Try to attach cable (IrCOMM link). This function will only return
  113.  *    when the link has been connected, or if an error condition occurs. 
  114.  *    If success, the return value is the resulting service type.
  115.  */
  116. int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
  117. {
  118. IRDA_DEBUG(0, __FUNCTION__ "()n");
  119. ASSERT(self != NULL, return -1;);
  120. ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
  121.         /* Check if somebody has already connected to us */
  122. if (ircomm_is_connected(self->ircomm)) {
  123. IRDA_DEBUG(0, __FUNCTION__ "(), already connected!n");
  124. return 0;
  125. }
  126. /* Make sure nobody tries to write before the link is up */
  127. self->tty->hw_stopped = 1;
  128. ircomm_tty_ias_register(self);
  129. /* Check if somebody has already connected to us */
  130. if (ircomm_is_connected(self->ircomm)) {
  131. IRDA_DEBUG(0, __FUNCTION__ "(), already connected!n");
  132. return 0;
  133. }
  134. ircomm_tty_do_event(self, IRCOMM_TTY_ATTACH_CABLE, NULL, NULL);
  135. return 0;
  136. }
  137. /*
  138.  * Function ircomm_detach_cable (driver)
  139.  *
  140.  *    Detach cable, or cable has been detached by peer
  141.  *
  142.  */
  143. void ircomm_tty_detach_cable(struct ircomm_tty_cb *self)
  144. {
  145. IRDA_DEBUG(0, __FUNCTION__ "()n");
  146. ASSERT(self != NULL, return;);
  147. ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
  148. del_timer(&self->watchdog_timer);
  149. /* Remove IrCOMM hint bits */
  150. irlmp_unregister_client(self->ckey);
  151. irlmp_unregister_service(self->skey);
  152. if (self->iriap) { 
  153. iriap_close(self->iriap);
  154. self->iriap = NULL;
  155. }
  156. /* Remove LM-IAS object */
  157. if (self->obj) {
  158. irias_delete_object(self->obj);
  159. self->obj = NULL;
  160. }
  161. ircomm_tty_do_event(self, IRCOMM_TTY_DETACH_CABLE, NULL, NULL);
  162. /* Reset some values */
  163. self->daddr = self->saddr = 0;
  164. self->dlsap_sel = self->slsap_sel = 0;
  165. memset(&self->settings, 0, sizeof(struct ircomm_params));
  166. }
  167. /*
  168.  * Function ircomm_tty_ias_register (self)
  169.  *
  170.  *    Register with LM-IAS depending on which service type we are
  171.  *
  172.  */
  173. static void ircomm_tty_ias_register(struct ircomm_tty_cb *self)
  174. {
  175. __u8 oct_seq[6];
  176. __u16 hints;
  177. IRDA_DEBUG(0, __FUNCTION__ "()n");
  178. ASSERT(self != NULL, return;);
  179. ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
  180. if (self->service_type & IRCOMM_3_WIRE_RAW) {
  181. hints = irlmp_service_to_hint(S_PRINTER);
  182. hints |= irlmp_service_to_hint(S_COMM);
  183. /* Register IrLPT with LM-IAS */
  184. self->obj = irias_new_object("IrLPT", IAS_IRLPT_ID);
  185. irias_add_integer_attrib(self->obj, "IrDA:IrLMP:LsapSel", 
  186.  self->slsap_sel, IAS_KERNEL_ATTR);
  187. irias_insert_object(self->obj);
  188. } else {
  189. hints = irlmp_service_to_hint(S_COMM);
  190. /* Register IrCOMM with LM-IAS */
  191. self->obj = irias_new_object("IrDA:IrCOMM", IAS_IRCOMM_ID);
  192. irias_add_integer_attrib(self->obj, "IrDA:TinyTP:LsapSel", 
  193.  self->slsap_sel, IAS_KERNEL_ATTR);
  194. /* Code the parameters into the buffer */
  195. irda_param_pack(oct_seq, "bbbbbb", 
  196. IRCOMM_SERVICE_TYPE, 1, self->service_type,
  197. IRCOMM_PORT_TYPE,    1, IRCOMM_SERIAL);
  198. /* Register parameters with LM-IAS */
  199. irias_add_octseq_attrib(self->obj, "Parameters", oct_seq, 6,
  200. IAS_KERNEL_ATTR);
  201. irias_insert_object(self->obj);
  202. }
  203. self->skey = irlmp_register_service(hints);
  204. self->ckey = irlmp_register_client(
  205. hints, ircomm_tty_discovery_indication, NULL, (void *) self);
  206. }
  207. /*
  208.  * Function ircomm_send_initial_parameters (self)
  209.  *
  210.  *    Send initial parameters to the remote IrCOMM device. These parameters
  211.  *    must be sent before any data.
  212.  */
  213. int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self)
  214. {
  215. ASSERT(self != NULL, return -1;);
  216. ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
  217. if (self->service_type & IRCOMM_3_WIRE_RAW) 
  218. return 0;
  219. /* 
  220.  * Set default values, but only if the application for some reason 
  221.  * haven't set them already
  222.  */
  223. IRDA_DEBUG(2, __FUNCTION__ "(), data-rate = %dn", 
  224.    self->settings.data_rate);
  225. if (!self->settings.data_rate)
  226. self->settings.data_rate = 9600;
  227. IRDA_DEBUG(2, __FUNCTION__ "(), data-format = %dn", 
  228.    self->settings.data_format);
  229. if (!self->settings.data_format)
  230. self->settings.data_format = IRCOMM_WSIZE_8;  /* 8N1 */
  231. IRDA_DEBUG(2, __FUNCTION__ "(), flow-control = %dn", 
  232.    self->settings.flow_control);
  233. /*self->settings.flow_control = IRCOMM_RTS_CTS_IN|IRCOMM_RTS_CTS_OUT;*/
  234. /* Do not set delta values for the initial parameters */
  235. self->settings.dte = IRCOMM_DTR | IRCOMM_RTS;
  236. /* Only send service type parameter when we are the client */
  237. if (self->client)
  238. ircomm_param_request(self, IRCOMM_SERVICE_TYPE, FALSE);
  239. ircomm_param_request(self, IRCOMM_DATA_RATE, FALSE);
  240. ircomm_param_request(self, IRCOMM_DATA_FORMAT, FALSE);
  241. /* For a 3 wire service, we just flush the last parameter and return */
  242. if (self->settings.service_type == IRCOMM_3_WIRE) {
  243. ircomm_param_request(self, IRCOMM_FLOW_CONTROL, TRUE);
  244. return 0;
  245. }
  246. /* Only 9-wire service types continue here */
  247. ircomm_param_request(self, IRCOMM_FLOW_CONTROL, FALSE);
  248. #if 0
  249. ircomm_param_request(self, IRCOMM_XON_XOFF, FALSE);
  250. ircomm_param_request(self, IRCOMM_ENQ_ACK, FALSE);
  251. #endif
  252. /* Notify peer that we are ready to receive data */
  253. ircomm_param_request(self, IRCOMM_DTE, TRUE);
  254. return 0;
  255. }
  256. /*
  257.  * Function ircomm_tty_discovery_indication (discovery)
  258.  *
  259.  *    Remote device is discovered, try query the remote IAS to see which
  260.  *    device it is, and which services it has.
  261.  *
  262.  */
  263. static void ircomm_tty_discovery_indication(discovery_t *discovery,
  264.     void *priv)
  265. {
  266. struct ircomm_tty_cb *self;
  267. struct ircomm_tty_info info;
  268. IRDA_DEBUG(2, __FUNCTION__"()n");
  269. info.daddr = discovery->daddr;
  270. info.saddr = discovery->saddr;
  271. self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty);
  272. while (self != NULL) {
  273. ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
  274. ircomm_tty_do_event(self, IRCOMM_TTY_DISCOVERY_INDICATION, 
  275.     NULL, &info);
  276. self = (struct ircomm_tty_cb *) hashbin_get_next(ircomm_tty);
  277. }
  278. }
  279. /*
  280.  * Function ircomm_tty_disconnect_indication (instance, sap, reason, skb)
  281.  *
  282.  *    Link disconnected
  283.  *
  284.  */
  285. void ircomm_tty_disconnect_indication(void *instance, void *sap, 
  286.       LM_REASON reason,
  287.       struct sk_buff *skb)
  288. {
  289. struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
  290. IRDA_DEBUG(2, __FUNCTION__ "()n");
  291. ASSERT(self != NULL, return;);
  292. ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
  293. if (!self->tty)
  294. return;
  295. /* This will stop control data transfers */
  296. self->flow = FLOW_STOP;
  297. /* Stop data transfers */
  298. self->tty->hw_stopped = 1;
  299. ircomm_tty_do_event(self, IRCOMM_TTY_DISCONNECT_INDICATION, NULL, 
  300.     NULL);
  301. }
  302. /*
  303.  * Function ircomm_tty_getvalue_confirm (result, obj_id, value, priv)
  304.  *
  305.  *    Got result from the IAS query we make
  306.  *
  307.  */
  308. static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id, 
  309. struct ias_value *value, 
  310. void *priv)
  311. {
  312. struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) priv;
  313. IRDA_DEBUG(2, __FUNCTION__"()n");
  314. ASSERT(self != NULL, return;);
  315. ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
  316. /* We probably don't need to make any more queries */
  317. iriap_close(self->iriap);
  318. self->iriap = NULL;
  319. /* Check if request succeeded */
  320. if (result != IAS_SUCCESS) {
  321. IRDA_DEBUG(4, __FUNCTION__ "(), got NULL value!n");
  322. return;
  323. }
  324. switch (value->type) {
  325.   case IAS_OCT_SEQ:
  326. IRDA_DEBUG(2, __FUNCTION__"(), got octet sequencen");
  327. irda_param_extract_all(self, value->t.oct_seq, value->len,
  328.        &ircomm_param_info);
  329. ircomm_tty_do_event(self, IRCOMM_TTY_GOT_PARAMETERS, NULL, 
  330.     NULL);
  331. break;
  332. case IAS_INTEGER:
  333. /* Got LSAP selector */
  334. IRDA_DEBUG(2, __FUNCTION__"(), got lsapsel = %dn", 
  335.    value->t.integer);
  336. if (value->t.integer == -1) {
  337. IRDA_DEBUG(0, __FUNCTION__"(), invalid value!n");
  338. } else
  339. self->dlsap_sel = value->t.integer;
  340. ircomm_tty_do_event(self, IRCOMM_TTY_GOT_LSAPSEL, NULL, NULL);
  341. break;
  342. case IAS_MISSING:
  343. IRDA_DEBUG(0, __FUNCTION__"(), got IAS_MISSINGn");
  344. break;
  345. default:
  346. IRDA_DEBUG(0, __FUNCTION__"(), got unknown type!n");
  347. break;
  348. }
  349. irias_delete_value(value);
  350. }
  351. /*
  352.  * Function ircomm_tty_connect_confirm (instance, sap, qos, max_sdu_size, skb)
  353.  *
  354.  *    Connection confirmed
  355.  *
  356.  */
  357. void ircomm_tty_connect_confirm(void *instance, void *sap, 
  358. struct qos_info *qos, 
  359. __u32 max_data_size, 
  360. __u8 max_header_size, 
  361. struct sk_buff *skb)
  362. {
  363. struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
  364. IRDA_DEBUG(2, __FUNCTION__ "()n");
  365. ASSERT(self != NULL, return;);
  366. ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
  367. self->client = TRUE;
  368. self->max_data_size = max_data_size;
  369. self->max_header_size = max_header_size;
  370. self->flow = FLOW_START;
  371. ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_CONFIRM, NULL, NULL);
  372. dev_kfree_skb(skb);
  373. }
  374. /*
  375.  * Function ircomm_tty_connect_indication (instance, sap, qos, max_sdu_size, 
  376.  *                                         skb)
  377.  *
  378.  *    we are discovered and being requested to connect by remote device !
  379.  *
  380.  */
  381. void ircomm_tty_connect_indication(void *instance, void *sap, 
  382.    struct qos_info *qos, 
  383.    __u32 max_data_size,
  384.    __u8 max_header_size, 
  385.    struct sk_buff *skb)
  386. {
  387. struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
  388. int clen;
  389. IRDA_DEBUG(2, __FUNCTION__ "()n");
  390. ASSERT(self != NULL, return;);
  391. ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
  392. self->client = FALSE;
  393. self->max_data_size = max_data_size;
  394. self->max_header_size = max_header_size;
  395. self->flow = FLOW_START;
  396. clen = skb->data[0];
  397. if (clen)
  398. irda_param_extract_all(self, skb->data+1, 
  399.        IRDA_MIN(skb->len, clen), 
  400.        &ircomm_param_info);
  401. ircomm_tty_do_event(self, IRCOMM_TTY_CONNECT_INDICATION, NULL, NULL);
  402. dev_kfree_skb(skb);
  403. }
  404. /*
  405.  * Function ircomm_tty_link_established (self)
  406.  *
  407.  *    Called when the IrCOMM link is established
  408.  *
  409.  */
  410. void ircomm_tty_link_established(struct ircomm_tty_cb *self)
  411. {
  412. IRDA_DEBUG(2, __FUNCTION__ "()n");
  413. ASSERT(self != NULL, return;);
  414. ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
  415. if (!self->tty)
  416. return;
  417. del_timer(&self->watchdog_timer);
  418. /* 
  419.  * IrCOMM link is now up, and if we are not using hardware
  420.  * flow-control, then declare the hardware as running. Otherwise we
  421.  * will have to wait for the peer device (DCE) to raise the CTS
  422.  * line.  
  423.  */
  424. if ((self->flags & ASYNC_CTS_FLOW) && ((self->settings.dce & IRCOMM_CTS) == 0)) {
  425. IRDA_DEBUG(0, __FUNCTION__ "(), waiting for CTS ...n");
  426. return;
  427. } else {
  428. IRDA_DEBUG(2, __FUNCTION__ "(), starting hardware!n");
  429. self->tty->hw_stopped = 0;
  430. /* Wake up processes blocked on open */
  431. wake_up_interruptible(&self->open_wait);
  432. }
  433. queue_task(&self->tqueue, &tq_immediate);
  434. mark_bh(IMMEDIATE_BH);
  435. }
  436. /*
  437.  * Function irlan_start_watchdog_timer (self, timeout)
  438.  *
  439.  *    Start the watchdog timer. This timer is used to make sure that any 
  440.  *    connection attempt is successful, and if not, we will retry after 
  441.  *    the timeout
  442.  */
  443. void ircomm_tty_start_watchdog_timer(struct ircomm_tty_cb *self, int timeout)
  444. {
  445. ASSERT(self != NULL, return;);
  446. ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
  447. irda_start_timer(&self->watchdog_timer, timeout, (void *) self,
  448.  ircomm_tty_watchdog_timer_expired);
  449. }
  450. /*
  451.  * Function ircomm_tty_watchdog_timer_expired (data)
  452.  *
  453.  *    Called when the connect procedure have taken to much time.
  454.  *
  455.  */
  456. void ircomm_tty_watchdog_timer_expired(void *data)
  457. {
  458. struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) data;
  459. IRDA_DEBUG(2, __FUNCTION__ "()n");
  460. ASSERT(self != NULL, return;);
  461. ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
  462. ircomm_tty_do_event(self, IRCOMM_TTY_WD_TIMER_EXPIRED, NULL, NULL);
  463. }
  464. /*
  465.  * Function ircomm_tty_state_idle (self, event, skb, info)
  466.  *
  467.  *    Just hanging around
  468.  *
  469.  */
  470. static int ircomm_tty_state_idle(struct ircomm_tty_cb *self, 
  471.  IRCOMM_TTY_EVENT event, 
  472.  struct sk_buff *skb, 
  473.  struct ircomm_tty_info *info)
  474. {
  475. int ret = 0;
  476. IRDA_DEBUG(2, __FUNCTION__": state=%s, event=%sn",
  477.    ircomm_tty_state[self->state], ircomm_tty_event[event]);
  478. switch (event) {
  479. case IRCOMM_TTY_ATTACH_CABLE:
  480. /* Try to discover any remote devices */
  481. ircomm_tty_start_watchdog_timer(self, 3*HZ);
  482. ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
  483. irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
  484. break;
  485. case IRCOMM_TTY_DISCOVERY_INDICATION:
  486. self->daddr = info->daddr;
  487. self->saddr = info->saddr;
  488. if (self->iriap) {
  489. WARNING(__FUNCTION__ 
  490. "(), busy with a previous queryn");
  491. return -EBUSY;
  492. }
  493. self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
  494.  ircomm_tty_getvalue_confirm);
  495. iriap_getvaluebyclass_request(self->iriap,
  496.       self->saddr, self->daddr,
  497.       "IrDA:IrCOMM", "Parameters");
  498. ircomm_tty_start_watchdog_timer(self, 3*HZ);
  499. ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_PARAMETERS);
  500. break;
  501. case IRCOMM_TTY_CONNECT_INDICATION:
  502. del_timer(&self->watchdog_timer);
  503. /* Accept connection */
  504. ircomm_connect_response(self->ircomm, NULL);
  505. ircomm_tty_next_state(self, IRCOMM_TTY_READY);
  506. break;
  507. case IRCOMM_TTY_WD_TIMER_EXPIRED:
  508. /* Just stay idle */
  509. break;
  510. case IRCOMM_TTY_DETACH_CABLE:
  511. ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
  512. break;
  513. default:
  514. IRDA_DEBUG(2, __FUNCTION__"(), unknown event: %sn",
  515.    ircomm_tty_event[event]);
  516. return -EINVAL;
  517. }
  518. return ret;
  519. }
  520. /*
  521.  * Function ircomm_tty_state_search (self, event, skb, info)
  522.  *
  523.  *    Trying to discover an IrCOMM device
  524.  *
  525.  */
  526. static int ircomm_tty_state_search(struct ircomm_tty_cb *self, 
  527.    IRCOMM_TTY_EVENT event, 
  528.    struct sk_buff *skb, 
  529.    struct ircomm_tty_info *info)
  530. {
  531. int ret = 0;
  532. IRDA_DEBUG(2, __FUNCTION__": state=%s, event=%sn",
  533.    ircomm_tty_state[self->state], ircomm_tty_event[event]);
  534. switch (event) {
  535. case IRCOMM_TTY_DISCOVERY_INDICATION:
  536. self->daddr = info->daddr;
  537. self->saddr = info->saddr;
  538. if (self->iriap) {
  539. WARNING(__FUNCTION__ 
  540. "(), busy with a previous queryn");
  541. return -EBUSY;
  542. }
  543. self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
  544.  ircomm_tty_getvalue_confirm);
  545. if (self->service_type == IRCOMM_3_WIRE_RAW) {
  546. iriap_getvaluebyclass_request(self->iriap, self->saddr,
  547.       self->daddr, "IrLPT", 
  548.       "IrDA:IrLMP:LsapSel");
  549. ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_LSAP_SEL);
  550. } else {
  551. iriap_getvaluebyclass_request(self->iriap, self->saddr,
  552.       self->daddr, 
  553.       "IrDA:IrCOMM", 
  554.       "Parameters");
  555. ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_PARAMETERS);
  556. }
  557. ircomm_tty_start_watchdog_timer(self, 3*HZ);
  558. break;
  559. case IRCOMM_TTY_CONNECT_INDICATION:
  560. del_timer(&self->watchdog_timer);
  561. /* Accept connection */
  562. ircomm_connect_response(self->ircomm, NULL);
  563. ircomm_tty_next_state(self, IRCOMM_TTY_READY);
  564. break;
  565. case IRCOMM_TTY_WD_TIMER_EXPIRED:
  566. #if 1
  567. /* Give up */
  568. #else
  569. /* Try to discover any remote devices */
  570. ircomm_tty_start_watchdog_timer(self, 3*HZ);
  571. irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
  572. #endif
  573. break;
  574. case IRCOMM_TTY_DETACH_CABLE:
  575. ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
  576. break;
  577. default:
  578. IRDA_DEBUG(2, __FUNCTION__"(), unknown event: %sn",
  579.    ircomm_tty_event[event]);
  580. return -EINVAL;
  581. }
  582. return ret;
  583. }
  584. /*
  585.  * Function ircomm_tty_state_query (self, event, skb, info)
  586.  *
  587.  *    Querying the remote LM-IAS for IrCOMM parameters
  588.  *
  589.  */
  590. static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self, 
  591.      IRCOMM_TTY_EVENT event, 
  592.      struct sk_buff *skb, 
  593.      struct ircomm_tty_info *info)
  594. {
  595. int ret = 0;
  596. IRDA_DEBUG(2, __FUNCTION__": state=%s, event=%sn",
  597.    ircomm_tty_state[self->state], ircomm_tty_event[event]);
  598. switch (event) {
  599. case IRCOMM_TTY_GOT_PARAMETERS:
  600. if (self->iriap) {
  601. WARNING(__FUNCTION__ 
  602. "(), busy with a previous queryn");
  603. return -EBUSY;
  604. }
  605. self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
  606.  ircomm_tty_getvalue_confirm);
  607. iriap_getvaluebyclass_request(self->iriap, self->saddr, 
  608.       self->daddr, "IrDA:IrCOMM", 
  609.       "IrDA:TinyTP:LsapSel");
  610. ircomm_tty_start_watchdog_timer(self, 3*HZ);
  611. ircomm_tty_next_state(self, IRCOMM_TTY_QUERY_LSAP_SEL);
  612. break;
  613. case IRCOMM_TTY_WD_TIMER_EXPIRED:
  614. /* Go back to search mode */
  615. ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
  616. ircomm_tty_start_watchdog_timer(self, 3*HZ); 
  617. break;
  618. case IRCOMM_TTY_CONNECT_INDICATION:
  619. del_timer(&self->watchdog_timer);
  620. /* Accept connection */
  621. ircomm_connect_response(self->ircomm, NULL);
  622. ircomm_tty_next_state(self, IRCOMM_TTY_READY);
  623. break;
  624. case IRCOMM_TTY_DETACH_CABLE:
  625. ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
  626. break;
  627. default:
  628. IRDA_DEBUG(2, __FUNCTION__"(), unknown event: %sn",
  629.    ircomm_tty_event[event]);
  630. return -EINVAL;
  631. }
  632. return ret;
  633. }
  634. /*
  635.  * Function ircomm_tty_state_query_lsap_sel (self, event, skb, info)
  636.  *
  637.  *    Query remote LM-IAS for the LSAP selector which we can connect to
  638.  *
  639.  */
  640. static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self, 
  641.    IRCOMM_TTY_EVENT event, 
  642.    struct sk_buff *skb, 
  643.    struct ircomm_tty_info *info)
  644. {
  645. int ret = 0;
  646. IRDA_DEBUG(2, __FUNCTION__": state=%s, event=%sn",
  647.    ircomm_tty_state[self->state], ircomm_tty_event[event]);
  648. switch (event) {
  649. case IRCOMM_TTY_GOT_LSAPSEL:
  650. /* Connect to remote device */
  651. ret = ircomm_connect_request(self->ircomm, self->dlsap_sel,
  652.      self->saddr, self->daddr, 
  653.      NULL, self->service_type);
  654. ircomm_tty_start_watchdog_timer(self, 3*HZ);
  655. ircomm_tty_next_state(self, IRCOMM_TTY_SETUP);
  656. break;
  657. case IRCOMM_TTY_WD_TIMER_EXPIRED:
  658. /* Go back to search mode */
  659. ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
  660. ircomm_tty_start_watchdog_timer(self, 3*HZ);
  661. break;
  662. case IRCOMM_TTY_CONNECT_INDICATION:
  663. del_timer(&self->watchdog_timer);
  664. /* Accept connection */
  665. ircomm_connect_response(self->ircomm, NULL);
  666. ircomm_tty_next_state(self, IRCOMM_TTY_READY);
  667. break;
  668. case IRCOMM_TTY_DETACH_CABLE:
  669. ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
  670. break;
  671. default:
  672. IRDA_DEBUG(2, __FUNCTION__"(), unknown event: %sn",
  673.    ircomm_tty_event[event]);
  674. return -EINVAL;
  675. }
  676. return ret;
  677. }
  678. /*
  679.  * Function ircomm_tty_state_setup (self, event, skb, info)
  680.  *
  681.  *    Trying to connect
  682.  *
  683.  */
  684. static int ircomm_tty_state_setup(struct ircomm_tty_cb *self, 
  685.   IRCOMM_TTY_EVENT event, 
  686.   struct sk_buff *skb, 
  687.   struct ircomm_tty_info *info)
  688. {
  689. int ret = 0;
  690. IRDA_DEBUG(2, __FUNCTION__": state=%s, event=%sn",
  691.    ircomm_tty_state[self->state], ircomm_tty_event[event]);
  692. switch (event) {
  693. case IRCOMM_TTY_CONNECT_CONFIRM:
  694. del_timer(&self->watchdog_timer);
  695. ircomm_tty_next_state(self, IRCOMM_TTY_READY);
  696. /* 
  697.  * Send initial parameters. This will also send out queued
  698.  * parameters waiting for the connection to come up 
  699.  */
  700. ircomm_tty_send_initial_parameters(self);
  701. ircomm_tty_link_established(self);
  702. break;
  703. case IRCOMM_TTY_CONNECT_INDICATION:
  704. del_timer(&self->watchdog_timer);
  705. /* Accept connection */
  706. ircomm_connect_response(self->ircomm, NULL);
  707. ircomm_tty_next_state(self, IRCOMM_TTY_READY);
  708. break;
  709. case IRCOMM_TTY_WD_TIMER_EXPIRED:
  710. /* Go back to search mode */
  711. ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
  712. ircomm_tty_start_watchdog_timer(self, 3*HZ);
  713. break;
  714. case IRCOMM_TTY_DETACH_CABLE:
  715. /* ircomm_disconnect_request(self->ircomm, NULL); */
  716. ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
  717. break;
  718. default:
  719. IRDA_DEBUG(2, __FUNCTION__"(), unknown event: %sn",
  720.    ircomm_tty_event[event]);
  721. return -EINVAL;
  722. }
  723. return ret;
  724. }
  725. /*
  726.  * Function ircomm_tty_state_ready (self, event, skb, info)
  727.  *
  728.  *    IrCOMM is now connected
  729.  *
  730.  */
  731. static int ircomm_tty_state_ready(struct ircomm_tty_cb *self, 
  732.   IRCOMM_TTY_EVENT event, 
  733.   struct sk_buff *skb, 
  734.   struct ircomm_tty_info *info)
  735. {
  736. int ret = 0;
  737. switch (event) {
  738. case IRCOMM_TTY_DATA_REQUEST:
  739. ret = ircomm_data_request(self->ircomm, skb);
  740. break;
  741. case IRCOMM_TTY_DETACH_CABLE:
  742. ircomm_disconnect_request(self->ircomm, NULL);
  743. ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
  744. break;
  745. case IRCOMM_TTY_DISCONNECT_INDICATION:
  746. ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
  747. ircomm_tty_start_watchdog_timer(self, 3*HZ);
  748. if (self->flags & ASYNC_CHECK_CD) {
  749. /* Drop carrier */
  750. self->settings.dce = IRCOMM_DELTA_CD;
  751. ircomm_tty_check_modem_status(self);
  752. } else {
  753. IRDA_DEBUG(0, __FUNCTION__ "(), hanging up!n");
  754. if (self->tty)
  755. tty_hangup(self->tty);
  756. }
  757. break;
  758. default:
  759. IRDA_DEBUG(2, __FUNCTION__"(), unknown event: %sn",
  760.    ircomm_tty_event[event]);
  761. return -EINVAL;
  762. }
  763. return ret;
  764. }
  765. /*
  766.  * Function ircomm_tty_do_event (self, event, skb)
  767.  *
  768.  *    Process event
  769.  *
  770.  */
  771. int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
  772. struct sk_buff *skb, struct ircomm_tty_info *info) 
  773. {
  774. ASSERT(self != NULL, return -1;);
  775. ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
  776. IRDA_DEBUG(2, __FUNCTION__": state=%s, event=%sn",
  777.    ircomm_tty_state[self->state], ircomm_tty_event[event]);
  778. return (*state[self->state])(self, event, skb, info);
  779. }
  780. /*
  781.  * Function ircomm_tty_next_state (self, state)
  782.  *
  783.  *    Switch state
  784.  *
  785.  */
  786. void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_STATE state)
  787. {
  788. ASSERT(self != NULL, return;);
  789. ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
  790. self->state = state;
  791. IRDA_DEBUG(2, __FUNCTION__": next state=%s, service type=%dn", 
  792.    ircomm_tty_state[self->state], self->service_type);
  793. }