1 /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
3 This software may be distributed and modified under the terms of the GNU
4 General Public License version 2 (GPL2) as published by the Free Software
5 Foundation and appearing in the file GPL2.TXT included in the packaging of
6 this file. Please note that GPL2 Section 2[b] requires that all works based
7 on this software must also be made publicly available under the terms of
14 Web : http://www.circuitsathome.com
15 e-mail : support@circuitsathome.com
18 #include "masstorage.h"
20 const uint8_t BulkOnly::epDataInIndex
= 1;
21 const uint8_t BulkOnly::epDataOutIndex
= 2;
22 const uint8_t BulkOnly::epInterruptInIndex
= 3;
24 ////////////////////////////////////////////////////////////////////////////////
28 ////////////////////////////////////////////////////////////////////////////////
31 * Get the capacity of the media
33 * @param lun Logical Unit Number
34 * @return media capacity
36 uint32_t BulkOnly::GetCapacity(uint8_t lun
) {
38 return CurrentCapacity
[lun
];
43 * Get the sector (block) size used on the media
45 * @param lun Logical Unit Number
46 * @return media sector size
48 uint16_t BulkOnly::GetSectorSize(uint8_t lun
) {
50 return CurrentSectorSize
[lun
];
55 * Test if LUN is ready for use
57 * @param lun Logical Unit Number
58 * @return true if LUN is ready for use
60 bool BulkOnly::LUNIsGood(uint8_t lun
) {
65 * Test if LUN is write protected
67 * @param lun Logical Unit Number
68 * @return cached status of write protect switch
70 bool BulkOnly::WriteProtected(uint8_t lun
) {
75 * Wrap and execute a SCSI CDB with length of 6
77 * @param cdb CDB to execute
78 * @param buf_size Size of expected transaction
80 * @param dir MASS_CMD_DIR_IN | MASS_CMD_DIR_OUT
83 uint8_t BulkOnly::SCSITransaction6(CDB6_t
*cdb
, uint16_t buf_size
, void *buf
, uint8_t dir
) {
84 // promote buf_size to 32bits.
85 CommandBlockWrapper cbw
= CommandBlockWrapper(++dCBWTag
, (uint32_t)buf_size
, cdb
, dir
);
86 //SetCurLUN(cdb->LUN);
87 return (HandleSCSIError(Transaction(&cbw
, buf_size
, buf
)));
91 * Wrap and execute a SCSI CDB with length of 10
93 * @param cdb CDB to execute
94 * @param buf_size Size of expected transaction
96 * @param dir MASS_CMD_DIR_IN | MASS_CMD_DIR_OUT
99 uint8_t BulkOnly::SCSITransaction10(CDB10_t
*cdb
, uint16_t buf_size
, void *buf
, uint8_t dir
) {
100 // promote buf_size to 32bits.
101 CommandBlockWrapper cbw
= CommandBlockWrapper(++dCBWTag
, (uint32_t)buf_size
, cdb
, dir
);
102 //SetCurLUN(cdb->LUN);
103 return (HandleSCSIError(Transaction(&cbw
, buf_size
, buf
)));
107 * Lock or Unlock the tray or door on device.
108 * Caution: Some devices with buggy firmware will lock up.
110 * @param lun Logical Unit Number
111 * @param lock 1 to lock, 0 to unlock
114 uint8_t BulkOnly::LockMedia(uint8_t lun
, uint8_t lock
) {
115 Notify(PSTR("\r\nLockMedia\r\n"), 0x80);
116 Notify(PSTR("---------\r\n"), 0x80);
118 CDB6_t cdb
= CDB6_t(SCSI_CMD_PREVENT_REMOVAL
, lun
, (uint8_t)0, lock
);
119 return SCSITransaction6(&cdb
, (uint16_t)0, NULL
, (uint8_t)MASS_CMD_DIR_IN
);
123 * Media control, for spindle motor and media tray or door.
124 * This includes CDROM, TAPE and anything with a media loader.
126 * @param lun Logical Unit Number
127 * @param ctl 0x00 Stop Motor, 0x01 Start Motor, 0x02 Eject Media, 0x03 Load Media
128 * @return 0 on success
130 uint8_t BulkOnly::MediaCTL(uint8_t lun
, uint8_t ctl
) {
131 Notify(PSTR("\r\nMediaCTL\r\n"), 0x80);
132 Notify(PSTR("-----------------\r\n"), 0x80);
134 uint8_t rcode
= MASS_ERR_UNIT_NOT_READY
;
136 CDB6_t cdb
= CDB6_t(SCSI_CMD_START_STOP_UNIT
, lun
, ctl
& 0x03, 0);
137 rcode
= SCSITransaction6(&cdb
, (uint16_t)0, NULL
, (uint8_t)MASS_CMD_DIR_OUT
);
145 * Read data from media
147 * @param lun Logical Unit Number
148 * @param addr LBA address on media to read
149 * @param bsize size of a block (we should probably use the cached size)
150 * @param blocks how many blocks to read
151 * @param buf memory that is able to hold the requested data
152 * @return 0 on success
154 uint8_t BulkOnly::Read(uint8_t lun
, uint32_t addr
, uint16_t bsize
, uint8_t blocks
, uint8_t *buf
) {
155 if(!LUNOk
[lun
]) return MASS_ERR_NO_MEDIA
;
156 Notify(PSTR("\r\nRead LUN:\t"), 0x80);
157 D_PrintHex
<uint8_t > (lun
, 0x90);
158 Notify(PSTR("\r\nLBA:\t\t"), 0x90);
159 D_PrintHex
<uint32_t > (addr
, 0x90);
160 Notify(PSTR("\r\nblocks:\t\t"), 0x90);
161 D_PrintHex
<uint8_t > (blocks
, 0x90);
162 Notify(PSTR("\r\nblock size:\t"), 0x90);
163 D_PrintHex
<uint16_t > (bsize
, 0x90);
164 Notify(PSTR("\r\n---------\r\n"), 0x80);
165 CDB10_t cdb
= CDB10_t(SCSI_CMD_READ_10
, lun
, blocks
, addr
);
168 uint8_t er
= SCSITransaction10(&cdb
, ((uint16_t)bsize
* blocks
), buf
, (uint8_t)MASS_CMD_DIR_IN
);
170 if(er
== MASS_ERR_STALL
) {
173 if(!TestUnitReady(lun
)) goto again
;
179 * Write data to media
181 * @param lun Logical Unit Number
182 * @param addr LBA address on media to write
183 * @param bsize size of a block (we should probably use the cached size)
184 * @param blocks how many blocks to write
185 * @param buf memory that contains the data to write
186 * @return 0 on success
188 uint8_t BulkOnly::Write(uint8_t lun
, uint32_t addr
, uint16_t bsize
, uint8_t blocks
, const uint8_t * buf
) {
189 if(!LUNOk
[lun
]) return MASS_ERR_NO_MEDIA
;
190 if(!WriteOk
[lun
]) return MASS_ERR_WRITE_PROTECTED
;
191 Notify(PSTR("\r\nWrite LUN:\t"), 0x80);
192 D_PrintHex
<uint8_t > (lun
, 0x90);
193 Notify(PSTR("\r\nLBA:\t\t"), 0x90);
194 D_PrintHex
<uint32_t > (addr
, 0x90);
195 Notify(PSTR("\r\nblocks:\t\t"), 0x90);
196 D_PrintHex
<uint8_t > (blocks
, 0x90);
197 Notify(PSTR("\r\nblock size:\t"), 0x90);
198 D_PrintHex
<uint16_t > (bsize
, 0x90);
199 Notify(PSTR("\r\n---------\r\n"), 0x80);
200 CDB10_t cdb
= CDB10_t(SCSI_CMD_WRITE_10
, lun
, blocks
, addr
);
203 uint8_t er
= SCSITransaction10(&cdb
, ((uint16_t)bsize
* blocks
), (void*)buf
, (uint8_t)MASS_CMD_DIR_OUT
);
205 if(er
== MASS_ERR_WRITE_STALL
) {
208 if(!TestUnitReady(lun
)) goto again
;
213 // End of user functions, the remaining code below is driver internals.
214 // Only developer serviceable parts below!
216 ////////////////////////////////////////////////////////////////////////////////
220 ////////////////////////////////////////////////////////////////////////////////
222 BulkOnly::BulkOnly(USB
*p
) :
234 pUsb
->RegisterDeviceClass(this);
238 * USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET == success
239 * We need to standardize either the rcode, or change the API to return values
240 * so a signal that additional actions are required can be produced.
241 * Some of these codes do exist already.
243 * TECHNICAL: We could do most of this code elsewhere, with the exception of checking the class instance.
244 * Doing so would save some program memory when using multiple drivers.
246 * @param parent USB address of parent
247 * @param port address of port on parent
248 * @param lowspeed true if device is low speed
251 uint8_t BulkOnly::ConfigureDevice(uint8_t parent
, uint8_t port
, bool lowspeed
) {
253 const uint8_t constBufSize
= sizeof (USB_DEVICE_DESCRIPTOR
);
255 uint8_t buf
[constBufSize
];
256 USB_DEVICE_DESCRIPTOR
* udd
= reinterpret_cast<USB_DEVICE_DESCRIPTOR
*>(buf
);
259 EpInfo
*oldep_ptr
= NULL
;
260 USBTRACE("MS ConfigureDevice\r\n");
262 AddressPool
&addrPool
= pUsb
->GetAddressPool();
266 return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE
;
269 // Get pointer to pseudo device with address 0 assigned
270 p
= addrPool
.GetUsbDevicePtr(0);
272 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
;
276 USBTRACE("epinfo\r\n");
277 return USB_ERROR_EPINFO_IS_NULL
;
280 // Save old pointer to EP_RECORD of address 0
281 oldep_ptr
= p
->epinfo
;
283 // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
286 p
->lowspeed
= lowspeed
;
287 // Get device descriptor
288 rcode
= pUsb
->getDevDescr(0, 0, constBufSize
, (uint8_t*)buf
);
291 p
->epinfo
= oldep_ptr
;
294 goto FailGetDevDescr
;
296 // Allocate new address according to device class
297 bAddress
= addrPool
.AllocAddress(parent
, false, port
);
300 return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL
;
302 // Extract Max Packet Size from the device descriptor
303 epInfo
[0].maxPktSize
= udd
->bMaxPacketSize0
;
304 // Steal and abuse from epInfo structure to save on memory.
305 epInfo
[1].epAddr
= udd
->bNumConfigurations
;
307 return USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET
;
310 #ifdef DEBUG_USB_HOST
311 NotifyFailGetDevDescr(rcode
);
313 rcode
= USB_ERROR_FailGetDevDescr
;
321 * @param parent (not used)
322 * @param port (not used)
323 * @param lowspeed true if device is low speed
324 * @return 0 for success
326 uint8_t BulkOnly::Init(uint8_t parent
, uint8_t port
, bool lowspeed
) {
328 uint8_t num_of_conf
= epInfo
[1].epAddr
; // number of configurations
329 epInfo
[1].epAddr
= 0;
330 USBTRACE("MS Init\r\n");
332 AddressPool
&addrPool
= pUsb
->GetAddressPool();
333 UsbDevice
*p
= addrPool
.GetUsbDevicePtr(bAddress
);
336 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
;
338 // Assign new address to the device
340 rcode
= pUsb
->setAddr(0, 0, bAddress
);
344 addrPool
.FreeAddress(bAddress
);
346 USBTRACE2("setAddr:", rcode
);
350 USBTRACE2("Addr:", bAddress
);
354 p
= addrPool
.GetUsbDevicePtr(bAddress
);
357 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
;
359 p
->lowspeed
= lowspeed
;
361 // Assign epInfo to epinfo pointer
362 rcode
= pUsb
->setEpInfoEntry(bAddress
, 1, epInfo
);
365 goto FailSetDevTblEntry
;
367 USBTRACE2("NC:", num_of_conf
);
369 for(uint8_t i
= 0; i
< num_of_conf
; i
++) {
370 ConfigDescParser
< USB_CLASS_MASS_STORAGE
,
373 CP_MASK_COMPARE_CLASS
|
374 CP_MASK_COMPARE_SUBCLASS
|
375 CP_MASK_COMPARE_PROTOCOL
> BulkOnlyParser(this);
377 rcode
= pUsb
->getConfDescr(bAddress
, 0, i
, &BulkOnlyParser
);
380 goto FailGetConfDescr
;
387 return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED
;
389 // Assign epInfo to epinfo pointer
390 pUsb
->setEpInfoEntry(bAddress
, bNumEP
, epInfo
);
392 USBTRACE2("Conf:", bConfNum
);
394 // Set Configuration Value
395 rcode
= pUsb
->setConf(bAddress
, 0, bConfNum
);
398 goto FailSetConfDescr
;
400 //Linux does a 1sec delay after this.
403 rcode
= GetMaxLUN(&bMaxLUN
);
407 if(bMaxLUN
>= MASS_MAX_SUPPORTED_LUN
) bMaxLUN
= MASS_MAX_SUPPORTED_LUN
- 1;
408 ErrorMessage
<uint8_t > (PSTR("MaxLUN"), bMaxLUN
);
410 delay(1000); // Delay a bit for slow firmware.
412 for(uint8_t lun
= 0; lun
<= bMaxLUN
; lun
++) {
413 InquiryResponse response
;
414 rcode
= Inquiry(lun
, sizeof (InquiryResponse
), (uint8_t*) & response
);
416 ErrorMessage
<uint8_t > (PSTR("Inquiry"), rcode
);
419 printf("LUN %i `", lun
);
420 uint8_t *buf
= response
.VendorID
;
421 for(int i
= 0; i
< 28; i
++) printf("%c", buf
[i
]);
422 printf("'\r\nQualifier %1.1X ", response
.PeripheralQualifier
);
423 printf("Device type %2.2X ", response
.DeviceType
);
424 printf("RMB %1.1X ", response
.Removable
);
425 printf("SSCS %1.1X ", response
.SCCS
);
426 uint8_t sv
= response
.Version
;
427 printf("SCSI version %2.2X\r\nDevice conforms to ", sv
);
430 printf("No specific");
433 printf("ANSI X3.131-1986 (ANSI 1)");
436 printf("ANSI X3.131-1994 (ANSI 2)");
439 printf("ANSI INCITS 301-1997 (SPC)");
442 printf("ANSI INCITS 351-2001 (SPC-2)");
445 printf("ANSI INCITS 408-2005 (SPC-4)");
448 printf("T10/1731-D (SPC-4)");
453 printf(" standards.\r\n");
455 uint8_t tries
= 0xf0;
456 while((rcode
= TestUnitReady(lun
))) {
457 if(rcode
== 0x08) break; // break on no media, this is OK to do.
458 // try to lock media and spin up
461 MediaCTL(lun
, 1); // I actually have a USB stick that needs this!
462 } else delay(2 * (tries
+ 1));
468 LUNOk
[lun
] = CheckLUN(lun
);
469 if(!LUNOk
[lun
]) LUNOk
[lun
] = CheckLUN(lun
);
482 #ifdef DEBUG_USB_HOST
483 USBTRACE("MS configured\r\n\r\n");
488 //USBTRACE("Poll enabled\r\n");
492 #ifdef DEBUG_USB_HOST
493 NotifyFailSetConfDescr();
498 #ifdef DEBUG_USB_HOST
504 #ifdef DEBUG_USB_HOST
505 USBTRACE("GetMaxLUN:");
509 //#ifdef DEBUG_USB_HOST
510 //FailInvalidSectorSize:
511 // USBTRACE("Sector Size is NOT VALID: ");
516 #ifdef DEBUG_USB_HOST
517 NotifyFailSetDevTblEntry();
522 #ifdef DEBUG_USB_HOST
523 NotifyFailGetConfDescr();
526 #ifdef DEBUG_USB_HOST
535 * For driver use only.
543 void BulkOnly::EndpointXtract(uint8_t conf
, uint8_t iface
, uint8_t alt
, uint8_t proto
, const USB_ENDPOINT_DESCRIPTOR
* pep
) {
544 ErrorMessage
<uint8_t > (PSTR("Conf.Val"), conf
);
545 ErrorMessage
<uint8_t > (PSTR("Iface Num"), iface
);
546 ErrorMessage
<uint8_t > (PSTR("Alt.Set"), alt
);
553 if((pep
->bmAttributes
& 0x02) == 2) {
554 index
= ((pep
->bEndpointAddress
& 0x80) == 0x80) ? epDataInIndex
: epDataOutIndex
;
555 // Fill in the endpoint info structure
556 epInfo
[index
].epAddr
= (pep
->bEndpointAddress
& 0x0F);
557 epInfo
[index
].maxPktSize
= (uint8_t)pep
->wMaxPacketSize
;
558 epInfo
[index
].epAttribs
= 0;
562 PrintEndpointDescriptor(pep
);
566 if((pep
->bmAttributes
& 0x03) == 3 && (pep
->bEndpointAddress
& 0x80) == 0x80)
567 index
= epInterruptInIndex
;
569 if((pep
->bmAttributes
& 0x02) == 2)
570 index
= ((pep
->bEndpointAddress
& 0x80) == 0x80) ? epDataInIndex
: epDataOutIndex
;
574 // Fill in the endpoint info structure
575 epInfo
[index
].epAddr
= (pep
->bEndpointAddress
& 0x0F);
576 epInfo
[index
].maxPktSize
= (uint8_t)pep
->wMaxPacketSize
;
577 epInfo
[index
].epAttribs
= 0;
581 PrintEndpointDescriptor(pep
);
586 * For driver use only.
590 uint8_t BulkOnly::Release() {
592 pUsb
->GetAddressPool().FreeAddress(bAddress
);
597 * For driver use only.
599 * @param lun Logical Unit Number
600 * @return true if LUN is ready for use.
602 bool BulkOnly::CheckLUN(uint8_t lun
) {
605 for(uint8_t i
= 0; i
< 8; i
++) capacity
.data
[i
] = 0;
607 rcode
= ReadCapacity10(lun
, (uint8_t*)capacity
.data
);
609 //printf(">>>>>>>>>>>>>>>>ReadCapacity returned %i\r\n", rcode);
612 ErrorMessage
<uint8_t > (PSTR(">>>>>>>>>>>>>>>>CAPACITY OK ON LUN"), lun
);
613 for(uint8_t i
= 0; i
< 8 /*sizeof (Capacity)*/; i
++)
614 D_PrintHex
<uint8_t > (capacity
.data
[i
], 0x80);
615 Notify(PSTR("\r\n\r\n"), 0x80);
616 // Only 512/1024/2048/4096 are valid values!
617 uint32_t c
= BMAKE32(capacity
.data
[4], capacity
.data
[5], capacity
.data
[6], capacity
.data
[7]);
618 if(c
!= 0x0200LU
&& c
!= 0x0400LU
&& c
!= 0x0800LU
&& c
!= 0x1000LU
) {
621 // Store capacity information.
622 CurrentSectorSize
[lun
] = (uint16_t)(c
); // & 0xFFFF);
624 CurrentCapacity
[lun
] = BMAKE32(capacity
.data
[0], capacity
.data
[1], capacity
.data
[2], capacity
.data
[3]) + 1;
625 if(CurrentCapacity
[lun
] == /*0xffffffffLU */ 0x01LU
|| CurrentCapacity
[lun
] == 0x00LU
) {
626 // Buggy firmware will report 0xffffffff or 0 for no media
627 if(CurrentCapacity
[lun
])
628 ErrorMessage
<uint8_t > (PSTR(">>>>>>>>>>>>>>>>BUGGY FIRMWARE. CAPACITY FAIL ON LUN"), lun
);
633 if(!TestUnitReady(lun
)) return true;
638 * For driver use only.
640 * Scan for media change on all LUNs
642 void BulkOnly::CheckMedia() {
643 for(uint8_t lun
= 0; lun
<= bMaxLUN
; lun
++) {
644 if(TestUnitReady(lun
)) {
649 LUNOk
[lun
] = CheckLUN(lun
);
652 printf("}}}}}}}}}}}}}}}}STATUS ");
653 for(uint8_t lun
= 0; lun
<= bMaxLUN
; lun
++) {
660 qNextPollTime
= millis() + 2000;
664 * For driver use only.
668 uint8_t BulkOnly::Poll() {
674 if((long)(millis() - qNextPollTime
) >= 0L) {
682 ////////////////////////////////////////////////////////////////////////////////
688 ////////////////////////////////////////////////////////////////////////////////
691 * For driver use only.
696 uint8_t BulkOnly::GetMaxLUN(uint8_t *plun
) {
697 uint8_t ret
= pUsb
->ctrlReq(bAddress
, 0, bmREQ_MASSIN
, MASS_REQ_GET_MAX_LUN
, 0, 0, bIface
, 1, 1, plun
, NULL
);
706 * For driver use only. Used during Driver Init
708 * @param lun Logical Unit Number
713 uint8_t BulkOnly::Inquiry(uint8_t lun
, uint16_t bsize
, uint8_t *buf
) {
714 Notify(PSTR("\r\nInquiry\r\n"), 0x80);
715 Notify(PSTR("---------\r\n"), 0x80);
717 CDB6_t cdb
= CDB6_t(SCSI_CMD_INQUIRY
, lun
, 0LU, (uint8_t)bsize
, 0);
718 uint8_t rc
= SCSITransaction6(&cdb
, bsize
, buf
, (uint8_t)MASS_CMD_DIR_IN
);
724 * For driver use only.
726 * @param lun Logical Unit Number
729 uint8_t BulkOnly::TestUnitReady(uint8_t lun
) {
732 return MASS_ERR_UNIT_NOT_READY
;
734 Notify(PSTR("\r\nTestUnitReady\r\n"), 0x80);
735 Notify(PSTR("-----------------\r\n"), 0x80);
737 CDB6_t cdb
= CDB6_t(SCSI_CMD_TEST_UNIT_READY
, lun
, (uint8_t)0, 0);
738 return SCSITransaction6(&cdb
, 0, NULL
, (uint8_t)MASS_CMD_DIR_IN
);
743 * For driver use only.
745 * @param lun Logical Unit Number
753 uint8_t BulkOnly::ModeSense6(uint8_t lun
, uint8_t pc
, uint8_t page
, uint8_t subpage
, uint8_t len
, uint8_t * pbuf
) {
754 Notify(PSTR("\r\rModeSense\r\n"), 0x80);
755 Notify(PSTR("------------\r\n"), 0x80);
757 CDB6_t cdb
= CDB6_t(SCSI_CMD_TEST_UNIT_READY
, lun
, (uint32_t)((((pc
<< 6) | page
) << 8) | subpage
), len
, 0);
758 return SCSITransaction6(&cdb
, len
, pbuf
, (uint8_t)MASS_CMD_DIR_IN
);
762 * For driver use only.
764 * @param lun Logical Unit Number
769 uint8_t BulkOnly::ReadCapacity10(uint8_t lun
, uint8_t *buf
) {
770 Notify(PSTR("\r\nReadCapacity\r\n"), 0x80);
771 Notify(PSTR("---------------\r\n"), 0x80);
773 CDB10_t cdb
= CDB10_t(SCSI_CMD_READ_CAPACITY_10
, lun
);
774 return SCSITransaction10(&cdb
, 8, buf
, (uint8_t)MASS_CMD_DIR_IN
);
778 * For driver use only.
780 * Page 3F contains write protect status.
782 * @param lun Logical Unit Number to test.
783 * @return Write protect switch status.
785 uint8_t BulkOnly::Page3F(uint8_t lun
) {
787 for(int i
= 0; i
< 192; i
++) {
791 uint8_t rc
= ModeSense6(lun
, 0, 0x3f, 0, 192, buf
);
793 WriteOk
[lun
] = ((buf
[2] & 0x80) == 0);
794 Notify(PSTR("Mode Sense: "), 0x80);
795 for(int i
= 0; i
< 4; i
++) {
796 D_PrintHex
<uint8_t > (buf
[i
], 0x80);
797 Notify(PSTR(" "), 0x80);
799 Notify(PSTR("\r\n"), 0x80);
805 * For driver use only.
807 * @param lun Logical Unit Number
812 uint8_t BulkOnly::RequestSense(uint8_t lun
, uint16_t size
, uint8_t *buf
) {
813 Notify(PSTR("\r\nRequestSense\r\n"), 0x80);
814 Notify(PSTR("----------------\r\n"), 0x80);
816 CDB6_t cdb
= CDB6_t(SCSI_CMD_REQUEST_SENSE
, lun
, 0LU, (uint8_t)size
, 0);
817 CommandBlockWrapper cbw
= CommandBlockWrapper(++dCBWTag
, (uint32_t)size
, &cdb
, (uint8_t)MASS_CMD_DIR_IN
);
819 return Transaction(&cbw
, size
, buf
);
823 ////////////////////////////////////////////////////////////////////////////////
829 ////////////////////////////////////////////////////////////////////////////////
832 * For driver use only.
837 uint8_t BulkOnly::ClearEpHalt(uint8_t index
) {
843 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))
847 ErrorMessage
<uint8_t > (PSTR("ClearEpHalt"), ret
);
848 ErrorMessage
<uint8_t > (PSTR("EP"), ((index
== epDataInIndex
) ? (0x80 | epInfo
[index
].epAddr
) : epInfo
[index
].epAddr
));
851 epInfo
[index
].bmSndToggle
= 0;
852 epInfo
[index
].bmRcvToggle
= 0;
858 * For driver use only.
861 void BulkOnly::Reset() {
862 while(pUsb
->ctrlReq(bAddress
, 0, bmREQ_MASSOUT
, MASS_REQ_BOMSR
, 0, 0, bIface
, 0, 0, NULL
, NULL
) == 0x01) delay(6);
866 * For driver use only.
868 * @return 0 if successful
870 uint8_t BulkOnly::ResetRecovery() {
871 Notify(PSTR("\r\nResetRecovery\r\n"), 0x80);
872 Notify(PSTR("-----------------\r\n"), 0x80);
877 ClearEpHalt(epDataInIndex
);
879 bLastUsbError
= ClearEpHalt(epDataOutIndex
);
881 return bLastUsbError
;
885 * For driver use only.
887 * Clear all EP data and clear all LUN status
889 void BulkOnly::ClearAllEP() {
890 for(uint8_t i
= 0; i
< MASS_MAX_ENDPOINTS
; i
++) {
891 epInfo
[i
].epAddr
= 0;
892 epInfo
[i
].maxPktSize
= (i
) ? 0 : 8;
893 epInfo
[i
].epAttribs
= 0;
895 epInfo
[i
].bmNakPower
= USB_NAK_DEFAULT
;
898 for(uint8_t i
= 0; i
< MASS_MAX_SUPPORTED_LUN
; i
++) {
901 CurrentCapacity
[i
] = 0lu;
902 CurrentSectorSize
[i
] = 0;
916 * For driver use only.
922 bool BulkOnly::IsValidCSW(CommandStatusWrapper
*pcsw
, CommandBlockWrapperBase
*pcbw
) {
923 if(pcsw
->dCSWSignature
!= MASS_CSW_SIGNATURE
) {
924 Notify(PSTR("CSW:Sig error\r\n"), 0x80);
927 if(pcsw
->dCSWTag
!= pcbw
->dCBWTag
) {
928 Notify(PSTR("CSW:Wrong tag\r\n"), 0x80);
935 * For driver use only.
941 uint8_t BulkOnly::HandleUsbError(uint8_t error
, uint8_t index
) {
944 bLastUsbError
= error
;
946 //ClearEpHalt(index);
947 while(error
&& count
) {
948 if(error
!= hrSUCCESS
) {
949 ErrorMessage
<uint8_t > (PSTR("USB Error"), error
);
950 ErrorMessage
<uint8_t > (PSTR("Index"), index
);
955 return MASS_ERR_SUCCESS
;
957 // SIE is busy, just hang out and try again.
958 return MASS_ERR_UNIT_BUSY
;
960 case hrJERR
: return MASS_ERR_DEVICE_DISCONNECTED
;
963 return MASS_ERR_STALL
;
965 if(index
!= epDataInIndex
)
966 return MASS_ERR_WRITE_STALL
;
967 return MASS_ERR_STALL
;
971 return MASS_ERR_UNIT_BUSY
;
972 return MASS_ERR_UNIT_BUSY
;
975 // Handle a very super rare corner case, where toggles become de-synched.
976 // I have only ran into one device that has this firmware bug, and this is
977 // the only clean way to get back into sync with the buggy device firmware.
979 if(bAddress
&& bConfNum
) {
980 error
= pUsb
->setConf(bAddress
, 0, bConfNum
);
985 return MASS_ERR_SUCCESS
;
987 ErrorMessage
<uint8_t > (PSTR("\r\nUSB"), error
);
988 return MASS_ERR_GENERAL_USB_ERROR
;
993 return ((error
&& !count
) ? MASS_ERR_GENERAL_USB_ERROR
: MASS_ERR_SUCCESS
);
998 uint8_t BulkOnly::Transaction(CommandBlockWrapper
*pcbw
, uint16_t buf_size
, void *buf
) {
999 return Transaction(CommandBlockWrapper
*pcbw
, uint16_t buf_size
, void *buf
, 0);
1004 * For driver use only.
1012 uint8_t BulkOnly::Transaction(CommandBlockWrapper
*pcbw
, uint16_t buf_size
, void *buf
1019 uint16_t bytes
= (pcbw
->dCBWDataTransferLength
> buf_size
) ? buf_size
: pcbw
->dCBWDataTransferLength
;
1020 printf("Transfersize %i\r\n", bytes
);
1023 bool callback
= (flags
& MASS_TRANS_FLG_CALLBACK
) == MASS_TRANS_FLG_CALLBACK
;
1025 uint16_t bytes
= buf_size
;
1027 bool write
= (pcbw
->bmCBWFlags
& MASS_CMD_DIR_IN
) != MASS_CMD_DIR_IN
;
1030 CommandStatusWrapper csw
; // up here, we allocate ahead to save cpu cycles.
1031 SetCurLUN(pcbw
->bmCBWLUN
);
1032 ErrorMessage
<uint32_t > (PSTR("CBW.dCBWTag"), pcbw
->dCBWTag
);
1034 while((usberr
= pUsb
->outTransfer(bAddress
, epInfo
[epDataOutIndex
].epAddr
, sizeof (CommandBlockWrapper
), (uint8_t*)pcbw
)) == hrBUSY
) delay(1);
1036 ret
= HandleUsbError(usberr
, epDataOutIndex
);
1037 //ret = HandleUsbError(pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, sizeof (CommandBlockWrapper), (uint8_t*)pcbw), epDataOutIndex);
1039 ErrorMessage
<uint8_t > (PSTR("============================ CBW"), ret
);
1045 uint8_t rbuf
[bytes
];
1046 while((usberr
= pUsb
->inTransfer(bAddress
, epInfo
[epDataInIndex
].epAddr
, &bytes
, rbuf
)) == hrBUSY
) delay(1);
1047 if(usberr
== hrSUCCESS
) ((USBReadParser
*)buf
)->Parse(bytes
, rbuf
, 0);
1050 while((usberr
= pUsb
->inTransfer(bAddress
, epInfo
[epDataInIndex
].epAddr
, &bytes
, (uint8_t*)buf
)) == hrBUSY
) delay(1);
1055 ret
= HandleUsbError(usberr
, epDataInIndex
);
1057 while((usberr
= pUsb
->outTransfer(bAddress
, epInfo
[epDataOutIndex
].epAddr
, bytes
, (uint8_t*)buf
)) == hrBUSY
) delay(1);
1058 ret
= HandleUsbError(usberr
, epDataOutIndex
);
1061 ErrorMessage
<uint8_t > (PSTR("============================ DAT"), ret
);
1067 bytes
= sizeof (CommandStatusWrapper
);
1070 while((usberr
= pUsb
->inTransfer(bAddress
, epInfo
[epDataInIndex
].epAddr
, &bytes
, (uint8_t*) & csw
)) == hrBUSY
) delay(1);
1072 ClearEpHalt(epDataInIndex
);
1073 if(tries
) ResetRecovery();
1076 Notify(PSTR("CBW:\t\tOK\r\n"), 0x80);
1077 Notify(PSTR("Data Stage:\tOK\r\n"), 0x80);
1079 // Throw away csw, IT IS NOT OF ANY USE.
1083 ret
= HandleUsbError(usberr
, epDataInIndex
);
1085 ErrorMessage
<uint8_t > (PSTR("============================ CSW"), ret
);
1087 if(usberr
== hrSUCCESS
) {
1088 if(IsValidCSW(&csw
, pcbw
)) {
1089 //ErrorMessage<uint32_t > (PSTR("CSW.dCBWTag"), csw.dCSWTag);
1090 //ErrorMessage<uint8_t > (PSTR("bCSWStatus"), csw.bCSWStatus);
1091 //ErrorMessage<uint32_t > (PSTR("dCSWDataResidue"), csw.dCSWDataResidue);
1092 Notify(PSTR("CSW:\t\tOK\r\n\r\n"), 0x80);
1093 return csw
.bCSWStatus
;
1095 // NOTE! Sometimes this is caused by the reported residue being wrong.
1096 // Get a different device. It isn't compliant, and should have never passed Q&A.
1097 // I own one... 05e3:0701 Genesys Logic, Inc. USB 2.0 IDE Adapter.
1098 // Other devices that exhibit this behavior exist in the wild too.
1099 // Be sure to check quirks in the Linux source code before reporting a bug. --xxxajk
1100 Notify(PSTR("Invalid CSW\r\n"), 0x80);
1102 //return MASS_ERR_SUCCESS;
1103 return MASS_ERR_INVALID_CSW
;
1111 * For driver use only.
1113 * @param lun Logical Unit Number
1116 uint8_t BulkOnly::SetCurLUN(uint8_t lun
) {
1118 return MASS_ERR_INVALID_LUN
;
1120 return MASS_ERR_SUCCESS
;
1124 * For driver use only.
1129 uint8_t BulkOnly::HandleSCSIError(uint8_t status
) {
1133 case 0: return MASS_ERR_SUCCESS
;
1136 ErrorMessage
<uint8_t > (PSTR("Phase Error"), status
);
1137 ErrorMessage
<uint8_t > (PSTR("LUN"), bTheLUN
);
1139 return MASS_ERR_GENERAL_SCSI_ERROR
;
1142 ErrorMessage
<uint8_t > (PSTR("SCSI Error"), status
);
1143 ErrorMessage
<uint8_t > (PSTR("LUN"), bTheLUN
);
1144 RequestSenseResponce rsp
;
1146 ret
= RequestSense(bTheLUN
, sizeof (RequestSenseResponce
), (uint8_t*) & rsp
);
1149 return MASS_ERR_GENERAL_SCSI_ERROR
;
1151 ErrorMessage
<uint8_t > (PSTR("Response Code"), rsp
.bResponseCode
);
1152 if(rsp
.bResponseCode
& 0x80) {
1153 Notify(PSTR("Information field: "), 0x80);
1154 for(int i
= 0; i
< 4; i
++) {
1155 D_PrintHex
<uint8_t > (rsp
.CmdSpecificInformation
[i
], 0x80);
1156 Notify(PSTR(" "), 0x80);
1158 Notify(PSTR("\r\n"), 0x80);
1160 ErrorMessage
<uint8_t > (PSTR("Sense Key"), rsp
.bmSenseKey
);
1161 ErrorMessage
<uint8_t > (PSTR("Add Sense Code"), rsp
.bAdditionalSenseCode
);
1162 ErrorMessage
<uint8_t > (PSTR("Add Sense Qual"), rsp
.bAdditionalSenseQualifier
);
1163 // warning, this is not testing ASQ, only SK and ASC.
1164 switch(rsp
.bmSenseKey
) {
1165 case SCSI_S_UNIT_ATTENTION
:
1166 switch(rsp
.bAdditionalSenseCode
) {
1167 case SCSI_ASC_MEDIA_CHANGED
:
1168 return MASS_ERR_MEDIA_CHANGED
;
1170 return MASS_ERR_UNIT_NOT_READY
;
1172 case SCSI_S_NOT_READY
:
1173 switch(rsp
.bAdditionalSenseCode
) {
1174 case SCSI_ASC_MEDIUM_NOT_PRESENT
:
1175 return MASS_ERR_NO_MEDIA
;
1177 return MASS_ERR_UNIT_NOT_READY
;
1179 case SCSI_S_ILLEGAL_REQUEST
:
1180 switch(rsp
.bAdditionalSenseCode
) {
1181 case SCSI_ASC_LBA_OUT_OF_RANGE
:
1182 return MASS_ERR_BAD_LBA
;
1184 return MASS_ERR_CMD_NOT_SUPPORTED
;
1187 return MASS_ERR_GENERAL_SCSI_ERROR
;
1190 // case 4: return MASS_ERR_UNIT_BUSY; // Busy means retry later.
1191 // case 0x05/0x14: we stalled out
1192 // case 0x15/0x16: we naked out.
1194 ErrorMessage
<uint8_t > (PSTR("Gen SCSI Err"), status
);
1195 ErrorMessage
<uint8_t > (PSTR("LUN"), bTheLUN
);
1201 ////////////////////////////////////////////////////////////////////////////////
1207 ////////////////////////////////////////////////////////////////////////////////
1213 void BulkOnly::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR
* ep_ptr
) {
1214 Notify(PSTR("Endpoint descriptor:"), 0x80);
1215 Notify(PSTR("\r\nLength:\t\t"), 0x80);
1216 D_PrintHex
<uint8_t > (ep_ptr
->bLength
, 0x80);
1217 Notify(PSTR("\r\nType:\t\t"), 0x80);
1218 D_PrintHex
<uint8_t > (ep_ptr
->bDescriptorType
, 0x80);
1219 Notify(PSTR("\r\nAddress:\t"), 0x80);
1220 D_PrintHex
<uint8_t > (ep_ptr
->bEndpointAddress
, 0x80);
1221 Notify(PSTR("\r\nAttributes:\t"), 0x80);
1222 D_PrintHex
<uint8_t > (ep_ptr
->bmAttributes
, 0x80);
1223 Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
1224 D_PrintHex
<uint16_t > (ep_ptr
->wMaxPacketSize
, 0x80);
1225 Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
1226 D_PrintHex
<uint8_t > (ep_ptr
->bInterval
, 0x80);
1227 Notify(PSTR("\r\n"), 0x80);
1231 ////////////////////////////////////////////////////////////////////////////////
1234 // misc/to kill/to-do
1237 ////////////////////////////////////////////////////////////////////////////////
1239 /* We won't be needing this... */
1240 uint8_t BulkOnly::Read(uint8_t lun
, uint32_t addr
, uint16_t bsize
, uint8_t blocks
, USBReadParser
* prs
) {
1242 if(!LUNOk
[lun
]) return MASS_ERR_NO_MEDIA
;
1243 Notify(PSTR("\r\nRead (With parser)\r\n"), 0x80);
1244 Notify(PSTR("---------\r\n"), 0x80);
1246 CommandBlockWrapper cbw
= CommandBlockWrapper();
1248 cbw
.dCBWSignature
= MASS_CBW_SIGNATURE
;
1249 cbw
.dCBWTag
= ++dCBWTag
;
1250 cbw
.dCBWDataTransferLength
= ((uint32_t)bsize
* blocks
);
1251 cbw
.bmCBWFlags
= MASS_CMD_DIR_IN
,
1253 cbw
.bmCBWCBLength
= 10;
1255 cbw
.CBWCB
[0] = SCSI_CMD_READ_10
;
1256 cbw
.CBWCB
[8] = blocks
;
1257 cbw
.CBWCB
[2] = ((addr
>> 24) & 0xff);
1258 cbw
.CBWCB
[3] = ((addr
>> 16) & 0xff);
1259 cbw
.CBWCB
[4] = ((addr
>> 8) & 0xff);
1260 cbw
.CBWCB
[5] = (addr
& 0xff);
1262 return HandleSCSIError(Transaction(&cbw
, bsize
, prs
, 1));
1264 return MASS_ERR_NOT_IMPLEMENTED
;