ircomm_tty_attach.c 27 KB

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