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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* $Id: asuscom.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
  2.  *
  3.  * low level stuff for ASUSCOM NETWORK INC. ISDNLink 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.  * Thanks to  ASUSCOM NETWORK INC. Taiwan and  Dynalink NL for information
  12.  *
  13.  */
  14. #define __NO_VERSION__
  15. #include <linux/init.h>
  16. #include <linux/isapnp.h>
  17. #include "hisax.h"
  18. #include "isac.h"
  19. #include "ipac.h"
  20. #include "hscx.h"
  21. #include "isdnl1.h"
  22. extern const char *CardType[];
  23. const char *Asuscom_revision = "$Revision: 1.1.4.1 $";
  24. #define byteout(addr,val) outb(val,addr)
  25. #define bytein(addr) inb(addr)
  26. #define ASUS_ISAC 0
  27. #define ASUS_HSCX 1
  28. #define ASUS_ADR 2
  29. #define ASUS_CTRL_U7 3
  30. #define ASUS_CTRL_POTS 5
  31. #define ASUS_IPAC_ALE 0
  32. #define ASUS_IPAC_DATA 1
  33. #define ASUS_ISACHSCX 1
  34. #define ASUS_IPAC 2
  35. /* CARD_ADR (Write) */
  36. #define ASUS_RESET      0x80 /* Bit 7 Reset-Leitung */
  37. static inline u_char
  38. readreg(unsigned int ale, unsigned int adr, u_char off)
  39. {
  40. register u_char ret;
  41. long flags;
  42. save_flags(flags);
  43. cli();
  44. byteout(ale, off);
  45. ret = bytein(adr);
  46. restore_flags(flags);
  47. return (ret);
  48. }
  49. static inline void
  50. readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
  51. {
  52. /* fifo read without cli because it's allready done  */
  53. byteout(ale, off);
  54. insb(adr, data, size);
  55. }
  56. static inline void
  57. writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
  58. {
  59. long flags;
  60. save_flags(flags);
  61. cli();
  62. byteout(ale, off);
  63. byteout(adr, data);
  64. restore_flags(flags);
  65. }
  66. static inline void
  67. writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
  68. {
  69. /* fifo write without cli because it's allready done  */
  70. byteout(ale, off);
  71. outsb(adr, data, size);
  72. }
  73. /* Interface functions */
  74. static u_char
  75. ReadISAC(struct IsdnCardState *cs, u_char offset)
  76. {
  77. return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset));
  78. }
  79. static void
  80. WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
  81. {
  82. writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset, value);
  83. }
  84. static void
  85. ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
  86. {
  87. readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size);
  88. }
  89. static void
  90. WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
  91. {
  92. writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size);
  93. }
  94. static u_char
  95. ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset)
  96. {
  97. return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset|0x80));
  98. }
  99. static void
  100. WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value)
  101. {
  102. writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset|0x80, value);
  103. }
  104. static void
  105. ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
  106. {
  107. readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size);
  108. }
  109. static void
  110. WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char * data, int size)
  111. {
  112. writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size);
  113. }
  114. static u_char
  115. ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
  116. {
  117. return (readreg(cs->hw.asus.adr,
  118. cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0)));
  119. }
  120. static void
  121. WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
  122. {
  123. writereg(cs->hw.asus.adr,
  124.  cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0), value);
  125. }
  126. /*
  127.  * fast interrupt HSCX stuff goes here
  128.  */
  129. #define READHSCX(cs, nr, reg) readreg(cs->hw.asus.adr, 
  130. cs->hw.asus.hscx, reg + (nr ? 0x40 : 0))
  131. #define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.asus.adr, 
  132. cs->hw.asus.hscx, reg + (nr ? 0x40 : 0), data)
  133. #define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.asus.adr, 
  134. cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt)
  135. #define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.asus.adr, 
  136. cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt)
  137. #include "hscx_irq.c"
  138. static void
  139. asuscom_interrupt(int intno, void *dev_id, struct pt_regs *regs)
  140. {
  141. struct IsdnCardState *cs = dev_id;
  142. u_char val;
  143. if (!cs) {
  144. printk(KERN_WARNING "ISDNLink: Spurious interrupt!n");
  145. return;
  146. }
  147. val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
  148.       Start_HSCX:
  149. if (val)
  150. hscx_int_main(cs, val);
  151. val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA);
  152.       Start_ISAC:
  153. if (val)
  154. isac_interrupt(cs, val);
  155. val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
  156. if (val) {
  157. if (cs->debug & L1_DEB_HSCX)
  158. debugl1(cs, "HSCX IntStat after IntRoutine");
  159. goto Start_HSCX;
  160. }
  161. val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA);
  162. if (val) {
  163. if (cs->debug & L1_DEB_ISAC)
  164. debugl1(cs, "ISAC IntStat after IntRoutine");
  165. goto Start_ISAC;
  166. }
  167. writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0xFF);
  168. writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0xFF);
  169. writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0xFF);
  170. writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0x0);
  171. writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0x0);
  172. writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0x0);
  173. }
  174. static void
  175. asuscom_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
  176. {
  177. struct IsdnCardState *cs = dev_id;
  178. u_char ista, val, icnt = 5;
  179. if (!cs) {
  180. printk(KERN_WARNING "ISDNLink: Spurious interrupt!n");
  181. return;
  182. }
  183. ista = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA);
  184. Start_IPAC:
  185. if (cs->debug & L1_DEB_IPAC)
  186. debugl1(cs, "IPAC ISTA %02X", ista);
  187. if (ista & 0x0f) {
  188. val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40);
  189. if (ista & 0x01)
  190. val |= 0x01;
  191. if (ista & 0x04)
  192. val |= 0x02;
  193. if (ista & 0x08)
  194. val |= 0x04;
  195. if (val)
  196. hscx_int_main(cs, val);
  197. }
  198. if (ista & 0x20) {
  199. val = 0xfe & readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA | 0x80);
  200. if (val) {
  201. isac_interrupt(cs, val);
  202. }
  203. }
  204. if (ista & 0x10) {
  205. val = 0x01;
  206. isac_interrupt(cs, val);
  207. }
  208. ista  = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA);
  209. if ((ista & 0x3f) && icnt) {
  210. icnt--;
  211. goto Start_IPAC;
  212. }
  213. if (!icnt)
  214. printk(KERN_WARNING "ASUS IRQ LOOPn");
  215. writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xFF);
  216. writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xC0);
  217. }
  218. void
  219. release_io_asuscom(struct IsdnCardState *cs)
  220. {
  221. int bytecnt = 8;
  222. if (cs->hw.asus.cfg_reg)
  223. release_region(cs->hw.asus.cfg_reg, bytecnt);
  224. }
  225. static void
  226. reset_asuscom(struct IsdnCardState *cs)
  227. {
  228. long flags;
  229. if (cs->subtyp == ASUS_IPAC)
  230. writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x20);
  231. else
  232. byteout(cs->hw.asus.adr, ASUS_RESET); /* Reset On */
  233. save_flags(flags);
  234. sti();
  235. set_current_state(TASK_UNINTERRUPTIBLE);
  236. schedule_timeout((10*HZ)/1000);
  237. if (cs->subtyp == ASUS_IPAC)
  238. writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x0);
  239. else
  240. byteout(cs->hw.asus.adr, 0); /* Reset Off */
  241. set_current_state(TASK_UNINTERRUPTIBLE);
  242. schedule_timeout((10*HZ)/1000);
  243. if (cs->subtyp == ASUS_IPAC) {
  244. writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_CONF, 0x0);
  245. writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ACFG, 0xff);
  246. writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_AOE, 0x0);
  247. writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xc0);
  248. writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_PCFG, 0x12);
  249. }
  250. restore_flags(flags);
  251. }
  252. static int
  253. Asus_card_msg(struct IsdnCardState *cs, int mt, void *arg)
  254. {
  255. switch (mt) {
  256. case CARD_RESET:
  257. reset_asuscom(cs);
  258. return(0);
  259. case CARD_RELEASE:
  260. release_io_asuscom(cs);
  261. return(0);
  262. case CARD_INIT:
  263. cs->debug |= L1_DEB_IPAC;
  264. inithscxisac(cs, 3);
  265. return(0);
  266. case CARD_TEST:
  267. return(0);
  268. }
  269. return(0);
  270. }
  271. #ifdef __ISAPNP__
  272. static struct isapnp_device_id asus_ids[] __initdata = {
  273. { ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
  274.   ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688), 
  275.   (unsigned long) "Asus1688 PnP" },
  276. { ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690),
  277.   ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690), 
  278.   (unsigned long) "Asus1690 PnP" },
  279. { ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020),
  280.   ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020), 
  281.   (unsigned long) "Isurf2 PnP" },
  282. { ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000),
  283.   ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000), 
  284.   (unsigned long) "Iscas TE320" },
  285. { 0, }
  286. };
  287. static struct isapnp_device_id *adev = &asus_ids[0];
  288. static struct pci_bus *pnp_c __devinitdata = NULL;
  289. #endif
  290. int __init
  291. setup_asuscom(struct IsdnCard *card)
  292. {
  293. int bytecnt;
  294. struct IsdnCardState *cs = card->cs;
  295. u_char val;
  296. char tmp[64];
  297. strcpy(tmp, Asuscom_revision);
  298. printk(KERN_INFO "HiSax: Asuscom ISDNLink driver Rev. %sn", HiSax_getrev(tmp));
  299. if (cs->typ != ISDN_CTYPE_ASUSCOM)
  300. return (0);
  301. #ifdef __ISAPNP__
  302. if (!card->para[1] && isapnp_present()) {
  303. struct pci_bus *pb;
  304. struct pci_dev *pd;
  305. while(adev->card_vendor) {
  306. if ((pb = isapnp_find_card(adev->card_vendor,
  307. adev->card_device, pnp_c))) {
  308. pnp_c = pb;
  309. pd = NULL;
  310. if ((pd = isapnp_find_dev(pnp_c,
  311. adev->vendor, adev->function, pd))) {
  312. printk(KERN_INFO "HiSax: %s detectedn",
  313. (char *)adev->driver_data);
  314. pd->prepare(pd);
  315. pd->deactivate(pd);
  316. pd->activate(pd);
  317. card->para[1] = pd->resource[0].start;
  318. card->para[0] = pd->irq_resource[0].start;
  319. if (!card->para[0] || !card->para[1]) {
  320. printk(KERN_ERR "AsusPnP:some resources are missing %ld/%lxn",
  321. card->para[0], card->para[1]);
  322. pd->deactivate(pd);
  323. return(0);
  324. }
  325. break;
  326. } else {
  327. printk(KERN_ERR "AsusPnP: PnP error card found, no devicen");
  328. }
  329. }
  330. adev++;
  331. pnp_c=NULL;
  332. if (!adev->card_vendor) {
  333. printk(KERN_INFO "AsusPnP: no ISAPnP card foundn");
  334. return(0);
  335. }
  336. }
  337. #endif
  338. bytecnt = 8;
  339. cs->hw.asus.cfg_reg = card->para[1];
  340. cs->irq = card->para[0];
  341. if (check_region((cs->hw.asus.cfg_reg), bytecnt)) {
  342. printk(KERN_WARNING
  343.        "HiSax: %s config port %x-%x already in usen",
  344.        CardType[card->typ],
  345.        cs->hw.asus.cfg_reg,
  346.        cs->hw.asus.cfg_reg + bytecnt);
  347. return (0);
  348. } else {
  349. request_region(cs->hw.asus.cfg_reg, bytecnt, "asuscom isdn");
  350. }
  351. printk(KERN_INFO "ISDNLink: defined at 0x%x IRQ %dn",
  352. cs->hw.asus.cfg_reg, cs->irq);
  353. cs->BC_Read_Reg = &ReadHSCX;
  354. cs->BC_Write_Reg = &WriteHSCX;
  355. cs->BC_Send_Data = &hscx_fill_fifo;
  356. cs->cardmsg = &Asus_card_msg;
  357. val = readreg(cs->hw.asus.cfg_reg + ASUS_IPAC_ALE, 
  358. cs->hw.asus.cfg_reg + ASUS_IPAC_DATA, IPAC_ID);
  359. if ((val == 1) || (val == 2)) {
  360. cs->subtyp = ASUS_IPAC;
  361. cs->hw.asus.adr  = cs->hw.asus.cfg_reg + ASUS_IPAC_ALE;
  362. cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA;
  363. cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA;
  364. test_and_set_bit(HW_IPAC, &cs->HW_Flags);
  365. cs->readisac = &ReadISAC_IPAC;
  366. cs->writeisac = &WriteISAC_IPAC;
  367. cs->readisacfifo = &ReadISACfifo_IPAC;
  368. cs->writeisacfifo = &WriteISACfifo_IPAC;
  369. cs->irq_func = &asuscom_interrupt_ipac;
  370. printk(KERN_INFO "Asus: IPAC version %xn", val);
  371. } else {
  372. cs->subtyp = ASUS_ISACHSCX;
  373. cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_ADR;
  374. cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_ISAC;
  375. cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_HSCX;
  376. cs->hw.asus.u7 = cs->hw.asus.cfg_reg + ASUS_CTRL_U7;
  377. cs->hw.asus.pots = cs->hw.asus.cfg_reg + ASUS_CTRL_POTS;
  378. cs->readisac = &ReadISAC;
  379. cs->writeisac = &WriteISAC;
  380. cs->readisacfifo = &ReadISACfifo;
  381. cs->writeisacfifo = &WriteISACfifo;
  382. cs->irq_func = &asuscom_interrupt;
  383. ISACVersion(cs, "ISDNLink:");
  384. if (HscxVersion(cs, "ISDNLink:")) {
  385. printk(KERN_WARNING
  386.       "ISDNLink: wrong HSCX versions check IO addressn");
  387. release_io_asuscom(cs);
  388. return (0);
  389. }
  390. }
  391. printk(KERN_INFO "ISDNLink: resetting cardn");
  392. reset_asuscom(cs);
  393. return (1);
  394. }