📄 uh4.c
字号:
/*
UH4.C: UH124 user interface library Level 4.
(C) Copyright TransDimension, Inc. All rights reserved.
Modification history
====================
18Aug2000 Original Release
31Jan2001 Modified, JW
*/
#include "types.h"
#include "uhc124.h"
#include "usb.h"
#include "enr.h"
#include "uh0.h"
#include "uh1.h"
#include "uh3.h"
#include "err.h"
#define RT_PORTPWR 10 /* power on waiting time */
#define RT_PORTRST 50 /* power reset waiting time */
#define RT_PORTSSPD 3 /* port suspend waiting time */
#define MAX_PORT_RESET 5 /* max num of reset tries */
/* turn on/off power for a port */
I16 UH_PortPwr(U8 op, U8 hub, U8 port)
{
I16 r;
U8 buf[PS_SIZE];
/* turn on/off power */
if (UH_PortFeature((U8) (op ? FSET : FCLR),
hub, port, PORT_POWER) < 0)
return(ERR_PORTPWR);
/* wait for some time */
UH_Wait(RT_PORTPWR);
/* read port status */
if ((r = UH_PortStatus(hub, port, buf)) < 0 ||
r != PS_SIZE) return(ERR_PORTSTS);
r = buf[PS_wPortStatusMSB];
r = (r << 8) | buf[PS_wPortStatusLSB];
/* verify power on/off operation */
if (!(log_eq(r & PS_PWRON, op))) return(ERR_PORTPWR);
return(ERR_NONE);
}
/* turn on/off power for all ports of a hub */
I16 UH_PortPwrAll(U8 op, U8 hub)
{
I16 r;
U8 buf[HD_SIZE], i, n;
/* read hub descriptor for number of ports */
if ((r = UH_HubDesc(hub, buf)) < 0 ||
buf[D_bDescriptorType] != HUB)
return(ERR_HUBDESC);
n = buf[HD_bNbrPorts];
/* turn on/off power for each port */
for (i = 1; i <= n; i++) {
if (UH_PortFeature((U8) ((op) ? FSET : FCLR),
hub, i, PORT_POWER))
return(ERR_PORTPWR);
}
/* wait for port to recover */
UH_Wait(RT_PORTPWR);
/* verify power on/off operation */
for (i = 1; i <= n; i++) {
if ((r = UH_PortStatus(hub, i, buf)) < 0 ||
r != PS_SIZE)
return(ERR_PORTSTS);
r = buf[PS_wPortStatusMSB];
r = (r << 8) | buf[PS_wPortStatusLSB];
if (!(log_eq(r & PS_PWRON, op)))
return(ERR_PORTPWR);
}
return(ERR_NONE);
}
/* port reset/enable */
I16 UH_PortReset(U8 hub, U8 port)
{
I16 r;
U8 buf[10], cnt = 0;
while (1) {
/* issue port reset */
if (UH_PortFeature(FSET, hub, port, PORT_RESET) < 0)
return(ERR_PORTRST);
/* delay 50 ms */
UH_Wait(RT_PORTRST);
/* read port status */
if ((r = UH_PortStatus(hub, port, buf)) < 0 ||
r != PS_SIZE) return(ERR_PORTSTS);
r = buf[PS_wPortStatusMSB];
r = (r << 8) | buf[PS_wPortStatusLSB];
/* check if reset is effective */
if (r & PS_ENA) return(ERR_NONE);
/* if enough attempts */
if (++cnt > MAX_PORT_RESET) return(ERR_PORTRST);
}
}
/* port suspend */
I16 UH_PortSuspend(U8 hub, U8 port)
{
I16 r;
U8 buf[PS_SIZE];
/* suspend the port */
if (UH_PortFeature((U8) FSET,
hub, port, PORT_SUSPEND) < 0)
return(ERR_PORTSSPD);
/* wait for some time */
UH_Wait(RT_PORTSSPD);
/* read port status */
if ((r = UH_PortStatus(hub, port, buf)) < 0 ||
r != PS_SIZE) return(ERR_PORTSTS);
r = buf[PS_wPortStatusMSB];
r = (r << 8) | buf[PS_wPortStatusLSB];
/* verify power on/off operation */
if (!(r & PS_SSPD)) return(ERR_PORTSSPD);
return(ERR_NONE);
}
/* port status change acknowledgement */
I16 UH_PortAck(U8 hub, U8 port, U8 change)
{
if (UH_PortFeature(FCLR, hub, port, change))
return(ERR_PORTACK);
return(ERR_NONE);
}
/* roothub enumeration */
I16 UH_RootHub(void)
{
I16 r;
U8 i;
/* initialize enr table */
UH_EnrInit();
UH_EnrDev0(ENR_FSPD);
/* set device address */
if ((r = UH_DevAddr(ROOTHUB)) < 0)
return(ERR_DEVADDR);
/* register EP0 of the root hub */
UH_EnrSet(ROOTHUB, EP0, ENR_CTL, 0, ENR_FSPD, 8);
/* set root hub configuration */
if (UH_SetConf(ROOTHUB, 1) < 0) {
UH_EnrDelete(ROOTHUB); return(ERR_SETCONF);
}
/* verify root hub configuration setting */
if ((r = UH_GetConf(ROOTHUB, &i)) < 0 || r != 1 || i != 1) {
UH_EnrDelete(ROOTHUB); return(ERR_GETCONF);
}
/* turn power on for all ports */
if ((r = UH_PortPwrAll(FSET, ROOTHUB)) < 0) {
UH_EnrDelete(ROOTHUB); return(ERR_PORTPWR);
}
/* register EP1 of root hub */
UH_EnrSet(ROOTHUB, EP1, ENR_INT, ENR_IN, ENR_FSPD, 1);
return(ROOTHUB);
}
/* enu a new device, hub = 0 to enu the root hub */
I16 UH_DevEnu(U8 hub, U8 port, U8 *dd)
{
ENR *enr;
U16 d;
I16 r;
U8 dev, spd, buf[PS_SIZE], i;
/* if device is not the root hub */
if (hub) {
/* if port is zero */
if (!port) return(ERR_PORTNUM);
/* check the hosting hub */
if (!(enr = UH_EnrGet(hub, EP0, -1)) ||
(enr->mode & ENR_SPD))
return(ERR_HOSTHUB);
/* turn on port power */
if(UH_PortPwr(FSET, hub, port) < 0)
return(ERR_PORTPWR);
/* reset/enable the port */
if (UH_PortReset(hub, port) < 0)
return(ERR_PORTRST);
/* get port status */
if ((r = UH_PortStatus(hub, port, buf)) < 0 ||
r != PS_SIZE)
return(ERR_PORTSTS);
r = buf[PS_wPortStatusMSB];
r = (r << 8) | buf[PS_wPortStatusLSB];
d = buf[PS_wPortChangeMSB];
d = (d << 8) | buf[PS_wPortChangeLSB];
/* check connectivity */
if (!(r & PS_CONN) || (d & PS_CONN) &&
UH_PortAck(hub, port, C_PORT_CONNECTION) < 0) {
return(ERR_PORTCONN);
}
/* speed of the device */
spd = (r & PS_LSPD) ? 1 : 0;
} else { /* root hub */
spd = 0; UH_EnrInit();
UH_Reset();
UH_Wait(50);
if (UH_USBOperational() < 0) return(ERR_STATE);
}
/* set speed for DEV0 */
UH_EnrDev0(spd);
/* get device descriptor via DEV0 */
if (UH_DevDesc(DEV0, dd) != 8 ||
dd[DD_bLength] != DD_SIZE ||
dd[DD_bDescriptorType] != DEVICE)
return(ERR_DEV0DESC);
/* new address for the new device */
if (!(dev = UH_AddrNew())) return(ERR_DEVFULL);
/* assign device address via DEV0 */
if (UH_DevAddr(dev) < 0) return(ERR_DEVADDR);
/* register EP0 for the new device */
if ((r = UH_EnrSet(dev, EP0, ENR_CTL, 0, spd,
dd[DD_bMaxPacketSize0])) < 0)
return(ERR_EPREG);
/* roothub */
if(!hub) {
/* set root hub configuration */
if (UH_SetConf(ROOTHUB, 1) < 0) {
UH_EnrDelete(ROOTHUB); return(ERR_SETCONF);
}
/* verify root hub configuration setting */
if ((r = UH_GetConf(ROOTHUB, &i)) < 0 || r != 1 || i != 1) {
UH_EnrDelete(ROOTHUB); return(ERR_GETCONF);
}
}
/* get full device descriptor via new device address */
if (UH_DevDesc(dev, dd) != DD_SIZE ||
dd[DD_bLength] != DD_SIZE ||
dd[DD_bDescriptorType] != DEVICE)
return(ERR_DEVDESC);
return(dev);
}
/* select a configuration for a device, assume EP0 registered */
I16 UH_ConfSel(U8 dev, U8 conf, U8 nc, U8 *cd)
{
U8 c;
U16 d;
I16 r;
/* index throuh configuration descriptors */
for (c = 0; c < nc; c++) {
/* get configuration descriptor */
r = UH_DevConf(dev, c, cd);
d = cd[CD_wTotalLengthMSB];
d = (d << 8) | cd[CD_wTotalLengthLSB];
if (r < 0 || r != d ||
cd[CD_bLength] != CD_SIZE ||
cd[CD_bDescriptorType] != CONFIGURATION)
return(ERR_CONFDESC);
if (!conf || cd[CD_bConfigurationValue] == conf)
break;
}
/* if conf num cannot be found */
if (c == nc) return(ERR_NOCONF);
/* set configuration */
conf = cd[CD_bConfigurationValue];
if (UH_SetConf(dev, conf) < 0) return(ERR_SETCONF);
/* verify configuration setting */
if ((r = UH_GetConf(dev, &c)) < 0 || r != 1 || c != conf)
return(ERR_GETCONF);
return(cd[CD_bNumInterfaces]);
}
/* Set an interface for a configured device */
I16 UH_IntfSel(U8 dev, U8 *cd, U8 intf, U8 alt)
{
U16 d;
U8 *p = cd + CD_SIZE;
U8 ni = cd[CD_bNumInterfaces];
U8 i, c, xfer, dir, ep, spd, n;
ENR *enr;
I16 r;
/* find total length returned in Cd */
d = cd[CD_wTotalLengthMSB];
d = (d << 8) | cd[CD_wTotalLengthLSB];
/* find interface and its alternate setting specification */
for (cd += (d - 1); p < cd; p += c)
if ((c = p[D_bLength]) == ID_SIZE &&
p[D_bDescriptorType] == INTERFACE &&
p[ID_bInterfaceNumber] == intf &&
p[ID_bAlternateSetting] == alt)
break;
if (p >= cd) return(ERR_NOINTF);
/* retrieve the current alternate setting for the intf */
if ((r = UH_GetIntf(dev, intf, &c)) < 0) {
/* may stall if dev supports only the default setting */
if (r == ERR_STL)
c = 0;
else
return(ERR_GETINTF);
}
/* set interface only if there is a change */
if (c != alt) {
/* set interface */
if (UH_SetIntf(dev, intf, alt) < 0)
return(ERR_SETINTF);
/* verify interface setting */
if (UH_GetIntf(dev, intf, &c) < 0 || alt != c)
return(ERR_GETINTF);
}
/* process endpoint descriptors under the intf/alt */
if (!(enr = UH_EnrGet(dev, EP0, -1))) return(ERR_ENREP0);
/* device speed */
spd = enr->mode & ENR_SPD;
/* register each endpoint associated with the intf alt */
n = p[ID_bNumEndpoints];
for (i = 0, p += ID_SIZE; i < n && p < cd; p += c) {
/* if out of the intf/alt area */
if ((c = p[D_bLength]) == ID_SIZE &&
p[D_bDescriptorType] == INTERFACE &&
(p[ID_bInterfaceNumber] != intf ||
p[ID_bAlternateSetting] != alt))
break;
/* skip class/other descriptors */
/* endpoint descriptor size could be 7 or 9, T.C */
if (((c = p[D_bLength]) != ED_SIZE && c != ID_SIZE) ||
p[D_bDescriptorType] != ENDPOINT)
continue;
/* ep desc found */
i++;
ep = p[ED_bEndpointAddress] & EP_NUM;
dir = p[ED_bEndpointAddress] & EP_DIR;
xfer = p[ED_bmAttributes] & EP_XFER;
/* register the endpoint */
UH_EnrSet(dev, ep, xfer, dir, spd,
((p[ED_wMaxPacketSizeMSB] << 8) |
p[ED_wMaxPacketSizeLSB] ) & 0xffff);
}
if (n != i) return(ERR_NUMEPS);
/* return number of eps */
return(n);
}
U8 *UH_IntfLookup(U8 *p, U8 *lim, U8 *k)
{
U8 *q;
U8 intf;
/* init alt setting count */
if (k) *k = 0;
/* search for the 1st intf desc from p */
while (p < lim && p[D_bDescriptorType] != INTERFACE)
p += p[D_bLength];
/* if over limit, no intf description found */
if (p >= lim) return(NULL);
/* process that intf descriptor */
intf = p[ID_bInterfaceNumber];
for (q = p; q < lim; q += q[D_bLength]) {
/* skip non-intf descriptors */
if (q[D_bDescriptorType] != INTERFACE) continue;
/* if over shoot, done */
if (q[ID_bInterfaceNumber] != intf) return(p);
/* find an alt setting under the intf */
(*k)++;
}
/* over the limit */
return(p);
}
/* enu a dev to default conf and default alt setting for each intf */
I16 UH_DevEnuDefault(U8 hub, U8 port, U8 *dd, U8 *cd)
{
U8 dev, intf, conf, alt;
U8 n, ep, dir, xfer, spd, i, c, t;
U16 s;
U8 *p;
ENR *enr;
/* set device address */
if ((dev = UH_DevEnu(hub, port, dd)) < 0) {
UH_EnrDelete(dev);
return(ERR_DEVENU);
}
/* set default configuration (conf index 0) */
if (UH_ConfSel(dev, 0,
dd[DD_bNumConfigurations], cd) < 0) {
UH_EnrDelete(dev);
return(ERR_DEVCONF);
}
/* use the default alternate setting for each interface */
s = cd[CD_wTotalLengthMSB];
s = (s << 8) | cd[CD_wTotalLengthLSB];
cd += s;
/* device speed */
if (!(enr = UH_EnrGet(dev, EP0, -1))) return(ERR_ENREP0);
spd = enr->mode & ENR_SPD;
while (p = UH_IntfLookup(p, cd, NULL)) {
intf = p[ID_bInterfaceNumber];
alt = p[ID_bAlternateSetting];
/* process ep descs under the intf/alt */
n = p[ID_bNumEndpoints];
for (i = 0, p += ID_SIZE; i < n && p < cd; p += c) {
/* record length and descriptor type */
c = p[D_bLength]; t = p[D_bDescriptorType];
/* if out of the intf/alt area */
if (c == ID_SIZE && t == INTERFACE &&
(p[ID_bInterfaceNumber] != intf ||
p[ID_bAlternateSetting] != alt))
break;
/* skip class/other descriptors */
if (c != ED_SIZE || t != ENDPOINT) continue;
/* ep desc found */
i++;
ep = p[ED_bEndpointAddress] & EP_NUM;
dir = p[ED_bEndpointAddress] & EP_DIR;
xfer = p[ED_bmAttributes] & EP_XFER;
/* register the endpoint */
UH_EnrSet(dev, ep, xfer, dir, spd,
p[ED_wMaxPacketSizeLSB]);
}
}
return((I16) dev);
}
/* reset and enu roothub */
I16 UH_UhcInit(void)
{
/* skip over potential POR */
UH_Wait(15);
/* reset pin */
UH_Reset();
/* wait for at least 50 ms per USB spec */
UH_Wait(50);
/* chip identification */
if (UH_MagicNumber() != MagicNumber)
return(ERR_NOTUHC124);
/* bring chip into state USBOperational */
if (UH_USBOperational() < 0)
return(ERR_STATE);
/* root hub enumeration */
if (UH_RootHub() < 0) return(ERR_HUBENU);
return(ERR_NONE);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -