isurf.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. /* $Id: isurf.c,v 1.12.2.4 2004/01/13 21:46:03 keil Exp $
  2. *
  3. * low level stuff for Siemens I-Surf/I-Talk cards
  4. *
  5. * Author Karsten Keil
  6. * Copyright by Karsten Keil <keil@isdn4linux.de>
  7. *
  8. * This software may be used and distributed according to the terms
  9. * of the GNU General Public License, incorporated herein by reference.
  10. *
  11. */
  12. #include <linux/init.h>
  13. #include "hisax.h"
  14. #include "isac.h"
  15. #include "isar.h"
  16. #include "isdnl1.h"
  17. #include <linux/isapnp.h>
  18. static const char *ISurf_revision = "$Revision: 1.12.2.4 $";
  19. #define byteout(addr,val) outb(val,addr)
  20. #define bytein(addr) inb(addr)
  21. #define ISURF_ISAR_RESET 1
  22. #define ISURF_ISAC_RESET 2
  23. #define ISURF_ISAR_EA 4
  24. #define ISURF_ARCOFI_RESET 8
  25. #define ISURF_RESET (ISURF_ISAR_RESET | ISURF_ISAC_RESET | ISURF_ARCOFI_RESET)
  26. #define ISURF_ISAR_OFFSET 0
  27. #define ISURF_ISAC_OFFSET 0x100
  28. #define ISURF_IOMEM_SIZE 0x400
  29. /* Interface functions */
  30. static u_char
  31. ReadISAC(struct IsdnCardState *cs, u_char offset)
  32. {
  33. return (readb(cs->hw.isurf.isac + offset));
  34. }
  35. static void
  36. WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
  37. {
  38. writeb(value, cs->hw.isurf.isac + offset); mb();
  39. }
  40. static void
  41. ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
  42. {
  43. register int i;
  44. for (i = 0; i < size; i++)
  45. data[i] = readb(cs->hw.isurf.isac);
  46. }
  47. static void
  48. WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
  49. {
  50. register int i;
  51. for (i = 0; i < size; i++){
  52. writeb(data[i], cs->hw.isurf.isac);mb();
  53. }
  54. }
  55. /* ISAR access routines
  56. * mode = 0 access with IRQ on
  57. * mode = 1 access with IRQ off
  58. * mode = 2 access with IRQ off and using last offset
  59. */
  60. static u_char
  61. ReadISAR(struct IsdnCardState *cs, int mode, u_char offset)
  62. {
  63. return(readb(cs->hw.isurf.isar + offset));
  64. }
  65. static void
  66. WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value)
  67. {
  68. writeb(value, cs->hw.isurf.isar + offset);mb();
  69. }
  70. static irqreturn_t
  71. isurf_interrupt(int intno, void *dev_id)
  72. {
  73. struct IsdnCardState *cs = dev_id;
  74. u_char val;
  75. int cnt = 5;
  76. u_long flags;
  77. spin_lock_irqsave(&cs->lock, flags);
  78. val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
  79. Start_ISAR:
  80. if (val & ISAR_IRQSTA)
  81. isar_int_main(cs);
  82. val = readb(cs->hw.isurf.isac + ISAC_ISTA);
  83. Start_ISAC:
  84. if (val)
  85. isac_interrupt(cs, val);
  86. val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
  87. if ((val & ISAR_IRQSTA) && --cnt) {
  88. if (cs->debug & L1_DEB_HSCX)
  89. debugl1(cs, "ISAR IntStat after IntRoutine");
  90. goto Start_ISAR;
  91. }
  92. val = readb(cs->hw.isurf.isac + ISAC_ISTA);
  93. if (val && --cnt) {
  94. if (cs->debug & L1_DEB_ISAC)
  95. debugl1(cs, "ISAC IntStat after IntRoutine");
  96. goto Start_ISAC;
  97. }
  98. if (!cnt)
  99. printk(KERN_WARNING "ISurf IRQ LOOP\n");
  100. writeb(0, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
  101. writeb(0xFF, cs->hw.isurf.isac + ISAC_MASK);mb();
  102. writeb(0, cs->hw.isurf.isac + ISAC_MASK);mb();
  103. writeb(ISAR_IRQMSK, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
  104. spin_unlock_irqrestore(&cs->lock, flags);
  105. return IRQ_HANDLED;
  106. }
  107. static void
  108. release_io_isurf(struct IsdnCardState *cs)
  109. {
  110. release_region(cs->hw.isurf.reset, 1);
  111. iounmap(cs->hw.isurf.isar);
  112. release_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
  113. }
  114. static void
  115. reset_isurf(struct IsdnCardState *cs, u_char chips)
  116. {
  117. printk(KERN_INFO "ISurf: resetting card\n");
  118. byteout(cs->hw.isurf.reset, chips); /* Reset On */
  119. mdelay(10);
  120. byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */
  121. mdelay(10);
  122. }
  123. static int
  124. ISurf_card_msg(struct IsdnCardState *cs, int mt, void *arg)
  125. {
  126. u_long flags;
  127. switch (mt) {
  128. case CARD_RESET:
  129. spin_lock_irqsave(&cs->lock, flags);
  130. reset_isurf(cs, ISURF_RESET);
  131. spin_unlock_irqrestore(&cs->lock, flags);
  132. return(0);
  133. case CARD_RELEASE:
  134. release_io_isurf(cs);
  135. return(0);
  136. case CARD_INIT:
  137. spin_lock_irqsave(&cs->lock, flags);
  138. reset_isurf(cs, ISURF_RESET);
  139. clear_pending_isac_ints(cs);
  140. writeb(0, cs->hw.isurf.isar+ISAR_IRQBIT);mb();
  141. initisac(cs);
  142. initisar(cs);
  143. /* Reenable ISAC IRQ */
  144. cs->writeisac(cs, ISAC_MASK, 0);
  145. /* RESET Receiver and Transmitter */
  146. cs->writeisac(cs, ISAC_CMDR, 0x41);
  147. spin_unlock_irqrestore(&cs->lock, flags);
  148. return(0);
  149. case CARD_TEST:
  150. return(0);
  151. }
  152. return(0);
  153. }
  154. static int
  155. isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
  156. int ret;
  157. u_long flags;
  158. if ((ic->command == ISDN_CMD_IOCTL) && (ic->arg == 9)) {
  159. ret = isar_auxcmd(cs, ic);
  160. spin_lock_irqsave(&cs->lock, flags);
  161. if (!ret) {
  162. reset_isurf(cs, ISURF_ISAR_EA | ISURF_ISAC_RESET |
  163. ISURF_ARCOFI_RESET);
  164. initisac(cs);
  165. cs->writeisac(cs, ISAC_MASK, 0);
  166. cs->writeisac(cs, ISAC_CMDR, 0x41);
  167. }
  168. spin_unlock_irqrestore(&cs->lock, flags);
  169. return(ret);
  170. }
  171. return(isar_auxcmd(cs, ic));
  172. }
  173. #ifdef __ISAPNP__
  174. static struct pnp_card *pnp_c __devinitdata = NULL;
  175. #endif
  176. int __devinit
  177. setup_isurf(struct IsdnCard *card)
  178. {
  179. int ver;
  180. struct IsdnCardState *cs = card->cs;
  181. char tmp[64];
  182. strcpy(tmp, ISurf_revision);
  183. printk(KERN_INFO "HiSax: ISurf driver Rev. %s\n", HiSax_getrev(tmp));
  184. if (cs->typ != ISDN_CTYPE_ISURF)
  185. return(0);
  186. if (card->para[1] && card->para[2]) {
  187. cs->hw.isurf.reset = card->para[1];
  188. cs->hw.isurf.phymem = card->para[2];
  189. cs->irq = card->para[0];
  190. } else {
  191. #ifdef __ISAPNP__
  192. if (isapnp_present()) {
  193. struct pnp_dev *pnp_d = NULL;
  194. int err;
  195. cs->subtyp = 0;
  196. if ((pnp_c = pnp_find_card(
  197. ISAPNP_VENDOR('S', 'I', 'E'),
  198. ISAPNP_FUNCTION(0x0010), pnp_c))) {
  199. if (!(pnp_d = pnp_find_dev(pnp_c,
  200. ISAPNP_VENDOR('S', 'I', 'E'),
  201. ISAPNP_FUNCTION(0x0010), pnp_d))) {
  202. printk(KERN_ERR "ISurfPnP: PnP error card found, no device\n");
  203. return (0);
  204. }
  205. pnp_disable_dev(pnp_d);
  206. err = pnp_activate_dev(pnp_d);
  207. cs->hw.isurf.reset = pnp_port_start(pnp_d, 0);
  208. cs->hw.isurf.phymem = pnp_mem_start(pnp_d, 1);
  209. cs->irq = pnp_irq(pnp_d, 0);
  210. if (!cs->irq || !cs->hw.isurf.reset || !cs->hw.isurf.phymem) {
  211. printk(KERN_ERR "ISurfPnP:some resources are missing %d/%x/%lx\n",
  212. cs->irq, cs->hw.isurf.reset, cs->hw.isurf.phymem);
  213. pnp_disable_dev(pnp_d);
  214. return(0);
  215. }
  216. } else {
  217. printk(KERN_INFO "ISurfPnP: no ISAPnP card found\n");
  218. return(0);
  219. }
  220. } else {
  221. printk(KERN_INFO "ISurfPnP: no ISAPnP bus found\n");
  222. return(0);
  223. }
  224. #else
  225. printk(KERN_WARNING "HiSax: Siemens I-Surf port/mem not set\n");
  226. return (0);
  227. #endif
  228. }
  229. if (!request_region(cs->hw.isurf.reset, 1, "isurf isdn")) {
  230. printk(KERN_WARNING
  231. "HiSax: Siemens I-Surf config port %x already in use\n",
  232. cs->hw.isurf.reset);
  233. return (0);
  234. }
  235. if (!request_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE, "isurf iomem")) {
  236. printk(KERN_WARNING "HiSax: Siemens I-Surf memory region "
  237. "%lx-%lx already in use\n",
  238. cs->hw.isurf.phymem,
  239. cs->hw.isurf.phymem + ISURF_IOMEM_SIZE);
  240. release_region(cs->hw.isurf.reset, 1);
  241. return (0);
  242. }
  243. cs->hw.isurf.isar = ioremap(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
  244. cs->hw.isurf.isac = cs->hw.isurf.isar + ISURF_ISAC_OFFSET;
  245. printk(KERN_INFO
  246. "ISurf: defined at 0x%x 0x%lx IRQ %d\n",
  247. cs->hw.isurf.reset,
  248. cs->hw.isurf.phymem,
  249. cs->irq);
  250. setup_isac(cs);
  251. cs->cardmsg = &ISurf_card_msg;
  252. cs->irq_func = &isurf_interrupt;
  253. cs->auxcmd = &isurf_auxcmd;
  254. cs->readisac = &ReadISAC;
  255. cs->writeisac = &WriteISAC;
  256. cs->readisacfifo = &ReadISACfifo;
  257. cs->writeisacfifo = &WriteISACfifo;
  258. cs->bcs[0].hw.isar.reg = &cs->hw.isurf.isar_r;
  259. cs->bcs[1].hw.isar.reg = &cs->hw.isurf.isar_r;
  260. test_and_set_bit(HW_ISAR, &cs->HW_Flags);
  261. ISACVersion(cs, "ISurf:");
  262. cs->BC_Read_Reg = &ReadISAR;
  263. cs->BC_Write_Reg = &WriteISAR;
  264. cs->BC_Send_Data = &isar_fill_fifo;
  265. ver = ISARVersion(cs, "ISurf:");
  266. if (ver < 0) {
  267. printk(KERN_WARNING
  268. "ISurf: wrong ISAR version (ret = %d)\n", ver);
  269. release_io_isurf(cs);
  270. return (0);
  271. }
  272. return (1);
  273. }