1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
// SPDX-License-Identifier: Apache-2.0
// Copyright 2024-2026, Amlal El Mahrouss (amlal@nekernel.org)
// Licensed under the Apache License, Version 2.0 (see LICENSE file)
// Official repository: https://github.com/ne-foss-org/nekernel
#include <DmaKit/DmaPool.h>
#include <HALKit/AMD64/Processor.h>
#include <KernelKit/PCI/Iterator.h>
#include <modules/ACPI/ACPIFactoryInterface.h>
/// @note BNID (RTL8139' Basic Network Interface) driver
#define kNetDevID (0x8139)
#define kNetSubClass (0x10EC)
using namespace Kernel;
using namespace Kernel::HAL;
STATIC UInt16 kRTLIOBase = 0xFFFF;
STATIC UInt32 kRXOffset = 0UL;
STATIC constexpr CONST UInt32 kRXBufferSize = 8192 + 16 + 1500;
STATIC UInt8* kRXUpperLayer = nullptr;
STATIC UInt8* kRXBuffer = nullptr;
STATIC PCI::Device kNetDev;
/***********************************************************************************/
///@brief BNID Init routine.
/***********************************************************************************/
EXTERN_C BOOL rtl_init_nic_rtl8139() {
STATIC BOOL kTXRXEnabled = NO;
if (kTXRXEnabled) return NO;
PCI::Iterator iterator(Types::PciDeviceKind::NetworkController, 0x00);
for (SizeT device_index = 0; device_index < NE_BUS_COUNT; ++device_index) {
kNetDev = iterator[device_index].Leak(); // Leak device.
if (kNetDev.VendorId() == kNetSubClass && kNetDev.DeviceId() == kNetDevID) {
kNetDev.EnableMmio();
kNetDev.BecomeBusMaster();
break;
}
}
kRTLIOBase = kNetDev.Bar(0);
MUST_PASS(kRTLIOBase != 0xFFFF);
kRXBuffer = reinterpret_cast<UInt8*>(rtl_dma_alloc(sizeof(UInt8) * kRXBufferSize, 0));
/// Reset first.
rt_out8(kRTLIOBase + 0x37, 0x10);
UInt16 timeout = 0U;
while (rt_in8(kRTLIOBase + 0x37) & 0x10) {
++timeout;
if (timeout > 0x1000) break;
}
rt_out32(kRTLIOBase + 0x30, (UInt32) (UIntPtr) kRXBuffer);
rt_out8(kRTLIOBase + 0x37, 0x0C);
rt_out32(kRTLIOBase + 0x44, 0xF | (1 << 7));
rt_out16(kRTLIOBase + 0x3C, 0x0005);
kTXRXEnabled = YES;
kout << "The Basic Network Interface Driver (BNID) has been initialized.\r";
return YES;
}
/***********************************************************************************/
/// @brief BNID I/O interrupt handler.
/// @param rsp stack pointer.
/// @note This function is called when the device interrupts to retrieve network data.
/***********************************************************************************/
EXTERN_C Void rtl_rtl8139_interrupt_handler(UIntPtr rsp) {
if (kRTLIOBase == 0xFFFF || kRTLIOBase == 0) return;
NE_UNUSED(rsp);
UInt16 status = rt_in16(kRTLIOBase + 0x3E);
rt_out16(kRTLIOBase + 0x3E, status);
if (status & 0x01) {
// While we receive data.
while ((rt_in8(kRTLIOBase + 0x37) & 0x01) == 0) {
// We grab an offset from the RX buffer.
UInt32 offset = kRXOffset % kRXBufferSize;
// If the offset is too high, we reset it.
if (offset >= (kRXBufferSize - 16)) {
kRXOffset = 0UL;
offset = 0UL;
}
volatile UInt8* packet = kRXBuffer + offset + 4;
UInt16 len = *(UInt16*) (kRXBuffer + offset + 2);
kRXUpperLayer[(offset + 4)] = *packet;
kRXOffset += (len + 4);
rt_out16(kRTLIOBase + 0x38, (UInt16) (kRXOffset - 16));
}
}
if (!(status & 0x04)) {
err_global_get() = kErrorNoNetwork;
}
}
/***********************************************************************************/
/// @brief BNID get upper layer function
/// @return the upper layer.
/// @retval nullptr if no upper layer is set.
/// @retval pointer to the upper layer if set.
/***********************************************************************************/
EXTERN_C UInt8* rtl_rtl8139_get_upper_layer() {
return kRXUpperLayer;
}
/***********************************************************************************/
/// @brief BNID set upper layer function
/// @param layer the upper layer.
/***********************************************************************************/
EXTERN_C BOOL rtl_rtl8139_set_upper_layer(UInt8* layer) {
if (!layer) return NO;
kRXUpperLayer = layer;
return YES;
}
|