usb_asix driver refactoring:

* work with multicast filter table implemented;
* new device lookup and creation procedure: avoid duplication 
  of supported devices information;
* coding style fixes;
 


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42758 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Siarzhuk Zharski 2011-09-18 16:47:47 +00:00
parent 117e135799
commit 1724ebde55
16 changed files with 974 additions and 763 deletions

View File

@ -1,32 +1,34 @@
/* /*
* ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver. * ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver.
* Copyright (c) 2008 S.Zharski <imker@gmx.li> * Copyright (c) 2008, 2011 S.Zharski <imker@gmx.li>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
* Heavily based on code of the * Heavily based on code of the
* Driver for USB Ethernet Control Model devices * Driver for USB Ethernet Control Model devices
* Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch> * Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
*/ */
#include "Driver.h"
#include "Settings.h"
#include "ASIXDevice.h" #include "ASIXDevice.h"
//TODO: multicast support #include <stdio.h>
//TODO: set media state support
#include "ASIXVendorRequests.h"
#include "Driver.h"
#include "Settings.h"
// frame header used during transfer data // frame header used during transfer data
struct TRXHeader { struct TRXHeader {
uint16 fLength; uint16 fLength;
uint16 fInvertedLength; uint16 fInvertedLength;
TRXHeader(uint16 length = 0){ SetLength(length); } TRXHeader(uint16 length = 0) { SetLength(length); }
bool IsValid() { return (fLength ^ fInvertedLength) == 0xffff; } bool IsValid() { return (fLength ^ fInvertedLength) == 0xffff; }
uint16 Length() { return fLength; } uint16 Length() { return fLength; }
//TODO: low-endian convertion? // TODO: low-endian convertion?
void SetLength(uint16 length) { void SetLength(uint16 length) {
fLength = length; fLength = length;
fInvertedLength = ~fLength; fInvertedLength = ~fLength;
@ -34,45 +36,37 @@ struct TRXHeader {
}; };
ASIXDevice::ASIXDevice(usb_device device, const char *description) ASIXDevice::ASIXDevice(usb_device device, DeviceInfo& deviceInfo)
: fStatus(B_ERROR), :
fDevice(device),
fStatus(B_ERROR),
fOpen(false), fOpen(false),
fRemoved(false), fRemoved(false),
fInsideNotify(0),
fDevice(device),
fDescription(description),
fNonBlocking(false),
fFrameSize(0),
fNotifyEndpoint(0),
fReadEndpoint(0),
fWriteEndpoint(0),
fNotifyReadSem(-1),
fNotifyWriteSem(-1),
fNotifyBuffer(NULL),
fNotifyBufferLength(0),
fLinkStateChangeSem(-1),
fHasConnection(false), fHasConnection(false),
fUseTRXHeader(false), fNonBlocking(false),
fReadNodeIDRequest(kInvalidRequest), fInsideNotify(0),
fReadRXControlRequest(kInvalidRequest), fFrameSize(0),
fWriteRXControlRequest(kInvalidRequest), fNotifyEndpoint(0),
fPromiscuousBits(0) fReadEndpoint(0),
{ fWriteEndpoint(0),
const usb_device_descriptor fActualLengthRead(0),
*deviceDescriptor = gUSBModule->get_device_descriptor(device); fActualLengthWrite(0),
fStatusRead(B_OK),
if (deviceDescriptor == NULL) { fStatusWrite(B_OK),
TRACE_ALWAYS("Error of getting USB device descriptor.\n"); fNotifyReadSem(-1),
return; fNotifyWriteSem(-1),
} fNotifyBuffer(NULL),
fNotifyBufferLength(0),
fLinkStateChangeSem(-1),
fUseTRXHeader(false),
fReadNodeIDRequest(kInvalidRequest)
{
fDeviceInfo = deviceInfo;
fIPG[0] = 0x15; fIPG[0] = 0x15;
fIPG[1] = 0x0c; fIPG[1] = 0x0c;
fIPG[2] = 0x12; fIPG[2] = 0x12;
fVendorID = deviceDescriptor->vendor_id;
fProductID = deviceDescriptor->product_id;
fNotifyReadSem = create_sem(0, DRIVER_NAME"_notify_read"); fNotifyReadSem = create_sem(0, DRIVER_NAME"_notify_read");
if (fNotifyReadSem < B_OK) { if (fNotifyReadSem < B_OK) {
TRACE_ALWAYS("Error of creating read notify semaphore:%#010x\n", TRACE_ALWAYS("Error of creating read notify semaphore:%#010x\n",
@ -82,7 +76,7 @@ ASIXDevice::ASIXDevice(usb_device device, const char *description)
fNotifyWriteSem = create_sem(0, DRIVER_NAME"_notify_write"); fNotifyWriteSem = create_sem(0, DRIVER_NAME"_notify_write");
if (fNotifyWriteSem < B_OK) { if (fNotifyWriteSem < B_OK) {
TRACE_ALWAYS("Error of creating write notify semaphore:%#010x\n", TRACE_ALWAYS("Error of creating write notify semaphore:%#010x\n",
fNotifyWriteSem); fNotifyWriteSem);
return; return;
} }
@ -90,7 +84,7 @@ ASIXDevice::ASIXDevice(usb_device device, const char *description)
if (_SetupEndpoints() != B_OK) { if (_SetupEndpoints() != B_OK) {
return; return;
} }
// must be set in derived class constructor // must be set in derived class constructor
// fStatus = B_OK; // fStatus = B_OK;
} }
@ -102,11 +96,11 @@ ASIXDevice::~ASIXDevice()
delete_sem(fNotifyReadSem); delete_sem(fNotifyReadSem);
if (fNotifyWriteSem >= B_OK) if (fNotifyWriteSem >= B_OK)
delete_sem(fNotifyWriteSem); delete_sem(fNotifyWriteSem);
if (!fRemoved) //??? if (!fRemoved) // ???
gUSBModule->cancel_queued_transfers(fNotifyEndpoint); gUSBModule->cancel_queued_transfers(fNotifyEndpoint);
if(fNotifyBuffer) if (fNotifyBuffer)
free(fNotifyBuffer); free(fNotifyBuffer);
} }
@ -118,23 +112,23 @@ ASIXDevice::Open(uint32 flags)
return B_BUSY; return B_BUSY;
if (fRemoved) if (fRemoved)
return B_ERROR; return B_ERROR;
status_t result = StartDevice(); status_t result = StartDevice();
if (result != B_OK) { if (result != B_OK) {
return result; return result;
} }
// setup state notifications // setup state notifications
result = gUSBModule->queue_interrupt(fNotifyEndpoint, fNotifyBuffer, result = gUSBModule->queue_interrupt(fNotifyEndpoint, fNotifyBuffer,
fNotifyBufferLength, _NotifyCallback, this); fNotifyBufferLength, _NotifyCallback, this);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of requesting notify interrupt:%#010x\n", result); TRACE_ALWAYS("Error of requesting notify interrupt:%#010x\n", result);
return result; return result;
} }
fNonBlocking = (flags & O_NONBLOCK) == O_NONBLOCK; fNonBlocking = (flags & O_NONBLOCK) == O_NONBLOCK;
fOpen = true; fOpen = true;
return result; return result;
} }
@ -154,7 +148,7 @@ ASIXDevice::Close()
gUSBModule->cancel_queued_transfers(fWriteEndpoint); gUSBModule->cancel_queued_transfers(fWriteEndpoint);
fOpen = false; fOpen = false;
return StopDevice(); return StopDevice();
} }
@ -171,9 +165,9 @@ ASIXDevice::Read(uint8 *buffer, size_t *numBytes)
{ {
size_t numBytesToRead = *numBytes; size_t numBytesToRead = *numBytes;
*numBytes = 0; *numBytes = 0;
if (fRemoved) { if (fRemoved) {
TRACE_ALWAYS("Error of receiving %d bytes from removed device.\n", TRACE_ALWAYS("Error of receiving %d bytes from removed device.\n",
numBytesToRead); numBytesToRead);
return B_DEVICE_NOT_FOUND; return B_DEVICE_NOT_FOUND;
} }
@ -189,7 +183,7 @@ ASIXDevice::Read(uint8 *buffer, size_t *numBytes)
size_t startIndex = fUseTRXHeader ? 0 : 1 ; size_t startIndex = fUseTRXHeader ? 0 : 1 ;
size_t chunkCount = fUseTRXHeader ? 2 : 1 ; size_t chunkCount = fUseTRXHeader ? 2 : 1 ;
status_t result = gUSBModule->queue_bulk_v(fReadEndpoint, status_t result = gUSBModule->queue_bulk_v(fReadEndpoint,
&rxData[startIndex], chunkCount, _ReadCallback, this); &rxData[startIndex], chunkCount, _ReadCallback, this);
if (result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of queue_bulk_v request:%#010x\n", result); TRACE_ALWAYS("Error of queue_bulk_v request:%#010x\n", result);
@ -202,33 +196,34 @@ ASIXDevice::Read(uint8 *buffer, size_t *numBytes)
TRACE_ALWAYS("Error of acquiring notify semaphore:%#010x.\n", result); TRACE_ALWAYS("Error of acquiring notify semaphore:%#010x.\n", result);
return result; return result;
} }
if (fStatusRead != B_OK && fStatusRead != B_CANCELED && !fRemoved) { if (fStatusRead != B_OK && fStatusRead != B_CANCELED && !fRemoved) {
TRACE_ALWAYS("Device status error:%#010x\n", fStatusRead); TRACE_ALWAYS("Device status error:%#010x\n", fStatusRead);
result = gUSBModule->clear_feature(fReadEndpoint, result = gUSBModule->clear_feature(fReadEndpoint,
USB_FEATURE_ENDPOINT_HALT); USB_FEATURE_ENDPOINT_HALT);
if (result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error during clearing of HALT state:%#010x.\n", result); TRACE_ALWAYS("Error during clearing of HALT state:%#010x.\n",
result);
return result; return result;
} }
} }
if(fUseTRXHeader) { if (fUseTRXHeader) {
if(fActualLengthRead < sizeof(TRXHeader)) { if (fActualLengthRead < sizeof(TRXHeader)) {
TRACE_ALWAYS("Error: no place for TRXHeader:only %d of %d bytes.\n", TRACE_ALWAYS("Error: no place for TRXHeader:only %d of %d bytes.\n",
fActualLengthRead, sizeof(TRXHeader)); fActualLengthRead, sizeof(TRXHeader));
return B_ERROR; //TODO: ??? return B_ERROR; // TODO: ???
} }
if(!header.IsValid()) { if (!header.IsValid()) {
TRACE_ALWAYS("Error:TRX Header is invalid: len:%#04x; ilen:%#04x\n", TRACE_ALWAYS("Error:TRX Header is invalid: len:%#04x; ilen:%#04x\n",
header.fLength, header.fInvertedLength); header.fLength, header.fInvertedLength);
return B_ERROR; //TODO: ??? return B_ERROR; // TODO: ???
} }
*numBytes = header.Length(); *numBytes = header.Length();
if(fActualLengthRead - sizeof(TRXHeader) > header.Length()) { if (fActualLengthRead - sizeof(TRXHeader) > header.Length()) {
TRACE_ALWAYS("MISMATCH of the frame length: hdr %d; received:%d\n", TRACE_ALWAYS("MISMATCH of the frame length: hdr %d; received:%d\n",
header.Length(), fActualLengthRead - sizeof(TRXHeader)); header.Length(), fActualLengthRead - sizeof(TRXHeader));
} }
@ -248,25 +243,25 @@ ASIXDevice::Write(const uint8 *buffer, size_t *numBytes)
{ {
size_t numBytesToWrite = *numBytes; size_t numBytesToWrite = *numBytes;
*numBytes = 0; *numBytes = 0;
if (fRemoved) { if (fRemoved) {
TRACE_ALWAYS("Error of writing %d bytes to removed device.\n", TRACE_ALWAYS("Error of writing %d bytes to removed device.\n",
numBytesToWrite); numBytesToWrite);
return B_DEVICE_NOT_FOUND; return B_DEVICE_NOT_FOUND;
} }
TRACE_FLOW("Write %d bytes.\n", numBytesToWrite); TRACE_FLOW("Write %d bytes.\n", numBytesToWrite);
TRXHeader header(numBytesToWrite); TRXHeader header(numBytesToWrite);
iovec txData[] = { iovec txData[] = {
{ &header, sizeof(TRXHeader) }, { &header, sizeof(TRXHeader) },
{ (uint8*)buffer, numBytesToWrite } { (uint8*)buffer, numBytesToWrite }
}; };
size_t startIndex = fUseTRXHeader ? 0 : 1 ; size_t startIndex = fUseTRXHeader ? 0 : 1 ;
size_t chunkCount = fUseTRXHeader ? 2 : 1 ; size_t chunkCount = fUseTRXHeader ? 2 : 1 ;
status_t result = gUSBModule->queue_bulk_v(fWriteEndpoint, status_t result = gUSBModule->queue_bulk_v(fWriteEndpoint,
&txData[startIndex], chunkCount, _WriteCallback, this); &txData[startIndex], chunkCount, _WriteCallback, this);
if (result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of queue_bulk_v request:%#010x\n", result); TRACE_ALWAYS("Error of queue_bulk_v request:%#010x\n", result);
@ -274,7 +269,7 @@ ASIXDevice::Write(const uint8 *buffer, size_t *numBytes)
} }
result = acquire_sem_etc(fNotifyWriteSem, 1, B_CAN_INTERRUPT, 0); result = acquire_sem_etc(fNotifyWriteSem, 1, B_CAN_INTERRUPT, 0);
if (result < B_OK) { if (result < B_OK) {
TRACE_ALWAYS("Error of acquiring notify semaphore:%#010x.\n", result); TRACE_ALWAYS("Error of acquiring notify semaphore:%#010x.\n", result);
return result; return result;
@ -290,7 +285,7 @@ ASIXDevice::Write(const uint8 *buffer, size_t *numBytes)
} }
} }
if(fUseTRXHeader) { if (fUseTRXHeader) {
*numBytes = fActualLengthWrite - sizeof(TRXHeader); *numBytes = fActualLengthWrite - sizeof(TRXHeader);
} else { } else {
*numBytes = fActualLengthWrite; *numBytes = fActualLengthWrite;
@ -311,36 +306,34 @@ ASIXDevice::Control(uint32 op, void *buffer, size_t length)
case ETHER_GETADDR: case ETHER_GETADDR:
memcpy(buffer, &fMACAddress, sizeof(fMACAddress)); memcpy(buffer, &fMACAddress, sizeof(fMACAddress));
return B_OK; return B_OK;
case ETHER_GETFRAMESIZE: case ETHER_GETFRAMESIZE:
*(uint32 *)buffer = fFrameSize; *(uint32 *)buffer = fFrameSize;
return B_OK; return B_OK;
case ETHER_NONBLOCK: case ETHER_NONBLOCK:
TRACE("ETHER_NONBLOCK\n"); TRACE("ETHER_NONBLOCK\n");
fNonBlocking = *((uint8*)buffer); fNonBlocking = *((uint8*)buffer);
return B_OK; return B_OK;
case ETHER_SETPROMISC: case ETHER_SETPROMISC:
TRACE("ETHER_SETPROMISC\n"); TRACE("ETHER_SETPROMISC\n");
return SetPromiscuousMode(*((uint8*)buffer)); return SetPromiscuousMode(*((uint8*)buffer));
case ETHER_ADDMULTI: case ETHER_ADDMULTI:
TRACE("ETHER_ADDMULTI\n"); TRACE("ETHER_ADDMULTI\n");
return ModifyMulticastTable(true, *((uint8*)buffer)); return ModifyMulticastTable(true, (ether_address_t*)buffer);
case ETHER_REMMULTI: case ETHER_REMMULTI:
TRACE("ETHER_REMMULTI\n"); TRACE("ETHER_REMMULTI\n");
return ModifyMulticastTable(false, *((uint8*)buffer)); return ModifyMulticastTable(false, (ether_address_t*)buffer);
#if HAIKU_TARGET_PLATFORM_HAIKU
case ETHER_SET_LINK_STATE_SEM: case ETHER_SET_LINK_STATE_SEM:
fLinkStateChangeSem = *(sem_id *)buffer; fLinkStateChangeSem = *(sem_id *)buffer;
return B_OK; return B_OK;
case ETHER_GET_LINK_STATE: case ETHER_GET_LINK_STATE:
return GetLinkState((ether_link_state *)buffer); return GetLinkState((ether_link_state *)buffer);
#endif
default: default:
TRACE_ALWAYS("Unhandled IOCTL catched: %#010x\n", op); TRACE_ALWAYS("Unhandled IOCTL catched: %#010x\n", op);
@ -379,29 +372,29 @@ ASIXDevice::SetupDevice(bool deviceReplugged)
{ {
ether_address address; ether_address address;
status_t result = ReadMACAddress(&address); status_t result = ReadMACAddress(&address);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of reading MAC address:%#010x\n", result); TRACE_ALWAYS("Error of reading MAC address:%#010x\n", result);
return result; return result;
} }
TRACE("MAC address is:%02x:%02x:%02x:%02x:%02x:%02x\n", TRACE("MAC address is:%02x:%02x:%02x:%02x:%02x:%02x\n",
address.ebyte[0], address.ebyte[1], address.ebyte[2], address.ebyte[0], address.ebyte[1], address.ebyte[2],
address.ebyte[3], address.ebyte[4], address.ebyte[5]); address.ebyte[3], address.ebyte[4], address.ebyte[5]);
if(deviceReplugged) { if (deviceReplugged) {
// this might be the same device that was replugged - read the MAC address // this might be the same device that was replugged - read the MAC
// (which should be at the same index) to make sure // address (which should be at the same index) to make sure
if(memcmp(&address, &fMACAddress, sizeof(address)) != 0) { if (memcmp(&address, &fMACAddress, sizeof(address)) != 0) {
TRACE_ALWAYS("Cannot replace device with MAC address:" TRACE_ALWAYS("Cannot replace device with MAC address:"
"%02x:%02x:%02x:%02x:%02x:%02x\n", "%02x:%02x:%02x:%02x:%02x:%02x\n",
fMACAddress.ebyte[0], fMACAddress.ebyte[1], fMACAddress.ebyte[2], fMACAddress.ebyte[0], fMACAddress.ebyte[1], fMACAddress.ebyte[2],
fMACAddress.ebyte[3], fMACAddress.ebyte[4], fMACAddress.ebyte[5]); fMACAddress.ebyte[3], fMACAddress.ebyte[4], fMACAddress.ebyte[5]);
return B_BAD_VALUE; // is not the same return B_BAD_VALUE; // is not the same
} }
} else } else
fMACAddress = address; fMACAddress = address;
return B_OK; return B_OK;
} }
@ -416,8 +409,8 @@ ASIXDevice::CompareAndReattach(usb_device device)
return B_ERROR; return B_ERROR;
} }
if (deviceDescriptor->vendor_id != fVendorID if (deviceDescriptor->vendor_id != fDeviceInfo.VendorId()
&& deviceDescriptor->product_id != fProductID) { && deviceDescriptor->product_id != fDeviceInfo.ProductId()) {
// this certainly isn't the same device // this certainly isn't the same device
return B_BAD_VALUE; return B_BAD_VALUE;
} }
@ -436,7 +429,7 @@ ASIXDevice::CompareAndReattach(usb_device device)
// we need to setup hardware on device replug // we need to setup hardware on device replug
result = SetupDevice(true); result = SetupDevice(true);
if (result != B_OK) { if (result != B_OK) {
return result; return result;
} }
if (fOpen) { if (fOpen) {
@ -470,40 +463,47 @@ ASIXDevice::_SetupEndpoints()
"USB device configuration\n"); "USB device configuration\n");
return B_ERROR; return B_ERROR;
} }
int notifyEndpoint = -1; int notifyEndpoint = -1;
int readEndpoint = -1; int readEndpoint = -1;
int writeEndpoint = -1; int writeEndpoint = -1;
for(size_t ep = 0; ep < interface->endpoint_count; ep++) { for (size_t ep = 0; ep < interface->endpoint_count; ep++) {
usb_endpoint_descriptor *epd = interface->endpoint[ep].descr; usb_endpoint_descriptor *epd = interface->endpoint[ep].descr;
if((epd->attributes & USB_ENDPOINT_ATTR_MASK) == USB_ENDPOINT_ATTR_INTERRUPT) { if ((epd->attributes & USB_ENDPOINT_ATTR_MASK)
notifyEndpoint = ep; == USB_ENDPOINT_ATTR_INTERRUPT)
continue; {
} notifyEndpoint = ep;
continue;
if((epd->attributes & USB_ENDPOINT_ATTR_MASK) != USB_ENDPOINT_ATTR_BULK) { }
TRACE_ALWAYS("Error: USB endpoint type %#04x is unknown.\n", epd->attributes);
continue; if ((epd->attributes & USB_ENDPOINT_ATTR_MASK)
} != USB_ENDPOINT_ATTR_BULK)
{
if((epd->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) TRACE_ALWAYS("Error: USB endpoint type %#04x is unknown.\n",
== USB_ENDPOINT_ADDR_DIR_IN) { epd->attributes);
readEndpoint = ep; continue;
continue; }
}
if ((epd->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN)
if((epd->endpoint_address & USB_ENDPOINT_ADDR_DIR_OUT) == USB_ENDPOINT_ADDR_DIR_IN)
== USB_ENDPOINT_ADDR_DIR_OUT) { {
writeEndpoint = ep; readEndpoint = ep;
continue; continue;
} }
if ((epd->endpoint_address & USB_ENDPOINT_ADDR_DIR_OUT)
== USB_ENDPOINT_ADDR_DIR_OUT)
{
writeEndpoint = ep;
continue;
}
} }
if (notifyEndpoint == -1 || readEndpoint == -1 || writeEndpoint == -1) { if (notifyEndpoint == -1 || readEndpoint == -1 || writeEndpoint == -1) {
TRACE_ALWAYS("Error: not all USB endpoints were found: " TRACE_ALWAYS("Error: not all USB endpoints were found: "
"notify:%d; read:%d; write:%d\n", "notify:%d; read:%d; write:%d\n",
notifyEndpoint, readEndpoint, writeEndpoint); notifyEndpoint, readEndpoint, writeEndpoint);
return B_ERROR; return B_ERROR;
} }
@ -512,7 +512,7 @@ ASIXDevice::_SetupEndpoints()
fNotifyEndpoint = interface->endpoint[notifyEndpoint].handle; fNotifyEndpoint = interface->endpoint[notifyEndpoint].handle;
fReadEndpoint = interface->endpoint[readEndpoint ].handle; fReadEndpoint = interface->endpoint[readEndpoint ].handle;
fWriteEndpoint = interface->endpoint[writeEndpoint ].handle; fWriteEndpoint = interface->endpoint[writeEndpoint ].handle;
return B_OK; return B_OK;
} }
@ -521,16 +521,16 @@ status_t
ASIXDevice::ReadMACAddress(ether_address_t *address) ASIXDevice::ReadMACAddress(ether_address_t *address)
{ {
size_t actual_length = 0; size_t actual_length = 0;
status_t result = gUSBModule->send_request(fDevice, status_t result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN,
fReadNodeIDRequest, 0, 0, sizeof(ether_address), fReadNodeIDRequest, 0, 0, sizeof(ether_address),
address, &actual_length); address, &actual_length);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of reading MAC address:%#010x\n", result); TRACE_ALWAYS("Error of reading MAC address:%#010x\n", result);
return result; return result;
} }
if(actual_length != sizeof(ether_address)) { if (actual_length != sizeof(ether_address)) {
TRACE_ALWAYS("Mismatch of NODE ID data size: %d instead of %d bytes\n", TRACE_ALWAYS("Mismatch of NODE ID data size: %d instead of %d bytes\n",
actual_length, sizeof(ether_address)); actual_length, sizeof(ether_address));
return B_ERROR; return B_ERROR;
@ -545,28 +545,28 @@ ASIXDevice::ReadRXControlRegister(uint16 *rxcontrol)
{ {
size_t actual_length = 0; size_t actual_length = 0;
*rxcontrol = 0; *rxcontrol = 0;
status_t result = gUSBModule->send_request(fDevice, status_t result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN,
fReadRXControlRequest, 0, 0, READ_RX_CONTROL, 0, 0,
sizeof(*rxcontrol), rxcontrol, &actual_length); sizeof(*rxcontrol), rxcontrol, &actual_length);
if(sizeof(*rxcontrol) != actual_length) { if (sizeof(*rxcontrol) != actual_length) {
TRACE_ALWAYS("Mismatch during reading RX control register." TRACE_ALWAYS("Mismatch during reading RX control register."
"Read %d bytes instead of %d.\n", "Read %d bytes instead of %d.\n",
actual_length, sizeof(*rxcontrol)); actual_length, sizeof(*rxcontrol));
} }
return result; return result;
} }
status_t status_t
ASIXDevice::WriteRXControlRegister(uint16 rxcontrol) ASIXDevice::WriteRXControlRegister(uint16 rxcontrol)
{ {
status_t result = gUSBModule->send_request(fDevice, status_t result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
fWriteRXControlRequest, rxcontrol, 0, 0, 0, 0); WRITE_RX_CONTROL, rxcontrol, 0, 0, 0, 0);
return result; return result;
} }
@ -575,13 +575,13 @@ status_t
ASIXDevice::StopDevice() ASIXDevice::StopDevice()
{ {
status_t result = WriteRXControlRegister(0); status_t result = WriteRXControlRegister(0);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n", 0, result); TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n", 0, result);
} }
TRACE_RET(result); TRACE_RET(result);
return result; return result;
} }
@ -589,35 +589,113 @@ status_t
ASIXDevice::SetPromiscuousMode(bool on) ASIXDevice::SetPromiscuousMode(bool on)
{ {
uint16 rxcontrol = 0; uint16 rxcontrol = 0;
status_t result = ReadRXControlRegister(&rxcontrol); status_t result = ReadRXControlRegister(&rxcontrol);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of reading RX Control:%#010x\n", result); TRACE_ALWAYS("Error of reading RX Control:%#010x\n", result);
return result; return result;
} }
if(on) if (on)
rxcontrol |= fPromiscuousBits; rxcontrol |= RXCTL_PROMISCUOUS;
else else
rxcontrol &= ~fPromiscuousBits; rxcontrol &= ~RXCTL_PROMISCUOUS;
result = WriteRXControlRegister(rxcontrol); result = WriteRXControlRegister(rxcontrol);
if(result != B_OK ) { if (result != B_OK ) {
TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n", rxcontrol, result); TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n",
rxcontrol, result);
} }
TRACE_RET(result); TRACE_RET(result);
return result; return result;
}
uint32
ASIXDevice::EthernetCRC32(const uint8* buffer, size_t length)
{
uint32 result = 0xffffffff;
for (size_t i = 0; i < length; i++) {
uint8 data = *buffer++;
for (int bit = 0; bit < 8; bit++, data >>= 1) {
uint32 carry = ((result & 0x80000000) ? 1 : 0) ^ (data & 0x01);
result <<= 1;
if (carry != 0)
result = (result ^ 0x04c11db6) | carry;
}
}
return result;
} }
status_t status_t
ASIXDevice::ModifyMulticastTable(bool add, uint8 address) ASIXDevice::ModifyMulticastTable(bool join, ether_address_t* group)
{ {
//TODO: !!! char groupName[6 * 3 + 1] = { 0 };
TRACE_ALWAYS("Call for (%d, %#02x) is not implemented\n", add, address); sprintf(groupName, "%02x:%02x:%02x:%02x:%02x:%02x",
return B_OK; group->ebyte[0], group->ebyte[1], group->ebyte[2],
group->ebyte[3], group->ebyte[4], group->ebyte[5]);
TRACE("%s multicast group %s\n", join ? "Joining" : "Leaving", groupName);
uint32 hash = EthernetCRC32(group->ebyte, 6);
bool isInTable = fMulticastHashes.Find(hash) != fMulticastHashes.End();
if (isInTable && join)
return B_OK; // already listed - nothing to do
if (!isInTable && !join) {
TRACE_ALWAYS("Cannot leave unlisted multicast group %s!\n", groupName);
return B_ERROR;
}
const size_t hashLength = 8;
uint8 hashTable[hashLength] = { 0 };
if (join)
fMulticastHashes.PushBack(hash);
else
fMulticastHashes.Remove(hash);
for (int32 i = 0; i < fMulticastHashes.Count(); i++) {
uint32 hash = fMulticastHashes[i] >> 26;
hashTable[hash / 8] |= 1 << (hash % 8);
}
uint16 rxcontrol = 0;
status_t result = ReadRXControlRegister(&rxcontrol);
if (result != B_OK) {
TRACE_ALWAYS("Error of reading RX Control:%#010x\n", result);
return result;
}
if (fMulticastHashes.Count() > 0)
rxcontrol |= RXCTL_MULTICAST;
else
rxcontrol &= ~RXCTL_MULTICAST;
// write multicast hash table
size_t actualLength = 0;
result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
WRITE_MF_ARRAY, 0, 0,
hashLength, hashTable, &actualLength);
if (result != B_OK) {
TRACE_ALWAYS("Error writing hash table in MAR: %#010x.\n", result);
return result;
}
if (actualLength != hashLength)
TRACE_ALWAYS("Incomplete writing of hash table: %d bytes of %d\n",
actualLength, hashLength);
result = WriteRXControlRegister(rxcontrol);
if (result != B_OK)
TRACE_ALWAYS("Error writing %#02X to RXC:%#010x.\n", rxcontrol, result);
return result;
} }
@ -660,10 +738,11 @@ ASIXDevice::_NotifyCallback(void *cookie, int32 status, void *data,
TRACE_ALWAYS("Device status error:%#010x\n", status); TRACE_ALWAYS("Device status error:%#010x\n", status);
status_t result = gUSBModule->clear_feature(device->fNotifyEndpoint, status_t result = gUSBModule->clear_feature(device->fNotifyEndpoint,
USB_FEATURE_ENDPOINT_HALT); USB_FEATURE_ENDPOINT_HALT);
if(result != B_OK) if (result != B_OK)
TRACE_ALWAYS("Error during clearing of HALT state:%#010x.\n", result); TRACE_ALWAYS("Error during clearing of HALT state:%#010x.\n",
result);
} }
// parse data in overriden class // parse data in overriden class
device->OnNotify(actualLength); device->OnNotify(actualLength);

