Linux character device driver

Source: Internet
Author: User
Tags semaphore

First, the full source of the program is listed

/root/drivers/freg

----FREG.C

----Freg.h

----Makefile

Freg.h

#ifndef _fake_reg_h_#define _fake_reg_h_#include <linux/cdev.h> #include <linux/semaphore.h> #define Freg _device_node_name "  freg" #define Freg_device_file_name  "Freg" #define Freg_device_proc_name  "Freg" # Define Freg_device_class_name "Freg" struct Fake_reg_dev {int val;struct semaphore sem;struct Cdev Dev;}; #endif

Freg.c

#include <linux/init.h> #include <linux/module.h> #include <linux/types.h> #include <linux/fs.h > #include <linux/proc_fs.h> #include <linux/device.h> #include <asm/uaccess.h> #include "freg.h" static int freg_major = 0;static int freg_minor = 0;static struct class* freg_class = null;static struct fake_reg_dev* fre G_dev = null;static int freg_open (struct inode* inode, struct file* filp); static int freg_release (struct inode* inode, str UCT file* Filp); static ssize_t freg_read (struct file* filp, char __user *buf, size_t count, loff_t* f_pos); static ssize_t  Freg_write (struct file* filp, const char __user *buf, size_t count, loff_t* f_pos); static struct file_operations freg_fops        = {. Owner = This_module,. Open = Freg_open,. Release = Freg_release,. Read = Freg_read, . write = freg_write,};static int freg_open (struct inode* inode, struct file* filp) {struct fake_reg_dev* Dev;dev = cont Ainer_of (Inode->i_cdev, struct fake_reG_dev, dev); filp->private_data = Dev;return 0;} static int freg_release (struct inode* inode, struct file* filp) {return 0;} Static ssize_t freg_read (struct file* filp, char __user *buf, size_t count, loff_t* f_pos) {ssize_t err = 0;struct fake_re g_dev* dev = filp->private_data;if (down_interruptible (& (Dev->sem))) {Return-erestartsys;} if (Count < sizeof (dev->val)) {goto out;} if (Copy_to_user (buf, & (Dev->val), sizeof (Dev->val))) {err =-efault;goto out;} Err = sizeof (dev->val); Out:up (& (Dev->sem)); return err;} Static ssize_t freg_write (struct file* filp, const char __user *buf, size_t count, loff_t* f_pos) {struct fake_reg_dev* de         v = filp->private_data;ssize_t Err = 0;if (down_interruptible (& (Dev->sem))) {Return-erestartsys;        } if (count! = sizeof (dev->val)) {goto out; }if (Copy_from_user (& (Dev->val), buf, Count)) {err =-efault;goto out;} Err = sizeof (dev->val); Out:up (& (Dev->sem)); return err;}  static int __freg_setup_dev (struct fake_reg_dev* dev) {int err;dev_t devno = MKDEV (Freg_major, Freg_minor); memset (Dev, 0, sizeof (struct fake_reg_dev)); Cdev_init (& (Dev->dev), &freg_fops);d Ev->dev.owner = this_module;dev- >dev.ops = &freg_fops;//callback Function err = Cdev_add (& (Dev->dev), Devno, 1); if (err) {return err;} Init_mutex (& (Dev->sem));//Semaphore dev->val = 0;return 0;} The static int __init freg_init (void) {int err = -1;dev_t Dev = 0;/A 32-bit number, where 12 bits are used to represent the main device number, while the remaining 20 bits are used to represent the secondary device number struct device* temp = NULL;PRINTK (kern_alert "Initializing freg device.\n"); err = alloc_chrdev_region (&dev, 0, 1, freg_device_node_name)        ;//dynamically assign main and secondary device numbers if (Err < 0) {PRINTK (Kern_alert "Failed to alloc Char dev region.\n"); goto fail;} Freg_major = major (dev);//Gets the main device number Freg_minor = minor (dev);//Gets the secondary device number Freg_dev = Kmalloc (sizeof (struct fake_reg_dev), Gfp_ KERNEL), if (!freg_dev) {err =-ENOMEM;PRINTK (Kern_alert "Failed to Alloc freg device.\n"); goto unregister;} Err = __freg_setup_dev(Freg_dev); if (err) {PRINTK (kern_alert "Failed to setup Freg device:%d.\n", err); goto cleanup;} Freg_class = Class_create (This_module, Freg_device_class_name), if (Is_err (Freg_class)) {ERR = Ptr_err (Freg_class); PRINTK (Kern_alert "Failed to create Freg device class.\n"); goto Destroy_cdev;} temp = Device_create (Freg_class, NULL, Dev, "%s", Freg_device_file_name), if (Is_err (temp)) {ERR = Ptr_err (temp);p RINTK ( Kern_alert "Failed to create Freg device.\n"); goto Destroy_class;} PRINTK (Kern_alert "succedded to initialize Freg device.\n"); return 0;destroy_class://error handling mechanism Class_destroy (Freg_class) ;d Estroy_cdev:cdev_del (& (Freg_dev->dev)); Cleanup:kfree (Freg_dev); Unregister:unregister_chrdev_region ( MKDEV (Freg_major, Freg_minor), 1); Fail:return err;} static void __exit freg_exit (void) {dev_t Devno = MKDEV (Freg_major, Freg_minor);//Get dev_t variable PRINTK (kern_alert "Destroy Freg device.\n "), if (Freg_class) {Device_destroy (Freg_class, MKDEV (Freg_major,freg_minor));//delete/dev/freg file Class_de Stroy (Freg_class);} If(Freg_dev) {//delete character device Cdev_del (& (Freg_dev->dev)); Kfree (Freg_dev);} Unregister_chrdev_region (Devno, 1);//cancellation of the original application of the main device number and the second device number}module_license ("GPL"); Module_description ("Fake Register Driver");//If the Android kernel source code, make Menuconfig interface will have this module_init (freg_init); Insmod executes this function module_exit (freg_exit);//rmmod executes this function

