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