diff --git a/CMakeLists.txt b/CMakeLists.txt index fff0b3f..4c25698 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,10 +3,10 @@ project(dicremote C) set(CMAKE_C_STANDARD 90) -set(MAIN_SOURCES main.c list_devices.c device.c) +set(MAIN_SOURCES main.c list_devices.c device.c scsi.c) if("${CMAKE_SYSTEM}" MATCHES "Linux") - set(PLATFORM_SOURCES linux/list_devices.c linux/linux.h linux/device.c) + set(PLATFORM_SOURCES linux/list_devices.c linux/linux.h linux/device.c linux/scsi.c) endif() add_executable(dicremote ${MAIN_SOURCES} ${PLATFORM_SOURCES}) diff --git a/dicmote.h b/dicmote.h index 86a36e8..b2dfa40 100644 --- a/dicmote.h +++ b/dicmote.h @@ -63,6 +63,11 @@ #define DICMOTE_DEVICE_TYPE_SECURE_DIGITAL 4 #define DICMOTE_DEVICE_TYPE_MMC 5 #define DICMOTE_DEVICE_TYPE_NVME 6 +#define DICMOTE_SCSI_DIRECTION_UNSPECIFIED -1 +#define DICMOTE_SCSI_DIRECTION_NONE 0 +#define DICMOTE_SCSI_DIRECTION_OUT 1 +#define DICMOTE_SCSI_DIRECTION_IN 2 +#define DICMOTE_SCSI_DIRECTION_INOUT 3 #pragma pack(push, 1) @@ -385,5 +390,16 @@ void FreeDeviceInfoList(DeviceInfoList* start); uint16_t DeviceInfoListCount(DeviceInfoList* start); int DeviceOpen(const char* devicePath); int32_t GetDeviceType(const char* devicePath); +int32_t SendScsiCommand(int device_fd, + char* cdb, + char* buffer, + char** senseBuffer, + uint32_t timeout, + int32_t direction, + uint32_t* duration, + uint32_t* sense, + uint32_t cdb_len, + uint32_t* buf_len, + uint32_t* sense_len); #endif diff --git a/linux/linux.h b/linux/linux.h index c7ea63f..6ac7f7e 100644 --- a/linux/linux.h +++ b/linux/linux.h @@ -24,5 +24,15 @@ DeviceInfoList* linux_list_devices(); int linux_open_device(const char* device_path); int32_t linux_get_device_type(const char* devicePath); - +int32_t linux_send_scsi_command(int device_fd, + char* cdb, + char* buffer, + char** senseBuffer, + uint32_t timeout, + int32_t direction, + uint32_t* duration, + uint32_t* sense, + uint32_t cdb_len, + uint32_t* buf_len, + uint32_t* sense_len); #endif // DICREMOTE_LINUX_H diff --git a/linux/scsi.c b/linux/scsi.c new file mode 100644 index 0000000..3fb15ea --- /dev/null +++ b/linux/scsi.c @@ -0,0 +1,76 @@ +/* + * This file is part of the DiscImageChef Remote Server. + * Copyright (c) 2019 Natalia Portillo. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "../dicmote.h" + +#include +#include +#include +#include +#include + +int32_t linux_send_scsi_command(int device_fd, + char* cdb, + char* buffer, + char** senseBuffer, + uint32_t timeout, + int32_t direction, + uint32_t* duration, + uint32_t* sense, + uint32_t cdb_len, + uint32_t* buf_len, + uint32_t* sense_len) +{ + sg_io_hdr_t hdr; + int dir, ret; + *sense_len = 32; + + memset(&hdr, 0, sizeof(sg_io_hdr_t)); + *senseBuffer = malloc(*sense_len); + + if(!*senseBuffer) return -1; + + switch(direction) + { + case DICMOTE_SCSI_DIRECTION_IN: dir = SG_DXFER_FROM_DEV; break; + case DICMOTE_SCSI_DIRECTION_OUT: dir = SG_DXFER_TO_DEV; break; + case DICMOTE_SCSI_DIRECTION_INOUT: dir = SG_DXFER_TO_FROM_DEV; break; + case DICMOTE_SCSI_DIRECTION_NONE: + case DICMOTE_SCSI_DIRECTION_UNSPECIFIED: + default: dir = SG_DXFER_NONE; break; + } + + hdr.interface_id = 'S'; + hdr.cmd_len = (char)cdb_len; + hdr.mx_sb_len = 32; + hdr.dxfer_direction = dir; + hdr.dxfer_len = *buf_len; + hdr.dxferp = buffer; + hdr.cmdp = (unsigned char*)cdb; + hdr.sbp = (unsigned char*)*senseBuffer; + hdr.timeout = timeout; + hdr.flags = SG_FLAG_DIRECT_IO; + + ret = ioctl(device_fd, SG_IO, &hdr); + + *sense |= (hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK; + // TODO: Manual timing if duration is 0 + *duration = hdr.duration; + *sense_len = hdr.sb_len_wr; + + return ret; // TODO: Implement +} \ No newline at end of file diff --git a/scsi.c b/scsi.c new file mode 100644 index 0000000..09411d3 --- /dev/null +++ b/scsi.c @@ -0,0 +1,40 @@ +/* + * This file is part of the DiscImageChef Remote Server. + * Copyright (c) 2019 Natalia Portillo. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#if defined(__linux__) && !defined(__ANDROID__) +#include "linux/linux.h" +#endif + +int32_t SendScsiCommand(int device_fd, + char* cdb, + char* buffer, + char** senseBuffer, + uint32_t timeout, + int32_t direction, + uint32_t* duration, + uint32_t* sense, + uint32_t cdb_len, + uint32_t* buf_len, + uint32_t* sense_len) +{ +#if defined(__linux__) && !defined(__ANDROID__) + return linux_send_scsi_command( + device_fd, cdb, buffer, senseBuffer, timeout, direction, duration, sense, cdb_len, buf_len, sense_len); +#else + return -1; +#endif +} \ No newline at end of file