View File

@ -1,26 +1,48 @@
/* /*
* ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver. * ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver.
* Copyright (c) 2008 S.Zharski <imker@gmx.li> * Copyright (c) 2008, 2011 S.Zharski <imker@gmx.li>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
* Heavily based on code of the * Heavily based on code of the
* Driver for USB Ethernet Control Model devices * Driver for USB Ethernet Control Model devices
* Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch> * Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
*/ */
#ifndef _USB_ASIX_DEVICE_H_ #ifndef _USB_ASIX_DEVICE_H_
#define _USB_ASIX_DEVICE_H_ #define _USB_ASIX_DEVICE_H_
#include <net/if_media.h>
#include <ether_driver.h>
#include <util/Vector.h>
#include "Driver.h" #include "Driver.h"
#include "MIIBus.h" #include "MIIBus.h"
struct DeviceInfo {
union Id {
uint16 fIds[2];
uint32 fKey;
} fId;
enum Type {
AX88172 = 0,
AX88772 = 1,
AX88178 = 2
} fType;
const char* fName;
inline uint16 VendorId() { return fId.fIds[0]; }
inline uint16 ProductId() { return fId.fIds[1]; }
inline uint32 Key() { return fId.fKey; }
};
class ASIXDevice { class ASIXDevice {
public: public:
ASIXDevice(usb_device device, const char *description); ASIXDevice(usb_device device, DeviceInfo& devInfo);
virtual ~ASIXDevice(); virtual ~ASIXDevice();
status_t InitCheck() { return fStatus; }; status_t InitCheck() { return fStatus; };
@ -40,7 +62,7 @@ public:
status_t CompareAndReattach(usb_device device); status_t CompareAndReattach(usb_device device);
virtual status_t SetupDevice(bool deviceReplugged); virtual status_t SetupDevice(bool deviceReplugged);
private: private:
static void _ReadCallback(void *cookie, int32 status, static void _ReadCallback(void *cookie, int32 status,
void *data, uint32 actualLength); void *data, uint32 actualLength);
@ -52,27 +74,31 @@ static void _NotifyCallback(void *cookie, int32 status,
status_t _SetupEndpoints(); status_t _SetupEndpoints();
protected: protected:
/* overrides */ // overrides
virtual status_t StartDevice() = 0; virtual status_t StartDevice() = 0;
virtual status_t StopDevice(); virtual status_t StopDevice();
virtual status_t OnNotify(uint32 actualLength) = 0; virtual status_t OnNotify(uint32 actualLength) = 0;
virtual status_t GetLinkState(ether_link_state *state) = 0; virtual status_t GetLinkState(ether_link_state *state) = 0;
virtual status_t SetPromiscuousMode(bool bOn); virtual status_t SetPromiscuousMode(bool bOn);
virtual status_t ModifyMulticastTable(bool add, uint8 address); uint32 EthernetCRC32(const uint8* buffer, size_t length);
virtual status_t ModifyMulticastTable(bool add,
ether_address_t* group);
status_t ReadMACAddress(ether_address_t *address); status_t ReadMACAddress(ether_address_t *address);
status_t ReadRXControlRegister(uint16 *rxcontrol); status_t ReadRXControlRegister(uint16 *rxcontrol);
status_t WriteRXControlRegister(uint16 rxcontrol); status_t WriteRXControlRegister(uint16 rxcontrol);
// device info
usb_device fDevice;
DeviceInfo fDeviceInfo;
ether_address_t fMACAddress;
// state tracking // state tracking
status_t fStatus; status_t fStatus;
bool fOpen; bool fOpen;
bool fRemoved; bool fRemoved;
vint32 fInsideNotify; bool fHasConnection;
usb_device fDevice;
uint16 fVendorID;
uint16 fProductID;
const char * fDescription;
bool fNonBlocking; bool fNonBlocking;
vint32 fInsideNotify;
// interface and device infos // interface and device infos
uint16 fFrameSize; uint16 fFrameSize;
@ -89,23 +115,19 @@ const char * fDescription;
int32 fStatusWrite; int32 fStatusWrite;
sem_id fNotifyReadSem; sem_id fNotifyReadSem;
sem_id fNotifyWriteSem; sem_id fNotifyWriteSem;
uint8 * fNotifyBuffer; uint8 * fNotifyBuffer;
uint32 fNotifyBufferLength; uint32 fNotifyBufferLength;
sem_id fLinkStateChangeSem;
// MII bus handler // MII bus handler
MIIBus fMII; MIIBus fMII;
// connection data // connection data
sem_id fLinkStateChangeSem;
ether_address_t fMACAddress;
bool fHasConnection;
bool fUseTRXHeader; bool fUseTRXHeader;
uint8 fIPG[3]; uint8 fIPG[3];
uint8 fReadNodeIDRequest; uint8 fReadNodeIDRequest;
uint8 fReadRXControlRequest; Vector<uint32> fMulticastHashes;
uint8 fWriteRXControlRequest;
uint16 fPromiscuousBits;
}; };
#endif //_USB_ASIX_DEVICE_H_ #endif // _USB_ASIX_DEVICE_H_

View File

@ -0,0 +1,73 @@
/*
* ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver.
* Copyright (c) 2011 S.Zharski <imker@gmx.li>
* Distributed under the terms of the MIT license.
*
*/
#ifndef _ASIX_VENDOR_REQUESTS_H_
#define _ASIX_VENDOR_REQUESTS_H_
// USB Vendor Requests used by all chip types
// For chip-spercific information look into
// corresponding AX88***Device.cpp files.
enum ASIXVendorRequests {
READ_RXTX_SRAM = 0x02,
WRITE_RXTX_SRAM = 0x03, // AX88178-772
WRITE_RX_SRAM = 0x03, // AX88172
WRITE_TX_SRAM = 0x04, // AX88172
SW_MII_OP = 0x06,
READ_MII = 0x07,
WRITE_MII = 0x08,
READ_MII_OP_MODE = 0x09, // AX88172-772
READ_MII_STATUS = 0x09, // AX88178
HW_MII_OP = 0x0A,
READ_SROM = 0x0B,
WRITE_SROM = 0x0C,
WRITE_SROM_ENABLE = 0x0D,
WRITE_SROM_DISABLE = 0x0E,
READ_RX_CONTROL = 0x0F,
WRITE_RX_CONTROL = 0x10,
READ_IPGS = 0x11,
WRITE_IPGS = 0x12, // AX88178-772
WRITE_IPG0 = 0x12, // AX88172
WRITE_IPG1 = 0x13, // AX88172
WRITE_IPG2 = 0x14, // AX88172
READ_NODEID = 0x13, // AX88178-772
WRITE_NODEID = 0x14, // AX88178-772
READ_MF_ARRAY = 0x15,
WRITE_MF_ARRAY = 0x16,
READ_TEST = 0x17, // AX88178-772
READ_NODEID_AX88172 = 0x17, // AX88172
WRITE_NODEID_AX88172 = 0x18, // AX88172
READ_PHYID = 0x19,
READ_MEDIUM_STATUS = 0x1A,
WRITE_MEDIUM_MODE = 0x1B,
GET_MONITOR_MODE = 0x1C,
SET_MONITOR_MODE = 0x1D,
READ_GPIOS = 0x1E,
WRITE_GPIOS = 0x1F,
WRITE_SOFT_RESET = 0x20, // AX88178-772
READ_PHY_SEL_STATE = 0x21, // AX88772
WRITE_PHY_SEL = 0x22, // AX88772
READ_MIIS_IF_STATE = 0x21, // AX88178
WRITE_MIIS_IF_STATE = 0x22 // AX88178
};
// RX Control Register bits
enum ASIXRXControl {
RXCTL_PROMISCUOUS = 0x0001,
RXCTL_ALL_MULTICAT = 0x0002,
RXCTL_UNICAST = 0x0004, // AX88172
RXCTL_SEP = 0x0004, // AX88772-178
RXCTL_BROADCAST = 0x0008,
RXCTL_MULTICAST = 0x0010,
RXCTL_AP = 0x0020, // AX88772-178
RXCTL_START = 0x0080,
RXCTL_USB_MFB = 0x0100 // AX88772-178
};
#endif // _ASIX_VENDOR_REQUESTS_H_

View File

@ -1,6 +1,6 @@
/* /*
* ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver. * ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver.
* Copyright (c) 2008 S.Zharski <imker@gmx.li> * Copyright (c) 2008, 2011 S.Zharski <imker@gmx.li>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
* Heavily based on code of the * Heavily based on code of the
@ -10,52 +10,60 @@
* *
*/ */
#include "Settings.h"
#include "AX88172Device.h" #include "AX88172Device.h"
#include <net/if_media.h>
enum AX88172_Requests { #include "ASIXVendorRequests.h"
READ_RXTX_SRAM = 0x02, // C0 02 XX YY 0M 00 0200 Read Rx/Tx SRAM #include "Settings.h"
// M = 0 : Rx, M=1 : Tx
WRITE_RX_SRAM = 0x03, // 40 03 XX YY PP QQ 0000 Write Rx SRAM
WRITE_TX_SRAM = 0x04, // 40 04 XX YY PP QQ 0000 Write Tx SRAM // Most of vendor requests for all supported chip types use the same
SW_MII_OP = 0x06, // 40 06 00 00 00 00 0000 Software MII Operation // constants (see ASIXVendorRequests.h) but the layout of request data
READ_MII = 0x07, // C0 07 PI 00 RG 00 0200 Read MII Register // may be slightly diferrent for specific chip type. Below is a quick
WRITE_MII = 0x08, // 40 08 PI 00 RG 00 0200 Write MII Register // reference for AX88172 vendor requests data layout.
READ_MII_OP_MODE = 0x09, // C0 09 00 00 00 00 0100 Read MII Operation Mode //
HW_MII_OP = 0x0A, // 40 0A 00 00 00 00 0000 Hardware MII Operation // READ_RXTX_SRAM, // C0 02 XX YY 0M 00 0200 Read Rx/Tx SRAM
READ_SROM = 0x0B, // C0 0B DR 00 00 00 0200 Read SROM // M = 0 : Rx, M=1 : Tx
WRITE_SROM = 0x0C, // 40 0C DR 00 MM SS 0000 Write SROM // WRITE_RX_SRAM, // 40 03 XX YY PP QQ 0000 Write Rx SRAM
WRITE_SROM_ENABLE = 0x0D, // 40 0D 00 00 00 00 0000 Write SROM Enable // WRITE_TX_SRAM, // 40 04 XX YY PP QQ 0000 Write Tx SRAM
WRITE_SROM_DISABLE = 0x0E, // 40 0E 00 00 00 00 0000 Write SROM Disable // SW_MII_OP, // 40 06 00 00 00 00 0000 Software MII Operation
READ_RX_CONTROL = 0x0F, // C0 0F 00 00 00 00 0200 Read Rx Control Register // READ_MII, // C0 07 PI 00 RG 00 0200 Read MII Register
WRITE_RX_CONTROL = 0x10, // 40 10 RR 00 00 00 0000 Write Rx Control Register // WRITE_MII, // 40 08 PI 00 RG 00 0200 Write MII Register
READ_IPGS = 0x11, // C0 11 00 00 00 00 0300 Read IPG/IPG1/IPG2 Register // READ_MII_OP_MODE, // C0 09 00 00 00 00 0100 Read MII Operation Mode
WRITE_IPG0 = 0x12, // 40 12 II 00 00 00 0000 Write IPG Register // HW_MII_OP, // 40 0A 00 00 00 00 0000 Hardware MII Operation
WRITE_IPG1 = 0x13, // 40 13 II 00 00 00 0000 Write IPG1 Register // READ_SROM, // C0 0B DR 00 00 00 0200 Read SROM
WRITE_IPG2 = 0x14, // 40 14 II 00 00 00 0000 Write IPG2 Register // WRITE_SROM, // 40 0C DR 00 MM SS 0000 Write SROM
READ_MF_ARRAY = 0x15, // C0 15 00 00 00 00 0800 Read Multi-Filter Array // WRITE_SROM_ENABLE, // 40 0D 00 00 00 00 0000 Write SROM Enable
WRITE_MF_ARRAY = 0x16, // 40 16 00 00 00 00 0800 Write Multi-Filter Array // WRITE_SROM_DISABLE, // 40 0E 00 00 00 00 0000 Write SROM Disable
READ_NODEID = 0x17, // C0 17 00 00 00 00 0600 Read Node ID // READ_RX_CONTROL, // C0 0F 00 00 00 00 0200 Read Rx Control Register
WRITE_NODEID = 0x18, // // WRITE_RX_CONTROL, // 40 10 RR 00 00 00 0000 Write Rx Control Register
READ_PHYID = 0x19, // C0 19 00 00 00 00 0200 Read Ethernet/HomePNA PhyID // READ_IPGS, // C0 11 00 00 00 00 0300 Read IPG/IPG1/IPG2 Register
READ_MEDIUM_STATUS = 0x1A, // C0 1A 00 00 00 00 0100 Read Medium Status // WRITE_IPG0, // 40 12 II 00 00 00 0000 Write IPG Register
WRITE_MEDIUM_MODE = 0x1B, // 40 1B MM 00 00 00 0000 Write Medium Mode // WRITE_IPG1, // 40 13 II 00 00 00 0000 Write IPG1 Register
GET_MONITOR_MODE = 0x1C, // C0 1C 00 00 00 00 0100 Get Monitor Mode Status // WRITE_IPG2, // 40 14 II 00 00 00 0000 Write IPG2 Register
SET_MONITOR_MODE = 0x1D, // 40 1D MM 00 00 00 0000 Set Monitor Mode On/Off // READ_MF_ARRAY, // C0 15 00 00 00 00 0800 Read Multi-Filter Array
READ_GPIOS = 0x1E, // C0 1E 00 00 00 00 0100 Read GPIOs // WRITE_MF_ARRAY, // 40 16 00 00 00 00 0800 Write Multi-Filter Array
WRITE_GPIOS = 0x1F // 40 1F MM 00 00 00 0000 Write GPIOs // READ_NODEID, // C0 17 00 00 00 00 0600 Read Node ID
}; // WRITE_NODEID, //
// READ_PHYID, // C0 19 00 00 00 00 0200 Read Ethernet/HomePNA PhyID
// READ_MEDIUM_STATUS, // C0 1A 00 00 00 00 0100 Read Medium Status
// WRITE_MEDIUM_MODE, // 40 1B MM 00 00 00 0000 Write Medium Mode
// GET_MONITOR_MODE, // C0 1C 00 00 00 00 0100 Get Monitor Mode Status
// SET_MONITOR_MODE, // 40 1D MM 00 00 00 0000 Set Monitor Mode On/Off
// READ_GPIOS, // C0 1E 00 00 00 00 0100 Read GPIOs
// WRITE_GPIOS, // 40 1F MM 00 00 00 0000 Write GPIOs
// RX Control Register bits // RX Control Register bits
enum AX88172_RXControl { // RXCTL_PROMISCUOUS, // forward all frames up to the host
RXCTL_PROMISCUOUS = 0x0001, // // RXCTL_ALL_MULTICAT, // forward all multicast frames up to the host
RXCTL_ALL_MULTICAT = 0x0002, // // RXCTL_UNICAST, // ???
RXCTL_UNICAST = 0x0004, // ??? // RXCTL_BROADCAST, // forward broadcast frames up to the host
RXCTL_BROADCAST = 0x0008, // // RXCTL_MULTICAST, // forward all multicast frames that are
RXCTL_MULTICAST = 0x0010, // // matching to multicast filter up to the host
RXCTL_START = 0x0080 // // RXCTL_START, // ethernet MAC start operating
};
// PHY IDs request answer data layout // PHY IDs request answer data layout
struct PhyIDs { struct PhyIDs {
@ -63,6 +71,7 @@ struct PhyIDs {
uint8 PhyID2; uint8 PhyID2;
} _PACKED; } _PACKED;
// Medium state bits // Medium state bits
enum AX88172_MediumState { enum AX88172_MediumState {
MEDIUM_STATE_FULL_DUPLEX = 0x02, MEDIUM_STATE_FULL_DUPLEX = 0x02,
@ -70,6 +79,7 @@ enum AX88172_MediumState {
MEDIUM_STATE_FLOW_CONTOL_EN = 0x10 MEDIUM_STATE_FLOW_CONTOL_EN = 0x10
}; };
// Monitor Mode bits // Monitor Mode bits
enum AX88172_MonitorMode { enum AX88172_MonitorMode {
MONITOR_MODE = 0x01, MONITOR_MODE = 0x01,
@ -78,6 +88,7 @@ enum AX88172_MonitorMode {
MONITOR_MODE_HS_FS = 0x10 MONITOR_MODE_HS_FS = 0x10
}; };
// General Purpose I/O Register // General Purpose I/O Register
enum AX88172_GPIO { enum AX88172_GPIO {
GPIO_OO_0EN = 0x01, GPIO_OO_0EN = 0x01,
@ -88,6 +99,7 @@ enum AX88172_GPIO {
GPIO_IO_2 = 0x20 GPIO_IO_2 = 0x20
}; };
// Notification data layout // Notification data layout
struct AX88172Notify { struct AX88172Notify {
uint8 btA1; uint8 btA1;
@ -100,16 +112,20 @@ struct AX88172Notify {
uint8 bt07; uint8 bt07;
} _PACKED; } _PACKED;
// Link-State bits // Link-State bits
enum AX88172_LinkState { enum AX88172_LinkState {
LINK_STATE_PHY1 = 0x01, LINK_STATE_PHY1 = 0x01,
LINK_STATE_PHY2 = 0x02 LINK_STATE_PHY2 = 0x02
}; };
const uint16 maxFrameSize = 1518; const uint16 maxFrameSize = 1518;
AX88172Device::AX88172Device(usb_device device, const char *description)
: ASIXDevice(device, description) AX88172Device::AX88172Device(usb_device device, DeviceInfo& deviceInfo)
:
ASIXDevice(device, deviceInfo)
{ {
fStatus = InitDevice(); fStatus = InitDevice();
} }
@ -120,11 +136,7 @@ AX88172Device::InitDevice()
{ {
fFrameSize = maxFrameSize; fFrameSize = maxFrameSize;
fReadNodeIDRequest = READ_NODEID; fReadNodeIDRequest = READ_NODEID_AX88172;
fReadRXControlRequest = READ_RX_CONTROL;
fWriteRXControlRequest = WRITE_RX_CONTROL;
fPromiscuousBits = RXCTL_PROMISCUOUS;
fNotifyBufferLength = sizeof(AX88172Notify); fNotifyBufferLength = sizeof(AX88172Notify);
fNotifyBuffer = (uint8 *)malloc(fNotifyBufferLength); fNotifyBuffer = (uint8 *)malloc(fNotifyBufferLength);
@ -136,19 +148,19 @@ AX88172Device::InitDevice()
TRACE_RET(B_OK); TRACE_RET(B_OK);
return B_OK; return B_OK;
} }
status_t status_t
AX88172Device::SetupDevice(bool deviceReplugged) AX88172Device::SetupDevice(bool deviceReplugged)
{ {
status_t result = ASIXDevice::SetupDevice(deviceReplugged); status_t result = ASIXDevice::SetupDevice(deviceReplugged);
if(result != B_OK) { if (result != B_OK) {
return result; return result;
} }
result = fMII.Init(fDevice, result = fMII.Init(fDevice);
SW_MII_OP, READ_MII, WRITE_MII,
READ_MII_OP_MODE, HW_MII_OP, READ_PHYID);
if(result == B_OK) if (result == B_OK)
return fMII.SetupPHY(); return fMII.SetupPHY();
TRACE_RET(result); TRACE_RET(result);
@ -161,27 +173,27 @@ AX88172Device::StartDevice()
{ {
size_t actualLength = 0; size_t actualLength = 0;
for(size_t i = 0; i < sizeof(fIPG)/sizeof(fIPG[0]); i++) { for (size_t i = 0; i < sizeof(fIPG) / sizeof(fIPG[0]); i++) {
status_t result = gUSBModule->send_request(fDevice, status_t result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
WRITE_IPG0, 0, 0, sizeof(fIPG[i]), &fIPG[i], &actualLength); WRITE_IPG0, 0, 0, sizeof(fIPG[i]), &fIPG[i], &actualLength);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error writing IPG%d: %#010x\n", i, result); TRACE_ALWAYS("Error writing IPG%d: %#010x\n", i, result);
return result; return result;
} }
if(actualLength != sizeof(fIPG[i])) { if (actualLength != sizeof(fIPG[i])) {
TRACE_ALWAYS("Mismatch of written IPG%d data. " TRACE_ALWAYS("Mismatch of written IPG%d data. "
"%d bytes of %d written.\n", i, actualLength, sizeof(fIPG[i])); "%d bytes of %d written.\n", i, actualLength, sizeof(fIPG[i]));
} }
} }
uint16 rxcontrol = RXCTL_START | RXCTL_MULTICAST uint16 rxcontrol = RXCTL_START | RXCTL_UNICAST | RXCTL_BROADCAST;
| RXCTL_UNICAST | RXCTL_BROADCAST;
status_t result = WriteRXControlRegister(rxcontrol); status_t result = WriteRXControlRegister(rxcontrol);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n", rxcontrol, result); TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n",
rxcontrol, result);
} }
TRACE_RET(result); TRACE_RET(result);
@ -200,7 +212,7 @@ AX88172Device::OnNotify(uint32 actualLength)
AX88172Notify *notification = (AX88172Notify *)fNotifyBuffer; AX88172Notify *notification = (AX88172Notify *)fNotifyBuffer;
if(notification->btA1 != 0xa1) { if (notification->btA1 != 0xa1) {
TRACE_ALWAYS("Notify magic byte is invalid: %#02x\n", TRACE_ALWAYS("Notify magic byte is invalid: %#02x\n",
notification->btA1); notification->btA1);
} }
@ -225,7 +237,7 @@ AX88172Device::OnNotify(uint32 actualLength)
bool linkStateChange = linkIsUp != fHasConnection; bool linkStateChange = linkIsUp != fHasConnection;
fHasConnection = linkIsUp; fHasConnection = linkIsUp;
if(linkStateChange) { if (linkStateChange) {
TRACE("Link state of PHY%d has been changed to '%s'\n", TRACE("Link state of PHY%d has been changed to '%s'\n",
phyIndex, fHasConnection ? "up" : "down"); phyIndex, fHasConnection ? "up" : "down");
} }
@ -236,6 +248,7 @@ AX88172Device::OnNotify(uint32 actualLength)
return B_OK; return B_OK;
} }
status_t status_t
AX88172Device::GetLinkState(ether_link_state *linkState) AX88172Device::GetLinkState(ether_link_state *linkState)
{ {
@ -243,13 +256,13 @@ AX88172Device::GetLinkState(ether_link_state *linkState)
uint16 miiANLPAR = 0; uint16 miiANLPAR = 0;
status_t result = fMII.Read(MII_ANAR, &miiANAR); status_t result = fMII.Read(MII_ANAR, &miiANAR);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error reading MII ANAR register:%#010x\n", result); TRACE_ALWAYS("Error reading MII ANAR register:%#010x\n", result);
return result; return result;
} }
result = fMII.Read(MII_ANLPAR, &miiANLPAR); result = fMII.Read(MII_ANLPAR, &miiANLPAR);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error reading MII ANLPAR register:%#010x\n", result); TRACE_ALWAYS("Error reading MII ANLPAR register:%#010x\n", result);
return result; return result;
} }
@ -261,14 +274,15 @@ AX88172Device::GetLinkState(ether_link_state *linkState)
linkState->quality = 1000; linkState->quality = 1000;
linkState->media = IFM_ETHER | (fHasConnection ? IFM_ACTIVE : 0); linkState->media = IFM_ETHER | (fHasConnection ? IFM_ACTIVE : 0);
linkState->media |= mediumStatus & (ANLPAR_TX_FD | ANLPAR_10_FD) ? linkState->media |= mediumStatus & (ANLPAR_TX_FD | ANLPAR_10_FD) ?
IFM_FULL_DUPLEX : IFM_HALF_DUPLEX; IFM_FULL_DUPLEX : IFM_HALF_DUPLEX;
linkState->speed = mediumStatus & (ANLPAR_TX_FD | ANLPAR_TX_HD) ? 100000000 : 10000000; linkState->speed = mediumStatus & (ANLPAR_TX_FD | ANLPAR_TX_HD)
? 100000000 : 10000000;
TRACE_FLOW("Medium state: %s, %lld MBit/s, %s duplex.\n", TRACE_FLOW("Medium state: %s, %lld MBit/s, %s duplex.\n",
(linkState->media & IFM_ACTIVE) ? "active" : "inactive", (linkState->media & IFM_ACTIVE) ? "active" : "inactive",
linkState->speed, linkState->speed / 1000000,
(linkState->media & IFM_FULL_DUPLEX) ? "full" : "half"); (linkState->media & IFM_FULL_DUPLEX) ? "full" : "half");
return B_OK; return B_OK;
} }

