ircomm_param.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. /*********************************************************************
  2. *
  3. * Filename: ircomm_param.c
  4. * Version: 1.0
  5. * Description: Parameter handling for the IrCOMM protocol
  6. * Status: Experimental.
  7. * Author: Dag Brattli <dagb@cs.uit.no>
  8. * Created at: Mon Jun 7 10:25:11 1999
  9. * Modified at: Sun Jan 30 14:32:03 2000
  10. * Modified by: Dag Brattli <dagb@cs.uit.no>
  11. *
  12. * Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
  13. *
  14. * This program is free software; you can redistribute it and/or
  15. * modify it under the terms of the GNU General Public License as
  16. * published by the Free Software Foundation; either version 2 of
  17. * the License, or (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software
  26. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  27. * MA 02111-1307 USA
  28. *
  29. ********************************************************************/
  30. #include <linux/workqueue.h>
  31. #include <linux/interrupt.h>
  32. #include <net/irda/irda.h>
  33. #include <net/irda/parameters.h>
  34. #include <net/irda/ircomm_core.h>
  35. #include <net/irda/ircomm_tty_attach.h>
  36. #include <net/irda/ircomm_tty.h>
  37. #include <net/irda/ircomm_param.h>
  38. static int ircomm_param_service_type(void *instance, irda_param_t *param,
  39. int get);
  40. static int ircomm_param_port_type(void *instance, irda_param_t *param,
  41. int get);
  42. static int ircomm_param_port_name(void *instance, irda_param_t *param,
  43. int get);
  44. static int ircomm_param_service_type(void *instance, irda_param_t *param,
  45. int get);
  46. static int ircomm_param_data_rate(void *instance, irda_param_t *param,
  47. int get);
  48. static int ircomm_param_data_format(void *instance, irda_param_t *param,
  49. int get);
  50. static int ircomm_param_flow_control(void *instance, irda_param_t *param,
  51. int get);
  52. static int ircomm_param_xon_xoff(void *instance, irda_param_t *param, int get);
  53. static int ircomm_param_enq_ack(void *instance, irda_param_t *param, int get);
  54. static int ircomm_param_line_status(void *instance, irda_param_t *param,
  55. int get);
  56. static int ircomm_param_dte(void *instance, irda_param_t *param, int get);
  57. static int ircomm_param_dce(void *instance, irda_param_t *param, int get);
  58. static int ircomm_param_poll(void *instance, irda_param_t *param, int get);
  59. static pi_minor_info_t pi_minor_call_table_common[] = {
  60. { ircomm_param_service_type, PV_INT_8_BITS },
  61. { ircomm_param_port_type, PV_INT_8_BITS },
  62. { ircomm_param_port_name, PV_STRING }
  63. };
  64. static pi_minor_info_t pi_minor_call_table_non_raw[] = {
  65. { ircomm_param_data_rate, PV_INT_32_BITS | PV_BIG_ENDIAN },
  66. { ircomm_param_data_format, PV_INT_8_BITS },
  67. { ircomm_param_flow_control, PV_INT_8_BITS },
  68. { ircomm_param_xon_xoff, PV_INT_16_BITS },
  69. { ircomm_param_enq_ack, PV_INT_16_BITS },
  70. { ircomm_param_line_status, PV_INT_8_BITS }
  71. };
  72. static pi_minor_info_t pi_minor_call_table_9_wire[] = {
  73. { ircomm_param_dte, PV_INT_8_BITS },
  74. { ircomm_param_dce, PV_INT_8_BITS },
  75. { ircomm_param_poll, PV_NO_VALUE },
  76. };
  77. static pi_major_info_t pi_major_call_table[] = {
  78. { pi_minor_call_table_common, 3 },
  79. { pi_minor_call_table_non_raw, 6 },
  80. { pi_minor_call_table_9_wire, 3 }
  81. /* { pi_minor_call_table_centronics } */
  82. };
  83. pi_param_info_t ircomm_param_info = { pi_major_call_table, 3, 0x0f, 4 };
  84. /*
  85. * Function ircomm_param_request (self, pi, flush)
  86. *
  87. * Queue a parameter for the control channel
  88. *
  89. */
  90. int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
  91. {
  92. struct tty_struct *tty;
  93. unsigned long flags;
  94. struct sk_buff *skb;
  95. int count;
  96. IRDA_DEBUG(2, "%s()\n", __func__ );
  97. IRDA_ASSERT(self != NULL, return -1;);
  98. IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
  99. tty = self->tty;
  100. if (!tty)
  101. return 0;
  102. /* Make sure we don't send parameters for raw mode */
  103. if (self->service_type == IRCOMM_3_WIRE_RAW)
  104. return 0;
  105. spin_lock_irqsave(&self->spinlock, flags);
  106. skb = self->ctrl_skb;
  107. if (!skb) {
  108. skb = alloc_skb(256, GFP_ATOMIC);
  109. if (!skb) {
  110. spin_unlock_irqrestore(&self->spinlock, flags);
  111. return -ENOMEM;
  112. }
  113. skb_reserve(skb, self->max_header_size);
  114. self->ctrl_skb = skb;
  115. }
  116. /*
  117. * Inserting is a little bit tricky since we don't know how much
  118. * room we will need. But this should hopefully work OK
  119. */
  120. count = irda_param_insert(self, pi, skb_tail_pointer(skb),
  121. skb_tailroom(skb), &ircomm_param_info);
  122. if (count < 0) {
  123. IRDA_WARNING("%s(), no room for parameter!\n", __func__);
  124. spin_unlock_irqrestore(&self->spinlock, flags);
  125. return -1;
  126. }
  127. skb_put(skb, count);
  128. spin_unlock_irqrestore(&self->spinlock, flags);
  129. IRDA_DEBUG(2, "%s(), skb->len=%d\n", __func__ , skb->len);
  130. if (flush) {
  131. /* ircomm_tty_do_softint will take care of the rest */
  132. schedule_work(&self->tqueue);
  133. }
  134. return count;
  135. }
  136. /*
  137. * Function ircomm_param_service_type (self, buf, len)
  138. *
  139. * Handle service type, this function will both be called after the LM-IAS
  140. * query and then the remote device sends its initial parameters
  141. *
  142. */
  143. static int ircomm_param_service_type(void *instance, irda_param_t *param,
  144. int get)
  145. {
  146. struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
  147. __u8 service_type = (__u8) param->pv.i;
  148. IRDA_ASSERT(self != NULL, return -1;);
  149. IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
  150. if (get) {
  151. param->pv.i = self->settings.service_type;
  152. return 0;
  153. }
  154. /* Find all common service types */
  155. service_type &= self->service_type;
  156. if (!service_type) {
  157. IRDA_DEBUG(2,
  158. "%s(), No common service type to use!\n", __func__ );
  159. return -1;
  160. }
  161. IRDA_DEBUG(0, "%s(), services in common=%02x\n", __func__ ,
  162. service_type);
  163. /*
  164. * Now choose a preferred service type of those available
  165. */
  166. if (service_type & IRCOMM_CENTRONICS)
  167. self->settings.service_type = IRCOMM_CENTRONICS;
  168. else if (service_type & IRCOMM_9_WIRE)
  169. self->settings.service_type = IRCOMM_9_WIRE;
  170. else if (service_type & IRCOMM_3_WIRE)
  171. self->settings.service_type = IRCOMM_3_WIRE;
  172. else if (service_type & IRCOMM_3_WIRE_RAW)
  173. self->settings.service_type = IRCOMM_3_WIRE_RAW;
  174. IRDA_DEBUG(0, "%s(), resulting service type=0x%02x\n", __func__ ,
  175. self->settings.service_type);
  176. /*
  177. * Now the line is ready for some communication. Check if we are a
  178. * server, and send over some initial parameters.
  179. * Client do it in ircomm_tty_state_setup().
  180. * Note : we may get called from ircomm_tty_getvalue_confirm(),
  181. * therefore before we even have open any socket. And self->client
  182. * is initialised to TRUE only later. So, we check if the link is
  183. * really initialised. - Jean II
  184. */
  185. if ((self->max_header_size != IRCOMM_TTY_HDR_UNINITIALISED) &&
  186. (!self->client) &&
  187. (self->settings.service_type != IRCOMM_3_WIRE_RAW))
  188. {
  189. /* Init connection */
  190. ircomm_tty_send_initial_parameters(self);
  191. ircomm_tty_link_established(self);
  192. }
  193. return 0;
  194. }
  195. /*
  196. * Function ircomm_param_port_type (self, param)
  197. *
  198. * The port type parameter tells if the devices are serial or parallel.
  199. * Since we only advertise serial service, this parameter should only
  200. * be equal to IRCOMM_SERIAL.
  201. */
  202. static int ircomm_param_port_type(void *instance, irda_param_t *param, int get)
  203. {
  204. struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
  205. IRDA_ASSERT(self != NULL, return -1;);
  206. IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
  207. if (get)
  208. param->pv.i = IRCOMM_SERIAL;
  209. else {
  210. self->settings.port_type = (__u8) param->pv.i;
  211. IRDA_DEBUG(0, "%s(), port type=%d\n", __func__ ,
  212. self->settings.port_type);
  213. }
  214. return 0;
  215. }
  216. /*
  217. * Function ircomm_param_port_name (self, param)
  218. *
  219. * Exchange port name
  220. *
  221. */
  222. static int ircomm_param_port_name(void *instance, irda_param_t *param, int get)
  223. {
  224. struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
  225. IRDA_ASSERT(self != NULL, return -1;);
  226. IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
  227. if (get) {
  228. IRDA_DEBUG(0, "%s(), not imp!\n", __func__ );
  229. } else {
  230. IRDA_DEBUG(0, "%s(), port-name=%s\n", __func__ , param->pv.c);
  231. strncpy(self->settings.port_name, param->pv.c, 32);
  232. }
  233. return 0;
  234. }
  235. /*
  236. * Function ircomm_param_data_rate (self, param)
  237. *
  238. * Exchange data rate to be used in this settings
  239. *
  240. */
  241. static int ircomm_param_data_rate(void *instance, irda_param_t *param, int get)
  242. {
  243. struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
  244. IRDA_ASSERT(self != NULL, return -1;);
  245. IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
  246. if (get)
  247. param->pv.i = self->settings.data_rate;
  248. else
  249. self->settings.data_rate = param->pv.i;
  250. IRDA_DEBUG(2, "%s(), data rate = %d\n", __func__ , param->pv.i);
  251. return 0;
  252. }
  253. /*
  254. * Function ircomm_param_data_format (self, param)
  255. *
  256. * Exchange data format to be used in this settings
  257. *
  258. */
  259. static int ircomm_param_data_format(void *instance, irda_param_t *param,
  260. int get)
  261. {
  262. struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
  263. IRDA_ASSERT(self != NULL, return -1;);
  264. IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
  265. if (get)
  266. param->pv.i = self->settings.data_format;
  267. else
  268. self->settings.data_format = (__u8) param->pv.i;
  269. return 0;
  270. }
  271. /*
  272. * Function ircomm_param_flow_control (self, param)
  273. *
  274. * Exchange flow control settings to be used in this settings
  275. *
  276. */
  277. static int ircomm_param_flow_control(void *instance, irda_param_t *param,
  278. int get)
  279. {
  280. struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
  281. IRDA_ASSERT(self != NULL, return -1;);
  282. IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
  283. if (get)
  284. param->pv.i = self->settings.flow_control;
  285. else
  286. self->settings.flow_control = (__u8) param->pv.i;
  287. IRDA_DEBUG(1, "%s(), flow control = 0x%02x\n", __func__ , (__u8) param->pv.i);
  288. return 0;
  289. }
  290. /*
  291. * Function ircomm_param_xon_xoff (self, param)
  292. *
  293. * Exchange XON/XOFF characters
  294. *
  295. */
  296. static int ircomm_param_xon_xoff(void *instance, irda_param_t *param, int get)
  297. {
  298. struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
  299. IRDA_ASSERT(self != NULL, return -1;);
  300. IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
  301. if (get) {
  302. param->pv.i = self->settings.xonxoff[0];
  303. param->pv.i |= self->settings.xonxoff[1] << 8;
  304. } else {
  305. self->settings.xonxoff[0] = (__u16) param->pv.i & 0xff;
  306. self->settings.xonxoff[1] = (__u16) param->pv.i >> 8;
  307. }
  308. IRDA_DEBUG(0, "%s(), XON/XOFF = 0x%02x,0x%02x\n", __func__ ,
  309. param->pv.i & 0xff, param->pv.i >> 8);
  310. return 0;
  311. }
  312. /*
  313. * Function ircomm_param_enq_ack (self, param)
  314. *
  315. * Exchange ENQ/ACK characters
  316. *
  317. */
  318. static int ircomm_param_enq_ack(void *instance, irda_param_t *param, int get)
  319. {
  320. struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
  321. IRDA_ASSERT(self != NULL, return -1;);
  322. IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
  323. if (get) {
  324. param->pv.i = self->settings.enqack[0];
  325. param->pv.i |= self->settings.enqack[1] << 8;
  326. } else {
  327. self->settings.enqack[0] = (__u16) param->pv.i & 0xff;
  328. self->settings.enqack[1] = (__u16) param->pv.i >> 8;
  329. }
  330. IRDA_DEBUG(0, "%s(), ENQ/ACK = 0x%02x,0x%02x\n", __func__ ,
  331. param->pv.i & 0xff, param->pv.i >> 8);
  332. return 0;
  333. }
  334. /*
  335. * Function ircomm_param_line_status (self, param)
  336. *
  337. *
  338. *
  339. */
  340. static int ircomm_param_line_status(void *instance, irda_param_t *param,
  341. int get)
  342. {
  343. IRDA_DEBUG(2, "%s(), not impl.\n", __func__ );
  344. return 0;
  345. }
  346. /*
  347. * Function ircomm_param_dte (instance, param)
  348. *
  349. * If we get here, there must be some sort of null-modem connection, and
  350. * we are probably working in server mode as well.
  351. */
  352. static int ircomm_param_dte(void *instance, irda_param_t *param, int get)
  353. {
  354. struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
  355. __u8 dte;
  356. IRDA_ASSERT(self != NULL, return -1;);
  357. IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
  358. if (get)
  359. param->pv.i = self->settings.dte;
  360. else {
  361. dte = (__u8) param->pv.i;
  362. self->settings.dce = 0;
  363. if (dte & IRCOMM_DELTA_DTR)
  364. self->settings.dce |= (IRCOMM_DELTA_DSR|
  365. IRCOMM_DELTA_RI |
  366. IRCOMM_DELTA_CD);
  367. if (dte & IRCOMM_DTR)
  368. self->settings.dce |= (IRCOMM_DSR|
  369. IRCOMM_RI |
  370. IRCOMM_CD);
  371. if (dte & IRCOMM_DELTA_RTS)
  372. self->settings.dce |= IRCOMM_DELTA_CTS;
  373. if (dte & IRCOMM_RTS)
  374. self->settings.dce |= IRCOMM_CTS;
  375. /* Take appropriate actions */
  376. ircomm_tty_check_modem_status(self);
  377. /* Null modem cable emulator */
  378. self->settings.null_modem = TRUE;
  379. }
  380. return 0;
  381. }
  382. /*
  383. * Function ircomm_param_dce (instance, param)
  384. *
  385. *
  386. *
  387. */
  388. static int ircomm_param_dce(void *instance, irda_param_t *param, int get)
  389. {
  390. struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
  391. __u8 dce;
  392. IRDA_DEBUG(1, "%s(), dce = 0x%02x\n", __func__ , (__u8) param->pv.i);
  393. dce = (__u8) param->pv.i;
  394. IRDA_ASSERT(self != NULL, return -1;);
  395. IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
  396. self->settings.dce = dce;
  397. /* Check if any of the settings have changed */
  398. if (dce & 0x0f) {
  399. if (dce & IRCOMM_DELTA_CTS) {
  400. IRDA_DEBUG(2, "%s(), CTS \n", __func__ );
  401. }
  402. }
  403. ircomm_tty_check_modem_status(self);
  404. return 0;
  405. }
  406. /*
  407. * Function ircomm_param_poll (instance, param)
  408. *
  409. * Called when the peer device is polling for the line settings
  410. *
  411. */
  412. static int ircomm_param_poll(void *instance, irda_param_t *param, int get)
  413. {
  414. struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
  415. IRDA_ASSERT(self != NULL, return -1;);
  416. IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
  417. /* Poll parameters are always of length 0 (just a signal) */
  418. if (!get) {
  419. /* Respond with DTE line settings */
  420. ircomm_param_request(self, IRCOMM_DTE, TRUE);
  421. }
  422. return 0;
  423. }