⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uh4.c

📁 TDI的USB HOST芯片UHC124的编程手册和固件驱动源代码
💻 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 + -