View File

@ -1,30 +1,31 @@
/* /*
* ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver. * ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver.
* Copyright (c) 2008 S.Zharski <imker@gmx.li> * Copyright (c) 2008, 2011 S.Zharski <imker@gmx.li>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
* Heavily based on code of the * Heavily based on code of the
* Driver for USB Ethernet Control Model devices * Driver for USB Ethernet Control Model devices
* Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch> * Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
*/ */
#ifndef _USB_AX88172_DEVICE_H_ #ifndef _USB_AX88172_DEVICE_H_
#define _USB_AX88172_DEVICE_H_ #define _USB_AX88172_DEVICE_H_
#include "ASIXDevice.h" #include "ASIXDevice.h"
class AX88172Device : public ASIXDevice { class AX88172Device : public ASIXDevice {
public: public:
AX88172Device(usb_device device, const char *description); AX88172Device(usb_device device, DeviceInfo& info);
protected: protected:
status_t InitDevice(); status_t InitDevice();
virtual status_t SetupDevice(bool deviceReplugged); virtual status_t SetupDevice(bool deviceReplugged);
virtual status_t StartDevice(); virtual status_t StartDevice();
virtual status_t OnNotify(uint32 actualLength); virtual status_t OnNotify(uint32 actualLength);
virtual status_t GetLinkState(ether_link_state *state); virtual status_t GetLinkState(ether_link_state *state);
}; };
#endif //_USB_AX88172_DEVICE_H_ #endif // _USB_AX88172_DEVICE_H_

View File

