1. character device driver source code
[Cpp]
# Include <linux/module. h>
# Include <linux/init. h>
# Include <linux/types. h>
# Include <linux/fs. h>
# Include <linux/errno. h>
# Include <linux/mm. h>
# Include <linux/sched. h>
# Include <linux/cdev. h>
# Include <asm/io. h>
# Include <asm/system. h>
# Include <asm/uaccess. h>
# Include <linux/slab. h>/* kmalloc header file */
# Include <linux/semaphore. h>/* semaphore header file */
# Define MEMDEV_MAJOR 251/* default mem master device Number */
# Define MEMDEV_NUM 2/* Number of devices */
# Define MEMDEV_SIZE 1024/* allocated memory size */
Struct mem_dev
{
Unsigned int size;
Char * data;
Struct semaphore sem;
};
Static int mem_major = MEMDEV_MAJOR;/* default mem master device Number */
Struct cdev mem_cdev;
Struct mem_dev * mem_devp;/* Device struct pointer */
/* File opening function */
Static int
Mem_open (struct inode * inode, struct file * filp)
{
Struct mem_dev * dev;
Unsigned int num;
Printk ("mem_open. \ n ");
Num = MINOR (inode-> I _rdev);/* obtain the device Number */
If (num> (MEMDEV_NUM-1 ))
Return-ENODEV;
Dev = & mem_devp [num];
Filp-> private_data = dev;/* Save the device structure as private data */
Return 0;
}
/* Call When closing */
Static int
Mem_release (struct inode * inode, struct file * filp)
{
Printk ("mem_release. \ n ");
Return 0;
}
/* Read function */
Static ssize_t
Mem_read (struct file * filp, char _ user * buf, size_t size, loff_t * ppos)
{
Int ret = 0;
Struct mem_dev * dev;
Unsigned long p;
Unsigned long count;
Printk ("mem_read. \ n ");
Dev = filp-> private_data;/* get the device structure */
Count = size;
P = * ppos;
/* Check the validity of the Offset and data size */
If (p> MEMDEV_SIZE)
Return 0;
If (count> (MEMDEV_SIZE-p ))
Count = MEMDEV_SIZE-p;
If (down_interruptible (& dev-> sem)/* Lock mutex semaphores */
Return-ERESTARTSYS;
/* Read data to the user space */
If (copy_to_user (buf, dev-> data + p, count ))
{
Ret =-EFAULT;
Printk ("copyfrom user failed \ n ");
}
Else
{
* Ppos + = count;
Ret = count;
Printk ("read % d bytes from dev \ n", count );
}
Up (& dev-> sem);/* unlock mutex semaphores */
Return ret;
}
/* Write a function */
Static ssize_t
Mem_write (struct file * filp, const char _ user * buf, size_t size, loff_t * ppos)
{
Int ret = 0;
Struct mem_dev * dev;
Unsigned long p;
Unsigned long count;
Printk ("mem_write. \ n ");
Dev = filp-> private_data;
Count = size;
P = * ppos;
If (p> MEMDEV_SIZE)
{
Return 0;
}
If (count> (MEMDEV_SIZE-p ))
Count = MEMDEV_SIZE-p;
If (down_interruptible (& dev-> sem ))
Return-ERESTARTSYS;
If (copy_from_user (dev-> data + p, buf, count ))
{
Ret =-EFAULT;
Printk ("copyfrom user failed \ n ");
}
Else
{
* Ppos + = count;
Ret = count;
Printk ("writed % d bytes to dev \ n", count );
}
Up (& dev-> sem );
Return ret;
}
/* Modify the current file read/write location */
Static loff_t
Mem_llseek (struct file * filp, loff_t offset, int whence)
{
Int newpos;
Printk ("mem_llsek. \ n ");
Switch (whence)
{
Case 0:
Newpos = offset;
Break;
Case 1:
Newpos = filp-> f_pos + offset;
Break;
Case 2:
Newpos = MEMDEV_SIZE-1 + offset;
Break;
Default:
Return-EINVAL;
}
If (newpos <0) | (newpos> (MEMDEV_SIZE-1 )))
Return-EINVAL;
Filp-> f_pos = newpos;
Return newpos;
}
/* File operation struct */
Static const struct file_operations mem_fops = {
. Owner = THIS_MODULE,
. Open = mem_open,
. Write = mem_write,
. Read = mem_read,
. Release = mem_release,
. Llseek = mem_llseek,
};
/* Device Driver Model Loading Function */
Static int
_ Init memdev_init (void)
{
Int result;
Int err;
Int I;
/* Apply for the device Number */
Dev_t devno = MKDEV (mem_major, 0 );
If (mem_major)
/* Pay attention to the difference between the dev_t parameter for static application and the dynamic dev_t parameter */
Result = register_chrdev_region (devno, MEMDEV_NUM, "memdev ");
Else
{
Result = alloc_chrdev_region (& devno, 0, MEMDEV_NUM, "memdev ");
Mem_major = MAJOR (devno );
}
If (result <0)
{
Printk ("can not get major devno: % d \ n", mem_major );
Return result;
}
/* Register the device driver */
Cdev_init (& mem_cdev, & mem_fops);/* initialize the cdev structure */
Mem_cdev.owner = THIS_MODULE;
/* Register the character Drive Device */
Err = cdev_add (& mem_cdev, MKDEV (mem_major, 0), MEMDEV_NUM );
If (err)
Printk ("addcdev faild, err is % d \ n", err );
/* Allocate device memory */
Mem_devp = kmalloc (MEMDEV_NUM * (sizeof (struct mem_dev), GFP_KERNEL );
If (! Mem_devp)
{
Result =-ENOMEM;
Goto fail_malloc;
}
Memset (mem_devp, 0, MEMDEV_NUM * (sizeof (struct mem_dev )));
For (I = 0; I <MEMDEV_NUM; I ++)
{
Mem_devp [I]. size = MEMDEV_SIZE;
Mem_devp [I]. data = kmalloc (MEMDEV_SIZE, GFP_KERNEL );
Memset (mem_devp [I]. data, 0, MEMDEV_SIZE );
// Init_MUTEX (& mem_devp [I]. sem);/* initialize the mutex lock */
Sema_init (& mem_devp [I]. sem, 1 );
}
Return result;
Fail_malloc:
Unregister_chrdev_region (MKDEV (mem_major, 0), MEMDEV_NUM );
Return result;
}
/* Device Driver Model uninstall function */
Static void
Memdev_exit (void)
{
Cdev_del (& mem_cdev );
/* Note that the number of device numbers to be released must be the same as the number of device numbers applied for. Otherwise, device number resources may be lost */
Unregister_chrdev_region (MKDEV (mem_major, 0), MEMDEV_NUM );
Printk ("memdev_exit \ n ");
}
Module_init (memdev_init );
Module_exit (memdev_exit );
MODULE_AUTHOR ("BQL ");
MODULE_LICENSE ("GPL ");
# Include <linux/module. h>
# Include <linux/init. h>
# Include <linux/types. h>
# Include <linux/fs. h>
# Include <linux/errno. h>
# Include <linux/mm. h>
# Include <linux/sched. h>
# Include <linux/cdev. h>
# Include <asm/io. h>
# Include <asm/system. h>
# Include <asm/uaccess. h>
# Include <linux/slab. h>/* kmalloc header file */
# Include <linux/semaphore. h>/* semaphore header file */
# Define MEMDEV_MAJOR 251/* default mem master device Number */
# Define MEMDEV_NUM 2/* Number of devices */
# Define MEMDEV_SIZE 1024/* allocated memory size */
Struct mem_dev
{
Unsigned int size;
Char * data;
Struct semaphore sem;
};
Static int mem_major = MEMDEV_MAJOR;/* default mem master device Number */
Struct cdev mem_cdev;
Struct mem_dev * mem_devp;/* Device struct pointer */
/* File opening function */
Static int
Mem_open (struct inode * inode, struct file * filp)
{
Struct mem_dev * dev;
Unsigned int num;
Printk ("mem_open. \ n ");
Num = MINOR (inode-> I _rdev);/* obtain the device Number */
If (num> (MEMDEV_NUM-1 ))
Return-ENODEV;
Dev = & mem_devp [num];
Filp-> private_data = dev;/* Save the device structure as private data */
Return 0;
}
/* Call When closing */
Static int
Mem_release (struct inode * inode, struct file * filp)
{
Printk ("mem_release. \ n ");
Return 0;
}
/* Read function */
Static ssize_t
Mem_read (struct file * filp, char _ user * buf, size_t size, loff_t * ppos)
{
Int ret = 0;
Struct mem_dev * dev;
Unsigned long p;
Unsigned long count;
Printk ("mem_read. \ n ");
Dev = filp-> private_data;/* get the device structure */
Count = size;
P = * ppos;
/* Check the validity of the Offset and data size */
If (p> MEMDEV_SIZE)
Return 0;
If (count> (MEMDEV_SIZE-p ))
Count = MEMDEV_SIZE-p;
If (down_interruptible (& dev-> sem)/* Lock mutex semaphores */
Return-ERESTARTSYS;
/* Read data to the user space */
If (copy_to_user (buf, dev-> data + p, count ))
{
Ret =-EFAULT;
Printk ("copyfrom user failed \ n ");
}
Else
{
* Ppos + = count;
Ret = count;
Printk ("read % d bytes from dev \ n", count );
}
Up (& dev-> sem);/* unlock mutex semaphores */
Return ret;
}
/* Write a function */
Static ssize_t
Mem_write (struct file * filp, const char _ user * buf, size_t size, loff_t * ppos)
{
Int ret = 0;
Struct mem_dev * dev;
Unsigned long p;
Unsigned long count;
Printk ("mem_write. \ n ");
Dev = filp-> private_data;
Count = size;
P = * ppos;
If (p> MEMDEV_SIZE)
{
Return 0;
}
If (count> (MEMDEV_SIZE-p ))
Count = MEMDEV_SIZE-p;
If (down_interruptible (& dev-> sem ))
Return-ERESTARTSYS;
If (copy_from_user (dev-> data + p, buf, count ))
{
Ret =-EFAULT;
Printk ("copyfrom user failed \ n ");
}
Else
{
* Ppos + = count;
Ret = count;
Printk ("writed % d bytes to dev \ n", count );
}
Up (& dev-> sem );
Return ret;
}
/* Modify the current file read/write location */
Static loff_t
Mem_llseek (struct file * filp, loff_t offset, int whence)
{
Int newpos;
Printk ("mem_llsek. \ n ");
Switch (whence)
{
Case 0:
Newpos = offset;
Break;
Case 1:
Newpos = filp-> f_pos + offset;
Break;
Case 2:
Newpos = MEMDEV_SIZE-1 + offset;
Break;
Default:
Return-EINVAL;
}
If (newpos <0) | (newpos> (MEMDEV_SIZE-1 )))
Return-EINVAL;
Filp-> f_pos = newpos;
Return newpos;
}
/* File operation struct */
Static const struct file_operations mem_fops = {
. Owner = THIS_MODULE,
. Open = mem_open,
. Write = mem_write,
. Read = mem_read,
. Release = mem_release,
. Llseek = mem_llseek,
};
/* Device Driver Model Loading Function */
Static int
_ Init memdev_init (void)
{
Int result;
Int err;
Int I;
/* Apply for the device Number */
Dev_t devno = MKDEV (mem_major, 0 );
If (mem_major)
/* Pay attention to the difference between the dev_t parameter for static application and the dynamic dev_t parameter */
Result = register_chrdev_region (devno, MEMDEV_NUM, "memdev ");
Else
{
Result = alloc_chrdev_region (& devno, 0, MEMDEV_NUM, "memdev ");
Mem_major = MAJOR (devno );
}
If (result <0)
{
Printk ("can not get major devno: % d \ n", mem_major );
Return result;
}
/* Register the device driver */
Cdev_init (& mem_cdev, & mem_fops);/* initialize the cdev structure */
Mem_cdev.owner = THIS_MODULE;
/* Register the character Drive Device */
Err = cdev_add (& mem_cdev, MKDEV (mem_major, 0), MEMDEV_NUM );
If (err)
Printk ("addcdev faild, err is % d \ n", err );
/* Allocate device memory */
Mem_devp = kmalloc (MEMDEV_NUM * (sizeof (struct mem_dev), GFP_KERNEL );
If (! Mem_devp)
{
Result =-ENOMEM;
Goto fail_malloc;
}
Memset (mem_devp, 0, MEMDEV_NUM * (sizeof (struct mem_dev )));
For (I = 0; I <MEMDEV_NUM; I ++)
{
Mem_devp [I]. size = MEMDEV_SIZE;
Mem_devp [I]. data = kmalloc (MEMDEV_SIZE, GFP_KERNEL );
Memset (mem_devp [I]. data, 0, MEMDEV_SIZE );
// Init_MUTEX (& mem_devp [I]. sem);/* initialize the mutex lock */
Sema_init (& mem_devp [I]. sem, 1 );
}
Return result;
Fail_malloc:
Unregister_chrdev_region (MKDEV (mem_major, 0), MEMDEV_NUM );
Return result;
}
/* Device Driver Model uninstall function */
Static void
Memdev_exit (void)
{
Cdev_del (& mem_cdev );
/* Note that the number of device numbers to be released must be the same as the number of device numbers applied for. Otherwise, device number resources may be lost */
Unregister_chrdev_region (MKDEV (mem_major, 0), MEMDEV_NUM );
Printk ("memdev_exit \ n ");
}
Module_init (memdev_init );
Module_exit (memdev_exit );
MODULE_AUTHOR ("BQL ");
MODULE_LICENSE ("GPL ");