USB Host Shield 2.0
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
address.h
Go to the documentation of this file.
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 
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
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 
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__
uint8_t bmRcvToggle
Definition: address.h:41
EpInfo * epinfo
Definition: address.h:76
bool lowspeed
Definition: address.h:79
uint8_t bmNakPower
Definition: address.h:42
uint8_t bmReserved
Definition: address.h:65
virtual void FreeAddress(uint8_t addr)=0
uint8_t epAttribs
Definition: address.h:37
virtual UsbDevice * GetUsbDevicePtr(uint8_t addr)=0
uint8_t epAddr
Definition: address.h:33
#define USB_NAK_MAX_POWER
Definition: address.h:27
virtual UsbDevice * GetUsbDevicePtr(uint8_t addr)
Definition: address.h:180
void(* UsbDeviceHandleFunc)(UsbDevice *pdev)
Definition: address.h:90
Definition: address.h:32
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub=false, uint8_t port=0)=0
uint8_t bmSndToggle
Definition: address.h:40
uint8_t devAddress
Definition: address.h:67
uint8_t bmAddress
Definition: address.h:62
uint8_t bmParent
Definition: address.h:63
uint8_t epcount
Definition: address.h:78
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc)
Definition: address.h:191
uint8_t maxPktSize
Definition: address.h:34
virtual void FreeAddress(uint8_t addr)
Definition: address.h:254
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub=false, uint8_t port=0)
Definition: address.h:202
UsbDeviceAddress address
Definition: address.h:77
uint8_t bmHub
Definition: address.h:64