@ -1,6 +1,6 @@
/* /*
* ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver. * ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver.
* Copyright (c) 2008 S.Zharski <imker@gmx.li> * Copyright (c) 2008, 2011 S.Zharski <imker@gmx.li>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
* Heavily based on code of the * Heavily based on code of the
@ -10,54 +10,63 @@
* *
*/ */
#include "Settings.h"
#include "AX88178Device.h" #include "AX88178Device.h"
// Vendor USB requests for AX88178 #include <net/if_media.h>
enum AX88178_Requests {
READ_RXTX_SRAM = 0x02, //C002_AA0B_0C00_0800 Rx/Tx SRAM Read #include "ASIXVendorRequests.h"
WRITE_RXTX_SRAM = 0x03, //4003_AA0B_0C00_0800 Rx/Tx SRAM Write #include "Settings.h"
SW_MII_OP = 0x06, //4006_0000_0000_0000 SW Serial Management Control
READ_MII = 0x07, //c007_aa00_cc00_0200 PHY Read
WRITE_MII = 0x08, //4008_aa00_cc00_0200 PHY Write // Most of vendor requests for all supported chip types use the same
READ_MII_STATUS = 0x09, //c009_0000_0000_0100 Serial Management Status // constants (see ASIXVendorRequests.h) but the layout of request data
HW_MII_OP = 0x0A, //400a_0000_0000_0000 HW Serial Management Control // may be slightly diferrent for specific chip type. Below is a quick
READ_SROM = 0x0B, //C00B_AA00_0000_0200 SROM Read // reference for AX88178 vendor requests data layout.
WRITE_SROM = 0x0C, //400C_AA00_CCDD_0000 SROM Write
WRITE_SROM_ENABLE = 0x0D, //400D_0000_0000_0000 SROM Write Enable // READ_RXTX_SRAM, //C002_AA0B_0C00_0800 Rx/Tx SRAM Read
WRITE_SROM_DISABLE = 0x0E, //400E_0000_0000_0000 SROM Write Disable // WRITE_RXTX_SRAM, //4003_AA0B_0C00_0800 Rx/Tx SRAM Write
READ_RX_CONTROL = 0x0F, //C00F_0000_0000_0200 Read Rx Control // SW_MII_OP, //4006_0000_0000_0000 SW Serial Management Control
WRITE_RX_CONTROL = 0x10, //4010_AABB_0000_0000 Write Rx Control // READ_MII, //c007_aa00_cc00_0200 PHY Read
READ_IPGS = 0x11, //C011_0000_0000_0300 Read IPG/IPG1/IPG2 Register // WRITE_MII, //4008_aa00_cc00_0200 PHY Write
WRITE_IPGS = 0x12, //4012_AABB_CC00_0000 Write IPG/IPG1/IPG2 Register // READ_MII_STATUS, //c009_0000_0000_0100 Serial Management Status
READ_NODEID = 0x13, //C013_0000_0000_0600 Read Node ID // HW_MII_OP, //400a_0000_0000_0000 HW Serial Management Control
WRITE_NODEID = 0x14, //4014_0000_0000_0600 Write Node ID // READ_SROM, //C00B_AA00_0000_0200 SROM Read
READ_MF_ARRAY = 0x15, //C015_0000_0000_0800 Read Multicast Filter Array // WRITE_SROM, //400C_AA00_CCDD_0000 SROM Write
WRITE_MF_ARRAY = 0x16, //4016_0000_0000_0800 Write Multicast Filter Array // WRITE_SROM_ENABLE, //400D_0000_0000_0000 SROM Write Enable
READ_TEST = 0x17, //4017_AA00_0000_0000 Write Test Register // WRITE_SROM_DISABLE, //400E_0000_0000_0000 SROM Write Disable
READ_PHYID = 0x19, //C019_0000_0000_0200 Read Ethernet/HomePNA PHY Address // READ_RX_CONTROL, //C00F_0000_0000_0200 Read Rx Control
READ_MEDIUM_STATUS = 0x1A, //C01A_0000_0000_0200 Read Medium Status // WRITE_RX_CONTROL, //4010_AABB_0000_0000 Write Rx Control
WRITE_MEDIUM_MODE = 0x1B, //401B_AABB_0000_0000 Write Medium Mode Register // READ_IPGS, //C011_0000_0000_0300 Read IPG/IPG1/IPG2 Register
GET_MONITOR_MODE = 0x1C, //C01C_0000_0000_0100 Read Monitor Mode Status // WRITE_IPGS, //4012_AABB_CC00_0000 Write IPG/IPG1/IPG2 Register
SET_MONITOR_MODE = 0x1D, //401D_AA00_0000_0000 Write Monitor Mode Register // READ_NODEID, //C013_0000_0000_0600 Read Node ID
READ_GPIOS = 0x1E, //C01E_0000_0000_0100 Read GPIOs Status // WRITE_NODEID, //4014_0000_0000_0600 Write Node ID
WRITE_GPIOS = 0x1F, //401F_AA00_0000_0000 Write GPIOs // READ_MF_ARRAY, //C015_0000_0000_0800 Read Multicast Filter Array
WRITE_SOFT_RESET = 0x20, //4020_AA00_0000_0000 Write Software Reset // WRITE_MF_ARRAY, //4016_0000_0000_0800 Write Multicast Filter Array
READ_MIIS_IF_STATE = 0x21, //C021_AA00_0000_0100 Read MII/GMII/RGMII Interface Status // READ_TEST, //4017_AA00_0000_0000 Write Test Register
WRITE_MIIS_IF_STATE = 0x22 //4022_AA00_0000_0000 Write MII/GMII/RGMII Interface Control // READ_PHYID, //C019_0000_0000_0200 Read Ethernet/HomePNA PHY Address
}; // READ_MEDIUM_STATUS, //C01A_0000_0000_0200 Read Medium Status
// WRITE_MEDIUM_MODE, //401B_AABB_0000_0000 Write Medium Mode Register
// GET_MONITOR_MODE, //C01C_0000_0000_0100 Read Monitor Mode Status
// SET_MONITOR_MODE, //401D_AA00_0000_0000 Write Monitor Mode Register
// READ_GPIOS, //C01E_0000_0000_0100 Read GPIOs Status
// WRITE_GPIOS, //401F_AA00_0000_0000 Write GPIOs
// WRITE_SOFT_RESET, //4020_AA00_0000_0000 Write Software Reset
// READ_MIIS_IF_STATE, //C021_AA00_0000_0100 Read MII/GMII/RGMII Iface Status
// WRITE_MIIS_IF_STATE, //4022_AA00_0000_0000 Write MII/GMII/RGMII Iface Control
// RX Control Register bits // RX Control Register bits
enum AX88178_RXControl { // RXCTL_PROMISCUOUS, // forward all frames up to the host
RXCTL_PROMISCUOUS = 0x0001, // // RXCTL_ALL_MULTICAT, // forward all multicast frames up to the host
RXCTL_ALL_MULTICAT = 0x0002, // // RXCTL_SEP, // forward frames with CRC error up to the host
// RXCTL_SEP = 0x0004, // do not set it! // RXCTL_BROADCAST, // forward broadcast frames up to the host
RXCTL_BROADCAST = 0x0008, // // RXCTL_MULTICAST, // forward multicast frames that are
RXCTL_MULTICAST = 0x0010, // // matching to multicast filter up to the host
RXCTL_AP = 0x0020, // // RXCTL_AP, // forward unicast frames that are matching
RXCTL_START = 0x0080, // // to multicast filter up to the host
RXCTL_USB_MFB = 0x0100 // Max Frame Burst TX on USB // RXCTL_START, // ethernet MAC start operating
}; // RXCTL_USB_MFB, // Max Frame Burst TX on USB
// PHY IDs request answer data layout // PHY IDs request answer data layout
struct AX88178_PhyIDs { struct AX88178_PhyIDs {
@ -65,6 +74,7 @@ struct AX88178_PhyIDs {
uint8 PriPhyID2; uint8 PriPhyID2;
} _PACKED; } _PACKED;
// Medium state bits // Medium state bits
enum AX88178_MediumState { enum AX88178_MediumState {
MEDIUM_STATE_GM = 0x0001, MEDIUM_STATE_GM = 0x0001,
@ -84,6 +94,7 @@ enum AX88178_MediumState {
MEDIUM_STATE_SM_ON = 0x1000 MEDIUM_STATE_SM_ON = 0x1000
}; };
// Monitor Mode bits // Monitor Mode bits
enum AX88178_MonitorMode { enum AX88178_MonitorMode {
MONITOR_MODE_MOM = 0x01, MONITOR_MODE_MOM = 0x01,
@ -92,6 +103,7 @@ enum AX88178_MonitorMode {
MONITOR_MODE_US = 0x10 MONITOR_MODE_US = 0x10
}; };
// General Purpose I/O Register // General Purpose I/O Register
enum AX88178_GPIO { enum AX88178_GPIO {
GPIO_OO_0EN = 0x01, GPIO_OO_0EN = 0x01,
@ -103,6 +115,7 @@ enum AX88178_GPIO {
GPIO_RSE = 0x80 GPIO_RSE = 0x80
}; };
// Software Reset Register bits // Software Reset Register bits
enum AX88178_SoftwareReset { enum AX88178_SoftwareReset {
SW_RESET_RR = 0x01, SW_RESET_RR = 0x01,
@ -113,12 +126,14 @@ enum AX88178_SoftwareReset {
SW_RESET_BIT6 = 0x40 // always set to 1 SW_RESET_BIT6 = 0x40 // always set to 1
}; };
// MII/GMII/RGMII Interface Conttrol // MII/GMII/RGMII Interface Conttrol
enum AX88178_MIISInterfaceStatus { enum AX88178_MIISInterfaceStatus {
MIIS_IF_STATE_DM = 0x01, MIIS_IF_STATE_DM = 0x01,
MIIS_IF_STATE_RB = 0x02 MIIS_IF_STATE_RB = 0x02
}; };
// Notification data layout // Notification data layout
struct AX88178_Notify { struct AX88178_Notify {
uint8 btA1; uint8 btA1;
@ -129,6 +144,7 @@ struct AX88178_Notify {
uint16 regEEFF; uint16 regEEFF;
} _PACKED; } _PACKED;
// Link-State bits // Link-State bits
enum AX88178_BBState { enum AX88178_BBState {
LINK_STATE_PPLS = 0x01, LINK_STATE_PPLS = 0x01,
@ -137,10 +153,13 @@ enum AX88178_BBState {
LINK_STATE_MDINT = 0x08 LINK_STATE_MDINT = 0x08
}; };
const uint16 maxFrameSize = 1536; const uint16 maxFrameSize = 1536;
AX88178Device::AX88178Device(usb_device device, const char *description)
: ASIXDevice(device, description) AX88178Device::AX88178Device(usb_device device, DeviceInfo& deviceInfo)
:
ASIXDevice(device, deviceInfo)
{ {
fStatus = InitDevice(); fStatus = InitDevice();
} }
@ -153,10 +172,6 @@ AX88178Device::InitDevice()
fUseTRXHeader = true; fUseTRXHeader = true;
fReadNodeIDRequest = READ_NODEID; fReadNodeIDRequest = READ_NODEID;
fReadRXControlRequest = READ_RX_CONTROL;
fWriteRXControlRequest = WRITE_RX_CONTROL;
fPromiscuousBits = RXCTL_PROMISCUOUS;
fNotifyBufferLength = sizeof(AX88178_Notify); fNotifyBufferLength = sizeof(AX88178_Notify);
fNotifyBuffer = (uint8 *)malloc(fNotifyBufferLength); fNotifyBuffer = (uint8 *)malloc(fNotifyBufferLength);
@ -174,15 +189,13 @@ status_t
AX88178Device::SetupDevice(bool deviceReplugged) AX88178Device::SetupDevice(bool deviceReplugged)
{ {
status_t result = ASIXDevice::SetupDevice(deviceReplugged); status_t result = ASIXDevice::SetupDevice(deviceReplugged);
if(result != B_OK) { if (result != B_OK) {
return result; return result;
} }
result = fMII.Init(fDevice, result = fMII.Init(fDevice);
SW_MII_OP, READ_MII, WRITE_MII,
READ_MII_STATUS, HW_MII_OP, READ_PHYID);
if(result != B_OK) { if (result != B_OK) {
return result; return result;
} }
@ -192,7 +205,7 @@ AX88178Device::SetupDevice(bool deviceReplugged)
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
WRITE_SROM_ENABLE, 0, 0, 0, 0, &actualLength); WRITE_SROM_ENABLE, 0, 0, 0, 0, &actualLength);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of enabling SROM access:%#010x\n", result); TRACE_ALWAYS("Error of enabling SROM access:%#010x\n", result);
return result; return result;
} }
@ -203,26 +216,26 @@ AX88178Device::SetupDevice(bool deviceReplugged)
READ_SROM, 0x17, 0, READ_SROM, 0x17, 0,
sizeof(eepromData), &eepromData, &actualLength); sizeof(eepromData), &eepromData, &actualLength);
if(op_result != B_OK) { if (op_result != B_OK) {
TRACE_ALWAYS("Error of reading SROM data:%#010x\n", result); TRACE_ALWAYS("Error of reading SROM data:%#010x\n", result);
} }
if(actualLength != sizeof(eepromData)) { if (actualLength != sizeof(eepromData)) {
TRACE_ALWAYS("Mismatch of reading SROM data." TRACE_ALWAYS("Mismatch of reading SROM data."
"Read %d bytes instead of %d\n", "Read %d bytes instead of %d\n",
actualLength, sizeof(eepromData)); actualLength, sizeof(eepromData));
} }
result = gUSBModule->send_request(fDevice, result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
WRITE_SROM_DISABLE, 0, 0, 0, 0, &actualLength); WRITE_SROM_DISABLE, 0, 0, 0, 0, &actualLength);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of disabling SROM access: %#010x\n", result); TRACE_ALWAYS("Error of disabling SROM access: %#010x\n", result);
return result; return result;
} }
if(op_result != B_OK) { if (op_result != B_OK) {
return op_result; return op_result;
} }
@ -246,7 +259,7 @@ AX88178Device::SetupDevice(bool deviceReplugged)
size_t from = bCase8 ? 0 : 4; size_t from = bCase8 ? 0 : 4;
size_t to = bCase8 ? 3 : 6; size_t to = bCase8 ? 3 : 6;
for(size_t i = from; i <= to; i++) { for (size_t i = from; i <= to; i++) {
result = gUSBModule->send_request(fDevice, result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
WRITE_GPIOS, GPIOCommands[i].value, WRITE_GPIOS, GPIOCommands[i].value,
@ -254,7 +267,7 @@ AX88178Device::SetupDevice(bool deviceReplugged)
snooze(GPIOCommands[i].delay); snooze(GPIOCommands[i].delay);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of GPIO setup command %d:[%#04x]: %#010x\n", TRACE_ALWAYS("Error of GPIO setup command %d:[%#04x]: %#010x\n",
i, GPIOCommands[i].value, result); i, GPIOCommands[i].value, result);
return result; return result;
@ -267,7 +280,7 @@ AX88178Device::SetupDevice(bool deviceReplugged)
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
WRITE_SOFT_RESET, uSWReset, 0, 0, 0, &actualLength); WRITE_SOFT_RESET, uSWReset, 0, 0, 0, &actualLength);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of SW reset to %#02x: %#010x\n", uSWReset, result); TRACE_ALWAYS("Error of SW reset to %#02x: %#010x\n", uSWReset, result);
return result; return result;
} }
@ -279,7 +292,7 @@ AX88178Device::SetupDevice(bool deviceReplugged)
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
WRITE_SOFT_RESET, uSWReset, 0, 0, 0, &actualLength); WRITE_SOFT_RESET, uSWReset, 0, 0, 0, &actualLength);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of SW reset to %#02x: %#010x\n", uSWReset, result); TRACE_ALWAYS("Error of SW reset to %#02x: %#010x\n", uSWReset, result);
return result; return result;
} }
@ -287,7 +300,7 @@ AX88178Device::SetupDevice(bool deviceReplugged)
snooze(150000); snooze(150000);
result = WriteRXControlRegister(0); result = WriteRXControlRegister(0);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n", 0, result); TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n", 0, result);
return result; return result;
} }
@ -307,20 +320,21 @@ AX88178Device::StartDevice()
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
WRITE_IPGS, 0, 0, sizeof(fIPG), fIPG, &actualLength); WRITE_IPGS, 0, 0, sizeof(fIPG), fIPG, &actualLength);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of writing IPGs:%#010x\n", result); TRACE_ALWAYS("Error of writing IPGs:%#010x\n", result);
return result; return result;
} }
if(actualLength != sizeof(fIPG)) { if (actualLength != sizeof(fIPG)) {
TRACE_ALWAYS("Mismatch of written IPGs data. " TRACE_ALWAYS("Mismatch of written IPGs data. "
"%d bytes of %d written.\n", actualLength, sizeof(fIPG)); "%d bytes of %d written.\n", actualLength, sizeof(fIPG));
} }
uint16 rxcontrol = RXCTL_START | RXCTL_MULTICAST | RXCTL_BROADCAST; uint16 rxcontrol = RXCTL_START | RXCTL_BROADCAST;
result = WriteRXControlRegister(rxcontrol); result = WriteRXControlRegister(rxcontrol);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n", rxcontrol, result); TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n",
rxcontrol, result);
} }
TRACE_RET(result); TRACE_RET(result);
@ -339,9 +353,9 @@ AX88178Device::OnNotify(uint32 actualLength)
AX88178_Notify *notification = (AX88178_Notify *)fNotifyBuffer; AX88178_Notify *notification = (AX88178_Notify *)fNotifyBuffer;
if(notification->btA1 != 0xa1) { if (notification->btA1 != 0xa1) {
TRACE_ALWAYS("Notify magic byte is invalid: %#02x\n", TRACE_ALWAYS("Notify magic byte is invalid: %#02x\n",
notification->btA1); notification->btA1);
} }
uint phyIndex = 0; uint phyIndex = 0;
@ -364,7 +378,7 @@ AX88178Device::OnNotify(uint32 actualLength)
bool linkStateChange = linkIsUp != fHasConnection; bool linkStateChange = linkIsUp != fHasConnection;
fHasConnection = linkIsUp; fHasConnection = linkIsUp;
if(linkStateChange) { if (linkStateChange) {
TRACE("Link state of PHY%d has been changed to '%s'\n", TRACE("Link state of PHY%d has been changed to '%s'\n",
phyIndex, fHasConnection ? "up" : "down"); phyIndex, fHasConnection ? "up" : "down");
} }
@ -386,12 +400,12 @@ AX88178Device::GetLinkState(ether_link_state *linkState)
READ_MEDIUM_STATUS, 0, 0, sizeof(mediumStatus), READ_MEDIUM_STATUS, 0, 0, sizeof(mediumStatus),
&mediumStatus, &actualLength); &mediumStatus, &actualLength);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of reading medium status:%#010x.\n", result); TRACE_ALWAYS("Error of reading medium status:%#010x.\n", result);
return result; return result;
} }
if(actualLength != sizeof(mediumStatus)) { if (actualLength != sizeof(mediumStatus)) {
TRACE_ALWAYS("Mismatch of reading medium status." TRACE_ALWAYS("Mismatch of reading medium status."
"Read %d bytes instead of %d\n", "Read %d bytes instead of %d\n",
actualLength, sizeof(mediumStatus)); actualLength, sizeof(mediumStatus));
@ -402,16 +416,17 @@ AX88178Device::GetLinkState(ether_link_state *linkState)
linkState->quality = 1000; linkState->quality = 1000;
linkState->media = IFM_ETHER | (fHasConnection ? IFM_ACTIVE : 0); linkState->media = IFM_ETHER | (fHasConnection ? IFM_ACTIVE : 0);
linkState->media |= (mediumStatus & MEDIUM_STATE_FD) ? linkState->media |= (mediumStatus & MEDIUM_STATE_FD) ?
IFM_FULL_DUPLEX : IFM_HALF_DUPLEX; IFM_FULL_DUPLEX : IFM_HALF_DUPLEX;
linkState->speed = (mediumStatus & MEDIUM_STATE_PS_100) ? 100000000 : 10000000; linkState->speed = (mediumStatus & MEDIUM_STATE_PS_100)
? 100000000 : 10000000;
linkState->speed = (mediumStatus & MEDIUM_STATE_GM) ? linkState->speed = (mediumStatus & MEDIUM_STATE_GM) ?
1000000000 : linkState->speed; 1000000000 : linkState->speed;
TRACE_FLOW("Medium state: %s, %lld MBit/s, %s duplex.\n", TRACE_FLOW("Medium state: %s, %lld MBit/s, %s duplex.\n",
(linkState->media & IFM_ACTIVE) ? "active" : "inactive", (linkState->media & IFM_ACTIVE) ? "active" : "inactive",
linkState->speed, linkState->speed / 1000000,
(linkState->media & IFM_FULL_DUPLEX) ? "full" : "half"); (linkState->media & IFM_FULL_DUPLEX) ? "full" : "half");
return B_OK; return B_OK;
} }

View File

