Zoltan Hudak / UsbHostMAX3421E

Dependents:   UsbHostMAX3421E_Hello

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers hiduniversal.cpp Source File

hiduniversal.cpp

00001 /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
00002 
00003 This software may be distributed and modified under the terms of the GNU
00004 General Public License version 2 (GPL2) as published by the Free Software
00005 Foundation and appearing in the file GPL2.TXT included in the packaging of
00006 this file. Please note that GPL2 Section 2[b] requires that all works based
00007 on this software must also be made publicly available under the terms of
00008 the GPL2 ("Copyleft").
00009 
00010 Contact information
00011 -------------------
00012 
00013 Circuits At Home, LTD
00014 Web      :  http://www.circuitsathome.com
00015 e-mail   :  support@circuitsathome.com
00016  */
00017 
00018 #include "hiduniversal.h"
00019 
00020 HIDUniversal::HIDUniversal(Usb *p) :
00021 USBHID(p),
00022 qNextPollTime(0),
00023 pollInterval(0),
00024 bPollEnable(false),
00025 bHasReportId(false) {
00026         Initialize();
00027 
00028         if(pUsb)
00029                 pUsb->RegisterDeviceClass(this);
00030 }
00031 
00032 uint16_t HIDUniversal::GetHidClassDescrLen(uint8_t type, uint8_t num) {
00033         for(uint8_t i = 0, n = 0; i < HID_MAX_HID_CLASS_DESCRIPTORS; i++) {
00034                 if(descrInfo[i].bDescrType == type) {
00035                         if(n == num)
00036                                 return descrInfo[i].wDescriptorLength;
00037                         n++;
00038                 }
00039         }
00040         return 0;
00041 }
00042 
00043 void HIDUniversal::Initialize() {
00044         for(uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
00045                 rptParsers[i].rptId = 0;
00046                 rptParsers[i].rptParser = NULL;
00047         }
00048         for(uint8_t i = 0; i < HID_MAX_HID_CLASS_DESCRIPTORS; i++) {
00049                 descrInfo[i].bDescrType = 0;
00050                 descrInfo[i].wDescriptorLength = 0;
00051         }
00052         for(uint8_t i = 0; i < maxHidInterfaces; i++) {
00053                 hidInterfaces[i].bmInterface = 0;
00054                 hidInterfaces[i].bmProtocol = 0;
00055 
00056                 for(uint8_t j = 0; j < maxEpPerInterface; j++)
00057                         hidInterfaces[i].epIndex[j] = 0;
00058         }
00059         for(uint8_t i = 0; i < totalEndpoints; i++) {
00060                 epInfo[i].epAddr = 0;
00061                 epInfo[i].maxPktSize = (i) ? 0 : 8;
00062                 epInfo[i].bmSndToggle = 0;
00063                 epInfo[i].bmRcvToggle = 0;
00064                 epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
00065         }
00066         bNumEP = 1;
00067         bNumIface = 0;
00068         bConfNum = 0;
00069         pollInterval = 0;
00070 
00071         ZeroMemory(constBuffLen, prevBuf);
00072 }
00073 
00074 bool HIDUniversal::SetReportParser(uint8_t id, HIDReportParser *prs) {
00075         for(uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
00076                 if(rptParsers[i].rptId == 0 && rptParsers[i].rptParser == NULL) {
00077                         rptParsers[i].rptId = id;
00078                         rptParsers[i].rptParser = prs;
00079                         return true;
00080                 }
00081         }
00082         return false;
00083 }
00084 
00085 HIDReportParser* HIDUniversal::GetReportParser(uint8_t id) {
00086         if(!bHasReportId)
00087                 return ((rptParsers[0].rptParser) ? rptParsers[0].rptParser : NULL);
00088 
00089         for(uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
00090                 if(rptParsers[i].rptId == id)
00091                         return rptParsers[i].rptParser;
00092         }
00093         return NULL;
00094 }
00095 
00096 uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed) {
00097         const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
00098 
00099         uint8_t buf[constBufSize];
00100         USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
00101         uint8_t rcode;
00102         UsbDevice *p = NULL;
00103         EpInfo *oldep_ptr = NULL;
00104         uint8_t len = 0;
00105 
00106         uint8_t num_of_conf; // number of configurations
00107         //uint8_t num_of_intf; // number of interfaces
00108 
00109         AddressPool &addrPool = pUsb->GetAddressPool();
00110 
00111         USBTRACE("HU Init\r\n");
00112 
00113         if(bAddress)
00114                 return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
00115 
00116         // Get pointer to pseudo device with address 0 assigned
00117         p = addrPool.GetUsbDevicePtr(0);
00118 
00119         if(!p)
00120                 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
00121 
00122         if(!p->epinfo) {
00123                 USBTRACE("epinfo\r\n");
00124                 return USB_ERROR_EPINFO_IS_NULL;
00125         }
00126 
00127         // Save old pointer to EP_RECORD of address 0
00128         oldep_ptr = p->epinfo;
00129 
00130         // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
00131         p->epinfo = epInfo;
00132 
00133         p->lowspeed = lowspeed;
00134 
00135         // Get device descriptor
00136         rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf);
00137 
00138         if(!rcode)
00139                 len = (buf[0] > constBufSize) ? constBufSize : buf[0];
00140 
00141         if(rcode) {
00142                 // Restore p->epinfo
00143                 p->epinfo = oldep_ptr;
00144 
00145                 goto FailGetDevDescr;
00146         }
00147 
00148         // Restore p->epinfo
00149         p->epinfo = oldep_ptr;
00150 
00151         // Allocate new address according to device class
00152         bAddress = addrPool.AllocAddress(parent, false, port);
00153 
00154         if(!bAddress)
00155                 return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
00156 
00157         // Extract Max Packet Size from the device descriptor
00158         epInfo[0].maxPktSize = udd->bMaxPacketSize0;
00159 
00160         // Assign new address to the device
00161         rcode = pUsb->setAddr(0, 0, bAddress);
00162 
00163         if(rcode) {
00164                 p->lowspeed = false;
00165                 addrPool.FreeAddress(bAddress);
00166                 bAddress = 0;
00167                 USBTRACE2("setAddr:", rcode);
00168                 return rcode;
00169         }
00170 
00171         //delay(2); //per USB 2.0 sect.9.2.6.3
00172 
00173         USBTRACE2("Addr:", bAddress);
00174 
00175         p->lowspeed = false;
00176 
00177         p = addrPool.GetUsbDevicePtr(bAddress);
00178 
00179         if(!p)
00180                 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
00181 
00182         p->lowspeed = lowspeed;
00183 
00184         if(len)
00185                 rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*)buf);
00186 
00187         if(rcode)
00188                 goto FailGetDevDescr;
00189 
00190         VID = udd->idVendor; // Can be used by classes that inherits this class to check the VID and PID of the connected device
00191         PID = udd->idProduct;
00192 
00193         num_of_conf = udd->bNumConfigurations;
00194 
00195         // Assign epInfo to epinfo pointer
00196         rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
00197 
00198         if(rcode)
00199                 goto FailSetDevTblEntry;
00200 
00201         USBTRACE2("NC:", num_of_conf);
00202 
00203         for(uint8_t i = 0; i < num_of_conf; i++) {
00204                 //HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
00205                 ConfigDescParser<USB_CLASS_HID, 0, 0,
00206                         CP_MASK_COMPARE_CLASS> confDescrParser(this);
00207 
00208                 //rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
00209                 rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
00210 
00211                 if(rcode)
00212                         goto FailGetConfDescr;
00213 
00214                 if(bNumEP > 1)
00215                         break;
00216         } // for
00217 
00218         if(bNumEP < 2)
00219                 return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
00220 
00221         // Assign epInfo to epinfo pointer
00222         rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
00223 
00224         USBTRACE2("Cnf:", bConfNum);
00225 
00226         // Set Configuration Value
00227         rcode = pUsb->setConf(bAddress, 0, bConfNum);
00228 
00229         if(rcode)
00230                 goto FailSetConfDescr;
00231 
00232         for(uint8_t i = 0; i < bNumIface; i++) {
00233                 if(hidInterfaces[i].epIndex[epInterruptInIndex] == 0)
00234                         continue;
00235 
00236                 rcode = SetIdle(hidInterfaces[i].bmInterface, 0, 0);
00237 
00238                 if(rcode && rcode != hrSTALL)
00239                         goto FailSetIdle;
00240         }
00241 
00242         USBTRACE("HU configured\r\n");
00243 
00244         OnInitSuccessful();
00245 
00246         bPollEnable = true;
00247         return 0;
00248 
00249 FailGetDevDescr:
00250 #ifdef DEBUG_USB_HOST
00251         NotifyFailGetDevDescr();
00252         goto Fail;
00253 #endif
00254 
00255 FailSetDevTblEntry:
00256 #ifdef DEBUG_USB_HOST
00257         NotifyFailSetDevTblEntry();
00258         goto Fail;
00259 #endif
00260 
00261 FailGetConfDescr:
00262 #ifdef DEBUG_USB_HOST
00263         NotifyFailGetConfDescr();
00264         goto Fail;
00265 #endif
00266 
00267 FailSetConfDescr:
00268 #ifdef DEBUG_USB_HOST
00269         NotifyFailSetConfDescr();
00270         goto Fail;
00271 #endif
00272 
00273 
00274 FailSetIdle:
00275 #ifdef DEBUG_USB_HOST
00276         USBTRACE("SetIdle:");
00277 #endif
00278 
00279 #ifdef DEBUG_USB_HOST
00280 Fail:
00281         NotifyFail(rcode);
00282 #endif
00283         Release();
00284         return rcode;
00285 }
00286 
00287 HIDUniversal::HIDInterface* HIDUniversal::FindInterface(uint8_t iface, uint8_t alt, uint8_t proto) {
00288         for(uint8_t i = 0; i < bNumIface && i < maxHidInterfaces; i++)
00289                 if(hidInterfaces[i].bmInterface == iface && hidInterfaces[i].bmAltSet == alt
00290                         && hidInterfaces[i].bmProtocol == proto)
00291                         return hidInterfaces + i;
00292         return NULL;
00293 }
00294 
00295 void HIDUniversal::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
00296         // If the first configuration satisfies, the others are not concidered.
00297         if(bNumEP > 1 && conf != bConfNum)
00298                 return;
00299 
00300         //ErrorMessage<uint8_t>(PSTR("\r\nConf.Val"), conf);
00301         //ErrorMessage<uint8_t>(PSTR("Iface Num"), iface);
00302         //ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
00303 
00304         bConfNum = conf;
00305 
00306         uint8_t index = 0;
00307         HIDInterface *piface = FindInterface(iface, alt, proto);
00308 
00309         // Fill in interface structure in case of new interface
00310         if(!piface) {
00311                 piface = hidInterfaces + bNumIface;
00312                 piface->bmInterface = iface;
00313                 piface->bmAltSet = alt;
00314                 piface->bmProtocol = proto;
00315                 bNumIface++;
00316         }
00317 
00318         if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT)
00319                 index = (pep->bEndpointAddress & 0x80) == 0x80 ? epInterruptInIndex : epInterruptOutIndex;
00320 
00321         if(index) {
00322                 // Fill in the endpoint info structure
00323                 epInfo[bNumEP].epAddr = (pep->bEndpointAddress & 0x0F);
00324                 epInfo[bNumEP].maxPktSize = (uint8_t)pep->wMaxPacketSize;
00325                 epInfo[bNumEP].bmSndToggle = 0;
00326                 epInfo[bNumEP].bmRcvToggle = 0;
00327                 epInfo[bNumEP].bmNakPower = USB_NAK_NOWAIT;
00328 
00329                 // Fill in the endpoint index list
00330                 piface->epIndex[index] = bNumEP; //(pep->bEndpointAddress & 0x0F);
00331 
00332                 if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints
00333                         pollInterval = pep->bInterval;
00334 
00335                 bNumEP++;
00336         }
00337         //PrintEndpointDescriptor(pep);
00338 }
00339 
00340 uint8_t HIDUniversal::Release() {
00341         pUsb->GetAddressPool().FreeAddress(bAddress);
00342 
00343         bNumEP = 1;
00344         bAddress = 0;
00345         qNextPollTime = 0;
00346         bPollEnable = false;
00347         return 0;
00348 }
00349 
00350 bool HIDUniversal::BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2) {
00351         for(uint8_t i = 0; i < len; i++)
00352                 if(buf1[i] != buf2[i])
00353                         return false;
00354         return true;
00355 }
00356 
00357 void HIDUniversal::ZeroMemory(uint8_t len, uint8_t *buf) {
00358         for(uint8_t i = 0; i < len; i++)
00359                 buf[i] = 0;
00360 }
00361 
00362 void HIDUniversal::SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest) {
00363         for(uint8_t i = 0; i < len; i++)
00364                 dest[i] = src[i];
00365 }
00366 
00367 uint8_t HIDUniversal::Poll() {
00368         uint8_t rcode = 0;
00369 
00370         if(!bPollEnable)
00371                 return 0;
00372 
00373         if((int32_t)((uint32_t)millis() - qNextPollTime) >= 0L) {
00374                 qNextPollTime = (uint32_t)millis() + pollInterval;
00375 
00376                 uint8_t buf[constBuffLen];
00377 
00378                 for(uint8_t i = 0; i < bNumIface; i++) {
00379                         uint8_t index = hidInterfaces[i].epIndex[epInterruptInIndex];
00380                         uint16_t read = (uint16_t)epInfo[index].maxPktSize;
00381 
00382                         ZeroMemory(constBuffLen, buf);
00383 
00384                         uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[index].epAddr, &read, buf);
00385 
00386                         if(rcode) {
00387                                 if(rcode != hrNAK)
00388                                         USBTRACE3("(hiduniversal.h) Poll:", rcode, 0x81);
00389                                 return rcode;
00390                         }
00391 
00392                         if(read > constBuffLen)
00393                                 read = constBuffLen;
00394 
00395                         bool identical = BuffersIdentical(read, buf, prevBuf);
00396 
00397                         SaveBuffer(read, buf, prevBuf);
00398 
00399                         if(identical)
00400                                 return 0;
00401 #if 0
00402                         Notify(PSTR("\r\nBuf: "), 0x80);
00403 
00404                         for(uint8_t i = 0; i < read; i++) {
00405                                 D_PrintHex<uint8_t > (buf[i], 0x80);
00406                                 Notify(PSTR(" "), 0x80);
00407                         }
00408 
00409                         Notify(PSTR("\r\n"), 0x80);
00410 #endif
00411                         ParseHIDData(this, bHasReportId, (uint8_t)read, buf);
00412 
00413                         HIDReportParser *prs = GetReportParser(((bHasReportId) ? *buf : 0));
00414 
00415                         if(prs)
00416                                 prs->Parse(this, bHasReportId, (uint8_t)read, buf);
00417                 }
00418         }
00419         return rcode;
00420 }
00421 
00422 // Send a report to interrupt out endpoint. This is NOT SetReport() request!
00423 uint8_t HIDUniversal::SndRpt(uint16_t nbytes, uint8_t *dataptr) {
00424         return pUsb->outTransfer(bAddress, epInfo[epInterruptOutIndex].epAddr, nbytes, dataptr);
00425 }