usb: getting string descriptors, minor improvements
[quarnos.git] / resources / rtl8139.cpp
blob33def41d2d0196d7e7a83f486547db58199fca65
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 if (status & 2) {
88 if (!(id.inb(cmd) & 1))
89 asm("cli\nhlt"::"a"(0xd00d00));
91 id.outw(isr, status);
92 id.inw(isr);
93 } else {
94 id.outw(isr, status);
95 id.inw(isr);
98 arch::unlock_irqs(id.irq);
102 void rtl8139::init() {
103 /* Set IRQ */
104 manes::manec::get()->get<services::interrupt_manager>("/interrupt_manager")->register_interrupt(id.irq + 0x20, delegate<void>::method(this, &rtl8139::irq_handler));
106 /* Power on */
107 id.outb(config1, 0);
109 /* Software reset */
110 id.outb(cmd, 0x10);
111 while (id.inb(cmd) & 0x10);
113 /* Prepare receive buffer */
114 rec_buffer = new char[8192 + 16];
115 id.outl(rbstart, (u32)rec_buffer);
117 /* Set IMR, ISR */
118 /* IRQ on Transmit OK and Receive OK */
119 id.outw(imr, 1);
120 id.outw(isr, 0xffff);
122 /* Configure receiver */
123 id.outl(rec_conf, (0xf | (1 << 7)) & ~(u32)1);
125 /* Enable receiver and transmitter */
126 id.outb(cmd, 0xc);
129 void rtl8139::send_packet(const buffer &x) {
130 assert("rtl8139: packet is too big", x.get_size() >= 0x700);
131 /* Set TSAD */
132 id.outl(tsad0 + send_index * 4, (u32)x.get_address());
134 /* Set TSD */
135 id.outl(tsd0 + send_index * 4, x.get_size());
136 send_index = (send_index + 1) % 4;
139 void rtl8139::receive_packet() {
140 while ((id.inb(cmd) & 1) == 0) {
141 packet *pkg = (packet*)((u32)rec_buffer + received_index);
142 u32 size = pkg->size;
143 u32 status = pkg->status;
145 received_index = (received_index + size + 4 + 3) & ~3;
146 //received_index %= 8192 + 16;
148 // if (status & 1) {
149 u8* buf = new u8[size];
150 memcpy(buf, pkg, size);
152 pkg = (packet*)buf;
153 id.outw(capr, received_index - 16);
154 // }
156 id.outw(isr, 1);
157 id.inw(isr);
159 // if (status & 1)
160 receiver(buffer((void*)&pkg[1], pkg->size - 4));
162 delete []buf;
166 void rtl8139::get_mac_addr(u8 *addr) const {
167 for (int i = 0; i < 6; i++)
168 addr[i] = id.inb(i);
172 void rtl8139::register_type() {
173 manes::manec::get()->register_driver<rtl8139>("rtl8139", "nic", delegate<bool, p<did> >::function(&rtl8139::check_device));