@ -1,29 +1,30 @@
/* /*
* ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver. * ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver.
* Copyright (c) 2008 S.Zharski <imker@gmx.li> * Copyright (c) 2008, 2011 S.Zharski <imker@gmx.li>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
* Heavily based on code of the * Heavily based on code of the
* Driver for USB Ethernet Control Model devices * Driver for USB Ethernet Control Model devices
* Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch> * Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
*/ */
#ifndef _USB_AX88178_DEVICE_H_ #ifndef _USB_AX88178_DEVICE_H_
#define _USB_AX88178_DEVICE_H_ #define _USB_AX88178_DEVICE_H_
#include "ASIXDevice.h" #include "ASIXDevice.h"
class AX88178Device : public ASIXDevice { class AX88178Device : public ASIXDevice {
public: public:
AX88178Device(usb_device device, const char *description); AX88178Device(usb_device device, DeviceInfo& info);
protected: protected:
status_t InitDevice(); status_t InitDevice();
virtual status_t SetupDevice(bool deviceReplugged); virtual status_t SetupDevice(bool deviceReplugged);
virtual status_t StartDevice(); virtual status_t StartDevice();
virtual status_t OnNotify(uint32 actualLength); virtual status_t OnNotify(uint32 actualLength);
virtual status_t GetLinkState(ether_link_state *state); virtual status_t GetLinkState(ether_link_state *state);
}; };
#endif //_USB_AX88178_DEVICE_H_ #endif // _USB_AX88178_DEVICE_H_

View File

@ -1,6 +1,6 @@
/* /*
* ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver. * ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver.
* Copyright (c) 2008 S.Zharski <imker@gmx.li> * Copyright (c) 2008, 2011 S.Zharski <imker@gmx.li>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
* Heavily based on code of the * Heavily based on code of the
@ -10,53 +10,63 @@
* *
*/ */
#include "Settings.h"
#include "AX88772Device.h" #include "AX88772Device.h"
enum AX88772_Requests { #include <net/if_media.h>
READ_RXTX_SRAM = 0x02, //C002_AA0B_0C00_0800 Rx/Tx SRAM Read
WRITE_RXTX_SRAM = 0x03, //4003_AA0B_0C00_0800 Rx/Tx SRAM Write #include "ASIXVendorRequests.h"
SW_MII_OP = 0x06, //4006_0000_0000_0000 SW Serial Management Control #include "Settings.h"
READ_MII = 0x07, //c007_aa00_cc00_0200 PHY Read
WRITE_MII = 0x08, //4008_aa00_cc00_0200 PHY Write
READ_MII_OP_MODE = 0x09, //c009_0000_0000_0100 Serial Management Status // Most of vendor requests for all supported chip types use the same
HW_MII_OP = 0x0A, //400a_0000_0000_0000 HW Serial Management Control // constants (see ASIXVendorRequests.h) but the layout of request data
READ_SROM = 0x0B, //C00B_AA00_0000_0200 SROM Read // may be slightly diferrent for specific chip type. Below is a quick
WRITE_SROM = 0x0C, //400C_AA00_CCDD_0000 SROM Write // reference for AX88772 vendor requests data layout.
WRITE_SROM_ENABLE = 0x0D, //400D_0000_0000_0000 SROM Write Enable
WRITE_SROM_DISABLE = 0x0E, //400E_0000_0000_0000 SROM Write Disable // READ_RXTX_SRAM, //C002_AA0B_0C00_0800 Rx/Tx SRAM Read
READ_RX_CONTROL = 0x0F, //C00F_0000_0000_0200 Read Rx Control // WRITE_RXTX_SRAM, //4003_AA0B_0C00_0800 Rx/Tx SRAM Write
WRITE_RX_CONTROL = 0x10, //4010_AABB_0000_0000 Write Rx Control // SW_MII_OP, //4006_0000_0000_0000 SW Serial Management Control
READ_IPGS = 0x11, //C011_0000_0000_0300 Read IPG/IPG1/IPG2 Register // READ_MII, //c007_aa00_cc00_0200 PHY Read
WRITE_IPGS = 0x12, //4012_AABB_CC00_0000 Write IPG/IPG1/IPG2 Register // WRITE_MII, //4008_aa00_cc00_0200 PHY Write
READ_NODEID = 0x13, //C013_0000_0000_0600 Read Node ID // READ_MII_OP_MODE, //c009_0000_0000_0100 Serial Management Status
WRITE_NODEID = 0x14, //4014_0000_0000_0600 Write Node ID // HW_MII_OP, //400a_0000_0000_0000 HW Serial Management Control
READ_MF_ARRAY = 0x15, //C015_0000_0000_0800 Read Multicast Filter Array // READ_SROM, //C00B_AA00_0000_0200 SROM Read
WRITE_MF_ARRAY = 0x16, //4016_0000_0000_0800 Write Multicast Filter Array // WRITE_SROM, //400C_AA00_CCDD_0000 SROM Write
READ_TEST = 0x17, //4017_AA00_0000_0000 Write Test Register // WRITE_SROM_ENABLE, //400D_0000_0000_0000 SROM Write Enable
READ_PHYID = 0x19, //C019_0000_0000_0200 Read Ethernet/HomePNA PHY Address // WRITE_SROM_DISABLE, //400E_0000_0000_0000 SROM Write Disable
READ_MEDIUM_STATUS = 0x1A, //C01A_0000_0000_0200 Read Medium Status // READ_RX_CONTROL, //C00F_0000_0000_0200 Read Rx Control
WRITE_MEDIUM_MODE = 0x1B, //401B_AABB_0000_0000 Write Medium Mode Register // WRITE_RX_CONTROL, //4010_AABB_0000_0000 Write Rx Control
GET_MONITOR_MODE = 0x1C, //C01C_0000_0000_0100 Read Monitor Mode Status // READ_IPGS, //C011_0000_0000_0300 Read IPG/IPG1/IPG2 Register
SET_MONITOR_MODE = 0x1D, //401D_AA00_0000_0000 Write Monitor Mode Register // WRITE_IPGS, //4012_AABB_CC00_0000 Write IPG/IPG1/IPG2 Register
READ_GPIOS = 0x1E, //C01E_0000_0000_0100 Read GPIOs Status // READ_NODEID, //C013_0000_0000_0600 Read Node ID
WRITE_GPIOS = 0x1F, //401F_AA00_0000_0000 Write GPIOs // WRITE_NODEID, //4014_0000_0000_0600 Write Node ID
WRITE_SOFT_RESET = 0x20, //4020_AA00_0000_0000 Write Software Reset // READ_MF_ARRAY, //C015_0000_0000_0800 Read Multicast Filter Array
READ_PHY_SEL_STATE = 0x21, //C021_AA00_0000_0100 Read Software PHY Select Status // WRITE_MF_ARRAY, //4016_0000_0000_0800 Write Multicast Filter Array
WRITE_PHY_SEL = 0x22 //4022_AA00_0000_0000 Write Software PHY Select // READ_TEST, //4017_AA00_0000_0000 Write Test Register
}; // READ_PHYID, //C019_0000_0000_0200 Read Ethernet/HomePNA PHY Address
// READ_MEDIUM_STATUS, //C01A_0000_0000_0200 Read Medium Status
// WRITE_MEDIUM_MODE, //401B_AABB_0000_0000 Write Medium Mode Register
// GET_MONITOR_MODE, //C01C_0000_0000_0100 Read Monitor Mode Status
// SET_MONITOR_MODE, //401D_AA00_0000_0000 Write Monitor Mode Register
// READ_GPIOS, //C01E_0000_0000_0100 Read GPIOs Status
// WRITE_GPIOS, //401F_AA00_0000_0000 Write GPIOs
// WRITE_SOFT_RESET, //4020_AA00_0000_0000 Write Software Reset
// READ_PHY_SEL_STATE, //C021_AA00_0000_0100 Read Software PHY Select Status
// WRITE_PHY_SEL, //4022_AA00_0000_0000 Write Software PHY Select
// RX Control Register bits // RX Control Register bits
enum AX88772_RXControl { // RXCTL_PROMISCUOUS, // forward all frames up to the host
RXCTL_PROMISCUOUS = 0x0001, // // RXCTL_ALL_MULTICAT, // forward all multicast frames up to the host
RXCTL_ALL_MULTICAT = 0x0002, // // RXCTL_SEP, // forward frames with CRC error up to the host
// RXCTL_SEP = 0x0004, // do not set it! // RXCTL_BROADCAST, // forward broadcast frames up to the host
RXCTL_BROADCAST = 0x0008, // // RXCTL_MULTICAST, // forward multicast frames that are
RXCTL_MULTICAST = 0x0010, // // matching to multicast filter up to the host
RXCTL_AP = 0x0020, // // RXCTL_AP, // forward unicast frames that are matching
RXCTL_START = 0x0080, // // to multicast filter up to the host
RXCTL_USB_MFB = 0x0100 // Max Frame Burst TX on USB // RXCTL_START, // ethernet MAC start operating
}; // RXCTL_USB_MFB, // Max Frame Burst TX on USB
// PHY IDs request answer data layout // PHY IDs request answer data layout
struct AX88772_PhyIDs { struct AX88772_PhyIDs {
@ -64,6 +74,7 @@ struct AX88772_PhyIDs {
uint8 PriPhyID2; uint8 PriPhyID2;
} _PACKED; } _PACKED;
// Medium state bits // Medium state bits
enum AX88772_MediumState { enum AX88772_MediumState {
MEDIUM_STATE_FD = 0x0002, MEDIUM_STATE_FD = 0x0002,
@ -80,6 +91,7 @@ enum AX88772_MediumState {
MEDIUM_STATE_SM_ON = 0x1000 MEDIUM_STATE_SM_ON = 0x1000
}; };
// Monitor Mode bits // Monitor Mode bits
enum AX88772_MonitorMode { enum AX88772_MonitorMode {
MONITOR_MODE_MOM = 0x01, MONITOR_MODE_MOM = 0x01,
@ -88,6 +100,7 @@ enum AX88772_MonitorMode {
MONITOR_MODE_US = 0x10 MONITOR_MODE_US = 0x10
}; };
// General Purpose I/O Register // General Purpose I/O Register
enum AX88772_GPIO { enum AX88772_GPIO {
GPIO_OO_0EN = 0x01, GPIO_OO_0EN = 0x01,
@ -99,6 +112,7 @@ enum AX88772_GPIO {
GPIO_RSE = 0x80 GPIO_RSE = 0x80
}; };
// Software Reset Register bits // Software Reset Register bits
enum AX88772_SoftwareReset { enum AX88772_SoftwareReset {
SW_RESET_CLR = 0x00, SW_RESET_CLR = 0x00,
@ -111,6 +125,7 @@ enum AX88772_SoftwareReset {
SW_RESET_IPPD = 0x40 SW_RESET_IPPD = 0x40
}; };
// Software PHY Select Status // Software PHY Select Status
enum AX88772_SoftwarePHYSelStatus { enum AX88772_SoftwarePHYSelStatus {
SW_PHY_SEL_STATUS_EXT = 0x00, SW_PHY_SEL_STATUS_EXT = 0x00,
@ -118,6 +133,7 @@ enum AX88772_SoftwarePHYSelStatus {
SW_PHY_SEL_STATUS_ASEL = 0x02 SW_PHY_SEL_STATUS_ASEL = 0x02
}; };
// Notification data layout // Notification data layout
struct AX88772_Notify { struct AX88772_Notify {
uint8 btA1; uint8 btA1;
@ -128,6 +144,7 @@ struct AX88772_Notify {
uint16 regEEFF; uint16 regEEFF;
} _PACKED; } _PACKED;
// Link-State bits // Link-State bits
enum AX88772_BBState { enum AX88772_BBState {
LINK_STATE_PPLS = 0x01, LINK_STATE_PPLS = 0x01,
@ -136,10 +153,13 @@ enum AX88772_BBState {
LINK_STATE_MDINT = 0x08 LINK_STATE_MDINT = 0x08
}; };
const uint16 maxFrameSize = 1536; const uint16 maxFrameSize = 1536;
AX88772Device::AX88772Device(usb_device device, const char *description)
: ASIXDevice(device, description) AX88772Device::AX88772Device(usb_device device, DeviceInfo& deviceInfo)
:
ASIXDevice(device, deviceInfo)
{ {
fStatus = InitDevice(); fStatus = InitDevice();
} }
@ -152,10 +172,6 @@ AX88772Device::InitDevice()
fUseTRXHeader = true; fUseTRXHeader = true;
fReadNodeIDRequest = READ_NODEID; fReadNodeIDRequest = READ_NODEID;
fReadRXControlRequest = READ_RX_CONTROL;
fWriteRXControlRequest = WRITE_RX_CONTROL;
fPromiscuousBits = RXCTL_PROMISCUOUS;
fNotifyBufferLength = sizeof(AX88772_Notify); fNotifyBufferLength = sizeof(AX88772_Notify);
fNotifyBuffer = (uint8 *)malloc(fNotifyBufferLength); fNotifyBuffer = (uint8 *)malloc(fNotifyBufferLength);
@ -172,13 +188,11 @@ status_t
AX88772Device::SetupDevice(bool deviceReplugged) AX88772Device::SetupDevice(bool deviceReplugged)
{ {
status_t result = ASIXDevice::SetupDevice(deviceReplugged); status_t result = ASIXDevice::SetupDevice(deviceReplugged);
if(result != B_OK) { if (result != B_OK) {
return result; return result;
} }
result = fMII.Init(fDevice, result = fMII.Init(fDevice);
SW_MII_OP, READ_MII, WRITE_MII,
READ_MII_OP_MODE, HW_MII_OP, READ_PHYID);
size_t actualLength = 0; size_t actualLength = 0;
// enable GPIO2 - magic from FreeBSD's if_axe // enable GPIO2 - magic from FreeBSD's if_axe
@ -187,7 +201,7 @@ AX88772Device::SetupDevice(bool deviceReplugged)
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
WRITE_GPIOS, GPIOs, 0, 0, 0, &actualLength); WRITE_GPIOS, GPIOs, 0, 0, 0, &actualLength);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of wrinting GPIOs: %#010x\n", result); TRACE_ALWAYS("Error of wrinting GPIOs: %#010x\n", result);
return result; return result;
} }
@ -205,7 +219,7 @@ AX88772Device::SetupDevice(bool deviceReplugged)
TRACE("Selecting %s PHY[%#02x].\n", TRACE("Selecting %s PHY[%#02x].\n",
useEmbeddedPHY ? "embedded" : "external", selectPHY); useEmbeddedPHY ? "embedded" : "external", selectPHY);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of selecting PHY:%#010x\n", result); TRACE_ALWAYS("Error of selecting PHY:%#010x\n", result);
return result; return result;
} }
@ -231,7 +245,7 @@ AX88772Device::SetupDevice(bool deviceReplugged)
size_t from = useEmbeddedPHY ? 0 : 4; size_t from = useEmbeddedPHY ? 0 : 4;
size_t to = useEmbeddedPHY ? 3 : 4; size_t to = useEmbeddedPHY ? 3 : 4;
for(size_t i = from; i <= to; i++) { for (size_t i = from; i <= to; i++) {
result = gUSBModule->send_request(fDevice, result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
WRITE_SOFT_RESET, resetCommands[i].reset, WRITE_SOFT_RESET, resetCommands[i].reset,
@ -239,7 +253,7 @@ AX88772Device::SetupDevice(bool deviceReplugged)
snooze(resetCommands[i].delay); snooze(resetCommands[i].delay);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of SW reset command %d:[%#04x]: %#010x\n", TRACE_ALWAYS("Error of SW reset command %d:[%#04x]: %#010x\n",
i, resetCommands[i].reset, result); i, resetCommands[i].reset, result);
return result; return result;
@ -249,13 +263,13 @@ AX88772Device::SetupDevice(bool deviceReplugged)
snooze(150000); snooze(150000);
result = WriteRXControlRegister(0); result = WriteRXControlRegister(0);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n", 0, result); TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n", 0, result);
return result; return result;
} }
result = fMII.SetupPHY(); result = fMII.SetupPHY();
if(result != B_OK) { if (result != B_OK) {
return result; return result;
} }
@ -267,7 +281,7 @@ AX88772Device::SetupDevice(bool deviceReplugged)
MEDIUM_STATE_RE | MEDIUM_STATE_PS_100, MEDIUM_STATE_RE | MEDIUM_STATE_PS_100,
0, 0, 0, &actualLength); 0, 0, 0, &actualLength);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of setting medium mode: %#010x\n", result); TRACE_ALWAYS("Error of setting medium mode: %#010x\n", result);
} }
@ -284,20 +298,21 @@ AX88772Device::StartDevice()
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
WRITE_IPGS, 0, 0, sizeof(fIPG), fIPG, &actualLength); WRITE_IPGS, 0, 0, sizeof(fIPG), fIPG, &actualLength);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of writing IPGs:%#010x\n", result); TRACE_ALWAYS("Error of writing IPGs:%#010x\n", result);
return result; return result;
} }
if(actualLength != sizeof(fIPG)) { if (actualLength != sizeof(fIPG)) {
TRACE_ALWAYS("Mismatch of written IPGs data. " TRACE_ALWAYS("Mismatch of written IPGs data. "
"%d bytes of %d written.\n", actualLength, sizeof(fIPG)); "%d bytes of %d written.\n", actualLength, sizeof(fIPG));
} }
uint16 rxcontrol = RXCTL_START | RXCTL_MULTICAST | RXCTL_BROADCAST; uint16 rxcontrol = RXCTL_START | RXCTL_BROADCAST;
result = WriteRXControlRegister(rxcontrol); result = WriteRXControlRegister(rxcontrol);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n", rxcontrol, result); TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n",
rxcontrol, result);
} }
TRACE_RET(result); TRACE_RET(result);
@ -316,7 +331,7 @@ AX88772Device::OnNotify(uint32 actualLength)
AX88772_Notify *notification = (AX88772_Notify *)fNotifyBuffer; AX88772_Notify *notification = (AX88772_Notify *)fNotifyBuffer;
if(notification->btA1 != 0xa1) { if (notification->btA1 != 0xa1) {
TRACE_ALWAYS("Notify magic byte is invalid: %#02x\n", TRACE_ALWAYS("Notify magic byte is invalid: %#02x\n",
notification->btA1); notification->btA1);
} }
@ -341,7 +356,7 @@ AX88772Device::OnNotify(uint32 actualLength)
bool linkStateChange = linkIsUp != fHasConnection; bool linkStateChange = linkIsUp != fHasConnection;
fHasConnection = linkIsUp; fHasConnection = linkIsUp;
if(linkStateChange) { if (linkStateChange) {
TRACE("Link state of PHY%d has been changed to '%s'\n", TRACE("Link state of PHY%d has been changed to '%s'\n",
phyIndex, fHasConnection ? "up" : "down"); phyIndex, fHasConnection ? "up" : "down");
} }
@ -363,12 +378,12 @@ AX88772Device::GetLinkState(ether_link_state *linkState)
READ_MEDIUM_STATUS, 0, 0, sizeof(mediumStatus), READ_MEDIUM_STATUS, 0, 0, sizeof(mediumStatus),
&mediumStatus, &actualLength); &mediumStatus, &actualLength);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of reading medium status:%#010x.\n", result); TRACE_ALWAYS("Error of reading medium status:%#010x.\n", result);
return result; return result;
} }
if(actualLength != sizeof(mediumStatus)) { if (actualLength != sizeof(mediumStatus)) {
TRACE_ALWAYS("Mismatch of reading medium status." TRACE_ALWAYS("Mismatch of reading medium status."
"Read %d bytes instead of %d\n", "Read %d bytes instead of %d\n",
actualLength, sizeof(mediumStatus)); actualLength, sizeof(mediumStatus));
@ -379,14 +394,15 @@ AX88772Device::GetLinkState(ether_link_state *linkState)
linkState->quality = 1000; linkState->quality = 1000;
linkState->media = IFM_ETHER | (fHasConnection ? IFM_ACTIVE : 0); linkState->media = IFM_ETHER | (fHasConnection ? IFM_ACTIVE : 0);
linkState->media |= (mediumStatus & MEDIUM_STATE_FD) ? linkState->media |= (mediumStatus & MEDIUM_STATE_FD) ?
IFM_FULL_DUPLEX : IFM_HALF_DUPLEX; IFM_FULL_DUPLEX : IFM_HALF_DUPLEX;
linkState->speed = (mediumStatus & MEDIUM_STATE_PS_100) ? 100000000 : 10000000; linkState->speed = (mediumStatus & MEDIUM_STATE_PS_100)
? 100000000 : 10000000;
TRACE_FLOW("Medium state: %s, %lld MBit/s, %s duplex.\n", TRACE_FLOW("Medium state: %s, %lld MBit/s, %s duplex.\n",
(linkState->media & IFM_ACTIVE) ? "active" : "inactive", (linkState->media & IFM_ACTIVE) ? "active" : "inactive",
linkState->speed, linkState->speed / 1000000,
(linkState->media & IFM_FULL_DUPLEX) ? "full" : "half"); (linkState->media & IFM_FULL_DUPLEX) ? "full" : "half");
return B_OK; return B_OK;
} }

