1 // Copyright (C) 2013 Michael McMaster <michael@codesrc.com>
3 // This file is part of SCSI2SD.
5 // SCSI2SD is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // SCSI2SD is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
26 // htonl/ntohl includes.
30 #include <arpa/inet.h>
35 #define MIN(a,b) (a < b ? a : b)
52 // Must be consistent with the structure defined in the SCSI2SD config.h header.
53 // We always transfer data in network byte order.
54 typedef struct __attribute((packed
))
61 uint8_t enableUnitAttention
;
62 uint8_t reserved1
; // Unused. Ensures maxBlocks is aligned.
64 uint16_t bytesPerSector
;
67 // Pad to 64 bytes, which is what we can fit into a USB HID packet.
71 static void printConfig(ConfigPacket
* packet
)
73 printf("SCSI ID:\t\t\t%d\n", packet
->scsiId
);
74 printf("Vendor:\t\t\t\t\"%.*s\"\n", 8, packet
->vendor
);
75 printf("Product ID:\t\t\t\"%.*s\"\n", 16, packet
->prodId
);
76 printf("Revision:\t\t\t\"%.*s\"\n", 4, packet
->revision
);
78 printf("Parity Checking:\t\t%s\n", packet
->enableParity
? "enabled" : "disabled");
79 printf("Unit Attention Condition:\t%s\n", packet
->enableUnitAttention
? "enabled" : "disabled");
80 printf("Bytes per sector:\t\t%d\n", packet
->bytesPerSector
);
81 if (packet
->maxSectors
)
84 uint64_t maxBytes
= packet
->maxSectors
* (uint64_t) packet
->bytesPerSector
;
85 if (maxBytes
> (1024*1024*1024))
87 sprintf(sizeBuf
, "%.02fGB", maxBytes
/ (1024.0*1024.0*1024.0));
89 else if (maxBytes
> (1024*1024))
91 sprintf(sizeBuf
, "%.02fMB", maxBytes
/ (1024.0*1024.0));
93 else if (maxBytes
> (1024))
95 sprintf(sizeBuf
, "%.02fKB", maxBytes
/ (1024.0));
99 sprintf(sizeBuf
, "%" PRIu64
" bytes", maxBytes
);
102 printf("Maximum Size:\t\t\t%s (%d sectors)\n", sizeBuf
, packet
->maxSectors
);
106 printf("Maximum Size:\t\t\tUnlimited\n");
110 static int readConfig(hid_device
* handle
, ConfigPacket
* packet
)
112 // First byte is the report ID (0)
113 unsigned char buf
[1 + sizeof(ConfigPacket
)];
114 memset(buf
, 0, sizeof(buf
));
115 memset(packet
, 0, sizeof(ConfigPacket
));
116 int result
= hid_read(handle
, buf
, sizeof(buf
));
120 fprintf(stderr
, "USB HID Read Failure: %ls\n", hid_error(handle
));
123 memcpy(packet
, buf
, result
);
124 packet
->maxSectors
= ntohl(packet
->maxSectors
);
125 packet
->bytesPerSector
= ntohs(packet
->bytesPerSector
);
130 static int writeConfig(hid_device
* handle
, ConfigPacket
* packet
)
132 unsigned char buf
[1 + sizeof(ConfigPacket
)];
133 buf
[0] = 0; // report ID
135 packet
->maxSectors
= htonl(packet
->maxSectors
);
136 packet
->bytesPerSector
= htons(packet
->bytesPerSector
);
137 memcpy(buf
+ 1, packet
, sizeof(ConfigPacket
));
138 packet
->maxSectors
= ntohl(packet
->maxSectors
);
139 packet
->bytesPerSector
= ntohs(packet
->bytesPerSector
);
141 int result
= hid_write(handle
, buf
, sizeof(buf
));
145 fprintf(stderr
, "USB HID Write Failure: %ls\n", hid_error(handle
));
153 printf("Usage: scsi2sd-config [options...]\n");
155 printf("--id={0-7}\tSCSI device ID.\n\n");
156 printf("--parity\tCheck the SCSI parity signal, and reject data where\n");
157 printf("\t\tthe parity is bad.\n\n");
158 printf("--no-parity\tDon't check the SCSI parity signal.\n");
159 printf("\t\tThis is required for SCSI host controllers that do not provide\n");
160 printf("\t\tparity.\n\n");
161 printf("--attention\tRespond with a Unit Attention status on device reset.\n");
162 printf("\t\tSome systems will fail on this response, even though it is\n");
163 printf("\t\trequired by the SCSI-2 standard.\n\n");
164 printf("--no-attention\tDisable Unit Attention responses.\n\n");
165 printf("--blocks={0-4294967295}\n\t\tSet a limit to the reported device size.\n");
166 printf("\t\tEach block is 512 bytes. The maximum possible size is 2TB.\n");
167 printf("\t\tThe reported size will be the lower of this value and the SD\n");
168 printf("\t\tcard size. 0 disables the limit.\n\n");
169 printf("--sector={64-2048}\n\t\tSet the bytes-per-sector. Normally 512 bytes.\n");
170 printf("\t\tCan also be set with a SCSI MODE SELECT command.\n\n");
171 printf("--apple\t\tSet the vendor, product ID and revision fields to simulate an \n");
172 printf("\t\tapple-suppled disk. Provides support for the Apple Drive Setup\n");
173 printf("\t\tutility.\n\n");
174 printf("--vendor={vendor}\tSets the reported device vendor. Up to 8 characters.\n\n");
175 printf("--prod-id={prod-id}\tSets the reported product ID. Up to 16 characters.\n\n");
176 printf("--rev={revision}\tSets the reported device revision. Up to 4 characters.\n\n");
178 printf("\nThe current configuration settings are displayed if no options are supplied");
183 int main(int argc
, char* argv
[])
185 printf("SCSI2SD Configuration Utility.\n");
186 printf("Copyright (C) 2013 Michael McMaster <michael@codesrc.com>\n\n");
188 uint16_t vendorId
= 0x04B4; // Cypress
189 uint16_t productId
= 0x1337; // SCSI2SD
192 "USB device parameters\n\tVendor ID:\t0x%04X\n\tProduct ID:\t0x%04X\n",
196 // Enumerate and print the HID devices on the system
197 struct hid_device_info
*dev
= hid_enumerate(vendorId
, productId
);
200 fprintf(stderr
, "ERROR: SCSI2SD USB device not found.\n");
204 printf("USB Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls",
205 dev
->vendor_id
, dev
->product_id
, dev
->path
, dev
->serial_number
);
207 printf(" Manufacturer: %ls\n", dev
->manufacturer_string
);
208 printf(" Product: %ls\n", dev
->product_string
);
211 // Open the device using the VID, PID,
212 // and optionally the Serial number.
213 hid_device
* handle
= hid_open(vendorId
, productId
, NULL
);
218 "ERROR: Could not open device %s. Check permissions.\n", dev
->path
224 if (readConfig(handle
, &packet
) <= 0)
226 fprintf(stderr
, "ERROR: Invalid data received from device.\n");
230 struct option options
[] =
233 "id", required_argument
, NULL
, PARAM_ID
236 "parity", no_argument
, NULL
, PARAM_PARITY
239 "no-parity", no_argument
, NULL
, PARAM_NOPARITY
242 "attention", no_argument
, NULL
, PARAM_UNITATT
245 "no-attention", no_argument
, NULL
, PARAM_NOUNITATT
248 "blocks", required_argument
, NULL
, PARAM_MAXBLOCKS
251 "apple", no_argument
, NULL
, PARAM_APPLE
254 "vendor", required_argument
, NULL
, PARAM_VENDOR
257 "prod-id", required_argument
, NULL
, PARAM_PRODID
260 "rev", required_argument
, NULL
, PARAM_REV
263 "sector", required_argument
, NULL
, PARAM_BYTESPERSECTOR
273 while ((c
= getopt_long(argc
, argv
, "", options
, &optIdx
)) != -1)
281 if (sscanf(optarg
, "%d", &id
) == 1 && id
>= 0 && id
<= 7)
293 packet
.enableParity
= 1;
297 packet
.enableParity
= 0;
301 packet
.enableUnitAttention
= 1;
304 case PARAM_NOUNITATT
:
305 packet
.enableUnitAttention
= 0;
308 case PARAM_MAXBLOCKS
:
310 int64_t maxSectors
= -1;
311 if (sscanf(optarg
, "%" PRId64
, &maxSectors
) == 1 &&
312 maxSectors
>= 0 && maxSectors
<= UINT32_MAX
)
314 packet
.maxSectors
= maxSectors
;
324 memcpy(packet
.vendor
, " SEAGATE", 8);
325 memcpy(packet
.prodId
, " ST225N", 16);
326 memcpy(packet
.revision
, "1.0 ", 4);
330 memset(packet
.vendor
, ' ', 8);
331 memcpy(packet
.vendor
, optarg
, MIN(strlen(optarg
), 8));
335 memset(packet
.prodId
, ' ', 16);
336 memcpy(packet
.prodId
, optarg
, MIN(strlen(optarg
), 16));
340 memset(packet
.revision
, ' ', 4);
341 memcpy(packet
.revision
, optarg
, MIN(strlen(optarg
), 4));
344 case PARAM_BYTESPERSECTOR
:
346 int64_t bytesPerSector
= -1;
347 if (sscanf(optarg
, "%" PRId64
, &bytesPerSector
) == 1 &&
348 bytesPerSector
>= 64 && bytesPerSector
<= 2048)
350 packet
.bytesPerSector
= bytesPerSector
;
365 printf("Saving configuration...");
366 if (writeConfig(handle
, &packet
) <= 0)
369 fprintf(stderr
, "ERROR: Failed to save config.\n");
374 // Clear outstanding stale data
375 readConfig(handle
, &packet
);
378 if (readConfig(handle
, &packet
) <= 0)
380 fprintf(stderr
, "ERROR: Invalid data received from device.\n");
385 printf("\nCurrent Device Settings:\n");
386 printConfig(&packet
);