环境:
操作系统:Federo core 6
内核版本:Linux-2.6.18.3
步骤:
1.安装内核
FC6操作系统自带的内核不是标准内核,内核源码有些文件没有。所以下载Linux-2.6.18.3版本的内核并安装。
1)将内核源码包拷贝到/usr/src/kernels目录下,解压。
# tar –zxvf linux-2.6.18.3.tar.gz
2) 进入源码根目录,配置内核,编译内核,编译内核模块,安装内核模块,安装内核
# make menuconfig
#make dep
#make bzImage
#make modules
#make modules_install
#make install
3)重新启动系统,在Grub中可以看到多了一个选项,选择Linux-2.6.18.3版本的内核启动系统。
2.Linux-2.6 与 Linux-2.4设备驱动程序的不同
Linux-2.6版本较之Linux-2.4版本的内核模块有很多的不同点,从设备管理的方式到许多系统函数的名称都有很多改变。内核模块的基本结构还是一样的。具体的不同点见http://net.stuun.cn/system/Linux/45194.html 中内核操作 Linux2.6内核驱动移植参考一文。在这主要说一下Linux-2.6下的设备管理——udev。在Linux-2.6种用udev代替了devfs管理设备。udev是一种工具,它能够根据系统中的硬件设备的状态动态更新设备文件,包括设备文件的创建,删除等。设备文件通常放在/dev目录下。使用udev后,在/dev目录下就只包含系统中真正存在的设备。udev依赖于sysfs文件系统提供的信息。
3.编写demo驱动程序
驱动程序功能:在内核空间开辟一块内存空间,实现open ,write,ioctl,release 操作,写入字符串后将字符串顺序反转。
Demo程序源码:
//内核头文件定义
#include
#include
#include
#include
#include
#include
#include
#define DEVICE_NAME "demo"
MODULE_LICENSE("Dual BSD/GPL");
struct demo_dev
{
char buffer[1024];
int curpos;
struct cdev cdev;
};
static struct demo_dev * demo_device;
static int demo_major=0; //主设备编号
static int demo_minor=0; //次设备编号
//将字符串内字符顺序反转
static void do_write(struct demo_dev *dev)
{
printk("do_write\n");
if(dev != NULL)
{
int i;
int len = dev->curpos;
char tmp;
printk("change \n");
for(i = 0; i < (len>>1); i++,len--)
{
tmp = dev->buffer[len-1];
dev->buffer[len-1] = dev->buffer[i];
dev->buffer[i] = tmp;
printk("%c %c\n",dev->buffer[i],dev->buffer[len-1]);
}
}
}
//demo驱动写操作
static int demo_write(struct file * filp,const char * buffer,
size_t count,loff_t * ppos)
{
int retval=0;
struct demo_dev *dev = filp->private_data;
if(dev->curpos + count > 1024)
{
count = 1024 - dev->curpos;
}
if(copy_from_user(dev->buffer + dev->curpos,buffer,count))
{
retval = -EFAULT;
goto out;
}
dev->curpos+=count;
*ppos=dev->curpos;
retval = count;
do_write(dev);
out:
return retval;
}
//demo 驱动读操作
static int demo_read(struct file * filp,char * buffer,
size_t count,loff_t * ppos)
{
int retval=0;
struct demo_dev *dev=filp->private_data;
printk("demo:read \n");
printk("demo pos %d count %d \n",*ppos,count);
if(*ppos >= dev->curpos) goto out;
if((*ppos) + count > dev->curpos)
count = dev->curpos - *ppos ;
if(copy_to_user(buffer,dev->buffer ,14))
{
retval = -EFAULT;
goto out;
}
*ppos+=count;
retval=count;
out:
return retval;
}
//demo 驱动ioctl操作
static int demo_ioctl(struct inode * inode,struct file * filp,
unsigned int cmd,unsigned long arg)
{
printk("ioctl running\n");
switch(cmd)
{
case 1: printk("command 1 \n");break;
case 2: printk("command 2 \n");break;
default:
printk("error cmd\n");
}
return 0;
}
//demo 驱动open操作
static int demo_open(struct inode * inode,struct file * filp)
{
struct demo_dev *dev;
dev=container_of(inode->i_cdev,struct demo_dev,cdev);
filp->private_data = dev;
printk("demo:open success\n");
return 0;
}
//demo 驱动release
static int demo_release(struct inode * inode,struct file * filp)
{
printk("demo:release success\n");
return 0;
}
//demo驱动文件操作结构体
static struct file_operations demo_fops={
.owner = THIS_MODULE,
.read = demo_read,
.write = demo_write,
.ioctl = demo_ioctl,
.open = demo_open,
.release = demo_release,
};
//demo 驱动初始化
static int demo_init(void)
{
dev_t dev;
int result=0;
printk("demo init\n");
if(demo_major)
{
dev=MKDEV(demo_major,demo_minor);
result=register_chrdev_region(dev,1,DEVICE_NAME); //静态注册
}
else
{
result=alloc_chrdev_region(&dev,demo_minor,1,DEVICE_NAME); //动态注册
demo_major=MAJOR(dev);
}
if(result < 0)
{
printk(KERN_WARNING"demo:can't get major %d\n",demo_major);
return result;
}
demo_device = (struct demo_dev *)kmalloc(sizeof(struct demo_dev),GFP_KERNEL);
if(demo_device == NULL)
{
result= -ENOMEM;
goto fail;
}
memset(demo_device,0,sizeof(struct demo_dev));
cdev_init(&demo_device->cdev,&demo_fops);
demo_device->cdev.owner = THIS_MODULE;
demo_device->cdev.ops = &demo_fops;
if(cdev_add(&demo_device->cdev,dev,1))
{
printk(KERN_NOTICE"Error adding scull");
}
printk("demo initialized\n");
return 0;
fail:
unregister_chrdev_region(dev,1);
return result;
}
//demo 驱动退出
static void demo_exit(void)
{
cdev_del(&demo_device->cdev);
kfree(demo_device);
unregister_chrdev_region(MKDEV(demo_major,demo_minor),1);
printk("demo exited\n");
}
module_init(demo_init);
module_exit(demo_exit);
Makefile编写:
obj-m := demo-26.o
编译模块:
#make -C /lib/modules/`uname -r`/build M=`pwd` modules
在/sysfs或/proc目录中查看设备信息,用mknod在/dev下建立设备节点。
4.编写测试程序,编译运行。
写入:abcdefghijk
输出:kjihgfedcba
结果正确。
(victor_tlh)