View File

@ -1,29 +1,30 @@
/* /*
* ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver. * ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver.
* Copyright (c) 2008 S.Zharski <imker@gmx.li> * Copyright (c) 2008, 2011 S.Zharski <imker@gmx.li>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
* Heavily based on code of the * Heavily based on code of the
* Driver for USB Ethernet Control Model devices * Driver for USB Ethernet Control Model devices
* Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch> * Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
*/ */
#ifndef _USB_AX88772_DEVICE_H_ #ifndef _USB_AX88772_DEVICE_H_
#define _USB_AX88772_DEVICE_H_ #define _USB_AX88772_DEVICE_H_
#include "ASIXDevice.h" #include "ASIXDevice.h"
class AX88772Device : public ASIXDevice { class AX88772Device : public ASIXDevice {
public: public:
AX88772Device(usb_device device, const char *description); AX88772Device(usb_device device, DeviceInfo& info);
protected: protected:
status_t InitDevice(); status_t InitDevice();
virtual status_t SetupDevice(bool deviceReplugged); virtual status_t SetupDevice(bool deviceReplugged);
virtual status_t StartDevice(); virtual status_t StartDevice();
virtual status_t OnNotify(uint32 actualLength); virtual status_t OnNotify(uint32 actualLength);
virtual status_t GetLinkState(ether_link_state *state); virtual status_t GetLinkState(ether_link_state *state);
}; };
#endif //_USB_AX88772_DEVICE_H_ #endif // _USB_AX88772_DEVICE_H_

View File

