DM9000网卡驱动分析(转)
s3c6410自带的DM9000网卡驱动也是基于platform设备模型。
1 #define DM9000_PHY 0x40 /* PHY address 0x01 */
2
3 #define CARDNAME "dm9000"
4 #define DRV_VERSION "1.31"
5 /*
6 * Transmit timeout, default 5 seconds.
7 */
8 static int watchdog = 5000; //5s的延时时间
9 module_param(watchdog, int, 0400);
10 MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");
11 enum dm9000_type { //开发板定义了三个DM9000类型
12 TYPE_DM9000E, /* original DM9000 */
13 TYPE_DM9000A,
14 TYPE_DM9000B
15 };
1 static int __init dm9000_init(void)
2 {
3 printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME, DRV_VERSION);
4
5 return platform_driver_register(&dm9000_driver); //platform设备模型注册驱动
6 }
dm9000的platform设备驱动函数如下:
1 static struct platform_driver dm9000_driver = {
2 .driver = {
3 .name = "dm9000",
4 .owner = THIS_MODULE,
5 .pm = &dm9000_drv_pm_ops,
6 },
7 .probe = dm9000_probe,
8 .remove = __devexit_p(dm9000_drv_remove),
9 };
1 static int __devinit dm9000_probe(struct platform_device *pdev)
2 {
3 struct dm9000_plat_data *pdata = pdev->dev.platform_data;//驱动程序中获得系统定义的网卡板级信息
4 //定义在/arch/arm/mach-s3c64xx/mach-smdk6410.c中。
5 struct board_info *db; /* Point a board information structure */
6 struct net_device *ndev; //定义设备结构体
7 const unsigned char *mac_src;
8 int ret = 0;
9 int iosize;
10 int i;
11 u32 id_val;
12
13 /* Init network device */
14 //分配生成net_device结构体 alloc_etherdev是alloc_netdev()针对以太网的快捷操作函数
15 ndev = alloc_etherdev(sizeof(struct board_info));
16
17 //判断是否分配正确
18 if (!ndev) {
19 dev_err(&pdev->dev, "could not allocate device.\n");
20 return -ENOMEM;
21 }
22 //建立net_device到device的连接
23 SET_NETDEV_DEV(ndev, &pdev->dev);
24 //内核输出信息
25 dev_dbg(&pdev->dev, "dm9000_probe()\n");
26 //函数netdev_priv直接返回了net_device结构末端地址,也就是网卡私有数据结构的起始地址。
27 /* setup board info structure */
28 db = netdev_priv(ndev);
29
30 db->dev = &pdev->dev;
31 db->ndev = ndev;
32
33 spin_lock_init(&db->lock);//初始化自旋锁
34 mutex_init(&db->addr_lock);
35
36 INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work); //??
37 //获取平台设备资源 resource 地址空间、数据空间、中断信号 7号中断
38 db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
39 db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
40 db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
41 //判断资源是否获取成功
42 if (db->addr_res == NULL || db->data_res == NULL ||
43 db->irq_res == NULL) {
44 dev_err(db->dev, "insufficient resources\n");
45 ret = -ENOENT;
46 goto out;
47 }
48 //platform_get_resource的变体 同 platform_get_resource(pdev, IORESOURCE_IRQ, 1)
49 db->irq_wake = platform_get_irq(pdev, 1);
50 if (db->irq_wake >= 0) {
51 dev_dbg(db->dev, "wakeup irq %d\n", db->irq_wake);
52 //前面获得中断号 申请中断
53 ret = request_irq(db->irq_wake, dm9000_wol_interrupt,
54 IRQF_SHARED, dev_name(db->dev), ndev);
55 if (ret) {
56 dev_err(db->dev, "cannot get wakeup irq (%d)\n", ret);
57 } else {
58 /* test to see if irq is really wakeup capable */
59 ret = set_irq_wake(db->irq_wake, 1);
60 if (ret) {
61 dev_err(db->dev, "irq %d cannot set wakeup (%d)\n",
62 db->irq_wake, ret);
63 ret = 0;
64 } else {
65 set_irq_wake(db->irq_wake, 0);
66 db->wake_supported = 1;
67 }
68 }
69 }
70 //IO资源分配大小 地址 为resource分配内存
71 iosize = resource_size(db->addr_res);
72 db->addr_req = request_mem_region(db->addr_res->start, iosize,
73 pdev->name); //内存申请
74
75 if (db->addr_req == NULL) {
76 dev_err(db->dev, "cannot claim address reg area\n");
77 ret = -EIO;
78 goto out;
79 }
80
81 db->io_addr = ioremap(db->addr_res->start, iosize);
82
83 if (db->io_addr == NULL) {
84 dev_err(db->dev, "failed to ioremap address reg\n");
85 ret = -EINVAL;
86 goto out;
87 }
88
89 iosize = resource_size(db->data_res);
90 db->data_req = request_mem_region(db->data_res->start, iosize,
91 pdev->name);
92
93 if (db->data_req == NULL) {
94 dev_err(db->dev, "cannot claim data reg area\n");
95 ret = -EIO;
96 goto out;
97 }
98
99 db->io_data = ioremap(db->data_res->start, iosize);
100
101 if (db->io_data == NULL) {
102 dev_err(db->dev, "failed to ioremap data reg\n");
103 ret = -EINVAL;
104 goto out;
105 }
106 //初始化net_device中的成员
107 /* fill in parameters for net-dev structure */
108 ndev->base_addr = (unsigned long)db->io_addr; //网络接口的IO基地址
109 ndev->irq = db->irq_res->start;//中断号 ifconfig时会打印出这个值 也可通过这个修改
110
111 /* ensure at least we have a default set of IO routines */
112 dm9000_set_io(db, iosize);
113
114 /* check to see if anything is being over-ridden */
115 if (pdata != NULL) {
116 /* check to see if the driver wants to over-ride the
117 * default IO width */
118 //检测与板级信息是否相同
119 if (pdata->flags & DM9000_PLATF_8BITONLY)
120 dm9000_set_io(db, 1);
121
122 if (pdata->flags & DM9000_PLATF_16BITONLY)
123 dm9000_set_io(db, 2);
124
125 if (pdata->flags & DM9000_PLATF_32BITONLY)
126 dm9000_set_io(db, 4);
127
128 /* check to see if there are any IO routine
129 * over-rides */
130
131 if (pdata->inblk != NULL)
132 db->inblk = pdata->inblk;
133
134 if (pdata->outblk != NULL)
135 db->outblk = pdata->outblk;
136
137 if (pdata->dumpblk != NULL)
138 db->dumpblk = pdata->dumpblk;
139
140 db->flags = pdata->flags;
141 }
142
143 #ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL
144 db->flags |= DM9000_PLATF_SIMPLE_PHY;
145 #endif
146
147 dm9000_reset(db);
148
149 /* try multiple times, DM9000 sometimes gets the read wrong */
150 for (i = 0; i < 8; i++) { //宏定义在dm9000.h中
151 id_val = ior(db, DM9000_VIDL);
152 id_val |= (u32)ior(db, DM9000_VIDH) << 8;
153 id_val |= (u32)ior(db, DM9000_PIDL) << 16;
154 id_val |= (u32)ior(db, DM9000_PIDH) << 24;
155
156 if (id_val == DM9000_ID)
157 break;
158 dev_err(db->dev, "read wrong id 0x%08x\n", id_val);
159 }
160
161 if (id_val != DM9000_ID) {
162 dev_err(db->dev, "wrong id: 0x%08x\n", id_val);
163 ret = -ENODEV;
164 goto out;
165 }
166
167 /* Identify what type of DM9000 we are working on */
168
169 id_val = ior(db, DM9000_CHIPR);
170 dev_dbg(db->dev, "dm9000 revision 0x%02x\n", id_val);
171
172 switch (id_val) {
173 case CHIPR_DM9000A:
174 db->type = TYPE_DM9000A;
175 break;
176 case CHIPR_DM9000B:
177 db->type = TYPE_DM9000B;
178 break;
179 default:
180 dev_dbg(db->dev, "ID %02x => defaulting to DM9000E\n", id_val);
181 db->type = TYPE_DM9000E;
182 }
183
184 /* dm9000a/b are capable of hardware checksum offload */
185 if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) {
186 db->can_csum = 1;
187 db->rx_csum = 1;
188 ndev->features |= NETIF_F_IP_CSUM;
189 }
190
191 /* from this point we assume that we have found a DM9000 */
192
193 /* driver system function */ //初始化以太网设备的公有成员
194 ether_setup(ndev);//在调用register_netdev之前必须初始化完全。该函数中为net_device设置了很多默认值
195
196 ndev->netdev_ops = &dm9000_netdev_ops;
197 ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
198 ndev->ethtool_ops = &dm9000_ethtool_ops;
199
200 db->msg_enable = NETIF_MSG_LINK;
201 db->mii.phy_id_mask = 0x1f;
202 db->mii.reg_num_mask = 0x1f;
203 db->mii.force_media = 0;
204 db->mii.full_duplex = 0;
205 db->mii.dev = ndev;
206 db->mii.mdio_read = dm9000_phy_read;
207 db->mii.mdio_write = dm9000_phy_write;
208
209 mac_src = "eeprom";
210
211 /* try reading the node address from the attached EEPROM */
212 for (i = 0; i < 6; i += 2)
213 dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);
214
215 if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {
216 mac_src = "platform data";
217 memcpy(ndev->dev_addr, pdata->dev_addr, 6);
218 }
219
220 if (!is_valid_ether_addr(ndev->dev_addr)) {
221 /* try reading from mac */
222
223 mac_src = "chip";
224 for (i = 0; i < 6; i++)
225 ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
226 }
227
228 if (!is_valid_ether_addr(ndev->dev_addr))
229 dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please "
230 "set using ifconfig\n", ndev->name);
231
232 platform_set_drvdata(pdev, ndev);
233 ret = register_netdev(ndev); //注册net_device结构体
234
235 if (ret == 0)
236 printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n",
237 ndev->name, dm9000_type_to_char(db->type),
238 db->io_addr, db->io_data, ndev->irq,
239 ndev->dev_addr, mac_src);
240 return 0;
241
242 out:
243 dev_err(db->dev, "not found (%d).\n", ret);
244
245 dm9000_release_board(pdev, db);
246 free_netdev(ndev); //分配错误则释放net_device结构
247
248 return ret;
249 }
1 m9000_open(struct net_device *dev)
2 {
3 board_info_t *db = netdev_priv(dev);//获取设备私有数据 返回board_info_t的地址
4 unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;
5
6 if (netif_msg_ifup(db))
7 dev_dbg(db->dev, "enabling %s\n", dev->name);
8
9 /* If there is no IRQ type specified, default to something that
10 * may work, and tell the user that this is a problem */
11
12 if (irqflags == IRQF_TRIGGER_NONE)
13 dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");
14
15 irqflags |= IRQF_SHARED;
16 //注册中断
17 if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
18 return -EAGAIN;
19
20 /* Initialize DM9000 board */
21 dm9000_reset(db); //复位DM9000
22 dm9000_init_dm9000(dev); //初始化dm9000中net_device结构中的成员
23
24 /* Init driver variable */
25 db->dbug_cnt = 0;
26
27 mii_check_media(&db->mii, netif_msg_link(db), 1);//检测mii接口状态
28 netif_start_queue(dev); //启动发送队列 协议栈向网卡发送
29
30 dm9000_schedule_poll(db);
31
32 return 0;
33 }
tatic int dm9000_stop(struct net_device *ndev)
{
board_info_t *db = netdev_priv(ndev); if (netif_msg_ifdown(db))
dev_dbg(db->dev, "shutting down %s\n", ndev->name); cancel_delayed_work_sync(&db->phy_poll); /* 终止phy_poll队列中被延迟的任务 */ netif_stop_queue(ndev); /* 关闭发送队列 */
netif_carrier_off(ndev); /* free interrupt */
free_irq(ndev->irq, ndev); /* 释放中断 */ dm9000_shutdown(ndev); /* 关闭DM9000网卡 */ return 0;
}
1 static void dm9000_shutdown(struct net_device *dev)
2 {
3 board_info_t *db = netdev_priv(dev);
4
5 /* RESET device */
6 dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET ,复位PHY*/
7 iow(db, DM9000_GPR, 0x01); /* Power-Down PHY */
8 iow(db, DM9000_IMR, IMR_PAR); /* Disable all interrupt ,关闭所有的中断*/
9 iow(db, DM9000_RCR, 0x00); /* Disable RX ,不再接受数据*/
10 }
1 static int dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
2 {
3 unsigned long flags;
4 board_info_t *db = netdev_priv(dev);
5
6 dm9000_dbg(db, 3, "%s:\n", __func__);
7
8 if (db->tx_pkt_cnt > 1)
9 return NETDEV_TX_BUSY;
10
11 spin_lock_irqsave(&db->lock, flags); //获得自旋锁
12
13 /* Move data to DM9000 TX RAM */
14 writeb(DM9000_MWCMD, db->io_addr); //根据 IO 操作模式(8-bit or 16-bit)来增加写指针 1 或 2
15
16 (db->outblk)(db->io_data, skb->data, skb->len); //将数据从sk_buff中copy到网卡的TX SRAM中
17 dev->stats.tx_bytes += skb->len; //统计发送的字节数
18
19 db->tx_pkt_cnt++; //待发送计数
20 /* TX control: First packet immediately send, second packet queue */
21 if (db->tx_pkt_cnt == 1) { //如果计数为1,直接发送
22 dm9000_send_packet(dev, skb->ip_summed, skb->len);
23 } else {
24 /* Second packet */
25 db->queue_pkt_len = skb->len;
26 db->queue_ip_summed = skb->ip_summed;
27 netif_stop_queue(dev); //告诉上层停止发送
28 }
29
30 spin_unlock_irqrestore(&db->lock, flags);//解锁
31
32 /* free this SKB */
33 dev_kfree_skb(skb); //释放SKB
34
35 return NETDEV_TX_OK;
36 }
dm9000_start_xmit通过调用dm9000_send_packet来发送数据。
1 static void dm9000_send_packet(struct net_device *dev,
2 int ip_summed,
3 u16 pkt_len)
4 {
5 board_info_t *dm = to_dm9000_board(dev);
6
7 /* The DM9000 is not smart enough to leave fragmented packets alone. */
8 if (dm->ip_summed != ip_summed) {
9 if (ip_summed == CHECKSUM_NONE)
10 iow(dm, DM9000_TCCR, 0);
11 else
12 iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP);
13 dm->ip_summed = ip_summed;
14 }
15
16 /* Set TX length to DM9000 *///设置发送数据的长度到TXPLL\TXPLH中
17 iow(dm, DM9000_TXPLL, pkt_len);
18 iow(dm, DM9000_TXPLH, pkt_len >> 8);
19
20 /* Issue TX polling command *///设置发送寄存器的发送控制位,启动发送数据
21 iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
22 }
1 static void dm9000_timeout(struct net_device *dev)
2 {
3 board_info_t *db = netdev_priv(dev);
4 u8 reg_save;
5 unsigned long flags;
6
7 /* Save previous register address */
8 reg_save = readb(db->io_addr);
9 spin_lock_irqsave(&db->lock, flags);
10
11 netif_stop_queue(dev);
12 dm9000_reset(db);
13 dm9000_init_dm9000(dev);
14 /* We can accept TX packets again */
15 dev->trans_start = jiffies; /* prevent tx timeout */
16 netif_wake_queue(dev); //重启发送队列
17
18 /* Restore previous register address */
19 writeb(reg_save, db->io_addr);
20 spin_unlock_irqrestore(&db->lock, flags);
21 }
1 static void dm9000_tx_done(struct net_device *dev, board_info_t *db)
2 {
3 int tx_status = ior(db, DM9000_NSR); /* Got TX status */
4
5 if (tx_status & (NSR_TX2END | NSR_TX1END)) { //检测一个数据包发送完毕
6 /* One packet sent complete */
7 db->tx_pkt_cnt--; //待发送的数据包数减1
8 dev->stats.tx_packets++;//已发送数据包加1
9
10 if (netif_msg_tx_done(db))
11 dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status);
12
13 /* Queue packet check & send */
14 if (db->tx_pkt_cnt > 0) //如果还有数据包,则继续发送
15 dm9000_send_packet(dev, db->queue_ip_summed,
16 db->queue_pkt_len);
17 netif_wake_queue(dev); //启动发送队列
18 }
19 }
11.中断处理函数
1 static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
2 {
3 struct net_device *dev = dev_id;
4 board_info_t *db = netdev_priv(dev);
5 int int_status;
6 unsigned long flags;
7 u8 reg_save;
8
9 dm9000_dbg(db, 3, "entering %s\n", __func__);
10
11 /* A real interrupt coming */
12
13 /* holders of db->lock must always block IRQs */
14 spin_lock_irqsave(&db->lock, flags);
15
16 /* Save previous register address */
17 reg_save = readb(db->io_addr);
18
19 /* Disable all interrupts */
20 iow(db, DM9000_IMR, IMR_PAR);
21
22 /* Got DM9000 interrupt status */ //获取中断类型
23 int_status = ior(db, DM9000_ISR); /* Got ISR */
24 iow(db, DM9000_ISR, int_status); /* Clear ISR status */
25
26 if (netif_msg_intr(db))
27 dev_dbg(db->dev, "interrupt status %02x\n", int_status);
28
29 /* Received the coming packet */ //接收到一个数据包
30 if (int_status & ISR_PRS)
31 dm9000_rx(dev); //调用数据接收函数
32
33 /* Trnasmit Interrupt check */ //发送一个数据包
34 if (int_status & ISR_PTS)
35 dm9000_tx_done(dev, db); //调用数据发送函数
36
37 if (db->type != TYPE_DM9000E) {
38 if (int_status & ISR_LNKCHNG) {
39 /* fire a link-change request */
40 schedule_delayed_work(&db->phy_poll, 1);
41 }
42 }
43
44 /* Re-enable interrupt mask */
45 iow(db, DM9000_IMR, db->imr_all);
46
47 /* Restore previous register address */
48 writeb(reg_save, db->io_addr);
49
50 spin_unlock_irqrestore(&db->lock, flags);
51
52 return IRQ_HANDLED;
53 }
1 dm9000_rx(struct net_device *dev)
2 {
3 board_info_t *db = netdev_priv(dev); //获得网卡私有数据首地址
4 struct dm9000_rxhdr rxhdr;
5 struct sk_buff *skb;
6 u8 rxbyte, *rdptr;
7 bool GoodPacket;
8 int RxLen;
9
10 /* Check packet ready or not */
11 do {//存储器地址不变的读数据
12 ior(db, DM9000_MRCMDX); /* Dummy read */ //MRCMDX是内存数据预取读命令
13
14 /* Get most updated data */
15 rxbyte = readb(db->io_data);
16
17 /* Status check: this byte must be 0 or 1 */ //0、1为正确,2表示接收出错
18 if (rxbyte & DM9000_PKT_ERR) {
19 dev_warn(db->dev, "status check fail: %d\n", rxbyte);
20 iow(db, DM9000_RCR, 0x00); /* Stop Device */ //关闭设备 并停止中断请求
21 iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */
22 return;
23 }
24
25 if (!(rxbyte & DM9000_PKT_RDY)) // 0x01没准备好,直接返回
26 return;
27
28 /* A packet ready now & Get status/length */
29 GoodPacket = true;
30 writeb(DM9000_MRCMD, db->io_addr);
31 //读取数据,从RX_SRAM读取到rxhdr中
32 (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));
33
34 RxLen = le16_to_cpu(rxhdr.RxLen);
35
36 if (netif_msg_rx_status(db))
37 dev_dbg(db->dev, "RX: status %02x, length %04x\n",
38 rxhdr.RxStatus, RxLen);
39
40 /* Packet Status check */ //检查包得完整性
41 if (RxLen < 0x40) {
42 GoodPacket = false;
43 if (netif_msg_rx_err(db))
44 dev_dbg(db->dev, "RX: Bad Packet (runt)\n");
45 }
46
47 if (RxLen > DM9000_PKT_MAX) {
48 dev_dbg(db->dev, "RST: RX Len:%x\n", RxLen);
49 }
50
51 /* rxhdr.RxStatus is identical to RSR register. */
52 if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE |
53 RSR_PLE | RSR_RWTO |
54 RSR_LCS | RSR_RF)) {
55 GoodPacket = false;
56 if (rxhdr.RxStatus & RSR_FOE) {
57 if (netif_msg_rx_err(db))
58 dev_dbg(db->dev, "fifo error\n");
59 dev->stats.rx_fifo_errors++;
60 }
61 if (rxhdr.RxStatus & RSR_CE) {
62 if (netif_msg_rx_err(db))
63 dev_dbg(db->dev, "crc error\n");
64 dev->stats.rx_crc_errors++;
65 }
66 if (rxhdr.RxStatus & RSR_RF) {
67 if (netif_msg_rx_err(db))
68 dev_dbg(db->dev, "length error\n");
69 dev->stats.rx_length_errors++;
70 }
71 }
72
73 /* Move data from DM9000 */ //从DM9000获取数据
74 if (GoodPacket && //分配SKB
75 ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) { //+4是因为除了数据包前面还有空读一字节、读状态一字节、读长度低位和高位各一个字节
76 skb_reserve(skb, 2); //定位data指针 DA(6)+SA(6)+type(2)+IP包+CFS(校验码4字节) IP包要求四字节对齐
77 rdptr = (u8 *) skb_put(skb, RxLen - 4); //定位tail指针 -4是减去校验码
78
79 /* Read received packet from RX SRAM */
80 //读取数据 从RX SRAM 到sk_buff中
81 (db->inblk)(db->io_data, rdptr, RxLen);
82 dev->stats.rx_bytes += RxLen;
83
84 /* Pass to upper layer */ //获取上层协议类型
85 skb->protocol = eth_type_trans(skb, dev);
86 if (db->rx_csum) {
87 if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0)
88 skb->ip_summed = CHECKSUM_UNNECESSARY;
89 else
90 skb->ip_summed = CHECKSUM_NONE;
91 }
92 netif_rx(skb); //把数据包交给上层
93 dev->stats.rx_packets++;
94
95 } else {
96 /* need to dump the packet's data */
97
98 (db->dumpblk)(db->io_data, RxLen);
99 }
100 } while (rxbyte & DM9000_PKT_RDY);
101 }
DM9000网卡驱动分析(转)的更多相关文章
- Linux网卡驱动移植--Dm9000网卡驱动分析
1. Linux网络体系结构由以下5部分组成 ① 系统调用接口: 位于Linux网络子系统的顶部,为应用程序提供访问内核网络子系统的方法,主要指socket系统调用. ② 协议无关接口: 实现一组基于 ...
- 【驱动】DM9000网卡驱动分析
Preface 内核源码版本:linux-2.6.18 网卡驱动·linux内核网络分层结构:http://infohacker.blog.51cto.com/6751239/122114 ...
- Xilinx Uboot网卡驱动分析
1.MAC控制器.网卡.PHY.MDIO.mii.gmii.rgmii概念扫盲 网卡在功能上包含OSI模型的两个层,数据链路层和物理层.物理层定义了数据传送与接收所需要的电与光信号.线路状态.时钟基准 ...
- DM9000网卡驱动深度分析
一.dm9000_porbe函数分析 不同于u-boot代码,tq2440中的DM9000更加复杂,需要分析的点也很多: /* * Search DM9000 board, allocate spac ...
- [国嵌攻略][136][DM9000网卡驱动深度分析]
网卡初始化 1.分配描述结构,alloc_etherdev 2.获取平台资源,platform_get_resource 2.1.在s3c_dm9k_resource中有相关的资源 2.2.add地址 ...
- mini2440移植uboot-2008.10 (二) DM9000网卡驱动移植
还是利用 mini2440移植uboot-2008.10 (一) 修改好的代码 通过观察可以发现,mini2400使用的网卡芯片是DM9000,在uboot-2008.10源码中已经支持该芯片的驱动 ...
- Linux网卡驱动分析
以太网(Ethernet)是一种计算机局域网组网技术,基于IEEE 802.3标准,它规定了包括物理层的连线.电信号和介质访问层协议. Ethernet接口的实质是MAC通过MII总线控制PHY的过程 ...
- DM9000网卡驱动接受数据从中断方式改成NAPI方式小记
平台是最最经典的s3c2440了,说了要做这件事情很久了,就是改几行代码,一直没有做.前几天逼了自己一下,终于给做了,拖延症患者伤不起. 以下是需要读者对napi机制有所熟悉: step1:在boar ...
- [国嵌攻略][137][DM9000网卡驱动编程]
DM9000数据发送 DM9000数据发送函数是在/drivers/net/dm9000.c中的dm9000_start_xmit函数 static int dm9000_start_xmit(str ...
随机推荐
- stack 数据结构
栈定义 栈:后进先出(永远从栈顶取元素)LIFO last-in-first-out 栈实现 class Stack { constructor() { this.items = [] this. ...
- shell小技巧(4)AIX和Linux计算天前日期
Linux计算天前日期: date -d "- day" +%Y%m%d AIX计算5天前日期: perl -e "use POSIX qw(strftime); pri ...
- CDH5.16.1集群企业真正离线部署
一.准备工作 1.离线部署主要分为三块: MySQL离线部署 CM离线部署 Parcel文件离线源部署 2.规划 节点 MySQL部署组件 Parcel文件离线源 CM服务进程 大数据组件 hadoo ...
- 关于给Tomcat设置maxPostSize的问题
一.为什么要设置maxPostSize tomcat容器对传输数据的大小有限制,如果上传了超过此值的文件,就会报错,使得程序不能正常使用. 二.设置方法 找到tomcat目录下的/conf/serve ...
- C# .Net 委托和事件的区别
在.net中,事件是一种特殊的委托,那他到底特殊在哪,换句话说,加上event关键字到底有什么用,我理解主要有两方面,下面用实例说明: 一 .事件只能在本类型内部“触发”,委托不管在本类型内部还是外部 ...
- Linux设备驱动模型简述(源码剖析)
1. Linux设备驱动模型和sysfs文件系统 Linux内核在2.6版本中引入设备驱动模型,简化了驱动程序的编写.Linux设备驱动模型包含设备(device).总线(bus).类(class)和 ...
- day09记录
今日内容大纲 毒鸡汤课 坚持.努力! 生成器 yield yeild return yeild from 生成器表达式 内置函数I 昨日内容回顾作业讲解 可迭代对象 可以更新得带的 实实在在的值. 内 ...
- [补题]匹配%#,%#之间的字符串重复%前的num遍
题目 匹配%#,%#之间的字符串重复%前的num遍. 样例1: 3%acm#2%acm# 输出: acmacmacmacmacm 样例2: 3%2%acm## 输出: acmacmacmacmacm ...
- 透过 Cucumber 学习 BDD
在需求的开发过程中,最令人困惑的地方就在于需求模糊.需求是解决业务的问题,那么验收的方式应该是由业务方提出,但是往往业务方(可能是产品经理,也可能是直接是客户)只能给出比较模糊的一个验收标准,而程序却 ...
- 初识ABP vNext(10):ABP设置管理
Tips:本篇已加入系列文章阅读目录,可点击查看更多相关文章. 目录 前言 开始 定义设置 使用设置 最后 前言 上一篇介绍了ABP模块化开发的基本步骤,完成了一个简单的文件上传功能.通常的模块都有一 ...