bkm_a8.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:12k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* $Id: bkm_a8.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  2.  *
  3.  * low level stuff for Scitel Quadro (4*S0, passive)
  4.  *
  5.  * Author       Roland Klabunde
  6.  * Copyright    by Roland Klabunde   <R.Klabunde@Berkom.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. #define __NO_VERSION__
  13. #include <linux/config.h>
  14. #include <linux/init.h>
  15. #include "hisax.h"
  16. #include "isac.h"
  17. #include "ipac.h"
  18. #include "hscx.h"
  19. #include "isdnl1.h"
  20. #include <linux/pci.h>
  21. #include "bkm_ax.h"
  22. #if CONFIG_PCI
  23. #define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */
  24. extern const char *CardType[];
  25. const char sct_quadro_revision[] = "$Revision: 1.1.4.1 $";
  26. static const char *sct_quadro_subtypes[] =
  27. {
  28. "",
  29. "#1",
  30. "#2",
  31. "#3",
  32. "#4"
  33. };
  34. #define wordout(addr,val) outw(val,addr)
  35. #define wordin(addr) inw(addr)
  36. static inline u_char
  37. readreg(unsigned int ale, unsigned int adr, u_char off)
  38. {
  39. register u_char ret;
  40. long flags;
  41. save_flags(flags);
  42. cli();
  43. wordout(ale, off);
  44. ret = wordin(adr) & 0xFF;
  45. restore_flags(flags);
  46. return (ret);
  47. }
  48. static inline void
  49. readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
  50. {
  51. /* fifo read without cli because it's allready done  */
  52. int i;
  53. wordout(ale, off);
  54. for (i = 0; i < size; i++)
  55. data[i] = wordin(adr) & 0xFF;
  56. }
  57. static inline void
  58. writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
  59. {
  60. long flags;
  61. save_flags(flags);
  62. cli();
  63. wordout(ale, off);
  64. wordout(adr, data);
  65. restore_flags(flags);
  66. }
  67. static inline void
  68. writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
  69. {
  70. /* fifo write without cli because it's allready done  */
  71. int i;
  72. wordout(ale, off);
  73. for (i = 0; i < size; i++)
  74. wordout(adr, data[i]);
  75. }
  76. /* Interface functions */
  77. static u_char
  78. ReadISAC(struct IsdnCardState *cs, u_char offset)
  79. {
  80. return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80));
  81. }
  82. static void
  83. WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
  84. {
  85. writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80, value);
  86. }
  87. static void
  88. ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
  89. {
  90. readfifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size);
  91. }
  92. static void
  93. WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
  94. {
  95. writefifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size);
  96. }
  97. static u_char
  98. ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
  99. {
  100. return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0)));
  101. }
  102. static void
  103. WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
  104. {
  105. writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0), value);
  106. }
  107. /* Set the specific ipac to active */
  108. static void
  109. set_ipac_active(struct IsdnCardState *cs, u_int active)
  110. {
  111. /* set irq mask */
  112. writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK,
  113. active ? 0xc0 : 0xff);
  114. }
  115. /*
  116.  * fast interrupt HSCX stuff goes here
  117.  */
  118. #define READHSCX(cs, nr, reg) readreg(cs->hw.ax.base, 
  119. cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0))
  120. #define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ax.base, 
  121. cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0), data)
  122. #define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.base, 
  123. cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt)
  124. #define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ax.base, 
  125. cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt)
  126. #include "hscx_irq.c"
  127. static void
  128. bkm_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
  129. {
  130. struct IsdnCardState *cs = dev_id;
  131. u_char ista, val, icnt = 5;
  132. if (!cs) {
  133. printk(KERN_WARNING "HiSax: Scitel Quadro: Spurious interrupt!n");
  134. return;
  135. }
  136. ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA);
  137. if (!(ista & 0x3f)) /* not this IPAC */
  138. return;
  139.       Start_IPAC:
  140. if (cs->debug & L1_DEB_IPAC)
  141. debugl1(cs, "IPAC ISTA %02X", ista);
  142. if (ista & 0x0f) {
  143. val = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, HSCX_ISTA + 0x40);
  144. if (ista & 0x01)
  145. val |= 0x01;
  146. if (ista & 0x04)
  147. val |= 0x02;
  148. if (ista & 0x08)
  149. val |= 0x04;
  150. if (val) {
  151. hscx_int_main(cs, val);
  152. }
  153. }
  154. if (ista & 0x20) {
  155. val = 0xfe & readreg(cs->hw.ax.base, cs->hw.ax.data_adr, ISAC_ISTA | 0x80);
  156. if (val) {
  157. isac_interrupt(cs, val);
  158. }
  159. }
  160. if (ista & 0x10) {
  161. val = 0x01;
  162. isac_interrupt(cs, val);
  163. }
  164. ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA);
  165. if ((ista & 0x3f) && icnt) {
  166. icnt--;
  167. goto Start_IPAC;
  168. }
  169. if (!icnt)
  170. printk(KERN_WARNING "HiSax: %s (%s) IRQ LOOPn",
  171.        CardType[cs->typ],
  172.        sct_quadro_subtypes[cs->subtyp]);
  173. writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xFF);
  174. writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xC0);
  175. }
  176. void
  177. release_io_sct_quadro(struct IsdnCardState *cs)
  178. {
  179. release_region(cs->hw.ax.base & 0xffffffc0, 128);
  180. if (cs->subtyp == SCT_1)
  181. release_region(cs->hw.ax.plx_adr, 64);
  182. }
  183. static void
  184. enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
  185. {
  186. if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
  187. if (bEnable)
  188. wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) | 0x41));
  189. else
  190. wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) & ~0x41));
  191. }
  192. }
  193. static void
  194. reset_bkm(struct IsdnCardState *cs)
  195. {
  196. long flags;
  197. if (cs->subtyp == SCT_1) {
  198. wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4));
  199. save_flags(flags);
  200. sti();
  201. set_current_state(TASK_UNINTERRUPTIBLE);
  202. schedule_timeout((10 * HZ) / 1000);
  203. /* Remove the soft reset */
  204. wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4));
  205. set_current_state(TASK_UNINTERRUPTIBLE);
  206. schedule_timeout((10 * HZ) / 1000);
  207. restore_flags(flags);
  208. }
  209. }
  210. static int
  211. BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
  212. {
  213. switch (mt) {
  214. case CARD_RESET:
  215. /* Disable ints */
  216. set_ipac_active(cs, 0);
  217. enable_bkm_int(cs, 0);
  218. reset_bkm(cs);
  219. return (0);
  220. case CARD_RELEASE:
  221. /* Sanity */
  222. set_ipac_active(cs, 0);
  223. enable_bkm_int(cs, 0);
  224. release_io_sct_quadro(cs);
  225. return (0);
  226. case CARD_INIT:
  227. cs->debug |= L1_DEB_IPAC;
  228. set_ipac_active(cs, 1);
  229. inithscxisac(cs, 3);
  230. /* Enable ints */
  231. enable_bkm_int(cs, 1);
  232. return (0);
  233. case CARD_TEST:
  234. return (0);
  235. }
  236. return (0);
  237. }
  238. int __init
  239. sct_alloc_io(u_int adr, u_int len)
  240. {
  241. if (check_region(adr, len)) {
  242. printk(KERN_WARNING
  243. "HiSax: Scitel port %#x-%#x already in usen",
  244. adr, adr + len);
  245. return (1);
  246. } else {
  247. request_region(adr, len, "scitel");
  248. }
  249. return(0);
  250. }
  251. static struct pci_dev *dev_a8 __initdata = NULL;
  252. static u16  sub_vendor_id __initdata = 0;
  253. static u16  sub_sys_id __initdata = 0;
  254. static u_char pci_bus __initdata = 0;
  255. static u_char pci_device_fn __initdata = 0;
  256. static u_char pci_irq __initdata = 0;
  257. #endif /* CONFIG_PCI */
  258. int __init
  259. setup_sct_quadro(struct IsdnCard *card)
  260. {
  261. #if CONFIG_PCI
  262. struct IsdnCardState *cs = card->cs;
  263. char tmp[64];
  264. u_char pci_rev_id;
  265. u_int found = 0;
  266. u_int pci_ioaddr1, pci_ioaddr2, pci_ioaddr3, pci_ioaddr4, pci_ioaddr5;
  267. strcpy(tmp, sct_quadro_revision);
  268. printk(KERN_INFO "HiSax: T-Berkom driver Rev. %sn", HiSax_getrev(tmp));
  269. if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
  270. cs->subtyp = SCT_1; /* Preset */
  271. } else
  272. return (0);
  273. /* Identify subtype by para[0] */
  274. if (card->para[0] >= SCT_1 && card->para[0] <= SCT_4)
  275. cs->subtyp = card->para[0];
  276. else {
  277. printk(KERN_WARNING "HiSax: %s: Invalid subcontroller in configuration, default to 1n",
  278. CardType[card->typ]);
  279. return (0);
  280. }
  281. if ((cs->subtyp != SCT_1) && ((sub_sys_id != PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) ||
  282. (sub_vendor_id != PCI_VENDOR_ID_BERKOM)))
  283. return (0);
  284. if (cs->subtyp == SCT_1) {
  285. if (!pci_present()) {
  286. printk(KERN_ERR "bkm_a4t: no PCI bus presentn");
  287. return (0);
  288. }
  289. while ((dev_a8 = pci_find_device(PCI_VENDOR_ID_PLX,
  290. PCI_DEVICE_ID_PLX_9050, dev_a8))) {
  291. sub_vendor_id = dev_a8->subsystem_vendor;
  292. sub_sys_id = dev_a8->subsystem_device;
  293. if ((sub_sys_id == PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) &&
  294. (sub_vendor_id == PCI_VENDOR_ID_BERKOM)) {
  295. if (pci_enable_device(dev_a8))
  296. return(0);
  297. pci_ioaddr1 = pci_resource_start(dev_a8, 1);
  298. pci_irq = dev_a8->irq;
  299. pci_bus = dev_a8->bus->number;
  300. pci_device_fn = dev_a8->devfn;
  301. found = 1;
  302. break;
  303. }
  304. }
  305. if (!found) {
  306. printk(KERN_WARNING "HiSax: %s (%s): Card not foundn",
  307. CardType[card->typ],
  308. sct_quadro_subtypes[cs->subtyp]);
  309. return (0);
  310. }
  311. #ifdef ATTEMPT_PCI_REMAPPING
  312. /* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */
  313. pcibios_read_config_byte(pci_bus, pci_device_fn,
  314. PCI_REVISION_ID, &pci_rev_id);
  315. if ((pci_ioaddr1 & 0x80) && (pci_rev_id == 1)) {
  316. printk(KERN_WARNING "HiSax: %s (%s): PLX rev 1, remapping required!n",
  317. CardType[card->typ],
  318. sct_quadro_subtypes[cs->subtyp]);
  319. /* Restart PCI negotiation */
  320. pcibios_write_config_dword(pci_bus, pci_device_fn,
  321. PCI_BASE_ADDRESS_1, (u_int) - 1);
  322. /* Move up by 0x80 byte */
  323. pci_ioaddr1 += 0x80;
  324. pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
  325. pcibios_write_config_dword(pci_bus, pci_device_fn,
  326. PCI_BASE_ADDRESS_1, pci_ioaddr1);
  327. dev_a8->resource[ 1].start = pci_ioaddr1;
  328. }
  329. #endif /* End HACK */
  330. }
  331. if (!pci_irq) { /* IRQ range check ?? */
  332. printk(KERN_WARNING "HiSax: %s (%s): No IRQn",
  333.        CardType[card->typ],
  334.        sct_quadro_subtypes[cs->subtyp]);
  335. return (0);
  336. }
  337. pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &pci_ioaddr1);
  338. pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &pci_ioaddr2);
  339. pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_3, &pci_ioaddr3);
  340. pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_4, &pci_ioaddr4);
  341. pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_5, &pci_ioaddr5);
  342. if (!pci_ioaddr1 || !pci_ioaddr2 || !pci_ioaddr3 || !pci_ioaddr4 || !pci_ioaddr5) {
  343. printk(KERN_WARNING "HiSax: %s (%s): No IO base address(es)n",
  344.        CardType[card->typ],
  345.        sct_quadro_subtypes[cs->subtyp]);
  346. return (0);
  347. }
  348. pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
  349. pci_ioaddr2 &= PCI_BASE_ADDRESS_IO_MASK;
  350. pci_ioaddr3 &= PCI_BASE_ADDRESS_IO_MASK;
  351. pci_ioaddr4 &= PCI_BASE_ADDRESS_IO_MASK;
  352. pci_ioaddr5 &= PCI_BASE_ADDRESS_IO_MASK;
  353. /* Take over */
  354. cs->irq = pci_irq;
  355. cs->irq_flags |= SA_SHIRQ;
  356. /* pci_ioaddr1 is unique to all subdevices */
  357. /* pci_ioaddr2 is for the fourth subdevice only */
  358. /* pci_ioaddr3 is for the third subdevice only */
  359. /* pci_ioaddr4 is for the second subdevice only */
  360. /* pci_ioaddr5 is for the first subdevice only */
  361. cs->hw.ax.plx_adr = pci_ioaddr1;
  362. /* Enter all ipac_base addresses */
  363. switch(cs->subtyp) {
  364. case 1:
  365. cs->hw.ax.base = pci_ioaddr5 + 0x00;
  366. if (sct_alloc_io(pci_ioaddr1, 128))
  367. return(0);
  368. if (sct_alloc_io(pci_ioaddr5, 64))
  369. return(0);
  370. /* disable all IPAC */
  371. writereg(pci_ioaddr5, pci_ioaddr5 + 4,
  372. IPAC_MASK, 0xFF);
  373. writereg(pci_ioaddr4 + 0x08, pci_ioaddr4 + 0x0c,
  374. IPAC_MASK, 0xFF);
  375. writereg(pci_ioaddr3 + 0x10, pci_ioaddr3 + 0x14,
  376. IPAC_MASK, 0xFF);
  377. writereg(pci_ioaddr2 + 0x20, pci_ioaddr2 + 0x24,
  378. IPAC_MASK, 0xFF);
  379. break;
  380. case 2:
  381. cs->hw.ax.base = pci_ioaddr4 + 0x08;
  382. if (sct_alloc_io(pci_ioaddr4, 64))
  383. return(0);
  384. break;
  385. case 3:
  386. cs->hw.ax.base = pci_ioaddr3 + 0x10;
  387. if (sct_alloc_io(pci_ioaddr3, 64))
  388. return(0);
  389. break;
  390. case 4:
  391. cs->hw.ax.base = pci_ioaddr2 + 0x20;
  392. if (sct_alloc_io(pci_ioaddr2, 64))
  393. return(0);
  394. break;
  395. }
  396. /* For isac and hscx data path */
  397. cs->hw.ax.data_adr = cs->hw.ax.base + 4;
  398. printk(KERN_INFO "HiSax: %s (%s) configured at 0x%.4lX, 0x%.4lX, 0x%.4lX and IRQ %dn",
  399.        CardType[card->typ],
  400.        sct_quadro_subtypes[cs->subtyp],
  401.        cs->hw.ax.plx_adr,
  402.        cs->hw.ax.base,
  403.        cs->hw.ax.data_adr,
  404.        cs->irq);
  405. test_and_set_bit(HW_IPAC, &cs->HW_Flags);
  406. cs->readisac = &ReadISAC;
  407. cs->writeisac = &WriteISAC;
  408. cs->readisacfifo = &ReadISACfifo;
  409. cs->writeisacfifo = &WriteISACfifo;
  410. cs->BC_Read_Reg = &ReadHSCX;
  411. cs->BC_Write_Reg = &WriteHSCX;
  412. cs->BC_Send_Data = &hscx_fill_fifo;
  413. cs->cardmsg = &BKM_card_msg;
  414. cs->irq_func = &bkm_interrupt_ipac;
  415. printk(KERN_INFO "HiSax: %s (%s): IPAC Version %dn",
  416. CardType[card->typ],
  417. sct_quadro_subtypes[cs->subtyp],
  418. readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID));
  419. return (1);
  420. #else
  421. printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systemsn");
  422. #endif /* CONFIG_PCI */
  423. }