20#include "UsbMassStorageDevice.h"
21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/Log.h"
23#include "pedigree/kernel/utilities/PointerGuard.h"
24#include "pedigree/kernel/utilities/Vector.h"
26#include "modules/system/usb/Usb.h"
27#include "modules/system/usb/UsbDevice.h"
29UsbMassStorageDevice::UsbMassStorageDevice(
UsbDevice* dev)
36 m_ResetRecoveryRequired(false),
37 m_DeviceAvailable(true) {
38 setSpecificType(
String(
"usb-msd-controller"));
41UsbMassStorageDevice::~UsbMassStorageDevice() {
42 if (m_DeviceAvailable) {
51 if (!m_DeviceAvailable) {
54 m_DeviceAvailable =
false;
63 for (
size_t i = 0; i <
m_pInterface->endpointList.count(); i++) {
65 if (!m_pInEndpoint && (pEndpoint->nTransferType == Endpoint::Bulk) && pEndpoint->bIn)
66 m_pInEndpoint = pEndpoint;
67 if (!m_pOutEndpoint && (pEndpoint->nTransferType == Endpoint::Bulk) && pEndpoint->bOut)
68 m_pOutEndpoint = pEndpoint;
69 if (m_pInEndpoint && m_pOutEndpoint)
74 ERROR(
"USB: MSD: No IN endpoint");
78 if (!m_pOutEndpoint) {
79 ERROR(
"USB: MSD: No OUT endpoint");
83 if (!massStorageReset())
87 static_cast<uint8_t
>(UsbRequestDirection::In) |
static_cast<uint8_t
>(MassStorageRequest),
88 MassStorageGetMaxLUN, 0,
m_pInterface->nInterface, 1,
reinterpret_cast<uintptr_t
>(&maxLun));
91 else if (result != 1 || maxLun > 15) {
92 WARNING(
"USB: MSD: invalid GET_MAX_LUN response");
95 m_nUnits = maxLun + 1;
102bool UsbMassStorageDevice::massStorageReset() {
106bool UsbMassStorageDevice::performResetRecovery() {
107 m_ResetRecoveryRequired =
true;
111 const bool reset = massStorageReset();
114 if (reset && clearedIn && clearedOut)
115 m_ResetRecoveryRequired =
false;
116 return !m_ResetRecoveryRequired;
119UsbMassStorageDevice::BotStatus UsbMassStorageDevice::readStatus(uint32_t tag,
120 uint32_t expectedBytes) {
123 ByteSet(pCsw, 0,
sizeof(Csw));
125 ssize_t result = syncIn(m_pInEndpoint,
reinterpret_cast<uintptr_t
>(pCsw),
sizeof(Csw));
126 if (result == -Stall) {
128 return BotStatus::RecoveryRequired;
129 ByteSet(pCsw, 0,
sizeof(Csw));
130 result = syncIn(m_pInEndpoint,
reinterpret_cast<uintptr_t
>(pCsw),
sizeof(Csw));
133 if (result !=
static_cast<ssize_t
>(
sizeof(Csw)) || pCsw->nSig != CswSig ||
134 pCsw->nTag != HOST_TO_LITTLE32(tag))
135 return BotStatus::RecoveryRequired;
137 const uint32_t residue = LITTLE_TO_HOST32(pCsw->nResidue);
138 if (residue > expectedBytes)
139 return BotStatus::RecoveryRequired;
141 if (pCsw->nStatus == 0)
142 return residue ? BotStatus::Failed : BotStatus::Passed;
143 if (pCsw->nStatus == 1)
144 return BotStatus::Failed;
145 return BotStatus::RecoveryRequired;
148bool UsbMassStorageDevice::sendCommand(
size_t nUnit, uintptr_t pCommand, uint8_t nCommandSize,
149 uintptr_t pRespBuffer, uint16_t nRespBytes,
bool bWrite) {
150 if (!pCommand || !nCommandSize || nCommandSize > 16 || nUnit >= m_nUnits || nUnit > 0xf ||
151 (nRespBytes && !pRespBuffer) || !
m_pInterface || !m_pInEndpoint || !m_pOutEndpoint)
154 if (!m_DeviceAvailable) {
157 if (m_ResetRecoveryRequired && !performResetRecovery())
162 ByteSet(pCbw, 0,
sizeof(Cbw));
163 const uint32_t tag = m_NextTag++;
165 pCbw->nTag = HOST_TO_LITTLE32(tag);
166 pCbw->nDataBytes = HOST_TO_LITTLE32(nRespBytes);
167 pCbw->nFlags = !bWrite && nRespBytes ? 0x80 : 0;
169 pCbw->nCommandSize = nCommandSize;
170 MemoryCopy(pCbw->pCommand,
reinterpret_cast<void*
>(pCommand), nCommandSize);
172 auto recover = [
this]() {
173 if (!performResetRecovery())
174 WARNING(
"USB: MSD: reset recovery incomplete; new commands remain blocked");
177 if (syncOut(m_pOutEndpoint,
reinterpret_cast<uintptr_t
>(pCbw),
sizeof(Cbw)) !=
sizeof(Cbw))
180 ssize_t transferred = 0;
182 transferred = bWrite ? syncOut(m_pOutEndpoint, pRespBuffer, nRespBytes)
183 : syncIn(m_pInEndpoint, pRespBuffer, nRespBytes);
184 if (transferred == -Stall) {
187 }
else if (transferred < 0 || transferred > nRespBytes || (bWrite && transferred != nRespBytes))
190 const BotStatus status = readStatus(tag, nRespBytes);
191 if (status == BotStatus::RecoveryRequired)
196 return status == BotStatus::Passed && (bWrite || transferred == nRespBytes);
void shutdownDiskCaches(bool deviceAvailable=true)
bool clearEndpointHalt(Endpoint *pEndpoint)
Clears a halt on the given endpoint.
Interface * m_pInterface
Interface in use.
bool controlRequest(uint8_t nRequestType, uint8_t nRequest, uint16_t nValue, uint16_t nIndex, uint16_t nLength=0, uintptr_t pBuffer=0, uint32_t timeout=5000)
Performs an USB control request.
UsbState m_UsbState
The current state of the device.
ssize_t controlRequestResult(uint8_t nRequestType, uint8_t nRequest, uint16_t nValue, uint16_t nIndex, uint16_t nLength=0, uintptr_t pBuffer=0, uint32_t timeout=5000)
Returns data bytes transferred, or a negative UsbError.
virtual void initialiseDriver()
Implemented by the driver class, initialises driver-specific stuff.
void prepareForDisconnection() override