/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * This file is part of libaacs * Copyright (C) 2009-2010 Obliter0n * Copyright (C) 2010-2015 npzacs * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see * . */ #if HAVE_CONFIG_H #include "config.h" #endif #include "mmc_device.h" #include "util/macro.h" #include "util/logging.h" #include #include #include #include /* * from ntddscsi.h, Windows DDK */ #define SCSI_IOCTL_DATA_OUT 0 #define SCSI_IOCTL_DATA_IN 1 #define SCSI_IOCTL_DATA_UNSPECIFIED 2 #define IOCTL_SCSI_PASS_THROUGH_DIRECT 0x4D014 #define MAX_SENSE_LEN 18 typedef struct _SCSI_PASS_THROUGH_DIRECT { USHORT Length; UCHAR ScsiStatus; UCHAR PathId; UCHAR TargetId; UCHAR Lun; UCHAR CdbLength; UCHAR SenseInfoLength; UCHAR DataIn; ULONG DataTransferLength; ULONG TimeOutValue; PVOID DataBuffer; ULONG SenseInfoOffset; UCHAR Cdb[16]; } SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT; /* * */ struct mmcdev { HANDLE fd; }; int device_send_cmd(MMCDEV *dev, const uint8_t *cmd, uint8_t *buf, size_t tx, size_t rx) { DWORD dwBytesReturned; struct { SCSI_PASS_THROUGH_DIRECT sptd; UCHAR SenseBuf[MAX_SENSE_LEN]; } sptd_sb; if (dev->fd == INVALID_HANDLE_VALUE) { return 0; } sptd_sb.sptd.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); sptd_sb.sptd.PathId = 0; sptd_sb.sptd.TargetId = 0; sptd_sb.sptd.Lun = 0; sptd_sb.sptd.CdbLength = 12; sptd_sb.sptd.SenseInfoLength = MAX_SENSE_LEN; sptd_sb.sptd.TimeOutValue = 5; sptd_sb.sptd.SenseInfoOffset = sizeof(SCSI_PASS_THROUGH_DIRECT); if (buf) { if (tx) { sptd_sb.sptd.DataIn = SCSI_IOCTL_DATA_OUT; sptd_sb.sptd.DataTransferLength = tx; sptd_sb.sptd.DataBuffer = buf; } else if (rx) { sptd_sb.sptd.DataIn = SCSI_IOCTL_DATA_IN; sptd_sb.sptd.DataTransferLength = rx; sptd_sb.sptd.DataBuffer = buf; } } else { sptd_sb.sptd.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED; sptd_sb.sptd.DataTransferLength = 0; sptd_sb.sptd.DataBuffer = NULL; } memcpy(sptd_sb.sptd.Cdb, cmd, 16); ZeroMemory(sptd_sb.SenseBuf, MAX_SENSE_LEN); if (DeviceIoControl(dev->fd, IOCTL_SCSI_PASS_THROUGH_DIRECT, (void*)&sptd_sb, sizeof(sptd_sb), (void*)&sptd_sb, sizeof(sptd_sb), &dwBytesReturned, NULL)) { if (sptd_sb.sptd.ScsiStatus == 0 /* STATUS_GOOD */) { BD_DEBUG(DBG_MMC, " Send succeeded!\n"); return 1; } } BD_DEBUG(DBG_MMC, " Send failed!\n"); return 0; } MMCDEV *device_open(const char *path) { char drive[] = { path[0], ':', '\\', 0 }; char volume[] = {'\\', '\\', '.', '\\', path[0], ':', 0}; UINT type; HANDLE fd; MMCDEV *dev; BD_DEBUG(DBG_MMC, "Opening Windows MMC drive %s...\n", drive); type = GetDriveType(drive); if (type != DRIVE_CDROM) { BD_DEBUG(DBG_MMC | DBG_CRIT, "Drive %s is not CD/DVD drive\n", drive); return NULL; } fd = CreateFile(volume, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (fd == INVALID_HANDLE_VALUE) { fd = CreateFile(volume, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (fd == INVALID_HANDLE_VALUE) { BD_DEBUG(DBG_MMC, "Failed opening Windows MMC drive %s\n", volume); return NULL; } } BD_DEBUG(DBG_MMC, "Windows MMC drive %s opened\n", volume); dev = calloc(1, sizeof(MMCDEV)); if (!dev) { BD_DEBUG(DBG_MKB | DBG_CRIT, "out of memory\n"); CloseHandle(fd); return NULL; } dev->fd = fd; return dev; } void device_close(MMCDEV **pp) { if (pp && *pp) { if ((*pp)->fd != INVALID_HANDLE_VALUE) { CloseHandle((*pp)->fd); } X_FREE(*pp); } }