@ -1,6 +1,6 @@
/* /*
* ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver. * ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver.
* Copyright (c) 2008 S.Zharski <imker@gmx.li> * Copyright (c) 2008, 2011 S.Zharski <imker@gmx.li>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
* Heavily based on code of the * Heavily based on code of the
@ -10,71 +10,62 @@
* *
*/ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAIKU_TARGET_PLATFORM_HAIKU
#include <lock.h> // for mutex
#else
#include "BeOSCompatibility.h" // for pseudo mutex
#endif
#include "Driver.h" #include "Driver.h"
#include "Settings.h"
#include <stdio.h>
#include <lock.h> // for mutex
#include <util/AutoLock.h>
#include "AX88172Device.h" #include "AX88172Device.h"
#include "AX88772Device.h"
#include "AX88178Device.h" #include "AX88178Device.h"
#include "AX88772Device.h"
#include "Settings.h"
int32 api_version = B_CUR_DRIVER_API_VERSION; int32 api_version = B_CUR_DRIVER_API_VERSION;
static const char *sDeviceBaseName = "net/usb_asix/"; static const char *sDeviceBaseName = "net/usb_asix/";
ASIXDevice *gASIXDevices[MAX_DEVICES]; ASIXDevice *gASIXDevices[MAX_DEVICES];
char *gDeviceNames[MAX_DEVICES + 1]; char *gDeviceNames[MAX_DEVICES + 1];
usb_module_info *gUSBModule = NULL; usb_module_info *gUSBModule = NULL;
mutex gDriverLock; mutex gDriverLock;
// auto-release helper class
class DriverSmartLock {
public:
DriverSmartLock() { mutex_lock(&gDriverLock); }
~DriverSmartLock() { mutex_unlock(&gDriverLock); }
};
usb_support_descriptor gSupportedDevices[] = {
// AX88172 // IMPORTANT: keep entries sorted by ids to let the
{ 0, 0, 0, 0x0b95, 0x1720}, // "ASIX 88172 10/100" // binary search lookup procedure work correctly !!!
{ 0, 0, 0, 0x07b8, 0x420a}, // "ABOCOM UF200" DeviceInfo gSupportedDevices[] = {
{ 0, 0, 0, 0x1189, 0x0893}, // "Acer C&M EP-1427X-2" { { { 0x0411, 0x003d } }, DeviceInfo::AX88172, "Melco LUA-U2-KTX" },
{ 0, 0, 0, 0x0557, 0x2009}, // "ATEN UC-210T" { { { 0x04bb, 0x0930 } }, DeviceInfo::AX88178, "I/O Data ETG-US2" },
{ 0, 0, 0, 0x08dd, 0x90ff}, // "Billionton USB2AR" { { { 0x04f1, 0x3008 } }, DeviceInfo::AX88172, "JVC MP-PRX1" },
{ 0, 0, 0, 0x07aa, 0x0017}, // "Corega USB2TX" { { { 0x050d, 0x5055 } }, DeviceInfo::AX88178, "Belkin F5D5055" },
{ 0, 0, 0, 0x2001, 0x1A00}, // "D-Link DUB-E100" { { { 0x0557, 0x2009 } }, DeviceInfo::AX88172, "ATEN UC-210T" },
{ 0, 0, 0, 0x1631, 0x6200}, // "GoodWay USB2Ethernet" { { { 0x05ac, 0x1402 } }, DeviceInfo::AX88772, "Apple A1277" },
{ 0, 0, 0, 0x04f1, 0x3008}, // "JVC MP-PRX1" { { { 0x077b, 0x2226 } }, DeviceInfo::AX88172, "LinkSys USB 2.0" },
{ 0, 0, 0, 0x077b, 0x2226}, // "LinkSys USB 2.0" { { { 0x07aa, 0x0017 } }, DeviceInfo::AX88172, "Corega USB2TX" },
{ 0, 0, 0, 0x0411, 0x003d}, // "Melco LUA-U2-KTX" { { { 0x07b8, 0x420a } }, DeviceInfo::AX88172, "ABOCOM UF200" },
{ 0, 0, 0, 0x0846, 0x1040}, // "NetGear USB 2.0 Ethernet" { { { 0x07d1, 0x3c05 } }, DeviceInfo::AX88772, "D-Link DUB-E100 rev.B1" },
{ 0, 0, 0, 0x086e, 0x1920}, // "System TALKS SGC-X2UL" { { { 0x0846, 0x1040 } }, DeviceInfo::AX88172, "NetGear USB 2.0 Ethernet" },
{ 0, 0, 0, 0x6189, 0x182d}, // "Sitecom LN-029" { { { 0x086e, 0x1920 } }, DeviceInfo::AX88172, "System TALKS SGC-X2UL" },
// AX88772 { { { 0x08dd, 0x90ff } }, DeviceInfo::AX88172, "Billionton USB2AR" },
{ 0, 0, 0, 0x0b95, 0x7720}, // "ASIX 88772 10/100" { { { 0x0b95, 0x1720 } }, DeviceInfo::AX88172, "ASIX 88172 10/100" },
{ 0, 0, 0, 0x13b1, 0x0018}, // "Linksys USB200M rev.2" { { { 0x0b95, 0x1780 } }, DeviceInfo::AX88178, "ASIX 88178 10/100/1000" },
{ 0, 0, 0, 0x07d1, 0x3c05}, // alternate D-Link DUB-E100 rev. B1 { { { 0x0b95, 0x7720 } }, DeviceInfo::AX88772, "ASIX 88772 10/100" },
{ 0, 0, 0, 0x2001, 0x3c05}, // "D-Link DUB-E100 rev.B1" { { { 0x0df6, 0x061c } }, DeviceInfo::AX88178, "Sitecom LN-028" },
{ 0, 0, 0, 0x1557, 0x7720}, // "OQO 01+ Ethernet" { { { 0x1189, 0x0893 } }, DeviceInfo::AX88172, "Acer C&M EP-1427X-2" },
{ 0, 0, 0, 0x05ac, 0x1402}, // "Apple A1277" { { { 0x13b1, 0x0018 } }, DeviceInfo::AX88772, "Linksys USB200M rev.2" },
// AX88178 { { { 0x14ea, 0xab11 } }, DeviceInfo::AX88178, "Planex GU-1000T" },
{ 0, 0, 0, 0x0b95, 0x1780}, // "ASIX 88178 10/100/1000" { { { 0x1557, 0x7720 } }, DeviceInfo::AX88772, "OQO 01+ Ethernet" },
{ 0, 0, 0, 0x050d, 0x5055}, // "Belkin F5D5055" { { { 0x1631, 0x6200 } }, DeviceInfo::AX88172, "GoodWay USB2Ethernet" },
{ 0, 0, 0, 0x04bb, 0x0930}, // "I/O Data ETG-US2" { { { 0x1737, 0x0039 } }, DeviceInfo::AX88178, "LinkSys 1000" },
{ 0, 0, 0, 0x1737, 0x0039}, // "LinkSys 1000" { { { 0x2001, 0x1A00 } }, DeviceInfo::AX88172, "D-Link DUB-E100" },
{ 0, 0, 0, 0x14ea, 0xab11}, // "Planex GU-1000T" { { { 0x2001, 0x3c05 } }, DeviceInfo::AX88772, "D-Link DUB-E100 rev.B1" },
{ 0, 0, 0, 0x0df6, 0x061c} // "Sitecom LN-028" { { { 0x6189, 0x182d } }, DeviceInfo::AX88172, "Sitecom LN-029" }
}; };
ASIXDevice * ASIXDevice *
create_asix_device(usb_device device) lookup_and_create_device(usb_device device)
{ {
const usb_device_descriptor *deviceDescriptor const usb_device_descriptor *deviceDescriptor
= gUSBModule->get_device_descriptor(device); = gUSBModule->get_device_descriptor(device);
@ -84,39 +75,34 @@ create_asix_device(usb_device device)
return NULL; return NULL;
} }
#define IDS(__vendor, __product) (((__vendor) << 16) | (__product)) TRACE("trying %#06x:%#06x.\n",
deviceDescriptor->vendor_id, deviceDescriptor->product_id);
switch(IDS(deviceDescriptor->vendor_id, deviceDescriptor->product_id)) {
// AX88172 // use binary search to lookup device in table
case IDS(0x0b95, 0x1720): return new AX88172Device(device, "ASIX 88172 10/100"); DeviceInfo::Id id = { { deviceDescriptor->vendor_id,
case IDS(0x07b8, 0x420a): return new AX88172Device(device, "ABOCOM UF200"); deviceDescriptor->product_id } };
case IDS(0x1189, 0x0893): return new AX88172Device(device, "Acer C&M EP-1427X-2"); int left = -1;
case IDS(0x0557, 0x2009): return new AX88172Device(device, "ATEN UC-210T"); int right = _countof(gSupportedDevices);
case IDS(0x08dd, 0x90ff): return new AX88172Device(device, "Billionton USB2AR"); while ((right - left) > 1) {
case IDS(0x07aa, 0x0017): return new AX88172Device(device, "Corega USB2TX"); int i = (left + right) / 2;
case IDS(0x2001, 0x1A00): return new AX88172Device(device, "D-Link DUB-E100"); ((gSupportedDevices[i].Key() < id.fKey) ? left : right) = i;
case IDS(0x1631, 0x6200): return new AX88172Device(device, "GoodWay USB2Ethernet");
case IDS(0x04f1, 0x3008): return new AX88172Device(device, "JVC MP-PRX1");
case IDS(0x077b, 0x2226): return new AX88172Device(device, "LinkSys USB 2.0");
case IDS(0x0411, 0x003d): return new AX88172Device(device, "Melco LUA-U2-KTX");
case IDS(0x0846, 0x1040): return new AX88172Device(device, "NetGear USB 2.0 Ethernet");
case IDS(0x086e, 0x1920): return new AX88172Device(device, "System TALKS SGC-X2UL");
case IDS(0x6189, 0x182d): return new AX88172Device(device, "Sitecom LN-029");
// AX88772
case IDS(0x0b95, 0x7720): return new AX88772Device(device, "ASIX 88772 10/100");
case IDS(0x13b1, 0x0018): return new AX88772Device(device, "Linksys USB200M rev.2");
case IDS(0x07d1, 0x3c05): // alternate D-Link DUB-E100 rev. B1
case IDS(0x2001, 0x3c05): return new AX88772Device(device, "D-Link DUB-E100 rev.B1");
case IDS(0x1557, 0x7720): return new AX88772Device(device, "OQO 01+ Ethernet");
case IDS(0x05ac, 0x1402): return new AX88772Device(device, "Apple A1277");
// AX88178
case IDS(0x0b95, 0x1780): return new AX88178Device(device, "ASIX 88178 10/100/1000");
case IDS(0x050d, 0x5055): return new AX88178Device(device, "Belkin F5D5055");
case IDS(0x04bb, 0x0930): return new AX88178Device(device, "I/O Data ETG-US2");
case IDS(0x1737, 0x0039): return new AX88178Device(device, "LinkSys 1000");
case IDS(0x14ea, 0xab11): return new AX88178Device(device, "Planex GU-1000T");
case IDS(0x0df6, 0x061c): return new AX88178Device(device, "Sitecom LN-028");
} }
if (gSupportedDevices[right].Key() == id.fKey) {
switch (gSupportedDevices[right].fType) {
case DeviceInfo::AX88172:
return new AX88172Device(device, gSupportedDevices[right]);
case DeviceInfo::AX88772:
return new AX88772Device(device, gSupportedDevices[right]);
case DeviceInfo::AX88178:
return new AX88178Device(device, gSupportedDevices[right]);
default:
TRACE_ALWAYS("Unknown device type:%#x ignored.\n",
static_cast<int>(gSupportedDevices[right].fType));
break;
}
}
return NULL; return NULL;
} }
@ -126,7 +112,7 @@ usb_asix_device_added(usb_device device, void **cookie)
{ {
*cookie = NULL; *cookie = NULL;
DriverSmartLock driverLock; // released on exit MutexLocker lock(gDriverLock); // released on exit
// check if this is a replug of an existing device first // check if this is a replug of an existing device first
for (int32 i = 0; i < MAX_DEVICES; i++) { for (int32 i = 0; i < MAX_DEVICES; i++) {
@ -142,7 +128,7 @@ usb_asix_device_added(usb_device device, void **cookie)
} }
// no such device yet, create a new one // no such device yet, create a new one
ASIXDevice *asixDevice = create_asix_device(device); ASIXDevice *asixDevice = lookup_and_create_device(device);
if (asixDevice == 0) { if (asixDevice == 0) {
return ENODEV; return ENODEV;
} }
@ -181,7 +167,7 @@ usb_asix_device_added(usb_device device, void **cookie)
status_t status_t
usb_asix_device_removed(void *cookie) usb_asix_device_removed(void *cookie)
{ {
DriverSmartLock driverLock; // released on exit MutexLocker lock(gDriverLock); // released on exit
ASIXDevice *device = (ASIXDevice *)cookie; ASIXDevice *device = (ASIXDevice *)cookie;
for (int32 i = 0; i < MAX_DEVICES; i++) { for (int32 i = 0; i < MAX_DEVICES; i++) {
@ -202,7 +188,7 @@ usb_asix_device_removed(void *cookie)
} }
//#pragma mark - // #pragma mark -
status_t status_t
@ -235,9 +221,17 @@ init_driver()
&usb_asix_device_removed &usb_asix_device_removed
}; };
gUSBModule->register_driver(DRIVER_NAME, gSupportedDevices, const size_t count = _countof(gSupportedDevices);
sizeof(gSupportedDevices) / sizeof(usb_support_descriptor), NULL); static usb_support_descriptor sDescriptors[count] = {{ 0 }};
for(size_t i = 0; i < count; i++) {
sDescriptors[i].vendor = gSupportedDevices[i].VendorId();
sDescriptors[i].product = gSupportedDevices[i].ProductId();
}
gUSBModule->register_driver(DRIVER_NAME, sDescriptors, count, NULL);
gUSBModule->install_notify(DRIVER_NAME, &notifyHooks); gUSBModule->install_notify(DRIVER_NAME, &notifyHooks);
return B_OK; return B_OK;
} }
@ -270,7 +264,7 @@ uninit_driver()
static status_t static status_t
usb_asix_open(const char *name, uint32 flags, void **cookie) usb_asix_open(const char *name, uint32 flags, void **cookie)
{ {
DriverSmartLock driverLock; // released on exit MutexLocker lock(gDriverLock); // released on exit
*cookie = NULL; *cookie = NULL;
status_t status = ENODEV; status_t status = ENODEV;
@ -322,7 +316,7 @@ usb_asix_free(void *cookie)
{ {
ASIXDevice *device = (ASIXDevice *)cookie; ASIXDevice *device = (ASIXDevice *)cookie;
DriverSmartLock driverLock; // released on exit MutexLocker lock(gDriverLock); // released on exit
status_t status = device->Free(); status_t status = device->Free();
for (int32 i = 0; i < MAX_DEVICES; i++) { for (int32 i = 0; i < MAX_DEVICES; i++) {
@ -348,7 +342,7 @@ publish_devices()
gDeviceNames[i] = NULL; gDeviceNames[i] = NULL;
} }
DriverSmartLock driverLock; // released on exit MutexLocker lock(gDriverLock); // released on exit
int32 deviceCount = 0; int32 deviceCount = 0;
for (int32 i = 0; i < MAX_DEVICES; i++) { for (int32 i = 0; i < MAX_DEVICES; i++) {
@ -361,7 +355,7 @@ publish_devices()
TRACE("publishing %s\n", gDeviceNames[deviceCount]); TRACE("publishing %s\n", gDeviceNames[deviceCount]);
deviceCount++; deviceCount++;
} else } else
TRACE_ALWAYS("Error: out of memory during allocating device name.\n"); TRACE_ALWAYS("Error: out of memory during allocating dev.name.\n");
} }
gDeviceNames[deviceCount] = NULL; gDeviceNames[deviceCount] = NULL;

View File

@ -1,39 +1,31 @@
/* /*
* ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver. * ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver.
* Copyright (c) 2008 S.Zharski <imker@gmx.li> * Copyright (c) 2008, 2011 S.Zharski <imker@gmx.li>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
* Heavily based on code of the * Heavily based on code of the
* Driver for USB Ethernet Control Model devices * Driver for USB Ethernet Control Model devices
* Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch> * Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
*/ */
#ifndef _USB_ASIX_DRIVER_H_ #ifndef _USB_ASIX_DRIVER_H_
#define _USB_ASIX_DRIVER_H_ #define _USB_ASIX_DRIVER_H_
#include <OS.h>
#include <KernelExport.h>
#include <Drivers.h> #include <Drivers.h>
#include <USB3.h> #include <USB3.h>
#include <ether_driver.h>
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <util/kernel_cpp.h>
#define DRIVER_NAME "usb_asix" #define DRIVER_NAME "usb_asix"
#define MAX_DEVICES 8 #define MAX_DEVICES 8
const uint8 kInvalidRequest = 0xff; const uint8 kInvalidRequest = 0xff;
const char* const kVersion = "ver.0.9.1";
const char* const kVersion = "ver.0.8.3";
extern usb_module_info *gUSBModule; extern usb_module_info *gUSBModule;
extern "C" { extern "C" {
status_t usb_asix_device_added(usb_device device, void **cookie); status_t usb_asix_device_added(usb_device device, void **cookie);
status_t usb_asix_device_removed(void *cookie); status_t usb_asix_device_removed(void *cookie);
@ -46,5 +38,5 @@ device_hooks *find_device(const char *name);
} }
#endif //_USB_ASIX_DRIVER_H_ #endif // _USB_ASIX_DRIVER_H_

View File

@ -3,6 +3,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers network usb_asix ;
SetSubDirSupportedPlatformsBeOSCompatible ; SetSubDirSupportedPlatformsBeOSCompatible ;
UsePrivateHeaders kernel net ; UsePrivateHeaders kernel net ;
UsePrivateKernelHeaders ;
KernelAddon usb_asix : KernelAddon usb_asix :
Driver.cpp Driver.cpp

View File

@ -1,105 +1,95 @@
/* /*
* ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver. * ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver.
* Copyright (c) 2008 S.Zharski <imker@gmx.li> * Copyright (c) 2008, 2011 S.Zharski <imker@gmx.li>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
* Heavily based on code of the * Heavily based on code of the
* Driver for USB Ethernet Control Model devices * Driver for USB Ethernet Control Model devices
* Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch> * Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
*/ */
#include "MIIBus.h"
#include "ASIXVendorRequests.h"
#include "Driver.h" #include "Driver.h"
#include "Settings.h" #include "Settings.h"
#include "MIIBus.h"
#define MII_OUI(id1, id2) (((id1) << 6) | ((id2) >> 10)) #define MII_OUI(id1, id2) (((id1) << 6) | ((id2) >> 10))
#define MII_MODEL(id2) (((id2) & 0x03f0) >> 4) #define MII_MODEL(id2) (((id2) & 0x03f0) >> 4)
#define MII_REV(id2) ((id2) & 0x000f) #define MII_REV(id2) ((id2) & 0x000f)
MIIBus::MIIBus() : fDevice(0),
fSelectedPHY(CurrentPHY), MIIBus::MIIBus()
fSWOperationRequest(kInvalidRequest), :
fReadValueRequest(kInvalidRequest), fStatus(B_NO_INIT),
fWriteValueRequest(kInvalidRequest), fDevice(0),
fReadStatusRequest(kInvalidRequest), fSelectedPHY(CurrentPHY)
fHWOperationRequest(kInvalidRequest),
fReadPHYIDsRequest(kInvalidRequest)
{ {
for(size_t i = 0; i < PHYsCount; i++) { for (size_t i = 0; i < PHYsCount; i++) {
fPHYs[i] = PHYNotInstalled; fPHYs[i] = PHYNotInstalled;
} }
} }
status_t status_t
MIIBus::Init(usb_device device, MIIBus::Init(usb_device device)
uint8 SWOperationRequest,
uint8 ReadValueRequest,
uint8 WriteValueRequest,
uint8 ReadStatusRequest,
uint8 HWOperationRequest,
uint8 ReadPHYIDsRequest)
{ {
fSWOperationRequest = SWOperationRequest; // reset to default state
fReadValueRequest = ReadValueRequest;
fWriteValueRequest = WriteValueRequest;
fReadStatusRequest = ReadStatusRequest;
fHWOperationRequest = HWOperationRequest;
fReadPHYIDsRequest = ReadPHYIDsRequest;
// reset to default state
fDevice = 0; fDevice = 0;
fSelectedPHY = CurrentPHY; fSelectedPHY = CurrentPHY;
for(size_t i = 0; i < PHYsCount; i++) { for (size_t i = 0; i < PHYsCount; i++) {
fPHYs[i] = PHYNotInstalled; fPHYs[i] = PHYNotInstalled;
} }
size_t actual_length = 0; size_t actual_length = 0;
status_t result = gUSBModule->send_request(device, status_t result = gUSBModule->send_request(device,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN,
fReadPHYIDsRequest, 0, 0, sizeof(fPHYs), fPHYs, &actual_length); READ_PHYID, 0, 0, sizeof(fPHYs), fPHYs, &actual_length);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Request of the PHYIDs failed:%#010x\n", result); TRACE_ALWAYS("Request of the PHYIDs failed:%#010x\n", result);
return result; return result;
} }
if(sizeof(fPHYs) != actual_length) { if (sizeof(fPHYs) != actual_length) {
TRACE_ALWAYS("Mismatch of reading %d PHYIDs bytes instead of %d.\n", TRACE_ALWAYS("Mismatch of reading %d PHYIDs bytes instead of %d.\n",
actual_length, sizeof(fPHYs)); actual_length, sizeof(fPHYs));
} }
TRACE("PHYIDs are:%#02x:%#02x\n", fPHYs[0], fPHYs[1]); TRACE("PHYIDs are:%#02x:%#02x\n", fPHYs[0], fPHYs[1]);
// simply tactic - we use first available PHY // simply tactic - we use first available PHY
if(PHYType(PrimaryPHY) != PHYNotInstalled) { if (PHYType(PrimaryPHY) != PHYNotInstalled) {
fSelectedPHY = PrimaryPHY; fSelectedPHY = PrimaryPHY;
} else } else
if(PHYType(SecondaryPHY) != PHYNotInstalled) { if (PHYType(SecondaryPHY) != PHYNotInstalled) {
fSelectedPHY = SecondaryPHY; fSelectedPHY = SecondaryPHY;
} }
TRACE("PHYs are configured: Selected:%#02x; Primary:%#02x; Secondary:%#02x\n", TRACE("PHYs are configured: Selected:%#02x; Primary:%#02x; 2ndary:%#02x\n",
PHYID(CurrentPHY), PHYID(PrimaryPHY), PHYID(SecondaryPHY)); PHYID(CurrentPHY), PHYID(PrimaryPHY), PHYID(SecondaryPHY));
if(fSelectedPHY == CurrentPHY) { if (fSelectedPHY == CurrentPHY) {
TRACE_ALWAYS("No PHYs found!\n"); TRACE_ALWAYS("No PHYs found!\n");
return B_ENTRY_NOT_FOUND; return B_ENTRY_NOT_FOUND;
} }
fDevice = device; fDevice = device;
fStatus = result;
return result;
return fStatus;
} }
status_t status_t
MIIBus::SetupPHY() MIIBus::SetupPHY()
{ {
uint16 control = 0; uint16 control = 0;
status_t result = Read(MII_BMCR, &control); status_t result = Read(MII_BMCR, &control);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of reading control word:%#010x.\n", result); TRACE_ALWAYS("Error of reading control word:%#010x.\n", result);
return result; return result;
} }
@ -108,128 +98,121 @@ MIIBus::SetupPHY()
control &= ~BMCR_Isolate; control &= ~BMCR_Isolate;
result = Write(MII_BMCR, control); result = Write(MII_BMCR, control);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of writing control word %#04x:%#010x.\n", control, result); TRACE_ALWAYS("Error of writing control word %#04x:%#010x.\n",
control, result);
} }
result = Write(MII_BMCR, BMCR_Reset); result = Write(MII_BMCR, BMCR_Reset);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of resetting PHY:%#010x.\n", result); TRACE_ALWAYS("Error of resetting PHY:%#010x.\n", result);
} }
uint16 id01 = 0, id02 = 0; uint16 id01 = 0, id02 = 0;
result = Read(MII_PHYID0, &id01); result = Read(MII_PHYID0, &id01);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of reading PHY ID1:%#010x.\n", result); TRACE_ALWAYS("Error of reading PHY ID1:%#010x.\n", result);
} }
result = Read(MII_PHYID1, &id02); result = Read(MII_PHYID1, &id02);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of reading PHY ID2:%#010x.\n", result); TRACE_ALWAYS("Error of reading PHY ID2:%#010x.\n", result);
} }
TRACE("MII Info: OUI:%04x; Model:%04x; rev:%02x.\n", TRACE("MII Info: OUI:%04x; Model:%04x; rev:%02x.\n",
MII_OUI(id01, id02), MII_MODEL(id02), MII_REV(id02)); MII_OUI(id01, id02), MII_MODEL(id02), MII_REV(id02));
//Dump(); // Dump();
return result; return result;
} }
status_t status_t
MIIBus::InitCheck() MIIBus::InitCheck()
{ {
if (fSelectedPHY == CurrentPHY) { if (fSelectedPHY == CurrentPHY) {
return B_ENTRY_NOT_FOUND; return B_ENTRY_NOT_FOUND;
} }
if(fSWOperationRequest == kInvalidRequest || return fStatus;
fReadValueRequest == kInvalidRequest ||
fWriteValueRequest == kInvalidRequest ||
fReadStatusRequest == kInvalidRequest ||
fHWOperationRequest == kInvalidRequest ||
fReadPHYIDsRequest == kInvalidRequest) {
return B_NO_INIT;
}
return B_OK;
} }
uint8 uint8
MIIBus::PHYID(PHYIndex phyIndex /*= CurrentPHY*/) MIIBus::PHYID(PHYIndex phyIndex /*= CurrentPHY*/)
{ {
if(phyIndex == CurrentPHY) { if (phyIndex == CurrentPHY) {
return (fSelectedPHY == CurrentPHY ? return (fSelectedPHY == CurrentPHY
0 : fPHYs[fSelectedPHY]) & PHYIDMask; ? 0 : fPHYs[fSelectedPHY]) & PHYIDMask;
} }
return fPHYs[phyIndex] & PHYIDMask; return fPHYs[phyIndex] & PHYIDMask;
} }
uint8 uint8
MIIBus::PHYType(PHYIndex phyIndex /*= CurrentPHY*/) MIIBus::PHYType(PHYIndex phyIndex /*= CurrentPHY*/)
{ {
if(phyIndex == CurrentPHY) { if (phyIndex == CurrentPHY) {
return (fSelectedPHY == CurrentPHY ? return (fSelectedPHY == CurrentPHY
PHYNotInstalled : fPHYs[fSelectedPHY]) & PHYTypeMask; ? PHYNotInstalled : fPHYs[fSelectedPHY]) & PHYTypeMask;
} }
return fPHYs[phyIndex] & PHYTypeMask; return fPHYs[phyIndex] & PHYTypeMask;
} }
status_t
MIIBus::Read(uint16 miiRegister, uint16 *value, PHYIndex phyIndex /*= CurrentPHY*/) status_t
MIIBus::Read(uint16 miiRegister, uint16 *value, PHYIndex phyIndex /*= CurrPHY*/)
{ {
status_t result = InitCheck(); status_t result = InitCheck();
if(B_OK != result) { if (B_OK != result) {
TRACE_ALWAYS("Error: MII is not ready:%#010x\n", result); TRACE_ALWAYS("Error: MII is not ready:%#010x\n", result);
return result; return result;
} }
if(PHYType(phyIndex) == PHYNotInstalled) { if (PHYType(phyIndex) == PHYNotInstalled) {
TRACE_ALWAYS("Error: Invalid PHY index:%#02x.\n", phyIndex); TRACE_ALWAYS("Error: Invalid PHY index:%#02x.\n", phyIndex);
return B_ENTRY_NOT_FOUND; return B_ENTRY_NOT_FOUND;
} }
uint16 phyId = PHYID(phyIndex); uint16 phyId = PHYID(phyIndex);
size_t actual_length = 0;
// switch to SW operation mode
result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
fSWOperationRequest, 0, 0, 0, 0, &actual_length);
if(result != B_OK) { size_t actual_length = 0;
// switch to SW operation mode
result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
SW_MII_OP, 0, 0, 0, 0, &actual_length);
if (result != B_OK) {
TRACE_ALWAYS("Error of switching MII to SW op.mode: %#010x\n", result); TRACE_ALWAYS("Error of switching MII to SW op.mode: %#010x\n", result);
return result; return result;
} }
// read register value // read register value
status_t op_result = gUSBModule->send_request(fDevice, status_t op_result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN,
fReadValueRequest, phyId, miiRegister, READ_MII, phyId, miiRegister,
sizeof(*value), value, &actual_length); sizeof(*value), value, &actual_length);
if(op_result != B_OK) { if (op_result != B_OK) {
TRACE_ALWAYS("Error of reading MII reg.%d at PHY%d:%#010x.\n", TRACE_ALWAYS("Error of reading MII reg.%d at PHY%d:%#010x.\n",
miiRegister, phyId, op_result); miiRegister, phyId, op_result);
} }
if(sizeof(*value) != actual_length) { if (sizeof(*value) != actual_length) {
TRACE_ALWAYS("Mismatch of reading MII reg.%d at PHY %d. " TRACE_ALWAYS("Mismatch of reading MII reg.%d at PHY %d. "
"Read %d bytes instead of %d.\n", "Read %d bytes instead of %d.\n",
miiRegister, phyId, actual_length, sizeof(*value)); miiRegister, phyId, actual_length, sizeof(*value));
} }
// switch to HW operation mode // switch to HW operation mode
result = gUSBModule->send_request(fDevice, result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
fHWOperationRequest, 0, 0, 0, 0, &actual_length); HW_MII_OP, 0, 0, 0, 0, &actual_length);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of switching MII to HW op.mode: %#010x\n", result); TRACE_ALWAYS("Error of switching MII to HW op.mode: %#010x\n", result);
} }
@ -237,57 +220,57 @@ MIIBus::Read(uint16 miiRegister, uint16 *value, PHYIndex phyIndex /*= CurrentPHY
} }
status_t status_t
MIIBus::Write(uint16 miiRegister, uint16 value, PHYIndex phyIndex /*= CurrentPHY*/) MIIBus::Write(uint16 miiRegister, uint16 value, PHYIndex phyIndex /*= CurrPHY*/)
{ {
size_t actual_length = 0; size_t actual_length = 0;
status_t result = InitCheck(); status_t result = InitCheck();
if(B_OK != result) { if (B_OK != result) {
TRACE_ALWAYS("Error: MII is not ready:%#010x\n", result); TRACE_ALWAYS("Error: MII is not ready:%#010x\n", result);
return result; return result;
} }
if(PHYType(phyIndex) == PHYNotInstalled) { if (PHYType(phyIndex) == PHYNotInstalled) {
TRACE_ALWAYS("Error: Invalid PHY index:%#02x\n", phyIndex); TRACE_ALWAYS("Error: Invalid PHY index:%#02x\n", phyIndex);
return B_ENTRY_NOT_FOUND; return B_ENTRY_NOT_FOUND;
} }
uint16 phyId = PHYID(phyIndex); uint16 phyId = PHYID(phyIndex);
// switch to SW operation mode // switch to SW operation mode
result = gUSBModule->send_request(fDevice, result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
fSWOperationRequest, 0, 0, 0, 0, &actual_length); SW_MII_OP, 0, 0, 0, 0, &actual_length);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of switching MII to SW op.mode: %#010x\n", result); TRACE_ALWAYS("Error of switching MII to SW op.mode: %#010x\n", result);
return result; return result;
} }
// write register value // write register value
status_t op_result = gUSBModule->send_request(fDevice, status_t op_result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
fWriteValueRequest, phyId, miiRegister, WRITE_MII, phyId, miiRegister,
sizeof(value), &value, &actual_length); sizeof(value), &value, &actual_length);
if(op_result != B_OK) { if (op_result != B_OK) {
TRACE_ALWAYS("Error of writing MII reg.%d at PHY %d:%#010x.\n", TRACE_ALWAYS("Error of writing MII reg.%d at PHY %d:%#010x.\n",
miiRegister, phyId, op_result); miiRegister, phyId, op_result);
} }
if(sizeof(value) != actual_length) { if (sizeof(value) != actual_length) {
TRACE_ALWAYS("Mismatch of writing MII reg.%d at PHY %d." TRACE_ALWAYS("Mismatch of writing MII reg.%d at PHY %d."
"Write %d bytes instead of %d.\n", "Write %d bytes instead of %d.\n",
miiRegister, phyId, actual_length, sizeof(value)); miiRegister, phyId, actual_length, sizeof(value));
} }
// switch to HW operation mode // switch to HW operation mode
result = gUSBModule->send_request(fDevice, result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
fHWOperationRequest, 0, 0, 0, 0, &actual_length); HW_MII_OP, 0, 0, 0, 0, &actual_length);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of switching MII to HW op.mode: %#010x\n", result); TRACE_ALWAYS("Error of switching MII to HW op.mode: %#010x\n", result);
} }
@ -295,75 +278,76 @@ MIIBus::Write(uint16 miiRegister, uint16 value, PHYIndex phyIndex /*= CurrentPHY
} }
status_t status_t
MIIBus::Status(uint16 *status, PHYIndex phyIndex /*= CurrentPHY*/) MIIBus::Status(uint16 *status, PHYIndex phyIndex /*= CurrentPHY*/)
{ {
return Read(MII_BMSR, status, phyIndex); return Read(MII_BMSR, status, phyIndex);
} }
status_t
status_t
MIIBus::Dump() MIIBus::Dump()
{ {
status_t result = InitCheck(); status_t result = InitCheck();
if(B_OK != result) { if (B_OK != result) {
TRACE_ALWAYS("Error: MII is not ready:%#010x.\n", result); TRACE_ALWAYS("Error: MII is not ready:%#010x.\n", result);
return result; return result;
} }
if(PHYType(CurrentPHY) == PHYNotInstalled) { if (PHYType(CurrentPHY) == PHYNotInstalled) {
TRACE_ALWAYS("Error: Current PHY index is invalid!\n"); TRACE_ALWAYS("Error: Current PHY index is invalid!\n");
return B_ENTRY_NOT_FOUND; return B_ENTRY_NOT_FOUND;
} }
uint16 phyId = PHYID(CurrentPHY); uint16 phyId = PHYID(CurrentPHY);
size_t actual_length = 0; size_t actual_length = 0;
// switch to SW operation mode // switch to SW operation mode
result = gUSBModule->send_request(fDevice, result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
fSWOperationRequest, 0, 0, 0, 0, &actual_length); SW_MII_OP, 0, 0, 0, 0, &actual_length);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of switching MII to SW op.mode: %#010x\n", result); TRACE_ALWAYS("Error of switching MII to SW op.mode: %#010x\n", result);
return result; return result;
} }
uint8 regs[] = { MII_BMCR, MII_BMSR, uint8 regs[] = { MII_BMCR, MII_BMSR,
MII_PHYID0, MII_PHYID1, MII_PHYID0, MII_PHYID1,
MII_ANAR, MII_ANLPAR/*, MII_ANER*/}; MII_ANAR, MII_ANLPAR/*, MII_ANER*/};
uint16 value = 0; uint16 value = 0;
for(size_t i = 0; i < sizeof(regs)/ sizeof(regs[0]); i++) { for (size_t i = 0; i < sizeof(regs)/ sizeof(regs[0]); i++) {
// read register value // read register value
status_t op_result = gUSBModule->send_request(fDevice, status_t op_result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_IN,
fReadValueRequest, phyId, regs[i], READ_MII, phyId, regs[i],
sizeof(value), &value, &actual_length); sizeof(value), &value, &actual_length);
if(op_result != B_OK) { if (op_result != B_OK) {
TRACE_ALWAYS("Error of reading MII reg.%d at PHY%d:%#010x.\n", TRACE_ALWAYS("Error of reading MII reg.%d at PHY%d:%#010x.\n",
regs[i], phyId, op_result); regs[i], phyId, op_result);
} }
if(sizeof(value) != actual_length) { if (sizeof(value) != actual_length) {
TRACE_ALWAYS("Mismatch of reading MII reg.%d at PHY%d." TRACE_ALWAYS("Mismatch of reading MII reg.%d at PHY%d."
" Read %d bytes instead of %d.\n", " Read %d bytes instead of %d.\n",
regs[i], phyId, actual_length, sizeof(value)); regs[i], phyId, actual_length, sizeof(value));
} }
TRACE_ALWAYS("MII reg: %d has %#04x\n", regs[i], value); TRACE_ALWAYS("MII reg: %d has %#04x\n", regs[i], value);
} }
// switch to HW operation mode // switch to HW operation mode
result = gUSBModule->send_request(fDevice, result = gUSBModule->send_request(fDevice,
USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT, USB_REQTYPE_VENDOR | USB_REQTYPE_DEVICE_OUT,
fHWOperationRequest, 0, 0, 0, 0, &actual_length); HW_MII_OP, 0, 0, 0, 0, &actual_length);
if(result != B_OK) { if (result != B_OK) {
TRACE_ALWAYS("Error of switching MII to HW op.mode: %#010x\n", result); TRACE_ALWAYS("Error of switching MII to HW op.mode: %#010x\n", result);
} }
return result; return result;
} }

