char_device_struct 结构体:
使用udev自动生成设备节点的函数:
class_create(…)在/drivers/base/class.c中实现:
/**
* class_create - create a struct class structure
* @owner: pointer to the module that is to "own" this struct class
* @nAME: pointer to a string for the name of this class.
*
* This is used to create a struct class pointer that can then be used
* in calls to device_create().
*
* Note, the pointer created here is to be destroyed when finished by
* making a call to class_destroy().
*/
struct class *class_create(struct module *owner, cONst char *name)
第一个参数指定类的所有者是哪个模块,第二个参数指定类名。
- static struct class *cdev_class;
- static int __init gm_cdev_init(void)
- {
- int result;
- dev_t devno = MKDEV(MAJOR_NR, 0);
- if(0 != MAJOR_NR){
- result = register_chrdev_region(devno, 2, DEV_NAME); //注册设备 支持两个设备,此设备号从0开始
- } else {
- result = alloc_chrdev_region(&devno, 0, 2, DEV_NAME);
- MAJOR_NR = MAJOR(devno);
- }
- printk(KERN_CRIT"hello\n");
- if(result < 0)
- return result;
- gm_cdevp = kmalloc(2*sizeof(struct gm_cdev_t), GFP_KERNEL);
- if(NULL == gm_cdevp){
- unregister_chrdev_region(MKDEV(MAJOR_NR, 0), 2);
- result = -ENOMEM;
- }
- memset(gm_cdevp, 0, 2*sizeof(struct gm_cdev_t));
- gm_setup_cdev(&gm_cdevp[0], 0);
- gm_setup_cdev(&gm_cdevp[0], 1);
- //gm_setup_cdev(&gm_cdevp[1], 1); //使用这一行的话支持两个设备
- cdev_class = class_create(THIS_MODULE, DEV_NAME);
- if(IS_ERR(cdev_class))
- return PTR_ERR(cdev_class);
- device_create(cdev_class, NULL, MKDEV(MAJOR_NR, 0), NULL, DEV_NAME"%d", 0); //生成 /dev/gmem0 节点
- device_create(cdev_class, NULL, MKDEV(MAJOR_NR, 1), NULL, DEV_NAME"%d", 1); //生成 /dev/gmem1 节点
- return 0;
- }
- void gm_cdev_exit(void)
- {
- cdev_del(&gm_cdevp[0].cdev);
- cdev_del(&gm_cdevp[0].cdev);
- device_destroy(cdev_class, MKDEV(MAJOR_NR, 0)); //delete device node under /dev
- device_destroy(cdev_class, MKDEV(MAJOR_NR, 1)); //delete device node under /dev
- class_destroy(cdev_class); //delete class created by us
- kfree(gm_cdevp);
- unregister_chrdev_region(MKDEV(MAJOR_NR, 0), 2);
- }
- static struct class *cdev_class;
- static int __init gm_cdev_init(void)
- {
- int result;
- dev_t devno = MKDEV(MAJOR_NR, 0);
- if(0 != MAJOR_NR){
- result = register_chrdev_region(devno, 2, DEV_NAME); //注册设备 支持两个设备,此设备号从0开始
- } else {
- result = alloc_chrdev_region(&devno, 0, 2, DEV_NAME);
- MAJOR_NR = MAJOR(devno);
- }
- printk(KERN_CRIT"hello\n");
- if(result < 0)
- return result;
- gm_cdevp = kmalloc(2*sizeof(struct gm_cdev_t), GFP_KERNEL);
- if(NULL == gm_cdevp){
- unregister_chrdev_region(MKDEV(MAJOR_NR, 0), 2);
- result = -ENOMEM;
- }
- memset(gm_cdevp, 0, 2*sizeof(struct gm_cdev_t));
- gm_setup_cdev(&gm_cdevp[0], 0);
- //gm_setup_cdev(&gm_cdevp[0], 1);
- gm_setup_cdev(&gm_cdevp[1], 1); //使用这一行的话支持两个设备
- cdev_class = class_create(THIS_MODULE, DEV_NAME);
- if(IS_ERR(cdev_class))
- return PTR_ERR(cdev_class);
- device_create(cdev_class, NULL, MKDEV(MAJOR_NR, 0), NULL, DEV_NAME"%d", 0); //生成 /dev/gmem0 节点
- device_create(cdev_class, NULL, MKDEV(MAJOR_NR, 1), NULL, DEV_NAME"%d", 1); //生成 /dev/gmem1 节点
- return 0;
- }
- void gm_cdev_exit(void)
- {
- cdev_del(&gm_cdevp[0].cdev);
- cdev_del(&gm_cdevp[1].cdev);
- device_destroy(cdev_class, MKDEV(MAJOR_NR, 0)); //delete device node under /dev
- device_destroy(cdev_class, MKDEV(MAJOR_NR, 1)); //delete device node under /dev
- class_destroy(cdev_class); //delete class created by us
- kfree(gm_cdevp);
- unregister_chrdev_region(MKDEV(MAJOR_NR, 0), 2);
- }
- root@wang:/work/wanghuan/drives# ls
- cdev.c cdev.ko hello.c Makefile modules.order
- root@wang:/work/wanghuan/drives# insmod cdev.ko
- root@wang:/work/wanghuan/drives# lsmod | grep cdev
- cdev 1853 0
- root@wang:/work/wanghuan/drives# ls /dev/gmem* -l
- crw------- 1 root root 250, 0 2011-06-12 14:08 /dev/gmem0
- crw------- 1 root root 250, 1 2011-06-12 14:08 /dev/gmem1
- root@wang:/work/wanghuan/drives# ls > /dev/gmem0
- root@wang:/work/wanghuan/drives# cat /dev/gmem1
- root@wang:/work/wanghuan/drives# cat /dev/gmem0
- cdev.c
- cdev.ko
- hello.c
- Makefile
- modules.order
-
- /**
- * =====================================================================================
- * Filename: cdev.c
- * Description: 字符设备驱动模型
- * Version: 1.0
- * Created: 2011年06月02日 19时27分50秒
- * Revision: none
- * Compiler: gcc
- *
- * Author: wanghuan,
- * Company:
- * =====================================================================================
- */
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/fs.h> /* file_operation */
- #include <linux/errno.h> /* Error number */
- #include <linux/mm.h>
- #include <linux/sched.h>
- #include <linux/slab.h>
- #include <linux/init.h> /* __init __exit */
- #include <linux/device.h>
- #include <linux/cdev.h>
- #include <asm/io.h>
- #include <asm/system.h>
- #include <asm/uaccess.h> /* copy_to_user, copy_from_user */
- #include <linux/kernel.h> /* printk() */
- #define GLOBALMEM_SIZE 0x1000
- #define MEM_CLEAN 0x1
- #define DEV_NAME "gmem"
- #define MEM_CLEAR _IO(GLOBALMEM_SIZE, 0)
- static int MAJOR_NR = 250; /* Driver Major Number */
- //static int MINOR_NR = 0; /* Driver Major Number */
- struct gm_cdev_t{
- struct cdev cdev;
- unsigned char mem[GLOBALMEM_SIZE];
- };
- static struct gm_cdev_t *gm_cdevp;
- static int gm_open(struct inode *inode, struct file *filp)
- {
- struct gm_cdev_t *dev;
- dev = container_of(inode->i_cdev, struct gm_cdev_t, cdev);
- filp->private_data = dev;
- return 0;
- }
- static int gm_release(struct inode *inode, struct file *filp)
- {
- filp->private_data = NULL;
- return 0;
- }
- static ssize_t gm_read(struct file *filp, char __user *buf, size_t count, loff_t *fpos)
- {
- unsigned long p = *fpos;
- int ret = 0;
- struct gm_cdev_t *dev = filp->private_data;
- if(p >= GLOBALMEM_SIZE)
- return 0;
- if(count > GLOBALMEM_SIZE - p)
- count = GLOBALMEM_SIZE -p;
- if(copy_to_user(buf, (void*)(dev->mem) + p, count))
- ret = -EFAULT;
- else{
- *fpos +=count;
- ret =count;
- printk(KERN_INFO "read %d butes from %ld \n", count, p);
- }
- return ret;
- }
- static ssize_t gm_write(struct file *filp, const char __user *buf, size_t count, loff_t *fpos)
- {
- unsigned long p = *fpos;
- int ret = 0;
- struct gm_cdev_t *dev = filp->private_data;
- if(p >= GLOBALMEM_SIZE)
- return 0;
- if(p >= GLOBALMEM_SIZE - p)
- count = GLOBALMEM_SIZE - p;
- if(copy_from_user(dev->mem + p, buf, count))
- ret = - EFAULT;
- else{
- *fpos +=count;
- ret = count;
- printk(KERN_INFO "write %d butes from %ld \n", count, p);
- }
- return ret;
- }
- static loff_t gm_llseek(struct file *filp, loff_t offset, int orig)
- {
- loff_t ret;
- switch(orig){
- case 0:
- if(offset < 0){
- ret = -EFAULT;
- break;
- }
- if((unsigned int)offset > GLOBALMEM_SIZE){
- ret = -EFAULT;
- break;
- }
- filp->f_pos = (unsigned int)offset;
- ret = filp->f_pos;
- break;
- case 1:
- if(filp->f_pos + offset > GLOBALMEM_SIZE){
- ret = -EFAULT;
- break;
- }
- if(filp->f_pos + offset < 0){
- ret = -EFAULT;
- break;
- }
- filp->f_pos += offset;
- ret = filp->f_pos;
- break;
- default:
- ret = -EFAULT;
- }
- return ret;
- }
- static int gm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
- {
- struct gm_cdev_t *dev = filp->private_data;
- switch(cmd){
- case MEM_CLEAR:
- memset(dev->mem, 0, GLOBALMEM_SIZE);
- printk(KERN_INFO "globalmem is set to zero \n");
- break;
- default:
- return -EINVAL;
- }
- return 0;
- }
- static const struct file_operations gm_fops = {
- .owner = THIS_MODULE,
- .open = gm_open,
- .release = gm_release,
- .read = gm_read,
- .write = gm_write,
- .ioctl = gm_ioctl,
- .llseek = gm_llseek,
- };
- static void gm_setup_cdev(struct gm_cdev_t *gm_cdev, int minor)
- {
- int err;
- dev_t devno = MKDEV(MAJOR_NR, minor);
- cdev_init(&gm_cdev->cdev, &gm_fops);
- gm_cdevp->cdev.owner = THIS_MODULE;
- err = cdev_add(&gm_cdev->cdev, devno, 1);
- if(err != 0)
- printk(KERN_NOTICE "Error %d adding gmen", err);
- }
- static struct class *cdev_class;
- static int __init gm_cdev_init(void)
- {
- int result;
- dev_t devno = MKDEV(MAJOR_NR, 0);
- if(0 != MAJOR_NR){
- result = register_chrdev_region(devno, 2, DEV_NAME); //注册设备 支持两个设备,此设备号从0开始
- } else {
- result = alloc_chrdev_region(&devno, 0, 2, DEV_NAME);
- MAJOR_NR = MAJOR(devno);
- }
- printk(KERN_CRIT"hello\n");
- if(result < 0)
- return result;
- gm_cdevp = kmalloc(2*sizeof(struct gm_cdev_t), GFP_KERNEL);
- if(NULL == gm_cdevp){
- unregister_chrdev_region(MKDEV(MAJOR_NR, 0), 2);
- result = -ENOMEM;
- }
- memset(gm_cdevp, 0, 2*sizeof(struct gm_cdev_t));
- gm_setup_cdev(&gm_cdevp[0], 0);
- //gm_setup_cdev(&gm_cdevp[0], 1);
- gm_setup_cdev(&gm_cdevp[1], 1);
- cdev_class = class_create(THIS_MODULE, DEV_NAME);
- if(IS_ERR(cdev_class))
- return PTR_ERR(cdev_class);
- device_create(cdev_class, NULL, MKDEV(MAJOR_NR, 0), NULL, DEV_NAME"%d", 0);
- device_create(cdev_class, NULL, MKDEV(MAJOR_NR, 1), NULL, DEV_NAME"%d", 1);
- return 0;
- }
- void gm_cdev_exit(void)
- {
- cdev_del(&gm_cdevp[0].cdev);
- cdev_del(&gm_cdevp[1].cdev);
- device_destroy(cdev_class, MKDEV(MAJOR_NR, 0)); //delete device node under /dev
- device_destroy(cdev_class, MKDEV(MAJOR_NR, 1)); //delete device node under /dev
- class_destroy(cdev_class); //delete class created by us
- kfree(gm_cdevp);
- unregister_chrdev_region(MKDEV(MAJOR_NR, 0), 2); //由于注册了两个设备,最后一个参数为 2
- }
- module_init(gm_cdev_init);
- module_exit(gm_cdev_exit);
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("wanghuan");