]> git.friedersdorff.com Git - max/tmk_keyboard.git/blob - tmk_core/protocol/usb_hid/USB_Host_Shield_2.0/hiduniversal.cpp
lufa: usb-usb: Use LUFA startup instead of cusotom
[max/tmk_keyboard.git] / tmk_core / protocol / usb_hid / USB_Host_Shield_2.0 / hiduniversal.cpp
1 /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
2
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
8 the GPL2 ("Copyleft").
9
10 Contact information
11 -------------------
12
13 Circuits At Home, LTD
14 Web      :  http://www.circuitsathome.com
15 e-mail   :  support@circuitsathome.com
16  */
17
18 #include "hiduniversal.h"
19
20 HIDUniversal::HIDUniversal(USB *p) :
21 HID(p),
22 qNextPollTime(0),
23 pollInterval(0),
24 bPollEnable(false),
25 bHasReportId(false) {
26         Initialize();
27
28         if(pUsb)
29                 pUsb->RegisterDeviceClass(this);
30 }
31
32 uint16_t HIDUniversal::GetHidClassDescrLen(uint8_t type, uint8_t num) {
33         for(uint8_t i = 0, n = 0; i < HID_MAX_HID_CLASS_DESCRIPTORS; i++) {
34                 if(descrInfo[i].bDescrType == type) {
35                         if(n == num)
36                                 return descrInfo[i].wDescriptorLength;
37                         n++;
38                 }
39         }
40         return 0;
41 }
42
43 void HIDUniversal::Initialize() {
44         for(uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
45                 rptParsers[i].rptId = 0;
46                 rptParsers[i].rptParser = NULL;
47         }
48         for(uint8_t i = 0; i < HID_MAX_HID_CLASS_DESCRIPTORS; i++) {
49                 descrInfo[i].bDescrType = 0;
50                 descrInfo[i].wDescriptorLength = 0;
51         }
52         for(uint8_t i = 0; i < maxHidInterfaces; i++) {
53                 hidInterfaces[i].bmInterface = 0;
54                 hidInterfaces[i].bmProtocol = 0;
55
56                 for(uint8_t j = 0; j < maxEpPerInterface; j++)
57                         hidInterfaces[i].epIndex[j] = 0;
58         }
59         for(uint8_t i = 0; i < totalEndpoints; i++) {
60                 epInfo[i].epAddr = 0;
61                 epInfo[i].maxPktSize = (i) ? 0 : 8;
62                 epInfo[i].epAttribs = 0;
63                 epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
64         }
65         bNumEP = 1;
66         bNumIface = 0;
67         bConfNum = 0;
68         pollInterval = 0;
69
70         ZeroMemory(constBuffLen, prevBuf);
71 }
72
73 bool HIDUniversal::SetReportParser(uint8_t id, HIDReportParser *prs) {
74         for(uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
75                 if(rptParsers[i].rptId == 0 && rptParsers[i].rptParser == NULL) {
76                         rptParsers[i].rptId = id;
77                         rptParsers[i].rptParser = prs;
78                         return true;
79                 }
80         }
81         return false;
82 }
83
84 HIDReportParser* HIDUniversal::GetReportParser(uint8_t id) {
85         if(!bHasReportId)
86                 return ((rptParsers[0].rptParser) ? rptParsers[0].rptParser : NULL);
87
88         for(uint8_t i = 0; i < MAX_REPORT_PARSERS; i++) {
89                 if(rptParsers[i].rptId == id)
90                         return rptParsers[i].rptParser;
91         }
92         return NULL;
93 }
94
95 uint8_t HIDUniversal::Init(uint8_t parent, uint8_t port, bool lowspeed) {
96         const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
97
98         uint8_t buf[constBufSize];
99         USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
100         uint8_t rcode;
101         UsbDevice *p = NULL;
102         EpInfo *oldep_ptr = NULL;
103         uint8_t len = 0;
104
105         uint8_t num_of_conf; // number of configurations
106         //uint8_t num_of_intf; // number of interfaces
107
108         AddressPool &addrPool = pUsb->GetAddressPool();
109
110         USBTRACE("HU Init\r\n");
111
112         if(bAddress)
113                 return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
114
115         // Get pointer to pseudo device with address 0 assigned
116         p = addrPool.GetUsbDevicePtr(0);
117
118         if(!p)
119                 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
120
121         if(!p->epinfo) {
122                 USBTRACE("epinfo\r\n");
123                 return USB_ERROR_EPINFO_IS_NULL;
124         }
125
126         // Save old pointer to EP_RECORD of address 0
127         oldep_ptr = p->epinfo;
128
129         // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
130         p->epinfo = epInfo;
131
132         p->lowspeed = lowspeed;
133
134         // Get device descriptor
135         rcode = pUsb->getDevDescr(0, 0, 8, (uint8_t*)buf);
136
137         if(!rcode)
138                 len = (buf[0] > constBufSize) ? constBufSize : buf[0];
139
140         if(rcode) {
141                 // Restore p->epinfo
142                 p->epinfo = oldep_ptr;
143
144                 goto FailGetDevDescr;
145         }
146
147         // Restore p->epinfo
148         p->epinfo = oldep_ptr;
149
150         // Allocate new address according to device class
151         bAddress = addrPool.AllocAddress(parent, false, port);
152
153         if(!bAddress)
154                 return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
155
156         // Extract Max Packet Size from the device descriptor
157         epInfo[0].maxPktSize = udd->bMaxPacketSize0;
158
159         // Assign new address to the device
160         rcode = pUsb->setAddr(0, 0, bAddress);
161
162         if(rcode) {
163                 p->lowspeed = false;
164                 addrPool.FreeAddress(bAddress);
165                 bAddress = 0;
166                 USBTRACE2("setAddr:", rcode);
167                 return rcode;
168         }
169
170         //delay(2); //per USB 2.0 sect.9.2.6.3
171
172         USBTRACE2("Addr:", bAddress);
173
174         p->lowspeed = false;
175
176         p = addrPool.GetUsbDevicePtr(bAddress);
177
178         if(!p)
179                 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
180
181         p->lowspeed = lowspeed;
182
183         if(len)
184                 rcode = pUsb->getDevDescr(bAddress, 0, len, (uint8_t*)buf);
185
186         if(rcode)
187                 goto FailGetDevDescr;
188
189         VID = udd->idVendor; // Can be used by classes that inherits this class to check the VID and PID of the connected device
190         PID = udd->idProduct;
191
192         num_of_conf = udd->bNumConfigurations;
193
194         // Assign epInfo to epinfo pointer
195         rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
196
197         if(rcode)
198                 goto FailSetDevTblEntry;
199
200         USBTRACE2("NC:", num_of_conf);
201
202         for(uint8_t i = 0; i < num_of_conf; i++) {
203                 //HexDumper<USBReadParser, uint16_t, uint16_t> HexDump;
204                 ConfigDescParser<USB_CLASS_HID, 0, 0,
205                         CP_MASK_COMPARE_CLASS> confDescrParser(this);
206
207                 //rcode = pUsb->getConfDescr(bAddress, 0, i, &HexDump);
208                 rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
209
210                 if(rcode)
211                         goto FailGetConfDescr;
212
213                 if(bNumEP > 1)
214                         break;
215         } // for
216
217         if(bNumEP < 2)
218                 return USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
219
220         // Assign epInfo to epinfo pointer
221         rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
222
223         USBTRACE2("Cnf:", bConfNum);
224
225         // Set Configuration Value
226         rcode = pUsb->setConf(bAddress, 0, bConfNum);
227
228         if(rcode)
229                 goto FailSetConfDescr;
230
231         for(uint8_t i = 0; i < bNumIface; i++) {
232                 if(hidInterfaces[i].epIndex[epInterruptInIndex] == 0)
233                         continue;
234
235                 rcode = SetIdle(hidInterfaces[i].bmInterface, 0, 0);
236
237                 if(rcode && rcode != hrSTALL)
238                         goto FailSetIdle;
239         }
240
241         USBTRACE("HU configured\r\n");
242
243         OnInitSuccessful();
244
245         bPollEnable = true;
246         return 0;
247
248 FailGetDevDescr:
249 #ifdef DEBUG_USB_HOST
250         NotifyFailGetDevDescr();
251         goto Fail;
252 #endif
253
254 FailSetDevTblEntry:
255 #ifdef DEBUG_USB_HOST
256         NotifyFailSetDevTblEntry();
257         goto Fail;
258 #endif
259
260 FailGetConfDescr:
261 #ifdef DEBUG_USB_HOST
262         NotifyFailGetConfDescr();
263         goto Fail;
264 #endif
265
266 FailSetConfDescr:
267 #ifdef DEBUG_USB_HOST
268         NotifyFailSetConfDescr();
269         goto Fail;
270 #endif
271
272
273 FailSetIdle:
274 #ifdef DEBUG_USB_HOST
275         USBTRACE("SetIdle:");
276 #endif
277
278 #ifdef DEBUG_USB_HOST
279 Fail:
280         NotifyFail(rcode);
281 #endif
282         Release();
283         return rcode;
284 }
285
286 HIDUniversal::HIDInterface* HIDUniversal::FindInterface(uint8_t iface, uint8_t alt, uint8_t proto) {
287         for(uint8_t i = 0; i < bNumIface && i < maxHidInterfaces; i++)
288                 if(hidInterfaces[i].bmInterface == iface && hidInterfaces[i].bmAltSet == alt
289                         && hidInterfaces[i].bmProtocol == proto)
290                         return hidInterfaces + i;
291         return NULL;
292 }
293
294 void HIDUniversal::EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *pep) {
295         // If the first configuration satisfies, the others are not concidered.
296         if(bNumEP > 1 && conf != bConfNum)
297                 return;
298
299         //ErrorMessage<uint8_t>(PSTR("\r\nConf.Val"), conf);
300         //ErrorMessage<uint8_t>(PSTR("Iface Num"), iface);
301         //ErrorMessage<uint8_t>(PSTR("Alt.Set"), alt);
302
303         bConfNum = conf;
304
305         uint8_t index = 0;
306         HIDInterface *piface = FindInterface(iface, alt, proto);
307
308         // Fill in interface structure in case of new interface
309         if(!piface) {
310                 piface = hidInterfaces + bNumIface;
311                 piface->bmInterface = iface;
312                 piface->bmAltSet = alt;
313                 piface->bmProtocol = proto;
314                 bNumIface++;
315         }
316
317         if((pep->bmAttributes & 0x03) == 3 && (pep->bEndpointAddress & 0x80) == 0x80)
318                 index = epInterruptInIndex;
319         else
320                 index = epInterruptOutIndex;
321
322         if(index) {
323                 // Fill in the endpoint info structure
324                 epInfo[bNumEP].epAddr = (pep->bEndpointAddress & 0x0F);
325                 epInfo[bNumEP].maxPktSize = (uint8_t)pep->wMaxPacketSize;
326                 epInfo[bNumEP].epAttribs = 0;
327                 epInfo[bNumEP].bmNakPower = USB_NAK_NOWAIT;
328
329                 // Fill in the endpoint index list
330                 piface->epIndex[index] = bNumEP; //(pep->bEndpointAddress & 0x0F);
331
332                 if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints
333                         pollInterval = pep->bInterval;
334
335                 bNumEP++;
336         }
337         //PrintEndpointDescriptor(pep);
338 }
339
340 uint8_t HIDUniversal::Release() {
341         pUsb->GetAddressPool().FreeAddress(bAddress);
342
343         bNumEP = 1;
344         bAddress = 0;
345         qNextPollTime = 0;
346         bPollEnable = false;
347         return 0;
348 }
349
350 bool HIDUniversal::BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2) {
351         for(uint8_t i = 0; i < len; i++)
352                 if(buf1[i] != buf2[i])
353                         return false;
354         return true;
355 }
356
357 void HIDUniversal::ZeroMemory(uint8_t len, uint8_t *buf) {
358         for(uint8_t i = 0; i < len; i++)
359                 buf[i] = 0;
360 }
361
362 void HIDUniversal::SaveBuffer(uint8_t len, uint8_t *src, uint8_t *dest) {
363         for(uint8_t i = 0; i < len; i++)
364                 dest[i] = src[i];
365 }
366
367 uint8_t HIDUniversal::Poll() {
368         uint8_t rcode = 0;
369
370         if(!bPollEnable)
371                 return 0;
372
373         if((long)(millis() - qNextPollTime) >= 0L) {
374                 qNextPollTime = millis() + pollInterval;
375
376                 uint8_t buf[constBuffLen];
377
378                 for(uint8_t i = 0; i < bNumIface; i++) {
379                         uint8_t index = hidInterfaces[i].epIndex[epInterruptInIndex];
380                         uint16_t read = (uint16_t)epInfo[index].maxPktSize;
381
382                         ZeroMemory(constBuffLen, buf);
383
384                         uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[index].epAddr, &read, buf);
385
386                         if(rcode) {
387                                 if(rcode != hrNAK)
388                                         USBTRACE3("(hiduniversal.h) Poll:", rcode, 0x81);
389                                 return rcode;
390                         }
391
392                         if(read > constBuffLen)
393                                 read = constBuffLen;
394
395                         bool identical = BuffersIdentical(read, buf, prevBuf);
396
397                         SaveBuffer(read, buf, prevBuf);
398
399                         if(identical)
400                                 return 0;
401 #if 0
402                         Notify(PSTR("\r\nBuf: "), 0x80);
403
404                         for(uint8_t i = 0; i < read; i++) {
405                                 D_PrintHex<uint8_t > (buf[i], 0x80);
406                                 Notify(PSTR(" "), 0x80);
407                         }
408
409                         Notify(PSTR("\r\n"), 0x80);
410 #endif
411                         ParseHIDData(this, bHasReportId, (uint8_t)read, buf);
412
413                         HIDReportParser *prs = GetReportParser(((bHasReportId) ? *buf : 0));
414
415                         if(prs)
416                                 prs->Parse(this, bHasReportId, (uint8_t)read, buf);
417                 }
418         }
419         return rcode;
420 }
421
422 // Send a report to interrupt out endpoint. This is NOT SetReport() request!
423 uint8_t HIDUniversal::SndRpt(uint16_t nbytes, uint8_t *dataptr) {
424         return pUsb->outTransfer(bAddress, epInfo[epInterruptOutIndex].epAddr, nbytes, dataptr);
425 }