improvements and fixes in arp protocol and rtl8139 driver code
[quarnos.git] / resources / rtl8139.cpp
blob6d6aaf7ef19fece948e6535434100fdc2dc489f3
1 /* Quarn OS
3 * Realtek 8139 ethernet card
5 * Copyright (C) 2009 Pawel Dziepak
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "rtl8139.h"
24 #include "pci.h"
26 #include "manes/manec.h"
27 #include "services/interrupt_manager.h"
29 #include "arch/low/lowlevel.h"
30 #include "arch/low/hlt.h"
32 using namespace resources;
34 extern p<net::nic> faar;
36 bool rtl8139::init_device(p<did> id) {
37 device_id = id;
38 this->id = *id.cast<pci_did>();
39 init();
40 faar = this;
42 return true;
45 bool rtl8139::check_device(p<did> id) {
46 p<pci_did> pid = id.cast<pci_did>();
48 if (!pid.valid())
49 return false;
51 /* It must be an ethernet card */
52 unsigned int devclass = pid->get_devclass() >> 8;
53 if (devclass != 0x0200)
54 return false;
56 unsigned int devid = pid->get_devid();
57 /* It must be a *compatible* ethernet card */
58 if (devid != 0x813910ec)
59 return false;
61 return true;
64 void rtl8139::send_data(const buffer &x) {
65 send_packet(x);
69 net::mac_addr rtl8139::get_haddr() const {
70 u8 addr[6];
71 get_mac_addr(addr);
72 return net::mac_addr::from_be(*(u32*)addr, ((u16*)addr)[2]);
76 void rtl8139::irq_handler() {
77 u16 status = id.inw(isr);
78 /* if (status & 4) {
79 id.outw(isr, 4);
80 id.inw(isr);
81 }*/
82 if (status & 1) {
83 receive_packet();
84 //delegate<void> rec;
85 //rec.method(this, &rtl8139::receive_packet);
86 //manes::manec::get()->get<services::asynch_tasks>("/asnych_tasks")->add_task(rec);
87 } else {
88 id.outw(isr, status);
89 id.inw(isr);
92 arch::unlock_irqs(id.irq);
96 void rtl8139::init() {
97 /* Set IRQ */
98 manes::manec::get()->get<services::interrupt_manager>("/interrupt_manager")->register_interrupt(id.irq + 0x20, delegate<void>::method(this, &rtl8139::irq_handler));
100 /* Power on */
101 id.outb(config1, 0);
103 /* Software reset */
104 id.outb(cmd, 0x10);
105 while (id.inb(cmd) & 0x10);
107 /* Prepare receive buffer */
108 rec_buffer = new char[8192 + 16];
109 id.outl(rbstart, (u32)rec_buffer);
111 /* Set IMR, ISR */
112 /* IRQ on Transmit OK and Receive OK */
113 id.outw(imr, 1);
114 id.outw(isr, 0xffff);
116 /* Configure receiver */
117 id.outl(rec_conf, 0xf | (1 << 7));
119 /* Enable receiver and transmitter */
120 id.outb(cmd, 0xc);
123 void rtl8139::send_packet(const buffer &x) {
124 assert("rtl8139: packet is too big", x.get_size() >= 0x700);
125 /* Set TSAD */
126 id.outl(tsad0 + send_index * 4, (u32)x.get_address());
128 /* Set TSD */
129 id.outl(tsd0 + send_index * 4, x.get_size());
130 send_index++;
133 void rtl8139::receive_packet() {
134 wait_loop();
136 packet *pkg = (packet*)((u32)rec_buffer + id.inl(capr));
137 u32 size = pkg->size;
138 u8* buf = new u8[size + 4];
139 memcpy(buf, pkg, size + 4);
141 pkg = (packet*)buf;
142 id.outl(capr, pkg->size);
144 id.outw(isr,0xffff);
145 id.inw(isr);
147 receiver(buffer((void*)&pkg[1], pkg->size));
149 // delete []buf;
152 void rtl8139::get_mac_addr(u8 *addr) const {
153 for (int i = 0; i < 6; i++)
154 addr[i] = id.inb(i);
158 void rtl8139::register_type() {
159 manes::manec::get()->register_driver<rtl8139>("rtl8139", "nic", delegate<bool, p<did> >::function(&rtl8139::check_device));