ix1_micro.c 8.2 KB

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