Zoltan Hudak / UsbHostMAX3421E

Dependents:   UsbHostMAX3421E_Hello

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers hidcomposite.cpp Source File

hidcomposite.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 "hidcomposite.h"
00019 
00020 HIDComposite::HIDComposite(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 HIDComposite::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 HIDComposite::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 
00072 bool HIDComposite::SetReportParser(uint8_t id, HIDReportParser *prs) {
00073         for(uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
00074                 if(rptParsers[i].rptId == 0 && rptParsers[i].rptParser == NULL) {
00075                         rptParsers[i].rptId = id;
00076                         rptParsers[i].rptParser = prs;
00077                         return true;
00078                 }
00079         }
00080         return false;
00081 }
00082 
00083 HIDReportParser* HIDComposite::GetReportParser(uint8_t id) {
00084         if(!bHasReportId)
00085                 return ((rptParsers[0].rptParser) ? rptParsers[0].rptParser : NULL);
00086 
00087         for(uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
00088                 if(rptParsers[i].rptId == id)
00089                         return rptParsers[i].rptParser;
00090         }
00091         return NULL;
00092 }
00093 
00094 uint8_t HIDComposite::Init(uint8_t parent, uint8_t port, bool lowspeed) {
00095         const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
00096 
00097         uint8_t buf[constBufSize];
00098         USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
00099         uint8_t rcode;
00100         UsbDevice *p = NULL;
00101         EpInfo *oldep_ptr = NULL;
00102         uint8_t len = 0;
00103 
00104         uint8_t num_of_conf; // number of configurations
00105         //uint8_t num_of_intf; // number of interfaces
00106 
00107         AddressPool &addrPool = pUsb->GetAddressPool();
00108 
00109         USBTRACE("HU Init\r\n");
00110 
00111         if(bAddress)
00112                 return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
00113 
00114         // Get pointer to pseudo device with address 0 assigned
00115         p = addrPool.GetUsbDevicePtr(0);
00116 
00117         if(!p)
00118                 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
00119 
00120         if(!p->epinfo) {
00121                 USBTRACE("epinfo\r\n");
00122                 return USB_ERROR_EPINFO_IS_NULL;
00123         }
00124 
00125         // Save old pointer to EP_RECORD of address 0
00126         oldep_ptr = p->epinfo;
00127 
00128         // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
00129         p->epinfo = epInfo;
00130 
00131         p->lowspeed = lowspeed;
00132 
00133         // Get device descriptor
00134         rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf);
00135 
00136         if(!rcode)
00137                 len = (buf[0] > constBufSize) ? constBufSize : buf[0];
00138 
00139         if(rcode) {
00140                 // Restore p->epinfo
00141                 p->epinfo = oldep_ptr;
00142 
00143                 goto FailGetDevDescr;
00144         }
00145 
00146         // Restore p->epinfo
00147         p->epinfo = oldep_ptr;
00148 
00149         // Allocate new address according to device class
00150         bAddress = addrPool.AllocAddress(parent, false, port);
00151 
00152         if(!bAddress)
00153                 return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
00154 
00155         // Extract Max Packet Size from the device descriptor
00156         epInfo[0].maxPktSize = udd->bMaxPacketSize0;
00157 
00158         // Assign new address to the device
00159         rcode = pUsb->setAddr(0, 0, bAddress);
00160 
00161         if(rcode) {
00162                 p->lowspeed = false;
00163                 addrPool.FreeAddress(bAddress);
00164                 bAddress = 0;
00165                 USBTRACE2("setAddr:", rcode);
00166                 return rcode;
00167         }
00168 
00169         //delay(2); //per USB 2.0 sect.9.2.6.3
00170 
00171         USBTRACE2("Addr:", bAddress);
00172 
00173         p->lowspeed = false;
00174 
00175         p = addrPool.GetUsbDevicePtr(bAddress);
00176 
00177         if(!p)
00178                 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
00179 
00180         p->lowspeed = lowspeed;
00181 
00182         if(len)
00183                 rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*)buf);
00184 
00185         if(rcode)
00186                 goto FailGetDevDescr;
00187 
00188         VID = udd->idVendor; // Can be used by classes that inherits this class to check the VID and PID of the connected device
00189         PID = udd->idProduct;
00190 
00191         num_of_conf = udd->bNumConfigurations;
00192 
00193         // Assign epInfo to epinfo pointer
00194         rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
00195 
00196         if(rcode)
00197                 goto FailSetDevTblEntry;
00198 
00199         USBTRACE2("NC:", num_of_conf);
00200 
00201         for(uint8_t i = 0; i < num_of_conf; i++) {
00202                 //HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
00203                 ConfigDescParser<USB_CLASS_HID, 0, 0,
00204                         CP_MASK_COMPARE_CLASS> confDescrParser(this);
00205 
00206                 //rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
00207                 rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
00208 
00209                 if(rcode)
00210                         goto FailGetConfDescr;
00211 
00212                 if(bNumEP > 1)
00213                         break;
00214         } // for
00215 
00216         if(bNumEP < 2)
00217                 return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
00218 
00219         // Assign epInfo to epinfo pointer
00220         rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
00221 
00222         USBTRACE2("Cnf:", bConfNum);
00223 
00224         // Set Configuration Value
00225         rcode = pUsb->setConf(bAddress, 0, bConfNum);
00226 
00227         if(rcode)
00228                 goto FailSetConfDescr;
00229 
00230         USBTRACE2("NumIface:", bNumIface);
00231 
00232         for(uint8_t i = 0; i < bNumIface; i++) {
00233                 if(hidInterfaces[i].epIndex[epInterruptInIndex] == 0)
00234                         continue;
00235 
00236                 USBTRACE2("SetIdle:", hidInterfaces[i].bmInterface);
00237 
00238                 rcode = SetIdle(hidInterfaces[i].bmInterface, 0, 0);
00239 
00240                 if(rcode && rcode != hrSTALL)
00241                         goto FailSetIdle;
00242         }
00243 
00244         USBTRACE("HU configured\r\n");
00245 
00246         OnInitSuccessful();
00247 
00248         bPollEnable = true;
00249         return 0;
00250 
00251 FailGetDevDescr:
00252 #ifdef DEBUG_USB_HOST
00253         NotifyFailGetDevDescr();
00254         goto Fail;
00255 #endif
00256 
00257 FailSetDevTblEntry:
00258 #ifdef DEBUG_USB_HOST
00259         NotifyFailSetDevTblEntry();
00260         goto Fail;
00261 #endif
00262 
00263 FailGetConfDescr:
00264 #ifdef DEBUG_USB_HOST
00265         NotifyFailGetConfDescr();
00266         goto Fail;
00267 #endif
00268 
00269 FailSetConfDescr:
00270 #ifdef DEBUG_USB_HOST
00271         NotifyFailSetConfDescr();
00272         goto Fail;
00273 #endif
00274 
00275 
00276 FailSetIdle:
00277 #ifdef DEBUG_USB_HOST
00278         USBTRACE("SetIdle:");
00279 #endif
00280 
00281 #ifdef DEBUG_USB_HOST
00282 Fail:
00283         NotifyFail(rcode);
00284 #endif
00285         Release();
00286         return rcode;
00287 }
00288 
00289 HIDComposite::HIDInterface* HIDComposite::FindInterface(uint8_t iface, uint8_t alt, uint8_t proto) {
00290         for(uint8_t i = 0; i < bNumIface && i < maxHidInterfaces; i++)
00291                 if(hidInterfaces[i].bmInterface == iface && hidInterfaces[i].bmAltSet == alt
00292                         && hidInterfaces[i].bmProtocol == proto)
00293                         return hidInterfaces + i;
00294         return NULL;
00295 }
00296 
00297 void HIDComposite::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
00298         //ErrorMessage<uint8_t>(PSTR("\r\nConf.Val"), conf);
00299         //ErrorMessage<uint8_t>(PSTR("Iface Num"), iface);
00300         //ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
00301 
00302         bConfNum = conf;
00303 
00304         uint8_t index = 0;
00305         HIDInterface *piface = FindInterface(iface, alt, proto);
00306 
00307         // Fill in interface structure in case of new interface
00308         if(!piface) {
00309                 piface = hidInterfaces + bNumIface;
00310                 piface->bmInterface = iface;
00311                 piface->bmAltSet = alt;
00312                 piface->bmProtocol = proto;
00313                 bNumIface++;
00314         }
00315 
00316         if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT)
00317                 index = (pep->bEndpointAddress & 0x80) == 0x80 ? epInterruptInIndex : epInterruptOutIndex;
00318 
00319         if(!SelectInterface(iface, proto))
00320                 index = 0;
00321 
00322         if(index) {
00323                 // Fill in the endpoint info structure
00324                 epInfo[bNumEP].epAddr = (pep->bEndpointAddress & 0x0F);
00325                 epInfo[bNumEP].maxPktSize = (uint8_t)pep->wMaxPacketSize;
00326                 epInfo[bNumEP].bmSndToggle = 0;
00327                 epInfo[bNumEP].bmRcvToggle = 0;
00328                 epInfo[bNumEP].bmNakPower = USB_NAK_NOWAIT;
00329 
00330                 // Fill in the endpoint index list
00331                 piface->epIndex[index] = bNumEP; //(pep->bEndpointAddress & 0x0F);
00332 
00333                 if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints
00334                         pollInterval = pep->bInterval;
00335 
00336                 bNumEP++;
00337         }
00338 }
00339 
00340 uint8_t HIDComposite::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 void HIDComposite::ZeroMemory(uint8_t len, uint8_t *buf) {
00351         for(uint8_t i = 0; i < len; i++)
00352                 buf[i] = 0;
00353 }
00354 
00355 uint8_t HIDComposite::Poll() {
00356         uint8_t rcode = 0;
00357 
00358         if(!bPollEnable)
00359                 return 0;
00360 
00361         if((int32_t)((uint32_t)millis() - qNextPollTime) >= 0L) {
00362                 qNextPollTime = (uint32_t)millis() + pollInterval;
00363 
00364                 uint8_t buf[constBuffLen];
00365 
00366                 for(uint8_t i = 0; i < bNumIface; i++) {
00367                         uint8_t index = hidInterfaces[i].epIndex[epInterruptInIndex];
00368 
00369                         if (index == 0)
00370                             continue;
00371 
00372                         uint16_t read = (uint16_t)epInfo[index].maxPktSize;
00373 
00374                         ZeroMemory(constBuffLen, buf);
00375 
00376                         uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[index].epAddr, &read, buf);
00377 
00378                         if(rcode) {
00379                                 if(rcode != hrNAK)
00380                                         USBTRACE3("(hidcomposite.h) Poll:", rcode, 0x81);
00381                                 continue;
00382                         }
00383 
00384                         if(read == 0)
00385                             continue;
00386 
00387                         if(read > constBuffLen)
00388                                 read = constBuffLen;
00389 
00390 #if 0
00391                         Notify(PSTR("\r\nBuf: "), 0x80);
00392 
00393                         for(uint8_t i = 0; i < read; i++) {
00394                                 D_PrintHex<uint8_t > (buf[i], 0x80);
00395                                 Notify(PSTR(" "), 0x80);
00396                         }
00397 
00398                         Notify(PSTR("\r\n"), 0x80);
00399 #endif
00400                         ParseHIDData(this, epInfo[index].epAddr, bHasReportId, (uint8_t)read, buf);
00401 
00402                         HIDReportParser *prs = GetReportParser(((bHasReportId) ? *buf : 0));
00403 
00404                         if(prs)
00405                                 prs->Parse(this, bHasReportId, (uint8_t)read, buf);
00406                     }
00407 
00408         }
00409         return rcode;
00410 }
00411 
00412 // Send a report to interrupt out endpoint. This is NOT SetReport() request!
00413 uint8_t HIDComposite::SndRpt(uint16_t nbytes, uint8_t *dataptr) {
00414         return pUsb->outTransfer(bAddress, epInfo[epInterruptOutIndex].epAddr, nbytes, dataptr);
00415 }