MAX3421E-based USB Host Shield Library

Dependents:   UsbHostMAX3421E_Hello

Committer:
hudakz
Date:
Mon Jul 13 07:03:06 2020 +0000
Revision:
1:2263e77400e9
Parent:
0:84353c479782
MAX3421E-based USB Host Shield Library

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hudakz 0:84353c479782 1 /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
hudakz 0:84353c479782 2
hudakz 0:84353c479782 3 This program is free software; you can redistribute it and/or modify
hudakz 0:84353c479782 4 it under the terms of the GNU General Public License as published by
hudakz 0:84353c479782 5 the Free Software Foundation; either version 2 of the License, or
hudakz 0:84353c479782 6 (at your option) any later version.
hudakz 0:84353c479782 7
hudakz 0:84353c479782 8 This program is distributed in the hope that it will be useful,
hudakz 0:84353c479782 9 but WITHOUT ANY WARRANTY; without even the implied warranty of
hudakz 0:84353c479782 10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
hudakz 0:84353c479782 11 GNU General Public License for more details.
hudakz 0:84353c479782 12
hudakz 0:84353c479782 13 You should have received a copy of the GNU General Public License
hudakz 0:84353c479782 14 along with this program; if not, write to the Free Software
hudakz 0:84353c479782 15 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
hudakz 0:84353c479782 16
hudakz 0:84353c479782 17 Contact information
hudakz 0:84353c479782 18 -------------------
hudakz 0:84353c479782 19
hudakz 0:84353c479782 20 Circuits At Home, LTD
hudakz 0:84353c479782 21 Web : http://www.circuitsathome.com
hudakz 0:84353c479782 22 e-mail : support@circuitsathome.com
hudakz 0:84353c479782 23 */
hudakz 0:84353c479782 24
hudakz 0:84353c479782 25 #include "masstorage.h"
hudakz 0:84353c479782 26
hudakz 0:84353c479782 27 const uint8_t BulkOnly::epDataInIndex = 1;
hudakz 0:84353c479782 28 const uint8_t BulkOnly::epDataOutIndex = 2;
hudakz 0:84353c479782 29 const uint8_t BulkOnly::epInterruptInIndex = 3;
hudakz 0:84353c479782 30
hudakz 0:84353c479782 31 ////////////////////////////////////////////////////////////////////////////////
hudakz 0:84353c479782 32
hudakz 0:84353c479782 33 // Interface code
hudakz 0:84353c479782 34
hudakz 0:84353c479782 35 ////////////////////////////////////////////////////////////////////////////////
hudakz 0:84353c479782 36
hudakz 0:84353c479782 37 /**
hudakz 0:84353c479782 38 * Get the capacity of the media
hudakz 0:84353c479782 39 *
hudakz 0:84353c479782 40 * @param lun Logical Unit Number
hudakz 0:84353c479782 41 * @return media capacity
hudakz 0:84353c479782 42 */
hudakz 0:84353c479782 43 uint32_t BulkOnly::GetCapacity(uint8_t lun) {
hudakz 0:84353c479782 44 if(LUNOk[lun])
hudakz 0:84353c479782 45 return CurrentCapacity[lun];
hudakz 0:84353c479782 46 return 0LU;
hudakz 0:84353c479782 47 }
hudakz 0:84353c479782 48
hudakz 0:84353c479782 49 /**
hudakz 0:84353c479782 50 * Get the sector (block) size used on the media
hudakz 0:84353c479782 51 *
hudakz 0:84353c479782 52 * @param lun Logical Unit Number
hudakz 0:84353c479782 53 * @return media sector size
hudakz 0:84353c479782 54 */
hudakz 0:84353c479782 55 uint16_t BulkOnly::GetSectorSize(uint8_t lun) {
hudakz 0:84353c479782 56 if(LUNOk[lun])
hudakz 0:84353c479782 57 return CurrentSectorSize[lun];
hudakz 0:84353c479782 58 return 0U;
hudakz 0:84353c479782 59 }
hudakz 0:84353c479782 60
hudakz 0:84353c479782 61 /**
hudakz 0:84353c479782 62 * Test if LUN is ready for use
hudakz 0:84353c479782 63 *
hudakz 0:84353c479782 64 * @param lun Logical Unit Number
hudakz 0:84353c479782 65 * @return true if LUN is ready for use
hudakz 0:84353c479782 66 */
hudakz 0:84353c479782 67 bool BulkOnly::LUNIsGood(uint8_t lun) {
hudakz 0:84353c479782 68 return LUNOk[lun];
hudakz 0:84353c479782 69 }
hudakz 0:84353c479782 70
hudakz 0:84353c479782 71 /**
hudakz 0:84353c479782 72 * Test if LUN is write protected
hudakz 0:84353c479782 73 *
hudakz 0:84353c479782 74 * @param lun Logical Unit Number
hudakz 0:84353c479782 75 * @return cached status of write protect switch
hudakz 0:84353c479782 76 */
hudakz 0:84353c479782 77 bool BulkOnly::WriteProtected(uint8_t lun) {
hudakz 0:84353c479782 78 return WriteOk[lun];
hudakz 0:84353c479782 79 }
hudakz 0:84353c479782 80
hudakz 0:84353c479782 81 /**
hudakz 0:84353c479782 82 * Wrap and execute a SCSI CDB with length of 6
hudakz 0:84353c479782 83 *
hudakz 0:84353c479782 84 * @param cdb CDB to execute
hudakz 0:84353c479782 85 * @param buf_size Size of expected transaction
hudakz 0:84353c479782 86 * @param buf Buffer
hudakz 0:84353c479782 87 * @param dir MASS_CMD_DIR_IN | MASS_CMD_DIR_OUT
hudakz 0:84353c479782 88 * @return
hudakz 0:84353c479782 89 */
hudakz 0:84353c479782 90 uint8_t BulkOnly::SCSITransaction6(CDB6_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) {
hudakz 0:84353c479782 91 // promote buf_size to 32bits.
hudakz 0:84353c479782 92 CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir);
hudakz 0:84353c479782 93 //SetCurLUN(cdb->LUN);
hudakz 0:84353c479782 94 return (HandleSCSIError(Transaction(&cbw, buf_size, buf)));
hudakz 0:84353c479782 95 }
hudakz 0:84353c479782 96
hudakz 0:84353c479782 97 /**
hudakz 0:84353c479782 98 * Wrap and execute a SCSI CDB with length of 10
hudakz 0:84353c479782 99 *
hudakz 0:84353c479782 100 * @param cdb CDB to execute
hudakz 0:84353c479782 101 * @param buf_size Size of expected transaction
hudakz 0:84353c479782 102 * @param buf Buffer
hudakz 0:84353c479782 103 * @param dir MASS_CMD_DIR_IN | MASS_CMD_DIR_OUT
hudakz 0:84353c479782 104 * @return
hudakz 0:84353c479782 105 */
hudakz 0:84353c479782 106 uint8_t BulkOnly::SCSITransaction10(CDB10_t *cdb, uint16_t buf_size, void *buf, uint8_t dir) {
hudakz 0:84353c479782 107 // promote buf_size to 32bits.
hudakz 0:84353c479782 108 CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)buf_size, cdb, dir);
hudakz 0:84353c479782 109 //SetCurLUN(cdb->LUN);
hudakz 0:84353c479782 110 return (HandleSCSIError(Transaction(&cbw, buf_size, buf)));
hudakz 0:84353c479782 111 }
hudakz 0:84353c479782 112
hudakz 0:84353c479782 113 /**
hudakz 0:84353c479782 114 * Lock or Unlock the tray or door on device.
hudakz 0:84353c479782 115 * Caution: Some devices with buggy firmware will lock up.
hudakz 0:84353c479782 116 *
hudakz 0:84353c479782 117 * @param lun Logical Unit Number
hudakz 0:84353c479782 118 * @param lock 1 to lock, 0 to unlock
hudakz 0:84353c479782 119 * @return
hudakz 0:84353c479782 120 */
hudakz 0:84353c479782 121 uint8_t BulkOnly::LockMedia(uint8_t lun, uint8_t lock) {
hudakz 0:84353c479782 122 Notify(PSTR("\r\nLockMedia\r\n"), 0x80);
hudakz 0:84353c479782 123 Notify(PSTR("---------\r\n"), 0x80);
hudakz 0:84353c479782 124
hudakz 0:84353c479782 125 CDB6_t cdb = CDB6_t(SCSI_CMD_PREVENT_REMOVAL, lun, (uint8_t)0, lock);
hudakz 0:84353c479782 126 return SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)MASS_CMD_DIR_IN);
hudakz 0:84353c479782 127 }
hudakz 0:84353c479782 128
hudakz 0:84353c479782 129 /**
hudakz 0:84353c479782 130 * Media control, for spindle motor and media tray or door.
hudakz 0:84353c479782 131 * This includes CDROM, TAPE and anything with a media loader.
hudakz 0:84353c479782 132 *
hudakz 0:84353c479782 133 * @param lun Logical Unit Number
hudakz 0:84353c479782 134 * @param ctl 0x00 Stop Motor, 0x01 Start Motor, 0x02 Eject Media, 0x03 Load Media
hudakz 0:84353c479782 135 * @return 0 on success
hudakz 0:84353c479782 136 */
hudakz 0:84353c479782 137 uint8_t BulkOnly::MediaCTL(uint8_t lun, uint8_t ctl) {
hudakz 0:84353c479782 138 Notify(PSTR("\r\nMediaCTL\r\n"), 0x80);
hudakz 0:84353c479782 139 Notify(PSTR("-----------------\r\n"), 0x80);
hudakz 0:84353c479782 140
hudakz 0:84353c479782 141 uint8_t rcode = MASS_ERR_UNIT_NOT_READY;
hudakz 0:84353c479782 142 if(bAddress) {
hudakz 0:84353c479782 143 CDB6_t cdb = CDB6_t(SCSI_CMD_START_STOP_UNIT, lun, ctl & 0x03, 0);
hudakz 0:84353c479782 144 rcode = SCSITransaction6(&cdb, (uint16_t)0, NULL, (uint8_t)MASS_CMD_DIR_OUT);
hudakz 0:84353c479782 145 } else {
hudakz 0:84353c479782 146 SetCurLUN(lun);
hudakz 0:84353c479782 147 }
hudakz 0:84353c479782 148 return rcode;
hudakz 0:84353c479782 149 }
hudakz 0:84353c479782 150
hudakz 0:84353c479782 151 /**
hudakz 0:84353c479782 152 * Read data from media
hudakz 0:84353c479782 153 *
hudakz 0:84353c479782 154 * @param lun Logical Unit Number
hudakz 0:84353c479782 155 * @param addr LBA address on media to read
hudakz 0:84353c479782 156 * @param bsize size of a block (we should probably use the cached size)
hudakz 0:84353c479782 157 * @param blocks how many blocks to read
hudakz 0:84353c479782 158 * @param buf memory that is able to hold the requested data
hudakz 0:84353c479782 159 * @return 0 on success
hudakz 0:84353c479782 160 */
hudakz 0:84353c479782 161 uint8_t BulkOnly::Read(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, uint8_t *buf) {
hudakz 0:84353c479782 162 if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA;
hudakz 0:84353c479782 163 Notify(PSTR("\r\nRead LUN:\t"), 0x80);
hudakz 0:84353c479782 164 D_PrintHex<uint8_t > (lun, 0x90);
hudakz 0:84353c479782 165 Notify(PSTR("\r\nLBA:\t\t"), 0x90);
hudakz 0:84353c479782 166 D_PrintHex<uint32_t > (addr, 0x90);
hudakz 0:84353c479782 167 Notify(PSTR("\r\nblocks:\t\t"), 0x90);
hudakz 0:84353c479782 168 D_PrintHex<uint8_t > (blocks, 0x90);
hudakz 0:84353c479782 169 Notify(PSTR("\r\nblock size:\t"), 0x90);
hudakz 0:84353c479782 170 D_PrintHex<uint16_t > (bsize, 0x90);
hudakz 0:84353c479782 171 Notify(PSTR("\r\n---------\r\n"), 0x80);
hudakz 0:84353c479782 172 CDB10_t cdb = CDB10_t(SCSI_CMD_READ_10, lun, blocks, addr);
hudakz 0:84353c479782 173
hudakz 0:84353c479782 174 again:
hudakz 0:84353c479782 175 uint8_t er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), buf, (uint8_t)MASS_CMD_DIR_IN);
hudakz 0:84353c479782 176
hudakz 0:84353c479782 177 if(er == MASS_ERR_STALL) {
hudakz 0:84353c479782 178 MediaCTL(lun, 1);
hudakz 0:84353c479782 179 wait_ms(150);
hudakz 0:84353c479782 180 if(!TestUnitReady(lun)) goto again;
hudakz 0:84353c479782 181 }
hudakz 0:84353c479782 182 return er;
hudakz 0:84353c479782 183 }
hudakz 0:84353c479782 184
hudakz 0:84353c479782 185 /**
hudakz 0:84353c479782 186 * Write data to media
hudakz 0:84353c479782 187 *
hudakz 0:84353c479782 188 * @param lun Logical Unit Number
hudakz 0:84353c479782 189 * @param addr LBA address on media to write
hudakz 0:84353c479782 190 * @param bsize size of a block (we should probably use the cached size)
hudakz 0:84353c479782 191 * @param blocks how many blocks to write
hudakz 0:84353c479782 192 * @param buf memory that contains the data to write
hudakz 0:84353c479782 193 * @return 0 on success
hudakz 0:84353c479782 194 */
hudakz 0:84353c479782 195 uint8_t BulkOnly::Write(uint8_t lun, uint32_t addr, uint16_t bsize, uint8_t blocks, const uint8_t * buf) {
hudakz 0:84353c479782 196 if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA;
hudakz 0:84353c479782 197 if(!WriteOk[lun]) return MASS_ERR_WRITE_PROTECTED;
hudakz 0:84353c479782 198 Notify(PSTR("\r\nWrite LUN:\t"), 0x80);
hudakz 0:84353c479782 199 D_PrintHex<uint8_t > (lun, 0x90);
hudakz 0:84353c479782 200 Notify(PSTR("\r\nLBA:\t\t"), 0x90);
hudakz 0:84353c479782 201 D_PrintHex<uint32_t > (addr, 0x90);
hudakz 0:84353c479782 202 Notify(PSTR("\r\nblocks:\t\t"), 0x90);
hudakz 0:84353c479782 203 D_PrintHex<uint8_t > (blocks, 0x90);
hudakz 0:84353c479782 204 Notify(PSTR("\r\nblock size:\t"), 0x90);
hudakz 0:84353c479782 205 D_PrintHex<uint16_t > (bsize, 0x90);
hudakz 0:84353c479782 206 Notify(PSTR("\r\n---------\r\n"), 0x80);
hudakz 0:84353c479782 207 CDB10_t cdb = CDB10_t(SCSI_CMD_WRITE_10, lun, blocks, addr);
hudakz 0:84353c479782 208
hudakz 0:84353c479782 209 again:
hudakz 0:84353c479782 210 uint8_t er = SCSITransaction10(&cdb, ((uint16_t)bsize * blocks), (void*)buf, (uint8_t)MASS_CMD_DIR_OUT);
hudakz 0:84353c479782 211
hudakz 0:84353c479782 212 if(er == MASS_ERR_WRITE_STALL) {
hudakz 0:84353c479782 213 MediaCTL(lun, 1);
hudakz 0:84353c479782 214 wait_ms(150);
hudakz 0:84353c479782 215 if(!TestUnitReady(lun)) goto again;
hudakz 0:84353c479782 216 }
hudakz 0:84353c479782 217 return er;
hudakz 0:84353c479782 218 }
hudakz 0:84353c479782 219
hudakz 0:84353c479782 220 // End of user functions, the remaining code below is driver internals.
hudakz 0:84353c479782 221 // Only developer serviceable parts below!
hudakz 0:84353c479782 222
hudakz 0:84353c479782 223 ////////////////////////////////////////////////////////////////////////////////
hudakz 0:84353c479782 224
hudakz 0:84353c479782 225 // Main driver code
hudakz 0:84353c479782 226
hudakz 0:84353c479782 227 ////////////////////////////////////////////////////////////////////////////////
hudakz 0:84353c479782 228
hudakz 1:2263e77400e9 229 BulkOnly::BulkOnly(Usb *p) :
hudakz 0:84353c479782 230 pUsb(p),
hudakz 0:84353c479782 231 bAddress(0),
hudakz 0:84353c479782 232 bIface(0),
hudakz 0:84353c479782 233 bNumEP(1),
hudakz 0:84353c479782 234 qNextPollTime(0),
hudakz 0:84353c479782 235 bPollEnable(false),
hudakz 0:84353c479782 236 //dCBWTag(0),
hudakz 0:84353c479782 237 bLastUsbError(0) {
hudakz 0:84353c479782 238 ClearAllEP();
hudakz 0:84353c479782 239 dCBWTag = 0;
hudakz 0:84353c479782 240 if(pUsb)
hudakz 0:84353c479782 241 pUsb->RegisterDeviceClass(this);
hudakz 0:84353c479782 242 }
hudakz 0:84353c479782 243
hudakz 0:84353c479782 244 /**
hudakz 0:84353c479782 245 * USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET == success
hudakz 0:84353c479782 246 * We need to standardize either the rcode, or change the API to return values
hudakz 0:84353c479782 247 * so a signal that additional actions are required can be produced.
hudakz 0:84353c479782 248 * Some of these codes do exist already.
hudakz 0:84353c479782 249 *
hudakz 0:84353c479782 250 * TECHNICAL: We could do most of this code elsewhere, with the exception of checking the class instance.
hudakz 0:84353c479782 251 * Doing so would save some program memory when using multiple drivers.
hudakz 0:84353c479782 252 *
hudakz 0:84353c479782 253 * @param parent USB address of parent
hudakz 0:84353c479782 254 * @param port address of port on parent
hudakz 0:84353c479782 255 * @param lowspeed true if device is low speed
hudakz 0:84353c479782 256 * @return
hudakz 0:84353c479782 257 */
hudakz 0:84353c479782 258 uint8_t BulkOnly::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) {
hudakz 0:84353c479782 259
hudakz 0:84353c479782 260 const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
hudakz 0:84353c479782 261
hudakz 0:84353c479782 262 uint8_t buf[constBufSize];
hudakz 0:84353c479782 263 USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
hudakz 0:84353c479782 264 uint8_t rcode;
hudakz 0:84353c479782 265 UsbDevice *p = NULL;
hudakz 0:84353c479782 266 EpInfo *oldep_ptr = NULL;
hudakz 0:84353c479782 267 USBTRACE("MS ConfigureDevice\r\n");
hudakz 0:84353c479782 268 ClearAllEP();
hudakz 0:84353c479782 269 AddressPool &addrPool = pUsb->GetAddressPool();
hudakz 0:84353c479782 270
hudakz 0:84353c479782 271
hudakz 0:84353c479782 272 if(bAddress)
hudakz 0:84353c479782 273 return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
hudakz 0:84353c479782 274
hudakz 0:84353c479782 275 // <TECHNICAL>
hudakz 0:84353c479782 276 // Get pointer to pseudo device with address 0 assigned
hudakz 0:84353c479782 277 p = addrPool.GetUsbDevicePtr(0);
hudakz 0:84353c479782 278 if(!p) {
hudakz 0:84353c479782 279 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
hudakz 0:84353c479782 280 }
hudakz 0:84353c479782 281
hudakz 0:84353c479782 282 if(!p->epinfo) {
hudakz 0:84353c479782 283 USBTRACE("epinfo\r\n");
hudakz 0:84353c479782 284 return USB_ERROR_EPINFO_IS_NULL;
hudakz 0:84353c479782 285 }
hudakz 0:84353c479782 286
hudakz 0:84353c479782 287 // Save old pointer to EP_RECORD of address 0
hudakz 0:84353c479782 288 oldep_ptr = p->epinfo;
hudakz 0:84353c479782 289
hudakz 0:84353c479782 290 // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
hudakz 0:84353c479782 291 p->epinfo = epInfo;
hudakz 0:84353c479782 292
hudakz 0:84353c479782 293 p->lowspeed = lowspeed;
hudakz 0:84353c479782 294 // Get device descriptor
hudakz 0:84353c479782 295 rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf);
hudakz 0:84353c479782 296
hudakz 0:84353c479782 297 // Restore p->epinfo
hudakz 0:84353c479782 298 p->epinfo = oldep_ptr;
hudakz 0:84353c479782 299
hudakz 0:84353c479782 300 if(rcode) {
hudakz 0:84353c479782 301 goto FailGetDevDescr;
hudakz 0:84353c479782 302 }
hudakz 0:84353c479782 303 // Allocate new address according to device class
hudakz 0:84353c479782 304 bAddress = addrPool.AllocAddress(parent, false, port);
hudakz 0:84353c479782 305
hudakz 0:84353c479782 306 if(!bAddress)
hudakz 0:84353c479782 307 return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
hudakz 0:84353c479782 308
hudakz 0:84353c479782 309 // Extract Max Packet Size from the device descriptor
hudakz 0:84353c479782 310 epInfo[0].maxPktSize = udd->bMaxPacketSize0;
hudakz 0:84353c479782 311 // Steal and abuse from epInfo structure to save on memory.
hudakz 0:84353c479782 312 epInfo[1].epAddr = udd->bNumConfigurations;
hudakz 0:84353c479782 313 // </TECHNICAL>
hudakz 0:84353c479782 314 return USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET;
hudakz 0:84353c479782 315
hudakz 0:84353c479782 316 FailGetDevDescr:
hudakz 0:84353c479782 317 #ifdef DEBUG_USB_HOST
hudakz 0:84353c479782 318 NotifyFailGetDevDescr(rcode);
hudakz 0:84353c479782 319 #endif
hudakz 0:84353c479782 320 rcode = USB_ERROR_FailGetDevDescr;
hudakz 0:84353c479782 321
hudakz 0:84353c479782 322 Release();
hudakz 0:84353c479782 323 return rcode;
hudakz 0:84353c479782 324 };
hudakz 0:84353c479782 325
hudakz 0:84353c479782 326 /**
hudakz 0:84353c479782 327 *
hudakz 0:84353c479782 328 * @param parent (not used)
hudakz 0:84353c479782 329 * @param port (not used)
hudakz 0:84353c479782 330 * @param lowspeed true if device is low speed
hudakz 0:84353c479782 331 * @return 0 for success
hudakz 0:84353c479782 332 */
hudakz 0:84353c479782 333 uint8_t BulkOnly::Init(uint8_t parent __attribute__((unused)), uint8_t port __attribute__((unused)), bool lowspeed) {
hudakz 0:84353c479782 334 uint8_t rcode;
hudakz 0:84353c479782 335 uint8_t num_of_conf = epInfo[1].epAddr; // number of configurations
hudakz 0:84353c479782 336 epInfo[1].epAddr = 0;
hudakz 0:84353c479782 337 USBTRACE("MS Init\r\n");
hudakz 0:84353c479782 338
hudakz 0:84353c479782 339 AddressPool &addrPool = pUsb->GetAddressPool();
hudakz 0:84353c479782 340 UsbDevice *p = addrPool.GetUsbDevicePtr(bAddress);
hudakz 0:84353c479782 341
hudakz 0:84353c479782 342 if(!p)
hudakz 0:84353c479782 343 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
hudakz 0:84353c479782 344
hudakz 0:84353c479782 345 // Assign new address to the device
hudakz 0:84353c479782 346 wait_ms(2000);
hudakz 0:84353c479782 347 rcode = pUsb->setAddr(0, 0, bAddress);
hudakz 0:84353c479782 348
hudakz 0:84353c479782 349 if(rcode) {
hudakz 0:84353c479782 350 p->lowspeed = false;
hudakz 0:84353c479782 351 addrPool.FreeAddress(bAddress);
hudakz 0:84353c479782 352 bAddress = 0;
hudakz 0:84353c479782 353 USBTRACE2("setAddr:", rcode);
hudakz 0:84353c479782 354 return rcode;
hudakz 0:84353c479782 355 }
hudakz 0:84353c479782 356
hudakz 0:84353c479782 357 USBTRACE2("Addr:", bAddress);
hudakz 0:84353c479782 358
hudakz 0:84353c479782 359 p->lowspeed = false;
hudakz 0:84353c479782 360
hudakz 0:84353c479782 361 p = addrPool.GetUsbDevicePtr(bAddress);
hudakz 0:84353c479782 362
hudakz 0:84353c479782 363 if(!p)
hudakz 0:84353c479782 364 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
hudakz 0:84353c479782 365
hudakz 0:84353c479782 366 p->lowspeed = lowspeed;
hudakz 0:84353c479782 367
hudakz 0:84353c479782 368 // Assign epInfo to epinfo pointer
hudakz 0:84353c479782 369 rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
hudakz 0:84353c479782 370
hudakz 0:84353c479782 371 if(rcode)
hudakz 0:84353c479782 372 goto FailSetDevTblEntry;
hudakz 0:84353c479782 373
hudakz 0:84353c479782 374 USBTRACE2("NC:", num_of_conf);
hudakz 0:84353c479782 375
hudakz 0:84353c479782 376 for(uint8_t i = 0; i < num_of_conf; i++) {
hudakz 0:84353c479782 377 ConfigDescParser< USB_CLASS_MASS_STORAGE,
hudakz 0:84353c479782 378 MASS_SUBCLASS_SCSI,
hudakz 0:84353c479782 379 MASS_PROTO_BBB,
hudakz 0:84353c479782 380 CP_MASK_COMPARE_CLASS |
hudakz 0:84353c479782 381 CP_MASK_COMPARE_SUBCLASS |
hudakz 0:84353c479782 382 CP_MASK_COMPARE_PROTOCOL > BulkOnlyParser(this);
hudakz 0:84353c479782 383
hudakz 0:84353c479782 384 rcode = pUsb->getConfDescr(bAddress, 0, i, &BulkOnlyParser);
hudakz 0:84353c479782 385
hudakz 0:84353c479782 386 if(rcode)
hudakz 0:84353c479782 387 goto FailGetConfDescr;
hudakz 0:84353c479782 388
hudakz 0:84353c479782 389 if(bNumEP > 1)
hudakz 0:84353c479782 390 break;
hudakz 0:84353c479782 391 }
hudakz 0:84353c479782 392
hudakz 0:84353c479782 393 if(bNumEP < 3)
hudakz 0:84353c479782 394 return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
hudakz 0:84353c479782 395
hudakz 0:84353c479782 396 // Assign epInfo to epinfo pointer
hudakz 0:84353c479782 397 pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
hudakz 0:84353c479782 398
hudakz 0:84353c479782 399 USBTRACE2("Conf:", bConfNum);
hudakz 0:84353c479782 400
hudakz 0:84353c479782 401 // Set Configuration Value
hudakz 0:84353c479782 402 rcode = pUsb->setConf(bAddress, 0, bConfNum);
hudakz 0:84353c479782 403
hudakz 0:84353c479782 404 if(rcode)
hudakz 0:84353c479782 405 goto FailSetConfDescr;
hudakz 0:84353c479782 406
hudakz 0:84353c479782 407 //Linux does a 1sec delay after this.
hudakz 0:84353c479782 408 wait_ms(1000);
hudakz 0:84353c479782 409
hudakz 0:84353c479782 410 rcode = GetMaxLUN(&bMaxLUN);
hudakz 0:84353c479782 411 if(rcode)
hudakz 0:84353c479782 412 goto FailGetMaxLUN;
hudakz 0:84353c479782 413
hudakz 0:84353c479782 414 if(bMaxLUN >= MASS_MAX_SUPPORTED_LUN) bMaxLUN = MASS_MAX_SUPPORTED_LUN - 1;
hudakz 0:84353c479782 415 ErrorMessage<uint8_t > (PSTR("MaxLUN"), bMaxLUN);
hudakz 0:84353c479782 416
hudakz 0:84353c479782 417 wait_ms(1000); // Delay a bit for slow firmware.
hudakz 0:84353c479782 418
hudakz 0:84353c479782 419 for(uint8_t lun = 0; lun <= bMaxLUN; lun++) {
hudakz 0:84353c479782 420 InquiryResponse response;
hudakz 0:84353c479782 421 rcode = Inquiry(lun, sizeof (InquiryResponse), (uint8_t*) & response);
hudakz 0:84353c479782 422 if(rcode) {
hudakz 0:84353c479782 423 ErrorMessage<uint8_t > (PSTR("Inquiry"), rcode);
hudakz 0:84353c479782 424 } else {
hudakz 0:84353c479782 425 #if 0
hudakz 0:84353c479782 426 printf("LUN %i `", lun);
hudakz 0:84353c479782 427 uint8_t *buf = response.VendorID;
hudakz 0:84353c479782 428 for(int i = 0; i < 28; i++) printf("%c", buf[i]);
hudakz 0:84353c479782 429 printf("'\r\nQualifier %1.1X ", response.PeripheralQualifier);
hudakz 0:84353c479782 430 printf("Device type %2.2X ", response.DeviceType);
hudakz 0:84353c479782 431 printf("RMB %1.1X ", response.Removable);
hudakz 0:84353c479782 432 printf("SSCS %1.1X ", response.SCCS);
hudakz 0:84353c479782 433 uint8_t sv = response.Version;
hudakz 0:84353c479782 434 printf("SCSI version %2.2X\r\nDevice conforms to ", sv);
hudakz 0:84353c479782 435 switch(sv) {
hudakz 0:84353c479782 436 case 0:
hudakz 0:84353c479782 437 printf("No specific");
hudakz 0:84353c479782 438 break;
hudakz 0:84353c479782 439 case 1:
hudakz 0:84353c479782 440 printf("ANSI X3.131-1986 (ANSI 1)");
hudakz 0:84353c479782 441 break;
hudakz 0:84353c479782 442 case 2:
hudakz 0:84353c479782 443 printf("ANSI X3.131-1994 (ANSI 2)");
hudakz 0:84353c479782 444 break;
hudakz 0:84353c479782 445 case 3:
hudakz 0:84353c479782 446 printf("ANSI INCITS 301-1997 (SPC)");
hudakz 0:84353c479782 447 break;
hudakz 0:84353c479782 448 case 4:
hudakz 0:84353c479782 449 printf("ANSI INCITS 351-2001 (SPC-2)");
hudakz 0:84353c479782 450 break;
hudakz 0:84353c479782 451 case 5:
hudakz 0:84353c479782 452 printf("ANSI INCITS 408-2005 (SPC-4)");
hudakz 0:84353c479782 453 break;
hudakz 0:84353c479782 454 case 6:
hudakz 0:84353c479782 455 printf("T10/1731-D (SPC-4)");
hudakz 0:84353c479782 456 break;
hudakz 0:84353c479782 457 default:
hudakz 0:84353c479782 458 printf("unknown");
hudakz 0:84353c479782 459 }
hudakz 0:84353c479782 460 printf(" standards.\r\n");
hudakz 0:84353c479782 461 #endif
hudakz 0:84353c479782 462 uint8_t tries = 0xf0;
hudakz 0:84353c479782 463 while((rcode = TestUnitReady(lun))) {
hudakz 0:84353c479782 464 if(rcode == 0x08) break; // break on no media, this is OK to do.
hudakz 0:84353c479782 465 // try to lock media and spin up
hudakz 0:84353c479782 466 if(tries < 14) {
hudakz 0:84353c479782 467 LockMedia(lun, 1);
hudakz 0:84353c479782 468 MediaCTL(lun, 1); // I actually have a USB stick that needs this!
hudakz 0:84353c479782 469 } else wait_ms(2 * (tries + 1));
hudakz 0:84353c479782 470 tries++;
hudakz 0:84353c479782 471 if(!tries) break;
hudakz 0:84353c479782 472 }
hudakz 0:84353c479782 473 if(!rcode) {
hudakz 0:84353c479782 474 wait_ms(1000);
hudakz 0:84353c479782 475 LUNOk[lun] = CheckLUN(lun);
hudakz 0:84353c479782 476 if(!LUNOk[lun]) LUNOk[lun] = CheckLUN(lun);
hudakz 0:84353c479782 477 }
hudakz 0:84353c479782 478 }
hudakz 0:84353c479782 479 }
hudakz 0:84353c479782 480
hudakz 0:84353c479782 481
hudakz 0:84353c479782 482 CheckMedia();
hudakz 0:84353c479782 483
hudakz 0:84353c479782 484 rcode = OnInit();
hudakz 0:84353c479782 485
hudakz 0:84353c479782 486 if(rcode)
hudakz 0:84353c479782 487 goto FailOnInit;
hudakz 0:84353c479782 488
hudakz 0:84353c479782 489 #ifdef DEBUG_USB_HOST
hudakz 0:84353c479782 490 USBTRACE("MS configured\r\n\r\n");
hudakz 0:84353c479782 491 #endif
hudakz 0:84353c479782 492
hudakz 0:84353c479782 493 bPollEnable = true;
hudakz 0:84353c479782 494
hudakz 0:84353c479782 495 //USBTRACE("Poll enabled\r\n");
hudakz 0:84353c479782 496 return 0;
hudakz 0:84353c479782 497
hudakz 0:84353c479782 498 FailSetConfDescr:
hudakz 0:84353c479782 499 #ifdef DEBUG_USB_HOST
hudakz 0:84353c479782 500 NotifyFailSetConfDescr();
hudakz 0:84353c479782 501 goto Fail;
hudakz 0:84353c479782 502 #endif
hudakz 0:84353c479782 503
hudakz 0:84353c479782 504 FailOnInit:
hudakz 0:84353c479782 505 #ifdef DEBUG_USB_HOST
hudakz 0:84353c479782 506 USBTRACE("OnInit:");
hudakz 0:84353c479782 507 goto Fail;
hudakz 0:84353c479782 508 #endif
hudakz 0:84353c479782 509
hudakz 0:84353c479782 510 FailGetMaxLUN:
hudakz 0:84353c479782 511 #ifdef DEBUG_USB_HOST
hudakz 0:84353c479782 512 USBTRACE("GetMaxLUN:");
hudakz 0:84353c479782 513 goto Fail;
hudakz 0:84353c479782 514 #endif
hudakz 0:84353c479782 515
hudakz 0:84353c479782 516 //#ifdef DEBUG_USB_HOST
hudakz 0:84353c479782 517 //FailInvalidSectorSize:
hudakz 0:84353c479782 518 // USBTRACE("Sector Size is NOT VALID: ");
hudakz 0:84353c479782 519 // goto Fail;
hudakz 0:84353c479782 520 //#endif
hudakz 0:84353c479782 521
hudakz 0:84353c479782 522 FailSetDevTblEntry:
hudakz 0:84353c479782 523 #ifdef DEBUG_USB_HOST
hudakz 0:84353c479782 524 NotifyFailSetDevTblEntry();
hudakz 0:84353c479782 525 goto Fail;
hudakz 0:84353c479782 526 #endif
hudakz 0:84353c479782 527
hudakz 0:84353c479782 528 FailGetConfDescr:
hudakz 0:84353c479782 529 #ifdef DEBUG_USB_HOST
hudakz 0:84353c479782 530 NotifyFailGetConfDescr();
hudakz 0:84353c479782 531 #endif
hudakz 0:84353c479782 532
hudakz 0:84353c479782 533 #ifdef DEBUG_USB_HOST
hudakz 0:84353c479782 534 Fail:
hudakz 0:84353c479782 535 NotifyFail(rcode);
hudakz 0:84353c479782 536 #endif
hudakz 0:84353c479782 537 Release();
hudakz 0:84353c479782 538 return rcode;
hudakz 0:84353c479782 539 }
hudakz 0:84353c479782 540
hudakz 0:84353c479782 541 /**
hudakz 0:84353c479782 542 * For driver use only.
hudakz 0:84353c479782 543 *
hudakz 0:84353c479782 544 * @param conf
hudakz 0:84353c479782 545 * @param iface
hudakz 0:84353c479782 546 * @param alt
hudakz 0:84353c479782 547 * @param proto
hudakz 0:84353c479782 548 * @param pep
hudakz 0:84353c479782 549 */
hudakz 0:84353c479782 550 void BulkOnly::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto __attribute__((unused)), const USB_ENDPOINT_DESCRIPTOR * pep) {
hudakz 0:84353c479782 551 ErrorMessage<uint8_t > (PSTR("Conf.Val"), conf);
hudakz 0:84353c479782 552 ErrorMessage<uint8_t > (PSTR("Iface Num"), iface);
hudakz 0:84353c479782 553 ErrorMessage<uint8_t > (PSTR("Alt.Set"), alt);
hudakz 0:84353c479782 554
hudakz 0:84353c479782 555 bConfNum = conf;
hudakz 0:84353c479782 556
hudakz 0:84353c479782 557 uint8_t index;
hudakz 0:84353c479782 558
hudakz 0:84353c479782 559 #if 1
hudakz 0:84353c479782 560 if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK) {
hudakz 0:84353c479782 561 index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
hudakz 0:84353c479782 562 // Fill in the endpoint info structure
hudakz 0:84353c479782 563 epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
hudakz 0:84353c479782 564 epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
hudakz 0:84353c479782 565 epInfo[index].bmSndToggle = 0;
hudakz 0:84353c479782 566 epInfo[index].bmRcvToggle = 0;
hudakz 0:84353c479782 567
hudakz 0:84353c479782 568 bNumEP++;
hudakz 0:84353c479782 569
hudakz 0:84353c479782 570 PrintEndpointDescriptor(pep);
hudakz 0:84353c479782 571
hudakz 0:84353c479782 572 }
hudakz 0:84353c479782 573 #else
hudakz 0:84353c479782 574 if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT && (pep->bEndpointAddress & 0x80) == 0x80)
hudakz 0:84353c479782 575 index = epInterruptInIndex;
hudakz 0:84353c479782 576 else if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_BULK)
hudakz 0:84353c479782 577 index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex;
hudakz 0:84353c479782 578 else
hudakz 0:84353c479782 579 return;
hudakz 0:84353c479782 580
hudakz 0:84353c479782 581 // Fill in the endpoint info structure
hudakz 0:84353c479782 582 epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
hudakz 0:84353c479782 583 epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
hudakz 0:84353c479782 584 epInfo[index].bmSndToggle = 0;
hudakz 0:84353c479782 585 epInfo[index].bmRcvToggle = 0;
hudakz 0:84353c479782 586
hudakz 0:84353c479782 587 bNumEP++;
hudakz 0:84353c479782 588
hudakz 0:84353c479782 589 PrintEndpointDescriptor(pep);
hudakz 0:84353c479782 590 #endif
hudakz 0:84353c479782 591 }
hudakz 0:84353c479782 592
hudakz 0:84353c479782 593 /**
hudakz 0:84353c479782 594 * For driver use only.
hudakz 0:84353c479782 595 *
hudakz 0:84353c479782 596 * @return
hudakz 0:84353c479782 597 */
hudakz 0:84353c479782 598 uint8_t BulkOnly::Release() {
hudakz 0:84353c479782 599 ClearAllEP();
hudakz 0:84353c479782 600 pUsb->GetAddressPool().FreeAddress(bAddress);
hudakz 0:84353c479782 601 return 0;
hudakz 0:84353c479782 602 }
hudakz 0:84353c479782 603
hudakz 0:84353c479782 604 /**
hudakz 0:84353c479782 605 * For driver use only.
hudakz 0:84353c479782 606 *
hudakz 0:84353c479782 607 * @param lun Logical Unit Number
hudakz 0:84353c479782 608 * @return true if LUN is ready for use.
hudakz 0:84353c479782 609 */
hudakz 0:84353c479782 610 bool BulkOnly::CheckLUN(uint8_t lun) {
hudakz 0:84353c479782 611 uint8_t rcode;
hudakz 0:84353c479782 612 Capacity capacity;
hudakz 0:84353c479782 613 for(uint8_t i = 0; i < 8; i++) capacity.data[i] = 0;
hudakz 0:84353c479782 614
hudakz 0:84353c479782 615 rcode = ReadCapacity10(lun, (uint8_t*)capacity.data);
hudakz 0:84353c479782 616 if(rcode) {
hudakz 0:84353c479782 617 //printf(">>>>>>>>>>>>>>>>ReadCapacity returned %i\r\n", rcode);
hudakz 0:84353c479782 618 return false;
hudakz 0:84353c479782 619 }
hudakz 0:84353c479782 620 ErrorMessage<uint8_t > (PSTR(">>>>>>>>>>>>>>>>CAPACITY OK ON LUN"), lun);
hudakz 0:84353c479782 621 for(uint8_t i = 0; i < 8 /*sizeof (Capacity)*/; i++)
hudakz 0:84353c479782 622 D_PrintHex<uint8_t > (capacity.data[i], 0x80);
hudakz 0:84353c479782 623 Notify(PSTR("\r\n\r\n"), 0x80);
hudakz 0:84353c479782 624 // Only 512/1024/2048/4096 are valid values!
hudakz 0:84353c479782 625 uint32_t c = BMAKE32(capacity.data[4], capacity.data[5], capacity.data[6], capacity.data[7]);
hudakz 0:84353c479782 626 if(c != 0x0200LU && c != 0x0400LU && c != 0x0800LU && c != 0x1000LU) {
hudakz 0:84353c479782 627 return false;
hudakz 0:84353c479782 628 }
hudakz 0:84353c479782 629 // Store capacity information.
hudakz 0:84353c479782 630 CurrentSectorSize[lun] = (uint16_t)(c); // & 0xFFFF);
hudakz 0:84353c479782 631
hudakz 0:84353c479782 632 CurrentCapacity[lun] = BMAKE32(capacity.data[0], capacity.data[1], capacity.data[2], capacity.data[3]) + 1;
hudakz 0:84353c479782 633 if(CurrentCapacity[lun] == /*0xffffffffLU */ 0x01LU || CurrentCapacity[lun] == 0x00LU) {
hudakz 0:84353c479782 634 // Buggy firmware will report 0xffffffff or 0 for no media
hudakz 0:84353c479782 635 if(CurrentCapacity[lun])
hudakz 0:84353c479782 636 ErrorMessage<uint8_t > (PSTR(">>>>>>>>>>>>>>>>BUGGY FIRMWARE. CAPACITY FAIL ON LUN"), lun);
hudakz 0:84353c479782 637 return false;
hudakz 0:84353c479782 638 }
hudakz 0:84353c479782 639 wait_ms(20);
hudakz 0:84353c479782 640 Page3F(lun);
hudakz 0:84353c479782 641 if(!TestUnitReady(lun)) return true;
hudakz 0:84353c479782 642 return false;
hudakz 0:84353c479782 643 }
hudakz 0:84353c479782 644
hudakz 0:84353c479782 645 /**
hudakz 0:84353c479782 646 * For driver use only.
hudakz 0:84353c479782 647 *
hudakz 0:84353c479782 648 * Scan for media change on all LUNs
hudakz 0:84353c479782 649 */
hudakz 0:84353c479782 650 void BulkOnly::CheckMedia() {
hudakz 0:84353c479782 651 for(uint8_t lun = 0; lun <= bMaxLUN; lun++) {
hudakz 0:84353c479782 652 if(TestUnitReady(lun)) {
hudakz 0:84353c479782 653 LUNOk[lun] = false;
hudakz 0:84353c479782 654 continue;
hudakz 0:84353c479782 655 }
hudakz 0:84353c479782 656 if(!LUNOk[lun])
hudakz 0:84353c479782 657 LUNOk[lun] = CheckLUN(lun);
hudakz 0:84353c479782 658 }
hudakz 0:84353c479782 659 #if 0
hudakz 0:84353c479782 660 printf("}}}}}}}}}}}}}}}}STATUS ");
hudakz 0:84353c479782 661 for(uint8_t lun = 0; lun <= bMaxLUN; lun++) {
hudakz 0:84353c479782 662 if(LUNOk[lun])
hudakz 0:84353c479782 663 printf("#");
hudakz 0:84353c479782 664 else printf(".");
hudakz 0:84353c479782 665 }
hudakz 0:84353c479782 666 printf("\r\n");
hudakz 0:84353c479782 667 #endif
hudakz 0:84353c479782 668 qNextPollTime = (uint32_t)millis() + 2000;
hudakz 0:84353c479782 669 }
hudakz 0:84353c479782 670
hudakz 0:84353c479782 671 /**
hudakz 0:84353c479782 672 * For driver use only.
hudakz 0:84353c479782 673 *
hudakz 0:84353c479782 674 * @return
hudakz 0:84353c479782 675 */
hudakz 0:84353c479782 676 uint8_t BulkOnly::Poll() {
hudakz 0:84353c479782 677 //uint8_t rcode = 0;
hudakz 0:84353c479782 678
hudakz 0:84353c479782 679 if(!bPollEnable)
hudakz 0:84353c479782 680 return 0;
hudakz 0:84353c479782 681
hudakz 0:84353c479782 682 if((int32_t)((uint32_t)millis() - qNextPollTime) >= 0L) {
hudakz 0:84353c479782 683 CheckMedia();
hudakz 0:84353c479782 684 }
hudakz 0:84353c479782 685 //rcode = 0;
hudakz 0:84353c479782 686
hudakz 0:84353c479782 687 return 0;
hudakz 0:84353c479782 688 }
hudakz 0:84353c479782 689
hudakz 0:84353c479782 690 ////////////////////////////////////////////////////////////////////////////////
hudakz 0:84353c479782 691
hudakz 0:84353c479782 692
hudakz 0:84353c479782 693 // SCSI code
hudakz 0:84353c479782 694
hudakz 0:84353c479782 695
hudakz 0:84353c479782 696 ////////////////////////////////////////////////////////////////////////////////
hudakz 0:84353c479782 697
hudakz 0:84353c479782 698 /**
hudakz 0:84353c479782 699 * For driver use only.
hudakz 0:84353c479782 700 *
hudakz 0:84353c479782 701 * @param plun
hudakz 0:84353c479782 702 * @return
hudakz 0:84353c479782 703 */
hudakz 0:84353c479782 704 uint8_t BulkOnly::GetMaxLUN(uint8_t *plun) {
hudakz 0:84353c479782 705 uint8_t ret = pUsb->ctrlReq(bAddress, 0, bmREQ_MASSIN, MASS_REQ_GET_MAX_LUN, 0, 0, bIface, 1, 1, plun, NULL);
hudakz 0:84353c479782 706
hudakz 0:84353c479782 707 if(ret == hrSTALL)
hudakz 0:84353c479782 708 *plun = 0;
hudakz 0:84353c479782 709
hudakz 0:84353c479782 710 return 0;
hudakz 0:84353c479782 711 }
hudakz 0:84353c479782 712
hudakz 0:84353c479782 713 /**
hudakz 0:84353c479782 714 * For driver use only. Used during Driver Init
hudakz 0:84353c479782 715 *
hudakz 0:84353c479782 716 * @param lun Logical Unit Number
hudakz 0:84353c479782 717 * @param bsize
hudakz 0:84353c479782 718 * @param buf
hudakz 0:84353c479782 719 * @return
hudakz 0:84353c479782 720 */
hudakz 0:84353c479782 721 uint8_t BulkOnly::Inquiry(uint8_t lun, uint16_t bsize, uint8_t *buf) {
hudakz 0:84353c479782 722 Notify(PSTR("\r\nInquiry\r\n"), 0x80);
hudakz 0:84353c479782 723 Notify(PSTR("---------\r\n"), 0x80);
hudakz 0:84353c479782 724
hudakz 0:84353c479782 725 CDB6_t cdb = CDB6_t(SCSI_CMD_INQUIRY, lun, 0LU, (uint8_t)bsize, 0);
hudakz 0:84353c479782 726 uint8_t rc = SCSITransaction6(&cdb, bsize, buf, (uint8_t)MASS_CMD_DIR_IN);
hudakz 0:84353c479782 727
hudakz 0:84353c479782 728 return rc;
hudakz 0:84353c479782 729 }
hudakz 0:84353c479782 730
hudakz 0:84353c479782 731 /**
hudakz 0:84353c479782 732 * For driver use only.
hudakz 0:84353c479782 733 *
hudakz 0:84353c479782 734 * @param lun Logical Unit Number
hudakz 0:84353c479782 735 * @return
hudakz 0:84353c479782 736 */
hudakz 0:84353c479782 737 uint8_t BulkOnly::TestUnitReady(uint8_t lun) {
hudakz 0:84353c479782 738 //SetCurLUN(lun);
hudakz 0:84353c479782 739 if(!bAddress)
hudakz 0:84353c479782 740 return MASS_ERR_UNIT_NOT_READY;
hudakz 0:84353c479782 741
hudakz 0:84353c479782 742 Notify(PSTR("\r\nTestUnitReady\r\n"), 0x80);
hudakz 0:84353c479782 743 Notify(PSTR("-----------------\r\n"), 0x80);
hudakz 0:84353c479782 744
hudakz 0:84353c479782 745 CDB6_t cdb = CDB6_t(SCSI_CMD_TEST_UNIT_READY, lun, (uint8_t)0, 0);
hudakz 0:84353c479782 746 return SCSITransaction6(&cdb, 0, NULL, (uint8_t)MASS_CMD_DIR_IN);
hudakz 0:84353c479782 747
hudakz 0:84353c479782 748 }
hudakz 0:84353c479782 749
hudakz 0:84353c479782 750 /**
hudakz 0:84353c479782 751 * For driver use only.
hudakz 0:84353c479782 752 *
hudakz 0:84353c479782 753 * @param lun Logical Unit Number
hudakz 0:84353c479782 754 * @param pc
hudakz 0:84353c479782 755 * @param page
hudakz 0:84353c479782 756 * @param subpage
hudakz 0:84353c479782 757 * @param len
hudakz 0:84353c479782 758 * @param pbuf
hudakz 0:84353c479782 759 * @return
hudakz 0:84353c479782 760 */
hudakz 0:84353c479782 761 uint8_t BulkOnly::ModeSense6(uint8_t lun, uint8_t pc, uint8_t page, uint8_t subpage, uint8_t len, uint8_t * pbuf) {
hudakz 0:84353c479782 762 Notify(PSTR("\r\rModeSense\r\n"), 0x80);
hudakz 0:84353c479782 763 Notify(PSTR("------------\r\n"), 0x80);
hudakz 0:84353c479782 764
hudakz 0:84353c479782 765 CDB6_t cdb = CDB6_t(SCSI_CMD_MODE_SENSE_6, lun, (uint32_t)((((pc << 6) | page) << 8) | subpage), len, 0);
hudakz 0:84353c479782 766 return SCSITransaction6(&cdb, len, pbuf, (uint8_t)MASS_CMD_DIR_IN);
hudakz 0:84353c479782 767 }
hudakz 0:84353c479782 768
hudakz 0:84353c479782 769 /**
hudakz 0:84353c479782 770 * For driver use only.
hudakz 0:84353c479782 771 *
hudakz 0:84353c479782 772 * @param lun Logical Unit Number
hudakz 0:84353c479782 773 * @param bsize
hudakz 0:84353c479782 774 * @param buf
hudakz 0:84353c479782 775 * @return
hudakz 0:84353c479782 776 */
hudakz 0:84353c479782 777 uint8_t BulkOnly::ReadCapacity10(uint8_t lun, uint8_t *buf) {
hudakz 0:84353c479782 778 Notify(PSTR("\r\nReadCapacity\r\n"), 0x80);
hudakz 0:84353c479782 779 Notify(PSTR("---------------\r\n"), 0x80);
hudakz 0:84353c479782 780
hudakz 0:84353c479782 781 CDB10_t cdb = CDB10_t(SCSI_CMD_READ_CAPACITY_10, lun);
hudakz 0:84353c479782 782 return SCSITransaction10(&cdb, 8, buf, (uint8_t)MASS_CMD_DIR_IN);
hudakz 0:84353c479782 783 }
hudakz 0:84353c479782 784
hudakz 0:84353c479782 785 /**
hudakz 0:84353c479782 786 * For driver use only.
hudakz 0:84353c479782 787 *
hudakz 0:84353c479782 788 * Page 3F contains write protect status.
hudakz 0:84353c479782 789 *
hudakz 0:84353c479782 790 * @param lun Logical Unit Number to test.
hudakz 0:84353c479782 791 * @return Write protect switch status.
hudakz 0:84353c479782 792 */
hudakz 0:84353c479782 793 uint8_t BulkOnly::Page3F(uint8_t lun) {
hudakz 0:84353c479782 794 uint8_t buf[192];
hudakz 0:84353c479782 795 for(int i = 0; i < 192; i++) {
hudakz 0:84353c479782 796 buf[i] = 0x00;
hudakz 0:84353c479782 797 }
hudakz 0:84353c479782 798 WriteOk[lun] = true;
hudakz 0:84353c479782 799 uint8_t rc = ModeSense6(lun, 0, 0x3f, 0, 192, buf);
hudakz 0:84353c479782 800 if(!rc) {
hudakz 0:84353c479782 801 WriteOk[lun] = ((buf[2] & 0x80) == 0);
hudakz 0:84353c479782 802 Notify(PSTR("Mode Sense: "), 0x80);
hudakz 0:84353c479782 803 for(int i = 0; i < 4; i++) {
hudakz 0:84353c479782 804 D_PrintHex<uint8_t > (buf[i], 0x80);
hudakz 0:84353c479782 805 Notify(PSTR(" "), 0x80);
hudakz 0:84353c479782 806 }
hudakz 0:84353c479782 807 Notify(PSTR("\r\n"), 0x80);
hudakz 0:84353c479782 808 }
hudakz 0:84353c479782 809 return rc;
hudakz 0:84353c479782 810 }
hudakz 0:84353c479782 811
hudakz 0:84353c479782 812 /**
hudakz 0:84353c479782 813 * For driver use only.
hudakz 0:84353c479782 814 *
hudakz 0:84353c479782 815 * @param lun Logical Unit Number
hudakz 0:84353c479782 816 * @param size
hudakz 0:84353c479782 817 * @param buf
hudakz 0:84353c479782 818 * @return
hudakz 0:84353c479782 819 */
hudakz 0:84353c479782 820 uint8_t BulkOnly::RequestSense(uint8_t lun, uint16_t size, uint8_t *buf) {
hudakz 0:84353c479782 821 Notify(PSTR("\r\nRequestSense\r\n"), 0x80);
hudakz 0:84353c479782 822 Notify(PSTR("----------------\r\n"), 0x80);
hudakz 0:84353c479782 823
hudakz 0:84353c479782 824 CDB6_t cdb = CDB6_t(SCSI_CMD_REQUEST_SENSE, lun, 0LU, (uint8_t)size, 0);
hudakz 0:84353c479782 825 CommandBlockWrapper cbw = CommandBlockWrapper(++dCBWTag, (uint32_t)size, &cdb, (uint8_t)MASS_CMD_DIR_IN);
hudakz 0:84353c479782 826 //SetCurLUN(lun);
hudakz 0:84353c479782 827 return Transaction(&cbw, size, buf);
hudakz 0:84353c479782 828 }
hudakz 0:84353c479782 829
hudakz 0:84353c479782 830
hudakz 0:84353c479782 831 ////////////////////////////////////////////////////////////////////////////////
hudakz 0:84353c479782 832
hudakz 0:84353c479782 833
hudakz 0:84353c479782 834 // USB code
hudakz 0:84353c479782 835
hudakz 0:84353c479782 836
hudakz 0:84353c479782 837 ////////////////////////////////////////////////////////////////////////////////
hudakz 0:84353c479782 838
hudakz 0:84353c479782 839 /**
hudakz 0:84353c479782 840 * For driver use only.
hudakz 0:84353c479782 841 *
hudakz 0:84353c479782 842 * @param index
hudakz 0:84353c479782 843 * @return
hudakz 0:84353c479782 844 */
hudakz 0:84353c479782 845 uint8_t BulkOnly::ClearEpHalt(uint8_t index) {
hudakz 0:84353c479782 846 if(index == 0)
hudakz 0:84353c479782 847 return 0;
hudakz 0:84353c479782 848
hudakz 0:84353c479782 849 uint8_t ret = 0;
hudakz 0:84353c479782 850
hudakz 0:84353c479782 851 while((ret = (pUsb->ctrlReq(bAddress, 0, USB_SETUP_HOST_TO_DEVICE | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_ENDPOINT, USB_REQUEST_CLEAR_FEATURE, USB_FEATURE_ENDPOINT_HALT, 0, ((index == epDataInIndex) ? (0x80 | epInfo[index].epAddr) : epInfo[index].epAddr), 0, 0, NULL, NULL)) == 0x01))
hudakz 0:84353c479782 852 wait_ms(6);
hudakz 0:84353c479782 853
hudakz 0:84353c479782 854 if(ret) {
hudakz 0:84353c479782 855 ErrorMessage<uint8_t > (PSTR("ClearEpHalt"), ret);
hudakz 0:84353c479782 856 ErrorMessage<uint8_t > (PSTR("EP"), ((index == epDataInIndex) ? (0x80 | epInfo[index].epAddr) : epInfo[index].epAddr));
hudakz 0:84353c479782 857 return ret;
hudakz 0:84353c479782 858 }
hudakz 0:84353c479782 859 epInfo[index].bmSndToggle = 0;
hudakz 0:84353c479782 860 epInfo[index].bmRcvToggle = 0;
hudakz 0:84353c479782 861 return 0;
hudakz 0:84353c479782 862 }
hudakz 0:84353c479782 863
hudakz 0:84353c479782 864 /**
hudakz 0:84353c479782 865 * For driver use only.
hudakz 0:84353c479782 866 *
hudakz 0:84353c479782 867 */
hudakz 0:84353c479782 868 void BulkOnly::Reset() {
hudakz 0:84353c479782 869 while(pUsb->ctrlReq(bAddress, 0, bmREQ_MASSOUT, MASS_REQ_BOMSR, 0, 0, bIface, 0, 0, NULL, NULL) == 0x01) wait_ms(6);
hudakz 0:84353c479782 870 }
hudakz 0:84353c479782 871
hudakz 0:84353c479782 872 /**
hudakz 0:84353c479782 873 * For driver use only.
hudakz 0:84353c479782 874 *
hudakz 0:84353c479782 875 * @return 0 if successful
hudakz 0:84353c479782 876 */
hudakz 0:84353c479782 877 uint8_t BulkOnly::ResetRecovery() {
hudakz 0:84353c479782 878 Notify(PSTR("\r\nResetRecovery\r\n"), 0x80);
hudakz 0:84353c479782 879 Notify(PSTR("-----------------\r\n"), 0x80);
hudakz 0:84353c479782 880
hudakz 0:84353c479782 881 wait_ms(6);
hudakz 0:84353c479782 882 Reset();
hudakz 0:84353c479782 883 wait_ms(6);
hudakz 0:84353c479782 884 ClearEpHalt(epDataInIndex);
hudakz 0:84353c479782 885 wait_ms(6);
hudakz 0:84353c479782 886 bLastUsbError = ClearEpHalt(epDataOutIndex);
hudakz 0:84353c479782 887 wait_ms(6);
hudakz 0:84353c479782 888 return bLastUsbError;
hudakz 0:84353c479782 889 }
hudakz 0:84353c479782 890
hudakz 0:84353c479782 891 /**
hudakz 0:84353c479782 892 * For driver use only.
hudakz 0:84353c479782 893 *
hudakz 0:84353c479782 894 * Clear all EP data and clear all LUN status
hudakz 0:84353c479782 895 */
hudakz 0:84353c479782 896 void BulkOnly::ClearAllEP() {
hudakz 0:84353c479782 897 for(uint8_t i = 0; i < MASS_MAX_ENDPOINTS; i++) {
hudakz 0:84353c479782 898 epInfo[i].epAddr = 0;
hudakz 0:84353c479782 899 epInfo[i].maxPktSize = (i) ? 0 : 8;
hudakz 0:84353c479782 900 epInfo[i].bmSndToggle = 0;
hudakz 0:84353c479782 901 epInfo[i].bmRcvToggle = 0;
hudakz 0:84353c479782 902 epInfo[i].bmNakPower = USB_NAK_DEFAULT;
hudakz 0:84353c479782 903 }
hudakz 0:84353c479782 904
hudakz 0:84353c479782 905 for(uint8_t i = 0; i < MASS_MAX_SUPPORTED_LUN; i++) {
hudakz 0:84353c479782 906 LUNOk[i] = false;
hudakz 0:84353c479782 907 WriteOk[i] = false;
hudakz 0:84353c479782 908 CurrentCapacity[i] = 0lu;
hudakz 0:84353c479782 909 CurrentSectorSize[i] = 0;
hudakz 0:84353c479782 910 }
hudakz 0:84353c479782 911
hudakz 0:84353c479782 912 bIface = 0;
hudakz 0:84353c479782 913 bNumEP = 1;
hudakz 0:84353c479782 914 bAddress = 0;
hudakz 0:84353c479782 915 qNextPollTime = 0;
hudakz 0:84353c479782 916 bPollEnable = false;
hudakz 0:84353c479782 917 bLastUsbError = 0;
hudakz 0:84353c479782 918 bMaxLUN = 0;
hudakz 0:84353c479782 919 bTheLUN = 0;
hudakz 0:84353c479782 920 }
hudakz 0:84353c479782 921
hudakz 0:84353c479782 922 /**
hudakz 0:84353c479782 923 * For driver use only.
hudakz 0:84353c479782 924 *
hudakz 0:84353c479782 925 * @param pcsw
hudakz 0:84353c479782 926 * @param pcbw
hudakz 0:84353c479782 927 * @return
hudakz 0:84353c479782 928 */
hudakz 0:84353c479782 929 bool BulkOnly::IsValidCSW(CommandStatusWrapper *pcsw, CommandBlockWrapperBase *pcbw) {
hudakz 0:84353c479782 930 if(pcsw->dCSWSignature != MASS_CSW_SIGNATURE) {
hudakz 0:84353c479782 931 Notify(PSTR("CSW:Sig error\r\n"), 0x80);
hudakz 0:84353c479782 932 return false;
hudakz 0:84353c479782 933 }
hudakz 0:84353c479782 934 if(pcsw->dCSWTag != pcbw->dCBWTag) {
hudakz 0:84353c479782 935 Notify(PSTR("CSW:Wrong tag\r\n"), 0x80);
hudakz 0:84353c479782 936 return false;
hudakz 0:84353c479782 937 }
hudakz 0:84353c479782 938 return true;
hudakz 0:84353c479782 939 }
hudakz 0:84353c479782 940
hudakz 0:84353c479782 941 /**
hudakz 0:84353c479782 942 * For driver use only.
hudakz 0:84353c479782 943 *
hudakz 0:84353c479782 944 * @param error
hudakz 0:84353c479782 945 * @param index
hudakz 0:84353c479782 946 * @return
hudakz 0:84353c479782 947 */
hudakz 0:84353c479782 948 uint8_t BulkOnly::HandleUsbError(uint8_t error, uint8_t index) {
hudakz 0:84353c479782 949 uint8_t count = 3;
hudakz 0:84353c479782 950
hudakz 0:84353c479782 951 bLastUsbError = error;
hudakz 0:84353c479782 952 //if (error)
hudakz 0:84353c479782 953 //ClearEpHalt(index);
hudakz 0:84353c479782 954 while(error && count) {
hudakz 0:84353c479782 955 if(error != hrSUCCESS) {
hudakz 0:84353c479782 956 ErrorMessage<uint8_t > (PSTR("USB Error"), error);
hudakz 0:84353c479782 957 ErrorMessage<uint8_t > (PSTR("Index"), index);
hudakz 0:84353c479782 958 }
hudakz 0:84353c479782 959 switch(error) {
hudakz 0:84353c479782 960 // case hrWRONGPID:
hudakz 0:84353c479782 961 case hrSUCCESS:
hudakz 0:84353c479782 962 return MASS_ERR_SUCCESS;
hudakz 0:84353c479782 963 case hrBUSY:
hudakz 0:84353c479782 964 // SIE is busy, just hang out and try again.
hudakz 0:84353c479782 965 return MASS_ERR_UNIT_BUSY;
hudakz 0:84353c479782 966 case hrTIMEOUT:
hudakz 0:84353c479782 967 case hrJERR: return MASS_ERR_DEVICE_DISCONNECTED;
hudakz 0:84353c479782 968 case hrSTALL:
hudakz 0:84353c479782 969 if(index == 0)
hudakz 0:84353c479782 970 return MASS_ERR_STALL;
hudakz 0:84353c479782 971 ClearEpHalt(index);
hudakz 0:84353c479782 972 if(index != epDataInIndex)
hudakz 0:84353c479782 973 return MASS_ERR_WRITE_STALL;
hudakz 0:84353c479782 974 return MASS_ERR_STALL;
hudakz 0:84353c479782 975
hudakz 0:84353c479782 976 case hrNAK:
hudakz 0:84353c479782 977 if(index == 0)
hudakz 0:84353c479782 978 return MASS_ERR_UNIT_BUSY;
hudakz 0:84353c479782 979 return MASS_ERR_UNIT_BUSY;
hudakz 0:84353c479782 980
hudakz 0:84353c479782 981 case hrTOGERR:
hudakz 0:84353c479782 982 // Handle a very super rare corner case, where toggles become de-synched.
hudakz 0:84353c479782 983 // I have only ran into one device that has this firmware bug, and this is
hudakz 0:84353c479782 984 // the only clean way to get back into sync with the buggy device firmware.
hudakz 0:84353c479782 985 // --AJK
hudakz 0:84353c479782 986 if(bAddress && bConfNum) {
hudakz 0:84353c479782 987 error = pUsb->setConf(bAddress, 0, bConfNum);
hudakz 0:84353c479782 988
hudakz 0:84353c479782 989 if(error)
hudakz 0:84353c479782 990 break;
hudakz 0:84353c479782 991 }
hudakz 0:84353c479782 992 return MASS_ERR_SUCCESS;
hudakz 0:84353c479782 993 default:
hudakz 0:84353c479782 994 ErrorMessage<uint8_t > (PSTR("\r\nUSB"), error);
hudakz 0:84353c479782 995 return MASS_ERR_GENERAL_USB_ERROR;
hudakz 0:84353c479782 996 }
hudakz 0:84353c479782 997 count--;
hudakz 0:84353c479782 998 } // while
hudakz 0:84353c479782 999
hudakz 0:84353c479782 1000 return ((error && !count) ? MASS_ERR_GENERAL_USB_ERROR : MASS_ERR_SUCCESS);
hudakz 0:84353c479782 1001 }
hudakz 0:84353c479782 1002
hudakz 0:84353c479782 1003 #if MS_WANT_PARSER
hudakz 0:84353c479782 1004
hudakz 0:84353c479782 1005 uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf) {
hudakz 0:84353c479782 1006 return Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf, 0);
hudakz 0:84353c479782 1007 }
hudakz 0:84353c479782 1008 #endif
hudakz 0:84353c479782 1009
hudakz 0:84353c479782 1010 /**
hudakz 0:84353c479782 1011 * For driver use only.
hudakz 0:84353c479782 1012 *
hudakz 0:84353c479782 1013 * @param pcbw
hudakz 0:84353c479782 1014 * @param buf_size
hudakz 0:84353c479782 1015 * @param buf
hudakz 0:84353c479782 1016 * @param flags
hudakz 0:84353c479782 1017 * @return
hudakz 0:84353c479782 1018 */
hudakz 0:84353c479782 1019 uint8_t BulkOnly::Transaction(CommandBlockWrapper *pcbw, uint16_t buf_size, void *buf
hudakz 0:84353c479782 1020 #if MS_WANT_PARSER
hudakz 0:84353c479782 1021 , uint8_t flags
hudakz 0:84353c479782 1022 #endif
hudakz 0:84353c479782 1023 ) {
hudakz 0:84353c479782 1024
hudakz 0:84353c479782 1025 #if MS_WANT_PARSER
hudakz 0:84353c479782 1026 uint16_t bytes = (pcbw->dCBWDataTransferLength > buf_size) ? buf_size : pcbw->dCBWDataTransferLength;
hudakz 0:84353c479782 1027 printf("Transfersize %i\r\n", bytes);
hudakz 0:84353c479782 1028 wait_ms(1000);
hudakz 0:84353c479782 1029
hudakz 0:84353c479782 1030 bool callback = (flags & MASS_TRANS_FLG_CALLBACK) == MASS_TRANS_FLG_CALLBACK;
hudakz 0:84353c479782 1031 #else
hudakz 0:84353c479782 1032 uint16_t bytes = buf_size;
hudakz 0:84353c479782 1033 #endif
hudakz 0:84353c479782 1034 bool write = (pcbw->bmCBWFlags & MASS_CMD_DIR_IN) != MASS_CMD_DIR_IN;
hudakz 0:84353c479782 1035 uint8_t ret = 0;
hudakz 0:84353c479782 1036 uint8_t usberr;
hudakz 0:84353c479782 1037 CommandStatusWrapper csw; // up here, we allocate ahead to save cpu cycles.
hudakz 0:84353c479782 1038 SetCurLUN(pcbw->bmCBWLUN);
hudakz 0:84353c479782 1039 ErrorMessage<uint32_t > (PSTR("CBW.dCBWTag"), pcbw->dCBWTag);
hudakz 0:84353c479782 1040
hudakz 0:84353c479782 1041 while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw)) == hrBUSY) wait_ms(1);
hudakz 0:84353c479782 1042
hudakz 0:84353c479782 1043 ret = HandleUsbError(usberr, epDataOutIndex);
hudakz 0:84353c479782 1044 //ret = HandleUsbError(pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw), epDataOutIndex);
hudakz 0:84353c479782 1045 if(ret) {
hudakz 0:84353c479782 1046 ErrorMessage<uint8_t > (PSTR("============================ CBW"), ret);
hudakz 0:84353c479782 1047 } else {
hudakz 0:84353c479782 1048 if(bytes) {
hudakz 0:84353c479782 1049 if(!write) {
hudakz 0:84353c479782 1050 #if MS_WANT_PARSER
hudakz 0:84353c479782 1051 if(callback) {
hudakz 0:84353c479782 1052 uint8_t rbuf[bytes];
hudakz 0:84353c479782 1053 while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, rbuf)) == hrBUSY) wait_ms(1);
hudakz 0:84353c479782 1054 if(usberr == hrSUCCESS) ((USBReadParser*)buf)->Parse(bytes, rbuf, 0);
hudakz 0:84353c479782 1055 } else {
hudakz 0:84353c479782 1056 #endif
hudakz 0:84353c479782 1057 while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*)buf)) == hrBUSY) wait_ms(1);
hudakz 0:84353c479782 1058 #if MS_WANT_PARSER
hudakz 0:84353c479782 1059
hudakz 0:84353c479782 1060 }
hudakz 0:84353c479782 1061 #endif
hudakz 0:84353c479782 1062 ret = HandleUsbError(usberr, epDataInIndex);
hudakz 0:84353c479782 1063 } else {
hudakz 0:84353c479782 1064 while((usberr = pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, bytes, (uint8_t*)buf)) == hrBUSY) wait_ms(1);
hudakz 0:84353c479782 1065 ret = HandleUsbError(usberr, epDataOutIndex);
hudakz 0:84353c479782 1066 }
hudakz 0:84353c479782 1067 if(ret) {
hudakz 0:84353c479782 1068 ErrorMessage<uint8_t > (PSTR("============================ DAT"), ret);
hudakz 0:84353c479782 1069 }
hudakz 0:84353c479782 1070 }
hudakz 0:84353c479782 1071 }
hudakz 0:84353c479782 1072
hudakz 0:84353c479782 1073 {
hudakz 0:84353c479782 1074 bytes = sizeof (CommandStatusWrapper);
hudakz 0:84353c479782 1075 int tries = 2;
hudakz 0:84353c479782 1076 while(tries--) {
hudakz 0:84353c479782 1077 while((usberr = pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, &bytes, (uint8_t*) & csw)) == hrBUSY) wait_ms(1);
hudakz 0:84353c479782 1078 if(!usberr) break;
hudakz 0:84353c479782 1079 ClearEpHalt(epDataInIndex);
hudakz 0:84353c479782 1080 if(tries) ResetRecovery();
hudakz 0:84353c479782 1081 }
hudakz 0:84353c479782 1082 if(!ret) {
hudakz 0:84353c479782 1083 Notify(PSTR("CBW:\t\tOK\r\n"), 0x80);
hudakz 0:84353c479782 1084 Notify(PSTR("Data Stage:\tOK\r\n"), 0x80);
hudakz 0:84353c479782 1085 } else {
hudakz 0:84353c479782 1086 // Throw away csw, IT IS NOT OF ANY USE.
hudakz 0:84353c479782 1087 ResetRecovery();
hudakz 0:84353c479782 1088 return ret;
hudakz 0:84353c479782 1089 }
hudakz 0:84353c479782 1090 ret = HandleUsbError(usberr, epDataInIndex);
hudakz 0:84353c479782 1091 if(ret) {
hudakz 0:84353c479782 1092 ErrorMessage<uint8_t > (PSTR("============================ CSW"), ret);
hudakz 0:84353c479782 1093 }
hudakz 0:84353c479782 1094 if(usberr == hrSUCCESS) {
hudakz 0:84353c479782 1095 if(IsValidCSW(&csw, pcbw)) {
hudakz 0:84353c479782 1096 //ErrorMessage<uint32_t > (PSTR("CSW.dCBWTag"), csw.dCSWTag);
hudakz 0:84353c479782 1097 //ErrorMessage<uint8_t > (PSTR("bCSWStatus"), csw.bCSWStatus);
hudakz 0:84353c479782 1098 //ErrorMessage<uint32_t > (PSTR("dCSWDataResidue"), csw.dCSWDataResidue);
hudakz 0:84353c479782 1099 Notify(PSTR("CSW:\t\tOK\r\n\r\n"), 0x80);
hudakz 0:84353c479782 1100 return csw.bCSWStatus;
hudakz 0:84353c479782 1101 } else {
hudakz 0:84353c479782 1102 // NOTE! Sometimes this is caused by the reported residue being wrong.
hudakz 0:84353c479782 1103 // Get a different device. It isn't compliant, and should have never passed Q&A.
hudakz 0:84353c479782 1104 // I own one... 05e3:0701 Genesys Logic, Inc. USB 2.0 IDE Adapter.
hudakz 0:84353c479782 1105 // Other devices that exhibit this behavior exist in the wild too.
hudakz 0:84353c479782 1106 // Be sure to check quirks in the Linux source code before reporting a bug. --xxxajk
hudakz 0:84353c479782 1107 Notify(PSTR("Invalid CSW\r\n"), 0x80);
hudakz 0:84353c479782 1108 ResetRecovery();
hudakz 0:84353c479782 1109 //return MASS_ERR_SUCCESS;
hudakz 0:84353c479782 1110 return MASS_ERR_INVALID_CSW;
hudakz 0:84353c479782 1111 }
hudakz 0:84353c479782 1112 }
hudakz 0:84353c479782 1113 }
hudakz 0:84353c479782 1114 return ret;
hudakz 0:84353c479782 1115 }
hudakz 0:84353c479782 1116
hudakz 0:84353c479782 1117 /**
hudakz 0:84353c479782 1118 * For driver use only.
hudakz 0:84353c479782 1119 *
hudakz 0:84353c479782 1120 * @param lun Logical Unit Number
hudakz 0:84353c479782 1121 * @return
hudakz 0:84353c479782 1122 */
hudakz 0:84353c479782 1123 uint8_t BulkOnly::SetCurLUN(uint8_t lun) {
hudakz 0:84353c479782 1124 if(lun > bMaxLUN)
hudakz 0:84353c479782 1125 return MASS_ERR_INVALID_LUN;
hudakz 0:84353c479782 1126 bTheLUN = lun;
hudakz 0:84353c479782 1127 return MASS_ERR_SUCCESS;
hudakz 0:84353c479782 1128 };
hudakz 0:84353c479782 1129
hudakz 0:84353c479782 1130 /**
hudakz 0:84353c479782 1131 * For driver use only.
hudakz 0:84353c479782 1132 *
hudakz 0:84353c479782 1133 * @param status
hudakz 0:84353c479782 1134 * @return
hudakz 0:84353c479782 1135 */
hudakz 0:84353c479782 1136 uint8_t BulkOnly::HandleSCSIError(uint8_t status) {
hudakz 0:84353c479782 1137 uint8_t ret = 0;
hudakz 0:84353c479782 1138
hudakz 0:84353c479782 1139 switch(status) {
hudakz 0:84353c479782 1140 case 0: return MASS_ERR_SUCCESS;
hudakz 0:84353c479782 1141
hudakz 0:84353c479782 1142 case 2:
hudakz 0:84353c479782 1143 ErrorMessage<uint8_t > (PSTR("Phase Error"), status);
hudakz 0:84353c479782 1144 ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN);
hudakz 0:84353c479782 1145 ResetRecovery();
hudakz 0:84353c479782 1146 return MASS_ERR_GENERAL_SCSI_ERROR;
hudakz 0:84353c479782 1147
hudakz 0:84353c479782 1148 case 1:
hudakz 0:84353c479782 1149 ErrorMessage<uint8_t > (PSTR("SCSI Error"), status);
hudakz 0:84353c479782 1150 ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN);
hudakz 0:84353c479782 1151 RequestSenseResponce rsp;
hudakz 0:84353c479782 1152
hudakz 0:84353c479782 1153 ret = RequestSense(bTheLUN, sizeof (RequestSenseResponce), (uint8_t*) & rsp);
hudakz 0:84353c479782 1154
hudakz 0:84353c479782 1155 if(ret) {
hudakz 0:84353c479782 1156 return MASS_ERR_GENERAL_SCSI_ERROR;
hudakz 0:84353c479782 1157 }
hudakz 0:84353c479782 1158 ErrorMessage<uint8_t > (PSTR("Response Code"), rsp.bResponseCode);
hudakz 0:84353c479782 1159 if(rsp.bResponseCode & 0x80) {
hudakz 0:84353c479782 1160 Notify(PSTR("Information field: "), 0x80);
hudakz 0:84353c479782 1161 for(int i = 0; i < 4; i++) {
hudakz 0:84353c479782 1162 D_PrintHex<uint8_t > (rsp.CmdSpecificInformation[i], 0x80);
hudakz 0:84353c479782 1163 Notify(PSTR(" "), 0x80);
hudakz 0:84353c479782 1164 }
hudakz 0:84353c479782 1165 Notify(PSTR("\r\n"), 0x80);
hudakz 0:84353c479782 1166 }
hudakz 0:84353c479782 1167 ErrorMessage<uint8_t > (PSTR("Sense Key"), rsp.bmSenseKey);
hudakz 0:84353c479782 1168 ErrorMessage<uint8_t > (PSTR("Add Sense Code"), rsp.bAdditionalSenseCode);
hudakz 0:84353c479782 1169 ErrorMessage<uint8_t > (PSTR("Add Sense Qual"), rsp.bAdditionalSenseQualifier);
hudakz 0:84353c479782 1170 // warning, this is not testing ASQ, only SK and ASC.
hudakz 0:84353c479782 1171 switch(rsp.bmSenseKey) {
hudakz 0:84353c479782 1172 case SCSI_S_UNIT_ATTENTION:
hudakz 0:84353c479782 1173 switch(rsp.bAdditionalSenseCode) {
hudakz 0:84353c479782 1174 case SCSI_ASC_MEDIA_CHANGED:
hudakz 0:84353c479782 1175 return MASS_ERR_MEDIA_CHANGED;
hudakz 0:84353c479782 1176 default:
hudakz 0:84353c479782 1177 return MASS_ERR_UNIT_NOT_READY;
hudakz 0:84353c479782 1178 }
hudakz 0:84353c479782 1179 case SCSI_S_NOT_READY:
hudakz 0:84353c479782 1180 switch(rsp.bAdditionalSenseCode) {
hudakz 0:84353c479782 1181 case SCSI_ASC_MEDIUM_NOT_PRESENT:
hudakz 0:84353c479782 1182 return MASS_ERR_NO_MEDIA;
hudakz 0:84353c479782 1183 default:
hudakz 0:84353c479782 1184 return MASS_ERR_UNIT_NOT_READY;
hudakz 0:84353c479782 1185 }
hudakz 0:84353c479782 1186 case SCSI_S_ILLEGAL_REQUEST:
hudakz 0:84353c479782 1187 switch(rsp.bAdditionalSenseCode) {
hudakz 0:84353c479782 1188 case SCSI_ASC_LBA_OUT_OF_RANGE:
hudakz 0:84353c479782 1189 return MASS_ERR_BAD_LBA;
hudakz 0:84353c479782 1190 default:
hudakz 0:84353c479782 1191 return MASS_ERR_CMD_NOT_SUPPORTED;
hudakz 0:84353c479782 1192 }
hudakz 0:84353c479782 1193 default:
hudakz 0:84353c479782 1194 return MASS_ERR_GENERAL_SCSI_ERROR;
hudakz 0:84353c479782 1195 }
hudakz 0:84353c479782 1196
hudakz 0:84353c479782 1197 // case 4: return MASS_ERR_UNIT_BUSY; // Busy means retry later.
hudakz 0:84353c479782 1198 // case 0x05/0x14: we stalled out
hudakz 0:84353c479782 1199 // case 0x15/0x16: we naked out.
hudakz 0:84353c479782 1200 default:
hudakz 0:84353c479782 1201 ErrorMessage<uint8_t > (PSTR("Gen SCSI Err"), status);
hudakz 0:84353c479782 1202 ErrorMessage<uint8_t > (PSTR("LUN"), bTheLUN);
hudakz 0:84353c479782 1203 return status;
hudakz 0:84353c479782 1204 } // switch
hudakz 0:84353c479782 1205 }
hudakz 0:84353c479782 1206
hudakz 0:84353c479782 1207
hudakz 0:84353c479782 1208 ////////////////////////////////////////////////////////////////////////////////
hudakz 0:84353c479782 1209
hudakz 0:84353c479782 1210
hudakz 0:84353c479782 1211 // Debugging code
hudakz 0:84353c479782 1212
hudakz 0:84353c479782 1213
hudakz 0:84353c479782 1214 ////////////////////////////////////////////////////////////////////////////////
hudakz 0:84353c479782 1215
hudakz 0:84353c479782 1216 /**
hudakz 0:84353c479782 1217 *
hudakz 0:84353c479782 1218 * @param ep_ptr
hudakz 0:84353c479782 1219 */
hudakz 0:84353c479782 1220 void BulkOnly::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR * ep_ptr) {
hudakz 0:84353c479782 1221 Notify(PSTR("Endpoint descriptor:"), 0x80);
hudakz 0:84353c479782 1222 Notify(PSTR("\r\nLength:\t\t"), 0x80);
hudakz 0:84353c479782 1223 D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
hudakz 0:84353c479782 1224 Notify(PSTR("\r\nType:\t\t"), 0x80);
hudakz 0:84353c479782 1225 D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
hudakz 0:84353c479782 1226 Notify(PSTR("\r\nAddress:\t"), 0x80);
hudakz 0:84353c479782 1227 D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
hudakz 0:84353c479782 1228 Notify(PSTR("\r\nAttributes:\t"), 0x80);
hudakz 0:84353c479782 1229 D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
hudakz 0:84353c479782 1230 Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
hudakz 0:84353c479782 1231 D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
hudakz 0:84353c479782 1232 Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
hudakz 0:84353c479782 1233 D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
hudakz 0:84353c479782 1234 Notify(PSTR("\r\n"), 0x80);
hudakz 0:84353c479782 1235 }
hudakz 0:84353c479782 1236
hudakz 0:84353c479782 1237
hudakz 0:84353c479782 1238 ////////////////////////////////////////////////////////////////////////////////
hudakz 0:84353c479782 1239
hudakz 0:84353c479782 1240
hudakz 0:84353c479782 1241 // misc/to kill/to-do
hudakz 0:84353c479782 1242
hudakz 0:84353c479782 1243
hudakz 0:84353c479782 1244 ////////////////////////////////////////////////////////////////////////////////
hudakz 0:84353c479782 1245
hudakz 0:84353c479782 1246 /* We won't be needing this... */
hudakz 0:84353c479782 1247 uint8_t BulkOnly::Read(uint8_t lun __attribute__((unused)), uint32_t addr __attribute__((unused)), uint16_t bsize __attribute__((unused)), uint8_t blocks __attribute__((unused)), USBReadParser * prs __attribute__((unused))) {
hudakz 0:84353c479782 1248 #if MS_WANT_PARSER
hudakz 0:84353c479782 1249 if(!LUNOk[lun]) return MASS_ERR_NO_MEDIA;
hudakz 0:84353c479782 1250 Notify(PSTR("\r\nRead (With parser)\r\n"), 0x80);
hudakz 0:84353c479782 1251 Notify(PSTR("---------\r\n"), 0x80);
hudakz 0:84353c479782 1252
hudakz 0:84353c479782 1253 CommandBlockWrapper cbw = CommandBlockWrapper();
hudakz 0:84353c479782 1254
hudakz 0:84353c479782 1255 cbw.dCBWSignature = MASS_CBW_SIGNATURE;
hudakz 0:84353c479782 1256 cbw.dCBWTag = ++dCBWTag;
hudakz 0:84353c479782 1257 cbw.dCBWDataTransferLength = ((uint32_t)bsize * blocks);
hudakz 0:84353c479782 1258 cbw.bmCBWFlags = MASS_CMD_DIR_IN,
hudakz 0:84353c479782 1259 cbw.bmCBWLUN = lun;
hudakz 0:84353c479782 1260 cbw.bmCBWCBLength = 10;
hudakz 0:84353c479782 1261
hudakz 0:84353c479782 1262 cbw.CBWCB[0] = SCSI_CMD_READ_10;
hudakz 0:84353c479782 1263 cbw.CBWCB[8] = blocks;
hudakz 0:84353c479782 1264 cbw.CBWCB[2] = ((addr >> 24) & 0xff);
hudakz 0:84353c479782 1265 cbw.CBWCB[3] = ((addr >> 16) & 0xff);
hudakz 0:84353c479782 1266 cbw.CBWCB[4] = ((addr >> 8) & 0xff);
hudakz 0:84353c479782 1267 cbw.CBWCB[5] = (addr & 0xff);
hudakz 0:84353c479782 1268
hudakz 0:84353c479782 1269 return HandleSCSIError(Transaction(&cbw, bsize, prs, 1));
hudakz 0:84353c479782 1270 #else
hudakz 0:84353c479782 1271 return MASS_ERR_NOT_IMPLEMENTED;
hudakz 0:84353c479782 1272 #endif
hudakz 0:84353c479782 1273 }