static int nic_send_frame(snic *nic, frame_buffer *buffer) { unsigned int iobase = nic->iobase; if (buffer->len>MAX_FRSIZE) return ETOOBIG; outportg(0x00, iobase + INTERRUPTMASK); // Disable interrupts nic->tx_frame = tx_wait_pkt = buffer; nic->tx_frame->page = nic->pstart ; nic_block_output(nic,(struct frame_buffer *)nic->tx_frame); if(nic_send(nic)<0) { outportg(IMR_DEFAULT, iobase + INTERRUPTMASK); nic->tx_frame = NULL; return ERR; } outportg(IMR_DEFAULT, iobase + INTERRUPTMASK); return NOERR; }
/* TODO- Have it check how lonk a transmission is taking and attempt to restart the card if it's too long. */ int nic_send_packet(snic *nic, packet_buffer *buffer) { uint timeout; uint f; int iobase; /* kprintf("nic_send_packet()\n"); */ if(!buffer) return ERRARG; if(!buffer->count || !buffer->buf) return ERRARG; if(!nic || !nic->iobase) return ERR; iobase=nic->iobase; t(A); buffer->len=0; for(f=0;f<buffer->count;f++) buffer->len+=buffer->buf[f].len; if(buffer->len>MAX_LENGTH) return ERRTOOBIG; t(B); /* the following wait for anyother tasks that are calling // nic_send_packet() right now. Note that this doesn't use // an atomic semaphore, so something MAY leak through. */ /* timeout=ticks+10; wait 10 ticks */ timeout=ticks+100; while(nic->busy && ticks<=timeout) idle(); /* Replace this with a proper timeout thing that doesn't use the // ticks method which will be diffrent on each OS. */ t(C); if(nic->busy) { kprintf("NE2000: ERROR: Card stalled, timeout.\n"); return ERRTIMEOUT; } nic->busy=1; /* mark as busy, replace with semaphore */ t(D); outb_p(0x00, iobase + INTERRUPTMASK); /* mask ints for now */ t(E); timeout=ticks+TIMEOUT_TX; while(idle(), ticks<=timeout) for(f=0;f<MAX_TX;f++) { if(!nic->tx_packet[f]) { t(F); /* nic->tx_packet[f]=*buffer;*/ nic->tx_packet[f]=buffer; nic->tx_packet[f]->page=nic->pstart + (f * MAX_PAGESPERPACKET); /*output page */ /* kprintf("NE2000: sending packet with count:%x on page:%X with buffer:%x\n", buffer->count,buffer->page,buffer->buf); */ t(>); nic_block_output(nic,nic->tx_packet[f]); t(<); if(!nic->sending) { nic->send=f; nic->sending=1; /* now let's actually trigger the transmitter */ t(I); if(nic_send(nic,f)<0) { nic->sending=0; break; } /* note, the nic_tx() interrupt will mark this // tx_packet buffer as free again once it // confirms that the packet was sent. */ } t(J); nic->stat.tx_buffered++; outb_p(IMR_DEFAULT, iobase + INTERRUPTMASK); /* unmask */ nic->busy=0; /* V() */ t(K); return NOERR; } }