mbed-os

Fork of mbed-os by erkin yucel

Committer:
xuaner
Date:
Thu Jul 20 14:26:57 2017 +0000
Revision:
1:3deb71413561
Parent:
0:f269e3021894
mbed_os

Who changed what in which revision?

UserRevisionLine numberNew contents of line
elessair 0:f269e3021894 1 /* Copyright (c) 2010-2011 mbed.org, MIT License
elessair 0:f269e3021894 2 *
elessair 0:f269e3021894 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
elessair 0:f269e3021894 4 * and associated documentation files (the "Software"), to deal in the Software without
elessair 0:f269e3021894 5 * restriction, including without limitation the rights to use, copy, modify, merge, publish,
elessair 0:f269e3021894 6 * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
elessair 0:f269e3021894 7 * Software is furnished to do so, subject to the following conditions:
elessair 0:f269e3021894 8 *
elessair 0:f269e3021894 9 * The above copyright notice and this permission notice shall be included in all copies or
elessair 0:f269e3021894 10 * substantial portions of the Software.
elessair 0:f269e3021894 11 *
elessair 0:f269e3021894 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
elessair 0:f269e3021894 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
elessair 0:f269e3021894 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
elessair 0:f269e3021894 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
elessair 0:f269e3021894 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
elessair 0:f269e3021894 17 */
elessair 0:f269e3021894 18
elessair 0:f269e3021894 19 #include "stdint.h"
elessair 0:f269e3021894 20 #include "USBMSD.h"
elessair 0:f269e3021894 21
elessair 0:f269e3021894 22 #define DISK_OK 0x00
elessair 0:f269e3021894 23 #define NO_INIT 0x01
elessair 0:f269e3021894 24 #define NO_DISK 0x02
elessair 0:f269e3021894 25 #define WRITE_PROTECT 0x04
elessair 0:f269e3021894 26
elessair 0:f269e3021894 27 #define CBW_Signature 0x43425355
elessair 0:f269e3021894 28 #define CSW_Signature 0x53425355
elessair 0:f269e3021894 29
elessair 0:f269e3021894 30 // SCSI Commands
elessair 0:f269e3021894 31 #define TEST_UNIT_READY 0x00
elessair 0:f269e3021894 32 #define REQUEST_SENSE 0x03
elessair 0:f269e3021894 33 #define FORMAT_UNIT 0x04
elessair 0:f269e3021894 34 #define INQUIRY 0x12
elessair 0:f269e3021894 35 #define MODE_SELECT6 0x15
elessair 0:f269e3021894 36 #define MODE_SENSE6 0x1A
elessair 0:f269e3021894 37 #define START_STOP_UNIT 0x1B
elessair 0:f269e3021894 38 #define MEDIA_REMOVAL 0x1E
elessair 0:f269e3021894 39 #define READ_FORMAT_CAPACITIES 0x23
elessair 0:f269e3021894 40 #define READ_CAPACITY 0x25
elessair 0:f269e3021894 41 #define READ10 0x28
elessair 0:f269e3021894 42 #define WRITE10 0x2A
elessair 0:f269e3021894 43 #define VERIFY10 0x2F
elessair 0:f269e3021894 44 #define READ12 0xA8
elessair 0:f269e3021894 45 #define WRITE12 0xAA
elessair 0:f269e3021894 46 #define MODE_SELECT10 0x55
elessair 0:f269e3021894 47 #define MODE_SENSE10 0x5A
elessair 0:f269e3021894 48
elessair 0:f269e3021894 49 // MSC class specific requests
elessair 0:f269e3021894 50 #define MSC_REQUEST_RESET 0xFF
elessair 0:f269e3021894 51 #define MSC_REQUEST_GET_MAX_LUN 0xFE
elessair 0:f269e3021894 52
elessair 0:f269e3021894 53 #define DEFAULT_CONFIGURATION (1)
elessair 0:f269e3021894 54
elessair 0:f269e3021894 55 // max packet size
elessair 0:f269e3021894 56 #define MAX_PACKET MAX_PACKET_SIZE_EPBULK
elessair 0:f269e3021894 57
elessair 0:f269e3021894 58 // CSW Status
elessair 0:f269e3021894 59 enum Status {
elessair 0:f269e3021894 60 CSW_PASSED,
elessair 0:f269e3021894 61 CSW_FAILED,
elessair 0:f269e3021894 62 CSW_ERROR,
elessair 0:f269e3021894 63 };
elessair 0:f269e3021894 64
elessair 0:f269e3021894 65
elessair 0:f269e3021894 66 USBMSD::USBMSD(uint16_t vendor_id, uint16_t product_id, uint16_t product_release): USBDevice(vendor_id, product_id, product_release) {
elessair 0:f269e3021894 67 stage = READ_CBW;
elessair 0:f269e3021894 68 memset((void *)&cbw, 0, sizeof(CBW));
elessair 0:f269e3021894 69 memset((void *)&csw, 0, sizeof(CSW));
elessair 0:f269e3021894 70 page = NULL;
elessair 0:f269e3021894 71 }
elessair 0:f269e3021894 72
elessair 0:f269e3021894 73 USBMSD::~USBMSD() {
elessair 0:f269e3021894 74 disconnect();
elessair 0:f269e3021894 75 }
elessair 0:f269e3021894 76
elessair 0:f269e3021894 77
elessair 0:f269e3021894 78 // Called in ISR context to process a class specific request
elessair 0:f269e3021894 79 bool USBMSD::USBCallback_request(void) {
elessair 0:f269e3021894 80
elessair 0:f269e3021894 81 bool success = false;
elessair 0:f269e3021894 82 CONTROL_TRANSFER * transfer = getTransferPtr();
elessair 0:f269e3021894 83 static uint8_t maxLUN[1] = {0};
elessair 0:f269e3021894 84
elessair 0:f269e3021894 85 if (transfer->setup.bmRequestType.Type == CLASS_TYPE) {
elessair 0:f269e3021894 86 switch (transfer->setup.bRequest) {
elessair 0:f269e3021894 87 case MSC_REQUEST_RESET:
elessair 0:f269e3021894 88 reset();
elessair 0:f269e3021894 89 success = true;
elessair 0:f269e3021894 90 break;
elessair 0:f269e3021894 91 case MSC_REQUEST_GET_MAX_LUN:
elessair 0:f269e3021894 92 transfer->remaining = 1;
elessair 0:f269e3021894 93 transfer->ptr = maxLUN;
elessair 0:f269e3021894 94 transfer->direction = DEVICE_TO_HOST;
elessair 0:f269e3021894 95 success = true;
elessair 0:f269e3021894 96 break;
elessair 0:f269e3021894 97 default:
elessair 0:f269e3021894 98 break;
elessair 0:f269e3021894 99 }
elessair 0:f269e3021894 100 }
elessair 0:f269e3021894 101
elessair 0:f269e3021894 102 return success;
elessair 0:f269e3021894 103 }
elessair 0:f269e3021894 104
elessair 0:f269e3021894 105
elessair 0:f269e3021894 106 bool USBMSD::connect(bool blocking) {
elessair 0:f269e3021894 107 //disk initialization
elessair 0:f269e3021894 108 if (disk_status() & NO_INIT) {
elessair 0:f269e3021894 109 if (disk_initialize()) {
elessair 0:f269e3021894 110 return false;
elessair 0:f269e3021894 111 }
elessair 0:f269e3021894 112 }
elessair 0:f269e3021894 113
elessair 0:f269e3021894 114 // get number of blocks
elessair 0:f269e3021894 115 BlockCount = disk_sectors();
elessair 0:f269e3021894 116
elessair 0:f269e3021894 117 // get memory size
elessair 0:f269e3021894 118 MemorySize = disk_size();
elessair 0:f269e3021894 119
elessair 0:f269e3021894 120 if (BlockCount > 0) {
elessair 0:f269e3021894 121 BlockSize = MemorySize / BlockCount;
elessair 0:f269e3021894 122 if (BlockSize != 0) {
elessair 0:f269e3021894 123 free(page);
elessair 0:f269e3021894 124 page = (uint8_t *)malloc(BlockSize * sizeof(uint8_t));
elessair 0:f269e3021894 125 if (page == NULL)
elessair 0:f269e3021894 126 return false;
elessair 0:f269e3021894 127 }
elessair 0:f269e3021894 128 } else {
elessair 0:f269e3021894 129 return false;
elessair 0:f269e3021894 130 }
elessair 0:f269e3021894 131
elessair 0:f269e3021894 132 //connect the device
elessair 0:f269e3021894 133 USBDevice::connect(blocking);
elessair 0:f269e3021894 134 return true;
elessair 0:f269e3021894 135 }
elessair 0:f269e3021894 136
elessair 0:f269e3021894 137 void USBMSD::disconnect() {
elessair 0:f269e3021894 138 USBDevice::disconnect();
elessair 0:f269e3021894 139 //De-allocate MSD page size:
elessair 0:f269e3021894 140 free(page);
elessair 0:f269e3021894 141 page = NULL;
elessair 0:f269e3021894 142 }
elessair 0:f269e3021894 143
elessair 0:f269e3021894 144 void USBMSD::reset() {
elessair 0:f269e3021894 145 stage = READ_CBW;
elessair 0:f269e3021894 146 }
elessair 0:f269e3021894 147
elessair 0:f269e3021894 148
elessair 0:f269e3021894 149 // Called in ISR context called when a data is received
elessair 0:f269e3021894 150 bool USBMSD::EPBULK_OUT_callback() {
elessair 0:f269e3021894 151 uint32_t size = 0;
elessair 0:f269e3021894 152 uint8_t buf[MAX_PACKET_SIZE_EPBULK];
elessair 0:f269e3021894 153 readEP(EPBULK_OUT, buf, &size, MAX_PACKET_SIZE_EPBULK);
elessair 0:f269e3021894 154 switch (stage) {
elessair 0:f269e3021894 155 // the device has to decode the CBW received
elessair 0:f269e3021894 156 case READ_CBW:
elessair 0:f269e3021894 157 CBWDecode(buf, size);
elessair 0:f269e3021894 158 break;
elessair 0:f269e3021894 159
elessair 0:f269e3021894 160 // the device has to receive data from the host
elessair 0:f269e3021894 161 case PROCESS_CBW:
elessair 0:f269e3021894 162 switch (cbw.CB[0]) {
elessair 0:f269e3021894 163 case WRITE10:
elessair 0:f269e3021894 164 case WRITE12:
elessair 0:f269e3021894 165 memoryWrite(buf, size);
elessair 0:f269e3021894 166 break;
elessair 0:f269e3021894 167 case VERIFY10:
elessair 0:f269e3021894 168 memoryVerify(buf, size);
elessair 0:f269e3021894 169 break;
elessair 0:f269e3021894 170 }
elessair 0:f269e3021894 171 break;
elessair 0:f269e3021894 172
elessair 0:f269e3021894 173 // an error has occured: stall endpoint and send CSW
elessair 0:f269e3021894 174 default:
elessair 0:f269e3021894 175 stallEndpoint(EPBULK_OUT);
elessair 0:f269e3021894 176 csw.Status = CSW_ERROR;
elessair 0:f269e3021894 177 sendCSW();
elessair 0:f269e3021894 178 break;
elessair 0:f269e3021894 179 }
elessair 0:f269e3021894 180
elessair 0:f269e3021894 181 //reactivate readings on the OUT bulk endpoint
elessair 0:f269e3021894 182 readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
elessair 0:f269e3021894 183 return true;
elessair 0:f269e3021894 184 }
elessair 0:f269e3021894 185
elessair 0:f269e3021894 186 // Called in ISR context when a data has been transferred
elessair 0:f269e3021894 187 bool USBMSD::EPBULK_IN_callback() {
elessair 0:f269e3021894 188 switch (stage) {
elessair 0:f269e3021894 189
elessair 0:f269e3021894 190 // the device has to send data to the host
elessair 0:f269e3021894 191 case PROCESS_CBW:
elessair 0:f269e3021894 192 switch (cbw.CB[0]) {
elessair 0:f269e3021894 193 case READ10:
elessair 0:f269e3021894 194 case READ12:
elessair 0:f269e3021894 195 memoryRead();
elessair 0:f269e3021894 196 break;
elessair 0:f269e3021894 197 }
elessair 0:f269e3021894 198 break;
elessair 0:f269e3021894 199
elessair 0:f269e3021894 200 //the device has to send a CSW
elessair 0:f269e3021894 201 case SEND_CSW:
elessair 0:f269e3021894 202 sendCSW();
elessair 0:f269e3021894 203 break;
elessair 0:f269e3021894 204
elessair 0:f269e3021894 205 // the host has received the CSW -> we wait a CBW
elessair 0:f269e3021894 206 case WAIT_CSW:
elessair 0:f269e3021894 207 stage = READ_CBW;
elessair 0:f269e3021894 208 break;
elessair 0:f269e3021894 209
elessair 0:f269e3021894 210 // an error has occured
elessair 0:f269e3021894 211 default:
elessair 0:f269e3021894 212 stallEndpoint(EPBULK_IN);
elessair 0:f269e3021894 213 sendCSW();
elessair 0:f269e3021894 214 break;
elessair 0:f269e3021894 215 }
elessair 0:f269e3021894 216 return true;
elessair 0:f269e3021894 217 }
elessair 0:f269e3021894 218
elessair 0:f269e3021894 219
elessair 0:f269e3021894 220 void USBMSD::memoryWrite (uint8_t * buf, uint16_t size) {
elessair 0:f269e3021894 221
elessair 0:f269e3021894 222 if ((addr + size) > MemorySize) {
elessair 0:f269e3021894 223 size = MemorySize - addr;
elessair 0:f269e3021894 224 stage = ERROR;
elessair 0:f269e3021894 225 stallEndpoint(EPBULK_OUT);
elessair 0:f269e3021894 226 }
elessair 0:f269e3021894 227
elessair 0:f269e3021894 228 // we fill an array in RAM of 1 block before writing it in memory
elessair 0:f269e3021894 229 for (int i = 0; i < size; i++)
elessair 0:f269e3021894 230 page[addr%BlockSize + i] = buf[i];
elessair 0:f269e3021894 231
elessair 0:f269e3021894 232 // if the array is filled, write it in memory
elessair 0:f269e3021894 233 if (!((addr + size)%BlockSize)) {
elessair 0:f269e3021894 234 if (!(disk_status() & WRITE_PROTECT)) {
elessair 0:f269e3021894 235 disk_write(page, addr/BlockSize, 1);
elessair 0:f269e3021894 236 }
elessair 0:f269e3021894 237 }
elessair 0:f269e3021894 238
elessair 0:f269e3021894 239 addr += size;
elessair 0:f269e3021894 240 length -= size;
elessair 0:f269e3021894 241 csw.DataResidue -= size;
elessair 0:f269e3021894 242
elessair 0:f269e3021894 243 if ((!length) || (stage != PROCESS_CBW)) {
elessair 0:f269e3021894 244 csw.Status = (stage == ERROR) ? CSW_FAILED : CSW_PASSED;
elessair 0:f269e3021894 245 sendCSW();
elessair 0:f269e3021894 246 }
elessair 0:f269e3021894 247 }
elessair 0:f269e3021894 248
elessair 0:f269e3021894 249 void USBMSD::memoryVerify (uint8_t * buf, uint16_t size) {
elessair 0:f269e3021894 250 uint32_t n;
elessair 0:f269e3021894 251
elessair 0:f269e3021894 252 if ((addr + size) > MemorySize) {
elessair 0:f269e3021894 253 size = MemorySize - addr;
elessair 0:f269e3021894 254 stage = ERROR;
elessair 0:f269e3021894 255 stallEndpoint(EPBULK_OUT);
elessair 0:f269e3021894 256 }
elessair 0:f269e3021894 257
elessair 0:f269e3021894 258 // beginning of a new block -> load a whole block in RAM
elessair 0:f269e3021894 259 if (!(addr%BlockSize))
elessair 0:f269e3021894 260 disk_read(page, addr/BlockSize, 1);
elessair 0:f269e3021894 261
elessair 0:f269e3021894 262 // info are in RAM -> no need to re-read memory
elessair 0:f269e3021894 263 for (n = 0; n < size; n++) {
elessair 0:f269e3021894 264 if (page[addr%BlockSize + n] != buf[n]) {
elessair 0:f269e3021894 265 memOK = false;
elessair 0:f269e3021894 266 break;
elessair 0:f269e3021894 267 }
elessair 0:f269e3021894 268 }
elessair 0:f269e3021894 269
elessair 0:f269e3021894 270 addr += size;
elessair 0:f269e3021894 271 length -= size;
elessair 0:f269e3021894 272 csw.DataResidue -= size;
elessair 0:f269e3021894 273
elessair 0:f269e3021894 274 if ( !length || (stage != PROCESS_CBW)) {
elessair 0:f269e3021894 275 csw.Status = (memOK && (stage == PROCESS_CBW)) ? CSW_PASSED : CSW_FAILED;
elessair 0:f269e3021894 276 sendCSW();
elessair 0:f269e3021894 277 }
elessair 0:f269e3021894 278 }
elessair 0:f269e3021894 279
elessair 0:f269e3021894 280
elessair 0:f269e3021894 281 bool USBMSD::inquiryRequest (void) {
elessair 0:f269e3021894 282 uint8_t inquiry[] = { 0x00, 0x80, 0x00, 0x01,
elessair 0:f269e3021894 283 36 - 4, 0x80, 0x00, 0x00,
elessair 0:f269e3021894 284 'M', 'B', 'E', 'D', '.', 'O', 'R', 'G',
elessair 0:f269e3021894 285 'M', 'B', 'E', 'D', ' ', 'U', 'S', 'B', ' ', 'D', 'I', 'S', 'K', ' ', ' ', ' ',
elessair 0:f269e3021894 286 '1', '.', '0', ' ',
elessair 0:f269e3021894 287 };
elessair 0:f269e3021894 288 if (!write(inquiry, sizeof(inquiry))) {
elessair 0:f269e3021894 289 return false;
elessair 0:f269e3021894 290 }
elessair 0:f269e3021894 291 return true;
elessair 0:f269e3021894 292 }
elessair 0:f269e3021894 293
elessair 0:f269e3021894 294
elessair 0:f269e3021894 295 bool USBMSD::readFormatCapacity() {
elessair 0:f269e3021894 296 uint8_t capacity[] = { 0x00, 0x00, 0x00, 0x08,
elessair 0:f269e3021894 297 (uint8_t)((BlockCount >> 24) & 0xff),
elessair 0:f269e3021894 298 (uint8_t)((BlockCount >> 16) & 0xff),
elessair 0:f269e3021894 299 (uint8_t)((BlockCount >> 8) & 0xff),
elessair 0:f269e3021894 300 (uint8_t)((BlockCount >> 0) & 0xff),
elessair 0:f269e3021894 301
elessair 0:f269e3021894 302 0x02,
elessair 0:f269e3021894 303 (uint8_t)((BlockSize >> 16) & 0xff),
elessair 0:f269e3021894 304 (uint8_t)((BlockSize >> 8) & 0xff),
elessair 0:f269e3021894 305 (uint8_t)((BlockSize >> 0) & 0xff),
elessair 0:f269e3021894 306 };
elessair 0:f269e3021894 307 if (!write(capacity, sizeof(capacity))) {
elessair 0:f269e3021894 308 return false;
elessair 0:f269e3021894 309 }
elessair 0:f269e3021894 310 return true;
elessair 0:f269e3021894 311 }
elessair 0:f269e3021894 312
elessair 0:f269e3021894 313
elessair 0:f269e3021894 314 bool USBMSD::readCapacity (void) {
elessair 0:f269e3021894 315 uint8_t capacity[] = {
elessair 0:f269e3021894 316 (uint8_t)(((BlockCount - 1) >> 24) & 0xff),
elessair 0:f269e3021894 317 (uint8_t)(((BlockCount - 1) >> 16) & 0xff),
elessair 0:f269e3021894 318 (uint8_t)(((BlockCount - 1) >> 8) & 0xff),
elessair 0:f269e3021894 319 (uint8_t)(((BlockCount - 1) >> 0) & 0xff),
elessair 0:f269e3021894 320
elessair 0:f269e3021894 321 (uint8_t)((BlockSize >> 24) & 0xff),
elessair 0:f269e3021894 322 (uint8_t)((BlockSize >> 16) & 0xff),
elessair 0:f269e3021894 323 (uint8_t)((BlockSize >> 8) & 0xff),
elessair 0:f269e3021894 324 (uint8_t)((BlockSize >> 0) & 0xff),
elessair 0:f269e3021894 325 };
elessair 0:f269e3021894 326 if (!write(capacity, sizeof(capacity))) {
elessair 0:f269e3021894 327 return false;
elessair 0:f269e3021894 328 }
elessair 0:f269e3021894 329 return true;
elessair 0:f269e3021894 330 }
elessair 0:f269e3021894 331
elessair 0:f269e3021894 332 bool USBMSD::write (uint8_t * buf, uint16_t size) {
elessair 0:f269e3021894 333
elessair 0:f269e3021894 334 if (size >= cbw.DataLength) {
elessair 0:f269e3021894 335 size = cbw.DataLength;
elessair 0:f269e3021894 336 }
elessair 0:f269e3021894 337 stage = SEND_CSW;
elessair 0:f269e3021894 338
elessair 0:f269e3021894 339 if (!writeNB(EPBULK_IN, buf, size, MAX_PACKET_SIZE_EPBULK)) {
elessair 0:f269e3021894 340 return false;
elessair 0:f269e3021894 341 }
elessair 0:f269e3021894 342
elessair 0:f269e3021894 343 csw.DataResidue -= size;
elessair 0:f269e3021894 344 csw.Status = CSW_PASSED;
elessair 0:f269e3021894 345 return true;
elessair 0:f269e3021894 346 }
elessair 0:f269e3021894 347
elessair 0:f269e3021894 348
elessair 0:f269e3021894 349 bool USBMSD::modeSense6 (void) {
elessair 0:f269e3021894 350 uint8_t sense6[] = { 0x03, 0x00, 0x00, 0x00 };
elessair 0:f269e3021894 351 if (!write(sense6, sizeof(sense6))) {
elessair 0:f269e3021894 352 return false;
elessair 0:f269e3021894 353 }
elessair 0:f269e3021894 354 return true;
elessair 0:f269e3021894 355 }
elessair 0:f269e3021894 356
elessair 0:f269e3021894 357 void USBMSD::sendCSW() {
elessair 0:f269e3021894 358 csw.Signature = CSW_Signature;
elessair 0:f269e3021894 359 writeNB(EPBULK_IN, (uint8_t *)&csw, sizeof(CSW), MAX_PACKET_SIZE_EPBULK);
elessair 0:f269e3021894 360 stage = WAIT_CSW;
elessair 0:f269e3021894 361 }
elessair 0:f269e3021894 362
elessair 0:f269e3021894 363 bool USBMSD::requestSense (void) {
elessair 0:f269e3021894 364 uint8_t request_sense[] = {
elessair 0:f269e3021894 365 0x70,
elessair 0:f269e3021894 366 0x00,
elessair 0:f269e3021894 367 0x05, // Sense Key: illegal request
elessair 0:f269e3021894 368 0x00,
elessair 0:f269e3021894 369 0x00,
elessair 0:f269e3021894 370 0x00,
elessair 0:f269e3021894 371 0x00,
elessair 0:f269e3021894 372 0x0A,
elessair 0:f269e3021894 373 0x00,
elessair 0:f269e3021894 374 0x00,
elessair 0:f269e3021894 375 0x00,
elessair 0:f269e3021894 376 0x00,
elessair 0:f269e3021894 377 0x30,
elessair 0:f269e3021894 378 0x01,
elessair 0:f269e3021894 379 0x00,
elessair 0:f269e3021894 380 0x00,
elessair 0:f269e3021894 381 0x00,
elessair 0:f269e3021894 382 0x00,
elessair 0:f269e3021894 383 };
elessair 0:f269e3021894 384
elessair 0:f269e3021894 385 if (!write(request_sense, sizeof(request_sense))) {
elessair 0:f269e3021894 386 return false;
elessair 0:f269e3021894 387 }
elessair 0:f269e3021894 388
elessair 0:f269e3021894 389 return true;
elessair 0:f269e3021894 390 }
elessair 0:f269e3021894 391
elessair 0:f269e3021894 392 void USBMSD::fail() {
elessair 0:f269e3021894 393 csw.Status = CSW_FAILED;
elessair 0:f269e3021894 394 sendCSW();
elessair 0:f269e3021894 395 }
elessair 0:f269e3021894 396
elessair 0:f269e3021894 397
elessair 0:f269e3021894 398 void USBMSD::CBWDecode(uint8_t * buf, uint16_t size) {
elessair 0:f269e3021894 399 if (size == sizeof(cbw)) {
elessair 0:f269e3021894 400 memcpy((uint8_t *)&cbw, buf, size);
elessair 0:f269e3021894 401 if (cbw.Signature == CBW_Signature) {
elessair 0:f269e3021894 402 csw.Tag = cbw.Tag;
elessair 0:f269e3021894 403 csw.DataResidue = cbw.DataLength;
elessair 0:f269e3021894 404 if ((cbw.CBLength < 1) || (cbw.CBLength > 16) ) {
elessair 0:f269e3021894 405 fail();
elessair 0:f269e3021894 406 } else {
elessair 0:f269e3021894 407 switch (cbw.CB[0]) {
elessair 0:f269e3021894 408 case TEST_UNIT_READY:
elessair 0:f269e3021894 409 testUnitReady();
elessair 0:f269e3021894 410 break;
elessair 0:f269e3021894 411 case REQUEST_SENSE:
elessair 0:f269e3021894 412 requestSense();
elessair 0:f269e3021894 413 break;
elessair 0:f269e3021894 414 case INQUIRY:
elessair 0:f269e3021894 415 inquiryRequest();
elessair 0:f269e3021894 416 break;
elessair 0:f269e3021894 417 case MODE_SENSE6:
elessair 0:f269e3021894 418 modeSense6();
elessair 0:f269e3021894 419 break;
elessair 0:f269e3021894 420 case READ_FORMAT_CAPACITIES:
elessair 0:f269e3021894 421 readFormatCapacity();
elessair 0:f269e3021894 422 break;
elessair 0:f269e3021894 423 case READ_CAPACITY:
elessair 0:f269e3021894 424 readCapacity();
elessair 0:f269e3021894 425 break;
elessair 0:f269e3021894 426 case READ10:
elessair 0:f269e3021894 427 case READ12:
elessair 0:f269e3021894 428 if (infoTransfer()) {
elessair 0:f269e3021894 429 if ((cbw.Flags & 0x80)) {
elessair 0:f269e3021894 430 stage = PROCESS_CBW;
elessair 0:f269e3021894 431 memoryRead();
elessair 0:f269e3021894 432 } else {
elessair 0:f269e3021894 433 stallEndpoint(EPBULK_OUT);
elessair 0:f269e3021894 434 csw.Status = CSW_ERROR;
elessair 0:f269e3021894 435 sendCSW();
elessair 0:f269e3021894 436 }
elessair 0:f269e3021894 437 }
elessair 0:f269e3021894 438 break;
elessair 0:f269e3021894 439 case WRITE10:
elessair 0:f269e3021894 440 case WRITE12:
elessair 0:f269e3021894 441 if (infoTransfer()) {
elessair 0:f269e3021894 442 if (!(cbw.Flags & 0x80)) {
elessair 0:f269e3021894 443 stage = PROCESS_CBW;
elessair 0:f269e3021894 444 } else {
elessair 0:f269e3021894 445 stallEndpoint(EPBULK_IN);
elessair 0:f269e3021894 446 csw.Status = CSW_ERROR;
elessair 0:f269e3021894 447 sendCSW();
elessair 0:f269e3021894 448 }
elessair 0:f269e3021894 449 }
elessair 0:f269e3021894 450 break;
elessair 0:f269e3021894 451 case VERIFY10:
elessair 0:f269e3021894 452 if (!(cbw.CB[1] & 0x02)) {
elessair 0:f269e3021894 453 csw.Status = CSW_PASSED;
elessair 0:f269e3021894 454 sendCSW();
elessair 0:f269e3021894 455 break;
elessair 0:f269e3021894 456 }
elessair 0:f269e3021894 457 if (infoTransfer()) {
elessair 0:f269e3021894 458 if (!(cbw.Flags & 0x80)) {
elessair 0:f269e3021894 459 stage = PROCESS_CBW;
elessair 0:f269e3021894 460 memOK = true;
elessair 0:f269e3021894 461 } else {
elessair 0:f269e3021894 462 stallEndpoint(EPBULK_IN);
elessair 0:f269e3021894 463 csw.Status = CSW_ERROR;
elessair 0:f269e3021894 464 sendCSW();
elessair 0:f269e3021894 465 }
elessair 0:f269e3021894 466 }
elessair 0:f269e3021894 467 break;
elessair 0:f269e3021894 468 case MEDIA_REMOVAL:
elessair 0:f269e3021894 469 csw.Status = CSW_PASSED;
elessair 0:f269e3021894 470 sendCSW();
elessair 0:f269e3021894 471 break;
elessair 0:f269e3021894 472 default:
elessair 0:f269e3021894 473 fail();
elessair 0:f269e3021894 474 break;
elessair 0:f269e3021894 475 }
elessair 0:f269e3021894 476 }
elessair 0:f269e3021894 477 }
elessair 0:f269e3021894 478 }
elessair 0:f269e3021894 479 }
elessair 0:f269e3021894 480
elessair 0:f269e3021894 481 void USBMSD::testUnitReady (void) {
elessair 0:f269e3021894 482
elessair 0:f269e3021894 483 if (cbw.DataLength != 0) {
elessair 0:f269e3021894 484 if ((cbw.Flags & 0x80) != 0) {
elessair 0:f269e3021894 485 stallEndpoint(EPBULK_IN);
elessair 0:f269e3021894 486 } else {
elessair 0:f269e3021894 487 stallEndpoint(EPBULK_OUT);
elessair 0:f269e3021894 488 }
elessair 0:f269e3021894 489 }
elessair 0:f269e3021894 490
elessair 0:f269e3021894 491 csw.Status = CSW_PASSED;
elessair 0:f269e3021894 492 sendCSW();
elessair 0:f269e3021894 493 }
elessair 0:f269e3021894 494
elessair 0:f269e3021894 495
elessair 0:f269e3021894 496 void USBMSD::memoryRead (void) {
elessair 0:f269e3021894 497 uint32_t n;
elessair 0:f269e3021894 498
elessair 0:f269e3021894 499 n = (length > MAX_PACKET) ? MAX_PACKET : length;
elessair 0:f269e3021894 500
elessair 0:f269e3021894 501 if ((addr + n) > MemorySize) {
elessair 0:f269e3021894 502 n = MemorySize - addr;
elessair 0:f269e3021894 503 stage = ERROR;
elessair 0:f269e3021894 504 }
elessair 0:f269e3021894 505
elessair 0:f269e3021894 506 // we read an entire block
elessair 0:f269e3021894 507 if (!(addr%BlockSize))
elessair 0:f269e3021894 508 disk_read(page, addr/BlockSize, 1);
elessair 0:f269e3021894 509
elessair 0:f269e3021894 510 // write data which are in RAM
elessair 0:f269e3021894 511 writeNB(EPBULK_IN, &page[addr%BlockSize], n, MAX_PACKET_SIZE_EPBULK);
elessair 0:f269e3021894 512
elessair 0:f269e3021894 513 addr += n;
elessair 0:f269e3021894 514 length -= n;
elessair 0:f269e3021894 515
elessair 0:f269e3021894 516 csw.DataResidue -= n;
elessair 0:f269e3021894 517
elessair 0:f269e3021894 518 if ( !length || (stage != PROCESS_CBW)) {
elessair 0:f269e3021894 519 csw.Status = (stage == PROCESS_CBW) ? CSW_PASSED : CSW_FAILED;
elessair 0:f269e3021894 520 stage = (stage == PROCESS_CBW) ? SEND_CSW : stage;
elessair 0:f269e3021894 521 }
elessair 0:f269e3021894 522 }
elessair 0:f269e3021894 523
elessair 0:f269e3021894 524
elessair 0:f269e3021894 525 bool USBMSD::infoTransfer (void) {
elessair 0:f269e3021894 526 uint32_t n;
elessair 0:f269e3021894 527
elessair 0:f269e3021894 528 // Logical Block Address of First Block
elessair 0:f269e3021894 529 n = (cbw.CB[2] << 24) | (cbw.CB[3] << 16) | (cbw.CB[4] << 8) | (cbw.CB[5] << 0);
elessair 0:f269e3021894 530
elessair 0:f269e3021894 531 addr = n * BlockSize;
elessair 0:f269e3021894 532
elessair 0:f269e3021894 533 // Number of Blocks to transfer
elessair 0:f269e3021894 534 switch (cbw.CB[0]) {
elessair 0:f269e3021894 535 case READ10:
elessair 0:f269e3021894 536 case WRITE10:
elessair 0:f269e3021894 537 case VERIFY10:
elessair 0:f269e3021894 538 n = (cbw.CB[7] << 8) | (cbw.CB[8] << 0);
elessair 0:f269e3021894 539 break;
elessair 0:f269e3021894 540
elessair 0:f269e3021894 541 case READ12:
elessair 0:f269e3021894 542 case WRITE12:
elessair 0:f269e3021894 543 n = (cbw.CB[6] << 24) | (cbw.CB[7] << 16) | (cbw.CB[8] << 8) | (cbw.CB[9] << 0);
elessair 0:f269e3021894 544 break;
elessair 0:f269e3021894 545 }
elessair 0:f269e3021894 546
elessair 0:f269e3021894 547 length = n * BlockSize;
elessair 0:f269e3021894 548
elessair 0:f269e3021894 549 if (!cbw.DataLength) { // host requests no data
elessair 0:f269e3021894 550 csw.Status = CSW_FAILED;
elessair 0:f269e3021894 551 sendCSW();
elessair 0:f269e3021894 552 return false;
elessair 0:f269e3021894 553 }
elessair 0:f269e3021894 554
elessair 0:f269e3021894 555 if (cbw.DataLength != length) {
elessair 0:f269e3021894 556 if ((cbw.Flags & 0x80) != 0) {
elessair 0:f269e3021894 557 stallEndpoint(EPBULK_IN);
elessair 0:f269e3021894 558 } else {
elessair 0:f269e3021894 559 stallEndpoint(EPBULK_OUT);
elessair 0:f269e3021894 560 }
elessair 0:f269e3021894 561
elessair 0:f269e3021894 562 csw.Status = CSW_FAILED;
elessair 0:f269e3021894 563 sendCSW();
elessair 0:f269e3021894 564 return false;
elessair 0:f269e3021894 565 }
elessair 0:f269e3021894 566
elessair 0:f269e3021894 567 return true;
elessair 0:f269e3021894 568 }
elessair 0:f269e3021894 569
elessair 0:f269e3021894 570
elessair 0:f269e3021894 571
elessair 0:f269e3021894 572
elessair 0:f269e3021894 573
elessair 0:f269e3021894 574 // Called in ISR context
elessair 0:f269e3021894 575 // Set configuration. Return false if the
elessair 0:f269e3021894 576 // configuration is not supported.
elessair 0:f269e3021894 577 bool USBMSD::USBCallback_setConfiguration(uint8_t configuration) {
elessair 0:f269e3021894 578 if (configuration != DEFAULT_CONFIGURATION) {
elessair 0:f269e3021894 579 return false;
elessair 0:f269e3021894 580 }
elessair 0:f269e3021894 581
elessair 0:f269e3021894 582 // Configure endpoints > 0
elessair 0:f269e3021894 583 addEndpoint(EPBULK_IN, MAX_PACKET_SIZE_EPBULK);
elessair 0:f269e3021894 584 addEndpoint(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
elessair 0:f269e3021894 585
elessair 0:f269e3021894 586 //activate readings
elessair 0:f269e3021894 587 readStart(EPBULK_OUT, MAX_PACKET_SIZE_EPBULK);
elessair 0:f269e3021894 588 return true;
elessair 0:f269e3021894 589 }
elessair 0:f269e3021894 590
elessair 0:f269e3021894 591
elessair 0:f269e3021894 592 uint8_t * USBMSD::stringIinterfaceDesc() {
elessair 0:f269e3021894 593 static uint8_t stringIinterfaceDescriptor[] = {
elessair 0:f269e3021894 594 0x08, //bLength
elessair 0:f269e3021894 595 STRING_DESCRIPTOR, //bDescriptorType 0x03
elessair 0:f269e3021894 596 'M',0,'S',0,'D',0 //bString iInterface - MSD
elessair 0:f269e3021894 597 };
elessair 0:f269e3021894 598 return stringIinterfaceDescriptor;
elessair 0:f269e3021894 599 }
elessair 0:f269e3021894 600
elessair 0:f269e3021894 601 uint8_t * USBMSD::stringIproductDesc() {
elessair 0:f269e3021894 602 static uint8_t stringIproductDescriptor[] = {
elessair 0:f269e3021894 603 0x12, //bLength
elessair 0:f269e3021894 604 STRING_DESCRIPTOR, //bDescriptorType 0x03
elessair 0:f269e3021894 605 'M',0,'b',0,'e',0,'d',0,' ',0,'M',0,'S',0,'D',0 //bString iProduct - Mbed Audio
elessair 0:f269e3021894 606 };
elessair 0:f269e3021894 607 return stringIproductDescriptor;
elessair 0:f269e3021894 608 }
elessair 0:f269e3021894 609
elessair 0:f269e3021894 610
elessair 0:f269e3021894 611 uint8_t * USBMSD::configurationDesc() {
elessair 0:f269e3021894 612 static uint8_t configDescriptor[] = {
elessair 0:f269e3021894 613
elessair 0:f269e3021894 614 // Configuration 1
elessair 0:f269e3021894 615 9, // bLength
elessair 0:f269e3021894 616 2, // bDescriptorType
elessair 0:f269e3021894 617 LSB(9 + 9 + 7 + 7), // wTotalLength
elessair 0:f269e3021894 618 MSB(9 + 9 + 7 + 7),
elessair 0:f269e3021894 619 0x01, // bNumInterfaces
elessair 0:f269e3021894 620 0x01, // bConfigurationValue: 0x01 is used to select this configuration
elessair 0:f269e3021894 621 0x00, // iConfiguration: no string to describe this configuration
elessair 0:f269e3021894 622 0xC0, // bmAttributes
elessair 0:f269e3021894 623 100, // bMaxPower, device power consumption is 100 mA
elessair 0:f269e3021894 624
elessair 0:f269e3021894 625 // Interface 0, Alternate Setting 0, MSC Class
elessair 0:f269e3021894 626 9, // bLength
elessair 0:f269e3021894 627 4, // bDescriptorType
elessair 0:f269e3021894 628 0x00, // bInterfaceNumber
elessair 0:f269e3021894 629 0x00, // bAlternateSetting
elessair 0:f269e3021894 630 0x02, // bNumEndpoints
elessair 0:f269e3021894 631 0x08, // bInterfaceClass
elessair 0:f269e3021894 632 0x06, // bInterfaceSubClass
elessair 0:f269e3021894 633 0x50, // bInterfaceProtocol
elessair 0:f269e3021894 634 0x04, // iInterface
elessair 0:f269e3021894 635
elessair 0:f269e3021894 636 // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
elessair 0:f269e3021894 637 7, // bLength
elessair 0:f269e3021894 638 5, // bDescriptorType
elessair 0:f269e3021894 639 PHY_TO_DESC(EPBULK_IN), // bEndpointAddress
elessair 0:f269e3021894 640 0x02, // bmAttributes (0x02=bulk)
elessair 0:f269e3021894 641 LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB)
elessair 0:f269e3021894 642 MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB)
elessair 0:f269e3021894 643 0, // bInterval
elessair 0:f269e3021894 644
elessair 0:f269e3021894 645 // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
elessair 0:f269e3021894 646 7, // bLength
elessair 0:f269e3021894 647 5, // bDescriptorType
elessair 0:f269e3021894 648 PHY_TO_DESC(EPBULK_OUT), // bEndpointAddress
elessair 0:f269e3021894 649 0x02, // bmAttributes (0x02=bulk)
elessair 0:f269e3021894 650 LSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (LSB)
elessair 0:f269e3021894 651 MSB(MAX_PACKET_SIZE_EPBULK),// wMaxPacketSize (MSB)
elessair 0:f269e3021894 652 0 // bInterval
elessair 0:f269e3021894 653 };
elessair 0:f269e3021894 654 return configDescriptor;
elessair 0:f269e3021894 655 }