#include <udi_nic.h>
#include "ne2000_common.h"
-#define NE2K_META_BUS 1
-#define NE2K_META_NIC 2
+enum {
+ NE2K_META_BUS = 1,
+ NE2K_META_NIC,
+};
+enum {
+ NE2K_OPS_DEV = 1,
+ NE2K_OPS_CTRL,
+ NE2K_OPS_TX,
+ NE2K_OPS_RX,
+ NE2K_OPS_IRQ,
+};
+enum {
+ NE2K_CB_INTR = 1,
+ NE2K_CB_INTR_EVENT,
+};
+
+#define NE2K_NUM_INTR_EVENT_CBS 4
// === GLOBALS ===
#define PIO_op_RI(op, reg, sz, val) {UDI_PIO_##op+UDI_PIO_DIRECT+UDI_PIO_##reg, UDI_PIO_##sz##BYTE, val}
#define PIO_OUT_RI1(reg, ofs) PIO_op_RI(OUT, reg, 1, ofs)
#define PIO_IN_RI1(reg, ofs) PIO_op_RI(IN, reg, 1, ofs)
// --- Programmed IO ---
-/// Ne2000 reset operation (reads MAC address too)
-udi_pio_trans_t ne2k_pio_reset[] = {
- // - Reset card
- PIO_IN_RI1(R0, NE2K_REG_RESET),
- PIO_OUT_RI1(R0, NE2K_REG_RESET),
- // While ISR bit 7 is unset, spin
- {UDI_PIO_LABEL, 0, 1},
- PIO_IN_RI1(R0, NE2K_REG_ISR),
- {UDI_PIO_AND_IMM+UDI_PIO_R0, UDI_PIO_1BYTE, 0x80},
- {UDI_PIO_CSKIP+UDI_PIO_R0, UDI_PIO_1BYTE, UDI_PIO_NZ},
- {UDI_PIO_BRANCH, 0, 1},
- // ISR = 0x80 [Clear reset]
- PIO_OUT_RI1(R0, NE2K_REG_ISR),
- // - Init pass 1
- // CMD = 0x40|0x21 [Page1, NoDMA, Stop]
- PIO_MOV_RI1(R0, 0x40|0x21),
- PIO_OUT_RI1(R0, NE2K_REG_CMD),
- // CURR = First RX page
- PIO_MOV_RI1(R0, NE2K_RX_FIRST_PG),
- PIO_OUT_RI1(R0, NE2K_REG_CURR),
- // CMD = 0x21 [Page0, NoDMA, Stop]
- PIO_MOV_RI1(R0, 0x21),
- PIO_OUT_RI1(R0, NE2K_REG_CMD),
- // DCR = ? [WORD, ...]
- PIO_MOV_RI1(R0, 0x49),
- PIO_OUT_RI1(R0, NE2K_REG_DCR),
- // IMR = 0 [Disable all]
- PIO_MOV_RI1(R0, 0x00),
- PIO_OUT_RI1(R0, NE2K_REG_IMR),
- // ISR = 0xFF [ACK all]
- PIO_MOV_RI1(R0, 0xFF),
- PIO_OUT_RI1(R0, NE2K_REG_ISR),
- // RCR = 0x20 [Monitor]
- PIO_MOV_RI1(R0, 0x20),
- PIO_OUT_RI1(R0, NE2K_REG_RCR),
- // TCR = 0x02 [TX Off, Loopback]
- PIO_MOV_RI1(R0, 0x02),
- PIO_OUT_RI1(R0, NE2K_REG_TCR),
- // - Read MAC address from EEPROM (24 bytes from 0)
- PIO_MOV_RI1(R0, 0),
- PIO_MOV_RI1(R1, 0),
- PIO_OUT_RI1(R0, NE2K_REG_RSAR0),
- PIO_OUT_RI1(R1, NE2K_REG_RSAR1),
- PIO_MOV_RI1(R0, 6*4),
- PIO_MOV_RI1(R1, 0),
- PIO_OUT_RI1(R0, NE2K_REG_RBCR0),
- PIO_OUT_RI1(R1, NE2K_REG_RBCR1),
- // CMD = 0x0A [Start remote DMA]
- PIO_MOV_RI1(R0, 0x0A),
- PIO_OUT_RI1(R0, NE2K_REG_CMD),
- // Read MAC address
- PIO_MOV_RI1(R0, 0), // - Buffer offset (incremented by 1 each iteration)
- PIO_MOV_RI1(R1, NE2K_REG_MEM), // - Reg offset (no increment)
- PIO_MOV_RI1(R2, 6), // - Six iterations
- {UDI_PIO_REP_IN_IND, UDI_PIO_1BYTE,
- UDI_PIO_REP_ARGS(UDI_PIO_BUF, UDI_PIO_R0, 1, UDI_PIO_R1, 0, UDI_PIO_R2)},
- // - Setup
- // PSTART = First RX page [Receive area start]
- PIO_MOV_RI1(R0, NE2K_RX_FIRST_PG),
- PIO_OUT_RI1(R0, NE2K_REG_PSTART),
- // BNRY = Last RX page - 1 [???]
- PIO_MOV_RI1(R0, NE2K_RX_LAST_PG-1),
- PIO_OUT_RI1(R0, NE2K_REG_BNRY),
- // PSTOP = Last RX page [???]
- PIO_MOV_RI1(R0, NE2K_RX_LAST_PG),
- PIO_OUT_RI1(R0, NE2K_REG_PSTOP),
- // > Clear all interrupt and set mask
- // ISR = 0xFF [ACK all]
- PIO_MOV_RI1(R0, 0xFF),
- PIO_OUT_RI1(R0, NE2K_REG_ISR),
- // IMR = 0x3F []
- PIO_MOV_RI1(R0, 0x3F),
- PIO_OUT_RI1(R0, NE2K_REG_IMR),
- // CMD = 0x22 [NoDMA, Start]
- PIO_MOV_RI1(R0, 0x22),
- PIO_OUT_RI1(R0, NE2K_REG_CMD),
- // RCR = 0x0F [Wrap, Promisc]
- PIO_MOV_RI1(R0, 0x0F),
- PIO_OUT_RI1(R0, NE2K_REG_RCR),
- // TCR = 0x00 [Normal]
- PIO_MOV_RI1(R0, 0x00),
- PIO_OUT_RI1(R0, NE2K_REG_TCR),
- // TPSR = 0x40 [TX Start]
- PIO_MOV_RI1(R0, 0x40),
- PIO_OUT_RI1(R0, NE2K_REG_TPSR),
- // End
- {UDI_PIO_END_IMM, UDI_PIO_2BYTE, 0}
-};
-struct {
- udi_pio_trans_t *trans_list;
- udi_ubit16_t list_length;
- udi_ubit16_t pio_attributes;
-} ne2k_pio_ops[] = {
- {ne2k_pio_reset, ARRAY_SIZEOF(ne2k_pio_reset), 0}
-};
-const int NE2K_NUM_PIO_OPS = ARRAY_SIZEOF(ne2k_pio_ops);
+#include "ne2000_pio.h"
// === CODE ===
// --- Management
rdata->macaddr[0], rdata->macaddr[1], rdata->macaddr[2],
rdata->macaddr[3], rdata->macaddr[4], rdata->macaddr[5] );
attr_list ++;
- udi_enumerate_ack(cb, UDI_ENUMERATE_OK, 2);
+ udi_enumerate_ack(cb, UDI_ENUMERATE_OK, NE2K_OPS_CTRL);
break;
case UDI_ENUMERATE_NEXT:
udi_enumerate_ack(cb, UDI_ENUMERATE_DONE, 0);
{
udi_cb_t *gcb = UDI_GCB(cb);
ne2k_rdata_t *rdata = gcb->context;
+ rdata->active_cb = gcb;
// Set up PIO handles
rdata->init.pio_index = -1;
ne2k_pio_ops[rdata->init.pio_index].list_length,
UDI_PIO_LITTLE_ENDIAN, 0, 0
);
+ return ;
}
- else
- {
- // Next!
- }
+
+ // Next: Bind interrupt
+ udi_channel_spawn(ne2k_bus_dev_bind__intr_chanel, gcb, gcb->channel,
+ 0, NE2K_OPS_IRQ, rdata);
+}
+void ne2k_bus_dev_bind__intr_chanel(udi_cb_t *gcb, udi_channel_t new_channel)
+{
+ ne2k_rdata_t *rdata = gcb->context;
+
+ rdata->interrupt_channel = new_channel;
+
+ udi_cb_alloc(ne2k_bus_dev_bind__intr_attach, gcb, NE2K_CB_INTR, gcb->channel);
+}
+void ne2k_bus_dev_bind__intr_attach(udi_cb_t *gcb, udi_cb_t *new_cb)
+{
+ ne2k_rdata_t *rdata = gcb->context;
+ udi_intr_attach_cb_t *intr_cb = UDI_MCB(new_cb, udi_intr_attach_cb_t);
+ intr_cb->interrupt_idx = 0;
+ intr_cb->min_event_pend = 2;
+ intr_cb->preprocessing_handle = rdata->pio_handles[NE2K_PIO_IRQACK];
+ udi_intr_attach_req(intr_cb);
+ // continued in ne2k_bus_dev_intr_attach_ack
}
void ne2k_bus_dev_bus_unbind_ack(udi_bus_bind_cb_t *cb)
{
}
void ne2k_bus_dev_intr_attach_ack(udi_intr_attach_cb_t *intr_attach_cb, udi_status_t status)
{
+ udi_cb_t *gcb = UDI_GCB(intr_attach_cb);
+ ne2k_rdata_t *rdata = gcb->context;
+ // continuing from ne2k_bus_dev_bind__intr_attach
+ if( status != UDI_OK ) {
+ // TODO: Error
+ udi_cb_free( UDI_GCB(intr_attach_cb) );
+ return ;
+ }
+
+ rdata->intr_attach_cb = intr_attach_cb;
+
+ rdata->init.n_intr_event_cb = 0;
+ udi_cb_alloc(ne2k_bus_dev_bind__intr_event_cb, gcb, NE2K_CB_INTR_EVENT, rdata->interrupt_channel);
+ // V V V V
+}
+void ne2k_bus_dev_bind__intr_event_cb(udi_cb_t *gcb, udi_cb_t *new_cb)
+{
+ ne2k_rdata_t *rdata = gcb->context;
+
+ udi_intr_event_cb_t *intr_event_cb = UDI_MCB(new_cb, udi_intr_event_cb_t);
+ udi_intr_event_rdy(intr_event_cb);
+ rdata->init.n_intr_event_cb ++;
+
+ if( rdata->init.n_intr_event_cb < NE2K_NUM_INTR_EVENT_CBS )
+ {
+ udi_cb_alloc(ne2k_bus_dev_bind__intr_event_cb, gcb,
+ NE2K_CB_INTR_EVENT, rdata->interrupt_channel);
+ // A A A A
+ return ;
+ }
+
+ udi_pio_trans(ne2k_bus_dev_bind__card_reset, gcb,
+ rdata->pio_handles[NE2K_PIO_RESET], 0, NULL, &rdata->macaddr);
+ // V V V V
+}
+
+void ne2k_bus_dev_bind__card_reset(udi_cb_t *gcb, udi_buf_t *new_buf, udi_status_t status, udi_ubit16_t result)
+{
+ ne2k_rdata_t *rdata = gcb->context;
+ // Done! (Finally)
+ udi_channel_event_complete( UDI_MCB(rdata->active_cb, udi_channel_event_cb_t), UDI_OK );
+ // = = = =
}
void ne2k_bus_dev_intr_detach_ack(udi_intr_detach_cb_t *intr_detach_cb)
{
}
void ne2k_nd_ctrl_bind_req(udi_nic_bind_cb_t *cb, udi_index_t tx_chan_index, udi_index_t rx_chan_index)
{
+ udi_cb_t *gcb = UDI_GCB(cb);
+ ne2k_rdata_t *rdata = gcb->context;
+ rdata->init.rx_chan_index = rx_chan_index;
+ udi_channel_spawn(ne2k_nd_ctrl_bind__tx_chan_ok, gcb, gcb->channel, tx_chan_index, NE2K_OPS_TX, rdata);
+ // V V V V
+}
+void ne2k_nd_ctrl_bind__tx_chan_ok(udi_cb_t *gcb, udi_channel_t new_channel)
+{
+ ne2k_rdata_t *rdata = gcb->context;
+ rdata->tx_channel = new_channel;
+ udi_channel_spawn(ne2k_nd_ctrl_bind__rx_chan_ok, gcb, gcb->channel,
+ rdata->init.rx_chan_index, NE2K_OPS_RX, rdata);
+ // V V V V
+}
+void ne2k_nd_ctrl_bind__rx_chan_ok(udi_cb_t *cb, udi_channel_t new_channel)
+{
+ ne2k_rdata_t *rdata = cb->context;
+ rdata->rx_channel = new_channel;
+ udi_nsr_bind_ack( UDI_MCB(cb, udi_nic_bind_cb_t), UDI_OK );
+ // = = = =
}
void ne2k_nd_ctrl_unbind_req(udi_nic_cb_t *cb)
{
}
void ne2k_nd_ctrl_enable_req(udi_nic_cb_t *cb)
{
+ // Enable
}
void ne2k_nd_ctrl_disable_req(udi_nic_cb_t *cb)
{
void ne2k_nd_ctrl_info_req(udi_nic_info_cb_t *cb, udi_boolean_t reset_statistics)
{
}
+// --- IRQ
+void ne2k_bus_irq_channel_event_ind(udi_channel_event_cb_t *cb)
+{
+}
+void ne2k_bus_irq_intr_event_ind(udi_intr_event_cb_t *cb, udi_ubit8_t flags)
+{
+ if( cb->intr_result & 0x01 )
+ {
+ ne2k_intr__rx_ok( UDI_GCB(cb) );
+ }
+ udi_intr_event_rdy(cb);
+}
// === Definition structures ===
udi_mgmt_ops_t ne2k_mgmt_ops = {
ne2k_nd_rx_rx_rdy
};
udi_ubit8_t ne2k_nd_rx_ops_flags[2] = {0};
+udi_intr_handler_ops_t ne2k_bus_irq_ops = {
+ ne2k_bus_irq_channel_event_ind,
+ ne2k_bus_irq_intr_event_ind
+};
+udi_ubit8_t ne2k_bus_irq_ops_flags[2] = {0};
+
udi_primary_init_t ne2k_pri_init = {
.mgmt_ops = &ne2k_mgmt_ops,
.mgmt_op_flags = ne2k_mgmt_op_flags,
};
udi_ops_init_t ne2k_ops_list[] = {
{
- 1, NE2K_META_BUS, UDI_BUS_DEVICE_OPS_NUM,
+ NE2K_OPS_DEV, NE2K_META_BUS, UDI_BUS_DEVICE_OPS_NUM,
0,
(udi_ops_vector_t*)&ne2k_bus_dev_ops,
ne2k_bus_dev_ops_flags
},
{
- 2, NE2K_META_NIC, UDI_ND_CTRL_OPS_NUM,
+ NE2K_OPS_CTRL, NE2K_META_NIC, UDI_ND_CTRL_OPS_NUM,
0,
(udi_ops_vector_t*)&ne2k_nd_ctrl_ops,
ne2k_nd_ctrl_ops_flags
},
{
- 3, NE2K_META_NIC, UDI_ND_TX_OPS_NUM,
+ NE2K_OPS_TX, NE2K_META_NIC, UDI_ND_TX_OPS_NUM,
0,
(udi_ops_vector_t*)&ne2k_nd_tx_ops,
ne2k_nd_tx_ops_flags
},
{
- 4, NE2K_META_NIC, UDI_ND_RX_OPS_NUM,
+ NE2K_OPS_RX, NE2K_META_NIC, UDI_ND_RX_OPS_NUM,
0,
(udi_ops_vector_t*)&ne2k_nd_rx_ops,
ne2k_nd_rx_ops_flags
},
+ {
+ NE2K_OPS_IRQ, NE2K_META_BUS, UDI_BUS_INTR_HANDLER_OPS_NUM,
+ 0,
+ (udi_ops_vector_t*)&ne2k_bus_irq_ops,
+ ne2k_bus_irq_ops_flags
+ },
{0}
};
const udi_init_t udi_init_info = {