ircomm_tty_attach.c 28 KB

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