max4146x_comp

Dependencies:   MAX14690

Committer:
sdivarci
Date:
Sun Oct 25 20:10:02 2020 +0000
Revision:
0:0061165683ee
sdivarci

Who changed what in which revision?

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