/* * Update the location of the hardware cursor. */ static void Update_Cursor(void) { /* * The cursor location is a character offset from the beginning * of page memory (I think). */ uint_t characterPos = (s_cons.row * NUMCOLS) + s_cons.col; uchar_t origAddr; /* * Save original contents of CRT address register. * It is considered good programming practice to restore * it to its original value after modifying it. */ origAddr = In_Byte(CRT_ADDR_REG); IO_Delay(); /* Set the high cursor location byte */ Out_Byte(CRT_ADDR_REG, CRT_CURSOR_LOC_HIGH_REG); IO_Delay(); Out_Byte(CRT_DATA_REG, (characterPos >> 8) & 0xff); IO_Delay(); /* Set the low cursor location byte */ Out_Byte(CRT_ADDR_REG, CRT_CURSOR_LOC_LOW_REG); IO_Delay(); Out_Byte(CRT_DATA_REG, characterPos & 0xff); IO_Delay(); /* Restore contents of the CRT address register */ Out_Byte(CRT_ADDR_REG, origAddr); }
/* called when an interrupt tells us to. */ static void NE2000_Do_Receive(struct Net_Device *device) { uchar_t currentBuffer; ulong_t baseAddr = device->baseAddr; ushort_t ringBufferPage; Out_Byte(baseAddr + NE2K_CR, NE2K_CR_PAGE1 + NE2K_CR_NODMA + NE2K_CR_STA); currentBuffer = In_Byte(baseAddr + NE2K1W_CURR); Out_Byte(baseAddr + NE2K_CR, NE2K_CR_PAGE0 + NE2K_CR_NODMA + NE2K_CR_STA); while (currentBuffer != In_Byte(baseAddr + NE2K0R_BNRY)) { ringBufferPage = In_Byte(baseAddr + NE2K0R_BNRY) << 8; /* Receive as a packet; enqueue for further processing */ Net_Device_Receive(device, ringBufferPage); /* Read the current buffer register */ Out_Byte(baseAddr + NE2K_CR, NE2K_CR_PAGE1 + NE2K_CR_NODMA + NE2K_CR_STA); currentBuffer = In_Byte(baseAddr + NE2K1W_CURR); Out_Byte(baseAddr + NE2K_CR, NE2K_CR_PAGE0 + NE2K_CR_NODMA + NE2K_CR_STA); //Print("Current buffer: %x\n", currentBuffer); //Print("Boundary pointer: %x\n", In_Byte(baseAddr + NE2K0R_BNRY)); } }
void readDriveConfig(int drive) { int i; short info[256]; Out_Byte(IDE_DRIVE_HEAD_REGISTER, (drive == 0) ? IDE_DRIVE_0 : IDE_DRIVE_1); Out_Byte(IDE_COMMAND_REGISTER, IDE_COMMAND_IDENTIFY_DRIVE); while (In_Byte(IDE_STATUS_REGISTER) != 0x58); for (i=0; i < 256; i++) { info[i] = In_Word(IDE_DATA_REGISTER); } drives[drive].num_Cylinders = info[IDE_INDENTIFY_NUM_CYLINDERS]; drives[drive].num_Heads = info[IDE_INDENTIFY_NUM_HEADS]; drives[drive].num_SectorsPerTrack = info[IDE_INDENTIFY_NUM_SECTORS_TRACK]; drives[drive].num_BytesPerSector = info[IDE_INDENTIFY_NUM_BYTES_SECTOR]; Print ("Found IDE: Drive %d\n", drive); Print (" %d cylinders, %d heads, %d sectors/tack, %d bytes/sector\n", drives[drive].num_Cylinders, drives[drive].num_Heads, drives[drive].num_SectorsPerTrack, drives[drive].num_BytesPerSector); Print (" Disk has %d blocks\n", IDE_getNumBlocks(drive)); }
/** * 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? */
/* * Put one character to the screen using the current cursor position * and attribute, scrolling if needed. The caller should update * the cursor position once all characters have been written. */ static void Output_Literal_Character(int c) { int numSpaces; switch (c) { case '\n': Clear_To_EOL(); Newline(); break; case '\t': numSpaces = TABWIDTH - (s_cons.col % TABWIDTH); while (numSpaces-- > 0) Put_Graphic_Char(' '); break; default: Put_Graphic_Char(c); break; } #ifndef NDEBUG /* * When compiled with --enable-port-e9-hack, Bochs will send writes * to port E9 to the console. This helps tremendously with debugging, * because it allows debug Print() statements to be visible after * Bochs has exited. */ Out_Byte(0xE9, c); #endif }
void shutMeDown() { 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'); }
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'); }
void Init_IDE(void) { int errorCode; Print("Initializing IDE controller...\n"); /* Reset the controller and drives */ Out_Byte(IDE_DEVICE_CONTROL_REGISTER, IDE_DCR_NOINTERRUPT | IDE_DCR_RESET); Micro_Delay(100); Out_Byte(IDE_DEVICE_CONTROL_REGISTER, IDE_DCR_NOINTERRUPT); /* * FIXME: This code doesn't work on Bochs 2.0. * while ((In_Byte(IDE_STATUS_REGISTER) & IDE_STATUS_DRIVE_READY) == 0) * ; */ /* This code does work on Bochs 2.0. */ while (In_Byte(IDE_STATUS_REGISTER) & IDE_STATUS_DRIVE_BUSY) ; if(ideDebug) Print("About to run drive Diagnosis\n"); Out_Byte(IDE_COMMAND_REGISTER, IDE_COMMAND_DIAGNOSTIC); while (In_Byte(IDE_STATUS_REGISTER) & IDE_STATUS_DRIVE_BUSY) ; errorCode = In_Byte(IDE_ERROR_REGISTER); if(ideDebug > 1) Print("ide: ide error register = %x\n", errorCode); /* Probe and register drives */ int i; for(i = 0; i < IDE_MAX_DRIVES; i++) { if(readDriveConfig(i) == 0) ++numDrives; } if(ideDebug) Print("Found %d IDE drives\n", numDrives); /* Start request thread */ if(numDrives > 0) Start_Kernel_Thread(IDE_Request_Thread, 0, PRIORITY_NORMAL, true, "{IDE}"); }
static void NE2000_Interrupt_Handler(struct Interrupt_State *state) { struct Net_Device *device; ulong_t baseAddr; unsigned char isrMask; int rc; Begin_IRQ(state); DEBUG_NE2K("Handling NE2000 interrupt\n"); rc = Get_Net_Device_By_IRQ(state->intNum - FIRST_EXTERNAL_INT, &device); if (rc != 0) { Print("NE2000: Could not identify interrupt number %d\n", state->intNum); goto fail; } baseAddr = device->baseAddr; isrMask = In_Byte(NE2K0R_ISR + baseAddr); // DEBUG_NE2K("ISR Mask: %x\n" , isrMask); if (isrMask & NE2K_ISR_RXE) { //Print("RSR: %x\n", In_Byte(NE2K0R_RSR + baseAddr)); ++device->rxPacketErrors; } if (isrMask & NE2K_ISR_TXE) { //Print("TSR: %x\n", In_Byte(NE2K0R_TSR + baseAddr)); ++device->txPacketErrors; } if (isrMask & NE2K_ISR_OVW) { //Print("Ring Buffer Overflow Encountered!!\n"); NE2000_Handle_Ring_Buffer_Overflow(device); } if (isrMask & NE2K_ISR_PRX) { DEBUG_NE2K("Receiving packet\n"); NE2000_Do_Receive(device); ++device->rxPackets; } if (isrMask & NE2K_ISR_PTX) { //Print("Packet transmitted\n"); DEBUG_NE2K("Transmitted.\n"); //Print("TSR: %x\n", In_Byte(NE2K0R_TSR + baseAddr)); ++device->txPackets; } fail: Out_Byte(baseAddr + NE2K0R_ISR, isrMask); End_IRQ(state); }
void NE2000_Reset(struct Net_Device *device) { ulong_t baseAddr = device->baseAddr; KASSERT(!Interrupts_Enabled()); Out_Byte(baseAddr + NE2K_RESET_PORT, In_Byte(NE2K_RESET_PORT)); while (In_Byte(baseAddr + NE2K0R_ISR) & NE2K_ISR_RST) { Print("NIC has not reset yet\n"); } }
void NE2000_Get_Dev_Hdr(struct Net_Device *device, struct Net_Device_Header *hdr, ulong_t pageOffset) { unsigned int i; ulong_t baseAddr = device->baseAddr; ulong_t size = sizeof(struct Net_Device_Header) >> 1; ushort_t *buffer = (ushort_t *) hdr; /* Set the Command Register */ Out_Byte(baseAddr + NE2K_CR, 0x22); /* Load the packet size into the registers */ Out_Byte(baseAddr + NE2K0W_RBCR0, sizeof(struct Net_Device_Header)); Out_Byte(baseAddr + NE2K0W_RBCR1, 0); /* Load the page start into the RSARX registers */ Out_Byte(baseAddr + NE2K0W_RSAR0, 0x00); Out_Byte(baseAddr + NE2K0W_RSAR1, pageOffset); /* Start the remote write */ Out_Byte(baseAddr + NE2K_CR, NE2K_CR_DMA_RREAD | NE2K_CR_STA); /* Read the data in through the I/O port */ for (i = 0; i < size; ++i) { buffer[i] = In_Word(baseAddr + NE2K_IO_PORT); } }
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"); }
void Init_Timer(void) { /* * TODO: reprogram the timer to set the frequency. * In bochs, it defaults to 18Hz, which is actually pretty * reasonable. */ Print("Initializing timer...\n"); /* configure for default clock */ Out_Byte(0x43, 0x36); Out_Byte(0x40, 0x00); Out_Byte(0x40, 0x00); /* Calibrate for delay loop */ Calibrate_Delay(); Print("Delay loop: %d iterations per tick\n", s_spinCountPerTick); /* Install an interrupt handler for the timer IRQ */ Install_IRQ(TIMER_IRQ, &Timer_Interrupt_Handler); Enable_IRQ(TIMER_IRQ); }
/***************************************************************************** * dump_proc *****************************************************************************/ PUBLIC void dump_proc(struct proc* p) { Pixel color_err = {31,0,0,0}; char info[STR_DEFAULT_LEN]; int i; int dump_len = sizeof(struct proc); Out_Byte(CRTC_ADDR_REG, START_ADDR_H); Out_Byte(CRTC_DATA_REG, 0); Out_Byte(CRTC_ADDR_REG, START_ADDR_L); Out_Byte(CRTC_DATA_REG, 0); sprintf(info, "byte dump of proc_table[%d]:\n", p - proc_table); //printf(info, color_err); for (i = 0; i < dump_len; i++) { sprintf(info, "%x.", ((unsigned char *)p)[i]); printf(info); } printf("^^"); printf("\n\n"); sprintf(info, "ANY: 0x%x.\n", ANY); printf(info); sprintf(info, "NO_TASK: 0x%x.\n", NO_TASK); printf(info); printf("\n", color_err); sprintf(info, "ldt_sel: 0x%x. ", p->ldt_sel); printf(info); sprintf(info, "ticks: 0x%x. ", p->ticks); printf(info); sprintf(info, "priority: 0x%x. ", p->priority); printf(info); sprintf(info, "pid: 0x%x. ", p->pid); printf(info); sprintf(info, "name: %s. ", p->name); printf(info); printf("\n"); sprintf(info, "p_flags: 0x%x. ", p->p_flags); printf(info); sprintf(info, "p_recvfrom: 0x%x. ", p->p_recvfrom);printf(info); sprintf(info, "p_sendto: 0x%x. ", p->p_sendto);printf(info); sprintf(info, "nr_tty: 0x%x. ", p->nr_tty); printf(info); printf("\n"); sprintf(info, "has_int_msg: 0x%x. ", p->has_int_msg); printf(info); }
void NE2000_Handle_Ring_Buffer_Overflow(struct Net_Device *device) { int txp, resend; ulong_t baseAddr = device->baseAddr; /* 1. Read and store the value of the TXP bit */ txp = In_Byte(baseAddr + NE2K_CR) & NE2K_CR_TXP; /* 2. Issue the STOP command to the NIC */ Out_Byte(baseAddr + NE2K_CR, 0x21); /* 3. Wait for at least 1.6 ms */ IO_Delay(); /* 4. Clear the NIC’s Remote Byte Count */ Out_Byte(baseAddr + NE2K0W_RBCR0, 0x00); Out_Byte(baseAddr + NE2K0W_RBCR1, 0x00); /* 5. Handle resend */ if (!txp) { resend = 0; } else { int isr = In_Byte(baseAddr + NE2K0R_ISR); if ((isr & NE2K_ISR_PTX) || (isr & NE2K_ISR_TXE)) { resend = 0; } else { resend = 1; } } /* 6. Place the NIC into loopback mode */ Out_Byte(baseAddr + NE2K0W_TCR, 0x02); /* 7. Issue START command to the NIC */ Out_Byte(baseAddr + NE2K_CR, 0x22); /* 8. Remove one or more packets from the receive buffer ring */ NE2000_Do_Receive(device); /* 9. Reset the overwrite warning (OVW) bit in the ISR */ Out_Byte(baseAddr + NE2K0R_ISR, NE2K_ISR_OVW); /* 10. Take the NIC out of loopback */ Out_Byte(baseAddr + NE2K0W_TCR, 0x00); /* 11. Restart the interrupted transmit if resend = 1 */ if (resend) { Out_Byte(baseAddr + NE2K_CR, 0x26); } }
/* * Reset and calibrate the controller. * Return true is successful, false otherwise. */ static bool Reset_Controller(void) { /* Reset */ Out_Byte(FDC_DOR_REG, 0); /*Micro_Delay(1000); */ /* * Enable fd0 * TODO: we might want to support drives other than 0 eventually */ Start_Motor(0); return Calibrate(0); }
/* * Initialize the floppy controller. */ void Init_Floppy(void) { uchar_t floppyByte; bool ready = false; bool good; Print("Initializing floppy controller...\n"); /* Allocate memory for DMA transfers */ s_transferBuf = (uchar_t*) Alloc_Page(); /* Use CMOS to get floppy configuration */ Out_Byte(CMOS_OUT, CMOS_FLOPPY_INDEX); floppyByte = In_Byte(CMOS_IN); Setup_Drive_Parameters(0, (floppyByte >> 4) & 0xF); Setup_Drive_Parameters(1, floppyByte & 0xF); /* Install floppy interrupt handler */ Install_IRQ(FDC_IRQ, &Floppy_Interrupt_Handler); Enable_IRQ(FDC_IRQ); /* Reset and calibrate the controller. */ Disable_Interrupts(); good = Reset_Controller(); Enable_Interrupts(); if (!good) { Print(" Failed to reset controller!\n"); goto done; } /* Reserve DMA channel 2. */ if (!Reserve_DMA(FDC_DMA)) { Print(" Failed to reserve DMA channel\n"); goto done; } /* * Driver is now ready for requests. * Start the request processing thread. */ ready = true; Start_Kernel_Thread(Floppy_Request_Thread, 0, PRIORITY_NORMAL, true); done: if (!ready) Print(" Floppy controller initialization FAILED\n"); }
/** * Reserve given DMA channel. * @param chan the channel to reserve * @return true if successful, false if not */ bool Reserve_DMA(int chan) { bool iflag = Begin_Int_Atomic(); bool result = false; KASSERT(VALID_CHANNEL(chan)); if (!IS_RESERVED(chan)) { /* Channel is available; unmask it. */ Out_Byte(DMA_MASK_ONE_REG(chan), chan & 3); /* Mask channel as allocated */ s_allocated |= (1 << chan); result = true; } End_Int_Atomic(iflag); return result; }
void Init_IDE() { int errorCode; while (In_Byte(IDE_STATUS_REGISTER) != 0x50); if (ideDebug) Print("About to run drive Diagnosis\n"); Out_Byte(IDE_COMMAND_REGISTER, IDE_COMMAND_DIAGNOSTIC); while (!(In_Byte(IDE_STATUS_REGISTER) & IDE_STATUS_DRIVE_READY)); errorCode = In_Byte(IDE_ERROR_REGISTER); readDriveConfig(0); if (errorCode & 0x80) { numDrives = 1; } else { numDrives = 2; readDriveConfig(1); } }
/* actually reads the data out of the device */ void NE2000_Receive(struct Net_Device *device, void *buffer, ulong_t length, ulong_t pageOffset) { ulong_t baseAddr = device->baseAddr; KASSERT(!Interrupts_Enabled()); int i; int newLength = length >> 1; unsigned short *newBuffer = (unsigned short *)buffer; /* Set the Command Register */ Out_Byte(baseAddr + NE2K_CR, 0x22); Out_Byte(baseAddr + NE2K0W_RCR, 0x0C); /* Load the packet size into the registers */ Out_Byte(baseAddr + NE2K0W_RBCR0, length & 0xFF); Out_Byte(baseAddr + NE2K0W_RBCR1, length >> 8); /* Load the page start into the RSARX registers */ Out_Byte(baseAddr + NE2K0W_RSAR0, pageOffset & 0xFF); Out_Byte(baseAddr + NE2K0W_RSAR1, pageOffset >> 8); /* Start the remote write */ Out_Byte(baseAddr + NE2K_CR, NE2K_CR_DMA_RREAD | NE2K_CR_STA); /* Read the data in through the I/O port */ for (i = 0; i < newLength; ++i) { newBuffer[i] = In_Word(baseAddr + NE2K_IO_PORT); } /* Receive the last byte of data if we have an odd length */ if (length & 0x1) { ((uchar_t *) buffer)[length - 1] = In_Byte(baseAddr + NE2K_IO_PORT); } /* Ack the remote DMA interrupt */ Out_Byte(baseAddr + NE2K0R_ISR, NE2K_ISR_RDC); device->rxBytes += length; }
void Init_8139() { cur_tx = 0; cur_rx = 0; /* Reset the chip */ Out_Byte(RTL8139_CR, CmdReset); //while( In_Byte(RTL8139_CR) != 0 ) /*udelay(10)*/; /* Unlock Config[01234] and BMCR register writes */ Out_Byte(RTL8139_9346CR, Cfg9346_Unlock); /* Enable Tx/Rx before setting transfer thresholds */ Out_Byte(RTL8139_CR, CmdRxEnb | CmdTxEnb); /* Using 32K ring */ Out_DWord(RTL8139_RCR, RxCfgRcv32K | RxNoWrap | (7 << RxCfgFIFOShift) | (7 << RxCfgDMAShift) | AcceptBroadcast | AcceptMyPhys); // Out_DWord(RTL8139_TCR, RxCfgRcv32K | RxNoWrap | (7 << RxCfgFIFOShift) | (7 << RxCfgDMAShift)); Out_DWord(RTL8139_TCR, TxIFG96 | (6 << TxDMAShift) | (8 << TxRetryShift)); /* Lock Config[01234] and BMCR register writes */ Out_Byte(RTL8139_9346CR, Cfg9346_Lock); /* init Rx ring buffer DMA address */ rx_buf = Malloc(RX_BUF_LEN); Out_DWord(RTL8139_RBSTART, (uint_t)rx_buf); /* init Tx buffer DMA addresses (4 registers) */ tx_buf = Malloc(TX_BUF_SIZE * 4); int i; for(i = 0; i < 4; i++) Out_DWord(RTL8139_TSAD0 + (i * 4), ((uint_t)tx_buf) + (i * TX_BUF_SIZE)); /* missed packet counter */ Out_DWord(RTL8139_MPC, 0); // rtl8139_set_rx_mode does some stuff here. Out_DWord(RTL8139_RCR, In_DWord(RTL8139_RCR) | AcceptBroadcast | AcceptMulticast | AcceptMyPhys | AcceptAllPhys); for(i = 0; i < 8; i++) Out_Byte(RTL8139_MAR0 + i, 0xff); /* no early-rx interrupts */ Out_Word(RTL8139_MULINT, In_Word(RTL8139_MULINT) & MultiIntrClear); /* make sure RxTx has started */ if(!(In_Byte(RTL8139_CR) & CmdRxEnb) || !(In_Byte(RTL8139_CR) & CmdTxEnb)) Out_Byte(RTL8139_CR, CmdRxEnb | CmdTxEnb); /* Enable all known interrupts by setting the interrupt mask. */ Out_Word(RTL8139_IMR, rtl8139_intr_mask); Install_IRQ(RTL8139_IRQ, rtl8139_interrupt); Enable_IRQ(RTL8139_IRQ); PrintBoth("8139 initialized\n"); }
/* * Write a block at the logical block number indicated. */ static int IDE_Write(int driveNum, int blockNum, char *buffer) { int i; int head; int sector; int cylinder; short *bufferW; int reEnable = 0; if (driveNum < 0 || driveNum > (numDrives - 1)) { return IDE_ERROR_BAD_DRIVE; } if (blockNum < 0 || blockNum >= IDE_getNumBlocks(driveNum)) { return IDE_ERROR_INVALID_BLOCK; } if (Interrupts_Enabled()) { Disable_Interrupts(); reEnable = 1; } /* now compute the head, cylinder, and sector */ sector = blockNum % drives[driveNum].num_SectorsPerTrack + 1; cylinder = blockNum / (drives[driveNum].num_Heads * drives[driveNum].num_SectorsPerTrack); head = (blockNum / drives[driveNum].num_SectorsPerTrack) % drives[driveNum].num_Heads; if (ideDebug) { Print("request to write block %d\n", blockNum); Print(" head %d\n", head); Print(" cylinder %d\n", cylinder); Print(" sector %d\n", sector); } Out_Byte(IDE_SECTOR_COUNT_REGISTER, 1); Out_Byte(IDE_SECTOR_NUMBER_REGISTER, sector); Out_Byte(IDE_CYLINDER_LOW_REGISTER, LOW_BYTE(cylinder)); Out_Byte(IDE_CYLINDER_HIGH_REGISTER, HIGH_BYTE(cylinder)); Out_Byte(IDE_DRIVE_HEAD_REGISTER, IDE_DRIVE(driveNum) | head); Out_Byte(IDE_COMMAND_REGISTER, IDE_COMMAND_WRITE_SECTORS); /* wait for the drive */ while (In_Byte(IDE_STATUS_REGISTER) & IDE_STATUS_DRIVE_BUSY); bufferW = (short *)buffer; for (i = 0; i < 256; i++) { Out_Word(IDE_DATA_REGISTER, bufferW[i]); } if (ideDebug) Print("About to wait for Write \n"); /* wait for the drive */ while (In_Byte(IDE_STATUS_REGISTER) & IDE_STATUS_DRIVE_BUSY); if (In_Byte(IDE_STATUS_REGISTER) & IDE_STATUS_DRIVE_ERROR) { Print("ERROR: Got Read %d\n", In_Byte(IDE_STATUS_REGISTER)); return IDE_ERROR_DRIVE_ERROR; } if (reEnable) Enable_Interrupts(); return IDE_ERROR_NO_ERROR; }
/* * Read a block at the logical block number indicated. */ static int IDE_Read(int driveNum, int blockNum, char *buffer) { int i; int head; int sector; int cylinder; short *bufferW; int reEnable = 0; if(driveNum < 0 || driveNum > (numDrives - 1)) { if(ideDebug) Print("ide: invalid drive %d\n", driveNum); return IDE_ERROR_BAD_DRIVE; } if(blockNum < 0 || blockNum >= IDE_getNumBlocks(driveNum)) { if(ideDebug) Print("ide: invalid block %d\n", blockNum); return IDE_ERROR_INVALID_BLOCK; } /* now compute the head, cylinder, and sector */ sector = blockNum % drives[driveNum].num_SectorsPerTrack + 1; cylinder = blockNum / (drives[driveNum].num_Heads * drives[driveNum].num_SectorsPerTrack); head = (blockNum / drives[driveNum].num_SectorsPerTrack) % drives[driveNum].num_Heads; if(ideDebug >= 2) { Print("request to read block %d\n", blockNum); Print(" head %d, cylinder %d, sector %d\n", head, cylinder, sector); // Print (" cylinder %d\n", cylinder); // Print (" sector %d\n", sector); } #ifndef NS_INTERRUPTABLE_NO_GLOBAL_LOCK reEnable = Begin_Int_Atomic(); #endif Out_Byte(IDE_SECTOR_COUNT_REGISTER, 1); Out_Byte(IDE_SECTOR_NUMBER_REGISTER, sector); Out_Byte(IDE_CYLINDER_LOW_REGISTER, LOW_BYTE(cylinder)); Out_Byte(IDE_CYLINDER_HIGH_REGISTER, HIGH_BYTE(cylinder)); Out_Byte(IDE_DRIVE_HEAD_REGISTER, IDE_DRIVE(driveNum) | head); Out_Byte(IDE_COMMAND_REGISTER, IDE_COMMAND_READ_SECTORS); if(ideDebug > 2) Print("About to wait for Read \n"); /* wait for the drive */ while (In_Byte(IDE_STATUS_REGISTER) & IDE_STATUS_DRIVE_BUSY) ; if(In_Byte(IDE_STATUS_REGISTER) & IDE_STATUS_DRIVE_ERROR) { Print("ERROR: Got Read %d\n", In_Byte(IDE_STATUS_REGISTER)); return IDE_ERROR_DRIVE_ERROR; } if(ideDebug > 2) Print("got buffer \n"); bufferW = (short *)buffer; for(i = 0; i < 256; i++) { bufferW[i] = In_Word(IDE_DATA_REGISTER); } if(ideDebug > 2) Print("read buffer \n"); #ifndef NS_INTERRUPTABLE_NO_GLOBAL_LOCK End_Int_Atomic(reEnable); #endif return IDE_ERROR_NO_ERROR; }
void NE2000_Transmit(struct Net_Device *device, void *buffer, ulong_t length) { ulong_t baseAddr = device->baseAddr; KASSERT(!Interrupts_Enabled()); unsigned int i; unsigned int newLength = length >> 1; unsigned short *newBuffer = (unsigned short *)buffer; /* Make sure we aren't currently transmitting */ if (In_Byte(baseAddr + NE2K_CR) & NE2K_CR_TXP) { Print("ERROR - Currently transmitting\n"); return; } /* Reset the card */ NE2000_Reset(device); /* Set the Command Register */ Out_Byte(baseAddr + NE2K_CR, 0x22); /* Handle the read before write bug */ Out_Byte(baseAddr + NE2K0W_RBCR0, 0x42); Out_Byte(baseAddr + NE2K0W_RBCR1, 0x00); Out_Byte(baseAddr + NE2K0W_RSAR0, 0x42); Out_Byte(baseAddr + NE2K0W_RSAR1, 0x00); Out_Byte(baseAddr + NE2K_CR, NE2K_CR_DMA_RREAD + NE2K_CR_STA); Out_Byte(baseAddr + NE2K0R_ISR, NE2K_ISR_RDC); /* Load the packet size into the registers */ Out_Byte(baseAddr + NE2K0W_RBCR0, length & 0xFF); Out_Byte(baseAddr + NE2K0W_RBCR1, length >> 8); /* Load the page start into the RSARX registers */ Out_Byte(baseAddr + NE2K0W_RSAR0, 0x00); Out_Byte(baseAddr + NE2K0W_RSAR1, NE2K_TRANSMIT_PAGE); /* Start the remote write */ Out_Byte(baseAddr + NE2K_CR, NE2K_CR_DMA_RWRITE | NE2K_CR_STA); /* Write the data to the I/O port */ for (i = 0; i < newLength; ++i) { Out_Word(baseAddr + NE2K_IO_PORT, newBuffer[i]); } /* Send the last byte of data if we have an odd length */ if (length & 0x1) { Out_Word(baseAddr + NE2K_IO_PORT, ((uchar_t *) buffer)[length - 1]); } /* Wait for transmit remote DMA */ while ((In_Byte(baseAddr + NE2K0R_ISR) & NE2K_ISR_RDC) == 0) { Print("Waiting on remote DMA for transmit \n"); } /* Ack the interrupt */ Out_Byte(baseAddr + NE2K0R_ISR, NE2K_ISR_RDC); /* Now that Remote DMA is complete, set up the transmit */ /* Store the transmit page in the transmit register */ Out_Byte(baseAddr + NE2K0W_TPSR, NE2K_TRANSMIT_PAGE); /* Set transmit byte count */ Out_Byte(baseAddr + NE2K0W_TBCR0, length & 0xFF); Out_Byte(baseAddr + NE2K0W_TBCR1, length >> 8); /* Issue transmit command */ Out_Byte(baseAddr + NE2K_CR, NE2K_CR_NODMA | NE2K_CR_STA | NE2K_CR_TXP); device->txBytes += length; }
static int readDriveConfig(int drive) { int i; int status; short info[256]; char devname[BLOCKDEV_MAX_NAME_LEN]; int rc; if (ideDebug > 1) Print("ide: about to read drive config for drive #%d\n", drive); Out_Byte(IDE_DRIVE_HEAD_REGISTER, IDE_DRIVE(drive)); Out_Byte(IDE_COMMAND_REGISTER, IDE_COMMAND_IDENTIFY_DRIVE); while (In_Byte(IDE_STATUS_REGISTER) & IDE_STATUS_DRIVE_BUSY); status = In_Byte(IDE_STATUS_REGISTER); /* * simulate failure * status = 0x50; */ if ((status & IDE_STATUS_DRIVE_DATA_REQUEST)) { Print("ide: probe found ATA drive\n"); /* drive responded to ATA probe */ for (i = 0; i < 256; i++) { info[i] = In_Word(IDE_DATA_REGISTER); } drives[drive].num_Cylinders = info[IDE_INDENTIFY_NUM_CYLINDERS]; drives[drive].num_Heads = info[IDE_INDENTIFY_NUM_HEADS]; drives[drive].num_SectorsPerTrack = info[IDE_INDENTIFY_NUM_SECTORS_TRACK]; drives[drive].num_BytesPerSector = info[IDE_INDENTIFY_NUM_BYTES_SECTOR]; } else { /* try for ATAPI */ Out_Byte(IDE_FEATURE_REG, 0); /* disable dma & overlap */ Out_Byte(IDE_DRIVE_HEAD_REGISTER, IDE_DRIVE(drive)); Out_Byte(IDE_COMMAND_REGISTER, IDE_COMMAND_ATAPI_IDENT_DRIVE); while (In_Byte(IDE_STATUS_REGISTER) & IDE_STATUS_DRIVE_BUSY); status = In_Byte(IDE_STATUS_REGISTER); Print("status is %x\n", status); if ((status & IDE_STATUS_DRIVE_DATA_REQUEST)) { Print("ide: found atapi drive\n"); } else { Print("ide: found no drive %d\n", drive); } return -1; } Print(" ide%d: cyl=%d, heads=%d, sectors=%d\n", drive, drives[drive].num_Cylinders, drives[drive].num_Heads, drives[drive].num_SectorsPerTrack); /* Register the drive as a block device */ snprintf(devname, sizeof(devname), "ide%d", drive); rc = Register_Block_Device(devname, &s_ideDeviceOps, drive, 0, &s_ideWaitQueue, &s_ideRequestQueue); if (rc != 0) Print(" Error: could not create block device for %s\n", devname); return 0; }
static void Stop_Motor(int drive) { Out_Byte(FDC_DOR_REG, FDC_DOR_DMA_ENABLE | FDC_DOR_RESET_DISABLE | FDC_DOR_DRIVE_SELECT(0)); }
/* * Write a byte to the data register. */ static void Floppy_Out(uchar_t val) { Wait_For_MRQ(FDC_STATUS_READY_WRITE); Out_Byte(FDC_DATA_REG, val); }
void NE2000_Complete_Receive(struct Net_Device *device, struct Net_Device_Header *hdr) { /* Advance the boundary pointer */ Out_Byte(device->baseAddr + NE2K0W_BNRY, hdr->next); }
/* * Read a block at the logical block number indicated. */ int IDE_Read(int driveNum, int blockNum, char *buffer) { int i; int head; int sector; int cylinder; short *bufferW; if (driveNum < 0 || driveNum > (numDrives-1)) { return IDE_ERROR_BAD_DRIVE; } if (blockNum < 0 || blockNum >= IDE_getNumBlocks(driveNum)) { return IDE_ERROR_INVALID_BLOCK; } /* now compute the head, cylinder, and sector */ sector = blockNum % drives[driveNum].num_SectorsPerTrack + 1; cylinder = blockNum / (drives[driveNum].num_Heads * drives[driveNum].num_SectorsPerTrack); head = (blockNum / drives[driveNum].num_SectorsPerTrack) % drives[driveNum].num_Heads; if (ideDebug) { Print ("request to read block %d\n", blockNum); Print (" head %d\n", head); Print (" cylinder %d\n", cylinder); Print (" sector %d\n", sector); } Out_Byte(IDE_SECTOR_COUNT_REGISTER, 1); Out_Byte(IDE_SECTOR_NUMBER_REGISTER, sector); Out_Byte(IDE_CYLINDER_LOW_REGISTER, LOW_BYTE(cylinder)); Out_Byte(IDE_CYLINDER_HIGH_REGISTER, HIGH_BYTE(cylinder)); if (driveNum == 0) { Out_Byte(IDE_DRIVE_HEAD_REGISTER, IDE_DRIVE_0 | head); } else if (driveNum == 1) { Out_Byte(IDE_DRIVE_HEAD_REGISTER, IDE_DRIVE_1 | head); } Out_Byte(IDE_COMMAND_REGISTER, IDE_COMMAND_READ_SECTORS); if (ideDebug) Print("About to wait for Read \n"); /* wait for the drive */ while (!(In_Byte(IDE_STATUS_REGISTER) & IDE_STATUS_DRIVE_READY)); if (In_Byte(IDE_STATUS_REGISTER) & IDE_STATUS_DRIVE_ERROR) { Print("ERROR: Got Read %d\n", In_Byte(IDE_STATUS_REGISTER)); return IDE_ERROR_DRIVE_ERROR; } if (ideDebug) Print("got buffer \n"); bufferW = (short *) buffer; for (i=0; i < 256; i++) { bufferW[i] = In_Word(IDE_DATA_REGISTER); } return IDE_ERROR_NO_ERROR; }
/** * Initialize the DMA controllers. */ void Init_DMA(void) { Print("Initializing DMA Controller...\n"); /* Reset the controller */ Out_Byte(DMA_MASTER_CLEAR_REG, 0); }