private void _ReadBlock(ulong aBlockNo, byte[] aData, uint DataOffset) { // Setup the packet #if PATAPI_TRACE BasicConsole.WriteLine("Setup ATAPI packet"); #endif byte[] atapi_packet = new byte[12]; atapi_packet[0] = 0xA8; atapi_packet[1] = 0x0; atapi_packet[2] = (byte)(aBlockNo >> 24); atapi_packet[3] = (byte)(aBlockNo >> 16); atapi_packet[4] = (byte)(aBlockNo >> 8); atapi_packet[5] = (byte)(aBlockNo >> 0); atapi_packet[6] = 0x0; atapi_packet[7] = 0x0; atapi_packet[8] = 0x0; atapi_packet[9] = 1; atapi_packet[10] = 0x0; atapi_packet[11] = 0x0; // Inform the controller we are using PIO mode #if PATAPI_TRACE BasicConsole.WriteLine("Tell controller we are using PIO mode"); #endif BaseDevice.IO.Features.Write_Byte(0); // Tell the drive the buffer size #if PATAPI_TRACE BasicConsole.WriteLine("Tell drive the buffer size"); #endif BaseDevice.IO.LBA1.Write_Byte((byte)BlockSize); // Low byte BaseDevice.IO.LBA1.Write_Byte((byte)(BlockSize >> 8)); // High byte // Send the packet command (includes the wait) #if PATAPI_TRACE BasicConsole.WriteLine("Send Packet command"); #endif PATABase.Status xStatus = BaseDevice.SendCmd(PATABase.Cmd.Packet); // Error occurred #if PATAPI_TRACE BasicConsole.WriteLine("Check for error"); #endif if ((xStatus & PATABase.Status.Error) != 0) { #if PATAPI_TRACE BasicConsole.WriteLine("Error detected"); #endif ExceptionMethods.Throw(new Exceptions.NoDiskException("ATAPI read error! Status bits incorrect in first check.")); } // Check if that invoked an IRQ - it shouldn't have #if PATAPI_TRACE BasicConsole.WriteLine("Check if IRQ invoked"); #endif if (IRQInvoked) { #if PATAPI_TRACE BasicConsole.WriteLine("IRQ had been invoked"); #endif // Allow future IRQs by reading Status register BaseDevice.IO.Status.Read_Byte(); IRQInvoked = false; } // Send the data #if PATAPI_TRACE BasicConsole.WriteLine("Write packet data"); #endif BaseDevice.IO.Data.Write_UInt16s(atapi_packet); // Wait a bit #if PATAPI_TRACE BasicConsole.WriteLine("Brief wait"); #endif BaseDevice.Wait(); // Wait for the IRQ #if PATAPI_TRACE BasicConsole.WriteLine("Wait for IRQ"); #endif if (WaitForIRQ()) { #if PATAPI_TRACE BasicConsole.WriteLine("Error! Wait for IRQ timed out."); BasicConsole.DelayOutput(5); #endif } // Wait for Busy to clear and check alternate status #if PATAPI_TRACE BasicConsole.WriteLine("Wait till not busy"); #endif uint timeout = 0xF0000000; do { BaseDevice.Wait(); xStatus = (PATABase.Status)BaseDevice.IO.Control.Read_Byte(); } while ((xStatus & PATABase.Status.Busy) != 0 && (xStatus & PATABase.Status.Error) == 0 && timeout-- > 0); // Read status reg to clear IRQ #if PATAPI_TRACE BasicConsole.WriteLine("Read status"); #endif xStatus = (PATABase.Status)BaseDevice.IO.Status.Read_Byte(); IRQInvoked = false; // Error occurred #if PATAPI_TRACE BasicConsole.WriteLine("Check for error"); #endif if ((xStatus & (PATABase.Status.Error | PATABase.Status.ATA_SR_DF)) != 0 || (xStatus & PATABase.Status.DRQ) == 0) { #if PATAPI_TRACE BasicConsole.WriteLine("Error detected"); #endif ExceptionMethods.Throw(new Exceptions.NoDiskException("ATAPI read error! Status bits incorrect in second check.")); } // Read the data #if PATAPI_TRACE BasicConsole.WriteLine("Read the data"); BasicConsole.WriteLine("Length: " + (FOS_System.String)aData.Length); #endif uint offset = DataOffset + 1; uint i = 0; for (; i < BlockSize && offset < aData.Length; i += 2, offset += 2) { UInt16 val = BaseDevice.IO.Data.Read_UInt16(); aData[offset - 1] = (byte)(val); aData[offset] = (byte)(val >> 8); } // Clear out any remaining data for (; i < BlockSize; i++) { BaseDevice.IO.Data.Read_UInt16(); } #if PATAPI_TRACE unsafe { BasicConsole.DumpMemory((byte *)Utilities.ObjectUtilities.GetHandle(aData) + FOS_System.Array.FieldsBytesSize, aData.Length); } BasicConsole.WriteLine("Wait for IRQ"); #endif // Wait for IRQ if (WaitForIRQ()) { #if PATAPI_TRACE BasicConsole.WriteLine("Error! Wait for IRQ timed out. (1)"); BasicConsole.DelayOutput(5); #endif } // Wait for Busy and DRQ to clear and check status #if PATAPI_TRACE BasicConsole.WriteLine("Wait till not busy"); #endif timeout = 0xF0000000; do { BaseDevice.Wait(); xStatus = (PATABase.Status)BaseDevice.IO.Control.Read_Byte(); } while ((xStatus & (PATABase.Status.Busy | PATABase.Status.DRQ)) != 0 && (xStatus & PATABase.Status.Error) == 0 && timeout-- > 0); // Error occurred #if PATAPI_TRACE BasicConsole.WriteLine("Check for error"); #endif if ((xStatus & (PATABase.Status.Error | PATABase.Status.ATA_SR_DF)) != 0 || (xStatus & (PATABase.Status.DRQ)) != 0) { #if PATAPI_TRACE BasicConsole.WriteLine("Error detected"); #endif ExceptionMethods.Throw(new FOS_System.Exception("ATAPI read error! Status bits incorrect in third check.")); } #if PATAPI_TRACE BasicConsole.WriteLine("Complete"); BasicConsole.DelayOutput(10); #endif }
protected override void _IssueTransfer(USBTransfer transfer) { #if UHCI_TRACE BasicConsole.WriteLine("UHCI: Issue Transfer"); BasicConsole.DelayOutput(5); #endif UHCITransaction firstTransaction = (UHCITransaction)((USBTransaction)transfer.transactions[0]).underlyingTz; UHCITransaction lastTransaction = (UHCITransaction)((USBTransaction)transfer.transactions[transfer.transactions.Count - 1]).underlyingTz; UHCI_qTD.SetIntOnComplete(lastTransaction.qTD, true); // We want an interrupt after complete transfer CreateQH((UHCI_QueueHead_Struct *)transfer.underlyingTransferData, (uint)transfer.underlyingTransferData, firstTransaction.qTD); #if UHCI_TRACE BasicConsole.WriteLine(" Queue head data:"); BasicConsole.DumpMemory(transfer.underlyingTransferData, sizeof(UHCI_QueueHead_Struct)); BasicConsole.WriteLine(" Transactions data:"); for (int i = 0; i < transfer.transactions.Count; i++) { BasicConsole.Write(" "); BasicConsole.Write(i); BasicConsole.WriteLine(" : "); BasicConsole.WriteLine(" - qTD:"); BasicConsole.DumpMemory( ((UHCITransaction)((USBTransaction)transfer.transactions[i]).underlyingTz).qTD, sizeof(UHCI_qTD_Struct)); BasicConsole.WriteLine(" - qTDBuffer:"); BasicConsole.DumpMemory( ((UHCITransaction)((USBTransaction)transfer.transactions[i]).underlyingTz).qTDBuffer, 16); } BasicConsole.DelayOutput(60); BasicConsole.WriteLine("UHCI: Issuing transfer..."); #endif for (byte i = 0; i < UHCI_Consts.NUMBER_OF_UHCI_RETRIES && !transfer.success; i++) { TransactionsCompleted = 0; for (int j = 0; j < transfer.transactions.Count; j++) { USBTransaction elem = (USBTransaction)transfer.transactions[j]; UHCITransaction uT = (UHCITransaction)(elem.underlyingTz); uT.qTD->u1 = uT.qTD->u1 & 0xFF00FFFF; UHCI_qTD.SetActive(uT.qTD, true); } // stop scheduler USBSTS.Write_UInt16(UHCI_Consts.STS_MASK); USBCMD.Write_UInt16((ushort)(USBCMD.Read_UInt16() & ~UHCI_Consts.CMD_RS)); while ((USBSTS.Read_UInt16() & UHCI_Consts.STS_HCHALTED) == 0) { Hardware.Devices.Timer.Default.Wait(10); } // update scheduler uint qhPhysAddr = ((uint)VirtMemManager.GetPhysicalAddress(transfer.underlyingTransferData) | UHCI_Consts.BIT_QH); FrameList[0] = qhPhysAddr; FRBASEADD.Write_UInt32((uint)VirtMemManager.GetPhysicalAddress(FrameList)); FRNUM.Write_UInt16(0); // start scheduler USBSTS.Write_UInt16(UHCI_Consts.STS_MASK); USBCMD.Write_UInt16((ushort)(USBCMD.Read_UInt16() | UHCI_Consts.CMD_RS)); while ((USBSTS.Read_UInt16() & UHCI_Consts.STS_HCHALTED) != 0) { Hardware.Devices.Timer.Default.Wait(10); } #if UHCI_TRACE BasicConsole.WriteLine(((FOS_System.String) "USBINT val: ") + USBINTR.Read_UInt16()); #endif // run transactions bool active = true; int timeout = 100; //5 seconds while (active && timeout > 0) { active = false; for (int j = 0; j < transfer.transactions.Count; j++) { USBTransaction elem = (USBTransaction)transfer.transactions[j]; UHCITransaction uT = (UHCITransaction)(elem.underlyingTz); active = active || ((uT.qTD->u1 & 0x00FF0000) == 0x00800000); } Hardware.Devices.Timer.Default.Wait(50); timeout--; } #if UHCI_TRACE BasicConsole.WriteLine("Finished waiting."); #endif FrameList[0] = UHCI_Consts.BIT_T; if (timeout == 0 || TransactionsCompleted != transfer.transactions.Count) { #if UHCI_TRACE BasicConsole.SetTextColour(BasicConsole.error_colour); BasicConsole.WriteLine("UHCI: Error! Transactions wait timed out or wrong number of transactions completed."); BasicConsole.SetTextColour(BasicConsole.default_colour); BasicConsole.WriteLine(((FOS_System.String) "Transactions completed: ") + TransactionsCompleted); if (timeout == 0) { BasicConsole.SetTextColour(BasicConsole.error_colour); BasicConsole.WriteLine("UHCI: Error! Transfer timed out."); BasicConsole.SetTextColour(BasicConsole.default_colour); } #endif transfer.success = false; bool completeDespiteNoInterrupt = true; for (int j = 0; j < transfer.transactions.Count; j++) { USBTransaction elem = (USBTransaction)transfer.transactions[j]; UHCITransaction uT = (UHCITransaction)(elem.underlyingTz); #if UHCI_TRACE BasicConsole.WriteLine(((FOS_System.String) "u1=") + uT.qTD->u1 + ", u2=" + uT.qTD->u2); BasicConsole.WriteLine(((FOS_System.String) "Status=") + (byte)(uT.qTD->u1 >> 16)); #endif completeDespiteNoInterrupt = completeDespiteNoInterrupt && isTransactionSuccessful(uT); } transfer.success = completeDespiteNoInterrupt; #if UHCI_TRACE BasicConsole.SetTextColour(BasicConsole.warning_colour); BasicConsole.WriteLine(((FOS_System.String) "Complete despite no interrupts: ") + completeDespiteNoInterrupt); BasicConsole.SetTextColour(BasicConsole.default_colour); BasicConsole.DelayOutput(5); #endif } else { transfer.success = true; } if (transfer.success) { // check conditions and save data for (int j = 0; j < transfer.transactions.Count; j++) { USBTransaction elem = (USBTransaction)transfer.transactions[j]; UHCITransaction uT = (UHCITransaction)(elem.underlyingTz); transfer.success = transfer.success && isTransactionSuccessful(uT); // executed w/o error if (uT.inBuffer != null && uT.inLength != 0) { MemoryUtils.MemCpy_32((byte *)uT.inBuffer, (byte *)uT.qTDBuffer, uT.inLength); } } } #if UHCI_TRACE if (!transfer.success) { BasicConsole.SetTextColour(BasicConsole.error_colour); BasicConsole.WriteLine("UHCI: Transfer failed."); BasicConsole.SetTextColour(BasicConsole.default_colour); } else { BasicConsole.SetTextColour((char)0x0200); BasicConsole.WriteLine("Transfer succeeded."); BasicConsole.SetTextColour(BasicConsole.default_colour); } #endif } }
/// <summary> /// Reads the specified number of bytes from the stream from the current position into the buffer at the /// specified offset or as many bytes as are available before the end of the stream is met. /// </summary> /// <param name="buffer">The byte array to read into.</param> /// <param name="offset">The offset within the buffer to start storing read data at.</param> /// <param name="count">The number of bytes to read.</param> /// <returns>The actual number of bytes read.</returns> public override int Read(byte[] buffer, int offset, int count) { //Don't attempt to read a file of 0 size. if (TheFile.Size > 0) { ISO9660FileSystem TheFS = TheISO9660FileSystem; #if ISO9660FileStream_TRACE BasicConsole.WriteLine("Checking params..."); #endif //Conditions for being able to read from the stream. if (count < 0) { ExceptionMethods.Throw(new Exceptions.ArgumentException("ISO9660FileStream.Read: aCount must be > 0")); } else if (offset < 0) { ExceptionMethods.Throw(new Exceptions.ArgumentException("ISO9660FileStream.Read: anOffset must be > 0")); } else if (buffer == null) { ExceptionMethods.Throw(new Exceptions.ArgumentException("ISO9660FileStream.Read: aBuffer must not be null!")); } else if (buffer.Length - offset < count) { ExceptionMethods.Throw(new Exceptions.ArgumentException("ISO9660FileStream.Read: Invalid offset / length values!")); } else if (position == TheFile.Size) { // EOF return(0); } #if ISO9660FileStream_TRACE BasicConsole.WriteLine("Params OK."); #endif // Clamp the count value so that no out of bounds exceptions occur ulong FileSize = TheFile.Size; ulong MaxReadableBytes = FileSize - position; ulong ActualCount = (ulong)count; if (ActualCount > MaxReadableBytes) { ActualCount = MaxReadableBytes; } #if ISO9660FileStream_TRACE BasicConsole.WriteLine("Creating new sector array..."); #endif //Temporary store of cluster data since we can only // read entire clusters at a time. if (ReadSectorBuffer == null) { ReadSectorBuffer = TheFS.ThePartition.NewBlockArray(1); ReadSectorSize = (uint)TheFS.ThePartition.BlockSize; #if ISO9660FileStream_TRACE BasicConsole.WriteLine(((FOS_System.String) "ReadSectorSize: ") + ReadSectorSize); #endif } int read = 0; #if ISO9660FileStream_TRACE BasicConsole.WriteLine("Reading data..."); #endif //Loop reading in the data while (ActualCount > 0) { UInt32 SectorIdx = ((UInt32)position / ReadSectorSize) + TheISO9660File.TheDirectoryRecord.LBALocation; UInt32 PosInSector = (UInt32)position % ReadSectorSize; #if ISO9660FileStream_TRACE BasicConsole.WriteLine(((FOS_System.String) "Reading sector ") + SectorIdx); #endif TheFS.ThePartition.ReadBlock(SectorIdx, 1, ReadSectorBuffer); #if ISO9660FileStream_TRACE BasicConsole.WriteLine("Read sector."); #endif uint ReadSize; if (PosInSector + ActualCount > ReadSectorSize) { ReadSize = ReadSectorSize - PosInSector; } else { ReadSize = (uint)ActualCount; } #if ISO9660FileStream_TRACE BasicConsole.WriteLine("Read sector buffer: "); unsafe { BasicConsole.DumpMemory((byte *)Utilities.ObjectUtilities.GetHandle(ReadSectorBuffer) + FOS_System.Array.FieldsBytesSize, ReadSectorBuffer.Length); } #endif // TODO: Should we do an argument check here just in case? FOS_System.Array.Copy(ReadSectorBuffer, (int)PosInSector, buffer, offset, (int)ReadSize); offset += (int)ReadSize; ActualCount -= (ulong)ReadSize; read += (int)ReadSize; position += ReadSize; } #if ISO9660FileStream_TRACE BasicConsole.WriteLine("Read data."); #endif return(read); } else { return(0); } }