149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini * QEMU NE2000 emulation
349ab747fSPaolo Bonzini *
449ab747fSPaolo Bonzini * Copyright (c) 2003-2004 Fabrice Bellard
549ab747fSPaolo Bonzini *
649ab747fSPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy
749ab747fSPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal
849ab747fSPaolo Bonzini * in the Software without restriction, including without limitation the rights
949ab747fSPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1049ab747fSPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is
1149ab747fSPaolo Bonzini * furnished to do so, subject to the following conditions:
1249ab747fSPaolo Bonzini *
1349ab747fSPaolo Bonzini * The above copyright notice and this permission notice shall be included in
1449ab747fSPaolo Bonzini * all copies or substantial portions of the Software.
1549ab747fSPaolo Bonzini *
1649ab747fSPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1749ab747fSPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1849ab747fSPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1949ab747fSPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2049ab747fSPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2149ab747fSPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2249ab747fSPaolo Bonzini * THE SOFTWARE.
2349ab747fSPaolo Bonzini */
240b8fa32fSMarkus Armbruster
25e8d40465SPeter Maydell #include "qemu/osdep.h"
26084e2b11SMark Cave-Ayland #include "net/eth.h"
270b8fa32fSMarkus Armbruster #include "qemu/module.h"
28d4842052SMarkus Armbruster #include "exec/memory.h"
2964552b6bSMarkus Armbruster #include "hw/irq.h"
30d6454270SMarkus Armbruster #include "migration/vmstate.h"
3147b43a1fSPaolo Bonzini #include "ne2000.h"
32cd4479a9SPhilippe Mathieu-Daudé #include "trace.h"
3349ab747fSPaolo Bonzini
3449ab747fSPaolo Bonzini /* debug NE2000 card */
3549ab747fSPaolo Bonzini //#define DEBUG_NE2000
3649ab747fSPaolo Bonzini
3749ab747fSPaolo Bonzini #define MAX_ETH_FRAME_SIZE 1514
3849ab747fSPaolo Bonzini
3949ab747fSPaolo Bonzini #define E8390_CMD 0x00 /* The command register (for all pages) */
4049ab747fSPaolo Bonzini /* Page 0 register offsets. */
4149ab747fSPaolo Bonzini #define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */
4249ab747fSPaolo Bonzini #define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */
4349ab747fSPaolo Bonzini #define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */
4449ab747fSPaolo Bonzini #define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */
4549ab747fSPaolo Bonzini #define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */
4649ab747fSPaolo Bonzini #define EN0_TSR 0x04 /* Transmit status reg RD */
4749ab747fSPaolo Bonzini #define EN0_TPSR 0x04 /* Transmit starting page WR */
4849ab747fSPaolo Bonzini #define EN0_NCR 0x05 /* Number of collision reg RD */
4949ab747fSPaolo Bonzini #define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */
5049ab747fSPaolo Bonzini #define EN0_FIFO 0x06 /* FIFO RD */
5149ab747fSPaolo Bonzini #define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */
5249ab747fSPaolo Bonzini #define EN0_ISR 0x07 /* Interrupt status reg RD WR */
5349ab747fSPaolo Bonzini #define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */
5449ab747fSPaolo Bonzini #define EN0_RSARLO 0x08 /* Remote start address reg 0 */
5549ab747fSPaolo Bonzini #define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */
5649ab747fSPaolo Bonzini #define EN0_RSARHI 0x09 /* Remote start address reg 1 */
5749ab747fSPaolo Bonzini #define EN0_RCNTLO 0x0a /* Remote byte count reg WR */
5849ab747fSPaolo Bonzini #define EN0_RTL8029ID0 0x0a /* Realtek ID byte #1 RD */
5949ab747fSPaolo Bonzini #define EN0_RCNTHI 0x0b /* Remote byte count reg WR */
6049ab747fSPaolo Bonzini #define EN0_RTL8029ID1 0x0b /* Realtek ID byte #2 RD */
6149ab747fSPaolo Bonzini #define EN0_RSR 0x0c /* rx status reg RD */
6249ab747fSPaolo Bonzini #define EN0_RXCR 0x0c /* RX configuration reg WR */
6349ab747fSPaolo Bonzini #define EN0_TXCR 0x0d /* TX configuration reg WR */
6449ab747fSPaolo Bonzini #define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */
6549ab747fSPaolo Bonzini #define EN0_DCFG 0x0e /* Data configuration reg WR */
6649ab747fSPaolo Bonzini #define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */
6749ab747fSPaolo Bonzini #define EN0_IMR 0x0f /* Interrupt mask reg WR */
6849ab747fSPaolo Bonzini #define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */
6949ab747fSPaolo Bonzini
7049ab747fSPaolo Bonzini #define EN1_PHYS 0x11
7149ab747fSPaolo Bonzini #define EN1_CURPAG 0x17
7249ab747fSPaolo Bonzini #define EN1_MULT 0x18
7349ab747fSPaolo Bonzini
7449ab747fSPaolo Bonzini #define EN2_STARTPG 0x21 /* Starting page of ring bfr RD */
7549ab747fSPaolo Bonzini #define EN2_STOPPG 0x22 /* Ending page +1 of ring bfr RD */
7649ab747fSPaolo Bonzini
7749ab747fSPaolo Bonzini #define EN3_CONFIG0 0x33
7849ab747fSPaolo Bonzini #define EN3_CONFIG1 0x34
7949ab747fSPaolo Bonzini #define EN3_CONFIG2 0x35
8049ab747fSPaolo Bonzini #define EN3_CONFIG3 0x36
8149ab747fSPaolo Bonzini
8249ab747fSPaolo Bonzini /* Register accessed at EN_CMD, the 8390 base addr. */
8349ab747fSPaolo Bonzini #define E8390_STOP 0x01 /* Stop and reset the chip */
8449ab747fSPaolo Bonzini #define E8390_START 0x02 /* Start the chip, clear reset */
8549ab747fSPaolo Bonzini #define E8390_TRANS 0x04 /* Transmit a frame */
8649ab747fSPaolo Bonzini #define E8390_RREAD 0x08 /* Remote read */
8749ab747fSPaolo Bonzini #define E8390_RWRITE 0x10 /* Remote write */
8849ab747fSPaolo Bonzini #define E8390_NODMA 0x20 /* Remote DMA */
8949ab747fSPaolo Bonzini #define E8390_PAGE0 0x00 /* Select page chip registers */
9049ab747fSPaolo Bonzini #define E8390_PAGE1 0x40 /* using the two high-order bits */
9149ab747fSPaolo Bonzini #define E8390_PAGE2 0x80 /* Page 3 is invalid. */
9249ab747fSPaolo Bonzini
9349ab747fSPaolo Bonzini /* Bits in EN0_ISR - Interrupt status register */
9449ab747fSPaolo Bonzini #define ENISR_RX 0x01 /* Receiver, no error */
9549ab747fSPaolo Bonzini #define ENISR_TX 0x02 /* Transmitter, no error */
9649ab747fSPaolo Bonzini #define ENISR_RX_ERR 0x04 /* Receiver, with error */
9749ab747fSPaolo Bonzini #define ENISR_TX_ERR 0x08 /* Transmitter, with error */
9849ab747fSPaolo Bonzini #define ENISR_OVER 0x10 /* Receiver overwrote the ring */
9949ab747fSPaolo Bonzini #define ENISR_COUNTERS 0x20 /* Counters need emptying */
10049ab747fSPaolo Bonzini #define ENISR_RDC 0x40 /* remote dma complete */
10149ab747fSPaolo Bonzini #define ENISR_RESET 0x80 /* Reset completed */
10249ab747fSPaolo Bonzini #define ENISR_ALL 0x3f /* Interrupts we will enable */
10349ab747fSPaolo Bonzini
10449ab747fSPaolo Bonzini /* Bits in received packet status byte and EN0_RSR*/
10549ab747fSPaolo Bonzini #define ENRSR_RXOK 0x01 /* Received a good packet */
10649ab747fSPaolo Bonzini #define ENRSR_CRC 0x02 /* CRC error */
10749ab747fSPaolo Bonzini #define ENRSR_FAE 0x04 /* frame alignment error */
10849ab747fSPaolo Bonzini #define ENRSR_FO 0x08 /* FIFO overrun */
10949ab747fSPaolo Bonzini #define ENRSR_MPA 0x10 /* missed pkt */
11049ab747fSPaolo Bonzini #define ENRSR_PHY 0x20 /* physical/multicast address */
11149ab747fSPaolo Bonzini #define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */
11249ab747fSPaolo Bonzini #define ENRSR_DEF 0x80 /* deferring */
11349ab747fSPaolo Bonzini
11449ab747fSPaolo Bonzini /* Transmitted packet status, EN0_TSR. */
11549ab747fSPaolo Bonzini #define ENTSR_PTX 0x01 /* Packet transmitted without error */
11649ab747fSPaolo Bonzini #define ENTSR_ND 0x02 /* The transmit wasn't deferred. */
11749ab747fSPaolo Bonzini #define ENTSR_COL 0x04 /* The transmit collided at least once. */
11849ab747fSPaolo Bonzini #define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */
11949ab747fSPaolo Bonzini #define ENTSR_CRS 0x10 /* The carrier sense was lost. */
12049ab747fSPaolo Bonzini #define ENTSR_FU 0x20 /* A "FIFO underrun" occurred during transmit. */
12149ab747fSPaolo Bonzini #define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */
12249ab747fSPaolo Bonzini #define ENTSR_OWC 0x80 /* There was an out-of-window collision. */
12349ab747fSPaolo Bonzini
ne2000_reset(NE2000State * s)12449ab747fSPaolo Bonzini void ne2000_reset(NE2000State *s)
12549ab747fSPaolo Bonzini {
12649ab747fSPaolo Bonzini int i;
12749ab747fSPaolo Bonzini
12849ab747fSPaolo Bonzini s->isr = ENISR_RESET;
12949ab747fSPaolo Bonzini memcpy(s->mem, &s->c.macaddr, 6);
13049ab747fSPaolo Bonzini s->mem[14] = 0x57;
13149ab747fSPaolo Bonzini s->mem[15] = 0x57;
13249ab747fSPaolo Bonzini
13349ab747fSPaolo Bonzini /* duplicate prom data */
13449ab747fSPaolo Bonzini for(i = 15;i >= 0; i--) {
13549ab747fSPaolo Bonzini s->mem[2 * i] = s->mem[i];
13649ab747fSPaolo Bonzini s->mem[2 * i + 1] = s->mem[i];
13749ab747fSPaolo Bonzini }
13849ab747fSPaolo Bonzini }
13949ab747fSPaolo Bonzini
ne2000_update_irq(NE2000State * s)14049ab747fSPaolo Bonzini static void ne2000_update_irq(NE2000State *s)
14149ab747fSPaolo Bonzini {
14249ab747fSPaolo Bonzini int isr;
14349ab747fSPaolo Bonzini isr = (s->isr & s->imr) & 0x7f;
14449ab747fSPaolo Bonzini #if defined(DEBUG_NE2000)
14549ab747fSPaolo Bonzini printf("NE2000: Set IRQ to %d (%02x %02x)\n",
14649ab747fSPaolo Bonzini isr ? 1 : 0, s->isr, s->imr);
14749ab747fSPaolo Bonzini #endif
14849ab747fSPaolo Bonzini qemu_set_irq(s->irq, (isr != 0));
14949ab747fSPaolo Bonzini }
15049ab747fSPaolo Bonzini
ne2000_buffer_full(NE2000State * s)15149ab747fSPaolo Bonzini static int ne2000_buffer_full(NE2000State *s)
15249ab747fSPaolo Bonzini {
15349ab747fSPaolo Bonzini int avail, index, boundary;
15449ab747fSPaolo Bonzini
155415ab35aSPrasad J Pandit if (s->stop <= s->start) {
156415ab35aSPrasad J Pandit return 1;
157415ab35aSPrasad J Pandit }
158415ab35aSPrasad J Pandit
15949ab747fSPaolo Bonzini index = s->curpag << 8;
16049ab747fSPaolo Bonzini boundary = s->boundary << 8;
16149ab747fSPaolo Bonzini if (index < boundary)
16249ab747fSPaolo Bonzini avail = boundary - index;
16349ab747fSPaolo Bonzini else
16449ab747fSPaolo Bonzini avail = (s->stop - s->start) - (index - boundary);
16549ab747fSPaolo Bonzini if (avail < (MAX_ETH_FRAME_SIZE + 4))
16649ab747fSPaolo Bonzini return 1;
16749ab747fSPaolo Bonzini return 0;
16849ab747fSPaolo Bonzini }
16949ab747fSPaolo Bonzini
ne2000_receive(NetClientState * nc,const uint8_t * buf,size_t size_)17049ab747fSPaolo Bonzini ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
17149ab747fSPaolo Bonzini {
17249ab747fSPaolo Bonzini NE2000State *s = qemu_get_nic_opaque(nc);
173fdc89e90SJason Wang size_t size = size_;
17449ab747fSPaolo Bonzini uint8_t *p;
17549ab747fSPaolo Bonzini unsigned int total_len, next, avail, len, index, mcast_idx;
17649ab747fSPaolo Bonzini static const uint8_t broadcast_macaddr[6] =
17749ab747fSPaolo Bonzini { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
17849ab747fSPaolo Bonzini
17949ab747fSPaolo Bonzini #if defined(DEBUG_NE2000)
180fdc89e90SJason Wang printf("NE2000: received len=%zu\n", size);
18149ab747fSPaolo Bonzini #endif
18249ab747fSPaolo Bonzini
18349ab747fSPaolo Bonzini if (s->cmd & E8390_STOP || ne2000_buffer_full(s))
18449ab747fSPaolo Bonzini return -1;
18549ab747fSPaolo Bonzini
18649ab747fSPaolo Bonzini /* XXX: check this */
18749ab747fSPaolo Bonzini if (s->rxcr & 0x10) {
18849ab747fSPaolo Bonzini /* promiscuous: receive all */
18949ab747fSPaolo Bonzini } else {
19049ab747fSPaolo Bonzini if (!memcmp(buf, broadcast_macaddr, 6)) {
19149ab747fSPaolo Bonzini /* broadcast address */
19249ab747fSPaolo Bonzini if (!(s->rxcr & 0x04))
19349ab747fSPaolo Bonzini return size;
19449ab747fSPaolo Bonzini } else if (buf[0] & 0x01) {
19549ab747fSPaolo Bonzini /* multicast */
19649ab747fSPaolo Bonzini if (!(s->rxcr & 0x08))
19749ab747fSPaolo Bonzini return size;
198084e2b11SMark Cave-Ayland mcast_idx = net_crc32(buf, ETH_ALEN) >> 26;
19949ab747fSPaolo Bonzini if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
20049ab747fSPaolo Bonzini return size;
20149ab747fSPaolo Bonzini } else if (s->mem[0] == buf[0] &&
20249ab747fSPaolo Bonzini s->mem[2] == buf[1] &&
20349ab747fSPaolo Bonzini s->mem[4] == buf[2] &&
20449ab747fSPaolo Bonzini s->mem[6] == buf[3] &&
20549ab747fSPaolo Bonzini s->mem[8] == buf[4] &&
20649ab747fSPaolo Bonzini s->mem[10] == buf[5]) {
20749ab747fSPaolo Bonzini /* match */
20849ab747fSPaolo Bonzini } else {
20949ab747fSPaolo Bonzini return size;
21049ab747fSPaolo Bonzini }
21149ab747fSPaolo Bonzini }
21249ab747fSPaolo Bonzini
21349ab747fSPaolo Bonzini index = s->curpag << 8;
2149bbdbc66SP J P if (index >= NE2000_PMEM_END) {
2159bbdbc66SP J P index = s->start;
2169bbdbc66SP J P }
21749ab747fSPaolo Bonzini /* 4 bytes for header */
21849ab747fSPaolo Bonzini total_len = size + 4;
21949ab747fSPaolo Bonzini /* address for next packet (4 bytes for CRC) */
22049ab747fSPaolo Bonzini next = index + ((total_len + 4 + 255) & ~0xff);
22149ab747fSPaolo Bonzini if (next >= s->stop)
22249ab747fSPaolo Bonzini next -= (s->stop - s->start);
22349ab747fSPaolo Bonzini /* prepare packet header */
22449ab747fSPaolo Bonzini p = s->mem + index;
22549ab747fSPaolo Bonzini s->rsr = ENRSR_RXOK; /* receive status */
22649ab747fSPaolo Bonzini /* XXX: check this */
22749ab747fSPaolo Bonzini if (buf[0] & 0x01)
22849ab747fSPaolo Bonzini s->rsr |= ENRSR_PHY;
22949ab747fSPaolo Bonzini p[0] = s->rsr;
23049ab747fSPaolo Bonzini p[1] = next >> 8;
23149ab747fSPaolo Bonzini p[2] = total_len;
23249ab747fSPaolo Bonzini p[3] = total_len >> 8;
23349ab747fSPaolo Bonzini index += 4;
23449ab747fSPaolo Bonzini
23549ab747fSPaolo Bonzini /* write packet data */
23649ab747fSPaolo Bonzini while (size > 0) {
23749ab747fSPaolo Bonzini if (index <= s->stop)
23849ab747fSPaolo Bonzini avail = s->stop - index;
23949ab747fSPaolo Bonzini else
240737d2b3cSP J P break;
24149ab747fSPaolo Bonzini len = size;
24249ab747fSPaolo Bonzini if (len > avail)
24349ab747fSPaolo Bonzini len = avail;
24449ab747fSPaolo Bonzini memcpy(s->mem + index, buf, len);
24549ab747fSPaolo Bonzini buf += len;
24649ab747fSPaolo Bonzini index += len;
24749ab747fSPaolo Bonzini if (index == s->stop)
24849ab747fSPaolo Bonzini index = s->start;
24949ab747fSPaolo Bonzini size -= len;
25049ab747fSPaolo Bonzini }
25149ab747fSPaolo Bonzini s->curpag = next >> 8;
25249ab747fSPaolo Bonzini
25349ab747fSPaolo Bonzini /* now we can signal we have received something */
25449ab747fSPaolo Bonzini s->isr |= ENISR_RX;
25549ab747fSPaolo Bonzini ne2000_update_irq(s);
25649ab747fSPaolo Bonzini
25749ab747fSPaolo Bonzini return size_;
25849ab747fSPaolo Bonzini }
25949ab747fSPaolo Bonzini
ne2000_ioport_write(void * opaque,uint32_t addr,uint32_t val)26049ab747fSPaolo Bonzini static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
26149ab747fSPaolo Bonzini {
26249ab747fSPaolo Bonzini NE2000State *s = opaque;
26349ab747fSPaolo Bonzini int offset, page, index;
26449ab747fSPaolo Bonzini
26549ab747fSPaolo Bonzini addr &= 0xf;
266a816b625SPhilippe Mathieu-Daudé trace_ne2000_ioport_write(addr, val);
26749ab747fSPaolo Bonzini if (addr == E8390_CMD) {
26849ab747fSPaolo Bonzini /* control register */
26949ab747fSPaolo Bonzini s->cmd = val;
27049ab747fSPaolo Bonzini if (!(val & E8390_STOP)) { /* START bit makes no sense on RTL8029... */
27149ab747fSPaolo Bonzini s->isr &= ~ENISR_RESET;
27249ab747fSPaolo Bonzini /* test specific case: zero length transfer */
27349ab747fSPaolo Bonzini if ((val & (E8390_RREAD | E8390_RWRITE)) &&
27449ab747fSPaolo Bonzini s->rcnt == 0) {
27549ab747fSPaolo Bonzini s->isr |= ENISR_RDC;
27649ab747fSPaolo Bonzini ne2000_update_irq(s);
27749ab747fSPaolo Bonzini }
27849ab747fSPaolo Bonzini if (val & E8390_TRANS) {
27949ab747fSPaolo Bonzini index = (s->tpsr << 8);
28049ab747fSPaolo Bonzini /* XXX: next 2 lines are a hack to make netware 3.11 work */
28149ab747fSPaolo Bonzini if (index >= NE2000_PMEM_END)
28249ab747fSPaolo Bonzini index -= NE2000_PMEM_SIZE;
28349ab747fSPaolo Bonzini /* fail safe: check range on the transmitted length */
28449ab747fSPaolo Bonzini if (index + s->tcnt <= NE2000_PMEM_END) {
28549ab747fSPaolo Bonzini qemu_send_packet(qemu_get_queue(s->nic), s->mem + index,
28649ab747fSPaolo Bonzini s->tcnt);
28749ab747fSPaolo Bonzini }
28849ab747fSPaolo Bonzini /* signal end of transfer */
28949ab747fSPaolo Bonzini s->tsr = ENTSR_PTX;
29049ab747fSPaolo Bonzini s->isr |= ENISR_TX;
29149ab747fSPaolo Bonzini s->cmd &= ~E8390_TRANS;
29249ab747fSPaolo Bonzini ne2000_update_irq(s);
29349ab747fSPaolo Bonzini }
29449ab747fSPaolo Bonzini }
29549ab747fSPaolo Bonzini } else {
29649ab747fSPaolo Bonzini page = s->cmd >> 6;
29749ab747fSPaolo Bonzini offset = addr | (page << 4);
29849ab747fSPaolo Bonzini switch(offset) {
29949ab747fSPaolo Bonzini case EN0_STARTPG:
3009bbdbc66SP J P if (val << 8 <= NE2000_PMEM_END) {
30149ab747fSPaolo Bonzini s->start = val << 8;
3029bbdbc66SP J P }
30349ab747fSPaolo Bonzini break;
30449ab747fSPaolo Bonzini case EN0_STOPPG:
3059bbdbc66SP J P if (val << 8 <= NE2000_PMEM_END) {
30649ab747fSPaolo Bonzini s->stop = val << 8;
3079bbdbc66SP J P }
30849ab747fSPaolo Bonzini break;
30949ab747fSPaolo Bonzini case EN0_BOUNDARY:
3109bbdbc66SP J P if (val << 8 < NE2000_PMEM_END) {
31149ab747fSPaolo Bonzini s->boundary = val;
3129bbdbc66SP J P }
31349ab747fSPaolo Bonzini break;
31449ab747fSPaolo Bonzini case EN0_IMR:
31549ab747fSPaolo Bonzini s->imr = val;
31649ab747fSPaolo Bonzini ne2000_update_irq(s);
31749ab747fSPaolo Bonzini break;
31849ab747fSPaolo Bonzini case EN0_TPSR:
31949ab747fSPaolo Bonzini s->tpsr = val;
32049ab747fSPaolo Bonzini break;
32149ab747fSPaolo Bonzini case EN0_TCNTLO:
32249ab747fSPaolo Bonzini s->tcnt = (s->tcnt & 0xff00) | val;
32349ab747fSPaolo Bonzini break;
32449ab747fSPaolo Bonzini case EN0_TCNTHI:
32549ab747fSPaolo Bonzini s->tcnt = (s->tcnt & 0x00ff) | (val << 8);
32649ab747fSPaolo Bonzini break;
32749ab747fSPaolo Bonzini case EN0_RSARLO:
32849ab747fSPaolo Bonzini s->rsar = (s->rsar & 0xff00) | val;
32949ab747fSPaolo Bonzini break;
33049ab747fSPaolo Bonzini case EN0_RSARHI:
33149ab747fSPaolo Bonzini s->rsar = (s->rsar & 0x00ff) | (val << 8);
33249ab747fSPaolo Bonzini break;
33349ab747fSPaolo Bonzini case EN0_RCNTLO:
33449ab747fSPaolo Bonzini s->rcnt = (s->rcnt & 0xff00) | val;
33549ab747fSPaolo Bonzini break;
33649ab747fSPaolo Bonzini case EN0_RCNTHI:
33749ab747fSPaolo Bonzini s->rcnt = (s->rcnt & 0x00ff) | (val << 8);
33849ab747fSPaolo Bonzini break;
33949ab747fSPaolo Bonzini case EN0_RXCR:
34049ab747fSPaolo Bonzini s->rxcr = val;
34149ab747fSPaolo Bonzini break;
34249ab747fSPaolo Bonzini case EN0_DCFG:
34349ab747fSPaolo Bonzini s->dcfg = val;
34449ab747fSPaolo Bonzini break;
34549ab747fSPaolo Bonzini case EN0_ISR:
34649ab747fSPaolo Bonzini s->isr &= ~(val & 0x7f);
34749ab747fSPaolo Bonzini ne2000_update_irq(s);
34849ab747fSPaolo Bonzini break;
34949ab747fSPaolo Bonzini case EN1_PHYS ... EN1_PHYS + 5:
35049ab747fSPaolo Bonzini s->phys[offset - EN1_PHYS] = val;
35149ab747fSPaolo Bonzini break;
35249ab747fSPaolo Bonzini case EN1_CURPAG:
3539bbdbc66SP J P if (val << 8 < NE2000_PMEM_END) {
35449ab747fSPaolo Bonzini s->curpag = val;
3559bbdbc66SP J P }
35649ab747fSPaolo Bonzini break;
35749ab747fSPaolo Bonzini case EN1_MULT ... EN1_MULT + 7:
35849ab747fSPaolo Bonzini s->mult[offset - EN1_MULT] = val;
35949ab747fSPaolo Bonzini break;
36049ab747fSPaolo Bonzini }
36149ab747fSPaolo Bonzini }
36249ab747fSPaolo Bonzini }
36349ab747fSPaolo Bonzini
ne2000_ioport_read(void * opaque,uint32_t addr)36449ab747fSPaolo Bonzini static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
36549ab747fSPaolo Bonzini {
36649ab747fSPaolo Bonzini NE2000State *s = opaque;
36749ab747fSPaolo Bonzini int offset, page, ret;
36849ab747fSPaolo Bonzini
36949ab747fSPaolo Bonzini addr &= 0xf;
37049ab747fSPaolo Bonzini if (addr == E8390_CMD) {
37149ab747fSPaolo Bonzini ret = s->cmd;
37249ab747fSPaolo Bonzini } else {
37349ab747fSPaolo Bonzini page = s->cmd >> 6;
37449ab747fSPaolo Bonzini offset = addr | (page << 4);
37549ab747fSPaolo Bonzini switch(offset) {
37649ab747fSPaolo Bonzini case EN0_TSR:
37749ab747fSPaolo Bonzini ret = s->tsr;
37849ab747fSPaolo Bonzini break;
37949ab747fSPaolo Bonzini case EN0_BOUNDARY:
38049ab747fSPaolo Bonzini ret = s->boundary;
38149ab747fSPaolo Bonzini break;
38249ab747fSPaolo Bonzini case EN0_ISR:
38349ab747fSPaolo Bonzini ret = s->isr;
38449ab747fSPaolo Bonzini break;
38549ab747fSPaolo Bonzini case EN0_RSARLO:
38649ab747fSPaolo Bonzini ret = s->rsar & 0x00ff;
38749ab747fSPaolo Bonzini break;
38849ab747fSPaolo Bonzini case EN0_RSARHI:
38949ab747fSPaolo Bonzini ret = s->rsar >> 8;
39049ab747fSPaolo Bonzini break;
39149ab747fSPaolo Bonzini case EN1_PHYS ... EN1_PHYS + 5:
39249ab747fSPaolo Bonzini ret = s->phys[offset - EN1_PHYS];
39349ab747fSPaolo Bonzini break;
39449ab747fSPaolo Bonzini case EN1_CURPAG:
39549ab747fSPaolo Bonzini ret = s->curpag;
39649ab747fSPaolo Bonzini break;
39749ab747fSPaolo Bonzini case EN1_MULT ... EN1_MULT + 7:
39849ab747fSPaolo Bonzini ret = s->mult[offset - EN1_MULT];
39949ab747fSPaolo Bonzini break;
40049ab747fSPaolo Bonzini case EN0_RSR:
40149ab747fSPaolo Bonzini ret = s->rsr;
40249ab747fSPaolo Bonzini break;
40349ab747fSPaolo Bonzini case EN2_STARTPG:
40449ab747fSPaolo Bonzini ret = s->start >> 8;
40549ab747fSPaolo Bonzini break;
40649ab747fSPaolo Bonzini case EN2_STOPPG:
40749ab747fSPaolo Bonzini ret = s->stop >> 8;
40849ab747fSPaolo Bonzini break;
40949ab747fSPaolo Bonzini case EN0_RTL8029ID0:
41049ab747fSPaolo Bonzini ret = 0x50;
41149ab747fSPaolo Bonzini break;
41249ab747fSPaolo Bonzini case EN0_RTL8029ID1:
41349ab747fSPaolo Bonzini ret = 0x43;
41449ab747fSPaolo Bonzini break;
41549ab747fSPaolo Bonzini case EN3_CONFIG0:
41649ab747fSPaolo Bonzini ret = 0; /* 10baseT media */
41749ab747fSPaolo Bonzini break;
41849ab747fSPaolo Bonzini case EN3_CONFIG2:
41949ab747fSPaolo Bonzini ret = 0x40; /* 10baseT active */
42049ab747fSPaolo Bonzini break;
42149ab747fSPaolo Bonzini case EN3_CONFIG3:
42249ab747fSPaolo Bonzini ret = 0x40; /* Full duplex */
42349ab747fSPaolo Bonzini break;
42449ab747fSPaolo Bonzini default:
42549ab747fSPaolo Bonzini ret = 0x00;
42649ab747fSPaolo Bonzini break;
42749ab747fSPaolo Bonzini }
42849ab747fSPaolo Bonzini }
429a816b625SPhilippe Mathieu-Daudé trace_ne2000_ioport_read(addr, ret);
43049ab747fSPaolo Bonzini return ret;
43149ab747fSPaolo Bonzini }
43249ab747fSPaolo Bonzini
ne2000_mem_writeb(NE2000State * s,uint32_t addr,uint32_t val)43349ab747fSPaolo Bonzini static inline void ne2000_mem_writeb(NE2000State *s, uint32_t addr,
43449ab747fSPaolo Bonzini uint32_t val)
43549ab747fSPaolo Bonzini {
43649ab747fSPaolo Bonzini if (addr < 32 ||
43749ab747fSPaolo Bonzini (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
43849ab747fSPaolo Bonzini s->mem[addr] = val;
43949ab747fSPaolo Bonzini }
44049ab747fSPaolo Bonzini }
44149ab747fSPaolo Bonzini
ne2000_mem_writew(NE2000State * s,uint32_t addr,uint32_t val)44249ab747fSPaolo Bonzini static inline void ne2000_mem_writew(NE2000State *s, uint32_t addr,
44349ab747fSPaolo Bonzini uint32_t val)
44449ab747fSPaolo Bonzini {
44549ab747fSPaolo Bonzini addr &= ~1; /* XXX: check exact behaviour if not even */
44649ab747fSPaolo Bonzini if (addr < 32 ||
44749ab747fSPaolo Bonzini (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
44849ab747fSPaolo Bonzini *(uint16_t *)(s->mem + addr) = cpu_to_le16(val);
44949ab747fSPaolo Bonzini }
45049ab747fSPaolo Bonzini }
45149ab747fSPaolo Bonzini
ne2000_mem_writel(NE2000State * s,uint32_t addr,uint32_t val)45249ab747fSPaolo Bonzini static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr,
45349ab747fSPaolo Bonzini uint32_t val)
45449ab747fSPaolo Bonzini {
45549ab747fSPaolo Bonzini addr &= ~1; /* XXX: check exact behaviour if not even */
456aa7f9966SPrasad J Pandit if (addr < 32
457aa7f9966SPrasad J Pandit || (addr >= NE2000_PMEM_START
458aa7f9966SPrasad J Pandit && addr + sizeof(uint32_t) <= NE2000_MEM_SIZE)) {
4596e931878SPeter Maydell stl_le_p(s->mem + addr, val);
46049ab747fSPaolo Bonzini }
46149ab747fSPaolo Bonzini }
46249ab747fSPaolo Bonzini
ne2000_mem_readb(NE2000State * s,uint32_t addr)46349ab747fSPaolo Bonzini static inline uint32_t ne2000_mem_readb(NE2000State *s, uint32_t addr)
46449ab747fSPaolo Bonzini {
46549ab747fSPaolo Bonzini if (addr < 32 ||
46649ab747fSPaolo Bonzini (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
46749ab747fSPaolo Bonzini return s->mem[addr];
46849ab747fSPaolo Bonzini } else {
46949ab747fSPaolo Bonzini return 0xff;
47049ab747fSPaolo Bonzini }
47149ab747fSPaolo Bonzini }
47249ab747fSPaolo Bonzini
ne2000_mem_readw(NE2000State * s,uint32_t addr)47349ab747fSPaolo Bonzini static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr)
47449ab747fSPaolo Bonzini {
47549ab747fSPaolo Bonzini addr &= ~1; /* XXX: check exact behaviour if not even */
47649ab747fSPaolo Bonzini if (addr < 32 ||
47749ab747fSPaolo Bonzini (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
47849ab747fSPaolo Bonzini return le16_to_cpu(*(uint16_t *)(s->mem + addr));
47949ab747fSPaolo Bonzini } else {
48049ab747fSPaolo Bonzini return 0xffff;
48149ab747fSPaolo Bonzini }
48249ab747fSPaolo Bonzini }
48349ab747fSPaolo Bonzini
ne2000_mem_readl(NE2000State * s,uint32_t addr)48449ab747fSPaolo Bonzini static inline uint32_t ne2000_mem_readl(NE2000State *s, uint32_t addr)
48549ab747fSPaolo Bonzini {
48649ab747fSPaolo Bonzini addr &= ~1; /* XXX: check exact behaviour if not even */
487aa7f9966SPrasad J Pandit if (addr < 32
488aa7f9966SPrasad J Pandit || (addr >= NE2000_PMEM_START
489aa7f9966SPrasad J Pandit && addr + sizeof(uint32_t) <= NE2000_MEM_SIZE)) {
490f567656aSPeter Maydell return ldl_le_p(s->mem + addr);
49149ab747fSPaolo Bonzini } else {
49249ab747fSPaolo Bonzini return 0xffffffff;
49349ab747fSPaolo Bonzini }
49449ab747fSPaolo Bonzini }
49549ab747fSPaolo Bonzini
ne2000_dma_update(NE2000State * s,int len)49649ab747fSPaolo Bonzini static inline void ne2000_dma_update(NE2000State *s, int len)
49749ab747fSPaolo Bonzini {
49849ab747fSPaolo Bonzini s->rsar += len;
49949ab747fSPaolo Bonzini /* wrap */
50049ab747fSPaolo Bonzini /* XXX: check what to do if rsar > stop */
50149ab747fSPaolo Bonzini if (s->rsar == s->stop)
50249ab747fSPaolo Bonzini s->rsar = s->start;
50349ab747fSPaolo Bonzini
50449ab747fSPaolo Bonzini if (s->rcnt <= len) {
50549ab747fSPaolo Bonzini s->rcnt = 0;
50649ab747fSPaolo Bonzini /* signal end of transfer */
50749ab747fSPaolo Bonzini s->isr |= ENISR_RDC;
50849ab747fSPaolo Bonzini ne2000_update_irq(s);
50949ab747fSPaolo Bonzini } else {
51049ab747fSPaolo Bonzini s->rcnt -= len;
51149ab747fSPaolo Bonzini }
51249ab747fSPaolo Bonzini }
51349ab747fSPaolo Bonzini
ne2000_asic_ioport_write(void * opaque,uint32_t addr,uint32_t val)51449ab747fSPaolo Bonzini static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
51549ab747fSPaolo Bonzini {
51649ab747fSPaolo Bonzini NE2000State *s = opaque;
51749ab747fSPaolo Bonzini
51849ab747fSPaolo Bonzini #ifdef DEBUG_NE2000
51949ab747fSPaolo Bonzini printf("NE2000: asic write val=0x%04x\n", val);
52049ab747fSPaolo Bonzini #endif
52149ab747fSPaolo Bonzini if (s->rcnt == 0)
52249ab747fSPaolo Bonzini return;
52349ab747fSPaolo Bonzini if (s->dcfg & 0x01) {
52449ab747fSPaolo Bonzini /* 16 bit access */
52549ab747fSPaolo Bonzini ne2000_mem_writew(s, s->rsar, val);
52649ab747fSPaolo Bonzini ne2000_dma_update(s, 2);
52749ab747fSPaolo Bonzini } else {
52849ab747fSPaolo Bonzini /* 8 bit access */
52949ab747fSPaolo Bonzini ne2000_mem_writeb(s, s->rsar, val);
53049ab747fSPaolo Bonzini ne2000_dma_update(s, 1);
53149ab747fSPaolo Bonzini }
53249ab747fSPaolo Bonzini }
53349ab747fSPaolo Bonzini
ne2000_asic_ioport_read(void * opaque,uint32_t addr)53449ab747fSPaolo Bonzini static uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr)
53549ab747fSPaolo Bonzini {
53649ab747fSPaolo Bonzini NE2000State *s = opaque;
53749ab747fSPaolo Bonzini int ret;
53849ab747fSPaolo Bonzini
53949ab747fSPaolo Bonzini if (s->dcfg & 0x01) {
54049ab747fSPaolo Bonzini /* 16 bit access */
54149ab747fSPaolo Bonzini ret = ne2000_mem_readw(s, s->rsar);
54249ab747fSPaolo Bonzini ne2000_dma_update(s, 2);
54349ab747fSPaolo Bonzini } else {
54449ab747fSPaolo Bonzini /* 8 bit access */
54549ab747fSPaolo Bonzini ret = ne2000_mem_readb(s, s->rsar);
54649ab747fSPaolo Bonzini ne2000_dma_update(s, 1);
54749ab747fSPaolo Bonzini }
54849ab747fSPaolo Bonzini #ifdef DEBUG_NE2000
54949ab747fSPaolo Bonzini printf("NE2000: asic read val=0x%04x\n", ret);
55049ab747fSPaolo Bonzini #endif
55149ab747fSPaolo Bonzini return ret;
55249ab747fSPaolo Bonzini }
55349ab747fSPaolo Bonzini
ne2000_asic_ioport_writel(void * opaque,uint32_t addr,uint32_t val)55449ab747fSPaolo Bonzini static void ne2000_asic_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
55549ab747fSPaolo Bonzini {
55649ab747fSPaolo Bonzini NE2000State *s = opaque;
55749ab747fSPaolo Bonzini
55849ab747fSPaolo Bonzini #ifdef DEBUG_NE2000
55949ab747fSPaolo Bonzini printf("NE2000: asic writel val=0x%04x\n", val);
56049ab747fSPaolo Bonzini #endif
56149ab747fSPaolo Bonzini if (s->rcnt == 0)
56249ab747fSPaolo Bonzini return;
56349ab747fSPaolo Bonzini /* 32 bit access */
56449ab747fSPaolo Bonzini ne2000_mem_writel(s, s->rsar, val);
56549ab747fSPaolo Bonzini ne2000_dma_update(s, 4);
56649ab747fSPaolo Bonzini }
56749ab747fSPaolo Bonzini
ne2000_asic_ioport_readl(void * opaque,uint32_t addr)56849ab747fSPaolo Bonzini static uint32_t ne2000_asic_ioport_readl(void *opaque, uint32_t addr)
56949ab747fSPaolo Bonzini {
57049ab747fSPaolo Bonzini NE2000State *s = opaque;
57149ab747fSPaolo Bonzini int ret;
57249ab747fSPaolo Bonzini
57349ab747fSPaolo Bonzini /* 32 bit access */
57449ab747fSPaolo Bonzini ret = ne2000_mem_readl(s, s->rsar);
57549ab747fSPaolo Bonzini ne2000_dma_update(s, 4);
57649ab747fSPaolo Bonzini #ifdef DEBUG_NE2000
57749ab747fSPaolo Bonzini printf("NE2000: asic readl val=0x%04x\n", ret);
57849ab747fSPaolo Bonzini #endif
57949ab747fSPaolo Bonzini return ret;
58049ab747fSPaolo Bonzini }
58149ab747fSPaolo Bonzini
ne2000_reset_ioport_write(void * opaque,uint32_t addr,uint32_t val)58249ab747fSPaolo Bonzini static void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val)
58349ab747fSPaolo Bonzini {
58449ab747fSPaolo Bonzini /* nothing to do (end of reset pulse) */
58549ab747fSPaolo Bonzini }
58649ab747fSPaolo Bonzini
ne2000_reset_ioport_read(void * opaque,uint32_t addr)58749ab747fSPaolo Bonzini static uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr)
58849ab747fSPaolo Bonzini {
58949ab747fSPaolo Bonzini NE2000State *s = opaque;
59049ab747fSPaolo Bonzini ne2000_reset(s);
59149ab747fSPaolo Bonzini return 0;
59249ab747fSPaolo Bonzini }
59349ab747fSPaolo Bonzini
ne2000_post_load(void * opaque,int version_id)59449ab747fSPaolo Bonzini static int ne2000_post_load(void* opaque, int version_id)
59549ab747fSPaolo Bonzini {
59649ab747fSPaolo Bonzini NE2000State* s = opaque;
59749ab747fSPaolo Bonzini
59849ab747fSPaolo Bonzini if (version_id < 2) {
59949ab747fSPaolo Bonzini s->rxcr = 0x0c;
60049ab747fSPaolo Bonzini }
60149ab747fSPaolo Bonzini return 0;
60249ab747fSPaolo Bonzini }
60349ab747fSPaolo Bonzini
60449ab747fSPaolo Bonzini const VMStateDescription vmstate_ne2000 = {
60549ab747fSPaolo Bonzini .name = "ne2000",
60649ab747fSPaolo Bonzini .version_id = 2,
60749ab747fSPaolo Bonzini .minimum_version_id = 0,
60849ab747fSPaolo Bonzini .post_load = ne2000_post_load,
609*1de81b42SRichard Henderson .fields = (const VMStateField[]) {
61049ab747fSPaolo Bonzini VMSTATE_UINT8_V(rxcr, NE2000State, 2),
61149ab747fSPaolo Bonzini VMSTATE_UINT8(cmd, NE2000State),
61249ab747fSPaolo Bonzini VMSTATE_UINT32(start, NE2000State),
61349ab747fSPaolo Bonzini VMSTATE_UINT32(stop, NE2000State),
61449ab747fSPaolo Bonzini VMSTATE_UINT8(boundary, NE2000State),
61549ab747fSPaolo Bonzini VMSTATE_UINT8(tsr, NE2000State),
61649ab747fSPaolo Bonzini VMSTATE_UINT8(tpsr, NE2000State),
61749ab747fSPaolo Bonzini VMSTATE_UINT16(tcnt, NE2000State),
61849ab747fSPaolo Bonzini VMSTATE_UINT16(rcnt, NE2000State),
61949ab747fSPaolo Bonzini VMSTATE_UINT32(rsar, NE2000State),
62049ab747fSPaolo Bonzini VMSTATE_UINT8(rsr, NE2000State),
62149ab747fSPaolo Bonzini VMSTATE_UINT8(isr, NE2000State),
62249ab747fSPaolo Bonzini VMSTATE_UINT8(dcfg, NE2000State),
62349ab747fSPaolo Bonzini VMSTATE_UINT8(imr, NE2000State),
62449ab747fSPaolo Bonzini VMSTATE_BUFFER(phys, NE2000State),
62549ab747fSPaolo Bonzini VMSTATE_UINT8(curpag, NE2000State),
62649ab747fSPaolo Bonzini VMSTATE_BUFFER(mult, NE2000State),
62749ab747fSPaolo Bonzini VMSTATE_UNUSED(4), /* was irq */
62849ab747fSPaolo Bonzini VMSTATE_BUFFER(mem, NE2000State),
62949ab747fSPaolo Bonzini VMSTATE_END_OF_LIST()
63049ab747fSPaolo Bonzini }
63149ab747fSPaolo Bonzini };
63249ab747fSPaolo Bonzini
ne2000_read(void * opaque,hwaddr addr,unsigned size)63349ab747fSPaolo Bonzini static uint64_t ne2000_read(void *opaque, hwaddr addr,
63449ab747fSPaolo Bonzini unsigned size)
63549ab747fSPaolo Bonzini {
63649ab747fSPaolo Bonzini NE2000State *s = opaque;
637cd4479a9SPhilippe Mathieu-Daudé uint64_t val;
63849ab747fSPaolo Bonzini
63949ab747fSPaolo Bonzini if (addr < 0x10 && size == 1) {
640cd4479a9SPhilippe Mathieu-Daudé val = ne2000_ioport_read(s, addr);
64149ab747fSPaolo Bonzini } else if (addr == 0x10) {
64249ab747fSPaolo Bonzini if (size <= 2) {
643cd4479a9SPhilippe Mathieu-Daudé val = ne2000_asic_ioport_read(s, addr);
64449ab747fSPaolo Bonzini } else {
645cd4479a9SPhilippe Mathieu-Daudé val = ne2000_asic_ioport_readl(s, addr);
64649ab747fSPaolo Bonzini }
64749ab747fSPaolo Bonzini } else if (addr == 0x1f && size == 1) {
648cd4479a9SPhilippe Mathieu-Daudé val = ne2000_reset_ioport_read(s, addr);
649cd4479a9SPhilippe Mathieu-Daudé } else {
650cd4479a9SPhilippe Mathieu-Daudé val = ((uint64_t)1 << (size * 8)) - 1;
65149ab747fSPaolo Bonzini }
652cd4479a9SPhilippe Mathieu-Daudé trace_ne2000_read(addr, val);
653cd4479a9SPhilippe Mathieu-Daudé
654cd4479a9SPhilippe Mathieu-Daudé return val;
65549ab747fSPaolo Bonzini }
65649ab747fSPaolo Bonzini
ne2000_write(void * opaque,hwaddr addr,uint64_t data,unsigned size)65749ab747fSPaolo Bonzini static void ne2000_write(void *opaque, hwaddr addr,
65849ab747fSPaolo Bonzini uint64_t data, unsigned size)
65949ab747fSPaolo Bonzini {
66049ab747fSPaolo Bonzini NE2000State *s = opaque;
66149ab747fSPaolo Bonzini
662cd4479a9SPhilippe Mathieu-Daudé trace_ne2000_write(addr, data);
66349ab747fSPaolo Bonzini if (addr < 0x10 && size == 1) {
66449ab747fSPaolo Bonzini ne2000_ioport_write(s, addr, data);
66549ab747fSPaolo Bonzini } else if (addr == 0x10) {
66649ab747fSPaolo Bonzini if (size <= 2) {
66749ab747fSPaolo Bonzini ne2000_asic_ioport_write(s, addr, data);
66849ab747fSPaolo Bonzini } else {
66949ab747fSPaolo Bonzini ne2000_asic_ioport_writel(s, addr, data);
67049ab747fSPaolo Bonzini }
67149ab747fSPaolo Bonzini } else if (addr == 0x1f && size == 1) {
67249ab747fSPaolo Bonzini ne2000_reset_ioport_write(s, addr, data);
67349ab747fSPaolo Bonzini }
67449ab747fSPaolo Bonzini }
67549ab747fSPaolo Bonzini
67649ab747fSPaolo Bonzini static const MemoryRegionOps ne2000_ops = {
67749ab747fSPaolo Bonzini .read = ne2000_read,
67849ab747fSPaolo Bonzini .write = ne2000_write,
67945d883dcSAurelien Jarno .endianness = DEVICE_LITTLE_ENDIAN,
68049ab747fSPaolo Bonzini };
68149ab747fSPaolo Bonzini
68249ab747fSPaolo Bonzini /***********************************************************/
68349ab747fSPaolo Bonzini /* PCI NE2000 definitions */
68449ab747fSPaolo Bonzini
ne2000_setup_io(NE2000State * s,DeviceState * dev,unsigned size)685dcb117bfSPaolo Bonzini void ne2000_setup_io(NE2000State *s, DeviceState *dev, unsigned size)
68649ab747fSPaolo Bonzini {
687dcb117bfSPaolo Bonzini memory_region_init_io(&s->io, OBJECT(dev), &ne2000_ops, s, "ne2000", size);
68849ab747fSPaolo Bonzini }
689