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