forked from ARMmbed/mbed-os
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathUSBMSD.h
315 lines (270 loc) · 8.03 KB
/
USBMSD.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
/*
* Copyright (c) 2018-2019, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef USBMSD_H
#define USBMSD_H
/* These headers are included for child class. */
#include "USBDescriptor.h"
#include "USBDevice_Types.h"
#include "platform/Callback.h"
#include "drivers/internal/PolledQueue.h"
#include "drivers/internal/Task.h"
#include "BlockDevice.h"
#include "Mutex.h"
#include "USBDevice.h"
/**
* \defgroup drivers_USBMSD USBMSD class
* \ingroup drivers-public-api-usb
* @{
*/
/**
* USBMSD class: generic class in order to use all kinds of blocks storage chip
*
* Introduction
*
* USBMSD implements the MSD protocol. It permits to access a block device (flash, SD Card,...)
* from a computer over USB.
*
* @code
* #include "mbed.h"
* #include "SDBlockDevice.h"
* #include "USBMSD.h"
*
* SDBlockDevice sd(PTE3, PTE1, PTE2, PTE4);
* USBMSD usb(&sd);
*
* int main() {
*
* while(true) {
* usb.process();
* }
*
* return 0;
* }
* @endcode
*/
class USBMSD: public USBDevice {
public:
/**
* Constructor
*
* This creates a new USBMSD object with the given block device. Connect must be called
* for the block device to connect.
*
* @param bd BlockDevice to mount as a USB drive
* @param connect_blocking true to perform a blocking connect, false to start in a disconnected state
* @param vendor_id Your vendor_id
* @param product_id Your product_id
* @param product_release Your preoduct_release
*/
USBMSD(BlockDevice *bd, bool connect_blocking = true, uint16_t vendor_id = 0x0703, uint16_t product_id = 0x0104, uint16_t product_release = 0x0001);
/**
* Fully featured constructor
*
* Construct this object with the supplied USBPhy and parameters. The user
* this object is responsible for calling connect() or init().
*
* @note Derived classes must use this constructor and call init() or
* connect() themselves. Derived classes should also call deinit() in
* their destructor. This ensures that no interrupts can occur when the
* object is partially constructed or destroyed.
*
* @param phy USB phy to use
* @param bd BlockDevice to mount as a USB drive
* @param vendor_id Your vendor_id
* @param product_id Your product_id
* @param product_release Your preoduct_release
*/
USBMSD(USBPhy *phy, BlockDevice *bd, uint16_t vendor_id, uint16_t product_id, uint16_t product_release);
/**
* Destroy this object
*
* Any classes which inherit from this class must call disconnect
* before this destructor runs.
*/
virtual ~USBMSD();
/**
* Connect the USB MSD device.
*
* @returns true if successful
*/
bool connect();
/**
* Disconnect the USB MSD device.
*/
void disconnect();
/**
* Perform USB processing
*/
void process();
/**
* Called when USBMSD needs to perform processing
*
* @param cb Callback called when USBMSD needs process() to be called
*/
void attach(mbed::Callback<void()> cb);
/**
* Check if MSD device was removed/unmounted on the host side.
*
* @returns true if device was removed/unmounted on the host side
*/
bool media_removed();
protected:
/*
* read one or more blocks on a storage chip
*
* @param data pointer where will be stored read data
* @param block starting block number
* @param count number of blocks to read
* @returns 0 if successful
*/
virtual int disk_read(uint8_t *data, uint64_t block, uint8_t count);
/*
* write one or more blocks on a storage chip
*
* @param data data to write
* @param block starting block number
* @param count number of blocks to write
* @returns 0 if successful
*/
virtual int disk_write(const uint8_t *data, uint64_t block, uint8_t count);
/*
* Disk initilization
*/
virtual int disk_initialize();
/*
* Return the number of blocks
*
* @returns number of blocks
*/
virtual uint64_t disk_sectors();
/*
* Return memory size
*
* @returns memory size
*/
virtual uint64_t disk_size();
/*
* To check the status of the storage chip
*
* @returns status: 0: OK, 1: disk not initialized, 2: no medium in the drive, 4: write protected
*/
virtual int disk_status();
private:
// MSC Bulk-only Stage
enum Stage {
READ_CBW, // wait a CBW
ERROR, // error
PROCESS_CBW, // process a CBW request
SEND_CSW, // send a CSW
};
// Bulk-only CBW
typedef MBED_PACKED(struct)
{
uint32_t Signature;
uint32_t Tag;
uint32_t DataLength;
uint8_t Flags;
uint8_t LUN;
uint8_t CBLength;
uint8_t CB[16];
} CBW;
// Bulk-only CSW
typedef MBED_PACKED(struct)
{
uint32_t Signature;
uint32_t Tag;
uint32_t DataResidue;
uint8_t Status;
} CSW;
// If this class has been initialized
bool _initialized;
// If msd device has been unmounted by host
volatile bool _media_removed;
//state of the bulk-only state machine
Stage _stage;
// current CBW
CBW _cbw;
// CSW which will be sent
CSW _csw;
// addr where will be read or written data
uint32_t _addr;
// length of a reading or writing
uint32_t _length;
// memory OK (after a memoryVerify)
bool _mem_ok;
// cache in RAM before writing in memory. Useful also to read a block.
uint8_t *_page;
int _block_size;
uint64_t _memory_size;
uint64_t _block_count;
// endpoints
usb_ep_t _bulk_in;
usb_ep_t _bulk_out;
uint8_t _bulk_in_buf[64];
uint8_t _bulk_out_buf[64];
bool _out_ready;
bool _in_ready;
uint32_t _bulk_out_size;
// Interrupt to thread deferral
events::PolledQueue _queue;
events::Task<void()> _in_task;
events::Task<void()> _out_task;
events::Task<void()> _reset_task;
events::Task<void(const setup_packet_t *)> _control_task;
events::Task<void()> _configure_task;
BlockDevice *_bd;
rtos::Mutex _mutex_init;
rtos::Mutex _mutex;
// space for config descriptor
uint8_t _configuration_descriptor[32];
virtual const uint8_t *string_iproduct_desc();
virtual const uint8_t *string_iinterface_desc();
virtual const uint8_t *configuration_desc(uint8_t index);
virtual void callback_set_configuration(uint8_t configuration);
virtual void callback_set_interface(uint16_t interface, uint8_t alternate);
virtual void callback_state_change(DeviceState new_state);
virtual void callback_request(const setup_packet_t *setup);
virtual void callback_request_xfer_done(const setup_packet_t *setup, bool aborted);
void _isr_out();
void _isr_in();
void _out();
void _in();
void _reset();
void _control(const setup_packet_t *request);
void _configure();
void _init();
void _process();
void _write_next(uint8_t *data, uint32_t size);
void _read_next();
void CBWDecode(uint8_t *buf, uint16_t size);
void sendCSW(void);
bool inquiryRequest(void);
bool write(uint8_t *buf, uint16_t size);
bool readFormatCapacity();
bool readCapacity(void);
bool infoTransfer(void);
void memoryRead(void);
bool modeSense6(void);
void testUnitReady(void);
bool requestSense(void);
void memoryVerify(uint8_t *buf, uint16_t size);
void memoryWrite(uint8_t *buf, uint16_t size);
void msd_reset();
void fail();
};
/** @}*/
#endif