#include "rtl8139.h" #include "string.h" #include "stdio.h" #include "stdlib.h" #define DEBUG static rtl8139_vtable_t const rtl8139_vtable = { { rtl8139_activate, rtl8139_deactivate, rtl8139_deinit, rtl8139_print_name, rtl8139_print_info } }; // registers #define REG_MAC0 0x00 #define REG_RBSTART 0x30 #define REG_CMD 0x37 #define REG_IMR 0x3C #define REG_ISR 0x3E #define REG_TCR 0x40 #define REG_RCR 0x44 // commands for REG_CMD (command register) #define CMD_RESET 0x10 #define CMD_RECEIVER_ENABLE 0x08 #define CMD_TRANSMITTER_ENABLE 0x04 // mask for reading the version in from the REG_TCR (transmit configuration register) #define TCR_MODEL_VERSION_AM 0x7C000000 #define TCR_MODEL_VERSION_BM 0x00C00000 // vendor identifiers received from the REG_TCR (transmit configuration register) #define TCR_MODEL_VERSION_RTL8139 0x60000000 #define TCR_MODEL_VERSION_RTL8139A 0x70000000 #define TCR_MODEL_VERSION_RTL8139B 0x78000000 #define TCR_MODEL_VERSION_RTL8130 0x78000000 #define TCR_MODEL_VERSION_RTL8139AG 0x74000000 #define TCR_MODEL_VERSION_RTL8139C 0x74000000 #define TCR_MODEL_VERSION_RTL8100 0x78800000 #define TCR_MODEL_VERSION_RTL8100B 0x74400000 #define TCR_MODEL_VERSION_RTL8139CP 0x74800000 #define TCR_MODEL_VERSION_RTL8101 0x74C00000 // values for REG_TCR (transmit configuration register) #define TCR_IFG_STANDARD 0x03000000 #define TCR_MXDMA_2048 0x00000700 // values for REG_RCR (receive configuration register) #define RCR_MXDMA_UNLIMITED 0x00000700 #define RCR_ACCEPT_BROADCAST 0x00000008 #define RCR_ACCEPT_PHYS_MATCH 0x00000002 // values for REG_IMR/REG_ISR (interrupt mask/status registers) #define ISR_SYSTEM_ERROR 0x8000 #define ISR_TIMEOUT 0x4000 #define ISR_CABLE_LENGTH_CHANGED 0x2000 #define ISR_RECEIVE_FIFO_OVERFLOW 0x0040 #define ISR_PACKET_UNDERRUN_LINK_CHANGED 0x0020 #define ISR_RECEIVE_BUFFER_OVERFLOW 0x0010 #define ISR_TRANSMIT_ERROR 0x0008 #define ISR_TRANSMIT_OK 0x0004 #define ISR_RECEIVE_ERROR 0x0002 #define ISR_RECEIVE_OK 0x0001 #define ISR_ALL \ ISR_CABLE_LENGTH_CHANGED | ISR_TIMEOUT | ISR_SYSTEM_ERROR | \ ISR_RECEIVE_FIFO_OVERFLOW | ISR_PACKET_UNDERRUN_LINK_CHANGED | \ ISR_RECEIVE_BUFFER_OVERFLOW | ISR_TRANSMIT_ERROR | ISR_TRANSMIT_OK | \ ISR_RECEIVE_ERROR | ISR_RECEIVE_OK // for now we follow the guide line on OSDEV on the size of the receive buffer #define RECEIVE_BUFFER_SIZE 8192 + 16 void rtl8139_init( rtl8139_t *rtl8139, pci_device_descriptor_t *descriptor, interrupt_t *interrupt, void *context ) { memset( rtl8139, 0, sizeof( rtl8139_t ) ); network_init( (network_t *)rtl8139, interrupt, context ); rtl8139->pci_descriptor = *descriptor; puts( "Initializing driver for Realtek 8139 network card.." ); for( int i = 0; i < NOF_MAC_REGISTERS; i++ ) { port8_init( &rtl8139->MAC_port[i], descriptor->port_base + REG_MAC0 + i ); } port8_init( &rtl8139->CMD_port, descriptor->port_base + REG_CMD ); port32_init( &rtl8139->RBSTART_port, descriptor->port_base + REG_RBSTART ); port16_init( &rtl8139->IMR_port, descriptor->port_base + REG_IMR ); port16_init( &rtl8139->ISR_port, descriptor->port_base + REG_ISR ); port32_init( &rtl8139->TCR_port, descriptor->port_base + REG_TCR ); port32_init( &rtl8139->RCR_port, descriptor->port_base + REG_RCR ); // software reset, the CR_RESET bit remains high till the // reset is finished port8_write( &rtl8139->CMD_port, CMD_RESET ); while( ( port8_read( &rtl8139->CMD_port ) & CMD_RESET ) == CMD_RESET ); // get MAC for( int i = 0; i < NOF_MAC_REGISTERS; i++ ) { rtl8139->base.mac_address.byte[i] = port8_read( &rtl8139->MAC_port[i] ); } // enable receiver and transmitter early port8_write( &rtl8139->CMD_port, CMD_RECEIVER_ENABLE | CMD_TRANSMITTER_ENABLE ); // get model rtl8139->model_id = port32_read( &rtl8139->TCR_port ) & ( TCR_MODEL_VERSION_AM | TCR_MODEL_VERSION_BM ); switch( rtl8139->model_id ) { case TCR_MODEL_VERSION_RTL8139: rtl8139->model = "RTL8139"; break; case TCR_MODEL_VERSION_RTL8139A: rtl8139->model = "RTL8139A"; break; // case TCR_MODEL_VERSION_RTL8139B: case TCR_MODEL_VERSION_RTL8130: rtl8139->model = "RTL8130/RTL8130B"; break; // case TCR_MODEL_VERSION_RTL8139AG: case TCR_MODEL_VERSION_RTL8139C: rtl8139->model = "RTL8139A-G/RTL8139C"; break; case TCR_MODEL_VERSION_RTL8100: rtl8139->model = "RTL8100"; break; case TCR_MODEL_VERSION_RTL8100B: rtl8139->model = "RTL8100B"; break; case TCR_MODEL_VERSION_RTL8139CP: rtl8139->model = "RTL8139C+"; break; case TCR_MODEL_VERSION_RTL8101: rtl8139->model = "RTL8101"; break; default: rtl8139->model = NULL; break; } // initialize TCR/RCR (take Lowlevel suggestions: TCR = 0x03000700, RCR = 0x0000070a) port32_write( &rtl8139->TCR_port, TCR_IFG_STANDARD | TCR_MXDMA_2048 ); port32_write( &rtl8139->RCR_port, RCR_MXDMA_UNLIMITED | RCR_ACCEPT_BROADCAST | RCR_ACCEPT_PHYS_MATCH ); // allocate receive buffer and register it rtl8139->receive_buffer = (uint8_t *)malloc( RECEIVE_BUFFER_SIZE ); port32_write( &rtl8139->RBSTART_port, (uint32_t)rtl8139->receive_buffer ); // register interrupts we are interested in (we want all and // filter them in the interrupt handler), read ISR to clear // the current values (if there are bits set) port16_write( &rtl8139->IMR_port, ISR_ALL ); (void)port16_read( &rtl8139->ISR_port ); interrupt_handler_init( &rtl8139->interrupt_handler, IRQ_BASE + descriptor->interrupt, interrupt, rtl8139_handle_interrupt, rtl8139 ); interrupts_register_interrupt_handler( rtl8139->interrupt_handler ); rtl8139_print_info( rtl8139 ); ((driver_t *)rtl8139)->vtable = (driver_vtable_t *)&rtl8139_vtable; } void rtl8139_activate( void *obj ) { puts( "Activating driver for Realtek 8139 network card.." ); rtl8139_t *rtl8139 = obj; } void rtl8139_deactivate( void *obj ) { puts( "Dectivating driver for Realtek 8139 network card.." ); rtl8139_t *rtl8139 = obj; } void rtl8139_deinit( void *obj ) { rtl8139_t *rtl8139 = (rtl8139_t *)obj; free( rtl8139->receive_buffer ); } uint32_t rtl8139_handle_interrupt( interrupt_handler_t *handler, uint32_t esp ) { rtl8139_t *rtl8139 = (rtl8139_t *)handler->driver; #ifdef DEBUG printf( "RTL8139 INTERRUPT\n" ); #endif return esp; } void rtl8139_print_name( void *obj ) { puts( "Realtek 8139 network card driver" ); } void rtl8139_print_info( void *obj ) { rtl8139_t *rtl8139 = (rtl8139_t *)obj; char buf[20]; char buf2[30]; snprintf( buf2, 30, "unknown submodel 0x%X", rtl8139->model_id ); network_mac_to_string( rtl8139->base.mac_address, buf, 20 ); printf( "rtl8139 NIC type %s\n at I/O base 0x%X, interrupt 0x%X, MAC: %s\n", ( rtl8139->model != NULL ) ? rtl8139->model : buf2, rtl8139->pci_descriptor.port_base, rtl8139->pci_descriptor.interrupt, buf ); }