2 * UDI Ne2000 NIC Driver
3 * By John Hodge (thePowersGang)
10 #include "ne2000_common.h"
12 #define NE2K_META_BUS 1
13 #define NE2K_META_NIC 2
16 #define PIO_op_RI(op, reg, sz, val) {UDI_PIO_##op+UDI_PIO_DIRECT+UDI_PIO_##reg, UDI_PIO_##sz##BYTE, val}
17 #define PIO_MOV_RI1(reg, val) PIO_op_RI(LOAD_IMM, reg, 1, val)
18 #define PIO_OUT_RI1(reg, ofs) PIO_op_RI(OUT, reg, 1, ofs)
19 #define PIO_IN_RI1(reg, ofs) PIO_op_RI(IN, reg, 1, ofs)
20 // --- Programmed IO ---
21 /// Ne2000 reset operation (reads MAC address too)
22 udi_pio_trans_t ne2k_pio_reset[] = {
24 PIO_IN_RI1(R0, NE2K_REG_RESET),
25 PIO_OUT_RI1(R0, NE2K_REG_RESET),
26 // While ISR bit 7 is unset, spin
27 {UDI_PIO_LABEL, 0, 1},
28 PIO_IN_RI1(R0, NE2K_REG_ISR),
29 {UDI_PIO_AND_IMM+UDI_PIO_R0, UDI_PIO_1BYTE, 0x80},
30 {UDI_PIO_CSKIP+UDI_PIO_R0, UDI_PIO_1BYTE, UDI_PIO_NZ},
31 {UDI_PIO_BRANCH, 0, 1},
32 // ISR = 0x80 [Clear reset]
33 PIO_OUT_RI1(R0, NE2K_REG_ISR),
35 // CMD = 0x40|0x21 [Page1, NoDMA, Stop]
36 PIO_MOV_RI1(R0, 0x40|0x21),
37 PIO_OUT_RI1(R0, NE2K_REG_CMD),
38 // CURR = First RX page
39 PIO_MOV_RI1(R0, NE2K_FIRST_RX_PAGE),
40 PIO_OUT_RI1(R0, NE2K_REG_CURR),
41 // CMD = 0x21 [Page0, NoDMA, Stop]
42 PIO_MOV_RI1(R0, 0x21),
43 PIO_OUT_RI1(R0, NE2K_REG_CMD),
44 // DCR = ? [WORD, ...]
45 PIO_MOV_RI1(R0, 0x49),
46 PIO_OUT_RI1(R0, NE2K_REG_DCR),
47 // IMR = 0 [Disable all]
48 PIO_MOV_RI1(R0, 0x00),
49 PIO_OUT_RI1(R0, NE2K_REG_IMR),
50 // ISR = 0xFF [ACK all]
51 PIO_MOV_RI1(R0, 0xFF),
52 PIO_OUT_RI1(R0, NE2K_REG_ISR),
53 // RCR = 0x20 [Monitor]
54 PIO_MOV_RI1(R0, 0x20),
55 PIO_OUT_RI1(R0, NE2K_REG_RCR),
56 // TCR = 0x02 [TX Off, Loopback]
57 PIO_MOV_RI1(R0, 0x02),
58 PIO_OUT_RI1(R0, NE2K_REG_TCR),
59 // - Read MAC address from EEPROM (24 bytes from 0)
62 PIO_OUT_RI1(R0, NE2K_REG_RBAR0),
63 PIO_OUT_RI1(R1, NE2K_REG_RBAR1),
66 PIO_OUT_RI1(R0, NE2K_REG_RBCR0),
67 PIO_OUT_RI1(R1, NE2K_REG_RBCR1),
68 // CMD = 0x0A [Start remote DMA]
69 PIO_MOV_RI1(R0, 0x0A),
70 PIO_OUT_RI1(R0, NE2K_REG_CMD),
72 PIO_MOV_RI1(R0, 0), // - Buffer offset (incremented by 1 each iteration)
73 PIO_MOV_RI1(R1, NE2K_REG_MEM), // - Reg offset (no increment)
74 PIO_MOV_RI1(R2, 6), // - Six iterations
75 {UDI_PIO_REP_IN_IND, UDI_PIO_1BYTE,
76 UDI_PIO_REP_ARGS(UDI_PIO_BUF, UDI_PIO_R0, 1, UDI_PIO_R1, 0, UDI_PIO_R2)},
78 // PSTART = First RX page [Receive area start]
79 PIO_MOV_RI1(R0, NE2K_FIRST_RX_PAGE),
80 PIO_OUT_RI1(R0, NE2K_REG_PSTART),
81 // BNRY = Last RX page - 1 [???]
82 PIO_MOV_RI1(R0, NE2K_LAST_RX_PAGE-1),
83 PIO_OUT_RI1(R0, NE2K_REG_BNRY),
84 // PSTOP = Last RX page [???]
85 PIO_MOV_RI1(R0, NE2K_LAST_RX_PAGE),
86 PIO_OUT_RI1(R0, NE2K_REG_PSTOP),
87 // > Clear all interrupt and set mask
88 // ISR = 0xFF [ACK all]
89 PIO_MOV_RI1(R0, 0xFF),
90 PIO_OUT_RI1(R0, NE2K_REG_ISR),
92 PIO_MOV_RI1(R0, 0x3F),
93 PIO_OUT_RI1(R0, NE2K_REG_IMR),
94 // CMD = 0x22 [NoDMA, Start]
95 PIO_MOV_RI1(R0, 0x22),
96 PIO_OUT_RI1(R0, NE2K_REG_CMD),
97 // RCR = 0x0F [Wrap, Promisc]
98 PIO_MOV_RI1(R0, 0x0F),
99 PIO_OUT_RI1(R0, NE2K_REG_RCR),
100 // TCR = 0x00 [Normal]
101 PIO_MOV_RI1(R0, 0x00),
102 PIO_OUT_RI1(R0, NE2K_REG_TCR),
103 // TPSR = 0x40 [TX Start]
104 PIO_MOV_RI1(R0, 0x40),
105 PIO_OUT_RI1(R0, NE2K_REG_TPSR),
107 {UDI_PIO_END_IMM, UDI_PIO_2BYTE, 0}
110 udi_pio_trans_t *trans_list;
111 udi_ubit16_t list_length;
112 udi_ubit16_t pio_attributes;
114 {ne2k_pio_reset, ARRAY_SIZEOF(ne2k_pio_reset), 0}}
116 const int NE2K_NUM_PIO_OPS = ARRAY_SIZEOF(ne2k_pio_ops);
120 void ne2k_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
123 void ne2k_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level)
125 ne2k_rdata_t *rdata = UDI_GCB(cb)->context;
126 udi_instance_attr_list_t *attr_list = cb->attr_list;
128 switch(enumeration_level)
130 case UDI_ENUMERATE_START:
131 case UDI_ENUMERATE_START_RESCAN:
132 // Emit the ND binding
133 DPT_SET_ATTR32(attr_list, "if_num", 0);
135 DPT_SET_ATTR_STRING(attr_list, "if_media", "eth");
137 NE2K_SET_ATTR_STRFMT(attr_list, "identifier", 2*6+1, "%2X%2X%2X%2X%2X%2X",
138 rdata->macaddr[0], rdata->macaddr[1], rdata->macaddr[2],
139 rdata->macaddr[3], rdata->macaddr[4], rdata->macaddr[5] );
141 udi_enumerate_ack(cb, UDI_ENUMERATE_OK, 2);
143 case UDI_ENUMERATE_NEXT:
144 udi_enumerate_ack(cb, UDI_ENUMERATE_DONE, 0);
148 void ne2k_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID)
151 void ne2k_final_cleanup_req(udi_mgmt_cb_t *cb)
155 void ne2k_bus_dev_channel_event_ind(udi_channel_event_cb_t *cb)
159 case UDI_CHANNEL_CLOSED:
161 case UDI_CHANNEL_BOUND: {
162 udi_bus_bind_cb_t *bus_bind_cb = UDI_MCB(cb->params.parent_bound.bind_cb, udi_bus_bind_cb_t);
163 udi_bus_bind_req( bus_bind_cb );
164 // continue at ne2k_bus_dev_bus_bind_ack
168 void ne2k_bus_dev_bus_bind_ack(udi_bus_bind_cb_t *cb,
169 udi_dma_constraints_t dma_constraints, udi_ubit8_t perferred_endianness, udi_status_t status)
171 udi_cb_t *gcb = UDI_GCB(cb);
172 ne2k_rdata_t *rdata = gcb->context;
174 // Set up PIO handles
175 rdata->init.pio_index = -1;
176 ne2k_bus_dev_bind__pio_map(gcb, UDI_NULL_PIO_HANDLE);
178 void ne2k_bus_dev_bind__pio_map(udi_cb_t *gcb, udi_pio_handle_t new_pio_handle)
180 ne2k_rdata_t *rdata = gcb->context;
182 if( rdata->init.pio_index != -1 )
184 rdata->pio_handles[rdata->init.pio_index] = new_pio_handle;
186 rdata->init.pio_index ++;
187 if( rdata->init.pio_index < NE2K_NUM_PIO_OPS )
189 udi_pio_map(ne2k_bus_dev_bind__pio_map, gcb,
190 UDI_PCI_BAR_0, 0, 0x20,
191 ne2k_pio_ops[rdata->init.pio_index].trans_list,
192 ne2k_pio_ops[rdata->init.pio_index].list_length,
193 UDI_PIO_LITTE_ENDIAN, 0, 0
201 void ne2k_bus_dev_bus_unbind_ack(udi_bus_bind_cb_t *cb)
204 void ne2k_bus_dev_intr_attach_ack(udi_intr_attach_cb_t *intr_attach_cb, udi_status_t status)
207 void ne2k_bus_dev_intr_detach_ack(udi_intr_detach_cb_t *intr_detach_cb)
211 void ne2k_nd_ctrl_channel_event_ind(udi_channel_event_cb_t *cb)
214 void ne2k_nd_ctrl_bind_req(udi_nic_bind_cb_t *cb, udi_index_t tx_chan_index, udi_index_t rx_chan_index)
217 void ne2k_nd_ctrl_unbind_req(udi_nic_cb_t *cb)
220 void ne2k_nd_ctrl_enable_req(udi_nic_cb_t *cb)
223 void ne2k_nd_ctrl_disable_req(udi_nic_cb_t *cb)
226 void ne2k_nd_ctrl_ctrl_req(udi_nic_ctrl_cb_t *cb)
229 void ne2k_nd_ctrl_info_req(udi_nic_info_cb_t *cb, udi_boolean_t reset_statistics)
233 // === Definition structures ===
234 udi_mgmt_ops_t ne2k_mgmt_ops = {
238 ne2k_final_cleanup_req
240 udi_ubit8_t ne2k_mgmt_op_flags[4] = {0,0,0,0};
241 udi_bus_device_ops_t ne2k_bus_dev_ops = {
242 ne2k_bus_dev_channel_event_ind,
243 ne2k_bus_dev_bus_bind_ack,
244 ne2k_bus_dev_bus_unbind_ack,
245 ne2k_bus_dev_intr_attach_ack,
246 ne2k_bus_dev_intr_detach_ack
248 udi_ubit8_t ne2k_bus_dev_ops_flags[5] = {0};
249 udi_nd_ctrl_ops_t ne2k_nd_ctrl_ops = {
250 ne2k_nd_ctrl_channel_event_ind,
251 ne2k_nd_ctrl_bind_req,
252 ne2k_nd_ctrl_unbind_req,
253 ne2k_nd_ctrl_enable_req,
254 ne2k_nd_ctrl_disable_req,
255 ne2k_nd_ctrl_ctrl_req,
256 ne2k_nd_ctrl_info_req
258 udi_ubit8_t ne2k_nd_ctrl_ops_flags[7] = {0};
259 udi_nd_tx_ops ne2k_nd_tx_ops = {
260 ne2k_nd_tx_channel_event_ind,
262 ne2k_nd_tx_exp_tx_req
264 udi_ubit8_t ne2k_nd_tx_ops_flags[3] = {0};
265 udi_nd_rx_ops ne2k_nd_rx_ops = {
266 ne2k_nd_rx_channel_event_ind,
269 udi_ubit8_t ne2k_nd_rx_ops_flags[2] = {0};
270 const udi_primary_init_t ne2k_pri_init = {
271 .mgmt_ops = &ne2k_mgmt_ops,
272 .mgmt_op_flags = ne2k_mgmt_op_flags,
273 .mgmt_scratch_requirement = 0,
274 .enumeration_attr_list_length = 4,
275 .rdata_size = sizeof(ne2k_rdata_t),
276 .child_data_size = 0,
277 .per_parent_paths = 0
279 const udi_ops_init_t ne2k_ops_list[] = {
281 1, NE2K_META_BUS, UDI_BUS_DEVICE_OPS_NUM,
283 (udi_ops_vector_t*)ne2k_bus_dev_ops,
284 ne2k_bus_dev_ops_flags
287 2, NE2K_META_NIC, UDI_ND_CTRL_OPS_NUM,
289 (udi_ops_vector_t*)ne2k_nd_ctrl_ops,
290 ne2k_nd_ctrl_ops_flags
293 3, NE2K_META_NIC, UDI_ND_TX_OPS_NUM,
295 (udi_ops_vector_t*)ne2k_nd_tx_ops,
299 4, NE2K_META_NIC, UDI_ND_RX_OPS_NUM,
301 (udi_ops_vector_t*)ne2k_nd_rx_ops,
306 const udi_init_t udi_init_info = {
307 .primary_init_info = &ne2k_pri_init,
308 .ops_init_list = ne2k_ops_list