QQ登录

只需一步,快速开始

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 1710|回复: 2

[求助]关于Linux下驱动程序的开发?

[复制链接]
发表于 2005-5-20 12:51:03 | 显示全部楼层 |阅读模式
大家好,我最近照着书上做一个驱动程序,但总是不能编译通过,我用的PC机,Redhat2.4.20-8,编辑完成后,用GCC编译,但总是出错,请大家帮助一下!

以下是源码:

# include <linux/kernel.h>
# include <linux/module.h>
# if CONFIG_MODVERSIONS==1 /*处理CONFIG_MODVERSIONS*/
# define MODVERSIONS
# include <linux/modversions.h>
# endif
/*下面是针对字符设备的头文件*/
# include <linux/fs.h>
# include <linux/wrapper.h>
# include <linux/errno.h>

/*对于不同的版本我们需要做一些必要的事情*/
# ifndef KERNEL_VERSION
# define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))
# endif
# if LINUX_VERSION_CODE > KERNEL_VERSION (2,4,0)
# include <asm/uaccess.h> /*for copy_to_user*/
# endif

# define SUCCESS 0

/*声明设备*/
/*这是本设备的名字,它将出现在/proc/devices*/
# define DEVICE_NAME "char_dev"

/*定义此设备消息缓冲的最大长度*/
# define BUF_LEN 100

/*为了防止不同的进程在同一个时间使用此设备,定义此静态变量跟踪其状态*/
static int Device_Open = 0;

/*当提出请求的时候,设备将读写的内容放在下面的数组中*/
static char Message[BUF_LEN];

/*在进程读取这个内容的时候,这个指针是指向读取的位置*/
static char *Message_Ptr;

/*在这个文件中,主设备号作为全局变量以便于这个设备在注册和释放的时候使用*/
static int Major;
struct file_operations Fops;

/*open()函数 功能:无论一个进程何时试图去打开这个设备都会调用这个函数.*/
static int device_open(struct inode * inode,struct file * file)
{
static int counter = 0;
#ifdef DEBUG
printk("device_open(%p,%p)\n",inode,file);
#endif

printk("Device:%d.%d\n",inode->i_rdev >> 8,inode->i_rdev & 0xFF);

/*这个设备是一个独占设备,为了避免同时有两个进程使用这一个设备我们需要采取一定的措施*/
if(Device_Open)
return -EBUSY;

Device_Open++;

/*下面是初始化消息,注意不要使读写内容的长度超出缓冲区的长度,特别是运行在内核模式时,否则如果出现缓冲区上溢则可能导致系统的崩溃*/
sprintf(Message,"If I told you once,I told you %d times - %s",counter++,"Hello,world\n");

Message_Ptr = Message;

/*当这个文件被打开的时候,我们必须确认该模块还没有被移走并且增加此模块的用户数目(在移走一个模块的 时候会根据这个数字去决定可否移走,如果不是 0 则表明还有进程正在使用这个模块,不能移走)*/
MOD_INC_USE_COUNT;

return SUCCESS;
}


/*release()函数 功能:当一个进程试图关闭这个设备特殊文件的时候调用这个函数.*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
static int device_release(struct inode *inode,struct file *file)
#else
static void device_release(struct inode *inode,struct file *file)
#endif
{
#ifdef DEBUG
printk("device_release(%p,%p)\n",inode,file);
#endif

/*为下一个使用这个设备的进程做准备*/
Device_Open--;

/*减少这个模块使用者的数目,否则一旦你打开这个模块以后,你永远都不能释放掉它*/
MOD_DEC_USE_COUNT;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
return 0;
#endif
}