View File

@ -1,20 +1,21 @@
/* /*
* ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver. * ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver.
* Copyright (c) 2008 S.Zharski <imker@gmx.li> * Copyright (c) 2008, 2011 S.Zharski <imker@gmx.li>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
* Heavily based on code of the * Heavily based on code of the
* Driver for USB Ethernet Control Model devices * Driver for USB Ethernet Control Model devices
* Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch> * Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
*/ */
#ifndef _USB_MII_BUS_H_ #ifndef _USB_MII_BUS_H_
#define _USB_MII_BUS_H_ #define _USB_MII_BUS_H_
#include "Driver.h" #include "Driver.h"
enum MII_Register { enum MII_Register {
MII_BMCR = 0x00, MII_BMCR = 0x00,
MII_BMSR = 0x01, MII_BMSR = 0x01,
@ -23,7 +24,8 @@ enum MII_Register {
MII_ANAR = 0x04, MII_ANAR = 0x04,
MII_ANLPAR = 0x05, MII_ANLPAR = 0x05,
MII_ANER = 0x06 MII_ANER = 0x06
}; };
enum MII_BMCR { enum MII_BMCR {
BMCR_Reset = 0x8000, BMCR_Reset = 0x8000,
@ -37,24 +39,26 @@ enum MII_BMCR {
BMCR_CollTest = 0x0080 BMCR_CollTest = 0x0080
}; };
enum MII_BMSR { enum MII_BMSR {
BMSR_CAP_100BASE_T4 = 0x8000, // PHY is able to perform 100base-T4 BMSR_CAP_100BASE_T4 = 0x8000, // PHY is able to perform 100base-T4
BMSR_CAP_100BASE_TXFD = 0x4000, // PHY is able to perform 100base-TX full duplex BMSR_CAP_100BASE_TXFD = 0x4000, // PHY is able to perform 100base-TX FD
BMSR_CAP_100BASE_TXHD = 0x2000, // PHY is able to perform 100base-TX half duplex BMSR_CAP_100BASE_TXHD = 0x2000, // PHY is able to perform 100base-TX HD
BMSR_CAP_10BASE_TXFD = 0x1000, // PHY is able to perform 10base-TX full duplex BMSR_CAP_10BASE_TXFD = 0x1000, // PHY is able to perform 10base-TX FD
BMSR_CAP_10BASE_TXHD = 0x0800, // PHY is able to perform 10base-TX half duplex BMSR_CAP_10BASE_TXHD = 0x0800, // PHY is able to perform 10base-TX HD
BMSR_MFPS = 0x0040, // Management frame preamble supression BMSR_MFPS = 0x0040, // Management frame preamble supression
BMSR_ANC = 0x0020, // Auto-negotiation complete BMSR_ANC = 0x0020, // Auto-negotiation complete
BMSR_RF = 0x0010, // Remote fault BMSR_RF = 0x0010, // Remote fault
BMSR_CAP_AN = 0x0008, // PHY is able to perform auto-negotiation BMSR_CAP_AN = 0x0008, // PHY is able to perform a-negotiation
BMSR_Link = 0x0004, // link state BMSR_Link = 0x0004, // link state
BMSR_Jabber = 0x0002, // Jabber condition detected BMSR_Jabber = 0x0002, // Jabber condition detected
BMSR_CAP_Ext = 0x0001 // Extended register capable BMSR_CAP_Ext = 0x0001 // Extended register capable
}; };
enum MII_ANAR { enum MII_ANAR {
ANAR_NP = 0x8000, // Next page available ANAR_NP = 0x8000, // Next page available
ANAR_ACK = 0x4000, // Link partner data reception ability acknowledged ANAR_ACK = 0x4000, // Link partner data reception ability ack-ed
ANAR_RF = 0x2000, // Fault condition detected and advertised ANAR_RF = 0x2000, // Fault condition detected and advertised
ANAR_PAUSE = 0x0400, // Pause operation enabled for full-duplex links ANAR_PAUSE = 0x0400, // Pause operation enabled for full-duplex links
ANAR_T4 = 0x0200, // 100BASE-T4 supported ANAR_T4 = 0x0200, // 100BASE-T4 supported
@ -62,40 +66,42 @@ enum MII_ANAR {
ANAR_TX_HD = 0x0080, // 100BASE-TX half duplex supported ANAR_TX_HD = 0x0080, // 100BASE-TX half duplex supported
ANAR_10_FD = 0x0040, // 10BASE-TX full duplex supported ANAR_10_FD = 0x0040, // 10BASE-TX full duplex supported
ANAR_10_HD = 0x0020, // 10BASE-TX half duplex supported ANAR_10_HD = 0x0020, // 10BASE-TX half duplex supported
ANAR_SELECTOR = 0x0001 // Protocol selection bits (hardcoded to ethernet) ANAR_SELECTOR = 0x0001 // Protocol sel. bits (hardcoded to ethernet)
}; };
enum MII_ANLPAR { enum MII_ANLPAR {
ANLPAR_NP = 0x8000, // Link partner next page enabled ANLPAR_NP = 0x8000, // Link partner next page enabled
ANLPAR_ACK = 0x4000, // Link partner data reception ability acknowledged ANLPAR_ACK = 0x4000, // Link partner data reception ability ack-ed
ANLPAR_RF = 0x2000, // Remote fault indicated by link partner ANLPAR_RF = 0x2000, // Remote fault indicated by link partner
ANLPAR_PAUSE = 0x0400, // Pause operation supported by link partner ANLPAR_PAUSE = 0x0400, // Pause operation supported by link partner
ANLPAR_T4 = 0x0200, // 100BASE-T4 supported by link partner ANLPAR_T4 = 0x0200, // 100BASE-T4 supported by link partner
ANLPAR_TX_FD = 0x0100, // 100BASE-TX full duplex supported by link partner ANLPAR_TX_FD = 0x0100, // 100BASE-TX FD supported by link partner
ANLPAR_TX_HD = 0x0080, // 100BASE-TX half duplex supported by link partner ANLPAR_TX_HD = 0x0080, // 100BASE-TX HD supported by link partner
ANLPAR_10_FD = 0x0040, // 10BASE-TX full duplex supported by link partner ANLPAR_10_FD = 0x0040, // 10BASE-TX FD supported by link partner
ANLPAR_10_HD = 0x0020, // 10BASE-TX half duplex supported by link partner ANLPAR_10_HD = 0x0020, // 10BASE-TX HD supported by link partner
ANLPAR_SELECTOR = 0x0001 // Link partner's binary encoded protocol selector ANLPAR_SELECTOR = 0x0001 // Link partner's bin. encoded protocol selector
}; };
// index used to different PHY on MII bus // index used to different PHY on MII bus
enum PHYIndex { enum PHYIndex {
CurrentPHY = -1, // currently selected PHY. CurrentPHY = -1, // currently selected PHY.
// Internally used as default index in case on PHYs found. // Internally used as def. index in case no PHYs found.
SecondaryPHY = 0, // secondary PHY SecondaryPHY = 0, // secondary PHY
PrimaryPHY = 1, // primary PHY PrimaryPHY = 1, // primary PHY
PHYsCount = 2 // maximal count of PHYs on bus PHYsCount = 2 // maximal count of PHYs on bus
}; };
// PHY type and id constants and masks. // PHY type and id constants and masks.
enum PHYType { enum PHYType {
PHYTypeMask = 0xe0, // mask for PHY type bits PHYTypeMask = 0xe0, // mask for PHY type bits
PHYNormal = 0x00, // 10/100 Ethernet PHY (Link reports as normal case) PHYNormal = 0x00, // 10/100 Ethernet PHY (Link reports as normal case)
PHYLinkAState = 0x80, // Special case 1 (Link reports is always active) PHYLinkAState = 0x80, // Special case 1 (Link reports is always active)
PHYGigabit = 0x20, // Gigabit Ethernet PHY on AX88178 PHYGigabit = 0x20, // Gigabit Ethernet PHY on AX88178
PHYNotInstalled = 0xe0, // non-supported PHY PHYNotInstalled = 0xe0, // non-supported PHY
PHYIDMask = 0x1f, // mask for PHY ID bits PHYIDMask = 0x1f, // mask for PHY ID bits
PHYIDEmbedded = 0x10 // id for embedded PHY on AX88772 PHYIDEmbedded = 0x10 // id for embedded PHY on AX88772
}; };
@ -104,40 +110,31 @@ enum PHYType {
class MIIBus { class MIIBus {
public: public:
MIIBus(); MIIBus();
status_t Init(usb_device device, status_t Init(usb_device device);
uint8 SWOperationRequest,
uint8 ReadValueRequest,
uint8 WriteValueRequest,
uint8 ReadStatusRequest,
uint8 HWOperationRequest,
uint8 ReadPHYIDsRequest);
status_t InitCheck(); status_t InitCheck();
status_t SetupPHY(); status_t SetupPHY();
uint8 PHYID(PHYIndex phyIndex = CurrentPHY); uint8 PHYID(PHYIndex phyIndex = CurrentPHY);
uint8 PHYType(PHYIndex phyIndex = CurrentPHY); uint8 PHYType(PHYIndex phyIndex = CurrentPHY);
PHYIndex ActivePHY() { return fSelectedPHY; } PHYIndex ActivePHY() { return fSelectedPHY; }
status_t Read(uint16 miiRegister, uint16 *value, PHYIndex phyIndex = CurrentPHY);
status_t Write(uint16 miiRegister, uint16 value, PHYIndex phyIndex = CurrentPHY);
status_t Status(uint16 *status, PHYIndex phyIndex = CurrentPHY); status_t Read(uint16 miiRegister, uint16 *value,
PHYIndex phyIndex = CurrentPHY);
status_t Write(uint16 miiRegister, uint16 value,
PHYIndex phyIndex = CurrentPHY);
status_t Status(uint16 *status,
PHYIndex phyIndex = CurrentPHY);
status_t Dump(); status_t Dump();
private: private:
status_t fStatus;
usb_device fDevice; usb_device fDevice;
uint8 fPHYs[PHYsCount]; uint8 fPHYs[PHYsCount];
PHYIndex fSelectedPHY; PHYIndex fSelectedPHY;
uint8 fSWOperationRequest;
uint8 fReadValueRequest;
uint8 fWriteValueRequest;
uint8 fReadStatusRequest;
uint8 fHWOperationRequest;
uint8 fReadPHYIDsRequest;
}; };
#endif //_USB_MII_BUS_H_ #endif // _USB_MII_BUS_H_

View File

@ -1,19 +1,26 @@
/* /*
* ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver. * ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver.
* Copyright (c) 2008 S.Zharski <imker@gmx.li> * Copyright (c) 2008,2011 S.Zharski <imker@gmx.li>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
* Heavily based on code of the * Heavily based on code of the
* Driver for USB Ethernet Control Model devices * Driver for USB Ethernet Control Model devices
* Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch> * Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
*/ */
#include <lock.h> // for mutex
#include "Settings.h" #include "Settings.h"
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include <driver_settings.h>
#include <lock.h>
bool gTraceOn = false; bool gTraceOn = false;
bool gTruncateLogFile = false; bool gTruncateLogFile = false;
bool gAddTimeStamp = true; bool gAddTimeStamp = true;
@ -21,10 +28,10 @@ bool gTraceFlow = false;
static char *gLogFilePath = NULL; static char *gLogFilePath = NULL;
mutex gLogLock; mutex gLogLock;
static static
void create_log() void create_log()
{ {
if(gLogFilePath == NULL) if (gLogFilePath == NULL)
return; return;
int flags = O_WRONLY | O_CREAT | ((gTruncateLogFile) ? O_TRUNC : 0); int flags = O_WRONLY | O_CREAT | ((gTruncateLogFile) ? O_TRUNC : 0);
@ -33,21 +40,23 @@ void create_log()
mutex_init(&gLogLock, DRIVER_NAME"-logging"); mutex_init(&gLogLock, DRIVER_NAME"-logging");
} }
void load_settings() void load_settings()
{ {
void *handle = load_driver_settings(DRIVER_NAME); void *handle = load_driver_settings(DRIVER_NAME);
if(handle == 0) if (handle == 0)
return; return;
gTraceOn = get_driver_boolean_parameter(handle, "trace", gTraceOn, true); gTraceOn = get_driver_boolean_parameter(handle, "trace", gTraceOn, true);
gTraceFlow = get_driver_boolean_parameter(handle, "trace_flow", gTraceFlow, true); gTraceFlow = get_driver_boolean_parameter(handle, "trace_flow",
gTruncateLogFile = get_driver_boolean_parameter(handle, "truncate_logfile", gTraceFlow, true);
gTruncateLogFile = get_driver_boolean_parameter(handle, "truncate_logfile",
gTruncateLogFile, true); gTruncateLogFile, true);
gAddTimeStamp = get_driver_boolean_parameter(handle, "add_timestamp", gAddTimeStamp = get_driver_boolean_parameter(handle, "add_timestamp",
gAddTimeStamp, true); gAddTimeStamp, true);
const char * logFilePath = get_driver_parameter(handle, "logfile", const char * logFilePath = get_driver_parameter(handle, "logfile",
NULL, "/var/log/"DRIVER_NAME".log"); NULL, "/var/log/"DRIVER_NAME".log");
if(logFilePath != NULL) { if (logFilePath != NULL) {
gLogFilePath = strdup(logFilePath); gLogFilePath = strdup(logFilePath);
} }
@ -56,17 +65,19 @@ void load_settings()
create_log(); create_log();
} }
void release_settings() void release_settings()
{ {
if(gLogFilePath != NULL) { if (gLogFilePath != NULL) {
mutex_destroy(&gLogLock); mutex_destroy(&gLogLock);
free(gLogFilePath); free(gLogFilePath);
} }
} }
void usb_asix_trace(bool force, const char* func, const char *fmt, ...) void usb_asix_trace(bool force, const char* func, const char *fmt, ...)
{ {
if(!(force || gTraceOn)) { if (!(force || gTraceOn)) {
return; return;
} }
@ -74,21 +85,21 @@ void usb_asix_trace(bool force, const char* func, const char *fmt, ...)
static const char *prefix = "\33[33m"DRIVER_NAME":\33[0m"; static const char *prefix = "\33[33m"DRIVER_NAME":\33[0m";
static char buffer[1024]; static char buffer[1024];
char *buf_ptr = buffer; char *buf_ptr = buffer;
if(gLogFilePath == NULL){ if (gLogFilePath == NULL) {
strcpy(buffer, prefix); strcpy(buffer, prefix);
buf_ptr += strlen(prefix); buf_ptr += strlen(prefix);
} }
if(gAddTimeStamp) {
bigtime_t time = system_time();
uint32 msec = time / 1000;
uint32 sec = msec / 1000;
sprintf(buf_ptr, "%02ld.%02ld.%03ld:",
sec / 60, sec % 60, msec % 1000);
buf_ptr += strlen(buf_ptr);
}
if(func != NULL) { if (gAddTimeStamp) {
bigtime_t time = system_time();
uint32 msec = time / 1000;
uint32 sec = msec / 1000;
sprintf(buf_ptr, "%02ld.%02ld.%03ld:",
sec / 60, sec % 60, msec % 1000);
buf_ptr += strlen(buf_ptr);
}
if (func != NULL) {
sprintf(buf_ptr, "%s::", func); sprintf(buf_ptr, "%s::", func);
buf_ptr += strlen(buf_ptr); buf_ptr += strlen(buf_ptr);
} }
@ -97,7 +108,7 @@ void usb_asix_trace(bool force, const char* func, const char *fmt, ...)
vsprintf(buf_ptr, fmt, arg_list); vsprintf(buf_ptr, fmt, arg_list);
va_end(arg_list); va_end(arg_list);
if(gLogFilePath == NULL) { if (gLogFilePath == NULL) {
dprintf(buffer); dprintf(buffer);
return; return;
} }

View File

@ -1,27 +1,36 @@
/* /*
* ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver. * ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver.
* Copyright (c) 2008 S.Zharski <imker@gmx.li> * Copyright (c) 2008, 2011 S.Zharski <imker@gmx.li>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
* Heavily based on code of the * Heavily based on code of the
* Driver for USB Ethernet Control Model devices * Driver for USB Ethernet Control Model devices
* Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch> * Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch>
* Distributed under the terms of the MIT license. * Distributed under the terms of the MIT license.
* *
*/ */
#ifndef _USB_ASIX_SETTINGS_H_
#define _USB_ASIX_SETTINGS_H_
#ifndef _USB_ASIX_SETTINGS_H_
#define _USB_ASIX_SETTINGS_H_
#include <driver_settings.h> #include <driver_settings.h>
#include "Driver.h" #include "Driver.h"
#ifdef _countof
#warning "_countof(...) WAS ALREADY DEFINED!!! Remove local definition!"
#undef _countof
#endif
#define _countof(array)(sizeof(array) / sizeof(array[0]))
void load_settings(); void load_settings();
void release_settings(); void release_settings();
void usb_asix_trace(bool force, const char *func, const char *fmt, ...); void usb_asix_trace(bool force, const char *func, const char *fmt, ...);
#define TRACE(x...) usb_asix_trace(false, __func__, x) #define TRACE(x...) usb_asix_trace(false, __func__, x)
#define TRACE_ALWAYS(x...) usb_asix_trace(true, __func__, x) #define TRACE_ALWAYS(x...) usb_asix_trace(true, __func__, x)
@ -31,4 +40,5 @@ extern bool gTraceFlow;
#define TRACE_RET(result) usb_asix_trace(false, __func__, \ #define TRACE_RET(result) usb_asix_trace(false, __func__, \
"Returns:%#010x\n", result); "Returns:%#010x\n", result);
#endif /*_USB_ASIX_SETTINGS_H_*/
#endif // _USB_ASIX_SETTINGS_H_