private static int ReadSubChannel <T>(UnixFileDescriptor fd, CDDataFormat format, byte track, out T data) where T : struct { var req = new ReadSubChannelRequest { address_format = CDAddressFormat.CD_LBA_FORMAT, data_format = format, track = track, data_len = Util.SizeOfStructure <T>(), }; req.data = Marshal.AllocHGlobal(new IntPtr(req.data_len)); try { var rc = NativeApi.SendIORequest(fd.Value, IOCTL.CDIOCREADSUBCHANNEL, ref req); if (rc == 0) { data = Util.MarshalPointerToStructure <T>(req.data); } else { data = default(T); } return(rc); } finally { Marshal.FreeHGlobal(req.data); } }
public static UnixFileDescriptor OpenDevice(string name) { const uint O_RDONLY = 0x0000; const uint O_NONBLOCK = 0x0800; return(UnixFileDescriptor.OpenPath(name, O_RDONLY | O_NONBLOCK, 0)); }
public static void GetCdTextInfo(UnixFileDescriptor fd, out MMC.CDTextDescriptor cdtext) { var cmd = MMC.CDB.ReadTocPmaAtip.CDText(); try { NativeApi.SendSCSIRequest(fd, ref cmd, out cdtext); } catch (Exception e) { throw new IOException("Failed to retrieve CD-TEXT information.", e); } cdtext.FixUp(); }
public static void GetTableOfContents(UnixFileDescriptor fd, out MMC.TOCDescriptor rawtoc) { var msf = false; var cmd = MMC.CDB.ReadTocPmaAtip.TOC(msf); try { NativeApi.SendSCSIRequest(fd, ref cmd, out rawtoc); } catch (Exception e) { throw new IOException("Failed to retrieve table of contents.", e); } rawtoc.FixUp(msf); }
public static string GetTrackIsrc(UnixFileDescriptor fd, byte track) { if (NativeApi.ReadSubChannel(fd, CDDataFormat.CD_TRACK_INFO, track, out MMC.SubChannelISRC isrc) != 0) { throw new IOException($"Failed to retrieve ISRC for track {track}.", new UnixException()); } isrc.FixUp(); return(isrc.Status.IsValid ? Encoding.ASCII.GetString(isrc.ISRC) : string.Empty); }
public static string GetMediaCatalogNumber(UnixFileDescriptor fd) { if (NativeApi.ReadSubChannel(fd, CDDataFormat.CD_MEDIA_CATALOG, 0, out MMC.SubChannelMediaCatalogNumber mcn) != 0) { throw new IOException("Failed to retrieve media catalog number.", new UnixException()); } mcn.FixUp(); return(mcn.Status.IsValid ? Encoding.ASCII.GetString(mcn.MCN) : string.Empty); }
private static void SendSCSIRequest <TCommand, TData>(UnixFileDescriptor fd, ref TCommand cmd, out TData data) where TCommand : struct where TData : struct { var cmdlen = Util.SizeOfStructure <TCommand>(); if (cmdlen > 16) { throw new InvalidOperationException("A SCSI command must not exceed 16 bytes in size."); } var req = new SCSIRequest { interface_id = 'S', dxfer_direction = SCSITransferDirection.FROM_DEV, timeout = NativeApi.DefaultSCSIRequestTimeOut, cmd_len = (byte)cmdlen, mx_sb_len = (byte)64, dxfer_len = (uint)Util.SizeOfStructure <TData>(), }; var memlen = (uint)(req.cmd_len + req.mx_sb_len + req.dxfer_len); var bytes = NativeApi.AllocZero(new UIntPtr(1), new UIntPtr(memlen)); try { req.cmdp = bytes; req.sbp = req.cmdp + req.cmd_len; req.dxferp = req.sbp + req.mx_sb_len; Marshal.StructureToPtr(cmd, req.cmdp, false); try { if (NativeApi.SendSCSIRequest(fd.Value, IOCTL.SG_IO, ref req) != 0) { throw new UnixException(); } if (req.status == SAM.StatusCode.CHECK_CONDITION || req.driver_status == SCSIDriverStatus.DRIVER_SENSE) { var response = Marshal.ReadByte(req.sbp) & 0x7f; switch (response) { case 0x70: case 0x71: // Fixed Format (Current or Deferred) throw new ScsiException(Util.MarshalPointerToStructure <SPC.FixedSenseData>(req.sbp)); case 0x72: case 0x73: // Descriptor Format (Current or Deferred) throw new ScsiException(Util.MarshalPointerToStructure <SPC.DescriptorSenseData>(req.sbp)); default: throw new IOException($"SCSI CHECK CONDITION: BAD RESPONSE CODE ({response:X2})"); } } data = Util.MarshalPointerToStructure <TData>(req.dxferp); } finally { Util.DestroyStructure <TCommand>(req.cmdp); } } finally { NativeApi.Free(bytes); } }
public static string GetTrackIsrc(UnixFileDescriptor fd, byte track) { MMC.SubChannelISRC isrc; var cmd = MMC.CDB.ReadSubChannel.ISRC(track); try { NativeApi.SendSCSIRequest(fd, ref cmd, out isrc); } catch (Exception e) { throw new IOException($"Failed to retrieve ISRC for track {track}.", e); } isrc.FixUp(); return(isrc.Status.IsValid ? Encoding.ASCII.GetString(isrc.ISRC) : string.Empty); }
public static string GetMediaCatalogNumber(UnixFileDescriptor fd) { MMC.SubChannelMediaCatalogNumber mcn; var cmd = MMC.CDB.ReadSubChannel.MediaCatalogNumber(); try { NativeApi.SendSCSIRequest(fd, ref cmd, out mcn); } catch (Exception e) { throw new IOException("Failed to retrieve media catalog number.", e); } mcn.FixUp(); return(mcn.Status.IsValid ? Encoding.ASCII.GetString(mcn.MCN) : string.Empty); }
public static void ReadTOC(UnixFileDescriptor fd, out byte first, out byte last, out MMC.TrackDescriptor[] tracks, bool nativeAddress) { { // Read the TOC header var req = new TOCHeaderRequest(); if (NativeApi.SendIORequest(fd.Value, IOCTL.CDIOREADTOCHEADER, ref req) != 0) { throw new IOException("Failed to retrieve table of contents.", new UnixException()); } first = req.starting_track; last = req.ending_track; } { var trackcount = last - first + 2; // first->last plus lead-out var itemsize = Util.SizeOfStructure <MMC.TrackDescriptor>(); var req = new TOCEntriesRequest { address_format = CDAddressFormat.CD_LBA_FORMAT, starting_track = first, data_len = (ushort)(trackcount * itemsize), }; req.data = Marshal.AllocHGlobal(new IntPtr(req.data_len)); try { if (NativeApi.SendIORequest(fd.Value, IOCTL.CDIOREADTOCENTRIES, ref req) != 0) { throw new IOException("Failed to retrieve TOC entries.", new UnixException()); } tracks = new MMC.TrackDescriptor[trackcount]; var walker = req.data; for (var i = 0; i < trackcount; ++i) { tracks[i] = Util.MarshalPointerToStructure <MMC.TrackDescriptor>(walker); // The FixUp call assumes the address is in network byte order. if (nativeAddress) { tracks[i].Address = IPAddress.HostToNetworkOrder(tracks[i].Address); } tracks[i].FixUp(req.address_format == CDAddressFormat.CD_MSF_FORMAT); walker += itemsize; } } finally { Marshal.FreeHGlobal(req.data); } } }