/*read()函数 功能:当一个进程已经打开此设备文件以后并且试图去读它的时候调用这个函数.*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
static ssize_t device_read(struct file *file,
char *buffer, /*把读出的数据放到这个缓冲区*/
size_t length, /*缓冲区的长度*/
loff_t *offset) /*文件中的偏移*/
#else
static int device_read(struct inode *inode,struct file *file,char *buffer,int length)
#endif
{
/*实际上读出的字节数*/
int bytes_read = 0;
/*如果读到缓冲区的末尾,则返回0,类似文件的结束*/
if(*Message_Ptr == 0)
return 0;
/*将数据放入缓冲区中*/
while(length && *Message_Ptr){
/*由于缓冲区是在用户空间而不是内核空间,所以我们必须使用copy_to_user()函数将内核空间中的数据拷贝到用户空间*/
copy_to_user(buffer++,*(Message_Ptr++),length--);
bytes_read++;
}

#ifdef DEBUG
printk("REad %d bytes,%d left\n",bytes_read,length);
#endif

/*Read函数返回一个真正读出的字节数*/
return bytes_read;
}


/*write()函数 功能:当试图将数据写入这个设备文件的时候,这个函数被调用*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
static ssize_t device_write(struct file *file,
const char *buffer,
size_t length,
loff_t *offset)
#else
static int device_write(struct inode *inode,struct file *file,const char *buffer,int length)
#endif
{
int i;

#ifdef DEBUG
printk("device_write(%p,%s,%d)",file,buffer,length);
#endif

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
copy_from_user(Message,buffer,length);
#endif

Message_Ptr = Message;

/*返回写入的字节数*/
return i;
}


/*这个设备驱动程序提供给文件系统的接口 功能:当一个进程试图对我们生成的设备进行操作的时候就利用下面这个结构,这个结构就是我们提供给操作系统的接口,它的指针保存在设备表中,在init_module()中被传递给操作系统.*/
struct file_operations Fops = {
read: device_read,
write: device_write,
open: device_open,
release: device_release,
};


/*模块的初始化和模块的卸载 功能:init_module函数用来初始化这个模块--注册该字符设备.init_module()函 数调用module_register_chrdev,把设备驱动程序添加到内核的字符设备驱动程序表中,它返回这个驱动程序 所使用的主设备号.*/
int init_module()
{
/*试图注册这个设备*/
Major = module_register_chrdev(0,DEVICE_NAME,&Fops);

/*失败的时候返回负值*/
if(Major < 0){
printk("%s device failed with %d\n","sorry, registering the character",Major);
return Major;
}

printk("%s The major device number is %d.\n","Registeration is a success.",Major);
printk("If you want to talk to the device driver,\n");
printk("you'll have to create a device file.\n");
printk("We suggest you use:\n");
printk("mknod <name> c %d <minor>\n",Major);
printk("You can try different minor numbers %s","and see what happens.\n");

return 0;
}


/*cleanup_module()函数 功能:卸载模块,主要是从/proc中取消注册的设备特殊文件.*/
void cleanup_module()
{
int ret;

/*取消注册的设备*/
ret=module_unregister_chrdev(Major,DEVICE_NAME);

/*如果出错则显示出错信息*/
if(ret < 0)
printk("Error in unregister_chrdev:%d\n",ret);
}

=========================END==================================

$Gcc -c simchrdev.c

请问应该怎样编译????
发表于 2005-6-9 14:18:45 | 显示全部楼层
用$Gcc -c simchrdev.c 不行么?
你错误提示有么?
是什么?
回复

使用道具 举报

发表于 2005-6-17 17:06:06 | 显示全部楼层
这个简单:
写个Makefile:

WARN    := -W -Wall -Wstrict-prototypes -Wmissing-prototypes
INCLUDE  := -isystem /lib/modules/`uname -r`/build/include
HS_ADDRESS := 0x$(word 1,$(shell /sbin/ksyms -a | grep handle_scancode))
CFLAGS   := -O2 -DMODULE -D__KERNEL__ ${WARN} ${INCLUDE} -D HS_ADDRESS
CC        := gcc
OBJS      := ${patsubst %.c, %.o, ${wildcard *.c}}

all : ${OBJS}

.PHONY : clean

clean:
        @rm -rf *.o
        @rm -rf *~
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

GMT+8, 2024-11-16 12:27 , Processed in 0.086068 second(s), 15 queries .

© 2021 Powered by Discuz! X3.5.

快速回复 返回顶部 返回列表