#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
static int major = 237;
static int minor = 0;
static int err;
static dev_t devno;
static struct class *hello_class;
struct device dev;
#define name "hello"
#define MAX_COM_NUM 2
struct mydev{
struct cdev cdev;
char *reg;
};
struct mydev *pmydev[MAX_COM_NUM];
ssize_t dev_fifo_read (struct file *file, char __user *buf, size_t size, loff_t *pos)
{
struct mydev *cd;
cd = (struct mydev *)file->private_data;
printk("read() file->private_data cd->test=%d\n",cd->test);
if(copy_to_user(buf, &(MINOR(cd->cdev.dev)), size)){
return -EFAULT;
}
return size;
}
int dev_fifo_close (struct inode *inode, struct file *file)
{
printk("dev_fifo_close()\n");
return 0;
}
static int dev_fifo_open (struct inode *inode, struct file *file)
{
struct mydev *cd;
cd = pmydev[MINOR(inode->i_rdev)];
file->private_data = cd;
return 0;
}
static struct file_operations dev_fifo_ops =
{
.open = dev_fifo_open,
.read = dev_fifo_read,
.release = dev_fifo_close,
};
static int dev_init(void)
{
int result;
int error;
int i = 0;
register_chrdev(major, "hello", &dev_fifo_ops);
hello_class = class_create(THIS_MODULE, "hello_class");
for(i=0;i<MAX_COM_NUM;i++){
pmydev[i] = kmalloc(sizeof(struct mydev), GFP_KERNEL);
}
for(i=0;i<MAX_COM_NUM;i++){
pmydev[i]->cdev.dev = MKDEV(major,i);
err = device_create(hello_class, NULL, MKDEV(major,i), NULL, "%s%d",name,i);
}
return 0;
}
static void __exit hello_exit(void)
{
int i;
printk("dev_fifo_exit \n");
for(i=0;i<MAX_COM_NUM;i++)
{
cdev_del(&pmydev[i]->cdev);
kfree(pmydev[i]);
device_destroy(hello_class, MKDEV(major, i));
}
class_destroy(hello_class);
unregister_chrdev(major, "hello");
return ;
}
module_init(dev_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
1、内存分配
pmydev[i] = kmalloc(sizeof(struct mydev), GFP_KERNEL);
kmalloc返回是无类型指针;pmydev[i]是struct mydev的指针;
2、设备号分配和储存
...
register_chrdev(major, "hello", &dev_fifo_ops);
hello_class = class_create(THIS_MODULE, "hello_class");
....
for(i=0;i<MAX_COM_NUM;i++){
pmydev[i]->test = i;
pmydev[i]->cdev.dev = MKDEV(major,i);
err = device_create(hello_class, NULL, MKDEV(major,i), NULL, "%s%d",name,i);
}
利用cdev结构体中dev_t dev来储存主次设备号;
register_chrdev和hello_class已经在sys下创建了对应目录了;
device_create 第三个参数是需要使用次设备号的,这点和cdev_add不一样 (cdev_add(&cdev,devno,2);只在意主设备号,第三个参数来设定次设备号);设备创建完之后由udev在/dev下创建设备节点。
3、open的实现
static int dev_fifo_open (struct inode *inode, struct file *file)
{
struct mydev *cd;
cd = pmydev[MINOR(inode->i_rdev)];
file->private_data = cd;
return 0;
}
利用file中的void类型成员private_data存储信息,将内核中的结构体mydev以指针形式赋值给private_data。所以只要愿意,就可以在mydev填充任何信息。
4、read的实现
ssize_t dev_fifo_read (struct file *file, char __user *buf, size_t size, loff_t *pos)
{
struct mydev *cd;
cd = (struct mydev *)file->private_data;
printk("read() file->private_data cd->test=%d\n",cd->test);
if(copy_to_user(buf, &(MINOR(cd->cdev.dev)), size)){
return -EFAULT;
}
return
;
}
cd = (struct mydev *)file->private_data;将private_data类型转化回去,准备读取pmydev[i]的数据。