ircomm_tty_attach.c 27 KB

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