ircomm_tty_attach.c 28 KB

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