Makefile

Obj-m: =FREG.O


Ii. steps to write a Linux driver

1th Step: Build Linux driver skeleton (load and unload Linux drivers)

Any type of program requires a function to begin execution, such as the C language requires a main function, Linux provides two functions module_init and module_exit to handle the initialization and exit of the driver respectively. Module_init corresponds to the C language's main function.

Module_init (Freg_init); Module_exit (Freg_exit);

2nd step: Registering and unregistering device files

Registering a device file in this procedure is divided into 3 small steps:

1, the dynamic distribution of the main equipment number and the second device number;

        dev_t dev = 0;err = alloc_chrdev_region (&dev, 0, 1, freg_device_node_name);//dynamic allocation of main and secondary device numbers
The dev_t is a 32-bit number, where 12 bits are used to represent the main device number, while the remaining 20 bits are used to represent the secondary device number.

MAJOR (dev_t Dev) is used to obtain the main device number, MINOR (dev_t Dev) is used to obtain the secondary device number.

MKDEV (int major,int minor) converts the main device number and the secondary device number to the dev_t type.

2. Register the character device according to the main equipment number and the secondary device number;

static int  __freg_setup_dev (struct fake_reg_dev* dev) {int err;dev_t devno = MKDEV (Freg_major, Freg_minor); Memset ( Dev, 0, sizeof (struct Fake_reg_dev)), Cdev_init (& (Dev->dev), &freg_fops);d ev->dev.owner = This_module; Dev->dev.ops = &freg_fops;err = Cdev_add (& (Dev->dev), Devno, 1); if (err) {return err;} Init_mutex (& (Dev->sem));d ev->val = 0;return 0;}

3, for the driver to establish file/dev/freg, to operate the character device driver.

        Freg_class = Class_create (This_module, Freg_device_class_name), if (Is_err (Freg_class)) {ERR = Ptr_err (Freg_class); PRINTK (Kern_alert "Failed to create Freg device class.\n"); goto Destroy_cdev;} temp = Device_create (Freg_class, NULL, Dev, "%s", Freg_device_file_name), if (Is_err (temp)) {ERR = Ptr_err (temp);p RINTK ( Kern_alert "Failed to create Freg device.\n"); goto Destroy_class;}


To unregister a device file:

the reverse operation of the previous 3 steps.

static void __exit freg_exit (void) {dev_t Devno = MKDEV (Freg_major, Freg_minor);p rintk (kern_alert "Destroy Freg device.\n "), if (freg_class) {        Device_destroy (Freg_class, MKDEV (Freg_major,freg_minor)); Class_destroy (Freg_class);} if (Freg_dev) {Cdev_del (& (Freg_dev->dev)); Kfree (Freg_dev);} Unregister_chrdev_region (Devno, 1);}

