Implemented UNDI ethernet interface, receiving frames already appears to work.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19628 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Marcus Overhagen
2006-12-26 16:00:35 +00:00
parent 2f9a049400
commit 57a88e1c79
3 changed files with 284 additions and 56 deletions
+180 -8
View File
@@ -70,12 +70,23 @@ public:
private:
mac_addr_t fMACAddress;
bool fRxFinished;
PXE_STRUCT * fPxeData;
};
UNDI::UNDI()
: fMACAddress()
, fRxFinished(true)
, fPxeData(NULL)
{
TRACE("UNDI::UNDI\n");
fPxeData = pxe_undi_find_data();
if (!fPxeData)
panic("can't find !PXE structure");
TRACE("PXE API entrypoint at %04x:%04x\n", fPxeData->EntryPointSP.seg, fPxeData->EntryPointSP.ofs);
}
@@ -89,7 +100,61 @@ status_t
UNDI::Init()
{
TRACE("UNDI::Init\n");
return B_OK;
PXENV_UNDI_GET_INFORMATION get_info;
PXENV_UNDI_GET_STATE get_state;
PXENV_UNDI_OPEN undi_open;
uint16 res;
undi_open.OpenFlag = 0;
undi_open.PktFilter = FLTR_DIRECTED | FLTR_BRDCST | FLTR_PRMSCS;
undi_open.R_Mcast_Buf.MCastAddrCount = 0;
res = call_pxe_bios(fPxeData, UNDI_OPEN, &undi_open);
if (res != 0 || get_state.Status != 0) {
TRACE("PXENV_UNDI_OPEN failed, res %x, status %x\n", res, undi_open.Status);
}
res = call_pxe_bios(fPxeData, UNDI_GET_STATE, &get_state);
if (res != 0 || get_state.Status != 0) {
TRACE("PXENV_UNDI_GET_STATE failed, res %x, status %x\n", res, get_state.Status);
} else {
switch (get_state.UNDIstate) {
case PXE_UNDI_GET_STATE_STARTED:
TRACE("PXE_UNDI_GET_STATE_STARTED\n");
break;
case PXE_UNDI_GET_STATE_INITIALIZED:
TRACE("PXE_UNDI_GET_STATE_INITIALIZED\n");
break;
case PXE_UNDI_GET_STATE_OPENED:
TRACE("PXE_UNDI_GET_STATE_OPENED\n");
break;
default:
TRACE("unknown undi state 0x%02x\n", get_state.UNDIstate);
break;
}
}
res = call_pxe_bios(fPxeData, UNDI_GET_INFORMATION, &get_info);
if (res != 0 || get_info.Status != 0) {
TRACE("PXENV_UNDI_GET_INFORMATION failed, res %x, status %x\n", res, get_info.Status);
return B_ERROR;
}
TRACE("Status = %x\n", get_info.Status);
TRACE("BaseIo = %x\n", get_info.BaseIo);
TRACE("IntNumber = %x\n", get_info.IntNumber);
TRACE("MaxTranUnit = %x\n", get_info.MaxTranUnit);
TRACE("HwType = %x\n", get_info.HwType);
TRACE("HwAddrLen = %x\n", get_info.HwAddrLen);
TRACE("RxBufCt = %x\n", get_info.RxBufCt);
TRACE("TxBufCt = %x\n", get_info.TxBufCt);
fMACAddress = get_info.CurrentNodeAddress;
TRACE("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", fMACAddress[0], fMACAddress[1], fMACAddress[2], fMACAddress[3], fMACAddress[4], fMACAddress[5]);
return B_OK;
}
@@ -99,11 +164,15 @@ UNDI::MACAddress() const
return fMACAddress;
}
void *
UNDI::AllocateSendReceiveBuffer(size_t size)
{
TRACE("UNDI::AllocateSendReceiveBuffer, size %ld\n", size);
return 0;
if (size > 0x3000)
return NULL;
return (void *)0x500;
}
@@ -117,16 +186,120 @@ UNDI::FreeSendReceiveBuffer(void *buffer)
ssize_t
UNDI::Send(const void *buffer, size_t size)
{
TRACE("UNDI::Send, size %ld\n", size);
return 0;
TRACE("UNDI::Send, buffer %p, size %ld\n", buffer, size);
hex_dump(buffer, size);
PXENV_UNDI_TRANSMIT undi_tx;
PXENV_UNDI_TBD undi_tbd;
undi_tx.Protocol = P_UNKNOWN;
undi_tx.XmitFlag = XMT_DESTADDR;
undi_tx.DestAddr.seg = SEG((char *)buffer + 16);
undi_tx.DestAddr.ofs = OFS((char *)buffer + 16);
undi_tx.TBD.seg = SEG(&undi_tbd);
undi_tx.TBD.ofs = OFS(&undi_tbd);
undi_tbd.ImmedLength = size;
undi_tbd.Xmit.seg = SEG(buffer);
undi_tbd.Xmit.ofs = OFS(buffer);
undi_tbd.DataBlkCount = 1;
undi_tbd.DataBlock[0].TDPtrType = 1;
undi_tbd.DataBlock[0].TDRsvdByte = 0;
undi_tbd.DataBlock[0].TDDataLen = size;
undi_tbd.DataBlock[0].TDDataPtr.seg = SEG(buffer);
undi_tbd.DataBlock[0].TDDataPtr.ofs = OFS(buffer);
uint16 res = call_pxe_bios(fPxeData, UNDI_TRANSMIT, &undi_tx);
if (res != 0 || undi_tx.Status != 0) {
TRACE("UNDI_TRANSMIT failed, res %x, status %x\n", res, undi_tx.Status);
return 0;
}
TRACE("UNDI_TRANSMIT success\n");
return size;
}
ssize_t
UNDI::Receive(void *buffer, size_t size)
{
TRACE("UNDI::Receive, size %ld\n", size);
return 0;
//TRACE("UNDI::Receive, buffer %p, size %ld\n", buffer, size);
PXENV_UNDI_ISR undi_isr;
uint16 res;
if (!fRxFinished) {
TRACE("continue receive...\n");
undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
res = call_pxe_bios(fPxeData, UNDI_ISR, &undi_isr);
if (res != 0 || undi_isr.Status != 0) {
TRACE("PXENV_UNDI_ISR_IN_GET_NEXT failed, res %x, status %x\n", res, undi_isr.Status);
fRxFinished = true;
return 0;
}
} else {
undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_START;
res = call_pxe_bios(fPxeData, UNDI_ISR, &undi_isr);
if (res != 0 || undi_isr.Status != 0) {
TRACE("PXENV_UNDI_ISR_IN_START failed, res %x, status %x\n", res, undi_isr.Status);
return 0;
}
if (undi_isr.FuncFlag != PXENV_UNDI_ISR_OUT_OURS) {
// TRACE("not ours\n");
return 0;
}
// send EOI to pic ?
TRACE("PXENV_UNDI_ISR_OUT_OURS\n");
undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
res = call_pxe_bios(fPxeData, UNDI_ISR, &undi_isr);
if (res != 0 || undi_isr.Status != 0) {
TRACE("PXENV_UNDI_ISR_IN_PROCESS failed, res %x, status %x\n", res, undi_isr.Status);
return 0;
}
}
switch (undi_isr.FuncFlag) {
case PXENV_UNDI_ISR_OUT_TRANSMIT:
TRACE("PXENV_UNDI_ISR_OUT_TRANSMIT\n");
fRxFinished = false;
return 0;
case PXENV_UNDI_ISR_OUT_RECEIVE:
TRACE("PXENV_UNDI_ISR_OUT_RECEIVE\n");
TRACE("BufferLength %d\n", undi_isr.BufferLength);
TRACE("FrameLength %d\n", undi_isr.FrameLength);
TRACE("FrameHeaderLength %d\n", undi_isr.FrameHeaderLength);
if (size > undi_isr.BufferLength)
size = undi_isr.BufferLength;
memcpy(buffer, (const void *)(undi_isr.Frame.seg * 16 + undi_isr.Frame.ofs), size);
hex_dump(buffer, size);
fRxFinished = false;
return size;
case PXENV_UNDI_ISR_OUT_BUSY:
TRACE("PXENV_UNDI_ISR_OUT_BUSY\n");
fRxFinished = true;
return 0;
case PXENV_UNDI_ISR_OUT_DONE:
TRACE("PXENV_UNDI_ISR_OUT_DONE\n");
fRxFinished = true;
return 0;
default:
TRACE("default!!!\n");
return 0;
}
}
@@ -135,14 +308,13 @@ platform_net_stack_init()
{
TRACE("platform_net_stack_init\n");
pxe_undi_init();
UNDI *interface = new(nothrow) UNDI;
if (!interface)
return B_NO_MEMORY;
status_t error = interface->Init();
if (error != B_OK) {
TRACE("platform_net_stack_init: interface init failed\n");
delete interface;
return error;
}
@@ -17,11 +17,6 @@
#endif
PXE_STRUCT *gPxeData;
PXE_STRUCT *
pxe_undi_find_data()
{
@@ -35,39 +30,3 @@ pxe_undi_find_data()
}
return data;
}
void
pxe_undi_init()
{
TRACE("pxe_undi_init\n");
gPxeData = pxe_undi_find_data();
if (!gPxeData)
panic("can't find !PXE structure");
TRACE("entrypoint at %p\n", *(uint32 *)&gPxeData->EntryPointSP);
PXENV_UNDI_GET_INFORMATION get_info;
memset(&get_info, 0, sizeof(get_info));
TRACE("PXENV_UNDI_GET_INFORMATION at %p\n", &get_info);
uint16 res = call_pxe_bios(gPxeData, UNDI_GET_INFORMATION, &get_info);
TRACE("res = %04x\n", res);
TRACE("Status = %x\n", get_info.Status);
TRACE("BaseIo = %x\n", get_info.BaseIo);
TRACE("IntNumber = %x\n", get_info.IntNumber);
TRACE("MaxTranUnit = %x\n", get_info.MaxTranUnit);
TRACE("HwType = %x\n", get_info.HwType);
TRACE("HwAddrLen = %x\n", get_info.HwAddrLen);
TRACE("MAC = %02x:%02x:%02x:%02x:%02x:%02x\n", get_info.CurrentNodeAddress[0], get_info.CurrentNodeAddress[1],
get_info.CurrentNodeAddress[2], get_info.CurrentNodeAddress[3],
get_info.CurrentNodeAddress[4], get_info.CurrentNodeAddress[5] );
TRACE("RxBufCt = %x\n", get_info.RxBufCt);
TRACE("TxBufCt = %x\n", get_info.TxBufCt);
}
+104 -7
View File
@@ -8,11 +8,17 @@
extern "C" uint16 call_pxe_bios(void *pxe, uint16 opcode, void *param);
void pxe_undi_init();
#define UNDI_OPEN 0x0006
#define UNDI_TRANSMIT 0x0008
#define UNDI_GET_INFORMATION 0x000C
#define UNDI_ISR 0x0014
#define UNDI_GET_STATE 0x0015
#define SEG(ptr) ((uint16)(((uint32)(ptr)) >> 4))
#define OFS(ptr) (((uint16)(ptr)) & 15)
#define MAC_ADDR_LEN 16
typedef uint8 MAC_ADDR[MAC_ADDR_LEN];
struct SEGSEL
{
@@ -21,8 +27,8 @@ struct SEGSEL
struct SEGOFF16
{
uint16 seg;
uint16 ofs;
uint16 seg;
};
struct SEGDESC
@@ -54,6 +60,34 @@ struct PXE_STRUCT
SEGDESC BC_CodeWrite;
};
struct PXENV_UNDI_MCAST_ADDRESS
{
#define MAXNUM_MCADDR 8
uint16 MCastAddrCount;
MAC_ADDR McastAddr[MAXNUM_MCADDR];
};
struct PXENV_UNDI_OPEN
{
uint16 Status;
uint16 OpenFlag;
uint16 PktFilter;
#define FLTR_DIRECTED 0x0001
#define FLTR_BRDCST 0x0002
#define FLTR_PRMSCS 0x0004
#define FLTR_SRC_RTG 0x0008
PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
};
struct PXENV_UNDI_GET_STATE
{
#define PXE_UNDI_GET_STATE_STARTED 1
#define PXE_UNDI_GET_STATE_INITIALIZED 2
#define PXE_UNDI_GET_STATE_OPENED 3
uint16 Status;
uint8 UNDIstate;
};
struct PXENV_UNDI_GET_INFORMATION
{
uint16 Status;
@@ -66,12 +100,75 @@ struct PXENV_UNDI_GET_INFORMATION
#define IEEE_TYPE 6
#define ARCNET_TYPE 7
uint16 HwAddrLen;
uint8 CurrentNodeAddress[16];
uint8 PermNodeAddress[16];
MAC_ADDR CurrentNodeAddress;
MAC_ADDR PermNodeAddress;
SEGSEL ROMAddress;
uint16 RxBufCt;
uint16 TxBufCt;
};
struct PXENV_UNDI_TRANSMIT
{
uint16 Status;
uint8 Protocol;
#define P_UNKNOWN 0
#define P_IP 1
#define P_ARP 2
#define P_RARP 3
uint8 XmitFlag;
#define XMT_DESTADDR 0x0000
#define XMT_BROADCAST 0x0001
SEGOFF16 DestAddr;
SEGOFF16 TBD;
uint32 Reserved[2];
};
#define MAX_DATA_BLKS 8
struct PXENV_UNDI_TBD
{
uint16 ImmedLength;
SEGOFF16 Xmit;
uint16 DataBlkCount;
struct DataBlk
{
uint8 TDPtrType;
uint8 TDRsvdByte;
uint16 TDDataLen;
SEGOFF16 TDDataPtr;
} DataBlock[MAX_DATA_BLKS];
};
struct PXENV_UNDI_ISR
{
uint16 Status;
uint16 FuncFlag;
uint16 BufferLength;
uint16 FrameLength;
uint16 FrameHeaderLength;
SEGOFF16 Frame;
uint8 ProtType;
uint8 PktType;
};
#define PXENV_UNDI_ISR_IN_START 1
#define PXENV_UNDI_ISR_IN_PROCESS 2
#define PXENV_UNDI_ISR_IN_GET_NEXT 3
/* One of these will be returned for
PXENV_UNDI_ISR_IN_START
*/
#define PXENV_UNDI_ISR_OUT_OURS 0
#define PXENV_UNDI_USR_OUT_NOT_OURS 1
/* One of these will be returned for
PXENV_UNDI_ISR_IN_PROCESS and
PXENV_UNDI_ISR_IN_GET_NEXT
*/
#define PXENV_UNDI_ISR_OUT_DONE 0
#define PXENV_UNDI_ISR_OUT_TRANSMIT 2
#define PXENV_UNDI_ISR_OUT_RECEIVE 3
#define PXENV_UNDI_ISR_OUT_BUSY 4
PXE_STRUCT * pxe_undi_find_data();
#endif