Max OS 0.3
Loading...
Searching...
No Matches
MaxOS::drivers::ethernet::AMD_AM79C973 Class Reference

Driver for the AMD AM79C973 Ethernet Controller. More...

#include <amd_am79c973.h>

Inheritance diagram for MaxOS::drivers::ethernet::AMD_AM79C973:
MaxOS::drivers::ethernet::EthernetDriver MaxOS::hardwarecommunication::InterruptHandler MaxOS::drivers::Driver MaxOS::common::EventManager< EthernetDriverEvents >

Public Member Functions

 AMD_AM79C973 (hardwarecommunication::PCIDeviceDescriptor *dev)
 Constructs a new AMD_AM79C973 Ethernet driver, reads the MAC address and sets up the initialisation block and buffer descriptors.
 
uint32_t reset () final
 This function resets the device.
 
void activate () final
 This function activates the device and starts it (Runs when the driver-manger calls activateAll())
 
void deactivate () final
 Deactivate the driver.
 
string vendor_name () final
 Get who created the device.
 
string device_name () final
 Get the device name of the driver.
 
void handle_interrupt () final
 This function handles the interrupt for the device.
 
void do_send (uint8_t *buffer, uint32_t size) final
 This function sends a package.
 
uint64_t get_media_access_control_address () final
 This function gets the MAC address.
 
- Public Member Functions inherited from MaxOS::drivers::ethernet::EthernetDriver
void send (uint8_t *buffer, uint32_t size)
 send data to the network via the driver backend
 
- Public Member Functions inherited from MaxOS::drivers::Driver
virtual void initialise ()
 Initialise the driver.
 
- Public Member Functions inherited from MaxOS::common::EventManager< EthernetDriverEvents >
void connect_event_handler (EventHandler< EthernetDriverEvents > *handler)
 connect an event handler to the event manager if it is not already connected
 
void disconnect_event_handler (EventHandler< EthernetDriverEvents > *handler)
 disconnect an event handler from the event manager if it is connected
 
Vector< Event< EthernetDriverEvents > * > raise_event (Event< EthernetDriverEvents > *event)
 Calls the on_event function of all the event m_handlers connected to the event manager and returns a list of the results.
 
- Public Member Functions inherited from MaxOS::hardwarecommunication::InterruptHandler
virtual system::cpu_status_thandle_interrupt (system::cpu_status_t *status)
 Handles an interrupt and returns the status.
 

Additional Inherited Members

- Static Public Member Functions inherited from MaxOS::drivers::ethernet::EthernetDriver
static MediaAccessControlAddress create_media_access_control_address (uint8_t digit1, uint8_t digit2, uint8_t digit3, uint8_t digit4, uint8_t digit5, uint8_t digit6)
 Create a Media Access Control Address.
 
- Protected Member Functions inherited from MaxOS::drivers::ethernet::EthernetDriver
void fire_data_received (uint8_t *buffer, uint32_t size)
 Handle the recieved data.
 
void fire_data_sent (uint8_t *buffer, uint32_t size)
 send data
 
- Protected Member Functions inherited from MaxOS::hardwarecommunication::InterruptHandler
 InterruptHandler (uint8_t interrupt_number, int64_t redirect=-1, uint64_t redirect_index=0)
 Creates a new interrupt handler and registers it with the interrupt manager.
 
 ~InterruptHandler ()
 Destroys the interrupt handler and unregisters it from the interrupt manager.
 
- Protected Attributes inherited from MaxOS::common::EventManager< EthernetDriverEvents >
Vector< EventHandler< EthernetDriverEvents > * > m_handlers
 
- Protected Attributes inherited from MaxOS::hardwarecommunication::InterruptHandler
uint8_t m_interrupt_number
 The interrupt number this handler handles.
 

Detailed Description

Driver for the AMD AM79C973 Ethernet Controller.

Definition at line 65 of file amd_am79c973.h.

Constructor & Destructor Documentation

◆ AMD_AM79C973()

AMD_AM79C973::AMD_AM79C973 ( hardwarecommunication::PCIDeviceDescriptor dev)
explicit