3rd Step: Specify the driver-related information

Module_license ("GPL"); Module_description ("Fake Register Driver");


4th step: Specify the callback function
static int Freg_open (struct inode* inode, struct file* filp), static int freg_release (struct inode* inode, struct file* fil p); static ssize_t freg_read (struct file* filp, char __user *buf, size_t count, loff_t* f_pos), Static ssize_t Freg_write (St Ruct file* Filp, const char __user *buf, size_t count, loff_t* f_pos); static struct file_operations freg_fops = {. Owner = This_module,. Open = Freg_open,. Release = Freg_release,. Read = Freg_read,. write = f reg_write,};static int Freg_open (struct inode* inode, struct file* filp) {struct fake_reg_dev* Dev;dev = container_of (Inod E->i_cdev, struct fake_reg_dev, dev); filp->private_data = Dev;return 0;} static int freg_release (struct inode* inode, struct file* filp) {return 0;} Static ssize_t freg_read (struct file* filp, char __user *buf, size_t count, loff_t* f_pos) {ssize_t err = 0;struct fake_re g_dev* dev = filp->private_data;if (down_interruptible (& (Dev->sem))) {Return-erestartsys;} if (Count < sIzeof (Dev->val)) {goto out;} if (Copy_to_user (buf, & (Dev->val), sizeof (Dev->val))) {err =-efault;goto out;} Err = sizeof (dev->val); Out:up (& (Dev->sem)); return err;} Static ssize_t freg_write (struct file* filp, const char __user *buf, size_t count, loff_t* f_pos) {struct fake_reg_dev* de         v = filp->private_data;ssize_t Err = 0;if (down_interruptible (& (Dev->sem))) {Return-erestartsys;        } if (count! = sizeof (dev->val)) {goto out; }if (Copy_from_user (& (Dev->val), buf, Count)) {err =-efault;goto out;} Err = sizeof (dev->val); Out:up (& (Dev->sem)); return err;}
Perhaps some readers have noticed. All functions and variables in the freg.c are declared static. This is because in the C language with static declaration functions, variables and other resources, these functions and variables will be placed in a separate area of memory, until the program exits completely, otherwise these resources will not be freed. Once the Linux driver is mounted, the drive will always reside in memory, unless it is manually uninstalled or shut down, so these functions and variable resources remain in memory. This means that multiple calls to these resources do not have to press the stack, the stack operation. It is advantageous to improve the running efficiency of the drive.


5th step: Writing the Makefile file

Obj-m: =FREG.O

6th step: Compiling the Linux driver module

sudo su into root mode

Make-c/usr/src/linux-headers-2.6.32-21-generic/m=/root/drivers/freg/


7th step: Install and uninstall Linux drivers

To install the Freg driver:

cd/root/drivers/freg/

Insmod Freg.ko


To see if Freg installed successfully:

Lsmod | grep Freg

Shown below:

       Freg                    2188  


View/dev/freg Information

Ls-l/dev/freg

Shown below:

       CRW-RW----1 root root 248, 0 2014-06-06 23:50/dev/freg

Uninstalling Linux Drivers

Rmmod Freg

Viewing log information from Linux-driven output

DMESG | grep Freg

The last three lines are displayed as follows:

[7722.273680] Initializing freg device. [7722.274095] succedded to initialize Freg device. [10766.282006] Destroy freg device.

Third, write the C language Program verification Freg driver

/root/drivers/freg

----HELLO.C

#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #define DEVICE_NAME "/dev/freg" int main (int ARGC, char** argv) {int FD = -1;int val = 0;fd = Open (Device_name, O_RDWR); if (fd = =-1) {printf ("Failed to open DEVICE%s.\ n ", device_name); return-1;} printf ("read original value:\n"); Read (fd, &val, sizeof (val));p rintf ("%d.\n\n", val); val = 5;printf ("Write value%d" To%s.\n\n ", Val, device_name);        Write (fd, &val, sizeof (val));p rintf ("Read The Value again:\n");        Read (FD, &val, sizeof (Val));        printf ("%d.\n\n", Val); close (FD); return 0;}

Compiling gcc hello.c-o Hello

Run the./hello and the results are as follows:

Read original value:0. Write value 5 To/dev/freg. Read the value Again:5.

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.