网络驱动移植之例解netdev_priv函数
版权声明:本文为博主原创文章,未经博主允许不得转载。
开发平台:Ubuntu 11.04
编译器:gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4)
内核源码:Linux-2.6.38.8.tar.bz2
1、如何分配struct net_device结构体以及私有数据
下面将通过实例来讲解Linux内核是如何通过alloc_netdev_mqs函数分配struct net_device结构体以及私有数据的(因为理解了这一点,就能完全理解netdev_priv函数的实现)。
首先,编写一个模块,代码如下:
- /* tanglinux.c */
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/miscdevice.h>
- #include <linux/fs.h>
- #include <linux/netdevice.h>
- #include <linux/etherdevice.h>
- #include <linux/kernel.h>
- #include <linux/ioctl.h>
- #define TANGLINUX _IO('T', 1)
- struct net_local {
- int count;
- char ch;
- };
- static int tanglinux_open(struct inode *inode, struct file *file)
- {
- return nonseekable_open(inode, file);
- }
- static long tanglinux_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
- {
- struct net_device *dev;
- size_t alloc_size;
- size_t sizeof_priv = sizeof(struct net_local);
- struct net_device *p;
- switch (cmd) {
- case TANGLINUX:
- alloc_size = sizeof(struct net_device);
- printk("first: alloc_size = %d\n", alloc_size);
- alloc_size += 1; //为验证ALIGN的作用,人为制造net_device结构体的大小不是32位对齐
- if (sizeof_priv) {
- /* ensure 32-byte alignment of private area */
- alloc_size = ALIGN(alloc_size, NETDEV_ALIGN); //#define NETDEV_ALIGN 32
- printk("second: alloc_size = %d\n", alloc_size);
- alloc_size += sizeof_priv;
- printk("third: alloc_size = %d\n", alloc_size);
- }
- /* ensure 32-byte alignment of whole construct */
- alloc_size += NETDEV_ALIGN - 1;
- printk("fourth: alloc_size = %d\n", alloc_size);
- p = kzalloc(alloc_size, GFP_KERNEL);
- if (!p) {
- printk(KERN_ERR "alloc_netdev: Unable to allocate device.\n");
- return -ENOMEM;
- }
- printk("p = %p\n", p);
- dev = PTR_ALIGN(p, NETDEV_ALIGN);
- printk("dev = %p\n", dev);
- dev->padded = (char *)dev - (char *)p;
- printk("dev->padded = %d\n", dev->padded);
- kfree(p);
- return 0;
- default:
- return -ENOTTY;
- }
- }
- static int tanglinux_release(struct inode *inode, struct file *file)
- {
- return 0;
- }
- static const struct file_operations tanglinux_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = tanglinux_ioctl,
- .open = tanglinux_open,
- .release = tanglinux_release,
- };
- static struct miscdevice tanglinux_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "tanglinux",
- .fops = &tanglinux_fops,
- };
- static int __init tanglinux_init(void)
- {
- printk("tanglinux driver\n");
- return misc_register(&tanglinux_miscdev);
- }
- static void __exit tanglinux_exit(void)
- {
- misc_deregister(&tanglinux_miscdev);
- }
- module_init(tanglinux_init);
- module_exit(tanglinux_exit);
- MODULE_LICENSE("GPL");
然后,编译并加载此模块:
- //获得Ubuntu 11.04正在运行的内核版本
- $ cat /proc/version
- Linux version 2.6.38-13-generic (buildd@roseapple) (gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4) ) #53-Ubuntu SMP Mon Nov 28 19:23:39 UTC 2011
- //根据上面获得的信息,在Makefile中指定Ubuntu 11.04的内核源码目录为/usr/src/linux-headers-2.6.38-13-generic/
- # Makefile
- KERN_DIR = /usr/src/linux-headers-2.6.38-13-generic/
- all:
- make -C $(KERN_DIR) M=`pwd` modules
- clean:
- make -C $(KERN_DIR) M=`pwd` modules clean
- obj-m += tanglinux.o
- //编译,并把编译好的模块tanglinux.ko加载到内核中
- $ make
- $ sudo insmod tanglinux.ko
最后,通过测试程序获得相关信息:
- /* test.c */
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <stdio.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <sys/ioctl.h>
- #define TANGLINUX _IO('T', 1)
- int main(void)
- {
- int fd;
- fd = open("/dev/tanglinux", O_RDWR);
- if (fd < 0)
- {
- printf("can't open /dev/tanglinux\n");
- return -1;
- }
- ioctl(fd, TANGLINUX);
- return 0;
- }
- //编译、执行测试程序,然后通过dmesg命令获得模块输出的信息
- $ make test
- $ sudo ./test
- $ dmesg | tail -7
- [19853.353282] first: alloc_size = 1088
- [19853.353296] second: alloc_size = 1120
- [19853.353306] third: alloc_size = 1128
- [19853.353316] fourth: alloc_size = 1159
- [19853.353348] p = cddf6000
- [19853.353358] dev = cddf6000
- [19853.353369] dev->padded = 0
根据Ubuntu 11.04(基于X86硬件平台)中的配置,struct net_device结构体的大小为1088字节,刚好32位对齐,为了验证对齐函数ALIGN的作用,在例子中故意把struct net_device结构体的大小增加了1,所以第二次输出的alloc_size大小为1120个字节,也就是在1089个字节的基础上为了对齐增加了31个字节。
PTR_ALIGN函数的作用是为了使struct net_device *dev最终得到的内存地址也是32位对齐的。
上面所讨论的问题都可以通过下面的图示体现出来:

