4985{
4988
4991
4994 UCHAR dma_status = 0;
4997 UCHAR statusByte = 0,interruptReason;
4998
5000
5001#ifdef _DEBUG
5003#endif
5008 ULONG TimerValue = 1000;
5009 ULONG TotalTimerValue = 0;
5010#ifdef UNIATA_USE_XXableInterrupts
5012#else
5014#endif
5016
5020
5022 if(InDpc) {
5024
5025 }
5026
5031
5033
5035
5036#ifdef _DEBUG
5037 Channel = (
UCHAR)(deviceExtension->
Channel + lChannel);
5038
5040#endif
5041
5047 }
5048
5049 if (srb) {
5053 } else {
5057 goto enqueue_next_req;
5058 }
5059
5060
5065
5066
5067 if(InDpc) {
5069 goto ServiceInterrupt;
5070 }
5071
5072 if (DmaTransfer) {
5074 }
5075
5077
5080 }
5081
5082
5083 if(AtaReq) {
5087 }
5088
5089
5090
5091
5092
5093
5094
5095 if(DmaTransfer)
5096 goto ServiceInterrupt;
5097
5098 switch(OldReqState) {
5106 goto ServiceInterrupt;
5110 }
5111
5112 if((!DmaTransfer && !atapiDev) || deviceExtension->
DriverMustPoll) {
5115 }
5116
5117#ifndef UNIATA_CORE
5118
5119 if(!UseDpc)
5120 goto ServiceInterrupt;
5121
5122#ifdef UNIATA_USE_XXableInterrupts
5123 if(InDpc) {
5126
5127 TimerValue = 1;
5128 goto CallTimerDpc;
5129 }
5130
5132 if(AtaReq) {
5135 } else {
5137 }
5138#else
5140 goto ServiceInterrupt;
5141#endif
5142
5143PostToDpc:
5144
5145
5146
5147
5148
5149
5151
5152
5156 }
5157
5159
5160#ifdef UNIATA_USE_XXableInterrupts
5161
5165#else
5166
5169 TimerValue);
5171#endif
5173
5174#ifndef UNIATA_CORE
5175CallTimerDpc:
5177CallTimerDpc2:
5179
5180
5181
5183
5184 }
5185
5188 TimerValue);
5190#endif
5191
5192ServiceInterrupt:
5193
5194 if(AtaReq && InDpc) {
5197 goto PIO_wait_DRQ0;
5199 goto PIO_wait_busy;
5201 goto PIO_wait_DRQ;
5203 goto continue_err;
5206
5207 break;
5208 }
5209 }
5210#else
5211ServiceInterrupt:
5212#endif
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5230
5236
5241 ) {
5243
5244 } else {
5245
5246
5247
5248
5254 }
5255 }
5256 } else {
5257
5258#ifdef _DEBUG
5259 UniataDumpAhciPortRegs(chan);
5260#endif
5263 }
5264#ifdef _DEBUG
5265 UniataDumpAhciPortRegs(chan);
5266#endif
5268 }
5269 }
5270
5271 } else {
5273 }
5274 if(atapiDev) {
5276 } else {
5278 }
5279
5280 if(!UseDpc) {
5283 }
5284
5285 if (!atapiDev) {
5286
5289 } else
5292
5293
5295 goto ReturnEnableIntr;
5296 }
5297try_dpc_wait:
5298
5299
5300 k = (InDpc && UseDpc) ? 1000 : 2;
5301
5302 for (
i = 0;
i <
k;
i++) {
5303
5306 break;
5307 }
5309 }
5310
5311 if (!InDpc && UseDpc &&
i == 2) {
5312
5314
5315 TimerValue = 50;
5317
5318#ifndef UNIATA_CORE
5319 goto PostToDpc;
5320#else
5322 goto ServiceInterrupt;
5323#endif
5324 } else
5325 if (InDpc &&
i ==
k) {
5326
5328 " Resetting due to BUSY on entry - %#x.\n",
5329 statusByte));
5330 goto IntrPrepareResetController;
5331 }
5332 }
5333 } else {
5334
5336 InDpc &&
5339 ) {
5340
5341
5342 }
5345 } else {
5348 }
5349
5351
5352
5353
5354
5355
5356
5357
5358
5360#ifndef UNIATA_CORE
5365 goto CallTimerDpc2;
5366 }
5367#endif
5368 TimerValue = 10;
5376 break;
5377 }
5378 TotalTimerValue += TimerValue;
5381 if(!InDpc) {
5383 TimerValue = 100;
5385 } else {
5387 TimerValue = 1000;
5389 }
5390#ifndef UNIATA_CORE
5391 if(UseDpc) {
5394 }
5395 goto CallTimerDpc2;
5396 }
5397#endif
5398 }
5399
5401 TimerValue += 10;
5402 }
5406 }
5409 goto try_dpc_wait;
5410 }
5411 }
5412 }
5413
5415 switch(OldReqState) {
5418
5422 }
5423 break;
5424 }
5425 }
5426
5427
5428
5431
5434
5435#ifdef _DEBUG
5436 UniataDumpAhciPortRegs(chan);
5437#endif
5440 }
5441
5443#ifdef _DEBUG
5444 UniataDumpAhciPortRegs(chan);
5445#endif
5452 }
5453 }
5454#ifdef _DEBUG
5455 UniataDumpAhciPortRegs(chan);
5456#endif
5457 } else {
5459 }
5461
5462
5463
5464
5465
5466
5467
5468 if(AtaReq) {
5470 } else {
5472 }
5473
5476 } else
5477 if(!atapiDev) {
5480 } else {
5483 }
5484continue_err:
5485
5488
5489 for (
k = atapiDev ? 0 : 200;
k;
k--) {
5493 } else {
5494 break;
5495 }
5496 }
5497
5498 if (!atapiDev) {
5499
5500
5503#ifdef IO_STATISTICS
5505#endif
5506 if(DmaTransfer
5507) {
5510
5512
5513
5515 }
5517 goto reenqueue_req;
5518 }
5519 } else {
5522 }
5524 }
5525 }
5526 } else {
5529
5532
5533 } else
5536 }
5537 }
5538
5542
5543
5544 AtaReq->
Flags &= ~REQ_FLAG_DMA_OPERATION;
5546
5548 goto reenqueue_req;
5549 }
5550 } else {
5553 }
5555 }
5556 }
5557
5560
5563 } else {
5565 }
5566 } else
5570 } else
5572#ifdef IO_STATISTICS
5578 ));
5582 ) {
5583#else
5585#endif
5589 }
5590 }
5591#ifdef IO_STATISTICS
5593
5595 }
5597#endif
5598
5599continue_PIO:
5600
5601
5602 if (atapiDev) {
5603
5605
5606
5609 if(DmaTransfer) {
5611 } else {
5613 }
5614
5615 } else {
5616
5617
5618
5619 if(DmaTransfer) {
5620
5622 }
5624
5625 if(DmaTransfer) {
5627 } else
5630 }
5631
5633
5635
5638
5639 } else {
5642 }
5643
5645
5646
5649
5650 } else {
5651
5654
5655
5656PIO_wait_DRQ0:
5657
5658 for (
k = 0;
k < 5000;
k++) {
5661 break;
5662 }
5663 if(!InDpc) {
5664
5666 TimerValue = 100;
5668#ifndef UNIATA_CORE
5669 goto PostToDpc;
5670#else
5672 goto ServiceInterrupt;
5673#endif
5674 }
5676 }
5678
5680 statusByte));
5681IntrPrepareResetController:
5683 goto ReturnEnableIntr;
5684
5685 } else {
5687 }
5688
5689 } else {
5690
5691
5693 }
5694 }
5695 }
5696
5697 KdPrint2((
PRINT_PREFIX "AtapiInterrupt: i-reason=%d, status=%#x\n", interruptReason, statusByte));
5700
5701
5702
5703
5704
5705
5708 } else {
5710 }
5711
5712
5713
5717 } else
5721 }
5722
5724
5729
5733 }
5734
5735 goto ReturnEnableIntr;
5736
5738
5739
5740 if (atapiDev) {
5741
5742
5743 wordCount =
5745
5746 wordCount |=
5748
5749
5750 wordCount >>= 1;
5752
5755 "AtapiInterrupt: %d words requested; %d words xferred\n",
5757 wordCount));
5758 }
5759
5760
5764 "AtapiInterrupt: Write underrun\n"));
5766 }
5767
5768 } else {
5769
5770
5771 if (AtaReq->
WordsLeft < wordsThisInterrupt) {
5772
5774 } else {
5775
5776 wordCount = wordsThisInterrupt;
5777 }
5778 }
5779
5780 if (DmaTransfer &&
5782
5785 "IdeIntr: DMA tmp INTR %#x vs %#x\n", AtaReq->
WordsLeft, wordCount));
5790 goto ReturnEnableIntr;
5791 }
5793 }
5799 }
5800
5801
5803
5805 "AtapiInterrupt: Write interrupt\n"));
5806
5808
5810 || (wordCount & 1)) {
5811
5814 wordCount,
5816 } else {
5817
5820 wordCount / 2,
5822 }
5823 } else {
5824
5826 "AtapiInterrupt: Int reason %#x, but srb is for a read %#x.\n",
5827 interruptReason,
5828 srb));
5829
5830
5833
5835 "AtapiInterrupt: Try ATAPI reset\n"));
5836
5842
5843
5844 }
5846 }
5847
5851
5852 if (atapiDev) {
5854 }
5855
5856 goto ReturnEnableIntr;
5857
5859
5860continue_read_drq:
5861
5862 if (atapiDev) {
5863
5864
5865 wordCount =
5868
5869
5871 wordCount >>= 1;
5872
5873
5874
5875
5876
5877
5880 "AtapiInterrupt: %d words requested; %d words xferred\n",
5882 wordCount));
5883 }
5884
5885
5889 }
5890
5891 } else {
5892
5893
5894 if (AtaReq->
WordsLeft < wordsThisInterrupt) {
5895
5897 } else {
5898
5899 wordCount = wordsThisInterrupt;
5900 }
5901 }
5902
5903 if(DmaTransfer &&
5907 "IdeIntr: DMA tmp INTR %#x vs %#x\n", AtaReq->
WordsLeft, wordCount));
5912 goto ReturnEnableIntr;
5913 }
5915 }
5916
5922 }
5923
5925
5926
5927
5928
5930
5933 "IdeIntr: unaligned ATAPI %#x Words\n", wordCount));
5934 } else
5937 "IdeIntr: pre-Read %#x Dwords\n", wordCount/2));
5938
5941 wordCount / 2,
5943
5947 wordCount &= 1;
5948 }
5949 if (wordCount) {
5951 "IdeIntr: Read %#x words\n", wordCount));
5952
5955 wordCount,
5957 }
5958
5959 KdPrint2((
"IdeIntr: PIO Read AtaReq->DataBuffer %#x, srb->DataBuffer %#x\n", AtaReq->
DataBuffer, (srb ? srb->
DataBuffer : (
void*)-1) ));
5960
5963 }
5964
5967
5968 if(DataOverrun) {
5972 }
5973
5975 for (
i = 0;
i < 2;
i++) {
5979 break;
5980 }
5981 }
5982 }
5983
5984 } else {
5985
5987 "AtapiInterrupt: Int reason %#x, but srb is for a read %#x.\n",
5988 interruptReason,
5989 srb));
5990
5991
5994 }
5995
5996
6000
6001
6003
6005 if (atapiDev) {
6006
6008
6009
6010
6011
6013
6017 }
6018
6021 }
6022#ifndef UNIATA_INIT_CHANGERS
6023 else
6025
6027
6029 srb,
6033 }
6034#endif
6035 }
6038
6039
6040
6041
6043
6046 }
6047
6048 } else {
6049
6050
6051
6052
6053
6054
6055
6056
6057
6058
6059
6062
6063 }
6064 } else {
6065 if (atapiDev) {
6069
6070
6071
6072
6073 KdPrint2((
PRINT_PREFIX "AtapiInterrupt: early complete + underrun ? status %x\n", statusByte));
6074
6077 }
6078 } else {
6082 goto continue_read_drq;
6083 }
6084 }
6085 }
6086
6087 goto ReturnEnableIntr;
6088
6090
6092
6093
6094 if(DmaTransfer) {
6098 } else {
6100
6102
6106
6108
6109 }
6110
6111
6112
6114
6115
6116#ifdef UNIATA_DUMP_ATAPI
6117 if(srb &&
6122 PCHAR ModeSelectData;
6125
6127 ScsiCommand =
Cdb->
CDB6.OperationCode;
6130
6131 if(CdbDataLen > 0x1000) {
6132 CdbDataLen = 0x1000;
6133 }
6134
6136 KdPrint2((
"DeviceID+VendorID/Rev %#x/%#x\n", deviceExtension->
DevID, deviceExtension->
RevID));
6141 KdPrint((
"Complete SCSI Command %2.2x\n", ScsiCommand));
6143
6147 ModeSelectData = CdbData+4;
6148 KdDump(CdbData, CdbDataLen);
6149 } else
6153 ModeSelectData = CdbData+8;
6154 KdDump(CdbData, CdbDataLen);
6155 } else {
6157 KdPrint((
"Read buffer from device:\n"));
6158 KdDump(CdbData, CdbDataLen);
6159 }
6160 }
6162 }
6163#endif
6164
6166
6168
6169
6173 }
6174
6176
6178
6181#ifdef UNIATA_INIT_CHANGERS
6182
6185
6187 srb,
6189
6190
6193
6194 } else {
6195
6197 HwDeviceExtension,
6199 }
6200
6201
6202
6203
6204
6205
6206
6207
6209
6211
6214 goto ReturnEnableIntr;
6215 }
6216
6217
6218
6219
6220
6221
6222
6223#else
6226#endif
6227 } else {
6228
6230#ifdef __REACTOS__
6231 (void)senseData;
6232#endif
6233
6236
6240 }
6241 }
6242
6244#ifndef UNIATA_CORE
6245#ifdef UNIATA_INIT_CHANGERS
6249
6251
6254 HwDeviceExtension,
6256 } else
6257#endif
6258 {
6259
6262 }
6263#endif
6264
6265
6266
6267
6268
6269
6270
6271
6273
6275
6278 goto ReturnEnableIntr;
6279 }
6280
6281
6282
6283
6284
6285
6286
6287 }
6288 }
6289
6290
6291
6292
6294
6298 }
6299
6301
6302
6308
6310
6311
6314 srb);
6315
6317
6318 } else if(!DmaTransfer) {
6319
6321
6322PIO_wait_busy:
6324
6325 for (
i = 0;
i < 5*30;
i++) {
6328 break;
6329 }
6330 if(!InDpc) {
6331
6333 TimerValue = 200;
6335#ifndef UNIATA_CORE
6336 goto PostToDpc;
6337#else
6339 goto ServiceInterrupt;
6340#endif
6341 }
6343 }
6344
6346
6347
6349 "AtapiInterrupt: Resetting due to BSY still up - %#x.\n",
6350 statusByte));
6351 goto IntrPrepareResetController;
6352 }
6353
6356 if(srb) {
6359 } else {
6361 }
6362 } else {
6364 }
6365 if(AtaReq) {
6367 } else {
6369 }
6371) {
6373 goto continue_PIO;
6374 }
6375 }
6376
6377
6380
6381PIO_wait_DRQ:
6383 for (
i = 0;
i < 200;
i++) {
6386 break;
6387 }
6388 if(!InDpc) {
6389
6392 TimerValue = 100;
6393#ifndef UNIATA_CORE
6394 goto PostToDpc;
6395#else
6397 goto ServiceInterrupt;
6398#endif
6399 }
6401 }
6402
6404
6406 statusByte));
6407 goto IntrPrepareResetController;
6408 }
6409 }
6410 if(atapiDev) {
6411 KdPrint2((
"IdeIntr: ATAPI Read AtaReq->DataBuffer %#x, srb->DataBuffer %#x, len %#x\n",
6413
6414 }
6416 KdPrint2((
"IdeIntr: Can't sync DMA and PIO buffers\n"));
6417 }
6418 }
6419
6420
6422
6425
6426
6428
6430
6431
6433
6435
6436
6440 } else {
6442 }
6443 } else {
6445 }
6446 }
6448
6449
6450
6451
6452 if(!atapiDev &&
6456 AtaReq->
Flags &= ~REQ_FLAG_DMA_OPERATION;
6458 goto reenqueue_req;
6459 } else {
6462 }
6463 }
6464
6466
6467CompleteRDP:
6468
6471IntrCompleteReq:
6472
6476
6478
6481 senseBuffer->
Valid = 1;
6486
6488 }
6494 deviceExtension,
6495 srb);
6496 }
6497 } else {
6498
6500
6504 }
6505
6507
6509
6513
6514
6515
6518
6521
6524
6526 }
6528 }
6529
6530 goto IntrCompleteReq;
6531 }
6532
6533 } else {
6534
6536 }
6537
6539
6540 for (
i = 0;
i < 5;
i++) {
6545 goto CompleteRDP;
6546 } else
6550 goto CompleteRDP;
6551 }
6553 }
6554 }
6555
6558
6559 TimerValue = 2000;
6560#ifndef UNIATA_CORE
6561 goto CallTimerDpc;
6562#else
6564 goto ServiceInterrupt;
6565#endif
6566 }
6567
6568
6569enqueue_next_req:
6570
6572
6573reenqueue_req:
6574
6575#ifndef UNIATA_CORE
6577 if(!srb) {
6579 deviceExtension,
6581 } else {
6583 deviceExtension,
6587
6590 }
6591 }
6592
6595 }
6596#endif
6597
6598 goto ReturnEnableIntr;
6599
6600 } else {
6601
6602
6603 KdPrint2((
PRINT_PREFIX "AtapiInterrupt: Unexpected ATAPI interrupt. InterruptReason %#x. Status %#x.\n",
6604 interruptReason,
6605 statusByte));
6606
6611 goto continue_PIO;
6612 }
6613 }
6614 }
6615
6622 }
6623 }
6624
6625ReturnEnableIntr:
6626
6628
6630 if(UseDpc) {
6631 if(CrNtInterlockedExchangeAdd(&(chan->
DisableIntr), 0)) {
6633#ifdef UNIATA_USE_XXableInterrupts
6634
6636
6639#else
6643
6644#ifndef UNIATA_CORE
6647 1);
6648#endif
6650#endif
6651 }
6652 }
6653
6655
6656
6657 KdPrint2((
PRINT_PREFIX "AtapiInterrupt: exiting, UseDpc=%d, NoStartIo=%d\n", UseDpc, NoStartIo));
6658
6659#ifndef UNIATA_CORE
6660 if(!UseDpc && !NoStartIo) {
6662 if(chan) {
6664 } else {
6666 }
6668 if(srb) {
6670 }
6671 }
6672#endif
6674
6675}
#define WriteBuffer(BaseIoAddress, Buffer, Count)
#define ReadBuffer(BaseIoAddress, Buffer, Count)
#define DFLAGS_TAPE_DEVICE
#define WriteBuffer2(BaseIoAddress, Buffer, Count)
#define ReadBuffer2(BaseIoAddress, Buffer, Count)
#define AtapiSoftReset(BaseIoAddress, DeviceNumber)
struct _SENDCMDOUTPARAMS * PSENDCMDOUTPARAMS
#define UniataGetPioTiming(LunExt)
#define REQ_STATE_PROCESSING_INTR
#define REQ_STATE_ATAPI_EXPECTING_DATA_INTR
#define ATA_SE_HANDSHAKE_ERR
BOOLEAN NTAPI AtapiDmaDBPreSync(IN PVOID HwDeviceExtension, PHW_CHANNEL chan, PSCSI_REQUEST_BLOCK Srb)
#define REQ_STATE_DPC_WAIT_BUSY0
#define REQ_STATE_DPC_WAIT_DRQ
#define REQ_FLAG_DMA_OPERATION
#define REQ_FLAG_FORCE_DOWNRATE
#define REQ_STATE_DPC_WAIT_BUSY
#define REQ_STATE_DPC_WAIT_BUSY1
#define REQ_FLAG_FORCE_DOWNRATE_LBA48
#define HBAFLAGS_DMA_DISABLED_LBA48
#define ATA_SE_LINKSEQ_ERR
#define REQ_STATE_ATAPI_DO_NOTHING_INTR
#define CTRFLAGS_DMA_OPERATION
#define ATA_SE_UNKNOWN_FIS
#define REQ_STATE_ATAPI_EXPECTING_CMD_INTR
BOOLEAN NTAPI AtapiDmaPioSync(PVOID HwDeviceExtension, PSCSI_REQUEST_BLOCK Srb, PUCHAR data, ULONG count)
#define REQ_STATE_PREPARE_TO_NEXT
#define ATA_SE_TRANSPORT_ERR
#define REQ_STATE_TRANSFER_COMPLETE
#define REQ_STATE_DPC_WAIT_DRQ_ERR
#define REQ_STATE_DPC_WAIT_DRQ0
#define REQ_STATE_DPC_INTR_REQ
VOID NTAPI AtapiDmaStart(IN PVOID HwDeviceExtension, IN ULONG DeviceNumber, IN ULONG lChannel, IN PSCSI_REQUEST_BLOCK Srb)
#define SCSIOP_MODE_SENSE10
#define SCSIOP_REQUEST_SENSE
struct _SENSE_DATA * PSENSE_DATA
#define SCSIOP_READ_CAPACITY
#define SCSIOP_MECHANISM_STATUS
#define SCSI_SENSE_ILLEGAL_REQUEST
#define SCSIOP_MODE_SENSE
#define SCSI_SENSE_HARDWARE_ERROR
struct _MODE_PARAMETER_HEADER * PMODE_PARAMETER_HEADER
NTSTATUS NTAPI CompleteRequest(IN PIRP Irp, IN NTSTATUS Status, IN ULONG_PTR Information)
#define SRB_STATUS_BUS_RESET
#define SRB_FUNCTION_IO_CONTROL
#define SRB_STATUS_DATA_OVERRUN
#define SRB_FLAGS_DATA_OUT
#define SRB_STATUS_PENDING
#define SRB_STATUS_AUTOSENSE_VALID
#define SRB_FLAGS_DATA_IN
#define SRB_STATUS_SUCCESS
#define KeGetCurrentIrql()
#define IDX_ATAPI_IO1_i_ByteCountHigh
#define IDX_ATAPI_IO1_i_ByteCountLow
#define IDX_ATAPI_IO1_i_Error
ULONG NTAPI AtapiSendCommand(IN PVOID HwDeviceExtension, IN PSCSI_REQUEST_BLOCK Srb, IN ULONG CmdAction)
#define RESET_COMPLETE_CURRENT
VOID NTAPI UniataSnapAtaRegs(IN PHW_CHANNEL chan, IN ULONG DeviceNumber, IN OUT PIDEREGS_EX regs)
PSCSI_REQUEST_BLOCK NTAPI BuildRequestSenseSrb(IN PVOID HwDeviceExtension, IN PSCSI_REQUEST_BLOCK Srb)
UCHAR DDKFASTAPI AtapiSuckPort2(IN PHW_CHANNEL chan)
VOID NTAPI AtapiHwInitializeChanger(IN PVOID HwDeviceExtension, IN PSCSI_REQUEST_BLOCK Srb, IN PMECHANICAL_STATUS_INFORMATION_HEADER MechanismStatus)
ULONG NTAPI MapError(IN PVOID HwDeviceExtension, IN PSCSI_REQUEST_BLOCK Srb)
ULONG g_opt_VirtualMachine
RETTYPE_XXableInterrupts NTAPI AtapiInterruptDpc(IN PVOID HwDeviceExtension)
PSCSI_REQUEST_BLOCK NTAPI BuildMechanismStatusSrb(IN PVOID HwDeviceExtension, IN PSCSI_REQUEST_BLOCK Srb)
BOOLEAN NTAPI UniataAhciAbortOperation(IN PHW_CHANNEL chan)
UCHAR NTAPI UniataAhciEndTransaction(IN PVOID HwDeviceExtension, IN ULONG lChannel, IN ULONG DeviceNumber, IN PSCSI_REQUEST_BLOCK Srb)
#define RETURN_SMART_STATUS
_In_opt_ WDFREQUEST _In_ ULONG _In_ BOOLEAN _In_ PCDB Cdb
struct _SRB_IO_CONTROL SRB_IO_CONTROL
ULONG MechStatusRetryCount
LONGLONG RecoverCount[MAX_RETRIES]
ULONG AtapiReadyWaitDelay
UCHAR SenseInfoBufferLength
DRIVERSTATUS DriverStatus
UCHAR AdditionalSenseLength
UCHAR AdditionalSenseCode
UCHAR AdditionalSenseCodeQualifier
#define FIELD_OFFSET(t, f)
struct _IDEREGS_EX * PIDEREGS_EX
#define ATAPI_IR_IO_toHost
#define DFLAGS_DWORDIO_ENABLED
#define ATAPI_IR_IO_toDev