diff --git a/Usb.cpp b/Usb.cpp index 992f57e1..8d51be40 100644 --- a/Usb.cpp +++ b/Usb.cpp @@ -234,7 +234,9 @@ uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, ui if(( regRd( rHIRQ ) & bmRCVDAVIRQ ) == 0 ) return ( 0xf0 ); //receive error - pktsize = regRd( rRCVBC ); //number of received bytes */ + pktsize = regRd( rRCVBC ); //number of received bytes + + assert(pktsize <= nbytes); int16_t mem_left = (int16_t)nbytes - *((int16_t*)nbytesptr); @@ -249,10 +251,10 @@ uint8_t USB::InTransfer(EpInfo *pep, uint16_t nak_limit, uint16_t *nbytesptr, ui /* The transfer is complete under two conditions: */ /* 1. The device sent a short packet (L.T. maxPacketSize) */ /* 2. 'nbytes' have been transferred. */ - if (/*pktsize == 6 ||*/ ( pktsize < maxpktsize ) || (*nbytesptr >= nbytes )) // have we transferred 'nbytes' bytes? + if (( pktsize < maxpktsize ) || (*nbytesptr >= nbytes )) // have we transferred 'nbytes' bytes? { // Save toggle value - pep->bmRcvToggle = ( regRd( rHRSL ) & bmRCVTOGRD ) ? 1 : 0; + pep->bmRcvToggle = (( regRd( rHRSL ) & bmRCVTOGRD )) ? 1 : 0; return( 0 ); } // if diff --git a/Usb.h b/Usb.h index d331a09b..5a81e80c 100644 --- a/Usb.h +++ b/Usb.h @@ -21,6 +21,9 @@ e-mail : support@circuitsathome.com #define USB_METHODS_INLINE #include + +#include + #include "avrpins.h" #include "max3421e.h" #include "usbhost.h" @@ -120,9 +123,6 @@ public: #define USB_STATE_RUNNING 0x90 #define USB_STATE_ERROR 0xa0 - -// byte usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE - /* USB Setup Packet Structure */ typedef struct { union { // offset description diff --git a/hid.cpp b/hid.cpp index 3c53bbc9..225ac7d3 100644 --- a/hid.cpp +++ b/hid.cpp @@ -1,19 +1,3 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. - -This software may be distributed and modified under the terms of the GNU -General Public License version 2 (GPL2) as published by the Free Software -Foundation and appearing in the file GPL2.TXT included in the packaging of -this file. Please note that GPL2 Section 2[b] requires that all works based -on this software must also be made publicly available under the terms of -the GPL2 ("Copyleft"). - -Contact information -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ #include "hid.h" //const uint16_t HID::maxHidInterfaces = 3; @@ -316,13 +300,13 @@ uint8_t HID::Poll() if (qNextPollTime <= millis()) { - qNextPollTime = millis() + 100; + qNextPollTime = millis() + 500; const uint8_t const_buff_len = 16; uint8_t buf[const_buff_len]; HexDumper Hex; - uint16_t read = (uint16_t)const_buff_len; + uint16_t read = (uint16_t)epInfo[epInterruptInIndex].maxPktSize; uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf); @@ -395,6 +379,22 @@ void ReportDescParser::Parse(const uint16_t len, const uint8_t *pbuf, const uint //if (ParseItem(&p, &cntdn)) // return; } + USBTRACE2("Total:", totalSize); +} + +void ReportDescParser::PrintValue(uint8_t *p, uint8_t len) +{ + Notify(PSTR("(")); + for (; len; p++, len--) + PrintHex(*p); + Notify(PSTR(")")); +} + +void ReportDescParser::PrintByteValue(uint8_t data) +{ + Notify(PSTR("(")); + PrintHex(data); + Notify(PSTR(")")); } uint8_t ReportDescParser::ParseItem(uint8_t **pp, uint16_t *pcntdn) @@ -404,6 +404,11 @@ uint8_t ReportDescParser::ParseItem(uint8_t **pp, uint16_t *pcntdn) switch (itemParseState) { case 0: + if (**pp == HID_LONG_ITEM_PREFIX) + USBTRACE("\r\nLONG\r\n"); + //totalSize = 0; + //rptSize = 0; + //rptCount = 0; //if (**pp == HID_LONG_ITEM_PREFIX) //{ // *pp ++; @@ -417,12 +422,19 @@ uint8_t ReportDescParser::ParseItem(uint8_t **pp, uint16_t *pcntdn) //else { uint8_t size = ((**pp) & DATA_SIZE_MASK); + + USBTRACE2("\r\nSZ:", size); + itemPrefix = (**pp); itemSize = 1 + ((size == DATA_SIZE_4) ? 4 : size); - //USBTRACE2("Sz1:", size); - //Serial.print("\r\nSz:"); - //Serial.println(itemSize,DEC); + Serial.print("\r\nSz:"); + Serial.println(itemSize,DEC); + + PrintHex(*pcntdn); + Serial.print(":"); + PrintHex((itemPrefix & (TYPE_MASK | TAG_MASK))); + Serial.println(""); switch (itemPrefix & (TYPE_MASK | TAG_MASK)) { @@ -518,21 +530,29 @@ uint8_t ReportDescParser::ParseItem(uint8_t **pp, uint16_t *pcntdn) pfUsage(*((uint16_t*)varBuffer)); else pfUsage(data); + case (TYPE_GLOBAL | TAG_GLOBAL_REPORTSIZE): + rptSize = data; + PrintByteValue(data); + break; + case (TYPE_GLOBAL | TAG_GLOBAL_REPORTCOUNT): + rptCount = data; + PrintByteValue(data); + break; case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMIN): case (TYPE_GLOBAL | TAG_GLOBAL_LOGICALMAX): case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMIN): case (TYPE_GLOBAL | TAG_GLOBAL_PHYSMAX): - case (TYPE_GLOBAL | TAG_GLOBAL_REPORTSIZE): - case (TYPE_GLOBAL | TAG_GLOBAL_REPORTCOUNT): case (TYPE_GLOBAL | TAG_GLOBAL_REPORTID): case (TYPE_LOCAL | TAG_LOCAL_USAGEMIN): case (TYPE_LOCAL | TAG_LOCAL_USAGEMAX): case (TYPE_GLOBAL | TAG_GLOBAL_UNITEXP): case (TYPE_GLOBAL | TAG_GLOBAL_UNIT): - Notify(PSTR("(")); - for (uint8_t i=0; i(data); - Notify(PSTR(")")); + PrintValue(varBuffer, theBuffer.valueSize); + //Notify(PSTR("(")); + //for (uint8_t i=0; i(varBuffer[i]); + // //PrintHex(data); + //Notify(PSTR(")")); break; case (TYPE_GLOBAL | TAG_GLOBAL_PUSH): case (TYPE_GLOBAL | TAG_GLOBAL_POP): @@ -540,11 +560,7 @@ uint8_t ReportDescParser::ParseItem(uint8_t **pp, uint16_t *pcntdn) case (TYPE_GLOBAL | TAG_GLOBAL_USAGEPAGE): SetUsagePage(data); PrintUsagePage(data); - - Notify(PSTR("(")); - for (uint8_t i=0; i(data); - Notify(PSTR(")")); + PrintByteValue(data); break; case (TYPE_MAIN | TAG_MAIN_COLLECTION): case (TYPE_MAIN | TAG_MAIN_ENDCOLLECTION): @@ -580,6 +596,9 @@ uint8_t ReportDescParser::ParseItem(uint8_t **pp, uint16_t *pcntdn) case (TYPE_MAIN | TAG_MAIN_INPUT): case (TYPE_MAIN | TAG_MAIN_OUTPUT): case (TYPE_MAIN | TAG_MAIN_FEATURE): + totalSize += (uint16_t)rptSize * (uint16_t)rptCount; + rptSize = 0; + rptCount = 0; Notify(PSTR("(")); PrintBin(data); Notify(PSTR(")")); @@ -588,6 +607,13 @@ uint8_t ReportDescParser::ParseItem(uint8_t **pp, uint16_t *pcntdn) } itemParseState = 4; case 4: + USBTRACE2("iSz:", itemSize); + + PrintHex(*pcntdn); + Serial.print(":"); + PrintHex((itemPrefix & (TYPE_MASK | TAG_MASK))); + Serial.println(""); + if (itemSize > 1 && !theSkipper.Skip(pp, pcntdn, itemSize)) return enErrorIncomplete; } // switch (itemParseState) diff --git a/hid.h b/hid.h index 0f41e7e5..9c3be7c5 100644 --- a/hid.h +++ b/hid.h @@ -1,19 +1,3 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. - -This software may be distributed and modified under the terms of the GNU -General Public License version 2 (GPL2) as published by the Free Software -Foundation and appearing in the file GPL2.TXT included in the packaging of -this file. Please note that GPL2 Section 2[b] requires that all works based -on this software must also be made publicly available under the terms of -the GPL2 ("Copyleft"). - -Contact information -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ #if !defined(__HID_H__) #define __HID_H__ @@ -26,9 +10,9 @@ e-mail : support@circuitsathome.com #include "Usb.h" #include -#include "printhex.h" -#include "hexdump.h" -#include "message.h" +#include "..\DebugTools\printhex.h" +#include "..\DebugTools\hexdump.h" +#include "..\DebugTools\message.h" #include "confdescparser.h" @@ -180,6 +164,9 @@ public: static void PrintAlphanumDisplayPageUsage(uint16_t usage); static void PrintMedicalInstrumentPageUsage(uint16_t usage); + static void PrintValue(uint8_t *p, uint8_t len); + static void PrintByteValue(uint8_t data); + private: static UsagePageFunc usagePageFunctions[]; @@ -191,6 +178,10 @@ private: uint8_t itemParseState; // Item parser state variable uint8_t itemSize; // Item size uint8_t itemPrefix; // Item prefix (first byte) + uint8_t rptSize; // Report Size + uint8_t rptCount; // Report Count + + uint8_t totalSize; // Report size in bytes uint8_t ParseItem(uint8_t **pp, uint16_t *pcntdn); @@ -204,6 +195,8 @@ public: itemParseState(0), itemSize(0), itemPrefix(0), + rptSize(0), + rptCount(0), pfUsage(NULL) { theBuffer.pValue = varBuffer; diff --git a/masstorage.cpp b/masstorage.cpp new file mode 100644 index 00000000..21c25202 --- /dev/null +++ b/masstorage.cpp @@ -0,0 +1,328 @@ +#include "masstorage.h" + +const uint8_t BulkOnly::epDataInIndex = 1; +const uint8_t BulkOnly::epDataOutIndex = 2; +const uint8_t BulkOnly::epInterruptInIndex = 3; + +BulkOnly::BulkOnly(USB *p /*, CDCAsyncOper *pasync*/) : + pUsb(p), + //pAsync(pasync), + bAddress(0), + qNextPollTime(0), + bPollEnable(false), + bIface(0), + bNumEP(1) +{ + for(uint8_t i=0; iRegisterDeviceClass(this); +} + +uint8_t BulkOnly::Init(uint8_t parent, uint8_t port, bool lowspeed) +{ + const uint8_t constBufSize = sizeof(USB_DEVICE_DESCRIPTOR); + + uint8_t buf[constBufSize]; + uint8_t rcode; + UsbDevice *p = NULL; + EpInfo *oldep_ptr = NULL; + uint8_t num_of_conf; // number of configurations + + AddressPool &addrPool = pUsb->GetAddressPool(); + + USBTRACE("MS Init\r\n"); + + if (bAddress) + return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; + + // Get pointer to pseudo device with address 0 assigned + p = addrPool.GetUsbDevicePtr(0); + + if (!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + if (!p->epinfo) + { + USBTRACE("epinfo\r\n"); + return USB_ERROR_EPINFO_IS_NULL; + } + + // Save old pointer to EP_RECORD of address 0 + oldep_ptr = p->epinfo; + + // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence + p->epinfo = epInfo; + + p->lowspeed = lowspeed; + + // Get device descriptor + rcode = pUsb->getDevDescr( 0, 0, constBufSize, (uint8_t*)buf ); + + // Restore p->epinfo + p->epinfo = oldep_ptr; + + if( rcode ) + goto FailGetDevDescr; + + // Allocate new address according to device class + bAddress = addrPool.AllocAddress(parent, false, port); + + if (!bAddress) + return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; + + // Extract Max Packet Size from the device descriptor + epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0; + + // Assign new address to the device + rcode = pUsb->setAddr( 0, 0, bAddress ); + + if (rcode) + { + p->lowspeed = false; + addrPool.FreeAddress(bAddress); + bAddress = 0; + USBTRACE2("setAddr:",rcode); + return rcode; + } + + USBTRACE2("Addr:", bAddress); + + p->lowspeed = false; + + p = addrPool.GetUsbDevicePtr(bAddress); + + if (!p) + return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; + + p->lowspeed = lowspeed; + + num_of_conf = ((USB_DEVICE_DESCRIPTOR*)buf)->bNumConfigurations; + + // Assign epInfo to epinfo pointer + rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); + + if (rcode) + goto FailSetDevTblEntry; + + USBTRACE2("NC:", num_of_conf); + + for (uint8_t i=0; i HexDump; + ConfigDescParser< USB_CLASS_MASS_STORAGE, + MASS_SUBCLASS_SCSI, + MASS_PROTO_BBB, + CP_MASK_COMPARE_CLASS | + CP_MASK_COMPARE_SUBCLASS | + CP_MASK_COMPARE_PROTOCOL> BulkOnlyParser(this); + + rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump); + rcode = pUsb->getConfDescr(bAddress, 0, i, &BulkOnlyParser); + + + if (bNumEP > 1) + break; + } // for + + if (bNumEP < 4) + return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; + + // Assign epInfo to epinfo pointer + rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); + + USBTRACE2("Conf:", bConfNum); + + // Set Configuration Value + rcode = pUsb->setConf(bAddress, 0, bConfNum); + + if (rcode) + goto FailSetConf; + + //rcode = pAsync->OnInit(this); + + if (rcode) + goto FailOnInit; + + USBTRACE("MS configured\r\n"); + + //bPollEnable = true; + + //USBTRACE("Poll enabled\r\n"); + return 0; + +FailGetDevDescr: + USBTRACE("getDevDescr:"); + goto Fail; + +FailSetDevTblEntry: + USBTRACE("setDevTblEn:"); + goto Fail; + +FailGetConfDescr: + USBTRACE("getConf:"); + goto Fail; + +FailSetConf: + USBTRACE("setConf:"); + goto Fail; + +FailOnInit: + USBTRACE("OnInit:"); + goto Fail; + +Fail: + Serial.println(rcode, HEX); + Release(); + return rcode; +} + + +void BulkOnly::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) +{ + ErrorMessage(PSTR("Conf.Val"), conf); + ErrorMessage(PSTR("Iface Num"),iface); + ErrorMessage(PSTR("Alt.Set"), alt); + + bConfNum = conf; + + uint8_t index; + + if ((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80) + index = epInterruptInIndex; + else + if ((pep->bmAttributes & 0x02) == 2) + index = ((pep->bEndpointAddress & 0x80) == 0x80) ? epDataInIndex : epDataOutIndex; + else + return; + + // Fill in the endpoint info structure + epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); + epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; + epInfo[index].epAttribs = 0; + + bNumEP ++; + + PrintEndpointDescriptor(pep); +} + +uint8_t BulkOnly::Release() +{ + pUsb->GetAddressPool().FreeAddress(bAddress); + + bIface = 0; + bNumEP = 1; + + bAddress = 0; + qNextPollTime = 0; + bPollEnable = false; + return 0; +} + +uint8_t BulkOnly::Poll() +{ + uint8_t rcode = 0; + + if (!bPollEnable) + return 0; + + uint32_t time_now = millis(); + + //if (qNextPollTime <= time_now) + //{ + // qNextPollTime = time_now + 100; + + // uint8_t rcode; + // const uint8_t constBufSize = 16; + // uint8_t buf[constBufSize]; + + // for (uint8_t i=0; i epInfo[epInterruptInIndex].maxPktSize) + // ? epInfo[epInterruptInIndex].maxPktSize : constBufSize; + // rcode = pUsb->inTransfer(bAddress, epInfo[epInterruptInIndex].epAddr, &read, buf); + + // if (rcode) + // return rcode; + + // for (uint8_t i=0; i(buf[i]); + // Serial.print(" "); + // } + // USBTRACE("\r\n"); + //} + return rcode; +} + +//uint8_t ACM::RcvData(uint16_t *bytes_rcvd, uint8_t *dataptr) +//{ +// return pUsb->inTransfer(bAddress, epInfo[epDataInIndex].epAddr, bytes_rcvd, dataptr); +//} +// +//uint8_t ACM::SndData(uint16_t nbytes, uint8_t *dataptr) +//{ +// return pUsb->outTransfer(bAddress, epInfo[epDataOutIndex].epAddr, nbytes, dataptr); +//} +// +//uint8_t ACM::SetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) +//{ +// return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_SET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL )); +//} +// +//uint8_t ACM::GetCommFeature(uint16_t fid, uint8_t nbytes, uint8_t *dataptr) +//{ +// return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCIN, CDC_GET_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, nbytes, nbytes, dataptr, NULL )); +//} +// +//uint8_t ACM::ClearCommFeature(uint16_t fid) +//{ +// return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_CLEAR_COMM_FEATURE, (fid & 0xff), (fid >> 8), bControlIface, 0, 0, NULL, NULL )); +//} +// +//uint8_t ACM::SetLineCoding(const LINE_CODING *dataptr) +//{ +// return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_SET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof(LINE_CODING), sizeof(LINE_CODING), (uint8_t*)dataptr, NULL )); +//} +// +//uint8_t ACM::GetLineCoding(LINE_CODING *dataptr) +//{ +// return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCIN, CDC_GET_LINE_CODING, 0x00, 0x00, bControlIface, sizeof(LINE_CODING), sizeof(LINE_CODING), (uint8_t*)dataptr, NULL )); +//} +// +//uint8_t ACM::SetControlLineState(uint8_t state) +//{ +// return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_SET_CONTROL_LINE_STATE, state, 0, bControlIface, 0, 0, NULL, NULL )); +//} +// +//uint8_t ACM::SendBreak(uint16_t duration) +//{ +// return( pUsb->ctrlReq( bAddress, 0, bmREQ_CDCOUT, CDC_SEND_BREAK, (duration & 0xff), (duration >> 8), bControlIface, 0, 0, NULL, NULL )); +//} + + +void BulkOnly::PrintEndpointDescriptor( const USB_ENDPOINT_DESCRIPTOR* ep_ptr ) +{ + Notify(PSTR("Endpoint descriptor:")); + Notify(PSTR("\r\nLength:\t\t")); + PrintHex(ep_ptr->bLength); + Notify(PSTR("\r\nType:\t\t")); + PrintHex(ep_ptr->bDescriptorType); + Notify(PSTR("\r\nAddress:\t")); + PrintHex(ep_ptr->bEndpointAddress); + Notify(PSTR("\r\nAttributes:\t")); + PrintHex(ep_ptr->bmAttributes); + Notify(PSTR("\r\nMaxPktSize:\t")); + PrintHex(ep_ptr->wMaxPacketSize); + Notify(PSTR("\r\nPoll Intrv:\t")); + PrintHex(ep_ptr->bInterval); + Notify(PSTR("\r\n")); +} diff --git a/masstorage.h b/masstorage.h index 2d667ad9..4126c9a8 100644 --- a/masstorage.h +++ b/masstorage.h @@ -1,19 +1,3 @@ -/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved. - -This software may be distributed and modified under the terms of the GNU -General Public License version 2 (GPL2) as published by the Free Software -Foundation and appearing in the file GPL2.TXT included in the packaging of -this file. Please note that GPL2 Section 2[b] requires that all works based -on this software must also be made publicly available under the terms of -the GPL2 ("Copyleft"). - -Contact information -------------------- - -Circuits At Home, LTD -Web : http://www.circuitsathome.com -e-mail : support@circuitsathome.com -*/ #if !defined(__MASSTORAGE_H__) #define __MASSTORAGE_H__ @@ -26,9 +10,9 @@ e-mail : support@circuitsathome.com #include "Usb.h" #include -#include "printhex.h" -#include "hexdump.h" -#include "message.h" +#include "..\DebugTools\printhex.h" +#include "..\DebugTools\hexdump.h" +#include "..\DebugTools\message.h" #include "confdescparser.h" @@ -73,7 +57,7 @@ struct CommandBlockWrapper struct { uint8_t bCBWLUN : 4; - uint8_r bReserved1 : 4; + uint8_t bReserved1 : 4; }; struct { @@ -92,9 +76,31 @@ struct CommandStatusWrapper uint8_t bCSWStatus; }; +#define MASS_MAX_ENDPOINTS 3 + class BulkOnly : public USBDeviceConfig, public UsbConfigXtracter { +protected: + static const uint8_t epDataInIndex; // DataIn endpoint index + static const uint8_t epDataOutIndex; // DataOUT endpoint index + static const uint8_t epInterruptInIndex; // InterruptIN endpoint index + + USB *pUsb; +// CDCAsyncOper *pAsync; + uint8_t bAddress; + uint8_t bConfNum; // configuration number + uint8_t bIface; // interface value + uint8_t bNumEP; // total number of EP in the configuration + uint32_t qNextPollTime; // next poll time + bool bPollEnable; // poll enable flag + + EpInfo epInfo[MASS_MAX_ENDPOINTS]; + + void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr); + public: + BulkOnly(USB *p); + uint8_t Reset(); uint8_t GetMaxLun(uint8_t *max_lun);