status_t device_write(void *data, off_t pos, const void *buffer, size_t *_length) { struct sis_info *info; status_t status; uint16 frameSize; int16 current; uint32 check; if (checkDeviceInfo(info = data) != B_OK) return EINVAL; //TRACE(("****\t%5ld: write... %lx, %ld (%d) thread: %ld, counter = %ld\n", counter++, buf, *len, info->txLock, threadID, intrCounter)); atomic_add(&info->txLock, 1); if (*_length > MAX_FRAME_SIZE) *_length = MAX_FRAME_SIZE; frameSize = *_length; current = info->txCurrent; //dprintf("\t%5ld: \twrite: tx: isr = %d, sent = %d, current = %d\n",counter++, // info->txInterruptIndex,info->txSent,info->txCurrent); // block until a free tx descriptor is available if ((status = acquire_sem_etc(info->txSem, 1, B_TIMEOUT, ETHER_TRANSMIT_TIMEOUT)) < B_NO_ERROR) { write32(info->registers + SiS900_MAC_COMMAND, SiS900_MAC_CMD_Tx_ENABLE); TRACE(("write: acquiring sem failed: %lx, %s\n", status, strerror(status))); atomic_add(&info->txLock, -1); return status; } check = info->txDescriptor[current].status; if (check & SiS900_DESCR_OWN) { // descriptor is still in use dprintf(DEVICE_NAME ": card owns buffer %d\n", current); atomic_add(&info->txLock, -1); return B_ERROR; } /* Copy data to tx buffer */ memcpy((void *)info->txBuffer[current], buffer, frameSize); info->txCurrent = (current + 1) & NUM_Tx_MASK; { cpu_status former; former = disable_interrupts(); acquire_spinlock(&info->txSpinlock); info->txDescriptor[current].status = SiS900_DESCR_OWN | frameSize; info->txSent++; #if 0 { struct buffer_desc *b = (void *)read32(info->registers + SiS900_MAC_Tx_DESCR); int16 that; dprintf("\twrite: status %d = %lx, sent = %d\n", current, info->txDescriptor[current].status,info->txSent); dprintf("write: %d: mem = %lx : hardware = %lx\n", current, physicalAddress(&info->txDescriptor[current],sizeof(struct buffer_desc)),read32(info->registers + SiS900_MAC_Tx_DESCR)); for (that = 0;that < NUM_Tx_DESCR && (void *)physicalAddress(&info->txDescriptor[that],sizeof(struct buffer_desc)) != b;that++); if (that == NUM_Tx_DESCR) { //dprintf("not in ring!\n"); that = 0; } dprintf("(hardware status %d = %lx)!\n", that, info->txDescriptor[that].status); } #endif release_spinlock(&info->txSpinlock); restore_interrupts(former); } // enable transmit state machine write32(info->registers + SiS900_MAC_COMMAND, SiS900_MAC_CMD_Tx_ENABLE); #ifdef EXCESSIVE_DEBUG acquire_sem(gIOLock); bug("\t\twrite last interrupts:\n"); { int ii; for (ii = (intrCounter-2) % 100; ii < intrCounter; ii = (ii + 1) % 100) bug("\t\t\t%ld: %08lx\n", ii, lastIntr[ii % 100]); } bug("\t\twrite block (%ld bytes) thread = %ld:\n", frameSize, threadID); dumpBlock(buf,frameSize, "\t\t\t"); release_sem(gIOLock); #endif atomic_add(&info->txLock, -1); return B_OK; }
Byte readByte(Word offset, int seg = -1) { return ram[physicalAddress(offset, seg) - 0x10000]; }
void writeByte(Byte value, Word offset, int seg = -1) { ram[physicalAddress(offset, seg) - 0x10000] = value; }
static int32 sis900_txInterrupt(struct sis_info *info) { int16 releaseTxSem = 0; uint32 status; int16 limit; acquire_spinlock(&info->txSpinlock); HACK(spin(10000)); for (limit = info->txSent; limit > 0; limit--) { status = info->txDescriptor[info->txInterruptIndex].status; //dprintf("txIntr: %d: mem = %lx : hardware = %lx\n",info->txInterruptIndex, // physicalAddress(&info->txDescriptor[info->txInterruptIndex],sizeof(struct buffer_desc)), // read32(info->registers + SiS900_MAC_Tx_DESCR)); /* Does the device generate extra interrupts? */ if (status & SiS900_DESCR_OWN) { struct buffer_desc *descriptor = (void *)read32(info->registers + SiS900_MAC_Tx_DESCR); int16 that; for (that = 0; that < NUM_Tx_DESCR && physicalAddress(&info->txDescriptor[that], sizeof(struct buffer_desc)) != (addr_t)descriptor; that++) { } if (that == NUM_Tx_DESCR) that = 0; //dprintf("tx busy %d: %lx (hardware status %d = %lx)!\n",info->txInterruptIndex,status,that,info->txDescriptor[that].status); // if (limit == info->txSent) // { //dprintf("oh no!\n"); // limit++; // continue; // } break; } if (status & (SiS900_DESCR_Tx_ABORT | SiS900_DESCR_Tx_UNDERRUN | SiS900_DESCR_Tx_OOW_COLLISION)) { dprintf("tx error: %lx\n", status); } else info->txDescriptor[info->txInterruptIndex].status = 0; releaseTxSem++; /* this many buffers are free */ info->txInterruptIndex = (info->txInterruptIndex + 1) & NUM_Tx_MASK; info->txSent--; if (info->txSent < 0 || info->txSent > NUM_Tx_DESCR) dprintf("ERROR interrupt: txSent = %d\n", info->txSent); } release_spinlock(&info->txSpinlock); if (releaseTxSem) { release_sem_etc(info->txSem, releaseTxSem, B_DO_NOT_RESCHEDULE); return B_INVOKE_SCHEDULER; } return B_HANDLED_INTERRUPT; }