ZealOS/docs/Home/Net/Drivers/PCNet.CC.html
TomAwezome 1b75d91002 Fix Mount AHCI Port selection.
Add arg to SATARep to specify drive types to show.
Add checks in AHCIPortInit to verify port signatures, add helper method to get signatures from port.
2021-08-02 16:40:05 -04:00

802 lines
76 KiB
HTML
Executable file

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=US-ASCII">
<meta name="generator" content="ZealOS V0.13">
<style type="text/css">
body {background-color:#fef1f0;}
.cF0{color:#000000;background-color:#fef1f0;}
.cF1{color:#0148a4;background-color:#fef1f0;}
.cF2{color:#3b7901;background-color:#fef1f0;}
.cF3{color:#057c7e;background-color:#fef1f0;}
.cF4{color:#bb2020;background-color:#fef1f0;}
.cF5{color:#9e42ae;background-color:#fef1f0;}
.cF6{color:#b57901;background-color:#fef1f0;}
.cF7{color:#b2b6af;background-color:#fef1f0;}
.cF8{color:#555753;background-color:#fef1f0;}
.cF9{color:#678fbb;background-color:#fef1f0;}
.cFA{color:#82bc49;background-color:#fef1f0;}
.cFB{color:#0097a2;background-color:#fef1f0;}
.cFC{color:#e26a6a;background-color:#fef1f0;}
.cFD{color:#c671bc;background-color:#fef1f0;}
.cFE{color:#c7ab00;background-color:#fef1f0;}
.cFF{color:#fef1f0;background-color:#fef1f0;}
</style>
</head>
<body>
<pre style="font-family:monospace;font-size:12pt">
<a name="l1"></a><span class=cF2>/*</span><span class=cF0> </span><span class=cF2>AMD PCNetII Driver</span><span class=cF0>
<a name="l2"></a> </span><span class=cF2>Author: TomAwezome</span><span class=cF0>
<a name="l3"></a>
<a name="l4"></a> </span><span class=cF2>Driver is based on:</span><span class=cF0>
<a name="l5"></a> </span><span class=cF2>-</span><span class=cF0> </span><span class=cF2>minexew's ShrineOS PCNet.CC implementation</span><span class=cF0>
<a name="l6"></a> </span><span class=cF2>-</span><span class=cF0> </span><span class=cF2>OSDev AMD_PCNET documentation</span><span class=cF0>
<a name="l7"></a> </span><span class=cF2>-</span><span class=cF0> </span><span class=cF2>AMD PCnet(TM)-PCI datasheet</span><span class=cF0>
<a name="l8"></a> </span><span class=cF2>-</span><span class=cF0> </span><span class=cF2>any other useful sources.</span><span class=cF0>
<a name="l9"></a>
<a name="l10"></a> </span><span class=cF2>Guidelines:</span><span class=cF0>
<a name="l11"></a> </span><span class=cF2>-</span><span class=cF0> </span><span class=cF2>Magic numbers are bad. #defines are good.</span><span class=cF0>
<a name="l12"></a> </span><span class=cF2>-</span><span class=cF0> </span><span class=cF2>Understandability over LOC.</span><span class=cF0>
<a name="l13"></a> </span><span class=cF2>-</span><span class=cF0> </span><span class=cF2>Clear documentation.</span><span class=cF0>
<a name="l14"></a></span><span class=cF2>*/</span><span class=cF0>
<a name="l15"></a>
<a name="l16"></a></span><span class=cF2>//#define</span><span class=cF0> </span><span class=cF2>PCNET_DEVICE_ID</span><span class=cF0> </span><span class=cF2>0x2000</span><span class=cF0>
<a name="l17"></a></span><span class=cF2>//#define</span><span class=cF0> </span><span class=cF2>PCNET_VENDOR_ID</span><span class=cF0> </span><span class=cF2>0x1022</span><span class=cF0>
<a name="l18"></a>
<a name="l19"></a></span><span class=cF2>//#define</span><span class=cF0> </span><span class=cF2>PCI_REG_COMMAND</span><span class=cF0> </span><span class=cF2>0x04</span><span class=cF0>
<a name="l20"></a>
<a name="l21"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CMDf_IOEN </span><span class=cFE>0</span><span class=cF0>
<a name="l22"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CMDf_BMEN </span><span class=cFE>2</span><span class=cF0>
<a name="l23"></a>
<a name="l24"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CMDF_IOEN (</span><span class=cFE>1</span><span class=cF0> &lt;&lt; PCNET_CMDf_IOEN)
<a name="l25"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CMDF_BMEN (</span><span class=cFE>1</span><span class=cF0> &lt;&lt; PCNET_CMDf_BMEN)
<a name="l26"></a>
<a name="l27"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_WD_RESET </span><span class=cFE>0x14</span><span class=cF0> </span><span class=cF2>// reset reg location when card is in 16-bit mode</span><span class=cF0>
<a name="l28"></a>
<a name="l29"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_DW_RDP </span><span class=cFE>0x10</span><span class=cF0>
<a name="l30"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_DW_RAP </span><span class=cFE>0x14</span><span class=cF0>
<a name="l31"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_DW_RESET </span><span class=cFE>0x18</span><span class=cF0> </span><span class=cF2>// reset reg location when card is in 32-bit mode</span><span class=cF0>
<a name="l32"></a>
<a name="l33"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CSR_CTRLSTATUS </span><span class=cFE>0</span><span class=cF0>
<a name="l34"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CSR_INTERRUPTS </span><span class=cFE>3</span><span class=cF0>
<a name="l35"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CSR_FEATURECTRL </span><span class=cFE>4</span><span class=cF0>
<a name="l36"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CSR_LADRF0 </span><span class=cFE>8</span><span class=cF0>
<a name="l37"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CSR_LADRF1 </span><span class=cFE>9</span><span class=cF0>
<a name="l38"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CSR_LADRF2 </span><span class=cFE>10</span><span class=cF0>
<a name="l39"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CSR_LADRF3 </span><span class=cFE>11</span><span class=cF0>
<a name="l40"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CSR_PADR0 </span><span class=cFE>12</span><span class=cF0>
<a name="l41"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CSR_PADR1 </span><span class=cFE>13</span><span class=cF0>
<a name="l42"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CSR_PADR2 </span><span class=cFE>14</span><span class=cF0>
<a name="l43"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CSR_MODE </span><span class=cFE>15</span><span class=cF0>
<a name="l44"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CSR_BADRL </span><span class=cFE>24</span><span class=cF0>
<a name="l45"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CSR_BADRU </span><span class=cFE>25</span><span class=cF0>
<a name="l46"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CSR_BADTL </span><span class=cFE>30</span><span class=cF0>
<a name="l47"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CSR_BADTU </span><span class=cFE>31</span><span class=cF0>
<a name="l48"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CSR_POLLINT </span><span class=cFE>47</span><span class=cF0>
<a name="l49"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CSR_SOFTWARESTYLE </span><span class=cFE>58</span><span class=cF0>
<a name="l50"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CSR_RXRINGLEN </span><span class=cFE>76</span><span class=cF0>
<a name="l51"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CSR_TXRINGLEN </span><span class=cFE>78</span><span class=cF0>
<a name="l52"></a>
<a name="l53"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_SWSTYLE_SELECTION </span><span class=cFE>2</span><span class=cF0> </span><span class=cF2>// (value, not bit) AMD PCNet datasheet p. 1-968</span><span class=cF0>
<a name="l54"></a>
<a name="l55"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_SWSTYLE_SSIZE32 </span><span class=cFE>8</span><span class=cF0> </span><span class=cF2>// Bit 8 of SWSTYLE</span><span class=cF0>
<a name="l56"></a>
<a name="l57"></a></span><span class=cF2>// Refer to AMD PCNet datasheet p. 1-954, 1-956, 1-957 for Interrupt Mask details.</span><span class=cF0>
<a name="l58"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_INT_BSWP </span><span class=cFE>2</span><span class=cF0> </span><span class=cF2>// Byte Swap (Big-Endian / Little-Endian)</span><span class=cF0>
<a name="l59"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_INT_IDONM </span><span class=cFE>8</span><span class=cF0> </span><span class=cF2>// Initialization Done Mask</span><span class=cF0>
<a name="l60"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_INT_TINTM </span><span class=cFE>9</span><span class=cF0> </span><span class=cF2>// Transmit Interrupt Mask</span><span class=cF0>
<a name="l61"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_INT_RINTM </span><span class=cFE>10</span><span class=cF0> </span><span class=cF2>// Receive Interrupt Mask</span><span class=cF0>
<a name="l62"></a>
<a name="l63"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_FEATURE_APADXMT </span><span class=cFE>11</span><span class=cF0>
<a name="l64"></a>
<a name="l65"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CTRL_INIT </span><span class=cFE>0</span><span class=cF0>
<a name="l66"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CTRL_STRT </span><span class=cFE>1</span><span class=cF0>
<a name="l67"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CTRL_STOP </span><span class=cFE>2</span><span class=cF0>
<a name="l68"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_CTRL_RINT </span><span class=cFE>10</span><span class=cF0>
<a name="l69"></a>
<a name="l70"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_RX_BUFF_COUNT </span><span class=cFE>32</span><span class=cF0> </span><span class=cF2>// Linux &amp; Shrine Driver use 32 and 8 for</span><span class=cF0>
<a name="l71"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_TX_BUFF_COUNT </span><span class=cFE>8</span><span class=cF0> </span><span class=cF2>// these, we could allow more if wanted.</span><span class=cF0>
<a name="l72"></a>
<a name="l73"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_DESCRIPTORf_ENP </span><span class=cFE>24</span><span class=cF0>
<a name="l74"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_DESCRIPTORf_STP </span><span class=cFE>25</span><span class=cF0>
<a name="l75"></a>#</span><span class=cF1>define</span><span class=cF0> PCNET_DESCRIPTORf_OWN </span><span class=cFE>31</span><span class=cF0> </span><span class=cF2>// AMD PCNet datasheet p.1-992, 1-994</span><span class=cF0>
<a name="l76"></a>
<a name="l77"></a></span><span class=cF1>class</span><span class=cF0> CPCNet
<a name="l78"></a>{
<a name="l79"></a> </span><span class=cF9>CPCIDev</span><span class=cF0> *pci;
<a name="l80"></a>
<a name="l81"></a> </span><span class=cF1>U8</span><span class=cF0> mac_address[</span><span class=cFE>6</span><span class=cF0>]; </span><span class=cF2>// MAC address is first 6 bytes of PCNet EEPROM</span><span class=cF0> </span><span class=cF2>(page # ? )</span><span class=cF0>
<a name="l82"></a>
<a name="l83"></a> </span><span class=cF9>I64</span><span class=cF0> current_rx_de_index; </span><span class=cF2>// Current Receive DE being processed. Gets incremented, wrapped to 0 at max of PCNET_RX_BUFF_COUNT.</span><span class=cF0>
<a name="l84"></a> </span><span class=cF9>I64</span><span class=cF0> current_tx_de_index; </span><span class=cF2>// Current Transmit DE being processed. Gets incremented, wrapped to 0 at max of PCNET_TX_BUFF_COUNT.</span><span class=cF0>
<a name="l85"></a>
<a name="l86"></a> </span><span class=cF1>U8</span><span class=cF0> *rx_de_buffer; </span><span class=cF2>// Uncached-alias of pointer to the buffer of RX Descriptor Entries.</span><span class=cF0>
<a name="l87"></a> </span><span class=cF1>U8</span><span class=cF0> *tx_de_buffer; </span><span class=cF2>// Uncached-alias of pointer to the buffer of TX Descriptor Entries.</span><span class=cF0>
<a name="l88"></a> </span><span class=cF1>U8</span><span class=cF0> *rx_de_buffer_phys; </span><span class=cF2>// Pointer to the buffer of RX Descriptor Entries. (Code Heap, lower 2Gb)</span><span class=cF0>
<a name="l89"></a> </span><span class=cF1>U8</span><span class=cF0> *tx_de_buffer_phys; </span><span class=cF2>// Pointer to the buffer of TX Descriptor Entries. (Code Heap, lower 2Gb)</span><span class=cF0>
<a name="l90"></a>
<a name="l91"></a> </span><span class=cF9>U32</span><span class=cF0> rx_buffer_addr; </span><span class=cF2>// Uncached-alias of address of receive buffers.</span><span class=cF0>
<a name="l92"></a> </span><span class=cF9>U32</span><span class=cF0> tx_buffer_addr; </span><span class=cF2>// Uncached-alias of address of transmit buffers.</span><span class=cF0>
<a name="l93"></a> </span><span class=cF9>U32</span><span class=cF0> rx_buffer_addr_phys; </span><span class=cF2>// Physical address of actual receive buffers (&lt; 4 Gb)</span><span class=cF0>
<a name="l94"></a> </span><span class=cF9>U32</span><span class=cF0> tx_buffer_addr_phys; </span><span class=cF2>// Physical address of actual transmit buffers (&lt; 4 Gb)</span><span class=cF0>
<a name="l95"></a>
<a name="l96"></a>} pcnet; </span><span class=cF2>// pcnet is the global variable we store all of this into.</span><span class=cF0>
<a name="l97"></a>
<a name="l98"></a></span><span class=cF1>class</span><span class=cF0> CPCNetDescriptorEntry
<a name="l99"></a>{</span><span class=cF2>/* AMD PCNet datasheet p.1-991 &amp; p.1-994 NOTE: chart typo on 1-994, see ONES and BCNT on 1-995.</span><span class=cF0>
<a name="l100"></a> </span><span class=cF2>TX and RX DE's are the same size (16-Bytes) and structure,</span><span class=cF0>
<a name="l101"></a> </span><span class=cF2>but have different registers and functions.</span><span class=cF0>
<a name="l102"></a> </span><span class=cF2>The RX and TX DE buffers of the CPCNet class</span><span class=cF0>
<a name="l103"></a> </span><span class=cF2>are allocated to a certain amount of these DEs. */</span><span class=cF0>
<a name="l104"></a>
<a name="l105"></a> </span><span class=cF9>U32</span><span class=cF0> buffer_addr;
<a name="l106"></a> </span><span class=cF9>U32</span><span class=cF0> status1;
<a name="l107"></a> </span><span class=cF9>U32</span><span class=cF0> status2;
<a name="l108"></a> </span><span class=cF9>U32</span><span class=cF0> reserved;
<a name="l109"></a>};
<a name="l110"></a>
<a name="l111"></a></span><span class=cF1>class</span><span class=cF0> CPCNetBufferSetup
<a name="l112"></a>{
<a name="l113"></a> </span><span class=cF9>U16</span><span class=cF0> mode;
<a name="l114"></a> </span><span class=cF1>U8</span><span class=cF0> rlen;
<a name="l115"></a> </span><span class=cF1>U8</span><span class=cF0> tlen;
<a name="l116"></a> </span><span class=cF1>U8</span><span class=cF0> mac[</span><span class=cFE>6</span><span class=cF0>];
<a name="l117"></a> </span><span class=cF9>U16</span><span class=cF0> reserved;
<a name="l118"></a> </span><span class=cF1>U8</span><span class=cF0> ladr[</span><span class=cFE>8</span><span class=cF0>];
<a name="l119"></a> </span><span class=cF9>U32</span><span class=cF0> rxbuf;
<a name="l120"></a> </span><span class=cF9>U32</span><span class=cF0> txbuf;
<a name="l121"></a>};
<a name="l122"></a>
<a name="l123"></a></span><span class=cF9>CPCIDev</span><span class=cF0> *PCNetPCIDevFind()
<a name="l124"></a>{</span><span class=cF2>// Find and return PCNetII card as a CPCIDev pointer.</span><span class=cF0>
<a name="l125"></a>
<a name="l126"></a> </span><span class=cF1>return</span><span class=cF0> </span><span class=cF5>PCIDevFind</span><span class=cF0>(,, PCIV_PCNET, PCID_PCNET);
<a name="l127"></a>}
<a name="l128"></a>
<a name="l129"></a></span><span class=cF9>U32</span><span class=cF0> PCNetIOBaseGet()
<a name="l130"></a>{</span><span class=cF2>/* Return memory IO base address</span><span class=cF0>
<a name="l131"></a> </span><span class=cF2>of PCNet card. Bits 0-4 are not</span><span class=cF0>
<a name="l132"></a> </span><span class=cF2>for the IO base, so an AND with</span><span class=cF0>
<a name="l133"></a> </span><span class=cF2>~0x1F ignores those bits. */</span><span class=cF0>
<a name="l134"></a>
<a name="l135"></a> </span><span class=cF9>U32</span><span class=cF0> io_base = pcnet.pci-&gt;base[</span><span class=cFE>0</span><span class=cF0>] &amp; ~</span><span class=cFE>0x1F</span><span class=cF0>;
<a name="l136"></a> </span><span class=cF1>return</span><span class=cF0> io_base;
<a name="l137"></a>}
<a name="l138"></a>
<a name="l139"></a></span><span class=cF1>U0</span><span class=cF0> PCNetReset()
<a name="l140"></a>{</span><span class=cF2>/* Reads the 32- and 16-bit RESET registers,</span><span class=cF0>
<a name="l141"></a> </span><span class=cF2>which, regardless of which mode the card is in,</span><span class=cF0>
<a name="l142"></a> </span><span class=cF2>will reset it back to 16-bit mode. */</span><span class=cF0>
<a name="l143"></a>
<a name="l144"></a> </span><span class=cF5>InU32</span><span class=cF0>(PCNetIOBaseGet + PCNET_DW_RESET);
<a name="l145"></a> </span><span class=cF5>InU16</span><span class=cF0>(PCNetIOBaseGet + PCNET_WD_RESET);
<a name="l146"></a> </span><span class=cF5>Busy</span><span class=cF0>(</span><span class=cFE>5</span><span class=cF0>); </span><span class=cF2>// OSDev says minimum 1 uS</span><span class=cF0>
<a name="l147"></a>}
<a name="l148"></a>
<a name="l149"></a></span><span class=cF1>U0</span><span class=cF0> PCNet32BitModeEnable()
<a name="l150"></a>{</span><span class=cF2>/* AMD PCNet datasheet p. 1-930</span><span class=cF0>
<a name="l151"></a> </span><span class=cF2>Summary: A 32-bit write (while in 16-bit mode)</span><span class=cF0>
<a name="l152"></a> </span><span class=cF2>to RDP will cause 16-bit mode exit</span><span class=cF0>
<a name="l153"></a> </span><span class=cF2>and immediate enter into 32-bit mode. */</span><span class=cF0>
<a name="l154"></a>
<a name="l155"></a> </span><span class=cF5>OutU32</span><span class=cF0>(PCNetIOBaseGet + PCNET_DW_RDP, </span><span class=cFE>0</span><span class=cF0>);
<a name="l156"></a>}
<a name="l157"></a>
<a name="l158"></a></span><span class=cF1>U0</span><span class=cF0> PCNetRAPWrite(</span><span class=cF9>U32</span><span class=cF0> value)
<a name="l159"></a>{</span><span class=cF2>/* AMD PCNet datasheet p. 1-952</span><span class=cF0>
<a name="l160"></a> </span><span class=cF2>Summary: Register Address Pointer register</span><span class=cF0>
<a name="l161"></a> </span><span class=cF2>value will indicate which CSR / BCR register</span><span class=cF0>
<a name="l162"></a> </span><span class=cF2>we want to access in RDP / BDP. */</span><span class=cF0>
<a name="l163"></a>
<a name="l164"></a> </span><span class=cF5>OutU32</span><span class=cF0>(PCNetIOBaseGet + PCNET_DW_RAP, value);
<a name="l165"></a>}
<a name="l166"></a>
<a name="l167"></a></span><span class=cF1>U0</span><span class=cF0> PCNetCSRWrite(</span><span class=cF9>U32</span><span class=cF0> csr, </span><span class=cF9>U32</span><span class=cF0> value)
<a name="l168"></a>{</span><span class=cF2>/* AMD PCNet datasheet p. 1-952</span><span class=cF0>
<a name="l169"></a> </span><span class=cF2>Summary: Control and Status Registers are</span><span class=cF0>
<a name="l170"></a> </span><span class=cF2>accessed via the RDP (Register Data Port).</span><span class=cF0>
<a name="l171"></a> </span><span class=cF2>Which CSR is selected is based on the value</span><span class=cF0>
<a name="l172"></a> </span><span class=cF2>in the RAP. */</span><span class=cF0>
<a name="l173"></a>
<a name="l174"></a> PCNetRAPWrite(csr);
<a name="l175"></a> </span><span class=cF5>OutU32</span><span class=cF0>(PCNetIOBaseGet + PCNET_DW_RDP, value);
<a name="l176"></a>}
<a name="l177"></a>
<a name="l178"></a></span><span class=cF9>U32</span><span class=cF0> PCNetCSRRead(</span><span class=cF9>U32</span><span class=cF0> csr)
<a name="l179"></a>{</span><span class=cF2>/* AMD PCNet datasheet p. 1-952</span><span class=cF0>
<a name="l180"></a> </span><span class=cF2>Summary: Control and Status Registers are</span><span class=cF0>
<a name="l181"></a> </span><span class=cF2>accessed via the RDP (Register Data Port).</span><span class=cF0>
<a name="l182"></a> </span><span class=cF2>Which CSR is selected is based on the value</span><span class=cF0>
<a name="l183"></a> </span><span class=cF2>in the RAP. */</span><span class=cF0>
<a name="l184"></a>
<a name="l185"></a> PCNetRAPWrite(csr);
<a name="l186"></a> </span><span class=cF1>return</span><span class=cF0> </span><span class=cF5>InU32</span><span class=cF0>(PCNetIOBaseGet + PCNET_DW_RDP);
<a name="l187"></a>}
<a name="l188"></a>
<a name="l189"></a></span><span class=cF1>U0</span><span class=cF0> PCNetSWStyleSet()
<a name="l190"></a>{</span><span class=cF2>/* AMD PCNet datasheet p. 1-968</span><span class=cF0>
<a name="l191"></a> </span><span class=cF2>In CSR58 (Software Style), the 8-bit</span><span class=cF0>
<a name="l192"></a> </span><span class=cF2>SWSTYLE register dictates interpretation of certain</span><span class=cF0>
<a name="l193"></a> </span><span class=cF2>bits in the CSR space, and widths of descriptors and</span><span class=cF0>
<a name="l194"></a> </span><span class=cF2>initialization block. In PCINet-PCI mode, CSR4 bits</span><span class=cF0>
<a name="l195"></a> </span><span class=cF2>function as defined in the datasheet , and TMD1[29]</span><span class=cF0>
<a name="l196"></a> </span><span class=cF2>functions as ADD_FCS. */</span><span class=cF0>
<a name="l197"></a>
<a name="l198"></a> </span><span class=cF9>U32</span><span class=cF0> csr = PCNetCSRRead(PCNET_CSR_SOFTWARESTYLE);
<a name="l199"></a>
<a name="l200"></a> csr &amp;= ~</span><span class=cFE>0xFF</span><span class=cF0>; </span><span class=cF2>// clears first 8 bits: SWSTYLE 8-bit register.</span><span class=cF0>
<a name="l201"></a> csr |= PCNET_SWSTYLE_SELECTION; </span><span class=cF2>// set SWSTYLE to PCNet-PCI mode.</span><span class=cF0>
<a name="l202"></a> </span><span class=cF5>Bts</span><span class=cF0>(&amp;csr, PCNET_SWSTYLE_SSIZE32); </span><span class=cF2>// set SSIZE32 bit 1</span><span class=cF0>
<a name="l203"></a>
<a name="l204"></a> PCNetCSRWrite(PCNET_CSR_SOFTWARESTYLE, csr);
<a name="l205"></a>}
<a name="l206"></a>
<a name="l207"></a></span><span class=cF1>U0</span><span class=cF0> PCNetMACGet()
<a name="l208"></a>{</span><span class=cF2>/* AMD PCNet datasheet p. 1-887, 1-931, 1-937</span><span class=cF0>
<a name="l209"></a> </span><span class=cF2>MAC address stored at first 6 bytes of PCNet EEPROM.</span><span class=cF0>
<a name="l210"></a> </span><span class=cF2>EEPROM addresses shadow-copied to APROM at hardware init.</span><span class=cF0>
<a name="l211"></a> </span><span class=cF2>APROM accessible at first 16 bytes of PCI IO space. */</span><span class=cF0>
<a name="l212"></a>
<a name="l213"></a> </span><span class=cF9>I64</span><span class=cF0> i;
<a name="l214"></a> NetLog(</span><span class=cF6>&quot;PCNET GET MAC: Getting VM MAC.&quot;</span><span class=cF0>);
<a name="l215"></a> </span><span class=cF1>for</span><span class=cF0> (i = </span><span class=cFE>0</span><span class=cF0>; i &lt; </span><span class=cFE>6</span><span class=cF0>; i++)
<a name="l216"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l217"></a> pcnet.mac_address[i] = </span><span class=cF5>InU8</span><span class=cF0>(PCNetIOBaseGet + i);
<a name="l218"></a> NetLog(</span><span class=cF6>&quot; %02X&quot;</span><span class=cF0>, pcnet.mac_address[i]);
<a name="l219"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l220"></a>}
<a name="l221"></a>
<a name="l222"></a></span><span class=cF1>U0</span><span class=cF0> PCNetDescriptorEntryInit(CPCNetDescriptorEntry *entry, </span><span class=cF9>U32</span><span class=cF0> buffer_address, </span><span class=cF9>I64</span><span class=cF0> is_rx)
<a name="l223"></a>{
<a name="l224"></a> </span><span class=cF9>U16</span><span class=cF0> buffer_byte_count;
<a name="l225"></a>
<a name="l226"></a> entry-&gt;buffer_addr = buffer_address;
<a name="l227"></a>
<a name="l228"></a> </span><span class=cF2>/*</span><span class=cF0> </span><span class=cF2>AMD PCNet datasheet p.1-991.</span><span class=cF0>
<a name="l229"></a> </span><span class=cF2>BCNT is the usable buffer length, expressed as first</span><span class=cF0>
<a name="l230"></a> </span><span class=cF2>12 bits of 2s-complement of desired length.</span><span class=cF0>
<a name="l231"></a> </span><span class=cF2>Bits 0-11 of a DE are for the buffer byte count (BCNT),</span><span class=cF0>
<a name="l232"></a> </span><span class=cF2>and bits 12-15 of a DE must be written all ones (ONES) */</span><span class=cF0>
<a name="l233"></a>
<a name="l234"></a> buffer_byte_count = -ETHERNET_FRAME_SIZE; </span><span class=cF2>// Sets up as 2s complement of the desired length.</span><span class=cF0>
<a name="l235"></a> buffer_byte_count &amp;= </span><span class=cFE>0x0FFF</span><span class=cF0>; </span><span class=cF2>// Masks 0 over everything except bits 0-11.</span><span class=cF0>
<a name="l236"></a>
<a name="l237"></a> entry-&gt;status1 |= buffer_byte_count; </span><span class=cF2>// Sets BCNT reg (first 12 bits) in DE TMD1/RMD1.</span><span class=cF0>
<a name="l238"></a> entry-&gt;status1 |= </span><span class=cFE>0xF000</span><span class=cF0>; </span><span class=cF2>// Sets bits 12-15 (ONES) in DE TMD1/RMD1 as all ones.</span><span class=cF0>
<a name="l239"></a>
<a name="l240"></a> </span><span class=cF2>//if this is a Receive DE, give ownership to the card so the PCNet can fill them.</span><span class=cF0>
<a name="l241"></a> </span><span class=cF1>if</span><span class=cF0> (is_rx)
<a name="l242"></a> </span><span class=cF5>Bts</span><span class=cF0>(&amp;entry-&gt;status1, PCNET_DESCRIPTORf_OWN);
<a name="l243"></a>}
<a name="l244"></a>
<a name="l245"></a></span><span class=cF1>U0</span><span class=cF0> PCNetBuffersAllocate()
<a name="l246"></a>{
<a name="l247"></a> </span><span class=cF9>I64</span><span class=cF0> de_index; </span><span class=cF2>// used in for loops for TX and RX DE access.</span><span class=cF0>
<a name="l248"></a>
<a name="l249"></a> </span><span class=cF2>/*</span><span class=cF0> </span><span class=cF2>AMD PCNet datasheet p.1-913, p.1-990</span><span class=cF0>
<a name="l250"></a> </span><span class=cF2>When SSIZE32=1, Descriptor Ring Entry Base Address</span><span class=cF0>
<a name="l251"></a> </span><span class=cF2>must be on 16-byte boundary. (TDRA[3:0]=0, RDRA[3:0]=0) */</span><span class=cF0>
<a name="l252"></a>
<a name="l253"></a> pcnet.rx_de_buffer_phys = </span><span class=cF5>CAllocAligned</span><span class=cF0>(</span><span class=cF1>sizeof</span><span class=cF7>(</span><span class=cF0>CPCNetDescriptorEntry</span><span class=cF7>)</span><span class=cF0> * PCNET_RX_BUFF_COUNT,
<a name="l254"></a> </span><span class=cFE>16</span><span class=cF0>,
<a name="l255"></a> </span><span class=cF5>Fs</span><span class=cF0>-&gt;code_heap);
<a name="l256"></a>
<a name="l257"></a> pcnet.tx_de_buffer_phys = </span><span class=cF5>CAllocAligned</span><span class=cF0>(</span><span class=cF1>sizeof</span><span class=cF7>(</span><span class=cF0>CPCNetDescriptorEntry</span><span class=cF7>)</span><span class=cF0> * PCNET_TX_BUFF_COUNT,
<a name="l258"></a> </span><span class=cFE>16</span><span class=cF0>,
<a name="l259"></a> </span><span class=cF5>Fs</span><span class=cF0>-&gt;code_heap);
<a name="l260"></a>
<a name="l261"></a> </span><span class=cF2>//Shrine does a check and returns -1 here, if the end of either buffer exceeds 0x100000000</span><span class=cF0>
<a name="l262"></a>
<a name="l263"></a> pcnet.rx_de_buffer = </span><span class=cFB>dev</span><span class=cF0>.uncached_alias + pcnet.rx_de_buffer_phys; </span><span class=cF2>// we want uncached</span><span class=cF0>
<a name="l264"></a> pcnet.tx_de_buffer = </span><span class=cFB>dev</span><span class=cF0>.uncached_alias + pcnet.tx_de_buffer_phys; </span><span class=cF2>// access to these.</span><span class=cF0>
<a name="l265"></a>
<a name="l266"></a> pcnet.rx_buffer_addr_phys = </span><span class=cF5>CAlloc</span><span class=cF0>(ETHERNET_FRAME_SIZE * PCNET_RX_BUFF_COUNT, </span><span class=cF5>Fs</span><span class=cF0>-&gt;code_heap);
<a name="l267"></a>
<a name="l268"></a> pcnet.tx_buffer_addr_phys = </span><span class=cF5>CAlloc</span><span class=cF0>(ETHERNET_FRAME_SIZE * PCNET_TX_BUFF_COUNT, </span><span class=cF5>Fs</span><span class=cF0>-&gt;code_heap);
<a name="l269"></a>
<a name="l270"></a> </span><span class=cF2>//Shrine does a check and returns -1 here, if the end of either buffer exceeds 0x100000000</span><span class=cF0>
<a name="l271"></a>
<a name="l272"></a> pcnet.rx_buffer_addr = </span><span class=cFB>dev</span><span class=cF0>.uncached_alias + pcnet.rx_buffer_addr_phys;
<a name="l273"></a> pcnet.tx_buffer_addr = </span><span class=cFB>dev</span><span class=cF0>.uncached_alias + pcnet.tx_buffer_addr_phys;
<a name="l274"></a>
<a name="l275"></a> CPCNetDescriptorEntry *entry = pcnet.rx_de_buffer;
<a name="l276"></a> </span><span class=cF1>for</span><span class=cF0> (de_index = </span><span class=cFE>0</span><span class=cF0>; de_index &lt; PCNET_RX_BUFF_COUNT; de_index++)
<a name="l277"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l278"></a> PCNetDescriptorEntryInit(&amp;entry[de_index],
<a name="l279"></a> pcnet.rx_buffer_addr + de_index * ETHERNET_FRAME_SIZE,
<a name="l280"></a> </span><span class=cF3>TRUE</span><span class=cF0>); </span><span class=cF2>// TRUE for is_rx.</span><span class=cF0>
<a name="l281"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l282"></a>
<a name="l283"></a> entry = pcnet.tx_de_buffer;
<a name="l284"></a> </span><span class=cF1>for</span><span class=cF0> (de_index = </span><span class=cFE>0</span><span class=cF0>; de_index &lt; PCNET_TX_BUFF_COUNT; de_index++)
<a name="l285"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l286"></a> PCNetDescriptorEntryInit(&amp;entry[de_index],
<a name="l287"></a> pcnet.tx_buffer_addr + de_index * ETHERNET_FRAME_SIZE,
<a name="l288"></a> </span><span class=cF3>FALSE</span><span class=cF0>); </span><span class=cF2>// FALSE for is_rx.</span><span class=cF0>
<a name="l289"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l290"></a>}
<a name="l291"></a>
<a name="l292"></a></span><span class=cF2>/*</span><span class=cF0>
<a name="l293"></a></span><span class=cF2>U0 PCNetDirectInit()</span><span class=cF0>
<a name="l294"></a></span><span class=cF2>{/* AMD PCNet datasheet p. 1-1021</span><span class=cF0>
<a name="l295"></a> </span><span class=cF2>Instead of setting up initialization block,</span><span class=cF0>
<a name="l296"></a> </span><span class=cF2>direct writes to the necessary CSRs can be</span><span class=cF0>
<a name="l297"></a> </span><span class=cF2>used to manually initialize the PCNet card. */</span><span class=cF0>
<a name="l298"></a>
<a name="l299"></a> </span><span class=cF2>/*</span><span class=cF0> </span><span class=cF2>AMD PCNet datasheet p.1-991</span><span class=cF0>
<a name="l300"></a> </span><span class=cF2>If Logical Address Filter is set as</span><span class=cF0>
<a name="l301"></a> </span><span class=cF2>all 0, all incoming logical addresses</span><span class=cF0>
<a name="l302"></a> </span><span class=cF2>are rejected. Disables multicast. */</span><span class=cF0>
<a name="l303"></a> </span><span class=cF2>PCNetCSRWrite(PCNET_CSR_LADRF0, 0);</span><span class=cF0>
<a name="l304"></a> </span><span class=cF2>PCNetCSRWrite(PCNET_CSR_LADRF1, 0);</span><span class=cF0>
<a name="l305"></a> </span><span class=cF2>PCNetCSRWrite(PCNET_CSR_LADRF2, 0);</span><span class=cF0>
<a name="l306"></a> </span><span class=cF2>PCNetCSRWrite(PCNET_CSR_LADRF3, 0);</span><span class=cF0>
<a name="l307"></a>
<a name="l308"></a> </span><span class=cF2>/*</span><span class=cF0> </span><span class=cF2>The Physical Address is the MAC.</span><span class=cF0>
<a name="l309"></a> </span><span class=cF2>AMD PCNet datasheet p.1-960, 1-961</span><span class=cF0>
<a name="l310"></a> </span><span class=cF2>The first 16 bits of CSRs 12-14 are</span><span class=cF0>
<a name="l311"></a> </span><span class=cF2>for the Physical Address, the upper bits</span><span class=cF0>
<a name="l312"></a> </span><span class=cF2>are reserved, written 0 read undefined. </span><span class=cF0>
<a name="l313"></a>
<a name="l314"></a> </span><span class=cF2>The OR and bit-shift of 8 allows writing</span><span class=cF0>
<a name="l315"></a> </span><span class=cF2>separate U8 values in the correct locations</span><span class=cF0>
<a name="l316"></a> </span><span class=cF2>of the CSR. */</span><span class=cF0>
<a name="l317"></a> </span><span class=cF2>NetLog(&quot;PCNetDirectInit: Write MAC to CSR: 0x%X &quot;, pcnet.mac_address[0] | (pcnet.mac_address[1] &lt;&lt; 8));</span><span class=cF0>
<a name="l318"></a> </span><span class=cF2>PCNetCSRWrite(PCNET_CSR_PADR0, pcnet.mac_address[0] | (pcnet.mac_address[1] &lt;&lt; 8));</span><span class=cF0>
<a name="l319"></a> </span><span class=cF2>NetLog(&quot;PCNetDirectInit: Write MAC to CSR: 0x%X &quot;, pcnet.mac_address[2] | (pcnet.mac_address[3] &lt;&lt; 8));</span><span class=cF0>
<a name="l320"></a> </span><span class=cF2>PCNetCSRWrite(PCNET_CSR_PADR1, pcnet.mac_address[2] | (pcnet.mac_address[3] &lt;&lt; 8));</span><span class=cF0>
<a name="l321"></a> </span><span class=cF2>NetLog(&quot;PCNetDirectInit: Write MAC to CSR: 0x%X &quot;, pcnet.mac_address[4] | (pcnet.mac_address[5] &lt;&lt; 8));</span><span class=cF0>
<a name="l322"></a> </span><span class=cF2>PCNetCSRWrite(PCNET_CSR_PADR2, pcnet.mac_address[4] | (pcnet.mac_address[5] &lt;&lt; 8));</span><span class=cF0>
<a name="l323"></a>
<a name="l324"></a> </span><span class=cF2>/*</span><span class=cF0> </span><span class=cF2>AMD PCNet datasheet p.1-961, 1-962, 1-963</span><span class=cF0>
<a name="l325"></a> </span><span class=cF2>Refer to datasheet for specifics.</span><span class=cF0>
<a name="l326"></a> </span><span class=cF2>Most relevant, when setting Mode to 0,</span><span class=cF0>
<a name="l327"></a> </span><span class=cF2>promiscuous mode is is disabled, TX and</span><span class=cF0>
<a name="l328"></a> </span><span class=cF2>RX enabled, enable RX broadcast and unicast. */</span><span class=cF0>
<a name="l329"></a> </span><span class=cF2>PCNetCSRWrite(PCNET_CSR_MODE, 0);</span><span class=cF0>
<a name="l330"></a>
<a name="l331"></a> </span><span class=cF2>/* </span><span class=cF0> </span><span class=cF2>AMD PCNet datasheet p.1-964</span><span class=cF0>
<a name="l332"></a> </span><span class=cF2>CSR 24 and 25 need to be filled</span><span class=cF0>
<a name="l333"></a> </span><span class=cF2>with the lower and upper 16 bits,</span><span class=cF0>
<a name="l334"></a> </span><span class=cF2>respectively, of the address of </span><span class=cF0>
<a name="l335"></a> </span><span class=cF2>the RX packet ring. Likewise for</span><span class=cF0>
<a name="l336"></a> </span><span class=cF2>CSR 30 and 31 for the TX packet ring.</span><span class=cF0>
<a name="l337"></a>
<a name="l338"></a> </span><span class=cF2>0xFFFF AND on address will leave</span><span class=cF0>
<a name="l339"></a> </span><span class=cF2>only lower 16 bits remaining.</span><span class=cF0>
<a name="l340"></a>
<a name="l341"></a> </span><span class=cF2>Bitshift right of 16 will replace</span><span class=cF0>
<a name="l342"></a> </span><span class=cF2>first 16 bits with upper 16 bits,</span><span class=cF0>
<a name="l343"></a> </span><span class=cF2>remaining bits cleared.*/</span><span class=cF0>
<a name="l344"></a> </span><span class=cF2>PCNetCSRWrite(PCNET_CSR_BADRL, pcnet.rx_buffer_addr &amp; 0xFFFF);</span><span class=cF0>
<a name="l345"></a> </span><span class=cF2>PCNetCSRWrite(PCNET_CSR_BADRU, pcnet.rx_buffer_addr &gt;&gt; 16);</span><span class=cF0>
<a name="l346"></a>
<a name="l347"></a> </span><span class=cF2>PCNetCSRWrite(PCNET_CSR_BADTL, pcnet.tx_buffer_addr &amp; 0xFFFF);</span><span class=cF0>
<a name="l348"></a> </span><span class=cF2>PCNetCSRWrite(PCNET_CSR_BADTU, pcnet.tx_buffer_addr &gt;&gt; 16);</span><span class=cF0>
<a name="l349"></a>
<a name="l350"></a> </span><span class=cF2>/*</span><span class=cF0> </span><span class=cF2>AMD PCNet datasheet p. 1-967</span><span class=cF0>
<a name="l351"></a> </span><span class=cF2>Default value at hardware init is</span><span class=cF0>
<a name="l352"></a> </span><span class=cF2>all 0. Standard init block process</span><span class=cF0>
<a name="l353"></a> </span><span class=cF2>sets this, but if doing directly</span><span class=cF0>
<a name="l354"></a> </span><span class=cF2>it is imperative to manually set it 0. */</span><span class=cF0>
<a name="l355"></a> </span><span class=cF2>PCNetCSRWrite(PCNET_CSR_POLLINT, 0);</span><span class=cF0>
<a name="l356"></a>
<a name="l357"></a> </span><span class=cF2>/*</span><span class=cF0> </span><span class=cF2>AMD PCNet datasheet p. 1-970</span><span class=cF0>
<a name="l358"></a> </span><span class=cF2>Receive and Transmit Ring Length CSRs</span><span class=cF0>
<a name="l359"></a> </span><span class=cF2>bits 0-15 need to be set as the 2s complement</span><span class=cF0>
<a name="l360"></a> </span><span class=cF2>of the ring length. The AND with 0xFFFF clears</span><span class=cF0>
<a name="l361"></a> </span><span class=cF2>the upper Reserved bits, which are to be written</span><span class=cF0>
<a name="l362"></a> </span><span class=cF2>as zeroes read undefined. */</span><span class=cF0>
<a name="l363"></a> </span><span class=cF2>PCNetCSRWrite(PCNET_CSR_RXRINGLEN, -PCNET_RX_BUFF_COUNT &amp; 0xFFFF);</span><span class=cF0>
<a name="l364"></a> </span><span class=cF2>PCNetCSRWrite(PCNET_CSR_TXRINGLEN, -PCNET_TX_BUFF_COUNT &amp; 0xFFFF);</span><span class=cF0>
<a name="l365"></a></span><span class=cF2>}</span><span class=cF0>
<a name="l366"></a></span><span class=cF2>*/</span><span class=cF0>
<a name="l367"></a>
<a name="l368"></a></span><span class=cF1>U8</span><span class=cF0> *PCNetInitBlockSetup()
<a name="l369"></a>{
<a name="l370"></a> </span><span class=cF1>U8</span><span class=cF0> *setup = </span><span class=cF5>CAlloc</span><span class=cF0>(</span><span class=cF1>sizeof</span><span class=cF7>(</span><span class=cF0>CPCNetBufferSetup</span><span class=cF7>)</span><span class=cF0>, </span><span class=cF5>Fs</span><span class=cF0>-&gt;code_heap);
<a name="l371"></a> CPCNetBufferSetup *u_setup = setup + </span><span class=cFB>dev</span><span class=cF0>.uncached_alias;
<a name="l372"></a> </span><span class=cF9>U32</span><span class=cF0> p_setup;
<a name="l373"></a>
<a name="l374"></a> u_setup-&gt;mode = </span><span class=cFE>0</span><span class=cF0>;
<a name="l375"></a> u_setup-&gt;rlen = </span><span class=cFE>5</span><span class=cF0> &lt;&lt; </span><span class=cFE>4</span><span class=cF0>;
<a name="l376"></a> u_setup-&gt;tlen = </span><span class=cFE>3</span><span class=cF0> &lt;&lt; </span><span class=cFE>4</span><span class=cF0>;
<a name="l377"></a> </span><span class=cF5>MemCopy</span><span class=cF0>(u_setup-&gt;mac, pcnet.mac_address, </span><span class=cFE>6</span><span class=cF0>);
<a name="l378"></a> u_setup-&gt;reserved = </span><span class=cFE>0</span><span class=cF0>;
<a name="l379"></a> </span><span class=cF5>MemSet</span><span class=cF0>(u_setup-&gt;ladr, </span><span class=cFE>0</span><span class=cF0>, </span><span class=cFE>8</span><span class=cF0>);
<a name="l380"></a> u_setup-&gt;rxbuf = pcnet.rx_de_buffer_phys;
<a name="l381"></a> u_setup-&gt;txbuf = pcnet.tx_de_buffer_phys;
<a name="l382"></a>
<a name="l383"></a> p_setup = setup;
<a name="l384"></a> PCNetCSRWrite(</span><span class=cFE>1</span><span class=cF0>, p_setup &amp; </span><span class=cFE>0xFFFF</span><span class=cF0>);
<a name="l385"></a> PCNetCSRWrite(</span><span class=cFE>2</span><span class=cF0>, p_setup &gt;&gt; </span><span class=cFE>16</span><span class=cF0>);
<a name="l386"></a>
<a name="l387"></a> </span><span class=cF1>return</span><span class=cF0> setup;
<a name="l388"></a>}
<a name="l389"></a>
<a name="l390"></a></span><span class=cF1>U0</span><span class=cF0> PCNetInterruptCSRSet()
<a name="l391"></a>{</span><span class=cF2>/* AMD PCNet datasheet p.1-952, 1-953, 1-954, 1-955, 1-956, 1-957</span><span class=cF0>
<a name="l392"></a> </span><span class=cF2>Refer to datasheet for specifics on the Interrupt Masks.</span><span class=cF0>
<a name="l393"></a> </span><span class=cF2>Most of these, when set 0, allow interrupts to be set in CSR0.</span><span class=cF0>
<a name="l394"></a> </span><span class=cF2>We set Big-Endian disabled, RX interrupts</span><span class=cF0>
<a name="l395"></a> </span><span class=cF2>enabled, Init Done interrupt disabled, and TX interrupt</span><span class=cF0>
<a name="l396"></a> </span><span class=cF2>disabled. */</span><span class=cF0>
<a name="l397"></a>
<a name="l398"></a> </span><span class=cF9>U32</span><span class=cF0> csr = PCNetCSRRead(PCNET_CSR_INTERRUPTS);
<a name="l399"></a>
<a name="l400"></a> </span><span class=cF5>Btr</span><span class=cF0>(&amp;csr, PCNET_INT_BSWP);
<a name="l401"></a> </span><span class=cF5>Btr</span><span class=cF0>(&amp;csr, PCNET_INT_RINTM);
<a name="l402"></a>
<a name="l403"></a> </span><span class=cF5>Bts</span><span class=cF0>(&amp;csr, PCNET_INT_IDONM);
<a name="l404"></a> </span><span class=cF5>Bts</span><span class=cF0>(&amp;csr, PCNET_INT_TINTM);
<a name="l405"></a>
<a name="l406"></a> PCNetCSRWrite(PCNET_CSR_INTERRUPTS, csr);
<a name="l407"></a>}
<a name="l408"></a>
<a name="l409"></a></span><span class=cF1>U0</span><span class=cF0> PCNetTXAutoPadEnable()
<a name="l410"></a>{</span><span class=cF2>/* AMD PCNet datasheet p.1-958</span><span class=cF0>
<a name="l411"></a> </span><span class=cF2>Setting bit 11 (Auto Pad Transmit) allows</span><span class=cF0>
<a name="l412"></a> </span><span class=cF2>shoft transmit frames to be automatically</span><span class=cF0>
<a name="l413"></a> </span><span class=cF2>extended to 64 bytes. */</span><span class=cF0>
<a name="l414"></a>
<a name="l415"></a> </span><span class=cF9>U32</span><span class=cF0> csr = PCNetCSRRead(PCNET_CSR_FEATURECTRL);
<a name="l416"></a>
<a name="l417"></a> </span><span class=cF5>Bts</span><span class=cF0>(&amp;csr, PCNET_FEATURE_APADXMT);
<a name="l418"></a>
<a name="l419"></a> PCNetCSRWrite(PCNET_CSR_FEATURECTRL, csr);
<a name="l420"></a>}
<a name="l421"></a>
<a name="l422"></a></span><span class=cF1>U0</span><span class=cF0> PCNetConfigModeExit()
<a name="l423"></a>{</span><span class=cF2>/* AMD PCNet datasheet p.1-954</span><span class=cF0>
<a name="l424"></a> </span><span class=cF2>PCNet controller can be started</span><span class=cF0>
<a name="l425"></a> </span><span class=cF2>after configuring by ensuring INIT</span><span class=cF0>
<a name="l426"></a> </span><span class=cF2>and STOP are cleared and START bit</span><span class=cF0>
<a name="l427"></a> </span><span class=cF2>is set, in Status and Control Register</span><span class=cF0>
<a name="l428"></a> </span><span class=cF2>(CSR0). */</span><span class=cF0>
<a name="l429"></a>
<a name="l430"></a> </span><span class=cF9>U32</span><span class=cF0> csr = PCNetCSRRead(PCNET_CSR_CTRLSTATUS);
<a name="l431"></a>
<a name="l432"></a> </span><span class=cF5>Btr</span><span class=cF0>(&amp;csr, PCNET_CTRL_INIT);
<a name="l433"></a> </span><span class=cF5>Btr</span><span class=cF0>(&amp;csr, PCNET_CTRL_STOP);
<a name="l434"></a>
<a name="l435"></a> </span><span class=cF5>Bts</span><span class=cF0>(&amp;csr, PCNET_CTRL_STRT);
<a name="l436"></a>
<a name="l437"></a> PCNetCSRWrite(PCNET_CSR_CTRLSTATUS, csr);
<a name="l438"></a>}
<a name="l439"></a>
<a name="l440"></a></span><span class=cF9>I64</span><span class=cF0> PCNetDriverOwns(CPCNetDescriptorEntry* entry)
<a name="l441"></a>{</span><span class=cF2>/* Returns whether the value of the OWN bit of the</span><span class=cF0>
<a name="l442"></a> </span><span class=cF2>Descriptor Entry is zero. If 0, driver owns,</span><span class=cF0>
<a name="l443"></a> </span><span class=cF2>if 1, PCNet card owns it. */</span><span class=cF0>
<a name="l444"></a>
<a name="l445"></a> </span><span class=cF1>return</span><span class=cF0> !</span><span class=cF5>Bt</span><span class=cF0>(&amp;entry-&gt;status1, PCNET_DESCRIPTORf_OWN);
<a name="l446"></a>}
<a name="l447"></a>
<a name="l448"></a></span><span class=cF9>I64</span><span class=cF0> PCNetTransmitPacketAllocate(</span><span class=cF1>U8</span><span class=cF0> **packet_buffer_out, </span><span class=cF9>I64</span><span class=cF0> length)
<a name="l449"></a>{</span><span class=cF2>/* Transmits the packet at the current TX DE index. The packet_buffer_out</span><span class=cF0>
<a name="l450"></a> </span><span class=cF2>is a pointer, since we modify its value, ending with returning the</span><span class=cF0>
<a name="l451"></a> </span><span class=cF2>index of the DE we just processed. Length is validated to fit in BCNT.</span><span class=cF0>
<a name="l452"></a> </span><span class=cF2>The increment of the current TX DE index is done by assigning it the</span><span class=cF0>
<a name="l453"></a> </span><span class=cF2>value of incrementing it AND the max DE index-1. This will increment it</span><span class=cF0>
<a name="l454"></a> </span><span class=cF2>as well as wrap back to 0 if we hit the max DE index. */</span><span class=cF0>
<a name="l455"></a>
<a name="l456"></a> </span><span class=cF9>U16</span><span class=cF0> buffer_byte_count;
<a name="l457"></a> </span><span class=cF9>I64</span><span class=cF0> de_index = pcnet.current_tx_de_index;
<a name="l458"></a>
<a name="l459"></a> </span><span class=cF1>if</span><span class=cF0> (length &gt; </span><span class=cFE>0xFFF</span><span class=cF0>)
<a name="l460"></a> </span><span class=cF7>{</span><span class=cF0> </span><span class=cF2>// Max packet length must fit into BCNT 12-bit register.</span><span class=cF0>
<a name="l461"></a> NetErr(</span><span class=cF6>&quot;PCNET ALLOCATE TX PACKET: Invalid TX Packet Length&quot;</span><span class=cF0>);
<a name="l462"></a> </span><span class=cF5>throw</span><span class=cF0>(</span><span class=cF6>'PCNet'</span><span class=cF0>);
<a name="l463"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l464"></a>
<a name="l465"></a> CPCNetDescriptorEntry *entry = &amp;pcnet.tx_de_buffer[de_index * </span><span class=cF1>sizeof</span><span class=cF0>(CPCNetDescriptorEntry)];
<a name="l466"></a>
<a name="l467"></a> </span><span class=cF1>if</span><span class=cF0> (!PCNetDriverOwns</span><span class=cF7>(</span><span class=cF0>entry</span><span class=cF7>)</span><span class=cF0>)
<a name="l468"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l469"></a> NetErr(</span><span class=cF6>&quot;PCNET ALLOCATE TX PACKET: TX FIFO Full&quot;</span><span class=cF0>);
<a name="l470"></a> </span><span class=cF1>return</span><span class=cF0> -</span><span class=cFE>1</span><span class=cF0>; </span><span class=cF2>// Positive value expected. Functions calling this must factor this in.</span><span class=cF0>
<a name="l471"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l472"></a> </span><span class=cF1>else</span><span class=cF0>
<a name="l473"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l474"></a> NetLog(</span><span class=cF6>&quot;PCNET ALLOCATE TX PACKET: Driver owns TX DE at index %d.&quot;</span><span class=cF0>, de_index);
<a name="l475"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l476"></a>
<a name="l477"></a> </span><span class=cF5>Bts</span><span class=cF0>(&amp;entry-&gt;status1, PCNET_DESCRIPTORf_STP);
<a name="l478"></a>
<a name="l479"></a> </span><span class=cF5>Bts</span><span class=cF0>(&amp;entry-&gt;status1, PCNET_DESCRIPTORf_ENP);
<a name="l480"></a>
<a name="l481"></a> </span><span class=cF2>/*</span><span class=cF0> </span><span class=cF2>AMD PCNet datasheet p.1-991.</span><span class=cF0>
<a name="l482"></a> </span><span class=cF2>BCNT is the usable buffer length, expressed as first</span><span class=cF0>
<a name="l483"></a> </span><span class=cF2>12 bits of 2s-complement of desired length.</span><span class=cF0>
<a name="l484"></a> </span><span class=cF2>Bits 0-11 of a DE are for the buffer byte count (BCNT),</span><span class=cF0>
<a name="l485"></a> </span><span class=cF2>and bits 12-15 of a DE must be written all ones (ONES) */</span><span class=cF0>
<a name="l486"></a> buffer_byte_count = -length; </span><span class=cF2>// Sets up as 2s complement of the desired length.</span><span class=cF0>
<a name="l487"></a> buffer_byte_count &amp;= </span><span class=cFE>0x0FFF</span><span class=cF0>; </span><span class=cF2>// Masks 0 over everything except bits 0-11.</span><span class=cF0>
<a name="l488"></a>
<a name="l489"></a> entry-&gt;status1 &amp;= </span><span class=cFE>0xFFFFF000</span><span class=cF0>; </span><span class=cF2>// Clear first 12 bits and retain other bits in DE TMD1.</span><span class=cF0>
<a name="l490"></a>
<a name="l491"></a> entry-&gt;status1 |= buffer_byte_count; </span><span class=cF2>// Sets BCNT reg (first 12 bits) in DE TMD1.</span><span class=cF0>
<a name="l492"></a> entry-&gt;status1 |= </span><span class=cFE>0xF000</span><span class=cF0>; </span><span class=cF2>// Sets bits 12-15 (ONES) in DE TMD1 as all ones.</span><span class=cF0>
<a name="l493"></a>
<a name="l494"></a> pcnet.current_tx_de_index = (pcnet.current_tx_de_index + </span><span class=cFE>1</span><span class=cF0>) &amp; (PCNET_TX_BUFF_COUNT - </span><span class=cFE>1</span><span class=cF0>);
<a name="l495"></a>
<a name="l496"></a> *packet_buffer_out = pcnet.tx_buffer_addr + de_index * ETHERNET_FRAME_SIZE;
<a name="l497"></a>
<a name="l498"></a> </span><span class=cF5>MemSet</span><span class=cF0>(*packet_buffer_out, </span><span class=cFE>0</span><span class=cF0>, ETHERNET_FRAME_SIZE); </span><span class=cF2>// Clear buffer contents in advance.</span><span class=cF0>
<a name="l499"></a>
<a name="l500"></a> NetLog(</span><span class=cF6>&quot;PCNET ALLOCATE TX PACKET: de_index: %X.&quot;</span><span class=cF0>, de_index);
<a name="l501"></a> </span><span class=cF1>return</span><span class=cF0> de_index;
<a name="l502"></a>}
<a name="l503"></a>
<a name="l504"></a></span><span class=cF1>U0</span><span class=cF0> PCNetTransmitPacketFinish(</span><span class=cF9>I64</span><span class=cF0> de_index)
<a name="l505"></a>{</span><span class=cF2>/* Release ownership of the packet to the PCNet card</span><span class=cF0>
<a name="l506"></a> </span><span class=cF2>by setting the OWN bit to 1. */</span><span class=cF0>
<a name="l507"></a>
<a name="l508"></a> CPCNetDescriptorEntry *entry = &amp;pcnet.tx_de_buffer[de_index * </span><span class=cF1>sizeof</span><span class=cF0>(CPCNetDescriptorEntry)];
<a name="l509"></a>
<a name="l510"></a> </span><span class=cF5>Bts</span><span class=cF0>(&amp;entry-&gt;status1, PCNET_DESCRIPTORf_OWN);
<a name="l511"></a> NetLog(</span><span class=cF6>&quot;PCNET FINISH TX PACKET: TX DE index: %X, OWN bit of entry at entry: %b.&quot;</span><span class=cF0>,
<a name="l512"></a> de_index, </span><span class=cF5>Bt</span><span class=cF7>(</span><span class=cF0>&amp;entry-&gt;status1, PCNET_DESCRIPTORf_OWN</span><span class=cF7>)</span><span class=cF0>);
<a name="l513"></a>}
<a name="l514"></a>
<a name="l515"></a></span><span class=cF1>U0</span><span class=cF0> EthernetFrameFinish(</span><span class=cF9>I64</span><span class=cF0> de_index)
<a name="l516"></a>{</span><span class=cF2>//Alias for driver Finish TX function.</span><span class=cF0>
<a name="l517"></a> PCNetTransmitPacketFinish(de_index);
<a name="l518"></a>}
<a name="l519"></a>
<a name="l520"></a></span><span class=cF9>I64</span><span class=cF0> PCNetPacketReceive(</span><span class=cF1>U8</span><span class=cF0> **packet_buffer_out, </span><span class=cF9>U16</span><span class=cF0> *packet_length_out)
<a name="l521"></a>{</span><span class=cF2>/* Receives the packet at the current RX DE index. Parameters</span><span class=cF0>
<a name="l522"></a> </span><span class=cF2>are both pointers, since we modify the value at the packet_buffer_out,</span><span class=cF0>
<a name="l523"></a> </span><span class=cF2>and at the packet_length, ending with returning the index of the DE</span><span class=cF0>
<a name="l524"></a> </span><span class=cF2>we just processed.</span><span class=cF0>
<a name="l525"></a> </span><span class=cF2>The MCNT is stored at the first two bytes of the RMD2. We AND with</span><span class=cF0>
<a name="l526"></a> </span><span class=cF2>0xFFFF to only take in those first two bytes: that is the packet_length.</span><span class=cF0>
<a name="l527"></a> </span><span class=cF2>The increment of the current RX DE index is done by assigning it the</span><span class=cF0>
<a name="l528"></a> </span><span class=cF2>value of incrementing it AND the max DE index-1. This will increment it</span><span class=cF0>
<a name="l529"></a> </span><span class=cF2>as well as wrap back to 0 if we hit the max DE index. */</span><span class=cF0>
<a name="l530"></a>
<a name="l531"></a> </span><span class=cF9>I64</span><span class=cF0> de_index = pcnet.current_rx_de_index;
<a name="l532"></a> </span><span class=cF9>U16</span><span class=cF0> packet_length;
<a name="l533"></a>
<a name="l534"></a> NetLog(</span><span class=cF6>&quot;PCNET RECEIVE PACKET: Output buffer ptr, output length ptr: %X, %X &quot;</span><span class=cF0>, packet_buffer_out, packet_length_out);
<a name="l535"></a>
<a name="l536"></a> CPCNetDescriptorEntry *entry = &amp;pcnet.rx_de_buffer[de_index * </span><span class=cF1>sizeof</span><span class=cF0>(CPCNetDescriptorEntry)];
<a name="l537"></a>
<a name="l538"></a> packet_length = entry-&gt;status2 &amp; </span><span class=cFE>0xFFFF</span><span class=cF0>;
<a name="l539"></a>
<a name="l540"></a> NetDebug(</span><span class=cF6>&quot;PCNET RECEIVE PACKET: de_index = 0x%0X&quot;</span><span class=cF0>, de_index);
<a name="l541"></a> pcnet.current_rx_de_index = (pcnet.current_rx_de_index + </span><span class=cFE>1</span><span class=cF0>) &amp; (PCNET_RX_BUFF_COUNT - </span><span class=cFE>1</span><span class=cF0>);
<a name="l542"></a> NetDebug(</span><span class=cF6>&quot;PCNET RECEIVE PACKET: de_index incremented = 0x%0X&quot;</span><span class=cF0>, pcnet.current_rx_de_index);
<a name="l543"></a>
<a name="l544"></a> *packet_buffer_out = pcnet.rx_buffer_addr + de_index * ETHERNET_FRAME_SIZE;
<a name="l545"></a> *packet_length_out = packet_length;
<a name="l546"></a>
<a name="l547"></a> </span><span class=cF1>return</span><span class=cF0> de_index;
<a name="l548"></a>}
<a name="l549"></a>
<a name="l550"></a></span><span class=cF1>U0</span><span class=cF0> PCNetReceivePacketRelease(</span><span class=cF9>I64</span><span class=cF0> de_index)
<a name="l551"></a>{</span><span class=cF2>/* Release ownership of the packet to the PCNet card</span><span class=cF0>
<a name="l552"></a> </span><span class=cF2>by setting the OWN bit to 1. */</span><span class=cF0>
<a name="l553"></a>
<a name="l554"></a> CPCNetDescriptorEntry *entry = &amp;pcnet.rx_de_buffer[de_index * </span><span class=cF1>sizeof</span><span class=cF0>(CPCNetDescriptorEntry)];
<a name="l555"></a>
<a name="l556"></a> </span><span class=cF5>Bts</span><span class=cF0>(&amp;entry-&gt;status1, PCNET_DESCRIPTORf_OWN);
<a name="l557"></a>}
<a name="l558"></a>
<a name="l559"></a></span><span class=cF1>interrupt</span><span class=cF0> </span><span class=cF1>U0</span><span class=cF0> PCNetIRQ()
<a name="l560"></a>{</span><span class=cF2>// todo: comments explaining process...maybe reimplement interrupt handling altogether.</span><span class=cF0>
<a name="l561"></a>
<a name="l562"></a> </span><span class=cF1>U8</span><span class=cF0> *packet_buffer;
<a name="l563"></a> </span><span class=cF9>U16</span><span class=cF0> packet_length;
<a name="l564"></a> </span><span class=cF9>I64</span><span class=cF0> de_index;
<a name="l565"></a>
<a name="l566"></a> </span><span class=cF9>U32</span><span class=cF0> csr = PCNetCSRRead(PCNET_CSR_CTRLSTATUS);
<a name="l567"></a></span><span class=cF2>//</span><span class=cF0> </span><span class=cF2>&quot;Interrupt Reason: %X , %b\n&quot;,csr,csr;Debug;</span><span class=cF0>
<a name="l568"></a>
<a name="l569"></a> CPCNetDescriptorEntry *entry = pcnet.rx_de_buffer;
<a name="l570"></a>
<a name="l571"></a> </span><span class=cF1>while</span><span class=cF0> (PCNetDriverOwns</span><span class=cF7>(</span><span class=cF0>&amp;entry[pcnet.current_rx_de_index]</span><span class=cF7>)</span><span class=cF0>)
<a name="l572"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l573"></a> NetLog(</span><span class=cF6>&quot;$BG,LTCYAN$$FG,WHITE$&quot;</span><span class=cF0>
<a name="l574"></a> </span><span class=cF6>&quot;==== PCNET IRQ ====&quot;</span><span class=cF0>
<a name="l575"></a> </span><span class=cF6>&quot;$BG$$FG$&quot;</span><span class=cF0>);
<a name="l576"></a>
<a name="l577"></a> NetLog(</span><span class=cF6>&quot;$BD,CYAN$$FD,WHITE$&quot;</span><span class=cF0>
<a name="l578"></a> </span><span class=cF6>&quot;PCNET IRQ: Saw owned RX DE index %d.&quot;</span><span class=cF0>, pcnet.current_rx_de_index);
<a name="l579"></a>
<a name="l580"></a> de_index = PCNetPacketReceive(&amp;packet_buffer, &amp;packet_length);
<a name="l581"></a>
<a name="l582"></a> </span><span class=cF1>if</span><span class=cF0> (de_index &gt;= </span><span class=cFE>0</span><span class=cF0>) </span><span class=cF2>// todo: necessary? check increment logic in PCNetPacketReceive.</span><span class=cF0>
<a name="l583"></a> {
<a name="l584"></a> NetLog(</span><span class=cF6>&quot;PCNET IRQ: Pushing copy into Net Queue, releasing receive packet.&quot;</span><span class=cF0>);
<a name="l585"></a> NetQueuePush(packet_buffer, packet_length);
<a name="l586"></a> PCNetReceivePacketRelease(de_index);
<a name="l587"></a> }
<a name="l588"></a>
<a name="l589"></a> </span><span class=cF5>Bts</span><span class=cF0>(&amp;csr, PCNET_CTRL_RINT);
<a name="l590"></a>
<a name="l591"></a> PCNetCSRWrite(PCNET_CSR_CTRLSTATUS, csr);
<a name="l592"></a>
<a name="l593"></a> NetLog(</span><span class=cF6>&quot;PCNET IRQ: Exiting.\n&quot;</span><span class=cF0>
<a name="l594"></a> </span><span class=cF6>&quot;$BD,WHITE$$FD,LTGRAY$&quot;</span><span class=cF0>
<a name="l595"></a> </span><span class=cF6>&quot;$BG,LTCYAN$$FG,WHITE$&quot;</span><span class=cF0>
<a name="l596"></a> </span><span class=cF6>&quot;===================&quot;</span><span class=cF0>
<a name="l597"></a> </span><span class=cF6>&quot;$BG$$FG$&quot;</span><span class=cF0>);
<a name="l598"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l599"></a>
<a name="l600"></a> *(</span><span class=cFB>dev</span><span class=cF0>.uncached_alias + </span><span class=cF3>LAPIC_EOI</span><span class=cF0>)(</span><span class=cF9>U32</span><span class=cF0>*) = </span><span class=cFE>0</span><span class=cF0>;
<a name="l601"></a>}
<a name="l602"></a>
<a name="l603"></a></span><span class=cF1>U0</span><span class=cF0> PCIInterruptsReroute(</span><span class=cF9>I64</span><span class=cF0> base)
<a name="l604"></a>{ </span><span class=cF2>// todo: comments explaining process, maybe better var names</span><span class=cF0>
<a name="l605"></a> </span><span class=cF9>I64</span><span class=cF0> i;
<a name="l606"></a> </span><span class=cF1>U8</span><span class=cF0> *da = </span><span class=cFB>dev</span><span class=cF0>.uncached_alias + </span><span class=cF3>IOAPIC_REG</span><span class=cF0>;
<a name="l607"></a> </span><span class=cF9>U32</span><span class=cF0> *_d = </span><span class=cFB>dev</span><span class=cF0>.uncached_alias + </span><span class=cF3>IOAPIC_DATA</span><span class=cF0>;
<a name="l608"></a>
<a name="l609"></a> </span><span class=cF1>for</span><span class=cF0> (i = </span><span class=cFE>0</span><span class=cF0>; i &lt; </span><span class=cFE>4</span><span class=cF0>; i++)
<a name="l610"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l611"></a> *da = </span><span class=cF3>IOREDTAB</span><span class=cF0> + i * </span><span class=cFE>2</span><span class=cF0> + </span><span class=cFE>1</span><span class=cF0>;
<a name="l612"></a> *_d = </span><span class=cFB>dev</span><span class=cF0>.mp_apic_ids[INT_DEST_CPU] &lt;&lt; </span><span class=cFE>24</span><span class=cF0>;
<a name="l613"></a> *da = </span><span class=cF3>IOREDTAB</span><span class=cF0> + i * </span><span class=cFE>2</span><span class=cF0>;
<a name="l614"></a> *_d = </span><span class=cFE>0x4000</span><span class=cF0> + base + i;
<a name="l615"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l616"></a>}
<a name="l617"></a>
<a name="l618"></a></span><span class=cF1>U0</span><span class=cF0> PCNetInterruptsSetup()
<a name="l619"></a>{ </span><span class=cF2>// todo: comments explaining process</span><span class=cF0>
<a name="l620"></a></span><span class=cF2>/*</span><span class=cF0> </span><span class=cF2>IntEntrySet(I_PCNET0, &amp;PCNetIRQ);</span><span class=cF0>
<a name="l621"></a> </span><span class=cF2>IntEntrySet(I_PCNET1, &amp;PCNetIRQ);</span><span class=cF0>
<a name="l622"></a> </span><span class=cF2>IntEntrySet(I_PCNET2, &amp;PCNetIRQ);</span><span class=cF0>
<a name="l623"></a> </span><span class=cF2>IntEntrySet(I_PCNET3, &amp;PCNetIRQ);</span><span class=cF0>
<a name="l624"></a> </span><span class=cF2>PCIInterruptsReroute(I_PCNET0);*/</span><span class=cF0>
<a name="l625"></a> </span><span class=cF9>I64</span><span class=cF0> irq, i;
<a name="l626"></a>
<a name="l627"></a> </span><span class=cF1>for</span><span class=cF0> (i = </span><span class=cFE>0</span><span class=cF0>; i &lt; </span><span class=cFE>4</span><span class=cF0>; i++)
<a name="l628"></a> </span><span class=cF5>IntEntrySet</span><span class=cF0>(</span><span class=cF7>(</span><span class=cF0>irq = </span><span class=cF5>IntEntryAlloc</span><span class=cF7>)</span><span class=cF0>, &amp;PCNetIRQ);
<a name="l629"></a>
<a name="l630"></a> PCIInterruptsReroute(irq);
<a name="l631"></a>}
<a name="l632"></a>
<a name="l633"></a></span><span class=cF1>U0</span><span class=cF0> PCNetInit()
<a name="l634"></a>{
<a name="l635"></a> </span><span class=cF1>U8</span><span class=cF0> *setup; </span><span class=cF2>// PCNetInitBlockSetup</span><span class=cF0>
<a name="l636"></a>
<a name="l637"></a> </span><span class=cF5>MemSet</span><span class=cF0>(&amp;pcnet, </span><span class=cFE>0</span><span class=cF0>, </span><span class=cF1>sizeof</span><span class=cF7>(</span><span class=cF0>CPCNet</span><span class=cF7>)</span><span class=cF0>); </span><span class=cF2>// pcnet global var will hold member data the driver uses often.</span><span class=cF0>
<a name="l638"></a>
<a name="l639"></a> pcnet.pci = PCNetPCIDevFind;
<a name="l640"></a> </span><span class=cF1>if</span><span class=cF0> (!pcnet.pci)
<a name="l641"></a> </span><span class=cF1>return</span><span class=cF0>; </span><span class=cF2>// if we don't find the card, quit.</span><span class=cF0>
<a name="l642"></a>
<a name="l643"></a> </span><span class=cF2>/*</span><span class=cF0> </span><span class=cF2>Clear command register of PCNet</span><span class=cF0>
<a name="l644"></a> </span><span class=cF2>PCI device, set IO Enable and Bus</span><span class=cF0>
<a name="l645"></a> </span><span class=cF2>Master Enable bits of the register. */</span><span class=cF0>
<a name="l646"></a> </span><span class=cF5>PCIWriteU16</span><span class=cF0>(pcnet.pci-&gt;bus,
<a name="l647"></a> pcnet.pci-&gt;</span><span class=cFB>dev</span><span class=cF0>,
<a name="l648"></a> pcnet.pci-&gt;fun,
<a name="l649"></a> </span><span class=cF3>PCIR_COMMAND</span><span class=cF0>,
<a name="l650"></a> PCNET_CMDF_IOEN | PCNET_CMDF_BMEN);
<a name="l651"></a>
<a name="l652"></a> PCNetReset;
<a name="l653"></a>
<a name="l654"></a> PCNet32BitModeEnable;
<a name="l655"></a>
<a name="l656"></a> </span><span class=cF9>U32</span><span class=cF0> csr = PCNetCSRRead(PCNET_CSR_CTRLSTATUS);
<a name="l657"></a> NetLog(</span><span class=cF6>&quot;PCNET INIT START: what is INIT ?: %d&quot;</span><span class=cF0>, </span><span class=cF5>Bt</span><span class=cF7>(</span><span class=cF0>&amp;csr, PCNET_CTRL_INIT</span><span class=cF7>)</span><span class=cF0>);
<a name="l658"></a> NetLog(</span><span class=cF6>&quot;PCNET INIT START: what is STRT ?: %d&quot;</span><span class=cF0>, </span><span class=cF5>Bt</span><span class=cF7>(</span><span class=cF0>&amp;csr, PCNET_CTRL_STRT</span><span class=cF7>)</span><span class=cF0>);
<a name="l659"></a> NetLog(</span><span class=cF6>&quot;PCNET INIT START: what is STOP ?: %d&quot;</span><span class=cF0>, </span><span class=cF5>Bt</span><span class=cF7>(</span><span class=cF0>&amp;csr, PCNET_CTRL_STOP</span><span class=cF7>)</span><span class=cF0>);
<a name="l660"></a> NetLog(</span><span class=cF6>&quot;PCNET INIT START: what is RINT ?: %d&quot;</span><span class=cF0>, </span><span class=cF5>Bt</span><span class=cF7>(</span><span class=cF0>&amp;csr, PCNET_CTRL_RINT</span><span class=cF7>)</span><span class=cF0>);
<a name="l661"></a>
<a name="l662"></a>
<a name="l663"></a> PCNetSWStyleSet;
<a name="l664"></a>
<a name="l665"></a> PCNetMACGet;
<a name="l666"></a></span><span class=cF2>//</span><span class=cF0> </span><span class=cF2>OSDev has code ensuring auto selected connection...</span><span class=cF0>
<a name="l667"></a>
<a name="l668"></a> PCNetBuffersAllocate;
<a name="l669"></a>
<a name="l670"></a></span><span class=cF2>//</span><span class=cF0> </span><span class=cF2>PCNetDirectInit;</span><span class=cF0>
<a name="l671"></a> setup = PCNetInitBlockSetup();
<a name="l672"></a>
<a name="l673"></a> PCNetInterruptCSRSet;
<a name="l674"></a>
<a name="l675"></a> PCNetTXAutoPadEnable;
<a name="l676"></a>
<a name="l677"></a> PCNetCSRWrite(</span><span class=cFE>0</span><span class=cF0>, PCNetCSRRead</span><span class=cF7>(</span><span class=cFE>0</span><span class=cF7>)</span><span class=cF0> | </span><span class=cFE>1</span><span class=cF0> | </span><span class=cFE>1</span><span class=cF0> &lt;&lt; </span><span class=cFE>6</span><span class=cF0>); </span><span class=cF2>// ?</span><span class=cF0>
<a name="l678"></a>
<a name="l679"></a> csr = PCNetCSRRead(PCNET_CSR_CTRLSTATUS);
<a name="l680"></a> NetLog(</span><span class=cF6>&quot;PCNET INIT UPLOAD: what is INIT ?: %d&quot;</span><span class=cF0>, </span><span class=cF5>Bt</span><span class=cF7>(</span><span class=cF0>&amp;csr, PCNET_CTRL_INIT</span><span class=cF7>)</span><span class=cF0>);
<a name="l681"></a> NetLog(</span><span class=cF6>&quot;PCNET INIT UPLOAD: what is STRT ?: %d&quot;</span><span class=cF0>, </span><span class=cF5>Bt</span><span class=cF7>(</span><span class=cF0>&amp;csr, PCNET_CTRL_STRT</span><span class=cF7>)</span><span class=cF0>);
<a name="l682"></a> NetLog(</span><span class=cF6>&quot;PCNET INIT UPLOAD: what is STOP ?: %d&quot;</span><span class=cF0>, </span><span class=cF5>Bt</span><span class=cF7>(</span><span class=cF0>&amp;csr, PCNET_CTRL_STOP</span><span class=cF7>)</span><span class=cF0>);
<a name="l683"></a> NetLog(</span><span class=cF6>&quot;PCNET INIT UPLOAD: what is RINT ?: %d&quot;</span><span class=cF0>, </span><span class=cF5>Bt</span><span class=cF7>(</span><span class=cF0>&amp;csr, PCNET_CTRL_RINT</span><span class=cF7>)</span><span class=cF0>);
<a name="l684"></a>
<a name="l685"></a> </span><span class=cF1>while</span><span class=cF0> (!</span><span class=cF7>(</span><span class=cF0>PCNetCSRRead(</span><span class=cFE>0</span><span class=cF0>) &amp; </span><span class=cFE>1</span><span class=cF0> &lt;&lt; </span><span class=cFE>8</span><span class=cF7>)</span><span class=cF0>) </span><span class=cF2>// ?</span><span class=cF0>
<a name="l686"></a> </span><span class=cF5>Yield</span><span class=cF0>;
<a name="l687"></a>
<a name="l688"></a> PCNetConfigModeExit;
<a name="l689"></a>
<a name="l690"></a> </span><span class=cF5>Sleep</span><span class=cF0>(</span><span class=cFE>100</span><span class=cF0>); </span><span class=cF2>//? necessary?</span><span class=cF0>
<a name="l691"></a>
<a name="l692"></a> csr = PCNetCSRRead(PCNET_CSR_CTRLSTATUS);
<a name="l693"></a> NetLog(</span><span class=cF6>&quot;PCNET INIT END: what is INIT ?: %d&quot;</span><span class=cF0>, </span><span class=cF5>Bt</span><span class=cF7>(</span><span class=cF0>&amp;csr, PCNET_CTRL_INIT</span><span class=cF7>)</span><span class=cF0>);
<a name="l694"></a> NetLog(</span><span class=cF6>&quot;PCNET INIT END: what is STRT ?: %d&quot;</span><span class=cF0>, </span><span class=cF5>Bt</span><span class=cF7>(</span><span class=cF0>&amp;csr, PCNET_CTRL_STRT</span><span class=cF7>)</span><span class=cF0>);
<a name="l695"></a> NetLog(</span><span class=cF6>&quot;PCNET INIT END: what is STOP ?: %d&quot;</span><span class=cF0>, </span><span class=cF5>Bt</span><span class=cF7>(</span><span class=cF0>&amp;csr, PCNET_CTRL_STOP</span><span class=cF7>)</span><span class=cF0>);
<a name="l696"></a> NetLog(</span><span class=cF6>&quot;PCNET INIT END: what is RINT ?: %d&quot;</span><span class=cF0>, </span><span class=cF5>Bt</span><span class=cF7>(</span><span class=cF0>&amp;csr, PCNET_CTRL_RINT</span><span class=cF7>)</span><span class=cF0>);
<a name="l697"></a> NetLog(</span><span class=cF6>&quot;PCNET INIT END: what is TXON ?: %d&quot;</span><span class=cF0>, </span><span class=cF5>Bt</span><span class=cF7>(</span><span class=cF0>&amp;csr, </span><span class=cFE>4</span><span class=cF7>)</span><span class=cF0>);
<a name="l698"></a> NetLog(</span><span class=cF6>&quot;PCNET INIT END: what is RXON ?: %d&quot;</span><span class=cF0>, </span><span class=cF5>Bt</span><span class=cF7>(</span><span class=cF0>&amp;csr, </span><span class=cFE>5</span><span class=cF7>)</span><span class=cF0>);
<a name="l699"></a>
<a name="l700"></a> csr = PCNetCSRRead(PCNET_CSR_POLLINT);
<a name="l701"></a> NetLog(</span><span class=cF6>&quot;PCNET INIT END: what is POLLINT ?: %d&quot;</span><span class=cF0>, </span><span class=cF5>Bt</span><span class=cF7>(</span><span class=cF0>&amp;csr, PCNET_CTRL_RINT</span><span class=cF7>)</span><span class=cF0>);
<a name="l702"></a>
<a name="l703"></a> NetLog(</span><span class=cF6>&quot;PCNET INIT END: Redirecting interrupts.&quot;</span><span class=cF0>);
<a name="l704"></a> PCNetInterruptsSetup;
<a name="l705"></a>
<a name="l706"></a>
<a name="l707"></a> </span><span class=cF5>Free</span><span class=cF0>(setup);
<a name="l708"></a>}
<a name="l709"></a>
<a name="l710"></a></span><span class=cF9>I64</span><span class=cF0> EthernetFrameAllocate(</span><span class=cF1>U8</span><span class=cF0> **packet_buffer_out,
<a name="l711"></a> </span><span class=cF1>U8</span><span class=cF0> *source_address,
<a name="l712"></a> </span><span class=cF1>U8</span><span class=cF0> *destination_address,
<a name="l713"></a> </span><span class=cF9>U16</span><span class=cF0> ethertype,
<a name="l714"></a> </span><span class=cF9>I64</span><span class=cF0> packet_length)
<a name="l715"></a>{</span><span class=cF2>/* Allocate an Ethernet Frame for transmit. The source</span><span class=cF0>
<a name="l716"></a> </span><span class=cF2>and destination addresses are copied to the Frame,</span><span class=cF0>
<a name="l717"></a> </span><span class=cF2>as well as the ethertype. The packet_buffer_out</span><span class=cF0>
<a name="l718"></a> </span><span class=cF2>parameter has the value at its pointer set to the</span><span class=cF0>
<a name="l719"></a> </span><span class=cF2>payload of the Ethernet Frame. */</span><span class=cF0>
<a name="l720"></a>
<a name="l721"></a> </span><span class=cF1>U8</span><span class=cF0> *ethernet_frame;
<a name="l722"></a> </span><span class=cF9>I64</span><span class=cF0> de_index;
<a name="l723"></a>
<a name="l724"></a> </span><span class=cF2>//need to see if 3 years later VirtualBox supports APAD_XMT!</span><span class=cF0>
<a name="l725"></a> </span><span class=cF1>if</span><span class=cF0> (packet_length &lt; ETHERNET_MIN_FRAME_SIZE)
<a name="l726"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l727"></a> NetWarn(</span><span class=cF6>&quot;ETHERNET FRAME ALLOCATE: PCNET APAD XMT TRUNCATE ? ...&quot;</span><span class=cF0>);
<a name="l728"></a> packet_length = ETHERNET_MIN_FRAME_SIZE;
<a name="l729"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l730"></a>
<a name="l731"></a> de_index = PCNetTransmitPacketAllocate(&amp;ethernet_frame, ETHERNET_MAC_HEADER_LENGTH + packet_length);
<a name="l732"></a>
<a name="l733"></a> </span><span class=cF1>if</span><span class=cF0> (de_index &lt; </span><span class=cFE>0</span><span class=cF0>)
<a name="l734"></a> </span><span class=cF7>{</span><span class=cF0>
<a name="l735"></a> NetErr(</span><span class=cF6>&quot;ETHERNET FRAME ALLOCATE: Failure&quot;</span><span class=cF0>);
<a name="l736"></a> </span><span class=cF1>return</span><span class=cF0> -</span><span class=cFE>1</span><span class=cF0>; </span><span class=cF2>// Positive value expected. Functions calling this must factor this in.</span><span class=cF0>
<a name="l737"></a> </span><span class=cF7>}</span><span class=cF0>
<a name="l738"></a>
<a name="l739"></a> </span><span class=cF5>MemCopy</span><span class=cF0>(ethernet_frame, destination_address, MAC_ADDRESS_LENGTH);
<a name="l740"></a> </span><span class=cF5>MemCopy</span><span class=cF0>(ethernet_frame + MAC_ADDRESS_LENGTH, source_address, MAC_ADDRESS_LENGTH);
<a name="l741"></a>
<a name="l742"></a> ethernet_frame[ETHERNET_ETHERTYPE_OFFSET] = ethertype &gt;&gt; </span><span class=cFE>8</span><span class=cF0>;
<a name="l743"></a> ethernet_frame[ETHERNET_ETHERTYPE_OFFSET + </span><span class=cFE>1</span><span class=cF0>] = ethertype &amp; </span><span class=cFE>0xFF</span><span class=cF0>;
<a name="l744"></a>
<a name="l745"></a> *packet_buffer_out = ethernet_frame + ETHERNET_MAC_HEADER_LENGTH;
<a name="l746"></a>
<a name="l747"></a> </span><span class=cF1>return</span><span class=cF0> de_index;
<a name="l748"></a>}
<a name="l749"></a>
<a name="l750"></a></span><span class=cF1>U8</span><span class=cF0> *EthernetMACGet()
<a name="l751"></a>{
<a name="l752"></a> </span><span class=cF1>return</span><span class=cF0> pcnet.mac_address;
<a name="l753"></a>}
<a name="l754"></a>
<a name="l755"></a></span><span class=cF1>U0</span><span class=cF0> NetStop()
<a name="l756"></a>{ </span><span class=cF2>// Halt network activity by setting STOP bit on Status CSR.</span><span class=cF0>
<a name="l757"></a> </span><span class=cF9>U32</span><span class=cF0> csr = PCNetCSRRead(PCNET_CSR_CTRLSTATUS);
<a name="l758"></a>
<a name="l759"></a> </span><span class=cF5>Bts</span><span class=cF0>(&amp;csr, PCNET_CTRL_STOP);
<a name="l760"></a>
<a name="l761"></a> PCNetCSRWrite(PCNET_CSR_CTRLSTATUS, csr);
<a name="l762"></a>
<a name="l763"></a>}
<a name="l764"></a>
<a name="l765"></a></span><span class=cF1>U0</span><span class=cF0> NetStart()
<a name="l766"></a>{ </span><span class=cF2>// Continue network activity. Setting START bit clears STOP/INIT.</span><span class=cF0>
<a name="l767"></a> </span><span class=cF9>U32</span><span class=cF0> csr = PCNetCSRRead(PCNET_CSR_CTRLSTATUS);
<a name="l768"></a>
<a name="l769"></a> </span><span class=cF5>Bts</span><span class=cF0>(&amp;csr, PCNET_CTRL_STRT);
<a name="l770"></a>
<a name="l771"></a> PCNetCSRWrite(PCNET_CSR_CTRLSTATUS, csr);
<a name="l772"></a>}
<a name="l773"></a>
<a name="l774"></a>PCNetInit;</span></pre></body>
</html>