ircomm_tty_attach.c 27 KB

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