User | Revision | Line number | New contents of line |
bediyap |
0:f6f434d9a03a
|
1
|
|
bediyap |
0:f6f434d9a03a
|
2
|
/*
|
bediyap |
0:f6f434d9a03a
|
3
|
Copyright (c) 2010 Peter Barrett
|
bediyap |
0:f6f434d9a03a
|
4
|
|
bediyap |
0:f6f434d9a03a
|
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
bediyap |
0:f6f434d9a03a
|
6
|
of this software and associated documentation files (the "Software"), to deal
|
bediyap |
0:f6f434d9a03a
|
7
|
in the Software without restriction, including without limitation the rights
|
bediyap |
0:f6f434d9a03a
|
8
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
bediyap |
0:f6f434d9a03a
|
9
|
copies of the Software, and to permit persons to whom the Software is
|
bediyap |
0:f6f434d9a03a
|
10
|
furnished to do so, subject to the following conditions:
|
bediyap |
0:f6f434d9a03a
|
11
|
|
bediyap |
0:f6f434d9a03a
|
12
|
The above copyright notice and this permission notice shall be included in
|
bediyap |
0:f6f434d9a03a
|
13
|
all copies or substantial portions of the Software.
|
bediyap |
0:f6f434d9a03a
|
14
|
|
bediyap |
0:f6f434d9a03a
|
15
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
bediyap |
0:f6f434d9a03a
|
16
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
bediyap |
0:f6f434d9a03a
|
17
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
bediyap |
0:f6f434d9a03a
|
18
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
bediyap |
0:f6f434d9a03a
|
19
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
bediyap |
0:f6f434d9a03a
|
20
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
bediyap |
0:f6f434d9a03a
|
21
|
THE SOFTWARE.
|
bediyap |
0:f6f434d9a03a
|
22
|
*/
|
bediyap |
0:f6f434d9a03a
|
23
|
|
bediyap |
0:f6f434d9a03a
|
24
|
#include "stdlib.h"
|
bediyap |
0:f6f434d9a03a
|
25
|
#include "stdio.h"
|
bediyap |
0:f6f434d9a03a
|
26
|
#include "string.h"
|
bediyap |
0:f6f434d9a03a
|
27
|
|
bediyap |
0:f6f434d9a03a
|
28
|
#include "Utils.h"
|
bediyap |
0:f6f434d9a03a
|
29
|
#include "USBHost.h"
|
bediyap |
0:f6f434d9a03a
|
30
|
|
bediyap |
0:f6f434d9a03a
|
31
|
|
bediyap |
0:f6f434d9a03a
|
32
|
int MassStorage_ReadCapacity(int device, u32* blockCount, u32* blockSize);
|
bediyap |
0:f6f434d9a03a
|
33
|
int MassStorage_ReadBlock(int device, u32 block, u8* dst);
|
bediyap |
0:f6f434d9a03a
|
34
|
int MassStorage_WriteBlock(int device, u32 block, const u8* dst);
|
bediyap |
0:f6f434d9a03a
|
35
|
|
bediyap |
0:f6f434d9a03a
|
36
|
|
bediyap |
0:f6f434d9a03a
|
37
|
#define ERR_BAD_CSW_SIGNATURE -200
|
bediyap |
0:f6f434d9a03a
|
38
|
|
bediyap |
0:f6f434d9a03a
|
39
|
#define CBW_SIGNATURE 0x43425355
|
bediyap |
0:f6f434d9a03a
|
40
|
#define CSW_SIGNATURE 0x53425355
|
bediyap |
0:f6f434d9a03a
|
41
|
|
bediyap |
0:f6f434d9a03a
|
42
|
// Command Block
|
bediyap |
0:f6f434d9a03a
|
43
|
typedef struct
|
bediyap |
0:f6f434d9a03a
|
44
|
{
|
bediyap |
0:f6f434d9a03a
|
45
|
u32 Signature;
|
bediyap |
0:f6f434d9a03a
|
46
|
u32 Tag;
|
bediyap |
0:f6f434d9a03a
|
47
|
u32 TransferLength;
|
bediyap |
0:f6f434d9a03a
|
48
|
u8 Flags;
|
bediyap |
0:f6f434d9a03a
|
49
|
u8 LUN;
|
bediyap |
0:f6f434d9a03a
|
50
|
u8 CBLength;
|
bediyap |
0:f6f434d9a03a
|
51
|
u8 CB[16]; // only 6 really
|
bediyap |
0:f6f434d9a03a
|
52
|
} CBW;
|
bediyap |
0:f6f434d9a03a
|
53
|
|
bediyap |
0:f6f434d9a03a
|
54
|
// Status block
|
bediyap |
0:f6f434d9a03a
|
55
|
typedef struct
|
bediyap |
0:f6f434d9a03a
|
56
|
{
|
bediyap |
0:f6f434d9a03a
|
57
|
u32 Signature;
|
bediyap |
0:f6f434d9a03a
|
58
|
u32 Tag;
|
bediyap |
0:f6f434d9a03a
|
59
|
u32 DataResidue;
|
bediyap |
0:f6f434d9a03a
|
60
|
u8 Status;
|
bediyap |
0:f6f434d9a03a
|
61
|
} CSW;
|
bediyap |
0:f6f434d9a03a
|
62
|
|
bediyap |
0:f6f434d9a03a
|
63
|
int SCSIRequestSense(int device);
|
bediyap |
0:f6f434d9a03a
|
64
|
|
bediyap |
0:f6f434d9a03a
|
65
|
int DoSCSI(int device, const u8* cmd, int cmdLen, int flags, u8* data, u32 transferLen)
|
bediyap |
0:f6f434d9a03a
|
66
|
{
|
bediyap |
0:f6f434d9a03a
|
67
|
CBW cbw;
|
bediyap |
0:f6f434d9a03a
|
68
|
cbw.Signature = CBW_SIGNATURE;
|
bediyap |
0:f6f434d9a03a
|
69
|
cbw.Tag = 0;
|
bediyap |
0:f6f434d9a03a
|
70
|
cbw.TransferLength = transferLen;
|
bediyap |
0:f6f434d9a03a
|
71
|
cbw.Flags = flags;
|
bediyap |
0:f6f434d9a03a
|
72
|
cbw.LUN = 0;
|
bediyap |
0:f6f434d9a03a
|
73
|
cbw.CBLength = cmdLen;
|
bediyap |
0:f6f434d9a03a
|
74
|
memset(cbw.CB,0,sizeof(cbw.CB));
|
bediyap |
0:f6f434d9a03a
|
75
|
memcpy(cbw.CB,cmd,cmdLen);
|
bediyap |
0:f6f434d9a03a
|
76
|
|
bediyap |
0:f6f434d9a03a
|
77
|
int r;
|
bediyap |
0:f6f434d9a03a
|
78
|
r = USBBulkTransfer(device,0x01,(u8*)&cbw,31); // Send the command
|
bediyap |
0:f6f434d9a03a
|
79
|
if (r < 0)
|
bediyap |
0:f6f434d9a03a
|
80
|
return r;
|
bediyap |
0:f6f434d9a03a
|
81
|
|
bediyap |
0:f6f434d9a03a
|
82
|
if (data)
|
bediyap |
0:f6f434d9a03a
|
83
|
{
|
bediyap |
0:f6f434d9a03a
|
84
|
r = USBBulkTransfer(device,flags | 1,data,transferLen);
|
bediyap |
0:f6f434d9a03a
|
85
|
if (r < 0)
|
bediyap |
0:f6f434d9a03a
|
86
|
return r;
|
bediyap |
0:f6f434d9a03a
|
87
|
}
|
bediyap |
0:f6f434d9a03a
|
88
|
|
bediyap |
0:f6f434d9a03a
|
89
|
CSW csw;
|
bediyap |
0:f6f434d9a03a
|
90
|
csw.Signature = 0;
|
bediyap |
0:f6f434d9a03a
|
91
|
r = USBBulkTransfer(device,0x81,(u8*)&csw,13);
|
bediyap |
0:f6f434d9a03a
|
92
|
if (r < 0)
|
bediyap |
0:f6f434d9a03a
|
93
|
return r;
|
bediyap |
0:f6f434d9a03a
|
94
|
|
bediyap |
0:f6f434d9a03a
|
95
|
if (csw.Signature != CSW_SIGNATURE)
|
bediyap |
0:f6f434d9a03a
|
96
|
return ERR_BAD_CSW_SIGNATURE;
|
bediyap |
0:f6f434d9a03a
|
97
|
|
bediyap |
0:f6f434d9a03a
|
98
|
// ModeSense?
|
bediyap |
0:f6f434d9a03a
|
99
|
if (csw.Status == 1 && cmd[0] != 3)
|
bediyap |
0:f6f434d9a03a
|
100
|
return SCSIRequestSense(device);
|
bediyap |
0:f6f434d9a03a
|
101
|
|
bediyap |
0:f6f434d9a03a
|
102
|
return csw.Status;
|
bediyap |
0:f6f434d9a03a
|
103
|
}
|
bediyap |
0:f6f434d9a03a
|
104
|
|
bediyap |
0:f6f434d9a03a
|
105
|
int SCSITestUnitReady(int device)
|
bediyap |
0:f6f434d9a03a
|
106
|
{
|
bediyap |
0:f6f434d9a03a
|
107
|
u8 cmd[6];
|
bediyap |
0:f6f434d9a03a
|
108
|
memset(cmd,0,6);
|
bediyap |
0:f6f434d9a03a
|
109
|
return DoSCSI(device,cmd,6,DEVICE_TO_HOST,0,0);
|
bediyap |
0:f6f434d9a03a
|
110
|
}
|
bediyap |
0:f6f434d9a03a
|
111
|
|
bediyap |
0:f6f434d9a03a
|
112
|
int SCSIRequestSense(int device)
|
bediyap |
0:f6f434d9a03a
|
113
|
{
|
bediyap |
0:f6f434d9a03a
|
114
|
u8 cmd[6] = {0x03,0,0,0,18,0};
|
bediyap |
0:f6f434d9a03a
|
115
|
u8 result[18];
|
bediyap |
0:f6f434d9a03a
|
116
|
int r = DoSCSI(device,cmd,6,DEVICE_TO_HOST,result,18);
|
bediyap |
0:f6f434d9a03a
|
117
|
return r;
|
bediyap |
0:f6f434d9a03a
|
118
|
}
|
bediyap |
0:f6f434d9a03a
|
119
|
|
bediyap |
0:f6f434d9a03a
|
120
|
int SCSIInquiry(int device)
|
bediyap |
0:f6f434d9a03a
|
121
|
{
|
bediyap |
0:f6f434d9a03a
|
122
|
u8 cmd[6] = {0x12,0,0,0,36,0};
|
bediyap |
0:f6f434d9a03a
|
123
|
u8 result[36+2];
|
bediyap |
0:f6f434d9a03a
|
124
|
result[36] = '\n';
|
bediyap |
0:f6f434d9a03a
|
125
|
result[37] = 0;
|
bediyap |
0:f6f434d9a03a
|
126
|
int r = DoSCSI(device,cmd,6,DEVICE_TO_HOST,result,36);
|
bediyap |
0:f6f434d9a03a
|
127
|
if (r == 0)
|
bediyap |
0:f6f434d9a03a
|
128
|
printf((const char*)result + 8);
|
bediyap |
0:f6f434d9a03a
|
129
|
return r;
|
bediyap |
0:f6f434d9a03a
|
130
|
}
|
bediyap |
0:f6f434d9a03a
|
131
|
|
bediyap |
0:f6f434d9a03a
|
132
|
int SCSIReadCapacity(int device, u32* blockCount, u32* blockSize)
|
bediyap |
0:f6f434d9a03a
|
133
|
{
|
bediyap |
0:f6f434d9a03a
|
134
|
u8 cmd[10] = {0x25,0,0,0,8,0,0,0,0,0};
|
bediyap |
0:f6f434d9a03a
|
135
|
u8 result[8];
|
bediyap |
0:f6f434d9a03a
|
136
|
*blockSize = 0;
|
bediyap |
0:f6f434d9a03a
|
137
|
*blockCount = 0;
|
bediyap |
0:f6f434d9a03a
|
138
|
int r = DoSCSI(device,cmd,10,DEVICE_TO_HOST,result,8);
|
bediyap |
0:f6f434d9a03a
|
139
|
if (r == 0)
|
bediyap |
0:f6f434d9a03a
|
140
|
{
|
bediyap |
0:f6f434d9a03a
|
141
|
*blockCount = BE32(result);
|
bediyap |
0:f6f434d9a03a
|
142
|
*blockSize = BE32(result+4);
|
bediyap |
0:f6f434d9a03a
|
143
|
}
|
bediyap |
0:f6f434d9a03a
|
144
|
return r;
|
bediyap |
0:f6f434d9a03a
|
145
|
}
|
bediyap |
0:f6f434d9a03a
|
146
|
|
bediyap |
0:f6f434d9a03a
|
147
|
int SCSITransfer(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize, int direction)
|
bediyap |
0:f6f434d9a03a
|
148
|
{
|
bediyap |
0:f6f434d9a03a
|
149
|
// USB hardware will only do 4k per transfer
|
bediyap |
0:f6f434d9a03a
|
150
|
while (blockCount*blockSize > 4096)
|
bediyap |
0:f6f434d9a03a
|
151
|
{
|
bediyap |
0:f6f434d9a03a
|
152
|
int count = 4096/blockSize;
|
bediyap |
0:f6f434d9a03a
|
153
|
int r = SCSITransfer(device,blockAddr,count,dst,blockSize,direction);
|
bediyap |
0:f6f434d9a03a
|
154
|
dst += count*blockSize;
|
bediyap |
0:f6f434d9a03a
|
155
|
blockAddr += count;
|
bediyap |
0:f6f434d9a03a
|
156
|
blockCount -= count;
|
bediyap |
0:f6f434d9a03a
|
157
|
}
|
bediyap |
0:f6f434d9a03a
|
158
|
|
bediyap |
0:f6f434d9a03a
|
159
|
u8 cmd[10];
|
bediyap |
0:f6f434d9a03a
|
160
|
memset(cmd,0,10);
|
bediyap |
0:f6f434d9a03a
|
161
|
cmd[0] = (direction == DEVICE_TO_HOST) ? 0x28 : 0x2A;
|
bediyap |
0:f6f434d9a03a
|
162
|
BE32(blockAddr,cmd+2);
|
bediyap |
0:f6f434d9a03a
|
163
|
BE16(blockCount,cmd+7);
|
bediyap |
0:f6f434d9a03a
|
164
|
return DoSCSI(device,cmd,10,direction,dst,blockSize*blockCount);
|
bediyap |
0:f6f434d9a03a
|
165
|
}
|
bediyap |
0:f6f434d9a03a
|
166
|
|
bediyap |
0:f6f434d9a03a
|
167
|
int MassStorage_ReadCapacity(int device, u32* blockCount, u32* blockSize)
|
bediyap |
0:f6f434d9a03a
|
168
|
{
|
bediyap |
0:f6f434d9a03a
|
169
|
return SCSIReadCapacity(device,blockCount,blockSize);
|
bediyap |
0:f6f434d9a03a
|
170
|
}
|
bediyap |
0:f6f434d9a03a
|
171
|
|
bediyap |
0:f6f434d9a03a
|
172
|
int MassStorage_Read(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize = 512)
|
bediyap |
0:f6f434d9a03a
|
173
|
{
|
bediyap |
0:f6f434d9a03a
|
174
|
return SCSITransfer(device,blockAddr,blockCount,dst,blockSize,DEVICE_TO_HOST);
|
bediyap |
0:f6f434d9a03a
|
175
|
}
|
bediyap |
0:f6f434d9a03a
|
176
|
|
bediyap |
0:f6f434d9a03a
|
177
|
int MassStorage_Write(int device, u32 blockAddr, u32 blockCount, u8* dst, u32 blockSize = 512)
|
bediyap |
0:f6f434d9a03a
|
178
|
{
|
bediyap |
0:f6f434d9a03a
|
179
|
return SCSITransfer(device,blockAddr,blockCount,dst,blockSize,HOST_TO_DEVICE);
|
bediyap |
0:f6f434d9a03a
|
180
|
}
|