Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2030 lines
71 KiB

  1. /*-------------------------------------------------------------------
  2. | ssci.c - low level interface routines to rocketport hardware.
  3. 03-16-98, add sModemSendROW for RocketModem - jl
  4. 02-05-98, add sModemReset for RocketModem - jl
  5. 10-22-96, add ReadAiopID to PCI case as hardware verification. - kpb
  6. Copyright 1993-98 Comtrol Corporation. All rights reserved.
  7. |--------------------------------------------------------------------*/
  8. #include "precomp.h"
  9. #define ONE_SECOND 10
  10. #define TWO_SECONDS (2 * ONE_SECOND)
  11. #define THREE_SECONDS (3 * ONE_SECOND)
  12. #define FOUR_SECONDS (4 * ONE_SECOND)
  13. #define FIVE_SECONDS (5 * ONE_SECOND)
  14. #define TENTH_SECOND (ONE_SECOND / 10)
  15. #define HALF_SECOND (ONE_SECOND / 2)
  16. // #define DUMPDATA 1
  17. #ifdef DUMPDATA
  18. // in case of changed responses from modem, the following allows
  19. // the unrecognized responses to be dumped to log...
  20. void DumpResponseByte(char buffer);
  21. char DumpArray[512];
  22. int DumpIndex = 0;
  23. #endif
  24. #ifdef PPC
  25. // #define INTEL_ORDER 1
  26. #endif
  27. #ifdef ALPHA
  28. #define INTEL_ORDER 1
  29. #define WORD_ALIGN 1
  30. #endif
  31. #ifdef i386
  32. #define INTEL_ORDER 1
  33. #endif
  34. #ifdef MIPS
  35. // #define INTEL_ORDER 1
  36. #endif
  37. /* Master copy of AIOP microcode. Organized as DWORDs. The 1st word of each
  38. DWORD holds the microcode index, the second word holds the microcode
  39. data. */
  40. unsigned char MasterMCode1[MCODE1_SIZE] =
  41. {
  42. /* indl indh dlo dhi */
  43. 0x00, 0x09, 0xf6, 0x82,
  44. 0x02, 0x09, 0x86, 0xfb,
  45. 0x04, 0x09, 0x00, 0x0a,
  46. 0x06, 0x09, 0x01, 0x0a,
  47. 0x08, 0x09, 0x8a, 0x13,
  48. 0x0a, 0x09, 0xc5, 0x11,
  49. 0x0c, 0x09, 0x86, 0x85,
  50. 0x0e, 0x09, 0x20, 0x0a,
  51. 0x10, 0x09, 0x21, 0x0a,
  52. 0x12, 0x09, 0x41, 0xff,
  53. 0x14, 0x09, 0x82, 0x00,
  54. 0x16, 0x09, 0x82, 0x7b,
  55. 0x18, 0x09, 0x8a, 0x7d,
  56. 0x1a, 0x09, 0x88, 0x81,
  57. 0x1c, 0x09, 0x86, 0x7a,
  58. 0x1e, 0x09, 0x84, 0x81,
  59. 0x20, 0x09, 0x82, 0x7c,
  60. 0x22, 0x09, 0x0a, 0x0a
  61. };
  62. /* Registers within microcode. Organized as DWORDs. The 1st word of each
  63. DWORD holds the microcode index of that register, the 2nd DWORD holds
  64. the current contents of that register. */
  65. unsigned char MCode1Reg[MCODE1REG_SIZE] =
  66. {
  67. /* indl indh dlo dhi */
  68. 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */
  69. 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */
  70. 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */
  71. 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */
  72. 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */
  73. 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */
  74. 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */
  75. 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */
  76. 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */
  77. 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */
  78. 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */
  79. 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */
  80. 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */
  81. };
  82. /* Controller structures */
  83. /* IRQ number to MUDBAC register 2 mapping */
  84. unsigned char sIRQMap[16] =
  85. {
  86. 0,0,0,0x10,0x20,0x30,0,0,0,0x40,0x50,0x60,0x70,0,0,0x80
  87. };
  88. //unsigned char sBitMapClrTbl[8] =
  89. // 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f
  90. //unsigned char sBitMapSetTbl[8] =
  91. // 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
  92. /***************************************************************************
  93. Function: sInitController
  94. Purpose: Initialization of controller global registers and controller
  95. structure.
  96. Call: **** This version of the call for all except Windows NT ****
  97. sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize,
  98. IRQNum,Frequency,PeriodicOnly)
  99. Call: **** This version of the call for Windows NT ***
  100. sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,PhyAiopIOList,
  101. AiopIOListSize,IRQNum,Frequency,PeriodicOnly)
  102. CONTROLLER_T *CtlP; Ptr to controller structure
  103. int CtlNum; Controller number
  104. BIOA_T MudbacIO; Mudbac base I/O address. For Win NT this
  105. is the TranslatedAddress returned by HalTranslateBusAddress().
  106. BIOA_T *AiopIOList; List of I/O addresses for each AIOP.
  107. This list must be in the order the AIOPs will be found on the
  108. controller. Once an AIOP in the list is not found, it is
  109. assumed that there are no more AIOPs on the controller.
  110. For Win NT these are the TranslatedAddresses returned by
  111. HalTranslateBusAddress().
  112. unsigned int *PhyAiopIOList; List of physical I/O addresses for
  113. each AIOP, used by Win NT only. These are the physical
  114. addresses corresponding to the TranslatedAddresses in
  115. AiopIOList.
  116. int AiopIOListSize; Number of addresses in AiopIOList
  117. int IRQNum; Interrupt Request number. Can be any of the following:
  118. 0: Disable global interrupts
  119. 3: IRQ 3
  120. 4: IRQ 4
  121. 5: IRQ 5
  122. 9: IRQ 9
  123. 10: IRQ 10
  124. 11: IRQ 11
  125. 12: IRQ 12
  126. 15: IRQ 15
  127. unsigned char Frequency: A flag identifying the frequency
  128. of the periodic interrupt, can be any one of the following:
  129. FREQ_DIS - periodic interrupt disabled
  130. FREQ_137HZ - 137 Hertz
  131. FREQ_69HZ - 69 Hertz
  132. FREQ_34HZ - 34 Hertz
  133. FREQ_17HZ - 17 Hertz
  134. FREQ_9HZ - 9 Hertz
  135. FREQ_4HZ - 4 Hertz
  136. If IRQNum is set to 0 the Frequency parameter is
  137. overidden, it is forced to a value of FREQ_DIS.
  138. int PeriodicOnly: TRUE if all interrupts except the periodic
  139. interrupt are to be blocked.
  140. FALSE is both the periodic interrupt and
  141. other channel interrupts are allowed.
  142. If IRQNum is set to 0 the PeriodicOnly parameter is
  143. overidden, it is forced to a value of FALSE.
  144. Return: int: 0 on success, errcode on failure
  145. Comments: This function must be called immediately after sSetChannelDefaults()
  146. for each controller in the system.
  147. If periodic interrupts are to be disabled but AIOP interrupts
  148. are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE.
  149. If interrupts are to be completely disabled set IRQNum to 0.
  150. Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an
  151. invalid combination.
  152. This function performs initialization of global interrupt modes,
  153. but it does not actually enable global interrupts. To enable
  154. and disable global interrupts use functions sEnGlobalInt() and
  155. sDisGlobalInt(). Enabling of global interrupts is normally not
  156. done until all other initializations are complete.
  157. Even if interrupts are globally enabled, they must also be
  158. individually enabled for each channel that is to generate
  159. interrupts.
  160. Warnings: No range checking on any of the parameters is done.
  161. No context switches are allowed while executing this function.
  162. After this function all AIOPs on the controller are disabled,
  163. they can be enabled with sEnAiop().
  164. */
  165. int sInitController(CONTROLLER_T *CtlP,
  166. // int CtlNum,
  167. BIOA_T MudbacIO,
  168. BIOA_T *AiopIOList,
  169. unsigned int *PhyAiopIOList,
  170. int AiopIOListSize,
  171. int IRQNum,
  172. unsigned char Frequency,
  173. int PeriodicOnly,
  174. int BusType,
  175. int prescaler)
  176. {
  177. // unsigned char MudbacID; /* MUDBAC ID byte*/
  178. int i;
  179. BIOA_T io; /* an I/O address */
  180. unsigned int pio; /* physical I/O address for Win NT */
  181. WIOA_T IoIndexAddr;
  182. WIOA_T IoIndexData;
  183. // IoIndexAddr=(PUSHORT)((PUCHAR)io+_INDX_ADDR);
  184. // IoIndexData=(PUSHORT)((PUCHAR)io+_INDX_DATA);
  185. //CtlP->CtlNum = CtlNum;
  186. CtlP->BusType = BusType;
  187. CtlP->PortsPerAiop = 8;
  188. if (CtlP->BusType == Isa)
  189. {
  190. MyKdPrint(D_Ssci,("One ISA ROCKET \n"))
  191. CtlP->CtlID = CTLID_0001; /* controller release 1 */
  192. if (AiopIOListSize == 0)
  193. AiopIOListSize = 32; // we figure out
  194. /* If we get here controller found, init MUDBAC and controller struct */
  195. CtlP->MBaseIO = MudbacIO;
  196. CtlP->MReg1IO = MudbacIO + 1;
  197. CtlP->MReg2IO = MudbacIO + 2;
  198. CtlP->MReg3IO = MudbacIO + 3;
  199. if (IRQNum > 15) IRQNum = 0; // limit
  200. if (sIRQMap[IRQNum] == 0) // interrupts globally disabled
  201. {
  202. MyKdPrint(D_Ssci,("No IRQ\n"))
  203. CtlP->MReg2 = 0; // interrupt disable
  204. CtlP->MReg3 = 0; // no periodic interrupts
  205. }
  206. else
  207. {
  208. MyKdPrint(D_Ssci,("IRQ used:%d\n",IRQNum))
  209. CtlP->MReg2 = sIRQMap[IRQNum]; // set IRQ number
  210. CtlP->MReg3 = Frequency; // set frequency
  211. if(PeriodicOnly) // periodic interrupt only
  212. {
  213. CtlP->MReg3 |= PERIODIC_ONLY;
  214. }
  215. }
  216. sOutB(CtlP->MReg2IO,CtlP->MReg2);
  217. sOutB(CtlP->MReg3IO,CtlP->MReg3);
  218. sControllerEOI(CtlP); /* clear EOI if warm init */
  219. sDisGlobalInt(CtlP);
  220. MyKdPrint(D_Ssci,("Disabled ISA interrupts Mreg2:%x := %x\n",
  221. CtlP->MReg2IO,CtlP->MReg2))
  222. /* Init AIOPs */
  223. CtlP->NumAiop = 0;
  224. for(i = 0;i < AiopIOListSize;i++)
  225. {
  226. io = AiopIOList[i];
  227. IoIndexAddr=(PUSHORT)(io+_INDX_ADDR);
  228. IoIndexData=(PUSHORT)(io+_INDX_DATA);
  229. pio = PhyAiopIOList[i]; /* io points to port, pio is the adrs */
  230. MyKdPrint(D_Ssci,("io=%xH pio=%xH\n", (unsigned int)io,
  231. (unsigned int)pio))
  232. CtlP->AiopIO[i] = (WIOA_T)io;
  233. CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
  234. MyKdPrint(D_Ssci,("Setup AIOP io, MReg2IO=%xH\n",
  235. (unsigned int)CtlP->MReg2IO))
  236. sOutB((CtlP->MReg2IO),(unsigned char)(CtlP->MReg2 | (i & 0x03))); /* AIOP index */
  237. sOutB(MudbacIO,(unsigned char)(pio >> 6)); /* set up AIOP I/O in MUDBAC */
  238. MyKdPrint(D_Ssci,("Enable AIOP\n"))
  239. sEnAiop(CtlP,i); /* enable the AIOP */
  240. MyKdPrint(D_Ssci,("Read AIOP ID\n"))
  241. CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
  242. if(CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
  243. {
  244. sDisAiop(CtlP,i); /* disable AIOP */
  245. break; /* done looking for AIOPs */
  246. }
  247. MyKdPrint(D_Ssci,("Read AIOP numchan\n"))
  248. CtlP->AiopNumChan[i] = sReadAiopNumChan((WIOA_T)io); /* num channels in AIOP */
  249. MyKdPrint(D_Ssci,("Setup Aiop Clk\n"))
  250. sOutW((WIOA_T)IoIndexAddr,_CLK_PRE); /* clock prescaler */
  251. //sOutB((PUCHAR)IoIndexData,CLOCK_PRESC);
  252. sOutB((PUCHAR)IoIndexData, (BYTE)prescaler);
  253. CtlP->NumAiop++; /* bump count of AIOPs */
  254. MyKdPrint(D_Ssci,("Setup aiop done\n"))
  255. sDisAiop(CtlP,i); /* disable AIOP */
  256. }
  257. MyKdPrint(D_Ssci,("One ISA ROCKET with %d aiops\n",CtlP->NumAiop))
  258. if(CtlP->NumAiop == 0) {
  259. MyKdPrint(D_Error,("ISA NumAiop == 0\n"))
  260. return 1; // error
  261. }
  262. return 0; // ok // old:(CtlP->NumAiop);
  263. } // end of ISA controller init
  264. else if(CtlP->BusType == PCIBus)
  265. {
  266. MyKdPrint(D_Ssci,("One PCI ROCKET \n"))
  267. //CtlP->CtlNum = CtlNum;
  268. CtlP->CtlID = CTLID_0001; /* controller release 1 */
  269. MyKdPrint(D_Ssci,("Ctrl(%x) IrqNum: %x \n", CtlP, IRQNum))
  270. if(IRQNum == 0) /* interrupts disabled for this controler*/
  271. {
  272. CtlP->PCI1 = 0x0008; /* no periodic, interrupts disabled */
  273. }
  274. else
  275. {
  276. Frequency >>= 4; /*Right shift 4 times to move 4:7 to 0:3 */
  277. CtlP->PCI1 |= Frequency;
  278. if(PeriodicOnly) /* periodic interrupt only */
  279. {
  280. CtlP->PCI1 |= PER_ONLY_PCI;
  281. }
  282. }
  283. CtlP->PCI1IO = (WIOA_T)((BIOA_T)AiopIOList[0] + _PCI_INT_FUNC);
  284. MyKdPrint(D_Ssci,("Setting PCI config reg with %x at %x\n",
  285. CtlP->PCI1,CtlP->PCI1IO)) // move these calls to ssci.h
  286. sOutW(CtlP->PCI1IO,CtlP->PCI1);
  287. ////////////////////new/////////////////////
  288. ///CtlP->PortsPerAiop = 8;
  289. switch (CtlP->PCI_DevID)
  290. {
  291. case PCI_DEVICE_4Q: // 4 Port Quadcable
  292. case PCI_DEVICE_4RJ: // 4 Port RJ
  293. CtlP->PortsPerAiop = 4;
  294. break;
  295. case PCI_DEVICE_8RJ: // 8 Port RJ
  296. case PCI_DEVICE_8O: // 8 Port Octacable
  297. case PCI_DEVICE_8I: // 8 Port interface
  298. case PCI_DEVICE_16I: //16 Port interface
  299. case PCI_DEVICE_32I: // 32 Port interface
  300. case PCI_DEVICE_SIEMENS8 :
  301. case PCI_DEVICE_SIEMENS16 :
  302. CtlP->PortsPerAiop = 8;
  303. break;
  304. case PCI_DEVICE_RMODEM6 :
  305. CtlP->PortsPerAiop = 6;
  306. break;
  307. case PCI_DEVICE_RMODEM4 :
  308. CtlP->PortsPerAiop = 4;
  309. break;
  310. case PCI_DEVICE_RPLUS4 :
  311. case PCI_DEVICE_RPLUS8 :
  312. CtlP->PortsPerAiop = 4;
  313. break;
  314. case PCI_DEVICE_RPLUS2 :
  315. case PCI_DEVICE_422RPLUS2 :
  316. CtlP->PortsPerAiop = 2;
  317. break;
  318. default:
  319. //Eprintf("Err,Bad PCI DevID:%d", CtlP->PCI_DevID);
  320. break;
  321. } // switch
  322. ///////////////////////////////////////////
  323. /* Init AIOPs */
  324. CtlP->NumAiop = 0;
  325. for(i=0; i < AiopIOListSize; i++)
  326. {
  327. io = AiopIOList[i];
  328. CtlP->AiopIO[i] = (WIOA_T)io;
  329. CtlP->AiopIntChanIO[i] = (BIOA_T)io + _INT_CHAN;
  330. // 10-22-96, add this(only hardware-verification done) kpb.
  331. CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
  332. if(CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
  333. {
  334. break; /* done looking for AIOPs */
  335. }
  336. ///////old CtlP->AiopNumChan[i] = sReadAiopNumChan((WIOA_T)io); /* num channels in AIOP */
  337. ////////////////////new///////////////////////
  338. CtlP->AiopNumChan[i] = CtlP->PortsPerAiop; /* num channels in AIOP */
  339. ///////////////////////////////////////////////////////////////
  340. IoIndexAddr=(WIOA_T)((BIOA_T)io+_INDX_ADDR);
  341. IoIndexData=(WIOA_T)((BIOA_T)io+_INDX_DATA);
  342. sOutW((WIOA_T)IoIndexAddr,_CLK_PRE); /* clock prescaler */
  343. sOutB((BIOA_T)IoIndexData, (BYTE)prescaler);
  344. CtlP->NumAiop++; /* bump count of AIOPs */
  345. }
  346. sDisGlobalIntPCI(CtlP);
  347. sPCIControllerEOI(CtlP); /* clear EOI if warm init */
  348. MyKdPrint(D_Ssci,("One PCI ROCKET with %d aiops\n",CtlP->NumAiop))
  349. if(CtlP->NumAiop == 0) {
  350. MyKdPrint(D_Error,("PCI NumAiop == 0\n"))
  351. return 2; // error
  352. }
  353. return 0; // old:(CtlP->NumAiop);
  354. } /*end of PCI rocket INIT */
  355. else { /* not PCI or ISA */
  356. MyKdPrint(D_Error,("Not ISA or PCI\n"))
  357. return 3; // old:(CTLID_NULL);
  358. }
  359. return 0;
  360. }
  361. /***************************************************************************
  362. Function: sReadAiopID
  363. Purpose: Read the AIOP idenfication number directly from an AIOP.
  364. Call: sReadAiopID(io)
  365. BIOA_T io: AIOP base I/O address
  366. Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X
  367. is replace by an identifying number.
  368. Flag AIOPID_NULL if no valid AIOP is found
  369. Warnings: No context switches are allowed while executing this function.
  370. -------------------------------------------------------------------------*/
  371. int _CDECL sReadAiopID(BIOA_T io)
  372. {
  373. unsigned char AiopID; /* ID byte from AIOP */
  374. sOutB(io + _CMD_REG,RESET_ALL); /* reset AIOP */
  375. sOutB(io + _CMD_REG,0x0);
  376. AiopID = sInB(io + _CHN_STAT0) & 0x07;
  377. if (AiopID == 0x06) /* AIOP release 1 */
  378. return(AIOPID_0001);
  379. else /* AIOP does not exist */
  380. return(AIOPID_NULL);
  381. }
  382. /***************************************************************************
  383. Function: sReadAiopNumChan
  384. Purpose: Read the number of channels available in an AIOP directly from
  385. an AIOP.
  386. Call: sReadAiopNumChan(io)
  387. WIOA_T io: AIOP base I/O address
  388. Return: int: The number of channels available
  389. Comments: The number of channels is determined by write/reads from identical
  390. offsets within the SRAM address spaces for channels 0 and 4.
  391. If the channel 4 space is mirrored to channel 0 it is a 4 channel
  392. AIOP, otherwise it is an 8 channel.
  393. Warnings: No context switches are allowed while executing this function.
  394. -------------------------------------------------------------------------*/
  395. int _CDECL sReadAiopNumChan(WIOA_T io)
  396. {
  397. unsigned int x;
  398. WIOA_T IoIndexAddr;
  399. WIOA_T IoIndexData;
  400. IoIndexAddr = (PUSHORT)((PUCHAR)io+_INDX_ADDR);
  401. IoIndexData = (PUSHORT)((PUCHAR)io+_INDX_DATA);
  402. sOutDW((DWIOA_T)IoIndexAddr, 0x12340000L); /* write to chan 0 SRAM */
  403. sOutW(IoIndexAddr,0); /* read from SRAM, chan 0 */
  404. x = sInW(IoIndexData);
  405. sOutW(IoIndexAddr, 0x4000); /* read from SRAM, chan 4 */
  406. if (x != sInW(IoIndexData)) /* if different must be 8 chan */
  407. return(8);
  408. else
  409. return(4);
  410. }
  411. /***************************************************************************
  412. Function: sInitChan
  413. Purpose: Initialization of a channel and channel structure
  414. Call: sInitChan(CtlP,ChP,AiopNum,ChanNum)
  415. CONTROLLER_T *CtlP; Ptr to controller structure
  416. CHANPTR_T ChP; Ptr to channel structure
  417. int AiopNum; AIOP number within controller
  418. int ChanNum; Channel number within AIOP
  419. Return: int: TRUE if initialization succeeded, FALSE if it fails because channel
  420. number exceeds number of channels available in AIOP.
  421. Comments: This function must be called before a channel can be used.
  422. Warnings: No range checking on any of the parameters is done.
  423. No context switches are allowed while executing this function.
  424. -------------------------------------------------------------------------*/
  425. int _CDECL sInitChan(CONTROLLER_T *CtlP,
  426. CHANPTR_T ChP,
  427. int AiopNum,
  428. int ChanNum)
  429. {
  430. int i;
  431. WIOA_T AiopIO;
  432. WIOA_T ChIOOff; /* I/O offset of chan with AIOP */
  433. unsigned char *ChMCode; /* channel copy of microcode */
  434. unsigned char *MasterMCode; /* master copy of microcode */
  435. unsigned int ChOff; /* SRAM offset of channel within AIOP */
  436. static unsigned char MCode[4]; /* local copy of microcode double word*/
  437. WIOA_T AiopIndexAddr;
  438. if(ChanNum >= CtlP->AiopNumChan[AiopNum])
  439. return(FALSE); /* exceeds num chans in AIOP */
  440. /* Channel, AIOP, and controller identifiers */
  441. ChP->CtlP = CtlP;
  442. ChP->ChanID = CtlP->AiopID[AiopNum];
  443. ChP->AiopNum = AiopNum;
  444. ChP->ChanNum = ChanNum;
  445. /* Tx FIFO size */
  446. sSetTxSize(ChP,MAXTX_SIZE);
  447. /* Global direct addresses */
  448. AiopIO = CtlP->AiopIO[AiopNum];
  449. ChP->Cmd = (BIOA_T)AiopIO + _CMD_REG;
  450. ChP->IntChan = (BIOA_T)AiopIO + _INT_CHAN;
  451. ChP->IntMask = (BIOA_T)AiopIO + _INT_MASK;
  452. AiopIndexAddr=(WIOA_T)((BIOA_T)AiopIO+_INDX_ADDR);
  453. ChP->IndexAddr = (DWIOA_T)AiopIndexAddr;
  454. ChP->IndexData = (WIOA_T)((BIOA_T)AiopIO + _INDX_DATA);
  455. /* Channel direct addresses */
  456. ChIOOff = (WIOA_T)((BIOA_T)AiopIO + ChP->ChanNum * 2);
  457. ChP->TxRxData = (WIOA_T)((BIOA_T)ChIOOff + _TD0);
  458. ChP->ChanStat = (WIOA_T)((BIOA_T)ChIOOff + _CHN_STAT0);
  459. ChP->TxRxCount =(WIOA_T)((BIOA_T)ChIOOff + _FIFO_CNT0);
  460. ChP->IntID = (BIOA_T)AiopIO + ChP->ChanNum + _INT_ID0;
  461. /* Channel microcode initialization. This writes a complete copy
  462. of the microcode into the SRAM. */
  463. MasterMCode = MasterMCode1;
  464. for(i = 0;i < MCODE1_SIZE; i+=4)
  465. {
  466. /* get low byte of index */
  467. MCode[0] = MasterMCode[i];
  468. /* get high byte of index */
  469. MCode[1] = MasterMCode[i+1] + 0x10 * ChanNum;
  470. /* get low microcode byte */
  471. MCode[2] = MasterMCode[i+2];
  472. /* get high microcode byte */
  473. MCode[3] = MasterMCode[i+3];
  474. sOutDW(ChP->IndexAddr,*((ULONGPTR_T)&MCode[0]));
  475. }
  476. /* Initialize SSCI copy of microcode registers. This saves only the portion
  477. of the microcode that will be used as registers. */
  478. ChMCode = ChP->MCode;
  479. MasterMCode = MCode1Reg;
  480. for(i = 0;i < MCODE1REG_SIZE; i+=4)
  481. {
  482. /* low byte of index */
  483. ChMCode[i] = MasterMCode[i];
  484. /* high byte of index */
  485. ChMCode[i+1] = MasterMCode[i+1] + 0x10 * ChanNum;
  486. /* low microcode byte */
  487. ChMCode[i+2] = MasterMCode[i+2];
  488. /* high microcode byte */
  489. ChMCode[i+3] = MasterMCode[i+3];
  490. }
  491. /* Indexed registers */
  492. ChOff = (unsigned int)ChanNum * 0x1000;
  493. ChP->BaudDiv[0] = (unsigned char)(ChOff + _BAUD);
  494. ChP->BaudDiv[1] = (unsigned char)((ChOff + _BAUD) >> 8);
  495. //ChP->BaudDiv[2] = (unsigned char)BRD9600;
  496. //ChP->BaudDiv[3] = (unsigned char)(BRD9600 >> 8);
  497. // just default the baud register to something..
  498. ChP->BaudDiv[2] = (unsigned char)47;
  499. ChP->BaudDiv[3] = (unsigned char)(47 >> 8);
  500. sOutDW(ChP->IndexAddr,*(ULONGPTR_T)&ChP->BaudDiv[0]);
  501. ChP->TxControl[0] = (unsigned char)(ChOff + _TX_CTRL);
  502. ChP->TxControl[1] = (unsigned char)((ChOff + _TX_CTRL) >> 8);
  503. ChP->TxControl[2] = 0;
  504. ChP->TxControl[3] = 0;
  505. sOutDW(ChP->IndexAddr,*(ULONGPTR_T)&ChP->TxControl[0]);
  506. ChP->RxControl[0] = (unsigned char)(ChOff + _RX_CTRL);
  507. ChP->RxControl[1] = (unsigned char)((ChOff + _RX_CTRL) >> 8);
  508. ChP->RxControl[2] = 0;
  509. ChP->RxControl[3] = 0;
  510. sOutDW(ChP->IndexAddr,*(ULONGPTR_T)&ChP->RxControl[0]);
  511. ChP->TxEnables[0] = (unsigned char)(ChOff + _TX_ENBLS);
  512. ChP->TxEnables[1] = (unsigned char)((ChOff + _TX_ENBLS) >> 8);
  513. ChP->TxEnables[2] = 0;
  514. ChP->TxEnables[3] = 0;
  515. sOutDW(ChP->IndexAddr,*(ULONGPTR_T)&ChP->TxEnables[0]);
  516. ChP->TxCompare[0] = (unsigned char)(ChOff + _TXCMP1);
  517. ChP->TxCompare[1] = (unsigned char)((ChOff + _TXCMP1) >> 8);
  518. ChP->TxCompare[2] = 0;
  519. ChP->TxCompare[3] = 0;
  520. sOutDW(ChP->IndexAddr,*(ULONGPTR_T)&ChP->TxCompare[0]);
  521. ChP->TxReplace1[0] = (unsigned char)(ChOff + _TXREP1B1);
  522. ChP->TxReplace1[1] = (unsigned char)((ChOff + _TXREP1B1) >> 8);
  523. ChP->TxReplace1[2] = 0;
  524. ChP->TxReplace1[3] = 0;
  525. sOutDW(ChP->IndexAddr,*(ULONGPTR_T)&ChP->TxReplace1[0]);
  526. ChP->TxReplace2[0] = (unsigned char)(ChOff + _TXREP2);
  527. ChP->TxReplace2[1] = (unsigned char)((ChOff + _TXREP2) >> 8);
  528. ChP->TxReplace2[2] = 0;
  529. ChP->TxReplace2[3] = 0;
  530. sOutDW(ChP->IndexAddr,*(ULONGPTR_T)&ChP->TxReplace2[0]);
  531. ChP->TxFIFOPtrs = ChOff + _TXF_OUTP;
  532. ChP->TxFIFO = ChOff + _TX_FIFO;
  533. sOutB(ChP->Cmd,(unsigned char)(ChanNum | RESTXFCNT)); /* apply reset Tx FIFO count */
  534. sOutB(ChP->Cmd,(unsigned char)ChanNum); /* remove reset Tx FIFO count */
  535. sOutW((WIOA_T)ChP->IndexAddr,(USHORT)ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
  536. sOutW(ChP->IndexData,0);
  537. ChP->RxFIFOPtrs = ChOff + _RXF_OUTP;
  538. ChP->RxFIFO = ChOff + _RX_FIFO;
  539. sOutB(ChP->Cmd,(unsigned char)(ChanNum | RESRXFCNT)); /* apply reset Rx FIFO count */
  540. sOutB(ChP->Cmd,(unsigned char)ChanNum); /* remove reset Rx FIFO count */
  541. sOutW((WIOA_T)ChP->IndexAddr,(USHORT)ChP->RxFIFOPtrs); /* clear Rx out ptr */
  542. sOutW(ChP->IndexData,0);
  543. sOutW((WIOA_T)ChP->IndexAddr,(USHORT)(ChP->RxFIFOPtrs + 2)); /* clear Rx in ptr */
  544. sOutW(ChP->IndexData,0);
  545. ChP->TxPrioCnt = ChOff + _TXP_CNT;
  546. sOutW((WIOA_T)ChP->IndexAddr,(USHORT)ChP->TxPrioCnt);
  547. sOutB((PUCHAR)ChP->IndexData,0);
  548. ChP->TxPrioPtr = ChOff + _TXP_PNTR;
  549. sOutW((WIOA_T)ChP->IndexAddr,(USHORT)ChP->TxPrioPtr);
  550. sOutB((PUCHAR)ChP->IndexData,0);
  551. ChP->TxPrioBuf = ChOff + _TXP_BUF;
  552. sEnRxProcessor(ChP); /* start the Rx processor */
  553. return(TRUE);
  554. }
  555. /*****************************************************************************
  556. Function: sGetRxErrStatus
  557. Purpose: Get a channel's receive error status
  558. Call: sGetRxErrStatus(ChP)
  559. CHANPTR_T ChP; Ptr to channel structure
  560. Return: unsigned char: Receive error status, can be 0 if there are no
  561. errors or any combination of the following flags:
  562. STMBREAK: BREAK
  563. STMFRAME: framing error
  564. STMRCVROVR: receiver over run error
  565. STMPARITY: parity error
  566. Warnings: The channel must be in Rx Status Mode (see sEnRxStatusMode())
  567. before calling this function.
  568. No context switches are allowed while executing this function.
  569. -------------------------------------------------------------------------*/
  570. unsigned char _CDECL sGetRxErrStatus(CHANPTR_T ChP)
  571. {
  572. unsigned int RxFIFOOut; /* Rx FIFO out status ptr */
  573. sOutW((WIOA_T)ChP->IndexAddr, (USHORT)ChP->RxFIFOPtrs); /* get Rx FIFO out status ptr */
  574. RxFIFOOut = sInW(ChP->IndexData) * 2 + 1;
  575. sOutW((WIOA_T)ChP->IndexAddr, (USHORT)(ChP->RxFIFO + RxFIFOOut)); /* return the status */
  576. return(sInB((PUCHAR)ChP->IndexData) & (STMBREAK | STMFRAME | STMPARITY | STMRCVROVR));
  577. }
  578. /***************************************************************************
  579. Function: sSetParity
  580. Purpose: Set parity to none, odd, or even.
  581. Call: sSetParity(ChP,Parity)
  582. CHANPTR_T ChP; Ptr to channel structure
  583. int Parity; Parity, can be one of the following:
  584. 0: no parity
  585. 1: odd parity
  586. 2: even parity
  587. Return: void
  588. Comments: Function sSetParity() can be used in place of functions sEnParity(),
  589. sDisParity(), sSetOddParity(), and sSetEvenParity().
  590. -------------------------------------------------------------------------*/
  591. void _CDECL sSetParity(CHANPTR_T ChP,int Parity)
  592. {
  593. if (Parity == 0)
  594. {
  595. ChP->TxControl[2] &= ~PARITY_EN;
  596. }
  597. else if (Parity == 1)
  598. {
  599. ChP->TxControl[2] |= PARITY_EN;
  600. ChP->TxControl[2] &= ~EVEN_PAR;
  601. }
  602. else if (Parity == 2)
  603. {
  604. ChP->TxControl[2] |= (PARITY_EN | EVEN_PAR);
  605. }
  606. sOutDW(ChP->IndexAddr,*(ULONGPTR_T)&ChP->TxControl[0]);
  607. }
  608. /***************************************************************************
  609. Function: sStopRxProcessor
  610. Purpose: Stop the receive processor from processing a channel's microcode.
  611. Call: sStopRxProcessor(ChP)
  612. CHANPTR_T ChP; Ptr to channel structure
  613. Return: void
  614. Comments: The receive processor can be started again with sStartRxProcessor().
  615. This function causes the receive processor to skip over the
  616. microcode for the stopped channel. It does not stop it from
  617. processing other channels.
  618. Warnings: No context switches are allowed while executing this function.
  619. Do not leave the receive processor stopped for more than one
  620. character time.
  621. After calling this function a delay of 4 uS is required to ensure
  622. that the receive processor is no longer processing microcode for
  623. this channel.
  624. -------------------------------------------------------------------------*/
  625. void _CDECL sStopRxProcessor(CHANPTR_T ChP)
  626. {
  627. unsigned char MCode[4]; /* 1st two microcode bytes */
  628. MCode[0] = ChP->MCode[0];
  629. MCode[1] = ChP->MCode[1];
  630. MCode[3] = ChP->MCode[3];
  631. MCode[2] = 0x0a; /* inc scan cnt inst to freeze Rx proc */
  632. sOutDW(ChP->IndexAddr,*(ULONGPTR_T)&MCode[0]);
  633. }
  634. /***************************************************************************
  635. Function: sStopSWInFlowCtl
  636. Purpose: Stop the receive processor from processing a channel's
  637. software input flow control microcode.
  638. Call: sStopSWInFlowCtl(ChP)
  639. CHANPTR_T ChP; Ptr to channel structure
  640. Return: void
  641. Comments: The receive processor can be started again with sStartRxProcessor().
  642. This function causes the receive processor to skip over the
  643. software input flow control microcode for the stopped channel.
  644. It does not stop it from processing other channels.
  645. Warnings: No context switches are allowed while executing this function.
  646. After calling this function a delay of 1 uS is required to ensure
  647. that the receive processor is no longer processing software input
  648. flow control microcode for this channel.
  649. -------------------------------------------------------------------------*/
  650. void _CDECL sStopSWInFlowCtl(CHANPTR_T ChP)
  651. {
  652. unsigned char MCode[4]; /* 1st two microcode bytes */
  653. MCode[0] = ChP->MCode[0];
  654. MCode[1] = ChP->MCode[1];
  655. MCode[2] = ChP->MCode[2];
  656. MCode[3] = 0x0a; /* inc scan cnt inst to freeze Rx proc */
  657. sOutDW(ChP->IndexAddr,*(ULONGPTR_T)&MCode[0]);
  658. }
  659. /***************************************************************************
  660. Function: sFlushRxFIFO
  661. Purpose: Flush the Rx FIFO
  662. Call: sFlushRxFIFO(ChP)
  663. CHANPTR_T ChP; Ptr to channel structure
  664. Return: void
  665. Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
  666. while it is being flushed the receive processor is stopped
  667. and the transmitter is disabled. After these operations a
  668. 4 uS delay is done before clearing the pointers to allow
  669. the receive processor to stop. These items are handled inside
  670. this function.
  671. Warnings: No context switches are allowed while executing this function.
  672. -------------------------------------------------------------------------*/
  673. void _CDECL sFlushRxFIFO(CHANPTR_T ChP)
  674. {
  675. int i;
  676. unsigned char Ch; /* channel number within AIOP */
  677. int RxFIFOEnabled; /* TRUE if Rx FIFO enabled */
  678. if (sGetRxCnt(ChP) == 0) /* Rx FIFO empty */
  679. return; /* don't need to flush */
  680. RxFIFOEnabled = FALSE;
  681. if (ChP->MCode[RXFIFO_DATA] == RXFIFO_EN) /* Rx FIFO is enabled */
  682. {
  683. RxFIFOEnabled = TRUE;
  684. sDisRxFIFO(ChP); /* disable it */
  685. for (i = 0;i < 2000/200;i++) /* delay 2 uS to allow proc to disable FIFO*/
  686. sInB(ChP->IntChan);
  687. }
  688. sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */
  689. Ch = (unsigned char)sGetChanNum(ChP);
  690. sOutB(ChP->Cmd, (UCHAR)(Ch | RESRXFCNT)); /* apply reset Rx FIFO count */
  691. sOutB(ChP->Cmd,Ch); /* remove reset Rx FIFO count */
  692. sOutW((WIOA_T)ChP->IndexAddr, (USHORT)(ChP->RxFIFOPtrs)); /* clear Rx out ptr */
  693. sOutW(ChP->IndexData,0);
  694. sOutW((WIOA_T)ChP->IndexAddr, (USHORT)(ChP->RxFIFOPtrs + 2)); /* clear Rx in ptr */
  695. sOutW(ChP->IndexData, 0);
  696. if (RxFIFOEnabled)
  697. sEnRxFIFO(ChP); /* enable Rx FIFO */
  698. }
  699. /***************************************************************************
  700. Function: sFlushTxFIFO
  701. Purpose: Flush the Tx FIFO
  702. Call: sFlushTxFIFO(ChP)
  703. CHANPTR_T ChP; Ptr to channel structure
  704. Return: void
  705. Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
  706. while it is being flushed the receive processor is stopped
  707. and the transmitter is disabled. After these operations a
  708. 4 uS delay is done before clearing the pointers to allow
  709. the receive processor to stop. These items are handled inside
  710. this function.
  711. Warnings: No context switches are allowed while executing this function.
  712. -------------------------------------------------------------------------*/
  713. void _CDECL sFlushTxFIFO(CHANPTR_T ChP)
  714. {
  715. int i;
  716. unsigned char Ch; /* channel number within AIOP */
  717. int TxEnabled; /* TRUE if transmitter enabled */
  718. if (sGetTxCnt(ChP) == 0) /* Tx FIFO empty */
  719. return; /* don't need to flush */
  720. TxEnabled = FALSE;
  721. if (ChP->TxControl[3] & TX_ENABLE)
  722. {
  723. TxEnabled = TRUE;
  724. sDisTransmit(ChP); /* disable transmitter */
  725. }
  726. sStopRxProcessor(ChP); /* stop Rx processor */
  727. for (i = 0;i < 4000/200;i++) /* delay 4 uS to allow proc to stop */
  728. sInB(ChP->IntChan);
  729. Ch = (unsigned char)sGetChanNum(ChP);
  730. sOutB(ChP->Cmd,(UCHAR)(Ch | RESTXFCNT)); /* apply reset Tx FIFO count */
  731. sOutB(ChP->Cmd,Ch); /* remove reset Tx FIFO count */
  732. sOutW((WIOA_T)ChP->IndexAddr, (USHORT)(ChP->TxFIFOPtrs)); /* clear Tx in/out ptrs */
  733. sOutW(ChP->IndexData,0);
  734. if (TxEnabled)
  735. sEnTransmit(ChP); /* enable transmitter */
  736. sStartRxProcessor(ChP); /* restart Rx processor */
  737. }
  738. /***************************************************************************
  739. Function: sFlushTxPriorityBuf
  740. Purpose: Flush the Tx priority buffer
  741. Call: sFlushTxPriorityBuf(ChP,unsigned char *Data)
  742. CHANPTR_T ChP; Ptr to channel structure
  743. unsigned char *Data; Next data byte to be transmitted from the
  744. Tx priority buffer before the flush occurred, if any. If
  745. the return value is TRUE a byte is returned in "Data," if
  746. the return value is FALSE nothing is returned in "Data."
  747. Return: int: TRUE if there was data in the Tx priority buffer before
  748. the flush occurs. In this case the next byte that would
  749. have been transmitted is returned in the "Data" parameter.
  750. FALSE if there was no data in the Tx priority buffer before
  751. the flush.
  752. Comments: This flush returns the next byte in the priority buffer to
  753. allow that byte to be sent via sWriteTxByte() after all
  754. transmit flushing is complete. This is done to allow pending
  755. XON and XOFF bytes to be transmitted regardless of the flush.
  756. Warnings: No context switches are allowed while executing this function.
  757. -------------------------------------------------------------------------*/
  758. int _CDECL sFlushTxPriorityBuf(CHANPTR_T ChP,unsigned char *Data)
  759. {
  760. unsigned int PrioState; /* Tx prio buf status, count, and pointer */
  761. unsigned int BufOff; /* Offset of next data byte in Tx prio buf */
  762. WIOA_T IndexAddr;
  763. WIOA_T IndexData;
  764. IndexAddr = (WIOA_T)ChP->IndexAddr;
  765. IndexData = (WIOA_T)ChP->IndexData;
  766. sDisTransmit(ChP);
  767. sOutW(IndexAddr, (USHORT)ChP->TxPrioCnt); /* get priority buf status */
  768. PrioState = sInW(IndexData);
  769. if (PrioState & PRI_PEND) /* data in Tx prio buf */
  770. {
  771. BufOff = PrioState >> 8; /* get offset of next data byte in buf */
  772. sOutW(IndexAddr,(USHORT)(ChP->TxPrioBuf + BufOff));
  773. *Data = sInB((BIOA_T)IndexData); /* return next data byte */
  774. sEnTransmit(ChP);
  775. return(TRUE);
  776. }
  777. sEnTransmit(ChP); /* no data in Tx prio buf */
  778. return(FALSE);
  779. }
  780. /***************************************************************************
  781. Function: sGetTxPriorityCnt
  782. Purpose: Get the number of data bytes in the Tx priority buffer
  783. Call: sGetTxPriorityCnt(ChP)
  784. CHANPTR_T ChP; Ptr to channel structure
  785. Return: unsigned char: The number of data bytes in the Tx FIFO.
  786. Warnings: No context switches are allowed while executing this function.
  787. -------------------------------------------------------------------------*/
  788. unsigned char _CDECL sGetTxPriorityCnt(CHANPTR_T ChP)
  789. {
  790. unsigned char Cnt;
  791. sOutW((WIOA_T)ChP->IndexAddr, (USHORT)ChP->TxPrioCnt); /* get priority buf status */
  792. Cnt = sInB((BIOA_T)ChP->IndexData);
  793. if (Cnt & PRI_PEND)
  794. return(Cnt & 0x1f); /* only lower 5 bits contain count */
  795. else
  796. return(0);
  797. }
  798. #ifndef INTEL_ORDER
  799. /*---------------------------------------------------------------------
  800. sReadRxBlk - MIPS VERSION
  801. |---------------------------------------------------------------------*/
  802. int _CDECL sReadRxBlk(CHANPTR_T ChP,unsigned char *Buffer,int Count)
  803. {
  804. int RetCount;
  805. int WordCount;
  806. int ByteCount = 0;
  807. unsigned short TempWord;
  808. RetCount = sGetRxCnt(ChP); /* number bytes in Rx FIFO */
  809. /* are there pending chars? */
  810. if (RetCount <= 0) /* no data available */
  811. return(0x0);
  812. if (RetCount > Count) /* only dequeue as much as requested */
  813. RetCount = Count;
  814. WordCount = RetCount >> 1; /* compute count as words */
  815. while (WordCount--)
  816. {
  817. TempWord = sInW((WIOA_T)sGetTxRxDataIO(ChP));
  818. Buffer[ByteCount++] = TempWord & 0xff;
  819. Buffer[ByteCount++] = ( TempWord >> 8 ) & 0xff;
  820. }
  821. if (RetCount & 1)
  822. {
  823. Buffer[ByteCount++] = sInB( (BIOA_T)sGetTxRxDataIO(ChP));
  824. }
  825. return(RetCount);
  826. }
  827. #else // NOT MIPS version
  828. /*------------------------------------------------------------------------
  829. Function: sReadRxBlk - X86 INTEL VERSION
  830. Purpose: Read a block of receive data from a channel
  831. Call: sReadRxBlk(ChP,Buffer,Count)
  832. CHANPTR_T ChP; Ptr to channel structure
  833. unsigned char *Buffer; Ptr to buffer for receive data
  834. int Count; Max number of bytes to read
  835. Return: int: Number of bytes actually read from the channel
  836. Warnings: Buffer must be large enough to hold Count characters.
  837. This function must not be called when in Rx Status Mode.
  838. -------------------------------------------------------------------------*/
  839. int _CDECL sReadRxBlk(CHANPTR_T ChP,unsigned char *Buffer,int Count)
  840. {
  841. int RetCount;
  842. int WordCount;
  843. USHORT UNALIGNED *WordP;
  844. WIOA_T io;
  845. RetCount = sGetRxCnt(ChP); // number bytes in Rx FIFO
  846. // are there pending chars?
  847. if (RetCount <= 0) // no data available
  848. return(0x0);
  849. if (RetCount > Count) // only dequeue as much as requested
  850. RetCount = Count;
  851. WordCount = RetCount >> 1; // compute count as words
  852. WordP = (USHORT UNALIGNED *)Buffer; // word ptr to buffer
  853. io = sGetTxRxDataIO(ChP);
  854. #ifdef WORD_ALIGN
  855. while (WordCount--)
  856. {
  857. *WordP++ = sInW(io);
  858. }
  859. #else
  860. sInStrW((PUSHORT)io, WordP, WordCount);
  861. #endif
  862. if (RetCount & 1) // odd count
  863. {
  864. Buffer[RetCount - 1] = sInB((PUCHAR)io); // read last byte
  865. }
  866. return(RetCount);
  867. }
  868. #endif // INTEL X86 version
  869. #ifndef INTEL_ORDER
  870. /*---------------------------------------------------------------------
  871. sWriteTxBlk - MIPS VERSION
  872. |---------------------------------------------------------------------*/
  873. ULONG _CDECL sWriteTxBlk(CHANPTR_T ChP,PUCHAR Buffer,ULONG Count)
  874. {
  875. ULONG RetCount;
  876. ULONG WordCount;
  877. unsigned short TempWordLo;
  878. unsigned short TempWordHi;
  879. int ByteCount = 0;
  880. RetCount = MAXTX_SIZE - (int)sGetTxCnt(ChP); /* open space in Tx FIFO*/
  881. if (RetCount <= 0) /* no space available */
  882. return(0x0);
  883. if (RetCount > Count)
  884. RetCount = Count; /* only enqueue as much as requested */
  885. WordCount = RetCount >> 1 ; /* compute count as words */
  886. while (WordCount--)
  887. {
  888. TempWordLo = Buffer[ByteCount++] & 0xff;
  889. TempWordHi = Buffer[ByteCount++];
  890. TempWordHi = (TempWordHi << 8) & 0xff00; /* shift to high byte */
  891. TempWordHi |= TempWordLo;
  892. sOutW((PUCHAR)sGetTxRxDataIO(ChP), TempWordHi);
  893. }
  894. if (RetCount & 1)
  895. {
  896. sOutB( (PUCHAR)sGetTxRxDataIO(ChP), Buffer[ByteCount++] );
  897. }
  898. return(RetCount);
  899. }
  900. #else // NOT MIPS
  901. /*------------------------------------------------------------------------
  902. Function: sWriteTxBlk
  903. Purpose: Write a block of transmit data to a channel
  904. Call: sWriteTxBlk(ChP,Buffer,Count)
  905. CHANPTR_T ChP; Ptr to channel structure
  906. unsigned char *Buffer; Ptr to buffer containing data to transmit
  907. int Count; Size of buffer in bytes
  908. Return: int: Number of bytes actually written to the channel
  909. -------------------------------------------------------------------------*/
  910. ULONG _CDECL sWriteTxBlk(CHANPTR_T ChP,PUCHAR Buffer,ULONG Count)
  911. {
  912. ULONG RetCount;
  913. ULONG WordCount;
  914. USHORT UNALIGNED *WordP;
  915. WIOA_T io;
  916. // 250, restrict to WORD amounts (boundary access thing)
  917. RetCount = MAXTX_SIZE - sGetTxCnt(ChP);
  918. if (RetCount > Count)
  919. {
  920. RetCount = Count; /* only enqueue as much as requested */
  921. #ifdef WORD_ALIGN
  922. // try to keep aligned on WORD boundary
  923. //if (RetCount & 1)
  924. //{
  925. // if (RetCount > 1)
  926. // --RetCount;
  927. //}
  928. #endif
  929. }
  930. if (RetCount <= 0) // no space or nothing to send
  931. return 0;
  932. WordCount = RetCount >> 1; /* compute count as words */
  933. WordP = (PUSHORT)Buffer; /* word ptr to buffer */
  934. io = sGetTxRxDataIO(ChP);
  935. /* Write the data */
  936. #ifdef WORD_ALIGN
  937. while( WordCount-- )
  938. {
  939. sOutW(io, *WordP++);
  940. }
  941. #else
  942. sOutStrW(io,WordP,WordCount);
  943. #endif
  944. if (RetCount & 1) /* odd count */
  945. {
  946. WordP=WordP+WordCount;
  947. sOutB((PUCHAR)io, Buffer[RetCount - 1]); /* send last byte */
  948. }
  949. return(RetCount);
  950. }
  951. #endif
  952. /*--------------------------------------------------------------------------
  953. Function: sWriteTxPrioBlk
  954. Purpose: Write a block of priority transmit data to a channel
  955. Call: sWriteTxPrioBlk(ChP,Buffer,Count)
  956. CHANPTR_T ChP; Ptr to channel structure
  957. unsigned char *Buffer; Ptr to buffer containing data to transmit
  958. int Count; Size of buffer in bytes, TXP_SIZE bytes maximum. If
  959. Count > TXP_SIZE only TXP_SIZE bytes will be written.
  960. Return: int: Number of bytes actually written to the channel, 0 if none
  961. written.
  962. Comments: The entire block of priority data is transmitted before any data
  963. in the Tx FIFO.
  964. Warnings: No context switches are allowed while executing this function.
  965. -------------------------------------------------------------------------*/
  966. int _CDECL sWriteTxPrioBlk(CHANPTR_T ChP,unsigned char *Buffer,int Count)
  967. {
  968. unsigned char DWBuf[4]; /* buffer for double word writes */
  969. register DWIOA_T IndexAddr;
  970. int WordCount,i;
  971. unsigned int UNALIGNED *WordP;
  972. unsigned int *DWBufLoP;
  973. unsigned int *DWBufHiP;
  974. IndexAddr = ChP->IndexAddr;
  975. sOutW((WIOA_T)IndexAddr,(USHORT)ChP->TxPrioCnt); /* get priority queue status */
  976. if (sInB((BIOA_T)ChP->IndexData) & PRI_PEND) /* priority queue busy */
  977. return(0); /* nothing sent */
  978. if (Count > TXP_SIZE)
  979. Count = TXP_SIZE;
  980. WordCount = Count >> 1; /* compute count as words */
  981. if (Count & 1) /* adjust for odd count */
  982. WordCount++;
  983. WordP = (unsigned int *)Buffer; /* word ptr to buffer */
  984. DWBufLoP = (unsigned int *)&DWBuf[0];
  985. DWBufHiP = (unsigned int *)&DWBuf[2];
  986. *DWBufLoP = ChP->TxPrioBuf; /* data byte address */
  987. for(i = 0;i < WordCount;i++) /* write data to Tx prioity buf */
  988. {
  989. *DWBufHiP = WordP[i]; /* data word value */
  990. sOutDW(IndexAddr,*(ULONGPTR_T)DWBuf); /* write it out */
  991. *DWBufLoP += 2;
  992. }
  993. *DWBufLoP = ChP->TxPrioCnt; /* Tx priority count address */
  994. *DWBufHiP = PRI_PEND + Count; /* indicate count bytes pending */
  995. sOutDW(IndexAddr, *(ULONGPTR_T)DWBuf); /* write it out */
  996. return(Count);
  997. }
  998. /***************************************************************************
  999. Function: sWriteTxPrioByte
  1000. Purpose: Write a byte of priority transmit data to a channel
  1001. Call: sWriteTxPrioByte(ChP,Data)
  1002. CHANPTR_T ChP; Ptr to channel structure
  1003. unsigned char Data; The transmit data byte
  1004. Return: int: 1 if the bytes is successfully written, otherwise 0.
  1005. Comments: The priority byte is transmitted before any data in the Tx FIFO.
  1006. Warnings: No context switches are allowed while executing this function.
  1007. -------------------------------------------------------------------------*/
  1008. int _CDECL sWriteTxPrioByte(CHANPTR_T ChP,unsigned char Data)
  1009. {
  1010. unsigned char DWBuf[4]; /* buffer for double word writes */
  1011. unsigned int UNALIGNED *WordPtr;
  1012. register DWIOA_T IndexAddr;
  1013. /* Don't write to prio buf unless guarenteed Tx FIFO is not empty because
  1014. of bug in AIOP */
  1015. if(sGetTxCnt(ChP) > 1) /* write it to Tx priority buffer */
  1016. {
  1017. IndexAddr = ChP->IndexAddr;
  1018. sOutW((WIOA_T)IndexAddr, (USHORT)ChP->TxPrioCnt); /* get priority buffer status */
  1019. if (sInB((BIOA_T)ChP->IndexData) & PRI_PEND) /* priority buffer busy */
  1020. return(0); /* nothing sent */
  1021. WordPtr = (unsigned int *)(&DWBuf[0]);
  1022. *WordPtr = ChP->TxPrioBuf; /* data byte address */
  1023. DWBuf[2] = Data; /* data byte value */
  1024. sOutDW(IndexAddr, *((ULONGPTR_T)(&DWBuf[0]))); /* write it out */
  1025. *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */
  1026. DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */
  1027. DWBuf[3] = 0; /* priority buffer pointer */
  1028. sOutDW(IndexAddr, *((ULONGPTR_T)(&DWBuf[0]))); /* write it out */
  1029. }
  1030. else /* write it to Tx FIFO */
  1031. {
  1032. sWriteTxByte((BIOA_T)sGetTxRxDataIO(ChP),Data);
  1033. }
  1034. return(1); /* 1 byte sent */
  1035. }
  1036. /***************************************************************************
  1037. Function: sEnInterrupts
  1038. Purpose: Enable one or more interrupts for a channel
  1039. Call: sEnInterrupts(ChP,Flags)
  1040. CHANPTR_T ChP; Ptr to channel structure
  1041. unsigned int Flags: Interrupt enable flags, can be any combination
  1042. of the following flags:
  1043. TXINT_EN: Interrupt on Tx FIFO empty
  1044. RXINT_EN: Interrupt on Rx FIFO at trigger level (see
  1045. sSetRxTrigger())
  1046. SRCINT_EN: Interrupt on SRC (Special Rx Condition)
  1047. MCINT_EN: Interrupt on modem input change
  1048. CHANINT_EN: Allow channel interrupt signal to the AIOP's
  1049. Interrupt Channel Register.
  1050. Return: void
  1051. Comments: If an interrupt enable flag is set in Flags, that interrupt will be
  1052. enabled. If an interrupt enable flag is not set in Flags, that
  1053. interrupt will not be changed. Interrupts can be disabled with
  1054. function sDisInterrupts().
  1055. This function sets the appropriate bit for the channel in the AIOP's
  1056. Interrupt Mask Register if the CHANINT_EN flag is set. This allows
  1057. this channel's bit to be set in the AIOP's Interrupt Channel Register.
  1058. Interrupts must also be globally enabled before channel interrupts
  1059. will be passed on the the host. This is done with function
  1060. sEnGlobalInt().
  1061. In some cases it may be desirable to disable interrupts globally but
  1062. enable channel interrupts. This would allow the global interrupt
  1063. status register to be used to determine which AIOPs need service.
  1064. -------------------------------------------------------------------------*/
  1065. void _CDECL sEnInterrupts(CHANPTR_T ChP,unsigned int Flags)
  1066. {
  1067. unsigned char Mask; /* Interrupt Mask Register */
  1068. ChP->RxControl[2] |=
  1069. ((unsigned char)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
  1070. sOutDW(ChP->IndexAddr,*(ULONGPTR_T)&ChP->RxControl[0]);
  1071. ChP->TxControl[2] |= ((unsigned char)Flags & TXINT_EN);
  1072. sOutDW(ChP->IndexAddr,*(ULONGPTR_T)&ChP->TxControl[0]);
  1073. if(Flags & CHANINT_EN)
  1074. {
  1075. Mask = sInB(ChP->IntMask) | (1 << ChP->ChanNum);
  1076. sOutB(ChP->IntMask,Mask);
  1077. }
  1078. }
  1079. /***************************************************************************
  1080. Function: sDisInterrupts
  1081. Purpose: Disable one or more interrupts for a channel
  1082. Call: sDisInterrupts(ChP,Flags)
  1083. CHANPTR_T ChP; Ptr to channel structure
  1084. unsigned int Flags: Interrupt flags, can be any combination
  1085. of the following flags:
  1086. TXINT_EN: Interrupt on Tx FIFO empty
  1087. RXINT_EN: Interrupt on Rx FIFO at trigger level (see
  1088. sSetRxTrigger())
  1089. SRCINT_EN: Interrupt on SRC (Special Rx Condition)
  1090. MCINT_EN: Interrupt on modem input change
  1091. CHANINT_EN: Disable channel interrupt signal to the
  1092. AIOP's Interrupt Channel Register.
  1093. Return: void
  1094. Comments: If an interrupt flag is set in Flags, that interrupt will be
  1095. disabled. If an interrupt flag is not set in Flags, that
  1096. interrupt will not be changed. Interrupts can be enabled with
  1097. function sEnInterrupts().
  1098. This function clears the appropriate bit for the channel in the AIOP's
  1099. Interrupt Mask Register if the CHANINT_EN flag is set. This blocks
  1100. this channel's bit from being set in the AIOP's Interrupt Channel
  1101. Register.
  1102. -------------------------------------------------------------------------*/
  1103. void _CDECL sDisInterrupts(CHANPTR_T ChP,unsigned int Flags)
  1104. {
  1105. unsigned char Mask; /* Interrupt Mask Register */
  1106. ChP->RxControl[2] &=
  1107. ~((unsigned char)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
  1108. sOutDW(ChP->IndexAddr,*(ULONGPTR_T)&ChP->RxControl[0]);
  1109. ChP->TxControl[2] &= ~((unsigned char)Flags & TXINT_EN);
  1110. sOutDW(ChP->IndexAddr,*(ULONGPTR_T)&ChP->TxControl[0]);
  1111. if(Flags & CHANINT_EN)
  1112. {
  1113. Mask = sInB(ChP->IntMask) & (~(1 << ChP->ChanNum));
  1114. sOutB(ChP->IntMask,Mask);
  1115. }
  1116. }
  1117. /***************************************************************************
  1118. Function: sReadMicrocode
  1119. Purpose: Read the microcode directly from a channel
  1120. Call: sReadMicrocode(ChP,Buffer,Count)
  1121. CHANPTR_T ChP; Ptr to channel structure
  1122. char *Buffer; Ptr to buffer for microcode
  1123. int Count; Number of bytes to read
  1124. Return: void
  1125. Warnings: Buffer must be large enough to hold Count bytes.
  1126. -------------------------------------------------------------------------*/
  1127. void _CDECL sReadMicrocode(CHANPTR_T ChP,char *Buffer,int Count)
  1128. {
  1129. WIOA_T IndexAddr;
  1130. BIOA_T IndexData;
  1131. unsigned int McodeOff;
  1132. IndexAddr = (WIOA_T)ChP->IndexAddr;
  1133. IndexData = (BIOA_T)ChP->IndexData;
  1134. McodeOff = MCODE_ADDR + (unsigned int)sGetChanNum(ChP) * 0x1000;
  1135. while(Count-- > 0)
  1136. {
  1137. sOutW(IndexAddr,(USHORT)(McodeOff++));
  1138. *Buffer++ = sInB((BIOA_T)IndexData);
  1139. }
  1140. }
  1141. /*------------------------------------------------------------------
  1142. sSetBaudRate - Set the desired baud rate. Return non-zero on error.
  1143. |-------------------------------------------------------------------*/
  1144. int sSetBaudRate(CHANNEL_T *ChP,
  1145. ULONG desired_baud,
  1146. USHORT SetHardware)
  1147. {
  1148. ULONG diff;
  1149. ULONG act_baud;
  1150. ULONG percent_error;
  1151. ULONG div;
  1152. ULONG base_clock_rate;
  1153. ULONG clock_freq = ChP->CtlP->ClkRate;
  1154. ULONG clk_prescaler = (ULONG)ChP->CtlP->ClkPrescaler;
  1155. base_clock_rate = ((clock_freq/16) / ((clk_prescaler & 0xf)+1));
  1156. ///////////////////////////////////////
  1157. // calculate the divisor for our hardware register.
  1158. // this is really just div = clk/desired_baud -1. but we do some
  1159. // work to minimize round-off error.
  1160. if (desired_baud <= 0)
  1161. desired_baud = 1; // guard against div 0
  1162. div = ((base_clock_rate+(desired_baud>>1)) / desired_baud) - 1;
  1163. if (div > 8191) // overflow hardware divide register
  1164. div = 8191;
  1165. // this is really just (clk) / (div+1) but we do some
  1166. // work to minimize round-off error.
  1167. act_baud = (base_clock_rate+((div+1)>>1)) / (div+1);
  1168. if (desired_baud > act_baud)
  1169. diff = desired_baud - act_baud;
  1170. else
  1171. diff = act_baud - desired_baud;
  1172. percent_error = (diff * 100) / desired_baud;
  1173. if (percent_error > 5)
  1174. return (int) percent_error;
  1175. if (SetHardware)
  1176. {
  1177. sChanOutWI(ChP, _BAUD, div);
  1178. }
  1179. return 0;
  1180. }
  1181. /*------------------------------------------------------------------
  1182. Function: sChanOutWI
  1183. Purpose: Write an Indirect Register on the Rocket Port Board
  1184. Call: sChanOutWI(CHANNEL_T *ChP, WORD RegNum, WORD val)
  1185. CHANPTR_T ChP; Ptr to channel structure
  1186. WORD RegNum; Indirect Register Number to Write
  1187. WORD val; Value to Write.
  1188. Return: void
  1189. Comments: This is a little slower than using macros but far less ugly
  1190. and error prone. Macros should only be used where speed is
  1191. imperative.
  1192. |-------------------------------------------------------------------*/
  1193. void sChanOutWI(CHANNEL_T *ChP, USHORT RegNum, ULONG val)
  1194. {
  1195. UCHAR m[4];
  1196. USHORT ChOff;
  1197. ChOff = ChP->ChanNum * 0x1000; // change this to look up table
  1198. // see about speeding this up:
  1199. m[0] = (unsigned char)(ChOff + RegNum);
  1200. m[1] = (unsigned char)((ChOff + RegNum) >> 8);
  1201. m[2] = (unsigned char) val;
  1202. m[3] = (unsigned char)(val >> 8);
  1203. sOutDW(ChP->IndexAddr,*(ULONG *)&m[0]);
  1204. }
  1205. /*------------------------------------------------------------------
  1206. Function: sModemReset
  1207. Purpose: Set or clear reset state on second generation RocketModem
  1208. Call: sModemReset(CHANNEL_T *ChP, int on)
  1209. CHANNEL_T *ChP; Ptr to channel structure
  1210. int on; on!=0 to enable reset; on=0 to clear reset
  1211. Return: void
  1212. Comments: The newer RocketModem boards power up in a reset state.
  1213. This routine is used to clear the board from reset state or
  1214. re-enable a reset state. Called from the driver during
  1215. initialization to clear the reset and via an ioctl to
  1216. manually reset the board. [jl] 980206
  1217. BUGBUG: this code violates io-resource handling under NT and will
  1218. probably break running on ALPHA machines due to bypassing NT's
  1219. io-mapping scheme(i.e. should not be doing AiopIO[1] = AiopIO[0] +..)
  1220. Also, this driver is probably not calling IoResource calls to claim
  1221. this IO space properly(could result in conflicting hardware.)
  1222. |-------------------------------------------------------------------*/
  1223. void sModemReset(CHANNEL_T *ChP, int on)
  1224. {
  1225. CONTROLLER_T *CtlP;
  1226. WIOA_T addr;
  1227. BYTE val;
  1228. CtlP = ChP->CtlP;
  1229. if (CtlP->BusType == Isa)
  1230. {
  1231. // ensure second aiop CS is enabled. there will be no physical
  1232. // aiop to enable, but the CS (which ususally goes to an aiop
  1233. // is routed to a latch, which latches the RESET signal. we
  1234. // have to also ensure that the mudback-Isa bus controller
  1235. // aiopic io-addr has been configured for the proper address
  1236. // space. since the rocketmodem Isa product is limited to
  1237. // eight ports, we know that the second aiop will be configured
  1238. // 400h above the first eight port aiop chip...
  1239. val = sInB(CtlP->MBaseIO + 3);
  1240. // read in, see if aiop[1] enabled...
  1241. if ((CtlP->AiopIO[1] != (PUSHORT)((unsigned int)(CtlP->AiopIO[0]) + 0x400)) ||
  1242. ((val & 2) == 0))
  1243. {
  1244. // cr second aiop chip not enabled. Isa board alias
  1245. CtlP->AiopIO[1] = (PUSHORT)((unsigned int)(CtlP->AiopIO[0]) + 0x400);
  1246. // tell mudback where to position the base-io of the aiopic...
  1247. val = sInB(CtlP->MBaseIO + 2); // read in irq, aiop-io reg
  1248. sOutB(CtlP->MBaseIO + 2, (BYTE)((val & 0xfc) | (1 & 0x03))); //aiop index
  1249. // setup aiop i/o in mudbac...
  1250. sOutB(CtlP->MBaseIO, (BYTE)((unsigned int)CtlP->AiopIO[1] >> 6));
  1251. }
  1252. sEnAiop(CtlP,1); // enable the (un)AIOP
  1253. }
  1254. else if (CtlP->BusType == PCIBus)
  1255. {
  1256. // PCI bus RocketModem reset...
  1257. // we reference where the second AIOP would be, if there were one,..
  1258. CtlP->AiopIO[1] = (PUSHORT)((unsigned int)CtlP->AiopIO[0] + 0x40);
  1259. }
  1260. // the latch has 3-pin mux which determines which latch the
  1261. // data gets routed to. these pins are hooked to the first
  1262. // three address lines. the fourth address line (8h) is used
  1263. // as the data line.
  1264. addr = CtlP->AiopIO[1];
  1265. // adjust reset state...
  1266. sOutB(((PUCHAR)(addr) + ChP->ChanNum + (on ? 0 : 8)), 0);
  1267. // disable the aiop; must disable to prevent chip select from getting hit
  1268. // with continuous pulses (causing reset to occur).
  1269. // additionally it seems that a read of some other address is required
  1270. // before the disable or the first channel on the board goes back into the
  1271. // reset state. there's nothing special about ChP->IntChan...a read of
  1272. // any port would probably work...
  1273. sInB(ChP->IntChan);
  1274. if (CtlP->BusType == Isa)
  1275. {
  1276. sDisAiop(CtlP, 1);
  1277. }
  1278. }
  1279. /*------------------------------------------------------------------
  1280. Function: sModemWriteROW
  1281. Purpose: Send the "Rest of World" configuration string to the
  1282. RocketModem port.
  1283. Call: sModemSendROW(CHANNEL_T *ChP, USHORT CountryCode)
  1284. CHANNEL_T *ChP; Ptr to channel structure
  1285. USHORT CountryCode; Country to configure the modem for
  1286. Return: void
  1287. Comments: The ROW "SocketModem" RocketModem boards can compensate for
  1288. the differences in various internation phone systems. This
  1289. function sends the appropriate configuration string based
  1290. upon a registry setting specified by the user. [jl] 980316
  1291. Modem should be hard reset before calling this function. Otherwise,
  1292. use AT modem reset commands...
  1293. |-------------------------------------------------------------------*/
  1294. void sModemWriteROW(CHANNEL_T *ChP, USHORT CountryCode)
  1295. {
  1296. CONTROLLER_T *CtlP = ChP->CtlP;
  1297. char *ModemConfigString = {"AT*NCxxZ\r"};
  1298. int max;
  1299. MyKdPrint(D_Init,("sModemWriteROW: %x, %x\n",(unsigned long)ChP,CountryCode)) // DEBUG
  1300. if (CountryCode == ROW_NA) {
  1301. MyKdPrint(D_Init,("ROW Write, North America\n"))
  1302. return;
  1303. }
  1304. /*
  1305. create the country config string...
  1306. */
  1307. ModemConfigString[5] = '0' + (CountryCode / 10);
  1308. ModemConfigString[6] = '0' + (CountryCode % 10);
  1309. MyKdPrint(D_Init,("ROW Write, Chan:%d, Cfg:%s\n", ChP->ChanNum, ModemConfigString))
  1310. time_stall(10); // TUNE
  1311. sFlushTxFIFO(ChP);
  1312. sFlushRxFIFO(ChP);
  1313. sSetBaudRate(ChP,9600,TRUE);
  1314. sSetData8(ChP);
  1315. sClrTxXOFF(ChP);
  1316. sEnRTSFlowCtl(ChP);
  1317. sEnCTSFlowCtl(ChP);
  1318. if (sGetChanStatus(ChP) & STATMODE) {
  1319. sDisRxStatusMode(ChP);
  1320. }
  1321. sGetChanIntID(ChP);
  1322. sEnRxFIFO(ChP);
  1323. sEnTransmit(ChP);
  1324. sSetRTS(ChP);
  1325. /*
  1326. spin while port readies...
  1327. */
  1328. time_stall(10);
  1329. sModemWriteDelay(ChP,ModemConfigString,strlen(ModemConfigString));
  1330. (void) sModemRead(ChP,"OK",sizeof("OK\r") - 1,10);
  1331. time_stall(1);
  1332. sFlushRxFIFO(ChP);
  1333. sClrRTS(ChP);
  1334. }
  1335. /*------------------------------------------------------------------
  1336. Function: sModemSpeakerEnable
  1337. Purpose: Enable RocketModemII board speaker
  1338. Call: sModemSpeakerEnable(CHANNEL_T *ChP)
  1339. CHANNEL_T *ChP; Ptr to channel structure
  1340. Return: void
  1341. Comments: Called from the driver during initialization to
  1342. enable the board speaker.
  1343. |-------------------------------------------------------------------*/
  1344. void sModemSpeakerEnable(CHANNEL_T *ChP)
  1345. {
  1346. CONTROLLER_T *CtlP;
  1347. WIOA_T addr;
  1348. BYTE val;
  1349. CtlP = ChP->CtlP;
  1350. /*
  1351. PCI bus RocketModem reset...
  1352. */
  1353. if (CtlP->BusType != PCIBus)
  1354. return;
  1355. /*
  1356. we reference where the second AIOP would be,..
  1357. */
  1358. CtlP->AiopIO[1] = (PUSHORT)((unsigned int)CtlP->AiopIO[0] + 0x40);
  1359. /*
  1360. the latch has 3-pin mux which determines which latch the
  1361. data gets routed to. these pins are hooked to the first
  1362. three address lines. the fourth address line (8h) is used
  1363. as the data line...
  1364. */
  1365. addr = CtlP->AiopIO[1];
  1366. /*
  1367. following is hack to enable the speaker (PCI cards only). we don't want
  1368. to construct an extension and related storage for a speaker, so we'll
  1369. just piggyback the enable of the speaker onto another channel...
  1370. */
  1371. sOutB(((PUCHAR)(addr) + 7 + 8), 0);
  1372. }
  1373. /*------------------------------------------------------------------
  1374. Function: sModemWriteDelay
  1375. Purpose: Send a string to the RocketModem port, pausing for each character
  1376. to clear the FIFO.
  1377. Call: sModemSendROW(CHANNEL_T *ChP, char *string,int length)
  1378. CHANNEL_T *ChP; Ptr to channel structure
  1379. char *string; String to write
  1380. int length Length of string, not including any trailing null
  1381. Return: void
  1382. Comments: Output characters one at a time
  1383. |-------------------------------------------------------------------*/
  1384. void
  1385. sModemWriteDelay(CHANNEL_T *ChP,char *string,int length)
  1386. {
  1387. int index,count;
  1388. unsigned char buffer[2];
  1389. sFlushTxFIFO(ChP);
  1390. sFlushRxFIFO(ChP);
  1391. if (
  1392. (length <= 0)
  1393. ||
  1394. (string == (char *)NULL)
  1395. )
  1396. return;
  1397. index = 0;
  1398. count = 0;
  1399. while (length--) {
  1400. while (count = (int)sGetTxCnt(ChP)) {
  1401. /*
  1402. byte or bytes in transmit FIFO. wait a while. adjust interval...
  1403. */
  1404. ms_time_stall(10 * count);
  1405. /*
  1406. no change? assume FIFO stuck, bail out of loop...
  1407. */
  1408. if (count == (int)sGetTxCnt(ChP)) {
  1409. break;
  1410. }
  1411. }
  1412. /*
  1413. transmit FIFO probably available. put a byte in it, pause a moment...
  1414. */
  1415. sWriteTxByte((BIOA_T)sGetTxRxDataIO(ChP),(unsigned char)string[index]);
  1416. ++index;
  1417. }
  1418. }
  1419. /********************************************************************
  1420. send string to modem...
  1421. *********************************************************************/
  1422. void
  1423. sModemWrite(CHANNEL_T *ChP, char *string, int length)
  1424. {
  1425. if (
  1426. (length <= 0)
  1427. ||
  1428. (string == (char *)NULL)
  1429. )
  1430. return;
  1431. sWriteTxBlk(ChP, (unsigned char *)string, length);
  1432. }
  1433. /********************************************************************
  1434. look for match on a particular character string...
  1435. ********************************************************************/
  1436. int sModemRead(CHANNEL_T *ChP, char *string,int length, int poll_retries)
  1437. {
  1438. unsigned char buffer;
  1439. long count;
  1440. int arg_index;
  1441. int read_retries;
  1442. WIOA_T io;
  1443. unsigned int fifo_data;
  1444. #ifdef DUMPDATA
  1445. DumpIndex = 0;
  1446. #endif
  1447. /*
  1448. bail if board not installed...
  1449. */
  1450. fifo_data = (unsigned int)sGetRxCnt(ChP);
  1451. /*
  1452. see if board installed and functioning. if not, architecture returns
  1453. bad value. if so, stonewall on read...
  1454. */
  1455. if (fifo_data > (unsigned int)RXFIFO_SIZE)
  1456. return(-1);
  1457. io = sGetTxRxDataIO(ChP);
  1458. poll_retries *= 10;
  1459. buffer = (char)0;
  1460. arg_index = 0;
  1461. /*
  1462. search until we see a match on the argument characters, or we run out of data...
  1463. */
  1464. do {
  1465. while (sGetRxCnt(ChP) > 0) {
  1466. buffer = sReadRxByte((PUCHAR)io);
  1467. #ifdef DUMPDATA
  1468. DumpResponseByte(buffer);
  1469. #endif
  1470. /*
  1471. force response to upper case, since responses are different depending on
  1472. whether the modem was loaded already or not...
  1473. */
  1474. if (buffer >= 'a')
  1475. buffer ^= 0x20;
  1476. if (string[arg_index] == buffer) {
  1477. ++arg_index;
  1478. /*
  1479. see if we're done. if so, bail with good return code...
  1480. */
  1481. if (arg_index == length) {
  1482. time_stall(TENTH_SECOND);
  1483. #ifdef DUMPDATA
  1484. while (sGetRxCnt(ChP) > 0) {
  1485. buffer = sReadRxByte((PUCHAR)io);
  1486. DumpResponseByte(buffer);
  1487. }
  1488. MyKdPrint(D_Init,("sModemRead: %x [%s]\n",(unsigned long)ChP,DumpArray))
  1489. #endif
  1490. sFlushRxFIFO(ChP);
  1491. return(0);
  1492. }
  1493. }
  1494. else {
  1495. arg_index = 0;
  1496. }
  1497. }
  1498. ms_time_stall(10);
  1499. } while (poll_retries-- > 0);
  1500. #ifdef DUMPDATA
  1501. MyKdPrint(D_Init,("sModemRead: %x [%s]\n",(unsigned long)ChP,DumpArray))
  1502. #endif
  1503. return(-1);
  1504. }
  1505. /********************************************************************
  1506. look for match on two possibilities...
  1507. ********************************************************************/
  1508. int sModemReadChoice(CHANNEL_T *ChP,
  1509. char *string0,
  1510. int length0,
  1511. char *string1,
  1512. int length1,
  1513. int poll_retries)
  1514. {
  1515. char buffer;
  1516. long count;
  1517. int arg_index0;
  1518. int arg_index1;
  1519. char *ptr;
  1520. WIOA_T io;
  1521. unsigned int fifo_data;
  1522. #ifdef DUMPDATA
  1523. DumpIndex = 0;
  1524. #endif
  1525. MyKdPrint(D_Init,("sModemReadChoice: %x\n",(unsigned long)ChP))
  1526. poll_retries *= 10;
  1527. /*
  1528. bail if board not installed...
  1529. */
  1530. fifo_data = (unsigned int)sGetRxCnt(ChP);
  1531. /*
  1532. see if board installed and functioning. if not, architecture returns
  1533. likely -1. if so, stonewall on read...
  1534. */
  1535. if (fifo_data > (unsigned int)RXFIFO_SIZE)
  1536. return(-1);
  1537. io = sGetTxRxDataIO(ChP);
  1538. buffer = (char)0;
  1539. arg_index0 = 0;
  1540. arg_index1 = 0;
  1541. /*
  1542. first, we discard characters until we see a match on the argument characters,
  1543. or we run out of data...
  1544. */
  1545. do {
  1546. while (sGetRxCnt(ChP) > 0) {
  1547. buffer = sReadRxByte((PUCHAR)io);
  1548. #ifdef DUMPDATA
  1549. DumpResponseByte(buffer);
  1550. #endif
  1551. /*
  1552. force response to upper case, since responses can be different depending on
  1553. whether the modem was loaded already or not...
  1554. */
  1555. if (buffer >= 'a')
  1556. buffer ^= 0x20;
  1557. /*
  1558. check first argument...
  1559. */
  1560. if (string0[arg_index0] == buffer) {
  1561. ++arg_index0;
  1562. /*
  1563. see if we're done matching on string 0...
  1564. */
  1565. if (arg_index0 >= length0) {
  1566. time_stall(TENTH_SECOND);
  1567. #ifdef DUMPDATA
  1568. while (sGetRxCnt(ChP) > 0) {
  1569. buffer = sReadRxByte((PUCHAR)io);
  1570. DumpResponseByte(buffer);
  1571. }
  1572. MyKdPrint(D_Init,("sModemReadChoice: %x\r\n[%s]\n",(unsigned long)ChP,DumpArray))
  1573. #endif
  1574. sFlushRxFIFO(ChP);
  1575. return(0);
  1576. }
  1577. }
  1578. else {
  1579. arg_index0 = 0;
  1580. }
  1581. /*
  1582. check argument 1...
  1583. */
  1584. if (string1[arg_index1] == buffer) {
  1585. ++arg_index1;
  1586. /*
  1587. see if we're done matching on string 1...
  1588. */
  1589. if (arg_index1 >= length1) {
  1590. time_stall(TENTH_SECOND);
  1591. #ifdef DUMPDATA
  1592. while (sGetRxCnt(ChP) > 0) {
  1593. buffer = sReadRxByte((PUCHAR)io);
  1594. DumpResponseByte(buffer);
  1595. }
  1596. MyKdPrint(D_Init,("sModemReadChoice: %x\r\n[%s]\n",(unsigned long)ChP,DumpArray))
  1597. #endif
  1598. sFlushRxFIFO(ChP);
  1599. return(1);
  1600. }
  1601. }
  1602. else {
  1603. arg_index1 = 0;
  1604. }
  1605. }
  1606. ms_time_stall(10);
  1607. } while (poll_retries-- > 0);
  1608. /*
  1609. no match...
  1610. */
  1611. #ifdef DUMPDATA
  1612. MyKdPrint(D_Init,("sModemReadChoice: %x\r\n[%s]\n",(unsigned long)ChP,DumpArray))
  1613. #endif
  1614. sFlushRxFIFO(ChP);
  1615. return(-1);
  1616. }
  1617. /********************************************************************
  1618. check transmit FIFO...
  1619. *********************************************************************/
  1620. int sTxFIFOStatus(CHANNEL_T *ChP)
  1621. {
  1622. unsigned int fifo_size;
  1623. /*
  1624. see if board installed and functioning. if not, architecture returns
  1625. bad count. if so, stonewall on fifo ready...
  1626. */
  1627. fifo_size = (unsigned int)sGetTxCnt(ChP);
  1628. if (fifo_size > (unsigned int)TXFIFO_SIZE)
  1629. return(MAXTX_SIZE);
  1630. if (MAXTX_SIZE <= (unsigned int)sGetTxCnt(ChP))
  1631. return(MAXTX_SIZE);
  1632. /*
  1633. return number of data bytes in FIFO...
  1634. */
  1635. return(sGetTxCnt(ChP));
  1636. }
  1637. /********************************************************************
  1638. check available space in transmit FIFO. there's two checks here:
  1639. one for whether the FIFO is present;
  1640. one for whether the FIFO is full...
  1641. *********************************************************************/
  1642. int sTxFIFOReady(CHANNEL_T *ChP)
  1643. {
  1644. unsigned int fifo_size;
  1645. /*
  1646. see if board installed and functioning. if not, architecture likely returns
  1647. a bad value. if so, stonewall on fifo ready...
  1648. */
  1649. fifo_size = (unsigned int)sGetTxCnt(ChP);
  1650. if (fifo_size > (unsigned int)TXFIFO_SIZE)
  1651. return(0);
  1652. /*
  1653. if number of data bytes currently in FIFO is greater than the
  1654. available space, return busy for now...
  1655. */
  1656. if (sGetTxCnt(ChP) >= MAXTX_SIZE)
  1657. return(0);
  1658. /*
  1659. return (size of FIFO - number of data bytes in FIFO)...
  1660. */
  1661. return(MAXTX_SIZE - sGetTxCnt(ChP));
  1662. }
  1663. /********************************************************************
  1664. discard pending data in receive FIFO. pull in data until data
  1665. runs out or count goes to zero...
  1666. *********************************************************************/
  1667. int sRxFIFOReady(CHANNEL_T *ChP)
  1668. {
  1669. unsigned char buffer;
  1670. int retries;
  1671. WIOA_T io;
  1672. unsigned int count;
  1673. count = (unsigned int)sGetRxCnt(ChP);
  1674. if (count > (unsigned int)RXFIFO_SIZE)
  1675. return(-1);
  1676. if (!count)
  1677. return(0);
  1678. retries = 20;
  1679. io = sGetTxRxDataIO(ChP);
  1680. do {
  1681. count = RXFIFO_SIZE + 2; // set to size of FIFO + slop...
  1682. while (
  1683. (sGetRxCnt(ChP))
  1684. &&
  1685. (count--)
  1686. ) {
  1687. buffer = sReadRxByte((PUCHAR)io);
  1688. }
  1689. /*
  1690. if receive FIFO is now empty, bail out. if it was full, though,
  1691. pause a moment and then check to see if it has refilled -
  1692. if it has, flush that, and then check again. what we're trying to do
  1693. here is empty the FIFO, and still detect a run-on condition...
  1694. */
  1695. if (count)
  1696. return(0);
  1697. ms_time_stall(10);
  1698. } while (--retries);
  1699. /*
  1700. receive FIFO didn't empty, though we gave it several chances...
  1701. */
  1702. return(-1);
  1703. }
  1704. #ifdef DUMPDATA
  1705. /********************************************************************
  1706. dump responses to log...
  1707. ********************************************************************/
  1708. void DumpResponseByte(char buffer)
  1709. {
  1710. if (DumpIndex < sizeof(DumpArray) - 2) {
  1711. switch (buffer) {
  1712. case '\n': {
  1713. DumpArray[DumpIndex++] = '\\';
  1714. DumpArray[DumpIndex++] = 'n';
  1715. break;
  1716. }
  1717. case '\r': {
  1718. DumpArray[DumpIndex++] = '\\';
  1719. DumpArray[DumpIndex++] = 'r';
  1720. break;
  1721. }
  1722. case '\t': {
  1723. DumpArray[DumpIndex++] = '\\';
  1724. DumpArray[DumpIndex++] = 't';
  1725. break;
  1726. }
  1727. case '\0': {
  1728. DumpArray[DumpIndex++] = '\\';
  1729. DumpArray[DumpIndex++] = '0';
  1730. break;
  1731. }
  1732. default: {
  1733. if (buffer < ' ') {
  1734. DumpArray[DumpIndex++] = '?';
  1735. }
  1736. else {
  1737. DumpArray[DumpIndex++] = buffer;
  1738. }
  1739. }
  1740. }
  1741. DumpArray[DumpIndex] = 0;
  1742. }
  1743. }
  1744. #endif