Windows NT 4.0 source code leak
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.

604 lines
12 KiB

4 years ago
  1. #if defined(JENSEN)
  2. /*++
  3. Copyright (c) 1991 Microsoft Corporation
  4. Copyright (c) 1992 Digital Equipment Corporation
  5. Module Name:
  6. jxport.c
  7. Abstract:
  8. This module implements the code that provides communication between
  9. the kernel debugger on a Jensen system and the host system.
  10. Stolen from ../mips/jxport.c
  11. Author:
  12. Miche Baker-Harvey (miche) 01-June-1992
  13. Jeff McLeman [DEC] 02-Feb-1993
  14. Environment:
  15. Kernel mode
  16. Revision History:
  17. Joe Notarangelo 21-Jun-1992
  18. update to use super-page access to serial port so we aren't depend
  19. on translation code, this will allow us to debug the translation
  20. code, use serial line 2
  21. --*/
  22. #include "halp.h"
  23. #include "jxserp.h"
  24. //
  25. // BUGBUG Temporarily, we use counter to do the timeout
  26. //
  27. #define TIMEOUT_COUNT 1024*512
  28. //
  29. // BUGBUG Temp until we have a configuration manager.
  30. //
  31. PUCHAR KdComPortInUse = NULL;
  32. BOOLEAN KdUseModemControl = FALSE;
  33. //
  34. // Define serial port read and write addresses.
  35. //
  36. PSP_READ_REGISTERS SP_READ;
  37. PSP_WRITE_REGISTERS SP_WRITE;
  38. //
  39. // Define forward referenced prototypes.
  40. //
  41. SP_LINE_STATUS
  42. KdReadLsr (
  43. IN BOOLEAN WaitReason
  44. );
  45. //
  46. // Define baud rate divisor to be used on the debugger port.
  47. //
  48. UCHAR HalpBaudRateDivisor = 0;
  49. ULONG
  50. HalpGetByte (
  51. IN PUCHAR Input,
  52. IN BOOLEAN Wait
  53. )
  54. /*++
  55. Routine Description:
  56. This routine gets a byte from the serial port used by the kernel debugger.
  57. N.B. It is assumed that the IRQL has been raised to the highest level,
  58. and necessary multiprocessor synchronization has been performed
  59. before this routine is called.
  60. Arguments:
  61. Input - Supplies a pointer to a variable that receives the input data
  62. byte.
  63. Return Value:
  64. CP_GET_SUCCESS is returned if a byte is successfully read from the
  65. kernel debugger line.
  66. CP_GET_ERROR is returned if error encountered during reading.
  67. CP_GET_NODATA is returned if timeout.
  68. --*/
  69. {
  70. SP_LINE_STATUS LsrByte;
  71. UCHAR DataByte;
  72. ULONG TimeoutCount;
  73. //
  74. // Attempt to read a byte from the debugger port until a byte is
  75. // available or until a timeout occurs.
  76. //
  77. TimeoutCount = Wait ? TIMEOUT_COUNT : 1;
  78. do {
  79. TimeoutCount -= 1;
  80. //
  81. // Wait until data is available in the receive buffer.
  82. //
  83. KeStallExecutionProcessor(1);
  84. LsrByte = KdReadLsr(TRUE);
  85. if (LsrByte.DataReady == 0) {
  86. continue;
  87. }
  88. //
  89. // Read input byte and store in callers buffer.
  90. //
  91. *Input = inVti(&SP_READ->ReceiveBuffer);
  92. //
  93. // If using modem controls, then skip any incoming data while
  94. // ReceiveData not set.
  95. //
  96. if (KdUseModemControl) {
  97. DataByte = inVti(&SP_READ->ModemStatus);
  98. if ( ((PSP_MODEM_STATUS)&DataByte)->ReceiveDetect == 0) {
  99. continue;
  100. }
  101. }
  102. //
  103. // Return function value as the not of the error indicators.
  104. //
  105. if (LsrByte.ParityError ||
  106. LsrByte.FramingError ||
  107. LsrByte.OverrunError ||
  108. LsrByte.BreakIndicator) {
  109. return CP_GET_ERROR;
  110. }
  111. return CP_GET_SUCCESS;
  112. } while(TimeoutCount != 0);
  113. return CP_GET_NODATA;
  114. }
  115. BOOLEAN
  116. KdPortInitialize (
  117. PDEBUG_PARAMETERS DebugParameters,
  118. PLOADER_PARAMETER_BLOCK LoaderBlock,
  119. BOOLEAN Initialize
  120. )
  121. /*++
  122. Routine Description:
  123. This routine initializes the serial port used by the kernel debugger
  124. and must be called during system initialization.
  125. Arguments:
  126. None.
  127. Return Value:
  128. None.
  129. --*/
  130. {
  131. PCONFIGURATION_COMPONENT_DATA ConfigurationEntry;
  132. UCHAR DataByte;
  133. PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
  134. PCM_SERIAL_DEVICE_DATA DeviceData;
  135. ULONG KdPortEntry;
  136. PCM_PARTIAL_RESOURCE_LIST List;
  137. ULONG MatchKey;
  138. ULONG BaudRate;
  139. ULONG BaudClock;
  140. ULONG Remainder;
  141. //
  142. // Find the configuration information for the first serial port.
  143. //
  144. if (LoaderBlock != NULL) {
  145. MatchKey = 0;
  146. ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot,
  147. ControllerClass,
  148. SerialController,
  149. &MatchKey);
  150. } else {
  151. ConfigurationEntry = NULL;
  152. }
  153. if (DebugParameters->BaudRate != 0) {
  154. BaudRate = DebugParameters->BaudRate;
  155. } else {
  156. BaudRate = 19200;
  157. }
  158. //
  159. // If the serial configuration entry was not found or the frequency
  160. // specified is not supported, then default the baud rate divisor to
  161. // six, which is 19.2Kbps on Jensen. Otherwise, set the baud rate divisor
  162. // to the correct value for 19.2 baud communication.
  163. //
  164. BaudClock = 1843200;
  165. if (ConfigurationEntry != NULL) {
  166. List = (PCM_PARTIAL_RESOURCE_LIST)ConfigurationEntry->ConfigurationData;
  167. Descriptor = &List->PartialDescriptors[List->Count];
  168. DeviceData = (PCM_SERIAL_DEVICE_DATA)Descriptor;
  169. if ((DeviceData->BaudClock == 1843200) ||
  170. (DeviceData->BaudClock == 4233600) ||
  171. (DeviceData->BaudClock == 8000000)) {
  172. BaudClock = DeviceData->BaudClock;
  173. }
  174. }
  175. HalpBaudRateDivisor = (UCHAR)(BaudClock / (BaudRate*16));
  176. //
  177. // round up
  178. //
  179. Remainder = BaudClock % (BaudRate*16);
  180. if ((Remainder*2) > BaudClock) {
  181. HalpBaudRateDivisor++;
  182. }
  183. //
  184. // If the debugger is not being enabled, then return.
  185. //
  186. if (Initialize == FALSE) {
  187. return TRUE;
  188. }
  189. //
  190. // Establish pointers to serial line register structures
  191. // Note: the natural port number addresses are used
  192. //
  193. if ( DebugParameters->CommunicationPort == 1 ) {
  194. SP_READ = ((PSP_READ_REGISTERS)(COMA_PORT_BASE));
  195. SP_WRITE = ((PSP_WRITE_REGISTERS)(COMA_PORT_BASE));
  196. KdComPortInUse = (PUCHAR)0x3f8;
  197. } else {
  198. SP_READ = ((PSP_READ_REGISTERS)(COMB_PORT_BASE));
  199. SP_WRITE = ((PSP_WRITE_REGISTERS)(COMB_PORT_BASE));
  200. KdComPortInUse = (PUCHAR)0x2f8;
  201. }
  202. //
  203. // Clear the divisor latch, clear all interrupt enables, and reset and
  204. // disable the FIFO's.
  205. //
  206. outVti( &SP_WRITE->LineControl, 0x0 );
  207. outVti( &SP_WRITE->InterruptEnable, 0x0 );
  208. // We shouldn't have to do anything with the FIFO here -
  209. //
  210. // Set the divisor latch and set the baud rate to 19200 baud.
  211. //
  212. // Note: the references to TransmitBuffer and InterruptEnable are
  213. // actually the Divisor Latch LSB and MSB registers respectively
  214. DataByte = 0;
  215. ((PSP_LINE_CONTROL)(&DataByte))->DivisorLatch = 1;
  216. outVti(&SP_WRITE->LineControl, DataByte);
  217. outVti(&SP_WRITE->TransmitBuffer, HalpBaudRateDivisor);
  218. outVti(&SP_WRITE->InterruptEnable, 0x0);
  219. //
  220. // Clear the divisor latch and set the character size to eight bits
  221. // with one stop bit and no parity checking.
  222. //
  223. DataByte = 0;
  224. ((PSP_LINE_CONTROL)(&DataByte))->CharacterSize = EIGHT_BITS;
  225. outVti(&SP_WRITE->LineControl, DataByte);
  226. //
  227. // Set data terminal ready and request to send.
  228. //
  229. DataByte = 0;
  230. ((PSP_MODEM_CONTROL)(&DataByte))->DataTerminalReady = 1;
  231. ((PSP_MODEM_CONTROL)(&DataByte))->RequestToSend = 1;
  232. outVti(&SP_WRITE->ModemControl, DataByte);
  233. return TRUE;
  234. }
  235. ULONG
  236. KdPortGetByte (
  237. OUT PUCHAR Input
  238. )
  239. /*++
  240. Routine Description:
  241. This routine gets a byte from the serial port used by the kernel
  242. debugger.
  243. N.B. It is assumed that the IRQL has been raised to the highest
  244. level, and necessary multiprocessor synchronization has been
  245. performed before this routine is called.
  246. Arguments:
  247. Input - Supplies a pointer to a variable that receives the input
  248. data byte.
  249. Return Value:
  250. CP_GET_SUCCESS is returned if a byte is successfully read from the
  251. kernel debugger line.
  252. CP_GET_ERROR is returned if an error is encountered during reading.
  253. CP_GET_NODATA is returned if timeout occurs.
  254. --*/
  255. {
  256. return HalpGetByte(Input, TRUE);
  257. }
  258. ULONG
  259. KdPortPollByte (
  260. OUT PUCHAR Input
  261. )
  262. /*++
  263. Routine Description:
  264. This routine gets a byte from the serial port used by the kernel
  265. debugger iff a byte is available.
  266. N.B. It is assumed that the IRQL has been raised to the highest
  267. level, and necessary multiprocessor synchronization has been
  268. performed before this routine is called.
  269. Arguments:
  270. Input - Supplies a pointer to a variable that receives the input
  271. data byte.
  272. Return Value:
  273. CP_GET_SUCCESS is returned if a byte is successfully read from the
  274. kernel debugger line.
  275. CP_GET_ERROR is returned if an error encountered during reading.
  276. CP_GET_NODATA is returned if timeout occurs.
  277. --*/
  278. {
  279. ULONG Status;
  280. //
  281. // Save port status, map the serial controller, get byte from the
  282. // debugger port is one is avaliable, restore port status, unmap
  283. // the serial controller, and return the operation status.
  284. //
  285. KdPortSave();
  286. Status = HalpGetByte(Input, FALSE);
  287. KdPortRestore();
  288. return Status;
  289. }
  290. VOID
  291. KdPortPutByte (
  292. IN UCHAR Output
  293. )
  294. /*++
  295. Routine Description:
  296. This routine puts a byte to the serial port used by the kernel debugger.
  297. N.B. It is assumed that the IRQL has been raised to the highest level,
  298. and necessary multiprocessor synchronization has been performed
  299. before this routine is called.
  300. Arguments:
  301. Output - Supplies the output data byte.
  302. Return Value:
  303. None.
  304. --*/
  305. {
  306. UCHAR DataByte;
  307. if (KdUseModemControl) {
  308. //
  309. // Modem control, make sure DSR, CTS and CD are all set before
  310. // sending any data.
  311. //
  312. for (; ;) {
  313. DataByte = inVti(&SP_READ->ModemStatus);
  314. if ( ((PSP_MODEM_STATUS)&DataByte)->ClearToSend &&
  315. ((PSP_MODEM_STATUS)&DataByte)->DataSetReady &&
  316. ((PSP_MODEM_STATUS)&DataByte)->ReceiveDetect ) {
  317. break;
  318. }
  319. KdReadLsr(FALSE);
  320. }
  321. }
  322. //
  323. // Wait for transmit ready.
  324. //
  325. while (KdReadLsr(FALSE).TransmitHoldingEmpty == 0 );
  326. //
  327. // Wait for data set ready.
  328. //
  329. // do {
  330. // LsrByte = inVti(&SP_READ->ModemStatus);
  331. // } while (((PSP_MODEM_STATUS)(&LsrByte))->DataSetReady == 0);
  332. //
  333. // Transmit data.
  334. //
  335. outVti(&SP_WRITE->TransmitBuffer, Output);
  336. return;
  337. }
  338. VOID
  339. KdPortRestore (
  340. VOID
  341. )
  342. /*++
  343. Routine Description:
  344. This routine restores the state of the serial port after the kernel
  345. debugger has been active.
  346. N.B. This routine performs no function on the Jazz system.
  347. Arguments:
  348. None.
  349. Return Value:
  350. None.
  351. --*/
  352. {
  353. return;
  354. }
  355. VOID
  356. KdPortSave (
  357. VOID
  358. )
  359. /*++
  360. Routine Description:
  361. This routine saves the state of the serial port and initializes the port
  362. for use by the kernel debugger.
  363. N.B. This routine performs no function on the Jazz system.
  364. Arguments:
  365. None.
  366. Return Value:
  367. None.
  368. --*/
  369. {
  370. return;
  371. }
  372. SP_LINE_STATUS
  373. KdReadLsr (
  374. IN BOOLEAN WaitReason
  375. )
  376. /*++
  377. Routine Description:
  378. Returns current line status.
  379. If status which is being waited for is ready, then the function
  380. checks the current modem status and causes a possible display update
  381. of the current statuses.
  382. Arguments:
  383. WaitReason - Suuplies a boolean value that determines whether the line
  384. status is required for a receive or transmit.
  385. Return Value:
  386. The current line status is returned as the function value.
  387. --*/
  388. {
  389. static UCHAR RingFlag = 0;
  390. UCHAR DataLsr, DataMsr;
  391. //
  392. // Get the line status for a receive or a transmit.
  393. //
  394. DataLsr = inVti(&SP_READ->LineStatus);
  395. if (WaitReason) {
  396. //
  397. // Get line status for receive data.
  398. //
  399. if (((PSP_LINE_STATUS)&DataLsr)->DataReady) {
  400. return *((PSP_LINE_STATUS)&DataLsr);
  401. }
  402. } else {
  403. //
  404. // Get line status for transmit empty.
  405. //
  406. if (((PSP_LINE_STATUS)&DataLsr)->TransmitEmpty) {
  407. return *((PSP_LINE_STATUS)&DataLsr);
  408. }
  409. }
  410. DataMsr = inVti(&SP_READ->ModemStatus);
  411. RingFlag |= ((PSP_MODEM_STATUS)&DataMsr)->RingIndicator ? 1 : 2;
  412. if (RingFlag == 3) {
  413. //
  414. // The ring indicate line has toggled, use modem control from
  415. // now on.
  416. //
  417. KdUseModemControl = TRUE;
  418. }
  419. return *((PSP_LINE_STATUS) &DataLsr);
  420. }
  421. #endif // JENSEN