ix1_micro.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. /* $Id: ix1_micro.c,v 2.12.2.4 2004/01/13 23:48:39 keil Exp $
  2. *
  3. * low level stuff for ITK ix1-micro Rev.2 isdn cards
  4. * derived from the original file teles3.c from Karsten Keil
  5. *
  6. * Author Klaus-Peter Nischke
  7. * Copyright by Klaus-Peter Nischke, ITK AG
  8. * <klaus@nischke.do.eunet.de>
  9. * by Karsten Keil <keil@isdn4linux.de>
  10. *
  11. * This software may be used and distributed according to the terms
  12. * of the GNU General Public License, incorporated herein by reference.
  13. *
  14. * Klaus-Peter Nischke
  15. * Deusener Str. 287
  16. * 44369 Dortmund
  17. * Germany
  18. */
  19. #include <linux/init.h>
  20. #include <linux/isapnp.h>
  21. #include "hisax.h"
  22. #include "isac.h"
  23. #include "hscx.h"
  24. #include "isdnl1.h"
  25. static const char *ix1_revision = "$Revision: 2.12.2.4 $";
  26. #define byteout(addr, val) outb(val, addr)
  27. #define bytein(addr) inb(addr)
  28. #define SPECIAL_PORT_OFFSET 3
  29. #define ISAC_COMMAND_OFFSET 2
  30. #define ISAC_DATA_OFFSET 0
  31. #define HSCX_COMMAND_OFFSET 2
  32. #define HSCX_DATA_OFFSET 1
  33. #define TIMEOUT 50
  34. static inline u_char
  35. readreg(unsigned int ale, unsigned int adr, u_char off)
  36. {
  37. register u_char ret;
  38. byteout(ale, off);
  39. ret = bytein(adr);
  40. return (ret);
  41. }
  42. static inline void
  43. readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
  44. {
  45. byteout(ale, off);
  46. insb(adr, data, size);
  47. }
  48. static inline void
  49. writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
  50. {
  51. byteout(ale, off);
  52. byteout(adr, data);
  53. }
  54. static inline void
  55. writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size)
  56. {
  57. byteout(ale, off);
  58. outsb(adr, data, size);
  59. }
  60. /* Interface functions */
  61. static u_char
  62. ReadISAC(struct IsdnCardState *cs, u_char offset)
  63. {
  64. return (readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset));
  65. }
  66. static void
  67. WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
  68. {
  69. writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset, value);
  70. }
  71. static void
  72. ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
  73. {
  74. readfifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size);
  75. }
  76. static void
  77. WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
  78. {
  79. writefifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size);
  80. }
  81. static u_char
  82. ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
  83. {
  84. return (readreg(cs->hw.ix1.hscx_ale,
  85. cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0)));
  86. }
  87. static void
  88. WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
  89. {
  90. writereg(cs->hw.ix1.hscx_ale,
  91. cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0), value);
  92. }
  93. #define READHSCX(cs, nr, reg) readreg(cs->hw.ix1.hscx_ale, \
  94. cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0))
  95. #define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ix1.hscx_ale, \
  96. cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0), data)
  97. #define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ix1.hscx_ale, \
  98. cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt)
  99. #define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ix1.hscx_ale, \
  100. cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt)
  101. #include "hscx_irq.c"
  102. static irqreturn_t
  103. ix1micro_interrupt(int intno, void *dev_id)
  104. {
  105. struct IsdnCardState *cs = dev_id;
  106. u_char val;
  107. u_long flags;
  108. spin_lock_irqsave(&cs->lock, flags);
  109. val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40);
  110. Start_HSCX:
  111. if (val)
  112. hscx_int_main(cs, val);
  113. val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA);
  114. Start_ISAC:
  115. if (val)
  116. isac_interrupt(cs, val);
  117. val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40);
  118. if (val) {
  119. if (cs->debug & L1_DEB_HSCX)
  120. debugl1(cs, "HSCX IntStat after IntRoutine");
  121. goto Start_HSCX;
  122. }
  123. val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA);
  124. if (val) {
  125. if (cs->debug & L1_DEB_ISAC)
  126. debugl1(cs, "ISAC IntStat after IntRoutine");
  127. goto Start_ISAC;
  128. }
  129. writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0xFF);
  130. writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0xFF);
  131. writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0xFF);
  132. writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0);
  133. writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0);
  134. writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0);
  135. spin_unlock_irqrestore(&cs->lock, flags);
  136. return IRQ_HANDLED;
  137. }
  138. static void
  139. release_io_ix1micro(struct IsdnCardState *cs)
  140. {
  141. if (cs->hw.ix1.cfg_reg)
  142. release_region(cs->hw.ix1.cfg_reg, 4);
  143. }
  144. static void
  145. ix1_reset(struct IsdnCardState *cs)
  146. {
  147. int cnt;
  148. /* reset isac */
  149. cnt = 3 * (HZ / 10) + 1;
  150. while (cnt--) {
  151. byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 1);
  152. HZDELAY(1); /* wait >=10 ms */
  153. }
  154. byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 0);
  155. }
  156. static int
  157. ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg)
  158. {
  159. u_long flags;
  160. switch (mt) {
  161. case CARD_RESET:
  162. spin_lock_irqsave(&cs->lock, flags);
  163. ix1_reset(cs);
  164. spin_unlock_irqrestore(&cs->lock, flags);
  165. return (0);
  166. case CARD_RELEASE:
  167. release_io_ix1micro(cs);
  168. return (0);
  169. case CARD_INIT:
  170. spin_lock_irqsave(&cs->lock, flags);
  171. ix1_reset(cs);
  172. inithscxisac(cs, 3);
  173. spin_unlock_irqrestore(&cs->lock, flags);
  174. return (0);
  175. case CARD_TEST:
  176. return (0);
  177. }
  178. return (0);
  179. }
  180. #ifdef __ISAPNP__
  181. static struct isapnp_device_id itk_ids[] = {
  182. { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25),
  183. ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25),
  184. (unsigned long) "ITK micro 2" },
  185. { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29),
  186. ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29),
  187. (unsigned long) "ITK micro 2." },
  188. { 0, }
  189. };
  190. static struct isapnp_device_id *ipid = &itk_ids[0];
  191. static struct pnp_card *pnp_c = NULL;
  192. #endif
  193. int setup_ix1micro(struct IsdnCard *card)
  194. {
  195. struct IsdnCardState *cs = card->cs;
  196. char tmp[64];
  197. strcpy(tmp, ix1_revision);
  198. printk(KERN_INFO "HiSax: ITK IX1 driver Rev. %s\n", HiSax_getrev(tmp));
  199. if (cs->typ != ISDN_CTYPE_IX1MICROR2)
  200. return (0);
  201. #ifdef __ISAPNP__
  202. if (!card->para[1] && isapnp_present()) {
  203. struct pnp_dev *pnp_d;
  204. while (ipid->card_vendor) {
  205. if ((pnp_c = pnp_find_card(ipid->card_vendor,
  206. ipid->card_device, pnp_c))) {
  207. pnp_d = NULL;
  208. if ((pnp_d = pnp_find_dev(pnp_c,
  209. ipid->vendor, ipid->function, pnp_d))) {
  210. int err;
  211. printk(KERN_INFO "HiSax: %s detected\n",
  212. (char *)ipid->driver_data);
  213. pnp_disable_dev(pnp_d);
  214. err = pnp_activate_dev(pnp_d);
  215. if (err < 0) {
  216. printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
  217. __func__, err);
  218. return (0);
  219. }
  220. card->para[1] = pnp_port_start(pnp_d, 0);
  221. card->para[0] = pnp_irq(pnp_d, 0);
  222. if (!card->para[0] || !card->para[1]) {
  223. printk(KERN_ERR "ITK PnP:some resources are missing %ld/%lx\n",
  224. card->para[0], card->para[1]);
  225. pnp_disable_dev(pnp_d);
  226. return (0);
  227. }
  228. break;
  229. } else {
  230. printk(KERN_ERR "ITK PnP: PnP error card found, no device\n");
  231. }
  232. }
  233. ipid++;
  234. pnp_c = NULL;
  235. }
  236. if (!ipid->card_vendor) {
  237. printk(KERN_INFO "ITK PnP: no ISAPnP card found\n");
  238. return (0);
  239. }
  240. }
  241. #endif
  242. /* IO-Ports */
  243. cs->hw.ix1.isac_ale = card->para[1] + ISAC_COMMAND_OFFSET;
  244. cs->hw.ix1.hscx_ale = card->para[1] + HSCX_COMMAND_OFFSET;
  245. cs->hw.ix1.isac = card->para[1] + ISAC_DATA_OFFSET;
  246. cs->hw.ix1.hscx = card->para[1] + HSCX_DATA_OFFSET;
  247. cs->hw.ix1.cfg_reg = card->para[1];
  248. cs->irq = card->para[0];
  249. if (cs->hw.ix1.cfg_reg) {
  250. if (!request_region(cs->hw.ix1.cfg_reg, 4, "ix1micro cfg")) {
  251. printk(KERN_WARNING
  252. "HiSax: ITK ix1-micro Rev.2 config port "
  253. "%x-%x already in use\n",
  254. cs->hw.ix1.cfg_reg,
  255. cs->hw.ix1.cfg_reg + 4);
  256. return (0);
  257. }
  258. }
  259. printk(KERN_INFO "HiSax: ITK ix1-micro Rev.2 config irq:%d io:0x%X\n",
  260. cs->irq, cs->hw.ix1.cfg_reg);
  261. setup_isac(cs);
  262. cs->readisac = &ReadISAC;
  263. cs->writeisac = &WriteISAC;
  264. cs->readisacfifo = &ReadISACfifo;
  265. cs->writeisacfifo = &WriteISACfifo;
  266. cs->BC_Read_Reg = &ReadHSCX;
  267. cs->BC_Write_Reg = &WriteHSCX;
  268. cs->BC_Send_Data = &hscx_fill_fifo;
  269. cs->cardmsg = &ix1_card_msg;
  270. cs->irq_func = &ix1micro_interrupt;
  271. ISACVersion(cs, "ix1-Micro:");
  272. if (HscxVersion(cs, "ix1-Micro:")) {
  273. printk(KERN_WARNING
  274. "ix1-Micro: wrong HSCX versions check IO address\n");
  275. release_io_ix1micro(cs);
  276. return (0);
  277. }
  278. return (1);
  279. }