updated on Tue Jan 17 08:05:08 UTC 2012
[aur-mirror.git] / dosbox-svn-patched / ne2000.patch
blobd2b20732e07f29424d535bbe346931f06009bd43
1 diff -urN dosbox.orig/configure.in dosbox/configure.in
2 --- dosbox.orig/configure.in 2011-01-11 20:18:46.141498770 -0300
3 +++ dosbox/configure.in 2011-01-11 20:28:09.718165438 -0300
4 @@ -351,6 +351,16 @@
5 AC_MSG_WARN([Can't find libpng, screenshot support disabled])
6 fi
8 +AH_TEMPLATE(C_NE2000,[Define to 1 to enable NE2000 ethernet passthrough, requires libpcap])
9 +AC_CHECK_HEADER(pcap.h,have_pcap_h=yes,)
10 +AC_CHECK_LIB(pcap, pcap_open_live, have_pcap_lib=yes, ,-lz)
11 +if test x$have_pcap_lib = xyes -a x$have_pcap_h = xyes ; then
12 + LIBS="$LIBS -lpcap";
13 + AC_DEFINE(C_NE2000,1)
14 +else
15 + AC_MSG_WARN([Can't find libpcap, NE2000 ethernet passthrough disabled])
16 +fi
18 AH_TEMPLATE(C_MODEM,[Define to 1 to enable internal modem support, requires SDL_net])
19 AH_TEMPLATE(C_IPX,[Define to 1 to enable IPX over Internet networking, requires SDL_net])
20 AC_CHECK_HEADER(SDL_net.h,have_sdl_net_h=yes,)
21 diff -urN dosbox.orig/include/Makefile.am dosbox/include/Makefile.am
22 --- dosbox.orig/include/Makefile.am 2011-01-11 20:18:46.141498770 -0300
23 +++ dosbox/include/Makefile.am 2011-01-11 20:28:09.714832104 -0300
24 @@ -35,5 +35,7 @@
25 support.h \
26 timer.h \
27 vga.h \
28 -video.h
29 +video.h \
30 +ne2000.h
33 diff -urN dosbox.orig/include/ne2000.h dosbox/include/ne2000.h
34 --- dosbox.orig/include/ne2000.h 1969-12-31 21:00:00.000000000 -0300
35 +++ dosbox/include/ne2000.h 2011-01-11 20:28:09.718165438 -0300
36 @@ -0,0 +1,251 @@
37 +/////////////////////////////////////////////////////////////////////////
38 +// $Id: ne2k.h,v 1.11.2.3 2003/04/06 17:29:49 bdenney Exp $
39 +/////////////////////////////////////////////////////////////////////////
40 +//
41 +// Copyright (C) 2001 MandrakeSoft S.A.
42 +//
43 +// MandrakeSoft S.A.
44 +// 43, rue d'Aboukir
45 +// 75002 Paris - France
46 +// http://www.linux-mandrake.com/
47 +// http://www.mandrakesoft.com/
48 +//
49 +// This library is free software; you can redistribute it and/or
50 +// modify it under the terms of the GNU Lesser General Public
51 +// License as published by the Free Software Foundation; either
52 +// version 2 of the License, or (at your option) any later version.
53 +//
54 +// This library is distributed in the hope that it will be useful,
55 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
56 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
57 +// Lesser General Public License for more details.
58 +//
59 +// You should have received a copy of the GNU Lesser General Public
60 +// License along with this library; if not, write to the Free Software
61 +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
63 +// Peter Grehan (grehan@iprg.nokia.com) coded all of this
64 +// NE2000/ether stuff.
66 +//
67 +// An implementation of an ne2000 ISA ethernet adapter. This part uses
68 +// a National Semiconductor DS-8390 ethernet MAC chip, with some h/w
69 +// to provide a windowed memory region for the chip and a MAC address.
70 +//
72 +#include "dosbox.h"
74 +#define bx_bool int
75 +#define bx_param_c Bit8u
78 +# define BX_NE2K_SMF
79 +# define BX_NE2K_THIS_PTR
80 +# define BX_NE2K_THIS
81 +#define BX_INFO
82 +//LOG_MSG
83 +#define BX_DEBUG
84 +//LOG_MSG
86 +#define BX_NE2K_MEMSIZ (32*1024)
87 +#define BX_NE2K_MEMSTART (16*1024)
88 +#define BX_NE2K_MEMEND (BX_NE2K_MEMSTART + BX_NE2K_MEMSIZ)
90 +typedef struct {
91 + //
92 + // ne2k register state
94 + //
95 + // Page 0
96 + //
97 + // Command Register - 00h read/write
98 + struct CR_t {
99 + bx_bool stop; // STP - Software Reset command
100 + bx_bool start; // START - start the NIC
101 + bx_bool tx_packet; // TXP - initiate packet transmission
102 + Bit8u rdma_cmd; // RD0,RD1,RD2 - Remote DMA command
103 + Bit8u pgsel; // PS0,PS1 - Page select
104 + } CR;
105 + // Interrupt Status Register - 07h read/write
106 + struct ISR_t {
107 + bx_bool pkt_rx; // PRX - packet received with no errors
108 + bx_bool pkt_tx; // PTX - packet transmitted with no errors
109 + bx_bool rx_err; // RXE - packet received with 1 or more errors
110 + bx_bool tx_err; // TXE - packet tx'd " " " " "
111 + bx_bool overwrite; // OVW - rx buffer resources exhausted
112 + bx_bool cnt_oflow; // CNT - network tally counter MSB's set
113 + bx_bool rdma_done; // RDC - remote DMA complete
114 + bx_bool reset; // RST - reset status
115 + } ISR;
116 + // Interrupt Mask Register - 0fh write
117 + struct IMR_t {
118 + bx_bool rx_inte; // PRXE - packet rx interrupt enable
119 + bx_bool tx_inte; // PTXE - packet tx interrput enable
120 + bx_bool rxerr_inte; // RXEE - rx error interrupt enable
121 + bx_bool txerr_inte; // TXEE - tx error interrupt enable
122 + bx_bool overw_inte; // OVWE - overwrite warn int enable
123 + bx_bool cofl_inte; // CNTE - counter o'flow int enable
124 + bx_bool rdma_inte; // RDCE - remote DMA complete int enable
125 + bx_bool reserved; // D7 - reserved
126 + } IMR;
127 + // Data Configuration Register - 0eh write
128 + struct DCR_t {
129 + bx_bool wdsize; // WTS - 8/16-bit select
130 + bx_bool endian; // BOS - byte-order select
131 + bx_bool longaddr; // LAS - long-address select
132 + bx_bool loop; // LS - loopback select
133 + bx_bool auto_rx; // AR - auto-remove rx packets with remote DMA
134 + Bit8u fifo_size; // FT0,FT1 - fifo threshold
135 + } DCR;
136 + // Transmit Configuration Register - 0dh write
137 + struct TCR_t {
138 + bx_bool crc_disable; // CRC - inhibit tx CRC
139 + Bit8u loop_cntl; // LB0,LB1 - loopback control
140 + bx_bool ext_stoptx; // ATD - allow tx disable by external mcast
141 + bx_bool coll_prio; // OFST - backoff algorithm select
142 + Bit8u reserved; // D5,D6,D7 - reserved
143 + } TCR;
144 + // Transmit Status Register - 04h read
145 + struct TSR_t {
146 + bx_bool tx_ok; // PTX - tx complete without error
147 + bx_bool reserved; // D1 - reserved
148 + bx_bool collided; // COL - tx collided >= 1 times
149 + bx_bool aborted; // ABT - aborted due to excessive collisions
150 + bx_bool no_carrier; // CRS - carrier-sense lost
151 + bx_bool fifo_ur; // FU - FIFO underrun
152 + bx_bool cd_hbeat; // CDH - no tx cd-heartbeat from transceiver
153 + bx_bool ow_coll; // OWC - out-of-window collision
154 + } TSR;
155 + // Receive Configuration Register - 0ch write
156 + struct RCR_t {
157 + bx_bool errors_ok; // SEP - accept pkts with rx errors
158 + bx_bool runts_ok; // AR - accept < 64-byte runts
159 + bx_bool broadcast; // AB - accept eth broadcast address
160 + bx_bool multicast; // AM - check mcast hash array
161 + bx_bool promisc; // PRO - accept all packets
162 + bx_bool monitor; // MON - check pkts, but don't rx
163 + Bit8u reserved; // D6,D7 - reserved
164 + } RCR;
165 + // Receive Status Register - 0ch read
166 + struct RSR_t {
167 + bx_bool rx_ok; // PRX - rx complete without error
168 + bx_bool bad_crc; // CRC - Bad CRC detected
169 + bx_bool bad_falign; // FAE - frame alignment error
170 + bx_bool fifo_or; // FO - FIFO overrun
171 + bx_bool rx_missed; // MPA - missed packet error
172 + bx_bool rx_mbit; // PHY - unicast or mcast/bcast address match
173 + bx_bool rx_disabled; // DIS - set when in monitor mode
174 + bx_bool deferred; // DFR - collision active
175 + } RSR;
177 + Bit16u local_dma; // 01,02h read ; current local DMA addr
178 + Bit8u page_start; // 01h write ; page start register
179 + Bit8u page_stop; // 02h write ; page stop register
180 + Bit8u bound_ptr; // 03h read/write ; boundary pointer
181 + Bit8u tx_page_start; // 04h write ; transmit page start register
182 + Bit8u num_coll; // 05h read ; number-of-collisions register
183 + Bit16u tx_bytes; // 05,06h write ; transmit byte-count register
184 + Bit8u fifo; // 06h read ; FIFO
185 + Bit16u remote_dma; // 08,09h read ; current remote DMA addr
186 + Bit16u remote_start; // 08,09h write ; remote start address register
187 + Bit16u remote_bytes; // 0a,0bh write ; remote byte-count register
188 + Bit8u tallycnt_0; // 0dh read ; tally counter 0 (frame align errors)
189 + Bit8u tallycnt_1; // 0eh read ; tally counter 1 (CRC errors)
190 + Bit8u tallycnt_2; // 0fh read ; tally counter 2 (missed pkt errors)
192 + //
193 + // Page 1
194 + //
195 + // Command Register 00h (repeated)
196 + //
197 + Bit8u physaddr[6]; // 01-06h read/write ; MAC address
198 + Bit8u curr_page; // 07h read/write ; current page register
199 + Bit8u mchash[8]; // 08-0fh read/write ; multicast hash array
201 + //
202 + // Page 2 - diagnostic use only
203 + //
204 + // Command Register 00h (repeated)
205 + //
206 + // Page Start Register 01h read (repeated)
207 + // Page Stop Register 02h read (repeated)
208 + // Current Local DMA Address 01,02h write (repeated)
209 + // Transmit Page start address 04h read (repeated)
210 + // Receive Configuration Register 0ch read (repeated)
211 + // Transmit Configuration Register 0dh read (repeated)
212 + // Data Configuration Register 0eh read (repeated)
213 + // Interrupt Mask Register 0fh read (repeated)
214 + //
215 + Bit8u rempkt_ptr; // 03h read/write ; remote next-packet pointer
216 + Bit8u localpkt_ptr; // 05h read/write ; local next-packet pointer
217 + Bit16u address_cnt; // 06,07h read/write ; address counter
219 + //
220 + // Page 3 - should never be modified.
221 + //
223 + // Novell ASIC state
224 + Bit8u macaddr[32]; // ASIC ROM'd MAC address, even bytes
225 + Bit8u mem[BX_NE2K_MEMSIZ]; // on-chip packet memory
227 + // ne2k internal state
228 + Bit32u base_address;
229 + int base_irq;
230 + int tx_timer_index;
231 + int tx_timer_active;
233 + void register_state(bx_param_c *list_p);
235 +} bx_ne2k_t;
239 +class bx_ne2k_c {
240 +public:
241 + bx_ne2k_c(void);
242 + ~bx_ne2k_c(void);
243 + virtual void init(void);
244 + virtual void reset(unsigned type);
246 +public:
247 + bx_ne2k_t s;
249 + /* TODO: Setup SDL */
250 + //eth_pktmover_c *ethdev;
252 + BX_NE2K_SMF Bit32u read_cr(void);
253 + BX_NE2K_SMF void write_cr(Bit32u value);
255 + BX_NE2K_SMF Bit32u chipmem_read(Bit32u address, unsigned io_len);
256 + BX_NE2K_SMF Bit32u asic_read(Bit32u offset, unsigned io_len);
257 + BX_NE2K_SMF Bit32u page0_read(Bit32u offset, unsigned io_len);
258 + BX_NE2K_SMF Bit32u page1_read(Bit32u offset, unsigned io_len);
259 + BX_NE2K_SMF Bit32u page2_read(Bit32u offset, unsigned io_len);
260 + BX_NE2K_SMF Bit32u page3_read(Bit32u offset, unsigned io_len);
262 + BX_NE2K_SMF void chipmem_write(Bit32u address, Bit32u value, unsigned io_len);
263 + BX_NE2K_SMF void asic_write(Bit32u address, Bit32u value, unsigned io_len);
264 + BX_NE2K_SMF void page0_write(Bit32u address, Bit32u value, unsigned io_len);
265 + BX_NE2K_SMF void page1_write(Bit32u address, Bit32u value, unsigned io_len);
266 + BX_NE2K_SMF void page2_write(Bit32u address, Bit32u value, unsigned io_len);
267 + BX_NE2K_SMF void page3_write(Bit32u address, Bit32u value, unsigned io_len);
269 +public:
270 + static void tx_timer_handler(void *);
271 + BX_NE2K_SMF void tx_timer(void);
273 + static void rx_handler(void *arg, const void *buf, unsigned len);
274 + BX_NE2K_SMF unsigned mcast_index(const void *dst);
275 + BX_NE2K_SMF void rx_frame(const void *buf, unsigned io_len);
278 + static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
279 + static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
280 +#if !BX_USE_NE2K_SMF
281 + Bit32u read(Bit32u address, unsigned io_len);
282 + void write(Bit32u address, Bit32u value, unsigned io_len);
283 +#endif
288 diff -urN dosbox.orig/src/dosbox.cpp dosbox/src/dosbox.cpp
289 --- dosbox.orig/src/dosbox.cpp 2011-01-11 20:18:46.158165437 -0300
290 +++ dosbox/src/dosbox.cpp 2011-01-11 20:28:09.714832104 -0300
291 @@ -43,6 +43,11 @@
292 #include "ints/int10.h"
293 #include "render.h"
295 +#ifdef C_NE2000
296 +//#include "ne2000.h"
297 +void NE2K_Init(Section* sec);
298 +#endif
300 Config * control;
301 MachineType machine;
302 SVGACards svgaCard;
303 @@ -694,6 +699,45 @@
304 Pbool = secprop->Add_bool("ipx",Property::Changeable::WhenIdle, false);
305 Pbool->Set_help("Enable ipx over UDP/IP emulation.");
306 #endif
308 +#ifdef C_NE2000
309 + secprop=control->AddSection_prop("ne2000",&NE2K_Init,true);
310 + MSG_Add("NE2000_CONFIGFILE_HELP",
311 + "macaddr -- The physical address the emulator will use on your network.\n"
312 + " If you have multiple DOSBoxes running on your network,\n"
313 + " this has to be changed. Modify the last three number blocks.\n"
314 + " I.e. AC:DE:48:88:99:AB.\n"
315 + "realnic -- Specifies which of your network interfaces is used.\n"
316 + " Write \'list\' here to see the list of devices in the\n"
317 + " Status Window. Then make your choice and put either the\n"
318 + " interface number (2 or something) or a part of your adapters\n"
319 + " name, e.g. VIA here.\n"
321 + );
323 + Pbool = secprop->Add_bool("ne2000", Property::Changeable::WhenIdle, true);
324 + Pbool->Set_help("Enable Ethernet passthrough. Requires [Win]Pcap.");
326 + Phex = secprop->Add_hex("nicbase", Property::Changeable::WhenIdle, 0x300);
327 + Phex->Set_help("The base address of the NE2000 board.");
329 + Pint = secprop->Add_int("nicirq", Property::Changeable::WhenIdle, 3);
330 + Pint->Set_help("The interrupt it uses. Note serial2 uses IRQ3 as default.");
332 + Pstring = secprop->Add_string("macaddr", Property::Changeable::WhenIdle,"AC:DE:48:88:99:AA");
333 + Pstring->Set_help("The physical address the emulator will use on your network.\n"
334 + "If you have multiple DOSBoxes running on your network,\n"
335 + "this has to be changed for each. AC:DE:48 is an address range reserved for\n"
336 + "private use, so modify the last three number blocks.\n"
337 + "I.e. AC:DE:48:88:99:AB.");
339 + Pstring = secprop->Add_string("realnic", Property::Changeable::WhenIdle,"list");
340 + Pstring->Set_help("Specifies which of your network interfaces is used.\n"
341 + "Write \'list\' here to see the list of devices in the\n"
342 + "Status Window. Then make your choice and put either the\n"
343 + "interface number (2 or something) or a part of your adapters\n"
344 + "name, e.g. VIA here.");
345 +#endif // C_NE2000
346 // secprop->AddInitFunction(&CREDITS_Init);
348 //TODO ?
349 diff -urN dosbox.orig/src/hardware/Makefile.am dosbox/src/hardware/Makefile.am
350 --- dosbox.orig/src/hardware/Makefile.am 2011-01-11 20:18:46.174832103 -0300
351 +++ dosbox/src/hardware/Makefile.am 2011-01-11 20:28:09.714832104 -0300
352 @@ -10,6 +10,6 @@
353 memory.cpp mixer.cpp pcspeaker.cpp pic.cpp sblaster.cpp tandy_sound.cpp timer.cpp \
354 vga.cpp vga_attr.cpp vga_crtc.cpp vga_dac.cpp vga_draw.cpp vga_gfx.cpp vga_other.cpp \
355 vga_memory.cpp vga_misc.cpp vga_seq.cpp vga_xga.cpp vga_s3.cpp vga_tseng.cpp vga_paradise.cpp \
356 - cmos.cpp disney.cpp gus.cpp mpu401.cpp ipx.cpp ipxserver.cpp dbopl.cpp glide.cpp
357 + cmos.cpp disney.cpp gus.cpp mpu401.cpp ipx.cpp ipxserver.cpp dbopl.cpp glide.cpp ne2000.cpp
360 diff -urN dosbox.orig/src/hardware/ne2000.cpp dosbox/src/hardware/ne2000.cpp
361 --- dosbox.orig/src/hardware/ne2000.cpp 1969-12-31 21:00:00.000000000 -0300
362 +++ dosbox/src/hardware/ne2000.cpp 2011-01-11 20:28:09.718165438 -0300
363 @@ -0,0 +1,1660 @@
364 +#include "config.h"
366 +#ifdef C_NE2000
369 +#include "dosbox.h"
370 +#include <string.h>
371 +#include <stdio.h>
372 +#include "support.h"
373 +#include "inout.h"
374 +#include "setup.h"
375 +#include "callback.h"
376 +#include "timer.h"
377 +#include "pic.h"
378 +#include "cpu.h"
380 +/* Couldn't find a real spec for the NE2000 out there, hence this is adapted heavily from Bochs */
383 +/////////////////////////////////////////////////////////////////////////
384 +// $Id: ne2k.cc,v 1.56.2.1 2004/02/02 22:37:22 cbothamy Exp $
385 +/////////////////////////////////////////////////////////////////////////
387 +// Copyright (C) 2002 MandrakeSoft S.A.
389 +// MandrakeSoft S.A.
390 +// 43, rue d'Aboukir
391 +// 75002 Paris - France
392 +// http://www.linux-mandrake.com/
393 +// http://www.mandrakesoft.com/
395 +// This library is free software; you can redistribute it and/or
396 +// modify it under the terms of the GNU Lesser General Public
397 +// License as published by the Free Software Foundation; either
398 +// version 2 of the License, or (at your option) any later version.
400 +// This library is distributed in the hope that it will be useful,
401 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
402 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
403 +// Lesser General Public License for more details.
405 +// You should have received a copy of the GNU Lesser General Public
406 +// License along with this library; if not, write to the Free Software
407 +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
409 +// Peter Grehan (grehan@iprg.nokia.com) coded all of this
410 +// NE2000/ether stuff.
412 +#include "ne2000.h"
414 +#define HAVE_REMOTE
416 +#include "pcap.h"
417 +// Handle to WinPCap device
418 +pcap_t *adhandle = 0;
419 +static void NE2000_TX_Event(Bitu val);
421 +#ifdef WIN32
422 +// DLL loading
423 +#define pcap_sendpacket(A,B,C) PacketSendPacket(A,B,C)
424 +#define pcap_close(A) PacketClose(A)
425 +#define pcap_freealldevs(A) PacketFreealldevs(A)
426 +#define pcap_open(A,B,C,D,E,F) PacketOpen(A,B,C,D,E,F)
427 +#define pcap_next_ex(A,B,C) PacketNextEx(A,B,C)
428 +#define pcap_findalldevs_ex(A,B,C,D) PacketFindALlDevsEx(A,B,C,D)
430 +int (*PacketSendPacket)(pcap_t *, const u_char *, int) = 0;
431 +void (*PacketClose)(pcap_t *) = 0;
432 +void (*PacketFreealldevs)(pcap_if_t *) = 0;
433 +pcap_t* (*PacketOpen)(char const *,int,int,int,struct pcap_rmtauth *,char *) = 0;
434 +int (*PacketNextEx)(pcap_t *, struct pcap_pkthdr **, const u_char **) = 0;
435 +int (*PacketFindALlDevsEx)(char *, struct pcap_rmtauth *, pcap_if_t **, char *) = 0;
437 +#endif
439 +//Never completely fill the ne2k ring so that we never
440 +// hit the unclear completely full buffer condition.
441 +#define BX_NE2K_NEVER_FULL_RING (1)
443 +#define LOG_THIS theNE2kDevice->
444 +//#define BX_DEBUG
445 +//#define BX_INFO
446 +#define BX_NULL_TIMER_HANDLE NULL
447 +#define BX_PANIC
448 +#define BX_ERROR
449 +#define BX_RESET_HARDWARE 0
450 +#define BX_RESET_SOFTWARE 1
452 +bx_ne2k_c* theNE2kDevice = NULL;
455 +bx_ne2k_c::bx_ne2k_c(void)
457 + s.tx_timer_index = BX_NULL_TIMER_HANDLE;
461 +bx_ne2k_c::~bx_ne2k_c(void)
463 + // nothing for now
467 +// reset - restore state to power-up, cancelling all i/o
469 +void
470 +bx_ne2k_c::reset(unsigned type)
472 + BX_DEBUG ("reset");
473 + // Zero out registers and memory
474 + memset( & BX_NE2K_THIS s.CR, 0, sizeof(BX_NE2K_THIS s.CR) );
475 + memset( & BX_NE2K_THIS s.ISR, 0, sizeof(BX_NE2K_THIS s.ISR));
476 + memset( & BX_NE2K_THIS s.IMR, 0, sizeof(BX_NE2K_THIS s.IMR));
477 + memset( & BX_NE2K_THIS s.DCR, 0, sizeof(BX_NE2K_THIS s.DCR));
478 + memset( & BX_NE2K_THIS s.TCR, 0, sizeof(BX_NE2K_THIS s.TCR));
479 + memset( & BX_NE2K_THIS s.TSR, 0, sizeof(BX_NE2K_THIS s.TSR));
480 + //memset( & BX_NE2K_THIS s.RCR, 0, sizeof(BX_NE2K_THIS s.RCR));
481 + memset( & BX_NE2K_THIS s.RSR, 0, sizeof(BX_NE2K_THIS s.RSR));
482 + BX_NE2K_THIS s.tx_timer_active = 0;
483 + BX_NE2K_THIS s.local_dma = 0;
484 + BX_NE2K_THIS s.page_start = 0;
485 + BX_NE2K_THIS s.page_stop = 0;
486 + BX_NE2K_THIS s.bound_ptr = 0;
487 + BX_NE2K_THIS s.tx_page_start = 0;
488 + BX_NE2K_THIS s.num_coll = 0;
489 + BX_NE2K_THIS s.tx_bytes = 0;
490 + BX_NE2K_THIS s.fifo = 0;
491 + BX_NE2K_THIS s.remote_dma = 0;
492 + BX_NE2K_THIS s.remote_start = 0;
493 + BX_NE2K_THIS s.remote_bytes = 0;
494 + BX_NE2K_THIS s.tallycnt_0 = 0;
495 + BX_NE2K_THIS s.tallycnt_1 = 0;
496 + BX_NE2K_THIS s.tallycnt_2 = 0;
498 + //memset( & BX_NE2K_THIS s.physaddr, 0, sizeof(BX_NE2K_THIS s.physaddr));
499 + //memset( & BX_NE2K_THIS s.mchash, 0, sizeof(BX_NE2K_THIS s.mchash));
500 + BX_NE2K_THIS s.curr_page = 0;
502 + BX_NE2K_THIS s.rempkt_ptr = 0;
503 + BX_NE2K_THIS s.localpkt_ptr = 0;
504 + BX_NE2K_THIS s.address_cnt = 0;
506 + memset( & BX_NE2K_THIS s.mem, 0, sizeof(BX_NE2K_THIS s.mem));
508 + // Set power-up conditions
509 + BX_NE2K_THIS s.CR.stop = 1;
510 + BX_NE2K_THIS s.CR.rdma_cmd = 4;
511 + BX_NE2K_THIS s.ISR.reset = 1;
512 + BX_NE2K_THIS s.DCR.longaddr = 1;
513 + PIC_DeActivateIRQ(s.base_irq);
514 + //DEV_pic_lower_irq(BX_NE2K_THIS s.base_irq);
518 +// read_cr/write_cr - utility routines for handling reads/writes to
519 +// the Command Register
521 +Bit32u
522 +bx_ne2k_c::read_cr(void)
524 + Bit32u val =
525 + (((BX_NE2K_THIS s.CR.pgsel & 0x03) << 6) |
526 + ((BX_NE2K_THIS s.CR.rdma_cmd & 0x07) << 3) |
527 + (BX_NE2K_THIS s.CR.tx_packet << 2) |
528 + (BX_NE2K_THIS s.CR.start << 1) |
529 + (BX_NE2K_THIS s.CR.stop));
530 + BX_DEBUG("read CR returns 0x%08x", val);
531 + return val;
534 +void
535 +bx_ne2k_c::write_cr(Bit32u value)
537 + BX_DEBUG ("wrote 0x%02x to CR", value);
539 + // Validate remote-DMA
540 + if ((value & 0x38) == 0x00) {
541 + BX_DEBUG("CR write - invalid rDMA value 0");
542 + value |= 0x20; /* dma_cmd == 4 is a safe default */
543 + //value = 0x22; /* dma_cmd == 4 is a safe default */
546 + // Check for s/w reset
547 + if (value & 0x01) {
548 + BX_NE2K_THIS s.ISR.reset = 1;
549 + BX_NE2K_THIS s.CR.stop = 1;
550 + } else {
551 + BX_NE2K_THIS s.CR.stop = 0;
554 + BX_NE2K_THIS s.CR.rdma_cmd = (value & 0x38) >> 3;
556 + // If start command issued, the RST bit in the ISR
557 + // must be cleared
558 + if ((value & 0x02) && !BX_NE2K_THIS s.CR.start) {
559 + BX_NE2K_THIS s.ISR.reset = 0;
562 + BX_NE2K_THIS s.CR.start = ((value & 0x02) == 0x02);
563 + BX_NE2K_THIS s.CR.pgsel = (value & 0xc0) >> 6;
565 + // Check for send-packet command
566 + if (BX_NE2K_THIS s.CR.rdma_cmd == 3) {
567 + // Set up DMA read from receive ring
568 + BX_NE2K_THIS s.remote_start = BX_NE2K_THIS s.remote_dma =
569 + BX_NE2K_THIS s.bound_ptr * 256;
570 + BX_NE2K_THIS s.remote_bytes = *((Bit16u*) &
571 + BX_NE2K_THIS s.mem[BX_NE2K_THIS s.bound_ptr * 256 + 2 - BX_NE2K_MEMSTART]);
572 + BX_INFO("Sending buffer #x%x length %d",
573 + BX_NE2K_THIS s.remote_start,
574 + BX_NE2K_THIS s.remote_bytes);
577 + // Check for start-tx
578 + if ((value & 0x04) && BX_NE2K_THIS s.TCR.loop_cntl) {
579 + // loopback mode
580 + if (BX_NE2K_THIS s.TCR.loop_cntl != 1) {
581 + BX_INFO("Loop mode %d not supported.", BX_NE2K_THIS s.TCR.loop_cntl);
582 + } else {
583 + rx_frame (& BX_NE2K_THIS s.mem[BX_NE2K_THIS s.tx_page_start*256 -
584 + BX_NE2K_MEMSTART],
585 + BX_NE2K_THIS s.tx_bytes);
587 + // do a TX interrupt
588 + // Generate an interrupt if not masked and not one in progress
589 + if (BX_NE2K_THIS s.IMR.tx_inte && !BX_NE2K_THIS s.ISR.pkt_tx) {
590 + //LOG_MSG("tx complete interrupt");
591 + PIC_ActivateIRQ(s.base_irq);
593 + BX_NE2K_THIS s.ISR.pkt_tx = 1;
595 + } else if (value & 0x04) {
596 + // start-tx and no loopback
597 + if (BX_NE2K_THIS s.CR.stop || !BX_NE2K_THIS s.CR.start)
598 + BX_PANIC(("CR write - tx start, dev in reset"));
600 + if (BX_NE2K_THIS s.tx_bytes == 0)
601 + BX_PANIC(("CR write - tx start, tx bytes == 0"));
603 +#ifdef notdef
604 + // XXX debug stuff
605 + printf("packet tx (%d bytes):\t", BX_NE2K_THIS s.tx_bytes);
606 + for (int i = 0; i < BX_NE2K_THIS s.tx_bytes; i++) {
607 + printf("%02x ", BX_NE2K_THIS s.mem[BX_NE2K_THIS s.tx_page_start*256 -
608 + BX_NE2K_MEMSTART + i]);
609 + if (i && (((i+1) % 16) == 0))
610 + printf("\t");
612 + printf("");
613 +#endif
615 + // Send the packet to the system driver
616 + /* TODO: Transmit packet */
617 + //BX_NE2K_THIS ethdev->sendpkt(& BX_NE2K_THIS s.mem[BX_NE2K_THIS s.tx_page_start*256 - BX_NE2K_MEMSTART], BX_NE2K_THIS s.tx_bytes);
618 + pcap_sendpacket(adhandle,&s.mem[s.tx_page_start*256 - BX_NE2K_MEMSTART], s.tx_bytes);
619 + // some more debug
620 + if (BX_NE2K_THIS s.tx_timer_active) {
621 + BX_PANIC(("CR write, tx timer still active"));
622 + PIC_RemoveEvents(NE2000_TX_Event);
624 + //LOG_MSG("send packet command");
625 + //s.tx_timer_index = (64 + 96 + 4*8 + BX_NE2K_THIS s.tx_bytes*8)/10;
626 + s.tx_timer_active = 1;
627 + PIC_AddEvent(NE2000_TX_Event,(float)((64 + 96 + 4*8 + BX_NE2K_THIS s.tx_bytes*8)/10000.0),0);
628 + // Schedule a timer to trigger a tx-complete interrupt
629 + // The number of microseconds is the bit-time / 10.
630 + // The bit-time is the preamble+sfd (64 bits), the
631 + // inter-frame gap (96 bits), the CRC (4 bytes), and the
632 + // the number of bits in the frame (s.tx_bytes * 8).
633 + //
635 + /* TODO: Code transmit timer */
636 + /*
637 + bx_pc_system.activate_timer(BX_NE2K_THIS s.tx_timer_index,
638 + (64 + 96 + 4*8 + BX_NE2K_THIS s.tx_bytes*8)/10,
639 + 0); // not continuous
640 + */
641 + } // end transmit-start branch
643 + // Linux probes for an interrupt by setting up a remote-DMA read
644 + // of 0 bytes with remote-DMA completion interrupts enabled.
645 + // Detect this here
646 + if (BX_NE2K_THIS s.CR.rdma_cmd == 0x01 &&
647 + BX_NE2K_THIS s.CR.start &&
648 + BX_NE2K_THIS s.remote_bytes == 0) {
649 + BX_NE2K_THIS s.ISR.rdma_done = 1;
650 + if (BX_NE2K_THIS s.IMR.rdma_inte) {
651 + PIC_ActivateIRQ(s.base_irq);
652 + //DEV_pic_raise_irq(BX_NE2K_THIS s.base_irq);
658 +// chipmem_read/chipmem_write - access the 64K private RAM.
659 +// The ne2000 memory is accessed through the data port of
660 +// the asic (offset 0) after setting up a remote-DMA transfer.
661 +// Both byte and word accesses are allowed.
662 +// The first 16 bytes contains the MAC address at even locations,
663 +// and there is 16K of buffer memory starting at 16K
665 +Bit32u bx_ne2k_c::chipmem_read(Bit32u address, unsigned int io_len)
667 + Bit32u retval = 0;
669 + if ((io_len == 2) && (address & 0x1))
670 + BX_PANIC(("unaligned chipmem word read"));
672 + // ROM'd MAC address
673 + if ((address >=0) && (address <= 31)) {
674 + retval = BX_NE2K_THIS s.macaddr[address];
675 + if ((io_len == 2) || (io_len == 4)) {
676 + retval |= (BX_NE2K_THIS s.macaddr[address + 1] << 8);
677 + if (io_len == 4) {
678 + retval |= (BX_NE2K_THIS s.macaddr[address + 2] << 16);
679 + retval |= (BX_NE2K_THIS s.macaddr[address + 3] << 24);
682 + return (retval);
685 + if ((address >= BX_NE2K_MEMSTART) && (address < BX_NE2K_MEMEND)) {
686 + retval = BX_NE2K_THIS s.mem[address - BX_NE2K_MEMSTART];
687 + if ((io_len == 2) || (io_len == 4)) {
688 + retval |= (BX_NE2K_THIS s.mem[address - BX_NE2K_MEMSTART + 1] << 8);
690 + if (io_len == 4) {
691 + retval |= (BX_NE2K_THIS s.mem[address - BX_NE2K_MEMSTART + 2] << 16);
692 + retval |= (BX_NE2K_THIS s.mem[address - BX_NE2K_MEMSTART + 3] << 24);
694 + return (retval);
697 + BX_DEBUG("out-of-bounds chipmem read, %04X", address);
699 + return (0xff);
702 +void
703 +bx_ne2k_c::chipmem_write(Bit32u address, Bit32u value, unsigned io_len)
705 + if ((io_len == 2) && (address & 0x1))
706 + BX_PANIC(("unaligned chipmem word write"));
708 + if ((address >= BX_NE2K_MEMSTART) && (address < BX_NE2K_MEMEND)) {
709 + BX_NE2K_THIS s.mem[address - BX_NE2K_MEMSTART] = value & 0xff;
710 + if (io_len == 2)
711 + BX_NE2K_THIS s.mem[address - BX_NE2K_MEMSTART + 1] = value >> 8;
712 + } else
713 + BX_DEBUG("out-of-bounds chipmem write, %04X", address);
717 +// asic_read/asic_write - This is the high 16 bytes of i/o space
718 +// (the lower 16 bytes is for the DS8390). Only two locations
719 +// are used: offset 0, which is used for data transfer, and
720 +// offset 0xf, which is used to reset the device.
721 +// The data transfer port is used to as 'external' DMA to the
722 +// DS8390. The chip has to have the DMA registers set up, and
723 +// after that, insw/outsw instructions can be used to move
724 +// the appropriate number of bytes to/from the device.
726 +Bit32u
727 +bx_ne2k_c::asic_read(Bit32u offset, unsigned int io_len)
729 + Bit32u retval = 0;
731 + switch (offset) {
732 + case 0x0: // Data register
733 + //
734 + // A read remote-DMA command must have been issued,
735 + // and the source-address and length registers must
736 + // have been initialised.
737 + //
738 + if (io_len > BX_NE2K_THIS s.remote_bytes)
740 + BX_ERROR("ne2K: dma read underrun iolen=%d remote_bytes=%d",io_len,BX_NE2K_THIS s.remote_bytes);
741 + //return 0;
744 + //BX_INFO(("ne2k read DMA: addr=%4x remote_bytes=%d",BX_NE2K_THIS s.remote_dma,BX_NE2K_THIS s.remote_bytes));
745 + retval = chipmem_read(BX_NE2K_THIS s.remote_dma, io_len);
746 + //
747 + // The 8390 bumps the address and decreases the byte count
748 + // by the selected word size after every access, not by
749 + // the amount of data requested by the host (io_len).
750 + //
751 + BX_NE2K_THIS s.remote_dma += (BX_NE2K_THIS s.DCR.wdsize + 1);
752 + if (BX_NE2K_THIS s.remote_dma == BX_NE2K_THIS s.page_stop << 8) {
753 + BX_NE2K_THIS s.remote_dma = BX_NE2K_THIS s.page_start << 8;
755 + // keep s.remote_bytes from underflowing
756 + if (BX_NE2K_THIS s.remote_bytes > 1)
757 + BX_NE2K_THIS s.remote_bytes -= (BX_NE2K_THIS s.DCR.wdsize + 1);
758 + else
759 + BX_NE2K_THIS s.remote_bytes = 0;
761 + // If all bytes have been written, signal remote-DMA complete
762 + if (BX_NE2K_THIS s.remote_bytes == 0) {
763 + BX_NE2K_THIS s.ISR.rdma_done = 1;
764 + if (BX_NE2K_THIS s.IMR.rdma_inte) {
765 + PIC_ActivateIRQ(s.base_irq);
766 + //DEV_pic_raise_irq(BX_NE2K_THIS s.base_irq);
769 + break;
771 + case 0xf: // Reset register
772 + theNE2kDevice->reset(BX_RESET_SOFTWARE);
773 + //retval=0x1;
774 + break;
776 + default:
777 + BX_INFO("asic read invalid address %04x", (unsigned) offset);
778 + break;
781 + return (retval);
784 +void
785 +bx_ne2k_c::asic_write(Bit32u offset, Bit32u value, unsigned io_len)
787 + BX_DEBUG("asic write addr=0x%02x, value=0x%04x", (unsigned) offset, (unsigned) value);
788 + switch (offset) {
789 + case 0x0: // Data register - see asic_read for a description
791 + if ((io_len == 2) && (BX_NE2K_THIS s.DCR.wdsize == 0)) {
792 + BX_PANIC(("dma write length 2 on byte mode operation"));
793 + break;
796 + if (BX_NE2K_THIS s.remote_bytes == 0)
797 + BX_PANIC(("ne2K: dma write, byte count 0"));
799 + chipmem_write(BX_NE2K_THIS s.remote_dma, value, io_len);
800 + // is this right ??? asic_read uses DCR.wordsize
801 + BX_NE2K_THIS s.remote_dma += io_len;
802 + if (BX_NE2K_THIS s.remote_dma == BX_NE2K_THIS s.page_stop << 8) {
803 + BX_NE2K_THIS s.remote_dma = BX_NE2K_THIS s.page_start << 8;
806 + BX_NE2K_THIS s.remote_bytes -= io_len;
807 + if (BX_NE2K_THIS s.remote_bytes > BX_NE2K_MEMSIZ)
808 + BX_NE2K_THIS s.remote_bytes = 0;
810 + // If all bytes have been written, signal remote-DMA complete
811 + if (BX_NE2K_THIS s.remote_bytes == 0) {
812 + BX_NE2K_THIS s.ISR.rdma_done = 1;
813 + if (BX_NE2K_THIS s.IMR.rdma_inte) {
814 + PIC_ActivateIRQ(s.base_irq);
815 + //DEV_pic_raise_irq(BX_NE2K_THIS s.base_irq);
818 + break;
820 + case 0xf: // Reset register
821 + theNE2kDevice->reset(BX_RESET_SOFTWARE);
822 + break;
824 + default: // this is invalid, but happens under win95 device detection
825 + BX_INFO("asic write invalid address %04x, ignoring", (unsigned) offset);
826 + break ;
831 +// page0_read/page0_write - These routines handle reads/writes to
832 +// the 'zeroth' page of the DS8390 register file
834 +Bit32u
835 +bx_ne2k_c::page0_read(Bit32u offset, unsigned int io_len)
837 + BX_DEBUG("page 0 read from port %04x, len=%u", (unsigned) offset,
838 + (unsigned) io_len);
839 + if (io_len > 1) {
840 + BX_ERROR("bad length! page 0 read from port %04x, len=%u", (unsigned) offset,
841 + (unsigned) io_len); /* encountered with win98 hardware probe */
842 + return 0;
846 + switch (offset) {
847 + case 0x1: // CLDA0
848 + return (BX_NE2K_THIS s.local_dma & 0xff);
849 + break;
851 + case 0x2: // CLDA1
852 + return (BX_NE2K_THIS s.local_dma >> 8);
853 + break;
855 + case 0x3: // BNRY
856 + return (BX_NE2K_THIS s.bound_ptr);
857 + break;
859 + case 0x4: // TSR
860 + return ((BX_NE2K_THIS s.TSR.ow_coll << 7) |
861 + (BX_NE2K_THIS s.TSR.cd_hbeat << 6) |
862 + (BX_NE2K_THIS s.TSR.fifo_ur << 5) |
863 + (BX_NE2K_THIS s.TSR.no_carrier << 4) |
864 + (BX_NE2K_THIS s.TSR.aborted << 3) |
865 + (BX_NE2K_THIS s.TSR.collided << 2) |
866 + (BX_NE2K_THIS s.TSR.tx_ok));
867 + break;
869 + case 0x5: // NCR
870 + return (BX_NE2K_THIS s.num_coll);
871 + break;
873 + case 0x6: // FIFO
874 + // reading FIFO is only valid in loopback mode
875 + BX_ERROR(("reading FIFO not supported yet"));
876 + return (BX_NE2K_THIS s.fifo);
877 + break;
879 + case 0x7: // ISR
880 + return ((BX_NE2K_THIS s.ISR.reset << 7) |
881 + (BX_NE2K_THIS s.ISR.rdma_done << 6) |
882 + (BX_NE2K_THIS s.ISR.cnt_oflow << 5) |
883 + (BX_NE2K_THIS s.ISR.overwrite << 4) |
884 + (BX_NE2K_THIS s.ISR.tx_err << 3) |
885 + (BX_NE2K_THIS s.ISR.rx_err << 2) |
886 + (BX_NE2K_THIS s.ISR.pkt_tx << 1) |
887 + (BX_NE2K_THIS s.ISR.pkt_rx));
888 + break;
890 + case 0x8: // CRDA0
891 + return (BX_NE2K_THIS s.remote_dma & 0xff);
892 + break;
894 + case 0x9: // CRDA1
895 + return (BX_NE2K_THIS s.remote_dma >> 8);
896 + break;
898 + case 0xa: // reserved
899 + BX_INFO(("reserved read - page 0, 0xa"));
900 + return (0xff);
901 + break;
903 + case 0xb: // reserved
904 + BX_INFO(("reserved read - page 0, 0xb"));
905 + return (0xff);
906 + break;
908 + case 0xc: // RSR
909 + return ((BX_NE2K_THIS s.RSR.deferred << 7) |
910 + (BX_NE2K_THIS s.RSR.rx_disabled << 6) |
911 + (BX_NE2K_THIS s.RSR.rx_mbit << 5) |
912 + (BX_NE2K_THIS s.RSR.rx_missed << 4) |
913 + (BX_NE2K_THIS s.RSR.fifo_or << 3) |
914 + (BX_NE2K_THIS s.RSR.bad_falign << 2) |
915 + (BX_NE2K_THIS s.RSR.bad_crc << 1) |
916 + (BX_NE2K_THIS s.RSR.rx_ok));
917 + break;
919 + case 0xd: // CNTR0
920 + return (BX_NE2K_THIS s.tallycnt_0);
921 + break;
923 + case 0xe: // CNTR1
924 + return (BX_NE2K_THIS s.tallycnt_1);
925 + break;
927 + case 0xf: // CNTR2
928 + return (BX_NE2K_THIS s.tallycnt_2);
929 + break;
931 + default:
932 + BX_PANIC("page 0 offset %04x out of range", (unsigned) offset);
935 + return(0);
938 +void
939 +bx_ne2k_c::page0_write(Bit32u offset, Bit32u value, unsigned io_len)
941 + BX_DEBUG("page 0 write to port %04x, len=%u", (unsigned) offset,
942 + (unsigned) io_len);
944 + // It appears to be a common practice to use outw on page0 regs...
946 + // break up outw into two outb's
947 + if (io_len == 2) {
948 + page0_write(offset, (value & 0xff), 1);
949 + page0_write(offset + 1, ((value >> 8) & 0xff), 1);
950 + return;
953 + switch (offset) {
954 + case 0x1: // PSTART
955 + BX_NE2K_THIS s.page_start = value;
956 + break;
958 + case 0x2: // PSTOP
959 + // BX_INFO(("Writing to PSTOP: %02x", value));
960 + BX_NE2K_THIS s.page_stop = value;
961 + break;
963 + case 0x3: // BNRY
964 + BX_NE2K_THIS s.bound_ptr = value;
965 + break;
967 + case 0x4: // TPSR
968 + BX_NE2K_THIS s.tx_page_start = value;
969 + break;
971 + case 0x5: // TBCR0
972 + // Clear out low byte and re-insert
973 + BX_NE2K_THIS s.tx_bytes &= 0xff00;
974 + BX_NE2K_THIS s.tx_bytes |= (value & 0xff);
975 + break;
977 + case 0x6: // TBCR1
978 + // Clear out high byte and re-insert
979 + BX_NE2K_THIS s.tx_bytes &= 0x00ff;
980 + BX_NE2K_THIS s.tx_bytes |= ((value & 0xff) << 8);
981 + break;
983 + case 0x7: // ISR
984 + value &= 0x7f; // clear RST bit - status-only bit
985 + // All other values are cleared iff the ISR bit is 1
986 + BX_NE2K_THIS s.ISR.pkt_rx &= ~((bx_bool)((value & 0x01) == 0x01));
987 + BX_NE2K_THIS s.ISR.pkt_tx &= ~((bx_bool)((value & 0x02) == 0x02));
988 + BX_NE2K_THIS s.ISR.rx_err &= ~((bx_bool)((value & 0x04) == 0x04));
989 + BX_NE2K_THIS s.ISR.tx_err &= ~((bx_bool)((value & 0x08) == 0x08));
990 + BX_NE2K_THIS s.ISR.overwrite &= ~((bx_bool)((value & 0x10) == 0x10));
991 + BX_NE2K_THIS s.ISR.cnt_oflow &= ~((bx_bool)((value & 0x20) == 0x20));
992 + BX_NE2K_THIS s.ISR.rdma_done &= ~((bx_bool)((value & 0x40) == 0x40));
993 + value = ((BX_NE2K_THIS s.ISR.rdma_done << 6) |
994 + (BX_NE2K_THIS s.ISR.cnt_oflow << 5) |
995 + (BX_NE2K_THIS s.ISR.overwrite << 4) |
996 + (BX_NE2K_THIS s.ISR.tx_err << 3) |
997 + (BX_NE2K_THIS s.ISR.rx_err << 2) |
998 + (BX_NE2K_THIS s.ISR.pkt_tx << 1) |
999 + (BX_NE2K_THIS s.ISR.pkt_rx));
1000 + value &= ((BX_NE2K_THIS s.IMR.rdma_inte << 6) |
1001 + (BX_NE2K_THIS s.IMR.cofl_inte << 5) |
1002 + (BX_NE2K_THIS s.IMR.overw_inte << 4) |
1003 + (BX_NE2K_THIS s.IMR.txerr_inte << 3) |
1004 + (BX_NE2K_THIS s.IMR.rxerr_inte << 2) |
1005 + (BX_NE2K_THIS s.IMR.tx_inte << 1) |
1006 + (BX_NE2K_THIS s.IMR.rx_inte));
1007 + if (value == 0)
1008 + PIC_DeActivateIRQ(s.base_irq);
1009 + //DEV_pic_lower_irq(BX_NE2K_THIS s.base_irq);
1010 + break;
1012 + case 0x8: // RSAR0
1013 + // Clear out low byte and re-insert
1014 + BX_NE2K_THIS s.remote_start &= 0xff00;
1015 + BX_NE2K_THIS s.remote_start |= (value & 0xff);
1016 + BX_NE2K_THIS s.remote_dma = BX_NE2K_THIS s.remote_start;
1017 + break;
1019 + case 0x9: // RSAR1
1020 + // Clear out high byte and re-insert
1021 + BX_NE2K_THIS s.remote_start &= 0x00ff;
1022 + BX_NE2K_THIS s.remote_start |= ((value & 0xff) << 8);
1023 + BX_NE2K_THIS s.remote_dma = BX_NE2K_THIS s.remote_start;
1024 + break;
1026 + case 0xa: // RBCR0
1027 + // Clear out low byte and re-insert
1028 + BX_NE2K_THIS s.remote_bytes &= 0xff00;
1029 + BX_NE2K_THIS s.remote_bytes |= (value & 0xff);
1030 + break;
1032 + case 0xb: // RBCR1
1033 + // Clear out high byte and re-insert
1034 + BX_NE2K_THIS s.remote_bytes &= 0x00ff;
1035 + BX_NE2K_THIS s.remote_bytes |= ((value & 0xff) << 8);
1036 + break;
1038 + case 0xc: // RCR
1039 + // Check if the reserved bits are set
1040 + if (value & 0xc0)
1041 + BX_INFO(("RCR write, reserved bits set"));
1043 + // Set all other bit-fields
1044 + BX_NE2K_THIS s.RCR.errors_ok = ((value & 0x01) == 0x01);
1045 + BX_NE2K_THIS s.RCR.runts_ok = ((value & 0x02) == 0x02);
1046 + BX_NE2K_THIS s.RCR.broadcast = ((value & 0x04) == 0x04);
1047 + BX_NE2K_THIS s.RCR.multicast = ((value & 0x08) == 0x08);
1048 + BX_NE2K_THIS s.RCR.promisc = ((value & 0x10) == 0x10);
1049 + BX_NE2K_THIS s.RCR.monitor = ((value & 0x20) == 0x20);
1051 + // Monitor bit is a little suspicious...
1052 + if (value & 0x20)
1053 + BX_INFO(("RCR write, monitor bit set!"));
1054 + break;
1056 + case 0xd: // TCR
1057 + // Check reserved bits
1058 + if (value & 0xe0)
1059 + BX_ERROR(("TCR write, reserved bits set"));
1061 + // Test loop mode (not supported)
1062 + if (value & 0x06) {
1063 + BX_NE2K_THIS s.TCR.loop_cntl = (value & 0x6) >> 1;
1064 + BX_INFO("TCR write, loop mode %d not supported", BX_NE2K_THIS s.TCR.loop_cntl);
1065 + } else {
1066 + BX_NE2K_THIS s.TCR.loop_cntl = 0;
1069 + // Inhibit-CRC not supported.
1070 + if (value & 0x01)
1071 + BX_PANIC(("TCR write, inhibit-CRC not supported"));
1073 + // Auto-transmit disable very suspicious
1074 + if (value & 0x08)
1075 + BX_PANIC(("TCR write, auto transmit disable not supported"));
1077 + // Allow collision-offset to be set, although not used
1078 + BX_NE2K_THIS s.TCR.coll_prio = ((value & 0x08) == 0x08);
1079 + break;
1081 + case 0xe: // DCR
1082 + // the loopback mode is not suppported yet
1083 + if (!(value & 0x08)) {
1084 + BX_ERROR(("DCR write, loopback mode selected"));
1086 + // It is questionable to set longaddr and auto_rx, since they
1087 + // aren't supported on the ne2000. Print a warning and continue
1088 + if (value & 0x04)
1089 + BX_INFO(("DCR write - LAS set ???"));
1090 + if (value & 0x10)
1091 + BX_INFO(("DCR write - AR set ???"));
1093 + // Set other values.
1094 + BX_NE2K_THIS s.DCR.wdsize = ((value & 0x01) == 0x01);
1095 + BX_NE2K_THIS s.DCR.endian = ((value & 0x02) == 0x02);
1096 + BX_NE2K_THIS s.DCR.longaddr = ((value & 0x04) == 0x04); // illegal ?
1097 + BX_NE2K_THIS s.DCR.loop = ((value & 0x08) == 0x08);
1098 + BX_NE2K_THIS s.DCR.auto_rx = ((value & 0x10) == 0x10); // also illegal ?
1099 + BX_NE2K_THIS s.DCR.fifo_size = (value & 0x50) >> 5;
1100 + break;
1102 + case 0xf: // IMR
1103 + // Check for reserved bit
1104 + if (value & 0x80)
1105 + BX_PANIC(("IMR write, reserved bit set"));
1107 + // Set other values
1108 + BX_NE2K_THIS s.IMR.rx_inte = ((value & 0x01) == 0x01);
1109 + BX_NE2K_THIS s.IMR.tx_inte = ((value & 0x02) == 0x02);
1110 + BX_NE2K_THIS s.IMR.rxerr_inte = ((value & 0x04) == 0x04);
1111 + BX_NE2K_THIS s.IMR.txerr_inte = ((value & 0x08) == 0x08);
1112 + BX_NE2K_THIS s.IMR.overw_inte = ((value & 0x10) == 0x10);
1113 + BX_NE2K_THIS s.IMR.cofl_inte = ((value & 0x20) == 0x20);
1114 + BX_NE2K_THIS s.IMR.rdma_inte = ((value & 0x40) == 0x40);
1115 + if(BX_NE2K_THIS s.ISR.pkt_tx && BX_NE2K_THIS s.IMR.tx_inte) {
1116 + LOG_MSG("tx irq retrigger");
1117 + PIC_ActivateIRQ(s.base_irq);
1119 + break;
1120 + default:
1121 + BX_PANIC("page 0 write, bad offset %0x", offset);
1127 +// page1_read/page1_write - These routines handle reads/writes to
1128 +// the first page of the DS8390 register file
1130 +Bit32u
1131 +bx_ne2k_c::page1_read(Bit32u offset, unsigned int io_len)
1133 + BX_DEBUG("page 1 read from port %04x, len=%u", (unsigned) offset,
1134 + (unsigned) io_len);
1135 + if (io_len > 1)
1136 + BX_PANIC("bad length! page 1 read from port %04x, len=%u", (unsigned) offset,
1137 + (unsigned) io_len);
1139 + switch (offset) {
1140 + case 0x1: // PAR0-5
1141 + case 0x2:
1142 + case 0x3:
1143 + case 0x4:
1144 + case 0x5:
1145 + case 0x6:
1146 + return (BX_NE2K_THIS s.physaddr[offset - 1]);
1147 + break;
1149 + case 0x7: // CURR
1150 + BX_DEBUG("returning current page: %02x", (BX_NE2K_THIS s.curr_page));
1151 + return (BX_NE2K_THIS s.curr_page);
1153 + case 0x8: // MAR0-7
1154 + case 0x9:
1155 + case 0xa:
1156 + case 0xb:
1157 + case 0xc:
1158 + case 0xd:
1159 + case 0xe:
1160 + case 0xf:
1161 + return (BX_NE2K_THIS s.mchash[offset - 8]);
1162 + break;
1164 + default:
1165 + BX_PANIC("page 1 r offset %04x out of range", (unsigned) offset);
1168 + return (0);
1171 +void
1172 +bx_ne2k_c::page1_write(Bit32u offset, Bit32u value, unsigned io_len)
1174 + BX_DEBUG("page 1 w offset %04x", (unsigned) offset);
1175 + switch (offset) {
1176 + case 0x1: // PAR0-5
1177 + case 0x2:
1178 + case 0x3:
1179 + case 0x4:
1180 + case 0x5:
1181 + case 0x6:
1182 + BX_NE2K_THIS s.physaddr[offset - 1] = value;
1183 + break;
1185 + case 0x7: // CURR
1186 + BX_NE2K_THIS s.curr_page = value;
1187 + break;
1189 + case 0x8: // MAR0-7
1190 + case 0x9:
1191 + case 0xa:
1192 + case 0xb:
1193 + case 0xc:
1194 + case 0xd:
1195 + case 0xe:
1196 + case 0xf:
1197 + BX_NE2K_THIS s.mchash[offset - 8] = value;
1198 + break;
1200 + default:
1201 + BX_PANIC("page 1 w offset %04x out of range", (unsigned) offset);
1202 + }
1207 +// page2_read/page2_write - These routines handle reads/writes to
1208 +// the second page of the DS8390 register file
1210 +Bit32u
1211 +bx_ne2k_c::page2_read(Bit32u offset, unsigned int io_len)
1213 + BX_DEBUG("page 2 read from port %04x, len=%u", (unsigned) offset, (unsigned) io_len);
1215 + if (io_len > 1)
1216 + BX_PANIC("bad length! page 2 read from port %04x, len=%u", (unsigned) offset, (unsigned) io_len);
1218 + switch (offset) {
1219 + case 0x1: // PSTART
1220 + return (BX_NE2K_THIS s.page_start);
1221 + break;
1223 + case 0x2: // PSTOP
1224 + return (BX_NE2K_THIS s.page_stop);
1225 + break;
1227 + case 0x3: // Remote Next-packet pointer
1228 + return (BX_NE2K_THIS s.rempkt_ptr);
1229 + break;
1231 + case 0x4: // TPSR
1232 + return (BX_NE2K_THIS s.tx_page_start);
1233 + break;
1235 + case 0x5: // Local Next-packet pointer
1236 + return (BX_NE2K_THIS s.localpkt_ptr);
1237 + break;
1239 + case 0x6: // Address counter (upper)
1240 + return (BX_NE2K_THIS s.address_cnt >> 8);
1241 + break;
1243 + case 0x7: // Address counter (lower)
1244 + return (BX_NE2K_THIS s.address_cnt & 0xff);
1245 + break;
1247 + case 0x8: // Reserved
1248 + case 0x9:
1249 + case 0xa:
1250 + case 0xb:
1251 + BX_ERROR("reserved read - page 2, 0x%02x", (unsigned) offset);
1252 + return (0xff);
1253 + break;
1255 + case 0xc: // RCR
1256 + return ((BX_NE2K_THIS s.RCR.monitor << 5) |
1257 + (BX_NE2K_THIS s.RCR.promisc << 4) |
1258 + (BX_NE2K_THIS s.RCR.multicast << 3) |
1259 + (BX_NE2K_THIS s.RCR.broadcast << 2) |
1260 + (BX_NE2K_THIS s.RCR.runts_ok << 1) |
1261 + (BX_NE2K_THIS s.RCR.errors_ok));
1262 + break;
1264 + case 0xd: // TCR
1265 + return ((BX_NE2K_THIS s.TCR.coll_prio << 4) |
1266 + (BX_NE2K_THIS s.TCR.ext_stoptx << 3) |
1267 + ((BX_NE2K_THIS s.TCR.loop_cntl & 0x3) << 1) |
1268 + (BX_NE2K_THIS s.TCR.crc_disable));
1269 + break;
1271 + case 0xe: // DCR
1272 + return (((BX_NE2K_THIS s.DCR.fifo_size & 0x3) << 5) |
1273 + (BX_NE2K_THIS s.DCR.auto_rx << 4) |
1274 + (BX_NE2K_THIS s.DCR.loop << 3) |
1275 + (BX_NE2K_THIS s.DCR.longaddr << 2) |
1276 + (BX_NE2K_THIS s.DCR.endian << 1) |
1277 + (BX_NE2K_THIS s.DCR.wdsize));
1278 + break;
1280 + case 0xf: // IMR
1281 + return ((BX_NE2K_THIS s.IMR.rdma_inte << 6) |
1282 + (BX_NE2K_THIS s.IMR.cofl_inte << 5) |
1283 + (BX_NE2K_THIS s.IMR.overw_inte << 4) |
1284 + (BX_NE2K_THIS s.IMR.txerr_inte << 3) |
1285 + (BX_NE2K_THIS s.IMR.rxerr_inte << 2) |
1286 + (BX_NE2K_THIS s.IMR.tx_inte << 1) |
1287 + (BX_NE2K_THIS s.IMR.rx_inte));
1288 + break;
1290 + default:
1291 + BX_PANIC("page 2 offset %04x out of range", (unsigned) offset);
1294 + return (0);
1297 +void
1298 +bx_ne2k_c::page2_write(Bit32u offset, Bit32u value, unsigned io_len)
1300 + // Maybe all writes here should be BX_PANIC()'d, since they
1301 + // affect internal operation, but let them through for now
1302 + // and print a warning.
1303 + if (offset != 0)
1304 + BX_ERROR(("page 2 write ?"));
1306 + switch (offset) {
1307 + case 0x1: // CLDA0
1308 + // Clear out low byte and re-insert
1309 + BX_NE2K_THIS s.local_dma &= 0xff00;
1310 + BX_NE2K_THIS s.local_dma |= (value & 0xff);
1311 + break;
1313 + case 0x2: // CLDA1
1314 + // Clear out high byte and re-insert
1315 + BX_NE2K_THIS s.local_dma &= 0x00ff;
1316 + BX_NE2K_THIS s.local_dma |= ((value & 0xff) << 8);
1317 + break;
1319 + case 0x3: // Remote Next-pkt pointer
1320 + BX_NE2K_THIS s.rempkt_ptr = value;
1321 + break;
1323 + case 0x4:
1324 + BX_PANIC(("page 2 write to reserved offset 4"));
1325 + break;
1327 + case 0x5: // Local Next-packet pointer
1328 + BX_NE2K_THIS s.localpkt_ptr = value;
1329 + break;
1331 + case 0x6: // Address counter (upper)
1332 + // Clear out high byte and re-insert
1333 + BX_NE2K_THIS s.address_cnt &= 0x00ff;
1334 + BX_NE2K_THIS s.address_cnt |= ((value & 0xff) << 8);
1335 + break;
1337 + case 0x7: // Address counter (lower)
1338 + // Clear out low byte and re-insert
1339 + BX_NE2K_THIS s.address_cnt &= 0xff00;
1340 + BX_NE2K_THIS s.address_cnt |= (value & 0xff);
1341 + break;
1343 + case 0x8:
1344 + case 0x9:
1345 + case 0xa:
1346 + case 0xb:
1347 + case 0xc:
1348 + case 0xd:
1349 + case 0xe:
1350 + case 0xf:
1351 + BX_PANIC("page 2 write to reserved offset %0x", offset);
1352 + break;
1354 + default:
1355 + BX_PANIC("page 2 write, illegal offset %0x", offset);
1356 + break;
1361 +// page3_read/page3_write - writes to this page are illegal
1363 +Bit32u
1364 +bx_ne2k_c::page3_read(Bit32u offset, unsigned int io_len)
1366 + BX_PANIC(("page 3 read attempted"));
1367 + return (0);
1370 +void
1371 +bx_ne2k_c::page3_write(Bit32u offset, Bit32u value, unsigned io_len)
1373 + BX_PANIC(("page 3 write attempted"));
1377 +// tx_timer_handler/tx_timer
1379 +void
1380 +bx_ne2k_c::tx_timer_handler(void *this_ptr)
1382 + bx_ne2k_c *class_ptr = (bx_ne2k_c *) this_ptr;
1384 + class_ptr->tx_timer();
1387 +void
1388 +bx_ne2k_c::tx_timer(void)
1390 + BX_DEBUG(("tx_timer"));
1391 + BX_NE2K_THIS s.TSR.tx_ok = 1;
1392 + // Generate an interrupt if not masked and not one in progress
1393 + if (BX_NE2K_THIS s.IMR.tx_inte && !BX_NE2K_THIS s.ISR.pkt_tx) {
1394 + //LOG_MSG("tx complete interrupt");
1395 + PIC_ActivateIRQ(s.base_irq);
1396 + //DEV_pic_raise_irq(BX_NE2K_THIS s.base_irq);
1397 + } //else LOG_MSG("no tx complete interrupt");
1398 + BX_NE2K_THIS s.ISR.pkt_tx = 1;
1399 + BX_NE2K_THIS s.tx_timer_active = 0;
1404 +// read_handler/read - i/o 'catcher' function called from BOCHS
1405 +// mainline when the CPU attempts a read in the i/o space registered
1406 +// by this ne2000 instance
1408 +Bit32u bx_ne2k_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
1410 +#if !BX_USE_NE2K_SMF
1411 + bx_ne2k_c *class_ptr = (bx_ne2k_c *) this_ptr;
1413 + return( class_ptr->read(address, io_len) );
1416 +Bit32u bx_ne2k_c::read(Bit32u address, unsigned io_len)
1418 +#else
1419 + UNUSED(this_ptr);
1420 +#endif // !BX_USE_NE2K_SMF
1421 + BX_DEBUG("read addr %x, len %d", address, io_len);
1422 + Bit32u retval = 0;
1423 + int offset = address - BX_NE2K_THIS s.base_address;
1425 + if (offset >= 0x10) {
1426 + retval = asic_read(offset - 0x10, io_len);
1427 + } else if (offset == 0x00) {
1428 + retval = read_cr();
1429 + } else {
1430 + switch (BX_NE2K_THIS s.CR.pgsel) {
1431 + case 0x00:
1432 + retval = page0_read(offset, io_len);
1433 + break;
1435 + case 0x01:
1436 + retval = page1_read(offset, io_len);
1437 + break;
1439 + case 0x02:
1440 + retval = page2_read(offset, io_len);
1441 + break;
1443 + case 0x03:
1444 + retval = page3_read(offset, io_len);
1445 + break;
1447 + default:
1448 + BX_PANIC("ne2K: unknown value of pgsel in read - %d",
1449 + BX_NE2K_THIS s.CR.pgsel);
1453 + return (retval);
1457 +// write_handler/write - i/o 'catcher' function called from BOCHS
1458 +// mainline when the CPU attempts a write in the i/o space registered
1459 +// by this ne2000 instance
1461 +void
1462 +bx_ne2k_c::write_handler(void *this_ptr, Bit32u address, Bit32u value,
1463 + unsigned io_len)
1465 +#if !BX_USE_NE2K_SMF
1466 + bx_ne2k_c *class_ptr = (bx_ne2k_c *) this_ptr;
1468 + class_ptr->write(address, value, io_len);
1471 +void
1472 +bx_ne2k_c::write(Bit32u address, Bit32u value, unsigned io_len)
1474 +#else
1475 + UNUSED(this_ptr);
1476 +#endif // !BX_USE_NE2K_SMF
1477 + BX_DEBUG("write with length %d", io_len);
1478 + int offset = address - BX_NE2K_THIS s.base_address;
1480 + //
1481 + // The high 16 bytes of i/o space are for the ne2000 asic -
1482 + // the low 16 bytes are for the DS8390, with the current
1483 + // page being selected by the PS0,PS1 registers in the
1484 + // command register
1485 + //
1486 + if (offset >= 0x10) {
1487 + asic_write(offset - 0x10, value, io_len);
1488 + } else if (offset == 0x00) {
1489 + write_cr(value);
1490 + } else {
1491 + switch (BX_NE2K_THIS s.CR.pgsel) {
1492 + case 0x00:
1493 + page0_write(offset, value, io_len);
1494 + break;
1496 + case 0x01:
1497 + page1_write(offset, value, io_len);
1498 + break;
1500 + case 0x02:
1501 + page2_write(offset, value, io_len);
1502 + break;
1504 + case 0x03:
1505 + page3_write(offset, value, io_len);
1506 + break;
1508 + default:
1509 + BX_PANIC("ne2K: unknown value of pgsel in write - %d",
1510 + BX_NE2K_THIS s.CR.pgsel);
1517 + * mcast_index() - return the 6-bit index into the multicast
1518 + * table. Stolen unashamedly from FreeBSD's if_ed.c
1519 + */
1520 +unsigned
1521 +bx_ne2k_c::mcast_index(const void *dst)
1523 +#define POLYNOMIAL 0x04c11db6
1524 + unsigned long crc = 0xffffffffL;
1525 + int carry, i, j;
1526 + unsigned char b;
1527 + unsigned char *ep = (unsigned char *) dst;
1529 + for (i = 6; --i >= 0;) {
1530 + b = *ep++;
1531 + for (j = 8; --j >= 0;) {
1532 + carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
1533 + crc <<= 1;
1534 + b >>= 1;
1535 + if (carry)
1536 + crc = ((crc ^ POLYNOMIAL) | carry);
1539 + return (crc >> 26);
1540 +#undef POLYNOMIAL
1544 + * Callback from the eth system driver when a frame has arrived
1545 + */
1547 +void
1548 +bx_ne2k_c::rx_handler(void *arg, const void *buf, unsigned len)
1550 + // BX_DEBUG(("rx_handler with length %d", len));
1551 + bx_ne2k_c *class_ptr = (bx_ne2k_c *) arg;
1552 + if(
1553 + class_ptr->rx_frame(buf, len);
1557 + * rx_frame() - called by the platform-specific code when an
1558 + * ethernet frame has been received. The destination address
1559 + * is tested to see if it should be accepted, and if the
1560 + * rx ring has enough room, it is copied into it and
1561 + * the receive process is updated
1562 + */
1563 +void
1564 +bx_ne2k_c::rx_frame(const void *buf, unsigned io_len)
1566 + int pages;
1567 + int avail;
1568 + unsigned idx;
1569 + int wrapped;
1570 + int nextpage;
1571 + unsigned char pkthdr[4];
1572 + unsigned char *pktbuf = (unsigned char *) buf;
1573 + unsigned char *startptr;
1574 + static unsigned char bcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
1576 + if(io_len != 60) {
1577 + BX_DEBUG("rx_frame with length %d", io_len);
1580 + //LOG_MSG("stop=%d, pagestart=%x, dcr_loop=%x, tcr_loopcntl=%x",
1581 + // BX_NE2K_THIS s.CR.stop, BX_NE2K_THIS s.page_start,
1582 + // BX_NE2K_THIS s.DCR.loop, BX_NE2K_THIS s.TCR.loop_cntl);
1583 + if ((BX_NE2K_THIS s.CR.stop != 0) ||
1584 + (BX_NE2K_THIS s.page_start == 0) /*||
1585 + ((BX_NE2K_THIS s.DCR.loop == 0) &&
1586 + (BX_NE2K_THIS s.TCR.loop_cntl != 0))*/) {
1587 + return;
1590 + // Add the pkt header + CRC to the length, and work
1591 + // out how many 256-byte pages the frame would occupy
1592 + pages = (io_len + 4 + 4 + 255)/256;
1594 + if (BX_NE2K_THIS s.curr_page < BX_NE2K_THIS s.bound_ptr) {
1595 + avail = BX_NE2K_THIS s.bound_ptr - BX_NE2K_THIS s.curr_page;
1596 + } else {
1597 + avail = (BX_NE2K_THIS s.page_stop - BX_NE2K_THIS s.page_start) -
1598 + (BX_NE2K_THIS s.curr_page - BX_NE2K_THIS s.bound_ptr);
1599 + wrapped = 1;
1602 + // Avoid getting into a buffer overflow condition by not attempting
1603 + // to do partial receives. The emulation to handle this condition
1604 + // seems particularly painful.
1605 + if ((avail < pages)
1606 +#if BX_NE2K_NEVER_FULL_RING
1607 + || (avail == pages)
1608 +#endif
1609 + ) {
1610 + BX_DEBUG("no space");
1611 + return;
1614 + if ((io_len < 40/*60*/) && !BX_NE2K_THIS s.RCR.runts_ok) {
1615 + BX_DEBUG("rejected small packet, length %d", io_len);
1616 + return;
1618 + // some computers don't care...
1619 + if (io_len < 60) io_len=60;
1621 + // Do address filtering if not in promiscuous mode
1622 + if (! BX_NE2K_THIS s.RCR.promisc) {
1623 + if (!memcmp(buf, bcast_addr, 6)) {
1624 + if (!BX_NE2K_THIS s.RCR.broadcast) {
1625 + return;
1627 + } else if (pktbuf[0] & 0x01) {
1628 + if (! BX_NE2K_THIS s.RCR.multicast) {
1629 + return;
1631 + idx = mcast_index(buf);
1632 + if (!(BX_NE2K_THIS s.mchash[idx >> 3] & (1 << (idx & 0x7)))) {
1633 + return;
1635 + } else if (0 != memcmp(buf, BX_NE2K_THIS s.physaddr, 6)) {
1636 + return;
1638 + } else {
1639 + BX_DEBUG(("rx_frame promiscuous receive"));
1642 + BX_INFO("rx_frame %d to %x:%x:%x:%x:%x:%x from %x:%x:%x:%x:%x:%x",
1643 + io_len,
1644 + pktbuf[0], pktbuf[1], pktbuf[2], pktbuf[3], pktbuf[4], pktbuf[5],
1645 + pktbuf[6], pktbuf[7], pktbuf[8], pktbuf[9], pktbuf[10], pktbuf[11]);
1647 + nextpage = BX_NE2K_THIS s.curr_page + pages;
1648 + if (nextpage >= BX_NE2K_THIS s.page_stop) {
1649 + nextpage -= BX_NE2K_THIS s.page_stop - BX_NE2K_THIS s.page_start;
1652 + // Setup packet header
1653 + pkthdr[0] = 0; // rx status - old behavior
1654 + pkthdr[0] = 1; // Probably better to set it all the time
1655 + // rather than set it to 0, which is clearly wrong.
1656 + if (pktbuf[0] & 0x01) {
1657 + pkthdr[0] |= 0x20; // rx status += multicast packet
1659 + pkthdr[1] = nextpage; // ptr to next packet
1660 + pkthdr[2] = (io_len + 4) & 0xff; // length-low
1661 + pkthdr[3] = (io_len + 4) >> 8; // length-hi
1663 + // copy into buffer, update curpage, and signal interrupt if config'd
1664 + startptr = & BX_NE2K_THIS s.mem[BX_NE2K_THIS s.curr_page * 256 -
1665 + BX_NE2K_MEMSTART];
1666 + if ((nextpage > BX_NE2K_THIS s.curr_page) ||
1667 + ((BX_NE2K_THIS s.curr_page + pages) == BX_NE2K_THIS s.page_stop)) {
1668 + memcpy(startptr, pkthdr, 4);
1669 + memcpy(startptr + 4, buf, io_len);
1670 + BX_NE2K_THIS s.curr_page = nextpage;
1671 + } else {
1672 + int endbytes = (BX_NE2K_THIS s.page_stop - BX_NE2K_THIS s.curr_page)
1673 + * 256;
1674 + memcpy(startptr, pkthdr, 4);
1675 + memcpy(startptr + 4, buf, endbytes - 4);
1676 + startptr = & BX_NE2K_THIS s.mem[BX_NE2K_THIS s.page_start * 256 -
1677 + BX_NE2K_MEMSTART];
1678 + memcpy(startptr, (void *)(pktbuf + endbytes - 4),
1679 + io_len - endbytes + 8);
1680 + BX_NE2K_THIS s.curr_page = nextpage;
1683 + BX_NE2K_THIS s.RSR.rx_ok = 1;
1684 + if (pktbuf[0] & 0x80) {
1685 + BX_NE2K_THIS s.RSR.rx_mbit = 1;
1688 + BX_NE2K_THIS s.ISR.pkt_rx = 1;
1690 + if (BX_NE2K_THIS s.IMR.rx_inte) {
1691 + //LOG_MSG("packet rx interrupt");
1692 + PIC_ActivateIRQ(s.base_irq);
1693 + //DEV_pic_raise_irq(BX_NE2K_THIS s.base_irq);
1694 + } //else LOG_MSG("no packet rx interrupt");
1698 +//Bit8u macaddr[6] = { 0xAC, 0xDE, 0x48, 0x8E, 0x89, 0x19 };
1700 +Bitu dosbox_read(Bitu port, Bitu len) {
1701 + Bitu retval = theNE2kDevice->read(port,len);
1702 + //LOG_MSG("ne2k rd port %x val %4x len %d page %d, CS:IP %8x:%8x",
1703 + // port, retval, len, theNE2kDevice->s.CR.pgsel,SegValue(cs),reg_eip);
1704 + return retval;
1706 +void dosbox_write(Bitu port, Bitu val, Bitu len) {
1707 + //LOG_MSG("ne2k wr port %x val %4x len %d page %d, CS:IP %8x:%8x",
1708 + // port, val, len,theNE2kDevice->s.CR.pgsel,SegValue(cs),reg_eip);
1709 + theNE2kDevice->write(port, val, len);
1712 +void bx_ne2k_c::init()
1714 + //BX_DEBUG(("Init $Id: ne2k.cc,v 1.56.2.1 2004/02/02 22:37:22 cbothamy Exp $"));
1716 + // Read in values from config file
1717 + //BX_NE2K_THIS s.base_address = 0x300;
1718 + //BX_NE2K_THIS s.base_irq = 3;
1719 + /*
1720 + if (BX_NE2K_THIS s.tx_timer_index == BX_NULL_TIMER_HANDLE) {
1721 + BX_NE2K_THIS s.tx_timer_index =
1722 + bx_pc_system.register_timer(this, tx_timer_handler, 0,
1723 + 0,0, "ne2k"); // one-shot, inactive
1724 + }*/
1725 + // Register the IRQ and i/o port addresses
1726 + //DEV_register_irq(BX_NE2K_THIS s.base_irq, "NE2000 ethernet NIC");
1728 + //DEV_register_ioread_handler(this, read_handler, addr, "ne2000 NIC", 3);
1729 + //DEV_register_iowrite_handler(this, write_handler, addr, "ne2000 NIC", 3);
1732 + BX_INFO("port 0x%x/32 irq %d mac %02x:%02x:%02x:%02x:%02x:%02x",
1733 + BX_NE2K_THIS s.base_address,
1734 + BX_NE2K_THIS s.base_irq,
1735 + BX_NE2K_THIS s.physaddr[0],
1736 + BX_NE2K_THIS s.physaddr[1],
1737 + BX_NE2K_THIS s.physaddr[2],
1738 + BX_NE2K_THIS s.physaddr[3],
1739 + BX_NE2K_THIS s.physaddr[4],
1740 + BX_NE2K_THIS s.physaddr[5]);
1742 + // Initialise the mac address area by doubling the physical address
1743 + BX_NE2K_THIS s.macaddr[0] = BX_NE2K_THIS s.physaddr[0];
1744 + BX_NE2K_THIS s.macaddr[1] = BX_NE2K_THIS s.physaddr[0];
1745 + BX_NE2K_THIS s.macaddr[2] = BX_NE2K_THIS s.physaddr[1];
1746 + BX_NE2K_THIS s.macaddr[3] = BX_NE2K_THIS s.physaddr[1];
1747 + BX_NE2K_THIS s.macaddr[4] = BX_NE2K_THIS s.physaddr[2];
1748 + BX_NE2K_THIS s.macaddr[5] = BX_NE2K_THIS s.physaddr[2];
1749 + BX_NE2K_THIS s.macaddr[6] = BX_NE2K_THIS s.physaddr[3];
1750 + BX_NE2K_THIS s.macaddr[7] = BX_NE2K_THIS s.physaddr[3];
1751 + BX_NE2K_THIS s.macaddr[8] = BX_NE2K_THIS s.physaddr[4];
1752 + BX_NE2K_THIS s.macaddr[9] = BX_NE2K_THIS s.physaddr[4];
1753 + BX_NE2K_THIS s.macaddr[10] = BX_NE2K_THIS s.physaddr[5];
1754 + BX_NE2K_THIS s.macaddr[11] = BX_NE2K_THIS s.physaddr[5];
1756 + // ne2k signature
1757 + for (Bitu i = 12; i < 32; i++)
1758 + BX_NE2K_THIS s.macaddr[i] = 0x57;
1760 + // Bring the register state into power-up state
1761 + reset(BX_RESET_HARDWARE);
1764 +static void NE2000_TX_Event(Bitu val) {
1765 + theNE2kDevice->tx_timer();
1768 +static void NE2000_Poller(void) {
1769 + int res;
1770 + struct pcap_pkthdr *header;
1771 + u_char *pkt_data;
1772 +//#if 0
1773 + while((res = pcap_next_ex( adhandle, &header, (const u_char **)&pkt_data)) > 0) {
1774 + //LOG_MSG("NE2000: Received %d bytes", header->len);
1776 + // don't receive in loopback modes
1777 + if((theNE2kDevice->s.DCR.loop == 0) || (theNE2kDevice->s.TCR.loop_cntl != 0))
1778 + return;
1779 + theNE2kDevice->rx_frame(pkt_data, header->len);
1781 +//#endif
1783 +#ifdef WIN32
1784 +#include <windows.h>
1785 +#endif
1787 +class NE2K: public Module_base {
1788 +private:
1789 + // Data
1790 + IO_ReadHandleObject ReadHandler8[0x20];
1791 + IO_WriteHandleObject WriteHandler8[0x20];
1792 + IO_ReadHandleObject ReadHandler16[0x10];
1793 + IO_WriteHandleObject WriteHandler16[0x10];
1795 +public:
1796 + bool load_success;
1797 + NE2K(Section* configuration):Module_base(configuration) {
1798 + Section_prop * section=static_cast<Section_prop *>(configuration);
1800 + load_success = true;
1801 + // enabled?
1803 + if(!section->Get_bool("ne2000")) {
1804 + load_success = false;
1805 + return;
1808 +#ifdef WIN32
1809 +/*
1810 + int (*PacketSendPacket)(pcap_t *, const u_char *, int);
1811 + void (*PacketClose)(pcap_t *);
1812 + void (*PacketFreealldevs)(pcap_if_t *);
1813 + pcap_t* (*PacketOpen)(char const *,int,int,int,struct pcap_rmtauth *,char *);
1814 + int (*PacketNextEx)(pcap_t *, struct pcap_pkthdr **, const u_char **);
1815 + int (*PacketFindALlDevsEx)(char *, struct pcap_rmtauth *, pcap_if_t **, char *);
1817 + // init the library
1818 + HINSTANCE pcapinst;
1819 + pcapinst = LoadLibrary("WPCAP.DLL");
1820 + if(pcapinst==NULL) {
1821 + LOG_MSG("WinPcap has to be installed for the NE2000 to work.");
1822 + load_success = false;
1823 + return;
1825 + FARPROC psp;
1827 + psp = GetProcAddress(pcapinst,"pcap_sendpacket");
1828 + if(!PacketSendPacket) PacketSendPacket =
1829 + (int (__cdecl *)(pcap_t *,const u_char *,int))psp;
1831 + psp = GetProcAddress(pcapinst,"pcap_close");
1832 + if(!PacketClose) PacketClose =
1833 + (void (__cdecl *)(pcap_t *)) psp;
1835 + psp = GetProcAddress(pcapinst,"pcap_freealldevs");
1836 + if(!PacketFreealldevs) PacketFreealldevs =
1837 + (void (__cdecl *)(pcap_if_t *)) psp;
1839 + psp = GetProcAddress(pcapinst,"pcap_open");
1840 + if(!PacketOpen) PacketOpen =
1841 + (pcap_t* (__cdecl *)(char const *,int,int,int,struct pcap_rmtauth *,char *)) psp;
1843 + psp = GetProcAddress(pcapinst,"pcap_next_ex");
1844 + if(!PacketNextEx) PacketNextEx =
1845 + (int (__cdecl *)(pcap_t *, struct pcap_pkthdr **, const u_char **)) psp;
1847 + psp = GetProcAddress(pcapinst,"pcap_findalldevs_ex");
1848 + if(!PacketFindALlDevsEx) PacketFindALlDevsEx =
1849 + (int (__cdecl *)(char *, struct pcap_rmtauth *, pcap_if_t **, char *)) psp;
1851 + if(PacketFindALlDevsEx==0 || PacketNextEx==0 || PacketOpen==0 ||
1852 + PacketFreealldevs==0 || PacketClose==0 || PacketSendPacket==0) {
1853 + LOG_MSG("Wrong WinPcap version or something");
1854 + load_success = false;
1855 + return;
1858 +#endif
1860 + // get irq and base
1861 + Bitu irq = section->Get_int("nicirq");
1862 + if(!(irq==3 || irq==4 || irq==5 || irq==6 ||irq==7 ||
1863 + irq==9 || irq==10 || irq==11 || irq==12 ||irq==14 ||irq==15)) {
1864 + irq=3;
1866 + Bitu base = section->Get_hex("nicbase");
1867 + if(!(base==0x260||base==0x280||base==0x300||base==0x320||base==0x340||base==0x380)) {
1868 + base=0x300;
1871 + // mac address
1872 + const char* macstring=section->Get_string("macaddr");
1873 + Bitu macint[6];
1874 + Bit8u mac[6];
1875 + if(sscanf(macstring,"%02x:%02x:%02x:%02x:%02x:%02x",
1876 + &macint[0],&macint[1],&macint[2],&macint[3],&macint[4],&macint[5]) != 6) {
1877 + mac[0]=0xac;mac[1]=0xde;mac[2]=0x48;
1878 + mac[3]=0x88;mac[4]=0xbb;mac[5]=0xaa;
1879 + } else {
1880 + mac[0]=macint[0]; mac[1]=macint[1];
1881 + mac[2]=macint[2]; mac[3]=macint[3];
1882 + mac[4]=macint[4]; mac[5]=macint[5];
1885 + // find out which pcap device to use
1886 + const char* realnicstring=section->Get_string("realnic");
1887 + pcap_if_t *alldevs;
1888 + pcap_if_t *currentdev = NULL;
1889 + char errbuf[PCAP_ERRBUF_SIZE];
1890 + Bitu userdev;
1891 +#ifdef WIN32
1892 + if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
1893 +#else
1894 + if (pcap_findalldevs(&alldevs, errbuf) == -1)
1895 +#endif
1897 + LOG_MSG("Cannot enumerate network interfaces: %s\n", errbuf);
1898 + load_success = false;
1899 + return;
1901 + if (!strcasecmp(realnicstring,"list")) {
1902 + // print list and quit
1903 + Bitu i = 0;
1904 + LOG_MSG("\nNetwork Interface List \n-----------------------------------");
1905 + for(currentdev=alldevs; currentdev!=NULL; currentdev=currentdev->next) {
1906 + const char* desc = "no description";
1907 + if(currentdev->description) desc=currentdev->description;
1908 + i++;
1909 + LOG_MSG("%2d. %s\n (%s)\n",i,currentdev->name,desc);
1911 + pcap_freealldevs(alldevs);
1912 + load_success = false;
1913 + return;
1914 + } else if(1==sscanf(realnicstring,"%u",&userdev)) {
1915 + // user passed us a number
1916 + Bitu i = 0;
1917 + currentdev=alldevs;
1918 + while(currentdev!=NULL) {
1919 + i++;
1920 + if(i==userdev) break;
1921 + else currentdev=currentdev->next;
1923 + } else {
1924 + // user might have passed a piece of name
1925 + for(currentdev=alldevs; currentdev!=NULL; currentdev=currentdev->next) {
1926 + if(strstr(currentdev->name,realnicstring)) {
1927 + break;
1928 + }else if(currentdev->description!=NULL &&
1929 + strstr(currentdev->description,realnicstring)) {
1930 + break;
1935 + if(currentdev==NULL) {
1936 + LOG_MSG("Unable to find network interface - check realnic parameter\n");
1937 + load_success = false;
1938 + pcap_freealldevs(alldevs);
1939 + return;
1941 + // print out which interface we are going to use
1942 + const char* desc = "no description";
1943 + if(currentdev->description) desc=currentdev->description;
1944 + LOG_MSG("Using Network interface:\n%s\n(%s)\n",currentdev->name,desc);
1946 + // attempt to open it
1947 +#ifdef WIN32
1948 + if ( (adhandle= pcap_open(
1949 + currentdev->name, // name of the device
1950 + 65536, // portion of the packet to capture
1951 + // 65536 = whole packet
1952 + PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode
1953 + -1, // read timeout
1954 + NULL, // authentication on the remote machine
1955 + errbuf // error buffer
1956 + ) ) == NULL)
1957 +#else
1958 + /*pcap_t *pcap_open_live(const char *device, int snaplen,
1959 + int promisc, int to_ms, char *errbuf)*/
1960 + if ( (adhandle= pcap_open_live(
1961 + currentdev->name, // name of the device
1962 + 65536, // portion of the packet to capture
1963 + // 65536 = whole packet
1964 + true, // promiscuous mode
1965 + -1, // read timeout
1966 + errbuf // error buffer
1967 + ) ) == NULL)
1969 +#endif
1971 + LOG_MSG("\nUnable to open the interface: %s.", errbuf);
1972 + pcap_freealldevs(alldevs);
1973 + load_success = false;
1974 + return;
1976 + pcap_freealldevs(alldevs);
1977 +#ifndef WIN32
1978 + pcap_setnonblock(adhandle,1,errbuf);
1979 +#endif
1980 + // create the bochs NIC class
1981 + theNE2kDevice = new bx_ne2k_c ();
1982 + memcpy(theNE2kDevice->s.physaddr, mac, 6);
1983 + theNE2kDevice->init();
1985 + theNE2kDevice->s.base_address=base;
1986 + theNE2kDevice->s.base_irq=irq;
1988 + // install I/O-handlers and timer
1989 + for(Bitu i = 0; i < 0x20; i++) {
1990 + ReadHandler8[i].Install((i+theNE2kDevice->s.base_address),
1991 + dosbox_read,IO_MB|IO_MW);
1992 + WriteHandler8[i].Install((i+theNE2kDevice->s.base_address),
1993 + dosbox_write,IO_MB|IO_MW);
1995 + TIMER_AddTickHandler(NE2000_Poller);
1996 + }
1998 + ~NE2K() {
1999 + if(adhandle) pcap_close(adhandle);
2000 + adhandle=0;
2001 + if(theNE2kDevice != 0) delete theNE2kDevice;
2002 + theNE2kDevice=0;
2003 + TIMER_DelTickHandler(NE2000_Poller);
2004 + PIC_RemoveEvents(NE2000_TX_Event);
2005 + }
2008 +static NE2K* test;
2009 +void NE2K_ShutDown(Section* sec) {
2010 + if(test) delete test;
2011 + test=0;
2014 +void NE2K_Init(Section* sec) {
2015 + test = new NE2K(sec);
2016 + sec->AddDestroyFunction(&NE2K_ShutDown,true);
2017 + if(!test->load_success) {
2018 + delete test;
2019 + test=0;
2023 +#endif // C_NE2000
2024 diff -urN dosbox.orig/src/platform/visualc/config.h dosbox/src/platform/visualc/config.h
2025 --- dosbox.orig/src/platform/visualc/config.h 2011-01-11 20:18:46.154832103 -0300
2026 +++ dosbox/src/platform/visualc/config.h 2011-01-11 20:28:09.718165438 -0300
2027 @@ -12,6 +12,9 @@
2028 /* Define to 1 to enable internal modem support, requires SDL_net */
2029 #define C_MODEM 1
2031 +/* Define to 1 to enable NE2000 ethernet passthrough, requires libpcap */
2032 +#define C_NE2000 1
2034 /* Define to 1 to enable IPX networking support, requires SDL_net */
2035 #define C_IPX 1
2037 diff -urN dosbox.orig/visualc_net/dosbox.vcproj dosbox/visualc_net/dosbox.vcproj
2038 --- dosbox.orig/visualc_net/dosbox.vcproj 2011-01-11 20:18:46.141498770 -0300
2039 +++ dosbox/visualc_net/dosbox.vcproj 2011-01-11 20:28:09.718165438 -0300
2040 @@ -481,6 +481,9 @@
2041 RelativePath="..\src\hardware\mixer.cpp">
2042 </File>
2043 <File
2044 + RelativePath="..\src\hardware\ne2000.cpp">
2045 + </File>
2046 + <File
2047 RelativePath="..\src\hardware\pic.cpp">
2048 </File>
2049 <File
2050 @@ -829,6 +832,9 @@
2051 RelativePath="..\include\mouse.h">
2052 </File>
2053 <File
2054 + RelativePath="..\include\ne2000.h">
2055 + </File>
2056 + <File
2057 RelativePath="..\include\paging.h">
2058 </File>
2059 <File