]> git.friedersdorff.com Git - max/tmk_keyboard.git/blob - tmk_core/protocol/usb_hid/USB_Host_Shield_2.0/address.h
c3e1b3141f2741f83c8d9310bc4a17376fe3eded
[max/tmk_keyboard.git] / tmk_core / protocol / usb_hid / USB_Host_Shield_2.0 / address.h
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 #if !defined(_usb_h_) || defined(__ADDRESS_H__)
19 #error "Never include address.h directly; include Usb.h instead"
20 #else
21 #define __ADDRESS_H__
22
23
24
25 /* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */
26 /* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
27 #define USB_NAK_MAX_POWER               15              //NAK binary order maximum value
28 #define USB_NAK_DEFAULT                 14              //default 32K-1 NAKs before giving up
29 #define USB_NAK_NOWAIT                  1               //Single NAK stops transfer
30 #define USB_NAK_NONAK                   0               //Do not count NAKs, stop retrying after USB Timeout
31
32 struct EpInfo {
33         uint8_t epAddr; // Endpoint address
34         uint8_t maxPktSize; // Maximum packet size
35
36         union {
37                 uint8_t epAttribs;
38
39                 struct {
40                         uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
41                         uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
42                         uint8_t bmNakPower : 6; // Binary order for NAK_LIMIT value
43                 } __attribute__((packed));
44         };
45 } __attribute__((packed));
46
47 //        7   6   5   4   3   2   1   0
48 //  ---------------------------------
49 //  |   | H | P | P | P | A | A | A |
50 //  ---------------------------------
51 //
52 // H - if 1 the address is a hub address
53 // P - parent hub address
54 // A - device address / port number in case of hub
55 //
56
57 struct UsbDeviceAddress {
58
59         union {
60
61                 struct {
62                         uint8_t bmAddress : 3; // device address/port number
63                         uint8_t bmParent : 3; // parent hub address
64                         uint8_t bmHub : 1; // hub flag
65                         uint8_t bmReserved : 1; // reserved, must be zero
66                 } __attribute__((packed));
67                 uint8_t devAddress;
68         };
69 } __attribute__((packed));
70
71 #define bmUSB_DEV_ADDR_ADDRESS          0x07
72 #define bmUSB_DEV_ADDR_PARENT           0x38
73 #define bmUSB_DEV_ADDR_HUB              0x40
74
75 struct UsbDevice {
76         EpInfo *epinfo; // endpoint info pointer
77         UsbDeviceAddress address;
78         uint8_t epcount; // number of endpoints
79         bool lowspeed; // indicates if a device is the low speed one
80         //      uint8_t devclass; // device class
81 } __attribute__((packed));
82
83 class AddressPool {
84 public:
85         virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) = 0;
86         virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) = 0;
87         virtual void FreeAddress(uint8_t addr) = 0;
88 };
89
90 typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
91
92 #define ADDR_ERROR_INVALID_INDEX                0xFF
93 #define ADDR_ERROR_INVALID_ADDRESS              0xFF
94
95 template <const uint8_t MAX_DEVICES_ALLOWED>
96 class AddressPoolImpl : public AddressPool {
97         EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device
98
99         uint8_t hubCounter; // hub counter is kept
100         // in order to avoid hub address duplication
101
102         UsbDevice thePool[MAX_DEVICES_ALLOWED];
103
104         // Initializes address pool entry
105
106         void InitEntry(uint8_t index) {
107                 thePool[index].address.devAddress = 0;
108                 thePool[index].epcount = 1;
109                 thePool[index].lowspeed = 0;
110                 thePool[index].epinfo = &dev0ep;
111         };
112
113         // Returns thePool index for a given address
114
115         uint8_t FindAddressIndex(uint8_t address = 0) {
116                 for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++) {
117                         if(thePool[i].address.devAddress == address)
118                                 return i;
119                 }
120                 return 0;
121         };
122
123         // Returns thePool child index for a given parent
124
125         uint8_t FindChildIndex(UsbDeviceAddress addr, uint8_t start = 1) {
126                 for(uint8_t i = (start < 1 || start >= MAX_DEVICES_ALLOWED) ? 1 : start; i < MAX_DEVICES_ALLOWED; i++) {
127                         if(thePool[i].address.bmParent == addr.bmAddress)
128                                 return i;
129                 }
130                 return 0;
131         };
132
133         // Frees address entry specified by index parameter
134
135         void FreeAddressByIndex(uint8_t index) {
136                 // Zero field is reserved and should not be affected
137                 if(index == 0)
138                         return;
139
140                 UsbDeviceAddress uda = thePool[index].address;
141                 // If a hub was switched off all port addresses should be freed
142                 if(uda.bmHub == 1) {
143                         for(uint8_t i = 1; (i = FindChildIndex(uda, i));)
144                                 FreeAddressByIndex(i);
145
146                         // If the hub had the last allocated address, hubCounter should be decremented
147                         if(hubCounter == uda.bmAddress)
148                                 hubCounter--;
149                 }
150                 InitEntry(index);
151         }
152
153         // Initializes the whole address pool at once
154
155         void InitAllAddresses() {
156                 for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
157                         InitEntry(i);
158
159                 hubCounter = 0;
160         };
161
162 public:
163
164         AddressPoolImpl() : hubCounter(0) {
165                 // Zero address is reserved
166                 InitEntry(0);
167
168                 thePool[0].address.devAddress = 0;
169                 thePool[0].epinfo = &dev0ep;
170                 dev0ep.epAddr = 0;
171                 dev0ep.maxPktSize = 8;
172                 dev0ep.epAttribs = 0; //set DATA0/1 toggles to 0
173                 dev0ep.bmNakPower = USB_NAK_MAX_POWER;
174
175                 InitAllAddresses();
176         };
177
178         // Returns a pointer to a specified address entry
179
180         virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) {
181                 if(!addr)
182                         return thePool;
183
184                 uint8_t index = FindAddressIndex(addr);
185
186                 return (!index) ? NULL : thePool + index;
187         };
188
189         // Performs an operation specified by pfunc for each addressed device
190
191         void ForEachUsbDevice(UsbDeviceHandleFunc pfunc) {
192                 if(!pfunc)
193                         return;
194
195                 for(uint8_t i = 1; i < MAX_DEVICES_ALLOWED; i++)
196                         if(thePool[i].address.devAddress)
197                                 pfunc(thePool + i);
198         };
199
200         // Allocates new address
201
202         virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) {
203                 /* if (parent != 0 && port == 0)
204                         USB_HOST_SERIAL.println("PRT:0"); */
205                 UsbDeviceAddress _parent;
206                 _parent.devAddress = parent;
207                 if(_parent.bmReserved || port > 7)
208                         //if(parent > 127 || port > 7)
209                         return 0;
210
211                 if(is_hub && hubCounter == 7)
212                         return 0;
213
214                 // finds first empty address entry starting from one
215                 uint8_t index = FindAddressIndex(0);
216
217                 if(!index) // if empty entry is not found
218                         return 0;
219
220                 if(_parent.devAddress == 0) {
221                         if(is_hub) {
222                                 thePool[index].address.devAddress = 0x41;
223                                 hubCounter++;
224                         } else
225                                 thePool[index].address.devAddress = 1;
226
227                         return thePool[index].address.devAddress;
228                 }
229
230                 UsbDeviceAddress addr;
231                 addr.devAddress = 0; // Ensure all bits are zero
232                 addr.bmParent = _parent.bmAddress;
233                 if(is_hub) {
234                         addr.bmHub = 1;
235                         addr.bmAddress = ++hubCounter;
236                 } else {
237                         addr.bmHub = 0;
238                         addr.bmAddress = port;
239                 }
240                 thePool[index].address = addr;
241                 /*
242                                 USB_HOST_SERIAL.print("Addr:");
243                                 USB_HOST_SERIAL.print(addr.bmHub, HEX);
244                                 USB_HOST_SERIAL.print(".");
245                                 USB_HOST_SERIAL.print(addr.bmParent, HEX);
246                                 USB_HOST_SERIAL.print(".");
247                                 USB_HOST_SERIAL.println(addr.bmAddress, HEX);
248                  */
249                 return thePool[index].address.devAddress;
250         };
251
252         // Empties pool entry
253
254         virtual void FreeAddress(uint8_t addr) {
255                 // if the root hub is disconnected all the addresses should be initialized
256                 if(addr == 0x41) {
257                         InitAllAddresses();
258                         return;
259                 }
260                 uint8_t index = FindAddressIndex(addr);
261                 FreeAddressByIndex(index);
262         };
263
264         // Returns number of hubs attached
265         // It can be rather helpfull to find out if there are hubs attached than getting the exact number of hubs.
266         //uint8_t GetNumHubs()
267         //{
268         //        return hubCounter;
269         //};
270         //uint8_t GetNumDevices()
271         //{
272         //        uint8_t counter = 0;
273
274         //        for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
275         //                if (thePool[i].address != 0);
276         //                        counter ++;
277
278         //        return counter;
279         //};
280 };
281
282 #endif // __ADDRESS_H__