驱动所需结构体定制,驱动基本操作函数映射(struct file_operations),xx_init(),
xx_exit(), _open(), xx _release()…,最后要用module_init(),module_exit(),指明函数入出口,再用MODULE_LISCENSE(“GPL”)
用一个驱动操纵四个管道, 每个管道有两个设备(dev0-7),偶数i做写设备, 奇数i+1做相应的读设备
一个major, 八个minor。cdev_init绑定一个struct cdev和struct file_operations, cdev_add将struct cdev和major的起始地和总设备长度绑定, 由于只有一个主设备所以class_create只用执行一次然而device_create要执行次设备数次,用于在/dev/下生成节点。不同设备节点进入可执行的功能不同,在open||release用参数struct inode来定位设备文件主副设备号, read||write则可用struct file。
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/wait.h>
#include <linux/semaphore.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/device.h>
#define f_dentry f_path.dentry
#define MAXNUM 100
#define MAJOR_NUM 500
struct mydev{
struct cdev devm;
struct semaphore sem[4];
wait_queue_head_t outq[4];
int flag[4];
char buffer[4][MAXNUM+1];
char *rd[4], *wr[4], *end[4];
}devwrite;
static struct class *myclass;
int major = MAJOR_NUM;
static ssize_t devwrite_read(struct file*, char * ,size_t ,loff_t *);
static ssize_t devwrite_write(struct file*, const char*, size_t, loff_t *);
static int devwrite_open(struct inode *inode, struct file *file);
static int devwrite_release(struct inode *inode, struct file *file);
struct file_operations devwrite_fops =
{
.read = devwrite_read,
.write = devwrite_write,
.open = devwrite_open,
.release = devwrite_release,
};
static int devwrite_init(void)
{
int i=0;
int result = 0;
int err = 0;
char str[30];
dev_t dev;
printk("start....");
/*if(major)
{
result = register_chrdev_region(dev, 8, "chwrite");
}
else
{*/
result = alloc_chrdev_region(&dev, 0, 8, "chwrite");
major = MAJOR(dev);
// }
if(result < 0)
return result;
printk("SUCCESS IN REGISTER\n");
cdev_init(&devwrite.devm, &devwrite_fops);
printk("SUCCESS IN INIT\n");
devwrite.devm.owner = THIS_MODULE;
err = cdev_add(&devwrite.devm, MKDEV(major, 0), 8);
printk("SUCCESS IN ADD\n");
for(i=0; i<4; i++)
{
//dev = MKDEV(major, i);
if(err)
printk(KERN_INFO "ERROR IN ADDING DEV NUMBER!", err);
else
{
printk(KERN_INFO "SUCCESS IN REGISTER!");
sema_init(&devwrite.sem[i], 1);
printk(KERN_INFO "SUCCESS IN SEM!");
init_waitqueue_head(&devwrite.outq[i]);
printk(KERN_INFO "SUCCESS IN OUTQ!");
devwrite.rd[i] = devwrite.buffer[i];
printk(KERN_INFO "SUCCESS IN BUFFER!");
devwrite.wr[i] = devwrite.buffer[i];
devwrite.end[i] = devwrite.buffer[i]+MAXNUM;
devwrite.flag[i]=0;
printk(KERN_INFO "SUCCESS IN ALL!");
}
}
// sprintf(str, "mypipe%d", i);
//printk(KERN_INFO "SUCCESS IN sprint! %s", str);
myclass = class_create(THIS_MODULE, "mydev");
printk(KERN_INFO "SUCCESS IN CLASS CREATE!");
device_create(myclass, NULL, MKDEV(major, 0), NULL, "mypipe0");
printk(KERN_INFO "SUCCESS IN DEVICE CREATE!");
device_create(myclass, NULL, MKDEV(major, 1), NULL, "mypipe1");
printk(KERN_INFO "SUCCESS IN DEVICE CREATE!");
device_create(myclass, NULL, MKDEV(major, 2), NULL, "mypipe2");
printk(KERN_INFO "SUCCESS IN DEVICE CREATE!");
device_create(myclass, NULL, MKDEV(major, 3), NULL, "mypipe3");
printk(KERN_INFO "SUCCESS IN DEVICE CREATE!");
device_create(myclass, NULL, MKDEV(major, 4), NULL, "mypipe4");
printk(KERN_INFO "SUCCESS IN DEVICE CREATE!");
device_create(myclass, NULL, MKDEV(major, 5), NULL, "mypipe5");
printk(KERN_INFO "SUCCESS IN DEVICE CREATE!");
device_create(myclass, NULL, MKDEV(major, 6), NULL, "mypipe6");
printk(KERN_INFO "SUCCESS IN DEVICE CREATE!");
device_create(myclass, NULL, MKDEV(major, 7), NULL, "mypipe7");
printk(KERN_INFO "SUCCESS IN DEVICE CREATE!");
return 0;
}
static int devwrite_open(struct inode *inode, struct file *file)
{
printk(KERN_INFO "SUCCESS IN ENTRANCE OPEN!");
try_module_get(THIS_MODULE);
printk("OPEN PIPE0\n");
return (0);
}
static int devwrite_release(struct inode *inode, struct file *file)
{
printk(KERN_INFO "SUCCESS IN ENTRANCE LEFT!");
module_put(THIS_MODULE);
printk("CLOSE PIPE0\n");
return (0);
}
static void devwrite_exit(void)
{
int j=0;
printk(KERN_INFO "SUCCESS IN ENTRANCE!");
cdev_del(&devwrite.devm);
for(j=0; j< 8; j++)
{
device_destroy(myclass, MKDEV(major, j));
printk(KERN_INFO "SUCCESS IN DD!");
}
class_destroy(myclass);
printk(KERN_INFO "SUCCESS IN CD!");
unregister_chrdev_region(MKDEV(major, 0), 8);
}
static ssize_t devwrite_read(struct file* file, char * buf,size_t len,loff_t *off)
{
int temp, tempn;
int minor = MINOR(file->f_dentry->d_inode->i_rdev);
temp = minor/2;
tempn = (minor%2);
switch(tempn)
{
case 0:
{
printk("CANT READ IN HERE!\n");
return -EFAULT;
}
case 1:
{
if(wait_event_interruptible(devwrite.outq[temp], devwrite.flag[temp]!=0))
return -ERESTARTSYS;
if(down_interruptible(&devwrite.sem[temp]))
return -ERESTARTSYS;
devwrite.flag[temp]=0;
if(devwrite.rd[temp] < devwrite.wr[temp])
{
len = min(len, (size_t)(devwrite.wr[temp] - devwrite.rd[temp]));
}
else
{
len = min(len, (size_t)(devwrite.end[temp] - devwrite.rd[temp]));
}
if(copy_to_user(buf, devwrite.rd[temp], len))
{
printk(KERN_ALERT"copy failed\n");
up(&devwrite.sem[temp]);
return -EFAULT;
}
devwrite.rd[temp] = devwrite.rd[temp] + len;
if(devwrite.rd[temp] == devwrite.end[temp])
devwrite.rd[temp] = devwrite.buffer[temp];
up(&devwrite.sem[temp]);
return len;
}
}
return -EFAULT;
}
static ssize_t devwrite_write(struct file* file, const char *buf, size_t len, loff_t *off)
{
int temp, tempn;
int minor = MINOR(file->f_dentry->d_inode->i_rdev);
temp = minor/2;
tempn = (minor%2);
switch(tempn)
{
case 0:
{
if(down_interruptible(&devwrite.sem[temp]))
return -ERESTARTSYS;
if(devwrite.rd[temp] <= devwrite.wr[temp])
len = min(len, (size_t)(devwrite.end[temp] - devwrite.wr[temp]));
else
len = min(len, (size_t)(devwrite.rd[temp] - devwrite.wr[temp] - 1));
if(copy_from_user(devwrite.wr[temp] , buf, len))
{
up(&devwrite.sem[temp]);
return -EFAULT;
}
devwrite.wr[temp] = devwrite.wr[temp] + len;
if(devwrite.wr[temp] == devwrite.end[temp])
devwrite.wr[temp] = devwrite.buffer[temp];
up(&devwrite.sem[temp]);
devwrite.flag[temp] = 1;
wake_up_interruptible(&devwrite.outq[temp]);
return len;
}
case 1:
{
printk("CANT WRITE IN HERE!\n");
return -EFAULT;
}
}
return -EFAULT;
}
module_init(devwrite_init);
module_exit(devwrite_exit);
MODULE_LICENSE("GPL");
ifneq ($(KERNELRELEASE),)
obj-m := mycdev.o#obj-m
else
KERNELDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD)
endif
clean:
rm -f *.o *.ko *.mod.c *.symvers *.c~ *~ *.order
make
insmod mycdev.ko
echo “hello, can you hear me?” > /dev/mypipe1
cat /dev/mypipe0
rmmod mycdev.ko
多加入printk输出错误信息
再使用 dmesg一步步检测