bdaef5890ddc68848d3494d98a389aaeb0d804d1
[SCSI2SD-V6.git] / src / firmware / scsiPhy.c
1 //      Copyright (C) 2013 Michael McMaster <michael@codesrc.com>\r
2 //\r
3 //      This file is part of SCSI2SD.\r
4 //\r
5 //      SCSI2SD is free software: you can redistribute it and/or modify\r
6 //      it under the terms of the GNU General Public License as published by\r
7 //      the Free Software Foundation, either version 3 of the License, or\r
8 //      (at your option) any later version.\r
9 //\r
10 //      SCSI2SD is distributed in the hope that it will be useful,\r
11 //      but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 //      GNU General Public License for more details.\r
14 //\r
15 //      You should have received a copy of the GNU General Public License\r
16 //      along with SCSI2SD.  If not, see <http://www.gnu.org/licenses/>.\r
17 \r
18 #include "stm32f2xx.h"\r
19 #include "stm32f2xx_hal.h"\r
20 #include "stm32f2xx_hal_dma.h"\r
21 \r
22 #include "scsi.h"\r
23 #include "scsiPhy.h"\r
24 #include "trace.h"\r
25 #include "time.h"\r
26 #include "fpga.h"\r
27 #include "led.h"\r
28 \r
29 // Private DMA variables.\r
30 static int dmaInProgress = 0;\r
31 \r
32 static DMA_HandleTypeDef memToFSMC;\r
33 static DMA_HandleTypeDef fsmcToMem;\r
34 \r
35 \r
36 volatile uint8_t scsiRxDMAComplete;\r
37 volatile uint8_t scsiTxDMAComplete;\r
38 \r
39 #if 0\r
40 CY_ISR_PROTO(scsiRxCompleteISR);\r
41 CY_ISR(scsiRxCompleteISR)\r
42 {\r
43         traceIrq(trace_scsiRxCompleteISR);\r
44         scsiRxDMAComplete = 1;\r
45 }\r
46 \r
47 CY_ISR_PROTO(scsiTxCompleteISR);\r
48 CY_ISR(scsiTxCompleteISR)\r
49 {\r
50         traceIrq(trace_scsiTxCompleteISR);\r
51         scsiTxDMAComplete = 1;\r
52 }\r
53 #endif\r
54 \r
55 uint8_t scsiPhyFifoSel = 0; // global\r
56 \r
57 // scsi IRQ handler is initialised by the STM32 HAL. Connected to\r
58 // PE4\r
59 // Note: naming is important to ensure this function is listed in the\r
60 // vector table.\r
61 void EXTI4_IRQHandler()\r
62 {\r
63         traceIrq(trace_scsiResetISR);\r
64 \r
65         // Make sure that interrupt flag is set\r
66         if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_4) != RESET) {\r
67 \r
68                 // Clear interrupt flag\r
69                 __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_4);\r
70 \r
71                 scsiDev.resetFlag = scsiDev.resetFlag || scsiStatusRST();\r
72                 // TODO grab SEL status as well\r
73 \r
74         }\r
75 }\r
76 \r
77 #if 0\r
78 uint8_t\r
79 scsiReadDBxPins()\r
80 {\r
81         return\r
82                 (SCSI_ReadPin(SCSI_In_DBx_DB7) << 7) |\r
83                 (SCSI_ReadPin(SCSI_In_DBx_DB6) << 6) |\r
84                 (SCSI_ReadPin(SCSI_In_DBx_DB5) << 5) |\r
85                 (SCSI_ReadPin(SCSI_In_DBx_DB4) << 4) |\r
86                 (SCSI_ReadPin(SCSI_In_DBx_DB3) << 3) |\r
87                 (SCSI_ReadPin(SCSI_In_DBx_DB2) << 2) |\r
88                 (SCSI_ReadPin(SCSI_In_DBx_DB1) << 1) |\r
89                 SCSI_ReadPin(SCSI_In_DBx_DB0);\r
90 }\r
91 #endif\r
92 \r
93 static void\r
94 startScsiRx(uint32_t count)\r
95 {\r
96         *SCSI_DATA_CNT_HI = count >> 8;\r
97         *SCSI_DATA_CNT_LO = count & 0xff;\r
98         *SCSI_DATA_CNT_SET = 1;\r
99 }\r
100 \r
101 uint8_t\r
102 scsiReadByte(void)\r
103 {\r
104         startScsiRx(1);\r
105 \r
106         trace(trace_spinPhyRxFifo);\r
107         while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) {}\r
108         scsiPhyFifoFlip();\r
109         uint8_t val = scsiPhyRx();\r
110         // TODO scsiDev.parityError = scsiDev.parityError || SCSI_Parity_Error_Read();\r
111 \r
112         return val;\r
113 }\r
114 \r
115 \r
116 static void\r
117 scsiReadPIO(uint8_t* data, uint32_t count)\r
118 {\r
119         for (int i = 0; i < count; ++i)\r
120         {\r
121                 data[i] = scsiPhyRx();\r
122         }\r
123         // TODO scsiDev.parityError = scsiDev.parityError || SCSI_Parity_Error_Read();\r
124 }\r
125 \r
126 void\r
127 scsiReadDMA(uint8_t* data, uint32_t count)\r
128 {\r
129         // Prepare DMA transfer\r
130         dmaInProgress = 1;\r
131         trace(trace_doRxSingleDMA);\r
132 \r
133         scsiTxDMAComplete = 1; // TODO not used much\r
134         scsiRxDMAComplete = 0; // TODO not used much\r
135 \r
136         HAL_DMA_Start(&fsmcToMem, (uint32_t) SCSI_FIFO_DATA, (uint32_t) data, count); // TODO MM count/4 for tx\r
137 }\r
138 \r
139 int\r
140 scsiReadDMAPoll()\r
141 {\r
142         int complete = __HAL_DMA_GET_COUNTER(&fsmcToMem) == 0;\r
143         complete = complete && (HAL_DMA_PollForTransfer(&fsmcToMem, HAL_DMA_FULL_TRANSFER, 0xffffffff) == HAL_OK);\r
144         if (complete)\r
145         {\r
146                 scsiTxDMAComplete = 1; // TODO MM FIX IRQ\r
147                 scsiRxDMAComplete = 1;\r
148 \r
149                 dmaInProgress = 0;\r
150 #if 0\r
151                 // TODO MM scsiDev.parityError = scsiDev.parityError || SCSI_Parity_Error_Read();\r
152 #endif\r
153                 return 1;\r
154 \r
155         }\r
156         else\r
157         {\r
158                 return 0;\r
159         }\r
160 }\r
161 \r
162 void\r
163 scsiRead(uint8_t* data, uint32_t count)\r
164 {\r
165         int i = 0;\r
166         while (i < count && likely(!scsiDev.resetFlag))\r
167         {\r
168                 uint32_t chunk = ((count - i) > SCSI_FIFO_DEPTH)\r
169                         ? SCSI_FIFO_DEPTH : (count - i);\r
170 \r
171                 if (chunk >= 16)\r
172                 {\r
173                         // DMA is doing 32bit transfers.\r
174                         chunk = chunk & 0xFFFFFFF8;\r
175                 }\r
176 \r
177                 startScsiRx(chunk);\r
178                 // Wait for the next scsi interrupt (or the 1ms systick)\r
179                 __WFI();\r
180 \r
181                 while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) {}\r
182                 scsiPhyFifoFlip();\r
183 \r
184                 if (chunk < 16)\r
185                 {\r
186                         scsiReadPIO(data + i, chunk);\r
187                 }\r
188                 else\r
189                 {\r
190                         scsiReadDMA(data + i, chunk);\r
191 \r
192                         // Wait for the next DMA interrupt (or the 1ms systick)\r
193                         // It's beneficial to halt the processor to\r
194                         // give the DMA controller more memory bandwidth to work with.\r
195 #if 0\r
196                         __WFI();\r
197 #endif\r
198                         trace(trace_spinReadDMAPoll);\r
199 \r
200                         while (!scsiReadDMAPoll() && likely(!scsiDev.resetFlag))\r
201                         {\r
202 #if 0\r
203 // TODO NEED SCSI DMA IRQs\r
204                         __WFI();\r
205 #endif\r
206                         };\r
207                 }\r
208 \r
209                 i += chunk;\r
210         }\r
211 }\r
212 \r
213 void\r
214 scsiWriteByte(uint8_t value)\r
215 {\r
216         trace(trace_spinPhyTxFifo);\r
217         scsiPhyTx(value);\r
218         scsiPhyFifoFlip();\r
219 \r
220         trace(trace_spinTxComplete);\r
221         while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) {}\r
222 }\r
223 \r
224 static void\r
225 scsiWritePIO(const uint8_t* data, uint32_t count)\r
226 {\r
227         for (int i = 0; i < count; ++i)\r
228         {\r
229                 scsiPhyTx(data[i]);\r
230         }\r
231 }\r
232 \r
233 void\r
234 scsiWriteDMA(const uint8_t* data, uint32_t count)\r
235 {\r
236         // Prepare DMA transfer\r
237         dmaInProgress = 1;\r
238         trace(trace_doTxSingleDMA);\r
239 \r
240         scsiTxDMAComplete = 0;\r
241         scsiRxDMAComplete = 1;\r
242 \r
243         HAL_DMA_Start(\r
244                 &memToFSMC,\r
245                 (uint32_t) data,\r
246                 (uint32_t) SCSI_FIFO_DATA,\r
247                 count / 4);\r
248 }\r
249 \r
250 int\r
251 scsiWriteDMAPoll()\r
252 {\r
253         int complete = __HAL_DMA_GET_COUNTER(&memToFSMC) == 0;\r
254         complete = complete && (HAL_DMA_PollForTransfer(&memToFSMC, HAL_DMA_FULL_TRANSFER, 0xffffffff) == HAL_OK);\r
255         if (complete)\r
256         {\r
257                 scsiTxDMAComplete = 1; // TODO MM FIX IRQ\r
258                 scsiRxDMAComplete = 1;\r
259 \r
260                 dmaInProgress = 0;\r
261                 return 1;\r
262         }\r
263         else\r
264         {\r
265                 return 0;\r
266         }\r
267 }\r
268 \r
269 void\r
270 scsiWrite(const uint8_t* data, uint32_t count)\r
271 {\r
272         int i = 0;\r
273         while (i < count && likely(!scsiDev.resetFlag))\r
274         {\r
275                 uint32_t chunk = ((count - i) > SCSI_FIFO_DEPTH)\r
276                         ? SCSI_FIFO_DEPTH : (count - i);\r
277 \r
278                 if (chunk < 16)\r
279                 {\r
280                         scsiWritePIO(data + i, chunk);\r
281                 }\r
282                 else\r
283                 {\r
284                         // DMA is doing 32bit transfers.\r
285                         chunk = chunk & 0xFFFFFFF8;\r
286                         scsiWriteDMA(data + i, chunk);\r
287 \r
288                         // Wait for the next DMA interrupt (or the 1ms systick)\r
289                         // It's beneficial to halt the processor to\r
290                         // give the DMA controller more memory bandwidth to work with.\r
291 #if 0\r
292                         __WFI();\r
293 #endif\r
294                         trace(trace_spinReadDMAPoll);\r
295 \r
296                         while (!scsiWriteDMAPoll() && likely(!scsiDev.resetFlag))\r
297                         {\r
298 #if 0\r
299 // TODO NEED SCSI DMA IRQs\r
300                         __WFI();\r
301 #endif\r
302                         };\r
303                 }\r
304 \r
305                 while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) {}\r
306                 scsiPhyFifoFlip();\r
307 #if 0\r
308 // TODO NEED SCSI IRQs\r
309                         __WFI();\r
310 #endif\r
311 \r
312                 i += chunk;\r
313         }\r
314         while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) {}\r
315 }\r
316 \r
317 static inline void busSettleDelay(void)\r
318 {\r
319         // Data Release time (switching IO) = 400ns\r
320         // + Bus Settle time (switching phase) = 400ns.\r
321         s2s_delay_us(1); // Close enough.\r
322 }\r
323 \r
324 void scsiEnterBusFree()\r
325 {\r
326         *SCSI_CTRL_PHASE = 0;\r
327         *SCSI_CTRL_BSY = 0x00;\r
328 }\r
329 \r
330 void scsiEnterPhase(int phase)\r
331 {\r
332         // ANSI INCITS 362-2002 SPI-3 10.7.1:\r
333         // Phase changes are not allowed while REQ or ACK is asserted.\r
334 #if 0\r
335         while (likely(!scsiDev.resetFlag) &&\r
336                 (SCSI_ReadPin(SCSI_In_REQ) || SCSI_ReadFilt(SCSI_Filt_ACK))\r
337                 ) {}\r
338 #endif\r
339 \r
340         int newPhase = phase > 0 ? phase : 0;\r
341         if (newPhase != *SCSI_CTRL_PHASE)\r
342         {\r
343                 *SCSI_CTRL_PHASE = newPhase;\r
344                 busSettleDelay();\r
345 \r
346                 if (scsiDev.compatMode < COMPAT_SCSI2)\r
347                 {\r
348                         s2s_delay_us(100);\r
349                 }\r
350         }\r
351 }\r
352 \r
353 void scsiPhyReset()\r
354 {\r
355         trace(trace_scsiPhyReset);\r
356         if (dmaInProgress)\r
357         {\r
358                 trace(trace_spinDMAReset);\r
359                 HAL_DMA_Abort(&memToFSMC);\r
360                 HAL_DMA_Abort(&fsmcToMem);\r
361 \r
362                 dmaInProgress = 0;\r
363         }\r
364 #if 0\r
365 \r
366         // Set the Clear bits for both SCSI device FIFOs\r
367         scsiTarget_AUX_CTL = scsiTarget_AUX_CTL | 0x03;\r
368 \r
369         // Trigger RST outselves.  It is connected to the datapath and will\r
370         // ensure it returns to the idle state.  The datapath runs at the BUS clk\r
371         // speed (ie. same as the CPU), so we can be sure it is active for a sufficient\r
372         // duration.\r
373         SCSI_RST_ISR_Disable();\r
374         SCSI_SetPin(SCSI_Out_RST);\r
375 \r
376         SCSI_CTL_PHASE_Write(0);\r
377         SCSI_ClearPin(SCSI_Out_ATN);\r
378         SCSI_ClearPin(SCSI_Out_BSY);\r
379         SCSI_ClearPin(SCSI_Out_ACK);\r
380         SCSI_ClearPin(SCSI_Out_RST);\r
381         SCSI_ClearPin(SCSI_Out_SEL);\r
382         SCSI_ClearPin(SCSI_Out_REQ);\r
383 \r
384         // Allow the FIFOs to fill up again.\r
385         SCSI_ClearPin(SCSI_Out_RST);\r
386         SCSI_RST_ISR_Enable();\r
387         scsiTarget_AUX_CTL = scsiTarget_AUX_CTL & ~(0x03);\r
388 \r
389         SCSI_Parity_Error_Read(); // clear sticky bits\r
390 #endif\r
391 \r
392         *SCSI_CTRL_PHASE = 0x00;\r
393         *SCSI_CTRL_BSY = 0x00;\r
394         s2s_fpgaReset(); // Clears fifos etc.\r
395 \r
396         scsiPhyFifoSel = 0;\r
397         *SCSI_FIFO_SEL = 0;\r
398 \r
399         // DMA Benchmark code\r
400         // Currently 10MB/s. Assume 20MB/s is achievable with 16 bits.\r
401         #ifdef DMA_BENCHMARK\r
402         while(1)\r
403         {\r
404                 s2s_ledOn();\r
405                 // 100MB\r
406                 for (int i = 0; i < (100LL * 1024 * 1024 / SCSI_FIFO_DEPTH); ++i)\r
407                 {\r
408                         HAL_DMA_Start(\r
409                                 &memToFSMC,\r
410                                 (uint32_t) &scsiDev.data[0],\r
411                                 (uint32_t) SCSI_FIFO_DATA,\r
412                                 SCSI_FIFO_DEPTH / 4);\r
413 \r
414                         HAL_DMA_PollForTransfer(\r
415                                 &memToFSMC,\r
416                                 HAL_DMA_FULL_TRANSFER,\r
417                                 0xffffffff);\r
418 \r
419                         s2s_fpgaReset();\r
420                 }\r
421                 s2s_ledOff();\r
422 \r
423                 for(int i = 0; i < 10; ++i) s2s_delay_ms(1000);\r
424         }\r
425         #endif\r
426 \r
427 }\r
428 \r
429 static void scsiPhyInitDMA()\r
430 {\r
431         // One-time init only.\r
432         static uint8_t init = 0;\r
433         if (init == 0)\r
434         {\r
435                 init = 1;\r
436 \r
437                 // Memory to memory transfers can only be done using DMA2\r
438                 __DMA2_CLK_ENABLE();\r
439 \r
440                 // Transmit SCSI data. The source data is treated as the\r
441                 // peripheral (even though this is memory-to-memory)\r
442                 memToFSMC.Instance = DMA2_Stream0;\r
443                 memToFSMC.Init.Channel = DMA_CHANNEL_0;\r
444                 memToFSMC.Init.Direction = DMA_MEMORY_TO_MEMORY;\r
445                 memToFSMC.Init.PeriphInc = DMA_PINC_ENABLE;\r
446                 memToFSMC.Init.MemInc = DMA_MINC_DISABLE;\r
447                 memToFSMC.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;\r
448                 memToFSMC.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;\r
449                 memToFSMC.Init.Mode = DMA_NORMAL;\r
450                 memToFSMC.Init.Priority = DMA_PRIORITY_LOW;\r
451                 // FIFO mode is needed to allow conversion from 32bit words to the\r
452                 // 8bit FSMC interface.\r
453                 memToFSMC.Init.FIFOMode = DMA_FIFOMODE_ENABLE;\r
454 \r
455                 // We only use 1 word (4 bytes) in the fifo at a time. Normally it's\r
456                 // better to let the DMA fifo fill up then do burst transfers, but\r
457                 // bursting out the FSMC interface will be very slow and may starve\r
458                 // other (faster) transfers. We don't want to risk the SDIO transfers\r
459                 // from overrun/underrun conditions.\r
460                 memToFSMC.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;\r
461                 memToFSMC.Init.MemBurst = DMA_MBURST_SINGLE;\r
462                 memToFSMC.Init.PeriphBurst = DMA_PBURST_SINGLE;\r
463                 HAL_DMA_Init(&memToFSMC);\r
464 \r
465                 // Receive SCSI data. The source data (fsmc) is treated as the\r
466                 // peripheral (even though this is memory-to-memory)\r
467                 fsmcToMem.Instance = DMA2_Stream1;\r
468                 fsmcToMem.Init.Channel = DMA_CHANNEL_0;\r
469                 fsmcToMem.Init.Direction = DMA_MEMORY_TO_MEMORY;\r
470                 fsmcToMem.Init.PeriphInc = DMA_PINC_DISABLE;\r
471                 fsmcToMem.Init.MemInc = DMA_MINC_ENABLE;\r
472                 fsmcToMem.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;\r
473                 fsmcToMem.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;\r
474                 fsmcToMem.Init.Mode = DMA_NORMAL;\r
475                 fsmcToMem.Init.Priority = DMA_PRIORITY_LOW;\r
476                 fsmcToMem.Init.FIFOMode = DMA_FIFOMODE_ENABLE;\r
477                 fsmcToMem.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;\r
478                 fsmcToMem.Init.MemBurst = DMA_MBURST_SINGLE;\r
479                 fsmcToMem.Init.PeriphBurst = DMA_PBURST_SINGLE;\r
480                 HAL_DMA_Init(&fsmcToMem);\r
481 \r
482                 // TODO configure IRQs\r
483         }\r
484 }\r
485 \r
486 \r
487 void scsiPhyInit()\r
488 {\r
489         scsiPhyInitDMA();\r
490 \r
491         *SCSI_CTRL_IDMASK = 0x00; // Reset in scsiPhyConfig\r
492         *SCSI_CTRL_PHASE = 0x00;\r
493         *SCSI_CTRL_BSY = 0x00;\r
494         scsiPhyFifoSel = 0;\r
495         *SCSI_FIFO_SEL = 0;\r
496 \r
497 }\r
498 \r
499 void scsiPhyConfig()\r
500 {\r
501         if (scsiDev.boardCfg.flags6 & S2S_CFG_ENABLE_TERMINATOR)\r
502         {\r
503                 HAL_GPIO_WritePin(nTERM_EN_GPIO_Port, nTERM_EN_Pin, GPIO_PIN_RESET);\r
504         }\r
505         else\r
506         {\r
507                 HAL_GPIO_WritePin(nTERM_EN_GPIO_Port, nTERM_EN_Pin, GPIO_PIN_SET);\r
508         }\r
509 \r
510 \r
511         uint8_t idMask = 0;\r
512         for (int i = 0; i < 8; ++i)\r
513         {\r
514                 const S2S_TargetCfg* cfg = s2s_getConfigById(i);\r
515                 if (cfg && (cfg->scsiId & S2S_CFG_TARGET_ENABLED))\r
516                 {\r
517                         idMask |= (1 << i);\r
518                 }\r
519         }\r
520         *SCSI_CTRL_IDMASK = idMask;\r
521 }\r
522 \r
523 \r
524 // 1 = DBx error\r
525 // 2 = Parity error\r
526 // 4 = MSG error\r
527 // 8 = CD error\r
528 // 16 = IO error\r
529 // 32 = other error\r
530 int scsiSelfTest()\r
531 {\r
532         return 0;\r
533 #if 0\r
534         int result = 0;\r
535 \r
536         // TEST DBx and DBp\r
537         int i;\r
538         SCSI_Out_Ctl_Write(1); // Write bits manually.\r
539         SCSI_CTL_PHASE_Write(__scsiphase_io); // Needed for parity generation\r
540         for (i = 0; i < 256; ++i)\r
541         {\r
542                 SCSI_Out_Bits_Write(i);\r
543                 scsiDeskewDelay();\r
544                 if (scsiReadDBxPins() != (i & 0xff))\r
545                 {\r
546                         result |= 1;\r
547                 }\r
548                 if (Lookup_OddParity[i & 0xff] != SCSI_ReadPin(SCSI_In_DBP))\r
549                 {\r
550                         result |= 2;\r
551                 }\r
552         }\r
553         SCSI_Out_Ctl_Write(0); // Write bits normally.\r
554 \r
555         // TEST MSG, CD, IO\r
556         for (i = 0; i < 8; ++i)\r
557         {\r
558                 SCSI_CTL_PHASE_Write(i);\r
559                 scsiDeskewDelay();\r
560 \r
561                 if (SCSI_ReadPin(SCSI_In_MSG) != !!(i & __scsiphase_msg))\r
562                 {\r
563                         result |= 4;\r
564                 }\r
565                 if (SCSI_ReadPin(SCSI_In_CD) != !!(i & __scsiphase_cd))\r
566                 {\r
567                         result |= 8;\r
568                 }\r
569                 if (SCSI_ReadPin(SCSI_In_IO) != !!(i & __scsiphase_io))\r
570                 {\r
571                         result |= 16;\r
572                 }\r
573         }\r
574         SCSI_CTL_PHASE_Write(0);\r
575 \r
576         uint32_t signalsOut[] = { SCSI_Out_ATN, SCSI_Out_BSY, SCSI_Out_RST, SCSI_Out_SEL };\r
577         uint32_t signalsIn[] = { SCSI_Filt_ATN, SCSI_Filt_BSY, SCSI_Filt_RST, SCSI_Filt_SEL };\r
578 \r
579         for (i = 0; i < 4; ++i)\r
580         {\r
581                 SCSI_SetPin(signalsOut[i]);\r
582                 scsiDeskewDelay();\r
583 \r
584                 int j;\r
585                 for (j = 0; j < 4; ++j)\r
586                 {\r
587                         if (i == j)\r
588                         {\r
589                                 if (! SCSI_ReadFilt(signalsIn[j]))\r
590                                 {\r
591                                         result |= 32;\r
592                                 }\r
593                         }\r
594                         else\r
595                         {\r
596                                 if (SCSI_ReadFilt(signalsIn[j]))\r
597                                 {\r
598                                         result |= 32;\r
599                                 }\r
600                         }\r
601                 }\r
602                 SCSI_ClearPin(signalsOut[i]);\r
603         }\r
604         return result;\r
605 #endif\r
606 }\r
607 \r