11#include <whb/sdcard.h>
12#include <mocha/mocha.h>
13#include <mocha/disc_interface.h>
18#include "WutFileSystemDriver.h"
23static const char *
const SD_FALLBACK_PREFIX =
"/vol/external01/";
26static const int SD_MOUNT_ATTEMPTS = 3;
27static const useconds_t SD_MOUNT_RETRY_DELAY_US = 100000;
31static void NormalizeSdPrefix(
char prefix[32])
33 const char * sdPath = WHBGetSdCardMountPath();
35 if(sdPath && sdPath[0])
37 strncpy(prefix, sdPath, 32 - 2);
38 prefix[32 - 2] =
'\0';
40 size_t len = strlen(prefix);
41 if(len == 0 || prefix[len - 1] !=
'/')
44 prefix[len + 1] =
'\0';
49 strncpy(prefix, SD_FALLBACK_PREFIX, 32 - 1);
50 prefix[32 - 1] =
'\0';
56 memset(devices, 0,
sizeof(devices));
62 mochaReady = (Mocha_InitLibrary() == MOCHA_RESULT_SUCCESS);
68 storageSlots[0] = { &Mocha_usb1_disc_interface,
"usb1", 0, 0 };
69 storageSlots[1] = { &Mocha_usb2_disc_interface,
"usb2", 0, 0 };
70 storageSlots[2] = { &Mocha_usb3_disc_interface,
"usb3", 0, 0 };
74 memset(&sd, 0,
sizeof(sd));
76 strcpy(sd.
name,
"SD Card");
78 bool sdMounted =
false;
79 for(
int attempt = 0; attempt < SD_MOUNT_ATTEMPTS && !sdMounted; attempt++)
82 usleep(SD_MOUNT_RETRY_DELAY_US);
83 sdMounted = WHBMountSdCard();
93 memset(&usb1, 0,
sizeof(usb1));
95 strcpy(usb1.
name,
"USB Storage 1");
99 memset(&usb2, 0,
sizeof(usb2));
100 usb2.
id = DEVICE_USB2;
101 strcpy(usb2.
name,
"USB Storage 2");
105 memset(&usb3, 0,
sizeof(usb3));
106 usb3.
id = DEVICE_USB3;
107 strcpy(usb3.
name,
"USB Storage 3");
113 memset(&smb, 0,
sizeof(smb));
115 strcpy(smb.
name,
"Network Share");
118 deviceCount = slotCount;
123 smbDriver.shutdown();
130 for(
int i = 0; i < storageSlotCount; i++)
131 unmountStorageSlot(i);
133 for(
int i = 0; i < storageSlotCount; i++)
134 if(storageSlots[i].iface)
135 storageSlots[i].iface->shutdown();
139 Mocha_DeInitLibrary();
143 memset(devices, 0,
sizeof(devices));
147int WutFileSystemDriver::findDeviceIndex(
int deviceId)
const
149 for(
int i = 0; i < deviceCount; i++)
150 if(devices[i].
id == deviceId)
155void WutFileSystemDriver::getVolumeLabel(
WutDeviceState & dev,
const char * dvmName)
166 snprintf(path,
sizeof(path),
"%s:", dvmName);
173bool WutFileSystemDriver::tryMountStorageSlot(
int slotIdx)
175 if(slotIdx < 0 || slotIdx >= storageSlotCount)
178 WutDeviceState & dev = devices[slotUSB1 + slotIdx];
179 WutStorageSlot & slot = storageSlots[slotIdx];
185 unmountStorageSlot(slotIdx);
198 if(dvmWutMountVolume(slot.
mountName, (DISC_INTERFACE *) slot.
iface, cachePages, sectorsPerPage))
210 slot.
iface->shutdown();
223void WutFileSystemDriver::unmountStorageSlot(
int slotIdx)
225 if(slotIdx < 0 || slotIdx >= storageSlotCount)
228 WutDeviceState & dev = devices[slotUSB1 + slotIdx];
229 WutStorageSlot & slot = storageSlots[slotIdx];
244bool WutFileSystemDriver::slotStillPresent(
int slotIdx)
246 if(slotIdx < 0 || slotIdx >= storageSlotCount || !mochaReady)
249 WutDeviceState & dev = devices[slotUSB1 + slotIdx];
254 return dvmWutVolumeStillPresent(storageSlots[slotIdx].mountName);
257void WutFileSystemDriver::refreshSmbSlot()
259 WutDeviceState & smb = devices[slotSMB];
260 bool connected = smbDriver.isConnected();
266 strncpy(smb.
prefix, smbDriver.getMountPath(),
sizeof(smb.
prefix) - 1);
281 for(
int i = 0; i < deviceCount && count < MAX_STORAGE_DEVICES; i++)
283 if(!devices[i].isPresent)
287 out.
id = devices[i].id;
288 strncpy(out.
name, devices[i].name,
sizeof(out.
name) - 1);
289 out.
name[
sizeof(out.
name) - 1] =
'\0';
292 const char * browsePrefix = (devices[i].id == DEVICE_SMB) ? devices[i].stablePrefix : devices[i].prefix;
293 strncpy(out.
prefix, browsePrefix,
sizeof(out.
prefix) - 1);
296 bool fixedDevice = (devices[i].id == DEVICE_SD || devices[i].id == DEVICE_SMB);
307 if(deviceId == DEVICE_SMB)
308 return smbDriver.isConnected();
310 int idx = findDeviceIndex(deviceId);
311 return idx >= 0 && devices[idx].isPresent;
316 int idx = findDeviceIndex(deviceId);
320 if(deviceId == DEVICE_SMB)
327 if(deviceId == DEVICE_SD)
328 return MountResult::Success;
337 return "Unable to mount device.";
339 if(deviceId == DEVICE_SD)
340 return "SD card not found!";
341 else if(deviceId == DEVICE_USB || deviceId == DEVICE_USB2 || deviceId == DEVICE_USB3)
342 return "USB drive not found!";
343 else if(deviceId == DEVICE_SMB)
344 return "Network share not connected!";
346 return "Storage device not found!";
351 if(deviceId == DEVICE_SMB)
353 smbDriver.disconnect();
358 if(deviceId == DEVICE_SD)
361 int idx = findDeviceIndex(deviceId);
365 devices[idx].isMounted =
false;
366 devices[idx].unmountRequired =
true;
367 devices[idx].labelFetched =
false;
373 deviceListChanged =
false;
382 ScanUsbHardwareSignature(currentHwSig);
384 if(UsbHardwareSignatureChanged(currentHwSig, usbHwSignature))
391 for(
int i = 0; i < storageSlotCount; i++)
392 storageSlots[i].backoffPollsLeft = 0;
395 usbHwSignature = currentHwSig;
397 for(
int slotIdx = 0; slotIdx < storageSlotCount; slotIdx++)
403 if(!slotStillPresent(slotIdx))
405 unmountStorageSlot(slotIdx);
407 if(outRemovedCount < MAX_STORAGE_DEVICES)
408 removedIds[outRemovedCount++] = dev.
id;
409 deviceListChanged =
true;
412 else if(tryMountStorageSlot(slotIdx))
414 deviceListChanged =
true;
421 int idx = findDeviceIndex(device);
422 return idx < 0 ?
"" : devices[idx].stablePrefix;
427 if(device == DEVICE_SMB)
430 int idx = findDeviceIndex(device);
431 if(idx < 0 || !devices[idx].isMounted || devices[idx].prefix[0] ==
'\0')
433 return devices[idx].prefix;
438 static const int devices[] = { DEVICE_AUTO, DEVICE_SD, DEVICE_USB, DEVICE_USB2, DEVICE_USB3, DEVICE_SMB };
439 outCount =
sizeof(devices) /
sizeof(devices[0]);
445 static const int devices[] = { DEVICE_AUTO, DEVICE_SD, DEVICE_USB, DEVICE_USB2, DEVICE_USB3, DEVICE_SMB };
446 outCount =
sizeof(devices) /
sizeof(devices[0]);
SD: a plain WHBMountSdCard() FSA mount, done once in init().
const char * getDevicePrefix(int device) const override
The devoptab prefix this device would use (eg.
const char * getMountPath(int device) const override
devoptab-style mount path for device (eg.
void shutdown() override
Unmounts every device and releases the driver's resources.
void pollStorageDevices(int removedIds[MAX_STORAGE_DEVICES], int &outRemovedCount, bool &deviceListChanged) override
Called once per device-checking thread cycle.
int enumerateStorageDevices(StorageDevice outDevices[MAX_STORAGE_DEVICES]) override
Fills outDevices (size MAX_STORAGE_DEVICES) and returns the device count.
void init() override
Initializes the driver and auto-mounts devices flagged autoMountAtStartup.
const int * getValidSaveDevices(int &outCount) const override
Devices (Device enum values, in priority order) that are offered when choosing where to save to on th...
const char * mountResultMessage(int deviceId, MountResult result) override
A short, user-displayable reason for a non-Success MountResult (eg.
bool isDevicePresent(int deviceId) const override
Lightweight, cached hardware-presence check for a single device - does NOT mount and does no invasive...
MountResult mountStorageDevice(int deviceId) override
Attempts to mount deviceId exactly once.
void invalidateStorageDevice(int deviceId) override
Marks deviceId as needing a fresh mount next time mountStorageDevice() is called, eg.
const int * getValidLoadDevices(int &outCount) const override
Devices (Device enum values, in priority order) that are offered when choosing where to load from on ...
MountResult
Result of a single mount attempt.
@ MountFailed
present, but couldn't be mounted (eg.
@ DeviceNotFound
not physically present / not inserted
Description of one storage device: id, display name, mount prefix, volume label and flags such as rem...
bool autoMountAtStartup
silently attempted at boot
bool removable
can this device disappear at runtime?
int id
Device enum value (DEVICE_SD, DEVICE_USB, ...)
bool alwaysListed
show in a device listing unconditionally, regardless of isDevicePresent()
char volumeLabel[16]
Volume label of the mounted filesystem, or empty if unknown.
char prefix[32]
devoptab mount prefix, eg.
char name[20]
Short display name for device lists.
The set of USBCLASS_STORAGE interfaces nsysuhs currently reports across every controller_num probed.
State tracker for a single storage device slot.
int id
Device enum value (DEVICE_SD, DEVICE_USB, ...)
char name[16]
human-readable base name, eg.
bool isMounted
A filesystem is currently mounted on this slot.
char volumeLabel[16]
volume label, best-effort - empty if none could be read
bool labelFetched
volume label already looked up since the last mount/removal - see getVolumeLabel()
char stablePrefix[32]
same string as prefix, but set once in init() and never cleared on unmount - this device's identity f...
bool unmountRequired
The slot was removed or invalidated and must be unmounted before the next mount attempt.
char prefix[32]
devoptab mount prefix, eg.
bool isPresent
found on the last poll
int failCount
consecutive mount failures since the last success or hardware change - see tryMountStorageSlot()
int backoffPollsLeft
polls left to skip before the next probe attempt (0 = probe now)
const DISC_INTERFACE * iface
&Mocha_usb1_disc_interface .
const char * mountName
devoptab basename, eg.