dgnc_mgmt.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /*
  2. * Copyright 2003 Digi International (www.digi.com)
  3. * Scott H Kilau <Scott_Kilau at digi dot com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2, or (at your option)
  8. * any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
  12. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  13. * PURPOSE. See the GNU General Public License for more details.
  14. */
  15. /************************************************************************
  16. *
  17. * This file implements the mgmt functionality for the
  18. * Neo and ClassicBoard based product lines.
  19. *
  20. ************************************************************************
  21. */
  22. #include <linux/kernel.h>
  23. #include <linux/ctype.h>
  24. #include <linux/sched.h> /* For jiffies, task states */
  25. #include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */
  26. #include <linux/serial_reg.h>
  27. #include <linux/termios.h>
  28. #include <linux/uaccess.h> /* For copy_from_user/copy_to_user */
  29. #include "dgnc_driver.h"
  30. #include "dgnc_pci.h"
  31. #include "dgnc_mgmt.h"
  32. /* Our "in use" variables, to enforce 1 open only */
  33. static int dgnc_mgmt_in_use[MAXMGMTDEVICES];
  34. /*
  35. * dgnc_mgmt_open()
  36. *
  37. * Open the mgmt/downld/dpa device
  38. */
  39. int dgnc_mgmt_open(struct inode *inode, struct file *file)
  40. {
  41. unsigned long flags;
  42. unsigned int minor = iminor(inode);
  43. spin_lock_irqsave(&dgnc_global_lock, flags);
  44. /* mgmt device */
  45. if (minor < MAXMGMTDEVICES) {
  46. /* Only allow 1 open at a time on mgmt device */
  47. if (dgnc_mgmt_in_use[minor]) {
  48. spin_unlock_irqrestore(&dgnc_global_lock, flags);
  49. return -EBUSY;
  50. }
  51. dgnc_mgmt_in_use[minor]++;
  52. } else {
  53. spin_unlock_irqrestore(&dgnc_global_lock, flags);
  54. return -ENXIO;
  55. }
  56. spin_unlock_irqrestore(&dgnc_global_lock, flags);
  57. return 0;
  58. }
  59. /*
  60. * dgnc_mgmt_close()
  61. *
  62. * Open the mgmt/dpa device
  63. */
  64. int dgnc_mgmt_close(struct inode *inode, struct file *file)
  65. {
  66. unsigned long flags;
  67. unsigned int minor = iminor(inode);
  68. spin_lock_irqsave(&dgnc_global_lock, flags);
  69. /* mgmt device */
  70. if (minor < MAXMGMTDEVICES) {
  71. if (dgnc_mgmt_in_use[minor])
  72. dgnc_mgmt_in_use[minor] = 0;
  73. }
  74. spin_unlock_irqrestore(&dgnc_global_lock, flags);
  75. return 0;
  76. }
  77. /*
  78. * dgnc_mgmt_ioctl()
  79. *
  80. * ioctl the mgmt/dpa device
  81. */
  82. long dgnc_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  83. {
  84. unsigned long flags;
  85. void __user *uarg = (void __user *)arg;
  86. switch (cmd) {
  87. case DIGI_GETDD:
  88. {
  89. /*
  90. * This returns the total number of boards
  91. * in the system, as well as driver version
  92. * and has space for a reserved entry
  93. */
  94. struct digi_dinfo ddi;
  95. spin_lock_irqsave(&dgnc_global_lock, flags);
  96. memset(&ddi, 0, sizeof(ddi));
  97. ddi.dinfo_nboards = dgnc_NumBoards;
  98. sprintf(ddi.dinfo_version, "%s", DG_PART);
  99. spin_unlock_irqrestore(&dgnc_global_lock, flags);
  100. if (copy_to_user(uarg, &ddi, sizeof(ddi)))
  101. return -EFAULT;
  102. break;
  103. }
  104. case DIGI_GETBD:
  105. {
  106. int brd;
  107. struct digi_info di;
  108. if (copy_from_user(&brd, uarg, sizeof(int)))
  109. return -EFAULT;
  110. if (brd < 0 || brd >= dgnc_NumBoards)
  111. return -ENODEV;
  112. memset(&di, 0, sizeof(di));
  113. di.info_bdnum = brd;
  114. spin_lock_irqsave(&dgnc_Board[brd]->bd_lock, flags);
  115. di.info_bdtype = dgnc_Board[brd]->dpatype;
  116. di.info_bdstate = dgnc_Board[brd]->dpastatus;
  117. di.info_ioport = 0;
  118. di.info_physaddr = (ulong)dgnc_Board[brd]->membase;
  119. di.info_physsize = (ulong)dgnc_Board[brd]->membase
  120. - dgnc_Board[brd]->membase_end;
  121. if (dgnc_Board[brd]->state != BOARD_FAILED)
  122. di.info_nports = dgnc_Board[brd]->nasync;
  123. else
  124. di.info_nports = 0;
  125. spin_unlock_irqrestore(&dgnc_Board[brd]->bd_lock, flags);
  126. if (copy_to_user(uarg, &di, sizeof(di)))
  127. return -EFAULT;
  128. break;
  129. }
  130. case DIGI_GET_NI_INFO:
  131. {
  132. struct channel_t *ch;
  133. struct ni_info ni;
  134. unsigned char mstat = 0;
  135. uint board = 0;
  136. uint channel = 0;
  137. if (copy_from_user(&ni, uarg, sizeof(ni)))
  138. return -EFAULT;
  139. board = ni.board;
  140. channel = ni.channel;
  141. /* Verify boundaries on board */
  142. if (board >= dgnc_NumBoards)
  143. return -ENODEV;
  144. /* Verify boundaries on channel */
  145. if (channel >= dgnc_Board[board]->nasync)
  146. return -ENODEV;
  147. ch = dgnc_Board[board]->channels[channel];
  148. if (!ch || ch->magic != DGNC_CHANNEL_MAGIC)
  149. return -ENODEV;
  150. memset(&ni, 0, sizeof(ni));
  151. ni.board = board;
  152. ni.channel = channel;
  153. spin_lock_irqsave(&ch->ch_lock, flags);
  154. mstat = (ch->ch_mostat | ch->ch_mistat);
  155. if (mstat & UART_MCR_DTR) {
  156. ni.mstat |= TIOCM_DTR;
  157. ni.dtr = TIOCM_DTR;
  158. }
  159. if (mstat & UART_MCR_RTS) {
  160. ni.mstat |= TIOCM_RTS;
  161. ni.rts = TIOCM_RTS;
  162. }
  163. if (mstat & UART_MSR_CTS) {
  164. ni.mstat |= TIOCM_CTS;
  165. ni.cts = TIOCM_CTS;
  166. }
  167. if (mstat & UART_MSR_RI) {
  168. ni.mstat |= TIOCM_RI;
  169. ni.ri = TIOCM_RI;
  170. }
  171. if (mstat & UART_MSR_DCD) {
  172. ni.mstat |= TIOCM_CD;
  173. ni.dcd = TIOCM_CD;
  174. }
  175. if (mstat & UART_MSR_DSR)
  176. ni.mstat |= TIOCM_DSR;
  177. ni.iflag = ch->ch_c_iflag;
  178. ni.oflag = ch->ch_c_oflag;
  179. ni.cflag = ch->ch_c_cflag;
  180. ni.lflag = ch->ch_c_lflag;
  181. if (ch->ch_digi.digi_flags & CTSPACE ||
  182. ch->ch_c_cflag & CRTSCTS)
  183. ni.hflow = 1;
  184. else
  185. ni.hflow = 0;
  186. if ((ch->ch_flags & CH_STOPI) ||
  187. (ch->ch_flags & CH_FORCED_STOPI))
  188. ni.recv_stopped = 1;
  189. else
  190. ni.recv_stopped = 0;
  191. if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_FORCED_STOP))
  192. ni.xmit_stopped = 1;
  193. else
  194. ni.xmit_stopped = 0;
  195. ni.curtx = ch->ch_txcount;
  196. ni.currx = ch->ch_rxcount;
  197. ni.baud = ch->ch_old_baud;
  198. spin_unlock_irqrestore(&ch->ch_lock, flags);
  199. if (copy_to_user(uarg, &ni, sizeof(ni)))
  200. return -EFAULT;
  201. break;
  202. }
  203. }
  204. return 0;
  205. }