+ 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;
+ txc->Desc.TXThreshold = 0; // TODO: What does this do on RHW?
+ txc->Desc.TBDCount = 0;
+ txc->Desc.CU.Command = CMD_Suspend|CMD_Tx;
+ // - Mark previous as not suspended
+ Card->TXCommands[ (txc_idx-1+NUM_TX) % NUM_TX ].Desc.CU.Command &= ~CMD_Suspend;
+
+ IPStack_Buffer_LockBuffer(Buffer);
+
+ // 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);
+
+ IPStack_Buffer_LockBuffer(Buffer);
+ IPStack_Buffer_UnlockBuffer(Buffer);
+
+ return 0;