+ tTXBufDesc *txb = &TXC->LocalBufs[*IndexPtr];
+ txb->Addr = Addr;
+ txb->Len = Len;
+ (*IndexPtr) ++;
+}
+
+int PRO100_SendPacket(void *Ptr, tIPStackBuffer *Buffer)
+{
+ tCard *Card = Ptr;
+
+ Semaphore_Wait(&Card->TXCommandSem, 1);
+
+ // Acquire a command buffer
+ Mutex_Acquire(&Card->lTXCommands);
+ int txc_idx = Card->CurTXIndex;
+ Card->CurTXIndex = (Card->CurTXIndex + 1) % NUM_TX;
+ Mutex_Release(&Card->lTXCommands);
+ tTXCommand *txc = &Card->TXCommands[txc_idx];
+
+ // Populate
+ int txb_idx = 0;
+ const void *ptr;
+ size_t len;
+ size_t total_size = 0;
+ int buf_idx = -1;
+ while( (buf_idx = IPStack_Buffer_GetBuffer(Buffer, buf_idx, &len, &ptr)) != -1 )
+ {
+ #if PHYS_BITS > 32
+ if( MM_GetPhysAddr(ptr) >> 32 ) {
+ // Need to bounce
+ TODO();
+ continue ;
+ }
+ #endif
+
+ ASSERTC(len, <, PAGE_SIZE);
+
+ // Check if buffer split is required
+ if( MM_GetPhysAddr((char*)ptr + len-1) != MM_GetPhysAddr(ptr)+len-1 )
+ {
+ // Need to split buffer
+ size_t space = PAGE_SIZE - ((tVAddr)ptr % PAGE_SIZE);
+ PRO100_int_SetBuf(txc, &txb_idx, MM_GetPhysAddr(ptr), space);
+ PRO100_int_SetBuf(txc, &txb_idx, MM_GetPhysAddr((char*)ptr+space), len-space);
+ }
+ else
+ {
+ // Single buffer
+ PRO100_int_SetBuf(txc, &txb_idx, MM_GetPhysAddr(ptr), len);
+ }
+
+ total_size += len;
+ }
+
+ // Set buffer pointer
+ Card->TXBuffers[txc_idx] = Buffer;
+ // Mark as usable
+ txc->Desc.TBDArrayAddr = 0xFFFFFFFF;
+ txc->Desc.TCBBytes = total_size | (1 << 15);
+ txc->Desc.TXThreshold = 3; // Start transmitting after 3*8 bytes
+ txc->Desc.TBDCount = 0;
+ txc->Desc.CU.Command = CMD_Suspend|CMD_Tx;
+ txc->Desc.CU.Status = 0;
+ IPStack_Buffer_LockBuffer(Buffer);
+ // - Mark previous as not suspended
+ Card->TXCommands[ (txc_idx-1+NUM_TX) % NUM_TX ].Desc.CU.Command &= ~CMD_Suspend;
+
+ LOG("Starting send on txc_idx=%i", txc_idx);
+ LOG("- REG_Status = %x", _Read8(Card, REG_Status));
+
+ // And dispatch
+ // - If currently running or idle, this should not matter
+ // NOTE: Qemu describes this behavior as 'broken'
+ _Write16(Card, REG_Command, CU_CMD_RESUME);
+ _FlushWait(Card, 4);
+
+ IPStack_Buffer_LockBuffer(Buffer);
+ IPStack_Buffer_UnlockBuffer(Buffer);
+
+ LOG("- CU Status = 0x%x", txc->Desc.CU.Status);
+
+ return 0;