Max OS 0.3
Loading...
Searching...
No Matches
amd_am79c973.cpp
Go to the documentation of this file.
1
10
11using namespace MaxOS;
12using namespace MaxOS::common;
13using namespace MaxOS::memory;
14using namespace MaxOS::drivers;
15using namespace MaxOS::drivers::ethernet;
16using namespace MaxOS::hardwarecommunication;
17
21
27: InterruptHandler(0x20 + dev->interrupt),
28mac_address_0_port(dev->port_base),
29mac_address_2_port(dev->port_base + 0x02),
30mac_address_4_port(dev->port_base + 0x04),
31register_data_port(dev->port_base + 0x10),
32register_address_port(dev->port_base + 0x12),
33bus_control_register_data_port(dev->port_base + 0x16),
34reset_port(dev->port_base + 0x14),
35init_block(),
36send_buffers(),
37recv_buffers() {
38 // No active buffer at the start
39 current_send_buffer = 0;
40 current_recv_buffer = 0;
41
42 //Not active or initialised
43 active = false;
44 init_done = false;
45
47
48 // Get the MAC addresses (split up in little endian order)
49 uint64_t mac_0 = mac_address_0_port.read() % 256;
50 uint64_t mac_1 = mac_address_0_port.read() / 256;
51 uint64_t mac_2 = mac_address_2_port.read() % 256;
52 uint64_t mac_3 = mac_address_2_port.read() / 256;
53 uint64_t mac_4 = mac_address_4_port.read() % 256;
54 uint64_t mac_5 = mac_address_4_port.read() / 256;
55
56 // Combine MAC addresses into one 48 bit number
57 own_mac = mac_5 << 40
58 | mac_4 << 32
59 | mac_3 << 24
60 | mac_2 << 16
61 | mac_1 << 8
62 | mac_0;
63
64 // Set the device to 32 bit mode
65 register_address_port.write(20); // Tell device to write to register 20
66 bus_control_register_data_port.write(0x102); // write desired data
67
68 // Reset the stop bit (tell device it's not supposed to be reset now)
69 register_address_port.write(0); // Tell device to write to register 0
70 register_data_port.write(0x04); // write desired data
71
72 // Set the initialization block
73 init_block.mode = 0x0000; // Promiscuous mode = false ( promiscuous mode tells it to receive all packets, not just broadcasts and those for its own MAC address)
74 init_block.reserved1 = 0; // Reserved
75 init_block.num_send_buffers = 3; // Means 8 because 2^8 (number of bits used)
76 init_block.reserved2 = 0; // Reserved
77 init_block.num_recv_buffers = 3; // Means 8 because 2^8 (number of bits used)
78 init_block.physical_address = own_mac; // Set the physical address to the MAC address
79 init_block.reserved3 = 0; // Reserved
80 init_block.logical_address = 0; // None for now
81
82 // Set Buffer descriptors memory
83 send_buffer_descr = (BufferDescriptor*) (MemoryManager::kmalloc((sizeof(BufferDescriptor) * 8) + 15)); // Allocate memory for 8 buffer descriptors
84 init_block.send_buffer_descr_address = (uint64_t) send_buffer_descr;
85
86 recv_buffer_descr = (BufferDescriptor*) (MemoryManager::kmalloc((sizeof(BufferDescriptor) * 8) + 15)); // Allocate memory for 8 buffer descriptors
87 init_block.recv_buffer_descr_address = (uint64_t) recv_buffer_descr;
88
89 for(uint8_t i = 0; i < 8; i++) {
90
91 // Send buffer descriptors
92 send_buffer_descr[i].address = (((uint64_t) &send_buffers[i]) + 15) & ~(uint32_t) 0xF; // Same as above
93 send_buffer_descr[i].flags =
94 0x7FF // Length of descriptor
95 | 0xF000; // Set it to send buffer
96 send_buffer_descr[i].flags2 = 0; // "Flags2" shows whether an error occurred while sending and should therefore be set to 0 by the drive
97 send_buffer_descr[i].avail = 0; // IF it is in use
98
99 // Receive
100 recv_buffer_descr[i].address = (((uint64_t) &recv_buffers[i]) + 15) & ~(uint32_t) 0xF; // Same as above
101 recv_buffer_descr[i].flags =
102 0xF7FF // Length of descriptor (This 0xF7FF is what was causing the problem, it used to be 0x7FF)
103 | 0x80000000; // Set it to receive buffer
104 recv_buffer_descr[i].flags2 = 0; // "Flags2" shows whether an error occurred while sending and should therefore be set to 0 by the drive
105 recv_buffer_descr[i].avail = 0; // IF it is in use
106 }
107
108 // Move initialization block into device
109 register_address_port.write(1); // Tell device to write to register 1
110 register_data_port.write((uint64_t) (&init_block) &
111 0xFFFF); // write address data
112 register_address_port.write(2); // Tell device to write to register 2
113 register_data_port.write(((uint64_t) (&init_block) >> 16) &
114 0xFFFF); // write shifted address data
115
116
117}
118
119AMD_AM79C973::~AMD_AM79C973() = default;
120
121
128
129 return;
130
131 init_done = false; // Set initDone to false
132 register_address_port.write(0); // Tell device to write to register 0
133 register_data_port.write(0x41); // Enable Interrupts and start the device
134 while(!init_done); // Wait for initDone to be set to true
135
136 register_address_port.write(4); // Tell device to read from register 4
137 uint32_t temp = register_data_port.read(); // Get current data
138
139 register_address_port.write(4); // Tell device to write to register 4
140 register_data_port.write(temp |
141 0xC00); // Bitwise OR function on data (This automatically enlarges packets smaller than 64 bytes to that size and removes some relatively superfluous information from received packets.)
142
143 register_address_port.write(0); // Tell device to write to register 0
144 register_data_port.write(
145 0x42); // Tell device that it is initialised and can begin operating
146
147 active = true; // Set active to true
148}
149
156
157 reset_port.read();
158 reset_port.write(0);
159 return 10; // 10 means wait for 10ms
160
161}
162
163
169
170 // Similar to PIC, data needs to be read when an interrupt is sent, or it hangs
171 register_address_port.write(0); // Tell device to read from register 0
172 uint32_t temp = register_data_port.read(); // Get current data
173
174 // Note: Cant be switch case as multiple errors can occur at the same time
175
176 // Errors
177 if((temp & 0x8000) == 0x8000)
178 Logger::WARNING() << "AMD am79c973 ERROR: ";
179 if((temp & 0x2000) == 0x2000)
180 Logger::WARNING() << "COLLISION ERROR\n";
181 if((temp & 0x1000) == 0x1000)
182 Logger::WARNING() << "MISSED FRAME\n";
183 if((temp & 0x0800) == 0x0800)
184 Logger::WARNING() << "MEMORY ERROR\n";
185
186
187 // Responses
188 if((temp & 0x0400) == 0x0400) fetch_data_received();
189 if((temp & 0x0200) == 0x0200) fetch_data_sent();
190 if((temp & 0x0100) == 0x0100) init_done = true;//
191
192 // Reply that it was received
193 register_address_port.write(0); // Tell device to write to register 0
194 register_data_port.write(temp); // Tell device that the interrupt was received
195}
196
197
198
199// Sending a package :
200// "Flags2" shows whether an error occurred while sending and should therefore be set to 0 by the driver.
201// The OWN bit must now be set in the “flags” field (0x80000000) in order to “transfer” the descriptor to the card.
202// Furthermore, STP (Start of Packet, 0x02000000) and ENP (End of Packet, 0x01000000) should be set - this indicates that the data is not split up, but that it is a single Ethernet packet.
203// Furthermore, bits 12-15 must be set (0x0000F000, are probably reserved) and bits 0-11 are negative Size of the package.
211
212 while(!active);
213
214 int send_descriptor = current_send_buffer; // Get where data has been written to
215 current_send_buffer = (current_send_buffer + 1) %
216 8; // Move send buffer to next send buffer (div by 8 so that it is cycled) (this allows for data to be sent from different m_tasks in parallel)
217
218 if(size >
219 1518) { // If attempt to send more than 1518 bytes at once it will be too large
220 size = 1518; // Discard all data after that (Generally if data is bigger than that at driver level then a higher up network layer must have made a mistake)
221
222 }
223
224 // What this loop does is copy the information passed as the parameter buffer (src) to the send buffer in the ram (dst) which the card will then use to send the data
225 for(uint8_t* src = buffer + size -
226 1, // Set src pointer to the end of the data that is being sent
227 * dst = (uint8_t*) (send_buffer_descr[send_descriptor].address + size -
228 1); // Take the buffer that has been selected
229 src >=
230 buffer; // While there is still information in the buffer that hasn't been written to src
231 src--, dst-- // Move 2 pointers to the end of the buffers
232 ) {
233 *dst = *src; // Copy data from source buffer to destination buffer
234 }
235
236
237 send_buffer_descr[send_descriptor].avail = 0; // Set that this buffer is in use
238 send_buffer_descr[send_descriptor].flags2 = 0; // Clear any previous error messages
239 send_buffer_descr[send_descriptor].flags = 0x8300F000 // Encode the size of what is being sent
240 | ((uint16_t) ((-size) & 0xFFF));
241
242 register_address_port.write(0); // Tell device to write to register 0
243 register_data_port.write(
244 0x48); // Tell device to send the data currently in the buffer
245}
246
247void AMD_AM79C973::fetch_data_received() {
248
249 for(; (recv_buffer_descr[current_recv_buffer].flags & 0x80000000) == 0; current_recv_buffer =
250 (current_recv_buffer + 1) %
251 8) //Loop through all the buffers
252 {
253 if(!(recv_buffer_descr[current_recv_buffer].flags & 0x40000000) //Check if there is an error
254 && (recv_buffer_descr[current_recv_buffer].flags & 0x03000000) ==
255 0x03000000) //Check start and end bits of the packet
256 {
257 uint32_t size = recv_buffer_descr[current_recv_buffer].flags2 & 0xFFF; //Get the size of the packet
258 if(size >
259 64) //If the size is the size of ethernet 2 frame
260 size -= 4; //remove the checksum
261
262 auto* buffer = (uint8_t*) (recv_buffer_descr[current_recv_buffer].address); //Get the buffer
263 fire_data_received(buffer, size); //Pass data to handler
264 }
265
266 recv_buffer_descr[current_recv_buffer].flags2 = 0; //write that the data has been read and can now be used again
267 recv_buffer_descr[current_recv_buffer].flags = 0x8000F7FF; //Clear the buffer
268 }
269}
270
271void AMD_AM79C973::fetch_data_sent() {
272
273 /*
274 for(;(recvBufferDescr[currentRecvBuffer].flags & 0x80000000) == 0; currentRecvBuffer = (currentRecvBuffer+1)%8)
275 {
276 if(!(recvBufferDescr[currentRecvBuffer].flags & 0x40000000)
277 && (recvBufferDescr[currentRecvBuffer].flags & 0x03000000) == 0x03000000)
278 {
279 uint32_t size = recvBufferDescr[currentRecvBuffer].flags2 & 0xFFF;
280 if (size > 64)
281 size -= 4;
282
283 uint8_t* buffer = (uint8_t*)(recvBufferDescr[currentRecvBuffer].address);
284 FireDataSent(buffer, size);
285 }
286
287 recvBufferDescr[currentRecvBuffer].flags2 = 0;
288 recvBufferDescr[currentRecvBuffer].flags = 0x8000F7FF;
289 }
290 */
291
292}
293
294
301 while(own_mac == 0);
302 return own_mac;
303}
304
306
307}
308
310 return "AMD";
311}
312
314 return "PCnet-Fast III (Am79C973)";
315}
316
317
Driver for the AMD AM79C973 Ethernet Controller.
static Logger WARNING()
Gets active logger set to WARNING level.
Definition logger.cpp:205
Stores the left, top, width and height of a rectangle.
Definition rectangle.h:22
uint32_t reset() final
This function resets the device.
string vendor_name() final
Get who created the device.
string device_name() final
Get the device name of the driver.
void activate() final
This function activates the device and starts it (Runs when the driver-manger calls activateAll())
AMD_AM79C973(hardwarecommunication::PCIDeviceDescriptor *dev)
Constructs a new AMD_AM79C973 Ethernet driver, reads the MAC address and sets up the initialisation b...
void handle_interrupt() final
This function handles the interrupt for the device.
uint64_t get_media_access_control_address() final
This function gets the MAC address.
void do_send(uint8_t *buffer, uint32_t size) final
This function sends a package.
void deactivate() final
Deactivate the driver.
void fire_data_received(uint8_t *buffer, uint32_t size)
Handle the recieved data.
Definition ethernet.cpp:122
Handles a certain interrupt number.
Definition interrupts.h:30
Stores information about a PCI device.
Definition pci.h:54
virtual void write(uint16_t data)
write a word to the port
Definition port.cpp:95
virtual uint16_t read()
read a word from the port
Definition port.cpp:105
static void * kmalloc(size_t size)
Allocates a block of memory in the KERNEL space.
Defines the layout of a buffer descriptor for the AMD AM79C973 Ethernet Controller.