ircomm_param.c 14 KB

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