ircomm_tty_attach.c 27 KB

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