2、如何通过netdev_priv访问到其私有数据
netdev_priv函数的源代码如下:
- static inline void *netdev_priv(const struct net_device *dev)
- {
- return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN);
- }
即通过struct net_device *dev首地址加对齐后的偏移量就得到了私有数据的首地址,如上图。
网络驱动移植之例解netdev_priv函数的更多相关文章
- 网络驱动移植之net_device结构体及其相关的操作函数
内核源码:Linux-2.6.38.8.tar.bz2 在Linux系统中,网络设备都被抽象为struct net_device结构体.它是网络设备硬件与上层协议之间联系的接口,了解它对编写网络驱动程 ...
- 网络驱动移植之解析Linux网络驱动的基本框架
内核源码:linux-2.6.38.8.tar.bz2 概括而言,编写Linux网络驱动其实只要完成两件事即可,一是分配并初始化网络设备,二是注册网络设备. 1.分配并初始化网络设备 动态分配网络设备 ...
- 网络驱动移植之简述CS8900A网络芯片的基本原理
CS8900A数据手册:http://www.cirrus.com/cn/products/cs8900a.html 1.概述 CS8900A是CIRRUS LOGIC公司生产的低功耗.性能优越的16 ...
- Linux 网卡驱动学习(一)(分析一个虚拟硬件的网络驱动样例)
在Linux,网络分为两个层,各自是网络堆栈协议支持层,以及接收和发送网络协议的设备驱动程序层. 网络堆栈是硬件中独立出来的部分.主要用来支持TCP/IP等多种协议,网络设备驱动层是连接网络堆栈协议层 ...
- Android安卓书籍推荐《Android驱动开发与移植实战详解》下载
百度云下载地址:点我 Android凭借其开源性.优异的用户体验和极为方便的开发方式,赢得了广大用户和开发者的青睐,目前已经发展成为市场占有率很高的智能手机操作系统. <Android驱动开发与 ...
- Linux网络驱动--snull
snull是<Linux Device Drivers>中的一个网络驱动的例子.这里引用这个例子学习Linux网络驱动. 因为snull的源码,网上已经更新到适合最新内核,而我自己用的还是 ...
- DM9000驱动移植在mini2440(linux2.6.29)和FS4412(linux3.14.78)上的实现(deep dive)篇一
关于dm9000的驱动移植分为两篇,第一篇在mini2440上实现,基于linux2.6.29,也成功在在6410上移植了一遍,和2440非常类似,第二篇在fs4412(Cortex A9)上实现,基 ...
- Windows网络驱动、NDIS驱动(微端口驱动、中间层驱动、协议驱动)、TDI驱动(网络传输层过滤)、WFP(Windows Filtering Platform)
catalog . 引言 . Windows 2000网络结构和OSI模型 . NDIS驱动 . NDIS微端口驱动编程实例 . NDIS中间层驱动编程实例 . NDIS协议层驱动编程实例 . TDI ...
- SPI在linux3.14.78 FS_S5PC100(Cortex A8)和S3C2440上驱动移植(deep dive)
由于工作的原因,对SPI的理解最为深刻,也和SPI最有感情了,之前工作都是基于OSEK操作系统上进行实现,也在US/OS3上实现过SPI驱动的实现和测试,但是都是基于基本的寄存器操作,没有一个系统软件 ...
随机推荐
- Struts2入门(1)——搭建简单的环境
步骤: 1.下载Struts2的开发包. 2.创建Web项目. 3.导入需要的jar包到项目里. 4.在web.xml文件里面配置struts2的核心控制器,也就是一个过滤器. 5.编写Action类 ...
- DEV Express中Bar Manager的使用
未排版 在barManager中可以添加多种元素,如皮肤按钮,复选框等,但是下拉菜单却给出了多个冗余的控件. 遗留问题:怎么设置Bar为大图标,查找是否存在Ribbon控件. Bar 1, ...
- python 中range和xrange的区别
range() 相当于直接构造一个列表,而xrange() 是返回一个迭代值. range用法: range( 开始值,结束值,步长) 在需要大量迭代的时候,比较适合使用xrange()
- HDU 5469 Antonidas
Antonidas Time Limit: 4000ms Memory Limit: 65536KB This problem will be judged on HDU. Original ID: ...
- HDU-3746Cyclic Nacklace,next数组简单应用。
Cyclic Nacklace 节省篇幅不粘题面了... 看懂题后脑袋里略过KMP,学过但没怎么用过,又直接跳下一题了.. 题意:给定一个字符串,可以从两边加上一些字符使其有循环节..求最少需要加多少 ...
- HDU 4418 高斯消元解决概率期望
题目大意: 一个人在n长的路径上走到底再往回,走i步停下来的概率为Pi , 求从起点开始到自己所希望的终点所走步数的数学期望 因为每个位置都跟后m个位置的数学期望有关 E[i] = sigma((E[ ...
- spoj 839 最小割+二进制
#include<stdio.h> #include<string.h> #include<queue> using namespace std; #define ...
- java中filter的用法
filter过滤器主要使用于前台向后台传递数据是的过滤操作.程度很简单就不说明了,直接给几个已经写好的代码: 一.使浏览器不缓存页面的过滤器 Java代码 import javax.servlet ...
- 关于NSArray的去重
提到去重,第一反应就是for或while循环来遍历处理. 然后有了几种思路: 1) 两个循环嵌套 对比 然后去重: 但是这种方法会数据丢失, arr为要去重的数组 ; i<arr.count; ...
- [Bzoj3209]花神的数论题(数位dp)
3209: 花神的数论题 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2633 Solved: 1182[Submit][Status][Disc ...