home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.sustworks.com 2018
/
ftp.sustworks.com.zip
/
ftp.sustworks.com
/
USBAx8817x_101.dmg
/
src
/
Source
/
USBAx88772.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
2005-10-08
|
12KB
|
386 lines
/*
File: USBAx88772.cpp
Description: Driver for USBAx8817 USB-To-Ethernet devices
Acknowledgements: This driver started out as a sample CDC
USB-To-Ethernet driver, provided by Apple, and
was slowly transformed into the Pegasus driver.
It is partly based upon the linux Pegausus driver
source. Some constants from the linux header
file were copied directly. Also, a CRC function
was copied almost directly from aue.c, the BSD
Pegasus driver.
Copyright: Copyright 2005, Daniel Sumorok and Peter Sichel
Disclaimer: This program is free software; you can redistribute it
and/or modify it under the terms of the GNU
General Public License as published by the Free
Software Foundation; either version 2, or (at
your option) any later version.
This program is distributed in the hope that it
will be useful, but WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU
General along with this program; if not, write to
the Free Software Foundation, 59 Temple Place -
Suite 330, Boston, MA 02111-1307, USA. Change
History (least recent first):
<1> 03/25/05 USBPegasusEthernet source
*/
/*
* Copyright (c) 1997, 1998, 1999, 2000-2003
* Bill Paul <wpaul@windriver.com>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Bill Paul.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*/
#include "USBAx88772_private.h"
#include "USBAx8817x.h"
#include "USBAx88772.h"
#include "USBAx8817xEthernetInterface.h"
#define super USBAx8817x
#define POSTEVENT(x) postEvent(this, (void *)(int)x, (void *)(int)true)
OSDefineMetaClassAndStructors(USBAx88772, USBAx8817x);
#define AX_SWRESET_CLEAR 0x00
#define AX_SWRESET_RR 0x01
#define AX_SWRESET_RT 0x02
#define AX_SWRESET_PRTE 0x04
#define AX_SWRESET_PRL 0x08
#define AX_SWRESET_BZ 0x10
#define AX_SWRESET_IPRL 0x20
#define AX_SWRESET_IPPD 0x40
#pragma mark -- Initialization --
/*****************************************************************************/
//
// Method: USBAx88772::resetMAC
//
// Inputs: None
//
// Outputs: true if successful, false otherwise
//
// Desc: Tries to reset the MAC and the phy, and read
// the ethernet address.
//
/*****************************************************************************/
bool USBAx88772::resetMAC() {
UInt8 ipgs[4];
UInt16 data16;
/*
* Reset
*/
IOLog("USBAx88772: Version 1.0.1.\n");
if(!axCmd(AXE_CMD_WRITE_GPIO, 0, 0x00b0, NULL)) {
IOLog("USBAx88772: resetMAC: Failed to write GPIO bits.\n");
return false;
}
IOSleep(5);
if(!axCmd(AXE_CMD_SW_PHY_SELECT, 0, 1, NULL)) {
IOLog("USBAx88772: resetMAC: Failed to select phy 1.\n");
return false;
}
if(!axCmd(AXE_CMD_RESET, 0, AX_SWRESET_IPPD, NULL)) {
IOLog("USBAx8877x: resetMAC: Failed to power down internal PHY.\n");
return false;
}
IOSleep(150);
if(!axCmd(AXE_CMD_RESET, 0, AX_SWRESET_CLEAR, NULL)) {
IOLog("USBAx88772: resetMAC: Failed to perform software reset.\n");
return false;
}
IOSleep(150);
if(!axCmd(AXE_CMD_RESET, 0, AX_SWRESET_IPRL | AX_SWRESET_PRL,
NULL) ) {
IOLog("USBAx88772: resetMAC: Failed to set Internal/External ");
IOLog("PHY reset control.\n");
return false;
}
IOSleep(150);
/*
* Get station address.
*/
bzero(fEaddr, 6);
if(!axCmd(AXE_CMD_READ_NODEID, 0, 0, &fEaddr)) {
IOLog("USBAx88772: resetMAC: Failed to read Node ID.\n");
return false;
}
if(!axCmd(AXE_CMD_READ_MEDIA, 0, 0, &mediumStatus)) {
IOLog("USBAx88772: resetMAC: Failed to read medium status.\n");
return false;
}
mediumStatus = USBToHostWord(mediumStatus);
mediumStatus |= AXE_MEDIA_RECEIVE_ENABLE;
if(!axCmd(AXE_CMD_WRITE_MEDIA, 0, mediumStatus, 0)) {
IOLog("USBAx88772: resetMAC: Failed to write medium status.\n");
return false;
}
data16 = 0;
if(!axCmd(AXE_CMD_RXCTL_READ, 0, 0, &data16)) {
IOLog("USBAx88772: resetMAC: Failed to read rx control.\n");
return false;
}
rxCtrlVal = USBToHostWord(data16);
rxCtrlVal &= ~USB_BURST_MASK;
rxCtrlVal |= USB_BURST_2048;
rxCtrlVal &= ~AXE_RXCMD_ENABLE;
rxCtrlVal |= (AXE_RXCMD_MULTICAST | AXE_RXCMD_BROADCAST);
if(!axCmd(AXE_CMD_RXCTL_WRITE, 0, rxCtrlVal, NULL)){
IOLog("USBAx88772: resetMAC: Failed to write rx control.\n");
return false;
}
if(!axCmd(AXE_CMD_READ_IPG012, 0, 0, ipgs)) {
IOLog("USBAx88772: resetMAC: Failed to read ipg values.\n");
return false;
}
data16 = (((UInt16)ipgs[1]) << 8) | ((UInt16)ipgs[0]);
if(!axCmd(AXE_CMD_WRITE_IPG012, ipgs[2], data16, NULL)) {
IOLog("USBAx88772: resetMAC: Failed to write IPG values.\n");
return false;
}
phy = 0xf0;
data16 = 0;
if(!readMiiWord(phy, 1, &data16)) {
IOLog("USBAx88772: resetMAC: Failed to read mii register 1.\n");
return false;
}
if( (data16 == 0xffff) || (data16 == 0) ) {
IOLog("USBAx88772: resetMAC: MII register 1 was read back as %d.\n",
(int)data16);
return false;
}
if(data16 & 0x0100) {
supports1000BaseT = true;
IOLog("USBAx88772: Found 1000BaseT capable phy.\n");
readMiiWord(phy, 15, &data16);
IOLog("USBAx88772: MII register 15 = 0x%X.\n", data16);
}
data16=0;
if(axCmd(AXE_CMD_SROM_READ, 0, 0x10, &data16)) {
data16 = USBToHostWord(data16);
IOLog("USBAx88772: Max packet size is = %d.\n", data16);
}
data16=0;
if(!axCmd(AXE_CMD_SROM_READ, 0, 0x01, &data16)) {
IOLog("USBAx88772: Failed to read flags.\n");
return false;
}
deviceFlag = USBToHostWord(data16);
IOLog("USBAx88772: flags = 0x%X.\n", deviceFlag);
/* Turn off phy. */
writeMiiWord(phy, 0, 0x0800);
return true;
} /* end resetMAC */
int USBAx88772::copyPktToBuffer(mbuf_t m, UInt8 *buf, int len) {
UInt16 *frameHdr;
UInt16 USBLen;
frameHdr = (UInt16 *)buf;
USBLen = HostToUSBWord(len);
frameHdr[0] = USBLen;
frameHdr[1] = ~USBLen;
buf += 4;
while(m) {
if(mbuf_len(m) > 0) {
bcopy(mbuf_data(m), buf, mbuf_len(m));
buf += mbuf_len(m);
}
m = mbuf_next(m);
}
/* Minimum packet is 60 bytes */
if(len < 60) {
bzero(buf, 60 - len);
len = 60;
}
return len + 4;
}
/***************************************************************************/
//
// Method: USBAx88772::receivePacket
//
// Inputs: completion - pointer to read completion routine
// inMDP - MDP where received data is
// remaining - BUFSIZE minus length of received packet
//
// Outputs: None
//
// Desc: Receives a packet. Allocates a buffer, copies
// the received packet to the buffer, and sends
// the buffer up the network stack. Then another
// read command is issued. If the read command
// fails, the network interface is freed.
//
//
/****************************************************************************/
void USBAx88772::receivePacket(UInt32 packetLength,
IOBufferMemoryDescriptor *inMDP,
IOUSBCompletion *completion) {
UInt8 *dataInPtr;
mbuf_t rcvd;
IOReturn ior;
UInt16 frameLen;
UInt16 *frameHdr;
UInt32 lenOrig;
int itr;
lenOrig = packetLength;
dataInPtr = (UInt8 *)inMDP->getBytesNoCopy();
itr = 0;
while(packetLength > 4) {
++itr;
frameHdr = (UInt16 *)dataInPtr;
if(frameHdr[0] != (UInt16)~(frameHdr[1])) {
IOLog("USBAx88772::receivePacket: Bad frame header. itr = %d\n",
itr);
break;
}
packetLength -= 4;
dataInPtr += 4;
frameLen = USBToHostWord(frameHdr[0]);
if(frameLen > packetLength) {
IOLog("USBAx88772::receivePacket: Famelen = %d, ",
(int)frameLen);
IOLog("lenOrig = %d, lenNow = %d.\n",
(int)lenOrig, (int)packetLength);
break;
}
rcvd = allocatePacket(frameLen);
if(!rcvd) {
IOLog("USBAx88772::receivePacket: Failed to allocate packet.\n");
return;
}
bcopy(dataInPtr, mbuf_data(rcvd), frameLen);
fNetworkInterface->inputPacket(rcvd, frameLen, 0x01);
if(fpNetStats) {
++fpNetStats->inputPackets;
}
/* Round up frameLen to the nearest multiple of 2. */
frameLen = (frameLen + 1) & 0xfffe;
packetLength -= frameLen;
dataInPtr += frameLen;
}
/* Read next packet. */
inMDP->setLength(BUFSIZE);
ior = fInPipe->Read(inMDP, 0, 0, BUFSIZE, completion, NULL);
if(ior != kIOReturnSuccess) {
if((fInPipe->GetPipeStatus()) == kIOUSBPipeStalled) {
IOLog("USBAx88772::receivePacket: return code = 0x%x.\n", ior);
IOLockLock(rxQueueLock);
readThreadCmd |= RXTHREAD_READSTALLED;
IOLockWakeup(rxQueueLock, NO_EVENT, true);
IOLockUnlock(rxQueueLock);
} else {
IOLog("USBAx88772::receivePacket: Failed to read next packet.\n");
}
}
} /* end receivePacket */
/*****************************************************************************/
//
// Method: USBAx88772::setMediumStatus
//
// Inputs: selectedMedium - Medium to select
//
// Outputs: Return code - none
//
// Desc: The mediumStatus tells the MAC what medium is
// currently selected.
//
/****************************************************************************/
void USBAx88772::setMediumStatus(UInt32 selectedMedium) {
switch(selectedMedium) {
case kIOMediumEthernet10BaseT | kIOMediumOptionHalfDuplex:
mediumStatus &= ~AXE_MEDIA_FULL_DUPLEX;
mediumStatus &= ~AXE_MEDIA_100_MODE;
mediumStatus &= ~AXE_MEDIA_GMII_MODE;
break;
case kIOMediumEthernet10BaseT | kIOMediumOptionFullDuplex:
mediumStatus |= AXE_MEDIA_FULL_DUPLEX;
mediumStatus &= ~AXE_MEDIA_100_MODE;
mediumStatus &= ~AXE_MEDIA_GMII_MODE;
break;
case kIOMediumEthernet100BaseTX | kIOMediumOptionHalfDuplex:
mediumStatus &= ~AXE_MEDIA_FULL_DUPLEX;
mediumStatus |= AXE_MEDIA_100_MODE;
mediumStatus &= ~AXE_MEDIA_GMII_MODE;
break;
case kIOMediumEthernet100BaseTX | kIOMediumOptionFullDuplex:
mediumStatus |= AXE_MEDIA_FULL_DUPLEX;
mediumStatus |= AXE_MEDIA_100_MODE;
mediumStatus &= ~AXE_MEDIA_GMII_MODE;
break;
case kIOMediumEthernet1000BaseTX | kIOMediumOptionHalfDuplex:
mediumStatus &= ~AXE_MEDIA_FULL_DUPLEX;
mediumStatus &= ~AXE_MEDIA_100_MODE;
mediumStatus |= AXE_MEDIA_GMII_MODE;
break;
case kIOMediumEthernet1000BaseTX | kIOMediumOptionFullDuplex:
mediumStatus |= AXE_MEDIA_FULL_DUPLEX;
mediumStatus &= ~AXE_MEDIA_100_MODE;
mediumStatus |= AXE_MEDIA_GMII_MODE;
break;
default:
mediumStatus &= ~AXE_MEDIA_FULL_DUPLEX;
mediumStatus &= ~AXE_MEDIA_100_MODE;
mediumStatus &= ~AXE_MEDIA_GMII_MODE;
break;
}
}