Constructs a new AMD_AM79C973 Ethernet driver, reads the MAC address and sets up the initialisation block and buffer descriptors.

MAX OS NET CODE: All the old (this) networking code poorly written and not used, this will be moved to userspace in the future but is kept here as a reference for now.

Parameters
devThe PCI device descriptor for this device
Todo:
move all this to initilise()

Definition at line 26 of file amd_am79c973.cpp.

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}
Stores the left, top, width and height of a rectangle.
Definition rectangle.h:22
Handles a certain interrupt number.
Definition interrupts.h:30
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.

References MaxOS::memory::MemoryManager::kmalloc(), MaxOS::hardwarecommunication::Port16Bit::read(), and MaxOS::hardwarecommunication::Port16Bit::write().

Member Function Documentation

◆ activate()

void AMD_AM79C973::activate ( )
finalvirtual

This function activates the device and starts it (Runs when the driver-manger calls activateAll())

Todo:
Re-implement this class

Reimplemented from MaxOS::drivers::Driver.

Definition at line 127 of file amd_am79c973.cpp.

127 {
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}

References MaxOS::hardwarecommunication::Port16Bit::read(), and MaxOS::hardwarecommunication::Port16Bit::write().

◆ deactivate()

void AMD_AM79C973::deactivate ( )
finalvirtual

Deactivate the driver.

Reimplemented from MaxOS::drivers::Driver.

Definition at line 305 of file amd_am79c973.cpp.

305 {
306
307}

◆ device_name()

string AMD_AM79C973::device_name ( )
finalvirtual

Get the device name of the driver.

Returns
The device name of the driver

Reimplemented from MaxOS::drivers::Driver.

Definition at line 313 of file amd_am79c973.cpp.

313 {
314 return "PCnet-Fast III (Am79C973)";
315}

◆ do_send()

void AMD_AM79C973::do_send ( uint8_t buffer,
uint32_t  size 
)
finalvirtual

This function sends a package.

Parameters
bufferThe buffer to send
sizeThe size of the buffer

Reimplemented from MaxOS::drivers::ethernet::EthernetDriver.

Definition at line 210 of file amd_am79c973.cpp.

210 {
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}

References MaxOS::hardwarecommunication::Port16Bit::write().

◆ get_media_access_control_address()

uint64_t AMD_AM79C973::get_media_access_control_address ( )
finalvirtual

This function gets the MAC address.

Returns
The MAC address

Reimplemented from MaxOS::drivers::ethernet::EthernetDriver.

Definition at line 300 of file amd_am79c973.cpp.

300 {
301 while(own_mac == 0);
302 return own_mac;
303}

◆ handle_interrupt()

void AMD_AM79C973::handle_interrupt ( )
finalvirtual

This function handles the interrupt for the device.

Reimplemented from MaxOS::hardwarecommunication::InterruptHandler.

Definition at line 168 of file amd_am79c973.cpp.

168 {
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}
static Logger WARNING()
Gets active logger set to WARNING level.
Definition logger.cpp:205

References MaxOS::hardwarecommunication::Port16Bit::read(), MaxOS::Logger::WARNING(), and MaxOS::hardwarecommunication::Port16Bit::write().

◆ reset()

uint32_t AMD_AM79C973::reset ( )
finalvirtual

This function resets the device.

Returns
The amount of ms to wait

Reimplemented from MaxOS::drivers::Driver.

Definition at line 155 of file amd_am79c973.cpp.

155 {
156
157 reset_port.read();
158 reset_port.write(0);
159 return 10; // 10 means wait for 10ms
160
161}

References MaxOS::hardwarecommunication::Port16Bit::read(), and MaxOS::hardwarecommunication::Port16Bit::write().

◆ vendor_name()

string AMD_AM79C973::vendor_name ( )
finalvirtual

Get who created the device.

Returns
The vendor name of the driver

Reimplemented from MaxOS::drivers::Driver.

Definition at line 309 of file amd_am79c973.cpp.

309 {
310 return "AMD";
311}

The documentation for this class was generated from the following files: