| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670 |
- /*
- * Copyright (c) 2006-2021, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2021-08-19 JasonHu first version
- */
- #include <board.h>
- #include <rtthread.h>
- #include <rtdevice.h>
- #include <rthw.h>
- #include <netif/ethernetif.h>
- #include <pci.h>
- #include <mmu.h>
- #define DBG_LVL DBG_INFO
- #define DBG_TAG "PCNET32"
- #include <rtdbg.h>
- #include "drv_pcnet32.h"
- #define DEV_NAME "e0"
- #define GET_PCNET32(eth) (struct eth_device_pcnet32 *)(eth)
- /**
- * rx ring desc struct
- */
- struct pcnet32_rx_desc
- {
- rt_uint32_t base; /* buffer base addr */
- rt_uint16_t buf_length; /* two`s complement of length */
- rt_uint16_t status; /* desc status */
- rt_uint16_t msg_length; /* Message Byte Count is the length in bytes of the received message. */
- rt_uint16_t rpc_rcc;
- rt_uint32_t reserved;
- } __attribute__ ((packed));
- /**
- * tx ring desc struct
- */
- struct pcnet32_tx_desc
- {
- rt_uint32_t base; /* buffer base addr */
- rt_uint16_t buf_length; /* two`s complement of length */
- rt_uint16_t status; /* desc status */
- rt_uint32_t misc;
- rt_uint32_t reserved;
- } __attribute__ ((packed));
- /**
- * The PCNET32 32-Bit initialization block, described in databook.
- * The Mode Register (CSR15) allows alteration of the chip's operating
- * parameters. The Mode field of the Initialization Block is copied directly
- * into CSR15. Normal operation is the result of configuring the Mode field
- * with all bits zero.
- */
- struct pcnet32_init_block
- {
- rt_uint16_t mode;
- rt_uint16_t tlen_rlen;
- rt_uint8_t phys_addr[6];
- rt_uint16_t reserved;
- rt_uint32_t filter[2];
- /* Receive and transmit ring base, along with extra bits. */
- rt_uint32_t rx_ring;
- rt_uint32_t tx_ring;
- } __attribute__ ((packed));
- struct eth_device_pcnet32
- {
- /* inherit from Ethernet device */
- struct eth_device parent;
- /* interface address info. */
- rt_uint8_t dev_addr[ETH_ALEN]; /* MAC address */
- rt_pci_device_t *pci_dev; /* pci device info */
- rt_uint32_t iobase; /* io port base */
- rt_uint32_t irqno; /* irq number */
- rt_mq_t rx_mqueue; /* msg queue for rx */
- struct pcnet32_init_block *init_block;
- rt_uint16_t rx_len_bits;
- rt_uint16_t tx_len_bits;
- rt_ubase_t rx_ring_dma_addr;
- rt_ubase_t tx_ring_dma_addr;
- rt_ubase_t init_block_dma_addr;
- rt_ubase_t rx_buffer_ptr;
- rt_ubase_t tx_buffer_ptr; /* pointers to transmit/receive buffers */
- rt_size_t rx_buffer_count; /* total number of receive buffers */
- rt_size_t tx_buffer_count; /* total number of transmit buffers */
- rt_size_t buffer_size; /* length of each packet buffer */
- rt_size_t de_size; /* length of descriptor entry */
- struct pcnet32_rx_desc *rdes; /* pointer to ring buffer of receive des */
- struct pcnet32_tx_desc *tdes; /* pointer to ring buffer of transmit des */
- rt_uint32_t rx_buffers; /* physical address of actual receive buffers (< 4 GiB) */
- rt_uint32_t tx_buffers; /* physical address of actual transmit buffers (< 4 GiB) */
- };
- static struct eth_device_pcnet32 eth_dev;
- static rt_uint8_t rx_cache_send_buf[RX_MSG_SIZE] = {0}; /* buf for rx packet, put size and data into mq */
- static rt_uint8_t rx_cache_recv_buf[RX_MSG_SIZE] = {0}; /* buf for rx packet, get size and data from mq */
- static rt_uint8_t tx_cache_pbuf[TX_CACHE_BUF_SIZE] = {0}; /* buf for tx packet, get data from pbuf payload */
- /**
- * does the driver own the particular buffer?
- */
- rt_inline rt_bool_t pcnet32_is_driver_own(struct eth_device_pcnet32 *dev, rt_bool_t is_tx, rt_uint32_t idx)
- {
- return (rt_bool_t)(is_tx ? ((dev->tdes[idx].status & PCNET32_DESC_STATUS_OWN) == 0) :
- ((dev->rdes[idx].status & PCNET32_DESC_STATUS_OWN) == 0));
- }
- /*
- * get the next desc buffer index
- */
- rt_inline rt_uint32_t pcnet32_get_next_desc(struct eth_device_pcnet32 *dev, rt_uint32_t cur_idx, rt_uint32_t buf_count)
- {
- return (cur_idx + 1) % buf_count;
- }
- static void pcnet32_init_rx_desc_entry(struct eth_device_pcnet32 *dev, rt_uint32_t idx)
- {
- struct pcnet32_rx_desc *des = dev->rdes + idx;
- rt_memset(des, 0, dev->de_size);
- des->base = dev->rx_buffers + idx * dev->buffer_size;
- /* next 2 bytes are 0xf000 OR'd with the first 12 bits of the 2s complement of the length */
- rt_uint16_t bcnt = (rt_uint16_t)(-dev->buffer_size);
- bcnt &= 0x0fff;
- bcnt |= 0xf000; /* high 4 bits fixed 1 */
- des->buf_length = bcnt;
- /* finally, set ownership bit - transmit buffers are owned by us, receive buffers by the card */
- des->status = PCNET32_DESC_STATUS_OWN;
- }
- static void pcnet32_init_tx_desc_entry(struct eth_device_pcnet32 *dev, rt_uint32_t idx)
- {
- struct pcnet32_tx_desc *des = dev->tdes + idx;
- rt_memset(des, 0, dev->de_size);
- des->base = dev->tx_buffers + idx * dev->buffer_size;
- /* next 2 bytes are 0xf000 OR'd with the first 12 bits of the 2s complement of the length */
- rt_uint16_t bcnt = (rt_uint16_t)(-dev->buffer_size);
- bcnt &= 0x0fff;
- bcnt |= 0xf000; /* high 4 bits fixed 1 */
- des->buf_length = bcnt;
- }
- static rt_uint16_t pcnet32_wio_read_mac(rt_uint32_t addr, int index)
- {
- return inw(addr + index);
- }
- /*
- * write index to RAP, read data from RDP
- */
- static rt_uint16_t pcnet32_wio_read_csr(rt_uint32_t addr, int index)
- {
- outw(addr + PCNET32_WIO_RAP, index);
- return inw(addr + PCNET32_WIO_RDP);
- }
- /**
- * write index to RAP, write data to RDP
- */
- static void pcnet32_wio_write_csr(rt_uint32_t addr, int index, rt_uint16_t val)
- {
- outw(addr + PCNET32_WIO_RAP, index);
- outw(addr + PCNET32_WIO_RDP, val);
- }
- static void pcnet32_wio_write_bcr(rt_uint32_t addr, int index, rt_uint16_t val)
- {
- outw(addr + PCNET32_WIO_RAP, index);
- outw(addr + PCNET32_WIO_BDP, val);
- }
- /*
- * Reset causes the device to cease operation and clear its internal logic.
- */
- static void pcnet32_wio_reset(rt_uint32_t addr)
- {
- inw(addr + PCNET32_WIO_RESET);
- }
- static int pcnet32_get_pci(struct eth_device_pcnet32 *dev)
- {
- /* get pci device */
- rt_pci_device_t *pci_dev = rt_pci_device_get(PCNET32_VENDOR_ID, PCNET32_DEVICE_ID);
- if (pci_dev == RT_NULL)
- {
- LOG_E("device not find on pci device.\n");
- return -1;
- }
- dev->pci_dev = pci_dev;
- dbg_log(DBG_LOG, "find device, vendor id: 0x%x, device id: 0x%x\n",
- pci_dev->vendor_id, pci_dev->device_id);
- /* enable bus mastering */
- rt_pci_enable_bus_mastering(pci_dev);
- /* get io port address */
- dev->iobase = rt_pci_device_get_io_addr(pci_dev);
- if (dev->iobase == 0)
- {
- LOG_E("invalid pci device io address.\n");
- return -1;
- }
- dbg_log(DBG_LOG, "io base address: 0x%x\n", dev->iobase);
- /* get irq */
- dev->irqno = rt_pci_device_get_irq_line(pci_dev);
- if (dev->irqno == 0xff)
- {
- LOG_E("invalid irqno.\n");
- return -1;
- }
- dbg_log(DBG_LOG, "irqno %d\n", dev->irqno);
- return 0;
- }
- static int pcnet32_transmit(struct eth_device_pcnet32 *dev, rt_uint8_t *buf, rt_size_t len)
- {
- if(len > ETH_FRAME_LEN)
- {
- len = ETH_FRAME_LEN;
- }
- rt_uint32_t tx_retry = PCNET32_TX_RETRY;
- while (tx_retry > 0)
- {
- /* the next available descriptor entry index is in tx_buffer_ptr */
- if(!pcnet32_is_driver_own(dev, RT_TRUE, dev->tx_buffer_ptr))
- {
- /* try encourage the card to send all buffers. */
- pcnet32_wio_write_csr(dev->iobase, CSR0, pcnet32_wio_read_csr(dev->iobase, CSR0) | CSR0_TXPOLL);
- }
- else
- {
- break;
- }
- --tx_retry;
- }
- if (!tx_retry) /* retry end, no entry available */
- {
- dbg_log(DBG_ERROR, "transmit no available descriptor entry\n")
- return -1;
- }
- rt_memcpy((void *)(dev->tx_buffers + dev->tx_buffer_ptr * dev->buffer_size), buf, len);
- struct pcnet32_tx_desc *tdes = dev->tdes + dev->tx_buffer_ptr;
- /**
- * set the STP bit in the descriptor entry (signals this is the first
- * frame in a split packet - we only support single frames)
- */
- tdes->status |= PCNET32_DESC_STATUS_STP;
- /* similarly, set the ENP bit to state this is also the end of a packet */
- tdes->status |= PCNET32_DESC_STATUS_ENP;
- rt_uint16_t bcnt = (rt_uint16_t)(-len);
- bcnt &= 0xfff;
- bcnt |= 0xf000; /* high 4 bits fixed 1 */
- tdes->buf_length = bcnt;
- /* finally, flip the ownership bit back to the card */
- tdes->status |= PCNET32_DESC_STATUS_OWN;
- dev->tx_buffer_ptr = pcnet32_get_next_desc(dev, dev->tx_buffer_ptr, dev->tx_buffer_count);
- return 0;
- }
- static rt_err_t pcnet32_tx(rt_device_t device, struct pbuf *p)
- {
- rt_err_t err = RT_EOK;
- /* copy data from pbuf to tx cache */
- pbuf_copy_partial(p, (void *)&tx_cache_pbuf[0], p->tot_len, 0);
- if (pcnet32_transmit(GET_PCNET32(device), tx_cache_pbuf, p->tot_len) < 0)
- {
- err = RT_ERROR;
- }
- return err;
- }
- static struct pbuf *pcnet32_rx(rt_device_t device)
- {
- struct eth_device_pcnet32 *dev = GET_PCNET32(device);
- int recv_len = 0;
- struct pbuf *pbuf = RT_NULL;
- rt_err_t err;
- /* get data from rx queue. */
- err = rt_mq_recv_interruptible(dev->rx_mqueue, rx_cache_recv_buf, RX_MSG_SIZE, 0);
- if (err != RT_EOK)
- {
- return pbuf;
- }
- /* get recv len from rx cache, 0~3: recv len, 3-n: frame data */
- recv_len = *(int *)rx_cache_recv_buf;
- if (recv_len > 0)
- {
- pbuf = pbuf_alloc(PBUF_LINK, recv_len, PBUF_RAM);
- rt_memcpy(pbuf->payload, (char *)rx_cache_recv_buf + 4, recv_len);
- }
- return pbuf;
- }
- static rt_err_t pcnet32_control(rt_device_t device, int cmd, void *args)
- {
- struct eth_device_pcnet32 *dev = GET_PCNET32(device);
- switch(cmd)
- {
- case NIOCTL_GADDR:
- /* get MAC address */
- if(args)
- {
- rt_memcpy(args, dev->dev_addr, ETH_ALEN);
- }
- else
- {
- return -RT_ERROR;
- }
- break;
- default :
- break;
- }
- return RT_EOK;
- }
- static void pcnet32_rx_packet(struct eth_device_pcnet32 *dev)
- {
- while (pcnet32_is_driver_own(dev, RT_FALSE, dev->rx_buffer_ptr))
- {
- struct pcnet32_rx_desc *rdes = dev->rdes + dev->rx_buffer_ptr;
- rt_uint32_t plen = rdes->msg_length; /* msg len no need to negate it unlike BCNT above */
- void *pbuf = (void *)(dev->rx_buffers + dev->rx_buffer_ptr * dev->buffer_size);
- dbg_log(DBG_LOG, "recv packet on ring %d: buf=%p, len=%d\n", dev->rx_buffer_ptr, pbuf, plen);
- /* merge size and data into receive pkg */
- rt_memcpy(rx_cache_send_buf, &plen, 4);
- rt_memcpy(&rx_cache_send_buf[4], pbuf, plen);
- rt_mq_send_interrupt(dev->rx_mqueue, rx_cache_send_buf, plen + 4);
- eth_device_ready(&dev->parent); /* notify eth thread to read packet */
- /* hand the buffer back to the card */
- rdes->status = PCNET32_DESC_STATUS_OWN;
- dev->rx_buffer_ptr = pcnet32_get_next_desc(dev, dev->rx_buffer_ptr, dev->rx_buffer_count);
- }
- }
- static void rt_hw_pcnet32_isr(int vector, void *param)
- {
- struct eth_device_pcnet32 *dev = GET_PCNET32(param);
- rt_uint32_t iobase = dev->iobase;
- rt_uint32_t csr0 = pcnet32_wio_read_csr(iobase, 0);
- if (csr0 & CSR0_RINT) /* recv packet */
- {
- dbg_log(DBG_LOG, "RX intr occur!\n");
- pcnet32_rx_packet(dev);
- }
- else if ((csr0 & CSR0_TINT)) /* packet transmitted */
- {
- dbg_log(DBG_LOG, "TX intr occur!\n");
- }
- else if ((csr0 & CSR0_IDON))
- {
- dbg_log(DBG_INFO, "init done\n");
- }
- else if ((csr0 & CSR0_MERR))
- {
- dbg_log(DBG_WARNING, "memory error!\n");
- }
- else if ((csr0 & CSR0_MISS))
- {
- dbg_log(DBG_WARNING, "missed frame!\n");
- }
- else if ((csr0 & CSR0_CERR))
- {
- dbg_log(DBG_WARNING, "collision error!\n");
- }
- else if ((csr0 & CSR0_BABL))
- {
- dbg_log(DBG_WARNING, "transmitter time-out error!\n");
- }
- else
- {
- dbg_log(DBG_WARNING, "unknown intr\n");
- }
- /* ack pcnet32 interrupt as handled */
- pcnet32_wio_write_csr(iobase, 0, csr0);
- }
- static rt_err_t pcnet32_alloc_ring_buffer(struct eth_device_pcnet32 *dev)
- {
- dev->rdes = rt_malloc_align(dev->rx_buffer_count * dev->de_size, 16);
- if (dev->rdes == RT_NULL)
- {
- dbg_log(DBG_ERROR, "alloc memory for rx ring failed!");
- return RT_ERROR;
- }
- dev->tdes = rt_malloc_align(dev->tx_buffer_count * dev->de_size, 16);
- if (dev->tdes == RT_NULL)
- {
- dbg_log(DBG_ERROR, "alloc memory for tx ring failed!");
- rt_free_align(dev->rdes);
- return RT_ERROR;
- }
- dev->rx_buffers = (uint32_t)rt_malloc_align(dev->rx_buffer_count * dev->buffer_size, 16);
- if (dev->rx_buffers == 0)
- {
- dbg_log(DBG_ERROR, "alloc memory for rx ring buffer failed!");
- rt_free_align(dev->rdes);
- rt_free_align(dev->tdes);
- return RT_ERROR;
- }
- dev->tx_buffers = (uint32_t)rt_malloc_align(dev->tx_buffer_count * dev->buffer_size, 16);
- if (dev->tx_buffers == 0)
- {
- dbg_log(DBG_ERROR, "alloc memory for tx ring buffer failed!");
- rt_free_align(dev->rdes);
- rt_free_align(dev->tdes);
- rt_free_align((void *)dev->rx_buffers);
- return RT_ERROR;
- }
- dbg_log(DBG_LOG, "rdes:%p tdes:%p rbuf:%p tbuf:%p\n", dev->rdes, dev->tdes, dev->rx_buffers, dev->tx_buffers);
- int i = 0;
- for (i = 0; i < dev->rx_buffer_count; i++)
- {
- pcnet32_init_rx_desc_entry(dev, i);
- }
- for (i = 0; i < dev->tx_buffer_count; i++)
- {
- pcnet32_init_tx_desc_entry(dev, i);
- }
- return RT_EOK;
- }
- static void pcnet32_free_ring_buffer(struct eth_device_pcnet32 *dev)
- {
- rt_free_align(dev->rdes);
- rt_free_align(dev->tdes);
- rt_free_align((void *)dev->rx_buffers);
- rt_free_align((void *)dev->tx_buffers);
- }
- static void pcnet32_print_init_block(struct eth_device_pcnet32 *dev)
- {
- rt_uint32_t iobase = dev->iobase;
- struct pcnet32_init_block *init_block = dev->init_block;
- dbg_log(DBG_LOG, "============\nprint init block\n");
- dbg_log(DBG_LOG, "mode: %x, tlen_rlen:%x\n", init_block->mode, init_block->tlen_rlen);
- dbg_log(DBG_LOG, "mac: %x:%x:%x:%x:%x:%x\n",
- init_block->phys_addr[0],
- init_block->phys_addr[1],
- init_block->phys_addr[2],
- init_block->phys_addr[3],
- init_block->phys_addr[4],
- init_block->phys_addr[5]);
- dbg_log(DBG_LOG, "filter0: %x, filter1: %x\n", init_block->filter[0], init_block->filter[1]);
- dbg_log(DBG_LOG, "rx ring dma: %x, tx ring dma: %x\n", init_block->rx_ring, init_block->tx_ring);
- dbg_log(DBG_LOG, "init block dma: %x\n", dev->init_block_dma_addr);
- int i = 0;
- for (; i <= 46; i++)
- {
- dbg_log(DBG_LOG, "csr%d=%x\n", i, pcnet32_wio_read_csr(iobase, i));
- }
- }
- static rt_err_t pcnet32_init(rt_device_t device)
- {
- struct eth_device_pcnet32 *dev = GET_PCNET32(device);
- rt_uint32_t iobase = dev->iobase;
- /* init buffer info */
- dev->rx_buffer_ptr = 0;
- dev->tx_buffer_ptr = 0;
- dev->rx_buffer_count = PCNET32_RX_BUFFERS;
- dev->tx_buffer_count = PCNET32_TX_BUFFERS;
- dev->buffer_size = ETH_FRAME_LEN;
- dev->de_size = PCNET32_RING_DE_SIZE;
- if (pcnet32_alloc_ring_buffer(dev) != RT_EOK)
- {
- return RT_ERROR;
- }
- dev->rx_ring_dma_addr = (rt_ubase_t)rt_hw_vir2phy(dev->rdes);
- dev->tx_ring_dma_addr = (rt_ubase_t)rt_hw_vir2phy(dev->tdes);
- /* create msg queue for eth rx */
- dev->rx_mqueue = rt_mq_create("rx_mqueue", RX_MSG_SIZE, RX_MSG_CNT, 0);
- if (dev->rx_mqueue == RT_NULL)
- {
- LOG_E("crete msg queue for rx buffer failed!\n");
- pcnet32_free_ring_buffer(dev);
- return RT_ERROR;
- }
- /* alloc init block, must 16 bit align */
- dev->init_block = rt_malloc_align(sizeof(struct pcnet32_init_block), 16);
- if (dev->init_block == RT_NULL)
- {
- dbg_log(DBG_ERROR, "alloc memory for init block failed!");
- rt_mq_delete(dev->rx_mqueue);
- pcnet32_free_ring_buffer(dev);
- return RT_ERROR;
- }
- dev->init_block_dma_addr = (rt_ubase_t)rt_hw_vir2phy(dev->init_block);
- dbg_log(DBG_LOG, "init block addr:%p size:%d\n", dev->init_block, sizeof(struct pcnet32_init_block));
- /* fill init block */
- dev->init_block->mode = 0;
- dev->tx_len_bits = (PCNET32_LOG_TX_BUFFERS << 4);
- dev->rx_len_bits = (PCNET32_LOG_RX_BUFFERS << 4);
- dev->init_block->tlen_rlen = (dev->tx_len_bits << 8) | dev->rx_len_bits;
- int i = 0;
- for (i = 0; i < ETH_ALEN; i++)
- {
- dev->init_block->phys_addr[i] = dev->dev_addr[i];
- }
- dev->init_block->filter[0] = 0x00000000;
- dev->init_block->filter[1] = 0x00000000;
- dev->init_block->rx_ring = dev->rx_ring_dma_addr;
- dev->init_block->tx_ring = dev->tx_ring_dma_addr;
- /* register init block, CSR1 save low 16 bit, CSR1 save high 16 bit */
- pcnet32_wio_write_csr(iobase, CSR1, (dev->init_block_dma_addr & 0xffff));
- pcnet32_wio_write_csr(iobase, CSR2, (dev->init_block_dma_addr >> 16) & 0xffff);
- /* register intr */
- if (rt_hw_interrupt_install(dev->irqno, rt_hw_pcnet32_isr, (void *) dev, "pcnet32") < 0)
- {
- LOG_E("install IRQ failed!\n");
- rt_free_align(dev->init_block);
- rt_mq_delete(dev->rx_mqueue);
- pcnet32_free_ring_buffer(dev);
- return RT_ERROR;
- }
- rt_hw_interrupt_umask(dev->irqno);
- /* Start init */
- pcnet32_wio_write_csr(iobase, CSR0, CSR0_INIT | CSR0_INTEN);
- dbg_log(DBG_LOG, "card init done.\n");
- /* add auto pad amd strip recv */
- rt_uint16_t csr4 = pcnet32_wio_read_csr(iobase, CSR4);
- pcnet32_wio_write_csr(iobase, CSR4, csr4 | CSR4_ASTRP_RCV | CSR4_APAD_XMT);
- /* start work */
- pcnet32_wio_write_csr(iobase, CSR0, CSR0_START | CSR0_INTEN);
- pcnet32_print_init_block(dev);
- eth_device_linkchange(&dev->parent, RT_TRUE);
- return RT_EOK;
- }
- #ifdef RT_USING_DEVICE_OPS
- const static struct rt_device_ops pcnet32_ops =
- {
- pcnet32_init,
- RT_NULL,
- RT_NULL,
- RT_NULL,
- RT_NULL,
- pcnet32_control
- };
- #endif
- static rt_err_t pcnet32_init_hw(struct eth_device_pcnet32 *dev)
- {
- rt_uint32_t iobase = dev->iobase;
- /* reset card to 16 bit io mode */
- pcnet32_wio_reset(iobase);
- /* use dealy to wait reset done, at least 1 microsecond */
- rt_thread_delay(1);
- /* switch to 32 bit soft-style mode, use 32 bit struct */
- pcnet32_wio_write_bcr(iobase, 20, 0x102);
- /* stop card work */
- pcnet32_wio_write_csr(iobase, 0, 0x4);
- /* read mac addr */
- rt_uint16_t mac0 = pcnet32_wio_read_mac(iobase, 0);
- rt_uint16_t mac1 = pcnet32_wio_read_mac(iobase, 2);
- rt_uint16_t mac2 = pcnet32_wio_read_mac(iobase, 4);
- dev->dev_addr[0] = mac0 & 0xff;
- dev->dev_addr[1] = (mac0 >> 8) & 0xff;
- dev->dev_addr[2] = mac1 & 0xff;
- dev->dev_addr[3] = (mac1 >> 8) & 0xff;
- dev->dev_addr[4] = mac2 & 0xff;
- dev->dev_addr[5] = (mac2 >> 8) & 0xff;
- dbg_log(DBG_INFO, "MAC addr: %x:%x:%x:%x:%x:%x\n",
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
- return RT_EOK;
- }
- static int rt_hw_pcnet32_init(void)
- {
- rt_memset(ð_dev, 0x0, sizeof(eth_dev));
- if (pcnet32_get_pci(ð_dev) < 0)
- {
- return -1;
- }
- if (pcnet32_init_hw(ð_dev) != RT_EOK)
- {
- return -1;
- }
- /* set device opts */
- #ifdef RT_USING_DEVICE_OPS
- eth_dev.parent.parent.ops = &pcnet32_ops;
- #else
- eth_dev.parent.parent.init = pcnet32_init;
- eth_dev.parent.parent.open = RT_NULL;
- eth_dev.parent.parent.close = RT_NULL;
- eth_dev.parent.parent.read = RT_NULL;
- eth_dev.parent.parent.write = RT_NULL;
- eth_dev.parent.parent.control = pcnet32_control;
- #endif
- eth_dev.parent.parent.user_data = RT_NULL;
- eth_dev.parent.eth_rx = pcnet32_rx;
- eth_dev.parent.eth_tx = pcnet32_tx;
- /* register ETH device */
- if (eth_device_init(&(eth_dev.parent), DEV_NAME) != RT_EOK)
- {
- return -1;
- }
- return 0;
- }
- INIT_DEVICE_EXPORT(rt_hw_pcnet32_init);
|