2012年(4)
分类: LINUX
2012-06-22 16:27:35
Makefile编写:
ifneq ($(KERNELRELEASE),)
obj-m :=globle.o
else
KDIR := /test/utukernel依附的内核,已经编译过的
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif
printk(KERN_INFO "read %u bytes from %lu\n", count,p);
printk(KERN_INFO "read %u bytes from %lu\n", count,p);
#defineKERN_EMERG"<0>"/*紧急事件消息,系统崩溃之前提示,表示系统不可用*
#defineKERN_ALERT"<1>"/*报告消息,表示必须立即采取措施*/
#defineKERN_CRIT"<2>"/*临界条件,通常涉及严重的硬件或软件操作失败*/
#defineKERN_ERR"<3>"/*错误条件,驱动程序常用KERN_ERR来报告硬件的错误
#defineKERN_WARNING"<4>"/*警告条件,对可能出现问题的情况进行警告*/
#defineKERN_NOTICE"<5>"/*正常但又重要的条件,用于提醒。常用于与安全相关的消息*/
#defineKERN_INFO"<6>"/*提示信息,如驱动程序启动时,打印硬件信息*/
#defineKERN_DEBUG"<7>"/*调试级别的消息*/
下面是我的代码,被改的面目全非,而我当初写的更是惨不忍睹惨不忍睹啊啊啊!
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define GLOBLEMEM_SIZE 0X1000//全局内存最大4kb
#define MEM_CLEAR 0x1
#define GLOBLEMEM_MAJOR 220//预设主设备号
int globlemajor=GLOBLEMEM_MAJOR;//注意的是主设备号要是全局变量
struct globle_cdev
{
struct cdev cdev;
unsigned char globlemem[GLOBLEMEM_SIZE];
};//自己定义的结构体也是全局变量
struct globle_cdev *mdev;
int globle_open(struct inode *inode, struct file *file)
{
file->private_data=mdev;//file结构代表一个打开的文件,由内核在open时创建,并传递给在该文件上操作的所有函数。直到close。
return 0;
}
int globle_release(struct inode *inode, struct file *filp)
{
return 0;
}
static ssize_t globle_read(struct file *file, const char __user *buf,size_t count,loff_t *f_pos)//函数前加static只能被本文件中的其他函数调用即内部函数。注意参数
{
//if(mdev->dev->)
unsigned int p=count;
unsigned long pos=*f_pos;//把参数赋值 ,最好是赋值,因为要返回的是初始的偏移值,而这个地方偏移值是个指针变量,改变后永远改变。
int ret=0;
struct globle_cdev *dev = file->private_data;//??
if(pos>=GLOBLEMEM_SIZE)//???
return 0;
if(p>GLOBLEMEM_SIZE-pos)
p=GLOBLEMEM_SIZE-pos;
if(copy_to_user(buf,(void*)(dev->globlemem+pos), p))//参数是void*to ,void __usr *from,unsigned long,返回值为不能被复制的字节数。这里用了个强制转换,不转换也是可以的。
ret=-EFAULT;
else
{
*f_pos+=p;
ret=p;
printk(KERN_INFO "read %d bytes from %d\n", p,pos);
}
return ret;//读了多少字节
/*end:
{
return -EFAULT;
}*/
}
static ssize_t globle_write(struct file *file,const char __user *buf,size_t count,loff_t *f_pos)
{
unsigned int p=count;
unsigned long pos=*f_pos;
int ret=0;
struct globle_cdev *dev = file->private_data;
if(pos>=GLOBLEMEM_SIZE)
return 0;
if(p>GLOBLEMEM_SIZE-pos)
p=GLOBLEMEM_SIZE-pos;
//copy_from_user(buf,(void*)(mdev->globlemem+pos),p);//转化
if(copy_from_user(dev->globlemem + pos, buf,p))
ret=-EFAULT;
else
{
*f_pos+=p;
ret=p;
printk(KERN_INFO "written %u bytes from %lu\n", p,pos);
}
//end:
//{
return ret;
//}
}
static loff_t globle_llseek(struct file *file, loff_t offset,int orig)//为什么有的地方是loff—t而有的是loff—t *?还有loff—t其实就是unsigned long同样的64位
{
loff_t ret=0;
//return ret;
switch (orig)
{
case 0:
if(offset>GLOBLEMEM_SIZE)
{
ret=-EINVAL;
break;
}
//if(file->f_pos+*offset>GLOBLEMEM_SIZE)
file->f_pos=offset;
ret=file->f_pos;
break;
//goto end;
case 1:
if(file->f_pos+offset>GLOBLEMEM_SIZE)
{
ret=-EINVAL;
//return ret;
break;
}
file->f_pos+=offset;
ret=file->f_pos;
break;
default:
ret=-EINVAL;
//return ret;
break;
//case 2:
// if(file->f_pos+offset>GLOBLEMEM_SIZE)
// goto end;
}
return ret;
}
int globle_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)
{
int ret=0;
switch (cmd)
{
case MEM_CLEAR:
memset(mdev->globlemem,0,GLOBLEMEM_SIZE);
break;
default:
{
ret=-EINVAL;
break;
}
}
return ret;
}
static const struct file_operations globle_fops={
.owner=THIS_MODULE,
.read=globle_read,
.open=globle_open,
.write=globle_write,
.llseek=globle_llseek,
.ioctl=globle_ioctl,
.release=globle_release,
};//注意格式,不是指针,中间隔开用逗号,末尾}有分号!
static void globle_setup_cdev(struct globle_cdev *dev, int index)//使用这个函数完成cdev的初始化和添加
{
int err;
dev_t devno=MKDEV(globlemajor,index);
cdev_init(&dev->cdev, &globle_fops);//初始化,第一个参数为*cdev,第二个关联*fops
//mdev->cdev.dev=MAJOR(globlemajor);
mdev->cdev.owner=THIS_MODULE;//cdev的owner要被设置为THIS_MODULE
mdev->cdev.ops=&globle_fops;
//memset(mdev->globlemem,0,sizeof(mdev->globlemem));
err=cdev_add(&dev->cdev,devno, 1);//告诉内核该结构的信息。第二个参数为设备编号和第三个参数为和该设备关联的设备编号的数量返回负值设备没有添加成功
if (err)
printk(KERN_NOTICE "Error %d adding globlemem %d\n", err, index);
}
int globle_init(void)
{
dev_t devno;
//char *globle_mem;
int ret;
ret=0;
devno=MKDEV(globlemajor,0);//最重要的部分,要记住步骤
if(globlemajor)//先判断有没有提前给他设备号,若是给了
{
ret=register_chrdev_region(devno,1,"globle");//向系统申请设备号,再申请内存。第一个参数为dev_t类型的,所以必须要有MKDEV转化!再使用MAJOR或者MINOR获取其主或次设备号,其中1为申请的个数,第三个参数为名字
}
else
{
ret=alloc_chrdev_region(&devno,0,1,"globle");//疑问!0为第一个请求的设备号,1为申请的设备编号个数。注意这个地方&devno为地址,把分配到的设备号放到其中,类型为dev_t,所以需要用MAJOR
globlemajor=MAJOR(devno);
}
if(ret<0)
return ret;
mdev=kmalloc(sizeof(struct globle_cdev),GFP_KERNEL);//申请到设备号再申请内存,注意这里要有出错处理,如果申请不到就要释放申请到的设备号。
if (!mdev)
{
ret=-ENOMEM;
goto fail_malloc;
}
memset(mdev, 0, sizeof(struct globle_cdev));//把申请到的内存范围清0.
globle_setup_cdev(mdev,0);
return 0;
fail_malloc:
unregister_chrdev_region(devno,1);//第一个参数为dev_t类型,第二个为数量
return ret;
}
void globle_exit(void)
{
cdev_del(&mdev->cdev);//地址,移除设备,参数为struct cdev*
kfree(mdev);//括号里面是什么
unregister_chrdev_region(MKDEV(globlemajor,0),1);
}
MODULE_LICENSE("Dual BSD/GPL");
module_param(globlemajor,int,S_IRUGO);
module_init(globle_init);
module_exit(globle_exit);
如果是申请两个设备代码改为
int globle_open(struct inode *inode, struct file *file)
{
struct globle *dev;
dev=container_of(inode->i_cdev,struct globle_cdev, cdev);//找globle_cdev结构并返回
file->private_data=dev;
return 0;
}//以后在别的函数调用的时候都要加一句struct globle_cdev *dev = file->private_data;
static void globle_setup_cdev(struct globle_cdev *dev, int index)
{
int err;
dev_t devno=MKDEV(globlemajor,index);
cdev_init(&dev->cdev, &globle_fops);
mdev->cdev.owner=THIS_MODULE;
mdev->cdev.ops=&globle_fops;
err=cdev_add(&dev->cdev,devno, 1);
if (err)
printk(KERN_NOTICE "Error %d adding globlemem %d\n", err, index);
}
int globle_init(void)
{
dev_t devno;
//char *globle_mem;
int ret;
ret=0;
devno=MKDEV(globlemajor,0);
if(globlemajor)
{
ret=register_chrdev_region(devno,2,"globle");//先申请设备号,再申请内存
}
else
{
ret=alloc_chrdev_region(&devno,0,2,"globle"); globlemajor=MAJOR(devno);
}
if(ret<0)
return ret;
mdev=kmalloc(2*sizeof(struct globle_cdev),GFP_KERNEL);
if (!mdev)
{
ret=-ENOMEM;
goto fail_malloc;
}
memset(mdev, 0, 2*sizeof(struct globle_cdev));
globle_setup_cdev(&mdev[0],0);//注意这里有两个结构体,主设备号相同,次设备号不同
globle_setup_cdev(&mdev[1],0);
return 0;
fail_malloc:
unregister_chrdev_region(devno,1);
return ret;
}
void globle_exit(void)
{
cdev_del(&mdev[0].cdev);//地址
cdev_del(&mdev[1].cdev);
kfree(mdev);//括号里面是什么
unregister_chrdev_region(MKDEV(globlemajor,0),2);
自动加载模块方法:
启动脚本是vsftpd,在/etc/init.d/vsftpd下
vi进入
加上一句:insmod /test/s3c24xx_leds.ko
ok啦
问题::怎么验证两个设备,怎么llseek函数该怎么验证!