USB_Host_Shield_2.0/address.h

288 lines
7.5 KiB
C
Raw Normal View History

2011-06-22 19:41:22 +02:00
/* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Circuits At Home, LTD
Web : http://www.circuitsathome.com
e-mail : support@circuitsathome.com
*/
2011-03-01 19:26:31 +01:00
#if !defined(__ADDRESS_H__)
#define __ADDRESS_H__
#include <inttypes.h>
2011-04-18 22:32:14 +02:00
#include <stddef.h>
2011-03-01 19:26:31 +01:00
#include "max3421e.h"
2012-01-10 20:49:42 +01:00
/* NAK powers. To save space in endpoint data structure, amount of retries before giving up and returning 0x4 is stored in */
/* bmNakPower as a power of 2. The actual nak_limit is then calculated as nak_limit = ( 2^bmNakPower - 1) */
2011-04-16 07:24:10 +02:00
#define USB_NAK_MAX_POWER 15 //NAK binary order maximum value
2012-01-10 20:49:42 +01:00
#define USB_NAK_DEFAULT 14 //default 32K-1 NAKs before giving up
#define USB_NAK_NOWAIT 1 //Single NAK stops transfer
#define USB_NAK_NONAK 0 //Do not count NAKs, stop retrying after USB Timeout
2011-04-16 07:24:10 +02:00
struct EpInfo
{
uint8_t epAddr; // Endpoint address
uint8_t maxPktSize; // Maximum packet size
union
{
uint8_t epAttribs;
struct
{
2012-01-10 20:49:42 +01:00
uint8_t bmSndToggle : 1; // Send toggle, when zero bmSNDTOG0, bmSNDTOG1 otherwise
uint8_t bmRcvToggle : 1; // Send toggle, when zero bmRCVTOG0, bmRCVTOG1 otherwise
2011-04-16 07:24:10 +02:00
uint8_t bmNakPower : 6; // Binary order for NAK_LIMIT value
};
};
};
2011-03-01 19:26:31 +01:00
// 7 6 5 4 3 2 1 0
// ---------------------------------
// | | H | P | P | P | A | A | A |
// ---------------------------------
//
// H - if 1 the address is a hub address
// P - parent hub address
// A - device address / port number in case of hub
//
struct UsbDeviceAddress
{
union
{
struct
{
uint8_t bmAddress : 3; // device address/port number
uint8_t bmParent : 3; // parent hub address
uint8_t bmHub : 1; // hub flag
uint8_t bmReserved : 1; // reserved, must be zerro
};
uint8_t devAddress;
};
};
#define bmUSB_DEV_ADDR_ADDRESS 0x07
#define bmUSB_DEV_ADDR_PARENT 0x38
#define bmUSB_DEV_ADDR_HUB 0x40
struct UsbDevice
{
2011-04-16 07:24:10 +02:00
EpInfo *epinfo; // endpoint info pointer
2011-03-01 19:26:31 +01:00
uint8_t address; // address
2011-04-16 07:24:10 +02:00
uint8_t epcount; // number of endpoints
2011-03-05 08:33:02 +01:00
bool lowspeed; // indicates if a device is the low speed one
2011-04-16 07:24:10 +02:00
// uint8_t devclass; // device class
2011-03-01 19:26:31 +01:00
};
class AddressPool
{
public:
2011-03-05 08:33:02 +01:00
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr) = 0;
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0) = 0;
virtual void FreeAddress(uint8_t addr) = 0;
2011-03-01 19:26:31 +01:00
};
typedef void (*UsbDeviceHandleFunc)(UsbDevice *pdev);
#define ADDR_ERROR_INVALID_INDEX 0xFF
#define ADDR_ERROR_INVALID_ADDRESS 0xFF
template <const uint8_t MAX_DEVICES_ALLOWED>
2011-03-05 08:33:02 +01:00
class AddressPoolImpl : public AddressPool
2011-03-01 19:26:31 +01:00
{
2011-04-16 07:24:10 +02:00
EpInfo dev0ep; //Endpoint data structure used during enumeration for uninitialized device
2011-03-01 19:26:31 +01:00
uint8_t hubCounter; // hub counter is kept
// in order to avoid hub address duplication
UsbDevice thePool[MAX_DEVICES_ALLOWED];
// Initializes address pool entry
void InitEntry(uint8_t index)
{
thePool[index].address = 0;
2011-04-16 07:24:10 +02:00
thePool[index].epcount = 1;
2011-03-05 08:33:02 +01:00
thePool[index].lowspeed = 0;
2011-03-01 19:26:31 +01:00
thePool[index].epinfo = &dev0ep;
};
// Returns thePool index for a given address
uint8_t FindAddressIndex(uint8_t address = 0)
{
for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
{
if (thePool[i].address == address)
return i;
}
return 0;
};
// Returns thePool child index for a given parent
uint8_t FindChildIndex(UsbDeviceAddress addr, uint8_t start = 1)
{
for (uint8_t i=(start<1 || start>=MAX_DEVICES_ALLOWED) ? 1 : start; i<MAX_DEVICES_ALLOWED; i++)
{
if (((UsbDeviceAddress*)&thePool[i].address)->bmParent == addr.bmAddress)
return i;
}
return 0;
};
// Frees address entry specified by index parameter
void FreeAddressByIndex(uint8_t index)
{
// Zerro field is reserved and should not be affected
if (index == 0)
return;
// If a hub was switched off all port addresses should be freed
if (((UsbDeviceAddress*)&thePool[index].address)->bmHub == 1)
{
for (uint8_t i=1; i = FindChildIndex(*((UsbDeviceAddress*)&thePool[index].address), i); )
FreeAddressByIndex(i);
// If the hub had the last allocated address, hubCounter should be decremented
if (hubCounter == ((UsbDeviceAddress*)&thePool[index].address)->bmAddress)
hubCounter --;
}
InitEntry(index);
}
// Initializes the whole address pool at once
void InitAllAddresses()
{
for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
InitEntry(i);
hubCounter = 0;
};
public:
AddressPoolImpl() : hubCounter(0)
{
2012-01-10 20:49:42 +01:00
// Zero address is reserved
2011-03-01 19:26:31 +01:00
InitEntry(0);
thePool[0].address = 0;
thePool[0].epinfo = &dev0ep;
dev0ep.epAddr = 0;
2011-04-16 07:24:10 +02:00
dev0ep.maxPktSize = 8;
dev0ep.epAttribs = 0; //set DATA0/1 toggles to 0
dev0ep.bmNakPower = USB_NAK_MAX_POWER;
2011-03-01 19:26:31 +01:00
InitAllAddresses();
};
// Returns a pointer to a specified address entry
2011-03-05 08:33:02 +01:00
virtual UsbDevice* GetUsbDevicePtr(uint8_t addr)
2011-03-01 19:26:31 +01:00
{
if (!addr)
return thePool;
uint8_t index = FindAddressIndex(addr);
return (!index) ? NULL : thePool + index;
};
// Performs an operation specified by pfunc for each addressed device
void ForEachUsbDevice(UsbDeviceHandleFunc pfunc)
{
if (!pfunc)
return;
for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
if (thePool[i].address)
pfunc(thePool + i);
};
// Allocates new address
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub = false, uint8_t port = 0)
{
2011-04-18 22:32:14 +02:00
/* if (parent != 0 && port == 0)
Serial.println("PRT:0"); */
2011-04-16 07:24:10 +02:00
2011-03-01 19:26:31 +01:00
if (parent > 127 || port > 7)
return 0;
2011-04-18 18:11:59 +02:00
if (is_hub && hubCounter == 7)
return 0;
2011-03-01 19:26:31 +01:00
// finds first empty address entry starting from one
uint8_t index = FindAddressIndex(0);
if (!index) // if empty entry is not found
return 0;
if (parent == 0)
{
2011-04-16 07:24:10 +02:00
if (is_hub)
{
thePool[index].address = 0x41;
hubCounter ++;
}
else
thePool[index].address = 1;
2011-03-01 19:26:31 +01:00
return thePool[index].address;
}
UsbDeviceAddress addr;
addr.bmParent = ((UsbDeviceAddress*)&parent)->bmAddress;
if (is_hub)
{
addr.bmHub = 1;
addr.bmAddress = ++hubCounter;
}
else
{
addr.bmHub = 0;
addr.bmAddress = port;
}
thePool[index].address = *((uint8_t*)&addr);
2011-04-18 22:32:14 +02:00
/*
2011-04-16 07:24:10 +02:00
Serial.print("Addr:");
Serial.print(addr.bmHub, HEX);
Serial.print(".");
Serial.print(addr.bmParent, HEX);
Serial.print(".");
Serial.println(addr.bmAddress, HEX);
2011-04-18 22:32:14 +02:00
*/
2011-03-01 19:26:31 +01:00
return thePool[index].address;
};
// Empties pool entry
virtual void FreeAddress(uint8_t addr)
{
// if the root hub is disconnected all the addresses should be initialized
if (addr == 0x41)
{
InitAllAddresses();
return;
}
uint8_t index = FindAddressIndex(addr);
FreeAddressByIndex(index);
};
// Returns number of hubs attached
// It can be rather helpfull to find out if there are hubs attached than getting the exact number of hubs.
2011-04-16 07:24:10 +02:00
//uint8_t GetNumHubs()
//{
// return hubCounter;
//};
//uint8_t GetNumDevices()
//{
// uint8_t counter = 0;
2011-03-01 19:26:31 +01:00
2011-04-16 07:24:10 +02:00
// for (uint8_t i=1; i<MAX_DEVICES_ALLOWED; i++)
// if (thePool[i].address != 0);
// counter ++;
2011-03-01 19:26:31 +01:00
2011-04-16 07:24:10 +02:00
// return counter;
//};
2011-03-01 19:26:31 +01:00
};
#endif // __ADDRESS_H__