开发平台:Ubuntu 11.04
-
- #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) { -
-
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); -
} -
-
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
-
- #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
- static
inline void *netdev_priv(const struct net_device *dev) - {
-
return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN); - }
1. include/linux/netdevice.h
#define NETDEV_ALIGN 32
#define NETDEV_ALIGN_CONST (NETDEV_ALIGN - 1)
static inline void *netdev_priv(struct net_device *dev)
{
return (char *)dev + ((sizeof(struct net_device)
+ NETDEV_ALIGN_CONST)
& ~NETDEV_ALIGN_CONST);
}
2. net/core/dev.c
struct net_device *alloc_netdev(int sizeof_priv, const char *name,
void (*setup)(struct net_device *))
{
......
alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST;
alloc_size += sizeof_priv + NETDEV_ALIGN_CONST;
p = kzalloc(alloc_size, GFP_KERNEL); // 对分配的内核内存清0
......
if (sizeof_priv)
dev->priv = netdev_priv(dev);
......
}
linux/driver/net网卡驱动程序中充满了类似这样的代码:
sturct nic *nic = netdev_priv(dev);
从文件2中可以看出net_device和网卡私有数据结构是一起分配的,要想获得网卡私有数据结构的地址,文件1中的函数netdev_priv直接返回了net_device结构末端地址,也就是网卡私有数据结构的起始地址。当然其中考虑了字节对齐的问题。至于为什么不直接返回:
sturct nic *nic = dev->priv;
《Linux Devcie Drivers》中说是为了性能和灵活性方面的考虑。
#define NETDEV_ALIGN
#define NETDEV_ALIGN_CONST
static inline void *netdev_priv(struct net_device *dev)
{
}
2. net/core/dev.c
struct net_device *alloc_netdev(int sizeof_priv, const char *name,
{
}
linux/driver/net网卡驱动程序中充满了类似这样的代码:
sturct nic *nic = netdev_priv(dev);
从文件2中可以看出net_device和网卡私有数据结构是一起分配的,要想获得网卡私有数据结构的地址,文件1中的函数netdev_priv直接返回了net_device结构末端地址,也就是网卡私有数据结构的起始地址。当然其中考虑了字节对齐的问题。至于为什么不直接返回:
sturct nic *nic = dev->priv;
《Linux Devcie Drivers》中说是为了性能和灵活性方面的考虑。