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.

763 lines
18 KiB

4 years ago
  1. //---------------------------------------------------------------------
  2. //
  3. // T338.C
  4. //
  5. // Trantor T338 Logic Module. Contains functions to access the T338
  6. // adapter.
  7. //
  8. // Revisions:
  9. // 02-01-93 KJB First.
  10. // 02-23-93 KJB Reorganized, supports dataunderrun with long delay
  11. // for under run on large xfers. Can we fix this?
  12. // 03-11-93 JAP Changed retcode equates to reflect new names.
  13. // 03-11-93 KJB Changed to use N5380Enable/DisableDmaRead/Write
  14. // routines.
  15. // 03-12-93 KJB Now supports polling thru CardInterrupt and
  16. // StartCommandInterrupt/FinishCommandInterrupt.
  17. // 03-19-93 JAP Implemented condition build FAR and NEAR pointers
  18. // 03-22-93 KJB Added support for scatter gather: T338DoIo.
  19. // 03-24-93 KJB Fixed SetScsiMode so it does not reset the n5380!
  20. // 05-14-93 KJB Added CardParseCommandString for card specific
  21. // standard string parsing across platforms.
  22. // Changed CardCheckAdapter to accept an
  23. // Initialization info from command line, ie
  24. // force bi-directional ports, etc.
  25. // All functions that used to take an PBASE_REGISTER
  26. // parameter now take PWORKSPACE. CardCheckAdapter
  27. // takes the both a PINIT and a PWORKSPACE parameters.
  28. // 05-14-93 KJB Remove all WINNT specific #ifdef i386 references.
  29. // 05-14-93 KJB Removed P3CDoIo, it did not work for scatter gather.
  30. // 05-16-93 KJB Fixed parameter bugs introduced while doing the
  31. // PWORKSPACE changes.
  32. // 05-17-93 KJB Fixed compiler warnings.
  33. //
  34. //---------------------------------------------------------------------
  35. #include CARDTXXX_H
  36. // Local Functions
  37. VOID T338PutControl(PADAPTER_INFO g,UCHAR mode, UCHAR reg);
  38. VOID T338SetPrinterMode(PADAPTER_INFO g, UCHAR data, UCHAR control);
  39. VOID T338SetScsiMode(PADAPTER_INFO g, PUCHAR data, PUCHAR control);
  40. //
  41. // T338PutControl
  42. //
  43. // Puts a control byte to the T338 style adapter. This sets the mode
  44. // to IOR or IOW and the address byte of the N5380 register.
  45. //
  46. VOID T338PutControl(PADAPTER_INFO g,UCHAR mode, UCHAR reg)
  47. {
  48. UCHAR tmp;
  49. // the following bits are active low: IOW, IOR, MR
  50. tmp = reg | (mode ^ (T338_MR | T338_IOW | T338_IOR));
  51. // put the control byte on the data lines
  52. ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,tmp);
  53. // assert slc to indicate byte is there
  54. ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,P_SLC);
  55. // clear slc
  56. ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,0);
  57. }
  58. //
  59. // T338SetPrinterMode
  60. //
  61. // This routine sets the T338 to printer pass through mode. This is the
  62. // default mode and should be set after the brief use of scsi mode.
  63. //
  64. VOID T338SetPrinterMode(PADAPTER_INFO g, UCHAR data, UCHAR control)
  65. {
  66. UCHAR tmp;
  67. // do we have to disable interrupts?
  68. // negate all control signals...
  69. T338PutControl(g,0,0);
  70. // restore data register
  71. ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,data);
  72. // leave p_init negated (1)
  73. tmp = control | P_INIT;
  74. ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
  75. }
  76. //
  77. // T338SetScsiMode
  78. //
  79. // This routine sets the T338 into scsi mode. Now the parallel port can
  80. // be used to send commands the the n5380. This mode should be set only
  81. // briefly during when the scsi command is being executed.
  82. //
  83. VOID T338SetScsiMode(PADAPTER_INFO g, PUCHAR data, PUCHAR control)
  84. {
  85. UCHAR tmp;
  86. // save parallel data
  87. ParallelPortGet(g->BaseIoAddress,PARALLEL_DATA,data);
  88. // zero data register
  89. // note: the signals IOW,IOR,MR are active low, so assert them..
  90. ParallelPortPut(g->BaseIoAddress,PARALLEL_DATA,
  91. T338_MR | T338_IOW | T338_IOR);
  92. // save parallel control
  93. ParallelPortGet(g->BaseIoAddress,PARALLEL_CONTROL,control);
  94. *control = *control & (P_BUFEN ^ 0xff);
  95. // clear p_init and set p_slc
  96. tmp = (*control & (P_INIT ^ 0xff) ) | P_SLC;
  97. ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
  98. // clear p_init and set p_slc
  99. tmp = (*control & (P_INIT ^ 0xff) ) | P_SLC;
  100. ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
  101. // clear slc, leave p_init asserted (0)
  102. tmp = tmp & (P_SLC ^ 0xff);
  103. ParallelPortPut(g->BaseIoAddress,PARALLEL_CONTROL,tmp);
  104. }
  105. //
  106. // T338CheckAdapter
  107. //
  108. // This routine is used to sense the presense of the T338 adapter out
  109. // on the Parallel port. It will only detect the adapter if a device
  110. // is providing termination power.
  111. //
  112. BOOLEAN T338CheckAdapter(PADAPTER_INFO g)
  113. {
  114. UCHAR data;
  115. UCHAR control;
  116. BOOLEAN rval;
  117. // set scsi mode
  118. T338SetScsiMode(g,&data,&control);
  119. // reset the 5380
  120. T338PutControl(g,T338_MR,0);
  121. T338PutControl(g,0,0);
  122. // check to see if a 5380 is there
  123. rval = N5380CheckAdapter(g);
  124. // set parallel port for use by printer
  125. T338SetPrinterMode(g,data,control);
  126. return rval;
  127. }
  128. //
  129. // T338DoCommand
  130. //
  131. // Called by the main loop to start a scsi command. This functions is the
  132. // main entry point for all cards. It returns an SRB status code as defined
  133. // in ..\..\inc\srb.h. A status code of RET_STATUS_PENDING means that the
  134. // request has been sent to the controller and an interrupt is needed to
  135. // finish the request. When this interrupt occurs CardFinishCommandInterrupt
  136. // will be called.
  137. //
  138. USHORT T338DoCommand(PTSRB t)
  139. {
  140. USHORT rval;
  141. UCHAR data;
  142. UCHAR control;
  143. PADAPTER_INFO g = t->pWorkspace;
  144. // put the parallel adapter into scsi mode
  145. T338SetScsiMode(g, &data, &control);
  146. // execute the complete command now, without interrupts
  147. rval = ScsiDoCommand(t);
  148. // put the parallel adapter back to parallel mode
  149. T338SetPrinterMode(g, data, control);
  150. return rval;
  151. }
  152. //
  153. // T338StartCommandInterrupt
  154. //
  155. // This routines allow the driver to be polled by checking its
  156. // CardInterrupt by for example using the timer interrupt, since
  157. // the T338 does not support interrupts on its own.
  158. //
  159. //
  160. USHORT T338StartCommandInterrupt(PTSRB t)
  161. {
  162. USHORT rval;
  163. UCHAR data;
  164. UCHAR control;
  165. PADAPTER_INFO g = t->pWorkspace;
  166. // put the parallel adapter into scsi mode
  167. T338SetScsiMode(g, &data, &control);
  168. // execute the complete command now, without interrupts
  169. rval = ScsiStartCommandInterrupt(t);
  170. // put the parallel adapter back to parallel mode
  171. T338SetPrinterMode(g, data, control);
  172. return rval;
  173. }
  174. //
  175. // T338FinishCommandInterrupt
  176. //
  177. // This routines allow the driver to be polled by checking its
  178. // CardInterrupt by for example using the timer interrupt, since
  179. // the T338 does not support interrupts on its own.
  180. //
  181. //
  182. USHORT T338FinishCommandInterrupt(PTSRB t)
  183. {
  184. USHORT rval;
  185. UCHAR data;
  186. UCHAR control;
  187. PADAPTER_INFO g = t->pWorkspace;
  188. // put the T338 into ScsiMode
  189. T338SetScsiMode(g, &data, &control);
  190. // execute the complete command now, without interrupts
  191. rval = ScsiFinishCommandInterrupt(t);
  192. // put the parallel adapter back to parallel mode
  193. T338SetPrinterMode(g, data, control);
  194. return rval;
  195. }
  196. //
  197. // T338StartCommandInterrupt
  198. //
  199. // This routines allow the driver to be polled by checking its
  200. // CardInterrupt by for example using the timer interrupt, since
  201. // the T338 does not support interrupts on its own.
  202. //
  203. BOOLEAN T338Interrupt(PADAPTER_INFO g)
  204. {
  205. BOOLEAN rval;
  206. UCHAR data;
  207. UCHAR control;
  208. // put the parallel adapter into scsi mode
  209. T338SetScsiMode(g, &data, &control);
  210. rval = N5380Interrupt(g);
  211. // put the parallel adapter back to parallel mode
  212. T338SetPrinterMode(g, data, control);
  213. return rval;
  214. }
  215. //
  216. //
  217. // T338ResetBus
  218. //
  219. // Resets the SCSI Bus
  220. //
  221. VOID T338ResetBus(PADAPTER_INFO g)
  222. {
  223. UCHAR data;
  224. UCHAR control;
  225. // put the parallel adapter into scsi mode
  226. T338SetScsiMode(g, &data, &control);
  227. // execute the complete command now, without interrupts
  228. N5380ResetBus(g);
  229. // put the parallel adapter back to parallel mode
  230. T338SetPrinterMode(g, data, control);
  231. }
  232. //
  233. // T338WriteBytesFast
  234. //
  235. // This routine is used by the ScsiFnc routines to write bytes to the scsi
  236. // bus quickly. The ScsiFnc routines don't know how to do this quickly for
  237. // a particular card, so they call this. This routine can be mapped to the
  238. // slower ScsiWriteBytesSlow routine for small transferrs or if this routine
  239. // is not supported.
  240. //
  241. USHORT T338WriteBytesFast (PADAPTER_INFO g, PUCHAR pbytes,
  242. ULONG len, PULONG pActualLen, UCHAR phase)
  243. {
  244. USHORT rval = 0;
  245. // use slow mode for odd xfers (inquiry type commands) & audio
  246. if (len % 512) {
  247. return ScsiWriteBytesSlow (g, pbytes, len,
  248. pActualLen, phase);
  249. }
  250. // start dma mode
  251. N5380EnableDmaWrite (g);
  252. // put the T338 into write dma mode
  253. T338PutControl (g,T338_IOW,0);
  254. {
  255. ULONG xfer_count = len;
  256. PBASE_REGISTER baseIoAddress = g->BaseIoAddress;
  257. _asm {
  258. push esi
  259. push ds
  260. #ifdef MODE_32BIT
  261. mov edx,baseIoAddress
  262. mov esi,pbytes
  263. mov ecx,len
  264. #else
  265. mov dx, word ptr baseIoAddress
  266. mov si, word ptr pbytes
  267. mov cx, word ptr len
  268. mov ds, word ptr pbytes+2
  269. #endif // MODE_32BIT
  270. add dx,2 // dx points to control reg
  271. get_bytes:
  272. dec dx // dx points to status register
  273. in al,dx
  274. test al,P_BUSY
  275. jnz big_wait
  276. ready:
  277. dec dx // dx points to parallel data reg
  278. mov al,[esi]
  279. out dx,al
  280. // assert DACK
  281. add dx,2 // dx points to control reg
  282. mov al, P_AFX
  283. out dx,al
  284. // deassert DACK
  285. mov al,0
  286. out dx,al
  287. inc esi
  288. dec ecx
  289. jnz get_bytes
  290. }
  291. goto done_asm;
  292. _asm {
  293. big_wait:
  294. in al,dx
  295. test al,P_BUSY
  296. jz ready
  297. in al,dx
  298. test al,P_BUSY
  299. jz ready
  300. in al,dx
  301. test al,P_BUSY
  302. jz ready
  303. in al,dx
  304. test al,P_BUSY
  305. jz ready
  306. // wait for a while before going to a bigger timeout
  307. push ecx
  308. push ebx
  309. mov ebx,TIMEOUT_READWRITE_LOOP
  310. loop0:
  311. mov ecx,0x10000
  312. loop1:
  313. in al,dx
  314. test al,P_BUSY
  315. jz ready1
  316. in al,dx
  317. test al,P_BUSY
  318. jz ready1
  319. dec ecx
  320. jnz loop1
  321. dec ebx
  322. jnz loop0
  323. pop ebx
  324. pop ecx
  325. jmp short error
  326. ready1:
  327. pop ebx
  328. pop ecx
  329. jmp short ready
  330. error:
  331. mov rval,RET_STATUS_TIMEOUT
  332. done_asm:
  333. pop ds
  334. pop esi
  335. #ifdef MODE_32BIT
  336. mov xfer_count,ecx
  337. #else
  338. mov word ptr xfer_count,ecx
  339. #endif
  340. }
  341. // compute actual xfer len
  342. *pActualLen = len - xfer_count;
  343. }
  344. // clear the dma bit of 5380
  345. N5380DisableDmaWrite (g);
  346. // if data underrun, return the under/over run error message
  347. if (rval) {
  348. UCHAR tmp;
  349. // phase mismatch means data under/over run
  350. N5380GetPhase (g,&tmp);
  351. if (tmp == PHASE_STATUS) {
  352. rval = RET_STATUS_DATA_OVERRUN;
  353. }
  354. }
  355. return rval;
  356. }
  357. //
  358. // T338ReadBytesFast
  359. //
  360. // This routine is used by the ScsiFnc routines to write bytes to the scsi
  361. // bus quickly. The ScsiFnc routines don't know how to do this quickly for
  362. // a particular card, so they call this. This routine can be mapped to the
  363. // slower ScsiReadBytesSlow routine for small transferrs or if this routine
  364. // is not supported.
  365. //
  366. #pragma optimize("",off)
  367. USHORT T338ReadBytesFast (PADAPTER_INFO g, PUCHAR pbytes,
  368. ULONG len, PULONG pActualLen, UCHAR phase)
  369. {
  370. USHORT rval = 0;
  371. // use slow mode for small xfers (inquiry type commands) and audio
  372. if (len % 512) {
  373. return ScsiReadBytesSlow (g, pbytes, len,
  374. pActualLen, phase);
  375. }
  376. // start dma read
  377. N5380EnableDmaRead (g);
  378. // put the t338 into read mode
  379. T338PutControl (g,T338_IOR,0);
  380. // to be fast, for 386 machines, this must be coded in assembly
  381. // for inline assembly, we don't have to save eax-edx registers
  382. {
  383. ULONG xfer_count = len;
  384. PBASE_REGISTER baseIoAddress = g->BaseIoAddress;
  385. _asm {
  386. push esi
  387. push ds
  388. #ifdef MODE_32BIT
  389. mov edx, baseIoAddress
  390. mov esi,pbytes
  391. mov ecx,len
  392. #else
  393. mov dx, word ptr baseIoAddress
  394. mov si, word ptr pbytes
  395. mov cx, word ptr len
  396. mov ds, word ptr pbytes+2
  397. #endif // MODE_32BIT
  398. inc dx // dx points to status register
  399. get_bytes:
  400. in al,dx
  401. test al,P_BUSY
  402. jnz big_wait
  403. ready:
  404. // assert DACK, the P_AFX bit
  405. inc dx // dx points to control register
  406. mov al,P_AFX
  407. out dx,al
  408. // select high nibble
  409. sub dx,2 // dx points to data register
  410. mov al,0x80
  411. out dx,al
  412. // get high nibble
  413. inc dx // dx points to status register
  414. in al,dx
  415. mov ah,al
  416. // select lower nibble
  417. dec dx // dx points to data register
  418. xor al,al
  419. out dx,al
  420. // calculate high nibble
  421. shl ah,1
  422. and ah,0f0h
  423. // get lower nibble
  424. inc dx // dx points to status register
  425. in al,dx
  426. mov bh,al
  427. // deassert DACK, clear P_AFX
  428. inc dx // dx points to control register
  429. xor al,al
  430. out dx,al
  431. dec dx // dx points to status register
  432. // compute low nibble and the whole byte
  433. shr bh,1
  434. shr bh,1
  435. shr bh,1
  436. and bh,0fh
  437. or ah,bh
  438. mov al,ah
  439. // store data and loop
  440. mov [esi],al
  441. inc esi
  442. dec ecx
  443. jnz get_bytes
  444. }
  445. goto done_asm;
  446. _asm {
  447. big_wait:
  448. in al,dx
  449. test al,P_BUSY
  450. jz ready
  451. in al,dx
  452. test al,P_BUSY
  453. jz ready
  454. in al,dx
  455. test al,P_BUSY
  456. jz ready
  457. in al,dx
  458. test al,P_BUSY
  459. jz ready
  460. // wait for a while before going to a bigger timeout
  461. push ecx
  462. push ebx
  463. mov ebx,TIMEOUT_READWRITE_LOOP
  464. loop0:
  465. mov ecx,0x10000
  466. loop1:
  467. in al,dx
  468. test al,P_BUSY
  469. jz ready1
  470. in al,dx
  471. test al,P_BUSY
  472. jz ready1
  473. dec ecx
  474. jnz loop1
  475. dec ebx
  476. jnz loop0
  477. pop ebx
  478. pop ecx
  479. jmp short error
  480. ready1:
  481. pop ebx
  482. pop ecx
  483. }
  484. goto ready;
  485. _asm {
  486. error:
  487. mov rval,RET_STATUS_TIMEOUT
  488. done_asm:
  489. pop ds
  490. pop esi
  491. #ifdef MODE_32BIT
  492. mov xfer_count,ecx
  493. #else
  494. mov word ptr xfer_count,ecx
  495. #endif
  496. }
  497. // compute actual xfer len
  498. *pActualLen = len - xfer_count;
  499. }
  500. // zero control register, disable read dma mode
  501. ParallelPortPut (g->BaseIoAddress,PARALLEL_CONTROL,0);
  502. // clear the dma read mode
  503. N5380DisableDmaRead (g);
  504. // if data underrun, return the under/over run error message
  505. if (rval) {
  506. UCHAR tmp;
  507. // phase mismatch means data under/over run
  508. N5380GetPhase (g,&tmp);
  509. if (tmp == PHASE_STATUS) {
  510. rval = RET_STATUS_DATA_OVERRUN;
  511. }
  512. }
  513. return rval;
  514. }
  515. #pragma optimize("",on)
  516. //
  517. // N5380PortPut
  518. //
  519. // This routine is used by the N5380.C module to write byte to a 5380
  520. // controller. This allows the module to be card independent. Other
  521. // modules that assume a N5380 may also use this function.
  522. //
  523. VOID N5380PortPut (PADAPTER_INFO g,UCHAR reg,UCHAR byte)
  524. {
  525. // set T338 logic into data write mode
  526. T338PutControl (g, T338_IOW, reg);
  527. // write the byte
  528. ParallelPortPut (g->BaseIoAddress, PARALLEL_DATA, byte);
  529. // toggle the strobe line
  530. ParallelPortPut (g->BaseIoAddress, PARALLEL_CONTROL, P_STB);
  531. ParallelPortPut (g->BaseIoAddress, PARALLEL_CONTROL, 0);
  532. // clear data write mode
  533. T338PutControl (g, 0, 0);
  534. }
  535. //
  536. // N5380PortGet
  537. //
  538. // This routine is used by the N5380.C module to get a byte from a 5380
  539. // controller. This allows the module to be card independent. Other
  540. // modules that assume a N5380 may also use this function.
  541. //
  542. VOID N5380PortGet (PADAPTER_INFO g, UCHAR reg, PUCHAR byte)
  543. {
  544. UCHAR tmp,tmp1;
  545. // set T338 logic to read mode
  546. T338PutControl (g, T338_IOR, reg);
  547. // select high nibble
  548. ParallelPortPut (g->BaseIoAddress, PARALLEL_DATA, 0x80);
  549. // assert stb
  550. ParallelPortPut (g->BaseIoAddress, PARALLEL_CONTROL, P_STB);
  551. // read high nibble
  552. ParallelPortGet (g->BaseIoAddress, PARALLEL_STATUS, &tmp);
  553. // compute high nibble
  554. tmp = (tmp << 1) & 0xf0;
  555. // select low nibble
  556. ParallelPortPut (g->BaseIoAddress, PARALLEL_DATA, 0x00);
  557. // read low nibble
  558. ParallelPortGet (g->BaseIoAddress, PARALLEL_STATUS, &tmp1);
  559. // compute low nibble
  560. tmp1 = (tmp1 >> 3) & 0x0f;
  561. // compute and return byte
  562. *byte = tmp1 | tmp;
  563. // clear slc
  564. ParallelPortPut (g->BaseIoAddress, PARALLEL_CONTROL, 0);
  565. // clear data read mode
  566. T338PutControl (g, 0, 0);
  567. }