s0box.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /* $Id: s0box.c,v 2.6.2.4 2004/01/13 23:48:39 keil Exp $
  2. *
  3. * low level stuff for Creatix S0BOX
  4. *
  5. * Author Enrik Berkhan
  6. * Copyright by Enrik Berkhan <enrik@starfleet.inka.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 "hscx.h"
  16. #include "isdnl1.h"
  17. static const char *s0box_revision = "$Revision: 2.6.2.4 $";
  18. static inline void
  19. writereg(unsigned int padr, signed int addr, u_char off, u_char val) {
  20. outb_p(0x1c, padr + 2);
  21. outb_p(0x14, padr + 2);
  22. outb_p((addr + off) & 0x7f, padr);
  23. outb_p(0x16, padr + 2);
  24. outb_p(val, padr);
  25. outb_p(0x17, padr + 2);
  26. outb_p(0x14, padr + 2);
  27. outb_p(0x1c, padr + 2);
  28. }
  29. static u_char nibtab[] = { 1, 9, 5, 0xd, 3, 0xb, 7, 0xf,
  30. 0, 0, 0, 0, 0, 0, 0, 0,
  31. 0, 8, 4, 0xc, 2, 0xa, 6, 0xe };
  32. static inline u_char
  33. readreg(unsigned int padr, signed int addr, u_char off) {
  34. register u_char n1, n2;
  35. outb_p(0x1c, padr + 2);
  36. outb_p(0x14, padr + 2);
  37. outb_p((addr + off) | 0x80, padr);
  38. outb_p(0x16, padr + 2);
  39. outb_p(0x17, padr + 2);
  40. n1 = (inb_p(padr + 1) >> 3) & 0x17;
  41. outb_p(0x16, padr + 2);
  42. n2 = (inb_p(padr + 1) >> 3) & 0x17;
  43. outb_p(0x14, padr + 2);
  44. outb_p(0x1c, padr + 2);
  45. return nibtab[n1] | (nibtab[n2] << 4);
  46. }
  47. static inline void
  48. read_fifo(unsigned int padr, signed int adr, u_char *data, int size)
  49. {
  50. int i;
  51. register u_char n1, n2;
  52. outb_p(0x1c, padr + 2);
  53. outb_p(0x14, padr + 2);
  54. outb_p(adr | 0x80, padr);
  55. outb_p(0x16, padr + 2);
  56. for (i = 0; i < size; i++) {
  57. outb_p(0x17, padr + 2);
  58. n1 = (inb_p(padr + 1) >> 3) & 0x17;
  59. outb_p(0x16, padr + 2);
  60. n2 = (inb_p(padr + 1) >> 3) & 0x17;
  61. *(data++) = nibtab[n1] | (nibtab[n2] << 4);
  62. }
  63. outb_p(0x14, padr + 2);
  64. outb_p(0x1c, padr + 2);
  65. return;
  66. }
  67. static inline void
  68. write_fifo(unsigned int padr, signed int adr, u_char *data, int size)
  69. {
  70. int i;
  71. outb_p(0x1c, padr + 2);
  72. outb_p(0x14, padr + 2);
  73. outb_p(adr & 0x7f, padr);
  74. for (i = 0; i < size; i++) {
  75. outb_p(0x16, padr + 2);
  76. outb_p(*(data++), padr);
  77. outb_p(0x17, padr + 2);
  78. }
  79. outb_p(0x14, padr + 2);
  80. outb_p(0x1c, padr + 2);
  81. return;
  82. }
  83. /* Interface functions */
  84. static u_char
  85. ReadISAC(struct IsdnCardState *cs, u_char offset)
  86. {
  87. return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset));
  88. }
  89. static void
  90. WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
  91. {
  92. writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset, value);
  93. }
  94. static void
  95. ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
  96. {
  97. read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size);
  98. }
  99. static void
  100. WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
  101. {
  102. write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size);
  103. }
  104. static u_char
  105. ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
  106. {
  107. return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset));
  108. }
  109. static void
  110. WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
  111. {
  112. writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset, value);
  113. }
  114. /*
  115. * fast interrupt HSCX stuff goes here
  116. */
  117. #define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg)
  118. #define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg, data)
  119. #define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt)
  120. #define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt)
  121. #include "hscx_irq.c"
  122. static irqreturn_t
  123. s0box_interrupt(int intno, void *dev_id)
  124. {
  125. #define MAXCOUNT 5
  126. struct IsdnCardState *cs = dev_id;
  127. u_char val;
  128. u_long flags;
  129. int count = 0;
  130. spin_lock_irqsave(&cs->lock, flags);
  131. val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA);
  132. Start_HSCX:
  133. if (val)
  134. hscx_int_main(cs, val);
  135. val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA);
  136. Start_ISAC:
  137. if (val)
  138. isac_interrupt(cs, val);
  139. count++;
  140. val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA);
  141. if (val && count < MAXCOUNT) {
  142. if (cs->debug & L1_DEB_HSCX)
  143. debugl1(cs, "HSCX IntStat after IntRoutine");
  144. goto Start_HSCX;
  145. }
  146. val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA);
  147. if (val && count < MAXCOUNT) {
  148. if (cs->debug & L1_DEB_ISAC)
  149. debugl1(cs, "ISAC IntStat after IntRoutine");
  150. goto Start_ISAC;
  151. }
  152. if (count >= MAXCOUNT)
  153. printk(KERN_WARNING "S0Box: more than %d loops in s0box_interrupt\n", count);
  154. writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF);
  155. writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF);
  156. writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0xFF);
  157. writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0x0);
  158. writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0x0);
  159. writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0x0);
  160. spin_unlock_irqrestore(&cs->lock, flags);
  161. return IRQ_HANDLED;
  162. }
  163. static void
  164. release_io_s0box(struct IsdnCardState *cs)
  165. {
  166. release_region(cs->hw.teles3.cfg_reg, 8);
  167. }
  168. static int
  169. S0Box_card_msg(struct IsdnCardState *cs, int mt, void *arg)
  170. {
  171. u_long flags;
  172. switch (mt) {
  173. case CARD_RESET:
  174. break;
  175. case CARD_RELEASE:
  176. release_io_s0box(cs);
  177. break;
  178. case CARD_INIT:
  179. spin_lock_irqsave(&cs->lock, flags);
  180. inithscxisac(cs, 3);
  181. spin_unlock_irqrestore(&cs->lock, flags);
  182. break;
  183. case CARD_TEST:
  184. break;
  185. }
  186. return (0);
  187. }
  188. int setup_s0box(struct IsdnCard *card)
  189. {
  190. struct IsdnCardState *cs = card->cs;
  191. char tmp[64];
  192. strcpy(tmp, s0box_revision);
  193. printk(KERN_INFO "HiSax: S0Box IO driver Rev. %s\n", HiSax_getrev(tmp));
  194. if (cs->typ != ISDN_CTYPE_S0BOX)
  195. return (0);
  196. cs->hw.teles3.cfg_reg = card->para[1];
  197. cs->hw.teles3.hscx[0] = -0x20;
  198. cs->hw.teles3.hscx[1] = 0x0;
  199. cs->hw.teles3.isac = 0x20;
  200. cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e;
  201. cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e;
  202. cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e;
  203. cs->irq = card->para[0];
  204. if (!request_region(cs->hw.teles3.cfg_reg, 8, "S0Box parallel I/O")) {
  205. printk(KERN_WARNING "HiSax: S0Box ports %x-%x already in use\n",
  206. cs->hw.teles3.cfg_reg,
  207. cs->hw.teles3.cfg_reg + 7);
  208. return 0;
  209. }
  210. printk(KERN_INFO "HiSax: S0Box config irq:%d isac:0x%x cfg:0x%x\n",
  211. cs->irq,
  212. cs->hw.teles3.isac, cs->hw.teles3.cfg_reg);
  213. printk(KERN_INFO "HiSax: hscx A:0x%x hscx B:0x%x\n",
  214. cs->hw.teles3.hscx[0], cs->hw.teles3.hscx[1]);
  215. setup_isac(cs);
  216. cs->readisac = &ReadISAC;
  217. cs->writeisac = &WriteISAC;
  218. cs->readisacfifo = &ReadISACfifo;
  219. cs->writeisacfifo = &WriteISACfifo;
  220. cs->BC_Read_Reg = &ReadHSCX;
  221. cs->BC_Write_Reg = &WriteHSCX;
  222. cs->BC_Send_Data = &hscx_fill_fifo;
  223. cs->cardmsg = &S0Box_card_msg;
  224. cs->irq_func = &s0box_interrupt;
  225. ISACVersion(cs, "S0Box:");
  226. if (HscxVersion(cs, "S0Box:")) {
  227. printk(KERN_WARNING
  228. "S0Box: wrong HSCX versions check IO address\n");
  229. release_io_s0box(cs);
  230. return (0);
  231. }
  232. return (1);
  233. }