A simple character Device Driver

Source: Internet
Author: User

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 ");


 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.