/** * Set up a DMA transfer. * @param direction the direction of the transfer (DMA_READ or DMA_WRITE) * @param chan the channel * @param addr the address of the buffer * @param size number of bytes to transfer */ void Setup_DMA(enum DMA_Direction direction, int chan, void *addr_, ulong_t size) { uchar_t mode = 0; ulong_t addr = (ulong_t) addr_; /* Make sure parameters are sensible */ KASSERT(direction == DMA_READ || direction == DMA_WRITE); KASSERT(VALID_CHANNEL(chan)); KASSERT(IS_RESERVED(chan)); KASSERT(VALID_MEM(addr, size)); KASSERT(size > 0); /* elaborate because the otherwise working test wouldn't work if the DMA region was precisely 64K page aligned. */ KASSERT0((((addr & 0xffff) == 0 && size <= 65536)) || (size <= (0xffff - (addr & 0xffff))), "DMA region can't cross 64K boundary"); /* Set up transfer mode */ mode |= DMA_MODE_SINGLE; mode |= (direction == DMA_READ) ? DMA_MODE_READ : DMA_MODE_WRITE; mode |= (chan & 3); if (chan == 5) mode |= 0x10; /* nspring testing, make this better if useful. */ Debug("Setup_DMA(%s,%d,%x,%d)\n", direction == DMA_READ ? "DMA_READ" : "DMA_WRITE", chan, addr, size); Debug("Setup_DMA: mode=%02x\n", mode); Debug("DMA_ADDR_REG for channel is %02x\n", DMA_ADDR_REG(chan)); Debug("DMA_PAGE_REG for channel is %02x\n", DMA_PAGE_REG(chan)); Debug("DMA_COUNT_REG for channel is %02x\n", DMA_COUNT_REG(chan)); /* Temporarily mask the DMA channel */ Mask_DMA(chan); /* Write the transfer mode */ Out_Byte(DMA_MODE_REG(chan), mode); /* Clear the byte pointer flip-flop */ Out_Byte(DMA_CLEAR_FF_REG(chan), 0); /* doesn't matter what value is written here */ /* Write the transfer address (LSB, then MSB) */ Out_Byte(DMA_ADDR_REG(chan), addr & 0xFF); Out_Byte(DMA_ADDR_REG(chan), (addr >> 8) & 0xFF); /* Write the page register */ Out_Byte(DMA_PAGE_REG(chan), (addr >> 16) & 0xFF); /* * Write the count (LSB, then MSB) * Note that the count is one less that the number of bytes transferred */ if (chan > 4) { size >>= 1; } /* words not bytes? */
void Hardware_Shutdown() { // works with > 1.3 qemu with the command line: -device isa-debug-exit,iobase=0x501 Out_Byte(0x501, 0x00); // works on Bochs, and QEMU prior to 1.4 Out_Byte(0x8900, 'S'); Out_Byte(0x8900, 'h'); Out_Byte(0x8900, 'u'); Out_Byte(0x8900, 't'); Out_Byte(0x8900, 'd'); Out_Byte(0x8900, 'o'); Out_Byte(0x8900, 'w'); Out_Byte(0x8900, 'n'); KASSERT0(false, "Hardware_Shutdown() failed: QEMU likely run with incorrect options.\n"); }
int Eth_Transmit(struct Net_Device *device, struct Net_Buf *nBuf, uchar_t * destAddr, ushort_t type) { struct Ethernet_Header header; int rc; KASSERT(Interrupts_Enabled()); /* all you have to do in this function is fill in the header. */ TODO_P(PROJECT_RAW_ETHERNET, "construct the ethernet header for the destination, this device's address, and the type."); rc = Net_Buf_Prepend(nBuf, &header, sizeof(header), NET_BUF_ALLOC_COPY); if (rc != 0) return rc; ulong_t size = MAX(NET_BUF_SIZE(nBuf), ETH_MIN_DATA); /* buffer size must be at least ETH_MIN_DATA, even if we don't use it. */ KASSERT0(size >= ETH_MIN_DATA, "input to Eth_Transmit should be at least ETH_MIN_DATA long"); /* paranoia. */ void *buffer = Malloc(size); if (buffer == 0) return ENOMEM; rc = Net_Buf_Extract_All(nBuf, buffer); if (rc != 0) { Free(buffer); return rc; } Disable_Interrupts(); device->transmit(device, buffer, size); Enable_Interrupts(); return 0; }