ircomm_tty_ioctl.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /*********************************************************************
  2. *
  3. * Filename: ircomm_tty_ioctl.c
  4. * Version:
  5. * Description:
  6. * Status: Experimental.
  7. * Author: Dag Brattli <dagb@cs.uit.no>
  8. * Created at: Thu Jun 10 14:39:09 1999
  9. * Modified at: Wed Jan 5 14:45:43 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/init.h>
  31. #include <linux/fs.h>
  32. #include <linux/sched.h>
  33. #include <linux/termios.h>
  34. #include <linux/tty.h>
  35. #include <linux/serial.h>
  36. #include <asm/uaccess.h>
  37. #include <net/irda/irda.h>
  38. #include <net/irda/irmod.h>
  39. #include <net/irda/ircomm_core.h>
  40. #include <net/irda/ircomm_param.h>
  41. #include <net/irda/ircomm_tty_attach.h>
  42. #include <net/irda/ircomm_tty.h>
  43. #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
  44. /*
  45. * Function ircomm_tty_change_speed (driver)
  46. *
  47. * Change speed of the driver. If the remote device is a DCE, then this
  48. * should make it change the speed of its serial port
  49. */
  50. static void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
  51. {
  52. unsigned cflag, cval;
  53. int baud;
  54. IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
  55. if (!self->tty || !self->tty->termios || !self->ircomm)
  56. return;
  57. cflag = self->tty->termios->c_cflag;
  58. /* byte size and parity */
  59. switch (cflag & CSIZE) {
  60. case CS5: cval = IRCOMM_WSIZE_5; break;
  61. case CS6: cval = IRCOMM_WSIZE_6; break;
  62. case CS7: cval = IRCOMM_WSIZE_7; break;
  63. case CS8: cval = IRCOMM_WSIZE_8; break;
  64. default: cval = IRCOMM_WSIZE_5; break;
  65. }
  66. if (cflag & CSTOPB)
  67. cval |= IRCOMM_2_STOP_BIT;
  68. if (cflag & PARENB)
  69. cval |= IRCOMM_PARITY_ENABLE;
  70. if (!(cflag & PARODD))
  71. cval |= IRCOMM_PARITY_EVEN;
  72. /* Determine divisor based on baud rate */
  73. baud = tty_get_baud_rate(self->tty);
  74. if (!baud)
  75. baud = 9600; /* B0 transition handled in rs_set_termios */
  76. self->settings.data_rate = baud;
  77. ircomm_param_request(self, IRCOMM_DATA_RATE, FALSE);
  78. /* CTS flow control flag and modem status interrupts */
  79. if (cflag & CRTSCTS) {
  80. self->flags |= ASYNC_CTS_FLOW;
  81. self->settings.flow_control |= IRCOMM_RTS_CTS_IN;
  82. /* This got me. Bummer. Jean II */
  83. if (self->service_type == IRCOMM_3_WIRE_RAW)
  84. IRDA_WARNING("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n", __FUNCTION__);
  85. } else {
  86. self->flags &= ~ASYNC_CTS_FLOW;
  87. self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN;
  88. }
  89. if (cflag & CLOCAL)
  90. self->flags &= ~ASYNC_CHECK_CD;
  91. else
  92. self->flags |= ASYNC_CHECK_CD;
  93. #if 0
  94. /*
  95. * Set up parity check flag
  96. */
  97. if (I_INPCK(self->tty))
  98. driver->read_status_mask |= LSR_FE | LSR_PE;
  99. if (I_BRKINT(driver->tty) || I_PARMRK(driver->tty))
  100. driver->read_status_mask |= LSR_BI;
  101. /*
  102. * Characters to ignore
  103. */
  104. driver->ignore_status_mask = 0;
  105. if (I_IGNPAR(driver->tty))
  106. driver->ignore_status_mask |= LSR_PE | LSR_FE;
  107. if (I_IGNBRK(self->tty)) {
  108. self->ignore_status_mask |= LSR_BI;
  109. /*
  110. * If we're ignore parity and break indicators, ignore
  111. * overruns too. (For real raw support).
  112. */
  113. if (I_IGNPAR(self->tty))
  114. self->ignore_status_mask |= LSR_OE;
  115. }
  116. #endif
  117. self->settings.data_format = cval;
  118. ircomm_param_request(self, IRCOMM_DATA_FORMAT, FALSE);
  119. ircomm_param_request(self, IRCOMM_FLOW_CONTROL, TRUE);
  120. }
  121. /*
  122. * Function ircomm_tty_set_termios (tty, old_termios)
  123. *
  124. * This routine allows the tty driver to be notified when device's
  125. * termios settings have changed. Note that a well-designed tty driver
  126. * should be prepared to accept the case where old == NULL, and try to
  127. * do something rational.
  128. */
  129. void ircomm_tty_set_termios(struct tty_struct *tty,
  130. struct termios *old_termios)
  131. {
  132. struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
  133. unsigned int cflag = tty->termios->c_cflag;
  134. IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
  135. if ((cflag == old_termios->c_cflag) &&
  136. (RELEVANT_IFLAG(tty->termios->c_iflag) ==
  137. RELEVANT_IFLAG(old_termios->c_iflag)))
  138. {
  139. return;
  140. }
  141. ircomm_tty_change_speed(self);
  142. /* Handle transition to B0 status */
  143. if ((old_termios->c_cflag & CBAUD) &&
  144. !(cflag & CBAUD)) {
  145. self->settings.dte &= ~(IRCOMM_DTR|IRCOMM_RTS);
  146. ircomm_param_request(self, IRCOMM_DTE, TRUE);
  147. }
  148. /* Handle transition away from B0 status */
  149. if (!(old_termios->c_cflag & CBAUD) &&
  150. (cflag & CBAUD)) {
  151. self->settings.dte |= IRCOMM_DTR;
  152. if (!(tty->termios->c_cflag & CRTSCTS) ||
  153. !test_bit(TTY_THROTTLED, &tty->flags)) {
  154. self->settings.dte |= IRCOMM_RTS;
  155. }
  156. ircomm_param_request(self, IRCOMM_DTE, TRUE);
  157. }
  158. /* Handle turning off CRTSCTS */
  159. if ((old_termios->c_cflag & CRTSCTS) &&
  160. !(tty->termios->c_cflag & CRTSCTS))
  161. {
  162. tty->hw_stopped = 0;
  163. ircomm_tty_start(tty);
  164. }
  165. }
  166. /*
  167. * Function ircomm_tty_tiocmget (tty, file)
  168. *
  169. *
  170. *
  171. */
  172. int ircomm_tty_tiocmget(struct tty_struct *tty, struct file *file)
  173. {
  174. struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
  175. unsigned int result;
  176. IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
  177. if (tty->flags & (1 << TTY_IO_ERROR))
  178. return -EIO;
  179. result = ((self->settings.dte & IRCOMM_RTS) ? TIOCM_RTS : 0)
  180. | ((self->settings.dte & IRCOMM_DTR) ? TIOCM_DTR : 0)
  181. | ((self->settings.dce & IRCOMM_CD) ? TIOCM_CAR : 0)
  182. | ((self->settings.dce & IRCOMM_RI) ? TIOCM_RNG : 0)
  183. | ((self->settings.dce & IRCOMM_DSR) ? TIOCM_DSR : 0)
  184. | ((self->settings.dce & IRCOMM_CTS) ? TIOCM_CTS : 0);
  185. return result;
  186. }
  187. /*
  188. * Function ircomm_tty_tiocmset (tty, file, set, clear)
  189. *
  190. *
  191. *
  192. */
  193. int ircomm_tty_tiocmset(struct tty_struct *tty, struct file *file,
  194. unsigned int set, unsigned int clear)
  195. {
  196. struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
  197. IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
  198. if (tty->flags & (1 << TTY_IO_ERROR))
  199. return -EIO;
  200. IRDA_ASSERT(self != NULL, return -1;);
  201. IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
  202. if (set & TIOCM_RTS)
  203. self->settings.dte |= IRCOMM_RTS;
  204. if (set & TIOCM_DTR)
  205. self->settings.dte |= IRCOMM_DTR;
  206. if (clear & TIOCM_RTS)
  207. self->settings.dte &= ~IRCOMM_RTS;
  208. if (clear & TIOCM_DTR)
  209. self->settings.dte &= ~IRCOMM_DTR;
  210. if ((set|clear) & TIOCM_RTS)
  211. self->settings.dte |= IRCOMM_DELTA_RTS;
  212. if ((set|clear) & TIOCM_DTR)
  213. self->settings.dte |= IRCOMM_DELTA_DTR;
  214. ircomm_param_request(self, IRCOMM_DTE, TRUE);
  215. return 0;
  216. }
  217. /*
  218. * Function get_serial_info (driver, retinfo)
  219. *
  220. *
  221. *
  222. */
  223. static int ircomm_tty_get_serial_info(struct ircomm_tty_cb *self,
  224. struct serial_struct __user *retinfo)
  225. {
  226. struct serial_struct info;
  227. if (!retinfo)
  228. return -EFAULT;
  229. IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
  230. memset(&info, 0, sizeof(info));
  231. info.line = self->line;
  232. info.flags = self->flags;
  233. info.baud_base = self->settings.data_rate;
  234. info.close_delay = self->close_delay;
  235. info.closing_wait = self->closing_wait;
  236. /* For compatibility */
  237. info.type = PORT_16550A;
  238. info.port = 0;
  239. info.irq = 0;
  240. info.xmit_fifo_size = 0;
  241. info.hub6 = 0;
  242. info.custom_divisor = 0;
  243. if (copy_to_user(retinfo, &info, sizeof(*retinfo)))
  244. return -EFAULT;
  245. return 0;
  246. }
  247. /*
  248. * Function set_serial_info (driver, new_info)
  249. *
  250. *
  251. *
  252. */
  253. static int ircomm_tty_set_serial_info(struct ircomm_tty_cb *self,
  254. struct serial_struct __user *new_info)
  255. {
  256. #if 0
  257. struct serial_struct new_serial;
  258. struct ircomm_tty_cb old_state, *state;
  259. IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
  260. if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
  261. return -EFAULT;
  262. state = self
  263. old_state = *self;
  264. if (!capable(CAP_SYS_ADMIN)) {
  265. if ((new_serial.baud_base != state->settings.data_rate) ||
  266. (new_serial.close_delay != state->close_delay) ||
  267. ((new_serial.flags & ~ASYNC_USR_MASK) !=
  268. (self->flags & ~ASYNC_USR_MASK)))
  269. return -EPERM;
  270. state->flags = ((state->flags & ~ASYNC_USR_MASK) |
  271. (new_serial.flags & ASYNC_USR_MASK));
  272. self->flags = ((self->flags & ~ASYNC_USR_MASK) |
  273. (new_serial.flags & ASYNC_USR_MASK));
  274. /* self->custom_divisor = new_serial.custom_divisor; */
  275. goto check_and_exit;
  276. }
  277. /*
  278. * OK, past this point, all the error checking has been done.
  279. * At this point, we start making changes.....
  280. */
  281. if (self->settings.data_rate != new_serial.baud_base) {
  282. self->settings.data_rate = new_serial.baud_base;
  283. ircomm_param_request(self, IRCOMM_DATA_RATE, TRUE);
  284. }
  285. self->close_delay = new_serial.close_delay * HZ/100;
  286. self->closing_wait = new_serial.closing_wait * HZ/100;
  287. /* self->custom_divisor = new_serial.custom_divisor; */
  288. self->flags = ((self->flags & ~ASYNC_FLAGS) |
  289. (new_serial.flags & ASYNC_FLAGS));
  290. self->tty->low_latency = (self->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
  291. check_and_exit:
  292. if (self->flags & ASYNC_INITIALIZED) {
  293. if (((old_state.flags & ASYNC_SPD_MASK) !=
  294. (self->flags & ASYNC_SPD_MASK)) ||
  295. (old_driver.custom_divisor != driver->custom_divisor)) {
  296. if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
  297. driver->tty->alt_speed = 57600;
  298. if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
  299. driver->tty->alt_speed = 115200;
  300. if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
  301. driver->tty->alt_speed = 230400;
  302. if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
  303. driver->tty->alt_speed = 460800;
  304. ircomm_tty_change_speed(driver);
  305. }
  306. }
  307. #endif
  308. return 0;
  309. }
  310. /*
  311. * Function ircomm_tty_ioctl (tty, file, cmd, arg)
  312. *
  313. *
  314. *
  315. */
  316. int ircomm_tty_ioctl(struct tty_struct *tty, struct file *file,
  317. unsigned int cmd, unsigned long arg)
  318. {
  319. struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
  320. int ret = 0;
  321. IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
  322. if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
  323. (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
  324. (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
  325. if (tty->flags & (1 << TTY_IO_ERROR))
  326. return -EIO;
  327. }
  328. switch (cmd) {
  329. case TIOCGSERIAL:
  330. ret = ircomm_tty_get_serial_info(self, (struct serial_struct __user *) arg);
  331. break;
  332. case TIOCSSERIAL:
  333. ret = ircomm_tty_set_serial_info(self, (struct serial_struct __user *) arg);
  334. break;
  335. case TIOCMIWAIT:
  336. IRDA_DEBUG(0, "(), TIOCMIWAIT, not impl!\n");
  337. break;
  338. case TIOCGICOUNT:
  339. IRDA_DEBUG(0, "%s(), TIOCGICOUNT not impl!\n", __FUNCTION__ );
  340. #if 0
  341. save_flags(flags); cli();
  342. cnow = driver->icount;
  343. restore_flags(flags);
  344. p_cuser = (struct serial_icounter_struct __user *) arg;
  345. if (put_user(cnow.cts, &p_cuser->cts) ||
  346. put_user(cnow.dsr, &p_cuser->dsr) ||
  347. put_user(cnow.rng, &p_cuser->rng) ||
  348. put_user(cnow.dcd, &p_cuser->dcd) ||
  349. put_user(cnow.rx, &p_cuser->rx) ||
  350. put_user(cnow.tx, &p_cuser->tx) ||
  351. put_user(cnow.frame, &p_cuser->frame) ||
  352. put_user(cnow.overrun, &p_cuser->overrun) ||
  353. put_user(cnow.parity, &p_cuser->parity) ||
  354. put_user(cnow.brk, &p_cuser->brk) ||
  355. put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
  356. return -EFAULT;
  357. #endif
  358. return 0;
  359. default:
  360. ret = -ENOIOCTLCMD; /* ioctls which we must ignore */
  361. }
  362. return ret;
  363. }