📄 pcnet.c
字号:
for (i = 0,checksum = 0; i < 16; i++) checksum += s->prom[i]; *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum); s->bcr[BCR_MSRDA] = 0x0005; s->bcr[BCR_MSWRA] = 0x0005; s->bcr[BCR_MC ] = 0x0002; s->bcr[BCR_LNKST] = 0x00c0; s->bcr[BCR_LED1 ] = 0x0084; s->bcr[BCR_LED2 ] = 0x0088; s->bcr[BCR_LED3 ] = 0x0090; s->bcr[BCR_FDC ] = 0x0000; s->bcr[BCR_BSBC ] = 0x9001; s->bcr[BCR_EECAS] = 0x0002; s->bcr[BCR_SWS ] = 0x0200; s->bcr[BCR_PLAT ] = 0xff06; pcnet_s_reset(s);}static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val){ PCNetState *s = opaque;#ifdef PCNET_DEBUG printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val);#endif /* Check APROMWE bit to enable write access */ if (pcnet_bcr_readw(s,2) & 0x80) s->prom[addr & 15] = val;} static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr){ PCNetState *s = opaque; uint32_t val = s->prom[addr &= 15];#ifdef PCNET_DEBUG printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val);#endif return val;}static void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val){ PCNetState *s = opaque; pcnet_poll_timer(s);#ifdef PCNET_DEBUG_IO printf("pcnet_ioport_writew addr=0x%08x val=0x%04x\n", addr, val);#endif if (!BCR_DWIO(s)) { switch (addr & 0x0f) { case 0x00: /* RDP */ pcnet_csr_writew(s, s->rap, val); break; case 0x02: s->rap = val & 0x7f; break; case 0x06: pcnet_bcr_writew(s, s->rap, val); break; } } pcnet_update_irq(s);}static uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr){ PCNetState *s = opaque; uint32_t val = -1; pcnet_poll_timer(s); if (!BCR_DWIO(s)) { switch (addr & 0x0f) { case 0x00: /* RDP */ val = pcnet_csr_readw(s, s->rap); break; case 0x02: val = s->rap; break; case 0x04: pcnet_s_reset(s); val = 0; break; case 0x06: val = pcnet_bcr_readw(s, s->rap); break; } } pcnet_update_irq(s);#ifdef PCNET_DEBUG_IO printf("pcnet_ioport_readw addr=0x%08x val=0x%04x\n", addr, val & 0xffff);#endif return val;}static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val){ PCNetState *s = opaque; pcnet_poll_timer(s);#ifdef PCNET_DEBUG_IO printf("pcnet_ioport_writel addr=0x%08x val=0x%08x\n", addr, val);#endif if (BCR_DWIO(s)) { switch (addr & 0x0f) { case 0x00: /* RDP */ pcnet_csr_writew(s, s->rap, val & 0xffff); break; case 0x04: s->rap = val & 0x7f; break; case 0x0c: pcnet_bcr_writew(s, s->rap, val & 0xffff); break; } } else if ((addr & 0x0f) == 0) { /* switch device to dword i/o mode */ pcnet_bcr_writew(s, BCR_BSBC, pcnet_bcr_readw(s, BCR_BSBC) | 0x0080);#ifdef PCNET_DEBUG_IO printf("device switched into dword i/o mode\n");#endif } pcnet_update_irq(s);}static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr){ PCNetState *s = opaque; uint32_t val = -1; pcnet_poll_timer(s); if (BCR_DWIO(s)) { switch (addr & 0x0f) { case 0x00: /* RDP */ val = pcnet_csr_readw(s, s->rap); break; case 0x04: val = s->rap; break; case 0x08: pcnet_s_reset(s); val = 0; break; case 0x0c: val = pcnet_bcr_readw(s, s->rap); break; } } pcnet_update_irq(s);#ifdef PCNET_DEBUG_IO printf("pcnet_ioport_readl addr=0x%08x val=0x%08x\n", addr, val);#endif return val;}static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type){ PCNetState *d = (PCNetState *)pci_dev;#ifdef PCNET_DEBUG_IO printf("pcnet_ioport_map addr=0x%04x size=0x%04x\n", addr, size);#endif register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d); register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d); register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d); register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d); register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d); register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d);}static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val){ PCNetState *d = opaque;#ifdef PCNET_DEBUG_IO printf("pcnet_mmio_writeb addr=0x%08x val=0x%02x\n", addr, val);#endif if (!(addr & 0x10)) pcnet_aprom_writeb(d, addr & 0x0f, val);}static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr) { PCNetState *d = opaque; uint32_t val = -1; if (!(addr & 0x10)) val = pcnet_aprom_readb(d, addr & 0x0f);#ifdef PCNET_DEBUG_IO printf("pcnet_mmio_readb addr=0x%08x val=0x%02x\n", addr, val & 0xff);#endif return val;}static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val){ PCNetState *d = opaque;#ifdef PCNET_DEBUG_IO printf("pcnet_mmio_writew addr=0x%08x val=0x%04x\n", addr, val);#endif if (addr & 0x10) pcnet_ioport_writew(d, addr & 0x0f, val); else { addr &= 0x0f; pcnet_aprom_writeb(d, addr, val & 0xff); pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); }}static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr) { PCNetState *d = opaque; uint32_t val = -1; if (addr & 0x10) val = pcnet_ioport_readw(d, addr & 0x0f); else { addr &= 0x0f; val = pcnet_aprom_readb(d, addr+1); val <<= 8; val |= pcnet_aprom_readb(d, addr); }#ifdef PCNET_DEBUG_IO printf("pcnet_mmio_readw addr=0x%08x val = 0x%04x\n", addr, val & 0xffff);#endif return val;}static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val){ PCNetState *d = opaque;#ifdef PCNET_DEBUG_IO printf("pcnet_mmio_writel addr=0x%08x val=0x%08x\n", addr, val);#endif if (addr & 0x10) pcnet_ioport_writel(d, addr & 0x0f, val); else { addr &= 0x0f; pcnet_aprom_writeb(d, addr, val & 0xff); pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16); pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24); }}static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr) { PCNetState *d = opaque; uint32_t val; if (addr & 0x10) val = pcnet_ioport_readl(d, addr & 0x0f); else { addr &= 0x0f; val = pcnet_aprom_readb(d, addr+3); val <<= 8; val |= pcnet_aprom_readb(d, addr+2); val <<= 8; val |= pcnet_aprom_readb(d, addr+1); val <<= 8; val |= pcnet_aprom_readb(d, addr); }#ifdef PCNET_DEBUG_IO printf("pcnet_mmio_readl addr=0x%08x val=0x%08x\n", addr, val);#endif return val;}static void pcnet_save(QEMUFile *f, void *opaque){ PCNetState *s = opaque; unsigned int i; if (s->pci_dev) pci_device_save(s->pci_dev, f); qemu_put_be32s(f, &s->rap); qemu_put_be32s(f, &s->isr); qemu_put_be32s(f, &s->lnkst); qemu_put_be32s(f, &s->rdra); qemu_put_be32s(f, &s->tdra); qemu_put_buffer(f, s->prom, 16); for (i = 0; i < 128; i++) qemu_put_be16s(f, &s->csr[i]); for (i = 0; i < 32; i++) qemu_put_be16s(f, &s->bcr[i]); qemu_put_be64s(f, &s->timer); qemu_put_be32s(f, &s->xmit_pos); qemu_put_be32s(f, &s->recv_pos); qemu_put_buffer(f, s->buffer, 4096); qemu_put_be32s(f, &s->tx_busy); qemu_put_timer(f, s->poll_timer);}static int pcnet_load(QEMUFile *f, void *opaque, int version_id){ PCNetState *s = opaque; int i, ret; if (version_id != 2) return -EINVAL; if (s->pci_dev) { ret = pci_device_load(s->pci_dev, f); if (ret < 0) return ret; } qemu_get_be32s(f, &s->rap); qemu_get_be32s(f, &s->isr); qemu_get_be32s(f, &s->lnkst); qemu_get_be32s(f, &s->rdra); qemu_get_be32s(f, &s->tdra); qemu_get_buffer(f, s->prom, 16); for (i = 0; i < 128; i++) qemu_get_be16s(f, &s->csr[i]); for (i = 0; i < 32; i++) qemu_get_be16s(f, &s->bcr[i]); qemu_get_be64s(f, &s->timer); qemu_get_be32s(f, &s->xmit_pos); qemu_get_be32s(f, &s->recv_pos); qemu_get_buffer(f, s->buffer, 4096); qemu_get_be32s(f, &s->tx_busy); qemu_get_timer(f, s->poll_timer); return 0;}static void pcnet_common_init(PCNetState *d, NICInfo *nd, const char *info_str){ int instance; d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d); d->nd = nd; d->vc = qemu_new_vlan_client(nd->vlan, pcnet_receive, pcnet_can_receive, d); snprintf(d->vc->info_str, sizeof(d->vc->info_str), "pcnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x", d->nd->macaddr[0], d->nd->macaddr[1], d->nd->macaddr[2], d->nd->macaddr[3], d->nd->macaddr[4], d->nd->macaddr[5]); pcnet_h_reset(d); instance = pci_bus_num(d->dev.bus) << 8 | d->dev.devfn; register_savevm("pcnet", instance, 2, pcnet_save, pcnet_load, d);}/* PCI interface */static CPUWriteMemoryFunc *pcnet_mmio_write[] = { (CPUWriteMemoryFunc *)&pcnet_mmio_writeb, (CPUWriteMemoryFunc *)&pcnet_mmio_writew, (CPUWriteMemoryFunc *)&pcnet_mmio_writel};static CPUReadMemoryFunc *pcnet_mmio_read[] = { (CPUReadMemoryFunc *)&pcnet_mmio_readb, (CPUReadMemoryFunc *)&pcnet_mmio_readw, (CPUReadMemoryFunc *)&pcnet_mmio_readl};static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num, uint32_t addr, uint32_t size, int type){ PCNetState *d = (PCNetState *)pci_dev;#ifdef PCNET_DEBUG_IO printf("pcnet_ioport_map addr=0x%08x 0x%08x\n", addr, size);#endif cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_index);}static void pcnet_pci_set_irq_cb(void *opaque, int isr){ PCNetState *s = opaque; pci_set_irq(&s->dev, 0, isr);}static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap){ cpu_physical_memory_write(addr, buf, len);}static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap){ cpu_physical_memory_read(addr, buf, len);}void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn){ PCNetState *d; uint8_t *pci_conf;#if 0 printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n", sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD));#endif d = (PCNetState *)pci_register_device(bus, "PCNet", sizeof(PCNetState), devfn, NULL, NULL); pci_conf = d->dev.config; *(uint16_t *)&pci_conf[0x00] = cpu_to_le16(0x1022); *(uint16_t *)&pci_conf[0x02] = cpu_to_le16(0x2000); *(uint16_t *)&pci_conf[0x04] = cpu_to_le16(0x0007); *(uint16_t *)&pci_conf[0x06] = cpu_to_le16(0x0280); pci_conf[0x08] = 0x10; pci_conf[0x09] = 0x00; pci_conf[0x0a] = 0x00; // ethernet network controller pci_conf[0x0b] = 0x02; pci_conf[0x0e] = 0x00; // header_type *(uint32_t *)&pci_conf[0x10] = cpu_to_le32(0x00000001); *(uint32_t *)&pci_conf[0x14] = cpu_to_le32(0x00000000); pci_conf[0x3d] = 1; // interrupt pin 0 pci_conf[0x3e] = 0x06; pci_conf[0x3f] = 0xff; /* Handler for memory-mapped I/O */ d->mmio_index = cpu_register_io_memory(0, pcnet_mmio_read, pcnet_mmio_write, d); pci_register_io_region((PCIDevice *)d, 0, PCNET_IOPORT_SIZE, PCI_ADDRESS_SPACE_IO, pcnet_ioport_map); pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE, PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map); d->set_irq_cb = pcnet_pci_set_irq_cb; d->phys_mem_read = pci_physical_memory_read; d->phys_mem_write = pci_physical_memory_write; d->pci_dev = &d->dev; pcnet_common_init(d, nd, "pcnet");}/* SPARC32 interface */#if defined (TARGET_SPARC) && !defined(TARGET_SPARC64) // Avoid compile failurestatic CPUReadMemoryFunc *lance_mem_read[3] = { (CPUReadMemoryFunc *)&pcnet_ioport_readw, (CPUReadMemoryFunc *)&pcnet_ioport_readw, (CPUReadMemoryFunc *)&pcnet_ioport_readw,};static CPUWriteMemoryFunc *lance_mem_write[3] = { (CPUWriteMemoryFunc *)&pcnet_ioport_writew, (CPUWriteMemoryFunc *)&pcnet_ioport_writew, (CPUWriteMemoryFunc *)&pcnet_ioport_writew,};static void pcnet_sparc_set_irq_cb(void *opaque, int isr){ PCNetState *s = opaque; ledma_set_irq(s->dma_opaque, isr);}void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque){ PCNetState *d; int lance_io_memory; d = qemu_mallocz(sizeof(PCNetState)); if (!d) return NULL; lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, d); d->dma_opaque = dma_opaque; cpu_register_physical_memory(leaddr, 4, lance_io_memory); d->set_irq_cb = pcnet_sparc_set_irq_cb; d->phys_mem_read = ledma_memory_read; d->phys_mem_write = ledma_memory_write; pcnet_common_init(d, nd, "lance"); return d;}#endif /* TARGET_SPARC */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -